@gobing-ai/spur 0.3.67 → 0.3.69

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 (79) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/corpus-baseline.json +2 -50
  3. package/config/templates/docs/99_PROJECT_CONSTITUTION.md +21 -16
  4. package/config/workflow-composition-baseline.json +110 -60
  5. package/config/workflows/basic.yaml +1 -1
  6. package/config/workflows/docs-pipeline.yaml +99 -23
  7. package/config/workflows/feature-dev.yaml +1 -1
  8. package/config/workflows/idea-pipeline.yaml +21 -23
  9. package/config/workflows/task-pipeline.yaml +233 -121
  10. package/config/workflows/wayfinder-resolution.yaml +1 -1
  11. package/config/workflows/wrapup-pipeline.yaml +1 -1
  12. package/package.json +9 -9
  13. package/plugins/sp/README.md +6 -7
  14. package/plugins/sp/commands/dev-idea.md +5 -3
  15. package/plugins/sp/commands/dev-plan.md +3 -1
  16. package/plugins/sp/commands/dev-review-session.md +2 -1
  17. package/plugins/sp/hooks/context-post-tool.ts +101 -2
  18. package/plugins/sp/hooks/context-session-start.ts +22 -1
  19. package/plugins/sp/plugin.json +1 -1
  20. package/plugins/sp/scripts/stage-registry-adapter.ts +144 -2
  21. package/plugins/sp/scripts/surface-drift-inventory.ts +2 -15
  22. package/plugins/sp/scripts/task-size-precheck.ts +21 -79
  23. package/plugins/sp/skills/session-review/SKILL.md +16 -0
  24. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +42 -17
  25. package/plugins/sp/skills/spur-dev/references/dev-operations.md +6 -6
  26. package/plugins/sp/skills/spur-dev/references/execution-batch.md +80 -11
  27. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +18 -13
  28. package/spur.js +2062 -609
  29. package/web/_astro/{BoardApp.BEtcJqde.js → BoardApp.BQFbkeqq.js} +15 -15
  30. package/web/_astro/BoardApp.CTkqrhWd.js +1 -0
  31. package/web/_astro/{TaskDetail.ClAbCXom.js → TaskDetail.Dl2Eaj1w.js} +1 -1
  32. package/web/_astro/{arc.CCvf51_y.js → arc.uG14rp8A.js} +1 -1
  33. package/web/_astro/{architectureDiagram-3BPJPVTR.C0cb0J5M.js → architectureDiagram-3BPJPVTR.Dye6uD_x.js} +1 -1
  34. package/web/_astro/{blockDiagram-GPEHLZMM.CIyjqoCE.js → blockDiagram-GPEHLZMM.B9Pkh7Hb.js} +1 -1
  35. package/web/_astro/{c4Diagram-AAUBKEIU.fs14IuFs.js → c4Diagram-AAUBKEIU.C2x7SC_X.js} +1 -1
  36. package/web/_astro/channel.Dsvulp7W.js +1 -0
  37. package/web/_astro/{chunk-2J33WTMH.CaBKv4ZO.js → chunk-2J33WTMH.D2p4-nWk.js} +1 -1
  38. package/web/_astro/{chunk-4BX2VUAB.BOllTPto.js → chunk-4BX2VUAB.S-6jf33o.js} +1 -1
  39. package/web/_astro/{chunk-55IACEB6.ChEof0O4.js → chunk-55IACEB6.DVXj4Fdh.js} +1 -1
  40. package/web/_astro/{chunk-727SXJPM.Co2kdjD8.js → chunk-727SXJPM.Dz689FMN.js} +1 -1
  41. package/web/_astro/{chunk-AQP2D5EJ.SWmfcnog.js → chunk-AQP2D5EJ.KxYj5TnI.js} +1 -1
  42. package/web/_astro/{chunk-FMBD7UC4.rDAFifF3.js → chunk-FMBD7UC4.itTQyHQB.js} +1 -1
  43. package/web/_astro/{chunk-ND2GUHAM.BCnoXKCw.js → chunk-ND2GUHAM.euSrbJf5.js} +1 -1
  44. package/web/_astro/{chunk-QZHKN3VN.RSmy2hDO.js → chunk-QZHKN3VN.OWASJRQy.js} +1 -1
  45. package/web/_astro/{classDiagram-4FO5ZUOK.Be7PEfrX.js → classDiagram-4FO5ZUOK.BLvrlpNO.js} +1 -1
  46. package/web/_astro/{classDiagram-v2-Q7XG4LA2.Be7PEfrX.js → classDiagram-v2-Q7XG4LA2.BLvrlpNO.js} +1 -1
  47. package/web/_astro/{cose-bilkent-S5V4N54A.BkUp2aSK.js → cose-bilkent-S5V4N54A.XBF-rmyD.js} +1 -1
  48. package/web/_astro/{cynefin-OW5HDTMX.BegGGlUV.js → cynefin-OW5HDTMX.DlCx762Z.js} +1 -1
  49. package/web/_astro/{dagre-BM42HDAG.BkUdjsaC.js → dagre-BM42HDAG.D17Rshxv.js} +1 -1
  50. package/web/_astro/{diagram-2AECGRRQ.E9vugt3-.js → diagram-2AECGRRQ.AhBIVJC8.js} +1 -1
  51. package/web/_astro/{diagram-5GNKFQAL.Dj4yeHXB.js → diagram-5GNKFQAL.C9ximjyC.js} +1 -1
  52. package/web/_astro/{diagram-KO2AKTUF.Buaquwli.js → diagram-KO2AKTUF.CZb7Ru_9.js} +1 -1
  53. package/web/_astro/{diagram-LMA3HP47.BV3dgGgm.js → diagram-LMA3HP47.BW7LwqoS.js} +1 -1
  54. package/web/_astro/{diagram-OG6HWLK6.Cnx3s-tc.js → diagram-OG6HWLK6.XC025W0V.js} +1 -1
  55. package/web/_astro/{erDiagram-TEJ5UH35.DKK_abu4.js → erDiagram-TEJ5UH35.CpMXmBDP.js} +1 -1
  56. package/web/_astro/{flowDiagram-I6XJVG4X.BNuu9fbm.js → flowDiagram-I6XJVG4X.D2ednJWg.js} +1 -1
  57. package/web/_astro/{ganttDiagram-6RSMTGT7.b16KUMjy.js → ganttDiagram-6RSMTGT7.BjL9FGKO.js} +1 -1
  58. package/web/_astro/{gitGraphDiagram-PVQCEYII.Kh41lbG5.js → gitGraphDiagram-PVQCEYII.B90g1VGk.js} +1 -1
  59. package/web/_astro/{infoDiagram-5YYISTIA.DEWBXkp-.js → infoDiagram-5YYISTIA.RqgycKtQ.js} +1 -1
  60. package/web/_astro/{ishikawaDiagram-YF4QCWOH.DiAdmcL6.js → ishikawaDiagram-YF4QCWOH.Ctn-zt6a.js} +1 -1
  61. package/web/_astro/{journeyDiagram-JHISSGLW.D1Ki7IRm.js → journeyDiagram-JHISSGLW.DJhT8Ctp.js} +1 -1
  62. package/web/_astro/{kanban-definition-UN3LZRKU.CWUhrQpc.js → kanban-definition-UN3LZRKU.BY1QdejI.js} +1 -1
  63. package/web/_astro/{linear.BaFsgcCe.js → linear.Di7YObSt.js} +1 -1
  64. package/web/_astro/{mermaid.core.CHw_AsGy.js → mermaid.core.CbxtJS3Q.js} +4 -4
  65. package/web/_astro/{mindmap-definition-RKZ34NQL.UIhghgmN.js → mindmap-definition-RKZ34NQL.CxvR4g_J.js} +1 -1
  66. package/web/_astro/{pieDiagram-4H26LBE5.D05l3JUA.js → pieDiagram-4H26LBE5.jNWqnBHH.js} +1 -1
  67. package/web/_astro/{quadrantDiagram-W4KKPZXB.BcWIhIcE.js → quadrantDiagram-W4KKPZXB.BCp12MbA.js} +1 -1
  68. package/web/_astro/{requirementDiagram-4Y6WPE33.B1rYvKGn.js → requirementDiagram-4Y6WPE33.Dxhm4TyR.js} +1 -1
  69. package/web/_astro/{sankeyDiagram-5OEKKPKP.CKylVRC4.js → sankeyDiagram-5OEKKPKP.BtQXp4J9.js} +1 -1
  70. package/web/_astro/{sequenceDiagram-3UESZ5HK.Dm3uA_s4.js → sequenceDiagram-3UESZ5HK.BWEM1R_Q.js} +1 -1
  71. package/web/_astro/{stateDiagram-AJRCARHV.Bgca_BLe.js → stateDiagram-AJRCARHV.BG3wUkWB.js} +1 -1
  72. package/web/_astro/{stateDiagram-v2-BHNVJYJU.C1T7YFrG.js → stateDiagram-v2-BHNVJYJU.BLtMeFVP.js} +1 -1
  73. package/web/_astro/{timeline-definition-PNZ67QCA.ZOHJn3Sn.js → timeline-definition-PNZ67QCA.D5fHo0az.js} +1 -1
  74. package/web/_astro/{vennDiagram-CIIHVFJN.DegZitjD.js → vennDiagram-CIIHVFJN.0DcuMluU.js} +1 -1
  75. package/web/_astro/{wardleyDiagram-YWT4CUSO.BDsC115d.js → wardleyDiagram-YWT4CUSO.BZ-dxgHm.js} +1 -1
  76. package/web/_astro/{xychartDiagram-2RQKCTM6.D0MO70ea.js → xychartDiagram-2RQKCTM6.Bg-XWF7z.js} +1 -1
  77. package/web/index.html +1 -1
  78. package/web/_astro/BoardApp.DBEin4N5.js +0 -1
  79. package/web/_astro/channel.BGn_DUCD.js +0 -1
