@gobing-ai/spur 0.3.42 → 0.3.43
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/workflows/task-pipeline.yaml +10 -0
- package/package.json +9 -9
- package/plugins/sp/commands/dev-run.md +3 -3
- package/plugins/sp/commands/dev-runall.md +7 -4
- package/plugins/sp/commands/dev-wrap.md +21 -3
- package/plugins/sp/commands/dev-wrapall.md +21 -3
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/skills/code-implementation/SKILL.md +27 -0
- package/plugins/sp/skills/issue-finding/SKILL.md +21 -3
- package/plugins/sp/skills/issue-finding/references/session-formats.md +30 -0
- package/plugins/sp/skills/next-router/references/routing-table.md +2 -2
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +9 -0
- package/plugins/sp/skills/spur-cli/references/tasks.md +3 -1
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +22 -6
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +13 -13
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +66 -3
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +4 -2
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +1 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +43 -11
- package/spur.js +383 -224
|
@@ -64,6 +64,30 @@ function normalizeArgs(raw: Args): Args {
|
|
|
64
64
|
- If `--feature FOO` is present and `--tasks` is absent, treat the effective selector as `feature:FOO`.
|
|
65
65
|
- If both are present, `--tasks` wins (with a one-line note in the batch report).
|
|
66
66
|
|
|
67
|
+
**Feature-derived strict preflight (R2, task 0510).** After normalization, if the **effective
|
|
68
|
+
selector** is `feature:<id>` (whether via `--tasks feature:<id>` or the `--feature <id>` sugar),
|
|
69
|
+
run a source-local strict feature check **once** before any task-list resolution, freeze,
|
|
70
|
+
dependency resolution, or worktree task execution:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# monorepo source; installed projects use their resolved `spur` binary
|
|
74
|
+
bun run apps/cli/src/index.ts feature check <id> --strict --json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **Abort shape.** A non-zero check aborts the batch immediately: verdict `aborted`, zero attempted
|
|
78
|
+
tasks, and the structured feature findings (the `--json` finding list) reported verbatim. This is
|
|
79
|
+
the same abort vocabulary as cycle / unknown selector (Step 4/Step 5).
|
|
80
|
+
- **Exactly once.** The check runs once per batch, before `task list`; it is not re-run per task.
|
|
81
|
+
- **Non-feature exclusion.** Explicit WBS lists, status pseudo-lists, and `ready` selectors add no
|
|
82
|
+
feature check — only an effective `feature:<id>` selector is feature-derived. When explicit
|
|
83
|
+
`--tasks` overrides `--feature`, the effective selector is not feature-derived, so no check runs.
|
|
84
|
+
- **Why.** `FeatureCheckService` emits `L3.scope-delineation` (Scope lacking an In/Out split) as a
|
|
85
|
+
**warning**; feature-scoped batches never ran a strict check before freezing, so the late feature
|
|
86
|
+
transition became the first blocking check. A selector-local strict preflight catches a known
|
|
87
|
+
strict finding before any task pipeline action without changing corpus-wide severity.
|
|
88
|
+
- **Scope.** This preflight is advisory to severity policy: it does not alter `FeatureCheckService`,
|
|
89
|
+
`L3.scope-delineation` severity, `feature sync`, or batch-create.
|
|
90
|
+
|
|
67
91
|
`--tasks <value>` (or the effective value after normalization) resolves to a frozen set of task WBS numbers. Resolution happens **once, at
|
|
68
92
|
kickoff** — the driver never re-queries `spur task list` to recompute membership mid-batch (R2.1).
|
|
69
93
|
|
|
@@ -71,7 +95,7 @@ kickoff** — the driver never re-queries `spur task list` to recompute membersh
|
|
|
71
95
|
|---|---|---|
|
|
72
96
|
| Explicit WBS list | `^[0-9, ]+$` | Split on comma; validate each token is a 4-digit WBS; collect the explicit set. (R1.1) |
|
|
73
97
|
| `feature:<id>` (via `--tasks` or `--feature <id>`) | literal `feature:` prefix or `--feature` flag | `spur task list --feature <id> --json`; collect `wbs` from each row. The `--feature` flag is sugar that becomes `--tasks feature:<id>` at the command layer. (R1.3) |
|
|
74
|
-
| `ready` | literal `ready` | Resolve the union of `spur task list --status todo --json` + `spur task list --status backlog --json`, drop tasks with open children (R1.5, umbrella-parent exclusion below), then keep only tasks whose every `dependencies[]` entry resolves to `status == done` (via `spur task show <dep> --json`). Report each excluded task with its unmet dependency. (R1.4) |
|
|
98
|
+
| `ready` | literal `ready` | Resolve the union of `spur task list --status todo --json` + `spur task list --status backlog --json`, drop tasks with open children (R1.5, umbrella-parent exclusion below), then keep only tasks whose every `dependencies[]` entry resolves to `status == done` (via `spur task show <dep> --json | jq '{wbs, status, dependencies, feature_id}'` — R5 metadata-only). Report each excluded task with its unmet dependency. (R1.4) |
|
|
75
99
|
| Status pseudo-list | `todo` \| `backlog` \| `wip` \| `blocked` \| `testing` | `spur task list --status <value> --json`; collect `wbs` from each row. (R1.2) |
|
|
76
100
|
| *(else)* | no match | Error: "unknown selector `<value>`" — list the valid forms and halt before running anything. |
|
|
77
101
|
|
|
@@ -113,7 +137,7 @@ edge `A → B` means "A depends on B" (B must complete before A runs). Only edge
|
|
|
113
137
|
### 2.3 Out-of-set dependency resolution
|
|
114
138
|
|
|
115
139
|
For each dependency edge to a task **outside** the frozen set, resolve its current status via
|
|
116
|
-
`spur task show <dep-wbs> --json
|
|
140
|
+
`spur task show <dep-wbs> --json | jq '{wbs, status, dependencies, feature_id}'` (R5 metadata-only):
|
|
117
141
|
|
|
118
142
|
- status `done` → edge satisfied, drop it from the graph (R2.5). The dependent is unblocked.
|
|
119
143
|
- status ≠ `done` → mark the dependent **blocked**. Transitively mark its in-set descendants blocked
|
|
@@ -211,7 +235,7 @@ step.
|
|
|
211
235
|
```bash
|
|
212
236
|
RUN=$(spur workflow run .spur/workflows/task-pipeline.yaml \
|
|
213
237
|
--vars '{"wbs":"<wbs>","profile":"auto","agent":"claude"}' --async --json | jq -r '.runId')
|
|
214
|
-
spur workflow trace "$RUN" --json # poll until status is terminal (done/failed)
|
|
238
|
+
spur workflow trace "$RUN" --json | jq '{runId, status, terminalState}' # poll until status is terminal (done/failed)
|
|
215
239
|
```
|
|
216
240
|
|
|
217
241
|
### 3.2 Flag → `--vars` passthrough (R4.2, R4.3)
|
|
@@ -262,6 +286,7 @@ in next-router; this only maps status → primary TABLE A hop for recovery.
|
|
|
262
286
|
|
|
263
287
|
### 3.3c Bounded feature-sync retry suppression (task 0411)
|
|
264
288
|
|
|
289
|
+
|
|
265
290
|
During a batch, the per-task `record` step and the wrap-up `feature-transition` step each invoke
|
|
266
291
|
feature status sync. When a feature is L4-gate-blocked (e.g. not all linked tasks are `done`), the
|
|
267
292
|
identical blocked proposal repeats on every call with no intervening input change — in the H9
|
|
@@ -295,6 +320,42 @@ pipeline's `record` step and the wrap-up's `feature-transition` step. The driver
|
|
|
295
320
|
The only observable difference is fewer redundant `feature sync` invocations and a one-line
|
|
296
321
|
`feature-sync-bounded:` annotation on stderr when a duplicate is suppressed.
|
|
297
322
|
|
|
323
|
+
### 3.4 Metadata-only host controller (R5, task 0510)
|
|
324
|
+
|
|
325
|
+
The batch **orchestrator** reads status, ordering, and terminal state — never task bodies or trace
|
|
326
|
+
output. Task `content`, section bodies (Solution/Testing/Review), and full workflow `output` are
|
|
327
|
+
stage/subagent data and must not enter the host context on the green path; the controller that
|
|
328
|
+
dispatches native subagents must not defeat that isolation by ingesting the very bodies the
|
|
329
|
+
subagents are meant to hold (task 0508's dispatch contract is preserved unchanged).
|
|
330
|
+
|
|
331
|
+
**Green-path projections — every controller-side read is projected to metadata:**
|
|
332
|
+
|
|
333
|
+
- `task show --json` reads pipe to `{wbs, status, dependencies, feature_id}` only:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
spur task show <wbs> --json | jq '{wbs, status, dependencies, feature_id}'
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Use this shape for out-of-set dependency resolution (Step 2.3), the `ready` selector's
|
|
340
|
+
dep-status lookups (Step 1), and any other controller-side `task show`. A status-only lookup may
|
|
341
|
+
narrow further (`| jq '.status'`), but never widen.
|
|
342
|
+
|
|
343
|
+
- Green-path trace observation projects to `{runId, status, terminalState}` only:
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
spur workflow trace "$RUN" --json | jq '{runId, status, terminalState}'
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
The controller decides continue/halt from `status`/`terminalState` (ADR-044: judge a run by
|
|
350
|
+
`status === 'done'`, never by string-matching a `finalState` name) plus the bounded verdict
|
|
351
|
+
artifact `.spur/run/<wbs>-verdict.json`. It never streams or re-reads a full trace merely to
|
|
352
|
+
summarize status.
|
|
353
|
+
|
|
354
|
+
**Failure-path reads are bounded.** On a failed/blocked task, request only the terminal error and
|
|
355
|
+
the minimal anchor set the batch report needs (e.g. the blocking finding line, the unmet-dep WBS,
|
|
356
|
+
the verdict line) — never the entire trace. If a fuller trace is needed for diagnosis, that read
|
|
357
|
+
belongs to a subagent or the operator, not to the batch controller's report loop.
|
|
358
|
+
|
|
298
359
|
## Step 4 — Failure policy (R3)
|
|
299
360
|
|
|
300
361
|
### 4.1 Stop-the-batch (default) (R3.1)
|
|
@@ -683,6 +744,8 @@ command doc so it does not read as a bug.
|
|
|
683
744
|
| R5.1 (orchestrator boundary) | "Zero engine code" preamble + Step 3 |
|
|
684
745
|
| R5.2 (structured batch report) | Step 5 |
|
|
685
746
|
| 0411 (bounded feature-sync retry suppression) | Step 3.3c — wrapper lives in pipeline `record` + wrap-up `feature-transition`; driver unchanged |
|
|
747
|
+
| 0510 R2 (feature-derived strict preflight) | Step 1 — "Feature-derived strict preflight (R2, task 0510)" |
|
|
748
|
+
| 0510 R5 (metadata-only host controller) | Step 3.4 + projected `task show` / trace snippets in Step 1, 2.3, 3.1 |
|
|
686
749
|
|
|
687
750
|
## Parallel Execution
|
|
688
751
|
|
|
@@ -52,8 +52,10 @@ one thing and yields, so the **pipeline (not the agent) owns the loop**.
|
|
|
52
52
|
|
|
53
53
|
Interactive omit/`inline` executes these model stages through the
|
|
54
54
|
[inline pipeline driver](inline-pipeline-driver.md) in the host session and records stage/session
|
|
55
|
-
provenance.
|
|
56
|
-
|
|
55
|
+
provenance. The host is the controller; eligible `agent.run` stages may dispatch once to a native
|
|
56
|
+
subagent (task 0508), with host fallback and no post-dispatch replay — see the driver reference.
|
|
57
|
+
`--agent <name|auto>`, parallel batches, and headless workflow invocation select
|
|
58
|
+
the existing subprocess actions. Direct invocations of the same dev operations remain inline by
|
|
57
59
|
default. See the [inline-default execution-surface contract](cross-cutting.md#inline-default-execution-surface).
|
|
58
60
|
|
|
59
61
|
> **Single-run & parse discipline (suite run cost control).** Run full quality/test suites (`bun run check` / `spur-check`) at most ONCE per task iteration (task 0436 R2). Parse failure details from the single retained command output rather than re-running full suites repeatedly to inspect errors. Re-run targeted/narrow test files (e.g. `bun test <file> --test-name-pattern <pattern>`) while iterating on fixes, and re-run the full suite only when all targeted fixes pass.
|
|
@@ -47,7 +47,7 @@ The value table below is the C3a cross-file parity surface (kept in lockstep wit
|
|
|
47
47
|
|
|
48
48
|
| Value | Who does the work | Derived surface |
|
|
49
49
|
| ------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
50
|
-
| `inline` (default when omitted) | Whoever is running this session (interactive) or `agent.default` (headless) | Interactive: inline
|
|
50
|
+
| `inline` (default when omitted) | Whoever is running this session (interactive) or `agent.default` (headless) | Interactive: inline — host-controlled, eligible model stages may use a native subagent (0508); headless: subprocess of `agent.default` |
|
|
51
51
|
| `auto` | Tier-resolved from the stage's `min_tier` + `fallback` | Subprocess |
|
|
52
52
|
| `<name>` | That coding agent or configured executor | Inline when it is the current session's agent; subprocess otherwise |
|
|
53
53
|
|
|
@@ -53,21 +53,53 @@ Action semantics come from the YAML and the workflow action contract:
|
|
|
53
53
|
actions/guards.
|
|
54
54
|
- `hitl.confirm` — under `profile=auto`, follow the YAML's auto-skip transition. Otherwise pause,
|
|
55
55
|
surface the prompt, and resume from the same state with the operator's answer.
|
|
56
|
-
- `agent.run` — execute the action's slash command
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
- `agent.run` — execute the action's slash command, native-subagent-first (task 0508). Do not call
|
|
57
|
+
`spur agent run` and do not re-enter `/sp:dev-run --mode full`. Preserve the YAML options: capture
|
|
58
|
+
`answerFile`; assert `expectFile`; enforce `requireDiff` against a pre-action git snapshot,
|
|
59
|
+
including the task-scope guard; honor declared error policy. `timeoutMs` is recorded as not
|
|
60
|
+
applicable because the host session has no independent kill boundary.
|
|
61
|
+
|
|
62
|
+
**Native-subagent dispatch (R2 eligibility, evaluated before each action):**
|
|
63
|
+
|
|
64
|
+
1. The invocation is one of the two interactive inline full-pipeline surfaces (`dev-run --mode full`
|
|
65
|
+
or sequential `dev-runall`, omit/`inline`).
|
|
66
|
+
2. The YAML action kind is `agent.run` and its input is a pure slash command. Shell, note, file,
|
|
67
|
+
guard, and operator-interaction actions remain host-executed.
|
|
68
|
+
3. The current state/action has no operator-confirmation action, `pause: true`, approve/taste/ask
|
|
69
|
+
decision, or other operator prompt.
|
|
70
|
+
4. The platform exposes a native subagent that shares the working tree and has read, write, shell,
|
|
71
|
+
and Spur task/run-artifact access.
|
|
72
|
+
|
|
73
|
+
All four pass → dispatch. Any pre-dispatch failure → execute the stage **once** in the host session.
|
|
74
|
+
No token estimate, stage-size threshold, model heuristic, or configuration switch is added.
|
|
75
|
+
|
|
76
|
+
**Dispatch and join:** before dispatch, capture the same pre-action git snapshot used by
|
|
77
|
+
`requireDiff` enforcement. Send only: the stage id, the YAML's exact pure slash command, and
|
|
78
|
+
`execution surface already resolved: native subagent; do not dispatch this stage again`. The WBS/path
|
|
79
|
+
already carried by the slash command is the handoff — do not paste task/session transcripts or embed
|
|
80
|
+
machine-specific session paths. Dispatch exactly one native subagent and wait for it; the inline FSM
|
|
81
|
+
must not advance actions or guards concurrently (one writer at a time). After join, validate
|
|
82
|
+
`answerFile`, `expectFile`, `requireDiff`, task scope, and the action's error policy from the shared
|
|
83
|
+
filesystem — a subagent success message is not evidence. On success append exactly:
|
|
63
84
|
|
|
64
85
|
```text
|
|
65
|
-
stage <id> executed
|
|
86
|
+
stage <id> executed via subagent <agent-id> (host session <session-id>)
|
|
66
87
|
```
|
|
67
88
|
|
|
68
|
-
|
|
69
|
-
the
|
|
70
|
-
|
|
89
|
+
Host fallback retains exactly `stage <id> executed inline in session <session-id>`. If launch fails
|
|
90
|
+
before the subagent starts, log the reason and use host fallback. If a started subagent fails or
|
|
91
|
+
leaves invalid artifacts, do **not** replay the stage in the host — follow the YAML error policy so
|
|
92
|
+
partial mutations are not duplicated.
|
|
93
|
+
|
|
94
|
+
**Host-owned interaction:** the host alone executes operator-confirmation actions, owns
|
|
95
|
+
`pause: true`, and surfaces approve/taste/ask decisions. A subagent that discovers missing authority
|
|
96
|
+
or an operator decision returns a blocker; the host pauses at the current state and presents it. The
|
|
97
|
+
subagent cannot approve, infer consent, or recursively invoke the full pipeline.
|
|
98
|
+
|
|
99
|
+
After every successful inline `agent.run` action append exactly one provenance line (inline or
|
|
100
|
+
subagent form above) to `.spur/run/<run-id>.log`, where `<id>` is the current YAML state id. Also
|
|
101
|
+
log start/failure and the ignored timeout value so an inline run remains auditable without
|
|
102
|
+
fabricating an `AgentRunTracedResult`.
|
|
71
103
|
|
|
72
104
|
Transition guards are not advisory. Execute the declared guard exactly, in order, with the same
|
|
73
105
|
resolved variables and artifacts. `--no-lifecycle` remains bookkeeping only; the YAML's task checks,
|