@gobing-ai/spur 0.4.3 → 0.4.5

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 (119) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/rules/docs/sourced-api-claims.yaml +3 -2
  3. package/config/rules/quality/coverage-gate.yaml +13 -0
  4. package/config/rules/recommended-pre-check.yaml +11 -5
  5. package/config/rules/strict/runtime-boundaries.yaml +3 -0
  6. package/config/rules/surface/check-cli-surface.yaml +1 -3
  7. package/config/templates/AGENTS.md +7 -0
  8. package/config/workflows/feature-verification.yaml +9 -1
  9. package/config/workflows/task-lifecycle.yaml +50 -0
  10. package/config/workflows/task-pipeline.yaml +31 -65
  11. package/package.json +10 -10
  12. package/plugins/sp/agents/super-reviewer.md +11 -24
  13. package/plugins/sp/commands/dev-changelog.md +1 -1
  14. package/plugins/sp/commands/dev-gitmsg.md +6 -2
  15. package/plugins/sp/commands/dev-handover.md +1 -0
  16. package/plugins/sp/commands/dev-job-dump.md +2 -1
  17. package/plugins/sp/commands/dev-refine.md +14 -2
  18. package/plugins/sp/commands/dev-refineall.md +7 -1
  19. package/plugins/sp/commands/dev-review.md +1 -0
  20. package/plugins/sp/lib/history-anatomy.generated.mjs +18 -18
  21. package/plugins/sp/lib/idea-handoff.generated.mjs +91 -91
  22. package/plugins/sp/lib/inline-run.generated.mjs +233 -277
  23. package/plugins/sp/lib/plan-projection.generated.mjs +62 -38
  24. package/plugins/sp/lib/quality-gate.generated.d.mts +1 -0
  25. package/plugins/sp/lib/quality-gate.generated.mjs +13793 -13966
  26. package/plugins/sp/lib/residual-scan.generated.mjs +20 -34
  27. package/plugins/sp/lib/step-profile.generated.mjs +8 -8
  28. package/plugins/sp/plugin.json +1 -1
  29. package/plugins/sp/scripts/batch-plan.mjs +62 -40
  30. package/plugins/sp/scripts/batch-preflight.mjs +34 -12
  31. package/plugins/sp/scripts/commit-guard.mjs +6 -6
  32. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +26 -28
  33. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +11 -11
  34. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +4 -4
  35. package/plugins/sp/scripts/feature-verification-steps.mjs +15 -4
  36. package/plugins/sp/scripts/feature-verification-steps.ts +29 -1
  37. package/plugins/sp/scripts/history-anatomy-cache.mjs +19 -19
  38. package/plugins/sp/scripts/idea-handoff.mjs +2 -2
  39. package/plugins/sp/scripts/inline-run-dispatch.mjs +2 -2
  40. package/plugins/sp/scripts/inline-run-setup.mjs +20 -20
  41. package/plugins/sp/scripts/persist-out-check.mjs +5 -5
  42. package/plugins/sp/scripts/pr-reviewing.mjs +13 -13
  43. package/plugins/sp/scripts/quality-gate.mjs +13715 -13884
  44. package/plugins/sp/scripts/residual-scan.mjs +24 -38
  45. package/plugins/sp/scripts/residual-scan.ts +4 -6
  46. package/plugins/sp/scripts/run-summary.mjs +15 -15
  47. package/plugins/sp/scripts/script-root.mjs +6 -6
  48. package/plugins/sp/scripts/session-timeline.mjs +16 -16
  49. package/plugins/sp/scripts/task-diffstat.mjs +8 -8
  50. package/plugins/sp/scripts/workflow-step-profile.mjs +12 -12
  51. package/plugins/sp/scripts/wrapup-drift-probe.mjs +9 -9
  52. package/plugins/sp/scripts/wrapup-steps.mjs +25 -25
  53. package/plugins/sp/skills/code-verification/SKILL.md +1 -2
  54. package/plugins/sp/skills/code-verification/references/verdict-schema.md +11 -32
  55. package/plugins/sp/skills/next-router/SKILL.md +3 -1
  56. package/plugins/sp/skills/next-router/references/routing-table.md +9 -3
  57. package/plugins/sp/skills/spur-cli/references/tasks.md +24 -4
  58. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +8 -1
  59. package/plugins/sp/skills/spur-dev/references/dev-operations.md +37 -11
  60. package/plugins/sp/skills/spur-dev/references/execution-batch.md +6 -3
  61. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +7 -11
  62. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +4 -2
  63. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +29 -8
  64. package/schemas/section-matrix.schema.json +3 -2
  65. package/spur.js +24597 -32769
  66. package/web/_astro/{BoardApp.5IIl2O-z.js → BoardApp.Niubpe6z.js} +1 -1
  67. package/web/_astro/{BoardApp.Drnx-KeM.js → BoardApp.hF0RAIrg.js} +112 -112
  68. package/web/_astro/TaskDetail.DJpapt38.js +1 -0
  69. package/web/_astro/{arc.j2EVkYVd.js → arc.BgKcK0i8.js} +1 -1
  70. package/web/_astro/{architectureDiagram-3BPJPVTR.DZWSFqEG.js → architectureDiagram-3BPJPVTR.ChP-Ig0V.js} +1 -1
  71. package/web/_astro/{blockDiagram-GPEHLZMM.DE6GpXCN.js → blockDiagram-GPEHLZMM.BVaCBoeN.js} +1 -1
  72. package/web/_astro/{c4Diagram-AAUBKEIU.DoVR1G6B.js → c4Diagram-AAUBKEIU.CHSDpEO5.js} +1 -1
  73. package/web/_astro/channel.DkpvN2tD.js +1 -0
  74. package/web/_astro/{chunk-2J33WTMH.Do6-Gbyf.js → chunk-2J33WTMH.MYRcYVRa.js} +1 -1
  75. package/web/_astro/{chunk-4BX2VUAB.BYV1HGHx.js → chunk-4BX2VUAB.S5j22Zqa.js} +1 -1
  76. package/web/_astro/{chunk-55IACEB6.CvI1zkrc.js → chunk-55IACEB6.gciRPvmZ.js} +1 -1
  77. package/web/_astro/{chunk-727SXJPM.DNGSCRlX.js → chunk-727SXJPM.CdqrSQkX.js} +1 -1
  78. package/web/_astro/{chunk-AQP2D5EJ.DXhhgT5z.js → chunk-AQP2D5EJ.CyokdHT3.js} +1 -1
  79. package/web/_astro/{chunk-FMBD7UC4.dzkRKP2u.js → chunk-FMBD7UC4.Bg9KJhjW.js} +1 -1
  80. package/web/_astro/{chunk-ND2GUHAM.DujGLeEf.js → chunk-ND2GUHAM.1gxxI-vD.js} +1 -1
  81. package/web/_astro/{chunk-QZHKN3VN.BWtIT3ZU.js → chunk-QZHKN3VN.DDEYtCKU.js} +1 -1
  82. package/web/_astro/{classDiagram-4FO5ZUOK.DyApg0Nn.js → classDiagram-4FO5ZUOK.Ch3zi37T.js} +1 -1
  83. package/web/_astro/{classDiagram-v2-Q7XG4LA2.DyApg0Nn.js → classDiagram-v2-Q7XG4LA2.Ch3zi37T.js} +1 -1
  84. package/web/_astro/{cose-bilkent-S5V4N54A.DJQB-u_l.js → cose-bilkent-S5V4N54A.D2q5AINI.js} +1 -1
  85. package/web/_astro/{cynefin-OW5HDTMX.bi3D_siV.js → cynefin-OW5HDTMX.BA9kC2YT.js} +1 -1
  86. package/web/_astro/{dagre-BM42HDAG.C-f7TrRg.js → dagre-BM42HDAG.CHO08nRp.js} +1 -1
  87. package/web/_astro/{diagram-2AECGRRQ.DrPfjHQB.js → diagram-2AECGRRQ.BfFQt0LW.js} +1 -1
  88. package/web/_astro/{diagram-5GNKFQAL.C9S4WUHO.js → diagram-5GNKFQAL.CHMwMTe4.js} +1 -1
  89. package/web/_astro/{diagram-KO2AKTUF.Dzzye8QH.js → diagram-KO2AKTUF.BJ-7gK-w.js} +1 -1
  90. package/web/_astro/{diagram-LMA3HP47.DX-LRiof.js → diagram-LMA3HP47.C5xqcc0t.js} +1 -1
  91. package/web/_astro/{diagram-OG6HWLK6.Z-kAKwIz.js → diagram-OG6HWLK6.C2pQjfrC.js} +1 -1
  92. package/web/_astro/{erDiagram-TEJ5UH35.D6dyClSv.js → erDiagram-TEJ5UH35._FoNyxgC.js} +1 -1
  93. package/web/_astro/{flowDiagram-I6XJVG4X.Cx3q2cxD.js → flowDiagram-I6XJVG4X.B_ENkT2I.js} +1 -1
  94. package/web/_astro/{ganttDiagram-6RSMTGT7.DU3gH6CT.js → ganttDiagram-6RSMTGT7.B3q8h77C.js} +1 -1
  95. package/web/_astro/{gitGraphDiagram-PVQCEYII.ISmCnJ87.js → gitGraphDiagram-PVQCEYII.QWZFDboZ.js} +1 -1
  96. package/web/_astro/index.BFyW13JJ.css +1 -0
  97. package/web/_astro/{infoDiagram-5YYISTIA.DR6_iNOK.js → infoDiagram-5YYISTIA.Cs6eEc92.js} +1 -1
  98. package/web/_astro/{ishikawaDiagram-YF4QCWOH.D7wY-ZGA.js → ishikawaDiagram-YF4QCWOH.BU9DJMHA.js} +1 -1
  99. package/web/_astro/{journeyDiagram-JHISSGLW.DkP9-WK8.js → journeyDiagram-JHISSGLW.D35k6Jpe.js} +1 -1
  100. package/web/_astro/{kanban-definition-UN3LZRKU.wtgY98M2.js → kanban-definition-UN3LZRKU.DBqcAT4m.js} +1 -1
  101. package/web/_astro/{linear.CI6djNi7.js → linear.D-LSNK8W.js} +1 -1
  102. package/web/_astro/{mermaid.core.CuQPxS8b.js → mermaid.core.CSruWVOa.js} +4 -4
  103. package/web/_astro/{mindmap-definition-RKZ34NQL.5HNIEG7R.js → mindmap-definition-RKZ34NQL.BiFaUsfj.js} +1 -1
  104. package/web/_astro/{pieDiagram-4H26LBE5.CchhDFjE.js → pieDiagram-4H26LBE5.D1KTKqb9.js} +1 -1
  105. package/web/_astro/{quadrantDiagram-W4KKPZXB.PYXXJPSJ.js → quadrantDiagram-W4KKPZXB.DBHflsMG.js} +1 -1
  106. package/web/_astro/{requirementDiagram-4Y6WPE33.cUQuNAKU.js → requirementDiagram-4Y6WPE33.hwX9CNdk.js} +1 -1
  107. package/web/_astro/{sankeyDiagram-5OEKKPKP.BO7MnRIA.js → sankeyDiagram-5OEKKPKP.DkI8mJiE.js} +1 -1
  108. package/web/_astro/{sequenceDiagram-3UESZ5HK.D9bElyD6.js → sequenceDiagram-3UESZ5HK.DMz7jBDx.js} +1 -1
  109. package/web/_astro/{stateDiagram-AJRCARHV.DhGdRz7I.js → stateDiagram-AJRCARHV.B6Ef2xJ1.js} +1 -1
  110. package/web/_astro/{stateDiagram-v2-BHNVJYJU.5GvLeAoL.js → stateDiagram-v2-BHNVJYJU.CgoaufB9.js} +1 -1
  111. package/web/_astro/{timeline-definition-PNZ67QCA.LtAT9haM.js → timeline-definition-PNZ67QCA.B3c8h1t-.js} +1 -1
  112. package/web/_astro/{vennDiagram-CIIHVFJN.DRth1yLA.js → vennDiagram-CIIHVFJN.BdHPAxAb.js} +1 -1
  113. package/web/_astro/{wardleyDiagram-YWT4CUSO.h9MlZfcr.js → wardleyDiagram-YWT4CUSO.BrJXPPAj.js} +1 -1
  114. package/web/_astro/{xychartDiagram-2RQKCTM6.DHqy9DYA.js → xychartDiagram-2RQKCTM6.CMH5yFsV.js} +1 -1
  115. package/web/index.html +2 -2
  116. package/web/spur_logo.svg +1 -1
  117. package/web/_astro/TaskDetail.Ci4LNn9S.js +0 -1
  118. package/web/_astro/channel.DmdDxGsq.js +0 -1
  119. package/web/_astro/index.Do2lLdgo.css +0 -1
