@gobing-ai/spur 0.3.10 → 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.
Files changed (60) hide show
  1. package/config/rules/typescript/guarded-happy-dom-register.yaml +14 -36
  2. package/config/workflows/feature-dev.yaml +5 -5
  3. package/config/workflows/idea-pipeline.yaml +2 -2
  4. package/config/workflows/task-pipeline.yaml +1 -1
  5. package/package.json +9 -9
  6. package/schemas/spur-config.schema.json +64 -0
  7. package/spur.js +1457 -285
  8. package/web/_astro/BoardApp.CXm9NttC.js +1 -0
  9. package/web/_astro/{BoardApp.C6AZyK1W.js → BoardApp.DDpBMmZh.js} +100 -100
  10. package/web/_astro/{TaskDetail.qCmrwQkG.js → TaskDetail.BuXwnD5s.js} +1 -1
  11. package/web/_astro/{arc.CbRppOdF.js → arc.ROFFfvlC.js} +1 -1
  12. package/web/_astro/{architectureDiagram-3BPJPVTR.9PfIcrsr.js → architectureDiagram-3BPJPVTR.BF8jS1C7.js} +1 -1
  13. package/web/_astro/{blockDiagram-GPEHLZMM.D8X1aH9F.js → blockDiagram-GPEHLZMM.BAZd0UR-.js} +1 -1
  14. package/web/_astro/{c4Diagram-AAUBKEIU.BnAemEBs.js → c4Diagram-AAUBKEIU.BQiuu65q.js} +1 -1
  15. package/web/_astro/channel.e58tDmJn.js +1 -0
  16. package/web/_astro/{chunk-2J33WTMH.DzOqcSmH.js → chunk-2J33WTMH.CaZ7Cj2C.js} +1 -1
  17. package/web/_astro/{chunk-4BX2VUAB.AqtW-DKu.js → chunk-4BX2VUAB.Dl95s7jh.js} +1 -1
  18. package/web/_astro/{chunk-55IACEB6.BIRjE6jR.js → chunk-55IACEB6.BS6cwIjQ.js} +1 -1
  19. package/web/_astro/{chunk-727SXJPM.CgDzPlSk.js → chunk-727SXJPM.BodG8be9.js} +1 -1
  20. package/web/_astro/{chunk-AQP2D5EJ.DjOW-ScW.js → chunk-AQP2D5EJ.D7bElS24.js} +1 -1
  21. package/web/_astro/{chunk-FMBD7UC4.wdJmHym6.js → chunk-FMBD7UC4.B4QCK-dI.js} +1 -1
  22. package/web/_astro/{chunk-ND2GUHAM.C-Ho8u3p.js → chunk-ND2GUHAM.X1msYFei.js} +1 -1
  23. package/web/_astro/{chunk-QZHKN3VN.BF1HouUh.js → chunk-QZHKN3VN.B2c4-Dz1.js} +1 -1
  24. package/web/_astro/{classDiagram-4FO5ZUOK.DAyOMMHn.js → classDiagram-4FO5ZUOK.b8-sWDxa.js} +1 -1
  25. package/web/_astro/{classDiagram-v2-Q7XG4LA2.DAyOMMHn.js → classDiagram-v2-Q7XG4LA2.b8-sWDxa.js} +1 -1
  26. package/web/_astro/{cose-bilkent-S5V4N54A.CNoutjqT.js → cose-bilkent-S5V4N54A.CT4xXx1C.js} +1 -1
  27. package/web/_astro/{dagre-BM42HDAG.yQbaJnir.js → dagre-BM42HDAG.DAukBvJI.js} +1 -1
  28. package/web/_astro/{diagram-2AECGRRQ.Y-0ZX0wP.js → diagram-2AECGRRQ.iAkt-am3.js} +1 -1
  29. package/web/_astro/{diagram-5GNKFQAL.Co7hW1JF.js → diagram-5GNKFQAL.BbKJ0fPo.js} +1 -1
  30. package/web/_astro/{diagram-KO2AKTUF.BW6g9zEB.js → diagram-KO2AKTUF.DmAKP2Me.js} +1 -1
  31. package/web/_astro/{diagram-LMA3HP47.5laYcnBs.js → diagram-LMA3HP47.CJzAaFxI.js} +1 -1
  32. package/web/_astro/{diagram-OG6HWLK6.DOXfn0B3.js → diagram-OG6HWLK6.z2Yhlt_S.js} +1 -1
  33. package/web/_astro/{erDiagram-TEJ5UH35.B65zPLW1.js → erDiagram-TEJ5UH35.C1inBaHt.js} +1 -1
  34. package/web/_astro/{flowDiagram-I6XJVG4X.EyV3nzyc.js → flowDiagram-I6XJVG4X.D6y2SP1V.js} +1 -1
  35. package/web/_astro/{ganttDiagram-6RSMTGT7.Dbg3JgqV.js → ganttDiagram-6RSMTGT7.BWgsQaJO.js} +1 -1
  36. package/web/_astro/{gitGraphDiagram-PVQCEYII.C_h4o8Bn.js → gitGraphDiagram-PVQCEYII.So8AZT3S.js} +1 -1
  37. package/web/_astro/index.BaoJPQzM.css +1 -0
  38. package/web/_astro/{infoDiagram-5YYISTIA.DmMa9Qku.js → infoDiagram-5YYISTIA.alTk5ecq.js} +1 -1
  39. package/web/_astro/{ishikawaDiagram-YF4QCWOH.GWMrgoLC.js → ishikawaDiagram-YF4QCWOH.X82FajaS.js} +1 -1
  40. package/web/_astro/{journeyDiagram-JHISSGLW.BWABlU6N.js → journeyDiagram-JHISSGLW.74uvU6ld.js} +1 -1
  41. package/web/_astro/{kanban-definition-UN3LZRKU.MbfHFA2-.js → kanban-definition-UN3LZRKU.D6BjF9UG.js} +1 -1
  42. package/web/_astro/{linear.BmIHCCO9.js → linear.BpRIYzdb.js} +1 -1
  43. package/web/_astro/{mermaid.core.CpHEEQAK.js → mermaid.core.fdUDKzul.js} +4 -4
  44. package/web/_astro/{mindmap-definition-RKZ34NQL.DYK94Ave.js → mindmap-definition-RKZ34NQL.Df5SdMrH.js} +1 -1
  45. package/web/_astro/{pieDiagram-4H26LBE5.CnEGAkqK.js → pieDiagram-4H26LBE5.xNCa7QSz.js} +1 -1
  46. package/web/_astro/{quadrantDiagram-W4KKPZXB.CsByTJjg.js → quadrantDiagram-W4KKPZXB.C_3DSB9b.js} +1 -1
  47. package/web/_astro/{requirementDiagram-4Y6WPE33.AL6ZRSrQ.js → requirementDiagram-4Y6WPE33.C2MFScI8.js} +1 -1
  48. package/web/_astro/{sankeyDiagram-5OEKKPKP.BLAeuWlE.js → sankeyDiagram-5OEKKPKP.DEy6YHUG.js} +1 -1
  49. package/web/_astro/{sequenceDiagram-3UESZ5HK.BGpsvxUR.js → sequenceDiagram-3UESZ5HK.CdQjeOkf.js} +1 -1
  50. package/web/_astro/{stateDiagram-AJRCARHV.BBk0gd25.js → stateDiagram-AJRCARHV.C-j_0D_L.js} +1 -1
  51. package/web/_astro/{stateDiagram-v2-BHNVJYJU.BrqvmSUS.js → stateDiagram-v2-BHNVJYJU.BMzYaYSQ.js} +1 -1
  52. package/web/_astro/{timeline-definition-PNZ67QCA.DkZf5CQT.js → timeline-definition-PNZ67QCA.BaAa5dDC.js} +1 -1
  53. package/web/_astro/{vennDiagram-CIIHVFJN.BZvWwMZF.js → vennDiagram-CIIHVFJN.GZL7T0cb.js} +1 -1
  54. package/web/_astro/{wardley-L42UT6IY.HfB08mt3.js → wardley-L42UT6IY.STDdK5oO.js} +1 -1
  55. package/web/_astro/{wardleyDiagram-YWT4CUSO.DgpZzmgA.js → wardleyDiagram-YWT4CUSO.BJLlSFei.js} +1 -1
  56. package/web/_astro/{xychartDiagram-2RQKCTM6.BlgrPsbQ.js → xychartDiagram-2RQKCTM6.CRGBFqsD.js} +1 -1
  57. package/web/index.html +2 -2
  58. package/web/_astro/BoardApp.EXjc9f_0.js +0 -1
  59. package/web/_astro/channel.DDlSVLNA.js +0 -1
  60. package/web/_astro/index.BSoQ0ZL0.css +0 -1
