@gobing-ai/spur 0.4.2 → 0.4.4

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 (168) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/decisions/maker-liveness.yaml +39 -0
  3. package/config/plugin-scripts.json +0 -4
  4. package/config/rules/README.md +1 -0
  5. package/config/rules/docs/sourced-api-claims.yaml +56 -12
  6. package/config/rules/docs/verdict-confidence.yaml +68 -0
  7. package/config/rules/quality/coverage-gate.yaml +13 -0
  8. package/config/rules/recommended-pre-check.yaml +6 -2
  9. package/config/rules/strict/runtime-boundaries.yaml +10 -0
  10. package/config/rules/surface/check-cli-surface.yaml +1 -3
  11. package/config/script-placement-baseline.json +1 -19
  12. package/config/templates/AGENTS.md +7 -0
  13. package/config/workflows/feature-lifecycle.yaml +46 -1
  14. package/config/workflows/feature-verification.yaml +20 -1
  15. package/config/workflows/task-lifecycle.yaml +50 -0
  16. package/config/workflows/task-pipeline.yaml +15 -9
  17. package/package.json +10 -10
  18. package/plugins/sp/README.md +22 -16
  19. package/plugins/sp/agents/super-reviewer.md +46 -0
  20. package/plugins/sp/bunfig.toml +8 -5
  21. package/plugins/sp/commands/dev-changelog.md +1 -1
  22. package/plugins/sp/commands/dev-gitmsg.md +6 -2
  23. package/plugins/sp/commands/dev-handover.md +1 -0
  24. package/plugins/sp/commands/dev-job-dump.md +2 -1
  25. package/plugins/sp/commands/dev-refine.md +14 -2
  26. package/plugins/sp/commands/dev-refineall.md +7 -1
  27. package/plugins/sp/commands/dev-review.md +1 -0
  28. package/plugins/sp/hooks/careful-guard.ts +1 -1
  29. package/plugins/sp/hooks/context-post-tool.ts +7 -427
  30. package/plugins/sp/hooks/context-session-start.ts +5 -213
  31. package/plugins/sp/hooks/context-session-stop.ts +5 -191
  32. package/plugins/sp/hooks/pi/guard-extension.ts +6 -5
  33. package/plugins/sp/hooks/task-write-guard.ts +1 -1
  34. package/plugins/sp/{hooks → lib}/agent-hint.ts +1 -1
  35. package/plugins/sp/lib/context-post-tool.ts +432 -0
  36. package/plugins/sp/lib/context-session-start.ts +214 -0
  37. package/plugins/sp/lib/context-session-stop.ts +196 -0
  38. package/plugins/sp/lib/dogfood-pipeline.ts +265 -0
  39. package/plugins/sp/lib/dogfood-report.ts +278 -0
  40. package/plugins/sp/lib/history-anatomy.generated.mjs +18 -18
  41. package/plugins/sp/lib/idea-handoff.generated.mjs +91 -91
  42. package/plugins/sp/lib/inline-run-app.ts +40 -0
  43. package/plugins/sp/lib/inline-run.generated.d.mts +3 -3
  44. package/plugins/sp/lib/inline-run.generated.mjs +1425 -212
  45. package/plugins/sp/lib/plan-projection.generated.d.mts +150 -0
  46. package/plugins/sp/lib/plan-projection.generated.mjs +623 -9
  47. package/plugins/sp/lib/quality-gate.generated.d.mts +1 -0
  48. package/plugins/sp/lib/quality-gate.generated.mjs +13809 -13969
  49. package/plugins/sp/lib/residual-scan.generated.d.mts +20 -1
  50. package/plugins/sp/lib/residual-scan.generated.mjs +120 -25
  51. package/plugins/sp/lib/run-summary-core.ts +34 -370
  52. package/plugins/sp/lib/step-profile.generated.mjs +8 -8
  53. package/plugins/sp/lib/transcript.ts +37 -228
  54. package/plugins/sp/plugin.json +1 -1
  55. package/plugins/sp/scripts/batch-plan.mjs +619 -11
  56. package/plugins/sp/scripts/batch-preflight.mjs +57 -13
  57. package/plugins/sp/scripts/batch-preflight.ts +35 -295
  58. package/plugins/sp/scripts/commit-guard.mjs +6 -6
  59. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +127 -108
  60. package/plugins/sp/scripts/daily-summary/daily-summary.ts +111 -104
  61. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +13 -12
  62. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +7 -265
  63. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +7 -4
  64. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +6 -272
  65. package/plugins/sp/scripts/feature-verification-steps.mjs +20 -125
  66. package/plugins/sp/scripts/feature-verification-steps.ts +57 -181
  67. package/plugins/sp/scripts/history-anatomy-cache.mjs +19 -19
  68. package/plugins/sp/scripts/idea-handoff.mjs +2 -2
  69. package/plugins/sp/scripts/inline-run-dispatch.mjs +25 -24
  70. package/plugins/sp/scripts/inline-run-dispatch.ts +1 -21
  71. package/plugins/sp/scripts/inline-run-setup.mjs +164 -137
  72. package/plugins/sp/scripts/inline-run-setup.ts +1 -21
  73. package/plugins/sp/scripts/persist-out-check.mjs +5 -5
  74. package/plugins/sp/scripts/pr-reviewing.mjs +13 -13
  75. package/plugins/sp/scripts/quality-gate.mjs +13730 -13887
  76. package/plugins/sp/scripts/residual-scan.mjs +129 -31
  77. package/plugins/sp/scripts/residual-scan.ts +16 -13
  78. package/plugins/sp/scripts/run-summary.mjs +166 -112
  79. package/plugins/sp/scripts/run-summary.ts +7 -5
  80. package/plugins/sp/scripts/script-root.mjs +6 -6
  81. package/plugins/sp/scripts/session-timeline.mjs +62 -35
  82. package/plugins/sp/scripts/task-diffstat.mjs +19 -9
  83. package/plugins/sp/scripts/task-diffstat.ts +8 -39
  84. package/plugins/sp/scripts/workflow-step-profile.mjs +12 -12
  85. package/plugins/sp/scripts/wrapup-drift-probe.mjs +9 -9
  86. package/plugins/sp/scripts/wrapup-steps.mjs +25 -25
  87. package/plugins/sp/skills/code-implementation/SKILL.md +7 -1
  88. package/plugins/sp/skills/code-verification/references/secu-review.md +2 -1
  89. package/plugins/sp/skills/code-verification/references/verdict-schema.md +4 -0
  90. package/plugins/sp/skills/dogfood-testing/SKILL.md +2 -2
  91. package/plugins/sp/skills/next-feature/SKILL.md +1 -1
  92. package/plugins/sp/skills/next-router/SKILL.md +3 -1
  93. package/plugins/sp/skills/next-router/references/routing-table.md +9 -3
  94. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
  95. package/plugins/sp/skills/source-driven-development/SKILL.md +7 -4
  96. package/plugins/sp/skills/spur-cli/references/builder.md +3 -2
  97. package/plugins/sp/skills/spur-cli/references/decision.md +32 -7
  98. package/plugins/sp/skills/spur-cli/references/features.md +46 -5
  99. package/plugins/sp/skills/spur-cli/references/tasks.md +24 -4
  100. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +8 -1
  101. package/plugins/sp/skills/spur-dev/references/dev-operations.md +37 -11
  102. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +1 -1
  103. package/plugins/sp/skills/spur-dev/references/execution-batch.md +19 -6
  104. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +22 -0
  105. package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +14 -0
  106. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +4 -2
  107. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +49 -12
  108. package/schemas/section-matrix.schema.json +3 -2
  109. package/spur.js +66591 -73262
  110. package/web/_astro/{BoardApp.B3GQZvj8.js → BoardApp.Niubpe6z.js} +1 -1
  111. package/web/_astro/{BoardApp.BT7L2kSb.js → BoardApp.hF0RAIrg.js} +150 -150
  112. package/web/_astro/TaskDetail.DJpapt38.js +1 -0
  113. package/web/_astro/{arc.vaT7tPOB.js → arc.BgKcK0i8.js} +1 -1
  114. package/web/_astro/{architectureDiagram-3BPJPVTR.DRMmTjkN.js → architectureDiagram-3BPJPVTR.ChP-Ig0V.js} +1 -1
  115. package/web/_astro/{blockDiagram-GPEHLZMM.cla0LO_q.js → blockDiagram-GPEHLZMM.BVaCBoeN.js} +1 -1
  116. package/web/_astro/{c4Diagram-AAUBKEIU.D4YAIBKn.js → c4Diagram-AAUBKEIU.CHSDpEO5.js} +1 -1
  117. package/web/_astro/channel.DkpvN2tD.js +1 -0
  118. package/web/_astro/{chunk-2J33WTMH.BrSJbMRZ.js → chunk-2J33WTMH.MYRcYVRa.js} +1 -1
  119. package/web/_astro/{chunk-4BX2VUAB.CuLMgKF5.js → chunk-4BX2VUAB.S5j22Zqa.js} +1 -1
  120. package/web/_astro/{chunk-55IACEB6.zkvgu54F.js → chunk-55IACEB6.gciRPvmZ.js} +1 -1
  121. package/web/_astro/{chunk-727SXJPM.DxWkACh8.js → chunk-727SXJPM.CdqrSQkX.js} +1 -1
  122. package/web/_astro/{chunk-AQP2D5EJ.42XrmIlH.js → chunk-AQP2D5EJ.CyokdHT3.js} +1 -1
  123. package/web/_astro/{chunk-FMBD7UC4.Bao2wMK9.js → chunk-FMBD7UC4.Bg9KJhjW.js} +1 -1
  124. package/web/_astro/{chunk-ND2GUHAM.BhydojD1.js → chunk-ND2GUHAM.1gxxI-vD.js} +1 -1
  125. package/web/_astro/{chunk-QZHKN3VN.CmZ82g-H.js → chunk-QZHKN3VN.DDEYtCKU.js} +1 -1
  126. package/web/_astro/{classDiagram-4FO5ZUOK.Blr83Gt_.js → classDiagram-4FO5ZUOK.Ch3zi37T.js} +1 -1
  127. package/web/_astro/{classDiagram-v2-Q7XG4LA2.Blr83Gt_.js → classDiagram-v2-Q7XG4LA2.Ch3zi37T.js} +1 -1
  128. package/web/_astro/{cose-bilkent-S5V4N54A.qmfv0SPn.js → cose-bilkent-S5V4N54A.D2q5AINI.js} +1 -1
  129. package/web/_astro/{cynefin-OW5HDTMX.BtELhXPR.js → cynefin-OW5HDTMX.BA9kC2YT.js} +1 -1
  130. package/web/_astro/{dagre-BM42HDAG.AWmaAvXo.js → dagre-BM42HDAG.CHO08nRp.js} +1 -1
  131. package/web/_astro/{diagram-2AECGRRQ.DdH34KDi.js → diagram-2AECGRRQ.BfFQt0LW.js} +1 -1
  132. package/web/_astro/{diagram-5GNKFQAL.BmNPix1k.js → diagram-5GNKFQAL.CHMwMTe4.js} +1 -1
  133. package/web/_astro/{diagram-KO2AKTUF.BNQd_Ppo.js → diagram-KO2AKTUF.BJ-7gK-w.js} +1 -1
  134. package/web/_astro/{diagram-LMA3HP47.BAPgDi0e.js → diagram-LMA3HP47.C5xqcc0t.js} +1 -1
  135. package/web/_astro/{diagram-OG6HWLK6.DZ4zyLdC.js → diagram-OG6HWLK6.C2pQjfrC.js} +1 -1
  136. package/web/_astro/{erDiagram-TEJ5UH35.Q1TySMmw.js → erDiagram-TEJ5UH35._FoNyxgC.js} +1 -1
  137. package/web/_astro/{flowDiagram-I6XJVG4X.BXhFBicG.js → flowDiagram-I6XJVG4X.B_ENkT2I.js} +1 -1
  138. package/web/_astro/{ganttDiagram-6RSMTGT7.vHSgcuo2.js → ganttDiagram-6RSMTGT7.B3q8h77C.js} +1 -1
  139. package/web/_astro/{gitGraphDiagram-PVQCEYII.Bi1f73C7.js → gitGraphDiagram-PVQCEYII.QWZFDboZ.js} +1 -1
  140. package/web/_astro/index.BFyW13JJ.css +1 -0
  141. package/web/_astro/{infoDiagram-5YYISTIA.DPvXZEWm.js → infoDiagram-5YYISTIA.Cs6eEc92.js} +1 -1
  142. package/web/_astro/{ishikawaDiagram-YF4QCWOH.Cz829fsV.js → ishikawaDiagram-YF4QCWOH.BU9DJMHA.js} +1 -1
  143. package/web/_astro/{journeyDiagram-JHISSGLW.enRnB9Me.js → journeyDiagram-JHISSGLW.D35k6Jpe.js} +1 -1
  144. package/web/_astro/{kanban-definition-UN3LZRKU.DnTNk6d2.js → kanban-definition-UN3LZRKU.DBqcAT4m.js} +1 -1
  145. package/web/_astro/{linear.BzGnBwNL.js → linear.D-LSNK8W.js} +1 -1
  146. package/web/_astro/{mermaid.core.CSbTpIVz.js → mermaid.core.CSruWVOa.js} +4 -4
  147. package/web/_astro/{mindmap-definition-RKZ34NQL.DGJDy8zT.js → mindmap-definition-RKZ34NQL.BiFaUsfj.js} +1 -1
  148. package/web/_astro/{pieDiagram-4H26LBE5.HSPdi5_8.js → pieDiagram-4H26LBE5.D1KTKqb9.js} +1 -1
  149. package/web/_astro/{quadrantDiagram-W4KKPZXB.6Gv8mz2Y.js → quadrantDiagram-W4KKPZXB.DBHflsMG.js} +1 -1
  150. package/web/_astro/{requirementDiagram-4Y6WPE33.CnBCtFwa.js → requirementDiagram-4Y6WPE33.hwX9CNdk.js} +1 -1
  151. package/web/_astro/{sankeyDiagram-5OEKKPKP.5M8VWAu8.js → sankeyDiagram-5OEKKPKP.DkI8mJiE.js} +1 -1
  152. package/web/_astro/{sequenceDiagram-3UESZ5HK.DN41XN-U.js → sequenceDiagram-3UESZ5HK.DMz7jBDx.js} +1 -1
  153. package/web/_astro/{stateDiagram-AJRCARHV.ErOO3W8j.js → stateDiagram-AJRCARHV.B6Ef2xJ1.js} +1 -1
  154. package/web/_astro/{stateDiagram-v2-BHNVJYJU.B_ZHICM-.js → stateDiagram-v2-BHNVJYJU.CgoaufB9.js} +1 -1
  155. package/web/_astro/{timeline-definition-PNZ67QCA.CWdosr07.js → timeline-definition-PNZ67QCA.B3c8h1t-.js} +1 -1
  156. package/web/_astro/{vennDiagram-CIIHVFJN.BHzYjNV5.js → vennDiagram-CIIHVFJN.BdHPAxAb.js} +1 -1
  157. package/web/_astro/{wardleyDiagram-YWT4CUSO.h8x4IwPX.js → wardleyDiagram-YWT4CUSO.BrJXPPAj.js} +1 -1
  158. package/web/_astro/{xychartDiagram-2RQKCTM6.RTapW2X8.js → xychartDiagram-2RQKCTM6.CMH5yFsV.js} +1 -1
  159. package/web/index.html +2 -2
  160. package/web/spur_logo.svg +1 -1
  161. package/config/proportional-route-table.ts +0 -155
  162. package/plugins/sp/scripts/daily-summary/logger.ts +0 -28
  163. package/web/_astro/TaskDetail.Cxov1_N_.js +0 -1
  164. package/web/_astro/channel.D4nG9YLf.js +0 -1
  165. package/web/_astro/index.BhSwN8yY.css +0 -1
  166. /package/plugins/sp/{hooks → lib}/context-owner.ts +0 -0
  167. /package/plugins/sp/{hooks → lib}/destructive-policy.ts +0 -0
  168. /package/plugins/sp/{hooks → lib}/task-file-policy.ts +0 -0