@@ -54,15 +54,16 @@ vars:
54
54
  # runs and `workflow validate` resolve the template. (See AGENTS.md / ADR-026.)
55
55
  spurBin: "spur"
56
56
  # Agent the pipeline's agent.run steps invoke. Override per run with
57
- # `--vars '{"agent":"claude"}'`. Pinned (not left to the AiRunner's <default>
58
- # selection) so a broken/misconfigured agent on the box can't silently capture the run.
59
- agent: "omp"
60
- # Implement-only executor override (R1, task 0454). Resolves to this YAML literal
61
- # unless overridden. The `--agent` flag (execution-batch.md §3.2) forwards into BOTH
57
+ # `--vars '{"agent":"claude"}'`. `auto` is the reserved config-resolving selector:
58
+ # `agent.default` role -> tier -> cheapest USABLE executor. A named literal here would
59
+ # pin a box-specific binary into tracked SSOT and escape that usability ladder.
60
+ agent: "auto"
61
+ # Implement-only executor override (R1, task 0454). Resolves like `agent` unless
62
+ # overridden. The `--agent` flag (execution-batch.md §3.2) forwards into BOTH
62
63
  # `agent` and `implementAgent`, so a pinned `--agent X` reaches implement too. To
63
64
  # pin ONLY implement while other hops keep the default, pass
64
65
  # `--vars '{"implementAgent":"omp-zai"}'`.
65
- implementAgent: "omp"
66
+ implementAgent: "auto"
66
67
  # Step-level timeout for agentic hops (review / verify / test-fix) in ms.
67
68
  # Soft quality-gate shells are unbounded by this var (host shell only).
68
69
  # Raised 600s → 1800s (task 0398 R4 / H6 dogfood). Override:
@@ -78,15 +79,25 @@ vars:
78
79
  # Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
79
80
  # Empty by default; only meaningful once the approve state has been entered.
80
81
  __hitlAnswer: ""
