@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/dist/cli/templates/agents/content/core/sfag-orchestrator.d.ts.map +1 -1
- package/dist/cli/templates/agents/content/core/sfag-orchestrator.js +17 -5
- package/dist/cli/templates/agents/content/core/sfag-orchestrator.js.map +1 -1
- package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.d.ts.map +1 -1
- package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.js +25 -3
- package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.js.map +1 -1
- package/dist/tools/core/git-injection.d.ts +17 -3
- package/dist/tools/core/git-injection.d.ts.map +1 -1
- package/dist/tools/core/git-injection.js +11 -2
- package/dist/tools/core/git-injection.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +13 -3
- package/dist/tools/index.js.map +1 -1
- package/package.json +5 -5
- package/src/cli/templates/agents/content/core/sfag-orchestrator.ts +17 -5
- package/src/cli/templates/agents/content/core/sfag-ticket-implementer.ts +25 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@specforge/canary-cli",
|
|
3
|
-
"version": "0.2.
|
|
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/
|
|
22
|
+
"@specforge/spec-types": "0.4.17",
|
|
23
23
|
"@specforge/session-types": "0.4.14",
|
|
24
|
-
"@specforge/
|
|
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.
|
|
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": "
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
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
|
|
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;
|
|
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
|