@gobing-ai/spur 0.4.9 → 0.4.10

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 (83) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/rules/README.md +1 -1
  3. package/config/rules/boundary/env-var-hygiene.yaml +0 -1
  4. package/config/rules/boundary/sp-script-placement.yaml +3 -3
  5. package/config/rules/docs/sourced-api-claims.yaml +23 -96
  6. package/config/workflows/feature-verification.yaml +1 -9
  7. package/config/workflows/task-pipeline.yaml +2 -2
  8. package/package.json +1 -1
  9. package/plugins/sp/agents/expert-spur.md +0 -1
  10. package/plugins/sp/commands/dev-changelog.md +1 -1
  11. package/plugins/sp/plugin.json +1 -1
  12. package/plugins/sp/skills/brainstorm/SKILL.md +12 -11
  13. package/plugins/sp/skills/brainstorm/agents/openai.yaml +1 -1
  14. package/plugins/sp/skills/brainstorm/examples/ideation-example.md +0 -4
  15. package/plugins/sp/skills/brainstorm/metadata.openclaw +1 -1
  16. package/plugins/sp/skills/brainstorm/references/workflows.md +4 -14
  17. package/plugins/sp/skills/code-verification/references/secu-review.md +3 -4
  18. package/plugins/sp/skills/history-anatomy/references/operations.md +3 -4
  19. package/plugins/sp/skills/history-anatomy/references/report-contract.md +2 -3
  20. package/plugins/sp/skills/issue-finding/SKILL.md +1 -1
  21. package/plugins/sp/skills/parallel-execution/SKILL.md +1 -1
  22. package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +9 -10
  23. package/plugins/sp/skills/reverse-engineering/SKILL.md +4 -6
  24. package/plugins/sp/skills/session-review/SKILL.md +10 -26
  25. package/plugins/sp/skills/source-driven-development/SKILL.md +25 -29
  26. package/plugins/sp/skills/spur-cli/references/agent.md +5 -2
  27. package/plugins/sp/skills/spur-cli/references/features.md +1 -1
  28. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +1 -1
  29. package/plugins/sp/skills/spur-dev/references/dev-operations.md +5 -6
  30. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +1 -1
  31. package/spur.js +378 -411
  32. package/web/_astro/{BoardApp.CaNvQBD_.js → BoardApp.B5rTVNd_.js} +1 -1
  33. package/web/_astro/{BoardApp.C5jnkkKP.js → BoardApp.BMprmPRc.js} +141 -141
  34. package/web/_astro/{TaskDetail.DGKndhI8.js → TaskDetail.Ddsur8qd.js} +1 -1
  35. package/web/_astro/{arc.DHrwdg3G.js → arc.DLqVVBxP.js} +1 -1
  36. package/web/_astro/{architectureDiagram-3BPJPVTR.pvKpK1s5.js → architectureDiagram-3BPJPVTR.C-Pk3uAi.js} +1 -1
  37. package/web/_astro/{blockDiagram-GPEHLZMM.BQmRcZsS.js → blockDiagram-GPEHLZMM.BRO1i_Nm.js} +1 -1
  38. package/web/_astro/{c4Diagram-AAUBKEIU.CCLjHeH1.js → c4Diagram-AAUBKEIU.BU_cWu6e.js} +1 -1
  39. package/web/_astro/channel.Bs3Illhy.js +1 -0
  40. package/web/_astro/{chunk-2J33WTMH.DL6Yuoma.js → chunk-2J33WTMH.D2VXiQ2t.js} +1 -1
  41. package/web/_astro/{chunk-4BX2VUAB.CzlyEI7l.js → chunk-4BX2VUAB.BcHT772J.js} +1 -1
  42. package/web/_astro/{chunk-55IACEB6.B60EWxp1.js → chunk-55IACEB6.DhDtICmo.js} +1 -1
  43. package/web/_astro/{chunk-727SXJPM.c7v_fRLo.js → chunk-727SXJPM.BoKHp7gV.js} +1 -1
  44. package/web/_astro/{chunk-AQP2D5EJ.8BxLWdDc.js → chunk-AQP2D5EJ.Chu4JRpE.js} +1 -1
  45. package/web/_astro/{chunk-FMBD7UC4.DmKuxGFT.js → chunk-FMBD7UC4.wHdwKPlq.js} +1 -1
  46. package/web/_astro/{chunk-ND2GUHAM.1Zwd4mqV.js → chunk-ND2GUHAM.ffN-M1JB.js} +1 -1
  47. package/web/_astro/{chunk-QZHKN3VN.BvYLu-A1.js → chunk-QZHKN3VN.FRubwg4S.js} +1 -1
  48. package/web/_astro/{classDiagram-4FO5ZUOK.CEqRt0WU.js → classDiagram-4FO5ZUOK.c22tQsc_.js} +1 -1
  49. package/web/_astro/{classDiagram-v2-Q7XG4LA2.CEqRt0WU.js → classDiagram-v2-Q7XG4LA2.c22tQsc_.js} +1 -1
  50. package/web/_astro/{cose-bilkent-S5V4N54A.C7JiUdj2.js → cose-bilkent-S5V4N54A.B9c6fiSj.js} +1 -1
  51. package/web/_astro/{cynefin-OW5HDTMX.B6mZ-1be.js → cynefin-OW5HDTMX.DrZsrUHl.js} +1 -1
  52. package/web/_astro/{dagre-BM42HDAG.BuryfDy6.js → dagre-BM42HDAG.DG1U4b3y.js} +1 -1
  53. package/web/_astro/{diagram-2AECGRRQ.dao39YQM.js → diagram-2AECGRRQ.CH15b-K3.js} +1 -1
  54. package/web/_astro/{diagram-5GNKFQAL.lnGZe4At.js → diagram-5GNKFQAL.BH1j7twR.js} +1 -1
  55. package/web/_astro/{diagram-KO2AKTUF.uWfhzEfT.js → diagram-KO2AKTUF.q2zCkbAj.js} +1 -1
  56. package/web/_astro/{diagram-LMA3HP47.ppq8-198.js → diagram-LMA3HP47.BLaaZnHV.js} +1 -1
  57. package/web/_astro/{diagram-OG6HWLK6.CKSCqDt5.js → diagram-OG6HWLK6.BcpRdQwI.js} +1 -1
  58. package/web/_astro/{erDiagram-TEJ5UH35.sFSf2yBN.js → erDiagram-TEJ5UH35.D7KBlqfM.js} +1 -1
  59. package/web/_astro/{flowDiagram-I6XJVG4X.BJQjKLbz.js → flowDiagram-I6XJVG4X.D_gmuRqg.js} +1 -1
  60. package/web/_astro/{ganttDiagram-6RSMTGT7.DAHKNj2N.js → ganttDiagram-6RSMTGT7.DzgWYniD.js} +1 -1
  61. package/web/_astro/{gitGraphDiagram-PVQCEYII.BlmzcW_O.js → gitGraphDiagram-PVQCEYII.576i3hm3.js} +1 -1
  62. package/web/_astro/index.DiC1a6lh.css +1 -0
  63. package/web/_astro/{infoDiagram-5YYISTIA.DGhjaqsi.js → infoDiagram-5YYISTIA.DMCclBiz.js} +1 -1
  64. package/web/_astro/{ishikawaDiagram-YF4QCWOH.gKIpgt6F.js → ishikawaDiagram-YF4QCWOH.9Kyca4SH.js} +1 -1
  65. package/web/_astro/{journeyDiagram-JHISSGLW.DG3tmP0R.js → journeyDiagram-JHISSGLW.chbdG-8q.js} +1 -1
  66. package/web/_astro/{kanban-definition-UN3LZRKU.CgHDSxkR.js → kanban-definition-UN3LZRKU.Bds54-e0.js} +1 -1
  67. package/web/_astro/{linear.BuGEpcuM.js → linear.D5ND9GN_.js} +1 -1
  68. package/web/_astro/{mermaid.core.DBVqkWBp.js → mermaid.core.D9N_PGbj.js} +4 -4
  69. package/web/_astro/{mindmap-definition-RKZ34NQL.D-kOcji9.js → mindmap-definition-RKZ34NQL.t0xop5vp.js} +1 -1
  70. package/web/_astro/{pieDiagram-4H26LBE5.BvGPwtZt.js → pieDiagram-4H26LBE5.DqgKh6hM.js} +1 -1
  71. package/web/_astro/{quadrantDiagram-W4KKPZXB.BKb_9FV6.js → quadrantDiagram-W4KKPZXB.DeuHVi2t.js} +1 -1
  72. package/web/_astro/{requirementDiagram-4Y6WPE33.Cx0fvD8v.js → requirementDiagram-4Y6WPE33.BdYFSG4W.js} +1 -1
  73. package/web/_astro/{sankeyDiagram-5OEKKPKP.fatULi0W.js → sankeyDiagram-5OEKKPKP.k1LPPETJ.js} +1 -1
  74. package/web/_astro/{sequenceDiagram-3UESZ5HK.ChHyKqco.js → sequenceDiagram-3UESZ5HK.DdyfpzoG.js} +1 -1
  75. package/web/_astro/{stateDiagram-AJRCARHV.BdUpKWyj.js → stateDiagram-AJRCARHV.DSEI8il0.js} +1 -1
  76. package/web/_astro/{stateDiagram-v2-BHNVJYJU.fmJxqIm5.js → stateDiagram-v2-BHNVJYJU.CoMnQRKo.js} +1 -1
  77. package/web/_astro/{timeline-definition-PNZ67QCA.BayDn5-V.js → timeline-definition-PNZ67QCA.DM1AHNm-.js} +1 -1
  78. package/web/_astro/{vennDiagram-CIIHVFJN.Bm2Aggwa.js → vennDiagram-CIIHVFJN.C-cJmVtl.js} +1 -1
  79. package/web/_astro/{wardleyDiagram-YWT4CUSO.DI75O-uG.js → wardleyDiagram-YWT4CUSO.D0xMzKPb.js} +1 -1
  80. package/web/_astro/{xychartDiagram-2RQKCTM6.DL90E7Q7.js → xychartDiagram-2RQKCTM6.BH5xJcEq.js} +1 -1
  81. package/web/index.html +2 -2
  82. package/web/_astro/channel.C7wG9RxA.js +0 -1
  83. package/web/_astro/index.BCY1JJHd.css +0 -1
