@gobing-ai/spur 0.3.95 → 0.3.96

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 (155) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/plugin-scripts.json +0 -54
  3. package/config/rules/boundary/sp-script-placement.yaml +19 -0
  4. package/config/rules/strict/runtime-boundaries.yaml +5 -0
  5. package/config/rules/structure/test-location.yaml +2 -0
  6. package/config/rules/typescript/no-syscall-emulation-in-boundary-mock.yaml +1 -1
  7. package/config/rules/typescript/output-boundaries.yaml +15 -2
  8. package/config/script-placement-baseline.json +51 -0
  9. package/config/workflows/feature-verification.yaml +1 -1
  10. package/config/workflows/history-anatomy.yaml +23 -11
  11. package/config/workflows/idea-pipeline.yaml +80 -85
  12. package/config/workflows/pr-review.yaml +18 -9
  13. package/config/workflows/task-pipeline.yaml +42 -95
  14. package/config/workflows/wrapup-pipeline.yaml +89 -37
  15. package/package.json +1 -1
  16. package/plugins/sp/README.md +8 -10
  17. package/plugins/sp/agents/super-reviewer.md +43 -18
  18. package/plugins/sp/commands/dev-fixgha.md +83 -0
  19. package/plugins/sp/commands/dev-gitmsg.md +8 -6
  20. package/plugins/sp/commands/dev-gtd.md +2 -2
  21. package/plugins/sp/commands/dev-idea.md +22 -12
  22. package/plugins/sp/commands/dev-plan.md +8 -9
  23. package/plugins/sp/commands/dev-review.md +22 -13
  24. package/plugins/sp/commands/dev-verifyall.md +1 -1
  25. package/plugins/sp/commands/spur-init.md +2 -2
  26. package/plugins/sp/lib/history-anatomy.generated.d.mts +112 -0
  27. package/plugins/sp/lib/history-anatomy.generated.mjs +686 -0
  28. package/plugins/sp/lib/idea-handoff.generated.mjs +5 -4
  29. package/plugins/sp/lib/inline-run.generated.d.mts +11 -0
  30. package/plugins/sp/lib/inline-run.generated.mjs +25 -8
  31. package/plugins/sp/lib/quality-gate.generated.d.mts +104 -0
  32. package/plugins/sp/lib/quality-gate.generated.mjs +438 -0
  33. package/plugins/sp/lib/residual-scan.generated.d.mts +62 -0
  34. package/plugins/sp/lib/residual-scan.generated.mjs +210 -0
  35. package/plugins/sp/lib/spur-bin.ts +36 -0
  36. package/plugins/sp/lib/step-profile.generated.d.mts +71 -0
  37. package/plugins/sp/lib/step-profile.generated.mjs +174 -0
  38. package/plugins/sp/plugin.json +1 -1
  39. package/plugins/sp/references/roles.md +1 -1
  40. package/plugins/sp/scripts/history-anatomy-cache.mjs +20 -19
  41. package/plugins/sp/scripts/history-anatomy-cache.ts +23 -928
  42. package/plugins/sp/scripts/inline-run-setup.mjs +85 -320
  43. package/plugins/sp/scripts/inline-run-setup.ts +104 -667
  44. package/plugins/sp/scripts/quality-gate.mjs +34 -19
  45. package/plugins/sp/scripts/quality-gate.ts +12 -658
  46. package/plugins/sp/scripts/residual-scan.mjs +135 -156
  47. package/plugins/sp/scripts/residual-scan.ts +102 -499
  48. package/plugins/sp/scripts/script-root.mjs +5 -1
  49. package/plugins/sp/scripts/script-root.ts +5 -1
  50. package/plugins/sp/scripts/workflow-step-profile.mjs +25 -17
  51. package/plugins/sp/scripts/workflow-step-profile.ts +21 -315
  52. package/plugins/sp/scripts/wrapup-drift-probe.mjs +8 -2
  53. package/plugins/sp/scripts/wrapup-drift-probe.ts +3 -2
  54. package/plugins/sp/scripts/wrapup-steps.mjs +10 -32
  55. package/plugins/sp/scripts/wrapup-steps.ts +8 -36
  56. package/plugins/sp/skills/code-improvement/SKILL.md +5 -4
  57. package/plugins/sp/skills/code-verification/SKILL.md +34 -9
  58. package/plugins/sp/skills/code-verification/references/verdict-schema.md +3 -3
  59. package/plugins/sp/skills/functional-review/SKILL.md +7 -4
  60. package/plugins/sp/skills/functional-review/references/verdict-schema.md +1 -1
  61. package/plugins/sp/skills/history-anatomy/references/modes.md +2 -1
  62. package/plugins/sp/skills/next-feature/references/handoff-routing.md +1 -1
  63. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  64. package/plugins/sp/skills/spur-cli/SKILL.md +3 -3
  65. package/plugins/sp/skills/spur-cli/references/agent.md +10 -10
  66. package/plugins/sp/skills/spur-cli/references/features.md +17 -6
  67. package/plugins/sp/skills/spur-cli/references/init.md +17 -16
  68. package/plugins/sp/skills/spur-cli/references/self.md +3 -2
  69. package/plugins/sp/skills/spur-cli/references/serve.md +10 -10
  70. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +21 -6
  71. package/plugins/sp/skills/spur-cli/references/tasks.md +14 -8
  72. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +4 -3
  73. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +11 -9
  74. package/plugins/sp/skills/spur-dev/references/decision-brief.md +1 -1
  75. package/plugins/sp/skills/spur-dev/references/dev-operations.md +86 -70
  76. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +3 -3
  77. package/plugins/sp/skills/spur-dev/references/execution-batch.md +77 -34
  78. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +5 -9
  79. package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +3 -3
  80. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +31 -21
  81. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +19 -19
  82. package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +4 -3
  83. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +29 -3
  84. package/plugins/sp/skills/spur-doctor/SKILL.md +1 -1
  85. package/plugins/sp/skills/sys-architecture/SKILL.md +3 -2
  86. package/spur.js +1495 -369
  87. package/web/_astro/{BoardApp.Cpxntzad.js → BoardApp.BIjMatT1.js} +1 -1
  88. package/web/_astro/{BoardApp.BxJuwD7I.js → BoardApp.GvjIe9Z6.js} +42 -42
  89. package/web/_astro/{TaskDetail.C5bW4WGV.js → TaskDetail.BZM3EAFx.js} +1 -1
  90. package/web/_astro/{arc.CyjRvNMY.js → arc.HkRiZnoI.js} +1 -1
  91. package/web/_astro/{architectureDiagram-3BPJPVTR.B4lWRzJA.js → architectureDiagram-3BPJPVTR.BDdK-tgZ.js} +1 -1
  92. package/web/_astro/{blockDiagram-GPEHLZMM.Be38USQ2.js → blockDiagram-GPEHLZMM.CZ9kOBxx.js} +1 -1
  93. package/web/_astro/{c4Diagram-AAUBKEIU.DT9Fj5Qx.js → c4Diagram-AAUBKEIU.DXK9qeRD.js} +1 -1
  94. package/web/_astro/channel.DlhX2MEt.js +1 -0
  95. package/web/_astro/{chunk-2J33WTMH.SeSBWLg5.js → chunk-2J33WTMH.BTD2WeX5.js} +1 -1
  96. package/web/_astro/{chunk-4BX2VUAB.DoO4VE14.js → chunk-4BX2VUAB.Ci6Qbcvk.js} +1 -1
  97. package/web/_astro/{chunk-55IACEB6.DrmTFA53.js → chunk-55IACEB6.yl3zsj7p.js} +1 -1
  98. package/web/_astro/{chunk-727SXJPM.Bi-TUb_V.js → chunk-727SXJPM.ClXZsfyR.js} +1 -1
  99. package/web/_astro/{chunk-AQP2D5EJ.B-xp8Uhi.js → chunk-AQP2D5EJ.BmKWZBcP.js} +1 -1
  100. package/web/_astro/{chunk-FMBD7UC4.DGWrDnUU.js → chunk-FMBD7UC4.By30fcb7.js} +1 -1
  101. package/web/_astro/{chunk-ND2GUHAM._BagvPDy.js → chunk-ND2GUHAM.24NmrD-k.js} +1 -1
  102. package/web/_astro/{chunk-QZHKN3VN.VOboYWQ0.js → chunk-QZHKN3VN.BN4sKdcS.js} +1 -1
  103. package/web/_astro/{classDiagram-4FO5ZUOK.D_apfHS7.js → classDiagram-4FO5ZUOK.CJpoMPb5.js} +1 -1
  104. package/web/_astro/{classDiagram-v2-Q7XG4LA2.D_apfHS7.js → classDiagram-v2-Q7XG4LA2.CJpoMPb5.js} +1 -1
  105. package/web/_astro/{cose-bilkent-S5V4N54A.DNLU_L-x.js → cose-bilkent-S5V4N54A.BraxQ2Nt.js} +1 -1
  106. package/web/_astro/{cynefin-OW5HDTMX.D8borhV-.js → cynefin-OW5HDTMX.gzoU73oL.js} +1 -1
  107. package/web/_astro/{dagre-BM42HDAG.Uc0lvjcV.js → dagre-BM42HDAG.wyDfWySU.js} +1 -1
  108. package/web/_astro/{diagram-2AECGRRQ.DDIxtDBo.js → diagram-2AECGRRQ.h2_EbMxV.js} +1 -1
  109. package/web/_astro/{diagram-5GNKFQAL.DVoDnD3H.js → diagram-5GNKFQAL.Db6dcs89.js} +1 -1
  110. package/web/_astro/{diagram-KO2AKTUF.CRubTJ-0.js → diagram-KO2AKTUF.NVwzxu_U.js} +1 -1
  111. package/web/_astro/{diagram-LMA3HP47.m9SeYcXQ.js → diagram-LMA3HP47.B-eNgDQk.js} +1 -1
  112. package/web/_astro/{diagram-OG6HWLK6.C6s2ZjV5.js → diagram-OG6HWLK6.Bsa8ZRbJ.js} +1 -1
  113. package/web/_astro/{erDiagram-TEJ5UH35.nSzr5KTj.js → erDiagram-TEJ5UH35.BospRE5Q.js} +1 -1
  114. package/web/_astro/{flowDiagram-I6XJVG4X.DrZcys16.js → flowDiagram-I6XJVG4X.DMzvHwAA.js} +1 -1
  115. package/web/_astro/{ganttDiagram-6RSMTGT7.Do4M1b-K.js → ganttDiagram-6RSMTGT7.Dmdxgd-M.js} +1 -1
  116. package/web/_astro/{gitGraphDiagram-PVQCEYII.BWc9oJ4l.js → gitGraphDiagram-PVQCEYII.CaqdO0rL.js} +1 -1
  117. package/web/_astro/index.EoZlzLK-.css +1 -0
  118. package/web/_astro/{infoDiagram-5YYISTIA.BIdOctFk.js → infoDiagram-5YYISTIA.DDVD9Wn7.js} +1 -1
  119. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CV5SuG2t.js → ishikawaDiagram-YF4QCWOH.EKyCUFsL.js} +1 -1
  120. package/web/_astro/{journeyDiagram-JHISSGLW.CxE-rEJ-.js → journeyDiagram-JHISSGLW.By2-RkYB.js} +1 -1
  121. package/web/_astro/{kanban-definition-UN3LZRKU.BPRdKWs_.js → kanban-definition-UN3LZRKU.ar-WmlyR.js} +1 -1
  122. package/web/_astro/{linear.zRsuuDTE.js → linear.BnzMBgo_.js} +1 -1
  123. package/web/_astro/{mermaid.core.jAJTcMKc.js → mermaid.core.DSqeFu2Y.js} +4 -4
  124. package/web/_astro/{mindmap-definition-RKZ34NQL.BffJxfCr.js → mindmap-definition-RKZ34NQL.1XcF8Wh2.js} +1 -1
  125. package/web/_astro/{pieDiagram-4H26LBE5.CacwWaE3.js → pieDiagram-4H26LBE5.DnItHOdK.js} +1 -1
  126. package/web/_astro/{quadrantDiagram-W4KKPZXB.hXELD06-.js → quadrantDiagram-W4KKPZXB.BQQyrnBt.js} +1 -1
  127. package/web/_astro/{requirementDiagram-4Y6WPE33.DdEbPcqT.js → requirementDiagram-4Y6WPE33.Dmzxun82.js} +1 -1
  128. package/web/_astro/{sankeyDiagram-5OEKKPKP.DgaDocKv.js → sankeyDiagram-5OEKKPKP.BBIeRKYB.js} +1 -1
  129. package/web/_astro/{sequenceDiagram-3UESZ5HK.B0KScnAu.js → sequenceDiagram-3UESZ5HK.CUNVdBBf.js} +1 -1
  130. package/web/_astro/{stateDiagram-AJRCARHV.CV9M_WNc.js → stateDiagram-AJRCARHV.DlFf2sJm.js} +1 -1
  131. package/web/_astro/{stateDiagram-v2-BHNVJYJU.BOAo74Et.js → stateDiagram-v2-BHNVJYJU.DXR7I1H5.js} +1 -1
  132. package/web/_astro/{timeline-definition-PNZ67QCA.CqqepUMe.js → timeline-definition-PNZ67QCA.BcO-GyX2.js} +1 -1
  133. package/web/_astro/{vennDiagram-CIIHVFJN.DDqe4dOG.js → vennDiagram-CIIHVFJN.ChCECmmW.js} +1 -1
  134. package/web/_astro/{wardleyDiagram-YWT4CUSO.B3R9OPdO.js → wardleyDiagram-YWT4CUSO.CRaT12mD.js} +1 -1
  135. package/web/_astro/{xychartDiagram-2RQKCTM6.B3SvgXpQ.js → xychartDiagram-2RQKCTM6.B3lsHVpj.js} +1 -1
  136. package/web/index.html +2 -2
  137. package/plugins/sp/lib/artifact-digest.generated.d.mts +0 -7
  138. package/plugins/sp/lib/artifact-digest.generated.mjs +0 -48
  139. package/plugins/sp/scripts/feature-sync-bounded.mjs +0 -301
  140. package/plugins/sp/scripts/feature-sync-bounded.ts +0 -481
  141. package/plugins/sp/scripts/idea-coverage-check.ts +0 -168
  142. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +0 -298
  143. package/plugins/sp/scripts/record-feature-sync.mjs +0 -63
  144. package/plugins/sp/scripts/record-feature-sync.ts +0 -84
  145. package/plugins/sp/scripts/script-contract-check.ts +0 -506
  146. package/plugins/sp/scripts/stage-registry-adapter.ts +0 -1533
  147. package/plugins/sp/scripts/surface-drift-inventory.ts +0 -989
  148. package/plugins/sp/scripts/task-evidence-precheck.ts +0 -189
  149. package/plugins/sp/scripts/task-size-precheck.ts +0 -212
  150. package/plugins/sp/scripts/transition-shim-check.ts +0 -238
  151. package/plugins/sp/scripts/validate-commands.ts +0 -689
  152. package/plugins/sp/scripts/validate-flag-contracts.ts +0 -890
  153. package/plugins/sp/scripts/verify-answer-lint.ts +0 -549
  154. package/web/_astro/channel.CI6N_tCg.js +0 -1
  155. package/web/_astro/index.CENnIEqT.css +0 -1
