@specforge/canary-cli 0.2.16 → 0.2.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specforge/canary-cli",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "MCP server for SpecForge - AI agent integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,9 +19,9 @@
19
19
  "ora": "^8.2.0",
20
20
  "zod": "^3.25.0",
21
21
  "@specforge/api-types": "0.4.17",
22
- "@specforge/report-types": "0.4.9",
22
+ "@specforge/spec-types": "0.4.17",
23
23
  "@specforge/session-types": "0.4.14",
24
- "@specforge/spec-types": "0.4.17"
24
+ "@specforge/report-types": "0.4.9"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/inquirer": "^9.0.9",
@@ -33,7 +33,7 @@
33
33
  "tsx": "^4.7.0",
34
34
  "typescript": "^5.0.0",
35
35
  "vitest": "4.0.18",
36
- "@specforge/lifecycle": "0.3.22"
36
+ "@specforge/lifecycle": "0.3.23"
37
37
  },
38
38
  "engines": {
39
39
  "node": ">=18.0.0"
@@ -61,7 +61,7 @@
61
61
  "@specforge/session-types",
62
62
  "@specforge/report-types"
63
63
  ],
64
- "gitHead": "5f09988626cf09d1d0f400bef277fac50c962344",
64
+ "gitHead": "64fe3cf4657914ccecc2c26c67c09d6890597a0a",
65
65
  "scripts": {
66
66
  "build": "tsup && tsc --emitDeclarationOnly --outDir dist",
67
67
  "typecheck": "tsc --noEmit",
@@ -103,9 +103,17 @@ This is how implementation runs. Internalize it before dispatching anything.
103
103
  - **Each worker is fully autonomous.** It picks up its ticket, runs the whole SWS → action_work_session
104
104
  → complete_work_session loop, records every dimension through the assay, commits, and finalizes
105
105
  \`active → done\` with no human touch. You do not step inside a worker's loop.
106
- - **Isolate the workers.** Give each worker its own git worktree/branch (use the \`branchPrefix\` from
107
- config, e.g. \`ticket/<ref>\`) so concurrent sessions don't collide on the worktree. SWS enforces a
108
- clean worktree per session.
106
+ - **Isolate the workers one worktree each, and hand each worker its path.** Before dispatching a
107
+ worker, create a fresh git worktree/branch for its ticket (\`git worktree add\`, using the
108
+ \`branchPrefix\` from config, e.g. \`ticket/<ref>\`). Then **tell the worker its worktree path** and
109
+ instruct it to pass that path as \`worktree\` on \`start_work_session\` and \`complete_work_session\`.
110
+ This is not optional for a parallel fleet: your workers all run under **one shared MCP server**
111
+ (one process, one working directory), so the MCP-local git evidence — clean status (at
112
+ start_work_session) and commit hash (at complete_work_session) — is read from THAT one directory
113
+ unless each worker names its own worktree. Two
114
+ concurrent sessions that end up in the same worktree are **denied** (\`concurrent_worktree\`); that
115
+ denial is the signal a worker was launched without its own worktree/path. SWS also enforces a clean
116
+ worktree per session.
109
117
  - **Respect the DAG.** Only \`ready\` (dependency-free) tickets are dispatchable. When a worker completes
110
118
  a ticket, the readiness cascade unblocks its dependents (\`pending → ready\`); you then dispatch the
111
119
  newly-ready ones. Never dispatch a ticket whose dependencies aren't \`done\`.
@@ -152,7 +160,9 @@ get_next_actionable_tickets({ specificationId, limit }) // the ready tickets to
152
160
  get_implementation_status({ projectId, specificationId, status: "active" }) // who is already running
153
161
  \`\`\`
154
162
  Then dispatch:
155
- - Launch one \`sfag-ticket-implementer\` per \`ready\` ticket, each in its own worktree/branch.
163
+ - Launch one \`sfag-ticket-implementer\` per \`ready\` ticket. For each, first \`git worktree add\` a
164
+ fresh worktree/branch, then hand the worker its worktree path (it passes it to SWS/CWS as
165
+ \`worktree\`). A single non-parallel worker can run in the current directory with no worktree arg.
156
166
  - Bound concurrency by the config: at most \`maxParallelEpics\` epics in flight and \`maxTicketsPerTeam\`
157
167
  tickets per epic team. If the strategy is \`single\`, run one worker at a time; \`parallel\` runs
158
168
  independent epics concurrently; \`phased\` runs the DAG in dependency-ordered phases; \`auto\` picks
@@ -258,7 +268,9 @@ sfag-ticket-implementer (ticket C, worktree C) ─┘ poll get_implementation_
258
268
  - ❌ Don't launch a worker without a spec. If no spec, HALT and hand planning to the main agent.
259
269
  - ❌ Don't try to create a spec, and don't delegate spec creation to any subagent. Planning is main-conversation-only.
260
270
  - ❌ Don't dispatch a ticket out of dependency order. Only \`ready\` (dependency-free) tickets are dispatchable.
261
- - ❌ Don't run workers in the same worktree. Give each its own worktree/branch or SWS collides on git-clean.
271
+ - ❌ Don't run workers in the same worktree, and don't dispatch a worker without giving it its own
272
+ worktree path to pass to SWS/CWS. Concurrent sessions sharing a worktree are DENIED
273
+ (\`concurrent_worktree\`) and their git evidence would otherwise be the launcher's, not the worker's.
262
274
  - ❌ Don't create the ImplementationSession yourself. The first worker's SWS creates it (first-write-wins).
263
275
  - ❌ Don't wait for a review/approval step — there isn't one. Workers self-complete through the CWS gates.
264
276
  - ❌ Don't resolve or unblock a discovery yourself. Hand it to \`sfag-work-resolver\`; the human unblocks in the web app.
@@ -98,6 +98,21 @@ So, before every \`start_work_session\`:
98
98
  (If you are not inside a git worktree, SWS still runs — the precondition treats a
99
99
  non-git caller as clean.)
100
100
 
101
+ ### Pass your \`worktree\` when you run in parallel
102
+
103
+ The MCP-local git reads (clean status, commit hash) resolve in the MCP server's current
104
+ directory. When several workers run **concurrently under one orchestrator, they share one
105
+ MCP server** — so each worker MUST tell SWS/CWS which worktree it lives in, or every
106
+ worker's git evidence would come from the launcher's directory instead of its own.
107
+
108
+ - If the orchestrator gave you a worktree path, pass it as \`worktree\` on **every**
109
+ \`start_work_session\` and \`complete_work_session\` call (use the same value for both).
110
+ - Two active sessions in the **same** worktree are denied (\`concurrent_worktree\`) — that
111
+ denial means you are missing (or sharing) a worktree; create your own (\`git worktree
112
+ add\`) and retry with its path.
113
+ - Running a **single** session in the current directory? Omit \`worktree\` — the current
114
+ directory is used, exactly as before.
115
+
101
116
  ## Step 1: Pick a ticket (autonomous)
102
117
 
103
118
  Pick the next actionable ticket yourself — no need to ask anyone:
@@ -111,7 +126,8 @@ Keep going through ready tickets until none remain.
111
126
 
112
127
  Ensure the worktree is clean (see the git-clean precondition), then:
113
128
  \`\`\`
114
- start_work_session({ ticketId })
129
+ start_work_session({ ticketId }) // single session, current directory
130
+ start_work_session({ ticketId, worktree: "/abs/path/to/your/worktree" }) // parallel worker
115
131
  // ready → active; returns the full orientation + workSessionId (the sessionId).
116
132
  \`\`\`
117
133
  Read the orientation in full. It IS your brief:
@@ -124,7 +140,9 @@ Read the orientation in full. It IS your brief:
124
140
 
125
141
  If SWS comes back \`outcome: "denied"\`, read the guidance and act on it: \`git_dirty\` →
126
142
  commit and retry; \`unfinished_dependencies\` → a dependency is not \`done\`, pick a
127
- different ready ticket; an aborted implementation stop, this spec is off-limits.
143
+ different ready ticket; \`concurrent_worktree\`another active session is in your
144
+ worktree, create your own (\`git worktree add\`) and retry with its \`worktree\` path; an
145
+ aborted implementation → stop, this spec is off-limits.
128
146
 
129
147
  ## Step 3: Implement + record — the assay-driven order
130
148
 
@@ -241,7 +259,10 @@ complete_work_session({
241
259
  ticketId,
242
260
  summary: "Implemented user registration: service, endpoint, validation, tests",
243
261
  filesCreated: [...], filesModified: [...],
244
- validation: { tests: { passed: 8, failed: 0 } }
262
+ validation: { tests: { passed: 8, failed: 0 } },
263
+ // If you passed a worktree to start_work_session, pass the SAME one here so the
264
+ // commit hash is read from YOUR worktree (omit it for a single session).
265
+ // worktree: "/abs/path/to/your/worktree"
245
266
  })
246
267
  // active → done; finalizes the WorkSession; the cascade unblocks dependents.
247
268
  // When every spec ticket is done, the spec → done and the ImplementationSession finalizes.
@@ -330,6 +351,7 @@ ticket — never a reset.
330
351
  ## Quality Gate (self-check before complete_work_session)
331
352
 
332
353
  - [ ] Worktree was clean before start_work_session (no \`git_dirty\` denial)
354
+ - [ ] If running in parallel: passed your \`worktree\` path to start_work_session AND complete_work_session
333
355
  - [ ] All implementation steps marked done via mark_implementation_step_completion
334
356
  - [ ] Tests run and recorded via record_test_result; every skip/failure justified
335
357
  - [ ] Every touched/divergent file recorded via record_file_change; divergences justified