package/spur.js CHANGED
@@ -14967,7 +14967,6 @@ var init_finding_codes = __esm(() => {
14967
14967
  "L4.feature-receipt-run",
14968
14968
  "L4.feature-receipt-stale",
14969
14969
  "L4.feature-receipt-contract",
14970
- "L4.feature-receipt-confidence",
14971
14970
  "precheck-size",
14972
14971
  "precheck-evidence",
14973
14972
  "inventory-coverage",
@@ -15040,7 +15039,6 @@ var init_finding_codes = __esm(() => {
15040
15039
  L4_FEATURE_RECEIPT_RUN: "L4.feature-receipt-run",
15041
15040
  L4_FEATURE_RECEIPT_STALE: "L4.feature-receipt-stale",
15042
15041
  L4_FEATURE_RECEIPT_CONTRACT: "L4.feature-receipt-contract",
15043
- L4_FEATURE_RECEIPT_CONFIDENCE: "L4.feature-receipt-confidence",
15044
15042
  PRECHECK_SIZE: "precheck-size",
15045
15043
  PRECHECK_EVIDENCE: "precheck-evidence",
15046
15044
  INVENTORY_COVERAGE: "inventory-coverage",
@@ -15065,6 +15063,7 @@ var init_projects = __esm(() => {
15065
15063
  projectEntrySchema = object2({
15066
15064
  name: string2().min(1),
15067
15065
  path: string2().min(1),
15066
+ host: string2().optional(),
15068
15067
  port: number2().int().nonnegative().default(0)
15069
15068
  });
15070
15069
  projectsFileSchema = object2({
@@ -85638,6 +85637,12 @@ function normalizeProjectPath(pathInput) {
85638
85637
  function setPortProbeForTests(probe) {
85639
85638
  testPortProbe = probe;
85640
85639
  }
85640
+ function isLocalHost(host) {
85641
+ if (!host)
85642
+ return true;
85643
+ const trimmed = host.trim().toLowerCase();
85644
+ return trimmed === "localhost" || trimmed === "127.0.0.1" || trimmed === "::1" || trimmed === "";
85645
+ }
85641
85646
  function classifyPortBindError(err) {
85642
85647
  const code = err && typeof err === "object" && "code" in err ? String(err.code) : "";
85643
85648
  if (code === "EADDRINUSE" || code === "EADDRNOTAVAIL") {
@@ -85648,31 +85653,34 @@ function classifyPortBindError(err) {
85648
85653
  async function isPortLiveOnHost(port, host, timeoutMs) {
85649
85654
  return new Promise((resolve) => {
85650
85655
  const socket = connect({ port, host, timeout: timeoutMs });
85651
- socket.on("connect", () => {
85652
- socket.destroy();
85653
- resolve(true);
85654
- });
85655
- socket.on("timeout", () => {
85656
- socket.destroy();
85657
- resolve(false);
85658
- });
85659
- socket.on("error", () => {
85656
+ socket.unref();
85657
+ let settled = false;
85658
+ const cleanup = (res) => {
85659
+ if (settled)
85660
+ return;
85661
+ settled = true;
85660
85662
  socket.destroy();
85661
- resolve(false);
85662
- });
85663
+ resolve(res);
85664
+ };
85665
+ socket.on("connect", () => cleanup(true));
85666
+ socket.on("timeout", () => cleanup(false));
85667
+ socket.on("error", () => cleanup(false));
85663
85668
  });
85664
85669
  }
85665
- async function isPortLive(port, timeoutMs = 200) {
85670
+ async function isPortLive(port, timeoutMs = 200, host = "localhost") {
85666
85671
  if (testPortProbe) {
85667
- return await testPortProbe(port) === "in-use";
85672
+ return await testPortProbe(port, host) === "in-use";
85668
85673
  }
85669
- if (port <= 0)
85674
+ if (port <= 0 || port > 65535)
85670
85675
  return false;
85671
- if (await isPortLiveOnHost(port, "127.0.0.1", timeoutMs))
85672
- return true;
85673
- if (await isPortLiveOnHost(port, "::1", timeoutMs))
85674
- return true;
85675
- return false;
85676
+ if (isLocalHost(host)) {
85677
+ if (await isPortLiveOnHost(port, "127.0.0.1", timeoutMs))
85678
+ return true;
85679
+ if (await isPortLiveOnHost(port, "::1", timeoutMs))
85680
+ return true;
85681
+ return false;
85682
+ }
85683
+ return isPortLiveOnHost(port, host, timeoutMs);
85676
85684
  }
85677
85685
  async function probePort(port) {
85678
85686
  if (testPortProbe) {
@@ -85943,10 +85951,12 @@ class ProjectRegistry {
85943
85951
  const data = this.readRaw();
85944
85952
  let changed = false;
85945
85953
  for (const project of data.projects) {
85946
- const normalized = normalizeProjectPath(project.path);
85947
- if (normalized !== project.path) {
85948
- project.path = normalized;
85949
- changed = true;
85954
+ if (isLocalHost(project.host)) {
85955
+ const normalized = normalizeProjectPath(project.path);
85956
+ if (normalized !== project.path) {
85957
+ project.path = normalized;
85958
+ changed = true;
85959
+ }
85950
85960
  }
85951
85961
  }
85952
85962
  if (changed) {
@@ -85957,13 +85967,17 @@ class ProjectRegistry {
85957
85967
  async list() {
85958
85968
  await this.healTildePaths();
85959
85969
  await this.refreshProjects();
85960
- await this.healStale();
85961
85970
  return this.readRaw().projects;
85962
85971
  }
85963
85972
  async getByPath(pathInput) {
85964
85973
  const normalized = normalizeProjectPath(pathInput);
85965
85974
  const projects = await this.list();
85966
- return projects.find((p) => normalizeProjectPath(p.path) === normalized);
85975
+ return projects.find((p) => {
85976
+ if (isLocalHost(p.host)) {
85977
+ return normalizeProjectPath(p.path) === normalized;
85978
+ }
85979
+ return p.path === pathInput || p.path === normalized;
85980
+ });
85967
85981
  }
85968
85982
  async getByName(nameInput) {
85969
85983
  const trimmed = nameInput.trim();
@@ -85973,11 +85987,20 @@ class ProjectRegistry {
85973
85987
  async upsert(entry) {
85974
85988
  return this.withLock(async () => {
85975
85989
  const currentData = this.readRaw();
85976
- const normalizedPath = normalizeProjectPath(entry.path);
85977
- const index = currentData.projects.findIndex((p) => normalizeProjectPath(p.path) === normalizedPath);
85990
+ const host = entry.host && entry.host.trim() !== "" ? entry.host.trim() : "localhost";
85991
+ const isLocal = isLocalHost(host);
85992
+ const normalizedPath = isLocal ? normalizeProjectPath(entry.path) : entry.path;
85993
+ const index = currentData.projects.findIndex((p) => {
85994
+ const pHost = p.host && p.host.trim() !== "" ? p.host.trim() : "localhost";
85995
+ if (isLocal) {
85996
+ return isLocalHost(pHost) && normalizeProjectPath(p.path) === normalizedPath;
85997
+ }
85998
+ return pHost.toLowerCase() === host.toLowerCase() && p.path === normalizedPath;
85999
+ });
85978
86000
  const newEntry = {
85979
86001
  name: entry.name,
85980
86002
  path: normalizedPath,
86003
+ host,
85981
86004
  port: entry.port ?? 0
85982
86005
  };
85983
86006
  if (index >= 0 && currentData.projects[index]) {
@@ -85985,13 +86008,20 @@ class ProjectRegistry {
85985
86008
  currentData.projects[index] = {
85986
86009
  ...existing,
85987
86010
  name: entry.name,
86011
+ host: entry.host ?? existing.host ?? "localhost",
85988
86012
  port: entry.port ?? existing.port
85989
86013
  };
85990
86014
  } else {
85991
86015
  currentData.projects.push(newEntry);
85992
86016
  }
85993
86017
  this.writeRaw(currentData);
85994
- const res = currentData.projects.find((p) => normalizeProjectPath(p.path) === normalizedPath);
86018
+ const res = currentData.projects.find((p) => {
86019
+ const pHost = p.host && p.host.trim() !== "" ? p.host.trim() : "localhost";
86020
+ if (isLocal) {
86021
+ return isLocalHost(pHost) && normalizeProjectPath(p.path) === normalizedPath;
86022
+ }
86023
+ return pHost.toLowerCase() === host.toLowerCase() && p.path === normalizedPath;
86024
+ });
85995
86025
  if (!res) {
85996
86026
  throw new Error(`Failed to upsert project: ${normalizedPath}`);
85997
86027
  }
@@ -86004,9 +86034,10 @@ class ProjectRegistry {
86004
86034
  const normalized = normalizeProjectPath(nameOrPath);
86005
86035
  const initialLen = currentData.projects.length;
86006
86036
  currentData.projects = currentData.projects.filter((p) => {
86007
- const pNorm = normalizeProjectPath(p.path);
86037
+ const pNorm = isLocalHost(p.host) ? normalizeProjectPath(p.path) : p.path;
86038
+ const pathMatch = pNorm === normalized || p.path === nameOrPath;
86008
86039
  const nameMatch = p.name.toLowerCase() === nameOrPath.trim().toLowerCase();
86009
- return pNorm !== normalized && !nameMatch;
86040
+ return !pathMatch && !nameMatch;
86010
86041
  });
86011
86042
  if (currentData.projects.length !== initialLen) {
86012
86043
  this.writeRaw(currentData);
@@ -86019,7 +86050,10 @@ class ProjectRegistry {
86019
86050
  return this.withLock(async () => {
86020
86051
  const currentData = this.readRaw();
86021
86052
  const normalized = normalizeProjectPath(pathInput);
86022
- const project = currentData.projects.find((p) => normalizeProjectPath(p.path) === normalized);
86053
+ const project = currentData.projects.find((p) => {
86054
+ const pNorm = isLocalHost(p.host) ? normalizeProjectPath(p.path) : p.path;
86055
+ return pNorm === normalized || p.path === pathInput;
86056
+ });
86023
86057
  if (project) {
86024
86058
  project.port = port;
86025
86059
  this.writeRaw(currentData);
@@ -86057,10 +86091,13 @@ class ProjectRegistry {
86057
86091
  return this.withLock(async () => {
86058
86092
  const data = this.readRaw();
86059
86093
  let changed = false;
86094
+ const resetProjects = [];
86060
86095
  for (const project of data.projects) {
86061
86096
  if (project.port > 0) {
86062
- const live = await isPortLive(project.port);
86097
+ const host = project.host ?? "localhost";
86098
+ const live = await isPortLive(project.port, 200, host);
86063
86099
  if (!live) {
86100
+ resetProjects.push({ ...project });
86064
86101
  project.port = 0;
86065
86102
  changed = true;
86066
86103
  }
@@ -86069,6 +86106,7 @@ class ProjectRegistry {
86069
86106
  if (changed) {
86070
86107
  this.writeRaw(data);
86071
86108
  }
86109
+ return resetProjects;
86072
86110
  });
86073
86111
  }
86074
86112
  async refreshProjects(options) {
@@ -86078,9 +86116,15 @@ class ProjectRegistry {
86078
86116
  await Promise.resolve().then(() => init_project_stop());
86079
86117
  const removed = await this.withLock(async () => {
86080
86118
  const data = this.readRaw();
86081
- const purged = data.projects.filter((p) => !existsSync8(normalizeProjectPath(p.path)));
86119
+ const purged = data.projects.filter((p) => {
86120
+ if (isLocalHost(p.host)) {
86121
+ return !existsSync8(normalizeProjectPath(p.path));
86122
+ }
86123
+ return false;
86124
+ });
86082
86125
  if (purged.length > 0) {
86083
- data.projects = data.projects.filter((p) => existsSync8(normalizeProjectPath(p.path)));
86126
+ const purgedPaths = new Set(purged.map((p) => `${p.host ?? "localhost"}:${normalizeProjectPath(p.path)}`));
86127
+ data.projects = data.projects.filter((p) => !purgedPaths.has(`${p.host ?? "localhost"}:${normalizeProjectPath(p.path)}`));
86084
86128
  this.writeRaw(data);
86085
86129
  }
86086
86130
  return purged;
@@ -86088,7 +86132,7 @@ class ProjectRegistry {
86088
86132
  const terminated = [];
86089
86133
  if (terminate) {
86090
86134
  for (const project of removed) {
86091
- if (project.port > 0) {
86135
+ if (project.port > 0 && isLocalHost(project.host)) {
86092
86136
  const stop = await stopRegisteredProject(project, {
86093
86137
  processExecutor: executor,
86094
86138
  killTimeoutMs,
@@ -86101,11 +86145,13 @@ class ProjectRegistry {
86101
86145
  }
86102
86146
  }
86103
86147
  }
86148
+ const resetPorts = await this.healStale();
86104
86149
  return {
86105
86150
  removed,
86106
86151
  terminated,
86107
86152
  purgedProjects: removed,
86108
- terminatedProcesses: terminated
86153
+ terminatedProcesses: terminated,
86154
+ resetPorts
86109
86155
  };
86110
86156
  }
86111
86157
  }
@@ -89363,22 +89409,11 @@ async function completeFeatureVerificationReceipt(fs, runDir, running, options)
89363
89409
  if (running.status !== "RUNNING") {
89364
89410
  throw new Error(`receipt for run ${running.runId} is already ${running.status}`);
89365
89411
  }
89366
- if (options.confidence !== undefined) {
89367
- if (!FEATURE_RECEIPT_CONFIDENCE_LEVELS.includes(options.confidence)) {
89368
- throw new Error(`confidence must be HIGH, MEDIUM or LOW (got ${JSON.stringify(options.confidence)})`);
89369
- }
89370
- if (options.confidenceBasis === undefined || options.confidenceBasis.length === 0) {
89371
- throw new Error(`confidence ${options.confidence} requires a non-empty confidenceBasis`);
89372
- }
89373
- }
89374
89412
  const receipt = {
89375
89413
  ...running,
89376
89414
  status: options.status,
89377
89415
  inputDigest: options.inputDigest ?? running.inputDigest,
89378
- completedAt: options.completedAt ?? new Date().toISOString().replace(/\.\d{3}Z$/, "Z"),
89379
- ...options.confidence === undefined ? {} : { confidence: options.confidence },
89380
- ...options.confidenceBasis === undefined ? {} : { confidenceBasis: [...options.confidenceBasis] },
89381
- ...options.confidenceAcknowledged === true ? { confidenceAcknowledged: true } : {}
89416
+ completedAt: options.completedAt ?? new Date().toISOString().replace(/\.\d{3}Z$/, "Z")
89382
89417
  };
89383
89418
  const paths = featureReceiptPaths(runDir, receipt.featureId, receipt.runId);
89384
89419
  await fs.ensureDir(runDir);
@@ -89406,23 +89441,6 @@ function parseFeatureVerificationReceipt(raw) {
89406
89441
  if (typeof r.featureId !== "string" || typeof r.runId !== "string" || typeof r.workdir !== "string" || typeof v?.name !== "string" || typeof v?.sourcePath !== "string" || typeof v?.layer !== "string" || typeof v?.definitionDigest !== "string" || typeof r.verificationCmd !== "string" || typeof r.inputDigest !== "string" || r.status !== "RUNNING" && r.status !== "PASS" && r.status !== "FAIL" || typeof r.startedAt !== "string" || r.completedAt !== null && typeof r.completedAt !== "string") {
89407
89442
  throw new Error("required fields missing or mistyped");
89408
89443
  }
89409
- if (r.confidence !== undefined) {
89410
- if (!FEATURE_RECEIPT_CONFIDENCE_LEVELS.includes(r.confidence)) {
89411
- throw new Error(`confidence must be HIGH, MEDIUM or LOW (got ${JSON.stringify(r.confidence)})`);
89412
- }
89413
- if (!Array.isArray(r.confidenceBasis) || r.confidenceBasis.length === 0) {
89414
- throw new Error("confidence requires a non-empty confidenceBasis");
89415
- }
89416
- if (!r.confidenceBasis.every((entry) => typeof entry === "string" && entry.length > 0)) {
89417
- throw new Error("confidenceBasis entries must be non-empty strings");
89418
- }
89419
- }
89420
- if (r.confidenceBasis !== undefined && !Array.isArray(r.confidenceBasis)) {
89421
- throw new Error("confidenceBasis must be an array");
89422
- }
89423
- if (r.confidenceAcknowledged !== undefined && typeof r.confidenceAcknowledged !== "boolean") {
89424
- throw new Error("confidenceAcknowledged must be a boolean");
89425
- }
89426
89444
  return parsed;
89427
89445
  }
89428
89446
  async function readReceiptCopy(fs, path, label) {
@@ -89560,15 +89578,6 @@ async function validateFeatureVerificationReceipt(fs, options) {
89560
89578
  detail: `receipt digest ${latest.inputDigest} \u2260 current inputs ${options.currentDigest} \u2014 tree, spec, learnings or check contract changed after the pass`
89561
89579
  };
89562
89580
  }
89563
- const confidence = latest.confidence;
89564
- const certified = confidence === "HIGH" || confidence === "MEDIUM";
89565
- if (!certified && latest.confidenceAcknowledged !== true) {
89566
- return {
89567
- ok: false,
89568
- reason: "unacknowledged-low-confidence",
89569
- detail: confidence === undefined ? "receipt records a PASS with no confidence level (written before the field existed) \u2014 re-run the feature-scoped verification pass, which derives HIGH or MEDIUM from its own evidence" : `receipt records a ${confidence} confidence${(latest.confidenceBasis ?? []).length > 0 ? ` (basis: ${(latest.confidenceBasis ?? []).join("; ")})` : ""} \u2014 re-run the pass where the level can be HIGH or MEDIUM, or re-run it with the acknowledgement (ackLowConfidence) when LOW is the honest level`
89570
- };
89571
- }
89572
89581
  return { ok: true, receipt: latest };
89573
89582
  }
89574
89583
  async function captureFeatureReceiptDigest(repoRoot, featureContent, learningsContent) {
@@ -89577,12 +89586,11 @@ async function captureFeatureReceiptDigest(repoRoot, featureContent, learningsCo
89577
89586
  function isProofCaptureError(err) {
89578
89587
  return err instanceof ProofCaptureError;
89579
89588
  }
89580
- var FEATURE_RECEIPT_SCHEMA_VERSION = 1, DEFAULT_FEATURE_VERIFICATION_CMD = "bun run spur-check-feature", FEATURE_RECEIPT_CONFIDENCE_LEVELS, RECEIPT_ID_PATTERN;
89589
+ var FEATURE_RECEIPT_SCHEMA_VERSION = 1, DEFAULT_FEATURE_VERIFICATION_CMD = "bun run spur-check-feature", RECEIPT_ID_PATTERN;
89581
89590
  var init_feature_verification_receipt = __esm(() => {
89582
89591
  init_durable_plane_ignore();
89583
89592
  init_run_path();
89584
89593
  init_proof_input_fingerprint();
89585
- FEATURE_RECEIPT_CONFIDENCE_LEVELS = ["HIGH", "MEDIUM", "LOW"];
89586
89594
  RECEIPT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
89587
89595
  });
89588
89596
 
@@ -92018,7 +92026,6 @@ var init_planning_check_base = __esm(() => {
92018
92026
  FINDING_CODES.L4_FEATURE_RECEIPT_RUN,
92019
92027
  FINDING_CODES.L4_FEATURE_RECEIPT_STALE,
92020
92028
  FINDING_CODES.L4_FEATURE_RECEIPT_CONTRACT,
92021
- FINDING_CODES.L4_FEATURE_RECEIPT_CONFIDENCE,
92022
92029
  FINDING_CODES.L3_REVIEW_TESTING_CONTRADICTION,
92023
92030
  FINDING_CODES.L4_ROLLUP_SUBTASKS_OPEN,
92024
92031
  FINDING_CODES.L4_ROLLUP_MISSING_ROSTER,
@@ -93604,8 +93611,7 @@ var init_feature_check = __esm(() => {
93604
93611
  failed: FINDING_CODES.L4_FEATURE_RECEIPT_FAILED,
93605
93612
  run: FINDING_CODES.L4_FEATURE_RECEIPT_RUN,
93606
93613
  stale: FINDING_CODES.L4_FEATURE_RECEIPT_STALE,
93607
- "contract-mismatch": FINDING_CODES.L4_FEATURE_RECEIPT_CONTRACT,
93608
- "unacknowledged-low-confidence": FINDING_CODES.L4_FEATURE_RECEIPT_CONFIDENCE
93614
+ "contract-mismatch": FINDING_CODES.L4_FEATURE_RECEIPT_CONTRACT
93609
93615
  };
93610
93616
  findings.push({
93611
93617
  layer: "L4",
@@ -101835,39 +101841,6 @@ var init_proof_fingerprint = __esm(() => {
101835
101841
  ACCEPTED_OPTION_KEYS = ["expect", "featureFile", "taskFile", "var"];
101836
101842
  });
101837
101843
 
101838
- // ../../packages/app/src/workflow/actions/response-validate.ts
101839
- class ResponseValidateActionRunner {
101840
- kind = KIND14;
101841
- engine;
101842
- constructor(engine) {
101843
- this.engine = engine;
101844
- }
101845
- async execute(options, _context) {
101846
- const text = asString5(options.text);
101847
- if (text === undefined) {
101848
- return {
101849
- ok: false,
101850
- error: "response.validate: text is required (use a template like {{ steps.generate.answer }})"
101851
- };
101852
- }
101853
- const result = this.engine.validate(text);
101854
- return {
101855
- ok: result.ok,
101856
- data: {
101857
- reason: result.reason,
101858
- ...result.issues !== undefined ? { issues: result.issues } : {}
101859
- },
101860
- error: result.ok ? undefined : result.reason
101861
- };
101862
- }
101863
- }
101864
- function asString5(value) {
101865
- if (value === undefined || value === null)
101866
- return;
101867
- return String(value);
101868
- }
101869
- var KIND14 = "response.validate";
101870
-
101871
101844
  // ../../packages/app/src/workflow/utils.ts
101872
101845
  var identity5 = (s) => s, NO_COLOR;
101873
101846
  var init_utils3 = __esm(() => {
@@ -101883,15 +101856,15 @@ var init_utils3 = __esm(() => {
101883
101856
 
101884
101857
  // ../../packages/app/src/workflow/actions/rule-check.ts
101885
101858
  class RuleCheckActionRunner {
101886
- kind = KIND15;
101859
+ kind = KIND14;
101887
101860
  ruleService;
101888
101861
  constructor(ruleService) {
101889
101862
  this.ruleService = ruleService;
101890
101863
  }
101891
101864
  async execute(options, _context) {
101892
- const preset = asString6(options.preset) ?? "recommended-pre-check";
101893
- const rule = asString6(options.rule);
101894
- const failOn = asString6(options.failOn) ?? "error";
101865
+ const preset = asString5(options.preset) ?? "recommended-pre-check";
101866
+ const rule = asString5(options.rule);
101867
+ const failOn = asString5(options.failOn) ?? "error";
101895
101868
  const result = await this.ruleService.evaluate({
101896
101869
  preset,
101897
101870
  failOn,
@@ -101913,12 +101886,12 @@ class RuleCheckActionRunner {
101913
101886
  };
101914
101887
  }
101915
101888
  }
101916
- function asString6(value) {
101889
+ function asString5(value) {
101917
101890
  if (value === undefined || value === null)
101918
101891
  return;
101919
101892
  return String(value);
101920
101893
  }
101921
- var KIND15 = "rule.check";
101894
+ var KIND14 = "rule.check";
101922
101895
  var init_rule_check = __esm(() => {
101923
101896
  init_utils3();
101924
101897
  });
@@ -101986,7 +101959,7 @@ class RunArtifactActionRunner {
101986
101959
  fileSystem;
101987
101960
  artifactDao;
101988
101961
  processExecutor;
101989
- kind = KIND16;
101962
+ kind = KIND15;
101990
101963
  constructor(getDb, fileSystem = createNodeFileSystem2(), artifactDao, processExecutor) {
101991
101964
  this.getDb = getDb;
101992
101965
  this.fileSystem = fileSystem;
@@ -102012,7 +101985,7 @@ class RunArtifactActionRunner {
102012
101985
  if (proofBinding !== undefined && proofBinding !== "current") {
102013
101986
  return {
102014
101987
  ok: false,
102015
- error: `${KIND16}: unsupported proofBinding "${String(proofBinding)}" - only "current" is defined (ADR-071)`
101988
+ error: `${KIND15}: unsupported proofBinding "${String(proofBinding)}" - only "current" is defined (ADR-071)`
102016
101989
  };
102017
101990
  }
102018
101991
  const workdir = context.workdir ?? process.cwd();
@@ -102046,7 +102019,7 @@ class RunArtifactActionRunner {
102046
102019
  try {
102047
102020
  registeredPath = await persistDurableArtifact(normalized, workdir, context.runId, this.fileSystem, !requireExisting);
102048
102021
  } catch (error) {
102049
- return { ok: false, error: `${KIND16}: durable persist failed: ${error.message}` };
102022
+ return { ok: false, error: `${KIND15}: durable persist failed: ${error.message}` };
102050
102023
  }
102051
102024
  }
102052
102025
  let dao = this.artifactDao;
@@ -102077,24 +102050,24 @@ class RunArtifactActionRunner {
102077
102050
  if (artifactKind !== "verify-verdict") {
102078
102051
  return {
102079
102052
  ok: false,
102080
- error: `${KIND16}: proofBinding "current" is only supported for the verify-verdict artifact kind (got "${artifactKind}")`
102053
+ error: `${KIND15}: proofBinding "current" is only supported for the verify-verdict artifact kind (got "${artifactKind}")`
102081
102054
  };
102082
102055
  }
102083
102056
  if (!this.getDb) {
102084
102057
  return {
102085
102058
  ok: false,
102086
- error: `${KIND16}: proofBinding "current" requires the composed database context (RunDao run identity) \u2014 refusing an unverifiable binding`
102059
+ error: `${KIND15}: proofBinding "current" requires the composed database context (RunDao run identity) \u2014 refusing an unverifiable binding`
102087
102060
  };
102088
102061
  }
102089
102062
  if (typeof options.taskFile !== "string" || options.taskFile.trim() === "") {
102090
102063
  return {
102091
102064
  ok: false,
102092
- error: `${KIND16}: proofBinding "current" requires a non-empty "taskFile" option \u2014 the fresh digest must cover the canonical task spec`
102065
+ error: `${KIND15}: proofBinding "current" requires a non-empty "taskFile" option \u2014 the fresh digest must cover the canonical task spec`
102093
102066
  };
102094
102067
  }
102095
102068
  const inputs = await readProofInputContents(this.fileSystem, workdir, options);
102096
102069
  if (!inputs.ok) {
102097
- return { ok: false, error: `${KIND16}: ${inputs.error}` };
102070
+ return { ok: false, error: `${KIND15}: ${inputs.error}` };
102098
102071
  }
102099
102072
  let digest;
102100
102073
  try {
@@ -102106,19 +102079,19 @@ class RunArtifactActionRunner {
102106
102079
  fileSystem: this.fileSystem
102107
102080
  });
102108
102081
  } catch (error) {
102109
- return { ok: false, error: `${KIND16}: fresh proof capture failed: ${error.message}` };
102082
+ return { ok: false, error: `${KIND15}: fresh proof capture failed: ${error.message}` };
102110
102083
  }
102111
102084
  const varDigest = context.vars.proofDigestNow ?? context.vars.proofDigest;
102112
102085
  if (typeof varDigest !== "string" || !PROOF_DIGEST_RE.test(varDigest)) {
102113
102086
  return {
102114
102087
  ok: false,
102115
- error: `${KIND16}: proofBinding "current" does not hold - the run has no current proof input ` + `digest (vars.proofDigestNow/proofDigest missing or malformed), so the artifact cannot be ` + `bound to a proof that was never captured; capture one with proof.fingerprint first`
102088
+ error: `${KIND15}: proofBinding "current" does not hold - the run has no current proof input ` + `digest (vars.proofDigestNow/proofDigest missing or malformed), so the artifact cannot be ` + `bound to a proof that was never captured; capture one with proof.fingerprint first`
102116
102089
  };
102117
102090
  }
102118
102091
  if (varDigest !== digest) {
102119
102092
  return {
102120
102093
  ok: false,
102121
- error: `${KIND16}: the run's declared proof digest (${varDigest}) does not match the freshly ` + `captured digest (${digest}) \u2014 a stale or forged var cannot bless artifact content (0785 R3)`
102094
+ error: `${KIND15}: the run's declared proof digest (${varDigest}) does not match the freshly ` + `captured digest (${digest}) \u2014 a stale or forged var cannot bless artifact content (0785 R3)`
102122
102095
  };
102123
102096
  }
102124
102097
  let normalized;
@@ -102148,7 +102121,7 @@ class RunArtifactActionRunner {
102148
102121
  try {
102149
102122
  raw = await this.fileSystem.readFile(normalized);
102150
102123
  } catch (error) {
102151
- return { ok: false, error: `${KIND16}: verdict artifact unreadable: ${error.message}` };
102124
+ return { ok: false, error: `${KIND15}: verdict artifact unreadable: ${error.message}` };
102152
102125
  }
102153
102126
  const taskWbs = String(context.vars.wbs ?? "");
102154
102127
  const outcome = parseVerifyVerdict(raw, taskWbs);
@@ -102156,33 +102129,33 @@ class RunArtifactActionRunner {
102156
102129
  const detail = outcome.kind === "invalid" && outcome.reason !== undefined ? `: ${outcome.reason}` : "";
102157
102130
  return {
102158
102131
  ok: false,
102159
- error: `${KIND16}: verdict artifact is ${outcome.kind}${detail} \u2014 refusing to bind (0785 R3)`
102132
+ error: `${KIND15}: verdict artifact is ${outcome.kind}${detail} \u2014 refusing to bind (0785 R3)`
102160
102133
  };
102161
102134
  }
102162
102135
  const verdict = outcome.verdict;
102163
102136
  if (verdict.wbs !== taskWbs) {
102164
102137
  return {
102165
102138
  ok: false,
102166
- error: `${KIND16}: verdict artifact names wbs "${verdict.wbs}" but the run carries task "${taskWbs}"`
102139
+ error: `${KIND15}: verdict artifact names wbs "${verdict.wbs}" but the run carries task "${taskWbs}"`
102167
102140
  };
102168
102141
  }
102169
102142
  if (verdict.verdict !== "PASS") {
102170
102143
  return {
102171
102144
  ok: false,
102172
- error: `${KIND16}: verdict aggregate is ${verdict.verdict}, not PASS \u2014 refusing to bind`
102145
+ error: `${KIND15}: verdict aggregate is ${verdict.verdict}, not PASS \u2014 refusing to bind`
102173
102146
  };
102174
102147
  }
102175
102148
  let root;
102176
102149
  try {
102177
102150
  root = JSON.parse(raw);
102178
102151
  } catch {
102179
- return { ok: false, error: `${KIND16}: verdict artifact is malformed JSON` };
102152
+ return { ok: false, error: `${KIND15}: verdict artifact is malformed JSON` };
102180
102153
  }
102181
102154
  const proof = root.proof;
102182
102155
  if (proof === null || typeof proof !== "object" || Array.isArray(proof)) {
102183
102156
  return {
102184
102157
  ok: false,
102185
- error: `${KIND16}: verdict artifact carries no raw proof block \u2014 binding refused (0785 R3)`
102158
+ error: `${KIND15}: verdict artifact carries no raw proof block \u2014 binding refused (0785 R3)`
102186
102159
  };
102187
102160
  }
102188
102161
  const p = proof;
@@ -102196,13 +102169,13 @@ class RunArtifactActionRunner {
102196
102169
  if (p.digest !== digest) {
102197
102170
  return {
102198
102171
  ok: false,
102199
- error: `${KIND16}: proof.digest ${String(p.digest)} does not equal the freshly captured digest (${digest})`
102172
+ error: `${KIND15}: proof.digest ${String(p.digest)} does not equal the freshly captured digest (${digest})`
102200
102173
  };
102201
102174
  }
102202
102175
  if (p.runId !== context.runId) {
102203
102176
  return {
102204
102177
  ok: false,
102205
- error: `${KIND16}: proof.runId ${String(p.runId)} does not match the certifying run ${context.runId}`
102178
+ error: `${KIND15}: proof.runId ${String(p.runId)} does not match the certifying run ${context.runId}`
102206
102179
  };
102207
102180
  }
102208
102181
  const db = await this.getDb();
@@ -102210,21 +102183,21 @@ class RunArtifactActionRunner {
102210
102183
  if (runRow === undefined) {
102211
102184
  return {
102212
102185
  ok: false,
102213
- error: `${KIND16}: run ${context.runId} has no authoritative row \u2014 refusing binding (0785 R3)`
102186
+ error: `${KIND15}: run ${context.runId} has no authoritative row \u2014 refusing binding (0785 R3)`
102214
102187
  };
102215
102188
  }
102216
102189
  let metadata = {};
102217
102190
  try {
102218
102191
  metadata = JSON.parse(runRow.metadata_json || "{}");
102219
102192
  } catch {
102220
- return { ok: false, error: `${KIND16}: run ${context.runId} metadata_json is malformed \u2014 refusing binding` };
102193
+ return { ok: false, error: `${KIND15}: run ${context.runId} metadata_json is malformed \u2014 refusing binding` };
102221
102194
  }
102222
102195
  const resumeDigest = metadata.resumeDefinitionDigest;
102223
102196
  const expectedDefinition = typeof resumeDigest === "string" && resumeDigest !== "" ? resumeDigest : metadata.definitionDigest;
102224
102197
  if (typeof expectedDefinition !== "string" || p.definitionDigest !== expectedDefinition) {
102225
102198
  return {
102226
102199
  ok: false,
102227
- error: `${KIND16}: proof.definitionDigest ${String(p.definitionDigest)} does not match the run's ` + `${typeof resumeDigest === "string" && resumeDigest !== "" ? "resume " : ""}definition digest \u2014 ` + `a stale-definition artifact cannot certify this run (0785 R3)`
102200
+ error: `${KIND15}: proof.definitionDigest ${String(p.definitionDigest)} does not match the run's ` + `${typeof resumeDigest === "string" && resumeDigest !== "" ? "resume " : ""}definition digest \u2014 ` + `a stale-definition artifact cannot certify this run (0785 R3)`
102228
102201
  };
102229
102202
  }
102230
102203
  const qualityGate = stageOf("qualityGate");
@@ -102233,7 +102206,7 @@ class RunArtifactActionRunner {
102233
102206
  if (qualityGate === null || review === null || verification === null) {
102234
102207
  return {
102235
102208
  ok: false,
102236
- error: `${KIND16}: proof.stages is missing qualityGate/review/verification evidence \u2014 binding refused`
102209
+ error: `${KIND15}: proof.stages is missing qualityGate/review/verification evidence \u2014 binding refused`
102237
102210
  };
102238
102211
  }
102239
102212
  for (const [name, stage] of [
@@ -102244,26 +102217,26 @@ class RunArtifactActionRunner {
102244
102217
  if (stage.digest !== digest) {
102245
102218
  return {
102246
102219
  ok: false,
102247
- error: `${KIND16}: proof.stages.${name}.digest does not equal the freshly captured digest`
102220
+ error: `${KIND15}: proof.stages.${name}.digest does not equal the freshly captured digest`
102248
102221
  };
102249
102222
  }
102250
102223
  }
102251
102224
  if (qualityGate.status !== "PASS") {
102252
102225
  return {
102253
102226
  ok: false,
102254
- error: `${KIND16}: proof.stages.qualityGate.status is ${String(qualityGate.status)}, not PASS`
102227
+ error: `${KIND15}: proof.stages.qualityGate.status is ${String(qualityGate.status)}, not PASS`
102255
102228
  };
102256
102229
  }
102257
102230
  if (verification.status !== "PASS") {
102258
102231
  return {
102259
102232
  ok: false,
102260
- error: `${KIND16}: proof.stages.verification.status is ${String(verification.status)}, not PASS`
102233
+ error: `${KIND15}: proof.stages.verification.status is ${String(verification.status)}, not PASS`
102261
102234
  };
102262
102235
  }
102263
102236
  if (review.status !== "completed") {
102264
102237
  return {
102265
102238
  ok: false,
102266
- error: `${KIND16}: proof.stages.review.status is "${String(review.status)}" \u2014 a skipped or stale review is not completed evidence (0785 R4)`
102239
+ error: `${KIND15}: proof.stages.review.status is "${String(review.status)}" \u2014 a skipped or stale review is not completed evidence (0785 R4)`
102267
102240
  };
102268
102241
  }
102269
102242
  const markerPath = join41(resolve15(workdir), ".spur", "run", `${context.runId}-review-proof.digest`);
@@ -102276,7 +102249,7 @@ class RunArtifactActionRunner {
102276
102249
  if (marker === null || marker.trim() !== digest) {
102277
102250
  return {
102278
102251
  ok: false,
102279
- error: `${KIND16}: review-proof marker ${context.runId}-review-proof.digest is missing or does not name ` + `the current digest \u2014 review completion is not evidenced for this run (0785 R4)`
102252
+ error: `${KIND15}: review-proof marker ${context.runId}-review-proof.digest is missing or does not name ` + `the current digest \u2014 review completion is not evidenced for this run (0785 R4)`
102280
102253
  };
102281
102254
  }
102282
102255
  const dao = this.artifactDao ?? new ArtifactDao(db);
@@ -102287,7 +102260,7 @@ class RunArtifactActionRunner {
102287
102260
  registeredPath = await persistDurableArtifact(normalized, workdir, context.runId, this.fileSystem);
102288
102261
  }
102289
102262
  } catch (error) {
102290
- return { ok: false, error: `${KIND16}: durable persist failed: ${error.message}` };
102263
+ return { ok: false, error: `${KIND15}: durable persist failed: ${error.message}` };
102291
102264
  }
102292
102265
  const record = await dao.record({
102293
102266
  path: registeredPath,
@@ -102308,7 +102281,7 @@ class RunArtifactActionRunner {
102308
102281
  };
102309
102282
  }
102310
102283
  }
102311
- var copyFile2, link, mkdir2, readFile5, unlink2, writeFile3, KIND16 = "run.artifact", PROOF_DIGEST_RE;
102284
+ var copyFile2, link, mkdir2, readFile5, unlink2, writeFile3, KIND15 = "run.artifact", PROOF_DIGEST_RE;
102312
102285
  var init_run_artifact = __esm(() => {
102313
102286
  init_src2();
102314
102287
  init_dist5();
@@ -102322,7 +102295,7 @@ var init_run_artifact = __esm(() => {
102322
102295
 
102323
102296
  // ../../packages/app/src/workflow/guards/contract-violation.ts
102324
102297
  class ContractViolationGuardRunner {
102325
- kind = KIND17;
102298
+ kind = KIND16;
102326
102299
  constructor() {}
102327
102300
  async evaluate(_options, context) {
102328
102301
  const data = context.lastActionResult?.data;
@@ -102339,7 +102312,7 @@ class ContractViolationGuardRunner {
102339
102312
  };
102340
102313
  }
102341
102314
  }
102342
- var KIND17 = "contract-violation";
102315
+ var KIND16 = "contract-violation";
102343
102316
 
102344
102317
  // ../../packages/app/src/workflow/builtins.ts
102345
102318
  function registerSpurBuiltins(host, options) {
@@ -102370,9 +102343,6 @@ function registerSpurBuiltins(host, options) {
102370
102343
  if (options.httpRequester) {
102371
102344
  host.registerAction(new HttpRequestActionRunner(options.httpRequester, options.hostAllowlist ?? new Set), "builtin");
102372
102345
  }
102373
- if (options.responseValidateEngine) {
102374
- host.registerAction(new ResponseValidateActionRunner(options.responseValidateEngine), "builtin");
102375
- }
102376
102346
  }
102377
102347
  var init_builtins2 = __esm(() => {
102378
102348
  init_dist5();
@@ -108278,11 +108248,15 @@ function classifyProviderUsage(usage) {
108278
108248
  const hasWindow = RATE_WINDOW_NAMES.some((n) => usage[n] !== null && usage[n] !== undefined);
108279
108249
  return hasWindow ? { status: "headroom", exhaustedWindow: undefined } : { status: "no-usage", exhaustedWindow: undefined };
108280
108250
  }
108251
+ function agentProviderSlug(agent) {
108252
+ const lower = (agent ?? "").toLowerCase();
108253
+ return PROVIDER_ALIASES[lower] ?? lower;
108254
+ }
108281
108255
  function mapProvidersToExecutors(providers, executors) {
108282
108256
  const mapping = new Map;
108283
108257
  for (const provider of providers) {
108284
108258
  const lower = provider.toLowerCase();
108285
- const names = executors.filter((e) => (e.agent ?? "").toLowerCase() === lower || typeof e.model === "string" && e.model.split("/")[0]?.toLowerCase() === lower).map((e) => e.name);
108259
+ const names = executors.filter((e) => agentProviderSlug(e.agent) === lower || typeof e.model === "string" && e.model.split("/")[0]?.toLowerCase() === lower).map((e) => e.name);
108286
108260
  if (names.length > 0)
108287
108261
  mapping.set(provider, names);
108288
108262
  }
@@ -108534,7 +108508,7 @@ async function finalizeOutcomes(entries, context) {
108534
108508
  }
108535
108509
  }
108536
108510
  }
108537
- var codexbarWindowSchema, codexbarEntrySchema, RATE_WINDOW_NAMES, AgentUsageProducerError;
108511
+ var codexbarWindowSchema, codexbarEntrySchema, RATE_WINDOW_NAMES, AgentUsageProducerError, PROVIDER_ALIASES;
108538
108512
  var init_agent_usage_producer = __esm(() => {
108539
108513
  init_src();
108540
108514
  init_agent_quota_events();
@@ -108566,6 +108540,9 @@ var init_agent_usage_producer = __esm(() => {
108566
108540
  this.name = "AgentUsageProducerError";
108567
108541
  }
108568
108542
  };
108543
+ PROVIDER_ALIASES = {
108544
+ "antigravity-cli": "antigravity"
108545
+ };
108569
108546
  });
108570
108547
 
108571
108548
  // ../../packages/app/src/services/agent-usage-source.ts
@@ -119962,36 +119939,6 @@ async function createFeatureLookup(workdir, fileSystem = createNodeFileSystem2()
119962
119939
  return { path, content: await fileSystem.readFile(path) };
119963
119940
  };
119964
119941
  }
119965
- function deriveFeatureConfidence(input) {
119966
- const override = input.override === undefined || input.override === "" ? undefined : input.override;
119967
- const measured = [];
119968
- if (input.status === "PASS")
119969
- measured.push("verification command exited 0");
119970
- else
119971
- measured.push("verification command did not exit 0");
119972
- if (input.afterDigest !== undefined) {
119973
- measured.push(input.afterDigest === input.inputDigest ? "proof-input digest unchanged across the pass" : "proof-input digest changed across the pass");
119974
- }
119975
- if (input.status !== "PASS")
119976
- return { confidence: "LOW", basis: measured };
119977
- const derived = input.effectiveCmd === input.configuredCmd ? "HIGH" : "MEDIUM";
119978
- if (input.effectiveCmd !== input.configuredCmd) {
119979
- measured.push(`caller command override: ${input.effectiveCmd}`);
119980
- measured.push(`the selected definition declares: ${input.configuredCmd}`);
119981
- }
119982
- if (override === undefined)
119983
- return { confidence: derived, basis: measured };
119984
- return { confidence: override, basis: [`operator-declared ${override}`, ...measured] };
119985
- }
119986
- function assertConfidenceOverride(raw) {
119987
- if (raw === undefined || raw === "")
119988
- return;
119989
- const upper = raw.toUpperCase();
119990
- if (!FEATURE_RECEIPT_CONFIDENCE_LEVELS.includes(upper)) {
119991
- throw new Error(`confidence must be HIGH, MEDIUM or LOW (got ${JSON.stringify(raw)})`);
119992
- }
119993
- return upper;
119994
- }
119995
119942
  async function defaultRegisterArtifact(workdir, artifact) {
119996
119943
  const db = await openInlineRunProjectDb(workdir);
119997
119944
  try {
@@ -120027,7 +119974,6 @@ async function runFeatureVerification(input) {
120027
119974
  const vars = selected.workflow.vars;
120028
119975
  const configuredCmd = typeof vars?.verificationCmd === "string" && vars.verificationCmd.length > 0 ? vars.verificationCmd : "bun run spur-check-feature";
120029
119976
  const effectiveCmd = input.cmdOverride !== undefined && input.cmdOverride !== "" ? input.cmdOverride : configuredCmd;
120030
- const confidenceOverride = assertConfidenceOverride(input.confidenceOverride);
120031
119977
  const spec = await lookup(input.featureId);
120032
119978
  if (spec === null) {
120033
119979
  throw new Error(`feature ${input.featureId} not found in the configured features directory`);
@@ -120053,25 +119999,13 @@ async function runFeatureVerification(input) {
120053
119999
  const base = { featureId: input.featureId, runId: input.runId, effectiveCmd, logPath, receiptPath: runScoped };
120054
120000
  const launchSplit = split(effectiveCmd, "feature-verification verificationCmd");
120055
120001
  if ("error" in launchSplit) {
120056
- const { confidence, basis } = deriveFeatureConfidence({
120057
- status: "FAIL",
120058
- configuredCmd,
120059
- effectiveCmd,
120060
- inputDigest: beforeDigest,
120061
- override: confidenceOverride
120062
- });
120063
120002
  await receipts.complete(fileSystem, runDir, receipt, {
120064
120003
  status: "FAIL",
120065
- inputDigest: beforeDigest,
120066
- confidence,
120067
- confidenceBasis: basis,
120068
- confidenceAcknowledged: input.ackLowConfidence === true
120004
+ inputDigest: beforeDigest
120069
120005
  });
120070
120006
  return {
120071
120007
  ...base,
120072
120008
  status: "FAIL",
120073
- confidence,
120074
- confidenceBasis: basis,
120075
120009
  message: `verification FAIL (${launchSplit.error})`
120076
120010
  };
120077
120011
  }
@@ -120085,27 +120019,14 @@ async function runFeatureVerification(input) {
120085
120019
  const exit = result.status ?? 1;
120086
120020
  const afterDigest = await receipts.captureDigest(input.workdir, spec.content, learningsContent);
120087
120021
  const status = exit === 0 && afterDigest === beforeDigest ? "PASS" : "FAIL";
120088
- const { confidence, basis } = deriveFeatureConfidence({
120089
- status,
120090
- configuredCmd,
120091
- effectiveCmd,
120092
- inputDigest: beforeDigest,
120093
- afterDigest,
120094
- override: confidenceOverride
120095
- });
120096
120022
  await receipts.complete(fileSystem, runDir, receipt, {
120097
120023
  status,
120098
- inputDigest: afterDigest,
120099
- confidence,
120100
- confidenceBasis: basis,
120101
- confidenceAcknowledged: input.ackLowConfidence === true
120024
+ inputDigest: afterDigest
120102
120025
  });
120103
120026
  return {
120104
120027
  ...base,
120105
120028
  status,
120106
- confidence,
120107
- confidenceBasis: basis,
120108
- message: `verification ${status} (run ${input.runId}, confidence ${confidence}, log ${logPath})`
120029
+ message: `verification ${status} (run ${input.runId}, log ${logPath})`
120109
120030
  };
120110
120031
  } finally {
120111
120032
  closeLog(logFd);
@@ -120950,7 +120871,6 @@ __export(exports_src, {
120950
120871
  FEATURE_ACTION_NAMES: () => FEATURE_ACTION_NAMES,
120951
120872
  FEATURE_LIFECYCLE_PROFILE: () => FEATURE_LIFECYCLE_PROFILE,
120952
120873
  FEATURE_LIFECYCLE_WORKFLOW: () => FEATURE_LIFECYCLE_WORKFLOW,
120953
- FEATURE_RECEIPT_CONFIDENCE_LEVELS: () => FEATURE_RECEIPT_CONFIDENCE_LEVELS,
120954
120874
  FEATURE_RECEIPT_SCHEMA_VERSION: () => FEATURE_RECEIPT_SCHEMA_VERSION,
120955
120875
  FINDING_CODES: () => FINDING_CODES,
120956
120876
  FLEET_AUTO_TAG: () => FLEET_AUTO_TAG,
@@ -121014,7 +120934,6 @@ __export(exports_src, {
121014
120934
  RUN_STORE_LIST_MAX_LIMIT: () => RUN_STORE_LIST_MAX_LIMIT,
121015
120935
  RUN_STORE_WBS_DEFAULT_LIMIT: () => RUN_STORE_WBS_DEFAULT_LIMIT,
121016
120936
  RUN_STORE_WBS_MAX_LIMIT: () => RUN_STORE_WBS_MAX_LIMIT,
121017
- ResponseValidateActionRunner: () => ResponseValidateActionRunner,
121018
120937
  RetroCorrelator: () => RetroCorrelator,
121019
120938
  RuleCheckActionRunner: () => RuleCheckActionRunner,
121020
120939
  RuleService: () => RuleService,
@@ -121142,7 +121061,6 @@ __export(exports_src, {
121142
121061
  decodeRunListCursor: () => decodeRunListCursor,
121143
121062
  decorateWorkflowEvent: () => decorateWorkflowEvent,
121144
121063
  deduceCommandCategory: () => deduceCommandCategory,
121145
- deriveFeatureConfidence: () => deriveFeatureConfidence,
121146
121064
  deriveVerdict: () => deriveVerdict,
121147
121065
  discoverEnabledClaudePlugins: () => discoverEnabledClaudePlugins,
121148
121066
  disposeDecisionServices: () => disposeDecisionServices,
@@ -121205,6 +121123,7 @@ __export(exports_src, {
121205
121123
  isInlineRunActionStatus: () => isInlineRunActionStatus,
121206
121124
  isInlineRunCloseStatus: () => isInlineRunCloseStatus,
121207
121125
  isInsideRoot: () => isInsideRoot,
121126
+ isLocalHost: () => isLocalHost,
121208
121127
  isPortAvailable: () => isPortAvailable,
121209
121128
  isPortLive: () => isPortLive,
121210
121129
  isProofCaptureError: () => isProofCaptureError,
@@ -128491,7 +128410,7 @@ import {
128491
128410
  statSync as statSync17,
128492
128411
  writeFileSync as writeFileSync17
128493
128412
  } from "fs";
128494
- import { join as join80 } from "path";
128413
+ import { join as join81 } from "path";
128495
128414
  function parseScalar(raw) {
128496
128415
  const t = raw.trim();
128497
128416
  if (t.startsWith('"') && t.endsWith('"'))
@@ -128700,10 +128619,6 @@ function checkReportStructure(reportMarkdown) {
128700
128619
  if (!/(^|[\s`])P[123]([\s`.]|$)/.test(block) && !block.includes("symbolic-severity")) {
128701
128620
  problems.push("finding-invalid-severity");
128702
128621
  }
128703
- const confValue = block.match(/`confidence`\s*[:=]\s*`?([^`\n]*?)`?\s*(?:\n|$)/)?.[1]?.trim();
128704
- if (confValue !== undefined && confValue !== "" && !FINDING_CONFIDENCES.includes(confValue.toLowerCase())) {
128705
- problems.push(`finding-invalid-confidence:${confValue}`);
128706
- }
128707
128622
  const catValue = block.match(/`category`\s*[:=]\s*`?([^`\n]+?)`?\s*(?:\n|$)/)?.[1];
128708
128623
  if (catValue && !FINDING_CATEGORIES.includes(catValue.trim())) {
128709
128624
  problems.push(`finding-invalid-category:${catValue.trim()}`);
@@ -128737,7 +128652,7 @@ function logicDigest(path) {
128737
128652
  try {
128738
128653
  const h = createHash17("sha256");
128739
128654
  if (statSync17(path).isDirectory()) {
128740
- const walk = (dir) => readdirSync13(dir, { withFileTypes: true }).flatMap((e) => e.isDirectory() ? walk(join80(dir, e.name)) : /\.(md|ya?ml)$/.test(e.name) ? [join80(dir, e.name)] : []).sort();
128655
+ const walk = (dir) => readdirSync13(dir, { withFileTypes: true }).flatMap((e) => e.isDirectory() ? walk(join81(dir, e.name)) : /\.(md|ya?ml)$/.test(e.name) ? [join81(dir, e.name)] : []).sort();
128741
128656
  for (const f of walk(path)) {
128742
128657
  h.update(f.slice(path.length));
128743
128658
  h.update(readFileSync25(f));
@@ -129042,7 +128957,7 @@ function diffPorcelain(before, now, expects) {
129042
128957
  const beforePaths = porcelainPaths(before);
129043
128958
  return [...porcelainPaths(now)].filter((p) => !beforePaths.has(p) && !expects.has(p)).sort();
129044
128959
  }
129045
- var REPORT_SECTIONS, FINDING_FIELDS, DISPOSITIONS, FINDING_CATEGORIES, FINDING_CONFIDENCES, NOT_AVAILABLE = "not available", YAML_KEYS;
128960
+ var REPORT_SECTIONS, FINDING_FIELDS, DISPOSITIONS, FINDING_CATEGORIES, NOT_AVAILABLE = "not available", YAML_KEYS;
129046
128961
  var init_history_anatomy = __esm(() => {
129047
128962
  init_artifact_digest();
129048
128963
  REPORT_SECTIONS = [
@@ -129066,7 +128981,6 @@ var init_history_anatomy = __esm(() => {
129066
128981
  "trend",
129067
128982
  "observation",
129068
128983
  "inference",
129069
- "confidence",
129070
128984
  "contradictions",
129071
128985
  "evidenceAnchor",
129072
128986
  "severity",
@@ -129083,7 +128997,6 @@ var init_history_anatomy = __esm(() => {
129083
128997
  "telemetry",
129084
128998
  "positive"
129085
128999
  ];
129086
- FINDING_CONFIDENCES = ["high", "medium", "low"];
129087
129000
  YAML_KEYS = [
129088
129001
  "windowState",
129089
129002
  "generatedAt",
@@ -129108,7 +129021,7 @@ var init_history_anatomy = __esm(() => {
129108
129021
  // ../../packages/app/src/services/history-anatomy-cli.ts
129109
129022
  import { existsSync as existsSync29, mkdirSync as mkdirSync21, readFileSync as readFileSync26, writeFileSync as writeFileSync18 } from "fs";
129110
129023
  import { homedir as homedir13 } from "os";
129111
- import { join as join81 } from "path";
129024
+ import { join as join82 } from "path";
129112
129025
  function parseFlags(args) {
129113
129026
  const out = {};
129114
129027
  for (let i = 0;i < args.length; i++) {
@@ -129130,9 +129043,9 @@ function resolveSkillDir(deps = {}) {
129130
129043
  const cwd = deps.cwd ?? process.cwd();
129131
129044
  const home = deps.home ?? homedir13();
129132
129045
  const candidates = [
129133
- join81(cwd, "plugins", "sp", "skills", "history-anatomy"),
129134
- join81(home, ".agents", "skills", "sp-history-anatomy"),
129135
- join81(home, ".claude", "skills", "sp-history-anatomy")
129046
+ join82(cwd, "plugins", "sp", "skills", "history-anatomy"),
129047
+ join82(home, ".agents", "skills", "sp-history-anatomy"),
129048
+ join82(home, ".claude", "skills", "sp-history-anatomy")
129136
129049
  ];
129137
129050
  return candidates.find((dir) => existsSync29(dir)) ?? candidates[0];
129138
129051
  }
@@ -129363,7 +129276,7 @@ var init_history_anatomy_cli = __esm(() => {
129363
129276
 
129364
129277
  // ../../packages/app/src/services/daily-summary.ts
129365
129278
  import { existsSync as existsSync30, mkdirSync as mkdirSync22, readlinkSync as readlinkSync2, writeFileSync as writeFileSync19 } from "fs";
129366
- import { dirname as dirname40, isAbsolute as isAbsolute14, join as join82, resolve as resolve30 } from "path";
129279
+ import { dirname as dirname40, isAbsolute as isAbsolute14, join as join83, resolve as resolve30 } from "path";
129367
129280
  function parseArgs2(argv) {
129368
129281
  const args = argv;
129369
129282
  const options = {
@@ -129750,8 +129663,8 @@ function ensureDir(path) {
129750
129663
  }
129751
129664
  function writeSummary(markdown, options) {
129752
129665
  const filename = `summary_${options.date.replace(/-/g, "")}.md`;
129753
- const outputPath = options.outputPath || join82(DAILY_DIR, filename);
129754
- ensureDir(join82(outputPath, ".."));
129666
+ const outputPath = options.outputPath || join83(DAILY_DIR, filename);
129667
+ ensureDir(join83(outputPath, ".."));
129755
129668
  writeFileSync19(outputPath, markdown, "utf-8");
129756
129669
  return outputPath;
129757
129670
  }
@@ -129900,7 +129813,7 @@ var init_daily_summary = __esm(() => {
129900
129813
  // ../../packages/app/src/workflow/transcript.ts
129901
129814
  import { existsSync as existsSync31, readdirSync as readdirSync14 } from "fs";
129902
129815
  import { homedir as homedir14 } from "os";
129903
- import { join as join83 } from "path";
129816
+ import { join as join84 } from "path";
129904
129817
  function sniffTranscriptFormat(rows) {
129905
129818
  for (const row of rows) {
129906
129819
  if (row.type === "message" && PI_ROLES.has(row.message?.role ?? ""))
@@ -129929,7 +129842,7 @@ function parseTranscriptRows(lines) {
129929
129842
  }
129930
129843
  return { rows, skippedLines, format: sniffTranscriptFormat(rows.map(([r]) => r)) };
129931
129844
  }
129932
- function resolveTranscript(env, projectsRoot = join83(homedir14(), ".claude", "projects"), override) {
129845
+ function resolveTranscript(env, projectsRoot = join84(homedir14(), ".claude", "projects"), override) {
129933
129846
  if (override)
129934
129847
  return existsSync31(override) ? { ok: true, path: override } : { ok: false, reason: "no transcript" };
129935
129848
  const id = env.CLAUDE_CODE_SESSION_ID;
@@ -129948,7 +129861,7 @@ function resolveTranscript(env, projectsRoot = join83(homedir14(), ".claude", "p
129948
129861
  if (!existsSync31(projectsRoot))
129949
129862
  return { ok: false, reason: `no transcript root ${projectsRoot}` };
129950
129863
  for (const dir of readdirSync14(projectsRoot)) {
129951
- const path = join83(projectsRoot, dir, `${id}.jsonl`);
129864
+ const path = join84(projectsRoot, dir, `${id}.jsonl`);
129952
129865
  if (existsSync31(path))
129953
129866
  return { ok: true, path };
129954
129867
  }
@@ -130143,7 +130056,7 @@ var require_src9 = __commonJS(function(exports, module) {
130143
130056
 
130144
130057
  // ../../packages/app/src/workflow/run-summary-render.ts
130145
130058
  import { existsSync as existsSync32, mkdirSync as mkdirSync24, readFileSync as readFileSync29, writeFileSync as writeFileSync21 } from "fs";
130146
- import { join as join98 } from "path";
130059
+ import { join as join99 } from "path";
130147
130060
  function renderSummaryMarkdown(summary) {
130148
130061
  const line = (r, bold = false) => {
130149
130062
  const stage = bold ? `**${r.stage}**` : r.stage;
@@ -130229,9 +130142,9 @@ function renderRollupMarkdown(rows) {
130229
130142
  }
130230
130143
  function writeCloseSummary(run, opts = {}) {
130231
130144
  const cwd = opts.cwd ?? process.cwd();
130232
- const runDir = join98(cwd, ".spur", "run");
130233
- const rel = join98(".spur", "run", `${run.runId}-summary.md`);
130234
- const abs = join98(cwd, rel);
130145
+ const runDir = join99(cwd, ".spur", "run");
130146
+ const rel = join99(".spur", "run", `${run.runId}-summary.md`);
130147
+ const abs = join99(cwd, rel);
130235
130148
  const na = (reason) => {
130236
130149
  mkdirSync24(runDir, { recursive: true });
130237
130150
  writeFileSync21(abs, `Execution summary: n/a (${reason})
@@ -130256,14 +130169,14 @@ function writeCloseSummary(run, opts = {}) {
130256
130169
  mkdirSync24(runDir, { recursive: true });
130257
130170
  writeFileSync21(abs, `${renderSummaryMarkdown(summary)}
130258
130171
  `);
130259
- writeFileSync21(join98(runDir, `${run.runId}-summary.json`), JSON.stringify({ ...summary, runId: run.runId, startedAt: run.startedAt, completedAt: run.completedAt }, null, 2));
130172
+ writeFileSync21(join99(runDir, `${run.runId}-summary.json`), JSON.stringify({ ...summary, runId: run.runId, startedAt: run.startedAt, completedAt: run.completedAt }, null, 2));
130260
130173
  return rel;
130261
130174
  } catch (error) {
130262
130175
  return na(error instanceof Error ? error.message : String(error));
130263
130176
  }
130264
130177
  }
130265
130178
  function gateFromReceipt(cwd, runId) {
130266
- const path = join98(cwd, ".spur", "run", `${runId}-check-receipt.json`);
130179
+ const path = join99(cwd, ".spur", "run", `${runId}-check-receipt.json`);
130267
130180
  if (!existsSync32(path))
130268
130181
  return { ms: null, reason: "no matching check receipt" };
130269
130182
  try {
@@ -138207,8 +138120,18 @@ init_src();
138207
138120
  init_dist5();
138208
138121
  import { homedir as homedir12 } from "os";
138209
138122
  import { join as join67 } from "path";
138210
- var CODEXBAR_ARGV = ["codexbar", "usage", "--format", "json", "--provider", "all"];
138211
- var DEFAULT_CAPTURE_TIMEOUT_MS = 180000;
138123
+ var CODEXBAR_ARGV = ["codexbar", "usage", "--format", "json"];
138124
+ var DEFAULT_CAPTURE_TIMEOUT_MS = 300000;
138125
+ var CAPTURE_TIMEOUT_OPTION = "agentUsageCaptureTimeoutMs";
138126
+ var MAX_TIMER_MS = 2147483647;
138127
+ function resolveCaptureTimeoutMs(spurConfig) {
138128
+ const raw = getAppOptions(spurConfig, CAPTURE_TIMEOUT_OPTION, undefined);
138129
+ if (raw === undefined)
138130
+ return DEFAULT_CAPTURE_TIMEOUT_MS;
138131
+ if (typeof raw === "number" && Number.isInteger(raw) && raw > 0 && raw <= MAX_TIMER_MS)
138132
+ return raw;
138133
+ throw new UsageSourceError(`bootstrap.options.${CAPTURE_TIMEOUT_OPTION} must be a positive integer number of milliseconds (at most ${MAX_TIMER_MS}); received ${JSON.stringify(raw)}`);
138134
+ }
138212
138135
 
138213
138136
  class CodexbarUsageSource {
138214
138137
  command;
@@ -138238,7 +138161,7 @@ class CodexbarUsageSource {
138238
138161
  }
138239
138162
  const outcome = result.outcome ?? "exit";
138240
138163
  if (outcome === "timeout" || outcome === "cancelled") {
138241
- throw new UsageSourceError(`\`${this.command.join(" ")}\` capture exceeded the ${this.timeoutMs} ms deadline and was terminated \u2014 ` + "result is unusable (fail-closed); retry or investigate the codexbar hang");
138164
+ throw new UsageSourceError(`\`${this.command.join(" ")}\` capture exceeded the ${this.timeoutMs} ms deadline and was terminated \u2014 ` + `result is unusable (fail-closed); retry, raise bootstrap.options.${CAPTURE_TIMEOUT_OPTION}, or investigate the codexbar hang`);
138242
138165
  }
138243
138166
  if (outcome === "signal" || outcome === "error") {
138244
138167
  throw new UsageSourceError(`\`${this.command.join(" ")}\` capture ended abnormally (${outcome}) \u2014 capture is unusable (fail-closed)`);
@@ -142424,13 +142347,13 @@ async function runAgentUsage(context, flags, deps) {
142424
142347
  }
142425
142348
  return 2;
142426
142349
  }
142427
- const options = {
142428
- source: deps?.source ?? _testUsageDeps?.source ?? new CodexbarUsageSource,
142429
- snapshotPath: deps?.snapshotPath ?? _testUsageDeps?.snapshotPath ?? defaultAgentUsageSnapshotPath(),
142430
- dryRun: flags.dryRun === true
142431
- };
142432
142350
  let result;
142433
142351
  try {
142352
+ const options = {
142353
+ source: deps?.source ?? _testUsageDeps?.source ?? new CodexbarUsageSource(undefined, resolveCaptureTimeoutMs(context.spurConfig)),
142354
+ snapshotPath: deps?.snapshotPath ?? _testUsageDeps?.snapshotPath ?? defaultAgentUsageSnapshotPath(),
142355
+ dryRun: flags.dryRun === true
142356
+ };
142434
142357
  result = await runAgentUsageProducer({
142435
142358
  getDb: () => context.getDb(),
142436
142359
  projectRoot: context.cwd,
@@ -142725,12 +142648,33 @@ function registerAgentCommand(program, context) {
142725
142648
  init_src();
142726
142649
  init_dist5();
142727
142650
  import { existsSync as existsSync26, readdirSync as readdirSync12, readFileSync as readFileSync23 } from "fs";
142728
- import { join as join78 } from "path";
142651
+ import { join as join79 } from "path";
142652
+
142653
+ // ../../scripts/commands/bundle-plugins.ts
142654
+ import { cp, rm as rm4 } from "fs/promises";
142655
+ import { join as join77 } from "path";
142656
+ import { fileURLToPath as fileURLToPath6 } from "url";
142657
+ var REPO_ROOT = fileURLToPath6(new URL("../../", import.meta.url));
142658
+ var PLUGIN_SOURCE = join77(REPO_ROOT, "plugins");
142659
+ var PLUGIN_TARGET = join77(REPO_ROOT, "apps/cli/plugins");
142660
+ var MARKETPLACE_SOURCE = join77(REPO_ROOT, ".claude-plugin");
142661
+ var MARKETPLACE_TARGET = join77(REPO_ROOT, "apps/cli/.claude-plugin");
142662
+ var EXCLUDE = /(^|\/)(\.DS_Store|tests|evals)($|\/)|\.test\.ts$/;
142663
+ async function bundlePlugins(pluginTarget = PLUGIN_TARGET, marketplaceTarget = MARKETPLACE_TARGET, pluginSource = PLUGIN_SOURCE, marketplaceSource = MARKETPLACE_SOURCE) {
142664
+ await rm4(pluginTarget, { recursive: true, force: true });
142665
+ await rm4(marketplaceTarget, { recursive: true, force: true });
142666
+ await cp(pluginSource, pluginTarget, {
142667
+ recursive: true,
142668
+ filter: (src) => !EXCLUDE.test(src.slice(pluginSource.length))
142669
+ });
142670
+ await cp(marketplaceSource, marketplaceTarget, { recursive: true });
142671
+ return { pluginTarget, marketplaceTarget };
142672
+ }
142729
142673
 
142730
142674
  // src/version-carriers.ts
142731
142675
  init_zod();
142732
142676
  import { existsSync as existsSync25 } from "fs";
142733
- import { join as join77 } from "path";
142677
+ import { join as join78 } from "path";
142734
142678
  var defaultLiteralProbe = { file: "src/config.ts", identifier: "binaryVersion" };
142735
142679
  var registry3 = new Map;
142736
142680
  function registerCarrierType(type, def) {
@@ -142789,7 +142733,7 @@ registerCarrierType("plugin-manifest", {
142789
142733
  schema: PluginManifestCarrierSchema,
142790
142734
  async syncRepoWide(carrier, { repoRoot }, version, staged, output) {
142791
142735
  for (const rel of carrier.paths) {
142792
- const absPath = join77(repoRoot, rel);
142736
+ const absPath = join78(repoRoot, rel);
142793
142737
  const manifest = await readJson(absPath);
142794
142738
  if (manifest === null) {
142795
142739
  output.write(` \u26A0 ${rel}: not found or malformed \u2014 skipping`);
@@ -142849,7 +142793,7 @@ async function run2(repoRoot, cmd, timeoutMs) {
142849
142793
  };
142850
142794
  }
142851
142795
  async function verifyLockfile(ctx, output) {
142852
- const lockPath = join78(ctx.repoRoot, "bun.lock");
142796
+ const lockPath = join79(ctx.repoRoot, "bun.lock");
142853
142797
  if (!existsSync26(lockPath) || Bun.file(lockPath).size === 0)
142854
142798
  return;
142855
142799
  const result = await run2(ctx.repoRoot, ["bun", "install", "--frozen-lockfile"]);
@@ -142859,7 +142803,7 @@ async function verifyLockfile(ctx, output) {
142859
142803
  output.write(" \u21B3 bun.lock: verified (bun install --frozen-lockfile)");
142860
142804
  }
142861
142805
  async function assertPluginInstallable(ctx, output) {
142862
- const smokePath = join78(ctx.repoRoot, "scripts", "commands", "plugin-install-smoke.ts");
142806
+ const smokePath = join79(ctx.repoRoot, "scripts", "commands", "plugin-install-smoke.ts");
142863
142807
  if (!existsSync26(smokePath)) {
142864
142808
  output.write(" \u21B3 plugin-install-smoke: gate script not present in this repo \u2014 skipped");
142865
142809
  return;
@@ -142901,7 +142845,7 @@ async function readJson2(path) {
142901
142845
  function rootWorkspaceGlobs(repoRoot) {
142902
142846
  let root;
142903
142847
  try {
142904
- root = JSON.parse(readFileSync23(join78(repoRoot, "package.json"), "utf8"));
142848
+ root = JSON.parse(readFileSync23(join79(repoRoot, "package.json"), "utf8"));
142905
142849
  } catch {
142906
142850
  return [];
142907
142851
  }
@@ -142918,11 +142862,11 @@ function workspaceDirs(repoRoot) {
142918
142862
  if (!glob.endsWith("/*"))
142919
142863
  continue;
142920
142864
  const parent = glob.slice(0, -2);
142921
- const parentAbs = join78(repoRoot, parent);
142865
+ const parentAbs = join79(repoRoot, parent);
142922
142866
  if (!existsSync26(parentAbs))
142923
142867
  continue;
142924
142868
  for (const entry of readdirSync12(parentAbs, { withFileTypes: true })) {
142925
- if (entry.isDirectory() && existsSync26(join78(parentAbs, entry.name, "package.json"))) {
142869
+ if (entry.isDirectory() && existsSync26(join79(parentAbs, entry.name, "package.json"))) {
142926
142870
  dirs.push(`${parent}/${entry.name}`);
142927
142871
  }
142928
142872
  }
@@ -142930,14 +142874,14 @@ function workspaceDirs(repoRoot) {
142930
142874
  return dirs;
142931
142875
  }
142932
142876
  async function releaseContext(repoRoot, bumpVerConfig = resolveBuilderBumpVerConfig(null)) {
142933
- const rootManifest = await readJson2(join78(repoRoot, "package.json"));
142877
+ const rootManifest = await readJson2(join79(repoRoot, "package.json"));
142934
142878
  if (rootManifest === null) {
142935
142879
  throw new Error(`no package.json found at ${repoRoot} \u2014 builder operates on a package workspace root.`);
142936
142880
  }
142937
142881
  const rootName = typeof rootManifest.name === "string" ? rootManifest.name : "root";
142938
142882
  const workspaces = [];
142939
142883
  for (const dir of workspaceDirs(repoRoot)) {
142940
- const manifest = await readJson2(join78(repoRoot, dir, "package.json"));
142884
+ const manifest = await readJson2(join79(repoRoot, dir, "package.json"));
142941
142885
  if (manifest === null)
142942
142886
  continue;
142943
142887
  workspaces.push({
@@ -142952,8 +142896,8 @@ async function releaseContext(repoRoot, bumpVerConfig = resolveBuilderBumpVerCon
142952
142896
  const packages = new Map;
142953
142897
  for (const ws of workspaces) {
142954
142898
  const probe = findLiteralProbe(versionCarriers, ws.dir) ?? defaultLiteralProbe;
142955
- const literalProbe = join78(ws.dir, probe.file);
142956
- const versionSourceFile = existsSync26(join78(repoRoot, literalProbe)) ? literalProbe : undefined;
142899
+ const literalProbe = join79(ws.dir, probe.file);
142900
+ const versionSourceFile = existsSync26(join79(repoRoot, literalProbe)) ? literalProbe : undefined;
142957
142901
  packages.set(shortName(ws.name), {
142958
142902
  packageDir: ws.dir,
142959
142903
  packageName: ws.name,
@@ -142991,7 +142935,7 @@ async function updateWorkspacePins(ctx, pkgName, oldVersion, newVersion, output)
142991
142935
  const changed = [];
142992
142936
  for (const dir of [".", ...workspaceDirs(ctx.repoRoot)]) {
142993
142937
  const relPath = dir === "." ? "package.json" : `${dir}/package.json`;
142994
- const manifest = await readJson2(join78(ctx.repoRoot, relPath));
142938
+ const manifest = await readJson2(join79(ctx.repoRoot, relPath));
142995
142939
  if (manifest === null)
142996
142940
  continue;
142997
142941
  let dirty = false;
@@ -143008,7 +142952,7 @@ async function updateWorkspacePins(ctx, pkgName, oldVersion, newVersion, output)
143008
142952
  }
143009
142953
  }
143010
142954
  if (dirty) {
143011
- await Bun.write(join78(ctx.repoRoot, relPath), `${JSON.stringify(manifest, null, 4)}
142955
+ await Bun.write(join79(ctx.repoRoot, relPath), `${JSON.stringify(manifest, null, 4)}
143012
142956
  `);
143013
142957
  output.write(` \u21B3 ${relPath}: ${pkgName} workspace pin ${oldVersion} \u2192 ${newVersion}`);
143014
142958
  changed.push(relPath);
@@ -143016,7 +142960,7 @@ async function updateWorkspacePins(ctx, pkgName, oldVersion, newVersion, output)
143016
142960
  }
143017
142961
  if (changed.length === 0)
143018
142962
  return changed;
143019
- const lockPath = join78(ctx.repoRoot, "bun.lock");
142963
+ const lockPath = join79(ctx.repoRoot, "bun.lock");
143020
142964
  if (existsSync26(lockPath)) {
143021
142965
  const lock = await Bun.file(lockPath).text();
143022
142966
  const staleSpec = `"${pkgName}": "workspace:${oldVersion}"`;
@@ -143028,7 +142972,7 @@ async function updateWorkspacePins(ctx, pkgName, oldVersion, newVersion, output)
143028
142972
  return changed;
143029
142973
  }
143030
142974
  async function updateVersionSourceFile(ctx, filePath, previous, next, output, identifier = "binaryVersion") {
143031
- const absPath = join78(ctx.repoRoot, filePath);
142975
+ const absPath = join79(ctx.repoRoot, filePath);
143032
142976
  const content = await Bun.file(absPath).text();
143033
142977
  const pattern = new RegExp(`(${identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*['"])\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z-.]+)?(?:\\+[0-9A-Za-z-.]+)?(['"])`);
143034
142978
  const updated = content.replace(pattern, `$1${next}$2`);
@@ -143046,7 +142990,7 @@ async function syncExtraCarriers(ctx, version, staged, output) {
143046
142990
  }
143047
142991
  }
143048
142992
  async function syncMarketplaceAndPlugins(ctx, version, staged, output) {
143049
- const marketplacePath = join78(ctx.repoRoot, ".claude-plugin", "marketplace.json");
142993
+ const marketplacePath = join79(ctx.repoRoot, ".claude-plugin", "marketplace.json");
143050
142994
  const marketplaceFile = Bun.file(marketplacePath);
143051
142995
  if (!await marketplaceFile.exists())
143052
142996
  return;
@@ -143071,7 +143015,7 @@ async function syncMarketplaceAndPlugins(ctx, version, staged, output) {
143071
143015
  output.write(`Bumped marketplace plugins to ${version}`);
143072
143016
  }
143073
143017
  for (const entry of plugins) {
143074
- const pluginJsonPath = join78(ctx.repoRoot, entry.source, "plugin.json");
143018
+ const pluginJsonPath = join79(ctx.repoRoot, entry.source, "plugin.json");
143075
143019
  const pluginJson = await readJson2(pluginJsonPath);
143076
143020
  if (pluginJson === null) {
143077
143021
  output.write(` \u26A0 plugin.json not found at ${entry.source}/plugin.json \u2014 skipping`);
@@ -143085,6 +143029,14 @@ async function syncMarketplaceAndPlugins(ctx, version, staged, output) {
143085
143029
  output.write(`Bumped ${entry.source}/plugin.json to ${version}`);
143086
143030
  }
143087
143031
  }
143032
+ for (const config of ctx.packages.values()) {
143033
+ const pkgDir = join79(ctx.repoRoot, config.packageDir);
143034
+ const stagedMarketplace = join79(pkgDir, ".claude-plugin", "marketplace.json");
143035
+ if (!existsSync26(stagedMarketplace))
143036
+ continue;
143037
+ await bundlePlugins(join79(pkgDir, "plugins"), join79(pkgDir, ".claude-plugin"), join79(ctx.repoRoot, "plugins"), join79(ctx.repoRoot, ".claude-plugin"));
143038
+ output.write(`Refreshed staged plugin copy in ${config.packageDir}`);
143039
+ }
143088
143040
  }
143089
143041
  async function assertCleanTreeOnBranch(ctx) {
143090
143042
  const RUNTIME_NOISE = /^\?\? \.spur\/(?:spur\.db|spur\.db-shm|spur\.db-wal|logs\/)/;
@@ -143125,7 +143077,7 @@ async function bumpVersion(ctx, config, version, options, output) {
143125
143077
  throw new Error(`${config.packageName}@${version} is already published on npm. Use a new version.`);
143126
143078
  }
143127
143079
  await assertPluginInstallable(ctx, output);
143128
- const manifestPath = join78(ctx.repoRoot, config.packageDir, "package.json");
143080
+ const manifestPath = join79(ctx.repoRoot, config.packageDir, "package.json");
143129
143081
  const manifest = await readJson2(manifestPath);
143130
143082
  if (manifest === null)
143131
143083
  throw new Error(`missing or malformed manifest at ${config.packageDir}/package.json`);
@@ -143144,7 +143096,7 @@ async function bumpVersion(ctx, config, version, options, output) {
143144
143096
  await syncMarketplaceAndPlugins(ctx, version, staged, output);
143145
143097
  await syncExtraCarriers(ctx, version, staged, output);
143146
143098
  await verifyLockfile(ctx, output);
143147
- const lockPath = join78(ctx.repoRoot, "bun.lock");
143099
+ const lockPath = join79(ctx.repoRoot, "bun.lock");
143148
143100
  if (existsSync26(lockPath) && Bun.file(lockPath).size > 0)
143149
143101
  staged.push("bun.lock");
143150
143102
  await git2(ctx.repoRoot, ["add", ...staged]);
@@ -143201,7 +143153,7 @@ async function bumpAll(ctx, version, options, output) {
143201
143153
  }
143202
143154
  const staged = [];
143203
143155
  for (const config of configs) {
143204
- const manifestPath = join78(ctx.repoRoot, config.packageDir, "package.json");
143156
+ const manifestPath = join79(ctx.repoRoot, config.packageDir, "package.json");
143205
143157
  const manifest = await readJson2(manifestPath);
143206
143158
  if (manifest === null) {
143207
143159
  throw new Error(`missing or malformed manifest at ${config.packageDir}/package.json`);
@@ -143222,7 +143174,7 @@ async function bumpAll(ctx, version, options, output) {
143222
143174
  await syncMarketplaceAndPlugins(ctx, version, staged, output);
143223
143175
  await syncExtraCarriers(ctx, version, staged, output);
143224
143176
  await verifyLockfile(ctx, output);
143225
- const lockPath = join78(ctx.repoRoot, "bun.lock");
143177
+ const lockPath = join79(ctx.repoRoot, "bun.lock");
143226
143178
  if (existsSync26(lockPath) && Bun.file(lockPath).size > 0)
143227
143179
  staged.push("bun.lock");
143228
143180
  await git2(ctx.repoRoot, ["add", ...staged]);
@@ -143378,9 +143330,9 @@ async function checkVersionDrift(target, repoRoot = process.cwd(), output = cons
143378
143330
  if (config === undefined) {
143379
143331
  throw releaseUsage(target === undefined ? "bump-ver --check needs a package id (no aggregate package is configured)" : `unknown package "${target}". Package IDs: ${[...ctx.packages.keys()].join(", ")}`);
143380
143332
  }
143381
- const manifest = await readJson2(join78(repoRoot, config.packageDir, "package.json"));
143333
+ const manifest = await readJson2(join79(repoRoot, config.packageDir, "package.json"));
143382
143334
  const pkgVersion = typeof manifest?.version === "string" ? manifest.version : "";
143383
- const marketplacePath = join78(repoRoot, ".claude-plugin", "marketplace.json");
143335
+ const marketplacePath = join79(repoRoot, ".claude-plugin", "marketplace.json");
143384
143336
  const marketplaceFile = Bun.file(marketplacePath);
143385
143337
  if (!await marketplaceFile.exists()) {
143386
143338
  output.write("No .claude-plugin/marketplace.json \u2014 nothing to check.");
@@ -143393,8 +143345,8 @@ async function checkVersionDrift(target, repoRoot = process.cwd(), output = cons
143393
143345
  for (const entry of parsed.plugins ?? []) {
143394
143346
  if (typeof entry.source !== "string")
143395
143347
  continue;
143396
- const label = join78(entry.source, "plugin.json").replace(/^\.\//, "");
143397
- const pluginJson = await readJson2(join78(repoRoot, entry.source, "plugin.json"));
143348
+ const label = join79(entry.source, "plugin.json").replace(/^\.\//, "");
143349
+ const pluginJson = await readJson2(join79(repoRoot, entry.source, "plugin.json"));
143398
143350
  plugins.push({ label, version: typeof pluginJson?.version === "string" ? pluginJson.version : "" });
143399
143351
  }
143400
143352
  } catch {}
@@ -143462,8 +143414,8 @@ async function publishPackage(target, opts = {}) {
143462
143414
  const repoRoot = opts.repoRoot ?? process.cwd();
143463
143415
  const output = opts.output ?? consoleOutput;
143464
143416
  const runner = opts.runner ?? defaultPublishRunner;
143465
- const dir = (target.startsWith("/") ? target : join78(repoRoot, target)).replace(/\/+$/, "");
143466
- const manifestPath = join78(dir, "package.json");
143417
+ const dir = (target.startsWith("/") ? target : join79(repoRoot, target)).replace(/\/+$/, "");
143418
+ const manifestPath = join79(dir, "package.json");
143467
143419
  const manifestFile = Bun.file(manifestPath);
143468
143420
  if (!await manifestFile.exists())
143469
143421
  throw new Error(`no package.json at ${dir}`);
@@ -143471,7 +143423,7 @@ async function publishPackage(target, opts = {}) {
143471
143423
  const manifest = JSON.parse(original);
143472
143424
  const workspaces = new Map;
143473
143425
  for (const wsDir of workspaceDirs(repoRoot)) {
143474
- const pkg = await readJson2(join78(repoRoot, wsDir, "package.json"));
143426
+ const pkg = await readJson2(join79(repoRoot, wsDir, "package.json"));
143475
143427
  if (pkg !== null && typeof pkg.name === "string") {
143476
143428
  workspaces.set(pkg.name, {
143477
143429
  ...typeof pkg.version === "string" ? { version: pkg.version } : {},
@@ -143479,7 +143431,7 @@ async function publishPackage(target, opts = {}) {
143479
143431
  });
143480
143432
  }
143481
143433
  }
143482
- const root = await readJson2(join78(repoRoot, "package.json"));
143434
+ const root = await readJson2(join79(repoRoot, "package.json"));
143483
143435
  const catalog = root?.workspaces?.catalog ?? {};
143484
143436
  const changed = resolvePublishRanges(manifest, workspaces, catalog);
143485
143437
  if (changed > 0) {
@@ -143514,7 +143466,7 @@ async function publishPackage(target, opts = {}) {
143514
143466
  init_src();
143515
143467
  import { spawnSync as spawnSync7 } from "child_process";
143516
143468
  import { existsSync as existsSync27, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "fs";
143517
- import { join as join79, resolve as resolve28 } from "path";
143469
+ import { join as join80, resolve as resolve28 } from "path";
143518
143470
  function createSpawnRunner(context = {}) {
143519
143471
  return (cmd) => {
143520
143472
  const proc = spawnSync7(cmd[0] ?? "", [...cmd.slice(1)], {
@@ -143657,7 +143609,7 @@ function extractSeverity2(body) {
143657
143609
  }
143658
143610
  var DEFAULT_FOCUS = "for correctness and regressions, security boundaries, data-loss risks, concurrency or race conditions, " + "API/backward compatibility, migration safety, error handling, and missing high-value tests. " + "Prioritize actionable issues over style or nits.";
143659
143611
  function hasCodeReviewRules(repoRoot) {
143660
- const agentsPath = join79(repoRoot, "AGENTS.md");
143612
+ const agentsPath = join80(repoRoot, "AGENTS.md");
143661
143613
  if (!existsSync27(agentsPath))
143662
143614
  return false;
143663
143615
  return /^## Code Review Rules\s*$/m.test(readFileSync24(agentsPath, "utf8"));
@@ -144717,9 +144669,9 @@ function registerFeatureVerifyCommand(feature, context) {
144717
144669
  "Runs the selected feature-verification definition\u2019s command once (or --cmd) and writes the",
144718
144670
  "run-scoped + feature-latest receipts and .spur/run/<runId>-feature-verification.status.",
144719
144671
  "Exit: 0 after a completed pass (PASS or FAIL); 1 when the pass could not run.",
144720
- "Flags fall back to the workflow env names: featureId, __runId, verificationCmd, confidence, ackLowConfidence."
144672
+ "Flags fall back to the workflow env names: featureId, __runId, verificationCmd."
144721
144673
  ].join(`
144722
- `)).argument("[id]", "Feature ID (env: featureId)").option("--run-id <id>", "workflow run id the receipt binds to (env: __runId)").option("--cmd <command>", "verification command override (env: verificationCmd)").option("--confidence <level>", "declared confidence HIGH | MEDIUM | LOW (env: confidence)").option("--ack-low-confidence", "acknowledge a LOW confidence level on the receipt (env: ackLowConfidence=true)").action(async (id, options) => {
144674
+ `)).argument("[id]", "Feature ID (env: featureId)").option("--run-id <id>", "workflow run id the receipt binds to (env: __runId)").option("--cmd <command>", "verification command override (env: verificationCmd)").action(async (id, options) => {
144723
144675
  await Promise.resolve().then(() => init_src3());
144724
144676
  const env = context.env;
144725
144677
  const featureId = id || env.featureId || "";
@@ -144728,9 +144680,7 @@ function registerFeatureVerifyCommand(feature, context) {
144728
144680
  workdir: context.cwd,
144729
144681
  featureId,
144730
144682
  runId: options.runId || env.__runId || "",
144731
- cmdOverride: options.cmd || env.verificationCmd || "",
144732
- confidenceOverride: options.confidence || env.confidence || "",
144733
- ackLowConfidence: options.ackLowConfidence === true || env.ackLowConfidence === "true"
144683
+ cmdOverride: options.cmd || env.verificationCmd || ""
144734
144684
  });
144735
144685
  context.output.write(`feature verify: ${featureId} ${result.message}`);
144736
144686
  } catch (err) {
@@ -145177,7 +145127,7 @@ import { createRequire as createRequire3 } from "module";
145177
145127
  var CLI_CONFIG = {
145178
145128
  binaryName: "spur",
145179
145129
  binaryLabel: "spur",
145180
- binaryVersion: "0.4.9",
145130
+ binaryVersion: "0.4.10",
145181
145131
  configDir: ".spur",
145182
145132
  configFile: ".spur/config.yaml",
145183
145133
  databaseFile: ".spur/spur.db"
@@ -145721,7 +145671,7 @@ init_loader2();
145721
145671
  init_src2();
145722
145672
  init_dist11();
145723
145673
  import { homedir as homedir15 } from "os";
145724
- import { join as join84, resolve as resolve31 } from "path";
145674
+ import { join as join85, resolve as resolve31 } from "path";
145725
145675
 
145726
145676
  // src/config/scaffold-manifest.ts
145727
145677
  var SCAFFOLD_MANIFEST = [
@@ -145750,8 +145700,8 @@ var SCAFFOLD_MANIFEST = [
145750
145700
  ];
145751
145701
 
145752
145702
  // src/commands/init.ts
145753
- var GLOBAL_CONFIG_DIR = join84(".config", "spur");
145754
- var GLOBAL_RULES_DIR2 = join84(GLOBAL_CONFIG_DIR, "rules");
145703
+ var GLOBAL_CONFIG_DIR = join85(".config", "spur");
145704
+ var GLOBAL_RULES_DIR2 = join85(GLOBAL_CONFIG_DIR, "rules");
145755
145705
  var GLOBAL_CONFIG_EXAMPLE = BUNDLED_GLOBAL_CONFIG;
145756
145706
  var GLOBAL_CONFIG_FILE2 = "config.yaml";
145757
145707
  var INDEXED_CONTEXT_MARKER = "## Indexed context";
@@ -145782,7 +145732,7 @@ If \`.spur/context/\` is absent, proceed normally. Never block work on its absen
145782
145732
  `;
145783
145733
  function globalRulesRoot(context) {
145784
145734
  const override = context.env.SPUR_GLOBAL_RULES_DIR;
145785
- return override !== undefined && override.length > 0 ? resolve31(context.cwd, override) : join84(homedir15(), GLOBAL_RULES_DIR2);
145735
+ return override !== undefined && override.length > 0 ? resolve31(context.cwd, override) : join85(homedir15(), GLOBAL_RULES_DIR2);
145786
145736
  }
145787
145737
  async function writeIfNew(context, path, content, force, result) {
145788
145738
  if (!force && await context.fs.exists(path)) {
@@ -145799,18 +145749,18 @@ async function seedGlobalRules(context) {
145799
145749
  const target = globalRulesRoot(context);
145800
145750
  let written = 0;
145801
145751
  for (const relPath of await listBundledRuleFiles()) {
145802
- const destination = join84(target, relPath);
145752
+ const destination = join85(target, relPath);
145803
145753
  if (await context.fs.exists(destination))
145804
145754
  continue;
145805
- await context.fs.ensureDir(join84(target, ...relPath.split("/").slice(0, -1)));
145806
- await context.fs.writeFile(destination, await context.fs.readFile(join84(source, relPath)));
145755
+ await context.fs.ensureDir(join85(target, ...relPath.split("/").slice(0, -1)));
145756
+ await context.fs.writeFile(destination, await context.fs.readFile(join85(source, relPath)));
145807
145757
  written += 1;
145808
145758
  }
145809
145759
  return written;
145810
145760
  }
145811
145761
  function resolveGlobalConfigDir(context) {
145812
145762
  const globalOverride = context.env.SPUR_GLOBAL_RULES_DIR;
145813
- return globalOverride !== undefined && globalOverride.length > 0 ? resolve31(context.cwd, globalOverride) : join84(homedir15(), GLOBAL_CONFIG_DIR);
145763
+ return globalOverride !== undefined && globalOverride.length > 0 ? resolve31(context.cwd, globalOverride) : join85(homedir15(), GLOBAL_CONFIG_DIR);
145814
145764
  }
145815
145765
  async function seedGlobalConfig(context) {
145816
145766
  const source = bundledConfigRoot();
@@ -145821,15 +145771,15 @@ async function seedGlobalConfig(context) {
145821
145771
  for (const relPath of listBundledConfigFiles()) {
145822
145772
  if (relPath === GLOBAL_CONFIG_EXAMPLE)
145823
145773
  continue;
145824
- const destination = join84(target, relPath);
145774
+ const destination = join85(target, relPath);
145825
145775
  if (await context.fs.exists(destination))
145826
145776
  continue;
145827
- await context.fs.ensureDir(join84(target, ...relPath.split("/").slice(0, -1)));
145828
- await context.fs.writeFile(destination, await context.fs.readFile(join84(source, relPath)));
145777
+ await context.fs.ensureDir(join85(target, ...relPath.split("/").slice(0, -1)));
145778
+ await context.fs.writeFile(destination, await context.fs.readFile(join85(source, relPath)));
145829
145779
  written += 1;
145830
145780
  }
145831
- const examplePath = join84(source, GLOBAL_CONFIG_EXAMPLE);
145832
- const globalConfigPath = join84(target, GLOBAL_CONFIG_FILE2);
145781
+ const examplePath = join85(source, GLOBAL_CONFIG_EXAMPLE);
145782
+ const globalConfigPath = join85(target, GLOBAL_CONFIG_FILE2);
145833
145783
  if (await context.fs.exists(examplePath) && !await context.fs.exists(globalConfigPath)) {
145834
145784
  await context.fs.ensureDir(target);
145835
145785
  await context.fs.writeFile(globalConfigPath, await context.fs.readFile(examplePath));
@@ -145844,10 +145794,10 @@ function registerInitCommand(program, context, options = {}) {
145844
145794
  const minimal = options.minimal === true;
145845
145795
  const adoptGlobal = options.adoptGlobalConfig === true;
145846
145796
  const projectName = options.name ?? "default";
145847
- const configPath = join84(context.cwd, CLI_CONFIG.configFile);
145797
+ const configPath = join85(context.cwd, CLI_CONFIG.configFile);
145848
145798
  const result = { created: [], skipped: [] };
145849
145799
  const globalConfigDir = resolveGlobalConfigDir(context);
145850
- const globalConfigPath = join84(globalConfigDir, GLOBAL_CONFIG_FILE2);
145800
+ const globalConfigPath = join85(globalConfigDir, GLOBAL_CONFIG_FILE2);
145851
145801
  const globalConfigExists = await context.fs.exists(globalConfigPath);
145852
145802
  let misplacedKeys = [];
145853
145803
  if (globalConfigExists) {
@@ -145860,20 +145810,20 @@ function registerInitCommand(program, context, options = {}) {
145860
145810
  const configRoot = bundledConfigRoot();
145861
145811
  if (configRoot !== null && !minimal) {
145862
145812
  for (const relPath of listBundledProjectSeedFiles()) {
145863
- const sourcePath = join84(configRoot, relPath);
145813
+ const sourcePath = join85(configRoot, relPath);
145864
145814
  if (!await context.fs.exists(sourcePath))
145865
145815
  continue;
145866
- const targetPath = join84(context.cwd, CLI_CONFIG.configDir, relPath);
145867
- await context.fs.ensureDir(join84(targetPath, ".."));
145816
+ const targetPath = join85(context.cwd, CLI_CONFIG.configDir, relPath);
145817
+ await context.fs.ensureDir(join85(targetPath, ".."));
145868
145818
  await writeIfNew(context, targetPath, await context.fs.readFile(sourcePath), false, result);
145869
145819
  }
145870
145820
  for (const entry of SCAFFOLD_MANIFEST) {
145871
- const sourcePath = join84(configRoot, entry.source);
145821
+ const sourcePath = join85(configRoot, entry.source);
145872
145822
  if (!await context.fs.exists(sourcePath))
145873
145823
  continue;
145874
- const baseDir = entry.root === true ? context.cwd : join84(context.cwd, CLI_CONFIG.configDir);
145875
- const targetPath = join84(baseDir, entry.target);
145876
- await context.fs.ensureDir(join84(targetPath, ".."));
145824
+ const baseDir = entry.root === true ? context.cwd : join85(context.cwd, CLI_CONFIG.configDir);
145825
+ const targetPath = join85(baseDir, entry.target);
145826
+ await context.fs.ensureDir(join85(targetPath, ".."));
145877
145827
  const entryForce = false;
145878
145828
  let body = await context.fs.readFile(sourcePath);
145879
145829
  if (entry.target === "AGENTS.md") {
@@ -145890,7 +145840,7 @@ function registerInitCommand(program, context, options = {}) {
145890
145840
  const backupPath = `${globalConfigPath}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
145891
145841
  await context.fs.writeFile(backupPath, await context.fs.readFile(globalConfigPath));
145892
145842
  const bundledRoot = bundledConfigRoot();
145893
- const examplePath = bundledRoot !== null ? join84(bundledRoot, GLOBAL_CONFIG_EXAMPLE) : null;
145843
+ const examplePath = bundledRoot !== null ? join85(bundledRoot, GLOBAL_CONFIG_EXAMPLE) : null;
145894
145844
  if (examplePath !== null && await context.fs.exists(examplePath)) {
145895
145845
  await context.fs.writeFile(globalConfigPath, await context.fs.readFile(examplePath));
145896
145846
  adoptedGlobal = true;
@@ -145963,13 +145913,13 @@ function registerInitCommand(program, context, options = {}) {
145963
145913
  ].join(`
145964
145914
  `)}
145965
145915
  `;
145966
- await context.fs.ensureDir(join84(context.cwd, CLI_CONFIG.configDir));
145916
+ await context.fs.ensureDir(join85(context.cwd, CLI_CONFIG.configDir));
145967
145917
  await context.fs.writeFile(configPath, configYaml);
145968
145918
  result.created.push(configPath);
145969
- const agentsDir = join84(context.cwd, CLI_CONFIG.configDir, "agents");
145919
+ const agentsDir = join85(context.cwd, CLI_CONFIG.configDir, "agents");
145970
145920
  await context.fs.ensureDir(agentsDir);
145971
- await writeIfNew(context, join84(agentsDir, ".gitkeep"), "", force, result);
145972
- const gitignorePath = join84(context.cwd, ".gitignore");
145921
+ await writeIfNew(context, join85(agentsDir, ".gitkeep"), "", force, result);
145922
+ const gitignorePath = join85(context.cwd, ".gitignore");
145973
145923
  const contextEntry = ".spur/context/";
145974
145924
  if (await context.fs.exists(gitignorePath)) {
145975
145925
  const existing = await context.fs.readFile(gitignorePath);
@@ -145989,20 +145939,20 @@ ${contextEntry}
145989
145939
  const configRoot = bundledConfigRoot();
145990
145940
  if (configRoot !== null) {
145991
145941
  for (const relPath of listBundledProjectSeedFiles()) {
145992
- const sourcePath = join84(configRoot, relPath);
145942
+ const sourcePath = join85(configRoot, relPath);
145993
145943
  if (!await context.fs.exists(sourcePath))
145994
145944
  continue;
145995
- const targetPath = join84(context.cwd, CLI_CONFIG.configDir, relPath);
145996
- await context.fs.ensureDir(join84(targetPath, ".."));
145945
+ const targetPath = join85(context.cwd, CLI_CONFIG.configDir, relPath);
145946
+ await context.fs.ensureDir(join85(targetPath, ".."));
145997
145947
  await writeIfNew(context, targetPath, await context.fs.readFile(sourcePath), force, result);
145998
145948
  }
145999
145949
  for (const entry of SCAFFOLD_MANIFEST) {
146000
- const sourcePath = join84(configRoot, entry.source);
145950
+ const sourcePath = join85(configRoot, entry.source);
146001
145951
  if (!await context.fs.exists(sourcePath))
146002
145952
  continue;
146003
- const baseDir = entry.root === true ? context.cwd : join84(context.cwd, CLI_CONFIG.configDir);
146004
- const targetPath = join84(baseDir, entry.target);
146005
- await context.fs.ensureDir(join84(targetPath, ".."));
145953
+ const baseDir = entry.root === true ? context.cwd : join85(context.cwd, CLI_CONFIG.configDir);
145954
+ const targetPath = join85(baseDir, entry.target);
145955
+ await context.fs.ensureDir(join85(targetPath, ".."));
146006
145956
  const entryForce = entry.preserve === true ? false : force;
146007
145957
  let body = await context.fs.readFile(sourcePath);
146008
145958
  if (entry.target === "AGENTS.md") {
@@ -146015,7 +145965,7 @@ ${contextEntry}
146015
145965
  }
146016
145966
  }
146017
145967
  }
146018
- const agentsMdPath = join84(context.cwd, "AGENTS.md");
145968
+ const agentsMdPath = join85(context.cwd, "AGENTS.md");
146019
145969
  if (await context.fs.exists(agentsMdPath)) {
146020
145970
  const existing = await context.fs.readFile(agentsMdPath);
146021
145971
  if (!existing.includes(INDEXED_CONTEXT_MARKER)) {
@@ -146056,11 +146006,11 @@ ${contextEntry}
146056
146006
  // src/commands/maintain.ts
146057
146007
  init_src();
146058
146008
  init_src2();
146059
- import { join as join85 } from "path";
146009
+ import { join as join86 } from "path";
146060
146010
  function registerMaintainCommand(program, context, options = {}) {
146061
146011
  program.command("maintain", { hidden: options.hidden === true }).summary("run database maintenance (optimize, WAL checkpoint truncation, optional VACUUM)").description("Run database maintenance: PRAGMA optimize, WAL checkpoint truncation; optionally VACUUM compaction.").option("--vacuum", "Run VACUUM defragmentation and page compaction", false).option(...SHARED_OPTIONS.jsonSupported).option(...SHARED_OPTIONS.jsonEnvelope).action(async (options) => {
146062
146012
  const db = await context.getDb();
146063
- const dbPath = context.env.DATABASE_URL ?? join85(context.cwd, DEFAULT_DATABASE_URL);
146013
+ const dbPath = context.env.DATABASE_URL ?? join86(context.cwd, DEFAULT_DATABASE_URL);
146064
146014
  const result = await maintainDatabase(db, {
146065
146015
  vacuum: options.vacuum === true,
146066
146016
  dbPath: dbPath.startsWith(":memory:") ? undefined : dbPath
@@ -146484,14 +146434,14 @@ async function waitForPendingDrain(agentService, coordination, pin, timeoutMs, s
146484
146434
 
146485
146435
  // src/commands/migrate.ts
146486
146436
  init_src2();
146487
- import { join as join87, relative as relative18 } from "path";
146437
+ import { join as join88, relative as relative18 } from "path";
146488
146438
 
146489
146439
  // src/context.ts
146490
146440
  init_src3();
146491
146441
  init_src();
146492
146442
  init_src2();
146493
146443
  init_dist5();
146494
- import { dirname as dirname41, join as join86, resolve as resolve32 } from "path";
146444
+ import { dirname as dirname41, join as join87, resolve as resolve32 } from "path";
146495
146445
  import { isatty as isatty4 } from "tty";
146496
146446
 
146497
146447
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -147476,7 +147426,7 @@ function createCliContext(options) {
147476
147426
  }
147477
147427
  function noopSetExitCode(_code) {}
147478
147428
  function resolveDatabaseUrl(cwd, env) {
147479
- return env.DATABASE_URL === undefined ? join86(cwd, DEFAULT_DATABASE_URL) : buildConfigFromEnv(env).database.url;
147429
+ return env.DATABASE_URL === undefined ? join87(cwd, DEFAULT_DATABASE_URL) : buildConfigFromEnv(env).database.url;
147480
147430
  }
147481
147431
  async function createMigratedDbAdapter(cwd = process.cwd(), env = getEnvVars(), dbUrl) {
147482
147432
  const url = dbUrl ?? resolveDatabaseUrl(cwd, env);
@@ -147539,7 +147489,7 @@ function registerMigrateCommand(program, context, options = {}) {
147539
147489
  context.setExitCode(1);
147540
147490
  return;
147541
147491
  }
147542
- const migrations = await loadSqlMigrations(join87(context.cwd, "drizzle")).catch(() => {
147492
+ const migrations = await loadSqlMigrations(join88(context.cwd, "drizzle")).catch(() => {
147543
147493
  return;
147544
147494
  });
147545
147495
  const db = await context.getDb();
@@ -147554,22 +147504,28 @@ function registerMigrateCommand(program, context, options = {}) {
147554
147504
  init_src3();
147555
147505
  init_src2();
147556
147506
  init_dist5();
147557
- import { basename as basename19, dirname as dirname42, join as join88, resolve as resolve33 } from "path";
147507
+ import { basename as basename19, dirname as dirname42, join as join89, resolve as resolve33 } from "path";
147558
147508
  function registerProjectsCommand(program, context) {
147559
147509
  const projectsCmd = program.command("projects").summary("manage the Spur multi-project registry");
147560
- projectsCmd.command("add").argument("<path>", "Project root directory path").option(...SHARED_OPTIONS.nameProjectDisplay).option(...SHARED_OPTIONS.jsonProjectsResponse).option(...SHARED_OPTIONS.jsonEnvelope).action(async (pathArg, options) => {
147510
+ projectsCmd.command("add").argument("<path>", "Project root directory path").option("--host <host>", 'Host for local or remote project (default: "localhost")').option(...SHARED_OPTIONS.nameProjectDisplay).option(...SHARED_OPTIONS.jsonProjectsResponse).option(...SHARED_OPTIONS.jsonEnvelope).action(async (pathArg, options) => {
147561
147511
  try {
147562
- const absolutePath = resolve33(context.cwd, pathArg);
147563
- if (!await context.fs.exists(absolutePath)) {
147564
- throw new Error(`Directory does not exist: ${absolutePath}`);
147512
+ const host = options.host ?? "localhost";
147513
+ const isLocal = isLocalHost(host);
147514
+ let absolutePath = pathArg;
147515
+ if (isLocal) {
147516
+ absolutePath = resolve33(context.cwd, pathArg);
147517
+ if (!await context.fs.exists(absolutePath)) {
147518
+ throw new Error(`Directory does not exist: ${absolutePath}`);
147519
+ }
147565
147520
  }
147566
147521
  const name = options.name ?? basename19(absolutePath);
147567
147522
  const registry = new ProjectRegistry;
147568
- const entry = await registry.upsert({ path: absolutePath, name, port: 0 });
147523
+ const entry = await registry.upsert({ path: absolutePath, name, host, port: 0 });
147569
147524
  if (options.json) {
147570
147525
  context.output.write(toEnvelopeJson({ ok: true, project: entry }, { enveloped: options.jsonEnvelope }));
147571
147526
  } else {
147572
- context.output.write(`Registered project "${entry.name}" at ${entry.path}`);
147527
+ const hostLabel = !isLocalHost(entry.host) ? ` on host ${entry.host}` : "";
147528
+ context.output.write(`Registered project "${entry.name}" at ${entry.path}${hostLabel}`);
147573
147529
  }
147574
147530
  } catch (err) {
147575
147531
  const message = err instanceof Error ? err.message : String(err);
@@ -147614,14 +147570,17 @@ function registerProjectsCommand(program, context) {
147614
147570
  ok: true,
147615
147571
  purgedCount: result.purgedProjects.length,
147616
147572
  purgedProjects: result.purgedProjects,
147617
- terminatedProcesses: result.terminatedProcesses
147573
+ terminatedProcesses: result.terminatedProcesses,
147574
+ ...result.resetPorts && result.resetPorts.length > 0 ? { resetPorts: result.resetPorts } : {}
147618
147575
  }, { enveloped: options.jsonEnvelope }));
147619
- } else if (result.purgedProjects.length === 0) {
147576
+ } else if (result.purgedProjects.length === 0 && (!result.resetPorts || result.resetPorts.length === 0)) {
147620
147577
  context.output.write("Registry is clean. No stale project entries found.");
147621
147578
  } else {
147622
- context.output.write(`Purged ${result.purgedProjects.length} stale project(s):`);
147623
- for (const project of result.purgedProjects) {
147624
- context.output.write(`- ${project.name} (${project.path})`);
147579
+ if (result.purgedProjects.length > 0) {
147580
+ context.output.write(`Purged ${result.purgedProjects.length} stale project(s):`);
147581
+ for (const project of result.purgedProjects) {
147582
+ context.output.write(`- ${project.name} (${project.path})`);
147583
+ }
147625
147584
  }
147626
147585
  if (result.terminatedProcesses.length > 0) {
147627
147586
  context.output.write(`Terminated ${result.terminatedProcesses.length} lingering process(es):`);
@@ -147629,6 +147588,13 @@ function registerProjectsCommand(program, context) {
147629
147588
  context.output.write(`- PID ${proc.pid} on port ${proc.port} (${proc.signal})`);
147630
147589
  }
147631
147590
  }
147591
+ if (result.resetPorts && result.resetPorts.length > 0) {
147592
+ context.output.write(`Reset ${result.resetPorts.length} closed port(s):`);
147593
+ for (const project of result.resetPorts) {
147594
+ const hostLabel = !isLocalHost(project.host) ? `${project.host}:` : "";
147595
+ context.output.write(`- ${project.name} (${hostLabel}${project.port} -> 0)`);
147596
+ }
147597
+ }
147632
147598
  }
147633
147599
  } catch (err) {
147634
147600
  const message = err instanceof Error ? err.message : String(err);
@@ -147646,10 +147612,10 @@ function registerProjectsCommand(program, context) {
147646
147612
  const rawProjects = await registry.list();
147647
147613
  const projects = await Promise.all(rawProjects.map(async (p) => ({
147648
147614
  ...p,
147649
- running: p.port > 0 ? await isPortLive(p.port) : false
147615
+ running: p.port > 0 ? await isPortLive(p.port, undefined, p.host) : false
147650
147616
  })));
147651
147617
  const openProjectDb = async (projectPath) => {
147652
- const url = join88(projectPath, ".spur", "spur.db");
147618
+ const url = join89(projectPath, ".spur", "spur.db");
147653
147619
  await context.fs.ensureDir(dirname42(url));
147654
147620
  return createMigratedDb({ url });
147655
147621
  };
@@ -147715,8 +147681,9 @@ function registerProjectsCommand(program, context) {
147715
147681
  context.output.write(`Registered Projects:
147716
147682
  `);
147717
147683
  for (const [i, p] of projects.entries()) {
147684
+ const hostLabel = !isLocalHost(p.host) ? ` (${p.host})` : "";
147718
147685
  const status = p.running ? `[RUNNING: ${p.port}]` : "[STOPPED]";
147719
- context.output.write(`- ${p.name} ${status} (${p.path})`);
147686
+ context.output.write(`- ${p.name}${hostLabel} ${status} (${p.path})`);
147720
147687
  const f = fleets?.[i];
147721
147688
  if (f === undefined)
147722
147689
  continue;
@@ -148078,7 +148045,7 @@ function formatTraceDetail(detail) {
148078
148045
  // src/commands/serve.ts
148079
148046
  init_src();
148080
148047
  import { statSync as statSync18 } from "fs";
148081
- import { join as join93, resolve as resolve36 } from "path";
148048
+ import { join as join94, resolve as resolve36 } from "path";
148082
148049
 
148083
148050
  // ../server/src/index.ts
148084
148051
  init_src();
@@ -148089,11 +148056,11 @@ init_src();
148089
148056
  init_loader2();
148090
148057
  init_src2();
148091
148058
  import { homedir as homedir17 } from "os";
148092
- import { basename as basename21, dirname as dirname44, isAbsolute as isAbsolute15, join as join92 } from "path";
148059
+ import { basename as basename21, dirname as dirname44, isAbsolute as isAbsolute15, join as join93 } from "path";
148093
148060
  init_dist5();
148094
148061
 
148095
148062
  // ../server/src/bootstrap.ts
148096
- import { join as join90 } from "path";
148063
+ import { join as join91 } from "path";
148097
148064
 
148098
148065
  // ../../node_modules/.bun/@orpc+shared@1.14.4+e40b0dfdd726a224/node_modules/@orpc/shared/dist/index.mjs
148099
148066
  function resolveMaybeOptionalOptions(rest) {
@@ -154946,9 +154913,9 @@ init_loader2();
154946
154913
  init_src2();
154947
154914
  init_dist5();
154948
154915
  import { homedir as homedir16 } from "os";
154949
- import { basename as basename20, join as join89, relative as relative19, resolve as resolve35 } from "path";
154916
+ import { basename as basename20, join as join90, relative as relative19, resolve as resolve35 } from "path";
154950
154917
  // ../server/package.json
154951
- var version3 = "0.4.9";
154918
+ var version3 = "0.4.10";
154952
154919
 
154953
154920
  // ../server/src/modules/health/index.ts
154954
154921
  var startedAt = Date.now();
@@ -155421,8 +155388,8 @@ var healthModule = {
155421
155388
  }
155422
155389
  });
155423
155390
  }
155424
- const projectPath = join89(ctx.cwd, ".spur", "config.yaml");
155425
- const globalPath = join89(homedir16(), ".config", "spur", "config.yaml");
155391
+ const projectPath = join90(ctx.cwd, ".spur", "config.yaml");
155392
+ const globalPath = join90(homedir16(), ".config", "spur", "config.yaml");
155426
155393
  let projectExists = false;
155427
155394
  let projectContent = "";
155428
155395
  let projectSizeBytes = 0;
@@ -155539,7 +155506,7 @@ var healthModule = {
155539
155506
  const projectRoot = ctx.cwd ?? process.cwd();
155540
155507
  const fs = ctx.fs ?? createNodeFileSystem2(projectRoot);
155541
155508
  const files = [];
155542
- const rootDesignPath = join89(projectRoot, "DESIGN.md");
155509
+ const rootDesignPath = join90(projectRoot, "DESIGN.md");
155543
155510
  if (await fs.exists(rootDesignPath)) {
155544
155511
  let title = "UI/UX Design System";
155545
155512
  try {
@@ -155556,7 +155523,7 @@ var healthModule = {
155556
155523
  category: "root"
155557
155524
  });
155558
155525
  }
155559
- const doc04Path = join89(projectRoot, "docs", "04_DESIGN.md");
155526
+ const doc04Path = join90(projectRoot, "docs", "04_DESIGN.md");
155560
155527
  if (await fs.exists(doc04Path)) {
155561
155528
  let title = "Concrete Surfaces & Contracts";
155562
155529
  try {
@@ -155573,7 +155540,7 @@ var healthModule = {
155573
155540
  category: "architecture"
155574
155541
  });
155575
155542
  }
155576
- const designDir = join89(projectRoot, "docs", "design");
155543
+ const designDir = join90(projectRoot, "docs", "design");
155577
155544
  if (await fs.exists(designDir)) {
155578
155545
  let mdFiles = [];
155579
155546
  try {
@@ -155582,7 +155549,7 @@ var healthModule = {
155582
155549
  } catch {}
155583
155550
  mdFiles.sort((a, b) => a.localeCompare(b));
155584
155551
  for (const filename of mdFiles) {
155585
- const fullPath = join89(designDir, filename);
155552
+ const fullPath = join90(designDir, filename);
155586
155553
  const relPath = `docs/design/${filename}`;
155587
155554
  let title = filename.replace(/\.md$/, "").replace(/-/g, " ");
155588
155555
  try {
@@ -155620,7 +155587,7 @@ var healthModule = {
155620
155587
  try {
155621
155588
  const projectRoot = ctx.cwd ?? process.cwd();
155622
155589
  const fs = ctx.fs ?? createNodeFileSystem2(projectRoot);
155623
- const fullPath = join89(projectRoot, reqPath);
155590
+ const fullPath = join90(projectRoot, reqPath);
155624
155591
  if (!await fs.exists(fullPath)) {
155625
155592
  return c.json({ ok: false, error: "File not found" }, 404);
155626
155593
  }
@@ -155646,7 +155613,7 @@ var healthModule = {
155646
155613
  const projectRoot = ctx.cwd ?? process.cwd();
155647
155614
  const fs = ctx.fs ?? createNodeFileSystem2(projectRoot);
155648
155615
  const files = [];
155649
- const roadmapPath = join89(projectRoot, "docs", "02_ROADMAP.md");
155616
+ const roadmapPath = join90(projectRoot, "docs", "02_ROADMAP.md");
155650
155617
  if (await fs.exists(roadmapPath)) {
155651
155618
  let title = "02 Roadmap \u2014 Spur";
155652
155619
  try {
@@ -155663,7 +155630,7 @@ var healthModule = {
155663
155630
  category: "roadmap"
155664
155631
  });
155665
155632
  }
155666
- const plansDir = join89(projectRoot, "docs", "plans");
155633
+ const plansDir = join90(projectRoot, "docs", "plans");
155667
155634
  if (await fs.exists(plansDir)) {
155668
155635
  let mdFiles = [];
155669
155636
  try {
@@ -155672,7 +155639,7 @@ var healthModule = {
155672
155639
  } catch {}
155673
155640
  mdFiles.sort((a, b) => b.localeCompare(a));
155674
155641
  for (const filename of mdFiles) {
155675
- const fullPath = join89(plansDir, filename);
155642
+ const fullPath = join90(plansDir, filename);
155676
155643
  const relPath = `docs/plans/${filename}`;
155677
155644
  let title = filename.replace(/\.md$/, "").replace(/-/g, " ");
155678
155645
  try {
@@ -155710,7 +155677,7 @@ var healthModule = {
155710
155677
  try {
155711
155678
  const projectRoot = ctx.cwd ?? process.cwd();
155712
155679
  const fs = ctx.fs ?? createNodeFileSystem2(projectRoot);
155713
- const fullPath = join89(projectRoot, reqPath);
155680
+ const fullPath = join90(projectRoot, reqPath);
155714
155681
  if (!await fs.exists(fullPath)) {
155715
155682
  return c.json({ ok: false, error: "File not found" }, 404);
155716
155683
  }
@@ -158224,7 +158191,7 @@ function createApp(appRt, opts) {
158224
158191
  app.use("*", async (c, next) => {
158225
158192
  const pathname = c.req.path === "/" ? "/index.html" : c.req.path;
158226
158193
  try {
158227
- const file = Bun.file(join90(webDistPath, pathname));
158194
+ const file = Bun.file(join91(webDistPath, pathname));
158228
158195
  if (await file.exists()) {
158229
158196
  const headers = new Headers({ "content-type": file.type });
158230
158197
  return new Response(file.stream(), { headers });
@@ -158237,7 +158204,7 @@ function createApp(appRt, opts) {
158237
158204
  return c.json({ error: "Not Found" }, 404);
158238
158205
  }
158239
158206
  try {
158240
- const indexFile = Bun.file(join90(webDistPath, "index.html"));
158207
+ const indexFile = Bun.file(join91(webDistPath, "index.html"));
158241
158208
  if (await indexFile.exists()) {
158242
158209
  return new Response(indexFile.stream(), {
158243
158210
  headers: { "content-type": "text/html; charset=utf-8" }
@@ -158259,7 +158226,7 @@ init_src();
158259
158226
  init_loader2();
158260
158227
  init_src2();
158261
158228
  init_dist5();
158262
- import { dirname as dirname43, join as join91 } from "path";
158229
+ import { dirname as dirname43, join as join92 } from "path";
158263
158230
  var NOOP_OUTPUT = { write: (_s) => {}, error: (_s) => {} };
158264
158231
 
158265
158232
  class LazyPlanningEventEmitter {
@@ -158295,7 +158262,7 @@ class NotConfiguredError extends Error {
158295
158262
  function createServerContext(appRt, options) {
158296
158263
  const cwd = options.cwd;
158297
158264
  const fs = options.fs;
158298
- const dbUrl = options.dbUrl ?? join91(cwd, DEFAULT_DATABASE_URL);
158265
+ const dbUrl = options.dbUrl ?? join92(cwd, DEFAULT_DATABASE_URL);
158299
158266
  const eventsBus = options.eventsBus ?? appRt.events;
158300
158267
  const jobQueueEnabled = options.jobQueueEnabled ?? false;
158301
158268
  const eventProjectContext = systemEventProjectContext(cwd);
@@ -158331,7 +158298,7 @@ function createServerContext(appRt, options) {
158331
158298
  return {
158332
158299
  cwd,
158333
158300
  fs,
158334
- runDir: join91(cwd, ".spur", "run"),
158301
+ runDir: join92(cwd, ".spur", "run"),
158335
158302
  webDistPath: options.webDistPath,
158336
158303
  boardModules: options.boardModules,
158337
158304
  logger: appRt.logger,
@@ -158695,7 +158662,7 @@ var BOARD_RUNTIME_MANIFEST_FILE = "board-runtime.json";
158695
158662
  async function readBoardHostRuntime(webDistPath, hasContributions) {
158696
158663
  if (!webDistPath)
158697
158664
  return null;
158698
- const manifestPath = join92(webDistPath, BOARD_RUNTIME_MANIFEST_FILE);
158665
+ const manifestPath = join93(webDistPath, BOARD_RUNTIME_MANIFEST_FILE);
158699
158666
  try {
158700
158667
  const file = Bun.file(manifestPath);
158701
158668
  if (!await file.exists())
@@ -158732,7 +158699,7 @@ function defaultUsageSnapshotPath(env) {
158732
158699
  const override = env.SPUR_AGENT_USAGE_SNAPSHOT;
158733
158700
  if (override !== undefined && override.length > 0)
158734
158701
  return override;
158735
- return join92(env.HOME ?? homedir17(), ".config", "spur", "agent-usage.json");
158702
+ return join93(env.HOME ?? homedir17(), ".config", "spur", "agent-usage.json");
158736
158703
  }
158737
158704
  var JOB_WORKER_START_DELAY_MS = 30000;
158738
158705
  var defaultDeps = {
@@ -158996,15 +158963,15 @@ async function handleFeatureActionJob(ctx, env, payload) {
158996
158963
  await runFeatureActionJob(ctx, env, payload);
158997
158964
  }
158998
158965
  async function resolveWebDistPath(configuredPath, projectRoot = process.cwd()) {
158999
- const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute15(configuredPath) ? configuredPath : join92(projectRoot, configuredPath)] : [
159000
- join92(projectRoot, "dist/web"),
159001
- join92(import.meta.dir, "web"),
159002
- join92(dirname44(process.execPath), "web"),
159003
- join92(dirname44(process.execPath), "../web"),
159004
- join92(import.meta.dir, "../../../dist/web")
158966
+ const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute15(configuredPath) ? configuredPath : join93(projectRoot, configuredPath)] : [
158967
+ join93(projectRoot, "dist/web"),
158968
+ join93(import.meta.dir, "web"),
158969
+ join93(dirname44(process.execPath), "web"),
158970
+ join93(dirname44(process.execPath), "../web"),
158971
+ join93(import.meta.dir, "../../../dist/web")
159005
158972
  ];
159006
158973
  for (const candidate of candidates) {
159007
- if (await Bun.file(join92(candidate, "index.html")).exists()) {
158974
+ if (await Bun.file(join93(candidate, "index.html")).exists()) {
159008
158975
  return candidate;
159009
158976
  }
159010
158977
  }
@@ -159479,7 +159446,7 @@ var SQLITE_BUSY_MESSAGE_CONSTANTS = Object.freeze({
159479
159446
 
159480
159447
  // src/commands/serve.ts
159481
159448
  function resolveServeDbUrl(cwd, env, configuredUrl) {
159482
- return env.DATABASE_URL === undefined ? join93(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
159449
+ return env.DATABASE_URL === undefined ? join94(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
159483
159450
  }
159484
159451
  function resolveServeCwd(cwd) {
159485
159452
  const resolved = resolve36(cwd);
@@ -159543,7 +159510,7 @@ function registerServeCommand(program, context, options = {}) {
159543
159510
  }
159544
159511
 
159545
159512
  // src/commands/status.ts
159546
- import { join as join94 } from "path";
159513
+ import { join as join95 } from "path";
159547
159514
 
159548
159515
  // src/git-context.ts
159549
159516
  init_dist5();
@@ -159591,8 +159558,8 @@ function registerStatusCommand(program, context, options = {}) {
159591
159558
  }
159592
159559
  async function runStatusCore(path, options, context) {
159593
159560
  const [packageJsonExists, spurConfigExists, git, agentSpecs] = await Promise.all([
159594
- context.fs.exists(join94(context.cwd, "package.json")),
159595
- context.fs.exists(join94(context.cwd, ".spur", "config.yaml")),
159561
+ context.fs.exists(join95(context.cwd, "package.json")),
159562
+ context.fs.exists(join95(context.cwd, ".spur", "config.yaml")),
159596
159563
  gitContext(context.cwd),
159597
159564
  listAgentSpecIds(context)
159598
159565
  ]);
@@ -159623,14 +159590,14 @@ async function runStatusCore(path, options, context) {
159623
159590
  return status.ok ? 0 : 1;
159624
159591
  }
159625
159592
  async function listAgentSpecIds(context) {
159626
- const dir = join94(context.cwd, ".spur", "agents");
159593
+ const dir = join95(context.cwd, ".spur", "agents");
159627
159594
  if (!await context.fs.exists(dir))
159628
159595
  return [];
159629
159596
  const entries = await context.fs.readDir(dir);
159630
159597
  return entries.filter((entry) => entry.endsWith(".yaml") || entry.endsWith(".yml")).map((entry) => entry.replace(/\.ya?ml$/, "")).sort();
159631
159598
  }
159632
159599
  async function readTargetStatus(context, targetPath) {
159633
- const resolved = join94(context.cwd, targetPath);
159600
+ const resolved = join95(context.cwd, targetPath);
159634
159601
  const stat = await context.fs.stat(resolved);
159635
159602
  if (stat === null)
159636
159603
  throw new CommandError(`status failed: path does not exist at ${resolved}`);
@@ -159881,11 +159848,11 @@ function registerWorkflowCleanCommand(workflow, context) {
159881
159848
  // ../../packages/app/src/workflow/commit-guard.ts
159882
159849
  init_dist5();
159883
159850
  import { mkdirSync as mkdirSync23, readFileSync as readFileSync28, renameSync as renameSync11, writeFileSync as writeFileSync20 } from "fs";
159884
- import { join as join95 } from "path";
159851
+ import { join as join96 } from "path";
159885
159852
  var COMMIT_GUARD_USAGE = "usage: spur workflow commit-guard start --run <id> | stage --run <id> [--base <sha>] -- <paths\u2026> | check --run <id> [--base <sha>]";
159886
159853
  var isBookkeeping = (path) => path === ".spur" || path.startsWith(".spur/");
159887
- var at2 = (options, rel) => options.cwd ? join95(options.cwd, rel) : rel;
159888
- var artifactPath = (run) => join95(".spur", "run", `${run}-tree-start.json`);
159854
+ var at2 = (options, rel) => options.cwd ? join96(options.cwd, rel) : rel;
159855
+ var artifactPath = (run) => join96(".spur", "run", `${run}-tree-start.json`);
159889
159856
  function gitOf(options) {
159890
159857
  if (options.git)
159891
159858
  return options.git;
@@ -159954,7 +159921,7 @@ function runContext(run, options) {
159954
159921
  let base = options.base ?? "";
159955
159922
  if (!base) {
159956
159923
  try {
159957
- const anchored = readFileSync28(at2(options, join95(".spur", "run", `${run}-base.sha`)), "utf8").trim();
159924
+ const anchored = readFileSync28(at2(options, join96(".spur", "run", `${run}-base.sha`)), "utf8").trim();
159958
159925
  if (/^[0-9a-f]{7,40}$/i.test(anchored))
159959
159926
  base = anchored;
159960
159927
  } catch {}
@@ -159994,7 +159961,7 @@ function commitGuardStart(run, options = {}) {
159994
159961
  dirty: parsePorcelainZ(status.stdout).map((path) => ({ path, sha: hashPath(path, git) }))
159995
159962
  };
159996
159963
  const abs = at2(options, artifactPath(run));
159997
- mkdirSync23(join95(abs, ".."), { recursive: true });
159964
+ mkdirSync23(join96(abs, ".."), { recursive: true });
159998
159965
  writeFileSync20(`${abs}.tmp`, `${JSON.stringify(snapshot, null, 2)}
159999
159966
  `);
160000
159967
  renameSync11(`${abs}.tmp`, abs);
@@ -160266,14 +160233,14 @@ function registerWorkflowContinueCommand(workflow, context) {
160266
160233
  }
160267
160234
 
160268
160235
  // src/commands/workflow/cost.ts
160269
- import { join as join97 } from "path";
160236
+ import { join as join98 } from "path";
160270
160237
 
160271
160238
  // ../../packages/app/src/workflow/run-cost.ts
160272
160239
  init_src2();
160273
160240
  init_dist5();
160274
160241
  init_dist2();
160275
160242
  init_composition_baseline();
160276
- import { join as join96 } from "path";
160243
+ import { join as join97 } from "path";
160277
160244
 
160278
160245
  // ../../packages/app/src/workflow/run-measurements.ts
160279
160246
  init_src2();
@@ -160507,7 +160474,7 @@ async function loadQueryCounts(workflowsDir, fs = createNodeFileSystem2()) {
160507
160474
  const name = /^(.+)\.ya?ml$/.exec(entry)?.[1];
160508
160475
  if (!name)
160509
160476
  continue;
160510
- const def = $parse(await fs.readFile(join96(workflowsDir, entry)));
160477
+ const def = $parse(await fs.readFile(join97(workflowsDir, entry)));
160511
160478
  out[name] = extractResolvedWorkflowFacts(def).modelQueries.length;
160512
160479
  }
160513
160480
  return out;
@@ -160533,7 +160500,7 @@ async function runBudgetGate(opts) {
160533
160500
  const fs = opts.fs ?? createNodeFileSystem2();
160534
160501
  const gitShow = opts.gitShow ?? defaultGitShow;
160535
160502
  const openDb = opts.openDb ?? defaultDbOpener;
160536
- const absBudget = opts.budgetPath.startsWith("/") ? opts.budgetPath : join96(opts.cwd, opts.budgetPath);
160503
+ const absBudget = opts.budgetPath.startsWith("/") ? opts.budgetPath : join97(opts.cwd, opts.budgetPath);
160537
160504
  const relBudget = absBudget.startsWith(`${opts.cwd}/`) ? absBudget.slice(opts.cwd.length + 1) : opts.budgetPath;
160538
160505
  const config = await loadPipelineBudgets(absBudget, fs);
160539
160506
  let head = null;
@@ -160549,7 +160516,7 @@ async function runBudgetGate(opts) {
160549
160516
  const queryCounts = await loadQueryCounts(opts.workflowsDir, fs);
160550
160517
  let measured;
160551
160518
  if (opts.measuredFile !== undefined) {
160552
- const measuredPath = opts.measuredFile.startsWith("/") ? opts.measuredFile : join96(opts.cwd, opts.measuredFile);
160519
+ const measuredPath = opts.measuredFile.startsWith("/") ? opts.measuredFile : join97(opts.cwd, opts.measuredFile);
160553
160520
  measured = JSON.parse(await fs.readFile(measuredPath));
160554
160521
  } else if (!await fs.exists(opts.dbPath)) {
160555
160522
  measured = {};
@@ -160598,8 +160565,8 @@ function registerWorkflowCostCommand(workflow, context, deps = {}) {
160598
160565
  ].join(`
160599
160566
  `)).option("--workflow <name>", "restrict to a workflow (repeatable)", collect3, []).option("--by-state", "report per-state rows instead of per-workflow rows").option("--include-bookkeeping", "keep bookkeeping workflows in the default cohort").option("--since <YYYY-MM-DD>", "only runs created on/after this UTC date").option("--budget <file>", "run the pipeline budget gate against this budget file").option("--measured-file <json>", "with --budget: read measured values from this file instead of the DB").option(...SHARED_OPTIONS.json).action(async (options) => {
160600
160567
  const cwd = context.cwd;
160601
- const dbPath = join97(cwd, ".spur/spur.db");
160602
- const workflowsDir = join97(cwd, ".spur", "workflows");
160568
+ const dbPath = join98(cwd, ".spur/spur.db");
160569
+ const workflowsDir = join98(cwd, ".spur", "workflows");
160603
160570
  const openDb = deps.openDb ?? defaultDbOpener;
160604
160571
  try {
160605
160572
  if (options.budget !== undefined) {
@@ -160663,9 +160630,9 @@ init_run_summary_render();
160663
160630
  // ../../packages/app/src/workflow/persist-check.ts
160664
160631
  init_dist5();
160665
160632
  import { existsSync as existsSync33, readdirSync as readdirSync15, readFileSync as readFileSync30, statSync as statSync19 } from "fs";
160666
- import { basename as basename22, dirname as dirname45, isAbsolute as isAbsolute16, join as join99, relative as relative20, resolve as resolve37 } from "path";
160667
- var EVIDENCE_DIR = join99(".spur", "memory", "evidence");
160668
- var RUN_DIR = join99(".spur", "run");
160633
+ import { basename as basename22, dirname as dirname45, isAbsolute as isAbsolute16, join as join100, relative as relative20, resolve as resolve37 } from "path";
160634
+ var EVIDENCE_DIR = join100(".spur", "memory", "evidence");
160635
+ var RUN_DIR = join100(".spur", "run");
160669
160636
  var NAMED_CAP = 32;
160670
160637
  var PREFIX_CAP = 64;
160671
160638
  var DURABLE_FAMILY_RE = /^\d{4}-(?:verdict|feature-verification)\.json$/;
@@ -160680,7 +160647,7 @@ function walkFiles(dir, root) {
160680
160647
  const out = [];
160681
160648
  const walk = (cur) => {
160682
160649
  for (const e of readdirSync15(cur, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
160683
- const p = join99(cur, e.name);
160650
+ const p = join100(cur, e.name);
160684
160651
  if (e.isDirectory())
160685
160652
  walk(p);
160686
160653
  else if (e.isFile())
@@ -160707,8 +160674,8 @@ function listObligations(wtRoot, wbsList, runIds) {
160707
160674
  const prefixes = [...new Set([...wbsList, ...runIds].filter(Boolean))];
160708
160675
  if (prefixes.length === 0)
160709
160676
  return null;
160710
- const evFiles = walkFiles(join99(wtRoot, EVIDENCE_DIR), wtRoot);
160711
- const runFiles = walkFiles(join99(wtRoot, RUN_DIR), wtRoot);
160677
+ const evFiles = walkFiles(join100(wtRoot, EVIDENCE_DIR), wtRoot);
160678
+ const runFiles = walkFiles(join100(wtRoot, RUN_DIR), wtRoot);
160712
160679
  const files = [];
160713
160680
  const counts = new Map;
160714
160681
  if (!collectOwned(evFiles, prefixes, counts, files))
@@ -160725,13 +160692,13 @@ function compareTrees(wtRoot, invokeRoot, files, foreignDivergent = new Set) {
160725
160692
  for (const rel of files) {
160726
160693
  if (foreignDivergent.has(rel) || foreignDivergent.has(basename22(rel)))
160727
160694
  continue;
160728
- const invPath = join99(invokeRoot, rel);
160695
+ const invPath = join100(invokeRoot, rel);
160729
160696
  if (!existsSync33(invPath)) {
160730
160697
  missing.push(rel);
160731
160698
  continue;
160732
160699
  }
160733
160700
  try {
160734
- if (readFileSync30(join99(wtRoot, rel)).equals(readFileSync30(invPath)))
160701
+ if (readFileSync30(join100(wtRoot, rel)).equals(readFileSync30(invPath)))
160735
160702
  ok++;
160736
160703
  else
160737
160704
  divergent.push(rel);
@@ -160748,7 +160715,7 @@ function defaultInvokeRoot(cwd) {
160748
160715
  });
160749
160716
  const common = run.stdout.trim();
160750
160717
  if (run.exitCode === 0 && common)
160751
- return dirname45(isAbsolute16(common) ? common : join99(cwd, common));
160718
+ return dirname45(isAbsolute16(common) ? common : join100(cwd, common));
160752
160719
  return cwd;
160753
160720
  }
160754
160721
  function readPersistOutSkips(candidates) {
@@ -160763,7 +160730,7 @@ function readPersistOutSkips(candidates) {
160763
160730
  for (const item of parsed.evidenceSkipped) {
160764
160731
  if (item.reason === "foreign-divergent" && typeof item.name === "string") {
160765
160732
  foreignDivergent.add(item.name);
160766
- foreignDivergent.add(join99(EVIDENCE_DIR, item.name));
160733
+ foreignDivergent.add(join100(EVIDENCE_DIR, item.name));
160767
160734
  }
160768
160735
  }
160769
160736
  }
@@ -160796,8 +160763,8 @@ function runPersistCheck(input) {
160796
160763
  const invokeRoot = input.root === undefined ? defaultInvokeRoot(input.cwd) : resolve37(input.cwd, input.root);
160797
160764
  const { foreignDivergent, skips } = readPersistOutSkips([
160798
160765
  input.successJson === undefined || input.successJson === "" ? "" : resolve37(input.cwd, input.successJson),
160799
- join99(invokeRoot, ".spur", "run", "persist-out.json"),
160800
- join99(wtRoot, ".spur", "run", "persist-out.json")
160766
+ join100(invokeRoot, ".spur", "run", "persist-out.json"),
160767
+ join100(wtRoot, ".spur", "run", "persist-out.json")
160801
160768
  ].filter(Boolean));
160802
160769
  const obligations = listObligations(wtRoot, wbsList, runIds);
160803
160770
  if (obligations === null) {
@@ -161166,7 +161133,7 @@ init_src3();
161166
161133
  init_capability_attestation();
161167
161134
  init_src();
161168
161135
  init_dist7();
161169
- import { join as join100 } from "path";
161136
+ import { join as join101 } from "path";
161170
161137
  import { createInterface } from "readline";
161171
161138
  import { setTimeout as sleep6 } from "timers/promises";
161172
161139
  var WORKFLOW_RUN_ACTIVE_ENV = "SPUR_WORKFLOW_RUN_ACTIVE";
@@ -161270,9 +161237,9 @@ async function writeWorkflowPlanArtifact(cwd, runId, resolved, secretValues, sta
161270
161237
  }))
161271
161238
  });
161272
161239
  const { mkdir, writeFile } = await import("fs/promises");
161273
- const artifactsDir = join100(cwd, ".spur", "run");
161240
+ const artifactsDir = join101(cwd, ".spur", "run");
161274
161241
  await mkdir(artifactsDir, { recursive: true });
161275
- const artifactPath = join100(artifactsDir, `${runId}-workflow-plan.json`);
161242
+ const artifactPath = join101(artifactsDir, `${runId}-workflow-plan.json`);
161276
161243
  await writeFile(artifactPath, payload);
161277
161244
  return artifactPath;
161278
161245
  }
@@ -161743,7 +161710,7 @@ function registerWorkflowSummaryCommand(workflow, context) {
161743
161710
  // src/commands/workflow/trace.ts
161744
161711
  init_src3();
161745
161712
  import { closeSync as closeSync11, fstatSync as fstatSync5, openSync as openSync11, readFileSync as readFileSync32, readSync as readSync3 } from "fs";
161746
- import { join as join101 } from "path";
161713
+ import { join as join102 } from "path";
161747
161714
  import { setTimeout as sleep7 } from "timers/promises";
161748
161715
  function formatTraceList2(result) {
161749
161716
  if (result.entries.length === 0) {
@@ -161912,8 +161879,8 @@ function readRunLogChunk(logPath, offset) {
161912
161879
  async function followRunLog(service, runId, dir, pollMs, write, wait = (ms) => sleep7(ms), now = Date.now, deadlineMs) {
161913
161880
  const start = now();
161914
161881
  const deadline = deadlineMs === undefined ? Number.POSITIVE_INFINITY : start + deadlineMs;
161915
- const runDir = join101(dir, ".spur", "run");
161916
- const pendingMdPath = join101(runDir, `${runId}.md`);
161882
+ const runDir = join102(dir, ".spur", "run");
161883
+ const pendingMdPath = join102(runDir, `${runId}.md`);
161917
161884
  let logPath;
161918
161885
  let record = { kind: "missing" };
161919
161886
  let offset = 0;