81
- # Proof-state bracket (task 0612, ADR-071). `proofDigest` is captured at verify-exit, once the
82
- # verdict artifact exists; `proofDigestNow` is the re-capture compared against it immediately
83
- # before `record`. A mismatch means a proof input changed after the verdict was established, so
84
- # the run routes to `failed` instead of crossing the completion boundary. `taskSpecPath` carries
85
- # the task file path because `docs/tasks*` is excluded from the digest's git-tree half — spec
86
- # content is folded in explicitly or a task-file edit would go undetected.
82
+ # Proof-state bracket (task 0612, ADR-071; restructured by task 0703). `proofDigest` is the
83
+ # canonical capture taken at quality-gate ENTRY immediately before the evidence-producing
84
+ # final chain (quality review verify) and re-captured at `test-recheck` when bounded
85
+ # remediation mutated the tree, so every evidence stage names one fresh digest (R2/R4).
86
+ # `proofDigestNow` is the live re-capture compared against `proofDigest` at verify entry and
87
+ # immediately before `record`; a mismatch means a proof input changed after evidence was
88
+ # established, so the run routes to `failed` instead of crossing the completion boundary (R5).
89
+ # `taskSpecPath` carries the task file path because `docs/tasks*` is excluded from the digest's
90
+ # git-tree half — spec content is folded in explicitly or a task-file edit would go undetected.
91
+ # The fingerprint scopes task content to the proof-input sections only (Background, Requirements,
92
+ # Acceptance Criteria, Design, Plan), so record-time Solution/Testing/Review evidence writes do
93
+ # not retroactively invalidate the certified input set (R6).
87
94
  proofDigest: ""
88
95
  proofDigestNow: ""
89
96
  taskSpecPath: ""
97
+ # 0710 R4: task priority tier (P0..P4) extracted from the task frontmatter at the
98
+ # quality-gate stage. P0/P1 make the review/verify distinct-executor policy apply;
99
+ # unknown/empty priority means fresh-context-only (executor reuse allowed).
100
+ taskPriority: ""
90
101
  # Project quality gate for the `test` hop (probe + fixall + recheck). Override per project
91
102
  # with the same package-manager surface (this monorepo is Bun-only):
92
103
  # `--vars '{"qualityGateCmd":"bun run lint && bun run test"}'`. Soft probe, hard recheck,
@@ -114,11 +125,11 @@ vars:
114
125
  # file:line instead of re-deriving it from a fresh gate run (0482 R3).
115
126
  gateFindings: ""
116
127
  # Max R-items in ## Requirements before size precheck fails (R2, task 0454).
117
- # Override with `--vars '{"maxImplementReqs":"12"}'`.
118
- maxImplementReqs: "5"
128
+ # Override with `--vars '{"maxImplementReqs":"20"}'`.
129
+ maxImplementReqs: "10"
119
130
  # Max checklist items under ## Plan before size precheck fails (R2, task 0454).
120
- # Override with `--vars '{"maxImplementPlanItems":"15"}'`.
121
- maxImplementPlanItems: "8"
131
+ # Override with `--vars '{"maxImplementPlanItems":"32"}'`.
132
+ maxImplementPlanItems: "16"
122
133
  # Diff-scope guard on the implement hop (R1, task 0487). When the target task
123
134
  # body backticks at least one path, non-corpus changes outside those paths
124
135
  # fail the step by name. New files beside a declared file are allowed. Empty
@@ -129,37 +140,9 @@ vars:
129
140
  states:
130
141
  - id: precheck
131
142
  description: >
132
- Pre-flight: soft agent doctor + transition guards for doctor PASS and
133
- `spur task check <wbs>`. Failures route to the `failed` terminal state
134
- (not a raw lifecycle abort mid-enter).
143
+ Fast deterministic task readiness and size checks. Failures route to the
144
+ `failed` terminal state (not a raw lifecycle abort mid-enter).
135
145
  onEnter:
136
- # Pre-launch executor doctor probe (task 0608 / D6 R4–R5). The auth classifier —
137
- # per-agent-family classification (omp/pi env-key misses soft, explicit auth
138
- # failures hard) plus the executor-divergence line — now lives in the
139
- # `doctor.probe` built-in action kind (`packages/app/src/workflow/actions/doctor-probe.ts`)
140
- # instead of this shell program; that is the ownership-surface landing for the
141
- # task-pipeline precheck doctor probe (option c, least-privilege built-in).
142
- #
143
- # Semantics preserved from the replaced shell (behavior parity is covered by
144
- # `packages/app/tests/workflow/actions/doctor-probe.test.ts`):
145
- # R2 (0487): probe BOTH resolved executors ($agent and $implementAgent) and
146
- # FAIL on `authenticated: unauthenticated`. Previously only $agent was probed
147
- # and auth was informational, so a run whose implement executor had no
148
- # provider key sailed through precheck into a guaranteed implement failure
149
- # (runs e8cb00e7 / b16bfbf4). `unknown` auth keeps the old soft behavior —
150
- # some agents expose no auth-status verb. `spur agent doctor` CLI exit-code
151
- # semantics are deliberately untouched; the gate lives here.
152
- # R4 (0487): one divergence line when the two executors differ.
153
- # R2 (0503): omp/pi env-key probe misses are soft because the CLI process
154
- # cannot see relay-owned credentials; explicit non-omp auth failures remain hard.
155
- # Soft probe: writes PASS/FAIL to the status file and always succeeds so the
156
- # transition guards below route on the token (never a raw lifecycle abort).
157
- - kind: doctor.probe
158
- options:
159
- resultFile: ".spur/run/${vars.wbs}-precheck-doctor.status"
160
- spurBin: "${vars.spurBin}"
161
- agent: "${vars.agent}"
162
- implementAgent: "${vars.implementAgent}"
163
146
  # R6 (0487): pre-launch hygiene WARNING (never a block) — starting a task on
164
147
  # a tree already dirty with another task's implementation is how 0485's diff
165
148
  # got swept into 0486's run. Corpus dirs are excluded: the pipeline writes
@@ -192,6 +175,10 @@ states:
192
175
  # R1 (0453): auto-profile precheck reopens a done feature before task check.