@@ -3,19 +3,7 @@
3
3
 
4
4
  // plugins/sp/scripts/feature-verification-steps.ts
5
5
  import { spawnSync } from "child_process";
6
- import {
7
- closeSync,
8
- existsSync,
9
- mkdirSync,
10
- openSync,
11
- readdirSync,
12
- readFileSync,
13
- realpathSync,
14
- renameSync,
15
- statSync,
16
- writeFileSync
17
- } from "fs";
18
- import { join } from "path";
6
+ import { existsSync } from "fs";
19
7
  import { fileURLToPath } from "url";
20
8
 
21
9
  // plugins/sp/lib/env.ts
@@ -25,12 +13,11 @@ function getEnvVar(name, fallback) {
25
13
  }
26
14
 
27
15
  // plugins/sp/scripts/feature-verification-steps.ts
28
- var SAFE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
29
16
  function bundleEntry() {
30
17
  return fileURLToPath(new URL("../lib/inline-run.generated.mjs", import.meta.url));
31
18
  }
32
19
  function sourceModeError(spurBin) {
33
- return new Error(`source mode: refusing to load packages/app/src/index.ts (spurBin=${JSON.stringify(spurBin)}). ` + "That entry is not the feature-verification contract surface \u2014 it does not export " + "splitLaunchCommand / ArtifactDao. Fix: run in bundle mode so " + "plugins/sp/lib/inline-run.generated.mjs is loaded (omit --module-mode, or pass --module-mode bundle) " + "and regenerate that bundle if it is missing. Reinstalling the sp plugin does not add these seams to the app source entry.");
20
+ return new Error(`source mode: refusing to load packages/app/src/index.ts (spurBin=${JSON.stringify(spurBin)}). ` + "That entry is not the feature-verification contract surface \u2014 it does not export " + "runFeatureVerification. Fix: run in bundle mode so " + "plugins/sp/lib/inline-run.generated.mjs is loaded (omit --module-mode, or pass --module-mode bundle) " + "and regenerate that bundle if it is missing. Reinstalling the sp plugin does not add the operation to the app source entry.");
34
21
  }
