@stonepandastudio/cairn 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# @stonepandastudio/cairn
|
|
2
2
|
|
|
3
|
-
Shared AI workflow scaffolding
|
|
3
|
+
Shared AI workflow scaffolding, kept in sync across several repos.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
the steps mirrored into Jira. They were copied between repos by hand and drifted.
|
|
5
|
+
Each repo carries an `ai/` folder and a `.claude/commands/` folder holding the same
|
|
6
|
+
workflow — brief → description → plan → execute → review → QA, with the steps
|
|
7
|
+
mirrored into an issue tracker. Copied between repos by hand, they drift.
|
|
9
8
|
|
|
10
9
|
A cairn is a stack of stones left to mark a trail. That is what this does: it leaves
|
|
11
10
|
markers — a manifest of what it generated, and a report of where the copies stopped
|
|
@@ -13,21 +12,21 @@ agreeing.
|
|
|
13
12
|
|
|
14
13
|
```bash
|
|
15
14
|
npm i -D @stonepandastudio/cairn
|
|
16
|
-
npx cairn init --stack backend --tracker jira-server --project-key
|
|
15
|
+
npx cairn init --stack backend --tracker jira-server --project-key MYPROJ --story-type Task
|
|
17
16
|
```
|
|
18
17
|
|
|
19
18
|
## What v1 does
|
|
20
19
|
|
|
21
20
|
| Command | |
|
|
22
21
|
|---|---|
|
|
23
|
-
| `cairn tracker <cmd>` | Issue tracker client. Replaces the
|
|
22
|
+
| `cairn tracker <cmd>` | Issue tracker client. Replaces the copied `ai/scripts/jira.js` files |
|
|
24
23
|
| `cairn doctor` | Cross-repo drift report, plus per-repo generated-file state |
|
|
25
24
|
| `cairn init` | Makes a repo cairn-managed: writes `cairn.config.json`, `_cairn/`, and the shim |
|
|
26
25
|
|
|
27
26
|
Template rendering — generating the command stubs, `WORKFLOW.md` and the agent role
|
|
28
27
|
contracts from one workflow declaration — is v2, and deliberately not in this release.
|
|
29
|
-
v1 swaps the
|
|
30
|
-
release would make any regression impossible to attribute.
|
|
28
|
+
v1 swaps the tracker client under the consuming repos; bundling prompt changes into
|
|
29
|
+
the same release would make any regression impossible to attribute.
|
|
31
30
|
|
|
32
31
|
## The two folders
|
|
33
32
|
|
|
@@ -37,7 +36,7 @@ repo/
|
|
|
37
36
|
_cairn/ cairn writes this. nobody hand-edits it.
|
|
38
37
|
manifest.json what was generated, from which template, at which hash
|
|
39
38
|
scripts/jira.js vendored shim
|
|
40
|
-
ai/ project-owned. cairn
|
|
39
|
+
ai/ project-owned. cairn never touches it.
|
|
41
40
|
contexts/ progress/ tasks/ infrastructure/
|
|
42
41
|
```
|
|
43
42
|
|
|
@@ -51,27 +50,27 @@ Generated files are **committed**, not gitignored. Claude Code discovers
|
|
|
51
50
|
## Tracker
|
|
52
51
|
|
|
53
52
|
```bash
|
|
54
|
-
cairn tracker list-statuses
|
|
55
|
-
cairn tracker create-task "
|
|
56
|
-
cairn tracker create-subtask
|
|
57
|
-
cairn tracker set-status
|
|
58
|
-
cairn tracker append-description
|
|
59
|
-
cairn tracker close-story
|
|
53
|
+
cairn tracker list-statuses MYPROJ
|
|
54
|
+
cairn tracker create-task "Some task title"
|
|
55
|
+
cairn tracker create-subtask MYPROJ-101 "Step 1: first slice"
|
|
56
|
+
cairn tracker set-status MYPROJ-102 "In Progress"
|
|
57
|
+
cairn tracker append-description MYPROJ-101 ./ai/tasks/MYPROJ-101/brief-step-1.md --markup
|
|
58
|
+
cairn tracker close-story MYPROJ-42 # cascades through subtasks first
|
|
60
59
|
```
|
|
61
60
|
|
|
62
|
-
Providers are `jira-server` and `none`. `none` is a real provider, not an error
|
|
63
|
-
|
|
64
|
-
command stub needing an "if this repo has
|
|
61
|
+
Providers are `jira-server` and `none`. `none` is a real provider, not an error
|
|
62
|
+
case: a repo with no tracker makes the workflow steps no-ops rather than every
|
|
63
|
+
command stub needing an "if this repo has a tracker" branch written in prose.
|
|
65
64
|
|
|
66
|
-
Three things the
|
|
65
|
+
Three things the copied scripts did that this does not:
|
|
67
66
|
|
|
68
67
|
- **`process.exit` from library code.** Failures throw `TrackerError`; the CLI layer
|
|
69
68
|
chooses the exit code. That is what makes the client callable from a workflow runner.
|
|
70
69
|
- **Fail on a re-run.** Transitioning to a status the issue already holds is a
|
|
71
70
|
successful no-op. `NoTransitionError` exits 0 — re-running a step must be safe.
|
|
72
71
|
- **Ask an agent to convert markup by hand.** `ai/JIRA_MARKUP.md` was a prose document
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
explaining markdown → Jira wiki conversion. It is `toMarkup()` now, under test,
|
|
73
|
+
reachable via `--markup`.
|
|
75
74
|
|
|
76
75
|
Credentials come from the repo's `.env` (`JIRA_BASE_URL`, `JIRA_USER`, `JIRA_PASSWORD`).
|
|
77
76
|
Jira Server 8.5.1 predates PAT support, so auth is Basic. Anything already in the
|
|
@@ -80,9 +79,9 @@ environment wins over the file.
|
|
|
80
79
|
### Legacy command names
|
|
81
80
|
|
|
82
81
|
`create-task`, `create-story`, `close-story` and friends are all still accepted, and
|
|
83
|
-
output formats are byte-for-byte what the old scripts printed.
|
|
84
|
-
references
|
|
85
|
-
|
|
82
|
+
output formats are byte-for-byte what the old scripts printed. Existing prose
|
|
83
|
+
references name these strings and the agents parse the output, so they are kept
|
|
84
|
+
until the v2 pass regenerates those documents.
|
|
86
85
|
|
|
87
86
|
## Doctor
|
|
88
87
|
|
|
@@ -93,13 +92,15 @@ cairn doctor --json
|
|
|
93
92
|
cairn doctor --strict # exit 1 on drift or a hand-edited generated file
|
|
94
93
|
```
|
|
95
94
|
|
|
95
|
+
Run it from the directory holding `repos.json`, or pass `--config <file>`.
|
|
96
|
+
|
|
96
97
|
It reports two independent axes, and keeping them apart is the point:
|
|
97
98
|
|
|
98
99
|
**Drift** — cross-repo. Do the copies still agree? Raw comparison is noise, so each
|
|
99
|
-
file is normalized first: BOM and CRLF stripped, repo paths and names folded,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
file is normalized first: BOM and CRLF stripped, repo paths and names folded, issue
|
|
101
|
+
keys folded to `{{ISSUE}}`, and declared vars folded to `{{placeholder}}`. What
|
|
102
|
+
survives is drift no template variable explains. Files are then clustered by
|
|
103
|
+
normalized content; the largest cluster becomes the reference.
|
|
103
104
|
|
|
104
105
|
| Status | Meaning |
|
|
105
106
|
|---|---|
|
|
@@ -116,8 +117,11 @@ match what is on disk?
|
|
|
116
117
|
|---|---|
|
|
117
118
|
| `MANAGED` | on-disk hash matches what cairn wrote |
|
|
118
119
|
| `MODIFIED` | someone hand-edited a generated file |
|
|
119
|
-
| `OUTDATED` | cairn has newer content for it |
|
|
120
|
-
| `DELETED` | it is gone; `sync` will restore it |
|
|
120
|
+
| `OUTDATED` | cairn has newer content for it — needs template hashes, wired in v2 |
|
|
121
|
+
| `DELETED` | it is gone; a future `cairn sync` will restore it |
|
|
122
|
+
|
|
123
|
+
v1 reports `MANAGED`, `MODIFIED` and `DELETED`. `OUTDATED` and the `sync` that acts
|
|
124
|
+
on these states arrive with the v2 renderer.
|
|
121
125
|
|
|
122
126
|
A file can be perfectly in sync across repos while being hand-edited away from its
|
|
123
127
|
template, and vice versa. `MODIFIED` outranks `OUTDATED` in the report because
|
|
@@ -128,17 +132,20 @@ overwriting a hand edit is the destructive outcome.
|
|
|
128
132
|
- `repos[]` — name, path, stack. Per-repo settings live in each repo's own
|
|
129
133
|
`cairn.config.json`; the inline `vars` blocks are a fallback used only until a repo
|
|
130
134
|
has been through `cairn init`, so migration can happen one repo at a time.
|
|
131
|
-
- `pathAliases` — local → canonical.
|
|
132
|
-
|
|
133
|
-
reporting one `MISSING` and one `STRANDED` for
|
|
135
|
+
- `pathAliases` — local → canonical. When one repo names a stub `execute-tests.md`
|
|
136
|
+
where the others use `execute-test-plan.md`, aliasing folds them onto the cohort's
|
|
137
|
+
names instead of reporting one `MISSING` and one `STRANDED` for the same file.
|
|
134
138
|
- `shared[]` — glob rules. `cohort: "all"` compares every repo; `cohort: "stack"`
|
|
135
139
|
compares backend-with-backend. `requires: { tracker: true }` skips repos with no
|
|
136
140
|
tracker. A repo with no config has an *unknown* tracker, not an absent one, and is
|
|
137
141
|
never skipped on that basis.
|
|
138
142
|
- Anything not matched by a rule — `ai/contexts/`, `ai/progress/`, `ai/tasks/`,
|
|
139
143
|
`DATABASE_SCHEMA.md` — is per-project by design and never inspected.
|
|
140
|
-
`ai/INITIAL_PROMPT.md` is explicitly excluded:
|
|
141
|
-
|
|
144
|
+
`ai/INITIAL_PROMPT.md` is explicitly excluded: variants at ~0% shared content make
|
|
145
|
+
it a per-project document, not a drifted template.
|
|
146
|
+
|
|
147
|
+
v2 splits this flat file into a per-project `workspace.json` plus an opt-in hub that
|
|
148
|
+
references the projects for cross-project comparison. See `DESIGN.md`.
|
|
142
149
|
|
|
143
150
|
## Layout
|
|
144
151
|
|
|
@@ -155,4 +162,4 @@ schema.json JSON Schema for cairn.config.json
|
|
|
155
162
|
test/run.js dependency-free test runner
|
|
156
163
|
```
|
|
157
164
|
|
|
158
|
-
No runtime dependencies. Node >= 18. `npm test` runs
|
|
165
|
+
No runtime dependencies. Node >= 18. `npm test` runs 35 tests.
|
package/package.json
CHANGED