@gobing-ai/spur 0.3.9 → 0.3.11
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/config/rules/boundary/sp-runtime-path.yaml +4 -0
- package/config/rules/typescript/guarded-happy-dom-register.yaml +14 -36
- package/config/workflows/feature-dev.yaml +5 -5
- package/config/workflows/idea-pipeline.yaml +2 -2
- package/config/workflows/task-pipeline.yaml +1 -1
- package/package.json +9 -9
- package/schemas/spur-config.schema.json +64 -0
- package/spur.js +2012 -383
- package/web/_astro/BoardApp.CXm9NttC.js +1 -0
- package/web/_astro/{BoardApp.DjpO2XHn.js → BoardApp.DDpBMmZh.js} +106 -105
- package/web/_astro/{TaskDetail.DilpuD7R.js → TaskDetail.BuXwnD5s.js} +1 -1
- package/web/_astro/{arc.KcqIior8.js → arc.ROFFfvlC.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.BTFU70BY.js → architectureDiagram-3BPJPVTR.BF8jS1C7.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.apx49Oy9.js → blockDiagram-GPEHLZMM.BAZd0UR-.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BM-J4juX.js → c4Diagram-AAUBKEIU.BQiuu65q.js} +1 -1
- package/web/_astro/channel.e58tDmJn.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.K6z7IYZU.js → chunk-2J33WTMH.CaZ7Cj2C.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.BDYhxKa0.js → chunk-4BX2VUAB.Dl95s7jh.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.BnNOxqnI.js → chunk-55IACEB6.BS6cwIjQ.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DNeg6N7v.js → chunk-727SXJPM.BodG8be9.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.BjILBkba.js → chunk-AQP2D5EJ.D7bElS24.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.DQ5UvvsV.js → chunk-FMBD7UC4.B4QCK-dI.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.Yn1OvRJs.js → chunk-ND2GUHAM.X1msYFei.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.UErqHgqw.js → chunk-QZHKN3VN.B2c4-Dz1.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.BmjVF7iZ.js → classDiagram-4FO5ZUOK.b8-sWDxa.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.BmjVF7iZ.js → classDiagram-v2-Q7XG4LA2.b8-sWDxa.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.iKBxnkbb.js → cose-bilkent-S5V4N54A.CT4xXx1C.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.OwnCCrs6.js → dagre-BM42HDAG.DAukBvJI.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.DCdcffxE.js → diagram-2AECGRRQ.iAkt-am3.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.Ai-LvmVW.js → diagram-5GNKFQAL.BbKJ0fPo.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.B6e21QDN.js → diagram-KO2AKTUF.DmAKP2Me.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.oPfqy1fq.js → diagram-LMA3HP47.CJzAaFxI.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.Dh5QRDCE.js → diagram-OG6HWLK6.z2Yhlt_S.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DpBiOcO3.js → erDiagram-TEJ5UH35.C1inBaHt.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.NbMxFlVk.js → flowDiagram-I6XJVG4X.D6y2SP1V.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.JgZ3fDME.js → ganttDiagram-6RSMTGT7.BWgsQaJO.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.oMjFeZRt.js → gitGraphDiagram-PVQCEYII.So8AZT3S.js} +1 -1
- package/web/_astro/index.BaoJPQzM.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.kaio3YzK.js → infoDiagram-5YYISTIA.alTk5ecq.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CXQfMyeF.js → ishikawaDiagram-YF4QCWOH.X82FajaS.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.AvNKMzx6.js → journeyDiagram-JHISSGLW.74uvU6ld.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.kv3cZGdE.js → kanban-definition-UN3LZRKU.D6BjF9UG.js} +1 -1
- package/web/_astro/{linear.CfLoHWjz.js → linear.BpRIYzdb.js} +1 -1
- package/web/_astro/{mermaid.core.BSV8pBn-.js → mermaid.core.fdUDKzul.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.CbL_3b32.js → mindmap-definition-RKZ34NQL.Df5SdMrH.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.5BXdOLRb.js → pieDiagram-4H26LBE5.xNCa7QSz.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.krXYbhlh.js → quadrantDiagram-W4KKPZXB.C_3DSB9b.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.COO4LapZ.js → requirementDiagram-4Y6WPE33.C2MFScI8.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BvL0Jbdx.js → sankeyDiagram-5OEKKPKP.DEy6YHUG.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.Dk7Tu15E.js → sequenceDiagram-3UESZ5HK.CdQjeOkf.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.Cqh_KmEW.js → stateDiagram-AJRCARHV.C-j_0D_L.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.WapPgDCy.js → stateDiagram-v2-BHNVJYJU.BMzYaYSQ.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.CEVdiX0n.js → timeline-definition-PNZ67QCA.BaAa5dDC.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.Cd9A63eF.js → vennDiagram-CIIHVFJN.GZL7T0cb.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.DEiaHiIT.js → wardley-L42UT6IY.STDdK5oO.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.B7nGP61E.js → wardleyDiagram-YWT4CUSO.BJLlSFei.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.Bq8CHmxC.js → xychartDiagram-2RQKCTM6.CRGBFqsD.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.Bcfvp2GH.js +0 -1
- package/web/_astro/channel.vSp82e1U.js +0 -1
- package/web/_astro/index.CA3GTZM6.css +0 -1
|
@@ -17,6 +17,10 @@ include:
|
|
|
17
17
|
exclude:
|
|
18
18
|
- "**/node_modules/**"
|
|
19
19
|
- "**/dist/**"
|
|
20
|
+
# `.pi-lens/cache/` holds autogenerated project snapshots (absolute paths that
|
|
21
|
+
# legitimately contain `config/...` substrings). Not source — exclude to avoid
|
|
22
|
+
# triaging snapshot noise every pre-check.
|
|
23
|
+
- "**/.pi-lens/**"
|
|
20
24
|
# Package build artifacts: `build:bundle` copies repo-root config/ → apps/cli/config/
|
|
21
25
|
# (and legacy spur-cli/config/). Those trees are the ADR-015 SSOT payload itself and
|
|
22
26
|
# legitimately contain `config/...` documentation / self-references — not runtime paths.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
$schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
2
|
-
#
|
|
2
|
+
# Forbid raw GlobalRegistrator.register() in web tests — use the shared helper.
|
|
3
3
|
#
|
|
4
4
|
# WHY: GlobalRegistrator.register() sets up happy-dom globals (window, document,
|
|
5
5
|
# etc.). In a full bun test suite, multiple test files call it. The first call
|
|
@@ -9,12 +9,10 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
|
9
9
|
# `bun test ./apps/web/`), not when a single file runs in isolation.
|
|
10
10
|
# Real incident: 52 CI-only failures across 4 test files, 2026-07-09.
|
|
11
11
|
#
|
|
12
|
-
# FIX:
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# The teardown helper (apps/web/tests/happy-dom.ts) is the sanctioned unregister
|
|
17
|
-
# caller (see happy-dom-teardown.yaml). This rule guards the register side.
|
|
12
|
+
# FIX: call `registerHappyDom()` from apps/web/tests/happy-dom.ts, which wraps
|
|
13
|
+
# the register() in try/catch internally. It is the sanctioned caller and the
|
|
14
|
+
# single exclude below. The teardown side is symmetric: `teardownHappyDom` is
|
|
15
|
+
# the only sanctioned unregister() caller (see happy-dom-teardown.yaml).
|
|
18
16
|
#
|
|
19
17
|
# Severity warning: the file may pass in isolation but will fail in the full
|
|
20
18
|
# suite; fix before merge.
|
|
@@ -24,41 +22,21 @@ include:
|
|
|
24
22
|
exclude:
|
|
25
23
|
- "**/node_modules/**"
|
|
26
24
|
- "**/dist/**"
|
|
27
|
-
#
|
|
25
|
+
# The shared helper is the one legitimate caller of register().
|
|
28
26
|
- "apps/web/tests/happy-dom.ts"
|
|
29
|
-
# These files already wrap register() in try/catch; they are compliant.
|
|
30
|
-
- "apps/web/tests/modules/task-kanban/board.test.tsx"
|
|
31
|
-
- "apps/web/tests/modules/task-kanban/components.test.tsx"
|
|
32
|
-
- "apps/web/tests/modules/task-kanban/task-detail.test.tsx"
|
|
33
|
-
- "apps/web/tests/modules/task-kanban/index.test.tsx"
|
|
34
|
-
- "apps/web/tests/modules/task-kanban/new-task-panel.test.tsx"
|
|
35
|
-
- "apps/web/tests/modules/task-kanban/markdown-body.test.tsx"
|
|
36
|
-
- "apps/web/tests/modules/task-kanban/useTaskParams.test.tsx"
|
|
37
|
-
- "apps/web/tests/modules/task-kanban/task-filters.test.tsx"
|
|
38
|
-
- "apps/web/tests/modules/task-kanban/useTasks.test.ts"
|
|
39
|
-
- "apps/web/tests/modules/features/components.test.tsx"
|
|
40
|
-
- "apps/web/tests/lib/theme.test.ts"
|
|
41
|
-
- "apps/web/tests/components/BoardLayout.test.tsx"
|
|
42
|
-
- "apps/web/tests/modules/observability/components.test.tsx"
|
|
43
|
-
- "apps/web/tests/components/ThemeToggle.test.tsx"
|
|
44
|
-
- "apps/web/tests/components/ResponsiveAndTheme.test.tsx"
|
|
45
27
|
|
|
46
28
|
rules:
|
|
47
29
|
- id: guarded-happy-dom-register
|
|
48
30
|
description: >
|
|
49
|
-
GlobalRegistrator.register()
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
2026-07-09.
|
|
31
|
+
Do not call `GlobalRegistrator.register()` directly in a web test — a
|
|
32
|
+
second caller in the same suite throws "already been globally registered"
|
|
33
|
+
and loses every test in that file (a CI-only failure that never reproduces
|
|
34
|
+
in isolation). Use `registerHappyDom()` from apps/web/tests/happy-dom.ts,
|
|
35
|
+
which guards the call; it is the single sanctioned register() caller.
|
|
36
|
+
52-real CI incidents, 2026-07-09.
|
|
55
37
|
severity: warning
|
|
56
38
|
evaluator:
|
|
57
39
|
type: rg
|
|
58
40
|
config:
|
|
59
|
-
# Match
|
|
60
|
-
|
|
61
|
-
pattern: "GlobalRegistrator\\.register\\(\\)"
|
|
62
|
-
# Only flag lines where the call is NOT preceded by try{ on the same line
|
|
63
|
-
# (the fixed version is `try { GlobalRegistrator.register(); } catch {}`)
|
|
64
|
-
# We match the call itself and let the description guide the fix
|
|
41
|
+
# Match the raw call anywhere; the helper is excluded by path.
|
|
42
|
+
pattern: "GlobalRegistrator\\.register\\(\\)"
|
|
@@ -60,10 +60,10 @@ states:
|
|
|
60
60
|
|
|
61
61
|
- id: execute-tasks
|
|
62
62
|
description: >
|
|
63
|
-
Drive EVERY pending task under the feature to done.
|
|
64
|
-
`spur task list --feature ${featureId} --status todo --json`,
|
|
65
|
-
task-pipeline.yaml (precheck → implement → test → review → approve → verify → record → done).
|
|
66
|
-
stops and reports on the first non-PASS verdict — a failing task fails the feature.
|
|
63
|
+
Drive EVERY pending task under the feature to done (e.g. `/sp:dev-runall --feature ${featureId} --auto`).
|
|
64
|
+
The agent enumerates the work with `spur task list --feature ${featureId} --status todo --json`,
|
|
65
|
+
then runs each task through task-pipeline.yaml (precheck → implement → test → review → approve → verify → record → done).
|
|
66
|
+
It stops and reports on the first non-PASS verdict — a failing task fails the feature.
|
|
67
67
|
onEnter:
|
|
68
68
|
- kind: agent.run
|
|
69
69
|
options:
|
|
@@ -72,7 +72,7 @@ states:
|
|
|
72
72
|
Run every pending task under feature ${vars.featureId} to done. Enumerate with
|
|
73
73
|
`${vars.spurBin} task list --feature ${vars.featureId} --status todo --json`; then
|
|
74
74
|
for each WBS run the standard single-task pipeline VERBATIM:
|
|
75
|
-
`${vars.spurBin} workflow run
|
|
75
|
+
`${vars.spurBin} workflow run .spur/workflows/task-pipeline.yaml --vars
|
|
76
76
|
'{"wbs":"<wbs>","profile":"${vars.profile}","agent":"${vars.agent}"}' --async --json`,
|
|
77
77
|
polling `${vars.spurBin} workflow trace <run-id>` until terminal and inspecting
|
|
78
78
|
`.spur/run/<wbs>-verdict.json`. Stop and report on the first non-PASS verdict
|
|
@@ -202,12 +202,12 @@ states:
|
|
|
202
202
|
- id: handoff
|
|
203
203
|
description: >
|
|
204
204
|
Terminal — idea pipeline complete. Output: feature id, task WBS list, and
|
|
205
|
-
the next command to run (/sp:dev-run <first-wbs> or /sp:dev-runall --tasks feature:<id>).
|
|
205
|
+
the next command to run (/sp:dev-run <first-wbs> or /sp:dev-runall --feature <id> or --tasks feature:<id>).
|
|
206
206
|
No task execution — the pipeline stops here.
|
|
207
207
|
onEnter:
|
|
208
208
|
- kind: note
|
|
209
209
|
options:
|
|
210
|
-
message: "Idea pipeline handoff. Feature: ${vars.featureId}. Tasks created. Next: /sp:dev-runall --
|
|
210
|
+
message: "Idea pipeline handoff. Feature: ${vars.featureId}. Tasks created. Next: /sp:dev-runall --feature ${vars.featureId}"
|
|
211
211
|
# Checkpoint write: record session state for resume (Phase 4, task 0171 R3)
|
|
212
212
|
- kind: shell
|
|
213
213
|
options:
|
|
@@ -243,7 +243,7 @@ transitions:
|
|
|
243
243
|
# ── approve: HITL gate (reached only when profile != auto). Routed by the
|
|
244
244
|
# operator's captured answer (R1, bug-750) — three ordered guards, declaration
|
|
245
245
|
# order matters (yes first, then no, then cancel), mirroring idea-pipeline's
|
|
246
|
-
# design-approval gate (
|
|
246
|
+
# design-approval gate (.spur/workflows/idea-pipeline.yaml:352-366). No
|
|
247
247
|
# `always` edge remains out of `approve`. ──
|
|
248
248
|
- from: approve
|
|
249
249
|
to: verify
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
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",
|
|
@@ -50,14 +50,14 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@commander-js/extra-typings": "^14.0.0",
|
|
53
|
-
"@gobing-ai/ts-db": "^0.4.
|
|
54
|
-
"@gobing-ai/ts-ai-runner": "^0.4.
|
|
55
|
-
"@gobing-ai/ts-dual-workflow-engine": "^0.4.
|
|
56
|
-
"@gobing-ai/ts-infra": "^0.4.
|
|
57
|
-
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.
|
|
58
|
-
"@gobing-ai/ts-rule-engine": "^0.4.
|
|
59
|
-
"@gobing-ai/ts-runtime": "^0.4.
|
|
60
|
-
"@gobing-ai/ts-utils": "^0.4.
|
|
53
|
+
"@gobing-ai/ts-db": "^0.4.10",
|
|
54
|
+
"@gobing-ai/ts-ai-runner": "^0.4.10",
|
|
55
|
+
"@gobing-ai/ts-dual-workflow-engine": "^0.4.10",
|
|
56
|
+
"@gobing-ai/ts-infra": "^0.4.10",
|
|
57
|
+
"@gobing-ai/ts-llm-jsonl-importer": "^0.4.10",
|
|
58
|
+
"@gobing-ai/ts-rule-engine": "^0.4.10",
|
|
59
|
+
"@gobing-ai/ts-runtime": "^0.4.10",
|
|
60
|
+
"@gobing-ai/ts-utils": "^0.4.10",
|
|
61
61
|
"@types/bun": "1.3.14",
|
|
62
62
|
"@types/figlet": "^1.7.0",
|
|
63
63
|
"@types/node-notifier": "8.0.5",
|
|
@@ -136,6 +136,70 @@
|
|
|
136
136
|
"additionalProperties": {
|
|
137
137
|
"type": "string"
|
|
138
138
|
}
|
|
139
|
+
},
|
|
140
|
+
"team": {
|
|
141
|
+
"type": "object",
|
|
142
|
+
"description": "Declarative agent teams keyed by team id (the map key is the teamId). Each team materializes a roster of agent specs (feature M). Mirrors @gobing-ai/spur-config TeamConfigSchema (Zod is SSOT).",
|
|
143
|
+
"additionalProperties": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"required": ["name", "work_dir", "members"],
|
|
146
|
+
"properties": {
|
|
147
|
+
"name": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"minLength": 1,
|
|
150
|
+
"description": "Human-readable team label."
|
|
151
|
+
},
|
|
152
|
+
"work_dir": {
|
|
153
|
+
"type": "string",
|
|
154
|
+
"minLength": 1,
|
|
155
|
+
"description": "Default member workspace. A leading `~` is tilde-expanded at load."
|
|
156
|
+
},
|
|
157
|
+
"autostart": {
|
|
158
|
+
"type": "boolean",
|
|
159
|
+
"description": "Team-wide autostart default; per-member autostart overrides (effective = member.autostart ?? team.autostart ?? false)."
|
|
160
|
+
},
|
|
161
|
+
"members": {
|
|
162
|
+
"type": "array",
|
|
163
|
+
"minItems": 1,
|
|
164
|
+
"description": "Roster of member references (>= 1). A bare string is shorthand for { executor: <string> }; the composed agent id is <teamId>-<id ?? executor>.",
|
|
165
|
+
"items": {
|
|
166
|
+
"oneOf": [
|
|
167
|
+
{ "type": "string", "minLength": 1 },
|
|
168
|
+
{
|
|
169
|
+
"type": "object",
|
|
170
|
+
"required": ["executor"],
|
|
171
|
+
"properties": {
|
|
172
|
+
"executor": {
|
|
173
|
+
"type": "string",
|
|
174
|
+
"minLength": 1,
|
|
175
|
+
"description": "Executor name — resolved against agent.executors first, else a raw canonical agent type."
|
|
176
|
+
},
|
|
177
|
+
"id": {
|
|
178
|
+
"type": "string",
|
|
179
|
+
"minLength": 1,
|
|
180
|
+
"description": "Local member id; composed id is <teamId>-<id ?? executor> (must match ^[a-z][a-z0-9_-]{1,63}$)."
|
|
181
|
+
},
|
|
182
|
+
"purpose": { "type": "string" },
|
|
183
|
+
"workspace": {
|
|
184
|
+
"type": "string",
|
|
185
|
+
"minLength": 1,
|
|
186
|
+
"description": "Per-member workspace override. A leading `~` is tilde-expanded at load."
|
|
187
|
+
},
|
|
188
|
+
"model": { "type": "string", "minLength": 1 },
|
|
189
|
+
"autonomy": { "type": "string" },
|
|
190
|
+
"systemPrompt": { "type": "string" },
|
|
191
|
+
"command": {
|
|
192
|
+
"type": "array",
|
|
193
|
+
"items": { "type": "string", "minLength": 1 }
|
|
194
|
+
},
|
|
195
|
+
"autostart": { "type": "boolean" }
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
139
203
|
}
|
|
140
204
|
}
|
|
141
205
|
},
|