@gobing-ai/spur 0.3.44 → 0.3.46
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/.claude-plugin/marketplace.json +1 -1
- package/config/rules/README.md +12 -4
- package/config/rules/recommended-pre-check.yaml +4 -4
- package/config/rules/strict-check.yaml +7 -4
- package/package.json +9 -9
- package/plugins/sp/commands/dev-find-next.md +20 -12
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/skills/next-feature/SKILL.md +17 -13
- package/plugins/sp/skills/next-feature/references/handoff-routing.md +12 -7
- package/plugins/sp/skills/next-feature/references/signal-derivation.md +39 -2
- package/plugins/sp/skills/spur-cli/references/agent.md +35 -2
- package/plugins/sp/skills/spur-cli/references/message.md +15 -4
- package/plugins/sp/skills/spur-cli/references/workflows/validation-and-extension.md +18 -3
- package/plugins/sp/skills/spur-cli/references/workflows.md +8 -2
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +5 -4
- package/schemas/state-machine-workflow.schema.json +137 -26
- package/schemas/transition-flow-workflow.schema.json +123 -23
- package/spur.js +2943 -703
- package/web/_astro/BoardApp.Ce6zJYAH.js +1 -0
- package/web/_astro/BoardApp.DKyrGxdo.js +179 -0
- package/web/_astro/{TaskDetail.B6yiT-U7.js → TaskDetail.6-27_LMa.js} +1 -1
- package/web/_astro/{arc.PbmgYm3_.js → arc.Df-9AQvS.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.BkOMSdmD.js → architectureDiagram-3BPJPVTR.VAI_-paS.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.BtomoUdy.js → blockDiagram-GPEHLZMM.DFpUY1ue.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.UzrYwJnF.js → c4Diagram-AAUBKEIU.CF8doOpg.js} +1 -1
- package/web/_astro/channel.Uhm9O3UV.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.nNChLHkw.js → chunk-2J33WTMH.BnjK3fjt.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.DLYAecPo.js → chunk-4BX2VUAB.x6ZDnJKq.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.t5bzuj1J.js → chunk-55IACEB6.zY-0uu7w.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DBV62bIy.js → chunk-727SXJPM.BZxKg_Vi.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.BdaPhTPs.js → chunk-AQP2D5EJ.Cpi9G9Td.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.eoZ88KMf.js → chunk-FMBD7UC4.DWTB-Pif.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.QdNDyeSh.js → chunk-ND2GUHAM.BPDQbiOG.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.DPaToLfx.js → chunk-QZHKN3VN.BRWIcuoM.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.By9BMe7b.js → classDiagram-4FO5ZUOK.mGTCZsDO.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.By9BMe7b.js → classDiagram-v2-Q7XG4LA2.mGTCZsDO.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.DMypl6q_.js → cose-bilkent-S5V4N54A.D1GEut-z.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.p26m9grg.js → dagre-BM42HDAG.BV0XG9Do.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.C6m3oTIu.js → diagram-2AECGRRQ.DzpYxsjo.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.JCxivn2z.js → diagram-5GNKFQAL.Cm9YzJh4.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.DifbEd3P.js → diagram-KO2AKTUF.BjhottUj.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.Bffga-cf.js → diagram-LMA3HP47.BFsQW5kb.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.CUKx5_Cx.js → diagram-OG6HWLK6.8pdpzSWO.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DaJ9KZR0.js → erDiagram-TEJ5UH35.Bd7KUJmJ.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.Do6l5pzg.js → flowDiagram-I6XJVG4X.7LWffkaE.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DqBKgB-3.js → ganttDiagram-6RSMTGT7.BeDcO5tI.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.B3VLSQ22.js → gitGraphDiagram-PVQCEYII.Ca4n730A.js} +1 -1
- package/web/_astro/{index.QfZ9SC3X.css → index.Dbvuw6d4.css} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.hK8ZC1oa.js → infoDiagram-5YYISTIA.B0OakQYb.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.C8DXwh9Z.js → ishikawaDiagram-YF4QCWOH.DSmNQe-1.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.mj5aHQDb.js → journeyDiagram-JHISSGLW.Cy5ruEUu.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.Dwlhi49r.js → kanban-definition-UN3LZRKU.CUJXub0p.js} +1 -1
- package/web/_astro/{linear.7zBHdlwl.js → linear.DC1jCCXn.js} +1 -1
- package/web/_astro/{mermaid.core.AYdA0EJr.js → mermaid.core.DxVP99Ab.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.BSnniHEq.js → mindmap-definition-RKZ34NQL.D0MaV6sJ.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.B7EVpA3J.js → pieDiagram-4H26LBE5.DCC6_q32.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.rg4i8YOY.js → quadrantDiagram-W4KKPZXB.BeUOAM7C.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.C4pr792x.js → requirementDiagram-4Y6WPE33.Dbl4MASO.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.DTXU996O.js → sankeyDiagram-5OEKKPKP.HsLg0VS4.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.D73DOjzi.js → sequenceDiagram-3UESZ5HK.DT7DJTnZ.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.CVkeSaEH.js → stateDiagram-AJRCARHV.d_ju1Vr1.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.DkBGwoN5.js → stateDiagram-v2-BHNVJYJU.DMCAjMJ4.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.DnJ9Yh7G.js → timeline-definition-PNZ67QCA.DNOHr62_.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DN1tvR4Y.js → vennDiagram-CIIHVFJN.B7dUy-1W.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.D54jJ-7-.js → wardley-L42UT6IY.DEqOXvBh.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.C2grUBbE.js → wardleyDiagram-YWT4CUSO.BCRb2p6x.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.D05okBnV.js → xychartDiagram-2RQKCTM6.NxVQLdBh.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.BnhkWEOG.js +0 -179
- package/web/_astro/BoardApp.CxOS4HSo.js +0 -1
- package/web/_astro/channel.DRRsElzO.js +0 -1
package/config/rules/README.md
CHANGED
|
@@ -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
|
|
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).
|
|
6
|
-
# boundary,
|
|
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 —
|
|
3
|
-
#
|
|
4
|
-
#
|
|
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.
|
|
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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.46",
|
|
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.
|
|
57
|
-
"@gobing-ai/ts-ai-runner": "^0.4.
|
|
58
|
-
"@gobing-ai/ts-dual-workflow-engine": "^0.4.
|
|
59
|
-
"@gobing-ai/ts-infra": "^0.4.
|
|
60
|
-
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.
|
|
61
|
-
"@gobing-ai/ts-rule-engine": "^0.4.
|
|
62
|
-
"@gobing-ai/ts-runtime": "^0.4.
|
|
63
|
-
"@gobing-ai/ts-utils": "^0.4.
|
|
56
|
+
"@gobing-ai/ts-db": "^0.4.31",
|
|
57
|
+
"@gobing-ai/ts-ai-runner": "^0.4.31",
|
|
58
|
+
"@gobing-ai/ts-dual-workflow-engine": "^0.4.31",
|
|
59
|
+
"@gobing-ai/ts-infra": "^0.4.31",
|
|
60
|
+
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.31",
|
|
61
|
+
"@gobing-ai/ts-rule-engine": "^0.4.31",
|
|
62
|
+
"@gobing-ai/ts-runtime": "^0.4.31",
|
|
63
|
+
"@gobing-ai/ts-utils": "^0.4.31",
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
47
|
-
command still performs no `spur feature move`, no sync apply, and no write under
|
|
48
|
-
Defect proposals conform to the `docs/plans/feature-tree-restructure-map.md`
|
|
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`.
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.46",
|
|
4
4
|
"description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics.",
|
|
5
5
|
"extensions": {
|
|
6
6
|
"pi": ["./hooks/pi/guard-extension.ts"]
|
|
@@ -40,9 +40,9 @@ in this corpus it is 76% one value (0493 measurement).
|
|
|
40
40
|
**Propose, never apply.** This skill performs no `spur feature move` and writes nothing under
|
|
41
41
|
`docs/features/**`. The only path from a structure proposal to a changed tree is
|
|
42
42
|
`/sp:dev-featurechange` (dry-run → confirm → apply). Ranking runs are read-only; the sole exception is
|
|
43
|
-
`--task`, which after an **
|
|
44
|
-
`/sp:dev-refineall` — commands that write `docs/tasks*/` through their
|
|
45
|
-
creates no tasks itself.
|
|
43
|
+
`--task`, which after an **operator confirm** (interactive, or auto-accepted under `--auto`)
|
|
44
|
+
dispatches `/sp:dev-plan` and `/sp:dev-refineall` — commands that write `docs/tasks*/` through their
|
|
45
|
+
own gates. This skill still creates no tasks itself.
|
|
46
46
|
|
|
47
47
|
## When to Use
|
|
48
48
|
|
|
@@ -89,13 +89,16 @@ Run the steps in order. Each step's depth lives in its reference; this file is t
|
|
|
89
89
|
at the ranking; advancing a chosen feature is `/sp:dev-next`'s job.
|
|
90
90
|
7. **`--task` only — confirm, then dispatch the planning half.** Offer the rank-1 candidate (or the
|
|
91
91
|
id passed as `--task <feature-id>` — which may name a **gated** feature, since T2/T3/T4 are tiers
|
|
92
|
-
the rubric assigns to the gated list and only T1 comes from the ranked frontier)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
the rubric assigns to the gated list and only T1 comes from the ranked frontier). **Without
|
|
93
|
+
`--auto`:** take an explicit operator confirmation (accept the offer, name another candidate, or
|
|
94
|
+
decline). **With `--auto`:** auto-accept the offered target (rank-1 for bare `--task`, or the
|
|
95
|
+
explicit id) — the flag is operator pre-consent to take the ranking's recommendation — then
|
|
96
|
+
proceed without a HITL pause. Route on the tier step 4 already assigned: T3 with zero tasks →
|
|
97
|
+
`/sp:dev-plan --feature <id>` then `/sp:dev-refineall --feature <id> --auto --depth ready`; T1 →
|
|
98
|
+
refineall only; T3 with invalid AC, T2, and T4 stop with their reason. **This skill creates no
|
|
99
|
+
tasks itself** — the dispatched commands own decomposition and its schema gate. Forward `--auto`
|
|
100
|
+
into the dispatched children. Full contract:
|
|
101
|
+
[references/handoff-routing.md](references/handoff-routing.md).
|
|
99
102
|
|
|
100
103
|
## Anti-patterns — do not do these
|
|
101
104
|
|
|
@@ -105,9 +108,10 @@ Run the steps in order. Each step's depth lives in its reference; this file is t
|
|
|
105
108
|
- Copying the B3 predicate into this skill. Cite it; read it at runtime.
|
|
106
109
|
- Any `spur feature move`, or writing proposals anywhere `docs/features/**` — featurechange owns apply.
|
|
107
110
|
- Decomposing a feature here, or calling `spur task create` / `spur task batch-create` under `--task`.
|
|
108
|
-
Dispatch `/sp:dev-plan`; it owns decomposition and the batch-create schema gate. Equally:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
Dispatch `/sp:dev-plan`; it owns decomposition and the batch-create schema gate. Equally:
|
|
112
|
+
dispatching under `--auto` without `--task` (there is no confirm to skip), auto-accepting a target
|
|
113
|
+
other than the offer / named `--task <id>`, or decomposing a T1 feature that already has a live
|
|
114
|
+
task frontier.
|
|
111
115
|
- Padding the defect list with tidiness findings that move no rank.
|
|
112
116
|
- Re-proposing F31's rejected merges (B∪H, J∪K body-merge) or reading
|
|
113
117
|
`## Applied mapping` as current state — letters are recycled; resolve against live features.
|
|
@@ -65,15 +65,20 @@ survivors would make its primary case unreachable. Offer the rank-1 ranked candi
|
|
|
65
65
|
| **T2 — unblock first** | gated on a blocker | **Refuse.** Name the blocker and its owner. Tasks created under a blocked feature cannot run. |
|
|
66
66
|
| **T4 — stale-done** | post-sync status would be `done` | **Refuse.** Route to `/sp:dev-wrapall --feature <id>` or the sync-first block; the work is finished, not startable. |
|
|
67
67
|
|
|
68
|
-
### The confirmation
|
|
68
|
+
### The confirmation — interactive by default, auto-accepted under `--auto`
|
|
69
69
|
|
|
70
70
|
| Rule | Detail |
|
|
71
71
|
| --- | --- |
|
|
72
|
-
| Default offer | The rank-1 candidate.
|
|
73
|
-
| `--task <feature-id>` | An explicit id skips the *default-offer* step.
|
|
74
|
-
| `--auto` |
|
|
75
|
-
|
|
|
76
|
-
| Refusal | Declining ends the run at the report. Nothing is written. |
|
|
72
|
+
| Default offer | The rank-1 candidate. Without `--auto`, the operator may confirm it, name another candidate from the report, or decline. |
|
|
73
|
+
| `--task <feature-id>` | An explicit id becomes the offered target (skips the *default-offer* step). Without `--auto` it still requires confirm; with `--auto` the named id is auto-accepted. |
|
|
74
|
+
| `--auto` | **Two effects:** (1) auto-accept the offered target — rank-1 for bare `--task`, or the explicit `--task <feature-id>` — without a HITL pause; (2) forward into the dispatched children (`dev-plan --auto`, `dev-refineall --auto`). Passing `--auto` is operator **pre-consent** to take the ranking's recommendation (streamline path); it does **not** invent a different target, and it does **not** bypass T2/T4 refuse or invalid-AC stop. Without `--task`, `--auto` is a no-op (ranking-only has no HITL). |
|
|
75
|
+
| Report the accept | When `--auto` accepts, print a one-line note: `auto-accepted target <id> (tier <Tn>) via --auto` so the transcript records the decision. |
|
|
76
|
+
| Refusal | Declining (interactive path only) ends the run at the report. Nothing is written. |
|
|
77
|
+
|
|
78
|
+
**Why this is not a Principle #5 taste auto-click.** The ranking already produced the recommendation;
|
|
79
|
+
`--auto` only skips the *proceed-with-offer* pause. Overriding the ranking (picking a non-offered
|
|
80
|
+
candidate) still requires the interactive confirm path. Architecture / design-approval taste gates
|
|
81
|
+
inside dispatched children remain governed by their own contracts (`--approve-taste` where applicable).
|
|
77
82
|
|
|
78
83
|
### What `--task` does not change
|
|
79
84
|
|
|
@@ -89,4 +94,4 @@ adds one gated path to `docs/tasks*/`, through commands that own their own gates
|
|
|
89
94
|
| Defect proposals | stdout; optionally appended to `docs/plans/feature-tree-restructure-map.md` |
|
|
90
95
|
| "Sync first" block | top of report when the dry-run proposes frontier changes |
|
|
91
96
|
| Winner handoff | printed `/sp:dev-next <id>` hint — operator runs it |
|
|
92
|
-
| `--task` dispatch | after
|
|
97
|
+
| `--task` dispatch | after confirm (interactive) or auto-accept (`--auto`): `/sp:dev-plan` and/or `/sp:dev-refineall`, which write `docs/tasks*/` through their own gates |
|
|
@@ -19,6 +19,11 @@ status on sync). Rules:
|
|
|
19
19
|
- Urgency signals premised on raw `status` (sunk-work decay, WIP pressure, staleness) are computed
|
|
20
20
|
only against the post-sync view — 0493 rejected all three as standalone signals; post-sync they
|
|
21
21
|
survive only as tie-break texture (see ranking-rubric.md).
|
|
22
|
+
- The dry run is captured **exactly once per run**; the captured result is the sole source of the
|
|
23
|
+
post-sync status view for protocol steps 1–4 (gating, roster completion, and signal derivation
|
|
24
|
+
all read the same in-memory capture). This is a prompt-run capture, not a cache/state file: the
|
|
25
|
+
run never issues a second `spur feature sync --all --dry-run --json` call, and no other verb
|
|
26
|
+
reproduces it in this run.
|
|
22
27
|
|
|
23
28
|
## §1 — Actionability gate (runtime citation, never restated)
|
|
24
29
|
|
|
@@ -32,11 +37,34 @@ Inputs per candidate feature:
|
|
|
32
37
|
spur task list --feature <id> --json
|
|
33
38
|
```
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
`task list --feature` is **active-folder-only**: it enumerates tasks in the active task folder
|
|
41
|
+
(`.spur/config.yaml`) and omits linked tasks archived in the other configured folders. Apply B3 over
|
|
42
|
+
that list. **Zero actionable tasks ⇒ gated, not ranked.** Record the gating
|
|
36
43
|
reason verbatim for the report's gated list: `all tasks terminal` / `blocked: <task wbs> — <reason>`
|
|
37
44
|
/ `no tasks`. A blocked task with no corpus dependency is an **external** block (approval, trigger) —
|
|
38
45
|
report it as such; it is not satisfiable by ranking other work first.
|
|
39
46
|
|
|
47
|
+
**Complete the roster before declaring terminal or empty.** If the active view yields no B3
|
|
48
|
+
frontier candidate and the tentative reason is `all tasks terminal` or `no tasks`, the active view
|
|
49
|
+
is not authoritative — a frontier task may be archived outside it. Run the fallback once:
|
|
50
|
+
|
|
51
|
+
1. Consult the §0 capture (the run's single `spur feature sync --all --dry-run --json` result) for
|
|
52
|
+
the feature's row as an **anomaly hint** only: it may flag the feature without naming a WBS. The
|
|
53
|
+
sync reason is never treated as a WBS source — no WBS is ever inferred from sync prose.
|
|
54
|
+
2. Scan the whole corpus for linked tasks:
|
|
55
|
+
```bash
|
|
56
|
+
rg -l '^feature_id: "?<id>"?$' docs/tasks*/
|
|
57
|
+
```
|
|
58
|
+
Corpus ids are `[A-Z][0-9]+`-shaped, so `<id>` is regex-safe as-is; escape metacharacters if a
|
|
59
|
+
non-conforming id ever appears.
|
|
60
|
+
3. Parse the leading WBS from each matched basename; resolve every corpus-only WBS (not present in
|
|
61
|
+
the active list) with `spur task show <wbs> --json`.
|
|
62
|
+
4. Union the active-list records with the resolved corpus records, deduplicate by WBS, and reapply
|
|
63
|
+
runtime B3 to the complete set.
|
|
64
|
+
5. Record the gating reason from the complete roster. If the union exposes a blocked task that the
|
|
65
|
+
active view omitted, the classification is `blocked: <task wbs> — <reason>` — never `all tasks
|
|
66
|
+
terminal` — with the blocker text taken from the resolved task body, not from sync prose.
|
|
67
|
+
|
|
40
68
|
## §2 — The four surviving signals
|
|
41
69
|
|
|
42
70
|
0493 measured eight candidate signals over this corpus; exactly four discriminate. Derivation
|
|
@@ -44,11 +72,20 @@ commands (per candidate feature `<id>`):
|
|
|
44
72
|
|
|
45
73
|
| Signal | Derivation | Notes |
|
|
46
74
|
| --- | --- | --- |
|
|
47
|
-
| **AC coverage** (readiness proxy) | `spur feature show <id> --json` → count `Scenario:` in body; `spur feature check <id> --json` for validity findings | 0 scenarios ⇒ "specify next", not "work next" (routes toward B4/B5 territory; see handoff-routing.md) |
|
|
75
|
+
| **AC coverage** (readiness proxy) | `spur feature show <id> --json` → count `Scenario:` in the frozen response's `.content` (the JSON carries the full body as `.content`); `spur feature check <id> --json` for validity findings | 0 scenarios ⇒ "specify next", not "work next" (routes toward B4/B5 territory; see handoff-routing.md) |
|
|
48
76
|
| **Churn exposure** (urgency proxy — WSJF cost-of-delay, numerator only) | `git rev-list --count --since="<40 days ago>" HEAD -- <dirs the feature's scope touches>` | 40d window is 0493's measured default; tune on dogfood. Scope = the paths named in the feature's Goal/Scope |
|
|
49
77
|
| **Dogfood proximity** (compound leverage) | `rg -c 'plugins/sp | apps/cli | task-pipeline | sp:' docs/features/<id>_*.md` + child task bodies | Degenerate-high in this harness (everything touches itself); discriminates mainly at **zero** — a 0-hit feature is "specify, don't ship" |
|
|
50
78
|
| **Authority pull** (declared intent) | `rg -n '\b<id>\b' docs/02_ROADMAP.md docs/00_ADR.md` | Presence is positive evidence; absence is not negative |
|
|
51
79
|
|
|
80
|
+
**Freeze each candidate input once.** Per candidate `<id>`, capture at most one
|
|
81
|
+
`spur feature show <id> --json` and at most one `spur feature check <id> --json`; reuse those
|
|
82
|
+
captures wherever the four-signal pass needs feature metadata, body, or AC validity. Count
|
|
83
|
+
`Scenario:` in the frozen show response's `.content` — the body is carried as `.content`, so no
|
|
84
|
+
`.filePath` re-read is required (read the file only when the response does not carry the corpus text
|
|
85
|
+
needed). No signal re-invokes a frozen capture. Churn, dogfood, and authority pull continue using
|
|
86
|
+
their own prescribed `git`/`rg` derivations above — they do not derive from the feature show/check
|
|
87
|
+
captures.
|
|
88
|
+
|
|
52
89
|
**Degenerate-spread rule.** After deriving a signal across the candidate set, check its spread. One
|
|
53
90
|
dominant value (as `priority` was at 76% P2) ⇒ the signal does not discriminate on this frontier:
|
|
54
91
|
report it as **rejected with its measured spread** for this run, and proceed without it. A rejected
|
|
@@ -23,6 +23,7 @@ that before using `run` for fan-out dispatch.
|
|
|
23
23
|
| ---- | ------- | --------- |
|
|
24
24
|
| `run <prompt>` | Execute a prompt or slash command via a coding agent | `--agent <name>` `--model <name>` `--mode <mode>` `--continue` `--cwd <path>` `--drain` `--json` |
|
|
25
25
|
| `loop` | Persistent self-draining inbox loop for a team member (supervisor-managed) | `--agent <id>` `--poll <ms>` |
|
|
26
|
+
| `wait <specId>` | Identity-pinned wait for an occupant run to reach a lifecycle state (G4 wave 2) | `--run <runId>` `--until <state>...` `--timeout <ms>` `--json` |
|
|
26
27
|
| `list` | List detected coding agents, or team agent specs with `--specs` | `--specs` `--json` |
|
|
27
28
|
| `doctor [agent]` | Check agent readiness | `--json` |
|
|
28
29
|
| `create <id>` | Write a team agent spec to `.spur/agents/<id>.yaml` | `--type` `--tags` `--model` `--autonomy` `--system-prompt` `--name` `--workspace` `--purpose` `--auto-start` `--no-identity-preamble` `--json` |
|
|
@@ -46,7 +47,7 @@ through a coding agent as an external process, producing a persisted run record
|
|
|
46
47
|
### Flags
|
|
47
48
|
|
|
48
49
|
| Flag | Purpose |
|
|
49
|
-
|
|
50
|
+
| ------ | --------- |
|
|
50
51
|
| `--agent <name>` | Agent name or `auto`. Selects which installed coding agent executes the prompt. |
|
|
51
52
|
| `--model <name>` | Agent model argument (e.g. `o3`, `sonnet`). Passed through to the agent's model flag. |
|
|
52
53
|
| `--mode <mode>` | Agent output mode: `text` or `json`. |
|
|
@@ -96,6 +97,38 @@ under supervision.
|
|
|
96
97
|
The loop runs until `SIGINT` / `SIGTERM`. Each iteration: check inbox -> if messages, drain each
|
|
97
98
|
into `run` with `--drain` -> else sleep for `--poll` ms.
|
|
98
99
|
|
|
100
|
+
## `wait` - identity-pinned occupant wait (G4 wave 2)
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
spur agent wait reviewer # default --until idle
|
|
104
|
+
spur agent wait reviewer --run R3 --until invoke-exit
|
|
105
|
+
spur agent wait reviewer --until working --until invoke-exit --timeout 30000 --json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`wait` pins an occupant's identity (`specId` + `runId` + `generation`) from the snapshot at wait
|
|
109
|
+
start, then polls until the first satisfied `--until` (OR). `--run` pins an explicit run; default
|
|
110
|
+
is the spec's latest run. Replacement, generation bump, or disappearance fails fast; a non-working
|
|
111
|
+
occupant that makes no progress inside the stall budget fails `wait_stalled`.
|
|
112
|
+
|
|
113
|
+
### Flags
|
|
114
|
+
|
|
115
|
+
| Flag | Purpose |
|
|
116
|
+
| ------ | --------- |
|
|
117
|
+
| `--run <runId>` | Pin a specific run id (default: the spec's latest run). |
|
|
118
|
+
| `--until <state>` | Lifecycle state to wait for (repeatable OR): `idle` \| `working` \| `invoke-exit` \| `blocked`. Default `idle`. |
|
|
119
|
+
| `--timeout <ms>` | Caller deadline. Undefined = no deadline (stall budget still applies). |
|
|
120
|
+
| `--json` | `{ satisfied, pin }` on success; `{ error: { code, message } }` on failure. |
|
|
121
|
+
|
|
122
|
+
### Exit codes + error envelope
|
|
123
|
+
|
|
124
|
+
| Code | Exit | Meaning |
|
|
125
|
+
| ------ | ------ | --------- |
|
|
126
|
+
| `occupant_gone` | 1 | No occupant for the specId, or it disappeared mid-wait. |
|
|
127
|
+
| `run_replaced` | 1 | The pinned run was replaced or its generation bumped. |
|
|
128
|
+
| `wait_stalled` | 1 | Non-working occupant, no progress within `min(timeout, 5000)ms`. |
|
|
129
|
+
| `timeout` | 1 | Caller `--timeout` elapsed (or aborted via SIGINT). |
|
|
130
|
+
| `usage` | 2 | Invalid flags, or `--until blocked` as the sole target (no first-class signal in wave 2). |
|
|
131
|
+
|
|
99
132
|
## `list` - detected agents and team specs
|
|
100
133
|
|
|
101
134
|
```bash
|
|
@@ -132,7 +165,7 @@ agent loop` can self-drain its inbox.
|
|
|
132
165
|
### Flags
|
|
133
166
|
|
|
134
167
|
| Flag | Purpose |
|
|
135
|
-
|
|
168
|
+
| ------ | --------- |
|
|
136
169
|
| `--type <agent-type>` | Agent spec type (e.g. `claude`, `codex`, `omp`). |
|
|
137
170
|
| `--tags <a,b>` | Comma-separated team identity tags (e.g. `team:alpha,role:worker`). |
|
|
138
171
|
| `--model <name>` | Agent model argument. |
|
|
@@ -19,7 +19,7 @@ use it well*.
|
|
|
19
19
|
|
|
20
20
|
| Verb | Purpose | Key flags |
|
|
21
21
|
| ---- | ------- | --------- |
|
|
22
|
-
| `send <body>` | Enqueue a message for an agent | `--to <id>` `--from <id>` `--json` |
|
|
22
|
+
| `send <body>` | Enqueue a message for an agent | `--to <id>` `--from <id>` `--wait` `--until <state>` `--timeout <ms>` `--json` |
|
|
23
23
|
| `inbox` | List messages addressed to an agent | `--agent <id>` `--json` |
|
|
24
24
|
| `reply <msg-id> <body>` | Thread a reply to a message | `--json` |
|
|
25
25
|
| `watch` | Follow an agent inbox - surface new messages as they arrive | `--agent <id>` `--interval <ms>` `--json` |
|
|
@@ -33,18 +33,29 @@ invalid usage.
|
|
|
33
33
|
spur message send "Please review PR 42" --to reviewer
|
|
34
34
|
spur message send "Task 0040 is blocked" --to worker-1 --from operator
|
|
35
35
|
spur message send "Done" --to planner --json
|
|
36
|
+
spur message send "Review 0042" --to reviewer --wait --until invoke-exit --timeout 30000
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
Enqueues a durable message addressed to `--to <id>`. The recipient drains it on its next `agent run
|
|
39
40
|
--drain` or `agent loop` iteration. `--from` defaults to `operator`.
|
|
40
41
|
|
|
42
|
+
`--wait` snapshots the recipient occupant **before** enqueue, then waits on that pin in the same CLI
|
|
43
|
+
process (G4 wave 2 / ADR-057). Default `--until invoke-exit`. A later occupant cannot satisfy the
|
|
44
|
+
wait; enqueue is **not** rolled back if the wait later fails.
|
|
45
|
+
|
|
41
46
|
### Flags
|
|
42
47
|
|
|
43
48
|
| Flag | Purpose |
|
|
44
|
-
|
|
49
|
+
| ------ | --------- |
|
|
45
50
|
| `--to <id>` | **Required.** Recipient agent id. |
|
|
46
51
|
| `--from <id>` | Sender id (default: `operator`). |
|
|
47
|
-
| `--
|
|
52
|
+
| `--wait` | Block until the recipient reaches `--until` (snapshots occupant before send). |
|
|
53
|
+
| `--until <state>` | Wait target: `injected` \| `invoke-exit` (repeatable OR). Default `invoke-exit`. |
|
|
54
|
+
| `--timeout <ms>` | Caller deadline in milliseconds. |
|
|
55
|
+
| `--json` | Output machine-readable JSON (`{ msgId, toId, status, wait: { satisfied } }`). |
|
|
56
|
+
|
|
57
|
+
`--wait` failures use the same error codes as `agent wait`: `occupant_gone`, `run_replaced`,
|
|
58
|
+
`wait_stalled`, `timeout` (exit 1).
|
|
48
59
|
|
|
49
60
|
## `inbox` - list addressed messages
|
|
50
61
|
|
|
@@ -79,7 +90,7 @@ lines.
|
|
|
79
90
|
### Flags
|
|
80
91
|
|
|
81
92
|
| Flag | Purpose |
|
|
82
|
-
|
|
93
|
+
| ------ | --------- |
|
|
83
94
|
| `--agent <id>` | **Required.** Agent id to watch. |
|
|
84
95
|
| `--interval <ms>` | Poll interval in milliseconds (default: `2000`). Must be a positive integer; exit `2` otherwise. |
|
|
85
96
|
| `--json` | Output one JSON object per new message. |
|
|
@@ -76,7 +76,22 @@ Once registered, any definition can use `kind: send-email` (in `onEnter`/`onExit
|
|
|
76
76
|
|
|
77
77
|
## Extension loading (trust-gated)
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
A workflow YAML can declare extension modules next to the workflow file itself:
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
name: ext-flow
|
|
83
|
+
kind: state-machine
|
|
84
|
+
extensions:
|
|
85
|
+
actions: ["./exts/audit.ts"] # default-exports { name, actions: [...] }
|
|
86
|
+
guards: ["./exts/flag.ts"] # default-exports { name, guards: [...] }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`spur workflow validate`, `run` (incl. `--dry-run`), and `continue` load YAML-declared extensions
|
|
90
|
+
onto the engine host before any step — the declaration itself is the `allowExtensions` gate (0533/D4).
|
|
91
|
+
Paths are relative to the workflow file; absolute paths and `..` traversal are rejected with no
|
|
92
|
+
import, and a missing or mis-shaped module fails the command before any step.
|
|
93
|
+
|
|
94
|
+
For library callers, use `loadWorkflowExtensionsIntoHost`. The trust gate
|
|
80
95
|
is **fail-closed**: `allowExtensions` defaults to `false`, and a declared-but-not-allowed extension
|
|
81
96
|
**throws before any import** — never silently dropped.
|
|
82
97
|
|
|
@@ -117,8 +132,8 @@ reach for the library (`@gobing-ai/ts-dual-workflow-engine`) directly when you n
|
|
|
117
132
|
| ---------- | --- | ------- |
|
|
118
133
|
| Validate / run / list definitions | ✅ | ✅ |
|
|
119
134
|
| Trace run history / continue HITL / cancel / clean orphans | ✅ | ✅ |
|
|
120
|
-
| Custom action/guard runners | ✅ (built-ins
|
|
121
|
-
| Extension modules |
|
|
135
|
+
| Custom action/guard runners | ✅ (built-ins + YAML extensions, 0533/D4) | ✅ (`registerAction`/`registerGuard`) |
|
|
136
|
+
| Extension modules | ✅ (YAML `extensions.actions`/`extensions.guards`, 0533/D4) | ✅ (`loadWorkflowExtensionsIntoHost`) |
|
|
122
137
|
| DB persistence + programmatic `listRuns()` | (via configured adapter + `trace`) | ✅ (`DbWorkflowPersistenceAdapter`) |
|
|
123
138
|
| Event-bus observability (progress bars, dashboards) | partial (CLI step reporter on sync human runs) | ✅ (`WorkflowEngineEvents` via `WorkflowRunOptions.events`) |
|
|
124
139
|
| OTel traces / structured logs | (emitted) | ✅ (`RunLifecycle`) |
|
|
@@ -281,6 +281,7 @@ redirecting `agent.run` stages (ADR-047).
|
|
|
281
281
|
both scopes (lists what would be removed, writes nothing). `--json` returns
|
|
282
282
|
`{ olderThanMinutes, dryRun, cleaned, logs: { retentionDays, dryRun, reclaimed, failures } }` (with
|
|
283
283
|
`--logs`, the reclamation object alone).
|
|
284
|
+
|
|
284
285
|
## Behavior
|
|
285
286
|
|
|
286
287
|
This skill behaves as an **author** (choose mode → write a correct definition → prove it runs) feeding
|
|
@@ -302,8 +303,11 @@ the workflow's actions (`shell`, custom runners) do that; this skill builds and
|
|
|
302
303
|
`.spur/workflows/basic.yaml` and `task-pipeline.yaml` quality-gate hop).
|
|
303
304
|
4. **`env.allow` is an allowlist.** `${env.X}` resolves only if `X` is listed under `env.allow`;
|
|
304
305
|
otherwise it resolves empty. A workflow that "loses" an environment value usually forgot to allow it.
|
|
305
|
-
5. **Extensions are fail-closed.**
|
|
306
|
-
|
|
306
|
+
5. **Extensions are fail-closed.** The CLI loads YAML-declared extension modules itself
|
|
307
|
+
(`extensions.actions` / `extensions.guards`, resolved relative to the workflow file) — the
|
|
308
|
+
declaration is the gate (0533/D4). A declared-but-missing or mis-shaped module, an absolute
|
|
309
|
+
path, or `..` traversal throws **before any import** — never silently dropped. Library callers
|
|
310
|
+
using `loadWorkflowExtensionsIntoHost` must pass `allowExtensions: true` explicitly. Inline
|
|
307
311
|
`host.registerAction`/`registerGuard` need no flag; only the module loader is gated.
|
|
308
312
|
6. **A failed run does not throw.** Action/guard failures come back as `WorkflowRunResult` with
|
|
309
313
|
`status: 'failed'`, preserving the run record. Read the trace; don't expect an exception. (Definition
|
|
@@ -341,11 +345,13 @@ the workflow's actions (`shell`, custom runners) do that; this skill builds and
|
|
|
341
345
|
## Platform Notes
|
|
342
346
|
|
|
343
347
|
### Claude Code
|
|
348
|
+
|
|
344
349
|
Run `spur workflow` via the Bash tool. During development the CLI entry is a `.ts` file that runs only
|
|
345
350
|
under Bun: `bun run apps/cli/src/index.ts workflow validate <file> --json`. The installed `spur` binary
|
|
346
351
|
works once built.
|
|
347
352
|
|
|
348
353
|
### Codex / OpenClaw / OpenCode / Antigravity
|
|
354
|
+
|
|
349
355
|
Run `spur workflow ...` via the Bash tool; parse `--json` output programmatically. Arguments are passed
|
|
350
356
|
directly on the command line.
|
|
351
357
|
|
|
@@ -203,10 +203,11 @@ behavior:
|
|
|
203
203
|
|
|
204
204
|
- `dev-brainstorm` `[<feature-id>]` — **creates** one task from the chosen approach, landing at
|
|
205
205
|
`todo` ready for refine. Optional feature id scopes it.
|
|
206
|
-
- `dev-find-next` `[<feature-id>]` — after
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
206
|
+
- `dev-find-next` `[<feature-id>]` — after confirm, dispatches the planning half on the ranked
|
|
207
|
+
winner (`/sp:dev-plan` to decompose, then `/sp:dev-refineall --depth ready` to freeze
|
|
208
|
+
implement-ready). Creates no task itself. Interactive by default; with `--auto`, auto-accepts the
|
|
209
|
+
offered target (rank-1 or the explicit id) and forwards `--auto` to the children. Optional feature
|
|
210
|
+
id names the target instead of offering rank 1.
|
|
210
211
|
- `dev-debug` `[<wbs>]` — **attaches** findings to an existing task. Optional WBS names it.
|
|
211
212
|
- `dev-dogfood` (no value) — **records** run outcomes against the task under test.
|
|
212
213
|
|