@gobing-ai/spur 0.3.77 → 0.3.80
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/templates/AGENTS.md +26 -23
- package/config/templates/docs/00_ADR.md +13 -23
- package/config/templates/docs/01_PRD.md +5 -2
- package/config/templates/docs/02_ROADMAP.md +9 -13
- package/config/templates/docs/03_ARCHITECTURE.md +2 -2
- package/config/templates/docs/04_DESIGN.md +12 -31
- package/config/templates/docs/05_FEATURES.md +6 -18
- package/config/templates/docs/99_PROJECT_CONSTITUTION.md +162 -394
- package/package.json +9 -9
- package/plugins/sp/README.md +12 -7
- package/plugins/sp/agents/super-reviewer.md +43 -8
- package/plugins/sp/commands/dev-refineall.md +1 -0
- package/plugins/sp/commands/dev-run.md +1 -0
- package/plugins/sp/commands/dev-runall.md +1 -0
- package/plugins/sp/commands/dev-verifyall.md +1 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/batch-preflight.mjs +173 -2
- package/plugins/sp/scripts/batch-preflight.ts +257 -2
- package/plugins/sp/scripts/verify-answer-lint.ts +32 -9
- package/plugins/sp/skills/conflict-finding/SKILL.md +6 -0
- package/plugins/sp/skills/daily-summary/SKILL.md +1 -1
- package/plugins/sp/skills/doc-evolve/SKILL.md +26 -40
- package/plugins/sp/skills/doc-evolve/references/operations.md +17 -30
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +17 -1
- package/plugins/sp/skills/spur-cli/references/tasks.md +31 -1
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +14 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +36 -3
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +12 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +17 -0
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +148 -17
- package/spur.js +1389 -615
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.80",
|
|
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.62",
|
|
57
|
+
"@gobing-ai/ts-ai-runner": "^0.4.62",
|
|
58
|
+
"@gobing-ai/ts-dual-workflow-engine": "^0.4.62",
|
|
59
|
+
"@gobing-ai/ts-infra": "^0.4.62",
|
|
60
|
+
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.62",
|
|
61
|
+
"@gobing-ai/ts-rule-engine": "^0.4.62",
|
|
62
|
+
"@gobing-ai/ts-runtime": "^0.4.62",
|
|
63
|
+
"@gobing-ai/ts-utils": "^0.4.62",
|
|
64
64
|
"@types/bun": "1.3.14",
|
|
65
65
|
"@types/figlet": "^1.7.0",
|
|
66
66
|
"@types/node-notifier": "8.0.5",
|
package/plugins/sp/README.md
CHANGED
|
@@ -171,10 +171,12 @@ Commands above are thin wrappers; the actual logic lives in `skills/`. The spine
|
|
|
171
171
|
dispatches five competency skills by function — design (`sp:sys-architecture`), decomposition
|
|
172
172
|
(`sp:spec-decomposition`), implementation (`sp:code-implementation`), testing (`sp:code-testing`),
|
|
173
173
|
and verification (`sp:code-verification`) — plus a CLI facade (`sp:spur-cli`, one reference per
|
|
174
|
-
`spur` noun) and standalone technique skills (`sp:next-router`, `sp:
|
|
175
|
-
`sp:
|
|
176
|
-
`sp:
|
|
177
|
-
`sp:
|
|
174
|
+
`spur` noun) and standalone technique skills (`sp:next-router`, `sp:next-feature`,
|
|
175
|
+
`sp:test-driven-development`, `sp:source-driven-development`, `sp:doubt-driven-development`,
|
|
176
|
+
`sp:brainstorm`, `sp:wayfinder`, `sp:sys-debugging`, `sp:code-review`, `sp:pr-reviewing`,
|
|
177
|
+
`sp:functional-review`, `sp:code-simplification`, `sp:code-improvement`, `sp:parallel-execution`,
|
|
178
|
+
`sp:branch-workflow`, `sp:doc-evolve`, `sp:dogfood-testing`, `sp:daily-summary`,
|
|
179
|
+
`sp:reverse-engineering`, `sp:history-anatomy`, `sp:issue-finding`, `sp:conflict-finding`,
|
|
178
180
|
`sp:indexed-context`, `sp:session-review`, `sp:redesign-web-ui`). See
|
|
179
181
|
[skills/spur-dev/SKILL.md](skills/spur-dev/SKILL.md)'s Step routing table for which skill owns which
|
|
180
182
|
pipeline step.
|
|
@@ -215,6 +217,7 @@ plugins/sp/
|
|
|
215
217
|
│ │ └── references/routing-table.md
|
|
216
218
|
│ ├── parallel-execution/ # Fan-out decision framework + patterns
|
|
217
219
|
│ │ └── references/{fan-out-patterns, result-synthesis}.md
|
|
220
|
+
│ ├── pr-reviewing/ # GitHub PR review loop backing /sp:dev-pr-review
|
|
218
221
|
│ ├── source-driven-development/ # Source-first API/contract verification (SKILL.md only)
|
|
219
222
|
│ ├── spec-decomposition/ # Feature/spec → task-batch competency
|
|
220
223
|
│ │ └── references/decomposition.md
|
|
@@ -255,6 +258,8 @@ plugins/sp/
|
|
|
255
258
|
├── agents/ # 4 specialist subagents (expert-spur, super-coder, super-planner, super-reviewer)
|
|
256
259
|
├── hooks/ # hooks.json + task-write-guard.{ts,test.ts} + context-{session-start,post-tool,session-stop}.ts
|
|
257
260
|
│ # + careful-guard.{ts,test.ts} + context-hooks.test.ts + token-estimate.test.ts
|
|
261
|
+
│ # + shared policy modules: agent-hint.ts, destructive-policy.{ts,test.ts}, task-file-policy.{ts,test.ts}
|
|
262
|
+
│ # + pi/guard-extension.{ts,test.ts} (plugin.json `extensions.pi` entry point)
|
|
258
263
|
├── scripts/ # Executable helpers, split from prompts (ADR-031) — validate-commands.ts (thin-wrapper validator), batch-preflight.ts + scripts/<skill>/
|
|
259
264
|
│ # (daily-summary: {daily-summary, logger}.ts; dogfood-testing: {detect-pipeline-driving, validate-report}.ts)
|
|
260
265
|
├── tests/ # Plugin tests — command-contract.test.ts + skill-structure.test.ts + batch-preflight.test.ts + per-skill suites
|
|
@@ -318,13 +323,13 @@ surface or run one workflow. All skills target the same five core platforms: `cl
|
|
|
318
323
|
| `daily-summary` | 1.0.0 | Daily summary report generator — orchestrates ccusage CLI + git history into structured markdown summaries |
|
|
319
324
|
| `doc-evolve` | 1.0 | Key-document evolution per `docs/99_PROJECT_CONSTITUTION.md` — drift audits, same-commit sync checks, frontmatter-contract verification, machine-appended lessons |
|
|
320
325
|
| `reverse-engineering` | 1.1 | Codebase analysis / HLD generation / audit — depth-driven reverse engineering with orthogonal mode, focus, and format controls; backs `/sp:dev-reverse` |
|
|
321
|
-
| `issue-finding` |
|
|
326
|
+
| `issue-finding` | 2.0 | Session-log forensics — multi-source discovery, bottleneck ranking, optional topic focus, CLI-gated fix task generation; **legacy path** — superseded by `history-anatomy` for indexed reporting; backs no current command; directly invocable as sp:issue-finding |
|
|
322
327
|
| `conflict-finding` | 1.0 | Authority-aware semantic audit — four-pillar (source/task/feature/authority) conflict discovery, claim-specific authority resolution, reproducible evidence, confirmed owner-routed remediation; backs `/sp:dev-find-conflict` |
|
|
323
328
|
| `next-feature` | 1.0 | Prompt-first feature frontier prioritizer — sync-first precondition, B3 actionability gate (cited, never restated), tiered rubric over measured signals, D1–D4 defect proposals conforming to the restructure map schema; backs `/sp:dev-find-next` |
|
|
324
329
|
| `pr-reviewing` | 1.0 | GitHub Codex PR review — PR prepare/reuse, `@codex review` request with per-HEAD dedupe, bounded polling, findings normalization, validated fix + re-review; spine SSOT `pr-review.yaml` + `scripts/pr-reviewing.ts`; backs `/sp:dev-pr-review` |
|
|
325
330
|
| `indexed-context` | 1.0 | Cross-agent project context — anatomy/learnings/pitfalls/buglog/memory in `.spur/context/`; hook-tracked token-ledger; graceful degradation on agents without hooks |
|
|
326
331
|
| `history-anatomy` | 1.0 | Diagnostic interpretation owner over already-imported history — daily/ad-hoc mode contract, closed finding taxonomy, twelve-section report contract, `enrich`/`validate` rubrics; no workflow launch, no JSONL fallback, no corpus mutation |
|
|
327
|
-
| `session-review` | 1.
|
|
332
|
+
| `session-review` | 1.1 | Inline review of the active coding-agent session — compact outcomes, evidence-backed resolved/open issue classification, proposal-only improvements, and next actions; no workflow, import, delegation, or mutation |
|
|
328
333
|
| `redesign-web-ui` | 1.0 | Existing-UI visual upgrade — audit generic AI fingerprints, apply in-stack polish against `DESIGN.md` / live tokens, verify behavior and viewports; does not migrate frameworks |
|
|
329
334
|
|
|
330
335
|
#### Bounded coexistence and retirement gate — `sp:issue-finding` (HA-S1 0661)
|
|
@@ -418,7 +423,7 @@ the pipeline's Phase 7 review step.
|
|
|
418
423
|
| ---------------- | ------------ | ----------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------- |
|
|
419
424
|
| `expert-spur` | expert | `sp:spur-cli` | green | "create tasks", "feature lifecycle", "add a rule", "author a workflow" |
|
|
420
425
|
| `super-coder` | builder | `sp:sys-architecture` + `sp:code-implementation` + `sp:code-testing` + `sp:sys-debugging` | blue | "implement this", "write the code", "fix this bug", "design the architecture" |
|
|
421
|
-
| `super-planner` | orchestrator | `sp:spur-dev` + `sp:dogfood-testing`
|
|
426
|
+
| `super-planner` | orchestrator | `sp:spur-dev` + `sp:parallel-execution` + `sp:dogfood-testing` + `sp:next-router` | green | "run this task end to end", "run all tasks", "run the batch", "runall" |
|
|
422
427
|
| `super-reviewer` | reviewer | `sp:code-verification` + `sp:functional-review` + `sp:code-improvement` | crimson | "review this", "check the code", "SECUA review", "run task 0042 through review" |
|
|
423
428
|
|
|
424
429
|
Each agent has:
|
|
@@ -97,7 +97,8 @@ HITL gate unless `--auto` was passed.
|
|
|
97
97
|
- [ ] Establish scope first: WBS mode (task diff) or path mode (source glob). Derive the diff
|
|
98
98
|
scope the same way `sp:code-verification` Step 3 does.
|
|
99
99
|
- [ ] Dispatch each requested dimension to its owning skill — do not inline the review logic.
|
|
100
|
-
- [ ] Merge findings into a single ranked report
|
|
100
|
+
- [ ] Merge findings into a single ranked report, emitting native priority cells
|
|
101
|
+
(`P1 (blocker)` > `P2 (major)` > `P3 (minor)` > `P4 (advisory)` — see Output Format).
|
|
101
102
|
- [ ] In pipeline mode, write the merged report to the task's `## Review` section via
|
|
102
103
|
`spur task update <wbs> --section Review --from-file`; in standalone mode, emit as output.
|
|
103
104
|
- [ ] Cite `file:line` evidence for every finding — no vague "implemented correctly."
|
|
@@ -109,6 +110,8 @@ HITL gate unless `--auto` was passed.
|
|
|
109
110
|
- [ ] Never edit `task-pipeline.yaml` or reach into a pipeline step.
|
|
110
111
|
- [ ] Never auto-approve a HITL gate unless `--auto` was passed.
|
|
111
112
|
- [ ] Never soften a FAIL to PARTIAL, or PARTIAL to PASS, to avoid surfacing.
|
|
113
|
+
- [ ] Never emit a word-only Severity cell, an empty priority scaffold, or a `##`/`###` heading
|
|
114
|
+
inside a `### Review` body — all three fail the existing checkers.
|
|
112
115
|
- [ ] Never skip a dimension the operator requested with `--focus`.
|
|
113
116
|
|
|
114
117
|
## Definition of Done Housekeeping
|
|
@@ -120,22 +123,44 @@ enforcement checklist. Reference:
|
|
|
120
123
|
|
|
121
124
|
## Output Format
|
|
122
125
|
|
|
126
|
+
### Priority vocabulary (task 0818 R3)
|
|
127
|
+
|
|
128
|
+
Emit priorities **natively** — the consumer (`hasPopulatedPriorityTable`,
|
|
129
|
+
`packages/app/src/services/task-check.ts`) requires a `P1`–`P4` cell, and a word-only severity cell
|
|
130
|
+
fails it. One explicit mapping, no transcription step anywhere downstream:
|
|
131
|
+
|
|
132
|
+
| Priority cell | Severity | Meaning |
|
|
133
|
+
| --- | --- | --- |
|
|
134
|
+
| `P1 (blocker)` | blocker | Ships broken or unsafe; blocks the verdict |
|
|
135
|
+
| `P2 (major)` | major | Real defect or structural problem; must be dispositioned |
|
|
136
|
+
| `P3 (minor)` | minor | Localized issue; fix or accept explicitly |
|
|
137
|
+
| `P4 (advisory)` | advisory | Observation, non-blocking |
|
|
138
|
+
|
|
139
|
+
Severity words stay visible in the same cell — the mapping adds the machine-readable label, it does
|
|
140
|
+
not replace the semantics.
|
|
141
|
+
|
|
142
|
+
**Section-relative headings.** In pipeline mode the report body is written *into* the task's
|
|
143
|
+
`### Review` section, so every heading inside it MUST be `####` or deeper. A `##`/`###` heading in
|
|
144
|
+
the body becomes a new top-level task section and corrupts the document. In standalone mode
|
|
145
|
+
(emitted as output, not written to a task) the same body may be rendered one level shallower.
|
|
146
|
+
|
|
123
147
|
```markdown
|
|
124
|
-
|
|
148
|
+
#### Review Report — <wbs|path>
|
|
125
149
|
|
|
126
150
|
**Scope:** <wbs diff | path glob>
|
|
127
151
|
**Dimensions:** functional, security, efficiency, correctness, usability, architecture
|
|
128
152
|
**Verdict:** PASS | PARTIAL | FAIL
|
|
129
153
|
|
|
130
|
-
|
|
154
|
+
##### Findings (ranked)
|
|
131
155
|
|
|
132
|
-
| # |
|
|
156
|
+
| # | Priority | Dimension | Finding | Location |
|
|
133
157
|
|---|----------|-----------|---------|----------|
|
|
134
|
-
| 1 | blocker | security | SQL injection in query builder | `src/api/users.ts:42` |
|
|
135
|
-
| 2 | major | architecture | Shallow pass-through UserService | `src/services/users.ts:15` |
|
|
136
|
-
| 3 | minor | correctness | Missing error branch in createUser | `src/api/users.ts:48` |
|
|
158
|
+
| 1 | P1 (blocker) | security | SQL injection in query builder | `src/api/users.ts:42` |
|
|
159
|
+
| 2 | P2 (major) | architecture | Shallow pass-through UserService | `src/services/users.ts:15` |
|
|
160
|
+
| 3 | P3 (minor) | correctness | Missing error branch in createUser | `src/api/users.ts:48` |
|
|
161
|
+
| 4 | P4 (advisory) | usability | `createUser` error text omits the field name | `src/api/users.ts:51` |
|
|
137
162
|
|
|
138
|
-
|
|
163
|
+
##### Functional Traceability
|
|
139
164
|
|
|
140
165
|
| Req | Status | Evidence |
|
|
141
166
|
|-----|--------|----------|
|
|
@@ -145,6 +170,16 @@ enforcement checklist. Reference:
|
|
|
145
170
|
**Next:** <one-line action>
|
|
146
171
|
```
|
|
147
172
|
|
|
173
|
+
**No findings.** Never invent a defect to populate the table. Emit one substantive `P4 (advisory)`
|
|
174
|
+
row that states what was reviewed and what was found — placeholder cells (empty, `—`, `n/a`) are
|
|
175
|
+
rejected by the checker, and so they should be:
|
|
176
|
+
|
|
177
|
+
```markdown
|
|
178
|
+
| # | Priority | Dimension | Finding | Location |
|
|
179
|
+
|---|----------|-----------|---------|----------|
|
|
180
|
+
| 1 | P4 (advisory) | — | No P1–P3 findings: 6 changed files reviewed across all six dimensions; R1–R3 traceable to tests | `packages/app/src/workflow/proof-input-fingerprint.ts:102-160` |
|
|
181
|
+
```
|
|
182
|
+
|
|
148
183
|
With `--json`, emit the same shape as a JSON object for machine consumption.
|
|
149
184
|
|
|
150
185
|
## Out of scope
|
|
@@ -62,5 +62,6 @@ thread `--depth` into each per-task refine.
|
|
|
62
62
|
## Implementation
|
|
63
63
|
|
|
64
64
|
- Apply the [inline-default execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface).
|
|
65
|
+
- Apply the [shared startup contract](../skills/spur-dev/references/cross-cutting.md#shared-startup-contract-task-0814-r1r3r4r6r7r8) — bootstrap checklist, quick readiness before isolation, workflow inventory before YAML, comprehensive checks at owning boundaries (task 0814 R1/R3/R4/R7/R8).
|
|
65
66
|
- Batch orchestration: `Skill(skill="sp:spur-dev", args="refineall $ARGUMENTS")`
|
|
66
67
|
- Per-task refine (inner): `Skill(skill="sp:spur-dev", args="refine <wbs> $SHARED_FLAGS")`
|
|
@@ -31,6 +31,7 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
|
|
|
31
31
|
## Implementation
|
|
32
32
|
|
|
33
33
|
- Apply the [inline-default execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface).
|
|
34
|
+
- Apply the [shared startup contract](../skills/spur-dev/references/cross-cutting.md#shared-startup-contract-task-0814-r1r3r4r6r7r8) — bootstrap checklist, quick readiness before isolation, workflow inventory before YAML, comprehensive checks at their owning boundaries (task 0814 R1/R3/R4/R7/R8).
|
|
34
35
|
- Full pipeline (default `--mode full`): interactive omit/`--agent inline` uses the
|
|
35
36
|
[inline pipeline driver](../skills/spur-dev/references/inline-pipeline-driver.md) via
|
|
36
37
|
`Skill(skill="sp:spur-dev", args="run-inline $ARGUMENTS")`; `--agent auto` or a named executor
|
|
@@ -82,5 +82,6 @@ full distinction.
|
|
|
82
82
|
## Implementation
|
|
83
83
|
|
|
84
84
|
- Apply the [inline-default execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface). Interactive sequential omit/`inline` keeps the orchestrator in the host session through the [inline pipeline driver](../skills/spur-dev/references/inline-pipeline-driver.md); the resolved selector applies uniformly — eligible `agent.run` stages dispatch once to a native subagent with host fallback (0508). `--agent auto`, a name, or parallel mode retains the isolated per-task workflow boundary.
|
|
85
|
+
- Apply the [shared startup contract](../skills/spur-dev/references/cross-cutting.md#shared-startup-contract-task-0814-r1r3r4r6r7r8) — bootstrap checklist, quick readiness before isolation, workflow inventory before YAML, comprehensive checks at owning boundaries (task 0814 R1/R3/R4/R7/R8).
|
|
85
86
|
- Interactive sequential omit/inline: `Skill(skill="sp:spur-dev", args="runall-inline $ARGUMENTS")`.
|
|
86
87
|
- Explicit executor or parallel mode: `Skill(skill="sp:spur-dev", args="runall $ARGUMENTS")` → `sp:super-planner` agent.
|
|
@@ -68,6 +68,7 @@ Without `--fix all`, shippable is not evaluated (optional note: use `--fix all`
|
|
|
68
68
|
## Implementation
|
|
69
69
|
|
|
70
70
|
- Apply the [inline-default execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface).
|
|
71
|
+
- Apply the [shared startup contract](../skills/spur-dev/references/cross-cutting.md#shared-startup-contract-task-0814-r1r3r4r6r7r8) — bootstrap checklist, quick readiness before isolation, workflow inventory before YAML, comprehensive checks at owning boundaries (task 0814 R1/R3/R4/R7/R8).
|
|
71
72
|
- Batch orchestration: `Skill(skill="sp:spur-dev", args="verifyall $ARGUMENTS")`
|
|
72
73
|
- Per-task verification (inner): `Skill(skill="sp:code-verification", args="verify <wbs> $SHARED_FLAGS")`
|
|
73
74
|
- Shippable gate: once after the batch (same skill § Shippable readiness gate)
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.80",
|
|
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"]
|
|
@@ -3,6 +3,119 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// plugins/sp/scripts/batch-preflight.ts
|
|
6
|
+
function quickReadiness(input) {
|
|
7
|
+
const status = (input.status ?? "").toLowerCase();
|
|
8
|
+
const operation = input.operation;
|
|
9
|
+
if (operation !== "run" && operation !== "refine" && operation !== "verify") {
|
|
10
|
+
return {
|
|
11
|
+
action: "invalid",
|
|
12
|
+
code: "IV",
|
|
13
|
+
reason: `quick-readiness: unknown operation '${operation}' (${input.wbs})`
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (input.filteredCount !== undefined) {
|
|
17
|
+
if (input.filteredCount < 0) {
|
|
18
|
+
return {
|
|
19
|
+
action: "invalid",
|
|
20
|
+
code: "IV",
|
|
21
|
+
reason: `quick-readiness: invalid negative filtered count '${input.filteredCount}' (${input.wbs})`
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (input.filteredCount === 0) {
|
|
25
|
+
return {
|
|
26
|
+
action: "skipped",
|
|
27
|
+
code: "EMPTY",
|
|
28
|
+
reason: `quick-readiness: empty status-filtered set — nothing to ${operation} (${input.wbs})`
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (status === "cancelled" || status === "done") {
|
|
33
|
+
if (operation === "verify" && input.force === true) {
|
|
34
|
+
return {
|
|
35
|
+
action: "runnable",
|
|
36
|
+
code: "FORCE",
|
|
37
|
+
reason: `quick-readiness: verify --force re-verification of ${status} task ${input.wbs}`
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
action: "skipped",
|
|
42
|
+
code: status === "done" ? "DONE" : "CANCELLED",
|
|
43
|
+
reason: `quick-readiness: already ${status} — no ${operation} hop (${input.wbs})`
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (status === "blocked") {
|
|
47
|
+
return {
|
|
48
|
+
action: "blocked",
|
|
49
|
+
code: "BLK",
|
|
50
|
+
reason: `quick-readiness: blocked — human/handover first (${input.wbs})`
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (operation === "run" && input.dependencies && input.dependencies.length > 0) {
|
|
54
|
+
const unmet = input.dependencies.filter((d) => (input.depStatuses?.[d] ?? "missing").toLowerCase() !== "done");
|
|
55
|
+
if (unmet.length > 0) {
|
|
56
|
+
return {
|
|
57
|
+
action: "blocked",
|
|
58
|
+
code: "DEP",
|
|
59
|
+
reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})`,
|
|
60
|
+
unmetDeps: unmet
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const required = input.requiredSections ?? [];
|
|
65
|
+
const present = input.presentSections ?? [];
|
|
66
|
+
const gaps = required.filter((s) => {
|
|
67
|
+
const finding = input.sectionFindings?.[s];
|
|
68
|
+
return !present.includes(s) || finding !== undefined && finding !== "";
|
|
69
|
+
});
|
|
70
|
+
if (operation === "refine") {
|
|
71
|
+
if (status !== "backlog" && status !== "todo") {
|
|
72
|
+
return {
|
|
73
|
+
action: "skipped",
|
|
74
|
+
code: "NONPLAN",
|
|
75
|
+
reason: `quick-readiness: refine targets backlog/todo only, not '${status}' (${input.wbs})`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
action: "runnable",
|
|
80
|
+
code: "OK",
|
|
81
|
+
reason: `quick-readiness: refine ready for ${input.wbs} (${gaps.length} planning gap(s) to fill)`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (operation === "verify") {
|
|
85
|
+
if (status !== "testing" && status !== "wip") {
|
|
86
|
+
return {
|
|
87
|
+
action: "invalid",
|
|
88
|
+
code: "NOVERIFY",
|
|
89
|
+
reason: `quick-readiness: verify needs testing/wip, not '${status}' (${input.wbs})`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
action: "runnable",
|
|
94
|
+
code: "OK",
|
|
95
|
+
reason: `quick-readiness: verify ready for ${input.wbs}`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (status !== "todo" && status !== "wip" && status !== "testing") {
|
|
99
|
+
return {
|
|
100
|
+
action: "invalid",
|
|
101
|
+
code: "NORUN",
|
|
102
|
+
reason: `quick-readiness: run needs todo/wip/testing, not '${status}' (${input.wbs})`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (gaps.length > 0) {
|
|
106
|
+
return {
|
|
107
|
+
action: "needs-refinement",
|
|
108
|
+
code: "REFINE",
|
|
109
|
+
reason: `quick-readiness: implementation sections incomplete (${input.wbs})`,
|
|
110
|
+
gaps
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
action: "runnable",
|
|
115
|
+
code: "OK",
|
|
116
|
+
reason: `quick-readiness: run ready for ${input.wbs}`
|
|
117
|
+
};
|
|
118
|
+
}
|
|
6
119
|
function preflightTask(input) {
|
|
7
120
|
const status = (input.status ?? "").toLowerCase();
|
|
8
121
|
const deps = input.dependencies ?? [];
|
|
@@ -72,6 +185,11 @@ function parsePreflightCliArgs(argv) {
|
|
|
72
185
|
let recovery = false;
|
|
73
186
|
let help = false;
|
|
74
187
|
let json = false;
|
|
188
|
+
let operation = null;
|
|
189
|
+
let force = false;
|
|
190
|
+
let filteredCount = null;
|
|
191
|
+
let requiredSections = [];
|
|
192
|
+
let presentSections = [];
|
|
75
193
|
for (let i = 0;i < argv.length; i++) {
|
|
76
194
|
const a = argv[i];
|
|
77
195
|
if (a === "--help" || a === "-h")
|
|
@@ -80,7 +198,21 @@ function parsePreflightCliArgs(argv) {
|
|
|
80
198
|
json = true;
|
|
81
199
|
else if (a === "--recovery")
|
|
82
200
|
recovery = true;
|
|
83
|
-
else if (a === "--
|
|
201
|
+
else if (a === "--force")
|
|
202
|
+
force = true;
|
|
203
|
+
else if (a === "--operation") {
|
|
204
|
+
const v = argv[++i] ?? "";
|
|
205
|
+
operation = v === "run" || v === "refine" || v === "verify" ? v : null;
|
|
206
|
+
} else if (a === "--filtered-count") {
|
|
207
|
+
const v = Number(argv[++i]);
|
|
208
|
+
filteredCount = Number.isFinite(v) ? v : null;
|
|
209
|
+
} else if (a === "--required-sections") {
|
|
210
|
+
const raw = argv[++i] ?? "";
|
|
211
|
+
requiredSections = raw.length === 0 ? [] : raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
212
|
+
} else if (a === "--present-sections") {
|
|
213
|
+
const raw = argv[++i] ?? "";
|
|
214
|
+
presentSections = raw.length === 0 ? [] : raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
215
|
+
} else if (a === "--wbs")
|
|
84
216
|
wbs = argv[++i] ?? wbs;
|
|
85
217
|
else if (a === "--status")
|
|
86
218
|
status = argv[++i] ?? null;
|
|
@@ -96,11 +228,25 @@ function parsePreflightCliArgs(argv) {
|
|
|
96
228
|
}
|
|
97
229
|
}
|
|
98
230
|
}
|
|
99
|
-
return {
|
|
231
|
+
return {
|
|
232
|
+
status,
|
|
233
|
+
deps,
|
|
234
|
+
depStatuses,
|
|
235
|
+
wbs,
|
|
236
|
+
recovery,
|
|
237
|
+
help,
|
|
238
|
+
json,
|
|
239
|
+
operation,
|
|
240
|
+
force,
|
|
241
|
+
filteredCount,
|
|
242
|
+
requiredSections,
|
|
243
|
+
presentSections
|
|
244
|
+
};
|
|
100
245
|
}
|
|
101
246
|
var PREFLIGHT_CLI_USAGE = `Usage:
|
|
102
247
|
bun plugins/sp/scripts/batch-preflight.ts --wbs <wbs> --status <status> \\
|
|
103
248
|
[--deps 0275,0276] [--dep-status 0275:done,0276:todo] [--recovery] [--json]
|
|
249
|
+
bun plugins/sp/scripts/batch-preflight.ts --operation <run|refine|verify> --wbs <wbs> --status <status> [--filtered-count <n>] [--required-sections A,B] [--present-sections A,B] [--force] [--json]
|
|
104
250
|
|
|
105
251
|
Exit: 0 = run (or recovery hint printed); 2 = skip; 1 = usage.`;
|
|
106
252
|
function runPreflightCli(argv) {
|
|
@@ -117,6 +263,30 @@ function runPreflightCli(argv) {
|
|
|
117
263
|
`;
|
|
118
264
|
return { exitCode: 0, stdout: body, stderr: "" };
|
|
119
265
|
}
|
|
266
|
+
if (args.operation !== null) {
|
|
267
|
+
const result2 = quickReadiness({
|
|
268
|
+
wbs: args.wbs,
|
|
269
|
+
status: args.status,
|
|
270
|
+
operation: args.operation,
|
|
271
|
+
dependencies: args.deps,
|
|
272
|
+
depStatuses: args.depStatuses,
|
|
273
|
+
...args.filteredCount !== null ? { filteredCount: args.filteredCount } : {},
|
|
274
|
+
...args.requiredSections.length > 0 ? { requiredSections: args.requiredSections } : {},
|
|
275
|
+
...args.presentSections.length > 0 ? { presentSections: args.presentSections } : {},
|
|
276
|
+
...args.force ? { force: true } : {}
|
|
277
|
+
});
|
|
278
|
+
const runnable = result2.action === "runnable" || result2.action === "needs-refinement";
|
|
279
|
+
if (args.json) {
|
|
280
|
+
return { exitCode: runnable ? 0 : 2, stdout: `${JSON.stringify(result2, null, 2)}
|
|
281
|
+
`, stderr: "" };
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
exitCode: runnable ? 0 : 2,
|
|
285
|
+
stdout: `${result2.action}${result2.code ? ` ${result2.code}` : ""}: ${result2.reason}
|
|
286
|
+
`,
|
|
287
|
+
stderr: ""
|
|
288
|
+
};
|
|
289
|
+
}
|
|
120
290
|
const result = preflightTask({
|
|
121
291
|
wbs: args.wbs,
|
|
122
292
|
status: args.status,
|
|
@@ -154,6 +324,7 @@ function runPreflightCli(argv) {
|
|
|
154
324
|
export {
|
|
155
325
|
runPreflightCli,
|
|
156
326
|
recoveryHint,
|
|
327
|
+
quickReadiness,
|
|
157
328
|
preflightTask,
|
|
158
329
|
parsePreflightCliArgs,
|
|
159
330
|
PREFLIGHT_CLI_USAGE
|