@@ -1,5 +1,5 @@
1
1
  $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
2
- # Require try/catch guard around GlobalRegistrator.register() in web tests.
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: wrap in try/catch:
13
- #
14
- # try { GlobalRegistrator.register(); } catch {} // already registered in suite
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
- # Helper that manages happy-dom lifecycle not a raw register call.
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() must be wrapped in try/catchwithout
50
- it, the second test file that calls it throws "already been globally
51
- registered" and all tests in that file are lost (a CI-only failure
52
- that never reproduces when a single file runs in isolation). Wrap:
53
- `try { GlobalRegistrator.register(); } catch {}`. 52-real CI incidents,
54
- 2026-07-09.
31
+ Do not call `GlobalRegistrator.register()` directly in a web testa
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 bare GlobalRegistrator.register() NOT inside try/catch
60
- # Negative lookbehind: line does NOT start with "try" before the call
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. The agent enumerates the work with
64
- `spur task list --feature ${featureId} --status todo --json`, then runs each task through
65
- task-pipeline.yaml (precheck → implement → test → review → approve → verify → record → done). It
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 config/workflows/task-pipeline.yaml --vars
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 --tasks feature:${vars.featureId}"
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 (config/workflows/idea-pipeline.yaml:352-366). No
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.10",
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.8",
54
- "@gobing-ai/ts-ai-runner": "^0.4.8",
55
- "@gobing-ai/ts-dual-workflow-engine": "^0.4.8",
56
- "@gobing-ai/ts-infra": "^0.4.8",
57
- "@gobing-ai/ts-llm-jsonl-importer": "^0.4.8",
58
- "@gobing-ai/ts-rule-engine": "^0.4.8",
59
- "@gobing-ai/ts-runtime": "^0.4.8",
60
- "@gobing-ai/ts-utils": "^0.4.8",
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
  },