@runcofactor/cli 0.10.0 → 0.15.0

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 (166) hide show
  1. package/dist/account-22LMP5PX.js +255 -0
  2. package/dist/account-22LMP5PX.js.map +1 -0
  3. package/dist/{api-catalog-GFGCLVS4.js → api-catalog-WTFQNLK6.js} +5 -4
  4. package/dist/{api-catalog-GFGCLVS4.js.map → api-catalog-WTFQNLK6.js.map} +1 -1
  5. package/dist/{attachment-SJC7D7FY.js → attachment-U3NKVPEY.js} +5 -4
  6. package/dist/{attachment-SJC7D7FY.js.map → attachment-U3NKVPEY.js.map} +1 -1
  7. package/dist/augmentor-5GMNAX4M.js +198 -0
  8. package/dist/augmentor-5GMNAX4M.js.map +1 -0
  9. package/dist/{auth-EN6NQCJY.js → auth-VQG2CDUD.js} +3 -2
  10. package/dist/{chunk-A4OFTUVV.js → chunk-3X3NW7QA.js} +7 -4
  11. package/dist/chunk-3X3NW7QA.js.map +1 -0
  12. package/dist/{chunk-N7HFALX3.js → chunk-46IUJXSD.js} +2 -2
  13. package/dist/{chunk-IMPZAX6L.js → chunk-5GD47G2D.js} +37 -1
  14. package/dist/{chunk-IMPZAX6L.js.map → chunk-5GD47G2D.js.map} +1 -1
  15. package/dist/{chunk-B2VISN2V.js → chunk-7VMO2WOZ.js} +238 -68
  16. package/dist/chunk-7VMO2WOZ.js.map +1 -0
  17. package/dist/{chunk-QFDOWABX.js → chunk-CMGI7UZD.js} +6 -3
  18. package/dist/chunk-CMGI7UZD.js.map +1 -0
  19. package/dist/{chunk-XQXVG7RA.js → chunk-FNPMWDUQ.js} +3 -3
  20. package/dist/chunk-G4UYGRZR.js +2 -0
  21. package/dist/{chunk-I4QLI3JO.js → chunk-HDFYUFBI.js} +2 -2
  22. package/dist/chunk-JMJVGMXI.js +92 -0
  23. package/dist/chunk-JMJVGMXI.js.map +1 -0
  24. package/dist/{chunk-SJJW77WN.js → chunk-JYGNMKZ5.js} +129 -38
  25. package/dist/chunk-JYGNMKZ5.js.map +1 -0
  26. package/dist/{chunk-52IO7ACJ.js → chunk-KCHKFYVX.js} +68 -10
  27. package/dist/{chunk-52IO7ACJ.js.map → chunk-KCHKFYVX.js.map} +1 -1
  28. package/dist/{chunk-ZD3KHESI.js → chunk-KRWRUU6R.js} +27 -7
  29. package/dist/chunk-KRWRUU6R.js.map +1 -0
  30. package/dist/{chunk-CLAWT7BJ.js → chunk-NHTEKEYE.js} +3 -3
  31. package/dist/{chunk-WOHL4FTB.js → chunk-PRBRSIZP.js} +16 -10
  32. package/dist/chunk-PRBRSIZP.js.map +1 -0
  33. package/dist/{chunk-GKY2KXO5.js → chunk-UETBLPKM.js} +154 -37
  34. package/dist/chunk-UETBLPKM.js.map +1 -0
  35. package/dist/{chunk-4PNOV7OV.js → chunk-VGYN2KU2.js} +9284 -1421
  36. package/dist/chunk-VGYN2KU2.js.map +1 -0
  37. package/dist/{chunk-Q4BO4Z5V.js → chunk-XJ5YYYGC.js} +4 -4
  38. package/dist/{credential-COLTBV6D.js → credential-E6KUHRGU.js} +24 -20
  39. package/dist/credential-E6KUHRGU.js.map +1 -0
  40. package/dist/{credential-template-EEPYFG7R.js → credential-template-4GPOPBGD.js} +30 -28
  41. package/dist/credential-template-4GPOPBGD.js.map +1 -0
  42. package/dist/{debug-workflow-KOVH5GOP.js → debug-workflow-XCLCY6S7.js} +5 -4
  43. package/dist/{debug-workflow-KOVH5GOP.js.map → debug-workflow-XCLCY6S7.js.map} +1 -1
  44. package/dist/{docs-3SSORHB5.js → docs-COCZYMW6.js} +95 -10
  45. package/dist/docs-COCZYMW6.js.map +1 -0
  46. package/dist/{doctor-OTSIWV6G.js → doctor-ERIVTCQS.js} +9 -5
  47. package/dist/doctor-ERIVTCQS.js.map +1 -0
  48. package/dist/environment-7Y4BV6XY.js +221 -0
  49. package/dist/environment-7Y4BV6XY.js.map +1 -0
  50. package/dist/{feature-flag-T2LRZME3.js → feature-flag-MHONEX6T.js} +164 -16
  51. package/dist/feature-flag-MHONEX6T.js.map +1 -0
  52. package/dist/index.js +123 -58
  53. package/dist/index.js.map +1 -1
  54. package/dist/{init-TGWRECT2.js → init-OROOM4HF.js} +5 -4
  55. package/dist/{init-TGWRECT2.js.map → init-OROOM4HF.js.map} +1 -1
  56. package/dist/{install-DXSNWZKO.js → install-OJFXHY6U.js} +7 -7
  57. package/dist/{issues-XIZOPX6T.js → issues-32GONR6C.js} +5 -4
  58. package/dist/{issues-XIZOPX6T.js.map → issues-32GONR6C.js.map} +1 -1
  59. package/dist/{knobs-NBINZIUB.js → knobs-UQGGY3CP.js} +7 -5
  60. package/dist/knobs-UQGGY3CP.js.map +1 -0
  61. package/dist/{list-3TDHK637.js → list-ZMIKEC5P.js} +5 -4
  62. package/dist/{list-3TDHK637.js.map → list-ZMIKEC5P.js.map} +1 -1
  63. package/dist/{local-HICVD6PU.js → local-PUD24GGQ.js} +7 -6
  64. package/dist/{local-HICVD6PU.js.map → local-PUD24GGQ.js.map} +1 -1
  65. package/dist/{login-UOIUXVUK.js → login-BSO7YX2D.js} +5 -4
  66. package/dist/{login-UOIUXVUK.js.map → login-BSO7YX2D.js.map} +1 -1
  67. package/dist/{mcp-54IJEOUA.js → mcp-4LS7OJUT.js} +24 -25
  68. package/dist/mcp-4LS7OJUT.js.map +1 -0
  69. package/dist/{pdf-extract-ABWV3L5X.js → pdf-extract-YHE54XU4.js} +2 -2
  70. package/dist/product-3JKSJCBC.js +346 -0
  71. package/dist/product-3JKSJCBC.js.map +1 -0
  72. package/dist/{property-UXLOLPTD.js → property-K5DBL4UE.js} +76 -4
  73. package/dist/property-K5DBL4UE.js.map +1 -0
  74. package/dist/{psql-BYUUNLGG.js → psql-PQFUFTSE.js} +3 -2
  75. package/dist/{psql-BYUUNLGG.js.map → psql-PQFUFTSE.js.map} +1 -1
  76. package/dist/{record-4TR2UIIS.js → record-EIIYLFJ4.js} +16 -17
  77. package/dist/record-EIIYLFJ4.js.map +1 -0
  78. package/dist/{redis-35VBUYW7.js → redis-BU36EZZI.js} +3 -2
  79. package/dist/redis-BU36EZZI.js.map +1 -0
  80. package/dist/{release-OOLTUBUT.js → release-LYC2P7DZ.js} +5 -4
  81. package/dist/{release-OOLTUBUT.js.map → release-LYC2P7DZ.js.map} +1 -1
  82. package/dist/{sandbox-XGSUU6G7.js → sandbox-CKHXXZHU.js} +55 -10
  83. package/dist/sandbox-CKHXXZHU.js.map +1 -0
  84. package/dist/{scenarios-GWLJEGHA.js → scenarios-2XJ2G3KR.js} +5 -4
  85. package/dist/{scenarios-GWLJEGHA.js.map → scenarios-2XJ2G3KR.js.map} +1 -1
  86. package/dist/{session-MYFNZPRP.js → session-UTOD5ZYH.js} +77 -10
  87. package/dist/session-UTOD5ZYH.js.map +1 -0
  88. package/dist/{skill-KM34LDMO.js → skill-GMAERMQL.js} +220 -70
  89. package/dist/skill-GMAERMQL.js.map +1 -0
  90. package/dist/skills/debug-run/SKILL.md +40 -23
  91. package/dist/skills/debug-run/history/1.2.0.md +262 -0
  92. package/dist/skills/debug-run/history/1.3.0.md +273 -0
  93. package/dist/skills/debug-run/history/1.3.1.md +279 -0
  94. package/dist/skills/debug-run/version.json +1 -1
  95. package/dist/skills/optimize-cache/SKILL.md +233 -0
  96. package/dist/{spec-RA3CFEKG.js → spec-2NP36U3Y.js} +54 -25
  97. package/dist/spec-2NP36U3Y.js.map +1 -0
  98. package/dist/{src-LB4HBTJQ.js → src-4T6GHXVO.js} +19 -11
  99. package/dist/src-4T6GHXVO.js.map +1 -0
  100. package/dist/{src-N3TPKGTY.js → src-CG52HEE7.js} +10 -7
  101. package/dist/{src-UVDX5UP6.js → src-PK5OZXCM.js} +4 -2
  102. package/dist/src-UEOOC425.js +5941 -0
  103. package/dist/src-UEOOC425.js.map +1 -0
  104. package/dist/{start-PSEQSQA3.js → start-3C7EEFW2.js} +5 -4
  105. package/dist/{start-PSEQSQA3.js.map → start-3C7EEFW2.js.map} +1 -1
  106. package/dist/{tag-YY6YAABQ.js → tag-JSHOMLBR.js} +6 -5
  107. package/dist/{task-IQC3YR5K.js → task-YGWVYTBJ.js} +5 -4
  108. package/dist/{task-IQC3YR5K.js.map → task-YGWVYTBJ.js.map} +1 -1
  109. package/dist/{test-suite-DZNJFXDW.js → test-suite-LI7ZH367.js} +12 -7
  110. package/dist/{test-suite-DZNJFXDW.js.map → test-suite-LI7ZH367.js.map} +1 -1
  111. package/dist/trace-UMLOSIIR.js +16 -0
  112. package/dist/{triage-ORG45R5W.js → triage-ZWJG4NBJ.js} +6 -5
  113. package/dist/triage-ZWJG4NBJ.js.map +1 -0
  114. package/dist/{upgrade-L2VYMP2V.js → upgrade-S7CGEK6H.js} +3 -3
  115. package/dist/{workflow-XYFH5LTP.js → workflow-T4HSAOGW.js} +316 -241
  116. package/dist/workflow-T4HSAOGW.js.map +1 -0
  117. package/dist/{workflow-cache-NQJQFWMV.js → workflow-cache-XVEZ36KF.js} +140 -7
  118. package/dist/workflow-cache-XVEZ36KF.js.map +1 -0
  119. package/dist/{workflow-debug-BGD4UIXU.js → workflow-debug-T2BULXZ7.js} +9 -8
  120. package/dist/{workflow-debug-BGD4UIXU.js.map → workflow-debug-T2BULXZ7.js.map} +1 -1
  121. package/dist/{workflow-proposals-MTUDX46O.js → workflow-proposals-XXEZICN2.js} +5 -6
  122. package/dist/workflow-proposals-XXEZICN2.js.map +1 -0
  123. package/package.json +2 -1
  124. package/dist/chunk-4PNOV7OV.js.map +0 -1
  125. package/dist/chunk-A4OFTUVV.js.map +0 -1
  126. package/dist/chunk-B2VISN2V.js.map +0 -1
  127. package/dist/chunk-GKY2KXO5.js.map +0 -1
  128. package/dist/chunk-JICSYFRJ.js +0 -46
  129. package/dist/chunk-JICSYFRJ.js.map +0 -1
  130. package/dist/chunk-QFDOWABX.js.map +0 -1
  131. package/dist/chunk-SJJW77WN.js.map +0 -1
  132. package/dist/chunk-WOHL4FTB.js.map +0 -1
  133. package/dist/chunk-ZD3KHESI.js.map +0 -1
  134. package/dist/credential-COLTBV6D.js.map +0 -1
  135. package/dist/credential-template-EEPYFG7R.js.map +0 -1
  136. package/dist/docs-3SSORHB5.js.map +0 -1
  137. package/dist/doctor-OTSIWV6G.js.map +0 -1
  138. package/dist/feature-flag-T2LRZME3.js.map +0 -1
  139. package/dist/knobs-NBINZIUB.js.map +0 -1
  140. package/dist/mcp-54IJEOUA.js.map +0 -1
  141. package/dist/property-UXLOLPTD.js.map +0 -1
  142. package/dist/record-4TR2UIIS.js.map +0 -1
  143. package/dist/redis-35VBUYW7.js.map +0 -1
  144. package/dist/sandbox-XGSUU6G7.js.map +0 -1
  145. package/dist/session-MYFNZPRP.js.map +0 -1
  146. package/dist/skill-KM34LDMO.js.map +0 -1
  147. package/dist/spec-RA3CFEKG.js.map +0 -1
  148. package/dist/src-LB4HBTJQ.js.map +0 -1
  149. package/dist/trace-HXIW7U2D.js +0 -14
  150. package/dist/workflow-XYFH5LTP.js.map +0 -1
  151. package/dist/workflow-cache-NQJQFWMV.js.map +0 -1
  152. package/dist/workflow-proposals-MTUDX46O.js.map +0 -1
  153. /package/dist/{auth-EN6NQCJY.js.map → auth-VQG2CDUD.js.map} +0 -0
  154. /package/dist/{chunk-N7HFALX3.js.map → chunk-46IUJXSD.js.map} +0 -0
  155. /package/dist/{chunk-XQXVG7RA.js.map → chunk-FNPMWDUQ.js.map} +0 -0
  156. /package/dist/{pdf-extract-ABWV3L5X.js.map → chunk-G4UYGRZR.js.map} +0 -0
  157. /package/dist/{chunk-I4QLI3JO.js.map → chunk-HDFYUFBI.js.map} +0 -0
  158. /package/dist/{chunk-CLAWT7BJ.js.map → chunk-NHTEKEYE.js.map} +0 -0
  159. /package/dist/{chunk-Q4BO4Z5V.js.map → chunk-XJ5YYYGC.js.map} +0 -0
  160. /package/dist/{install-DXSNWZKO.js.map → install-OJFXHY6U.js.map} +0 -0
  161. /package/dist/{src-N3TPKGTY.js.map → pdf-extract-YHE54XU4.js.map} +0 -0
  162. /package/dist/{src-UVDX5UP6.js.map → src-CG52HEE7.js.map} +0 -0
  163. /package/dist/{tag-YY6YAABQ.js.map → src-PK5OZXCM.js.map} +0 -0
  164. /package/dist/{trace-HXIW7U2D.js.map → tag-JSHOMLBR.js.map} +0 -0
  165. /package/dist/{triage-ORG45R5W.js.map → trace-UMLOSIIR.js.map} +0 -0
  166. /package/dist/{upgrade-L2VYMP2V.js.map → upgrade-S7CGEK6H.js.map} +0 -0