193
176
  # Under profile=auto, resolve feature_id, sync (preferred) or update to active.
194
177
  # Under non-auto, leave R4 message to guide the operator.
178
+ # R3 (0723): a real reactivation failure is surfaced, not swallowed —
179
+ # the default 'fail' onEnter policy halts the sequence and routes the
180
+ # run to `failed` before implementation. Verbs stay single-shot:
181
+ # one sync, then one update fallback, never retried in a loop.
195
182
  - kind: shell
196
183
  options:
197
184
  command: >-
@@ -199,17 +186,23 @@ states:
199
186
  FID=$($spurBin task show $wbs --json 2>/dev/null |
200
187
  jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null);
201
188
  if [ -n "$FID" ]; then
202
- $spurBin feature sync "$FID" --force --json 2>/dev/null ||
203
- $spurBin feature update "$FID" active 2>/dev/null || true;
189
+ if ! $spurBin feature sync "$FID" --force 2>/dev/null; then
190
+ if ! $spurBin feature update "$FID" active 2>/dev/null; then
191
+ echo "precheck: FAIL - feature reactivation $FID failed;" >&2;
192
+ echo "precheck: feature sync + feature update both errored" >&2;
193
+ exit 1;
194
+ fi;
195
+ fi;
204
196
  fi;
205
197
  fi;
206
198
  exit 0
207
- # R2 (0454): task size precheck — evaluate R-item and Plan-item counts.
208
- # Writes PASS/FAIL to .spur/run/<wbs>-precheck-size.status. Always exit 0
209
- # (soft check, like doctor). The precheck→implement guard reads the file.
210
- # R3 (0487): `--executor` adds the size-vs-capability gate a task past the
211
- # DEFAULT caps routed to a sub-`capable-1` executor blocks here instead of
212
- # burning the full implementTimeoutMs and exiting 3 (run ca130182).
199
+ # R2 (0454, 0723): task size precheck — deterministic count-only
200
+ # evaluation of R-item and Plan-item counts. No executor-tier policy:
201
+ # dispatch-time requiresCapabilities at `agent.run` is the
202
+ # authoritative capability check. Writes PASS/FAIL to
203
+ # .spur/run/<wbs>-precheck-size.status. Always exit 0 (soft action);
204
+ # the precheck→implement guard reads the file, so a missing checker
205
+ # fails closed (writes FAIL, never PASS).
213
206
  - kind: shell
214
207
  options:
215
208
  command: >-
@@ -217,11 +210,12 @@ states:
217
210
  mkdir -p .spur/run &&
218
211
  if [ -f plugins/sp/scripts/task-size-precheck.ts ]; then
219
212
  bun plugins/sp/scripts/task-size-precheck.ts "$wbs"
220
- --spur-bin "$spurBin" --max-reqs "$maxImplementReqs" --max-plan-items "$maxImplementPlanItems"
221
- --executor "$implementAgent";
213
+ --spur-bin "$spurBin" --max-reqs "$maxImplementReqs"
214
+ --max-plan-items "$maxImplementPlanItems";
222
215
  else
223
- echo "task-size-precheck skippedplugins/sp/scripts/task-size-precheck.ts not present in project." >&2 &&
224
- echo "PASS" > "$SIZE_FILE";
216
+ echo "task-size-precheck failed closed checker script" >&2 &&
217
+ echo "plugins/sp/scripts/task-size-precheck.ts absent." >&2 &&
218
+ echo "FAIL" > "$SIZE_FILE";
225
219
  fi &&
226
220
  exit 0
227
221
 
@@ -243,7 +237,7 @@ states:
243
237
  options:
244
238
  agent: ${vars.implementAgent}
245
239
  # Pure slash command only (ADR-043). Anti-recursion / implement discipline
246
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
240
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
247
241
  role: coder
248
242
  # lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
249
243
  input: /sp:dev-run --mode implement ${vars.wbs} --auto
@@ -253,6 +247,14 @@ states:
253
247
  # a silent no-op routes the run to `failed` here instead of drifting
254
248
  # into test/review and being caught a full pass later.
255
249
  requireDiff: true
250
+ # 0706 R6: this stage mutates the working tree unattended under the
251
+ # auto profile, so it declares minimum execution-capability
252
+ # requirements. Dispatch fails closed (before spawn) when the
253
+ # resolved executor's attestation cannot satisfy them — attest the
254
+ # executor in agent config.
255
+ requiresCapabilities:
256
+ fsWrite: available
257
+ processSpawn: available
256
258
  - kind: shell
257
259
  options:
258
260
  command: >-
@@ -296,11 +298,37 @@ states:
296
298
  # test-recheck — soft recheck → review | test-fix | failed (never silent lifecycle abort)
297
299
  - id: test
298
300
  description: >
299
- Soft quality-gate probe (single logical gate on the green path; bounded retries only
300
- for SQLite lock contention). Runs
301
+ Proof-chain entry + soft quality-gate probe (single logical gate on the green path; bounded retries only
302
+ for SQLite lock contention). Capture of the canonical proof-input digest happens HERE — before any
303
+ evidence-producing final check (task 0703, ADR-071) — so the gate, review, and verification evidence
304
+ all name one digest. Then runs
301
305
  `${vars.qualityGateCmd}`, records PASS|FAIL under
302
306
  `.spur/run/<wbs>-test-gate.status`, resets the fix attempt counter, always exit 0.
303
307
  onEnter:
308
+ # R6/R2 (0703): resolve the task-spec path BEFORE the digest capture. `docs/tasks*` is excluded
309
+ # from the digest's git-tree half, so the spec is folded in explicitly via `taskSpecPath`.
310
+ - kind: shell
311
+ options:
312
+ # 0710 R4: resolve the spec path, then extract `priority:` from the TASK FILE itself (not the
313
+ # path listing); normalize to upper so requiresDistinctExecutor's exact 'P0'/'P1' match hits.
314
+ # Missing spec/line -> empty var -> back-compat (no distinctness requirement).
315
+ command: '$spurBin task path $wbs --json 2>/dev/null | jq -r ".path // .filePath // empty" > ".spur/run/$wbs-taskpath.txt" || true; sed -n "s/^priority:[[:space:]]*//p" "$(cat ".spur/run/$wbs-taskpath.txt" 2>/dev/null)" 2>/dev/null | head -1 | tr -d "[:space:]" | tr "[:lower:]" "[:upper:]" > ".spur/run/$wbs-priority.txt"; exit 0'
316
+ - kind: file.read.into-var
317
+ options:
318
+ path: .spur/run/${vars.wbs}-taskpath.txt
319
+ var: taskSpecPath
320
+ # 0710 R4: carry the task's priority tier into the review/verify risk policy.
321
+ - kind: file.read.into-var
322
+ options:
323
+ path: .spur/run/${vars.wbs}-priority.txt
324
+ var: taskPriority
325
+ # R2 (0703, ADR-071): THE canonical proof capture. Placement is load-bearing: immediately before
326
+ # the final evidence chain, after every implement mutation (including the post-implement format).
327
+ # Capture-only here; `record` compares. A remediation pass re-captures at `test-recheck` (R4).
328
+ - kind: proof.fingerprint
329
+ options:
330
+ var: proofDigest
331
+ taskFile: ${vars.taskSpecPath}
304
332
  - kind: shell
305
333
  options:
306
334
  command: >-
@@ -331,13 +359,17 @@ states:
331
359
  else
332
360
  printf 'FAIL\n' > "$STATUS_FILE";
333
361
  fi &&
362
+ printf 'proof-digest: %s\n' "$proofDigest" >> "$LOG_FILE" &&
334
363
  exit 0
335
364
 
336
365
  - id: test-fix
337
366
  description: >
338
- Bounded auto-fix hop when the quality gate is red. Increments
339
- `.spur/run/<wbs>-test-fix-attempt`, then pure slash (ADR-043)
340
- `/sp:dev-fixall` against `${vars.qualityGateCmd}`.
367
+ Bounded auto-fix hop when the quality gate is red OR final verification returned a
368
+ repairable non-PASS (task 0703 R4: remediation never happens inside verify — it loops
369
+ through here, then re-enters quality → review → verify on a fresh digest). Increments
370
+ `.spur/run/<wbs>-test-fix-attempt` (the shared bound with the quality path), projects the
371
+ verify verdict into the gate log when one exists so the repair hop sees it, then pure
372
+ slash (ADR-043) `/sp:dev-fixall` against `${vars.qualityGateCmd}`.
341
373
  onEnter:
342
374
  - kind: shell
343
375
  options:
@@ -345,7 +377,13 @@ states:
345
377
  mkdir -p .spur/run &&
346
378
  ATTEMPT_FILE=".spur/run/$wbs-test-fix-attempt" &&
347
379
  n=$(cat "$ATTEMPT_FILE" 2>/dev/null || echo 0) &&
348
- printf '%s\n' "$((n + 1))" > "$ATTEMPT_FILE"
380
+ printf '%s\n' "$((n + 1))" > "$ATTEMPT_FILE" &&
381
+ if [ -f ".spur/run/$wbs-verdict.json" ]; then
382
+ { echo '--- verify verdict (remediation input, task 0703 R4) ---';
383
+ cat ".spur/run/$wbs-verdict.json";
384
+ } >> ".spur/run/$wbs-test-gate.log";
385
+ fi;
386
+ exit 0
349
387
  # R3 (0482): project the extracted gate anchors into a var so the dispatch input
350
388
  # can NAME the failing file:line, not merely point at a log. A vars template cannot
351
389
  # run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
@@ -357,11 +395,16 @@ states:
357
395
  options:
358
396
  agent: ${vars.agent}
359
397
  # R3 (0482): `--findings` names the failing anchors inline; `--gate-log` remains
360
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
398
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
361
399
  role: coder
362
400
  # the full-context escape hatch when the digest is not enough.
363
401
  input: /sp:dev-fixall "${vars.qualityGateCmd}" --gate-log .spur/run/${vars.wbs}-test-gate.log --findings "${vars.gateFindings}"
364
402
  timeoutMs: ${vars.stepTimeoutMs}
403
+ # 0706 R6: bounded remediation hop — unattended and tree-mutating,
404
+ # so it declares the same minimum requirements as `implement`.
405
+ requiresCapabilities:
406
+ fsWrite: available
407
+ processSpawn: available
365
408
 
366
409
  - id: test-recheck
367
410
  description: >
@@ -370,6 +413,13 @@ states:
370
413
  or the pipeline `failed` state (FAIL and attempts exhausted) — never a
371
414
  raw lifecycle abort that skips the terminal `failed` state.
372
415
  onEnter:
416
+ # R4 (0703, ADR-071): bounded remediation mutated the tree by design, so the fresh evidence
417
+ # chain (recheck gate → review → verify) must start from a NEWLY captured digest. Capture-only;
418
+ # the guards and `record` compare against this value.
419
+ - kind: proof.fingerprint
420
+ options:
421
+ var: proofDigest
422
+ taskFile: ${vars.taskSpecPath}
373
423
  # 0587 R3: probe-then-full recheck. A red gateProbeCmd records FAIL and skips the full
374
424
  # gate (the measured waste is re-running a 110–140s gate to learn the tree is still red);
375
425
  # a green probe (or empty gateProbeCmd) falls through to the full-gate loop unchanged.
@@ -413,6 +463,7 @@ states:
413
463
  else
414
464
  printf 'FAIL\n' > "$STATUS_FILE";
415
465
  fi &&
466
+ printf 'proof-digest: %s\n' "$proofDigest" >> "$LOG_FILE" &&
416
467
  exit 0
417
468
 
418
469
  - id: review
@@ -420,10 +471,19 @@ states:
420
471
  onEnter:
421
472
  - kind: agent.run
422
473
  options:
423
- agent: ${vars.agent}
474
+ # 0710 R2: review always runs on a fresh session — no implementation-session
475
+ # inheritance, no latch resume; implementation context reaches the reviewer
476
+ # only via the persisted task spec, the recorded diff, and run artifacts.
477
+ # 0710 R4/R5: the agent pin is deliberately gone — role: reviewer routes
478
+ # through the executor registry, and the runner enforces (pre-dispatch,
479
+ # fail-closed) that a P0/P1 task's review resolves a DIFFERENT executor
480
+ # spec than the implement stage recorded in __agentRouting_implement.
424
481
  input: /sp:dev-review ${vars.wbs} --auto
425
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
482
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
426
483
  role: reviewer
484
+ freshSession: true
485
+ priority: ${vars.taskPriority}
486
+ compareExecutorWith: implement
427
487
  timeoutMs: ${vars.stepTimeoutMs}
428
488
 
429
489
  - id: approve
@@ -441,47 +501,64 @@ states:
441
501
 
442
502
  - id: verify
443
503
  description: >
444
- Functional verification (BDD + traceability) via /sp:dev-verify. The agent's
504
+ Observe-only functional verification (BDD + traceability) via /sp:dev-verify --fix none
505
+ (task 0703 R1, ADR-071): the verifier certifies the state, it never repairs its own subject.
506
+ A live digest compare BEFORE the agent refuses to certify a state that drifted after the
507
+ quality/review evidence was produced (R2). The agent's
445
508
  captured answer is written to `.spur/run/<wbs>-verify-answer.txt` and MUST follow
446
509
  the answer-file schema contract (explicit `Verdict: PASS|PARTIAL|FAIL` line plus
447
510
  `| Req | Status | Evidence |` and `| AC | Status | Evidence Type | Evidence |` tables);
448
511
  a deterministic shell step then derives the verdict and writes the gate artifact
449
512
  `.spur/run/<wbs>-verdict.json` (so the completion gate reads a real verdict, not
450
- agent discretion — R9). The verdict is PASS only if the agent both reported PASS
451
- AND `spur task check` passes; otherwise FAIL.
513
+ agent discretion — R9) with a proof block naming the digest and the per-stage results (R3).
514
+ Repairable non-PASS routes once through the bounded remediation hop (verify → test-fix,
515
+ R4); the chain reruns on a fresh digest.
452
516
  onEnter:
517
+ # R2 (0703): midpoint bracket compare — refuse to spend verification on a state that no
518
+ # longer matches the digest the quality/review evidence names. Reuses `proofDigestNow`:
519
+ # set here and re-set by the final compare at `record` entry.
520
+ - kind: proof.fingerprint
521
+ options:
522
+ var: proofDigestNow
523
+ taskFile: ${vars.taskSpecPath}
524
+ expect: ${vars.proofDigest}
453
525
  - kind: agent.run
454
526
  options:
455
- agent: ${vars.agent}
456
- input: /sp:dev-verify ${vars.wbs} --auto --fix all --focus all
457
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
527
+ # 0710 R2: verify is a separate fresh-session execution — never the review
528
+ # session, never the implement session (R6).
529
+ # 0710 R4/R5: role-routed like review; P0/P1 demands a distinct executor.
530
+ # R1 (0703, ADR-071): `--fix none` — final verification is observe-only. Remediation
531
+ # belongs to the bounded test-fix hop, never to the certifying pass.
532
+ input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
533
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
458
534
  role: reviewer
535
+ freshSession: true
536
+ priority: ${vars.taskPriority}
537
+ compareExecutorWith: implement
459
538
  timeoutMs: ${vars.stepTimeoutMs}
460
539
  answerFile: .spur/run/${vars.wbs}-verify-answer.txt
461
540
  - kind: shell
462
541
  options:
463
542
  command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
464
- # Proof-state capture (task 0612, ADR-071). Placement is load-bearing: AFTER the verdict
465
- # artifact exists, never before `verify`. `/sp:dev-verify --fix all` writes to the tree by
466
- # design when it repairs a row, so an earlier capture would fire on verify's own legitimate
467
- # repairs instead of on a violation.
468
- - kind: shell
469
- options:
470
- command: '$spurBin task path $wbs --json 2>/dev/null | jq -r ".path // empty" > ".spur/run/$wbs-taskpath.txt" || true; exit 0'
471
- - kind: file.read.into-var
472
- options:
473
- path: .spur/run/${vars.wbs}-taskpath.txt
474
- var: taskSpecPath
475
- - kind: proof.fingerprint
476
- options:
477
- var: proofDigest
478
- taskFile: ${vars.taskSpecPath}
479
- # R3: the evidence must NAME the digest, not just assert proof validity in prose. Stamp it
480
- # into the verdict artifact's checks[] so the document that aggregates quality, review, and
481
- # verification results carries the value `record`'s compare then proves unchanged.
543
+ # R3 (0703): write the required proof block into the verdict artifact — the digest, the
544
+ # capture point, and the named per-stage results, each stage carrying the SAME digest
545
+ # value (prose asserting proof validity is insufficient). Also keeps the flat
546
+ # `proof-input-digest` check row for consumers that read `checks[]`. Soft action + hard
547
+ # guard: a missing/malformed stamp fails the `verify → record` guard below, not this step.
482
548
  - kind: shell
483
549
  options:
484
- command: 'V=".spur/run/$wbs-verdict.json"; if [ -f "$V" ] && [ -n "$proofDigest" ]; then jq --arg d "$proofDigest" ".checks += [{\"name\":\"proof-input-digest\",\"status\":\"pass\",\"evidence\":\$d}]" "$V" > "$V.tmp" && mv "$V.tmp" "$V"; fi; exit 0'
550
+ command: >-
551
+ V=".spur/run/$wbs-verdict.json";
552
+ if [ -f "$V" ] && [ -n "$proofDigest" ]; then
553
+ jq --arg d "$proofDigest" --arg g "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null || echo UNKNOWN)"
554
+ '. + {proof: {digest: $d, capturePoint: "quality-gate-entry", stages: {
555
+ qualityGate: {status: $g, digest: $d},
556
+ review: {status: "completed", digest: $d},
557
+ verification: {status: .verdict, digest: $d}}}}
558
+ | .checks += [{name: "proof-input-digest", status: "pass", evidence: $d}]'
559
+ "$V" > "$V.tmp" && mv "$V.tmp" "$V";
560
+ fi;
561
+ exit 0
485
562
 