@@ -3,18 +3,7 @@
3
3
 
4
4
  // plugins/sp/scripts/inline-run-setup.ts
5
5
  import { spawnSync } from "child_process";
6
- import {
7
- appendFileSync,
8
- closeSync,
9
- existsSync,
10
- mkdirSync,
11
- openSync,
12
- readFileSync,
13
- renameSync,
14
- unlinkSync,
15
- writeFileSync,
16
- writeSync
17
- } from "fs";
6
+ import { existsSync } from "fs";
18
7
  import { dirname, join, resolve } from "path";
19
8
  import { fileURLToPath } from "url";
20
9
 
@@ -26,35 +15,34 @@ function getEnvVar(name, fallback) {
26
15
 
27
16
  // plugins/sp/scripts/inline-run-setup.ts
28
17
  function usage() {
29
- console.error("Usage: bun plugins/sp/scripts/inline-run-setup.ts --run-id <id> --file <definition> [--spur-bin <path>]");
30
- console.error(" bun plugins/sp/scripts/inline-run-setup.ts --fingerprint --task-file <path> [--feature-file <path>] [--spur-bin <path>]");
31
- console.error(" bun plugins/sp/scripts/inline-run-setup.ts --action --run-id <id> --node <state> --kind <kind> " + "--status <done|failed> --ok <true|false> --duration-ms <n> [--spur-bin <path>]");
32
- console.error(" bun plugins/sp/scripts/inline-run-setup.ts --close --run-id <id> --status <done|failed|paused> [--reason <terminal-reason>] [--spur-bin <path>]");
33
- console.error(" bun plugins/sp/scripts/inline-run-setup.ts --persist-out --from <worktree-path> [--task-file <path>]... [--spur-bin <path>]");
34
- console.error(" terminal-reason is a closed enum (0937 R2): done, paused-operator, failed-check, failed-agent, " + "failed-timeout, failed-guard, cancelled, interrupted, retry-exhausted");
35
- console.error(" bun plugins/sp/scripts/inline-run-setup.ts --decide --run-id <id> --node <state> --options-json <file> [--spur-bin <path>]");
18
+ console.error([
19
+ "Usage: bun plugins/sp/scripts/inline-run-setup.ts --run-id <id> --file <definition> [--spur-bin <path>]",
20
+ " bun plugins/sp/scripts/inline-run-setup.ts --fingerprint --task-file <path> [--feature-file <path>] [--spur-bin <path>]",
21
+ " bun plugins/sp/scripts/inline-run-setup.ts --action --run-id <id> --node <state> --kind <kind> --status <done|failed> --ok <true|false> --duration-ms <n> [--spur-bin <path>]",
22
+ " bun plugins/sp/scripts/inline-run-setup.ts --actions-file <json-file> --run-id <id> [--spur-bin <path>] (1007 R5 batch trace emission)",
23
+ " bun plugins/sp/scripts/inline-run-setup.ts --close --run-id <id> --status <done|failed|paused> [--reason <terminal-reason>] [--spur-bin <path>]",
24
+ " bun plugins/sp/scripts/inline-run-setup.ts --persist-out --from <worktree-path> [--task-file <path>]... [--spur-bin <path>]",
25
+ " terminal-reason is a closed enum (0937 R2): done, paused-operator, failed-check, failed-agent, failed-timeout, failed-guard, cancelled, interrupted, retry-exhausted",
26
+ " bun plugins/sp/scripts/inline-run-setup.ts --decide --run-id <id> --node <state> --options-json <file> [--spur-bin <path>]"
27
+ ].join(`
28
+ `));
36
29
  process.exit(2);
37
30
  }
38
31
  var SAFE_RUN_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
39
32
  function refuseUnsafeRunId(runId) {
40
33
  console.error(`inline-run-setup: refusing unsafe run id: ${runId}`);
41
- console.error(" The run id must be a single safe filename component (alphanumeric/._-, no leading dot, " + "no path separators, interpolation or traversal; same class as the task-pipeline " + "route-reason guard, task 0804 R8). Allocate a fresh run id (uuid or timestamp slug) and retry.");
34
+ console.error(" The run id must be a single safe filename component (alphanumeric/._-, no leading dot, no path separators, interpolation or traversal; same class as the task-pipeline route-reason guard, task 0804 R8). Allocate a fresh run id (uuid or timestamp slug) and retry.");
42
35
  process.exit(1);
43
36
  }
44
37
  function resolveAppEntry(spurBin) {
45
- let candidates = [];
46
- if (spurBin !== "") {
47
- candidates = [spurBin];
48
- } else {
49
- candidates = [fileURLToPath(new URL("../../../apps/cli/src/index.ts", import.meta.url))];
50
- }
38
+ const fallback = fileURLToPath(new URL("../../../apps/cli/src/index.ts", import.meta.url));
39
+ const candidates = spurBin !== "" ? [spurBin] : [fallback];
51
40
  for (const candidate of candidates) {
52
41
  const tokens = candidate.split(/\s+/).filter(Boolean);
53
42
  const mainModule = [...tokens].reverse().find((t) => t.endsWith(".ts"));
54
43
  if (mainModule === undefined || !existsSync(mainModule))
55
44
  continue;
56
- const srcDir = dirname(mainModule);
57
- const repoRoot = resolve(srcDir, "..", "..", "..");
45
+ const repoRoot = resolve(dirname(mainModule), "..", "..", "..");
58
46
  const appEntry = join(repoRoot, "packages", "app", "src", "index.ts");
59
47
  if (existsSync(appEntry))
60
48
  return { entry: appEntry, portable: false };
@@ -77,86 +65,10 @@ async function readInstalledInventory(file, spurBin) {
77
65
  throw new Error(`could not resolve the workflow definition with the installed CLI: ${result.error?.message ?? result.stderr}`);
78
66
  }
79
67
  const value = JSON.parse(result.stdout);
80
- if (value && typeof value === "object" && "ok" in value && "data" in value && value.ok === true) {
68
+ if (value && typeof value === "object" && "ok" in value && "data" in value && value.ok === true)
81
69
  return value.data;
82
- }
83
70
  return value;
84
71
  }
85
- function writeOutcome(runId, outcome) {
86
- const runDir = join(process.cwd(), ".spur", "run");
87
- if (!existsSync(runDir))
88
- mkdirSync(runDir, { recursive: true });
89
- const statePath = join(runDir, `${runId}.state.json`);
90
- const markdownPath = join(runDir, `${runId}.md`);
91
- let prior = {};
92
- try {
93
- const parsed = JSON.parse(readFileSync(statePath, "utf8"));
94
- if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
95
- prior = parsed;
96
- }
97
- } catch {}
98
- const at = new Date().toISOString();
99
- const state = {
100
- schemaVersion: 1,
101
- runId,
102
- ...outcome.workflowName !== undefined ? { workflowName: outcome.workflowName } : {},
103
- ...outcome.status !== undefined ? { status: outcome.status } : {},
104
- startedAt: typeof prior.startedAt === "string" ? prior.startedAt : at,
105
- updatedAt: at,
106
- ...outcome.attached !== undefined ? { attached: outcome.attached } : {},
107
- ...outcome.definitionDigest !== undefined ? { definitionDigest: outcome.definitionDigest } : {},
108
- ...outcome.workflowVersion !== undefined ? { workflowVersion: outcome.workflowVersion } : {},
109
- ...outcome.resolvedPath !== undefined ? { resolvedPath: outcome.resolvedPath } : {},
110
- ...outcome.layer !== undefined ? { layer: outcome.layer } : {},
111
- ...outcome.workdir !== undefined ? { workdir: outcome.workdir } : {},
112
- ok: outcome.ok,
113
- ...outcome.ok === false && outcome.error !== undefined ? { error: outcome.error } : {}
114
- };
115
- const temp = `${statePath}.tmp`;
116
- try {
117
- writeFileSync(temp, `${JSON.stringify(state, null, 4)}
118
- `);
119
- renameSync(temp, statePath);
120
- } catch {
121
- try {
122
- unlinkSync(temp);
123
- } catch {}
124
- }
125
- let headerFd;
126
- try {
127
- headerFd = openSync(markdownPath, "wx");
128
- writeSync(headerFd, `# spur inline run ${runId} \u2014 ${outcome.workflowName ?? "unknown workflow"} \u2014 setup ${at}
129
- `);
130
- } catch {} finally {
131
- if (headerFd !== undefined)
132
- closeSync(headerFd);
133
- }
134
- }
135
- async function printFingerprint(taskFile, featureFile, spurBin) {
136
- const { entry } = resolveAppEntry(spurBin);
137
- const app = await import(entry);
138
- const workdir = process.cwd();
139
- const inputs = await app.readProofInputContents(undefined, workdir, {
140
- taskFile,
141
- ...featureFile.trim() !== "" ? { featureFile } : {}
142
- });
143
- if (!inputs.ok) {
144
- console.error(`inline-run-setup: FAIL \u2014 ${inputs.error}`);
145
- return 1;
146
- }
147
- const digest = await app.computeProofInputFingerprint({
148
- cwd: workdir,
149
- ...inputs.taskContent !== undefined ? { taskContent: inputs.taskContent } : {},
150
- ...inputs.featureContent !== undefined ? { featureContent: inputs.featureContent } : {}
151
- });
152
- process.stdout.write(`${digest}
153
- `);
154
- return 0;
155
- }
156
- var CLOSE_STATUSES = new Set(["done", "failed", "paused"]);
157
- function isCloseStatus(status) {
158
- return CLOSE_STATUSES.has(status);
159
- }
160
72
  var TERMINAL_REASONS = new Set([
161
73
  "done",
162
74
  "paused-operator",
@@ -168,135 +80,6 @@ var TERMINAL_REASONS = new Set([
168
80
  "interrupted",
169
81
  "retry-exhausted"
170
82
  ]);
171
- var ACTION_STATUSES = new Set(["done", "failed"]);
172
- function isActionStatus(status) {
173
- return ACTION_STATUSES.has(status);
174
- }
175
- function runRecordLogPath(runDir, runId) {
176
- const markdownPath = join(runDir, `${runId}.md`);
177
- const legacyLogPath = join(runDir, `${runId}.log`);
178
- if (existsSync(legacyLogPath) && !existsSync(markdownPath))
179
- return legacyLogPath;
180
- return markdownPath;
181
- }
182
- function appendRunLogLine(runId, detail) {
183
- try {
184
- const runDir = join(process.cwd(), ".spur", "run");
185
- if (!existsSync(runDir))
186
- mkdirSync(runDir, { recursive: true });
187
- const safeRunId = runId.replace(/[^A-Za-z0-9._-]/g, "_");
188
- const stamp = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
189
- appendFileSync(runRecordLogPath(runDir, safeRunId), `[${stamp}] ${detail}
190
- `);
191
- } catch {}
192
- }
193
- async function runTraceMode(input) {
194
- const operation = input.close ? "run.close" : "action.finish";
195
- const fail = (error) => {
196
- appendRunLogLine(input.runId, `trace-emission-failed operation=${operation} run=${input.runId}${input.node === "" ? "" : ` node=${input.node}`}${input.kind === "" ? "" : ` kind=${input.kind}`}: ${error}`);
197
- process.stdout.write(`${JSON.stringify({ ok: false, runId: input.runId, error })}
198
- `);
199
- return input.close ? 1 : 0;
200
- };
201
- let projectDb;
202
- try {
203
- const { entry } = resolveAppEntry(input.spurBin);
204
- const app = await import(entry);
205
- projectDb = await app.openInlineRunProjectDb(process.cwd());
206
- const writer = app.createWorkflowActionTraceWriter(projectDb.adapter, (failure) => {
207
- const detail = failure;
208
- appendRunLogLine(input.runId, `trace-emission-failed operation=${detail.operation ?? operation} run=${input.runId}: ${detail.error ?? "unknown error"}`);
209
- });
210
- const result = input.close ? await writer.closeRun(input.runId, input.status, undefined, input.reason) : await writer.recordAction({
211
- runId: input.runId,
212
- node: input.node,
213
- kind: input.kind,
214
- status: input.status,
215
- ok: input.ok,
216
- durationMs: input.durationMs
217
- });
218
- if (result.ok !== true && result.failure !== undefined) {
219
- const failure = result.failure;
220
- return fail(failure.error ?? "unknown trace emission failure");
221
- }
222
- if (input.close && input.status === "done" && result.actionRows === 0) {
223
- const error = `run ${input.runId} closed done with zero action_runs rows`;
224
- appendRunLogLine(input.runId, `trace-close-failed run=${input.runId}: ${error}`);
225
- process.stdout.write(`${JSON.stringify({ ok: false, runId: input.runId, error, code: "NO_ACTION_ROWS", actionRows: 0 })}
226
- `);
227
- return 1;
228
- }
229
- process.stdout.write(`${JSON.stringify({ ...result, runId: input.runId })}
230
- `);
231
- return 0;
232
- } catch (error) {
233
- if (input.close && error.name === "RunRowNotFoundError") {
234
- const message = error instanceof Error ? error.message : String(error);
235
- appendRunLogLine(input.runId, `trace-close-failed run=${input.runId}: ${message}`);
236
- process.stdout.write(`${JSON.stringify({ ok: false, runId: input.runId, error: message, code: "RUN_NOT_FOUND" })}
237
- `);
238
- return 1;
239
- }
240
- return fail(error instanceof Error ? error.message : String(error));
241
- } finally {
242
- projectDb?.close();
243
- }
244
- }
245
- async function runDecideMode(input) {
246
- const decideFailed = (error) => {
247
- process.stdout.write(`${JSON.stringify({ ok: false, runId: input.runId, error })}
248
- `);
249
- return 1;
250
- };
251
- let outcome;
252
- try {
253
- const { entry, portable } = resolveAppEntry(input.spurBin);
254
- const app = await import(entry);
255
- const lib = await import(fileURLToPath(new URL("../lib/inline-run.generated.mjs", import.meta.url)));
256
- const enabled = await lib.resolveDecideDecisionMakerEnabled(process.cwd(), portable ? { embeddedSchemas: lib.EMBEDDED_SPUR_SCHEMAS } : undefined);
257
- outcome = await app.runDecideForInlineRun({
258
- workdir: process.cwd(),
259
- optionsFile: input.optionsFile,
260
- enabled
261
- });
262
- } catch (error) {
263
- return decideFailed(error instanceof Error ? error.message : String(error));
264
- }
265
- if (!outcome.ok)
266
- return decideFailed(outcome.error ?? "decide failed without an error message");
267
- process.stdout.write(`${JSON.stringify({ runId: input.runId, node: input.node, ...outcome, ok: true })}
268
- `);
269
- appendRunLogLine(input.runId, `decide node=${input.node} value=${outcome.value ?? ""} source=${outcome.source ?? "default"} reason=${outcome.reason ?? ""}`);
270
- return await runTraceMode({
271
- runId: input.runId,
272
- close: false,
273
- node: input.node,
274
- kind: "decide",
275
- status: "done",
276
- ok: true,
277
- durationMs: outcome.durationMs ?? 0,
278
- spurBin: input.spurBin
279
- });
280
- }
281
- async function runPersistOutMode(input) {
282
- try {
283
- const { entry } = resolveAppEntry(input.spurBin);
284
- const app = await import(entry);
285
- const result = await app.persistWorktreeRuns({
286
- fromWorkdir: input.from,
287
- toWorkdir: process.cwd(),
288
- ...input.taskFiles.length > 0 ? { taskFiles: input.taskFiles } : {}
289
- });
290
- process.stdout.write(`${JSON.stringify({ ok: true, persisted: result.persisted, skipped: result.skipped })}
291
- `);
292
- return 0;
293
- } catch (error) {
294
- const message = error instanceof Error ? error.message : String(error);
295
- process.stdout.write(`${JSON.stringify({ ok: false, error: message })}
296
- `);
297
- return 1;
298
- }
299
- }
300
83
  async function main() {
301
84
  if (!process.versions.bun) {
302
85
  const child = spawnSync("bun", [fileURLToPath(import.meta.url), ...process.argv.slice(2)], {
@@ -306,67 +89,59 @@ async function main() {
306
89
  console.error(`inline-run-setup requires Bun on PATH: ${child.error.message}`);
307
90
  process.exit(child.status ?? 1);
308
91
  }
309
- let runId = "";
310
- let file = "";
311
- let fingerprint = false;
92
+ const flags = new Map;
93
+ let fingerprint = false, action = false, close = false, decide = false, persistOut = false;
312
94
  const taskFiles = [];
313
- let featureFile = "";
314
- let action = false;
315
- let close = false;
316
- let decide = false;
317
- let persistOut = false;
318
- let from = "";
319
- let optionsJson = "";
320
- let node = "";
321
- let kind = "";
322
- let status = "";
323
- let reason = "";
324
- let okRaw = "";
325
- let durationRaw = "";
326
95
  let spurBin = getEnvVar("SPUR_BIN") ?? "";
327
96
  const argv = process.argv.slice(2);
328
97
  for (let i = 0;i < argv.length; i++) {
329
- if (argv[i] === "--run-id")
330
- runId = argv[++i] ?? "";
331
- else if (argv[i] === "--file")
332
- file = argv[++i] ?? "";
333
- else if (argv[i] === "--fingerprint")
98
+ const flag = argv[i];
99
+ if (flag === "--fingerprint")
334
100
  fingerprint = true;
335
- else if (argv[i] === "--task-file")
336
- taskFiles.push(argv[++i] ?? "");
337
- else if (argv[i] === "--feature-file")
338
- featureFile = argv[++i] ?? "";
339
- else if (argv[i] === "--action")
101
+ else if (flag === "--action")
340
102
  action = true;
341
- else if (argv[i] === "--close")
103
+ else if (flag === "--close")
342
104
  close = true;
343
- else if (argv[i] === "--decide")
105
+ else if (flag === "--decide")
344
106
  decide = true;
345
- else if (argv[i] === "--persist-out")
107
+ else if (flag === "--persist-out")
346
108
  persistOut = true;
347
- else if (argv[i] === "--from")
348
- from = argv[++i] ?? "";
349
- else if (argv[i] === "--options-json")
350
- optionsJson = argv[++i] ?? "";
351
- else if (argv[i] === "--node")
352
- node = argv[++i] ?? "";
353
- else if (argv[i] === "--kind")
354
- kind = argv[++i] ?? "";
355
- else if (argv[i] === "--status")
356
- status = argv[++i] ?? "";
357
- else if (argv[i] === "--reason")
358
- reason = argv[++i] ?? "";
359
- else if (argv[i] === "--ok")
360
- okRaw = argv[++i] ?? "";
361
- else if (argv[i] === "--duration-ms")
362
- durationRaw = argv[++i] ?? "";
363
- else if (argv[i] === "--spur-bin")
109
+ else if (flag === "--task-file")
110
+ taskFiles.push(argv[++i] ?? "");
111
+ else if (flag === "--spur-bin")
364
112
  spurBin = argv[++i] ?? spurBin;
365
- }
113
+ else if (flag !== undefined)
114
+ flags.set(flag, argv[++i] ?? "");
115
+ }
116
+ const runId = flags.get("--run-id") ?? "";
117
+ const file = flags.get("--file") ?? "";
118
+ const featureFile = flags.get("--feature-file") ?? "";
119
+ const from = flags.get("--from") ?? "";
120
+ const optionsJson = flags.get("--options-json") ?? "";
121
+ const node = flags.get("--node") ?? "";
122
+ const kind = flags.get("--kind") ?? "";
123
+ const status = flags.get("--status") ?? "";
124
+ const reason = flags.get("--reason") ?? "";
125
+ const okRaw = flags.get("--ok") ?? "";
126
+ const durationRaw = flags.get("--duration-ms") ?? "";
127
+ const actionsFile = flags.get("--actions-file") ?? "";
366
128
  if (fingerprint) {
367
129
  if (runId !== "" || file !== "" || taskFiles.length !== 1 || (taskFiles[0] ?? "").trim() === "")
368
130
  usage();
369
- process.exit(await printFingerprint(taskFiles[0] ?? "", featureFile, spurBin));
131
+ const app2 = await import(resolveAppEntry(spurBin).entry);
132
+ process.exit(await app2.runInlineRunFingerprint({ taskFile: taskFiles[0] ?? "", featureFile }));
133
+ }
134
+ if (actionsFile !== "") {
135
+ if (action || close || fingerprint || decide || persistOut || file !== "" || taskFiles.length > 0)
136
+ usage();
137
+ if (runId.trim() === "" || status !== "" || node !== "" || kind !== "")
138
+ usage();
139
+ if (okRaw !== "" || durationRaw !== "")
140
+ usage();
141
+ if (!SAFE_RUN_ID_RE.test(runId))
142
+ refuseUnsafeRunId(runId);
143
+ const app2 = await import(resolveAppEntry(spurBin).entry);
144
+ process.exit(await app2.runInlineRunTraceBatch({ runId, actionsFile }));
370
145
  }
371
146
  if (decide) {
372
147
  if (action || close || fingerprint || file !== "" || taskFiles.length > 0)
@@ -375,14 +150,27 @@ async function main() {
375
150
  usage();
376
151
  if (!SAFE_RUN_ID_RE.test(runId))
377
152
  refuseUnsafeRunId(runId);
378
- process.exit(await runDecideMode({ runId, node, optionsFile: optionsJson, spurBin }));
153
+ try {
154
+ const { entry: entry2, portable: portable2 } = resolveAppEntry(spurBin);
155
+ const app2 = await import(entry2);
156
+ const bundlePath = fileURLToPath(new URL("../lib/inline-run.generated.mjs", import.meta.url));
157
+ const lib = await import(bundlePath);
158
+ const enabled = await lib.resolveDecideDecisionMakerEnabled(process.cwd(), portable2 ? { embeddedSchemas: lib.EMBEDDED_SPUR_SCHEMAS } : undefined);
159
+ process.exit(await app2.runInlineRunDecide({ runId, node, optionsFile: optionsJson, enabled }));
160
+ } catch (error) {
161
+ const message = error instanceof Error ? error.message : String(error);
162
+ process.stdout.write(`${JSON.stringify({ ok: false, runId, error: message })}
163
+ `);
164
+ process.exit(1);
165
+ }
379
166
  }
380
167
  if (persistOut) {
381
168
  if (fingerprint || decide || action || close || runId !== "" || file !== "")
382
169
  usage();
383
170
  if (from.trim() === "" || taskFiles.some((taskFile) => taskFile.trim() === ""))
384
171
  usage();
385
- process.exit(await runPersistOutMode({ from, taskFiles, spurBin }));
172
+ const app2 = await import(resolveAppEntry(spurBin).entry);
173
+ process.exit(await app2.runInlineRunPersistOut({ from, taskFiles }));
386
174
  }
387
175
  if (action || close) {
388
176
  if (action && close)
@@ -391,16 +179,13 @@ async function main() {
391
179
  usage();
392
180
  if (!SAFE_RUN_ID_RE.test(runId))
393
181
  refuseUnsafeRunId(runId);
182
+ const app2 = await import(resolveAppEntry(spurBin).entry);
394
183
  if (close) {
395
- if (!isCloseStatus(status))
184
+ if (!app2.isInlineRunCloseStatus(status))
396
185
  usage();
397
- if (reason.trim() === "") {
398
- if (status === "failed")
399
- usage();
400
- } else if (!TERMINAL_REASONS.has(reason)) {
186
+ if (reason.trim() === "" ? status === "failed" : !TERMINAL_REASONS.has(reason))
401
187
  usage();
402
- }
403
- process.exit(await runTraceMode({
188
+ process.exit(await app2.runInlineRunTrace({
404
189
  runId,
405
190
  close: true,
406
191
  node: "",
@@ -408,21 +193,19 @@ async function main() {
408
193
  status,
409
194
  ok: true,
410
195
  durationMs: 0,
411
- spurBin,
412
196
  ...reason.trim() === "" ? {} : { reason }
413
197
  }));
414
198
  }
415
199
  if (node.trim() === "" || kind.trim() === "")
416
200
  usage();
417
- if (!isActionStatus(status))
201
+ if (!app2.isInlineRunActionStatus(status))
418
202
  usage();
419
203
  if (okRaw !== "true" && okRaw !== "false")
420
204
  usage();
421
- const ok = okRaw === "true";
422
205
  const durationMs = Number(durationRaw);
423
206
  if (durationRaw.trim() === "" || !Number.isFinite(durationMs) || durationMs < 0)
424
207
  usage();
425
- process.exit(await runTraceMode({ runId, close: false, node, kind, status, ok, durationMs, spurBin }));
208
+ process.exit(await app2.runInlineRunTrace({ runId, close: false, node, kind, status, ok: okRaw === "true", durationMs }));
426
209
  }
427
210
  if (runId.trim() === "" || file.trim() === "")
428
211
  usage();
@@ -430,38 +213,20 @@ async function main() {
430
213
  refuseUnsafeRunId(runId);
431
214
  const { entry, portable } = resolveAppEntry(spurBin);
432
215
  const app = await import(entry);
433
- const workdir = process.cwd();
434
216
  let inventory;
435
217
  try {
436
218
  inventory = await readInstalledInventory(file, spurBin);
437
219
  } catch (error) {
438
220
  const message = `could not resolve the workflow definition: ${error instanceof Error ? error.message : String(error)}`;
439
- writeOutcome(runId, { ok: false, runId, error: message });
221
+ app.writeInlineRunOutcome(runId, { ok: false, runId, error: message });
440
222
  throw new Error(message);
441
223
  }
442
- const projectDb = await app.openInlineRunProjectDb(workdir);
443
- let exitCode = 0;
444
- try {
445
- const result = await app.createOrAttachInlineRun({
446
- workdir,
447
- getDb: async () => projectDb.adapter,
448
- file,
449
- runId,
450
- inventory,
451
- ...portable ? { embeddedSchemas: app.EMBEDDED_SPUR_SCHEMAS } : {}
452
- });
453
- writeOutcome(runId, result);
454
- if (!result.ok) {
455
- console.error(`inline-run-setup: FAIL for run ${runId}`);
456
- console.error(` ${result.error}`);
457
- exitCode = 1;
458
- } else {
459
- console.error(`inline-run-setup: ${result.attached ? "attached" : "created"} run ${runId} (${result.workflowName}, layer ${result.layer}, digest ${result.definitionDigest}, status ${result.status})`);
460
- }
461
- } finally {
462
- projectDb.close();
463
- }
464
- process.exit(exitCode);
224
+ process.exit(await app.runInlineRunSetup({
225
+ runId,
226
+ file,
227
+ inventory,
228
+ ...portable ? { embeddedSchemas: app.EMBEDDED_SPUR_SCHEMAS } : {}
229
+ }));
465
230
  }
466
231
  main().catch((e) => {
467
232
  console.error(`inline-run-setup: FAIL \u2014 ${e instanceof Error ? e.message : String(e)}`);