@gobing-ai/spur 0.3.43 → 0.3.45

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.
Files changed (76) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/rules/README.md +12 -4
  3. package/config/rules/recommended-pre-check.yaml +4 -4
  4. package/config/rules/strict-check.yaml +7 -4
  5. package/config/templates/AGENTS.md +5 -0
  6. package/config/workflows/idea-pipeline.yaml +205 -33
  7. package/config/workflows/task-pipeline.yaml +1 -1
  8. package/package.json +9 -9
  9. package/plugins/sp/commands/dev-find-next.md +20 -12
  10. package/plugins/sp/commands/dev-runall.md +3 -1
  11. package/plugins/sp/plugin.json +1 -1
  12. package/plugins/sp/skills/next-feature/SKILL.md +17 -13
  13. package/plugins/sp/skills/next-feature/references/handoff-routing.md +12 -7
  14. package/plugins/sp/skills/next-feature/references/signal-derivation.md +39 -2
  15. package/plugins/sp/skills/spur-cli/SKILL.md +3 -0
  16. package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +8 -3
  17. package/plugins/sp/skills/spur-cli/references/tasks.md +22 -0
  18. package/plugins/sp/skills/spur-dev/SKILL.md +12 -4
  19. package/plugins/sp/skills/spur-dev/references/dev-operations.md +1 -1
  20. package/plugins/sp/skills/spur-dev/references/execution-batch.md +12 -3
  21. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +6 -5
  22. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +53 -0
  23. package/spur.js +1866 -544
  24. package/web/_astro/BoardApp.Ce6zJYAH.js +1 -0
  25. package/web/_astro/BoardApp.DKyrGxdo.js +179 -0
  26. package/web/_astro/{TaskDetail.DOKJP-Kp.js → TaskDetail.6-27_LMa.js} +1 -1
  27. package/web/_astro/{arc.CTqmqspU.js → arc.Df-9AQvS.js} +1 -1
  28. package/web/_astro/{architectureDiagram-3BPJPVTR.B0iBdehs.js → architectureDiagram-3BPJPVTR.VAI_-paS.js} +1 -1
  29. package/web/_astro/{blockDiagram-GPEHLZMM.BHE5UFj5.js → blockDiagram-GPEHLZMM.DFpUY1ue.js} +1 -1
  30. package/web/_astro/{c4Diagram-AAUBKEIU.DQApkgGM.js → c4Diagram-AAUBKEIU.CF8doOpg.js} +1 -1
  31. package/web/_astro/channel.Uhm9O3UV.js +1 -0
  32. package/web/_astro/{chunk-2J33WTMH.fPrKLM8v.js → chunk-2J33WTMH.BnjK3fjt.js} +1 -1
  33. package/web/_astro/{chunk-4BX2VUAB.DExvwBhn.js → chunk-4BX2VUAB.x6ZDnJKq.js} +1 -1
  34. package/web/_astro/{chunk-55IACEB6.EjNkjuD6.js → chunk-55IACEB6.zY-0uu7w.js} +1 -1
  35. package/web/_astro/{chunk-727SXJPM.Dl8xy5rT.js → chunk-727SXJPM.BZxKg_Vi.js} +1 -1
  36. package/web/_astro/{chunk-AQP2D5EJ.BSzMBgBs.js → chunk-AQP2D5EJ.Cpi9G9Td.js} +1 -1
  37. package/web/_astro/{chunk-FMBD7UC4.CAeOHpbb.js → chunk-FMBD7UC4.DWTB-Pif.js} +1 -1
  38. package/web/_astro/{chunk-ND2GUHAM.Bbeu_ZOH.js → chunk-ND2GUHAM.BPDQbiOG.js} +1 -1
  39. package/web/_astro/{chunk-QZHKN3VN.Da_GaIAZ.js → chunk-QZHKN3VN.BRWIcuoM.js} +1 -1
  40. package/web/_astro/{classDiagram-4FO5ZUOK.sMfFYSQp.js → classDiagram-4FO5ZUOK.mGTCZsDO.js} +1 -1
  41. package/web/_astro/{classDiagram-v2-Q7XG4LA2.sMfFYSQp.js → classDiagram-v2-Q7XG4LA2.mGTCZsDO.js} +1 -1
  42. package/web/_astro/{cose-bilkent-S5V4N54A.PS3IwOH4.js → cose-bilkent-S5V4N54A.D1GEut-z.js} +1 -1
  43. package/web/_astro/{dagre-BM42HDAG.EQCx8a6D.js → dagre-BM42HDAG.BV0XG9Do.js} +1 -1
  44. package/web/_astro/{diagram-2AECGRRQ.aEFQl8v8.js → diagram-2AECGRRQ.DzpYxsjo.js} +1 -1
  45. package/web/_astro/{diagram-5GNKFQAL.jyN4tqFX.js → diagram-5GNKFQAL.Cm9YzJh4.js} +1 -1
  46. package/web/_astro/{diagram-KO2AKTUF.DaTVHnme.js → diagram-KO2AKTUF.BjhottUj.js} +1 -1
  47. package/web/_astro/{diagram-LMA3HP47.DWsGRLAN.js → diagram-LMA3HP47.BFsQW5kb.js} +1 -1
  48. package/web/_astro/{diagram-OG6HWLK6.DYxmOViu.js → diagram-OG6HWLK6.8pdpzSWO.js} +1 -1
  49. package/web/_astro/{erDiagram-TEJ5UH35.BKM75coa.js → erDiagram-TEJ5UH35.Bd7KUJmJ.js} +1 -1
  50. package/web/_astro/{flowDiagram-I6XJVG4X.B7qpqDW5.js → flowDiagram-I6XJVG4X.7LWffkaE.js} +1 -1
  51. package/web/_astro/{ganttDiagram-6RSMTGT7.CYBL-hwy.js → ganttDiagram-6RSMTGT7.BeDcO5tI.js} +1 -1
  52. package/web/_astro/{gitGraphDiagram-PVQCEYII.Cz4ly3Kq.js → gitGraphDiagram-PVQCEYII.Ca4n730A.js} +1 -1
  53. package/web/_astro/{index.yAse9IaO.css → index.Dbvuw6d4.css} +1 -1
  54. package/web/_astro/{infoDiagram-5YYISTIA.CIS7cXrJ.js → infoDiagram-5YYISTIA.B0OakQYb.js} +1 -1
  55. package/web/_astro/{ishikawaDiagram-YF4QCWOH.DQ-pmaOG.js → ishikawaDiagram-YF4QCWOH.DSmNQe-1.js} +1 -1
  56. package/web/_astro/{journeyDiagram-JHISSGLW.DVS6F7UM.js → journeyDiagram-JHISSGLW.Cy5ruEUu.js} +1 -1
  57. package/web/_astro/{kanban-definition-UN3LZRKU.D8t-G-U6.js → kanban-definition-UN3LZRKU.CUJXub0p.js} +1 -1
  58. package/web/_astro/{linear.IO8rTd_n.js → linear.DC1jCCXn.js} +1 -1
  59. package/web/_astro/{mermaid.core.CjVnvFNf.js → mermaid.core.DxVP99Ab.js} +4 -4
  60. package/web/_astro/{mindmap-definition-RKZ34NQL.DZoEMTnU.js → mindmap-definition-RKZ34NQL.D0MaV6sJ.js} +1 -1
  61. package/web/_astro/{pieDiagram-4H26LBE5.86r1QWnX.js → pieDiagram-4H26LBE5.DCC6_q32.js} +1 -1
  62. package/web/_astro/{quadrantDiagram-W4KKPZXB.DzFA9uPk.js → quadrantDiagram-W4KKPZXB.BeUOAM7C.js} +1 -1
  63. package/web/_astro/{requirementDiagram-4Y6WPE33.dQvdvfMr.js → requirementDiagram-4Y6WPE33.Dbl4MASO.js} +1 -1
  64. package/web/_astro/{sankeyDiagram-5OEKKPKP.BvC-VNI8.js → sankeyDiagram-5OEKKPKP.HsLg0VS4.js} +1 -1
  65. package/web/_astro/{sequenceDiagram-3UESZ5HK.DDQNwHs8.js → sequenceDiagram-3UESZ5HK.DT7DJTnZ.js} +1 -1
  66. package/web/_astro/{stateDiagram-AJRCARHV.BKwYy-tQ.js → stateDiagram-AJRCARHV.d_ju1Vr1.js} +1 -1
  67. package/web/_astro/{stateDiagram-v2-BHNVJYJU.KxCiRYYf.js → stateDiagram-v2-BHNVJYJU.DMCAjMJ4.js} +1 -1
  68. package/web/_astro/{timeline-definition-PNZ67QCA.Bh9NDjOx.js → timeline-definition-PNZ67QCA.DNOHr62_.js} +1 -1
  69. package/web/_astro/{vennDiagram-CIIHVFJN.DIM-n6us.js → vennDiagram-CIIHVFJN.B7dUy-1W.js} +1 -1
  70. package/web/_astro/{wardley-L42UT6IY.DW15qOFQ.js → wardley-L42UT6IY.DEqOXvBh.js} +1 -1
  71. package/web/_astro/{wardleyDiagram-YWT4CUSO.UTIvjsG9.js → wardleyDiagram-YWT4CUSO.BCRb2p6x.js} +1 -1
  72. package/web/_astro/{xychartDiagram-2RQKCTM6.CQYhkVDS.js → xychartDiagram-2RQKCTM6.NxVQLdBh.js} +1 -1
  73. package/web/index.html +2 -2
  74. package/web/_astro/BoardApp.8sc6Rb1t.js +0 -179
  75. package/web/_astro/BoardApp.ChKnY1JD.js +0 -1
  76. package/web/_astro/channel.B0q9WGrH.js +0 -1
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "plugins": [
8
8
  {
9
- "version": "0.3.43",
9
+ "version": "0.3.45",
10
10
  "name": "sp",
11
11
  "source": "./plugins/sp",
12
12
  "description": "Spur - my harness toolkits"
@@ -15,14 +15,17 @@ install or to ts-libs.
15
15
  | `structure` | `structure/` | File layout, protected files, no focused/skipped tests |
16
16
  | `quality` | `quality/` | Post-test gates (coverage) |
17
17
  | `surface` | `surface/` | CLI surface consistency (registerXxxCommand wiring, --json serialization) |
18
+ | `migration` | `migration/` | Transitional helpers for the regex → `rg` evaluator move (`rg-dialect`) |
19
+ | `ui` | `ui/` | Web UI seam boundaries (import seam, daisyUI class leak) |
18
20
 
19
21
  ## Presets
20
22
 
21
23
  | Preset | When | Extends |
22
24
  |---|---|---|
23
- | `recommended-pre-check` | Before tests | `typescript`, `structure`, `boundary`, `surface` |
25
+ | `recommended-pre-check` | Before tests | `typescript`, `structure`, `boundary`, `surface`, `ui`, `strict` |
24
26
  | `recommended-post-check` | After tests | `quality` |
25
- | `strict-check` | Opt-in | `strict` |
27
+ | `strict-check` | Opt-in single-category cherry-pick (strict only) | `strict` |
28
+ | `rg-migration` | On-demand during the regex → `rg` evaluator migration | `migration` |
26
29
 
27
30
  ## Relationship to ts-libs
28
31
 
@@ -32,9 +35,14 @@ ts-libs/.spur/rules/...` header documenting what was re-scoped, omitted, or
32
35
  tuned for Spur's app-repo layout. After absorption, ts-libs and spur-new
33
36
  maintain their rulesets independently.
34
37
 
38
+ ## Transitional helpers
39
+
40
+ - `migration/rg-dialect` (category `migration/`) and the `rg-migration` preset
41
+ are **shipped and live**: run `spur rule run --preset rg-migration` on demand
42
+ during the regex → `rg` evaluator migration. They are intentionally excluded
43
+ from the standing pre/post-check gates (transitional, not a permanent gate).
44
+
35
45
  ## Not absorbed (Spur-irrelevant)
36
46
 
37
47
  - `typescript/esm-build-conventions` — governs ts-libs' library publish/dist
38
48
  flow. Spur apps don't publish libraries this way.
39
- - `migration/rg-dialect` — one-time grep→rg migration helper.
40
- - `migration/rg-migration` — one-time grep→rg migration helper.
@@ -1,10 +1,10 @@
1
1
  $schema: "@gobing-ai/spur/schemas/preset.schema.json"
2
- # Recommended pre-check preset — portable rule categories from global install.
2
+ # Recommended pre-check preset — portable rule categories bundled with the catalog.
3
3
  # Use with: spur rule run --preset recommended-pre-check
4
4
  #
5
- # Runs BEFORE tests (test-pre-check). TypeScript quality, structural, DB
6
- # boundary, CLI surface consistency, and UI seam-boundary rules. TSDoc exports
7
- # run in post-check alongside coverage-gate.
5
+ # Runs BEFORE tests (test-pre-check). Extends six categories: typescript,
6
+ # structure, boundary, surface, ui, and strict (ui since bc267cc8, strict since
7
+ # 79186391). TSDoc exports run in post-check alongside coverage-gate.
8
8
  name: recommended-pre-check
9
9
  extends:
10
10
  - typescript
@@ -1,7 +1,9 @@
1
1
  $schema: "@gobing-ai/spur/schemas/preset.schema.json"
2
- # Strict-check preset — opt-in hygiene rules absorbed from ts-libs but kept OUT
3
- # of the default recommended-pre-check gate (they need project-specific tuning
4
- # or are redundant with engine-level validation). Run explicitly:
2
+ # Strict-check preset — explicit single-category cherry-pick of the `strict/`
3
+ # category only. The same category is already included in recommended-pre-check
4
+ # (extends: typescript, structure, boundary, surface, ui, strict) since 79186391;
5
+ # use this preset when you want ONLY strict rules, not the full pre-check set.
6
+ # Run explicitly:
5
7
  # spur rule run --preset strict-check
6
8
  # or cherry-pick a single rule:
7
9
  # spur rule run --rule no-third-party-http-clients
@@ -11,6 +13,7 @@ $schema: "@gobing-ai/spur/schemas/preset.schema.json"
11
13
  name: strict-check
12
14
  description: >
13
15
  Opt-in boundary hygiene: HTTP-client centralization, runtime fs/spawn seams,
14
- and local rule-file structural validation. Not part of recommended-pre-check.
16
+ and local rule-file structural validation. Included in recommended-pre-check;
17
+ this preset selects the strict/ category alone.
15
18
  extends:
16
19
  - strict
@@ -69,6 +69,11 @@ All product development work goes through the harness by default.
69
69
  auto`, a name, parallel/headless execution, direct `spur agent run`, and engine-driven workflow
70
70
  `agent.run` remain subprocess surfaces.
71
71
 
72
+ **Task lookup fast path:** Given a WBS, do not search `docs/tasks*` or guess `--folder`. Use
73
+ `spur task show <wbs> --json` for task metadata and content; its response also includes `filePath`.
74
+ Use `spur task path <wbs> --json` only when a filesystem consumer needs the absolute path. Both
75
+ commands resolve across configured task folders. Reuse the first `show` response within the run.
76
+
72
77
  **Platform fallback:** Platforms without slash commands and/or subagents still use the harness.
73
78
  Install the plugin through Superskill for the target platform, then use skills `sp:spur-dev`,
74
79
  `sp:spur-cli`, `sp:code-verification` (and related) plus the `spur` CLI. Do not invent a parallel
@@ -10,7 +10,7 @@
10
10
  # Shape: start -> discovery -> idea-eval -> feature-create -> ac-generate -> feature-check
11
11
  # -> system-design (conditional: needs_design signal)
12
12
  # -> design-approval (taste HITL gate; not auto-clicked by --auto)
13
- # -> decompose -> batch-create -> handoff
13
+ # -> decompose -> batch-create -> handoff-finalize -> handoff
14
14
  # (idea-eval rejection -> cancelled)
15
15
  # (feature-check failure routes back to ac-generate; batch-create failure to decompose).
16
16
  #
@@ -128,20 +128,36 @@ states:
128
128
  - id: feature-create
129
129
  description: >
130
130
  Create a feature via spur feature create, or select an existing feature id.
131
- The agent writes the feature id to .spur/run/${vars.__runId}-idea-feature-id.txt for subsequent
132
- states to read. Prefer the enhanced idea from .spur/run/${vars.__runId}-idea-eval-report.md as
131
+ The agent writes the feature id to .spur/run/${vars.__runId}-idea-feature-id.txt and body-only
132
+ intent artifacts .spur/run/${vars.__runId}-idea-goal.md / -idea-scope.md. Goal carries
133
+ concise intent only; Scope carries explicit in/out boundaries — task breakdowns and
134
+ checklists never enter Goal. Shell actions then persist both sections through
135
+ `spur feature update --section Goal|Scope --from-file ...`; a missing/empty artifact
136
+ stops the state. Prefer the enhanced idea from .spur/run/${vars.__runId}-idea-eval-report.md as
133
137
  context; do not overwrite vars.idea.
134
138
  onEnter:
135
139
  - kind: agent.run
136
140
  options:
137
141
  agent: ${vars.agent}
138
- input: "Create a feature for the idea: ${vars.idea}. Read .spur/run/${vars.__runId}-idea-eval-report.md if present for the enhanced idea and scores. Use 'spur feature create \"<name>\" --json' to create it. Write the feature id to .spur/run/${vars.__runId}-idea-feature-id.txt. If an existing feature is appropriate, use its id instead."
142
+ input: "Create a feature for the idea: ${vars.idea}. Read .spur/run/${vars.__runId}-idea-eval-report.md if present for the enhanced idea and scores. Use 'spur feature create \"<name>\" --json' to create it. Write the feature id to .spur/run/${vars.__runId}-idea-feature-id.txt. If an existing feature is appropriate, use its id instead. Also write two body-only intent artifacts: .spur/run/${vars.__runId}-idea-goal.md with concise Goal intent only (a short statement of what the feature achieves; never task breakdowns, checklists, or how-to steps), and .spur/run/${vars.__runId}-idea-scope.md with explicit in-scope and out-of-scope boundary bullets."
139
143
  expectFile: .spur/run/${vars.__runId}-idea-feature-id.txt
140
144
  timeoutMs: ${vars.stepTimeoutMs}
141
145
  - kind: file.read.into-var
142
146
  options:
143
147
  path: .spur/run/${vars.__runId}-idea-feature-id.txt
144
148
  var: featureId
149
+ - kind: shell
150
+ options:
151
+ command: >-
152
+ mkdir -p .spur/run &&
153
+ test -s .spur/run/$__runId-idea-goal.md &&
154
+ $spurBin feature update "$featureId" --section Goal --from-file .spur/run/$__runId-idea-goal.md
155
+ - kind: shell
156
+ options:
157
+ command: >-
158
+ mkdir -p .spur/run &&
159
+ test -s .spur/run/$__runId-idea-scope.md &&
160
+ $spurBin feature update "$featureId" --section Scope --from-file .spur/run/$__runId-idea-scope.md
145
161
 
146
162
  - id: ac-generate
147
163
  description: >
@@ -177,7 +193,7 @@ states:
177
193
  options:
178
194
  command: >-
179
195
  if test -s .spur/run/$__runId-idea-ac-content.md; then
180
- $spurBin feature update $featureId --section "Acceptance Criteria" --from-file .spur/run/$__runId-idea-ac-content.md && date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-ac-done.txt;
196
+ $spurBin feature update "$featureId" --section "Acceptance Criteria" --from-file .spur/run/$__runId-idea-ac-content.md && date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-ac-done.txt;
181
197
  else
182
198
  exit 0;
183
199
  fi
@@ -206,13 +222,33 @@ states:
206
222
  Dispatch sp:sys-architecture to produce the system design. This state runs
207
223
  only when needs_design=true (design=auto signal path). The agent creates ADR
208
224
  entries, architecture updates, and design satellites through constitution rules.
209
- The design-approval state follows (taste gate).
225
+ A run-scoped design-review artifact (.spur/run/${vars.__runId}-idea-design-review.md)
226
+ with fixed headings `## Proposed design`, `## Operator feedback`, and `## Reconciliation`
227
+ carries operator rejection feedback back into this state: on the first pass the agent
228
+ fills `## Proposed design`; on retry (operator feedback present) it revises the design,
229
+ records the reconciliation, and updates invalidated Acceptance Criteria through
230
+ `spur feature update` before design can exit. The design-approval state follows (taste gate).
210
231
  onEnter:
232
+ - kind: shell
233
+ options:
234
+ command: >-
235
+ mkdir -p .spur/run &&
236
+ REVIEW=".spur/run/$__runId-idea-design-review.md" &&
237
+ test -f "$REVIEW" || printf '## Proposed design\n\n## Operator feedback\n\n## Reconciliation\n' > "$REVIEW"
211
238
  - kind: agent.run
212
239
  options:
213
240
  agent: ${vars.agent}
214
- input: "Run sp:sys-architecture for feature ${vars.featureId}. Read the brainstorm artifact and feature AC. Produce ADR entries, architecture updates, and design satellites (docs/design/<slug>.md) following the constitution edit rules. Do not write task or feature corpus files directly."
241
+ input: "Run sp:sys-architecture for feature ${vars.featureId}. Read the brainstorm artifact, feature AC, and .spur/run/${vars.__runId}-idea-design-review.md. Produce ADR entries, architecture updates, and design satellites (docs/design/<slug>.md) following the constitution edit rules. Do not write task or feature corpus files directly. Design-review contract (.spur/run/${vars.__runId}-idea-design-review.md, fixed headings `## Proposed design`, `## Operator feedback`, `## Reconciliation`): on the first pass write the proposed design summary under `## Proposed design` and leave `## Operator feedback` empty; on retry with operator feedback present, revise the design/ADR artifacts, document the changes under `## Reconciliation`, and when the feedback invalidates an Acceptance Criteria scenario write the revised AC section body to a file and persist it via `$spurBin feature update \"$featureId\" --section \"Acceptance Criteria\" --from-file <file>` — never edit feature corpus files directly."
242
+ expectFile: .spur/run/${vars.__runId}-idea-design-review.md
215
243
  timeoutMs: ${vars.stepTimeoutMs}
244
+ # expectFile proves existence only, and the onEnter skeleton pre-creates the file — so an
245
+ # agent no-op would still pass it (0515 P3-2). Fail closed: the `## Proposed design` section
246
+ # must carry non-whitespace content before design can exit to approval/decompose.
247
+ - kind: shell
248
+ options:
249
+ command: >-
250
+ REVIEW=".spur/run/$__runId-idea-design-review.md" &&
251
+ awk '/^## Proposed design/{f=1; next} /^## Operator feedback/{f=0} f' "$REVIEW" | grep -q '[^[:space:]]'
216
252
 
217
253
  - id: design-approval
218
254
  description: >
@@ -226,6 +262,11 @@ states:
226
262
  agent passes. The onEnter shell increments a reject counter; the `no`
227
263
  edge to system-design is capped at 1 revise, after which the run
228
264
  terminates as `failed` naming this gate.
265
+
266
+ Rejection must carry operator feedback: before answering `no`, the operator
267
+ records the concrete issue(s) in the run-scoped design-review artifact
268
+ (.spur/run/${vars.__runId}-idea-design-review.md) under `## Operator feedback` —
269
+ the revision pass reads it to reconcile invalidated AC before re-approval.
229
270
  pause: true
230
271
  onEnter:
231
272
  - kind: shell
@@ -233,23 +274,45 @@ states:
233
274
  command: 'mkdir -p .spur/run && count=$(cat .spur/run/$__runId-idea-design-reject-count 2>/dev/null || echo 0); echo $((count + 1)) > .spur/run/$__runId-idea-design-reject-count'
234
275
  - kind: hitl.confirm
235
276
  options:
236
- prompt: "Review the system design for feature ${vars.featureId}. Approve to proceed to decomposition?"
277
+ prompt: "Review the system design for feature ${vars.featureId}. Approve to proceed to decomposition? To reject, first record your feedback in .spur/run/${vars.__runId}-idea-design-review.md under the `## Operator feedback` heading, then answer no."
237
278
 
238
279
  - id: decompose
239
280
  description: >
240
281
  Dispatch sp:spec-decomposition with the brainstorm artifact, feature AC, and
241
282
  design doc as input. The agent produces a task-batch JSON file at
242
- .spur/run/${vars.__runId}-idea-task-batch.json, validated against task-batch.schema.json.
283
+ .spur/run/${vars.__runId}-idea-task-batch.json, validated against task-batch.schema.json,
284
+ plus the private task-order sidecar .spur/run/${vars.__runId}-idea-task-order.json
285
+ (a JSON array of { name, depends_on_names[] }; `[]` when no ordering exists).
286
+ A post-agent shell action validates the sidecar shape before decomposition
287
+ can exit — missing or ambiguous title-to-WBS resolution fails before handoff.
243
288
  onEnter:
244
289
  - kind: shell
245
290
  options:
246
- command: 'mkdir -p .spur/run && count=$(cat .spur/run/$__runId-idea-decompose-retry-count 2>/dev/null || echo 0); echo $((count + 1)) > .spur/run/$__runId-idea-decompose-retry-count; rm -f .spur/run/$__runId-idea-task-batch.json .spur/run/$__runId-idea-batch-create.done .spur/run/$__runId-idea-batch-create.failed'
291
+ command: 'mkdir -p .spur/run && count=$(cat .spur/run/$__runId-idea-decompose-retry-count 2>/dev/null || echo 0); echo $((count + 1)) > .spur/run/$__runId-idea-decompose-retry-count; rm -f .spur/run/$__runId-idea-task-batch.json .spur/run/$__runId-idea-task-order.json .spur/run/$__runId-idea-batch-create.done .spur/run/$__runId-idea-batch-create.failed .spur/run/$__runId-idea-batch-create-result.json .spur/run/$__runId-idea-handoff.md'
247
292
  - kind: agent.run
248
293
  options:
249
294
  agent: ${vars.agent}
250
- input: "Run sp:spec-decomposition for feature ${vars.featureId}. Read the brainstorm artifact, feature AC, and design doc. SIZING FIRST, before any JSON: apply the skill's `Default to NOT decomposing` rubric to the whole unit of work — if it scores 0-2 the correct output is a ONE-entry batch, not many. Scenario count is not task count: merge scenarios that one task delivers (same file surface, same subsystem, or unreadable apart in review), and list every scenario a task covers in its background. Merging never costs AC coverage — one task may carry several scenarios. Do not emit one entry per scenario or per requirement by reflex. Then produce a task-batch JSON array at .spur/run/${vars.__runId}-idea-task-batch.json, validated against apps/cli/schemas/task-batch.schema.json. Schema-permitted fields per entry: `name`, `background`, `requirements`, `feature_id`, `parent_wbs`, `priority`, `tags`, `template` — schema validation rejects anything else. Acceptance Criteria, Design, and Plan sections are filled in by the per-task refine step after batch-create, NOT at decompose time. Validate locally against the schema before emitting."
295
+ input: "Run sp:spec-decomposition for feature ${vars.featureId}. Read the brainstorm artifact, feature AC, and design doc. SIZING FIRST, before any JSON: apply the skill's `Default to NOT decomposing` rubric to the whole unit of work — if it scores 0-2 the correct output is a ONE-entry batch, not many. Scenario count is not task count: merge scenarios that one task delivers (same file surface, same subsystem, or unreadable apart in review), and list every scenario a task covers in its background. Merging never costs AC coverage — one task may carry several scenarios. Do not emit one entry per scenario or per requirement by reflex. Then produce a task-batch JSON array at .spur/run/${vars.__runId}-idea-task-batch.json, validated against apps/cli/schemas/task-batch.schema.json. Schema-permitted fields per entry: `name`, `background`, `requirements`, `feature_id`, `parent_wbs`, `priority`, `tags`, `template` — schema validation rejects anything else. Acceptance Criteria, Design, and Plan sections are filled in by the per-task refine step after batch-create, NOT at decompose time. Validate locally against the schema before emitting. Also emit the private task-order sidecar at .spur/run/${vars.__runId}-idea-task-order.json: a JSON array (one entry per batch item) of `{ name: <exact batch item name>, depends_on_names: [<batch item names>] }` declaring ordering/dependencies between the batch items; use `[]` when no ordering exists. Every `name` and every dependency must match exactly one batch item `name` — it is private workflow data, not part of task-batch.schema.json."
251
296
  expectFile: .spur/run/${vars.__runId}-idea-task-batch.json
252
297
  timeoutMs: ${vars.stepTimeoutMs}
298
+ # R1 (0518): the task-order sidecar is the ordering contract for handoff-finalize.
299
+ # Validate it fails closed: sidecar must be an array, batch names unique, sidecar names
300
+ # unique, every sidecar name/dependency must refer to exactly one batch name, and — the
301
+ # converse (F2, 0518 verify) — every batch name must appear in the sidecar, so a partial
302
+ # sidecar can never silently skip `task deps` for an unlisted item (`[]` is valid).
303
+ - kind: shell
304
+ options:
305
+ command: >-
306
+ BATCH=".spur/run/$__runId-idea-task-batch.json" &&
307
+ ORDER=".spur/run/$__runId-idea-task-order.json" &&
308
+ jq -e --slurpfile b "$BATCH" '
309
+ (type == "array") and
310
+ (($b[0] | map(.name) | length) == ($b[0] | map(.name) | unique | length)) and
311
+ ((map(.name) | length) == (map(.name) | unique | length)) and
312
+ ((map(.name) - ($b[0] | map(.name))) | length == 0) and
313
+ ((($b[0] | map(.name)) - map(.name)) | length == 0) and
314
+ (((map(.depends_on_names // []) | flatten | unique) - ($b[0] | map(.name))) | length == 0)
315
+ ' "$ORDER" >/dev/null
253
316
 
254
317
  - id: batch-create
255
318
  description: >
@@ -269,21 +332,116 @@ states:
269
332
  description: >
270
333
  Executes task batch creation exactly once per decomposition attempt. The
271
334
  side effect lives in onEnter and records a sentinel; transition guards only
272
- inspect sentinel/retry state.
335
+ inspect sentinel/retry state. The `--json` result is captured atomically in
336
+ .spur/run/${vars.__runId}-idea-batch-create-result.json (temp file + mv); the done
337
+ sentinel is written only after the JSON parses and `created == (.wbs | length)`,
338
+ so handoff-finalize can zip batch names to the returned WBS list. Any failure
339
+ (CLI error or malformed result) writes the failed sentinel, preserving the
340
+ existing retry behavior.
273
341
  onEnter:
274
342
  - kind: shell
275
343
  options:
276
- command: 'if test -f .spur/run/$__runId-idea-batch-create.done; then exit 0; fi; rm -f .spur/run/$__runId-idea-batch-create.failed; if $spurBin task batch-create --file .spur/run/$__runId-idea-task-batch.json; then date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-batch-create.done; else date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-batch-create.failed; fi'
344
+ command: >-
345
+ if test -f .spur/run/$__runId-idea-batch-create.done; then exit 0; fi;
346
+ rm -f .spur/run/$__runId-idea-batch-create.failed .spur/run/$__runId-idea-batch-create-result.json .spur/run/$__runId-idea-batch-create-result.json.tmp;
347
+ if $spurBin task batch-create --file .spur/run/$__runId-idea-task-batch.json --json > .spur/run/$__runId-idea-batch-create-result.json.tmp && jq -e ".created == (.wbs | length)" .spur/run/$__runId-idea-batch-create-result.json.tmp >/dev/null 2>&1; then
348
+ mv .spur/run/$__runId-idea-batch-create-result.json.tmp .spur/run/$__runId-idea-batch-create-result.json &&
349
+ date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-batch-create.done;
350
+ else
351
+ rm -f .spur/run/$__runId-idea-batch-create-result.json.tmp;
352
+ date -u +%Y-%m-%dT%H:%M:%SZ > .spur/run/$__runId-idea-batch-create.failed;
353
+ fi
354
+
355
+ - id: handoff-finalize
356
+ description: >
357
+ Post-create finalization (0518): zip batch item names to the created WBS
358
+ values from the captured batch-create result (equal-length/unique-name
359
+ checks), apply every non-empty depends_on_names list through
360
+ `spur task deps`, refresh the feature roster, check every created task, and
361
+ write the run-scoped handoff report
362
+ (.spur/run/${vars.__runId}-idea-handoff.md) with exactly one next command.
363
+ A mapping or CLI error fails the run before terminal handoff; an unready
364
+ task is a successful planning outcome recorded as a refineall recommendation.
365
+ onEnter:
366
+ # F1 (0518 verify): the per-task check loop fails closed. A stderr-only (non-JSON)
367
+ # `task check --json` exception would otherwise drop that task from the JSONL results
368
+ # without failing the run (the loop's exit status is its last body command), silently
369
+ # flipping the recommendation to runall — violating R3's any-fail=>refineall invariant.
370
+ # Each `jq -c … >> "$CHECKS"` appends under `|| exit 1`, and a row-count assertion
371
+ # (CHECKS lines == WBS count) gates the recommendation computation.
372
+ - kind: shell
373
+ options:
374
+ command: >-
375
+ BATCH=".spur/run/$__runId-idea-task-batch.json" &&
376
+ RESULT=".spur/run/$__runId-idea-batch-create-result.json" &&
377
+ ORDER=".spur/run/$__runId-idea-task-order.json" &&
378
+ REPORT=".spur/run/$__runId-idea-handoff.md" &&
379
+ DEPMAP=".spur/run/$__runId-idea-dep-map.tsv" &&
380
+ CHECKS=".spur/run/$__runId-idea-check-results.jsonl" &&
381
+ rm -f "$DEPMAP" "$CHECKS" &&
382
+ jq -e --slurpfile b "$BATCH" '(.wbs | length) == ($b[0] | length) and (($b[0] | map(.name) | unique | length) == ($b[0] | length))' "$RESULT" >/dev/null &&
383
+ jq -r --slurpfile b "$BATCH" --slurpfile r "$RESULT" --slurpfile o "$ORDER" '
384
+ ($b[0] | map(.name)) as $names | ($r[0].wbs) as $wbs |
385
+ $o[0] | .[] |
386
+ (.name as $n | $names | index($n)) as $i |
387
+ (if $i == null or $wbs[$i] == null then "MISSING" else $wbs[$i] end) as $own |
388
+ ((.depends_on_names // []) | map(. as $dep | $names | index($dep) as $d | if $d == null then "MISSING" else $wbs[$d] end) | join(" ")) as $deps |
389
+ [.name, $own, $deps] | @tsv
390
+ ' "$ORDER" > "$DEPMAP" &&
391
+ while IFS="$(printf '\t')" read -r name own deps; do
392
+ test "$own" != MISSING || exit 1;
393
+ if test -n "$deps"; then
394
+ for d in $deps; do test "$d" != MISSING || exit 1; done;
395
+ $spurBin task deps "$own" set $deps --json >/dev/null || exit 1;
396
+ fi;
397
+ done < "$DEPMAP" &&
398
+ $spurBin feature refresh --feature "$featureId" --json >/dev/null &&
399
+ WBS_LIST=$(jq -r '.wbs | join(" ")' "$RESULT") &&
400
+ for wbs in $WBS_LIST; do
401
+ TMP=".spur/run/$__runId-idea-check-$wbs.tmp";
402
+ if $spurBin task check "$wbs" --json > "$TMP" 2>&1; then P=true; else P=false; fi;
403
+ jq -c --arg w "$wbs" --argjson p "$P" 'if (type == "array" and length > 0) then {wbs: $w, pass: $p, status: (.[0].status // "unknown")} else {wbs: $w, pass: $p, status: "missing"} end' "$TMP" >> "$CHECKS" || exit 1;
404
+ rm -f "$TMP";
405
+ done &&
406
+ CHECK_ROWS=$(wc -l < "$CHECKS" | tr -d ' ') &&
407
+ WBS_COUNT=$(printf '%s\n' $WBS_LIST | wc -l | tr -d ' ') &&
408
+ test "$CHECK_ROWS" = "$WBS_COUNT" &&
409
+ NEXT=$(jq -r --arg feature "$featureId" --slurpfile c "$CHECKS" 'if ($c | any(.[]; .pass == false)) then "/sp:dev-refineall --feature \($feature) --auto --depth ready" else "/sp:dev-runall --feature \($feature) --auto" end' "$RESULT") &&
410
+ {
411
+ echo "# Idea pipeline handoff report";
412
+ echo;
413
+ echo "Feature: $featureId";
414
+ echo "Run ID: $__runId";
415
+ echo;
416
+ echo "## Created tasks";
417
+ printf '%s\n' $WBS_LIST | sed 's/^/ - /';
418
+ echo;
419
+ echo "## Per-task readiness (spur task check)";
420
+ echo;
421
+ echo "| WBS | Outcome |";
422
+ echo "|-----|---------|";
423
+ while IFS= read -r line; do
424
+ w=$(printf '%s' "$line" | jq -r '.wbs');
425
+ o=$(printf '%s' "$line" | jq -r 'if .pass then "PASS" else "FAIL" end');
426
+ printf '| %s | %s |\n' "$w" "$o";
427
+ done < "$CHECKS";
428
+ echo;
429
+ echo "## Next command";
430
+ echo;
431
+ echo "$NEXT";
432
+ } > "$REPORT"
277
433
 
278
434
  - id: handoff
279
435
  description: >
280
- Terminal — idea pipeline complete. Output: feature id, task WBS list, and
281
- the next command to run (/sp:dev-run <first-wbs> or /sp:dev-runall --feature <id> or --tasks feature:<id>).
282
- No task execution the pipeline stops here.
436
+ Terminal — idea pipeline complete. Ordering applied, roster refreshed, and
437
+ the handoff report written at .spur/run/${vars.__runId}-idea-handoff.md:
438
+ feature id, task WBS list, per-task readiness, and exactly one recommended
439
+ next command (ready-depth refineall when any task is unready, else auto
440
+ runall). No task execution — the pipeline stops here.
283
441
  onEnter:
284
442
  - kind: note
285
443
  options:
286
- message: "Idea pipeline handoff. Feature: ${vars.featureId}. Tasks created. Next: /sp:dev-runall --feature ${vars.featureId}"
444
+ message: "Idea pipeline handoff. Feature: ${vars.featureId}. See .spur/run/${vars.__runId}-idea-handoff.md for the created task list and recommended next command."
287
445
  # Checkpoint write: record session state for resume (Phase 4, task 0171 R3)
288
446
  - kind: shell
289
447
  options:
@@ -374,7 +532,7 @@ transitions:
374
532
  guard:
375
533
  kind: shell
376
534
  options:
377
- command: 'test "$profile" = auto && $spurBin feature check $featureId && test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false'
535
+ command: 'test "$profile" = auto && $spurBin feature check "$featureId" && test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false'
378
536
  # Auto-skip 2: pass + skip-design route → decompose
379
537
  - from: ac-generate
380
538
  to: decompose
@@ -382,7 +540,7 @@ transitions:
382
540
  guard:
383
541
  kind: shell
384
542
  options:
385
- command: 'test "$profile" = auto && $spurBin feature check $featureId && (test "$design" = skip || (test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false))'
543
+ command: 'test "$profile" = auto && $spurBin feature check "$featureId" && (test "$design" = skip || (test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false))'
386
544
  # Auto-skip 3: check failed, retry < 3 → loop back to ac-generate (self-loop)
387
545
  - from: ac-generate
388
546
  to: ac-generate
@@ -390,7 +548,7 @@ transitions:
390
548
  guard:
391
549
  kind: shell
392
550
  options:
393
- command: 'test "$profile" = auto && ! $spurBin feature check $featureId && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3'
551
+ command: 'test "$profile" = auto && ! $spurBin feature check "$featureId" && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3'
394
552
  # Auto-skip 4: check failed, retry cap reached → escalate to failed
395
553
  - from: ac-generate
396
554
  to: failed
@@ -398,7 +556,7 @@ transitions:
398
556
  guard:
399
557
  kind: shell
400
558
  options:
401
- command: 'test "$profile" = auto && ! $spurBin feature check $featureId && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3'
559
+ command: 'test "$profile" = auto && ! $spurBin feature check "$featureId" && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3'
402
560
  # Interactive fallback: enter feature-check HITL gate
403
561
  - from: ac-generate
404
562
  to: feature-check
@@ -414,28 +572,28 @@ transitions:
414
572
  guard:
415
573
  kind: shell
416
574
  options:
417
- command: 'test "$__hitlAnswer" = yes && $spurBin feature check $featureId && test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false'
575
+ command: 'test "$__hitlAnswer" = yes && $spurBin feature check "$featureId" && test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" != false'
418
576
  - from: feature-check
419
577
  to: decompose
420
578
  description: Feature check passed, skip-design route — go directly to decompose.
421
579
  guard:
422
580
  kind: shell
423
581
  options:
424
- command: 'test "$__hitlAnswer" = yes && $spurBin feature check $featureId && (test "$design" = skip || (test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false))'
582
+ command: 'test "$__hitlAnswer" = yes && $spurBin feature check "$featureId" && (test "$design" = skip || (test "$design" = auto && test "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false))'
425
583
  - from: feature-check
426
584
  to: ac-generate
427
585
  description: "Feature check failed — revise AC (retry cap: 3)."
428
586
  guard:
429
587
  kind: shell
430
588
  options:
431
- command: '(test "$__hitlAnswer" = no || ! $spurBin feature check $featureId) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3'
589
+ command: '(test "$__hitlAnswer" = no || ! $spurBin feature check "$featureId") && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3'
432
590
  - from: feature-check
433
591
  to: failed
434
592
  description: Feature check failed after 3 retries — escalate to failed.
435
593
  guard:
436
594
  kind: shell
437
595
  options:
438
- command: '(test "$__hitlAnswer" = no || ! $spurBin feature check $featureId) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3'
596
+ command: '(test "$__hitlAnswer" = no || ! $spurBin feature check "$featureId") && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3'
439
597
  - from: feature-check
440
598
  to: cancelled
441
599
  description: Operator cancelled the feature-check gate.
@@ -448,25 +606,32 @@ transitions:
448
606
  # Declaration order: auto-skip guard tried FIRST (like task-pipeline's review->verify pattern).
449
607
  - from: system-design
450
608
  to: decompose
451
- description: profile=auto AND design_approved=true — skip design approval gate.
609
+ description: profile=auto AND design_approved=true AND feature check passes — skip design approval gate.
452
610
  guard:
453
611
  kind: shell
454
612
  options:
455
- command: 'test "$profile" = auto && test "$design_approved" = true'
613
+ command: 'test "$profile" = auto && test "$design_approved" = true && $spurBin feature check "$featureId"'
456
614
  - from: system-design
457
615
  to: design-approval
458
616
  description: System design done — gate on design approval.
459
617
  guard:
460
618
  kind: always
461
619
 
462
- # ── design-approval -> decompose (after operator approval) ──
620
+ # ── design-approval -> decompose (after operator approval), AC-failure -> feature-check ──
463
621
  - from: design-approval
464
622
  to: decompose
465
- description: Design approved — proceed to decomposition.
623
+ description: Design approved and feature check passes — proceed to decomposition.
466
624
  guard:
467
625
  kind: shell
468
626
  options:
469
- command: 'test "$__hitlAnswer" = yes'
627
+ command: 'test "$__hitlAnswer" = yes && $spurBin feature check "$featureId"'
628
+ - from: design-approval
629
+ to: feature-check
630
+ description: "Design approved but feature check fails — route back through the AC gate (revise AC, retry cap: 3)."
631
+ guard:
632
+ kind: shell
633
+ options:
634
+ command: 'test "$__hitlAnswer" = yes && ! $spurBin feature check "$featureId"'
470
635
  - from: design-approval
471
636
  to: system-design
472
637
  description: "Design rejected - revise system design (cap: 1 revise)."
@@ -526,10 +691,10 @@ transitions:
526
691
  options:
527
692
  command: 'test "$__hitlAnswer" = cancel'
528
693
 
529
- # ── batch-create-run: success -> handoff, failure -> decompose (retry cap: 3), failure+cap -> failed ──
694
+ # ── batch-create-run: success -> handoff-finalize, failure -> decompose (retry cap: 3), failure+cap -> failed ──
530
695
  - from: batch-create-run
531
- to: handoff
532
- description: Batch created — handoff.
696
+ to: handoff-finalize
697
+ description: Batch created and result captured apply ordering, refresh roster, write handoff report.
533
698
  guard:
534
699
  kind: shell
535
700
  options:
@@ -548,3 +713,10 @@ transitions:
548
713
  kind: shell
549
714
  options:
550
715
  command: 'test -f .spur/run/$__runId-idea-batch-create.failed && test "$(cat .spur/run/$__runId-idea-decompose-retry-count 2>/dev/null || echo 0)" -ge 3'
716
+
717
+ # ── handoff-finalize: -> handoff (terminal) ──
718
+ - from: handoff-finalize
719
+ to: handoff
720
+ description: Ordering applied, roster refreshed, handoff report written — terminal handoff.
721
+ guard:
722
+ kind: always
@@ -451,7 +451,7 @@ states:
451
451
  - kind: agent.run
452
452
  options:
453
453
  agent: ${vars.agent}
454
- input: /sp:dev-verify ${vars.wbs} --auto --fix all
454
+ input: /sp:dev-verify ${vars.wbs} --auto --fix all --focus all
455
455
  timeoutMs: ${vars.stepTimeoutMs}
456
456
  answerFile: .spur/run/${vars.wbs}-verify-answer.txt
457
457
  - kind: shell
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.43",
3
+ "version": "0.3.45",
4
4
  "description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
5
5
  "keywords": [
6
6
  "spur",
@@ -53,14 +53,14 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@commander-js/extra-typings": "^14.0.0",
56
- "@gobing-ai/ts-db": "^0.4.27",
57
- "@gobing-ai/ts-ai-runner": "^0.4.27",
58
- "@gobing-ai/ts-dual-workflow-engine": "^0.4.27",
59
- "@gobing-ai/ts-infra": "^0.4.27",
60
- "@gobing-ai/ts-llm-jsonl-importer": "^0.4.27",
61
- "@gobing-ai/ts-rule-engine": "^0.4.27",
62
- "@gobing-ai/ts-runtime": "^0.4.27",
63
- "@gobing-ai/ts-utils": "^0.4.27",
56
+ "@gobing-ai/ts-db": "^0.4.30",
57
+ "@gobing-ai/ts-ai-runner": "^0.4.30",
58
+ "@gobing-ai/ts-dual-workflow-engine": "^0.4.30",
59
+ "@gobing-ai/ts-infra": "^0.4.30",
60
+ "@gobing-ai/ts-llm-jsonl-importer": "^0.4.30",
61
+ "@gobing-ai/ts-rule-engine": "^0.4.30",
62
+ "@gobing-ai/ts-runtime": "^0.4.30",
63
+ "@gobing-ai/ts-utils": "^0.4.30",
64
64
  "@types/bun": "1.3.14",
65
65
  "@types/figlet": "^1.7.0",
66
66
  "@types/node-notifier": "8.0.5",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: "Prompt-first feature frontier prioritizer — answers 'which feature should we work on now?' with a ranked, evidence-carrying frontier, and emits rank-distorting tree defects as proposals /sp:dev-featurechange consumes. Triggers: find next, which feature, feature ranking, frontier priority, what should I work on."
3
- argument-hint: "[--task [<feature-id>]] [--agent <inline|auto|name>] [--json]"
3
+ argument-hint: "[--task [<feature-id>]] [--agent <inline|auto|name>] [--auto] [--json]"
4
4
  allowed-tools: ["Bash", "Read", "Write", "Grep", "Glob", "Skill"]
5
5
  ---
6
6
 
@@ -20,6 +20,7 @@ Answers *"which X"* — the question `/sp:dev-next` deliberately does not (next-
20
20
  | --- | --- | --- |
21
21
  | `--task` `[<feature-id>]` | After the report, confirm one target and dispatch the planning half to produce implement-ready tasks. | omitted |
22
22
  | `--agent` `<inline\|auto\|name>` | Who runs the model-bearing analysis. | inline |
23
+ | `--auto` | Skip the `--task` confirm (accept the offered target) and forward into dispatched children. | off |
23
24
  | `--json` | Emit the ranked frontier, gated list, and proposals as a JSON envelope. | off |
24
25
 
25
26
  For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag-glossary.md).
@@ -30,23 +31,30 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
30
31
  /sp:dev-find-next
31
32
  /sp:dev-find-next --json
32
33
  /sp:dev-find-next --task
34
+ /sp:dev-find-next --task --auto
33
35
  /sp:dev-find-next --task H1 --auto
34
36
  ```
35
37
 
36
38
  **`--task` — confirm, then dispatch.** The command offers the rank-1 candidate (or the id you pass),
37
- takes an **explicit** confirmation, then routes on the tier the ranking already assigned: a **T3**
38
- feature with valid AC and no tasks goes to `/sp:dev-plan --feature <id>` and then
39
- `/sp:dev-refineall --feature <id> --auto --depth ready`; a **T1** feature (open tasks already exist)
40
- goes to refineall only, never a second decomposition; **T2** (blocked), **T4** (stale-done), and T3
41
- with invalid AC stop with their reason. The command creates no tasks itself — decomposition and its
42
- schema gate belong to `/sp:dev-plan`. The confirmation pauses **regardless of `--auto`**; `--auto`
43
- is forwarded only to the dispatched children. Declining writes nothing.
39
+ then routes on the tier the ranking already assigned: a **T3** feature with valid AC and no tasks
40
+ goes to `/sp:dev-plan --feature <id>` and then `/sp:dev-refineall --feature <id> --auto --depth ready`;
41
+ a **T1** feature (open tasks already exist) goes to refineall only, never a second decomposition;
42
+ **T2** (blocked), **T4** (stale-done), and T3 with invalid AC stop with their reason. The command
43
+ creates no tasks itself — decomposition and its schema gate belong to `/sp:dev-plan`.
44
+
45
+ **Confirm under `--auto`.** Without `--auto`, confirmation is interactive (accept the offer, name
46
+ another candidate, or decline). With `--auto`, the offered target is accepted automatically —
47
+ rank-1 for bare `--task`, or the explicit `--task <feature-id>` — and dispatch proceeds without a
48
+ HITL pause. Passing `--auto` is operator pre-consent to take the ranking's recommendation; it is
49
+ not a license to invent a different target or to bypass T2/T4 refuse / invalid-AC stop. `--auto`
50
+ is also forwarded to the dispatched children. Declining (interactive path only) writes nothing.
51
+ Without `--task`, `--auto` is a no-op (the ranking report has no HITL gate).
44
52
 
45
53
  Without `--task` the command is read-only with respect to the corpus and docs. Under `--task` the
46
- only mutation is the one the dispatched commands perform on `docs/tasks*/` after you confirm — the
47
- command still performs no `spur feature move`, no sync apply, and no write under `docs/features/**`.
48
- Defect proposals conform to the `docs/plans/feature-tree-restructure-map.md` schema and are applied
49
- only through `/sp:dev-featurechange` (dry-run → confirm → apply).
54
+ only mutation is the one the dispatched commands perform on `docs/tasks*/` after confirm (or
55
+ auto-accept) — the command still performs no `spur feature move`, no sync apply, and no write under
56
+ `docs/features/**`. Defect proposals conform to the `docs/plans/feature-tree-restructure-map.md`
57
+ schema and are applied only through `/sp:dev-featurechange` (dry-run → confirm → apply).
50
58
 
51
59
  **See also:** skill `sp:next-feature` (SSOT), `sp:next-router` (`/sp:dev-next`),
52
60
  `sp:conflict-finding` (the prompt-first template), `sp:spur-cli`.
@@ -36,7 +36,9 @@ Flags: `--tasks <selector>` (required — explicit WBS list, status pseudo-list,
36
36
  or `ready`), `--feature <id>` (sugar for `feature:<id>`; when the effective selector is
37
37
  feature-derived, `dev-runall` runs `spur feature check <id> --strict --json` **once** before
38
38
  resolving tasks — a non-zero strict check aborts the batch with verdict `aborted` and the
39
- structured findings, before any task pipeline action, task 0510 R2), `--mode`
39
+ structured findings, before any task pipeline action, task 0510 R2; scoped: `L4.scenario-unverified`
40
+ (the expected pre-run state of any not-yet-run feature) is reported verbatim but does not abort —
41
+ any other strict error aborts), `--mode`
40
42
  `<sequential|parallel>` (default `sequential`; `parallel` fans out a proven-independent subset —
41
43
  see `execution-batch.md` § Parallel Execution), `--keep-going`
42
44
  (batch failure policy — skip a failed task's in-batch dependents, continue independents; default