specflow-cc 1.19.0 → 1.20.0

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/bin/sf-tools.cjs CHANGED
@@ -14,8 +14,13 @@
14
14
  * todo next-id Next available TODO-XXX number
15
15
  * todo reindex Regenerate INDEX.md from TODO files
16
16
  * queue next First actionable spec from queue
17
- * state get Current active spec, status, next step
18
- * state set-active <id> <status> [next] Update active spec in STATE.md
17
+ * state get Current active spec, status, next step (legacy shim)
18
+ * state set-active <id> <status> [next] Update active spec in STATE.md (legacy shim)
19
+ * state list-active List all active specs from Active Specifications table
20
+ * state add-active <id> <status> <next> Append/update one row in Active Specifications table
21
+ * state remove-active <id> Remove one row from Active Specifications table
22
+ * state resolve [id] Resolve active spec; emit JSON contract
23
+ * state migrate One-shot idempotent migration to new schema
19
24
  * resolve-model <agent-type> Model for agent by current profile
20
25
  * verify-structure Check .specflow/ integrity
21
26
  * generate-slug <text> Text to URL-safe slug
@@ -24,7 +29,16 @@
24
29
  'use strict';
25
30
 
26
31
  const { output, error, generateSlug } = require('./lib/core.cjs');
27
- const { cmdStateGet, cmdStateSetActive, cmdQueueNext } = require('./lib/state.cjs');
32
+ const {
33
+ cmdStateGet,
34
+ cmdStateSetActive,
35
+ cmdStateListActive,
36
+ cmdStateAddActive,
37
+ cmdStateRemoveActive,
38
+ cmdStateResolve,
39
+ cmdStateMigrate,
40
+ cmdQueueNext,
41
+ } = require('./lib/state.cjs');
28
42
  const { cmdSpecLoad, cmdSpecList, cmdSpecNextId } = require('./lib/spec.cjs');
29
43
  const { cmdTodoLoad, cmdTodoList, cmdTodoNextId, cmdTodoReindex } = require('./lib/todo.cjs');
30
44
  const { cmdResolveModel } = require('./lib/config.cjs');
