@gobing-ai/spur 0.3.48 → 0.3.49
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/config.example.yaml +52 -4
- package/config/workflows/pr-review.yaml +338 -0
- package/package.json +8 -8
- package/plugins/sp/README.md +9 -6
- package/plugins/sp/commands/{dev-featurechange.md → dev-feature-change.md} +7 -10
- package/plugins/sp/commands/dev-find-issue.md +24 -19
- package/plugins/sp/commands/dev-find-next.md +3 -3
- package/plugins/sp/commands/dev-gtd.md +11 -12
- package/plugins/sp/commands/dev-history-load.md +63 -0
- package/plugins/sp/commands/dev-pr-review.md +39 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +25 -12
- package/plugins/sp/scripts/history-load.ts +400 -0
- package/plugins/sp/scripts/pr-reviewing.ts +867 -0
- package/plugins/sp/scripts/validate-commands.ts +33 -2
- package/plugins/sp/skills/code-implementation/SKILL.md +9 -1
- package/plugins/sp/skills/code-verification/SKILL.md +27 -28
- package/plugins/sp/skills/issue-finding/SKILL.md +6 -5
- package/plugins/sp/skills/issue-finding/references/session-formats.md +4 -2
- package/plugins/sp/skills/next-feature/SKILL.md +6 -6
- package/plugins/sp/skills/next-feature/references/handoff-routing.md +5 -5
- package/plugins/sp/skills/next-feature/references/signal-derivation.md +7 -2
- package/plugins/sp/skills/pr-reviewing/SKILL.md +285 -0
- package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +5 -5
- package/plugins/sp/skills/spur-cli/references/features.md +1 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +14 -4
- package/schemas/spur-config.schema.json +20 -0
- package/spur.js +682 -222
|
@@ -49,6 +49,28 @@ agent:
|
|
|
49
49
|
# naming both accepted sets.
|
|
50
50
|
default: coder
|
|
51
51
|
|
|
52
|
+
# Role → tier map (SSOT: DEFAULT_AGENT_ROLES in packages/config, task 0572 /
|
|
53
|
+
# ADR-061; plugins/sp/references/roles.md is a parity-gated projection).
|
|
54
|
+
# Resolution: role → tier → cheapest USABLE executor whose tier >= the role's
|
|
55
|
+
# tier, climbing the ladder across gaps. Declare at least one usable executor
|
|
56
|
+
# at or above each rung or that role fails loudly at dispatch:
|
|
57
|
+
# scribe=cheap · coder=standard · reviewer=capable-1 · planner=capable-2
|
|
58
|
+
# Stage floors (stage-registry model_policy): changelog=cheap;
|
|
59
|
+
# implement/test/wrap/review/refine/brainstorm=standard;
|
|
60
|
+
# verify/dogfood=capable-1; plan=capable-2. A stage's fallback ladder
|
|
61
|
+
# (auth / resource-exhaustion / gate-fail) only advances when a higher rung
|
|
62
|
+
# has a usable executor — an empty rung turns a quota failure into a hang.
|
|
63
|
+
#
|
|
64
|
+
# Optional per-project override (0572): re-tier / re-stage a KNOWN role only —
|
|
65
|
+
# the vocabulary is closed; a config naming any other key fails at config load
|
|
66
|
+
# naming the accepted four. Per-field merge over the defaults (restate only
|
|
67
|
+
# what you override; a role you omit keeps its default wholesale):
|
|
68
|
+
# roles:
|
|
69
|
+
# reviewer:
|
|
70
|
+
# tier: capable-2 # e.g. pin review work one rung higher
|
|
71
|
+
# coder:
|
|
72
|
+
# stages: [implement] # e.g. stop folding test/wrap into coder
|
|
73
|
+
|
|
52
74
|
# Canonical coding-agent ids (ts-ai-runner DISPLAY_ORDER, 0.4.8+):
|
|
53
75
|
# claude, codex, gemini, pi, omp, opencode, antigravity-cli,
|
|
54
76
|
# openclaw, hermes, grok
|
|
@@ -56,32 +78,58 @@ agent:
|
|
|
56
78
|
# auth-status verb).
|
|
57
79
|
|
|
58
80
|
# Named executor profiles (ADR-033 / 0343). Each pairs a canonical agent with
|
|
59
|
-
# an
|
|
81
|
+
# an explicit model override and an explicit capability tier.
|
|
82
|
+
# `model` is pinned on every entry: omitting it defers to the agent CLI's own
|
|
83
|
+
# default, which drifts with CLI upgrades and account state — pin what your
|
|
84
|
+
# CLI would resolve today (`grok models`, omp config.yml modelRoles.default,
|
|
85
|
+
# ~/.codex/config.toml, ~/.claude.json). The ids below are working examples,
|
|
86
|
+
# not vendor defaults — re-pin for your accounts.
|
|
87
|
+
#
|
|
88
|
+
# Pairing philosophy (operator guidance, 2026-08): a `native` pair — a vendor's
|
|
89
|
+
# model served by that vendor's own CLI (gpt-5.6-* via codex, claude-*-5 via
|
|
90
|
+
# claude, grok-4.6 via grok, gemini-3.x via agy) — consistently outperforms the
|
|
91
|
+
# same model routed through a third-party CLI, and belongs at the capable rungs.
|
|
92
|
+
# `portable` models (glm-5.x, deepseek-v4-*, …) are provider-agnostic and best
|
|
93
|
+
# carried by omp or pi at the cheap/standard rungs. The ladder below mixes both
|
|
94
|
+
# classes on purpose; measure pairings with the history plane before promoting
|
|
95
|
+
# a portable model into a capable rung.
|
|
60
96
|
# Live tiers: cheap | standard | capable-1 | capable-2 | capable-3
|
|
61
97
|
# (1=low quality within capable, 3=high). DECLARE tier — inference never
|
|
62
98
|
# invents capable-2/3. Stage routing starts on the cheapest executor whose
|
|
63
99
|
# tier >= min_tier; same exact tier ties break by array order.
|
|
64
100
|
# Legacy bare `capable` is accepted at runtime as synonym for capable-1.
|
|
65
101
|
executors:
|
|
102
|
+
# cheap rung is optional: with none declared, scribe-role work starts one
|
|
103
|
+
# rung up at the cheapest standard executor. Add one when transcript-heavy
|
|
104
|
+
# mechanical commands (changelog/gitmsg/handover) get noisy on cost.
|
|
105
|
+
# - name: minimax
|
|
106
|
+
# agent: omp
|
|
107
|
+
# model: minimax/MiniMax-M3
|
|
108
|
+
# tier: cheap
|
|
66
109
|
- name: omp
|
|
67
110
|
agent: omp
|
|
111
|
+
model: opencode/deepseek-v4-flash
|
|
68
112
|
tier: standard
|
|
69
113
|
# - name: omp-zai
|
|
70
114
|
# agent: omp
|
|
71
115
|
# model: zai/glm-5.2
|
|
72
116
|
# tier: standard
|
|
117
|
+
- name: pi
|
|
118
|
+
agent: pi
|
|
119
|
+
model: "k3"
|
|
120
|
+
tier: capable-1
|
|
73
121
|
- name: grok
|
|
74
122
|
agent: grok
|
|
123
|
+
model: grok-4.6
|
|
75
124
|
tier: capable-2
|
|
76
125
|
- name: claude
|
|
77
126
|
agent: claude
|
|
127
|
+
model: k3
|
|
78
128
|
tier: capable-3
|
|
79
129
|
- name: codex
|
|
80
130
|
agent: codex
|
|
131
|
+
model: gpt-5.6
|
|
81
132
|
tier: capable-3
|
|
82
|
-
# - name: pi
|
|
83
|
-
# agent: pi
|
|
84
|
-
# tier: capable-1
|
|
85
133
|
|
|
86
134
|
# `default-by-phase` is a REMOVED (0452). Prefer
|
|
87
135
|
# executor `tier` + stage-registry model_policy. When present, a matching
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# PR-review workflow: deterministic spine for /sp:dev-pr-review (skill sp:pr-reviewing).
|
|
2
|
+
# Authored for the @gobing-ai/ts-dual-workflow-engine state-machine schema
|
|
3
|
+
# (initialState / states[].id / onEnter / top-level transitions), same family as
|
|
4
|
+
# basic.yaml / task-pipeline.yaml. Seeded into projects by `spur init` (scaffold manifest).
|
|
5
|
+
#
|
|
6
|
+
# Shape: preflight → hygiene → precheck → push → ensure-pr → request → wait → collect → done
|
|
7
|
+
# (soft probes everywhere: red gates route to `failed`/`pending` via transitions,
|
|
8
|
+
# never a raw lifecycle abort — same reliability contract as basic.yaml)
|
|
9
|
+
#
|
|
10
|
+
# This YAML is the SSOT for the review spine's state order and guards. Every state shells
|
|
11
|
+
# out to the staged pr-reviewing.ts entrypoint (the tested deterministic core); no gh/git
|
|
12
|
+
# logic lives in this file. All model-bearing work — finding triage, `fix` mode, `rules`
|
|
13
|
+
# mode — stays in the sp:pr-reviewing skill and never enters this machine.
|
|
14
|
+
#
|
|
15
|
+
# Non-negotiable: the external review goes through the GitHub PR + an `@codex review`
|
|
16
|
+
# comment. Never substitute a local Codex review mechanism.
|
|
17
|
+
#
|
|
18
|
+
# Vars (override per run: --vars '{"mode":"submit","focus":"migration safety"}'):
|
|
19
|
+
# mode — full (default) | submit | rerun
|
|
20
|
+
# full: dedupe an up-to-date Codex review, else request + wait + collect
|
|
21
|
+
# submit: request and stop at `pending` (no wait)
|
|
22
|
+
# rerun: request with --force even when HEAD is already reviewed
|
|
23
|
+
# baseBranch — base for a newly created PR (default: existing PR base, else repo default)
|
|
24
|
+
# focus — extra review focus appended to the @codex request
|
|
25
|
+
# noWait — "true" returns pending right after the request instead of polling
|
|
26
|
+
# waitTimeoutSec — poll budget for Codex output (default 600)
|
|
27
|
+
# waitIntervalSec — poll interval (default 30; do not poll aggressively)
|
|
28
|
+
# preReviewCmd — project fast check run before requesting (empty = skipped).
|
|
29
|
+
# TRUSTED CONFIG ONLY — executed via `sh -c` (task 0436 SECUA residual).
|
|
30
|
+
# Never interpolate untrusted operator/LLM input into it.
|
|
31
|
+
# __runId — injected by WorkflowAppService.run(); scopes .spur/run artifacts.
|
|
32
|
+
|
|
33
|
+
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
34
|
+
name: pr-review
|
|
35
|
+
kind: state-machine
|
|
36
|
+
description: GitHub Codex PR-review spine — preflight → hygiene → precheck → push → ensure-pr → request → wait → collect
|
|
37
|
+
iterationBound: 16
|
|
38
|
+
initialState: preflight
|
|
39
|
+
terminalStates:
|
|
40
|
+
- done
|
|
41
|
+
- pending
|
|
42
|
+
- failed
|
|
43
|
+
failureStates:
|
|
44
|
+
- failed
|
|
45
|
+
vars:
|
|
46
|
+
mode: 'full'
|
|
47
|
+
baseBranch: ''
|
|
48
|
+
focus: ''
|
|
49
|
+
noWait: 'false'
|
|
50
|
+
waitTimeoutSec: '600'
|
|
51
|
+
waitIntervalSec: '30'
|
|
52
|
+
preReviewCmd: ''
|
|
53
|
+
__runId: ''
|
|
54
|
+
|
|
55
|
+
states:
|
|
56
|
+
- id: preflight
|
|
57
|
+
description: >
|
|
58
|
+
Soft probe: git/gh/repo checks (detached HEAD, dirty tree, gh auth, GitHub remote).
|
|
59
|
+
Writes PASS|FAIL to .spur/run/${vars.__runId}-pr-preflight.status; always exit 0.
|
|
60
|
+
onEnter:
|
|
61
|
+
- kind: shell
|
|
62
|
+
options:
|
|
63
|
+
command: >-
|
|
64
|
+
mkdir -p .spur/run &&
|
|
65
|
+
STATUS_FILE=".spur/run/$__runId-pr-preflight.status" &&
|
|
66
|
+
set +e &&
|
|
67
|
+
bun "$(superskill script path sp pr-reviewing.ts)" preflight --json > ".spur/run/$__runId-pr-context.json";
|
|
68
|
+
rc=$?; set -e &&
|
|
69
|
+
if [ "$rc" -eq 0 ]; then printf 'PASS\n' > "$STATUS_FILE"; else printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
70
|
+
exit 0
|
|
71
|
+
|
|
72
|
+
- id: hygiene
|
|
73
|
+
description: >
|
|
74
|
+
Submission sanity scan of base...HEAD: secrets/.env/conflict markers BLOCK the run;
|
|
75
|
+
debug residue only WARNs. Not a replacement for the independent Codex review.
|
|
76
|
+
onEnter:
|
|
77
|
+
- kind: shell
|
|
78
|
+
options:
|
|
79
|
+
command: >-
|
|
80
|
+
mkdir -p .spur/run &&
|
|
81
|
+
STATUS_FILE=".spur/run/$__runId-pr-hygiene.status" &&
|
|
82
|
+
set +e &&
|
|
83
|
+
bun "$(superskill script path sp pr-reviewing.ts)" hygiene --base "$baseBranch" --json
|
|
84
|
+
--status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-hygiene.json";
|
|
85
|
+
rc=$?; set -e &&
|
|
86
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
87
|
+
exit 0
|
|
88
|
+
|
|
89
|
+
- id: precheck
|
|
90
|
+
description: >
|
|
91
|
+
Optional project fast check (vars.preReviewCmd) before spending a review request.
|
|
92
|
+
Empty command records SKIP; a red check stops the run before request (fail loud).
|
|
93
|
+
onEnter:
|
|
94
|
+
- kind: shell
|
|
95
|
+
options:
|
|
96
|
+
command: >-
|
|
97
|
+
mkdir -p .spur/run &&
|
|
98
|
+
STATUS_FILE=".spur/run/$__runId-pr-precheck.status" &&
|
|
99
|
+
if [ -z "$preReviewCmd" ]; then
|
|
100
|
+
printf 'SKIP\n' > "$STATUS_FILE";
|
|
101
|
+
else
|
|
102
|
+
set +e; sh -c "$preReviewCmd"; rc=$?; set -e;
|
|
103
|
+
if [ "$rc" -eq 0 ]; then printf 'PASS\n' > "$STATUS_FILE"; else printf 'FAIL\n' > "$STATUS_FILE"; fi;
|
|
104
|
+
fi &&
|
|
105
|
+
exit 0
|
|
106
|
+
|
|
107
|
+
- id: push
|
|
108
|
+
description: >
|
|
109
|
+
Publish the branch (normal push only, never force; sets upstream when missing).
|
|
110
|
+
A PR reviews pushed commits only.
|
|
111
|
+
onEnter:
|
|
112
|
+
- kind: shell
|
|
113
|
+
options:
|
|
114
|
+
command: >-
|
|
115
|
+
mkdir -p .spur/run &&
|
|
116
|
+
STATUS_FILE=".spur/run/$__runId-pr-push.status" &&
|
|
117
|
+
set +e &&
|
|
118
|
+
bun "$(superskill script path sp pr-reviewing.ts)" push --json --status-file "$STATUS_FILE"
|
|
119
|
+
> ".spur/run/$__runId-pr-push.json";
|
|
120
|
+
rc=$?; set -e &&
|
|
121
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
122
|
+
exit 0
|
|
123
|
+
|
|
124
|
+
- id: ensure-pr
|
|
125
|
+
description: Find or create the GitHub PR for the current branch — never a duplicate.
|
|
126
|
+
onEnter:
|
|
127
|
+
- kind: shell
|
|
128
|
+
options:
|
|
129
|
+
command: >-
|
|
130
|
+
mkdir -p .spur/run &&
|
|
131
|
+
STATUS_FILE=".spur/run/$__runId-pr-ensure.status" &&
|
|
132
|
+
set +e &&
|
|
133
|
+
bun "$(superskill script path sp pr-reviewing.ts)" ensure-pr --base "$baseBranch" --json
|
|
134
|
+
--status-file "$STATUS_FILE" > ".spur/run/$__runId-pr.json";
|
|
135
|
+
rc=$?; set -e &&
|
|
136
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
137
|
+
exit 0
|
|
138
|
+
|
|
139
|
+
- id: request
|
|
140
|
+
description: >
|
|
141
|
+
Post the `@codex review` request (per-HEAD dedupe unless mode=rerun forces).
|
|
142
|
+
Records the request under .spur/run/${vars.__runId}-pr-request.json.
|
|
143
|
+
onEnter:
|
|
144
|
+
- kind: shell
|
|
145
|
+
options:
|
|
146
|
+
command: >-
|
|
147
|
+
mkdir -p .spur/run &&
|
|
148
|
+
STATUS_FILE=".spur/run/$__runId-pr-request.status" &&
|
|
149
|
+
FORCE_FLAG="" &&
|
|
150
|
+
if [ "$mode" = "rerun" ]; then FORCE_FLAG="--force"; fi &&
|
|
151
|
+
set +e &&
|
|
152
|
+
bun "$(superskill script path sp pr-reviewing.ts)" request --focus "$focus" $FORCE_FLAG --json
|
|
153
|
+
--status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-request.json";
|
|
154
|
+
rc=$?; set -e &&
|
|
155
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
156
|
+
exit 0
|
|
157
|
+
|
|
158
|
+
- id: wait
|
|
159
|
+
description: >
|
|
160
|
+
Bounded poll for Codex output on the current pushed HEAD. Timeout records TIMEOUT
|
|
161
|
+
and routes to `pending` — never a failure (collect later with /sp:dev-pr-review collect).
|
|
162
|
+
onEnter:
|
|
163
|
+
- kind: shell
|
|
164
|
+
options:
|
|
165
|
+
command: >-
|
|
166
|
+
mkdir -p .spur/run &&
|
|
167
|
+
STATUS_FILE=".spur/run/$__runId-pr-wait.status" &&
|
|
168
|
+
set +e &&
|
|
169
|
+
SINCE="$(bun -e 'const fs=require("node:fs");const value=JSON.parse(fs.readFileSync(process.argv[1],"utf8")).requestedAt;process.stdout.write(value ?? "")' ".spur/run/$__runId-pr-request.json")" &&
|
|
170
|
+
REQUEST_HEAD="$(bun -e 'const fs=require("node:fs");const value=JSON.parse(fs.readFileSync(process.argv[1],"utf8")).head;process.stdout.write(value ?? "")' ".spur/run/$__runId-pr-request.json")" &&
|
|
171
|
+
bun "$(superskill script path sp pr-reviewing.ts)" wait --since "$SINCE" --head "$REQUEST_HEAD" --timeout "$waitTimeoutSec" --interval "$waitIntervalSec"
|
|
172
|
+
--json --status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-wait.json";
|
|
173
|
+
rc=$?; set -e &&
|
|
174
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
175
|
+
exit 0
|
|
176
|
+
|
|
177
|
+
- id: collect
|
|
178
|
+
description: Normalize the latest current-HEAD Codex result and record composite PR/CI status.
|
|
179
|
+
onEnter:
|
|
180
|
+
- kind: shell
|
|
181
|
+
options:
|
|
182
|
+
command: >-
|
|
183
|
+
mkdir -p .spur/run &&
|
|
184
|
+
STATUS_FILE=".spur/run/$__runId-pr-collect.status" &&
|
|
185
|
+
set +e &&
|
|
186
|
+
SINCE="$(bun -e 'const fs=require("node:fs");const value=JSON.parse(fs.readFileSync(process.argv[1],"utf8")).requestedAt;process.stdout.write(value ?? "")' ".spur/run/$__runId-pr-request.json")" &&
|
|
187
|
+
REQUEST_HEAD="$(bun -e 'const fs=require("node:fs");const value=JSON.parse(fs.readFileSync(process.argv[1],"utf8")).head;process.stdout.write(value ?? "")' ".spur/run/$__runId-pr-request.json")" &&
|
|
188
|
+
bun "$(superskill script path sp pr-reviewing.ts)" collect --since "$SINCE" --head "$REQUEST_HEAD" --json
|
|
189
|
+
--status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-findings.json";
|
|
190
|
+
collect_rc=$?;
|
|
191
|
+
bun "$(superskill script path sp pr-reviewing.ts)" status --since "$SINCE" --head "$REQUEST_HEAD" --json > ".spur/run/$__runId-pr-status.json";
|
|
192
|
+
status_rc=$?; set -e &&
|
|
193
|
+
if [ "$collect_rc" -ne 0 ] || [ "$status_rc" -ne 0 ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
194
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
195
|
+
{ cat ".spur/run/$__runId-pr-findings.json" 2>/dev/null || true; } &&
|
|
196
|
+
exit 0
|
|
197
|
+
|
|
198
|
+
- id: done
|
|
199
|
+
description: Terminal — review collected; findings artifact at .spur/run/${vars.__runId}-pr-findings.json
|
|
200
|
+
- id: pending
|
|
201
|
+
description: Terminal — review requested (or timed out) but not yet collected; run /sp:dev-pr-review collect later
|
|
202
|
+
- id: failed
|
|
203
|
+
description: Terminal — a gate went red; the stage .status/.json artifacts under .spur/run name the blocker
|
|
204
|
+
|
|
205
|
+
transitions:
|
|
206
|
+
- from: preflight
|
|
207
|
+
to: hygiene
|
|
208
|
+
description: Repo, gh auth, and clean tree verified
|
|
209
|
+
guard:
|
|
210
|
+
kind: shell
|
|
211
|
+
options:
|
|
212
|
+
command: 'test "$(cat .spur/run/$__runId-pr-preflight.status 2>/dev/null)" = PASS'
|
|
213
|
+
- from: preflight
|
|
214
|
+
to: failed
|
|
215
|
+
description: Preflight red (detached HEAD, dirty tree, gh auth, no GitHub remote) — stop before any publishing
|
|
216
|
+
guard:
|
|
217
|
+
kind: always
|
|
218
|
+
|
|
219
|
+
- from: hygiene
|
|
220
|
+
to: precheck
|
|
221
|
+
description: Clean or warn-only — warnings ride along to the report
|
|
222
|
+
guard:
|
|
223
|
+
kind: shell
|
|
224
|
+
options:
|
|
225
|
+
command: 'grep -qE "^(PASS|WARN)$" .spur/run/$__runId-pr-hygiene.status 2>/dev/null'
|
|
226
|
+
- from: hygiene
|
|
227
|
+
to: failed
|
|
228
|
+
description: BLOCK (secrets/.env/conflict markers) or probe failure — never submit a tainted diff
|
|
229
|
+
guard:
|
|
230
|
+
kind: always
|
|
231
|
+
|
|
232
|
+
- from: precheck
|
|
233
|
+
to: push
|
|
234
|
+
description: Project fast check passed or was skipped
|
|
235
|
+
guard:
|
|
236
|
+
kind: shell
|
|
237
|
+
options:
|
|
238
|
+
command: 'grep -qE "^(PASS|SKIP)$" .spur/run/$__runId-pr-precheck.status 2>/dev/null'
|
|
239
|
+
- from: precheck
|
|
240
|
+
to: failed
|
|
241
|
+
description: Project checks red — do not spend a review request on code that fails its own gate
|
|
242
|
+
guard:
|
|
243
|
+
kind: always
|
|
244
|
+
|
|
245
|
+
- from: push
|
|
246
|
+
to: ensure-pr
|
|
247
|
+
description: Branch published (or already up to date)
|
|
248
|
+
guard:
|
|
249
|
+
kind: shell
|
|
250
|
+
options:
|
|
251
|
+
command: 'grep -qE "^(PUSHED|UP_TO_DATE)$" .spur/run/$__runId-pr-push.status 2>/dev/null'
|
|
252
|
+
- from: push
|
|
253
|
+
to: failed
|
|
254
|
+
description: Push rejected (e.g. non-fast-forward) — report; never force-push as a workaround
|
|
255
|
+
guard:
|
|
256
|
+
kind: always
|
|
257
|
+
|
|
258
|
+
- from: ensure-pr
|
|
259
|
+
to: request
|
|
260
|
+
description: PR found or created
|
|
261
|
+
guard:
|
|
262
|
+
kind: shell
|
|
263
|
+
options:
|
|
264
|
+
command: 'grep -qE "^(FOUND|CREATED)$" .spur/run/$__runId-pr-ensure.status 2>/dev/null'
|
|
265
|
+
- from: ensure-pr
|
|
266
|
+
to: failed
|
|
267
|
+
description: No reviewable delta or PR creation failed — report the actual git/GitHub state
|
|
268
|
+
guard:
|
|
269
|
+
kind: always
|
|
270
|
+
|
|
271
|
+
# Declaration order matters: ALREADY_REVIEWED routes straight to collect (full mode dedupe);
|
|
272
|
+
# submit/noWait stop at pending; everything else waits.
|
|
273
|
+
- from: request
|
|
274
|
+
to: collect
|
|
275
|
+
description: Current HEAD already carries a Codex review — collect instead of duplicating
|
|
276
|
+
guard:
|
|
277
|
+
kind: shell
|
|
278
|
+
options:
|
|
279
|
+
command: 'test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = ALREADY_REVIEWED'
|
|
280
|
+
- from: request
|
|
281
|
+
to: pending
|
|
282
|
+
description: Request already in flight, or mode=submit/--no-wait after posting — return pending
|
|
283
|
+
guard:
|
|
284
|
+
kind: shell
|
|
285
|
+
options:
|
|
286
|
+
command: 'test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = ALREADY_REQUESTED || { test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = REQUESTED && { test "$mode" = "submit" || test "$noWait" = "true"; }; }'
|
|
287
|
+
- from: request
|
|
288
|
+
to: wait
|
|
289
|
+
description: Request posted — poll for the result
|
|
290
|
+
guard:
|
|
291
|
+
kind: shell
|
|
292
|
+
options:
|
|
293
|
+
command: 'test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = REQUESTED'
|
|
294
|
+
- from: request
|
|
295
|
+
to: failed
|
|
296
|
+
description: Request failed (no PR, gh error) — report the preserved error
|
|
297
|
+
guard:
|
|
298
|
+
kind: always
|
|
299
|
+
|
|
300
|
+
- from: wait
|
|
301
|
+
to: collect
|
|
302
|
+
description: Codex findings or an explicit clean result on the current HEAD found
|
|
303
|
+
guard:
|
|
304
|
+
kind: shell
|
|
305
|
+
options:
|
|
306
|
+
command: 'grep -qE "^(FOUND|CLEAN)$" .spur/run/$__runId-pr-wait.status 2>/dev/null'
|
|
307
|
+
- from: wait
|
|
308
|
+
to: pending
|
|
309
|
+
description: Poll budget exhausted — pending, not failed
|
|
310
|
+
guard:
|
|
311
|
+
kind: shell
|
|
312
|
+
options:
|
|
313
|
+
command: 'test "$(cat .spur/run/$__runId-pr-wait.status 2>/dev/null)" = TIMEOUT'
|
|
314
|
+
- from: wait
|
|
315
|
+
to: failed
|
|
316
|
+
description: Poll probe itself failed
|
|
317
|
+
guard:
|
|
318
|
+
kind: always
|
|
319
|
+
|
|
320
|
+
- from: collect
|
|
321
|
+
to: done
|
|
322
|
+
description: Current-HEAD review collected (CLEAN/FINDINGS)
|
|
323
|
+
guard:
|
|
324
|
+
kind: shell
|
|
325
|
+
options:
|
|
326
|
+
command: 'grep -qE "^(FINDINGS|CLEAN)$" .spur/run/$__runId-pr-collect.status 2>/dev/null'
|
|
327
|
+
- from: collect
|
|
328
|
+
to: pending
|
|
329
|
+
description: No current-HEAD result yet — pending, never clean
|
|
330
|
+
guard:
|
|
331
|
+
kind: shell
|
|
332
|
+
options:
|
|
333
|
+
command: 'test "$(cat .spur/run/$__runId-pr-collect.status 2>/dev/null)" = PENDING'
|
|
334
|
+
- from: collect
|
|
335
|
+
to: failed
|
|
336
|
+
description: Collect probe failed
|
|
337
|
+
guard:
|
|
338
|
+
kind: always
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.49",
|
|
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.
|
|
56
|
+
"@gobing-ai/ts-db": "^0.4.35",
|
|
57
|
+
"@gobing-ai/ts-ai-runner": "^0.4.35",
|
|
58
|
+
"@gobing-ai/ts-dual-workflow-engine": "^0.4.35",
|
|
59
|
+
"@gobing-ai/ts-infra": "^0.4.35",
|
|
60
60
|
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.31",
|
|
61
|
-
"@gobing-ai/ts-rule-engine": "^0.4.
|
|
62
|
-
"@gobing-ai/ts-runtime": "^0.4.
|
|
63
|
-
"@gobing-ai/ts-utils": "^0.4.
|
|
61
|
+
"@gobing-ai/ts-rule-engine": "^0.4.35",
|
|
62
|
+
"@gobing-ai/ts-runtime": "^0.4.35",
|
|
63
|
+
"@gobing-ai/ts-utils": "^0.4.35",
|
|
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
|
@@ -103,11 +103,12 @@ list this README is checked against.
|
|
|
103
103
|
| `dev-next` | Status-aware router — inspect a task (or next frontier under a feature), dispatch the best existing `/sp:dev-*` command, chain on clean success |
|
|
104
104
|
| `dev-run` | Run a task — full pipeline (precheck→implement→test→review→approve→verify→record→done) or single-step (implement) |
|
|
105
105
|
| `dev-review` | Multi-dimensional review for a task or path — functional requirements traceability, SECUA framework, and architectural depth |
|
|
106
|
+
| `dev-pr-review` | GitHub Codex PR review — prepare/reuse a PR, request `@codex review`, collect findings, validate/fix/re-review (fix mode); workflow-backed spine |
|
|
106
107
|
| `dev-verify` | Verify a task against its requirements and Acceptance Criteria — traceability check producing a PASS/PARTIAL/FAIL verdict with evidence |
|
|
107
108
|
| `dev-unit` | Generate or extend tests until the unit target is met |
|
|
108
109
|
| `dev-wrap` | Wrap up a single completed task — learnings, metrics, doc-sync, optional feature transition and branch cleanup |
|
|
109
110
|
| `dev-refresh` | Refresh feature status by feature ID, task WBS, or batch sweep via spur feature sync |
|
|
110
|
-
| `dev-
|
|
111
|
+
| `dev-feature-change` | Restructure feature tree from a mapping file — dry-run/apply via `spur feature move`, task edges, root `docs/*.md` only |
|
|
111
112
|
|
|
112
113
|
#### Lifecycle — batch and parallel
|
|
113
114
|
|
|
@@ -126,6 +127,7 @@ list this README is checked against.
|
|
|
126
127
|
| `dev-handover` | Generate a structured handover document when blocked — captures goal, progress, blocker, rejected approaches, and next steps |
|
|
127
128
|
| `dev-debug` | Systematic debugging protocol — reproduce, isolate, diagnose root cause, apply minimal fix, and verify with regression tests |
|
|
128
129
|
| `dev-daily` | Generate a daily summary report from agent usage data, git history, and notes |
|
|
130
|
+
| `dev-history-load` | On-demand cumulative history load + narrowed analyze — import (checkpoint-resume) then analyze, optionally by session/task/window, with optional forensics render |
|
|
129
131
|
| `dev-dogfood` | Dogfood an agent skill/command/CLI — drive it end-to-end with bounded auto-fix, self-monitor, and emit a comprehensive report |
|
|
130
132
|
| `dev-find-issue` | Review agent session logs, identify performance bottlenecks and behavioral anti-patterns, and generate a structured task file with proposed fixes |
|
|
131
133
|
| `dev-find-conflict` | Authority-aware semantic audit across source, task, feature, and project authority files — detect conflicts, resolve claim-specific authority, and route confirmed repairs through owner surfaces |
|
|
@@ -135,7 +137,7 @@ list this README is checked against.
|
|
|
135
137
|
| `dev-arch` | Survey a codebase (or module tree) for shallow modules and deepening opportunities — emit a ranked MARKDOWN candidate report that feeds the planning half; never auto-refactors |
|
|
136
138
|
| `dev-reverse` | Reverse-engineer a codebase — analyze unfamiliar repos, generate HLD/architecture docs, audit quality/security, and produce onboarding documentation |
|
|
137
139
|
| `dev-gitmsg` | Generate conventional commit message(s) from staged changes via per-file summarization, optionally commit |
|
|
138
|
-
| `dev-gtd` | Get things done — quality gate (auto-fix) →
|
|
140
|
+
| `dev-gtd` | Get things done — quality gate (auto-fix) → conventional commit → push → gh verify in one flow; optional act CI simulation via `--act` |
|
|
139
141
|
| `dev-changelog` | Generate changelog from git commits |
|
|
140
142
|
|
|
141
143
|
#### Rule authoring
|
|
@@ -313,6 +315,7 @@ surface or run one workflow. All skills target the same five core platforms: `cl
|
|
|
313
315
|
| `issue-finding` | 1.1 | Session-log forensics — multi-source discovery, bottleneck ranking, optional topic focus, CLI-gated fix task generation; backs `/sp:dev-find-issue` |
|
|
314
316
|
| `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` |
|
|
315
317
|
| `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` |
|
|
318
|
+
| `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` |
|
|
316
319
|
| `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 |
|
|
317
320
|
|
|
318
321
|
Each skill directory contains:
|
|
@@ -335,11 +338,11 @@ Skills contain zero validation logic — the CLI is the gate.
|
|
|
335
338
|
|
|
336
339
|
Thin slash-command wrappers that parse user arguments and delegate to the corresponding skill. Each
|
|
337
340
|
command is a user-facing entry point that bridges natural language to skill invocation. There are
|
|
338
|
-
**
|
|
341
|
+
**39 commands** (see the Command index above for the full list), organized by the surface they wrap:
|
|
339
342
|
|
|
340
343
|
| Prefix | Count | Delegates to | Purpose |
|
|
341
344
|
| ------------ | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
342
|
-
| `dev-*` |
|
|
345
|
+
| `dev-*` | 33 | `sp:spur-dev`, `sp:code-implementation`, `sp:code-testing`, `sp:code-verification`, `sp:code-simplification`, `sp:next-router`, `sp:brainstorm`, `sp:dogfood-testing`, `sp:parallel-execution`, `sp:sys-debugging`, `sp:daily-summary`, `sp:issue-finding`, `sp:conflict-finding`, `sp:reverse-engineering`, `sp:pr-reviewing`, inline | The dev-workflow surface — planning, execution, batch, wrap-up, review/verify, hygiene |
|
|
343
346
|
| `rule-*` | 3 | `sp:spur-cli` | The rule surface — `rule-add`, `rule-refine`, `rule-scan` |
|
|
344
347
|
| `workflow-*` | 2 | `sp:spur-cli` | The workflow surface — `workflow-add`, `workflow-refine` |
|
|
345
348
|
| `spur-init` | 1 | `sp:doc-evolve` | Project bootstrap (`spur init`) with doc-evolve integration |
|
|
@@ -349,7 +352,7 @@ Each command file contains:
|
|
|
349
352
|
- YAML frontmatter (`description`, `argument-hint`, `allowed-tools`).
|
|
350
353
|
- A delegation block: `Skill(skill="sp:<skill-name>", args="<operation> $ARGUMENTS")`.
|
|
351
354
|
|
|
352
|
-
**Commands as SSOT (ADR-032).** The
|
|
355
|
+
**Commands as SSOT (ADR-032).** The 39 `.md` files in `commands/` are the authoritative,
|
|
353
356
|
hand-editable source for the operator command surface. Per-platform adapters are **install-time
|
|
354
357
|
output** owned by `superskill` (`superskill install sp`) and never committed here. Plugin `sp` ships
|
|
355
358
|
no per-platform artifacts — only the platform-independent thin wrappers.
|
|
@@ -357,7 +360,7 @@ no per-platform artifacts — only the platform-independent thin wrappers.
|
|
|
357
360
|
**Thin-wrapper contract** is enforced by `scripts/validate-commands.ts`:
|
|
358
361
|
|
|
359
362
|
```bash
|
|
360
|
-
bun plugins/sp/scripts/validate-commands.ts # validate all
|
|
363
|
+
bun plugins/sp/scripts/validate-commands.ts # validate all 39 commands
|
|
361
364
|
bun plugins/sp/scripts/validate-commands.ts --json # machine-readable output
|
|
362
365
|
```
|
|
363
366
|
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: "Restructure the feature tree from a mapping file — dry-run then apply via spur feature move / task feature_id edges / root docs/*.md reference rewrites (CLI-gated; no raw Write on docs/features or docs/tasks). Triggers: feature restructure, feature tree move, reparent features, apply mapping file"
|
|
3
3
|
role: planner
|
|
4
|
-
Restructure the feature tree from a mapping file — dry-run then apply via
|
|
5
|
-
spur feature move / task feature_id edges / root docs/*.md reference rewrites
|
|
6
|
-
(CLI-gated; no raw Write on docs/features or docs/tasks)
|
|
7
4
|
argument-hint: "[--map <path>] [--dry-run] [--apply] [--limit <old-id>] [--wave <1|2|3|all>] [--yes]"
|
|
8
5
|
allowed-tools: ["Bash", "Read", "AskUserQuestion", "Skill"]
|
|
9
6
|
---
|
|
10
7
|
|
|
11
|
-
# Dev
|
|
8
|
+
# Dev Feature Change
|
|
12
9
|
|
|
13
10
|
CLI-gated feature-tree restructure orchestrator. Executes dispositions from a mapping file; does not invent hierarchy.
|
|
14
11
|
|
|
@@ -28,7 +25,7 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
|
|
|
28
25
|
## Usage
|
|
29
26
|
|
|
30
27
|
```
|
|
31
|
-
/sp:dev-
|
|
28
|
+
/sp:dev-feature-change [--map <path>] [--dry-run] [--apply] [--limit <old-id>] [--wave <1|2|3|all>] [--yes]
|
|
32
29
|
```
|
|
33
30
|
|
|
34
31
|
## Implementation
|
|
@@ -43,7 +40,7 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
|
|
|
43
40
|
|
|
44
41
|
- Read `--map`. Collect rows where disposition is not `keep` (typically `reparent-under:<parent>`).
|
|
45
42
|
- Filter by `--limit` / `--wave` if set.
|
|
46
|
-
- Wave
|
|
43
|
+
- Wave membership comes from the map itself (its wave column/section is the SSOT). Never hard-code letter sets here — the tree moves under the command and literals go stale.
|
|
47
44
|
|
|
48
45
|
**Free-digit preflight (mandatory before dry-run report)**
|
|
49
46
|
|
|
@@ -53,7 +50,7 @@ Group selected reparent rows by `new_parent`. For each parent:
|
|
|
53
50
|
spur feature list --json
|
|
54
51
|
```
|
|
55
52
|
|
|
56
|
-
Count current children (ids where `id` starts with parent and length = parent.length+1, digit 1–9).
|
|
53
|
+
Count current children (ids where `id` starts with parent and length = parent.length+1, digit 1–9).
|
|
57
54
|
`free = 9 - childCount`. If `rowsUnderParent.length > free`, **abort the plan** with a clear error naming the parent, free slots, and competing old_ids. Do not apply a partial wave.
|
|
58
55
|
|
|
59
56
|
**Dry-run plan (always) — sequential prediction**
|
|
@@ -102,10 +99,10 @@ spur feature refresh --json
|
|
|
102
99
|
spur feature check --json
|
|
103
100
|
```
|
|
104
101
|
|
|
105
|
-
Task edges: `feature move` rewrites `feature_id` across **all** configured task folders (via `foldersConfig`). Safety check:
|
|
102
|
+
Task edges: `feature move` rewrites `feature_id` across **all** configured task folders (via `foldersConfig`). Safety check (the glob covers every tasks folder, present and future):
|
|
106
103
|
|
|
107
104
|
```bash
|
|
108
|
-
rg -n '^feature_id: <old_id>$' docs/tasks
|
|
105
|
+
rg -n '^feature_id: <old_id>$' docs/tasks*/
|
|
109
106
|
```
|
|
110
107
|
|
|
111
108
|
If any stale edges remain, fix with:
|