@@ -12,8 +12,7 @@ import {
12
12
  workflowToSpec,
13
13
  writeNodeIds,
14
14
  writeWorkflowId
15
- } from "./chunk-B2VISN2V.js";
16
- import "./chunk-SJJW77WN.js";
15
+ } from "./chunk-7VMO2WOZ.js";
17
16
  import {
18
17
  fetchOrExit
19
18
  } from "./chunk-3CZU7XCS.js";
@@ -21,7 +20,15 @@ import {
21
20
  getArgValue,
22
21
  hasFlag,
23
22
  resolveAppUrl
24
- } from "./chunk-A4OFTUVV.js";
23
+ } from "./chunk-3X3NW7QA.js";
24
+ import {
25
+ isSpecFile,
26
+ readableSpecDirs,
27
+ specDir,
28
+ specExtension,
29
+ splitSpecExtension
30
+ } from "./chunk-JMJVGMXI.js";
31
+ import "./chunk-JYGNMKZ5.js";
25
32
  import "./chunk-VKVL7WBN.js";
26
33
 
27
34
  // src/spec/index.ts
@@ -175,7 +182,7 @@ async function resolvePropertyNameMap(ctx, names) {
175
182
  var UnsupportedFieldEditError = class extends Error {
176
183
  constructor(fields) {
177
184
  super(
178
- `Editing ${fields.join(", ")} via .canary.md is not supported yet. These fields require name \u2192 id resolution that lands in a follow-up. Edit them in the Canary UI for now; the rest of your changes will still apply.`
185
+ `Editing ${fields.join(", ")} via a spec file is not supported yet. These fields require name \u2192 id resolution that lands in a follow-up. Edit them in the Canary UI for now; the rest of your changes will still apply.`
179
186
  );
180
187
  this.name = "UnsupportedFieldEditError";
181
188
  }
@@ -289,21 +296,19 @@ function printSpecHelp() {
289
296
  " validate <file> Parse + lint the spec offline",
290
297
  " compile <file> Validate, then create the workflow",
291
298
  " diff <file> Preview what `compile` would change (no writes)",
292
- " pull <workflow-id> Reverse: workflow \u2192 round-trippable .canary.md",
299
+ ` pull <workflow-id> Reverse: workflow \u2192 round-trippable ${specExtension}`,
293
300
  " pull --all Sync a directory of specs down from all workflows",
294
301
  "",
295
302
  "Compile flags:",
296
- " --publish Create as published instead of draft",
297
- " --run-and-publish After create, trigger a test run; publish if green",
298
303
  " --allow-duplicate Fresh compile: create even when a same-named workflow exists",
299
304
  " --create-with-duplicate-title",
300
305
  " Alias for --allow-duplicate",
301
306
  " --json Machine-readable output",
302
307
  "",
303
308
  "Pull flags:",
304
- " --output <path|dir> File (single) or directory (--all); default canary/specs/",
309
+ ` --output <path|dir> File (single) or directory (--all); default ${specDir}/`,
305
310
  " --all Sync every workflow into the directory (add new, update matching by workflowId)",
306
- " --status <s> With --all, filter workflows by status (draft|published|\u2026)",
311
+ " --status <s> With --all, filter workflows by status (draft|approved|\u2026)",
307
312
  " --force Overwrite an existing file (single pull)"
308
313
  ].join("\n")
309
314
  );
@@ -473,7 +478,7 @@ async function handlePull(argv, apiUrl, token) {
473
478
  console.error(`Error: workflow ${workflowId} not found (or no permission).`);
474
479
  process.exit(1);
475
480
  }
476
- const outPath = getArgValue(argv, "--output") ?? path.join("canary", "specs", `${slugify(live.name)}.canary.md`);
481
+ const outPath = getArgValue(argv, "--output") ?? path.join(specDir, `${slugify(live.name)}${specExtension}`);
477
482
  const preserved = await readPreservedFrontmatter(outPath);
478
483
  const sidecarPath = await fetchAndWriteApiSequenceSidecar(
479
484
  apiUrl,
@@ -524,10 +529,12 @@ async function handlePull(argv, apiUrl, token) {
524
529
  }
525
530
  async function handlePullAll(argv, apiUrl, token) {
526
531
  const json = hasFlag(argv, "--json");
527
- const dir = getArgValue(argv, "--output") ?? argv.find((a) => !a.startsWith("-")) ?? path.join("canary", "specs");
532
+ const explicitDir = getArgValue(argv, "--output") ?? argv.find((a) => !a.startsWith("-"));
533
+ const dir = explicitDir ?? specDir;
528
534
  const status = getArgValue(argv, "--status");
529
535
  const workflows = await fetchWorkflowList(apiUrl, token, status);
530
- const byWorkflowId = await indexSpecFiles(dir);
536
+ const indexDirs = explicitDir ? [explicitDir] : readableSpecDirs();
537
+ const byWorkflowId = await mergeSpecRoots(indexDirs);
531
538
  const usedNames = new Set([...byWorkflowId.values()].map((p) => path.basename(p)));
532
539
  const results = [];
533
540
  for (const wf of workflows) {
@@ -651,7 +658,7 @@ async function indexSpecFiles(dir) {
651
658
  }
652
659
  const ID_RE = /^workflowId:\s*([0-9a-f-]{36})\s*$/im;
653
660
  for (const rel of entries) {
654
- if (!rel.endsWith(".canary.md")) continue;
661
+ if (!isSpecFile(rel)) continue;
655
662
  const full = path.join(dir, rel);
656
663
  try {
657
664
  const src = await fs.readFile(full, "utf-8");
@@ -662,9 +669,18 @@ async function indexSpecFiles(dir) {
662
669
  }
663
670
  return map;
664
671
  }
672
+ async function mergeSpecRoots(roots) {
673
+ const byWorkflowId = /* @__PURE__ */ new Map();
674
+ for (const root of roots) {
675
+ for (const [id, file] of await indexSpecFiles(root)) {
676
+ if (!byWorkflowId.has(id)) byWorkflowId.set(id, file);
677
+ }
678
+ }
679
+ return byWorkflowId;
680
+ }
665
681
  function uniqueName(slug, workflowId, used) {
666
- let name = `${slug}.canary.md`;
667
- if (used.has(name)) name = `${slug}-${workflowId.slice(0, 8)}.canary.md`;
682
+ let name = `${slug}${specExtension}`;
683
+ if (used.has(name)) name = `${slug}-${workflowId.slice(0, 8)}${specExtension}`;
668
684
  return name;
669
685
  }
670
686
  async function runFreshCompile(opts) {
@@ -699,7 +715,13 @@ async function runFreshCompile(opts) {
699
715
  }
700
716
  process.exit(1);
701
717
  }
702
- const status = hasFlag(argv, "--publish") ? "published" : emitted.status ?? "draft";
718
+ if (hasFlag(argv, "--publish")) {
719
+ console.error(
720
+ "Error: --publish was removed. Compile the spec, then approve it (canary workflow approve <id> --yes) and promote it (canary workflow promote <id>)."
721
+ );
722
+ process.exit(1);
723
+ }
724
+ const status = emitted.status ?? "draft";
703
725
  const payload = {
704
726
  name: emitted.name,
705
727
  description: emitted.description,
@@ -769,8 +791,10 @@ async function runFreshCompile(opts) {
769
791
  for (const w of body.warnings) console.log(` \u26A0 ${w}`);
770
792
  }
771
793
  if (hasFlag(argv, "--run-and-publish")) {
772
- console.log("\n\u2139 --run-and-publish for spec compile is not wired in this MVP. Run:");
773
- console.log(` canary workflow run ${body.workflow.id} --publish-on-pass`);
794
+ console.log("\n\u2139 --run-and-publish was removed. Run, approve, then promote:");
795
+ console.log(` canary workflow run ${body.workflow.id}`);
796
+ console.log(` canary workflow approve ${body.workflow.id} --yes`);
797
+ console.log(` canary workflow promote ${body.workflow.id}`);
774
798
  }
775
799
  }
776
800
  var DUPLICATE_WORKFLOW_TITLE_ALLOW_FLAGS = [
@@ -823,10 +847,11 @@ async function fetchFreshCompileDuplicateWorkflows(opts) {
823
847
  return exactWorkflowTitleMatches(body.data ?? [], opts.workflowName);
824
848
  }
825
849
  function stampedSpecPath(file) {
826
- if (file.endsWith(".canary.md")) {
827
- return `${file.slice(0, -".canary.md".length)}.stamped.canary.md`;
850
+ const split = splitSpecExtension(file);
851
+ if (split) {
852
+ return `${split.base}.stamped${split.ext}`;
828
853
  }
829
- return `${file}.stamped.canary.md`;
854
+ return `${file}.stamped${specExtension}`;
830
855
  }
831
856
  async function runRecompile(opts) {
832
857
  const { argv, apiUrl, token, file, emitted } = opts;
@@ -881,9 +906,9 @@ async function runRecompile(opts) {
881
906
  if (diff.nameDrift) {
882
907
  console.log(` \u270E renamed: "${diff.nameDrift.from}" \u2192 "${diff.nameDrift.to}"`);
883
908
  }
884
- if (live.status === "published") {
909
+ if (live.promotion === "promoted") {
885
910
  console.log(
886
- ` \u26A0 workflow is published \u2014 changes land on draft state; next publish captures them.`
911
+ ` \u26A0 workflow is promoted \u2014 suites run the live definition, so these changes take effect on the next suite run.`
887
912
  );
888
913
  }
889
914
  if (diff.duplicateSpecIds.length > 0) {
@@ -945,7 +970,11 @@ export {
945
970
  handleCompile,
946
971
  handleSpec,
947
972
  handleValidate,
973
+ indexSpecFiles,
948
974
  lintSpec,
949
- parseSpec
975
+ mergeSpecRoots,
976
+ parseSpec,
977
+ stampedSpecPath,
978
+ uniqueName
950
979
  };
951
- //# sourceMappingURL=spec-RA3CFEKG.js.map
980
+ //# sourceMappingURL=spec-2NP36U3Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spec/index.ts","../src/spec/sync.ts"],"sourcesContent":["/**\n * `canary spec` subcommand entry points.\n *\n * Subcommands:\n * canary spec validate <file> — parse + lint, exit non-zero on errors\n * canary spec compile <file> — validate, then POST to /workflows/create-with-nodes\n * canary spec pull <id> — reverse: workflow → spec (TODO)\n * canary spec diff <file> <id> — what would compile change? (TODO)\n *\n * @module spec\n */\n\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport process from 'node:process';\nimport { getArgValue, hasFlag, resolveAppUrl } from '../auth.js';\nimport { fetchOrExit } from '../api-fetch.js';\nimport {\n isSpecFile,\n readableSpecDirs,\n specDir,\n specExtension,\n splitSpecExtension,\n} from '../brand.js';\nimport {\n ApiSequenceFileSchema,\n diffWorkflow,\n emitSpec,\n extractPreservedFrontmatter,\n hasAnyChange,\n lintSpec,\n parseSpec,\n summarize,\n workflowToSpec,\n writeNodeIds,\n writeWorkflowId,\n type DiffResult,\n type LiveWorkflow,\n type PullWorkflow,\n type PullOptions,\n type SpecAst,\n type SpecIssue,\n} from '@chatsdet/canary-spec';\nimport { applyDiff } from './sync.js';\n\nexport async function handleSpec(argv: string[], apiUrl: string, token: string): Promise<void> {\n const sub = argv[0];\n switch (sub) {\n case 'validate':\n await handleValidate(argv.slice(1));\n return;\n case 'compile':\n await handleCompile(argv.slice(1), apiUrl, token);\n return;\n case 'pull':\n await handlePull(argv.slice(1), apiUrl, token);\n return;\n case 'diff':\n await handleDiff(argv.slice(1), apiUrl, token);\n return;\n default:\n printSpecHelp();\n process.exit(sub ? 1 : 0);\n }\n}\n\nfunction printSpecHelp(): void {\n console.log(\n [\n 'Usage: canary spec <subcommand> <file>',\n '',\n 'Subcommands:',\n ' validate <file> Parse + lint the spec offline',\n ' compile <file> Validate, then create the workflow',\n ' diff <file> Preview what `compile` would change (no writes)',\n ` pull <workflow-id> Reverse: workflow → round-trippable ${specExtension}`,\n ' pull --all Sync a directory of specs down from all workflows',\n '',\n 'Compile flags:',\n ' --allow-duplicate Fresh compile: create even when a same-named workflow exists',\n ' --create-with-duplicate-title',\n ' Alias for --allow-duplicate',\n ' --json Machine-readable output',\n '',\n 'Pull flags:',\n ` --output <path|dir> File (single) or directory (--all); default ${specDir}/`,\n ' --all Sync every workflow into the directory (add new, update matching by workflowId)',\n ' --status <s> With --all, filter workflows by status (draft|approved|…)',\n ' --force Overwrite an existing file (single pull)',\n ].join('\\n')\n );\n}\n\nasync function handleValidate(argv: string[]): Promise<void> {\n const file = argv[0];\n if (!file) {\n console.error('Error: canary spec validate <file>');\n process.exit(1);\n }\n const json = hasFlag(argv, '--json');\n\n const result = await loadAndValidate(file);\n if (json) {\n console.log(\n JSON.stringify(\n {\n ok: result.ok,\n issues: result.issues,\n ...(result.ok ? { workflowName: result.ast.frontmatter.name } : {}),\n },\n null,\n 2\n )\n );\n process.exit(result.ok ? 0 : 1);\n }\n printIssues(result.issues, file);\n if (!result.ok) {\n process.exit(1);\n }\n console.log(`✓ ${file} validates`);\n}\n\nasync function handleCompile(argv: string[], apiUrl: string, token: string): Promise<void> {\n const file = argv[0];\n if (!file) {\n console.error('Error: canary spec compile <file>');\n process.exit(1);\n }\n const result = await loadAndValidate(file);\n printIssues(result.issues, file);\n if (!result.ok) {\n process.exit(1);\n }\n\n const ast = result.ast;\n // Append a default end node only on a fresh create; on recompile (spec\n // already bound to a workflow) suppress it so an end-less workflow doesn't\n // gain a phantom node on every round-trip.\n const emitted = emitSpec(ast, { appendDefaultEnd: !ast.frontmatter.workflowId });\n\n // Load any api_sequence sidecar referenced by a node. Multiple nodes pointing\n // at the same path share one sidecar (DB enforces one api_sequence row per\n // workflow); divergent paths produce a clear error before any state changes.\n try {\n emitted.apiSequenceConfig = await loadApiSequenceSidecar(emitted.nodes, file);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n // Branch: recompile (frontmatter has `workflowId`) vs fresh create.\n if (emitted.workflowId) {\n await runRecompile({ argv, apiUrl, token, file, emitted });\n return;\n }\n\n await runFreshCompile({ argv, apiUrl, token, file, emitted });\n}\n\n/**\n * Resolve and load the api_sequence sidecar(s) referenced by spec nodes.\n *\n * The DB enforces one api_sequence row per workflow, so a single workflow may\n * carry many `nodeType: 'api_sequence'` nodes but they all point at the same\n * sidecar. We accept multiple identical paths but reject divergent ones with\n * a clear error before any state mutation.\n */\nasync function loadApiSequenceSidecar(\n nodes: ReadonlyArray<{ nodeType: string; configJson: Record<string, unknown> }>,\n specFile: string\n): Promise<unknown> {\n const refs = nodes\n .filter((n) => n.nodeType === 'api_sequence')\n .map((n) => n.configJson['__apiSequenceSidecar'])\n .filter((p): p is string => typeof p === 'string' && p.length > 0);\n if (refs.length === 0) return undefined;\n const unique = Array.from(new Set(refs));\n if (unique.length > 1) {\n throw new Error(\n `Spec has divergent api_sequence sidecar paths: ${unique\n .map((p) => `\"${p}\"`)\n .join(', ')}. The DB stores one config per workflow — pick a single path.`\n );\n }\n const sidecarPath = path.resolve(path.dirname(specFile), unique[0]);\n let raw: string;\n try {\n raw = await fs.readFile(sidecarPath, 'utf-8');\n } catch (err) {\n throw new Error(\n `Could not read api_sequence sidecar at ${sidecarPath}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n const yaml = await import('yaml');\n let parsed: unknown;\n try {\n parsed = yaml.parse(raw);\n } catch (err) {\n throw new Error(\n `Sidecar YAML at ${sidecarPath} is invalid: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n const validated = ApiSequenceFileSchema.safeParse(parsed);\n if (!validated.success) {\n throw new Error(\n `Sidecar at ${sidecarPath} doesn't match the api_sequence shape: ${validated.error.message}`\n );\n }\n return validated.data;\n}\n\nasync function handleDiff(argv: string[], apiUrl: string, token: string): Promise<void> {\n const file = argv[0];\n if (!file) {\n console.error('Error: canary spec diff <file>');\n process.exit(1);\n }\n const result = await loadAndValidate(file);\n printIssues(result.issues, file);\n if (!result.ok) process.exit(1);\n\n const emitted = emitSpec(result.ast, { appendDefaultEnd: false });\n if (!emitted.workflowId) {\n console.log(\n `ℹ ${file} has no workflowId in frontmatter — \\`canary spec compile\\` would create a new workflow.`\n );\n console.log(` Nodes that would be created: ${emitted.nodes.length}`);\n return;\n }\n\n const liveRes = await fetchOrExit(`${apiUrl}/workflows/${emitted.workflowId}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${token}` },\n token,\n });\n if (!liveRes.ok) {\n console.error(`Error: failed to fetch workflow ${emitted.workflowId} (${liveRes.status})`);\n process.exit(1);\n }\n const liveBody = (await liveRes.json().catch(() => ({}))) as { workflow?: LiveWorkflow };\n const live = liveBody.workflow;\n if (!live) {\n console.error(`Error: workflow ${emitted.workflowId} not found.`);\n process.exit(1);\n }\n\n let diff: DiffResult;\n try {\n diff = diffWorkflow(emitted, live);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n if (hasFlag(argv, '--json')) {\n console.log(JSON.stringify({ ok: true, summary: summarize(diff), diff }, null, 2));\n return;\n }\n\n if (!hasAnyChange(diff)) {\n console.log(`✓ ${file} — in sync with workflow ${emitted.workflowId}`);\n return;\n }\n const s = summarize(diff);\n console.log(`\\nPreview for \"${live.name}\" (${emitted.workflowId}):`);\n console.log(\n ` +${s.created} create · ~${s.updated} update · -${s.deleted} delete · ↻ ${s.moved} move`\n );\n if (diff.nameDrift) console.log(` ✎ rename: \"${diff.nameDrift.from}\" → \"${diff.nameDrift.to}\"`);\n const fieldKeys = Object.keys(diff.workflowFieldChanges).filter((k) => k !== 'name');\n if (fieldKeys.length > 0) console.log(` ✎ workflow fields: ${fieldKeys.join(', ')}`);\n console.log(`\\nRun \\`canary spec compile ${file}\\` to apply.`);\n}\n\nasync function handlePull(argv: string[], apiUrl: string, token: string): Promise<void> {\n if (hasFlag(argv, '--all')) {\n await handlePullAll(argv, apiUrl, token);\n return;\n }\n\n const workflowId = argv.find((a) => !a.startsWith('-'));\n if (!workflowId) {\n console.error('Error: canary spec pull <workflow-id> [--output <path>] [--force]');\n console.error(' canary spec pull --all [--output <dir>] [--status <s>] [--force]');\n process.exit(1);\n }\n const json = hasFlag(argv, '--json');\n const force = hasFlag(argv, '--force');\n\n const live = await fetchWorkflow(apiUrl, token, workflowId);\n if (!live) {\n console.error(`Error: workflow ${workflowId} not found (or no permission).`);\n process.exit(1);\n }\n\n const outPath =\n getArgValue(argv, '--output') ??\n path.join(specDir, `${slugify(live.name)}${specExtension}`);\n\n // Preserve spec-source-only frontmatter from the prior file (requirementRef,\n // scenario skipReason). These have no live equivalent, so a naive overwrite\n // would silently drop the author's notes on re-pull.\n const preserved = await readPreservedFrontmatter(outPath);\n // When the workflow has an api_sequence config, fetch it + write a sidecar\n // file alongside the spec. Pull annotates each api_sequence node in the live\n // workflow with `__apiSequenceSidecar` so `workflowToSpec` can emit the\n // `- apiSequence:` bullet. The sidecar path lives next to the spec under a\n // sibling `sequences/` directory by convention.\n const sidecarPath = await fetchAndWriteApiSequenceSidecar(\n apiUrl,\n token,\n workflowId,\n live,\n outPath\n );\n if (sidecarPath) {\n for (const node of live.nodes) {\n if (node.nodeType === 'api_sequence') {\n node.configJson = {\n ...node.configJson,\n __apiSequenceSidecar: path.relative(path.dirname(outPath), sidecarPath),\n };\n }\n }\n }\n const source = workflowToSpec(live, preserved);\n\n // Validate the round-trip so a malformed pull surfaces immediately.\n const parsed = parseSpec(source);\n const lintIssues = parsed.ok ? lintSpec(parsed.ast) : [];\n const parseIssues = parsed.ok ? [] : parsed.issues;\n const issues = [...parseIssues, ...lintIssues];\n\n if (!force) {\n try {\n await fs.access(outPath);\n console.error(\n `Error: ${outPath} already exists. Use --output <path> or --force to overwrite.`\n );\n process.exit(1);\n } catch {\n // file does not exist — good.\n }\n }\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, source, 'utf-8');\n\n if (json) {\n console.log(JSON.stringify({ ok: true, file: outPath, workflowId, issues }, null, 2));\n return;\n }\n\n console.log(`\\n✓ Pulled \"${live.name}\" → ${outPath}`);\n console.log(` Nodes: ${live.nodes.length}`);\n console.log(` Edit the file, then \\`canary spec compile ${outPath}\\` to push changes back.`);\n if (issues.length > 0) {\n console.log('\\n Notes:');\n printIssues(issues, outPath);\n }\n}\n\n/**\n * `canary spec pull --all` — sync a directory of spec files (`.cofactor.md`,\n * legacy `.canary.md`) down from the live workflows. Existing files are matched\n * to a workflow by their `workflowId:` frontmatter and rewritten in place;\n * workflows with no matching file get a fresh `<slug>` spec in the active\n * brand's extension. Files are only written when their\n * content actually changes, so an already-synced repo produces no churn.\n */\nasync function handlePullAll(argv: string[], apiUrl: string, token: string): Promise<void> {\n const json = hasFlag(argv, '--json');\n const explicitDir = getArgValue(argv, '--output') ?? argv.find((a) => !a.startsWith('-'));\n // New files default to the active brand's dir (e.g. `cofactor/specs`).\n const dir = explicitDir ?? specDir;\n const status = getArgValue(argv, '--status');\n\n const workflows = await fetchWorkflowList(apiUrl, token, status);\n // Map existing files by their declared workflowId so re-pulls land in place.\n // With no explicit dir, scan every recognized spec root so an existing\n // `canary/specs` repo is matched and rewritten in place rather than\n // duplicated under the new default `cofactor/specs`.\n const indexDirs = explicitDir ? [explicitDir] : readableSpecDirs();\n const byWorkflowId = await mergeSpecRoots(indexDirs);\n const usedNames = new Set<string>([...byWorkflowId.values()].map((p) => path.basename(p)));\n\n const results: Array<{\n id: string;\n name: string;\n file: string;\n action: 'added' | 'synced' | 'unchanged' | 'failed';\n note?: string;\n }> = [];\n\n for (const wf of workflows) {\n const live = await fetchWorkflow(apiUrl, token, wf.id);\n if (!live) {\n results.push({ id: wf.id, name: wf.name, file: '', action: 'failed', note: 'fetch failed' });\n continue;\n }\n const existing = byWorkflowId.get(wf.id);\n let target: string;\n let isNew = false;\n if (existing) {\n target = existing;\n } else {\n target = path.join(dir, uniqueName(slugify(live.name), wf.id, usedNames));\n usedNames.add(path.basename(target));\n isNew = true;\n }\n\n let prior: string | null = null;\n try {\n prior = await fs.readFile(target, 'utf-8');\n } catch {\n // no prior file\n }\n // Spec-source-only fields (requirementRef, scenario skipReason) have no\n // server-side representation — lift them from the prior file before\n // emitting, so re-pull doesn't drop them.\n const preserved = prior ? extractPreservedFrontmatter(prior) : {};\n const source = workflowToSpec(live, preserved);\n if (prior === source) {\n results.push({ id: wf.id, name: live.name, file: target, action: 'unchanged' });\n continue;\n }\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, source, 'utf-8');\n results.push({ id: wf.id, name: live.name, file: target, action: isNew ? 'added' : 'synced' });\n }\n\n if (json) {\n console.log(JSON.stringify({ ok: true, dir, results }, null, 2));\n return;\n }\n const count = (a: string) => results.filter((r) => r.action === a).length;\n console.log(`\\n✓ Synced ${results.length} workflow(s) → ${dir}`);\n console.log(\n ` +${count('added')} added · ~${count('synced')} synced · =${count('unchanged')} unchanged${count('failed') ? ` · ✗${count('failed')} failed` : ''}`\n );\n for (const r of results) {\n if (r.action === 'unchanged') continue;\n const mark = r.action === 'added' ? '+' : r.action === 'synced' ? '~' : '✗';\n console.log(\n ` ${mark} ${path.relative(process.cwd(), r.file) || r.file}${r.note ? ` (${r.note})` : ''}`\n );\n }\n}\n\n/** Fetch the full live workflow (with nodes + edges) for the diff/pull path. */\n/**\n * Fetch the workflow's api_sequence config (if any) and write it to a sidecar\n * YAML alongside the spec. Returns the absolute path to the sidecar, or null\n * when the workflow doesn't have an api_sequence row.\n *\n * The sidecar filename is derived from the workflow slug and lands in a\n * sibling `sequences/` directory: `<spec-dir>/sequences/<slug>.yaml`.\n * Re-pull overwrites the file in place.\n */\nasync function fetchAndWriteApiSequenceSidecar(\n apiUrl: string,\n token: string,\n workflowId: string,\n live: PullWorkflow,\n outPath: string\n): Promise<string | null> {\n // Skip when the workflow has no api_sequence nodes.\n if (!live.nodes.some((n) => n.nodeType === 'api_sequence')) return null;\n const res = await fetchOrExit(`${apiUrl}/api-sequences/by-workflow/${workflowId}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${token}` },\n token,\n });\n if (!res.ok) {\n // Workflow may have api_sequence nodes but no row yet (e.g. legacy state);\n // leave the sidecar off so the round-trip stays graceful.\n return null;\n }\n const body = (await res.json().catch(() => ({}))) as { data?: { config?: unknown } };\n const config = body.data?.config;\n if (!config) return null;\n\n const sequencesDir = path.join(path.dirname(outPath), 'sequences');\n const sidecarSlug = slugify(live.name);\n const sidecarPath = path.join(sequencesDir, `${sidecarSlug}.yaml`);\n await fs.mkdir(sequencesDir, { recursive: true });\n const yaml = await import('yaml');\n await fs.writeFile(sidecarPath, yaml.stringify(config), 'utf-8');\n return sidecarPath;\n}\n\n/**\n * Read spec-source-only frontmatter from the prior file at `target` (if any).\n * Returns an empty `PullOptions` when no prior file exists.\n */\nasync function readPreservedFrontmatter(target: string): Promise<PullOptions> {\n try {\n const prior = await fs.readFile(target, 'utf-8');\n return extractPreservedFrontmatter(prior);\n } catch {\n return {};\n }\n}\n\nasync function fetchWorkflow(\n apiUrl: string,\n token: string,\n workflowId: string\n): Promise<PullWorkflow | null> {\n const res = await fetchOrExit(`${apiUrl}/workflows/${workflowId}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${token}` },\n token,\n });\n if (!res.ok) return null;\n const body = (await res.json().catch(() => ({}))) as { workflow?: PullWorkflow };\n return body.workflow ?? null;\n}\n\n/** List workflows (paginated), optionally filtered by status. */\nasync function fetchWorkflowList(\n apiUrl: string,\n token: string,\n status: string | undefined\n): Promise<Array<{ id: string; name: string }>> {\n const out: Array<{ id: string; name: string }> = [];\n let page = 1;\n for (;;) {\n const params = new URLSearchParams({ page: String(page), pageSize: '100' });\n if (status) params.set('status', status);\n const res = await fetchOrExit(`${apiUrl}/workflows?${params.toString()}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${token}` },\n token,\n });\n if (!res.ok) {\n console.error(`Error: failed to list workflows (${res.status})`);\n process.exit(1);\n }\n const body = (await res.json().catch(() => ({}))) as {\n data?: Array<{ id: string; name: string }>;\n pagination?: { page: number; totalPages: number };\n };\n for (const w of body.data ?? []) out.push({ id: w.id, name: w.name });\n const pg = body.pagination;\n if (!pg || pg.page >= pg.totalPages || (body.data ?? []).length === 0) break;\n page += 1;\n }\n return out;\n}\n\n/** Build a map of `workflowId` → spec file path across a directory tree. */\nexport async function indexSpecFiles(dir: string): Promise<Map<string, string>> {\n const map = new Map<string, string>();\n let entries: string[];\n try {\n entries = await fs.readdir(dir, { recursive: true });\n } catch {\n return map; // directory doesn't exist yet\n }\n const ID_RE = /^workflowId:\\s*([0-9a-f-]{36})\\s*$/im;\n for (const rel of entries) {\n if (!isSpecFile(rel)) continue;\n const full = path.join(dir, rel);\n try {\n const src = await fs.readFile(full, 'utf-8');\n const m = ID_RE.exec(src);\n if (m && !map.has(m[1])) map.set(m[1], full);\n } catch {\n // unreadable — skip\n }\n }\n return map;\n}\n\n/**\n * Index several spec roots and merge into one `workflowId` → path map.\n * Roots are processed in order and the FIRST occurrence of a `workflowId` wins,\n * so callers pass roots highest-precedence-first (see {@link readableSpecDirs}).\n * This is what keeps a `pull --all` from duplicating an existing legacy\n * `canary/specs` file under the new default `cofactor/specs`.\n */\nexport async function mergeSpecRoots(roots: string[]): Promise<Map<string, string>> {\n const byWorkflowId = new Map<string, string>();\n for (const root of roots) {\n for (const [id, file] of await indexSpecFiles(root)) {\n if (!byWorkflowId.has(id)) byWorkflowId.set(id, file);\n }\n }\n return byWorkflowId;\n}\n\n/** Pick a collision-free filename, disambiguating with a short id when needed. */\nexport function uniqueName(slug: string, workflowId: string, used: Set<string>): string {\n let name = `${slug}${specExtension}`;\n if (used.has(name)) name = `${slug}-${workflowId.slice(0, 8)}${specExtension}`;\n return name;\n}\n\nasync function runFreshCompile(opts: {\n argv: string[];\n apiUrl: string;\n token: string;\n file: string;\n emitted: ReturnType<typeof emitSpec>;\n}): Promise<void> {\n const { argv, apiUrl, token, file, emitted } = opts;\n\n const duplicateMatches = await fetchFreshCompileDuplicateWorkflows({\n argv,\n apiUrl,\n token,\n workflowName: emitted.name,\n });\n if (duplicateMatches.length > 0) {\n const message = formatDuplicateWorkflowTitleWarning({\n file,\n workflowName: emitted.name,\n matches: duplicateMatches,\n });\n if (hasFlag(argv, '--json')) {\n console.log(\n JSON.stringify(\n {\n ok: false,\n error: 'duplicate_workflow_title',\n message,\n workflows: duplicateMatches,\n },\n null,\n 2\n )\n );\n } else {\n console.error(message);\n }\n process.exit(1);\n }\n\n // `--publish` was removed with the approval/promotion lifecycle split — approval\n // is an explicit human act (canary workflow approve) and suite inclusion is a\n // separate promote step. Flows always compile as drafts.\n if (hasFlag(argv, '--publish')) {\n console.error(\n 'Error: --publish was removed. Compile the spec, then approve it ' +\n '(canary workflow approve <id> --yes) and promote it (canary workflow promote <id>).'\n );\n process.exit(1);\n }\n const status = emitted.status ?? 'draft';\n\n const payload: Record<string, unknown> = {\n name: emitted.name,\n description: emitted.description,\n preflight: emitted.preflight,\n cleanup: emitted.cleanup,\n status,\n flowType: emitted.flowType,\n createdVia: 'cli-spec',\n // The route only knows about (nodeType, configJson) — strip our meta.\n nodes: emitted.nodes.map(({ nodeType, configJson }) => ({ nodeType, configJson })),\n ...(emitted.inputsJson.length > 0 ? { inputsJson: emitted.inputsJson } : {}),\n ...(emitted.scenariosJson.length > 0 ? { scenariosJson: emitted.scenariosJson } : {}),\n };\n\n const res = await fetchOrExit(`${apiUrl}/workflows/create-with-nodes`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n token,\n body: JSON.stringify(payload),\n });\n\n const body = (await res.json().catch(() => ({}))) as {\n ok: boolean;\n error?: string;\n warnings?: string[];\n workflow?: { id: string; name: string; status: string };\n nodes?: Array<{ id: string; nodeType: string; orderIndex: number }>;\n };\n\n if (!res.ok || !body.ok || !body.workflow) {\n console.error(`Error: ${body.error ?? `${res.status} ${res.statusText}`}`);\n process.exit(1);\n }\n\n // Write workflowId back to frontmatter + @id comments to each lead-in line.\n // Pair each emitted node with its sourceLine and the corresponding new\n // server-side node UUID (the route returns nodes in orderIndex order).\n const writebackPairs: Array<{ sourceLine: number; nodeId: string }> = [];\n if (body.nodes && body.nodes.length === emitted.nodes.length) {\n for (let i = 0; i < emitted.nodes.length; i++) {\n const sourceLine = emitted.nodes[i].sourceLine;\n if (sourceLine === undefined) continue;\n writebackPairs.push({ sourceLine, nodeId: body.nodes[i].id });\n }\n }\n\n try {\n const source = await fs.readFile(file, 'utf-8');\n const withWorkflowId = writeWorkflowId(source, body.workflow.id);\n // writeWorkflowId may insert a new frontmatter line, shifting all subsequent\n // line numbers by +1. Shift sourceLine accordingly so node @id markers land\n // on the lead-in (not on the blank line before it).\n const lineShift = withWorkflowId.split('\\n').length - source.split('\\n').length;\n const shiftedPairs = writebackPairs.map((p) => ({\n ...p,\n sourceLine: p.sourceLine + lineShift,\n }));\n const next = writeNodeIds(withWorkflowId, shiftedPairs);\n if (next !== source) {\n await fs.writeFile(file, next, 'utf-8');\n }\n } catch (err) {\n console.warn(\n `⚠ Workflow created, but failed to write IDs back to ${file}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n if (hasFlag(argv, '--json')) {\n console.log(JSON.stringify({ ok: true, workflow: body.workflow, writebackPairs }, null, 2));\n return;\n }\n\n const appUrl = resolveAppUrl(apiUrl);\n console.log(`\\n✓ Spec compiled: ${body.workflow.name}`);\n console.log(` ID: ${body.workflow.id}`);\n console.log(` Status: ${body.workflow.status}`);\n console.log(` Nodes: ${body.nodes?.length ?? 0}`);\n console.log(` URL: ${appUrl}/flows/${body.workflow.id}`);\n console.log(` → wrote workflowId + @id markers back to ${file}`);\n if (body.warnings && body.warnings.length > 0) {\n console.log('\\n Warnings:');\n for (const w of body.warnings) console.log(` ⚠ ${w}`);\n }\n\n if (hasFlag(argv, '--run-and-publish')) {\n console.log('\\nℹ --run-and-publish was removed. Run, approve, then promote:');\n console.log(` canary workflow run ${body.workflow.id}`);\n console.log(` canary workflow approve ${body.workflow.id} --yes`);\n console.log(` canary workflow promote ${body.workflow.id}`);\n }\n}\n\nexport const DUPLICATE_WORKFLOW_TITLE_ALLOW_FLAGS = [\n '--allow-duplicate',\n '--create-with-duplicate-title',\n] as const;\n\nexport type WorkflowTitleMatch = {\n id: string;\n name: string;\n status?: string;\n flowType?: string;\n};\n\nexport function allowsDuplicateWorkflowTitle(argv: string[]): boolean {\n return DUPLICATE_WORKFLOW_TITLE_ALLOW_FLAGS.some((flag) => hasFlag(argv, flag));\n}\n\nexport function exactWorkflowTitleMatches(\n workflows: ReadonlyArray<WorkflowTitleMatch>,\n workflowName: string\n): WorkflowTitleMatch[] {\n return workflows.filter((workflow) => workflow.name === workflowName);\n}\n\nexport function formatDuplicateWorkflowTitleWarning(opts: {\n file: string;\n workflowName: string;\n matches: ReadonlyArray<WorkflowTitleMatch>;\n}): string {\n const first = opts.matches[0];\n const stampedFile = stampedSpecPath(opts.file);\n const workflowLines = opts.matches\n .map((workflow) => {\n const details = [workflow.status, workflow.flowType].filter(Boolean).join(', ');\n return ` - ${workflow.id}${details ? ` (${details})` : ''}`;\n })\n .join('\\n');\n return [\n `Error: fresh spec compile would create a duplicate workflow named \"${opts.workflowName}\".`,\n '',\n 'Existing workflow(s):',\n workflowLines,\n '',\n 'To update an existing workflow instead, pull a stamped spec, re-apply your edits, then compile it:',\n ` canary spec pull ${first.id} --output ${stampedFile}`,\n ` canary spec compile ${stampedFile}`,\n '',\n 'To intentionally create another workflow with the same title, re-run with:',\n ` canary spec compile ${opts.file} --allow-duplicate`,\n ].join('\\n');\n}\n\nasync function fetchFreshCompileDuplicateWorkflows(opts: {\n argv: string[];\n apiUrl: string;\n token: string;\n workflowName: string;\n}): Promise<WorkflowTitleMatch[]> {\n if (allowsDuplicateWorkflowTitle(opts.argv)) return [];\n const params = new URLSearchParams({\n search: opts.workflowName,\n pageSize: '50',\n });\n const res = await fetchOrExit(`${opts.apiUrl}/workflows?${params.toString()}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${opts.token}` },\n token: opts.token,\n });\n if (!res.ok) {\n console.error(`Error: failed to check for existing workflow titles (${res.status})`);\n process.exit(1);\n }\n const body = (await res.json().catch(() => ({}))) as {\n data?: WorkflowTitleMatch[];\n };\n return exactWorkflowTitleMatches(body.data ?? [], opts.workflowName);\n}\n\nexport function stampedSpecPath(file: string): string {\n const split = splitSpecExtension(file);\n if (split) {\n return `${split.base}.stamped${split.ext}`;\n }\n return `${file}.stamped${specExtension}`;\n}\n\nasync function runRecompile(opts: {\n argv: string[];\n apiUrl: string;\n token: string;\n file: string;\n emitted: ReturnType<typeof emitSpec>;\n}): Promise<void> {\n const { argv, apiUrl, token, file, emitted } = opts;\n const workflowId = emitted.workflowId!;\n\n // 1. Fetch live workflow. GET /workflows/:id returns the workflow with\n // nodes + edges via getWorkflowWithDetails.\n const liveRes = await fetchOrExit(`${apiUrl}/workflows/${workflowId}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${token}` },\n token,\n });\n if (!liveRes.ok) {\n console.error(`Error: failed to fetch workflow ${workflowId} (${liveRes.status})`);\n process.exit(1);\n }\n const liveBody = (await liveRes.json().catch(() => ({}))) as {\n workflow?: LiveWorkflow & { snapshotVersion?: number };\n };\n const live = liveBody.workflow;\n if (!live) {\n console.error(`Error: workflow ${workflowId} not found (or no permission).`);\n process.exit(1);\n }\n\n // 2. Compute the diff.\n let diff: DiffResult;\n try {\n diff = diffWorkflow(emitted, live);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n if (!hasAnyChange(diff)) {\n console.log(`✓ ${file} — no changes (workflow ${workflowId} already in sync)`);\n return;\n }\n\n // 3. Apply.\n const ctx = { apiUrl, token, workflowId };\n const sync = await applyDiff(ctx, diff, emitted, live);\n\n // 4. Write back any new @id comments.\n if (sync.created.length > 0) {\n try {\n const source = await fs.readFile(file, 'utf-8');\n const next = writeNodeIds(source, sync.created);\n if (next !== source) await fs.writeFile(file, next, 'utf-8');\n } catch (err) {\n console.warn(\n `⚠ Recompile applied, but failed to write new @id markers to ${file}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n // 5. Summary.\n const s = summarize(diff);\n const appUrl = resolveAppUrl(apiUrl);\n console.log(`\\n✓ Recompiled \"${live.name}\"`);\n console.log(\n ` +${s.created} created · ~${s.updated} updated · -${s.deleted} deleted · ↻ ${s.moved} moved`\n );\n console.log(` URL: ${appUrl}/flows/${workflowId}`);\n if (diff.nameDrift) {\n console.log(` ✎ renamed: \"${diff.nameDrift.from}\" → \"${diff.nameDrift.to}\"`);\n }\n if (live.promotion === 'promoted') {\n console.log(\n ` ⚠ workflow is promoted — suites run the live definition, so these changes take effect on the next suite run.`\n );\n }\n if (diff.duplicateSpecIds.length > 0) {\n console.log(\n ` ⚠ duplicate @id in spec (treated as fresh creates): ${diff.duplicateSpecIds.join(', ')}`\n );\n }\n if (diff.orphanedSpecIds.length > 0) {\n console.log(\n ` ⚠ stale @id in spec (no matching node — rebound to new): ${diff.orphanedSpecIds.join(', ')}`\n );\n }\n\n if (hasFlag(argv, '--json')) {\n console.log(JSON.stringify({ ok: true, workflowId, summary: s, diff }, null, 2));\n }\n}\n\ntype LoadResult =\n | { ok: true; ast: SpecAst; issues: SpecIssue[] }\n | { ok: false; issues: SpecIssue[] };\n\nasync function loadAndValidate(file: string): Promise<LoadResult> {\n let source: string;\n try {\n source = await fs.readFile(file, 'utf-8');\n } catch (err) {\n return {\n ok: false,\n issues: [\n {\n severity: 'error',\n message: `Could not read ${file}: ${err instanceof Error ? err.message : String(err)}`,\n },\n ],\n };\n }\n const parsed = parseSpec(source);\n if (!parsed.ok) return { ok: false, issues: parsed.issues };\n const lintIssues = lintSpec(parsed.ast);\n const allIssues = [...lintIssues];\n const hasError = allIssues.some((i) => i.severity === 'error');\n if (hasError) return { ok: false, issues: allIssues };\n return { ok: true, ast: parsed.ast, issues: allIssues };\n}\n\n/** Kebab-case slug for the default pull filename. */\nfunction slugify(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 60);\n return slug || 'workflow';\n}\n\nfunction printIssues(issues: SpecIssue[], file: string): void {\n if (issues.length === 0) return;\n for (const i of issues) {\n const prefix = i.severity === 'error' ? '✗ error' : '⚠ warn';\n const loc = i.line ? `${file}:${i.line}` : file;\n console.error(`${prefix} ${loc}: ${i.message}`);\n if (i.hint) console.error(` hint: ${i.hint}`);\n }\n}\n\nexport { handleValidate, handleCompile };\n\n// Used by tests.\nexport { emitSpec, lintSpec, parseSpec };\n","/**\n * Apply a DiffResult to a live workflow via the existing REST endpoints\n * (`POST /workflows/:id/nodes`, `PUT /workflows/:id/nodes/:nodeId`,\n * `POST /workflows/:id/nodes/bulk-delete`, edge routes, `PUT /workflows/:id`).\n *\n * Returns the set of `(sourceLine → newNodeId)` pairs the writeback step\n * needs to stamp the spec file with fresh `@id` comments.\n *\n * @module spec/sync\n */\n\nimport { fetchOrExit } from '../api-fetch.js';\nimport {\n reconcileLinearEdges,\n type DiffResult,\n type EmittedWorkflow,\n type LiveEdge,\n type LiveWorkflow,\n type SpecOp,\n type WorkflowFieldChanges,\n} from '@chatsdet/canary-spec';\n\nexport type SyncContext = {\n apiUrl: string;\n token: string;\n workflowId: string;\n};\n\nexport type SyncResult = {\n /** New nodes that were created — caller uses these to write `@id` back to the spec. */\n created: Array<{ sourceLine: number; nodeId: string }>;\n};\n\nexport async function applyDiff(\n ctx: SyncContext,\n diff: DiffResult,\n emitted: EmittedWorkflow,\n live: LiveWorkflow,\n): Promise<SyncResult> {\n // 1. Bulk-delete removed nodes (reconnect: true so adjacent edges heal).\n const deletes = diff.ops.filter((o): o is Extract<SpecOp, { kind: 'delete' }> => o.kind === 'delete');\n if (deletes.length > 0) {\n await postJson(ctx, `/workflows/${ctx.workflowId}/nodes/bulk-delete`, {\n nodeIds: deletes.map((o) => o.nodeId),\n reconnect: true,\n });\n }\n\n // 2. Create new nodes. The route assigns final orderIndex, but we send the\n // desired orderIndex so it lands at the right position. We need final IDs\n // back for both writeback and downstream edge reconciliation.\n const creates = diff.ops.filter((o): o is Extract<SpecOp, { kind: 'create' }> => o.kind === 'create');\n const createdIds = new Map<number, string>(); // specIndex → new node UUID\n const writebackPairs: SyncResult['created'] = [];\n for (const op of creates) {\n const res = await postJson<{ ok?: boolean; node?: { id: string }; error?: string }>(\n ctx,\n `/workflows/${ctx.workflowId}/nodes`,\n {\n nodeType: op.nodeType,\n configJson: op.configJson,\n orderIndex: op.orderIndex,\n },\n );\n const created = res.node;\n if (!created) {\n throw new Error(\n `Failed to create node at orderIndex ${op.orderIndex}: ${res.error ?? JSON.stringify(res)}`,\n );\n }\n createdIds.set(op.specIndex, created.id);\n if (op.sourceLine !== undefined) {\n writebackPairs.push({ sourceLine: op.sourceLine, nodeId: created.id });\n }\n }\n\n // 3. Update existing nodes whose config or orderIndex changed.\n const updates = diff.ops.filter((o): o is Extract<SpecOp, { kind: 'update' }> => o.kind === 'update');\n for (const op of updates) {\n if (!op.changes.configChanged && !op.changes.orderChanged) continue;\n await putJson(ctx, `/workflows/${ctx.workflowId}/nodes/${op.nodeId}`, {\n ...(op.changes.configChanged ? { configJson: op.configJson } : {}),\n ...(op.changes.orderChanged ? { orderIndex: op.orderIndex } : {}),\n });\n }\n\n // 4. Edge reconciliation. Spec authors a single linear default chain; we\n // re-derive the expected edges from final node order and DELETE+POST to\n // converge. Non-default edges (condition then/else) are left alone.\n if (diff.ops.length > 0) {\n const finalNodeIds = computeFinalNodeOrder(diff, live, createdIds);\n const fresh = await getJson<{ workflow?: { edges?: LiveEdge[] } }>(\n ctx,\n `/workflows/${ctx.workflowId}`,\n );\n const liveEdges = fresh.workflow?.edges ?? live.edges ?? [];\n const { ops: edgeOps } = reconcileLinearEdges(finalNodeIds, liveEdges);\n for (const op of edgeOps) {\n if (op.kind === 'delete') {\n await deleteJson(ctx, `/workflows/${ctx.workflowId}/edges/${op.edgeId}`);\n } else {\n await postJson(ctx, `/workflows/${ctx.workflowId}/edges`, {\n sourceNodeId: op.sourceNodeId,\n targetNodeId: op.targetNodeId,\n edgeType: 'default',\n });\n }\n }\n }\n\n // 5. Workflow-level fields. Some fields require name → id resolution against\n // org/property scope (tags, environments, sandboxTemplate); those land in\n // a follow-up PR. Surface a clear error rather than silently dropping the\n // edit, so the author isn't surprised by missing changes.\n rejectUnsupportedFieldEdits(diff.workflowFieldChanges);\n if (Object.keys(diff.workflowFieldChanges).length > 0) {\n const payload = await resolveFieldUpdatePayload(ctx, diff.workflowFieldChanges);\n await putJson(ctx, `/workflows/${ctx.workflowId}`, payload);\n }\n\n // 6. Optional api_sequence DSL upsert. The spec carries the full\n // ApiSequenceConfig in a YAML sidecar referenced from any api_sequence\n // node; here we POST it to `/api-sequences/save`, which upserts the\n // workflow-scoped row keyed by workflowId. Skipping when the sidecar is\n // absent leaves any existing live config untouched (no implicit clear).\n if (emitted.apiSequenceConfig) {\n await postJson(ctx, `/api-sequences/save`, {\n workflowId: ctx.workflowId,\n config: emitted.apiSequenceConfig,\n });\n }\n\n return { created: writebackPairs };\n}\n\n/**\n * Look up a teardown workflow by name in the org. Matches on (name, flowType\n * === 'teardown'); throws when missing so the author gets a clear \"compile the\n * teardown spec first\" message instead of a silent FK clear.\n */\nasync function resolveTeardownWorkflowId(\n ctx: SyncContext,\n specName: string,\n): Promise<string> {\n const res = await getJson<{\n ok?: boolean;\n data?: Array<{ id: string; name: string; flowType: string }>;\n }>(\n ctx,\n `/workflows?search=${encodeURIComponent(specName)}&flowType=teardown&pageSize=50`,\n );\n const match = (res.data ?? []).find(\n (w) => w.name === specName && w.flowType === 'teardown',\n );\n if (!match) {\n throw new Error(\n `Teardown workflow \"${specName}\" not found (flowType=teardown). ` +\n `Compile the teardown spec first so the seed can link to it by name.`,\n );\n }\n return match.id;\n}\n\n/**\n * Map name-form workflow fields to their wire shape. Currently only teardown\n * and seedOutputs need lookup; tags/environments/sandboxTemplate are gated by\n * `rejectUnsupportedFieldEdits` above and never reach here.\n */\nasync function resolveFieldUpdatePayload(\n ctx: SyncContext,\n changes: WorkflowFieldChanges,\n): Promise<Record<string, unknown>> {\n const payload = fieldUpdatePayload(changes);\n // teardownSpec carries the name; the API expects teardownWorkflowId.\n if ('teardownSpec' in payload) {\n const specName = payload.teardownSpec;\n delete payload.teardownSpec;\n if (specName === null) {\n payload.teardownWorkflowId = null;\n } else if (typeof specName === 'string') {\n payload.teardownWorkflowId = await resolveTeardownWorkflowId(ctx, specName);\n }\n }\n // teardownSnapshotVersion: 'latest' → null on the wire (DB convention).\n if ('teardownSnapshotVersion' in payload) {\n if (payload.teardownSnapshotVersion === 'latest') payload.teardownSnapshotVersion = null;\n }\n // seedOutputs: rename to `seedOutputsJson` and resolve propertyName → id.\n // The route's normalizeSeedOutputs accepts entries with propertyId set;\n // we ferry across credentialOutput/attributes verbatim per the diff layer.\n if ('seedOutputs' in payload) {\n const inputRows = payload.seedOutputs as\n | Array<{\n dataKey: string;\n label?: string;\n description?: string;\n propertyName?: string;\n credentialOutput?: unknown;\n attributes?: unknown;\n }>\n | undefined;\n delete payload.seedOutputs;\n if (inputRows) {\n const propIds = await resolvePropertyNameMap(\n ctx,\n Array.from(new Set(inputRows.map((r) => r.propertyName).filter((p): p is string => !!p))),\n );\n payload.seedOutputsJson = inputRows.map((r) => {\n const propertyId = r.propertyName ? propIds.get(r.propertyName) : undefined;\n if (r.propertyName && !propertyId) {\n throw new Error(\n `Declared output \"${r.dataKey}\": property \"${r.propertyName}\" not found in this org.`,\n );\n }\n return {\n dataKey: r.dataKey,\n name: r.dataKey,\n displayLabel: r.label ?? r.dataKey,\n ...(r.description ? { description: r.description } : {}),\n ...(propertyId ? { propertyId } : {}),\n ...(r.credentialOutput !== undefined ? { credentialOutput: r.credentialOutput } : {}),\n ...(r.attributes !== undefined ? { attributes: r.attributes } : {}),\n };\n });\n }\n }\n return payload;\n}\n\n/**\n * Look up property ids by name in a single round trip. Used for seed-output\n * declarations where the spec author writes `property: <name>` and sync needs\n * the propertyId for the wire payload.\n */\nasync function resolvePropertyNameMap(\n ctx: SyncContext,\n names: string[],\n): Promise<Map<string, string>> {\n const out = new Map<string, string>();\n if (names.length === 0) return out;\n const res = await getJson<{\n ok?: boolean;\n data?: Array<{ id: string; name: string }>;\n properties?: Array<{ id: string; name: string }>;\n }>(ctx, `/org/properties`);\n const all = res.data ?? res.properties ?? [];\n for (const want of names) {\n const match = all.find((p) => p.name === want);\n if (match) out.set(want, match.id);\n }\n return out;\n}\n\nexport class UnsupportedFieldEditError extends Error {\n constructor(fields: string[]) {\n super(\n `Editing ${fields.join(', ')} via a spec file is not supported yet. ` +\n `These fields require name → id resolution that lands in a follow-up. ` +\n `Edit them in the Canary UI for now; the rest of your changes will still apply.`,\n );\n this.name = 'UnsupportedFieldEditError';\n }\n}\n\nexport function rejectUnsupportedFieldEdits(changes: WorkflowFieldChanges): void {\n const unsupported = (['tags', 'environmentConstraints', 'sandboxTemplate'] as const).filter(\n (k) => changes[k] !== undefined,\n );\n if (unsupported.length > 0) throw new UnsupportedFieldEditError(unsupported);\n}\n\n/**\n * Build the final ordered list of node UUIDs after applying the diff —\n * positions correspond to the spec's order, IDs resolved from either the live\n * workflow (for UPDATE) or the new-node map (for CREATE).\n */\nfunction computeFinalNodeOrder(\n diff: DiffResult,\n live: LiveWorkflow,\n createdIds: Map<number, string>,\n): string[] {\n const liveById = new Map(live.nodes.map((n) => [n.id, n] as const));\n const total = diff.ops.filter((o) => o.kind !== 'delete').length;\n const result: string[] = Array.from({ length: total });\n for (const op of diff.ops) {\n if (op.kind === 'create') {\n const id = createdIds.get(op.specIndex);\n if (!id) throw new Error(`Missing created node id for specIndex ${op.specIndex}`);\n result[op.specIndex] = id;\n } else if (op.kind === 'update') {\n if (!liveById.has(op.nodeId)) {\n throw new Error(`UPDATE references nodeId ${op.nodeId} not in live workflow`);\n }\n result[op.specIndex] = op.nodeId;\n }\n }\n return result;\n}\n\nfunction fieldUpdatePayload(changes: WorkflowFieldChanges): Record<string, unknown> {\n // PUT /workflows/:id accepts each field independently; pass through only\n // what changed. Scenario `skipReason` is spec-source-only — the API's\n // `normalizeScenarios` strips it, but stripping here keeps the wire payload\n // honest and the round-trip test deterministic.\n const payload: Record<string, unknown> = {};\n for (const k of Object.keys(changes) as (keyof WorkflowFieldChanges)[]) {\n if (k === 'scenariosJson' && Array.isArray(changes.scenariosJson)) {\n payload.scenariosJson = (changes.scenariosJson as Array<Record<string, unknown>>).map((s) => {\n const { skipReason: _skip, ...rest } = s;\n return rest;\n });\n } else {\n payload[k] = changes[k];\n }\n }\n return payload;\n}\n\nasync function postJson<T = unknown>(\n ctx: SyncContext,\n path: string,\n body: unknown,\n): Promise<T> {\n const res = await fetchOrExit(`${ctx.apiUrl}${path}`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${ctx.token}`,\n 'Content-Type': 'application/json',\n },\n token: ctx.token,\n body: JSON.stringify(body),\n });\n return (await res.json()) as T;\n}\n\nasync function putJson<T = unknown>(\n ctx: SyncContext,\n path: string,\n body: unknown,\n): Promise<T> {\n const res = await fetchOrExit(`${ctx.apiUrl}${path}`, {\n method: 'PUT',\n headers: {\n Authorization: `Bearer ${ctx.token}`,\n 'Content-Type': 'application/json',\n },\n token: ctx.token,\n body: JSON.stringify(body),\n });\n return (await res.json()) as T;\n}\n\nasync function getJson<T = unknown>(ctx: SyncContext, path: string): Promise<T> {\n const res = await fetchOrExit(`${ctx.apiUrl}${path}`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${ctx.token}` },\n token: ctx.token,\n });\n return (await res.json()) as T;\n}\n\nasync function deleteJson<T = unknown>(ctx: SyncContext, path: string): Promise<T> {\n const res = await fetchOrExit(`${ctx.apiUrl}${path}`, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${ctx.token}` },\n token: ctx.token,\n });\n return (await res.json()) as T;\n}\n"],"mappings":"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","names":["path"]}
@@ -2,7 +2,7 @@ import { createRequire as __cr } from "module"; const require = __cr(import.meta
2
2
  import {
3
3
  parseTraceActions,
4
4
  reconstructSnapshots
5
- } from "./chunk-52IO7ACJ.js";
5
+ } from "./chunk-KCHKFYVX.js";
6
6
  import "./chunk-VKVL7WBN.js";
7
7
 
8
8
  // ../diagnostic-workspace/src/assemble-workspace.ts
@@ -99,6 +99,9 @@ var WORKSPACE_PATHS = {
99
99
  history: "history",
100
100
  historyRecentRuns: "history/recent-runs.jsonl",
101
101
  historyLastGreen: "history/last-green",
102
+ // CLI-only: `canary workflow debug materialize --out` target
103
+ historyRuns: "history/runs",
104
+ // agent-only: history/runs/<runId>/ — comparison workspaces from materialize_run
102
105
  notes: "notes"
103
106
  };
104
107
  var WORKSPACE_DIRS = [
@@ -1160,7 +1163,8 @@ var writeSummary = async (input) => {
1160
1163
  const historyHint = buildHistoryHint(
1161
1164
  input.recentRuns,
1162
1165
  input.runId,
1163
- input.lastGreenComparison ?? null
1166
+ input.lastGreenComparison ?? null,
1167
+ input.greenRunAccess ?? "cli"
1164
1168
  );
1165
1169
  if (historyHint.length > 0) {
1166
1170
  lines.push("## History");
@@ -1225,7 +1229,7 @@ var formatCounts = (counts) => {
1225
1229
  }
1226
1230
  return parts.join(", ");
1227
1231
  };
1228
- var buildHistoryHint = (runs, currentRunId, lastGreenComparison) => {
1232
+ var buildHistoryHint = (runs, currentRunId, lastGreenComparison, greenRunAccess) => {
1229
1233
  const lookback = runs.slice(0, MAX_HISTORY_LOOKBACK);
1230
1234
  if (lookback.length <= 1) return [];
1231
1235
  const others = lookback.filter((r) => r.workflowRunId !== currentRunId);
@@ -1242,9 +1246,10 @@ var buildHistoryHint = (runs, currentRunId, lastGreenComparison) => {
1242
1246
  out.push(
1243
1247
  `Most recent green: testRunId=${lastGreen.testRunId}${lastGreen.startedAt ? ` (${lastGreen.startedAt.slice(0, 10)})` : ""}`
1244
1248
  );
1245
- const greenRunId = lastGreen.workflowRunId ?? lastGreen.testRunId;
1249
+ if (greenRunAccess === "none") return out;
1250
+ const greenRunId = lastGreenComparison?.greenRunId ?? lastGreen.workflowRunId ?? lastGreen.testRunId;
1246
1251
  out.push(
1247
- `Comparison is REQUIRED \u2014 materialize via: canary workflow debug materialize ${greenRunId} --out history/last-green/`
1252
+ greenRunAccess === "agent-tool" ? `Comparison is REQUIRED \u2014 call the materialize_run tool with runId=${greenRunId}, then read the returned workspace under history/runs/${greenRunId}/.` : `Comparison is REQUIRED \u2014 materialize via: canary workflow debug materialize ${greenRunId} --out history/last-green/`
1248
1253
  );
1249
1254
  }
1250
1255
  const authoredUnchanged = lastGreenComparison?.authoredUnchanged ?? null;
@@ -1252,7 +1257,7 @@ var buildHistoryHint = (runs, currentRunId, lastGreenComparison) => {
1252
1257
  if (regime === "STABLE_REGRESSION" && lastGreen) {
1253
1258
  if (authoredUnchanged === true) {
1254
1259
  out.push(
1255
- `AUTHORED TEST UNCHANGED since last green${greenDate} \u2014 the authored workflow is byte-identical across this pass\u2192fail boundary, so this CANNOT be test_underspecified. A pass\u2192fail here means APP BEHAVIOR CHANGED: classify app_changed (or software_bug if the delta is clearly a defect), name the concrete behavior delta, and note in openQuestions that intent could not be verified from the sandbox.`
1260
+ `AUTHORED TEST UNCHANGED since last green${greenDate} \u2014 the authored workflow is byte-identical across this pass\u2192fail boundary, so test_underspecified is off the table. That leaves FOUR live hypotheses: a legitimate app change (app_changed), an app regression (software_bug), an agent error (agent_confusion \u2014 e.g. verification/interpretation drift), or a platform error (platform_error \u2014 cache/replay/sandbox machinery). Do NOT default to app_changed. Follow the green\u2192red methodology: establish HOW each side of the boundary executed (cache replay vs live agent), then compare. Only classify app_changed after confirming a concrete behavior delta against the materialized green run, and note in openQuestions that intent could not be verified from the sandbox.`
1256
1261
  );
1257
1262
  } else if (authoredUnchanged === false) {
1258
1263
  out.push(
@@ -1260,7 +1265,7 @@ var buildHistoryHint = (runs, currentRunId, lastGreenComparison) => {
1260
1265
  );
1261
1266
  } else {
1262
1267
  out.push(
1263
- `Stably green before this break \u2014 comparison REQUIRED. If the authored workflow is unchanged vs the green run, a pass\u2192fail means APP BEHAVIOR CHANGED (app_changed), not the test.`
1268
+ `Stably green before this break \u2014 comparison REQUIRED. The pass\u2192fail boundary alone does not discriminate between app_changed, software_bug, agent_confusion, and platform_error; materialize the green run and follow the green\u2192red methodology before classifying.`
1264
1269
  );
1265
1270
  }
1266
1271
  } else if (regime === "FLAKY") {
@@ -1274,7 +1279,7 @@ var formatRelativePrefix = (timestampMs, baselineMs) => baselineMs !== null ? `[
1274
1279
 
1275
1280
  // ../diagnostic-workspace/src/assemble-workspace.ts
1276
1281
  var assembleWorkspace = async (input) => {
1277
- const { runData, workspaceRoot, traceZipPath } = input;
1282
+ const { runData, workspaceRoot, traceZipPath, greenRunAccess } = input;
1278
1283
  await fs10.mkdir(workspaceRoot, { recursive: true, mode: 448 });
1279
1284
  for (const dir of WORKSPACE_DIRS) {
1280
1285
  await fs10.mkdir(resolveWorkspacePath(workspaceRoot, dir), { recursive: true, mode: 448 });
@@ -1375,7 +1380,8 @@ var assembleWorkspace = async (input) => {
1375
1380
  consoleLogs: eventProjection.consoleLogs,
1376
1381
  navigation: eventProjection.navigation,
1377
1382
  recentRuns: runData.recentRuns,
1378
- lastGreenComparison: runData.lastGreenComparison
1383
+ lastGreenComparison: runData.lastGreenComparison,
1384
+ greenRunAccess
1379
1385
  });
1380
1386
  await writeManifest({
1381
1387
  workspaceRoot,
@@ -1400,7 +1406,9 @@ var assembleWorkspace = async (input) => {
1400
1406
  runId: runData.runId,
1401
1407
  orgId: runData.orgId,
1402
1408
  materializedAt: (/* @__PURE__ */ new Date()).toISOString(),
1403
- runStartedAt: runData.startedAt
1409
+ runStartedAt: runData.startedAt,
1410
+ runStatus: runData.status,
1411
+ lastGreenRunId: runData.lastGreenComparison?.greenRunId ?? null
1404
1412
  };
1405
1413
  };
1406
1414
  var isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
@@ -1513,4 +1521,4 @@ export {
1513
1521
  writeStepRollups,
1514
1522
  writeSummary
1515
1523
  };
1516
- //# sourceMappingURL=src-LB4HBTJQ.js.map
1524
+ //# sourceMappingURL=src-4T6GHXVO.js.map