@@ -62,13 +76,42 @@ const COMMANDS = {
62
76
  'todo next-id': () => cmdTodoNextId(cwd, raw),
63
77
  'todo reindex': () => cmdTodoReindex(cwd, raw),
64
78
  'queue next': () => cmdQueueNext(cwd, raw),
79
+
80
+ // Legacy shims (backwards compatible)
65
81
  'state get': () => cmdStateGet(cwd, raw),
66
82
  'state set-active': () => {
67
83
  if (!filteredArgs[2] || !filteredArgs[3]) {
68
84
  error('Missing arguments. Usage: state set-active <id> <status> [next_step]');
69
85
  }
70
- cmdStateSetActive(cwd, filteredArgs[2], filteredArgs[3], filteredArgs[4], raw);
86
+ Promise.resolve(cmdStateSetActive(cwd, filteredArgs[2], filteredArgs[3], filteredArgs[4], raw))
87
+ .catch(e => error(e.message));
88
+ },
89
+
90
+ // New multi-spec state commands
91
+ 'state list-active': () => cmdStateListActive(cwd, raw),
92
+ 'state add-active': () => {
93
+ if (!filteredArgs[2] || !filteredArgs[3]) {
94
+ error('Missing arguments. Usage: state add-active <id> <status> <next_step>');
95
+ }
96
+ Promise.resolve(cmdStateAddActive(cwd, filteredArgs[2], filteredArgs[3], filteredArgs[4] || '', raw))
97
+ .catch(e => error(e.message));
71
98
  },
99
+ 'state remove-active': () => {
100
+ if (!filteredArgs[2]) {
101
+ error('Missing arguments. Usage: state remove-active <id>');
102
+ }
103
+ Promise.resolve(cmdStateRemoveActive(cwd, filteredArgs[2], raw))
104
+ .catch(e => error(e.message));
105
+ },
106
+ 'state resolve': () => {
107
+ // Optional specId argument (filteredArgs[2])
108
+ cmdStateResolve(cwd, filteredArgs[2] || undefined, raw);
109
+ },
110
+ 'state migrate': () => {
111
+ Promise.resolve(cmdStateMigrate(cwd, raw))
112
+ .catch(e => error(e.message));
113
+ },
114
+
72
115
  'resolve-model': () => {
73
116
  if (!filteredArgs[1]) error('Missing agent type. Usage: resolve-model <agent-type>');
74
117
  cmdResolveModel(cwd, filteredArgs[1], raw);
@@ -94,8 +137,13 @@ Commands:
94
137
  todo next-id Next available TODO-XXX number
95
138
  todo reindex Regenerate INDEX.md from TODO files
96
139
  queue next First actionable spec from queue table
97
- state get Current active spec, status, next step
98
- state set-active <id> <status> [next] Update active spec, status, next step
140
+ state get Current active spec, status, next step (legacy shim)
141
+ state set-active <id> <status> [next] Update active spec, status, next step (legacy shim)
142
+ state list-active List all rows in Active Specifications table
143
+ state add-active <id> <status> <next> Append/update one row (under advisory lock)
144
+ state remove-active <id> Remove one row (under advisory lock)
145
+ state resolve [SPEC-ID] Resolve active spec; emit JSON contract
146
+ state migrate One-shot idempotent migration to new schema
99
147
  resolve-model <agent-type> Resolve model for agent by current profile
100
148
  verify-structure Check .specflow/ directory integrity
101
149
  generate-slug <text> Convert text to URL-safe slug
@@ -2,6 +2,7 @@
2
2
  name: sf:audit
3
3
  description: Audit the active specification in a fresh context
4
4
  argument-hint: "[SPEC-XXX] [--import \"feedback\"]"
5
+ # SPEC-011: Accepts optional SPEC-XXX as first positional arg; resolves via state resolve
5
6
  allowed-tools:
6
7
  - Read
7
8
  - Write
@@ -40,17 +41,27 @@ Run `/sf:init` first.
40
41
  ```
41
42
  Exit.
42
43
 
43
- ## Step 2: Get Active Specification
44
+ ## Step 2: Resolve Active Specification
44
45
 
45
- Read `.specflow/STATE.md` and extract Active Specification.
46
+ Call `node bin/sf-tools.cjs state resolve $ARGUMENTS` (pass the optional SPEC-XXX arg if provided).
46
47
 
47
- **If no active specification:**
48
- ```
49
- No active specification to audit.
48
+ Parse the JSON response:
49
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
50
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display error and exit:
51
+ ```
52
+ No active specification to audit.
50
53
 
51
- Run `/sf:new "task description"` to create one.
52
- ```
53
- Exit.
54
+ Run `/sf:new "task description"` to create one.
55
+ ```
56
+ - `{"action":"error","code":"SPEC_NOT_ACTIVE","id":"SPEC-XXX"}` → display error and exit:
57
+ ```
58
+ SPEC-XXX is not in the Active Specifications table.
59
+ ```
60
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to show picker:
61
+ ```
62
+ Multiple active specifications. Which one to audit?
63
+ Options: {id — title (status)} for each entry
64
+ ```
54
65
 
55
66
  ## Step 3: Load Specification
56
67
 
@@ -143,10 +154,11 @@ In spec frontmatter, set: `status: revision_requested`
143
154
 
144
155
  ### 4.6 Update STATE.md
145
156
 
146
- Update STATE.md:
147
- - Status → "external_review"
148
- - Next Step "/sf:revise"
149
- - Add decision: "Imported external feedback for SPEC-XXX"
157
+ Update STATE.md via CLI:
158
+ ```bash
159
+ node bin/sf-tools.cjs state add-active SPEC-XXX external_review /sf:revise
160
+ ```
161
+ Add decision: "Imported external feedback for SPEC-XXX"
150
162
 
151
163
  ### 4.7 Display Import Result
152
164
 
@@ -2,6 +2,7 @@
2
2
  name: sf:autopilot
3
3
  description: Run full spec lifecycle autonomously (audit -> run -> review -> done)
4
4
  argument-hint: "[SPEC-XXX] [--all]"
5
+ # SPEC-011: Accepts optional SPEC-XXX; resolves via state resolve; FAILS when N>1 and no ID (no picker)
5
6
  allowed-tools:
6
7
  - Read
7
8
  - Write
@@ -43,25 +44,42 @@ Parse the command argument to determine execution mode:
43
44
 
44
45
  | Argument | Mode | Behavior |
45
46
  |----------|------|----------|
46
- | (none) | single | Process the active spec in STATE.md |
47
- | `SPEC-XXX` | single | Set SPEC-XXX as active, then process it |
48
- | `--all` | batch | Process all actionable specs in Queue order |
47
+ | (none) | single | Resolve active spec; fail fast if N>1 (no picker) |
48
+ | `SPEC-XXX` | single | Process this explicit spec ID |
49
+ | `--all` | batch | Process all actionable specs in Queue order; still requires explicit SPEC-ID if N>1 |
49
50
 
50
- **If single mode:**
51
- - If SPEC-XXX argument provided: update STATE.md to set it as active spec
52
- - If no argument and no active spec exists: display error and exit
51
+ **CRITICAL N>1 guard (autopilot must be unambiguous):**
53
52
 
54
- **If batch mode (--all):**
55
- - Identify all actionable specs from Queue (any spec with status: draft, auditing, revision_requested, audited, running, review)
53
+ Call `node bin/sf-tools.cjs state resolve $SPEC_ID_ARG` (pass SPEC-ID arg if provided; omit if not).
56
54
 
57
- **Error case (single mode, no active, no argument):**
58
- ```
59
- No active specification to process.
55
+ Parse the JSON response:
56
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
57
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display error and exit:
58
+ ```
59
+ No active specification to process.
60
60
 
61
- Provide a spec ID: `/sf:autopilot SPEC-XXX`
62
- Or run on all specs: `/sf:autopilot --all`
63
- ```
64
- Exit.
61
+ Provide a spec ID: `/sf:autopilot SPEC-XXX`
62
+ Or run on all specs: `/sf:autopilot --all`
63
+ ```
64
+ - `{"action":"error","code":"SPEC_NOT_ACTIVE","id":"SPEC-XXX"}` → display error and exit:
65
+ ```
66
+ SPEC-XXX is not in the Active Specifications table.
67
+ ```
68
+ - `{"action":"ask","options":[...]}` → **FAIL FAST** (do NOT show picker):
69
+ ```
70
+ Autopilot requires explicit SPEC-ID when >1 active specs.
71
+
72
+ Active specs: {list SPEC-IDs from options}
73
+
74
+ Provide a spec ID: `/sf:autopilot SPEC-XXX`
75
+ ```
76
+ Exit. (This applies to both plain `/sf:autopilot` AND `/sf:autopilot --all` without a SPEC-ID. `--all` controls within-spec behavior, not multi-spec iteration.)
77
+
78
+ **If single mode with explicit SPEC-ID:**
79
+ - SPEC-ID was resolved via state resolve above (action:use)
80
+
81
+ **If batch mode (--all):**
82
+ - Identify all actionable specs from Queue (any spec with status: draft, auditing, revision_requested, audited, running, review)
65
83
 
66
84
  ## Step 3: Set Configuration Constants
67
85
 
@@ -107,8 +125,7 @@ current_spec = null
107
125
 
108
126
  ### 5.1 Load Current Spec State
109
127
 
110
- Read `.specflow/STATE.md` to get active specification.
111
- Read `.specflow/specs/SPEC-XXX.md` to get frontmatter status.
128
+ Read `.specflow/specs/SPEC-XXX.md` to get frontmatter status (spec ID resolved in Step 2).
112
129
 
113
130
  ### 5.2 Determine Current Phase
114
131
 
@@ -255,10 +272,11 @@ mv .specflow/specs/SPEC-XXX.md .specflow/archive/
255
272
  ```
256
273
 
257
274
  5. **Update STATE.md:**
258
- - Active Specification → "none"
259
- - Status → "idle"
260
- - Next Step → "/sf:new or /sf:next"
261
- - Remove SPEC-XXX row from Queue table
275
+ Remove SPEC-XXX from Active Specifications table:
276
+ ```bash
277
+ node bin/sf-tools.cjs state remove-active SPEC-XXX
278
+ ```
279
+ Remove SPEC-XXX row from Queue table (using Read+Write).
262
280
 
263
281
  6. **Check STATE.md size and rotate** (same logic as 5.5 step 2)
264
282
 
@@ -62,9 +62,10 @@ Determine discussion mode from arguments:
62
62
  - Mode: `requirements-gathering`
63
63
 
64
64
  **Case E: No arguments**
65
- - Check STATE.md for active spec
66
- - If active spec exists: discuss that spec
67
- - If no active spec: ask what to discuss
65
+ - Call `node bin/sf-tools.cjs state resolve` to resolve active spec
66
+ - `{"action":"use","id":"SPEC-XXX"}` discuss that spec
67
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` ask what to discuss
68
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to pick which spec to discuss
68
69
 
69
70
  ## 3. Load Context
70
71
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: sf:done
3
3
  description: Finalize specification, archive, and update state
4
+ # SPEC-011: Accepts optional SPEC-XXX as first positional arg; resolves via state resolve
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Write
@@ -36,17 +37,27 @@ Run `/sf:init` first.
36
37
  ```
37
38
  Exit.
38
39
 
39
- ## Step 2: Get Active Specification
40
+ ## Step 2: Resolve Active Specification
40
41
 
41
- Read `.specflow/STATE.md` and extract Active Specification.
42
+ Call `node bin/sf-tools.cjs state resolve $ARGUMENTS` (pass the optional SPEC-XXX arg if provided).
42
43
 
43
- **If no active specification:**
44
- ```
45
- No active specification to finalize.
44
+ Parse the JSON response:
45
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
46
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display error and exit:
47
+ ```
48
+ No active specification to finalize.
46
49
 
47
- Run `/sf:new "task description"` to create one.
48
- ```
49
- Exit.
50
+ Run `/sf:new "task description"` to create one.
51
+ ```
52
+ - `{"action":"error","code":"SPEC_NOT_ACTIVE","id":"SPEC-XXX"}` → display error and exit:
53
+ ```
54
+ SPEC-XXX is not in the Active Specifications table.
55
+ ```
56
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to show picker:
57
+ ```
58
+ Multiple active specifications. Which one to finalize?
59
+ Options: {id — title (status)} for each entry
60
+ ```
50
61
 
51
62
  ## Step 3: Load Specification
52
63
 
@@ -309,11 +320,11 @@ mv .specflow/specs/SPEC-XXX.md .specflow/archive/
309
320
 
310
321
  ## Step 9: Update STATE.md
311
322
 
312
- ### Clear Active Specification
323
+ ### Remove from Active Specifications Table
313
324
 
314
- - Active Specification → "none"
315
- - Status "idle"
316
- - Next Step → "/sf:new or /sf:next"
325
+ ```bash
326
+ node bin/sf-tools.cjs state remove-active SPEC-XXX
327
+ ```
317
328
 
318
329
  ### Remove from Queue
319
330
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: sf:fix
3
3
  description: Fix implementation based on review feedback
4
+ # SPEC-011: Accepts optional SPEC-XXX as first positional arg; resolves via state resolve
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Write
@@ -38,17 +39,27 @@ Run `/sf:init` first.
38
39
  ```
39
40
  Exit.
40
41
 
41
- ## Step 2: Get Active Specification
42
+ ## Step 2: Resolve Active Specification
42
43
 
43
- Read `.specflow/STATE.md` and extract Active Specification.
44
+ Call `node bin/sf-tools.cjs state resolve $ARGUMENTS` (pass the optional SPEC-XXX arg if provided).
44
45
 
45
- **If no active specification:**
46
- ```
47
- No active specification to fix.
46
+ Parse the JSON response:
47
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
48
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display error and exit:
49
+ ```
50
+ No active specification to fix.
48
51
 
49
- Run `/sf:new "task description"` to create one.
50
- ```
51
- Exit.
52
+ Run `/sf:new "task description"` to create one.
53
+ ```
54
+ - `{"action":"error","code":"SPEC_NOT_ACTIVE","id":"SPEC-XXX"}` → display error and exit:
55
+ ```
56
+ SPEC-XXX is not in the Active Specifications table.
57
+ ```
58
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to show picker:
59
+ ```
60
+ Multiple active specifications. Which one to fix?
61
+ Options: {id — title (status)} for each entry
62
+ ```
52
63
 
53
64
  ## Step 3: Load Specification
54
65
 
@@ -164,8 +175,9 @@ Append to Review History:
164
175
 
165
176
  ## Step 8: Update STATE.md
166
177
 
167
- - Status → "review" (ready for re-review)
168
- - Next Step "/sf:review"
178
+ ```bash
179
+ node bin/sf-tools.cjs state add-active SPEC-XXX review /sf:review
180
+ ```
169
181
 
170
182
  ## Step 9: Display Result
171
183
 
@@ -2,6 +2,7 @@
2
2
  name: sf:health
3
3
  description: Diagnose .specflow/ directory health and optionally repair issues
4
4
  argument-hint: [--repair]
5
+ # SPEC-011: Invokes migrate-state on entry; re-stamps STATE.md header from template after migration (--repair path)
5
6
  allowed-tools:
6
7
  - Read
7
8
  - Bash
@@ -32,7 +33,19 @@ SpecFlow not initialized. Run `/sf:init` first.
32
33
  ```
33
34
  Exit.
34
35
 
35
- ## Step 2: Parse Arguments
36
+ ## Step 2: Invoke STATE.md Migration (entry point)
37
+
38
+ Run migration on entry — idempotent, no-op when already migrated:
39
+
40
+ ```bash
41
+ node bin/sf-tools.cjs state migrate
42
+ ```
43
+
44
+ Parse the response:
45
+ - `{"migrated":true,...}` → Migration completed. After migration, re-stamp the `## Active Specifications` header block in STATE.md from `templates/state.md` to reconcile any format drift (non-destructive: Queue, Decisions, Notes sections are preserved; only the Active Specifications block is normalized). This is the `--repair` path.
46
+ - `{"migrated":false,...}` → Already migrated, no action needed.
47
+
48
+ ## Step 2.5: Parse Arguments
36
49
 
37
50
  Check if `--repair` flag is present.
38
51
 
@@ -71,9 +84,9 @@ For each check:
71
84
  Read STATE.md and validate:
72
85
 
73
86
  **E003: Active spec references non-existent file**
74
- - Extract active spec ID from `## Active Specification`
75
- - If not "—" or empty, check `.specflow/specs/{ID}.md` exists
76
- - If missing: error (repairable — clear active spec to "—")
87
+ - List all active specs via `node bin/sf-tools.cjs state list-active`
88
+ - For each SPEC-ID, check `.specflow/specs/{ID}.md` exists
89
+ - If missing: error (repairable — remove that row via `state remove-active`)
77
90
 
78
91
  **W005: Queue references non-existent spec file**
79
92
  - Parse queue table rows
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: sf:help
3
3
  description: Show SpecFlow help and command reference
4
+ # SPEC-011: Uses state list-active to show active specs in overview; no state resolve needed (no single-spec operations)
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Glob
@@ -203,6 +204,11 @@ Exit.
203
204
 
204
205
  ## Step 2b: Overview Help
205
206
 
207
+ Show active specs count (uses list-active for multi-spec awareness):
208
+ ```bash
209
+ node bin/sf-tools.cjs state list-active --raw
210
+ ```
211
+
206
212
  Display full command reference:
207
213
 
208
214
  ```
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: sf:pause
3
3
  description: Save current work context for later resumption
4
+ # SPEC-011: Accepts optional SPEC-XXX as first positional arg; resolves via state resolve
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Write
@@ -33,20 +34,26 @@ Run `/sf:init` to start.
33
34
  ```
34
35
  Exit.
35
36
 
36
- ## Step 2: Get Current State
37
+ ## Step 2: Resolve Active Specification
37
38
 
38
- Read `.specflow/STATE.md` and extract:
39
- - Active Specification
40
- - Status
41
- - Next Step
39
+ Call `node bin/sf-tools.cjs state resolve $ARGUMENTS` (pass the optional SPEC-XXX arg if provided).
42
40
 
43
- **If no active specification:**
44
- ```
45
- No active work to pause.
41
+ Parse the JSON response:
42
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
43
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display info and allow general notes:
44
+ ```
45
+ No active work to pause.
46
46
 
47
- Current state: idle
48
- ```
49
- But still allow pausing to capture general notes.
47
+ Current state: idle
48
+ ```
49
+ Still allow pausing to capture general notes.
50
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to show picker:
51
+ ```
52
+ Multiple active specifications. Which session to pause?
53
+ Options: {id — title (status)} for each entry
54
+ ```
55
+
56
+ Also call `node bin/sf-tools.cjs state list-active` to capture all active specs in the pause file.
50
57
 
51
58
  ## Step 3: Load Active Specification Details
52
59
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: sf:review
3
3
  description: Review the implementation against specification
4
+ # SPEC-011: Accepts optional SPEC-XXX as first positional arg; resolves via state resolve
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Write
@@ -36,17 +37,27 @@ Run `/sf:init` first.
36
37
  ```
37
38
  Exit.
38
39
 
39
- ## Step 2: Get Active Specification
40
+ ## Step 2: Resolve Active Specification
40
41
 
41
- Read `.specflow/STATE.md` and extract Active Specification.
42
+ Call `node bin/sf-tools.cjs state resolve $ARGUMENTS` (pass the optional SPEC-XXX arg if provided).
42
43
 
43
- **If no active specification:**
44
- ```
45
- No active specification to review.
44
+ Parse the JSON response:
45
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
46
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display error and exit:
47
+ ```
48
+ No active specification to review.
46
49
 
47
- Run `/sf:new "task description"` to create one.
48
- ```
49
- Exit.
50
+ Run `/sf:new "task description"` to create one.
51
+ ```
52
+ - `{"action":"error","code":"SPEC_NOT_ACTIVE","id":"SPEC-XXX"}` → display error and exit:
53
+ ```
54
+ SPEC-XXX is not in the Active Specifications table.
55
+ ```
56
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to show picker:
57
+ ```
58
+ Multiple active specifications. Which one to review?
59
+ Options: {id — title (status)} for each entry
60
+ ```
50
61
 
51
62
  ## Step 3: Load Specification
52
63
 
@@ -319,8 +330,12 @@ Append Review History to spec.
319
330
 
320
331
  ### Update STATE.md
321
332
 
322
- - If APPROVED: Status → "done", Next Step → "/sf:done"
323
- - If CHANGES_REQUESTED: Status → "review", Next Step → "/sf:fix"
333
+ ```bash
334
+ # If APPROVED:
335
+ node bin/sf-tools.cjs state add-active SPEC-XXX done /sf:done
336
+ # If CHANGES_REQUESTED:
337
+ node bin/sf-tools.cjs state add-active SPEC-XXX review /sf:fix
338
+ ```
324
339
 
325
340
  </fallback>
326
341
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: sf:revise
3
3
  description: Revise specification based on audit feedback
4
+ # SPEC-011: Accepts optional SPEC-XXX as first positional arg; resolves via state resolve
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Write
@@ -37,17 +38,27 @@ Run `/sf:init` first.
37
38
  ```
38
39
  Exit.
39
40
 
40
- ## Step 2: Get Active Specification
41
+ ## Step 2: Resolve Active Specification
41
42
 
42
- Read `.specflow/STATE.md` and extract Active Specification.
43
+ Call `node bin/sf-tools.cjs state resolve $ARGUMENTS` (pass the optional SPEC-XXX arg if provided; strip non-SPEC-ID args first).
43
44
 
44
- **If no active specification:**
45
- ```
46
- No active specification to revise.
45
+ Parse the JSON response:
46
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
47
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display error and exit:
48
+ ```
49
+ No active specification to revise.
47
50
 
48
- Run `/sf:new "task description"` to create one.
49
- ```
50
- Exit.
51
+ Run `/sf:new "task description"` to create one.
52
+ ```
53
+ - `{"action":"error","code":"SPEC_NOT_ACTIVE","id":"SPEC-XXX"}` → display error and exit:
54
+ ```
55
+ SPEC-XXX is not in the Active Specifications table.
56
+ ```
57
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to show picker:
58
+ ```
59
+ Multiple active specifications. Which one to revise?
60
+ Options: {id — title (status)} for each entry
61
+ ```
51
62
 
52
63
  ## Step 3: Load Specification
53
64
 
@@ -508,8 +519,9 @@ After recording the Response, if any items were marked "Deferred":
508
519
  In spec frontmatter: `status: auditing`
509
520
 
510
521
  In STATE.md:
511
- - Status → "auditing"
512
- - Next Step "/sf:audit"
522
+ ```bash
523
+ node bin/sf-tools.cjs state add-active SPEC-XXX auditing /sf:audit
524
+ ```
513
525
 
514
526
  </fallback>
515
527
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: sf:run
3
3
  description: Execute the specification (implement the code)
4
+ # SPEC-011: Accepts optional SPEC-XXX as first positional arg; resolves via state resolve
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Write
@@ -39,17 +40,27 @@ Run `/sf:init` first.
39
40
  ```
40
41
  Exit.
41
42
 
42
- ## Step 2: Get Active Specification
43
+ ## Step 2: Resolve Active Specification
43
44
 
44
- Read `.specflow/STATE.md` and extract Active Specification.
45
+ Call `node bin/sf-tools.cjs state resolve $ARGUMENTS` (pass the optional SPEC-XXX arg if provided).
45
46
 
46
- **If no active specification:**
47
- ```
48
- No active specification to execute.
47
+ Parse the JSON response:
48
+ - `{"action":"use","id":"SPEC-XXX"}` → proceed with SPEC-XXX
49
+ - `{"action":"error","code":"NO_ACTIVE_SPEC"}` display error and exit:
50
+ ```
51
+ No active specification to execute.
49
52
 
50
- Run `/sf:new "task description"` to create one.
51
- ```
52
- Exit.
53
+ Run `/sf:new "task description"` to create one.
54
+ ```
55
+ - `{"action":"error","code":"SPEC_NOT_ACTIVE","id":"SPEC-XXX"}` → display error and exit:
56
+ ```
57
+ SPEC-XXX is not in the Active Specifications table.
58
+ ```
59
+ - `{"action":"ask","options":[...]}` → use AskUserQuestion to show picker:
60
+ ```
61
+ Multiple active specifications. Which one to run?
62
+ Options: {id — title (status)} for each entry
63
+ ```
53
64
 
54
65
  ## Step 3: Load Specification
55
66
 
@@ -182,9 +193,9 @@ Use model for `spec-executor` or `spec-executor-orchestrator` from selected prof
182
193
 
183
194
  ## Step 7: Update Status
184
195
 
185
- Update STATE.md:
186
- - Status "running"
187
- - Next Step → "(in progress)"
196
+ ```bash
197
+ node bin/sf-tools.cjs state add-active SPEC-XXX running "(in progress)"
198
+ ```
188
199
 
189
200
  Update spec frontmatter:
190
201
  - status → "running"