486
563
  - id: record
487
564
  description: >
@@ -492,10 +569,15 @@ states:
492
569
  retry-suppression) if `feature_id` is present, or appends an orphan link proposal
493
570
  to the run report if absent (task 0328 / ADR-0322).
494
571
  onEnter:
495
- # Proof-state compare (task 0612, ADR-071) FIRST action in the state, so it runs before any
496
- # record write. Re-captures the digest and asserts it equals the value taken at verify-exit.
497
- # A mismatch means a proof input changed after the verdict was established; the default `fail`
498
- # policy halts the sequence and routes the run to `failed` rather than crossing into `record`.
572
+ # Proof-state compare (task 0612, ADR-071; bracket closed against the pre-chain
573
+ # capture per task 0703) FIRST action in the state, before any record write.
574
+ # Re-captures the digest and asserts it equals the value the evidence chain started
575
+ # from. A mismatch means a proof input changed after evidence was established; the
576
+ # default `fail` policy halts the sequence and routes the run to `failed` rather
577
+ # than crossing into `record`. Task-spec evidence writes (Testing/Review/Solution,
578
+ # R6) happen only in the actions AFTER this comparison, and the fingerprint scopes
579
+ # task content to the proof-input sections, so they cannot invalidate the certified
580
+ # input set.
499
581
  - kind: proof.fingerprint
500
582
  options:
501
583
  var: proofDigestNow
@@ -573,10 +655,17 @@ states:
573
655
  - kind: note
574
656
  options:
575
657
  message: "Pipeline complete for task ${vars.wbs} (done gate cleared)."
576
- # Checkpoint write: record session state for resume (Phase 4, task 0171 R3)
658
+ # Checkpoint write: record session state for resume (0711 R1–R3)
659
+ # canonical frontmatter contract; mirrors the Session Checkpoint
660
+ # Convention in plugins/sp/skills/spur-dev/references/cross-cutting.md.
661
+ # Advisory only: the task file and the persisted run row stay authoritative.
577
662
  - kind: shell
578
663
  options:
579
- command: 'mkdir -p .spur/memory/sessions && echo "checkpoint: task-pipeline done wbs=$wbs ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)" > .spur/memory/sessions/$wbs-checkpoint.md'
664
+ # Single logical line: the composition-baseline argument-split lint flags any
665
+ # command whose continuation lines look like argument lists (heredocs with
666
+ # `- item` entries trip it), so the checkpoint body is one printf with \n escapes.
667
+ command: >-
668
+ mkdir -p .spur/memory/sessions; CP_TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"; CP_COMMIT="$(git rev-parse HEAD 2>/dev/null || echo unknown)"; CP_DIGEST="$(cut -d= -f2 .spur/run/$wbs-proofdigest.txt 2>/dev/null || echo '')"; CP_RUN="$SPUR_RUN_ID"; [ -z "$CP_RUN" ] && CP_RUN="$RUN_ID"; printf '%s\n' '---' 'schema_version: 1' "session_id: $(date -u +%Y-%m-%d)-$wbs" 'workflow: task-pipeline' "run_id: $CP_RUN" "task_wbs: $wbs" 'feature_id: ""' 'phase: done' 'status: done' 'last_gate: record' "source_commit: $CP_COMMIT" "digest: $CP_DIGEST" "generated_at: $CP_TS" "updated_at: $CP_TS" "next_action: none - task $wbs complete (terminal; advisory only)" 'artifacts:' ' - .spur/run/$wbs-verdict.json' ' - .spur/run/$wbs-test-gate.log' '---' '' '## Session Notes' '' "Terminal checkpoint for task $wbs (task-pipeline done)." 'Advisory only; the task file is authoritative.' > .spur/memory/sessions/$wbs-checkpoint.md; exit 0
580
669
 
581
670
  - id: failed
582
671
  description: >
@@ -587,17 +676,17 @@ states:
587
676
  description: Terminal — pipeline cancelled by operator at the approval gate (R1).
588
677
 
589
678
  transitions:
590
- # ── precheck: doctor PASS + task check → implement; else → failed ──
679
+ # ── precheck: size PASS + task check → implement; else → failed ──
591
680
  - from: precheck
592
681
  to: implement
593
- description: Agent doctor PASS and task check green — begin implementation.
682
+ description: Deterministic size and task checks are green — begin implementation.
594
683
  guard:
595
684
  kind: shell
596
685
  options:
597
- command: 'test "$(cat .spur/run/$wbs-precheck-doctor.status 2>/dev/null)" = PASS && test "$(cat .spur/run/$wbs-precheck-size.status 2>/dev/null)" = PASS && $spurBin task check $wbs'
686
+ command: 'test "$(cat .spur/run/$wbs-precheck-size.status 2>/dev/null)" = PASS && $spurBin task check $wbs'
598
687
  - from: precheck
599
688
  to: failed
600
- description: Doctor FAIL and/or task check failed — stop before implement.
689
+ description: Size and/or task check failed — stop before implement.
601
690
  guard:
602
691
  kind: always
603
692
 
@@ -707,39 +796,62 @@ transitions:
707
796
  command: 'test "$__hitlAnswer" = cancel'
708
797
 
709
798
  # ── completion gate (the YAML-native replacement for rd3's default-on --postflight-verify) ──
710
- # The verify step emits .spur/run/<wbs>-verdict.json. Only `verdict: PASS` clears
711
- # the gate to `record`; any non-PASS (PARTIAL/FAIL), a missing file, or malformed
712
- # JSON routes to `failed`. Declaration order: PASS guard tried FIRST.
799
+ # The verify step emits .spur/run/<wbs>-verdict.json with a required proof block (task 0703 R3/R5).
800
+ # Only `verdict: PASS` PLUS a proof block whose digest — top level and every named stage — equals
801
+ # the captured `proofDigest` clears the gate to `record`; any non-PASS, a missing file, malformed
802
+ # JSON, or missing/mismatched proof evidence does not. Declaration order: PASS+proof guard FIRST,
803
+ # then the bounded remediation route (R4), then the always catch-all so a PASS verdict with a
804
+ # missing/malformed proof block still terminates at `failed` instead of hanging the state.
713
805
  - from: verify