35
22
  function resolveModuleMode(raw) {
36
23
  if (raw === "" || raw === "bundle")
@@ -50,125 +37,33 @@ async function loadModule(spurBin, mode) {
50
37
  }
51
38
  async function requireModule(entry, mode) {
52
39
  const mod = await import(entry);
53
- const missing = [
54
- "startFeatureVerificationReceipt",
55
- "completeFeatureVerificationReceipt",
56
- "captureFeatureReceiptDigest",
57
- "resolveWorkflowDefinition",
58
- "splitLaunchCommand",
59
- "openInlineRunProjectDb",
60
- "ArtifactDao"
61
- ].filter((k) => typeof mod[k] !== "function");
40
+ const missing = ["runFeatureVerification"].filter((k) => typeof mod[k] !== "function");
62
41
  if (missing.length > 0) {
63
42
  throw new Error(`feature-verification-steps: mode=${mode} \u2014 application entry ${entry} is missing feature-verification seams (${missing.join(", ")}). ` + "Fix: the generated inline bundle is stale or incomplete \u2014 run `bun run build:bundle` in a source checkout, or reinstall the sp plugin.");
64
43
  }
65
44
  return mod;
66
45
  }
67
- function assertSafeId(kind, id) {
68
- if (!SAFE_ID_RE.test(id) || id.includes("..")) {
69
- throw new Error(`refusing unsafe ${kind}: ${id}`);
70
- }
71
- }
72
- function findFeatureFile(featureDir, featureId) {
73
- if (!existsSync(featureDir))
74
- return;
75
- const name = readdirSync(featureDir).find((n) => n.startsWith(`${featureId}_`) && n.endsWith(".md"));
76
- return name === undefined ? undefined : join(featureDir, name);
77
- }
78
- var nodeFsShim = {
79
- realPath: realpathSync,
80
- readDir: readdirSync,
81
- stat: (path) => {
82
- try {
83
- return statSync(path);
84
- } catch (error) {
85
- if (error.code === "ENOENT")
86
- return null;
87
- throw error;
88
- }
89
- },
90
- ensureDir: (dir) => {
91
- mkdirSync(dir, { recursive: true });
92
- },
93
- writeFile: (path, body) => {
94
- writeFileSync(path, body);
95
- },
96
- rename: (src, dest) => {
97
- renameSync(src, dest);
98
- },
99
- readFile: (path) => {
100
- return readFileSync(path, "utf8");
101
- }
102
- };
103
- async function verify(featureId, runId, cmdOverride, spurBin, mode) {
104
- assertSafeId("feature id", featureId);
105
- assertSafeId("run id", runId);
106
- const cwd = process.cwd();
46
+ async function verify(featureId, runId, cmdOverride, spurBin, mode, confidenceOverride, ackLowConfidence) {
107
47
  const mod = await loadModule(spurBin, mode);
108
- const runDir = join(cwd, ".spur", "run");
109
- mkdirSync(runDir, { recursive: true });
110
- const selected = await mod.resolveWorkflowDefinition(cwd, "feature-verification");
111
- const vars = selected.workflow.vars;
112
- const configuredCmd = typeof vars?.verificationCmd === "string" && vars.verificationCmd.length > 0 ? vars.verificationCmd : "bun run spur-check-feature";
113
- const effectiveCmd = cmdOverride !== "" ? cmdOverride : configuredCmd;
114
- const featureFile = findFeatureFile(join(cwd, "docs", "features"), featureId);
115
- if (featureFile === undefined) {
116
- throw new Error(`feature ${featureId} not found under ${join(cwd, "docs", "features")}`);
117
- }
118
- const featureContent = readFileSync(featureFile, "utf8");
119
- const learningsPath = join(cwd, ".spur", "context", "learnings.md");
120
- const learningsContent = existsSync(learningsPath) ? readFileSync(learningsPath, "utf8") : undefined;
121
- const beforeDigest = await mod.captureFeatureReceiptDigest(cwd, featureContent, learningsContent);
122
- const receipt = await mod.startFeatureVerificationReceipt(nodeFsShim, runDir, {
48
+ const result = await mod.runFeatureVerification({
49
+ workdir: process.cwd(),
123
50
  featureId,
124
51
  runId,
125
- workdir: cwd,
126
- verifier: {
127
- name: "feature-verification",
128
- sourcePath: selected.path,
129
- layer: selected.layer,
130
- definitionDigest: selected.digest
131
- },
132
- verificationCmd: effectiveCmd,
133
- inputDigest: beforeDigest
52
+ cmdOverride,
53
+ confidenceOverride,
54
+ ackLowConfidence
134
55
  });
135
- const db = await mod.openInlineRunProjectDb(cwd);
136
- try {
137
- await new mod.ArtifactDao(db.adapter).record({
138
- runId,
139
- path: mod.featureReceiptPaths(runDir, featureId, runId).runScoped,
140
- kind: "feature-verification"
141
- });
142
- } finally {
143
- db.close();
144
- }
145
- const logPath = join(runDir, `${runId}-feature-verification.log`);
146
- const launch = mod.splitLaunchCommand(effectiveCmd, "feature-verification verificationCmd");
147
- if ("error" in launch) {
148
- await mod.completeFeatureVerificationReceipt(nodeFsShim, runDir, receipt, {
149
- status: "FAIL",
150
- inputDigest: beforeDigest
151
- });
152
- console.log(`feature-verification-steps: ${featureId} verification FAIL (${launch.error})`);
153
- return;
154
- }
155
- const logFd = openSync(logPath, "a");
156
- try {
157
- const result = spawnSync(launch.command, launch.leadingArgs, {
158
- cwd,
159
- stdio: ["ignore", logFd, logFd],
160
- timeout: 14400000
161
- });
162
- const exit = result.status ?? 1;
163
- const afterDigest = await mod.captureFeatureReceiptDigest(cwd, featureContent, learningsContent);
164
- const status = exit === 0 && afterDigest === beforeDigest ? "PASS" : "FAIL";
165
- await mod.completeFeatureVerificationReceipt(nodeFsShim, runDir, receipt, { status, inputDigest: afterDigest });
166
- console.log(`feature-verification-steps: ${featureId} verification ${status} (run ${runId}, log ${logPath})`);
167
- } finally {
168
- closeSync(logFd);
169
- }
56
+ console.log(`feature-verification-steps: ${featureId} ${result.message}`);
170
57
  }
171
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
+ }
172
67
  const args = process.argv.slice(2);
173
68
  const command = args[0];
174
69
  const flag = (name) => {
@@ -176,10 +71,10 @@ function main() {
176
71
  return i >= 0 && i + 1 < args.length ? args[i + 1] ?? "" : "";
177
72
  };
178
73
  if (command !== "verify") {
179
- 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]");
180
75
  process.exit(2);
181
76
  }
182
- 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) => {
183
78
  console.error(`feature-verification-steps: ${String(err)}`);
184
79
  process.exit(1);
185
80
  });
@@ -1,62 +1,40 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
- * feature-verification-steps — the single writer of feature verification
4
- * receipts behind the `feature-verification` workflow (task 0915, remediated
5
- * to the frozen v1 contract; no public CLI verb exists by design).
3
+ * feature-verification-steps — argv adapter for the feature-verification pass (task 0915; reduced to
4
+ * an adapter in task 1176).
5
+ *
6
+ * The pass itself — resolve the selected `feature-verification` definition, capture the before
7
+ * proof-input digest, record and register the RUNNING receipt, run the effective command through the
8
+ * safe argv splitter (never `sh -c`), compare the after digest, complete PASS/FAIL plus the coarse
9
+ * status file — lives in the application operation
10
+ * `packages/app/src/workflow/feature-verification-run.ts`, reached through the generated inline
11
+ * bundle. This entry owns argv, usage and exit codes only: it opens no project DB, constructs no
12
+ * `ArtifactDao`, and scans no feature directory (that lookup is app-owned too).
6
13
  *
7
14
  * Usage (workflow onEnter, vars: featureId, verificationCmd, spurBin, __runId):
8
15
  * bun plugins/sp/scripts/feature-verification-steps.ts verify \
9
- * --feature-id D63 --run-id <runId> --cmd "bun run spur-check-feature"
16
+ * --feature-id D63 --run-id <runId> [--cmd "bun run spur-check-feature"] [--module-mode bundle]
17
+ *
18
+ * Always exits 0 after a completed pass; the transition guard reads the status file and the
19
+ * completion boundary validates the receipt (fail-closed). Unsafe ids are refused by the operation.
10
20
  *
11
- * One pass, in order:
12
- * 1. resolve the selected `feature-verification` definition (project override
13
- * wins) for the verifier identity + configured command,
14
- * 2. capture the before proof-input digest, record the RUNNING receipt (both
15
- * copies) and register the run-scoped receipt as a run artifact,
16
- * 3. run the effective command via the safe launch splitter (never `sh -c`
17
- * interpolation), output to the run-scoped log,
18
- * 4. capture the after digest — a mismatch records FAIL,
19
- * 5. complete the receipt PASS/FAIL (both copies) and the coarse status file.
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.
20
25
  *
21
- * Always exits 0 after verify; the transition guard reads the status file and
22
- * the completion boundary validates the receipt (fail-closed). Unsafe ids are
23
- * refused outright. Node-builtin imports only (ADR-065); the application seams come
24
- * from the generated inline bundle (`plugins/sp/lib/inline-run.generated.mjs`) — never
25
- * from `packages/app/src/index.ts`, which is not a plugin-script contract surface (0948 R3).
26
+ * Node-builtin imports only (ADR-065); the application seams come from the generated inline bundle,
27
+ * never from `packages/app/src/index.ts`, which is not a plugin-script contract surface (0948 R3).
26
28
  */
27
29
 
28
30
  import { spawnSync } from 'node:child_process';
29
- import {
30
- closeSync,
31
- existsSync,
32
- mkdirSync,
33
- openSync,
34
- readdirSync,
35
- readFileSync,
36
- realpathSync,
37
- renameSync,
38
- statSync,
39
- writeFileSync,
40
- } from 'node:fs';
41
- import { join } from 'node:path';
31
+ import { existsSync } from 'node:fs';
42
32
  import { fileURLToPath } from 'node:url';
43
33
  import { getEnvVar } from '../lib/env';
44
34
 
45
- /** Single safe filename component — same class as the inline-run-setup run-id guard. */
46
- const SAFE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
47
-
48
35
  /** Shape of the generated inline bundle / repo app source this script consumes. */
49
36
  interface VerificationModule {
50
- featureReceiptPaths: typeof import('../../../packages/app/src/workflow/feature-verification-receipt')['featureReceiptPaths'];
51
- startFeatureVerificationReceipt: typeof import('../../../packages/app/src/workflow/feature-verification-receipt')['startFeatureVerificationReceipt'];
52
- completeFeatureVerificationReceipt: typeof import('../../../packages/app/src/workflow/feature-verification-receipt')['completeFeatureVerificationReceipt'];
53
- captureFeatureReceiptDigest: typeof import('../../../packages/app/src/workflow/feature-verification-receipt')['captureFeatureReceiptDigest'];
54
- resolveWorkflowDefinition: typeof import('../../../packages/app/src/workflow/workflow-resolver')['resolveWorkflowDefinition'];
55
- splitLaunchCommand: typeof import('../../../packages/app/src/workflow/split-launch-command')['splitLaunchCommand'];
56
- openInlineRunProjectDb: typeof import('../../../packages/app/src/services/inline-run-setup')['openInlineRunProjectDb'];
57
- ArtifactDao: new (
58
- adapter: never,
59
- ) => { record: (input: { runId: string; path: string; kind: string }) => Promise<unknown> };
37
+ runFeatureVerification: typeof import('../../../packages/app/src/workflow/feature-verification-run')['runFeatureVerification'];
60
38
  }
61
39
 
62
40
  /** Explicit module surface. Source is not the contract; the generated bundle is (0948 R3). */
@@ -67,16 +45,16 @@ function bundleEntry(): string {
67
45
  }
68
46
 
69
47
  /**
70
- * Source mode names the mode and the fix. The app source entry does not export
71
- * the verification seams, and "rebuild/install the sp plugin" cannot add them.
48
+ * Source mode names the mode and the fix. The app source entry does not export the verification
49
+ * operation, and "rebuild/install the sp plugin" cannot add it.
72
50
  */
73
51
  function sourceModeError(spurBin: string): Error {
74
52
  return new Error(
75
53
  `source mode: refusing to load packages/app/src/index.ts (spurBin=${JSON.stringify(spurBin)}). ` +
76
54
  'That entry is not the feature-verification contract surface — it does not export ' +
77
- 'splitLaunchCommand / ArtifactDao. Fix: run in bundle mode so ' +
55
+ 'runFeatureVerification. Fix: run in bundle mode so ' +
78
56
  'plugins/sp/lib/inline-run.generated.mjs is loaded (omit --module-mode, or pass --module-mode bundle) ' +
79
- 'and regenerate that bundle if it is missing. Reinstalling the sp plugin does not add these seams to the app source entry.',
57
+ 'and regenerate that bundle if it is missing. Reinstalling the sp plugin does not add the operation to the app source entry.',
80
58
  );
81
59
  }
82
60
 
@@ -89,8 +67,8 @@ function resolveModuleMode(raw: string): ModuleMode {
89
67
  /**
90
68
  * Bundle mode loads the generated inline bundle. Source mode fails closed with a named fix.
91
69
  *
92
- * `spurBin` no longer selects the module (it named the *caller's* CLI entry, not this
93
- * script's runtime surface); it is kept only to make the failure message actionable.
70
+ * `spurBin` no longer selects the module (it named the *caller's* CLI entry, not this script's runtime
71
+ * surface); it is kept only to make the failure message actionable.
94
72
  */
95
73
  async function loadModule(spurBin: string, mode: ModuleMode): Promise<VerificationModule> {
96
74
  if (mode === 'source') throw sourceModeError(spurBin);
@@ -105,20 +83,10 @@ async function loadModule(spurBin: string, mode: ModuleMode): Promise<Verificati
105
83
  return requireModule(bundle, mode);
106
84
  }
107
85
 
108
- /** Dynamic-import the entry and refuse modules missing the verification seams. */
86
+ /** Dynamic-import the entry and refuse a module missing the verification operation. */
109
87
  async function requireModule(entry: string, mode: ModuleMode): Promise<VerificationModule> {
110
88
  const mod = (await import(entry)) as Partial<VerificationModule> & Record<string, unknown>;
111
- const missing = (
112
- [
113
- 'startFeatureVerificationReceipt',
114
- 'completeFeatureVerificationReceipt',
115
- 'captureFeatureReceiptDigest',
116
- 'resolveWorkflowDefinition',
117
- 'splitLaunchCommand',
118
- 'openInlineRunProjectDb',
119
- 'ArtifactDao',
120
- ] as const
121
- ).filter((k) => typeof mod[k] !== 'function');
89
+ const missing = (['runFeatureVerification'] as const).filter((k) => typeof mod[k] !== 'function');
122
90
  if (missing.length > 0) {
123
91
  throw new Error(
124
92
  `feature-verification-steps: mode=${mode} — application entry ${entry} is missing feature-verification seams (${missing.join(', ')}). ` +
@@ -128,48 +96,6 @@ async function requireModule(entry: string, mode: ModuleMode): Promise<Verificat
128
96
  return mod as VerificationModule;
129
97
  }
130
98
 
131
- /** Refuse ids that could escape the run directory through receipt filenames. */
132
- function assertSafeId(kind: string, id: string): void {
133
- if (!SAFE_ID_RE.test(id) || id.includes('..')) {
134
- throw new Error(`refusing unsafe ${kind}: ${id}`);
135
- }
136
- }
137
-
138
- /** Locate `<id>_<slug>.md` under the features directory. */
139
- function findFeatureFile(featureDir: string, featureId: string): string | undefined {
140
- if (!existsSync(featureDir)) return undefined;
141
- const name = readdirSync(featureDir).find((n) => n.startsWith(`${featureId}_`) && n.endsWith('.md'));
142
- return name === undefined ? undefined : join(featureDir, name);
143
- }
144
-
145
- // ponytail: the receipt service is filesystem-pure over the ts-runtime
146
- // FileSystem port; only ensureDir/writeFile/rename are exercised on the
147
- // start/complete paths. Swap to createNodeFileSystem if more surface is needed.
148
- const nodeFsShim = {
149
- realPath: realpathSync,
150
- readDir: readdirSync,
151
- stat: (path: string) => {
152
- try {
153
- return statSync(path);
154
- } catch (error) {
155
- if ((error as { code?: string }).code === 'ENOENT') return null;
156
- throw error;
157
- }
158
- },
159
- ensureDir: (dir: string) => {
160
- mkdirSync(dir, { recursive: true });
161
- },
162
- writeFile: (path: string, body: string) => {
163
- writeFileSync(path, body);
164
- },
165
- rename: (src: string, dest: string) => {
166
- renameSync(src, dest);
167
- },
168
- readFile: (path: string) => {
169
- return readFileSync(path, 'utf8');
170
- },
171
- } as never;
172
-
173
99
  /** One full verification pass for one feature. Always exits 0. */
174
100
  async function verify(
175
101
  featureId: string,
@@ -177,90 +103,35 @@ async function verify(
177
103
  cmdOverride: string,
178
104
  spurBin: string,
179
105
  mode: ModuleMode,
106
+ confidenceOverride: string,
107
+ ackLowConfidence: boolean,
180
108
  ): Promise<void> {
181
- assertSafeId('feature id', featureId);
182
- assertSafeId('run id', runId);
183
- const cwd = process.cwd();
184
109
  const mod = await loadModule(spurBin, mode);
185
- const runDir = join(cwd, '.spur', 'run');
186
- mkdirSync(runDir, { recursive: true });
187
-
188
- // 1. Selected verifier definition (project override wins); its configured
189
- // command is the completion contract — an override records but can't complete.
190
- const selected = await mod.resolveWorkflowDefinition(cwd, 'feature-verification');
191
- const vars = selected.workflow.vars as { verificationCmd?: unknown } | undefined;
192
- const configuredCmd =
193
- typeof vars?.verificationCmd === 'string' && vars.verificationCmd.length > 0
194
- ? vars.verificationCmd
195
- : 'bun run spur-check-feature';
196
- const effectiveCmd = cmdOverride !== '' ? cmdOverride : configuredCmd;
197
-
198
- const featureFile = findFeatureFile(join(cwd, 'docs', 'features'), featureId);
199
- if (featureFile === undefined) {
200
- throw new Error(`feature ${featureId} not found under ${join(cwd, 'docs', 'features')}`);
201
- }
202
- const featureContent = readFileSync(featureFile, 'utf8');
203
- const learningsPath = join(cwd, '.spur', 'context', 'learnings.md');
204
- const learningsContent = existsSync(learningsPath) ? readFileSync(learningsPath, 'utf8') : undefined;
205
-
206
- // 2. Before digest + RUNNING receipt (both copies) + artifact registration.
207
- const beforeDigest = await mod.captureFeatureReceiptDigest(cwd, featureContent, learningsContent);
208
- const receipt = await mod.startFeatureVerificationReceipt(nodeFsShim, runDir, {
110
+ const result = await mod.runFeatureVerification({
111
+ workdir: process.cwd(),
209
112
  featureId,
210
113
  runId,
211
- workdir: cwd,
212
- verifier: {
213
- name: 'feature-verification',
214
- sourcePath: selected.path,
215
- layer: selected.layer,
216
- definitionDigest: selected.digest,
217
- },
218
- verificationCmd: effectiveCmd,
219
- inputDigest: beforeDigest,
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,
220
120
  });
221
- const db = await mod.openInlineRunProjectDb(cwd);
222
- try {
223
- await new mod.ArtifactDao(db.adapter as never).record({
224
- runId,
225
- path: mod.featureReceiptPaths(runDir, featureId, runId).runScoped,
226
- kind: 'feature-verification',
227
- });
228
- } finally {
229
- db.close();
230
- }
231
-
232
- // 3. Run the effective command via the safe splitter (no `sh -c`).
233
- const logPath = join(runDir, `${runId}-feature-verification.log`);
234
- const launch = mod.splitLaunchCommand(effectiveCmd, 'feature-verification verificationCmd');
235
- if ('error' in launch) {
236
- await mod.completeFeatureVerificationReceipt(nodeFsShim, runDir, receipt, {
237
- status: 'FAIL',
238
- inputDigest: beforeDigest,
239
- });
240
- console.log(`feature-verification-steps: ${featureId} verification FAIL (${launch.error})`);
241
- return;
242
- }
243
- const logFd = openSync(logPath, 'a');
244
- try {
245
- const result = spawnSync(launch.command, launch.leadingArgs, {
246
- cwd,
247
- stdio: ['ignore', logFd, logFd],
248
- timeout: 4 * 60 * 60 * 1000,
249
- });
250
- const exit = result.status ?? 1;
251
-
252
- // 4/5. After digest — a mismatch records FAIL (the pass did not verify
253
- // the tree it left behind); otherwise the exit code decides.
254
- const afterDigest = await mod.captureFeatureReceiptDigest(cwd, featureContent, learningsContent);
255
- const status: 'PASS' | 'FAIL' = exit === 0 && afterDigest === beforeDigest ? 'PASS' : 'FAIL';
256
- await mod.completeFeatureVerificationReceipt(nodeFsShim, runDir, receipt, { status, inputDigest: afterDigest });
257
- console.log(`feature-verification-steps: ${featureId} verification ${status} (run ${runId}, log ${logPath})`);
258
- } finally {
259
- closeSync(logFd);
260
- }
121
+ console.log(`feature-verification-steps: ${featureId} ${result.message}`);
261
122
  }
262
123
 
263
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
+ }
264
135
  const args = process.argv.slice(2);
265
136
  const command = args[0];
266
137
  const flag = (name: string): string => {
@@ -268,7 +139,10 @@ function main(): void {
268
139
  return i >= 0 && i + 1 < args.length ? (args[i + 1] ?? '') : '';
269
140
  };
270
141
  if (command !== 'verify') {
271
- 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
+ );
272
146
  process.exit(2);
273
147
  }
274
148
  verify(
@@ -277,6 +151,8 @@ function main(): void {
277
151
  flag('--cmd') || getEnvVar('verificationCmd') || '',
278
152
  flag('--spur-bin') || getEnvVar('spurBin') || '',
279
153
  resolveModuleMode(flag('--module-mode')),
154
+ flag('--confidence') || getEnvVar('confidence') || '',
155
+ args.includes('--ack-low-confidence') || getEnvVar('ackLowConfidence') === 'true',
280
156
  )
281
157
  .then(() => process.exit(0))
282
158
  .catch((err: unknown) => {
@@ -908,24 +908,24 @@ ${reasons}`, stderr: "" };
908
908
  process.exitCode = exitCode;
909
909
  }
910
910
  export {
911
- validateSelector,
912
- stampReport,
913
- semanticArtifactDigest,
914
- runCacheCli,
915
- resolvePaths,
916
- renderProvenanceFrontmatter,
917
- refreshReport,
918
- publishAtomically,
919
- probe,
920
- porcelainPaths,
921
- parseProvenance,
922
- logicDigest,
923
- importedSnapshotAsOf,
924
- diffPorcelain,
925
- decideCache,
926
- checkReportStructure,
927
- buildProvenance,
928
- bannerLine,
911
+ FINDING_FIELDS,
929
912
  REPORT_SECTIONS,
930
- FINDING_FIELDS
913
+ bannerLine,
914
+ buildProvenance,
915
+ checkReportStructure,
916
+ decideCache,
917
+ diffPorcelain,
918
+ importedSnapshotAsOf,
919
+ logicDigest,
920
+ parseProvenance,
921
+ porcelainPaths,
922
+ probe,
923
+ publishAtomically,
924
+ refreshReport,
925
+ renderProvenanceFrontmatter,
926
+ resolvePaths,
927
+ runCacheCli,
928
+ semanticArtifactDigest,
929
+ stampReport,
930
+ validateSelector
931
931
  };
@@ -26,7 +26,7 @@ async function main(argv, env = getEnvVars()) {
26
26
  process.exit(await main(process.argv.slice(2)));
27
27
  }
28
28
  export {
29
- main,
29
+ IDEA_HANDOFF_USAGE,
30
30
  loadHandoffLib,
31
- IDEA_HANDOFF_USAGE
31
+ main
32
32
  };
@@ -3,9 +3,7 @@
3
3
 
4
4
  // plugins/sp/scripts/inline-run-dispatch.ts
5
5
  import { spawnSync } from "child_process";
6
- import { existsSync } from "fs";
7
- import { dirname, join, resolve } from "path";
8
- import { fileURLToPath } from "url";
6
+ import { fileURLToPath as fileURLToPath2 } from "url";
9
7
 
10
8
  // plugins/sp/lib/env.ts
11
9
  function getEnvVar(name, fallback) {
@@ -14,6 +12,28 @@ function getEnvVar(name, fallback) {
14
12
  }
15
13
 
16
14
  // plugins/sp/lib/inline-run-app.ts
15
+ import { existsSync } from "node:fs";
16
+ import { dirname, join, resolve } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ function resolveAppEntry(spurBin) {
19
+ const fallback = fileURLToPath(new URL("../../../apps/cli/src/index.ts", import.meta.url));
20
+ const candidates = spurBin !== "" ? [spurBin] : [fallback];
21
+ for (const candidate of candidates) {
22
+ const tokens = candidate.split(/\s+/).filter(Boolean);
23
+ const mainModule = [...tokens].reverse().find((t) => t.endsWith(".ts"));
24
+ if (mainModule === undefined || !existsSync(mainModule))
25
+ continue;
26
+ const repoRoot = resolve(dirname(mainModule), "..", "..", "..");
27
+ const appEntry = join(repoRoot, "packages", "app", "src", "index.ts");
28
+ if (existsSync(appEntry))
29
+ return { entry: appEntry, portable: false };
30
+ }
31
+ const entry = fileURLToPath(new URL("../lib/inline-run.generated.mjs", import.meta.url));
32
+ if (!existsSync(entry)) {
33
+ throw new Error("inline application bundle is missing — rebuild/install the sp plugin before running inline");
34
+ }
35
+ return { entry, portable: true };
36
+ }
17
37
  async function loadInlineApp(spurBin, resolveAppEntry, required) {
18
38
  const { entry, portable } = resolveAppEntry(spurBin);
19
39
  const app = await import(entry);
@@ -36,28 +56,9 @@ function usage() {
36
56
  process.exit(2);
37
57
  }
38
58
  var SAFE_RUN_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
39
- function resolveAppEntry(spurBin) {
40
- const fallback = fileURLToPath(new URL("../../../apps/cli/src/index.ts", import.meta.url));
41
- const candidates = spurBin !== "" ? [spurBin] : [fallback];
42
- for (const candidate of candidates) {
43
- const tokens = candidate.split(/\s+/).filter(Boolean);
44
- const mainModule = [...tokens].reverse().find((t) => t.endsWith(".ts"));
45
- if (mainModule === undefined || !existsSync(mainModule))
46
- continue;
47
- const repoRoot = resolve(dirname(mainModule), "..", "..", "..");
48
- const appEntry = join(repoRoot, "packages", "app", "src", "index.ts");
49
- if (existsSync(appEntry))
50
- return { entry: appEntry, portable: false };
51
- }
52
- const entry = fileURLToPath(new URL("../lib/inline-run.generated.mjs", import.meta.url));
53
- if (!existsSync(entry)) {
54
- throw new Error("inline application bundle is missing \u2014 rebuild/install the sp plugin before running inline");
55
- }
56
- return { entry, portable: true };
57
- }
58
59
  async function main() {
59
60
  if (!process.versions.bun) {
60
- const child = spawnSync("bun", [fileURLToPath(import.meta.url), ...process.argv.slice(2)], {
61
+ const child = spawnSync("bun", [fileURLToPath2(import.meta.url), ...process.argv.slice(2)], {
61
62
  stdio: "inherit"
62
63
  });
63
64
  if (child.error)
@@ -113,7 +114,7 @@ async function main() {
113
114
  }
114
115
  if (decision.trim() === "" || text === "" === (textFile === ""))
115
116
  usage();
116
- const { app: lib } = await loadInlineApp(spurBin, () => ({ entry: fileURLToPath(new URL("../lib/inline-run.generated.mjs", import.meta.url)), portable }), ["loadSpurConfig"]);
117
+ const { app: lib } = await loadInlineApp(spurBin, () => ({ entry: fileURLToPath2(new URL("../lib/inline-run.generated.mjs", import.meta.url)), portable }), ["loadSpurConfig"]);
117
118
  const spurConfig = await lib.loadSpurConfig(process.cwd(), portable ? { embeddedSchemas: lib.EMBEDDED_SPUR_SCHEMAS } : undefined);
118
119
  process.exit(await app.runInlineRunDispatchFailure({
119
120
  runId,