@@ -21,14 +21,6 @@ function hasClaimMarker(evidence) {
21
21
  function hasCitationForm(evidence) {
22
22
  return CITATION_FORMS.some((re) => re.test(evidence));
23
23
  }
24
- var CONFIDENCE_LEVELS = ["HIGH", "MEDIUM", "LOW"];
25
- function extractAnswerConfidence(text) {
26
- const matches = [...text.matchAll(/^\s*Confidence:\s*(\S+)\s*$/gim)];
27
- if (matches.length !== 1)
28
- return;
29
- const value = (matches[0]?.[1] ?? "").toUpperCase();
30
- return CONFIDENCE_LEVELS.includes(value) ? value : undefined;
31
- }
32
24
 
33
25
  // packages/app/src/services/residual-scan.ts
34
26
  var MARKER_PATTERN = /TODO|FIXME|XXX|HACK/;
@@ -202,13 +194,6 @@ function blockingReviewFindings(taskContent, deferrals) {
202
194
  }
203
195
  function reviewContractViolations(taskContent) {
204
196
  const violations = [];
205
- const body = reviewBody(taskContent);
206
- if (body !== null && extractAnswerConfidence(body.replace(/\*\*/g, "")) === undefined) {
207
- violations.push({
208
- location: "task-file:Review",
209
- text: "Review report carries no single valid `**Confidence:** HIGH | MEDIUM | LOW` line — " + "state the level the report can defend (HIGH: every requirement row MET, every finding " + "dispositioned, evidence cited; MEDIUM/LOW: name the gap)."
210
- });
211
- }
212
197
  for (const row of parseReviewFindings(taskContent)) {
213
198
  if (hasClaimMarker(row.text) && !hasCitationForm(row.text)) {
214
199
  violations.push({
@@ -220,9 +205,10 @@ function reviewContractViolations(taskContent) {
220
205
  return violations;
221
206
  }
222
207
  function buildReviewGateArtifact(wbs, taskContent, deferrals) {
208
+ const contractViolations = reviewContractViolations(taskContent);
223
209
  const items = [
224
210
  ...blockingReviewFindings(taskContent, deferrals),
225
- ...reviewContractViolations(taskContent).map((v) => ({
211
+ ...contractViolations.map((v) => ({
226
212
  id: makeItemId("review-contract", v.location, v.text),
227
213
  category: "review-contract",
228
214
  class: "blocking",
@@ -375,23 +361,23 @@ function parseScanArgs(argv, cwd, defaultTmpDir) {
375
361
  return mode === "" || wbs === "" ? null : { mode, wbs, spurBin, root, tmpDir };
376
362
  }
377
363
  export {
378
- verdictDisagreementNote,
379
- scanResiduals,
380
- reviewContractViolations,
381
- renderReport,
382
- recordedVerdictPath,
383
- parseScanArgs,
384
- parseReviewFindings,
385
- parseDiffMarkers,
386
- parseDeferralEntries,
387
- normalizeAnchor,
388
- makeItemId,
389
- locationOf,
390
- foldVerdict,
391
- findUncheckedBoxes,
392
- classify,
393
- buildReviewGateArtifact,
394
- blockingReviewFindings,
364
+ ALLOW_PRAGMA,
395
365
  blockingAnchors,
396
- ALLOW_PRAGMA
366
+ blockingReviewFindings,
367
+ buildReviewGateArtifact,
368
+ classify,
369
+ findUncheckedBoxes,
370
+ foldVerdict,
371
+ locationOf,
372
+ makeItemId,
373
+ normalizeAnchor,
374
+ parseDeferralEntries,
375
+ parseDiffMarkers,
376
+ parseReviewFindings,
377
+ parseScanArgs,
378
+ recordedVerdictPath,
379
+ renderReport,
380
+ reviewContractViolations,
381
+ scanResiduals,
382
+ verdictDisagreementNote
397
383
  };
@@ -162,13 +162,13 @@ function formatStepProfileHuman(profile) {
162
162
  `;
163
163
  }
164
164
  export {
165
- rowFlags,
166
- nonDryRuns,
167
- nearestRankP50,
168
- formatStepProfileHuman,
169
- extractExecutions,
170
- buildStepProfile,
171
- buildRows,
165
+ DEFAULT_LAST,
172
166
  DEFAULT_WINDOW_SEC,
173
- DEFAULT_LAST
167
+ buildRows,
168
+ buildStepProfile,
169
+ extractExecutions,
170
+ formatStepProfileHuman,
171
+ nearestRankP50,
172
+ nonDryRuns,
173
+ rowFlags
174
174
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sp",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics.",
5
5
  "extensions": {
6
6
  "pi": ["./hooks/pi/guard-extension.ts"]
@@ -5,6 +5,12 @@
5
5
  import { readFileSync } from "fs";
6
6
 
7
7
  // plugins/sp/lib/plan-projection.generated.mjs
8
+ function isTaskFrozen(status) {
9
+ return status?.toLowerCase() === "deprecated";
10
+ }
11
+ function undeprecateTaskCommand(wbs) {
12
+ return `spur task update ${wbs} todo`;
13
+ }
8
14
  var NON_ABORTING_PREFLIGHT_CODES = new Set([
9
15
  "L4.scenario-unverified",
10
16
  "L4.verifying-incomplete-tasks"
@@ -55,6 +61,13 @@ function quickReadiness(input) {
55
61
  };
56
62
  }
57
63
  }
64
+ if (isTaskFrozen(status)) {
65
+ return {
66
+ action: "skipped",
67
+ code: "DEPRECATED",
68
+ reason: `quick-readiness: deprecated (frozen) — no ${operation} hop; un-deprecate with \`${undeprecateTaskCommand(input.wbs)}\` (${input.wbs})`
69
+ };
70
+ }
58
71
  if (status === "cancelled" || status === "done") {
59
72
  if (operation === "verify" && input.force === true) {
60
73
  return {
@@ -79,10 +92,12 @@ function quickReadiness(input) {
79
92
  if (operation === "run" && input.dependencies && input.dependencies.length > 0) {
80
93
  const unmet = input.dependencies.filter((d) => (input.depStatuses?.[d] ?? "missing").toLowerCase() !== "done");
81
94
  if (unmet.length > 0) {
95
+ const frozen = unmet.filter((d) => isTaskFrozen(input.depStatuses?.[d]));
96
+ const hint = frozen.length > 0 ? ` — ${frozen.map((d) => `${d} deprecated (frozen); re-point the edge or un-deprecate: \`${undeprecateTaskCommand(d)}\``).join("; ")}` : "";
82
97
  return {
83
98
  action: "blocked",
84
99
  code: "DEP",
85
- reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})`,
100
+ reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})${hint}`,
86
101
  unmetDeps: unmet
87
102
  };
88
103
  }
@@ -167,6 +182,13 @@ function preflightTask(input) {
167
182
  reason: `dev-next: blocked — do not launch pipeline; human/handover first (${input.wbs})`
168
183
  };
169
184
  }
185
+ if (isTaskFrozen(status)) {
186
+ return {
187
+ action: "skip",
188
+ code: "DEPRECATED",
189
+ reason: `dev-next: deprecated (frozen) — un-deprecate first: ${undeprecateTaskCommand(input.wbs)} (${input.wbs})`
190
+ };
191
+ }
170
192
  if (status === "todo" || status === "backlog") {
171
193
  const unmet = deps.filter((d) => {
172
194
  const st = (depStatuses[d] ?? "missing").toLowerCase();
@@ -274,21 +296,21 @@ function accumulate(acc, row, ts) {
274
296
  if (row.type === "message") {
275
297
  const m = row.message;
276
298
  if (m?.role === "assistant") {
277
- const blocks2 = Array.isArray(m.content) ? m.content : [];
278
- for (const b of blocks2) {
299
+ const blocks = Array.isArray(m.content) ? m.content : [];
300
+ for (const b of blocks) {
279
301
  if (b.type === "toolCall" && b.id) {
280
302
  acc.toolIds.add(b.id);
281
303
  if (b.name && OPERATOR_TOOLS.has(b.name))
282
304
  acc.asks.set(b.id, ts);
283
305
  }
284
306
  }
285
- const u2 = m.usage;
286
- if (u2 && row.id)
307
+ const u = m.usage;
308
+ if (u && row.id)
287
309
  acc.messages.set(row.id, {
288
- input: u2.input ?? 0,
289
- cacheCreate: u2.cacheWrite ?? 0,
290
- cacheRead: u2.cacheRead ?? 0,
291
- output: u2.output ?? 0
310
+ input: u.input ?? 0,
311
+ cacheCreate: u.cacheWrite ?? 0,
312
+ cacheRead: u.cacheRead ?? 0,
313
+ output: u.output ?? 0
292
314
  });
293
315
  } else if (m?.role === "toolResult" && m.toolCallId && acc.asks.has(m.toolCallId)) {
294
316
  acc.askMs += ts - (acc.asks.get(m.toolCallId) ?? ts);
@@ -1039,36 +1061,36 @@ function main(argv) {
1039
1061
  process.exit(main(process.argv.slice(2)));
1040
1062
  }
1041
1063
  export {
1042
- zeroTokens,
1043
- validatePhaseTable,
1044
- taskPhaseChildren,
1045
- sumTokens,
1046
- sumSpans,
1047
- skillInvocationPrompt,
1048
- sensitiveReasonForPath,
1049
- scheduleBatch,
1050
- quickReadiness,
1051
- promptText,
1052
- preflightTask,
1053
- planLetter,
1054
- planChild,
1055
- newAcc,
1056
- main,
1057
- isCompaction,
1058
- insertOnEntry,
1059
- hostText,
1060
- hostStatus,
1061
- formatTokens,
1062
- formatTokenSplit,
1063
- formatDuration,
1064
- classifyFeaturePreflightFindings,
1065
- buildRunSummary,
1066
- buildPhasedPlan,
1067
- buildBatchPlan,
1068
- actorSplit,
1069
- accumulate,
1070
- SENSITIVE_PREFIXES,
1071
- SENSITIVE_GLOBS,
1064
+ BATCH_PLAN_USAGE,
1072
1065
  NON_ABORTING_PREFLIGHT_CODES,
1073
- BATCH_PLAN_USAGE
1066
+ SENSITIVE_GLOBS,
1067
+ SENSITIVE_PREFIXES,
1068
+ accumulate,
1069
+ actorSplit,
1070
+ buildBatchPlan,
1071
+ buildPhasedPlan,
1072
+ buildRunSummary,
1073
+ classifyFeaturePreflightFindings,
1074
+ formatDuration,
1075
+ formatTokenSplit,
1076
+ formatTokens,
1077
+ hostStatus,
1078
+ hostText,
1079
+ insertOnEntry,
1080
+ isCompaction,
1081
+ main,
1082
+ newAcc,
1083
+ planChild,
1084
+ planLetter,
1085
+ preflightTask,
1086
+ promptText,
1087
+ quickReadiness,
1088
+ scheduleBatch,
1089
+ sensitiveReasonForPath,
1090
+ skillInvocationPrompt,
1091
+ sumSpans,
1092
+ sumTokens,
1093
+ taskPhaseChildren,
1094
+ validatePhaseTable,
1095
+ zeroTokens
1074
1096
  };
@@ -3,6 +3,12 @@ import { createRequire } from "node:module";
3
3
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // plugins/sp/lib/plan-projection.generated.mjs
6
+ function isTaskFrozen(status) {
7
+ return status?.toLowerCase() === "deprecated";
8
+ }
9
+ function undeprecateTaskCommand(wbs) {
10
+ return `spur task update ${wbs} todo`;
11
+ }
6
12
  var NON_ABORTING_PREFLIGHT_CODES = new Set([
7
13
  "L4.scenario-unverified",
8
14
  "L4.verifying-incomplete-tasks"
@@ -53,6 +59,13 @@ function quickReadiness(input) {
53
59
  };
54
60
  }
55
61
  }
62
+ if (isTaskFrozen(status)) {
63
+ return {
64
+ action: "skipped",
65
+ code: "DEPRECATED",
66
+ reason: `quick-readiness: deprecated (frozen) — no ${operation} hop; un-deprecate with \`${undeprecateTaskCommand(input.wbs)}\` (${input.wbs})`
67
+ };
68
+ }
56
69
  if (status === "cancelled" || status === "done") {
57
70
  if (operation === "verify" && input.force === true) {
58
71
  return {
@@ -77,10 +90,12 @@ function quickReadiness(input) {
77
90
  if (operation === "run" && input.dependencies && input.dependencies.length > 0) {
78
91
  const unmet = input.dependencies.filter((d) => (input.depStatuses?.[d] ?? "missing").toLowerCase() !== "done");
79
92
  if (unmet.length > 0) {
93
+ const frozen = unmet.filter((d) => isTaskFrozen(input.depStatuses?.[d]));
94
+ const hint = frozen.length > 0 ? ` — ${frozen.map((d) => `${d} deprecated (frozen); re-point the edge or un-deprecate: \`${undeprecateTaskCommand(d)}\``).join("; ")}` : "";
80
95
  return {
81
96
  action: "blocked",
82
97
  code: "DEP",
83
- reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})`,
98
+ reason: `quick-readiness: unmet deps — ${unmet.join(", ")} (${input.wbs})${hint}`,
84
99
  unmetDeps: unmet
85
100
  };
86
101
  }
@@ -165,6 +180,13 @@ function preflightTask(input) {
165
180
  reason: `dev-next: blocked — do not launch pipeline; human/handover first (${input.wbs})`
166
181
  };
167
182
  }
183
+ if (isTaskFrozen(status)) {
184
+ return {
185
+ action: "skip",
186
+ code: "DEPRECATED",
187
+ reason: `dev-next: deprecated (frozen) — un-deprecate first: ${undeprecateTaskCommand(input.wbs)} (${input.wbs})`
188
+ };
189
+ }
168
190
  if (status === "todo" || status === "backlog") {
169
191
  const unmet = deps.filter((d) => {
170
192
  const st = (depStatuses[d] ?? "missing").toLowerCase();
@@ -332,7 +354,7 @@ function runPreflightCli(argv) {
332
354
  return { exitCode: 0, stdout: body, stderr: "" };
333
355
  }
334
356
  if (args.operation !== null) {
335
- const result2 = quickReadiness({
357
+ const result = quickReadiness({
336
358
  wbs: args.wbs,
337
359
  status: args.status,
338
360
  operation: args.operation,
@@ -343,14 +365,14 @@ function runPreflightCli(argv) {
343
365
  ...args.presentSections.length > 0 ? { presentSections: args.presentSections } : {},
344
366
  ...args.force ? { force: true } : {}
345
367
  });
346
- const runnable = result2.action === "runnable" || result2.action === "needs-refinement";
368
+ const runnable = result.action === "runnable" || result.action === "needs-refinement";
347
369
  if (args.json) {
348
- return { exitCode: runnable ? 0 : 2, stdout: `${JSON.stringify(result2, null, 2)}
370
+ return { exitCode: runnable ? 0 : 2, stdout: `${JSON.stringify(result, null, 2)}
349
371
  `, stderr: "" };
350
372
  }
351
373
  return {
352
374
  exitCode: runnable ? 0 : 2,
353
- stdout: `${result2.action}${result2.code ? ` ${result2.code}` : ""}: ${result2.reason}
375
+ stdout: `${result.action}${result.code ? ` ${result.code}` : ""}: ${result.reason}
354
376
  `,
355
377
  stderr: ""
356
378
  };
@@ -390,12 +412,12 @@ function runPreflightCli(argv) {
390
412
  process.exit(exitCode);
391
413
  }
392
414
  export {
393
- runPreflightCli,
394
- recoveryHint,
395
- quickReadiness,
396
- preflightTask,
397
- parsePreflightCliArgs,
398
- classifyFeaturePreflightFindings,
415
+ NON_ABORTING_PREFLIGHT_CODES,
399
416
  PREFLIGHT_CLI_USAGE,
400
- NON_ABORTING_PREFLIGHT_CODES
417
+ classifyFeaturePreflightFindings,
418
+ parsePreflightCliArgs,
419
+ preflightTask,
420
+ quickReadiness,
421
+ recoveryHint,
422
+ runPreflightCli
401
423
  };
@@ -206,11 +206,11 @@ function main(argv, options = {}) {
206
206
  process.exit(main(process.argv.slice(2)));
207
207
  }
208
208
  export {
209
- runStart,
210
- runStage,
211
- runCheck,
212
- parsePorcelainZ,
213
- main,
209
+ COMMIT_GUARD_USAGE,
214
210
  conflictMarkerLine,
215
- COMMIT_GUARD_USAGE
211
+ main,
212
+ parsePorcelainZ,
213
+ runCheck,
214
+ runStage,
215
+ runStart
216
216
  };
@@ -1,7 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  // @bun
3
- import { createRequire } from "node:module";
4
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
3
 
6
4
  // plugins/sp/scripts/daily-summary/daily-summary.ts
7
5
  import { spawn, spawnSync } from "child_process";
@@ -41,8 +39,8 @@ function resolveAppEntry(spurBin) {
41
39
  }
42
40
  return { entry, portable: true };
43
41
  }
44
- async function loadInlineApp(spurBin, resolveAppEntry2, required) {
45
- const { entry, portable } = resolveAppEntry2(spurBin);
42
+ async function loadInlineApp(spurBin, resolveAppEntry, required) {
43
+ const { entry, portable } = resolveAppEntry(spurBin);
46
44
  const app = await import(entry);
47
45
  const missing = portable ? required.filter((name) => typeof app[name] !== "function") : [];
48
46
  if (missing.length > 0) {
@@ -143,7 +141,7 @@ function getDateRange(dateStr) {
143
141
  return { start, end };
144
142
  }
145
143
  var defaultProcessSpawner = (cmd, args, env) => {
146
- return new Promise((resolve3, reject) => {
144
+ return new Promise((resolve, reject) => {
147
145
  try {
148
146
  const proc = spawn(cmd, args, {
149
147
  stdio: ["ignore", "pipe", "pipe"],
@@ -154,7 +152,7 @@ var defaultProcessSpawner = (cmd, args, env) => {
154
152
  proc.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.from(chunk)));
155
153
  proc.stderr.on("data", (chunk) => stderrChunks.push(Buffer.from(chunk)));
156
154
  proc.on("close", (exitCode) => {
157
- resolve3({
155
+ resolve({
158
156
  stdout: Buffer.concat(stdoutChunks).toString("utf8"),
159
157
  stderr: Buffer.concat(stderrChunks).toString("utf8"),
160
158
  exitCode: exitCode ?? 0
@@ -319,12 +317,12 @@ Please provide the following (press Enter to skip):
319
317
  chunks.push(chunk);
320
318
  }
321
319
  const buffered = Buffer.concat(chunks).toString("utf-8");
322
- const [learnings2 = "", issuesFixed2 = "", pending2 = ""] = buffered.split(`
320
+ const [learnings = "", issuesFixed = "", pending = ""] = buffered.split(`
323
321
  `);
324
322
  return {
325
- learnings: learnings2.trim(),
326
- issuesFixed: issuesFixed2.trim(),
327
- pending: pending2.trim()
323
+ learnings: learnings.trim(),
324
+ issuesFixed: issuesFixed.trim(),
325
+ pending: pending.trim()
328
326
  };
329
327
  }
330
328
  const readline = await import("readline");
@@ -332,9 +330,9 @@ Please provide the following (press Enter to skip):
332
330
  input: process.stdin,
333
331
  output: process.stdout
334
332
  });
335
- const question = (prompt) => new Promise((resolve3) => {
333
+ const question = (prompt) => new Promise((resolve) => {
336
334
  rl.question(prompt, (answer) => {
337
- resolve3(answer.trim());
335
+ resolve(answer.trim());
338
336
  });
339
337
  });
340
338
  const learnings = await question(`1. What did you learn today? (optional)
@@ -608,21 +606,21 @@ ${markdown}
608
606
  });
609
607
  }
610
608
  export {
611
- yesterdayLocal,
612
- writeSummary,
613
- todayLocal,
614
- setProcessSpawner,
615
- promptUser,
616
- printUsage,
617
- parseArgs,
618
- main,
619
- getSpurHistoryHealth,
620
- getGitCommits,
621
- getDateRange,
622
- getCcusageData,
623
- generateMarkdown,
624
- ensureDir,
625
- enableLogger,
609
+ buildDailySummary,
626
610
  defaultProcessSpawner,
627
- buildDailySummary
611
+ enableLogger,
612
+ ensureDir,
613
+ generateMarkdown,
614
+ getCcusageData,
615
+ getDateRange,
616
+ getGitCommits,
617
+ getSpurHistoryHealth,
618
+ main,
619
+ parseArgs,
620
+ printUsage,
621
+ promptUser,
622
+ setProcessSpawner,
623
+ todayLocal,
624
+ writeSummary,
625
+ yesterdayLocal
628
626
  };
@@ -196,16 +196,16 @@ function runCli(argv) {
196
196
  process.exit(exitCode);
197
197
  }
198
198
  export {
199
- runCli,
200
- parseCliArgs,
201
- isImplementHeavyStep,
202
- hasMutatingFixMode,
203
- evaluateDogfoodGate,
204
- detectPipelineDriving,
205
- detectImplementHeavy,
206
- PIPELINE_TOKENS,
207
- PIPELINE_DRIVING_REFUSE_MESSAGE,
208
- MUTATING_FIX_REFUSE_MESSAGE,
199
+ CLI_USAGE,
209
200
  IMPLEMENT_HEAVY_ADVISORY_MESSAGE,
210
- CLI_USAGE
201
+ MUTATING_FIX_REFUSE_MESSAGE,
202
+ PIPELINE_DRIVING_REFUSE_MESSAGE,
203
+ PIPELINE_TOKENS,
204
+ detectImplementHeavy,
205
+ detectPipelineDriving,
206
+ evaluateDogfoodGate,
207
+ hasMutatingFixMode,
208
+ isImplementHeavyStep,
209
+ parseCliArgs,
210
+ runCli
211
211
  };
@@ -274,9 +274,9 @@ function mainCli(argv = process.argv.slice(2)) {
274
274
  process.exit(mainCli());
275
275
  }
276
276
  export {
277
- validateReport,
278
- runValidateCli,
279
- parseValidateCliArgs,
277
+ VALIDATE_CLI_USAGE,
280
278
  mainCli,
281
- VALIDATE_CLI_USAGE
279
+ parseValidateCliArgs,
280
+ runValidateCli,
281
+ validateReport
282
282
  };
@@ -2,6 +2,7 @@
2
2
  // @bun
3
3
 
4
4
  // plugins/sp/scripts/feature-verification-steps.ts
5
+ import { spawnSync } from "child_process";
5
6
  import { existsSync } from "fs";
6
7
  import { fileURLToPath } from "url";
7
8
 
@@ -42,17 +43,27 @@ async function requireModule(entry, mode) {
42
43
  }
43
44
  return mod;
44
45
  }
45
- async function verify(featureId, runId, cmdOverride, spurBin, mode) {
46
+ async function verify(featureId, runId, cmdOverride, spurBin, mode, confidenceOverride, ackLowConfidence) {
46
47
  const mod = await loadModule(spurBin, mode);
47
48
  const result = await mod.runFeatureVerification({
48
49
  workdir: process.cwd(),
49
50
  featureId,
50
51
  runId,
51
- cmdOverride
52
+ cmdOverride,
53
+ confidenceOverride,
54
+ ackLowConfidence
52
55
  });
53
56
  console.log(`feature-verification-steps: ${featureId} ${result.message}`);
54
57
  }
55
58
  function main() {
59
+ if (!process.versions.bun) {
60
+ const child = spawnSync("bun", [fileURLToPath(import.meta.url), ...process.argv.slice(2)], {
61
+ stdio: "inherit"
62
+ });
63
+ if (child.error)
64
+ console.error(`feature-verification-steps requires Bun on PATH: ${child.error.message}`);
65
+ process.exit(child.status ?? 1);
66
+ }
56
67
  const args = process.argv.slice(2);
57
68
  const command = args[0];
58
69
  const flag = (name) => {
@@ -60,10 +71,10 @@ function main() {
60
71
  return i >= 0 && i + 1 < args.length ? args[i + 1] ?? "" : "";
61
72
  };
62
73
  if (command !== "verify") {
63
- console.error("Usage: feature-verification-steps.ts verify --feature-id <id> --run-id <id> [--cmd <command>]");
74
+ console.error("Usage: feature-verification-steps.ts verify --feature-id <id> --run-id <id> [--cmd <command>] [--confidence HIGH|MEDIUM|LOW] [--ack-low-confidence]");
64
75
  process.exit(2);
65
76
  }
66
- verify(flag("--feature-id") || getEnvVar("featureId") || "", flag("--run-id") || getEnvVar("__runId") || "", flag("--cmd") || getEnvVar("verificationCmd") || "", flag("--spur-bin") || getEnvVar("spurBin") || "", resolveModuleMode(flag("--module-mode"))).then(() => process.exit(0)).catch((err) => {
77
+ verify(flag("--feature-id") || getEnvVar("featureId") || "", flag("--run-id") || getEnvVar("__runId") || "", flag("--cmd") || getEnvVar("verificationCmd") || "", flag("--spur-bin") || getEnvVar("spurBin") || "", resolveModuleMode(flag("--module-mode")), flag("--confidence") || getEnvVar("confidence") || "", args.includes("--ack-low-confidence") || getEnvVar("ackLowConfidence") === "true").then(() => process.exit(0)).catch((err) => {
67
78
  console.error(`feature-verification-steps: ${String(err)}`);
68
79
  process.exit(1);
69
80
  });
@@ -18,10 +18,16 @@
18
18
  * Always exits 0 after a completed pass; the transition guard reads the status file and the
19
19
  * completion boundary validates the receipt (fail-closed). Unsafe ids are refused by the operation.
20
20
  *
21
+ * The installed `.mjs` twin may be launched with plain `node` (the `feature-verification` workflow
22
+ * selects `installed -> node`), but the generated inline bundle keeps `bun:sqlite` external by design, so the
23
+ * twin re-enters Bun at the top of `main()` (task 1197). Unlike daily-summary it fails closed when Bun
24
+ * is missing — a verifier that cannot load its bundle cannot run the checks.
25
+ *
21
26
  * Node-builtin imports only (ADR-065); the application seams come from the generated inline bundle,
22
27
  * never from `packages/app/src/index.ts`, which is not a plugin-script contract surface (0948 R3).
23
28
  */
24
29
 
30
+ import { spawnSync } from 'node:child_process';
25
31
  import { existsSync } from 'node:fs';
26
32
  import { fileURLToPath } from 'node:url';
27
33
  import { getEnvVar } from '../lib/env';
@@ -97,6 +103,8 @@ async function verify(
97
103
  cmdOverride: string,
98
104
  spurBin: string,
99
105
  mode: ModuleMode,
106
+ confidenceOverride: string,
107
+ ackLowConfidence: boolean,
100
108
  ): Promise<void> {
101
109
  const mod = await loadModule(spurBin, mode);
102
110
  const result = await mod.runFeatureVerification({
@@ -104,11 +112,26 @@ async function verify(
104
112
  featureId,
105
113
  runId,
106
114
  cmdOverride,
115
+ // Operator-declared level (empty = derive from the pass) and the acknowledgement of a LOW
116
+ // level. Both ride the receipt, so the completion boundary reads them from the evidence
117
+ // rather than from whatever flags a later transition happens to pass.
118
+ confidenceOverride,
119
+ ackLowConfidence,
107
120
  });
108
121
  console.log(`feature-verification-steps: ${featureId} ${result.message}`);
109
122
  }
110
123
 
111
124
  function main(): void {
125
+ // The portable Node twin has no workspace imports; the generated bundle still uses Spur's Bun
126
+ // runtime (bun:sqlite stays external by design). Re-enter Bun before any app import; fail closed
127
+ // when Bun is missing — the verifier must not report a pass it could not run.
128
+ if (!process.versions.bun) {
129
+ const child = spawnSync('bun', [fileURLToPath(import.meta.url), ...process.argv.slice(2)], {
130
+ stdio: 'inherit',
131
+ });
132
+ if (child.error) console.error(`feature-verification-steps requires Bun on PATH: ${child.error.message}`);
133
+ process.exit(child.status ?? 1);
134
+ }
112
135
  const args = process.argv.slice(2);
113
136
  const command = args[0];
114
137
  const flag = (name: string): string => {
@@ -116,7 +139,10 @@ function main(): void {
116
139
  return i >= 0 && i + 1 < args.length ? (args[i + 1] ?? '') : '';
117
140
  };
118
141
  if (command !== 'verify') {
119
- console.error('Usage: feature-verification-steps.ts verify --feature-id <id> --run-id <id> [--cmd <command>]');
142
+ console.error(
143
+ 'Usage: feature-verification-steps.ts verify --feature-id <id> --run-id <id> [--cmd <command>] ' +
144
+ '[--confidence HIGH|MEDIUM|LOW] [--ack-low-confidence]',
145
+ );
120
146
  process.exit(2);
121
147
  }
122
148
  verify(
@@ -125,6 +151,8 @@ function main(): void {
125
151
  flag('--cmd') || getEnvVar('verificationCmd') || '',
126
152
  flag('--spur-bin') || getEnvVar('spurBin') || '',
127
153
  resolveModuleMode(flag('--module-mode')),
154
+ flag('--confidence') || getEnvVar('confidence') || '',
155
+ args.includes('--ack-low-confidence') || getEnvVar('ackLowConfidence') === 'true',
128
156
  )
129
157
  .then(() => process.exit(0))
130
158
  .catch((err: unknown) => {