714
806
  to: record
715
- description: Verification verdict is PASS — record results and proceed to done.
807
+ description: Verification verdict is PASS and its proof block names the captured digest on every stage — record results and proceed to done.
716
808
  guard:
717
809
  kind: shell
718
810
  options:
719
- command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS'
811
+ command: >-
812
+ V=".spur/run/$wbs-verdict.json";
813
+ test "$(jq -r .verdict "$V" 2>/dev/null)" = PASS &&
814
+ test "$(jq -r '.proof.digest // ""' "$V" 2>/dev/null)" = "$proofDigest" &&
815
+ test "$(jq -r '.proof.stages.qualityGate.digest // ""' "$V" 2>/dev/null)" = "$proofDigest" &&
816
+ test "$(jq -r '.proof.stages.review.digest // ""' "$V" 2>/dev/null)" = "$proofDigest" &&
817
+ test "$(jq -r '.proof.stages.verification.digest // ""' "$V" 2>/dev/null)" = "$proofDigest"
720
818
  - from: verify
721
- to: failed
722
- description: Verification verdict is not PASS (PARTIAL/FAIL/missing) — block before done.
819
+ to: test-fix
820
+ description: >-
821
+ Verification returned a repairable non-PASS and the shared fix budget is not exhausted —
822
+ bounded remediation hop (task 0703 R4); the chain re-enters quality → review → verify on a
823
+ freshly captured digest. Never reached on PASS: remediation cannot follow certification.
723
824
  guard:
724
825
  kind: shell
725
826
  options:
726
- command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" != PASS'
727
- # ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23) ──
728
- # The record step guarantees every done-required section ([Solution, Testing, Review])
729
- # has real content (each owned by its pipeline step). This guard is defense-in-depth
730
- # it certifies the matrix before done; a genuinely non-compliant task routes to failed.
827
+ command: >-
828
+ V="$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)";
829
+ test -n "$V" && test "$V" != PASS &&
830
+ test "$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)" -lt "$qualityGateMaxFixAttempts"
831
+ - from: verify
832
+ to: failed
833
+ description: >-
834
+ Non-PASS with the fix budget exhausted, or a PASS/missing/malformed verdict whose proof
835
+ block is absent or mismatched (task 0703 R5) — block before done; defense catch-all so the
836
+ state always has a viable outgoing edge.
837
+ guard:
838
+ kind: always
839
+ # ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23)
840
+ # PLUS the proof-block re-assertion (task 0703 R5): the verdict artifact must still be PASS and
841
+ # still name the captured digest — a forged or mutated completion artifact fails closed here.
731
842
  # Declaration order: pass guard first.
732
843
  - from: record
733
844
  to: done
734
- description: Task check passed — certify done.
845
+ description: Task check passed and the verdict proof block still names the captured digest — certify done.
735
846
  guard:
736
847
  kind: shell
737
848
  options:
738
- command: "$spurBin task check $wbs"
849
+ command: >-
850
+ $spurBin task check $wbs &&
851
+ test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS &&
852
+ test "$(jq -r '.proof.digest // ""' .spur/run/$wbs-verdict.json 2>/dev/null)" = "$proofDigest"
739
853
  - from: record
740
854
  to: failed
741
- description: Task check failed — block before done; investigate missing sections.
855
+ description: Task check failed or proof evidence missing/malformed/mismatched — block before done.
742
856
  guard:
743
- kind: shell
744
- options:
745
- command: "! $spurBin task check $wbs"
857
+ kind: always
@@ -27,7 +27,7 @@ vars:
27
27
  wbs: "0000"
28
28
  profile: "standard"
29
29
  spurBin: "spur"
30
- agent: "omp"
30
+ agent: "auto"
31
31
  stepTimeoutMs: "1800000"
32
32
  approval: "required"
33
33
  resolutionMode: "research"
@@ -49,7 +49,7 @@ vars:
49
49
  profile: "standard"
50
50
  merge: "false"
51
51
  spurBin: "spur"
52
- agent: "omp"
52
+ agent: "auto"
53
53
  stepTimeoutMs: "1800000"
54
54
  # Corpus-aware quality gate for the feature-transition hop (R1, task 0625).
55
55
  # The per-task gate (`spur-check`) deliberately excludes corpus-check — the only
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.67",
3
+ "version": "0.3.69",
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.46",
57
- "@gobing-ai/ts-ai-runner": "^0.4.46",
58
- "@gobing-ai/ts-dual-workflow-engine": "^0.4.46",
59
- "@gobing-ai/ts-infra": "^0.4.46",
60
- "@gobing-ai/ts-llm-jsonl-importer": "^0.4.46",
61
- "@gobing-ai/ts-rule-engine": "^0.4.46",
62
- "@gobing-ai/ts-runtime": "^0.4.46",
63
- "@gobing-ai/ts-utils": "^0.4.46",
56
+ "@gobing-ai/ts-db": "^0.4.48",
57
+ "@gobing-ai/ts-ai-runner": "^0.4.48",
58
+ "@gobing-ai/ts-dual-workflow-engine": "^0.4.48",
59
+ "@gobing-ai/ts-infra": "^0.4.48",
60
+ "@gobing-ai/ts-llm-jsonl-importer": "^0.4.48",
61
+ "@gobing-ai/ts-rule-engine": "^0.4.48",
62
+ "@gobing-ai/ts-runtime": "^0.4.48",
63
+ "@gobing-ai/ts-utils": "^0.4.48",
64
64
  "@types/bun": "1.3.14",
65
65
  "@types/figlet": "^1.7.0",
66
66
  "@types/node-notifier": "8.0.5",