@gobing-ai/spur 0.3.24 → 0.3.26

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 (61) hide show
  1. package/config/config.example.yaml +74 -31
  2. package/config/templates/AGENTS.md +1 -0
  3. package/config/workflows/docs-pipeline.yaml +9 -0
  4. package/config/workflows/idea-pipeline.yaml +78 -18
  5. package/package.json +9 -9
  6. package/schemas/spur-config.schema.json +4 -4
  7. package/schemas/task-batch.schema.json +12 -0
  8. package/spur.js +1643 -460
  9. package/web/_astro/{BoardApp.Cuna9Z5I.js → BoardApp.DH9wI8y7.js} +72 -72
  10. package/web/_astro/BoardApp.DZiwQCP7.js +1 -0
  11. package/web/_astro/{TaskDetail.Bso6Ccoa.js → TaskDetail.Dsk9DnGY.js} +1 -1
  12. package/web/_astro/{arc.BpfaYkuC.js → arc.Biv8k-OR.js} +1 -1
  13. package/web/_astro/{architectureDiagram-3BPJPVTR.Bsc64OWC.js → architectureDiagram-3BPJPVTR.BrtW5Sn7.js} +1 -1
  14. package/web/_astro/{blockDiagram-GPEHLZMM.CgrqZDLK.js → blockDiagram-GPEHLZMM.CTpFZJhW.js} +1 -1
  15. package/web/_astro/{c4Diagram-AAUBKEIU.5ROHxpqD.js → c4Diagram-AAUBKEIU._ZJj9H0G.js} +1 -1
  16. package/web/_astro/channel.Ih1_8SAH.js +1 -0
  17. package/web/_astro/{chunk-2J33WTMH.BIuSLWP4.js → chunk-2J33WTMH.DD9mDiEM.js} +1 -1
  18. package/web/_astro/{chunk-4BX2VUAB.u-fSGnxt.js → chunk-4BX2VUAB.ENDQu3TH.js} +1 -1
  19. package/web/_astro/{chunk-55IACEB6.pL62Yh8J.js → chunk-55IACEB6.DLpJf8Xp.js} +1 -1
  20. package/web/_astro/{chunk-727SXJPM.Cxy6KODj.js → chunk-727SXJPM.BR6vsvIV.js} +1 -1
  21. package/web/_astro/{chunk-AQP2D5EJ.D2XUILVx.js → chunk-AQP2D5EJ.DGOBzXM6.js} +1 -1
  22. package/web/_astro/{chunk-FMBD7UC4.DNnV20jb.js → chunk-FMBD7UC4.DrghnRtZ.js} +1 -1
  23. package/web/_astro/{chunk-ND2GUHAM.Cc-L-_6y.js → chunk-ND2GUHAM.BqIqI3oO.js} +1 -1
  24. package/web/_astro/{chunk-QZHKN3VN.Bw_kp1ef.js → chunk-QZHKN3VN.CJ2RJt0K.js} +1 -1
  25. package/web/_astro/{classDiagram-4FO5ZUOK.CoE-GIzM.js → classDiagram-4FO5ZUOK.Qu1p6crX.js} +1 -1
  26. package/web/_astro/{classDiagram-v2-Q7XG4LA2.CoE-GIzM.js → classDiagram-v2-Q7XG4LA2.Qu1p6crX.js} +1 -1
  27. package/web/_astro/{cose-bilkent-S5V4N54A.CDsPYTeJ.js → cose-bilkent-S5V4N54A.7VrRetJ0.js} +1 -1
  28. package/web/_astro/{dagre-BM42HDAG.BUw8fm5M.js → dagre-BM42HDAG.r4lTyJXQ.js} +1 -1
  29. package/web/_astro/{diagram-2AECGRRQ.Bx3Ndc4x.js → diagram-2AECGRRQ.DahExuaR.js} +1 -1
  30. package/web/_astro/{diagram-5GNKFQAL.DZOACNsA.js → diagram-5GNKFQAL.B-dSm3op.js} +1 -1
  31. package/web/_astro/{diagram-KO2AKTUF.BVmZqHXi.js → diagram-KO2AKTUF.CQGlKa6a.js} +1 -1
  32. package/web/_astro/{diagram-LMA3HP47.Dhw7Sl9e.js → diagram-LMA3HP47.CJ6nomD-.js} +1 -1
  33. package/web/_astro/{diagram-OG6HWLK6.xOqh3zFz.js → diagram-OG6HWLK6.ijGl68sM.js} +1 -1
  34. package/web/_astro/{erDiagram-TEJ5UH35.VX6HV9QU.js → erDiagram-TEJ5UH35.DBAe2Iin.js} +1 -1
  35. package/web/_astro/{flowDiagram-I6XJVG4X.D5tzv1nF.js → flowDiagram-I6XJVG4X.z3iXF6Ku.js} +1 -1
  36. package/web/_astro/{ganttDiagram-6RSMTGT7.bRb0hclW.js → ganttDiagram-6RSMTGT7.DP2ouiRt.js} +1 -1
  37. package/web/_astro/{gitGraphDiagram-PVQCEYII.BrXfUWT_.js → gitGraphDiagram-PVQCEYII.DizVfgVG.js} +1 -1
  38. package/web/_astro/index.D3Y4Q0mx.css +1 -0
  39. package/web/_astro/{infoDiagram-5YYISTIA.LIQUmEkh.js → infoDiagram-5YYISTIA.BPTTgL0f.js} +1 -1
  40. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BMMwawXt.js → ishikawaDiagram-YF4QCWOH.CXdMa4-b.js} +1 -1
  41. package/web/_astro/{journeyDiagram-JHISSGLW.F7Rw6EQ6.js → journeyDiagram-JHISSGLW.ChSKZ-1j.js} +1 -1
  42. package/web/_astro/{kanban-definition-UN3LZRKU.BnZBa0gE.js → kanban-definition-UN3LZRKU.DUUlW-km.js} +1 -1
  43. package/web/_astro/{linear.DamosLmv.js → linear.AzHrSiEQ.js} +1 -1
  44. package/web/_astro/{mermaid.core.BjIs-rhV.js → mermaid.core.BajX78G7.js} +4 -4
  45. package/web/_astro/{mindmap-definition-RKZ34NQL.CAJpo14X.js → mindmap-definition-RKZ34NQL.BmdUHcac.js} +1 -1
  46. package/web/_astro/{pieDiagram-4H26LBE5.AcbGV8z3.js → pieDiagram-4H26LBE5.Dh59Ur2v.js} +1 -1
  47. package/web/_astro/{quadrantDiagram-W4KKPZXB.DFHo7-vl.js → quadrantDiagram-W4KKPZXB.D2qYQmFj.js} +1 -1
  48. package/web/_astro/{requirementDiagram-4Y6WPE33.ZcAUCpFg.js → requirementDiagram-4Y6WPE33.DW5nnrHl.js} +1 -1
  49. package/web/_astro/{sankeyDiagram-5OEKKPKP.B3jEuSva.js → sankeyDiagram-5OEKKPKP.CMl1PJrk.js} +1 -1
  50. package/web/_astro/{sequenceDiagram-3UESZ5HK.Cpz6c_VX.js → sequenceDiagram-3UESZ5HK.U5dq1PA0.js} +1 -1
  51. package/web/_astro/{stateDiagram-AJRCARHV.g_pKql00.js → stateDiagram-AJRCARHV.zrt55DVx.js} +1 -1
  52. package/web/_astro/{stateDiagram-v2-BHNVJYJU.DFINnXL2.js → stateDiagram-v2-BHNVJYJU.CKBGQ0dG.js} +1 -1
  53. package/web/_astro/{timeline-definition-PNZ67QCA.D0m2aZaf.js → timeline-definition-PNZ67QCA.CKAlx9rU.js} +1 -1
  54. package/web/_astro/{vennDiagram-CIIHVFJN.Cyk_24V8.js → vennDiagram-CIIHVFJN.Bgt1eF06.js} +1 -1
  55. package/web/_astro/{wardley-L42UT6IY.CW7JQlsX.js → wardley-L42UT6IY.BF02aioC.js} +1 -1
  56. package/web/_astro/{wardleyDiagram-YWT4CUSO.CkaxqiW8.js → wardleyDiagram-YWT4CUSO.C94wxcnJ.js} +1 -1
  57. package/web/_astro/{xychartDiagram-2RQKCTM6.DJorKgMY.js → xychartDiagram-2RQKCTM6.BwK7SRoW.js} +1 -1
  58. package/web/index.html +2 -2
  59. package/web/_astro/BoardApp.DSSZTsSW.js +0 -1
  60. package/web/_astro/channel.DKzvLld2.js +0 -1
  61. package/web/_astro/index.BRj8-zmo.css +0 -1
package/spur.js CHANGED
@@ -47,7 +47,7 @@ var __export = (target, all) => {
47
47
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
48
48
  var __require = import.meta.require;
49
49
 
50
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.11/node_modules/@gobing-ai/ts-utils/dist/errors.js
50
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.14/node_modules/@gobing-ai/ts-utils/dist/errors.js
51
51
  var ErrorCode;
52
52
  var init_errors = __esm(() => {
53
53
  ErrorCode = {
@@ -58,7 +58,7 @@ var init_errors = __esm(() => {
58
58
  };
59
59
  });
60
60
 
61
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.11/node_modules/@gobing-ai/ts-utils/dist/api-response.js
61
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.14/node_modules/@gobing-ai/ts-utils/dist/api-response.js
62
62
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
63
63
  var init_api_response = __esm(() => {
64
64
  init_errors();
@@ -81,10 +81,10 @@ var init_api_response = __esm(() => {
81
81
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
82
82
  });
83
83
 
84
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.11/node_modules/@gobing-ai/ts-utils/dist/cursor.js
84
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.14/node_modules/@gobing-ai/ts-utils/dist/cursor.js
85
85
  var init_cursor = () => {};
86
86
 
87
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.11/node_modules/@gobing-ai/ts-utils/dist/object.js
87
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.14/node_modules/@gobing-ai/ts-utils/dist/object.js
88
88
  function isPlainObject(value) {
89
89
  return typeof value === "object" && value !== null && !Array.isArray(value);
90
90
  }
@@ -100,7 +100,7 @@ function deepMerge(target, source) {
100
100
  return result;
101
101
  }
102
102
 
103
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.11/node_modules/@gobing-ai/ts-utils/dist/output.js
103
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.14/node_modules/@gobing-ai/ts-utils/dist/output.js
104
104
  function processStream(name) {
105
105
  const proc = globalThis.process;
106
106
  const stream = proc?.[name];
@@ -121,7 +121,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
121
121
  }
122
122
  var defaultStdoutTarget, defaultStderrTarget;
123
123
 
124
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.11/node_modules/@gobing-ai/ts-utils/dist/index.js
124
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.14/node_modules/@gobing-ai/ts-utils/dist/index.js
125
125
  var init_dist = __esm(() => {
126
126
  init_api_response();
127
127
  init_cursor();
@@ -21743,7 +21743,7 @@ var init_zod = __esm(() => {
21743
21743
  init_external();
21744
21744
  });
21745
21745
 
21746
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/config.js
21746
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/config.js
21747
21747
  function getProcessEnv() {
21748
21748
  return process.env;
21749
21749
  }
@@ -21821,7 +21821,7 @@ var init_config = __esm(() => {
21821
21821
  };
21822
21822
  });
21823
21823
 
21824
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21824
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21825
21825
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
21826
21826
  import { dirname, resolve as resolvePath } from "path";
21827
21827
  function createNodeFileSystem(root) {
@@ -21908,7 +21908,7 @@ function findProjectRoot(startDir) {
21908
21908
  }
21909
21909
  var init_file_system_node = () => {};
21910
21910
 
21911
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21911
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21912
21912
  var DbModuleNotInstalledError;
21913
21913
  var init_db_errors = __esm(() => {
21914
21914
  DbModuleNotInstalledError = class DbModuleNotInstalledError extends Error {
@@ -29099,7 +29099,7 @@ var init_execa = __esm(() => {
29099
29099
  } = getIpcExport());
29100
29100
  });
29101
29101
 
29102
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29102
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29103
29103
  import { isatty } from "tty";
29104
29104
 
29105
29105
  class NodeProcessExecutor {
@@ -29141,7 +29141,11 @@ class NodeProcessExecutor {
29141
29141
  ...options.label !== undefined ? { label: options.label } : {}
29142
29142
  });
29143
29143
  try {
29144
- const result = await execa(options.command, args, execaOptions);
29144
+ const subprocess = execa(options.command, args, execaOptions);
29145
+ const stopGroupCancellation = observeProcessGroupCancellation(subprocess, options.signal);
29146
+ observeOutput(subprocess.stdout, "stdout", options.onOutput);
29147
+ observeOutput(subprocess.stderr, "stderr", options.onOutput);
29148
+ const result = await subprocess.finally(stopGroupCancellation);
29145
29149
  const processResult = {
29146
29150
  command: options.command,
29147
29151
  args,
@@ -29367,9 +29371,42 @@ function buildExecaOptions(opts) {
29367
29371
  ...opts.env !== undefined ? { env: opts.env } : {},
29368
29372
  ...opts.timeout !== undefined ? { timeout: opts.timeout } : {},
29369
29373
  ...opts.maxOutput !== undefined ? { maxBuffer: opts.maxOutput } : {},
29370
- ...opts.signal !== undefined ? { cancelSignal: opts.signal } : {}
29374
+ ...opts.signal !== undefined ? {
29375
+ cancelSignal: opts.signal,
29376
+ ...process.platform !== "win32" ? { detached: true } : {}
29377
+ } : {}
29371
29378
  };
29372
29379
  }
29380
+ function observeProcessGroupCancellation(subprocess, signal) {
29381
+ const pid = subprocess.pid;
29382
+ if (signal === undefined || process.platform === "win32" || pid === undefined)
29383
+ return () => {};
29384
+ const abort = () => {
29385
+ try {
29386
+ process.kill(-pid, "SIGTERM");
29387
+ } catch {
29388
+ subprocess.kill("SIGTERM");
29389
+ }
29390
+ };
29391
+ if (signal.aborted)
29392
+ abort();
29393
+ else
29394
+ signal.addEventListener("abort", abort, { once: true });
29395
+ return () => signal.removeEventListener("abort", abort);
29396
+ }
29397
+ function observeOutput(stream, name, observer) {
29398
+ if (!stream || !observer)
29399
+ return;
29400
+ stream.on("data", (chunk) => {
29401
+ try {
29402
+ observer({
29403
+ stream: name,
29404
+ chunk: asString(chunk),
29405
+ timestamp: new Date().toISOString()
29406
+ });
29407
+ } catch {}
29408
+ });
29409
+ }
29373
29410
  function asString(value) {
29374
29411
  if (typeof value === "string")
29375
29412
  return value;
@@ -29392,7 +29429,7 @@ var init_process_executor = __esm(() => {
29392
29429
  init_execa();
29393
29430
  });
29394
29431
 
29395
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29432
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29396
29433
  function getNodeFileSystem() {
29397
29434
  if (!_nodeFileSystem)
29398
29435
  _nodeFileSystem = createNodeFileSystem();
@@ -29452,7 +29489,7 @@ var init_runtime_node_bun = __esm(() => {
29452
29489
  };
29453
29490
  });
29454
29491
 
29455
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/context.js
29492
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/context.js
29456
29493
  class RuntimeContext {
29457
29494
  scope;
29458
29495
  runtimeName;
@@ -29522,7 +29559,7 @@ var init_context = __esm(() => {
29522
29559
  init_runtime_node_bun();
29523
29560
  });
29524
29561
 
29525
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/path.js
29562
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/path.js
29526
29563
  function normalizeSeparators(path6) {
29527
29564
  return path6.replaceAll("\\", "/");
29528
29565
  }
@@ -29583,17 +29620,17 @@ var init_path = __esm(() => {
29583
29620
  SEP = globalThis.process?.platform === "win32" ? "\\" : "/";
29584
29621
  });
29585
29622
 
29586
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29623
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29587
29624
  var REMOTE_SCHEMA_MAX_BYTES;
29588
29625
  var init_schema_validation = __esm(() => {
29589
29626
  init_dist2();
29590
29627
  REMOTE_SCHEMA_MAX_BYTES = 5 * 1024 * 1024;
29591
29628
  });
29592
29629
 
29593
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/types.js
29630
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/types.js
29594
29631
  var init_types = () => {};
29595
29632
 
29596
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/index.js
29633
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/index.js
29597
29634
  var init_dist3 = __esm(() => {
29598
29635
  init_config();
29599
29636
  init_context();
@@ -29602,7 +29639,7 @@ var init_dist3 = __esm(() => {
29602
29639
  init_types();
29603
29640
  });
29604
29641
 
29605
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+92240aa39452d4a9/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29642
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+c51d44ed7d8b072c/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29606
29643
  import { Database } from "bun:sqlite";
29607
29644
  var init_bun_sqlite = () => {};
29608
29645
 
@@ -33794,7 +33831,7 @@ var init_bun_sqlite2 = __esm(() => {
33794
33831
  init_session2();
33795
33832
  });
33796
33833
 
33797
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33834
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33798
33835
  var inboxMessages;
33799
33836
  var init_inbox_messages = __esm(() => {
33800
33837
  init_sqlite_core();
@@ -33813,7 +33850,7 @@ var init_inbox_messages = __esm(() => {
33813
33850
  }, (table2) => [index("idx_inbox_messages_to_status").on(table2.toId, table2.status)]);
33814
33851
  });
33815
33852
 
33816
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33853
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33817
33854
  function nowTimestamp() {
33818
33855
  return Date.now();
33819
33856
  }
@@ -33842,7 +33879,7 @@ var init_common3 = __esm(() => {
33842
33879
  appendOnlyColumns = buildAppendOnlyColumns();
33843
33880
  });
33844
33881
 
33845
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33882
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33846
33883
  var queueJobs;
33847
33884
  var init_queue_jobs = __esm(() => {
33848
33885
  init_sqlite_core();
@@ -33862,7 +33899,7 @@ var init_queue_jobs = __esm(() => {
33862
33899
  }, (table2) => [index("queue_jobs_ready_idx").on(table2.status, table2.nextRetryAt, table2.createdAt)]);
33863
33900
  });
33864
33901
 
33865
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33902
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33866
33903
  var exports_runtime = {};
33867
33904
  __export(exports_runtime, {
33868
33905
  queueJobs: () => queueJobs,
@@ -33873,7 +33910,7 @@ var init_runtime = __esm(() => {
33873
33910
  init_queue_jobs();
33874
33911
  });
33875
33912
 
33876
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33913
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33877
33914
  var exports_bun_sqlite = {};
33878
33915
  __export(exports_bun_sqlite, {
33879
33916
  BunSqliteAdapter: () => BunSqliteAdapter
@@ -34162,7 +34199,7 @@ var init_d1 = __esm(() => {
34162
34199
  init_session3();
34163
34200
  });
34164
34201
 
34165
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34202
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34166
34203
  var exports_d1 = {};
34167
34204
  __export(exports_d1, {
34168
34205
  D1Adapter: () => D1Adapter
@@ -34226,7 +34263,7 @@ var init_d12 = __esm(() => {
34226
34263
  init_runtime();
34227
34264
  });
34228
34265
 
34229
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/adapter.js
34266
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/adapter.js
34230
34267
  async function createDbAdapter(config3) {
34231
34268
  switch (config3.driver) {
34232
34269
  case "bun-sqlite": {
@@ -34266,7 +34303,7 @@ var init_drizzle_orm = __esm(() => {
34266
34303
  init_view_common();
34267
34304
  });
34268
34305
 
34269
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34306
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34270
34307
  function compilePredicate(predicate) {
34271
34308
  if ("and" in predicate) {
34272
34309
  const parts = predicate.and.map(compilePredicate).filter((p) => p !== undefined);
@@ -34304,7 +34341,7 @@ var init_query_spec = __esm(() => {
34304
34341
  };
34305
34342
  });
34306
34343
 
34307
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34344
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34308
34345
  function asSelectQuery(query) {
34309
34346
  return query;
34310
34347
  }
@@ -34346,7 +34383,7 @@ var init_base_dao = __esm(() => {
34346
34383
  init_query_spec();
34347
34384
  });
34348
34385
 
34349
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34386
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34350
34387
  var embeddedMigrations;
34351
34388
  var init_embedded_migrations = __esm(() => {
34352
34389
  embeddedMigrations = [
@@ -34378,7 +34415,7 @@ var init_embedded_migrations = __esm(() => {
34378
34415
  ];
34379
34416
  });
34380
34417
 
34381
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34418
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34382
34419
  var EntityDao;
34383
34420
  var init_entity_dao = __esm(() => {
34384
34421
  init_drizzle_orm();
@@ -34540,7 +34577,7 @@ var init_entity_dao = __esm(() => {
34540
34577
  };
34541
34578
  });
34542
34579
 
34543
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34580
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34544
34581
  function isPromiseLike(value) {
34545
34582
  return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
34546
34583
  }
@@ -34713,7 +34750,7 @@ var init_migrator2 = __esm(() => {
34713
34750
  init_migrator();
34714
34751
  });
34715
34752
 
34716
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/migrate.js
34753
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/migrate.js
34717
34754
  async function ensureJournalTable(adapter, table3) {
34718
34755
  await adapter.exec(`CREATE TABLE IF NOT EXISTS "${table3}" (` + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "hash text NOT NULL, " + "created_at numeric" + ")");
34719
34756
  }
@@ -34788,7 +34825,7 @@ var init_migrate = __esm(() => {
34788
34825
  init_embedded_migrations();
34789
34826
  });
34790
34827
 
34791
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34828
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34792
34829
  var QueueJobDao;
34793
34830
  var init_queue_job_dao = __esm(() => {
34794
34831
  init_drizzle_orm();
@@ -34929,7 +34966,7 @@ var init_queue_job_dao = __esm(() => {
34929
34966
  };
34930
34967
  });
34931
34968
 
34932
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/index.js
34969
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/index.js
34933
34970
  var exports_dist = {};
34934
34971
  __export(exports_dist, {
34935
34972
  embeddedMigrations: () => embeddedMigrations,
@@ -37111,7 +37148,8 @@ var init_finding_codes = __esm(() => {
37111
37148
  "L4.uncovered-feature-scenario",
37112
37149
  "L4.verifying-incomplete-tasks",
37113
37150
  "L4.dogfood-missing",
37114
- "L4.scenario-unverified"
37151
+ "L4.scenario-unverified",
37152
+ "L4.stale-line-anchor"
37115
37153
  ];
37116
37154
  FINDING_CODES = {
37117
37155
  L1_MARKDOWN_PARSE: "L1.markdown-parse",
@@ -37154,7 +37192,8 @@ var init_finding_codes = __esm(() => {
37154
37192
  L4_UNCOVERED_FEATURE_SCENARIO: "L4.uncovered-feature-scenario",
37155
37193
  L4_VERIFYING_INCOMPLETE_TASKS: "L4.verifying-incomplete-tasks",
37156
37194
  L4_DOGFOOD_MISSING: "L4.dogfood-missing",
37157
- L4_SCENARIO_UNVERIFIED: "L4.scenario-unverified"
37195
+ L4_SCENARIO_UNVERIFIED: "L4.scenario-unverified",
37196
+ L4_STALE_LINE_ANCHOR: "L4.stale-line-anchor"
37158
37197
  };
37159
37198
  });
37160
37199
 
@@ -37162,6 +37201,9 @@ var init_finding_codes = __esm(() => {
37162
37201
  function folderPathWithDefault(defaultPath) {
37163
37202
  return exports_external.preprocess((v) => v == null ? undefined : v, exports_external.string().default(defaultPath));
37164
37203
  }
37204
+ function normalizeExecutorTier(value) {
37205
+ return value === "capable" ? "capable-1" : value;
37206
+ }
37165
37207
  function normalizeMember(member) {
37166
37208
  return typeof member === "string" ? { executor: member } : { ...member };
37167
37209
  }
@@ -37202,7 +37244,7 @@ function buildConfigFromEnv(env = process.env) {
37202
37244
  }
37203
37245
  });
37204
37246
  }
37205
- var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, AgentExecutorConfigSchema, AGENT_ID_REGEX, TeamMemberConfigSchema, TeamConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, RedactionConfigSchema, spurConfigSchema, configSchema2;
37247
+ var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, EXECUTOR_CAPABILITY_TIERS, executorCapabilityTierSchema, AgentExecutorConfigSchema, AGENT_ID_REGEX, TeamMemberConfigSchema, TeamConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, RedactionConfigSchema, spurConfigSchema, configSchema2;
37206
37248
  var init_src = __esm(() => {
37207
37249
  init_zod();
37208
37250
  init_finding_codes();
@@ -37238,11 +37280,17 @@ var init_src = __esm(() => {
37238
37280
  featuresConfigSchema = exports_external.object({
37239
37281
  dir: folderPathWithDefault(DEFAULT_FEATURES_DIR)
37240
37282
  });
37283
+ EXECUTOR_CAPABILITY_TIERS = ["cheap", "standard", "capable-1", "capable-2", "capable-3"];
37284
+ executorCapabilityTierSchema = exports_external.preprocess((value) => {
37285
+ if (value === undefined || value === null)
37286
+ return;
37287
+ return normalizeExecutorTier(value);
37288
+ }, exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional());
37241
37289
  AgentExecutorConfigSchema = exports_external.object({
37242
37290
  name: exports_external.string().min(1),
37243
37291
  agent: exports_external.string().min(1),
37244
37292
  model: exports_external.string().min(1).optional(),
37245
- tier: exports_external.enum(["cheap", "standard", "capable"]).optional()
37293
+ tier: executorCapabilityTierSchema.optional()
37246
37294
  });
37247
37295
  AGENT_ID_REGEX = /^[a-z][a-z0-9_-]{1,63}$/;
37248
37296
  TeamMemberConfigSchema = exports_external.union([
@@ -37360,7 +37408,7 @@ var init_src = __esm(() => {
37360
37408
  });
37361
37409
  });
37362
37410
 
37363
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/config.js
37411
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/config.js
37364
37412
  function parseYamlObject(text3) {
37365
37413
  let parsed;
37366
37414
  try {
@@ -37487,7 +37535,7 @@ var init_config2 = __esm(() => {
37487
37535
  };
37488
37536
  });
37489
37537
 
37490
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37538
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37491
37539
  import { appendFileSync as appendFileSync3, cpSync as cpSync2, createReadStream as createReadStream3, createWriteStream as createWriteStream3, existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync4, realpathSync as realpathSync2, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
37492
37540
  import { dirname as dirname2, resolve as resolvePath3 } from "path";
37493
37541
  function createNodeFileSystem3(root) {
@@ -37574,7 +37622,7 @@ function findProjectRoot3(startDir) {
37574
37622
  }
37575
37623
  var init_file_system_node2 = () => {};
37576
37624
 
37577
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37625
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37578
37626
  var D1NotConfiguredError2, DbModuleNotInstalledError3;
37579
37627
  var init_db_errors2 = __esm(() => {
37580
37628
  D1NotConfiguredError2 = class D1NotConfiguredError2 extends Error {
@@ -37591,7 +37639,7 @@ var init_db_errors2 = __esm(() => {
37591
37639
  };
37592
37640
  });
37593
37641
 
37594
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37642
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37595
37643
  function createCfFileSystem2() {
37596
37644
  return {
37597
37645
  getProjectRoot: () => "/bundle",
@@ -37630,7 +37678,7 @@ function createCfFileSystem2() {
37630
37678
  }
37631
37679
  var UNSUPPORTED = "FileSystem is not available on Cloudflare Workers. Use D1, KV, or R2 for persistent storage.";
37632
37680
 
37633
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37681
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37634
37682
  var exports_runtime_cf = {};
37635
37683
  __export(exports_runtime_cf, {
37636
37684
  cloudflareWorkersFactory: () => cloudflareWorkersFactory2
@@ -37668,7 +37716,7 @@ var init_runtime_cf = __esm(() => {
37668
37716
  };
37669
37717
  });
37670
37718
 
37671
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37719
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37672
37720
  import { isatty as isatty2 } from "tty";
37673
37721
 
37674
37722
  class NodeProcessExecutor3 {
@@ -37710,7 +37758,11 @@ class NodeProcessExecutor3 {
37710
37758
  ...options.label !== undefined ? { label: options.label } : {}
37711
37759
  });
37712
37760
  try {
37713
- const result = await execa(options.command, args, execaOptions);
37761
+ const subprocess = execa(options.command, args, execaOptions);
37762
+ const stopGroupCancellation = observeProcessGroupCancellation2(subprocess, options.signal);
37763
+ observeOutput2(subprocess.stdout, "stdout", options.onOutput);
37764
+ observeOutput2(subprocess.stderr, "stderr", options.onOutput);
37765
+ const result = await subprocess.finally(stopGroupCancellation);
37714
37766
  const processResult = {
37715
37767
  command: options.command,
37716
37768
  args,
@@ -37976,9 +38028,42 @@ function buildExecaOptions2(opts) {
37976
38028
  ...opts.env !== undefined ? { env: opts.env } : {},
37977
38029
  ...opts.timeout !== undefined ? { timeout: opts.timeout } : {},
37978
38030
  ...opts.maxOutput !== undefined ? { maxBuffer: opts.maxOutput } : {},
37979
- ...opts.signal !== undefined ? { cancelSignal: opts.signal } : {}
38031
+ ...opts.signal !== undefined ? {
38032
+ cancelSignal: opts.signal,
38033
+ ...process.platform !== "win32" ? { detached: true } : {}
38034
+ } : {}
37980
38035
  };
37981
38036
  }
38037
+ function observeProcessGroupCancellation2(subprocess, signal) {
38038
+ const pid = subprocess.pid;
38039
+ if (signal === undefined || process.platform === "win32" || pid === undefined)
38040
+ return () => {};
38041
+ const abort = () => {
38042
+ try {
38043
+ process.kill(-pid, "SIGTERM");
38044
+ } catch {
38045
+ subprocess.kill("SIGTERM");
38046
+ }
38047
+ };
38048
+ if (signal.aborted)
38049
+ abort();
38050
+ else
38051
+ signal.addEventListener("abort", abort, { once: true });
38052
+ return () => signal.removeEventListener("abort", abort);
38053
+ }
38054
+ function observeOutput2(stream, name, observer) {
38055
+ if (!stream || !observer)
38056
+ return;
38057
+ stream.on("data", (chunk) => {
38058
+ try {
38059
+ observer({
38060
+ stream: name,
38061
+ chunk: asString2(chunk),
38062
+ timestamp: new Date().toISOString()
38063
+ });
38064
+ } catch {}
38065
+ });
38066
+ }
37982
38067
  function asString2(value) {
37983
38068
  if (typeof value === "string")
37984
38069
  return value;
@@ -38008,7 +38093,7 @@ var init_process_executor2 = __esm(() => {
38008
38093
  ProcessExecutor2 = NodeProcessExecutor3;
38009
38094
  });
38010
38095
 
38011
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38096
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38012
38097
  var exports_runtime_node_bun = {};
38013
38098
  __export(exports_runtime_node_bun, {
38014
38099
  nodeBunFactory: () => nodeBunFactory3,
@@ -38076,7 +38161,7 @@ var init_runtime_node_bun2 = __esm(() => {
38076
38161
  };
38077
38162
  });
38078
38163
 
38079
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38164
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38080
38165
  function isCloudflareWorkerRuntime2() {
38081
38166
  return globalThis.navigator?.userAgent?.startsWith("Cloudflare-Workers") ?? false;
38082
38167
  }
@@ -38106,7 +38191,7 @@ function _resetRuntimeFactory2() {
38106
38191
  }
38107
38192
  var _factory, _runtimeName;
38108
38193
 
38109
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/context.js
38194
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/context.js
38110
38195
  class RuntimeContext2 {
38111
38196
  scope;
38112
38197
  runtimeName;
@@ -38196,7 +38281,7 @@ var init_context2 = __esm(() => {
38196
38281
  init_runtime_node_bun2();
38197
38282
  });
38198
38283
 
38199
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/path.js
38284
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/path.js
38200
38285
  function normalizeSeparators2(path7) {
38201
38286
  return path7.replaceAll("\\", "/");
38202
38287
  }
@@ -38319,7 +38404,7 @@ var init_path2 = __esm(() => {
38319
38404
  SEP2 = globalThis.process?.platform === "win32" ? "\\" : "/";
38320
38405
  });
38321
38406
 
38322
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38407
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38323
38408
  async function ensureDirForFile2(path7, fs2 = createNodeFileSystem3()) {
38324
38409
  await fs2.ensureDir(dirnamePath(path7));
38325
38410
  }
@@ -38370,7 +38455,7 @@ var init_fs = __esm(() => {
38370
38455
  init_path2();
38371
38456
  });
38372
38457
 
38373
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38458
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38374
38459
  function allocateId() {
38375
38460
  nextIdSeq += 1;
38376
38461
  return `pe_${Date.now().toString(36)}_${nextIdSeq.toString(36)}`;
@@ -38494,7 +38579,7 @@ function createInMemoryProcessRegistry2(options) {
38494
38579
  }
38495
38580
  var nextIdSeq = 0;
38496
38581
 
38497
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38582
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38498
38583
  async function loadStructuredConfig(path7, options = {}) {
38499
38584
  const content = await (options.fileSystem ?? createNodeFileSystem3()).readFile(path7);
38500
38585
  return await parseStructuredConfig(content, path7, options);
@@ -38771,10 +38856,10 @@ var init_schema_validation2 = __esm(() => {
38771
38856
  defaultResolve = typeof Bun !== "undefined" ? (specifier, from) => Bun.resolveSync(specifier, from) : undefined;
38772
38857
  });
38773
38858
 
38774
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/types.js
38859
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/types.js
38775
38860
  var init_types2 = () => {};
38776
38861
 
38777
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/index.js
38862
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/index.js
38778
38863
  var exports_dist2 = {};
38779
38864
  __export(exports_dist2, {
38780
38865
  writeJsonFile: () => writeJsonFile2,
@@ -40923,7 +41008,7 @@ var init_mod = __esm(() => {
40923
41008
  init_config3();
40924
41009
  });
40925
41010
 
40926
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/logger.js
41011
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/logger.js
40927
41012
  function toLogTapeLevel(level) {
40928
41013
  return level === "warn" ? "warning" : level;
40929
41014
  }
@@ -42476,7 +42561,7 @@ var require_src = __commonJS((exports) => {
42476
42561
  };
42477
42562
  });
42478
42563
 
42479
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42564
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42480
42565
  function getTelemetryConfig(configPartial = {}) {
42481
42566
  return {
42482
42567
  enabled: configPartial.enabled ?? CONFIG_DEFAULTS.enabled,
@@ -42512,7 +42597,7 @@ var init_sdk = __esm(() => {
42512
42597
  resolvedConfig = getTelemetryConfig();
42513
42598
  });
42514
42599
 
42515
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42600
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42516
42601
  function isSuppressed(tracer2) {
42517
42602
  return tracer2 === undefined && !getResolvedConfig().enabled;
42518
42603
  }
@@ -42552,7 +42637,7 @@ var init_tracing2 = __esm(() => {
42552
42637
  import_api2 = __toESM(require_src(), 1);
42553
42638
  });
42554
42639
 
42555
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42640
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42556
42641
  function getMeter() {
42557
42642
  return import_api3.metrics.getMeter(METER_NAME, METER_VERSION);
42558
42643
  }
@@ -42649,7 +42734,7 @@ var init_metrics = __esm(() => {
42649
42734
  instruments = {};
42650
42735
  });
42651
42736
 
42652
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42737
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42653
42738
  function busLogger() {
42654
42739
  if (!_busLogger)
42655
42740
  _busLogger = getLogger2("event-bus");
@@ -42894,7 +42979,7 @@ var init_event_bus = __esm(() => {
42894
42979
  init_metrics();
42895
42980
  });
42896
42981
 
42897
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
42982
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
42898
42983
  function obsLogger() {
42899
42984
  if (!_obsLogger)
42900
42985
  _obsLogger = getLogger2("event-bus.observers");
@@ -42958,7 +43043,7 @@ var init_default_observers = __esm(() => {
42958
43043
  init_event_bus();
42959
43044
  });
42960
43045
 
42961
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
43046
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
42962
43047
  function parentDir(filePath) {
42963
43048
  const idx = filePath.lastIndexOf("/");
42964
43049
  return idx <= 0 ? "." : filePath.slice(0, idx);
@@ -43056,7 +43141,7 @@ var init_file_observer = __esm(() => {
43056
43141
  init_logger3();
43057
43142
  });
43058
43143
 
43059
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43144
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43060
43145
  function parseInterval(cron) {
43061
43146
  const trimmed = cron.trim();
43062
43147
  const num = Number(trimmed);
@@ -43130,7 +43215,7 @@ var init_node3 = __esm(() => {
43130
43215
  init_metrics();
43131
43216
  });
43132
43217
 
43133
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43218
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43134
43219
  var exports_scheduler_node = {};
43135
43220
  __export(exports_scheduler_node, {
43136
43221
  NodeSchedulerAdapter: () => NodeSchedulerAdapter
@@ -49386,6 +49471,168 @@ var init_errors5 = __esm(() => {
49386
49471
  };
49387
49472
  });
49388
49473
 
49474
+ // ../../packages/app/src/observability/agent-execution.ts
49475
+ class AgentExecutionLifecycle {
49476
+ observer;
49477
+ secrets;
49478
+ heartbeatMs;
49479
+ sequence = 0;
49480
+ correlation;
49481
+ queue = [];
49482
+ draining = false;
49483
+ dropped = 0;
49484
+ heartbeat;
49485
+ startedAt = 0;
49486
+ timeoutMs;
49487
+ outputCarry = { stdout: "", stderr: "" };
49488
+ constructor(observer, correlation, secrets, heartbeatMs = 30000) {
49489
+ this.observer = observer;
49490
+ this.secrets = secrets;
49491
+ this.heartbeatMs = heartbeatMs;
49492
+ this.correlation = correlation ?? {
49493
+ runId: crypto.randomUUID(),
49494
+ executionId: crypto.randomUUID()
49495
+ };
49496
+ }
49497
+ get identity() {
49498
+ return this.correlation;
49499
+ }
49500
+ start(detail) {
49501
+ this.startedAt = Date.now();
49502
+ this.timeoutMs = detail.timeoutMs;
49503
+ this.emit({
49504
+ kind: "started",
49505
+ agent: redactAndBound(detail.agent, this.secrets, 256),
49506
+ ...detail.model !== undefined ? { model: redactAndBound(detail.model, this.secrets, 256) } : {},
49507
+ invocation: redactAndBound(detail.invocation, this.secrets, 512),
49508
+ ...detail.timeoutMs !== undefined ? { timeoutMs: detail.timeoutMs } : {}
49509
+ });
49510
+ if (!this.observer || this.heartbeatMs <= 0)
49511
+ return;
49512
+ this.heartbeat = setInterval(() => {
49513
+ this.drain();
49514
+ this.emit({
49515
+ kind: "heartbeat",
49516
+ elapsedMs: Math.max(0, Date.now() - this.startedAt),
49517
+ ...this.timeoutMs !== undefined ? { timeoutMs: this.timeoutMs } : {}
49518
+ });
49519
+ }, this.heartbeatMs);
49520
+ this.heartbeat.unref?.();
49521
+ }
49522
+ observe(output2) {
49523
+ if (!this.observer)
49524
+ return;
49525
+ const combined = this.outputCarry[output2.stream] + output2.chunk;
49526
+ const { ready, carry } = redactStreamingValue(combined, this.secrets);
49527
+ this.outputCarry[output2.stream] = carry;
49528
+ if (ready === "")
49529
+ return;
49530
+ this.enqueueOutput(output2.stream, ready);
49531
+ }
49532
+ finish(detail) {
49533
+ if (this.heartbeat !== undefined)
49534
+ clearInterval(this.heartbeat);
49535
+ this.heartbeat = undefined;
49536
+ for (const stream of ["stdout", "stderr"]) {
49537
+ const carry = this.outputCarry[stream];
49538
+ this.outputCarry[stream] = "";
49539
+ if (carry !== "")
49540
+ this.enqueueOutput(stream, redactAndBound(carry, this.secrets, MAX_CHUNK_CHARS));
49541
+ }
49542
+ this.drain();
49543
+ if (this.dropped > 0) {
49544
+ this.emit({ kind: "dropped", chunks: this.dropped });
49545
+ this.dropped = 0;
49546
+ }
49547
+ const cancelled = detail.signal !== undefined || detail.reason === "cancelled";
49548
+ this.emit({
49549
+ kind: "finished",
49550
+ outcome: cancelled ? "cancelled" : detail.exitCode === 0 ? "done" : "failed",
49551
+ exitCode: detail.exitCode,
49552
+ durationMs: detail.durationMs,
49553
+ ...detail.signal !== undefined ? { signal: detail.signal } : {},
49554
+ usage: "unavailable",
49555
+ ...detail.reason !== undefined ? { reason: redactAndBound(detail.reason, this.secrets, 512) } : {}
49556
+ });
49557
+ }
49558
+ enqueueOutput(stream, chunk) {
49559
+ if (this.queue.length >= MAX_PENDING_CHUNKS) {
49560
+ this.dropped += 1;
49561
+ return;
49562
+ }
49563
+ this.queue.push(this.makeEvent({
49564
+ kind: "output",
49565
+ stream,
49566
+ chunk: redactAndBound(chunk, this.secrets, MAX_CHUNK_CHARS)
49567
+ }));
49568
+ this.scheduleDrain();
49569
+ }
49570
+ scheduleDrain() {
49571
+ if (this.draining)
49572
+ return;
49573
+ this.draining = true;
49574
+ queueMicrotask(() => this.drain());
49575
+ }
49576
+ drain() {
49577
+ this.draining = false;
49578
+ while (this.queue.length > 0) {
49579
+ const event = this.queue.shift();
49580
+ if (event !== undefined)
49581
+ this.deliver(event);
49582
+ }
49583
+ }
49584
+ emit(detail) {
49585
+ this.deliver(this.makeEvent(detail));
49586
+ }
49587
+ makeEvent(detail) {
49588
+ this.sequence += 1;
49589
+ return {
49590
+ ...detail,
49591
+ schemaVersion: 1,
49592
+ eventId: crypto.randomUUID(),
49593
+ sequence: this.sequence,
49594
+ runId: this.correlation.runId,
49595
+ executionId: this.correlation.executionId,
49596
+ ...this.correlation.actionId !== undefined ? { actionId: this.correlation.actionId } : {},
49597
+ at: new Date().toISOString()
49598
+ };
49599
+ }
49600
+ deliver(event) {
49601
+ try {
49602
+ this.observer?.(event);
49603
+ } catch {}
49604
+ }
49605
+ }
49606
+ function configuredSecretValues(env) {
49607
+ return Object.entries(env).filter(([key, value]) => /(?:secret|token|password|api[_-]?key|credential)/i.test(key) && (value?.length ?? 0) >= 4).map(([, value]) => value);
49608
+ }
49609
+ function redactAndBound(value, secrets, maxChars) {
49610
+ let redacted = value.replace(SECRET_PATTERN, "[REDACTED]");
49611
+ for (const secret of secrets) {
49612
+ if (secret !== "")
49613
+ redacted = redacted.split(secret).join("[REDACTED]");
49614
+ }
49615
+ return redacted.length <= maxChars ? redacted : `${redacted.slice(0, maxChars)}\u2026`;
49616
+ }
49617
+ function redactStreamingValue(value, secrets) {
49618
+ const redacted = redactAndBound(value, secrets, Number.MAX_SAFE_INTEGER);
49619
+ let carryLength = 0;
49620
+ for (const secret of secrets) {
49621
+ for (let length = 1;length < secret.length && length <= redacted.length; length += 1) {
49622
+ if (redacted.endsWith(secret.slice(0, length)))
49623
+ carryLength = Math.max(carryLength, length);
49624
+ }
49625
+ }
49626
+ return {
49627
+ ready: carryLength === 0 ? redacted : redacted.slice(0, -carryLength),
49628
+ carry: carryLength === 0 ? "" : redacted.slice(-carryLength)
49629
+ };
49630
+ }
49631
+ var MAX_CHUNK_CHARS = 4096, MAX_PENDING_CHUNKS = 64, SECRET_PATTERN;
49632
+ var init_agent_execution = __esm(() => {
49633
+ SECRET_PATTERN = /(?:sk-[a-z0-9_-]{8,}|(?:api[_-]?key|token|secret|password)\s*[:=]\s*\S+|bearer\s+\S+)/gi;
49634
+ });
49635
+
49389
49636
  // ../../packages/domain/src/analytics/models.ts
49390
49637
  function resolvePricing(model) {
49391
49638
  if (model === undefined || model.length === 0)
@@ -50663,7 +50910,7 @@ var init_drizzle_zod = __esm(() => {
50663
50910
  };
50664
50911
  });
50665
50912
 
50666
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
50913
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
50667
50914
  function sqlExpressionToText(value) {
50668
50915
  if (typeof value !== "object" || value === null || !("queryChunks" in value)) {
50669
50916
  return;
@@ -50686,7 +50933,7 @@ function getDrizzleTableName(table3) {
50686
50933
  return String(table3[nameSym]);
50687
50934
  }
50688
50935
 
50689
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
50936
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
50690
50937
  function quoteIdent(name) {
50691
50938
  return `"${name.replace(/"/g, '""')}"`;
50692
50939
  }
@@ -50780,7 +51027,7 @@ var init_ddl = __esm(() => {
50780
51027
  init_sqlite_core();
50781
51028
  });
50782
51029
 
50783
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
51030
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
50784
51031
  function defineTable(name, columns2) {
50785
51032
  const table3 = sqliteTable(name, columns2);
50786
51033
  let insert2;
@@ -50814,7 +51061,7 @@ var init_define_table = __esm(() => {
50814
51061
  init_ddl();
50815
51062
  });
50816
51063
 
50817
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.11+3ced2785cbe4d5ed/node_modules/@gobing-ai/ts-db/dist/schema/index.js
51064
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.14+eb0d628435e6547b/node_modules/@gobing-ai/ts-db/dist/schema/index.js
50818
51065
  var init_schema = __esm(() => {
50819
51066
  init_sqlite_core();
50820
51067
  init_define_table();
@@ -51143,6 +51390,15 @@ var init_run_dao = __esm(() => {
51143
51390
  stampMetadata(runId, metadata) {
51144
51391
  return this.adapter.run("UPDATE runs SET metadata_json = ? WHERE id = ?", JSON.stringify(metadata), runId);
51145
51392
  }
51393
+ stampFailureReason(runId, reason) {
51394
+ return this.adapter.run(`UPDATE runs
51395
+ SET metadata_json = json_set(
51396
+ COALESCE(NULLIF(metadata_json, ''), '{}'),
51397
+ '$.failureReason',
51398
+ ?1
51399
+ )
51400
+ WHERE id = ?2`, reason, runId);
51401
+ }
51146
51402
  listStaleRuns(cutoffIso) {
51147
51403
  return this.adapter.queryAll(`SELECT id, status, started_at
51148
51404
  FROM runs
@@ -51390,7 +51646,7 @@ var init_dao = __esm(() => {
51390
51646
  init_workspace_dao();
51391
51647
  });
51392
51648
 
51393
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
51649
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
51394
51650
  var WorkflowValidationError, FSMError, RunCollisionError, WorkflowResumeError;
51395
51651
  var init_errors6 = __esm(() => {
51396
51652
  WorkflowValidationError = class WorkflowValidationError extends Error {
@@ -51425,12 +51681,12 @@ var init_errors6 = __esm(() => {
51425
51681
  };
51426
51682
  });
51427
51683
 
51428
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
51684
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
51429
51685
  var init_event_bus2 = __esm(() => {
51430
51686
  init_event_bus();
51431
51687
  });
51432
51688
 
51433
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/api-client.js
51689
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/api-client.js
51434
51690
  function sanitizeUrlForObservability(url2) {
51435
51691
  try {
51436
51692
  const parsed = new URL(url2);
@@ -51660,12 +51916,12 @@ var init_api_client = __esm(() => {
51660
51916
  };
51661
51917
  });
51662
51918
 
51663
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
51919
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
51664
51920
  var init_telemetry = __esm(() => {
51665
51921
  init_tracing2();
51666
51922
  });
51667
51923
 
51668
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/index.js
51924
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/index.js
51669
51925
  var init_dist6 = __esm(() => {
51670
51926
  init_api_client();
51671
51927
  init_event_bus2();
@@ -51673,7 +51929,7 @@ var init_dist6 = __esm(() => {
51673
51929
  init_telemetry();
51674
51930
  });
51675
51931
 
51676
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
51932
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
51677
51933
  function runtimeBuiltins(workflowName, stateOrNodeId, runId, transitionsTaken, mode) {
51678
51934
  return {
51679
51935
  workflow: workflowName,
@@ -51746,9 +52002,12 @@ class RunLifecycle {
51746
52002
  return await loop(lifecycle);
51747
52003
  }, { attributes: { "workflow.name": workflowName, "workflow.mode": mode } });
51748
52004
  }
51749
- async enter(stateOrNodeId, transitionsTaken, persist = true) {
52005
+ async enter(stateOrNodeId, transitionsTaken, persist = true, vars) {
51750
52006
  if (persist) {
51751
- await this.persistence.saveWorkflowState(this.runId, stateOrNodeId, { transitionsTaken });
52007
+ const data = { transitionsTaken };
52008
+ if (vars !== undefined)
52009
+ data.effectiveVars = vars;
52010
+ await this.persistence.saveWorkflowState(this.runId, stateOrNodeId, data);
51752
52011
  await this.persistence.savePhase(this.runId, stateOrNodeId, "running");
51753
52012
  }
51754
52013
  addSpanEvent("workflow.node.enter", {
@@ -51762,8 +52021,11 @@ class RunLifecycle {
51762
52021
  transitionsTaken
51763
52022
  });
51764
52023
  }
51765
- async commitHop(from, to, trigger, transitionsTaken, phase) {
51766
- await this.persistence.commitTransition(this.runId, from, to, trigger, to, { transitionsTaken }, phase);
52024
+ async commitHop(from, to, trigger, transitionsTaken, phase, vars) {
52025
+ const data = { transitionsTaken };
52026
+ if (vars !== undefined)
52027
+ data.effectiveVars = vars;
52028
+ await this.persistence.commitTransition(this.runId, from, to, trigger, to, data, phase);
51767
52029
  addSpanEvent("workflow.node.transition", {
51768
52030
  runId: this.runId,
51769
52031
  from,
@@ -51820,7 +52082,11 @@ class RunLifecycle {
51820
52082
  this.logger.warn("workflow run failed", { finalState, transitionsTaken, reason });
51821
52083
  return this.result("failed", finalState, transitionsTaken, reason);
51822
52084
  }
51823
- async pause(stateOrNodeId, transitionsTaken) {
52085
+ async pause(stateOrNodeId, transitionsTaken, vars) {
52086
+ const data = { transitionsTaken };
52087
+ if (vars !== undefined)
52088
+ data.effectiveVars = vars;
52089
+ await this.persistence.saveWorkflowState(this.runId, stateOrNodeId, data);
51824
52090
  await this.persistence.savePhase(this.runId, stateOrNodeId, "paused");
51825
52091
  await this.persistence.finalizeRun(this.runId, "paused", new Date().toISOString());
51826
52092
  this.logger.info("workflow run paused", { stateOrNodeId, transitionsTaken });
@@ -51922,7 +52188,7 @@ var init_run_lifecycle = __esm(() => {
51922
52188
  ];
51923
52189
  });
51924
52190
 
51925
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
52191
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
51926
52192
  var RESERVED_VAR_NAMES, IDENTIFIER, VarsSchema, EnvSchema, ActionDefSchema, GuardDefSchema, StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema, WorkflowDefSchema;
51927
52193
  var init_schema2 = __esm(() => {
51928
52194
  init_zod();
@@ -52006,7 +52272,7 @@ var init_schema2 = __esm(() => {
52006
52272
  WorkflowDefSchema = exports_external.union([StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema]);
52007
52273
  });
52008
52274
 
52009
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
52275
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
52010
52276
  async function loadWorkflowDef(path9, options = {}) {
52011
52277
  return parseWorkflowDef(await loadStructuredConfig(path9, options), path9);
52012
52278
  }
@@ -52165,7 +52431,7 @@ var init_config4 = __esm(() => {
52165
52431
  RUNTIME_TEMPLATE_NAMESPACES = new Set(RUNTIME_BUILTIN_KEYS);
52166
52432
  });
52167
52433
 
52168
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
52434
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
52169
52435
  class CapabilityRegistry {
52170
52436
  kind;
52171
52437
  capabilities = new Map;
@@ -52196,7 +52462,7 @@ class CapabilityRegistry {
52196
52462
  }
52197
52463
  }
52198
52464
 
52199
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
52465
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
52200
52466
  function assertRelativeExtensionPath(path9, options = {}) {
52201
52467
  const where = options.sourceName !== undefined ? ` declared by "${options.sourceName}"` : "";
52202
52468
  if (/^([/\\]|[A-Za-z]:[/\\])/.test(path9)) {
@@ -52207,20 +52473,20 @@ function assertRelativeExtensionPath(path9, options = {}) {
52207
52473
  }
52208
52474
  }
52209
52475
 
52210
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
52476
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
52211
52477
  var init_extension_loader = () => {};
52212
52478
 
52213
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
52479
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
52214
52480
  var init_extension = __esm(() => {
52215
52481
  init_extension_loader();
52216
52482
  });
52217
52483
 
52218
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.11+b7f415af47cc46d8/node_modules/@gobing-ai/ts-runtime/dist/extension.js
52484
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.14+1afbae169bbe5102/node_modules/@gobing-ai/ts-runtime/dist/extension.js
52219
52485
  var init_extension2 = __esm(() => {
52220
52486
  init_extension();
52221
52487
  });
52222
52488
 
52223
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
52489
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
52224
52490
  class WorkflowEngineHost {
52225
52491
  lifecycleBus;
52226
52492
  actions = new CapabilityRegistry("workflow action");
@@ -52389,7 +52655,7 @@ var init_host = __esm(() => {
52389
52655
  init_errors6();
52390
52656
  });
52391
52657
 
52392
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
52658
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
52393
52659
  var WORKFLOW_ENGINE_SCHEMA_SQL;
52394
52660
  var init_schema_sql = __esm(() => {
52395
52661
  WORKFLOW_ENGINE_SCHEMA_SQL = `
@@ -52462,7 +52728,7 @@ CREATE TABLE IF NOT EXISTS action_runs (
52462
52728
  `.trim();
52463
52729
  });
52464
52730
 
52465
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
52731
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
52466
52732
  async function applyWorkflowEngineSchema(db2) {
52467
52733
  for (const statement of WORKFLOW_ENGINE_SCHEMA_SQL.split(";")) {
52468
52734
  const sql4 = statement.trim();
@@ -52614,6 +52880,21 @@ class DbWorkflowPersistenceAdapter {
52614
52880
  const row = await this.db.queryFirst("SELECT state FROM workflow_states WHERE run_id = ? ORDER BY created_at DESC, rowid DESC LIMIT 1", runId);
52615
52881
  return row?.state;
52616
52882
  }
52883
+ async loadLatestStateSnapshot(runId) {
52884
+ await this.ensureSchema();
52885
+ const row = await this.db.queryFirst("SELECT state, data_json FROM workflow_states WHERE run_id = ? ORDER BY created_at DESC, rowid DESC LIMIT 1", runId);
52886
+ if (row == null)
52887
+ return;
52888
+ let data = {};
52889
+ if (row.data_json !== null && row.data_json.length > 0) {
52890
+ try {
52891
+ data = JSON.parse(row.data_json);
52892
+ } catch {
52893
+ data = {};
52894
+ }
52895
+ }
52896
+ return { state: row.state, data };
52897
+ }
52617
52898
  async listPausedRuns(options) {
52618
52899
  await this.ensureSchema();
52619
52900
  const where = ["status = 'paused'"];
@@ -52716,6 +52997,12 @@ class MemoryWorkflowPersistenceAdapter {
52716
52997
  const last = this.states.findLast((s) => s.runId === runId);
52717
52998
  return last?.state;
52718
52999
  }
53000
+ async loadLatestStateSnapshot(runId) {
53001
+ const last = this.states.findLast((s) => s.runId === runId);
53002
+ if (last === undefined)
53003
+ return;
53004
+ return { state: last.state, data: last.data };
53005
+ }
52719
53006
  async listPausedRuns(options) {
52720
53007
  let runs2 = [...this.runs.values()].filter((r) => r.status === "paused");
52721
53008
  if (options?.workflowName !== undefined) {
@@ -52730,7 +53017,7 @@ var init_persistence = __esm(() => {
52730
53017
  init_schema_sql();
52731
53018
  });
52732
53019
 
52733
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
53020
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
52734
53021
  function mergeVars(workflowVars = {}, overrideVars = {}) {
52735
53022
  return { ...workflowVars, ...overrideVars };
52736
53023
  }
@@ -52790,7 +53077,7 @@ var init_variables = __esm(() => {
52790
53077
  TEMPLATE_REF = /\$\{([^}]+)\}/g;
52791
53078
  });
52792
53079
 
52793
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
53080
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
52794
53081
  async function runActionStep(action, vars, deps) {
52795
53082
  const { host, persistence, lifecycle, stateOrNodeId, runId } = deps;
52796
53083
  const resolved = resolveTemplates(action.options ?? {}, {
@@ -52805,6 +53092,7 @@ async function runActionStep(action, vars, deps) {
52805
53092
  try {
52806
53093
  result = await host.runAction(action.kind, resolved, {
52807
53094
  runId,
53095
+ actionId,
52808
53096
  workdir: deps.options.workdir,
52809
53097
  stateOrNodeId,
52810
53098
  vars,
@@ -52847,7 +53135,7 @@ var init_action_step = __esm(() => {
52847
53135
  init_variables();
52848
53136
  });
52849
53137
 
52850
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
53138
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
52851
53139
  class StateMachineDriver {
52852
53140
  options;
52853
53141
  constructor(options) {
@@ -52881,7 +53169,7 @@ class StateMachineDriver {
52881
53169
  isResume = false;
52882
53170
  persistedViaHop = true;
52883
53171
  } else {
52884
- await lifecycle.enter(current.id, transitionsTaken, !persistedViaHop);
53172
+ await lifecycle.enter(current.id, transitionsTaken, !persistedViaHop, vars);
52885
53173
  const enter = options.dryRun ? EMPTY_OUTCOME : await runActionSequence(current.onEnter ?? [], vars, {
52886
53174
  host: this.options.host,
52887
53175
  persistence: this.options.persistence,
@@ -52906,7 +53194,7 @@ class StateMachineDriver {
52906
53194
  return await lifecycle.fail(current.id, transitionsTaken, lastActionResult?.error);
52907
53195
  }
52908
53196
  if (current.pause === true) {
52909
- return await lifecycle.pause(current.id, transitionsTaken);
53197
+ return await lifecycle.pause(current.id, transitionsTaken, vars);
52910
53198
  }
52911
53199
  }
52912
53200
  const outbound = workflow.transitions.filter((transition) => transition.from === current?.id);
@@ -52945,7 +53233,7 @@ class StateMachineDriver {
52945
53233
  await lifecycle.commitHop(current.id, nextTransition.to, nextTransition.trigger ?? null, transitionsTaken, {
52946
53234
  phase: nextTransition.to,
52947
53235
  status: "running"
52948
- });
53236
+ }, vars);
52949
53237
  if (transitionsTaken > iterationBound) {
52950
53238
  return await lifecycle.fail(current.id, transitionsTaken, "iteration-bound-exceeded");
52951
53239
  }
@@ -52981,7 +53269,7 @@ var init_state_machine = __esm(() => {
52981
53269
  EMPTY_OUTCOME = { outcome: "completed", result: undefined };
52982
53270
  });
52983
53271
 
52984
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
53272
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
52985
53273
  class TransitionFlowDriver {
52986
53274
  options;
52987
53275
  constructor(options) {
@@ -53015,7 +53303,7 @@ class TransitionFlowDriver {
53015
53303
  isResume = false;
53016
53304
  persistedViaHop = true;
53017
53305
  } else {
53018
- await lifecycle.enter(current.id, transitionsTaken, !persistedViaHop);
53306
+ await lifecycle.enter(current.id, transitionsTaken, !persistedViaHop, vars);
53019
53307
  if (options.dryRun) {
53020
53308
  if (current.action !== undefined) {
53021
53309
  lastActionResult = undefined;
@@ -53045,7 +53333,7 @@ class TransitionFlowDriver {
53045
53333
  }
53046
53334
  }
53047
53335
  if (current.pause === true) {
53048
- return await lifecycle.pause(current.id, transitionsTaken);
53336
+ return await lifecycle.pause(current.id, transitionsTaken, vars);
53049
53337
  }
53050
53338
  }
53051
53339
  const outbound = workflow.edges.filter((edge2) => edge2.from === current?.id);
@@ -53065,7 +53353,7 @@ class TransitionFlowDriver {
53065
53353
  await lifecycle.commitHop(current.id, edge.to, edge.condition?.kind ?? null, transitionsTaken, {
53066
53354
  phase: edge.to,
53067
53355
  status: "running"
53068
- });
53356
+ }, vars);
53069
53357
  if (transitionsTaken > iterationBound) {
53070
53358
  return await lifecycle.fail(current.id, transitionsTaken, "iteration-bound-exceeded");
53071
53359
  }
@@ -53099,7 +53387,7 @@ var init_transition_flow = __esm(() => {
53099
53387
  init_variables();
53100
53388
  });
53101
53389
 
53102
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
53390
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
53103
53391
  class WorkflowService {
53104
53392
  host;
53105
53393
  persistence;
@@ -53189,20 +53477,24 @@ class WorkflowService {
53189
53477
  if (currentState === undefined) {
53190
53478
  throw new WorkflowResumeError(`Run "${runId}" has no persisted state to resume from`);
53191
53479
  }
53480
+ const snapshot = await this.persistence.loadLatestStateSnapshot(runId);
53481
+ const persistedVars = extractEffectiveVars(snapshot?.data);
53482
+ const restoredVars = mergeVars(persistedVars, options?.vars);
53483
+ const mergedOptions = { ...options, vars: restoredVars };
53192
53484
  const extKey = run.external_key ?? undefined;
53193
53485
  await this.persistence.finalizeRun(runId, "running", "");
53194
- const events = this.resolveEvents(options?.events);
53486
+ const events = this.resolveEvents(mergedOptions.events);
53195
53487
  events?.emit("workflow.run.resumed", { runId, node: currentState, externalKey: extKey });
53196
53488
  if (workflow.kind === "transition-flow") {
53197
53489
  return await new TransitionFlowDriver({
53198
53490
  host: this.host,
53199
53491
  persistence: this.persistence
53200
- }).resume(workflow, runId, currentState, extKey, { ...options, events });
53492
+ }).resume(workflow, runId, currentState, extKey, mergedOptions);
53201
53493
  }
53202
53494
  return await new StateMachineDriver({
53203
53495
  host: this.host,
53204
53496
  persistence: this.persistence
53205
- }).resume(workflow, runId, currentState, extKey, { ...options, events });
53497
+ }).resume(workflow, runId, currentState, extKey, mergedOptions);
53206
53498
  }
53207
53499
  async listPausedRuns(options) {
53208
53500
  return await this.persistence.listPausedRuns(options);
@@ -53287,6 +53579,21 @@ class WorkflowService {
53287
53579
  return { allowed: false, ...denial };
53288
53580
  }
53289
53581
  }
53582
+ function extractEffectiveVars(data) {
53583
+ if (data === undefined)
53584
+ return {};
53585
+ const raw = data.effectiveVars;
53586
+ if (raw === undefined || raw === null)
53587
+ return {};
53588
+ if (typeof raw !== "object")
53589
+ return {};
53590
+ const filtered = {};
53591
+ for (const [key, value] of Object.entries(raw)) {
53592
+ if (typeof value === "string")
53593
+ filtered[key] = value;
53594
+ }
53595
+ return filtered;
53596
+ }
53290
53597
  var init_service = __esm(() => {
53291
53598
  init_dist6();
53292
53599
  init_config4();
@@ -53297,7 +53604,7 @@ var init_service = __esm(() => {
53297
53604
  init_variables();
53298
53605
  });
53299
53606
 
53300
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
53607
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
53301
53608
  var init_dist7 = __esm(() => {
53302
53609
  init_config4();
53303
53610
  init_host();
@@ -53306,7 +53613,7 @@ var init_dist7 = __esm(() => {
53306
53613
  init_service();
53307
53614
  });
53308
53615
 
53309
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.11+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
53616
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.14+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
53310
53617
  var HistoryImportError;
53311
53618
  var init_errors7 = __esm(() => {
53312
53619
  HistoryImportError = class HistoryImportError extends Error {
@@ -53319,7 +53626,7 @@ var init_errors7 = __esm(() => {
53319
53626
  };
53320
53627
  });
53321
53628
 
53322
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.11+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
53629
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.14+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
53323
53630
  import { createHash } from "crypto";
53324
53631
  function stableJson(value) {
53325
53632
  if (Array.isArray(value)) {
@@ -53336,7 +53643,7 @@ function sha256(value) {
53336
53643
  }
53337
53644
  var init_hash = () => {};
53338
53645
 
53339
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.11+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
53646
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.14+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
53340
53647
  function redactValue(value, rules = DEFAULT_REDACTION_RULES) {
53341
53648
  if (typeof value === "string") {
53342
53649
  return rules.reduce((current, rule) => current.replace(rule.pattern, rule.replacement), value);
@@ -53373,7 +53680,7 @@ var init_redaction = __esm(() => {
53373
53680
  ];
53374
53681
  });
53375
53682
 
53376
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.11+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
53683
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.14+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
53377
53684
  var HISTORY_IMPORT_SCHEMA_SQL;
53378
53685
  var init_schema_sql2 = __esm(() => {
53379
53686
  HISTORY_IMPORT_SCHEMA_SQL = `
@@ -53460,7 +53767,7 @@ CREATE TABLE IF NOT EXISTS history_etl_openclaw (
53460
53767
  `.trim();
53461
53768
  });
53462
53769
 
53463
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.11+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
53770
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.14+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
53464
53771
  function firstString(...values) {
53465
53772
  for (const value of values) {
53466
53773
  if (typeof value === "string" && value.length > 0)
@@ -53548,7 +53855,7 @@ var init_sources = __esm(() => {
53548
53855
  };
53549
53856
  });
53550
53857
 
53551
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.11+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
53858
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.14+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
53552
53859
  async function applyHistoryImportSchema(db2) {
53553
53860
  for (const statement of HISTORY_IMPORT_SCHEMA_SQL.split(";")) {
53554
53861
  const sql4 = statement.trim();
@@ -53785,13 +54092,13 @@ var init_importer = __esm(() => {
53785
54092
  VALID_TABLE_NAME = /^history_etl_[a-z_]+$/;
53786
54093
  });
53787
54094
 
53788
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.11+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
54095
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.14+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
53789
54096
  var init_dist8 = __esm(() => {
53790
54097
  init_importer();
53791
54098
  init_schema_sql2();
53792
54099
  });
53793
54100
 
53794
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
54101
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
53795
54102
  function collectExtensions(sourceName, sourceDir, extensions) {
53796
54103
  if (extensions === undefined)
53797
54104
  return [];
@@ -53807,7 +54114,7 @@ var init_extensions = __esm(() => {
53807
54114
  init_dist5();
53808
54115
  });
53809
54116
 
53810
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
54117
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
53811
54118
  function createFinding(rule, message, filePath, extras = {}) {
53812
54119
  return {
53813
54120
  ruleId: rule.id,
@@ -53878,7 +54185,7 @@ var init_types3 = __esm(() => {
53878
54185
  });
53879
54186
  });
53880
54187
 
53881
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
54188
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
53882
54189
  async function loadPreset(name, options) {
53883
54190
  const merged = await buildMergedRoots(options.roots.map((root) => resolvePath4(root)), options.fileSystem);
53884
54191
  const presetPath = findMergedPreset(merged, name);
@@ -54093,7 +54400,7 @@ var init_loader2 = __esm(() => {
54093
54400
  FIX_MODE_AUTHORITY = { none: 0, suggest: 1, auto: 2 };
54094
54401
  });
54095
54402
 
54096
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
54403
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
54097
54404
  function normalizeFindingPath(filePath) {
54098
54405
  if (!filePath || isAbsolutePath2(filePath))
54099
54406
  return null;
@@ -54158,7 +54465,7 @@ var init_test_stub_fixer = __esm(() => {
54158
54465
  realFileSystem = createNodeFileSystem3();
54159
54466
  });
54160
54467
 
54161
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
54468
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
54162
54469
  function registerBuiltinFixers(host, exec) {
54163
54470
  const regexFixer = new RegexFixerProvider;
54164
54471
  const pathFixer = new PathFixerProvider;
@@ -54361,7 +54668,7 @@ var init_fixers = __esm(() => {
54361
54668
  };
54362
54669
  });
54363
54670
 
54364
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
54671
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
54365
54672
  function resolveAgentName(input) {
54366
54673
  if (isCanonicalName(input))
54367
54674
  return input;
@@ -54612,7 +54919,7 @@ var init_shims = __esm(() => {
54612
54919
  ALIAS_TO_CANONICAL = Object.fromEntries(Object.values(AGENT_SHIMS).flatMap((shim) => (shim.aliases ?? []).map((alias3) => [alias3, shim.name])));
54613
54920
  });
54614
54921
 
54615
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
54922
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
54616
54923
  function buildIdentityPreamble(ctx) {
54617
54924
  const sections = [
54618
54925
  `You are agent \`${ctx.agentId}\` (${ctx.agentType}) in workspace \`${ctx.workspace}\`.`
@@ -54672,7 +54979,7 @@ var init_identity = __esm(() => {
54672
54979
  init_dist5();
54673
54980
  });
54674
54981
 
54675
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
54982
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
54676
54983
  function isClaudeStyleSlashCommand(input) {
54677
54984
  return SLASH_COMMAND_RE.test(input);
54678
54985
  }
@@ -54700,7 +55007,7 @@ var init_slash_command = __esm(() => {
54700
55007
  SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
54701
55008
  });
54702
55009
 
54703
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
55010
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
54704
55011
  class AiRunner {
54705
55012
  processExecutor;
54706
55013
  defaultCwd;
@@ -54753,7 +55060,12 @@ class AiRunner {
54753
55060
  async invoke(agent, operation, command, options, forceBuffered) {
54754
55061
  const label = `ai-runner.${agent}.${operation}`;
54755
55062
  this.logger.debug("invoke", { label, command: command.command, args: command.args.join(" ") });
54756
- this.events?.emit("agent.invoke.start", { agent, operation, label });
55063
+ this.events?.emit("agent.invoke.start", {
55064
+ agent,
55065
+ operation,
55066
+ label,
55067
+ ...options.correlation !== undefined ? { correlation: options.correlation } : {}
55068
+ });
54757
55069
  const result = await this.processExecutor.run({
54758
55070
  command: command.command,
54759
55071
  args: command.args,
@@ -54762,7 +55074,8 @@ class AiRunner {
54762
55074
  forceBuffered,
54763
55075
  cwd: options.cwd ?? this.defaultCwd,
54764
55076
  timeout: options.timeout ?? this.defaultTimeout,
54765
- ...options.signal !== undefined ? { signal: options.signal } : {}
55077
+ ...options.signal !== undefined ? { signal: options.signal } : {},
55078
+ ...options.onOutput !== undefined ? { onOutput: options.onOutput } : {}
54766
55079
  });
54767
55080
  if (result.exitCode !== 0) {
54768
55081
  this.logger.error("invoke exited non-zero", {
@@ -54777,7 +55090,8 @@ class AiRunner {
54777
55090
  label,
54778
55091
  exitCode: result.exitCode,
54779
55092
  ...result.signal !== undefined ? { signal: result.signal } : {},
54780
- durationMs: result.durationMs
55093
+ durationMs: result.durationMs,
55094
+ ...options.correlation !== undefined ? { correlation: options.correlation } : {}
54781
55095
  });
54782
55096
  return {
54783
55097
  exitCode: result.exitCode,
@@ -54818,7 +55132,7 @@ var init_ai_runner = __esm(() => {
54818
55132
  init_slash_command();
54819
55133
  });
54820
55134
 
54821
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
55135
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
54822
55136
  class AgentDetector {
54823
55137
  runner;
54824
55138
  timeout;
@@ -54894,7 +55208,7 @@ var init_agent_detector = __esm(() => {
54894
55208
  VERSION_PATTERN = /(?<version>\d+\.\d+(?:\.\d+)?)/;
54895
55209
  });
54896
55210
 
54897
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
55211
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
54898
55212
  function validateAgentId(id) {
54899
55213
  if (!/^[a-z][a-z0-9_-]{1,63}$/.test(id)) {
54900
55214
  throw new ValueError(`Invalid agent id "${id}": expected 2-64 chars, lowercase alphanumeric, "_" or "-"`);
@@ -54991,7 +55305,7 @@ var init_agent_spec = __esm(() => {
54991
55305
  };
54992
55306
  });
54993
55307
 
54994
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
55308
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
54995
55309
  function isNonEmpty(value) {
54996
55310
  return value !== undefined && value.trim().length > 0;
54997
55311
  }
@@ -55096,7 +55410,7 @@ var init_auth_shims = __esm(() => {
55096
55410
  };
55097
55411
  });
55098
55412
 
55099
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
55413
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
55100
55414
  class ModelHealthProbeRegistry {
55101
55415
  probes = new Map;
55102
55416
  register(providerPrefix, probe) {
@@ -55204,7 +55518,7 @@ var init_model_health_probe = __esm(() => {
55204
55518
  };
55205
55519
  });
55206
55520
 
55207
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
55521
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
55208
55522
  class DoctorRunner {
55209
55523
  detector;
55210
55524
  runner;
@@ -55341,15 +55655,15 @@ var init_doctor_runner = __esm(() => {
55341
55655
  init_model_health_probe();
55342
55656
  });
55343
55657
 
55344
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
55658
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
55345
55659
  var init_events = () => {};
55346
55660
 
55347
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
55661
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
55348
55662
  function formatMessage(msg) {
55349
55663
  return `[task from=${msg.fromId ?? "operator"} id=${msg.id}] ${msg.body}`;
55350
55664
  }
55351
55665
 
55352
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
55666
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
55353
55667
  import { Buffer as Buffer5 } from "buffer";
55354
55668
 
55355
55669
  class TeamAgentProcess {
@@ -55483,7 +55797,7 @@ var init_team_agent_process = __esm(() => {
55483
55797
  init_dist5();
55484
55798
  });
55485
55799
 
55486
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
55800
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
55487
55801
  class TeamOrchestrator {
55488
55802
  configDir;
55489
55803
  inbox;
@@ -55612,7 +55926,7 @@ var init_team_orchestrator = __esm(() => {
55612
55926
  init_team_agent_process();
55613
55927
  });
55614
55928
 
55615
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.11+267785e00c831d29/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
55929
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.14+127e896e9a498407/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
55616
55930
  var exports_dist3 = {};
55617
55931
  __export(exports_dist3, {
55618
55932
  validateAgentId: () => validateAgentId,
@@ -55660,7 +55974,7 @@ var init_dist9 = __esm(() => {
55660
55974
  init_team_orchestrator();
55661
55975
  });
55662
55976
 
55663
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
55977
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
55664
55978
  function stringArray(value) {
55665
55979
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
55666
55980
  }
@@ -55698,7 +56012,7 @@ function parseInlineFlags(source) {
55698
56012
  return { flags, rest: source.slice(match[0].length) };
55699
56013
  }
55700
56014
 
55701
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
56015
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
55702
56016
  function matchesAny(path9, patterns) {
55703
56017
  if (patterns === undefined || patterns.length === 0)
55704
56018
  return true;
@@ -55746,7 +56060,7 @@ function escapeRegExp(value) {
55746
56060
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
55747
56061
  }
55748
56062
 
55749
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
56063
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
55750
56064
  async function discoverFiles2(options) {
55751
56065
  const fs3 = options.fs ?? createNodeFileSystem3();
55752
56066
  const allFiles = await walkDir2(options.workdir, fs3, DEFAULT_EXCLUDES);
@@ -55774,12 +56088,12 @@ var init_file_discovery = __esm(() => {
55774
56088
  DEFAULT_EXCLUDES = new Set([".git", "node_modules", "dist", ".coverage", ".astro", ".wrangler"]);
55775
56089
  });
55776
56090
 
55777
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
56091
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
55778
56092
  var init_file_utils = __esm(() => {
55779
56093
  init_file_discovery();
55780
56094
  });
55781
56095
 
55782
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
56096
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
55783
56097
  class AgentDetectionEvaluator {
55784
56098
  detector;
55785
56099
  constructor(detector = new AgentDetector) {
@@ -55807,7 +56121,7 @@ var init_agent_detection_evaluator = __esm(() => {
55807
56121
  init_file_utils();
55808
56122
  });
55809
56123
 
55810
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
56124
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
55811
56125
  class CoverageGateEvaluator {
55812
56126
  constructor() {}
55813
56127
  async evaluate(rule, context4) {
@@ -55891,7 +56205,7 @@ var init_coverage_gate_evaluator = __esm(() => {
55891
56205
  init_file_utils();
55892
56206
  });
55893
56207
 
55894
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
56208
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
55895
56209
  class ExitCodeEvaluator {
55896
56210
  executor;
55897
56211
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -55927,7 +56241,7 @@ var init_exit_code_evaluator = __esm(() => {
55927
56241
  init_file_utils();
55928
56242
  });
55929
56243
 
55930
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
56244
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
55931
56245
  class ForbiddenImportEvaluator {
55932
56246
  constructor() {}
55933
56247
  async evaluate(rule, context4) {
@@ -56008,7 +56322,7 @@ var init_forbidden_import_evaluator = __esm(() => {
56008
56322
  init_file_utils();
56009
56323
  });
56010
56324
 
56011
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
56325
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
56012
56326
  class ImportBoundaryEvaluator {
56013
56327
  async evaluate(rule, context4) {
56014
56328
  const config4 = rule.evaluator.config ?? {};
@@ -56101,7 +56415,7 @@ var init_import_boundary_evaluator = __esm(() => {
56101
56415
  init_file_utils();
56102
56416
  });
56103
56417
 
56104
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
56418
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
56105
56419
  class PathEvaluator {
56106
56420
  constructor() {}
56107
56421
  async evaluate(rule, context4) {
@@ -56162,7 +56476,7 @@ var init_path_evaluator = __esm(() => {
56162
56476
  init_file_utils();
56163
56477
  });
56164
56478
 
56165
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
56479
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
56166
56480
  class RegexEvaluator {
56167
56481
  constructor() {}
56168
56482
  async evaluate(rule, context4) {
@@ -56240,7 +56554,7 @@ var init_regex_evaluator = __esm(() => {
56240
56554
  init_file_utils();
56241
56555
  });
56242
56556
 
56243
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
56557
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
56244
56558
  class RipgrepEvaluator {
56245
56559
  executor;
56246
56560
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -56333,7 +56647,7 @@ var init_ripgrep_evaluator = __esm(() => {
56333
56647
  init_file_utils();
56334
56648
  });
56335
56649
 
56336
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
56650
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
56337
56651
  class SchemaArtifactEvaluator {
56338
56652
  constructor() {}
56339
56653
  async evaluate(rule, context4) {
@@ -56411,7 +56725,7 @@ var init_schema_artifact_evaluator = __esm(() => {
56411
56725
  init_file_utils();
56412
56726
  });
56413
56727
 
56414
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
56728
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
56415
56729
  class SecretsScannerEvaluator {
56416
56730
  constructor() {}
56417
56731
  async evaluate(rule, context4) {
@@ -56479,7 +56793,7 @@ var init_secrets_scanner_evaluator = __esm(() => {
56479
56793
  ALL_CATEGORIES = Object.keys(BUILTIN_PATTERNS);
56480
56794
  });
56481
56795
 
56482
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
56796
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
56483
56797
  class SgEvaluator {
56484
56798
  executor;
56485
56799
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -56576,7 +56890,7 @@ var init_sg_evaluator = __esm(() => {
56576
56890
  init_file_utils();
56577
56891
  });
56578
56892
 
56579
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
56893
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
56580
56894
  class TypeScriptTestPathResolver {
56581
56895
  name = "typescript";
56582
56896
  constructor() {}
@@ -56659,7 +56973,7 @@ function testify(rel) {
56659
56973
  return `${dir}test_${base2}`;
56660
56974
  }
56661
56975
 
56662
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
56976
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
56663
56977
  class TestLocationEvaluator {
56664
56978
  resolvers;
56665
56979
  constructor(resolvers) {
@@ -56734,7 +57048,7 @@ var init_test_location_evaluator = __esm(() => {
56734
57048
  TYPESCRIPT_FALLBACK = new TypeScriptTestPathResolver;
56735
57049
  });
56736
57050
 
56737
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
57051
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
56738
57052
  class TsdocExportEvaluator {
56739
57053
  constructor() {}
56740
57054
  async evaluate(rule, context4) {
@@ -56819,7 +57133,7 @@ var init_tsdoc_export_evaluator = __esm(() => {
56819
57133
  };
56820
57134
  });
56821
57135
 
56822
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
57136
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
56823
57137
  class JsonFormatter {
56824
57138
  constructor() {}
56825
57139
  format(result) {
@@ -56827,7 +57141,7 @@ class JsonFormatter {
56827
57141
  }
56828
57142
  }
56829
57143
 
56830
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
57144
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
56831
57145
  class TextFormatter {
56832
57146
  constructor() {}
56833
57147
  format(result) {
@@ -56841,7 +57155,7 @@ class TextFormatter {
56841
57155
  }
56842
57156
  }
56843
57157
 
56844
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
57158
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
56845
57159
  function registerBuiltins(host, executor) {
56846
57160
  const path9 = new PathEvaluator;
56847
57161
  host.evaluators.register("regex", new RegexEvaluator, "builtin");
@@ -56881,7 +57195,7 @@ var init_builtins = __esm(() => {
56881
57195
  init_tsdoc_export_evaluator();
56882
57196
  });
56883
57197
 
56884
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
57198
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
56885
57199
  class RuleEngineHost {
56886
57200
  evaluators;
56887
57201
  formatters;
@@ -56898,7 +57212,7 @@ var init_rule_engine_host = __esm(() => {
56898
57212
  init_extension2();
56899
57213
  });
56900
57214
 
56901
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
57215
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
56902
57216
  class RuleEngine {
56903
57217
  host;
56904
57218
  events;
@@ -57069,7 +57383,7 @@ var init_engine = __esm(() => {
57069
57383
  init_types3();
57070
57384
  });
57071
57385
 
57072
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
57386
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
57073
57387
  async function bundledRulesRoot() {
57074
57388
  if (cachedRoot2 !== undefined)
57075
57389
  return cachedRoot2;
@@ -57120,7 +57434,7 @@ var init_bundled_rules = __esm(() => {
57120
57434
  init_dist5();
57121
57435
  });
57122
57436
 
57123
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
57437
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
57124
57438
  class DbRulePersistenceAdapter {
57125
57439
  db;
57126
57440
  constructor(db2) {
@@ -57154,7 +57468,7 @@ class DbRulePersistenceAdapter {
57154
57468
  }
57155
57469
  }
57156
57470
 
57157
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
57471
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
57158
57472
  var RULE_ENGINE_SCHEMA_SQL = `
57159
57473
  CREATE TABLE IF NOT EXISTS rule_runs (
57160
57474
  id TEXT PRIMARY KEY,
@@ -57200,10 +57514,10 @@ CREATE TABLE IF NOT EXISTS rule_eval_runs (
57200
57514
  CREATE INDEX IF NOT EXISTS idx_rule_eval_runs_run_id ON rule_eval_runs (run_id);
57201
57515
  `;
57202
57516
 
57203
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
57517
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
57204
57518
  var init_persistence2 = () => {};
57205
57519
 
57206
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.11+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
57520
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.14+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
57207
57521
  var init_dist10 = __esm(() => {
57208
57522
  init_extensions();
57209
57523
  init_loader2();
@@ -57402,7 +57716,7 @@ ${SYSTEM_EVENTS_SCHEMA_SQL}
57402
57716
  ];
57403
57717
  });
57404
57718
 
57405
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
57719
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
57406
57720
  function queueLogger() {
57407
57721
  if (!_queueLogger)
57408
57722
  _queueLogger = getLogger2("job-queue");
@@ -57630,7 +57944,7 @@ var init_db_job_queue = __esm(() => {
57630
57944
  init_tracing2();
57631
57945
  });
57632
57946
 
57633
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
57947
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
57634
57948
  var exports_job_queue_db = {};
57635
57949
  __export(exports_job_queue_db, {
57636
57950
  DBQueueConsumer: () => DBQueueConsumer,
@@ -57694,6 +58008,9 @@ function bumpStageSchemaMajor(version3) {
57694
58008
  function bumpStageSchemaMinor(version3) {
57695
58009
  return { major: version3.major, minor: version3.minor + 1 };
57696
58010
  }
58011
+ function normalizeCapabilityTier(value) {
58012
+ return value === LEGACY_CAPABLE_ALIAS ? "capable-1" : value;
58013
+ }
57697
58014
  function isTierEligible(candidateTier, minTier) {
57698
58015
  return TIER_RANK[candidateTier] >= TIER_RANK[minTier];
57699
58016
  }
@@ -57765,7 +58082,7 @@ function parseStageRecord(raw, consumerVersion = STAGE_REGISTRY_SCHEMA_VERSION)
57765
58082
  function getCanonicalStage(idOrAlias) {
57766
58083
  return CANONICAL_STAGE_BY_KEY.get(idOrAlias);
57767
58084
  }
57768
- var STAGE_REGISTRY_SCHEMA_VERSION, stageSchemaVersionSchema, AUTHORITY_LANES, MUTATION_CLASSES, EXECUTION_KINDS, inlineExecutionSchema, subprocessExecutionSchema, deterministicExecutionSchema, hitlExecutionSchema, irreversibleExecutionSchema, executionKindSchema, ARTIFACT_DIRECTIONS, stageArtifactSchema, stageGateSchema, stageRetryPolicySchema, stageModelPolicySchema, TIER_RANK, CONTEXT_LAYER_NAMES, stageContextLayerSchema, stageEventSchema, STAGE_ID_PATTERN, stageRecordSchema, StageRegistryError, REGISTERED_CANONICAL_STAGES, CANONICAL_STAGE_BY_KEY;
58085
+ var STAGE_REGISTRY_SCHEMA_VERSION, stageSchemaVersionSchema, AUTHORITY_LANES, MUTATION_CLASSES, EXECUTION_KINDS, inlineExecutionSchema, subprocessExecutionSchema, deterministicExecutionSchema, hitlExecutionSchema, irreversibleExecutionSchema, executionKindSchema, ARTIFACT_DIRECTIONS, stageArtifactSchema, stageGateSchema, stageRetryPolicySchema, CAPABILITY_TIERS, LEGACY_CAPABLE_ALIAS = "capable", capabilityTierSchema, stageModelPolicySchema, TIER_RANK, CONTEXT_LAYER_NAMES, stageContextLayerSchema, stageEventSchema, STAGE_ID_PATTERN, stageRecordSchema, StageRegistryError, REGISTERED_CANONICAL_STAGES, CANONICAL_STAGE_BY_KEY;
57769
58086
  var init_schema4 = __esm(() => {
57770
58087
  init_zod();
57771
58088
  STAGE_REGISTRY_SCHEMA_VERSION = {
@@ -57839,10 +58156,12 @@ var init_schema4 = __esm(() => {
57839
58156
  terminal_stop: exports_external.enum(["block", "escalate", "fail"]),
57840
58157
  timeout_seconds: exports_external.number().int().positive().optional()
57841
58158
  }).strict();
58159
+ CAPABILITY_TIERS = ["cheap", "standard", "capable-1", "capable-2", "capable-3"];
58160
+ capabilityTierSchema = exports_external.preprocess(normalizeCapabilityTier, exports_external.enum(CAPABILITY_TIERS));
57842
58161
  stageModelPolicySchema = exports_external.object({
57843
- min_tier: exports_external.enum(["cheap", "standard", "capable"]),
58162
+ min_tier: capabilityTierSchema,
57844
58163
  fallback: exports_external.array(exports_external.object({
57845
- tier: exports_external.enum(["cheap", "standard", "capable"]),
58164
+ tier: capabilityTierSchema,
57846
58165
  trigger: exports_external.enum(["gate-fail", "timeout", "insufficient-evidence", "retry-exhausted"])
57847
58166
  }).strict()),
57848
58167
  override_key: exports_external.string().optional()
@@ -57850,7 +58169,9 @@ var init_schema4 = __esm(() => {
57850
58169
  TIER_RANK = {
57851
58170
  cheap: 1,
57852
58171
  standard: 2,
57853
- capable: 3
58172
+ "capable-1": 3,
58173
+ "capable-2": 4,
58174
+ "capable-3": 5
57854
58175
  };
57855
58176
  CONTEXT_LAYER_NAMES = [
57856
58177
  "harness-policy",
@@ -57912,7 +58233,7 @@ var init_schema4 = __esm(() => {
57912
58233
  retry: { max_attempts: 3, terminal_stop: "block" },
57913
58234
  model_policy: {
57914
58235
  min_tier: "standard",
57915
- fallback: [{ tier: "capable", trigger: "gate-fail" }]
58236
+ fallback: [{ tier: "capable-2", trigger: "gate-fail" }]
57916
58237
  },
57917
58238
  context_layers: [],
57918
58239
  observability: [],
@@ -57930,8 +58251,8 @@ var init_schema4 = __esm(() => {
57930
58251
  mutation_class: "corpus",
57931
58252
  retry: { max_attempts: 3, terminal_stop: "block" },
57932
58253
  model_policy: {
57933
- min_tier: "capable",
57934
- fallback: []
58254
+ min_tier: "capable-2",
58255
+ fallback: [{ tier: "capable-3", trigger: "gate-fail" }]
57935
58256
  },
57936
58257
  context_layers: [],
57937
58258
  observability: [],
@@ -57951,8 +58272,8 @@ var init_schema4 = __esm(() => {
57951
58272
  model_policy: {
57952
58273
  min_tier: "standard",
57953
58274
  fallback: [
57954
- { tier: "capable", trigger: "gate-fail" },
57955
- { tier: "capable", trigger: "timeout" }
58275
+ { tier: "capable-1", trigger: "gate-fail" },
58276
+ { tier: "capable-1", trigger: "timeout" }
57956
58277
  ]
57957
58278
  },
57958
58279
  context_layers: [],
@@ -57972,7 +58293,7 @@ var init_schema4 = __esm(() => {
57972
58293
  retry: { max_attempts: 3, terminal_stop: "block" },
57973
58294
  model_policy: {
57974
58295
  min_tier: "standard",
57975
- fallback: [{ tier: "capable", trigger: "gate-fail" }]
58296
+ fallback: [{ tier: "capable-1", trigger: "gate-fail" }]
57976
58297
  },
57977
58298
  context_layers: [],
57978
58299
  observability: [],
@@ -57990,7 +58311,7 @@ var init_schema4 = __esm(() => {
57990
58311
  mutation_class: "verdict",
57991
58312
  retry: { max_attempts: 2, terminal_stop: "escalate" },
57992
58313
  model_policy: {
57993
- min_tier: "capable",
58314
+ min_tier: "capable-1",
57994
58315
  fallback: []
57995
58316
  },
57996
58317
  context_layers: [],
@@ -58010,7 +58331,7 @@ var init_schema4 = __esm(() => {
58010
58331
  retry: { max_attempts: 2, terminal_stop: "block" },
58011
58332
  model_policy: {
58012
58333
  min_tier: "standard",
58013
- fallback: [{ tier: "capable", trigger: "gate-fail" }]
58334
+ fallback: [{ tier: "capable-1", trigger: "gate-fail" }]
58014
58335
  },
58015
58336
  context_layers: [],
58016
58337
  observability: [],
@@ -58029,7 +58350,7 @@ var init_schema4 = __esm(() => {
58029
58350
  retry: { max_attempts: 2, terminal_stop: "block" },
58030
58351
  model_policy: {
58031
58352
  min_tier: "standard",
58032
- fallback: [{ tier: "capable", trigger: "gate-fail" }]
58353
+ fallback: [{ tier: "capable-1", trigger: "gate-fail" }]
58033
58354
  },
58034
58355
  context_layers: [],
58035
58356
  observability: [],
@@ -58047,7 +58368,7 @@ var init_schema4 = __esm(() => {
58047
58368
  mutation_class: "driver",
58048
58369
  retry: { max_attempts: 3, terminal_stop: "block" },
58049
58370
  model_policy: {
58050
- min_tier: "capable",
58371
+ min_tier: "capable-1",
58051
58372
  fallback: []
58052
58373
  },
58053
58374
  context_layers: [],
@@ -59303,6 +59624,9 @@ var init_schema6 = __esm(() => {
59303
59624
  name: exports_external.string().min(1, "name is required"),
59304
59625
  background: exports_external.string().optional(),
59305
59626
  requirements: exports_external.string().optional(),
59627
+ design: exports_external.string().optional(),
59628
+ plan: exports_external.string().optional(),
59629
+ acceptance_criteria: exports_external.string().optional(),
59306
59630
  feature_id: featureId,
59307
59631
  parent_wbs: wbsString,
59308
59632
  priority: exports_external.enum(PRIORITIES).optional(),
@@ -59680,6 +60004,7 @@ __export(exports_src, {
59680
60004
  normalizeTaskStatusSafe: () => normalizeTaskStatusSafe,
59681
60005
  normalizeTaskStatus: () => normalizeTaskStatus,
59682
60006
  normalizeFeatureStatus: () => normalizeFeatureStatus,
60007
+ normalizeCapabilityTier: () => normalizeCapabilityTier,
59683
60008
  mergeStubs: () => mergeStubs,
59684
60009
  matrixEntrySchema: () => matrixEntrySchema,
59685
60010
  matchEtlPayloads: () => matchEtlPayloads,
@@ -59732,6 +60057,7 @@ __export(exports_src, {
59732
60057
  cleanupTempFiles: () => cleanupTempFiles,
59733
60058
  checkLayerStale: () => checkLayerStale,
59734
60059
  checkAcCoverage: () => checkAcCoverage,
60060
+ capabilityTierSchema: () => capabilityTierSchema,
59735
60061
  canonicalJson: () => canonicalJson,
59736
60062
  cacheHitRatio: () => cacheHitRatio,
59737
60063
  bumpStageSchemaMinor: () => bumpStageSchemaMinor,
@@ -59785,6 +60111,7 @@ __export(exports_src, {
59785
60111
  MarkdownDocument: () => MarkdownDocument,
59786
60112
  MUTATION_CLASSES: () => MUTATION_CLASSES,
59787
60113
  MODEL_PRICING: () => MODEL_PRICING,
60114
+ LEGACY_CAPABLE_ALIAS: () => LEGACY_CAPABLE_ALIAS,
59788
60115
  InlineContext: () => InlineContext,
59789
60116
  InboxRecentDao: () => InboxRecentDao,
59790
60117
  InboxMessageDao: () => InboxMessageDao,
@@ -59802,6 +60129,7 @@ __export(exports_src, {
59802
60129
  CLI_SCHEMA_SQL: () => CLI_SCHEMA_SQL,
59803
60130
  CLI_MIGRATION_FILE_MARKER: () => CLI_MIGRATION_FILE_MARKER,
59804
60131
  CLI_MIGRATIONS: () => CLI_MIGRATIONS,
60132
+ CAPABILITY_TIERS: () => CAPABILITY_TIERS,
59805
60133
  CACHEABILITY_CLASSES: () => CACHEABILITY_CLASSES,
59806
60134
  ArtifactDao: () => ArtifactDao,
59807
60135
  ActionRunDao: () => ActionRunDao,
@@ -59887,7 +60215,10 @@ class AgentService {
59887
60215
  return results.some((result) => !result.usable && result.tier === 1) ? 1 : 0;
59888
60216
  }
59889
60217
  async run(prompt, flags, deps) {
59890
- const outcome = await this.executeRun(prompt, flags, deps, { silent: false });
60218
+ const outcome = await this.executeRun(prompt, flags, deps, {
60219
+ silent: false,
60220
+ execution: this.defaultExecutionOptions(flags)
60221
+ });
59891
60222
  if (!outcome.ok) {
59892
60223
  this.ctx.output.error(outcome.message);
59893
60224
  return outcome.exitCode;
@@ -59919,8 +60250,12 @@ class AgentService {
59919
60250
  stderr: result.stderr
59920
60251
  };
59921
60252
  }
59922
- async runTraced(prompt, flags, deps) {
59923
- const outcome = await this.executeRun(prompt, flags, deps, { silent: true, nonInteractive: true });
60253
+ async runTraced(prompt, flags, deps, execution) {
60254
+ const outcome = await this.executeRun(prompt, flags, deps, {
60255
+ silent: true,
60256
+ nonInteractive: true,
60257
+ execution: execution ?? this.defaultExecutionOptions(flags)
60258
+ });
59924
60259
  if (!outcome.ok) {
59925
60260
  return { exitCode: outcome.exitCode, stdout: "", message: outcome.message };
59926
60261
  }
@@ -60029,22 +60364,59 @@ class AgentService {
60029
60364
  let result;
60030
60365
  const controller = new AbortController;
60031
60366
  const onTerminate = () => controller.abort();
60367
+ const onExternalAbort = () => controller.abort();
60368
+ const lifecycle = new AgentExecutionLifecycle(options.execution?.observer, options.execution?.correlation, configuredSecretValues(this.ctx.env), options.execution?.heartbeatMs);
60369
+ lifecycle.start({
60370
+ agent,
60371
+ ...model !== undefined ? { model } : {},
60372
+ invocation: `${invocation.command} ${invocation.argv.join(" ")}`,
60373
+ ...timeoutMs !== undefined ? { timeoutMs } : {}
60374
+ });
60375
+ const dispatchStartedAt = Date.now();
60032
60376
  try {
60033
60377
  process.on("SIGTERM", onTerminate);
60034
60378
  process.on("SIGINT", onTerminate);
60379
+ options.execution?.signal?.addEventListener("abort", onExternalAbort, { once: true });
60380
+ if (options.execution?.signal?.aborted === true)
60381
+ controller.abort();
60035
60382
  result = await runner.runPromptCommand(agent, promptOptions, {
60036
60383
  cwd: cwd || undefined,
60037
60384
  ...timeoutMs !== undefined ? { timeout: timeoutMs } : {},
60038
- signal: controller.signal
60385
+ signal: controller.signal,
60386
+ correlation: lifecycle.identity,
60387
+ onOutput: (output2) => lifecycle.observe(output2)
60039
60388
  });
60040
60389
  } catch (error51) {
60390
+ lifecycle.finish({
60391
+ exitCode: null,
60392
+ durationMs: Date.now() - dispatchStartedAt,
60393
+ ...controller.signal.aborted ? { reason: "cancelled" } : {},
60394
+ ...!controller.signal.aborted ? { reason: error51 instanceof Error ? error51.message : String(error51) } : {}
60395
+ });
60041
60396
  return { ok: false, exitCode: 2, message: error51 instanceof Error ? error51.message : String(error51) };
60042
60397
  } finally {
60043
60398
  process.off("SIGTERM", onTerminate);
60044
60399
  process.off("SIGINT", onTerminate);
60400
+ options.execution?.signal?.removeEventListener("abort", onExternalAbort);
60045
60401
  }
60402
+ lifecycle.finish({
60403
+ exitCode: result.exitCode,
60404
+ durationMs: result.durationMs,
60405
+ ...result.signal !== undefined ? { signal: result.signal } : {},
60406
+ ...controller.signal.aborted && result.signal === undefined ? { reason: "cancelled" } : {}
60407
+ });
60046
60408
  return { ok: true, result, invocation };
60047
60409
  }
60410
+ defaultExecutionOptions(flags) {
60411
+ const runId = stringFlag(flags, "run-id", "") || crypto.randomUUID();
60412
+ const observer = this.ctx.events === undefined ? undefined : (event) => {
60413
+ this.ctx.events?.emit("agent.execution", event);
60414
+ };
60415
+ return {
60416
+ correlation: { runId, executionId: crypto.randomUUID() },
60417
+ ...observer !== undefined ? { observer } : {}
60418
+ };
60419
+ }
60048
60420
  hasWarnedDeprecation = false;
60049
60421
  warnDeprecationOnce(message) {
60050
60422
  if (!this.hasWarnedDeprecation) {
@@ -60350,13 +60722,15 @@ function parseTagsFlag(flags) {
60350
60722
  return tags.length > 0 ? tags : undefined;
60351
60723
  }
60352
60724
  function getExecutorTier(executor) {
60353
- if (executor.tier)
60354
- return executor.tier;
60725
+ if (executor.tier) {
60726
+ const declared = executor.tier;
60727
+ return declared === "capable" ? "capable-1" : declared;
60728
+ }
60355
60729
  const combined = `${executor.name} ${executor.model ?? ""} ${executor.agent}`.toLowerCase();
60356
60730
  if (/\b(cheap|haiku|flash|lite|mini|fast)\b/.test(combined))
60357
60731
  return "cheap";
60358
60732
  if (/\b(capable|opus|pro|sonnet|r1|o1|o3|expert)\b/.test(combined))
60359
- return "capable";
60733
+ return "capable-1";
60360
60734
  return "standard";
60361
60735
  }
60362
60736
  var TRACE_SAFE_SLASH_COMMAND, TRACE_SAFE_SLASH_TOKEN, SENSITIVE_FLAG, SENSITIVE_INLINE_FLAG;
@@ -60364,6 +60738,7 @@ var init_agent_service = __esm(() => {
60364
60738
  init_src2();
60365
60739
  init_dist9();
60366
60740
  init_dist5();
60741
+ init_agent_execution();
60367
60742
  TRACE_SAFE_SLASH_COMMAND = /^(?:\/skill:(?:sp|rd3)-|\/(?:sp|rd3)[:-]|\$(?:sp|rd3)-)[A-Za-z0-9._-]+(?:\s|$)/;
60368
60743
  TRACE_SAFE_SLASH_TOKEN = /^(?:\d{4}|--(?:auto|next|force|bdd)|--(?:mode|fix|focus)|implement|test|review|verify|all|none|blockers-first|quick|requirements|background|constraints|acceptance)$/;
60369
60744
  SENSITIVE_FLAG = /^--?(?:api[-_]?key|authorization|credential|password|secret|token)$/i;
@@ -60898,12 +61273,23 @@ function evaluateDoneTransition(input) {
60898
61273
  if (targetStatus === currentStatus) {
60899
61274
  return { kind: "noop", fromStatus: currentStatus, message: formatNoopMessage(wbs, currentStatus) };
60900
61275
  }
60901
- if (artifact === undefined) {
60902
- return { kind: "allow", reason: "no-artifact" };
60903
- }
60904
61276
  if (forced) {
60905
61277
  return { kind: "allow", reason: "forced" };
60906
61278
  }
61279
+ if (artifact === undefined) {
61280
+ const verdictPath2 = `.spur/run/${wbs}-verdict.json`;
61281
+ return {
61282
+ kind: "deny",
61283
+ verdict: "UNKNOWN",
61284
+ message: [
61285
+ `Cannot transition task ${wbs} to done: missing verify verdict artifact.`,
61286
+ ` task: ${taskFilePath}`,
61287
+ ` verdict: ${verdictPath2} (not found)`,
61288
+ ` remediation: re-run \`/sp:dev-verify ${wbs}\` until PASS (writes the artifact), ` + `or override with \`spur task update ${wbs} done --force-done --reason "<why>"\`.`
61289
+ ].join(`
61290
+ `)
61291
+ };
61292
+ }
60907
61293
  const computed = computeAggregate(artifact);
60908
61294
  const effective = harshnessMax(artifact.verdict, computed);
60909
61295
  if (effective === "PASS") {
@@ -61172,10 +61558,22 @@ var init_planning_check_base = __esm(() => {
61172
61558
  // ../../packages/app/src/services/feature-check.ts
61173
61559
  var exports_feature_check = {};
61174
61560
  __export(exports_feature_check, {
61561
+ defaultVerdictRunDir: () => defaultVerdictRunDir,
61175
61562
  FeatureCheckService: () => FeatureCheckService,
61176
61563
  DEFAULT_FEATURE_MATRIX: () => DEFAULT_FEATURE_MATRIX
61177
61564
  });
61178
61565
  import { dirname as dirname8, join as join7 } from "path";
61566
+ function defaultVerdictRunDir(tasksDir) {
61567
+ const norm = tasksDir.replace(/\\/g, "/");
61568
+ if (/\/docs\/tasks\d*$/.test(norm) || /\/docs\/tasks$/.test(norm)) {
61569
+ return join7(dirname8(dirname8(tasksDir)), ".spur", "run");
61570
+ }
61571
+ return join7(dirname8(tasksDir), ".spur", "run");
61572
+ }
61573
+ function rowMatchesScenario(id, sc) {
61574
+ const stripped = id.replace(/^Scenario:\s*/i, "").trim();
61575
+ return normalizeTitle(id) === sc.normalized || normalizeTitle(stripped) === sc.normalized || id === sc.alias || stripped === sc.alias;
61576
+ }
61179
61577
  var DEFAULT_FEATURE_MATRIX, FeatureCheckService;
61180
61578
  var init_feature_check = __esm(() => {
61181
61579
  init_src2();
@@ -61241,7 +61639,7 @@ var init_feature_check = __esm(() => {
61241
61639
  await this.checkChildrenLimit(featureId2, options.featuresDir, findings);
61242
61640
  }
61243
61641
  const dogfoodDir = options?.dogfoodDir ?? (options?.featuresDir ? join7(dirname8(options.featuresDir), "dogfood") : undefined);
61244
- const runDir = options?.runDir ?? (options?.tasksDir ? join7(dirname8(options.tasksDir), ".spur", "run") : undefined);
61642
+ const runDir = options?.runDir ?? (options?.tasksDir ? defaultVerdictRunDir(options.tasksDir) : undefined);
61245
61643
  await this.runL4(doc2, featureId2, status, options?.tasksDir, dogfoodDir, runDir, findings);
61246
61644
  return { id: featureId2, ...this.summarizeWithStatus(status, findings, strict, options?.severityOverrides) };
61247
61645
  }
@@ -61533,7 +61931,8 @@ var init_feature_check = __esm(() => {
61533
61931
  continue;
61534
61932
  if (artifact.verdict !== "PASS")
61535
61933
  continue;
61536
- const matched = artifact.requirements.find((r) => normalizeTitle(r.id) === sc.normalized || normalizeTitle(r.alias ?? r.id) === sc.normalized || r.id === sc.alias);
61934
+ const rows = [...artifact.requirements, ...artifact.acceptanceCriteria];
61935
+ const matched = rows.find((r) => rowMatchesScenario(r.id, sc));
61537
61936
  if (matched !== undefined && matched.status === "MET")
61538
61937
  return true;
61539
61938
  }
@@ -61545,10 +61944,12 @@ var init_feature_check = __esm(() => {
61545
61944
  const parsed = JSON.parse(raw);
61546
61945
  if (typeof parsed.verdict !== "string")
61547
61946
  return null;
61548
- if (!Array.isArray(parsed.requirements))
61947
+ const pickRows = (arr) => (arr ?? []).filter((r) => typeof r?.id === "string" && typeof r?.status === "string").map((r) => ({ id: r.id, status: r.status }));
61948
+ const requirements = pickRows(parsed.requirements);
61949
+ const acceptanceCriteria = pickRows(parsed.acceptanceCriteria);
61950
+ if (requirements.length === 0 && acceptanceCriteria.length === 0)
61549
61951
  return null;
61550
- const requirements = parsed.requirements.filter((r) => typeof r?.id === "string" && typeof r?.status === "string").map((r) => ({ id: r.id, status: r.status }));
61551
- return { verdict: parsed.verdict, requirements };
61952
+ return { verdict: parsed.verdict, requirements, acceptanceCriteria };
61552
61953
  } catch {
61553
61954
  return null;
61554
61955
  }
@@ -61556,6 +61957,75 @@ var init_feature_check = __esm(() => {
61556
61957
  };
61557
61958
  });
61558
61959
 
61960
+ // ../../packages/app/src/services/task-locator.ts
61961
+ import { resolve as resolvePath5 } from "path";
61962
+ async function readDirIfPresent(fs3, dir) {
61963
+ try {
61964
+ return await fs3.readDir(dir);
61965
+ } catch (error51) {
61966
+ const code = error51.code;
61967
+ if (code === "ENOENT" || code === "ENOTDIR")
61968
+ return [];
61969
+ throw error51;
61970
+ }
61971
+ }
61972
+
61973
+ class TaskLocator {
61974
+ fs;
61975
+ dirs;
61976
+ constructor(source) {
61977
+ this.fs = source.fs;
61978
+ if ("dirs" in source) {
61979
+ this.dirs = [...new Set(source.dirs)];
61980
+ return;
61981
+ }
61982
+ const folderKeys = source.foldersConfig ? Object.keys(source.foldersConfig.folders) : [];
61983
+ this.dirs = [...new Set([source.tasksDir, ...folderKeys.map((key) => source.fs.resolve(key))])];
61984
+ }
61985
+ static forSingleDir(fs3, dir) {
61986
+ return new TaskLocator({ fs: fs3, tasksDir: dir });
61987
+ }
61988
+ static forDirs(fs3, dirs) {
61989
+ return new TaskLocator({ fs: fs3, dirs });
61990
+ }
61991
+ folderDirs() {
61992
+ return this.dirs;
61993
+ }
61994
+ async findByWbs(wbs) {
61995
+ const prefix = `${wbs}_`;
61996
+ for (const dir of this.folderDirs()) {
61997
+ for (const name of await readDirIfPresent(this.fs, dir)) {
61998
+ if (name.startsWith(prefix) && name.endsWith(".md")) {
61999
+ return { wbs, name, filePath: `${dir}/${name}` };
62000
+ }
62001
+ }
62002
+ }
62003
+ return null;
62004
+ }
62005
+ async findPathByWbs(wbs) {
62006
+ return (await this.findByWbs(wbs))?.filePath ?? null;
62007
+ }
62008
+ async exactMatch(target) {
62009
+ const normalized = resolvePath5(target);
62010
+ for (const dir of this.folderDirs()) {
62011
+ for (const name of await readDirIfPresent(this.fs, dir)) {
62012
+ const captured = TASK_FILENAME_RE.exec(name);
62013
+ if (captured === null)
62014
+ continue;
62015
+ const filePath = `${dir}/${name}`;
62016
+ if (resolvePath5(filePath) === normalized) {
62017
+ return { wbs: captured[1], name, filePath };
62018
+ }
62019
+ }
62020
+ }
62021
+ return null;
62022
+ }
62023
+ }
62024
+ var TASK_FILENAME_RE;
62025
+ var init_task_locator = __esm(() => {
62026
+ TASK_FILENAME_RE = /^(\d{4})_(.+)\.md$/;
62027
+ });
62028
+
61559
62029
  // ../../packages/app/src/services/feature-service.ts
61560
62030
  function stripLeadingSectionHeader(body, sectionName) {
61561
62031
  const match = body.match(/^(\s*)#{1,6}\s+(.+?)\s*(?:\n|$)/);
@@ -61746,7 +62216,8 @@ class FeatureService {
61746
62216
  const checkSvc = new FeatureCheckService(this.ctx.fs);
61747
62217
  const res = await checkSvc.check(feature.filePath, featureId2, {
61748
62218
  featuresDir: this.ctx.featuresDir,
61749
- tasksDir: this.ctx.tasksDir
62219
+ tasksDir: this.ctx.tasksDir,
62220
+ runDir: defaultVerdictRunDir(this.ctx.tasksDir)
61750
62221
  });
61751
62222
  const l4Errors = res.findings.filter((f) => f.layer === "L4" && f.severity === "error");
61752
62223
  return { pass: l4Errors.length === 0, findings: res.findings };
@@ -61870,36 +62341,45 @@ class FeatureService {
61870
62341
  results
61871
62342
  };
61872
62343
  }
62344
+ taskLocator() {
62345
+ return new TaskLocator({
62346
+ fs: this.ctx.fs,
62347
+ tasksDir: this.ctx.tasksDir,
62348
+ foldersConfig: this.ctx.foldersConfig
62349
+ });
62350
+ }
61873
62351
  async collectTasksByFeature() {
61874
62352
  const byFeature = new Map;
61875
- let names;
61876
- try {
61877
- names = await this.ctx.fs.readDir(this.ctx.tasksDir);
61878
- } catch {
61879
- return byFeature;
61880
- }
61881
- for (const name of names) {
61882
- if (!/^\d{4}_.+\.md$/.test(name))
61883
- continue;
61884
- const wbs = name.match(/^(\d{4})_/)?.[1];
61885
- if (!wbs)
61886
- continue;
62353
+ for (const dir of this.taskLocator().folderDirs()) {
62354
+ let names;
61887
62355
  try {
61888
- const raw = await this.ctx.fs.readFile(`${this.ctx.tasksDir}/${name}`);
61889
- const doc2 = MarkdownDocument.parse(raw, "task");
61890
- const fm = doc2.frontmatterData ?? {};
61891
- const fid = fm.feature_id ?? fm["feature-id"];
61892
- if (fid === undefined)
62356
+ names = await this.ctx.fs.readDir(dir);
62357
+ } catch {
62358
+ continue;
62359
+ }
62360
+ for (const name of names) {
62361
+ if (!/^\d{4}_.+\.md$/.test(name))
61893
62362
  continue;
61894
- const row = {
61895
- wbs,
61896
- name: fm.name ?? wbs,
61897
- status: fm.status ?? "backlog"
61898
- };
61899
- const list = byFeature.get(fid) ?? [];
61900
- list.push(row);
61901
- byFeature.set(fid, list);
61902
- } catch {}
62363
+ const wbs = name.match(/^(\d{4})_/)?.[1];
62364
+ if (!wbs)
62365
+ continue;
62366
+ try {
62367
+ const raw = await this.ctx.fs.readFile(`${dir}/${name}`);
62368
+ const doc2 = MarkdownDocument.parse(raw, "task");
62369
+ const fm = doc2.frontmatterData ?? {};
62370
+ const fid = fm.feature_id ?? fm["feature-id"];
62371
+ if (fid === undefined)
62372
+ continue;
62373
+ const row = {
62374
+ wbs,
62375
+ name: fm.name ?? wbs,
62376
+ status: fm.status ?? "backlog"
62377
+ };
62378
+ const list = byFeature.get(fid) ?? [];
62379
+ list.push(row);
62380
+ byFeature.set(fid, list);
62381
+ } catch {}
62382
+ }
61903
62383
  }
61904
62384
  for (const list of byFeature.values()) {
61905
62385
  list.sort((a2, b) => a2.wbs.localeCompare(b.wbs));
@@ -61997,26 +62477,29 @@ class FeatureService {
61997
62477
  }
61998
62478
  async tasksWithFeatureIds(ids) {
61999
62479
  const out = [];
62000
- let names;
62001
- try {
62002
- names = await this.ctx.fs.readDir(this.ctx.tasksDir);
62003
- } catch {
62004
- return out;
62005
- }
62006
- for (const name of names) {
62007
- if (!/^\d{4}_.+\.md$/.test(name))
62008
- continue;
62009
- const wbs = name.match(/^(\d{4})_/)?.[1];
62010
- if (!wbs)
62011
- continue;
62480
+ for (const dir of this.taskLocator().folderDirs()) {
62481
+ let names;
62012
62482
  try {
62013
- const raw = await this.ctx.fs.readFile(`${this.ctx.tasksDir}/${name}`);
62014
- const fm = MarkdownDocument.parse(raw, "task").frontmatterData ?? {};
62015
- const fid = fm.feature_id ?? fm["feature-id"];
62016
- if (fid !== undefined && ids.has(fid)) {
62017
- out.push({ wbs, path: `${this.ctx.tasksDir}/${name}`, featureId: fid });
62018
- }
62019
- } catch {}
62483
+ names = await this.ctx.fs.readDir(dir);
62484
+ } catch {
62485
+ continue;
62486
+ }
62487
+ for (const name of names) {
62488
+ if (!/^\d{4}_.+\.md$/.test(name))
62489
+ continue;
62490
+ const wbs = name.match(/^(\d{4})_/)?.[1];
62491
+ if (!wbs)
62492
+ continue;
62493
+ try {
62494
+ const path9 = `${dir}/${name}`;
62495
+ const raw = await this.ctx.fs.readFile(path9);
62496
+ const fm = MarkdownDocument.parse(raw, "task").frontmatterData ?? {};
62497
+ const fid = fm.feature_id ?? fm["feature-id"];
62498
+ if (fid !== undefined && ids.has(fid)) {
62499
+ out.push({ wbs, path: path9, featureId: fid });
62500
+ }
62501
+ } catch {}
62502
+ }
62020
62503
  }
62021
62504
  out.sort((a2, b) => a2.wbs.localeCompare(b.wbs));
62022
62505
  return out;
@@ -62192,6 +62675,7 @@ var FEATURE_FILE_RE;
62192
62675
  var init_feature_service = __esm(() => {
62193
62676
  init_src2();
62194
62677
  init_feature_check();
62678
+ init_task_locator();
62195
62679
  FEATURE_FILE_RE = /^([A-Z][1-9]*)_(.+)\.md$/;
62196
62680
  });
62197
62681
 
@@ -63636,75 +64120,6 @@ var init_system_event_emitter = __esm(() => {
63636
64120
  init_system_event_tap();
63637
64121
  });
63638
64122
 
63639
- // ../../packages/app/src/services/task-locator.ts
63640
- import { resolve as resolvePath5 } from "path";
63641
- async function readDirIfPresent(fs3, dir) {
63642
- try {
63643
- return await fs3.readDir(dir);
63644
- } catch (error51) {
63645
- const code = error51.code;
63646
- if (code === "ENOENT" || code === "ENOTDIR")
63647
- return [];
63648
- throw error51;
63649
- }
63650
- }
63651
-
63652
- class TaskLocator {
63653
- fs;
63654
- dirs;
63655
- constructor(source) {
63656
- this.fs = source.fs;
63657
- if ("dirs" in source) {
63658
- this.dirs = [...new Set(source.dirs)];
63659
- return;
63660
- }
63661
- const folderKeys = source.foldersConfig ? Object.keys(source.foldersConfig.folders) : [];
63662
- this.dirs = [...new Set([source.tasksDir, ...folderKeys.map((key) => source.fs.resolve(key))])];
63663
- }
63664
- static forSingleDir(fs3, dir) {
63665
- return new TaskLocator({ fs: fs3, tasksDir: dir });
63666
- }
63667
- static forDirs(fs3, dirs) {
63668
- return new TaskLocator({ fs: fs3, dirs });
63669
- }
63670
- folderDirs() {
63671
- return this.dirs;
63672
- }
63673
- async findByWbs(wbs) {
63674
- const prefix = `${wbs}_`;
63675
- for (const dir of this.folderDirs()) {
63676
- for (const name of await readDirIfPresent(this.fs, dir)) {
63677
- if (name.startsWith(prefix) && name.endsWith(".md")) {
63678
- return { wbs, name, filePath: `${dir}/${name}` };
63679
- }
63680
- }
63681
- }
63682
- return null;
63683
- }
63684
- async findPathByWbs(wbs) {
63685
- return (await this.findByWbs(wbs))?.filePath ?? null;
63686
- }
63687
- async exactMatch(target) {
63688
- const normalized = resolvePath5(target);
63689
- for (const dir of this.folderDirs()) {
63690
- for (const name of await readDirIfPresent(this.fs, dir)) {
63691
- const captured = TASK_FILENAME_RE.exec(name);
63692
- if (captured === null)
63693
- continue;
63694
- const filePath = `${dir}/${name}`;
63695
- if (resolvePath5(filePath) === normalized) {
63696
- return { wbs: captured[1], name, filePath };
63697
- }
63698
- }
63699
- }
63700
- return null;
63701
- }
63702
- }
63703
- var TASK_FILENAME_RE;
63704
- var init_task_locator = __esm(() => {
63705
- TASK_FILENAME_RE = /^(\d{4})_(.+)\.md$/;
63706
- });
63707
-
63708
64123
  // ../../packages/app/src/services/task-check.ts
63709
64124
  import { dirname as dirname9, join as join9 } from "path";
63710
64125
  function isPlaceholderBody(body) {
@@ -63764,6 +64179,36 @@ function isProseOnlyReview(body) {
63764
64179
  return !stripped.split(`
63765
64180
  `).some((l) => l.includes("|"));
63766
64181
  }
64182
+ function resolveProjectRootFromTasksDir(tasksDir) {
64183
+ const norm = tasksDir.replace(/\\/g, "/");
64184
+ if (/\/docs\/tasks\d*$/.test(norm) || /\/docs\/tasks$/.test(norm)) {
64185
+ return dirname9(dirname9(tasksDir));
64186
+ }
64187
+ return dirname9(tasksDir);
64188
+ }
64189
+ function extractBacktickLineAnchors(body) {
64190
+ const out = [];
64191
+ const re = /`([^`\n]+?:(\d+)(?:-(\d+))?)`/g;
64192
+ let m = re.exec(body);
64193
+ while (m !== null) {
64194
+ const raw = m[1] ?? "";
64195
+ const startStr = m[2];
64196
+ const endStr = m[3];
64197
+ if (startStr) {
64198
+ const pathPart = raw.replace(/:(\d+)(?:-(\d+))?$/, "");
64199
+ const hasExt = /\.\w{1,8}$/.test(pathPart.split("/").pop() ?? "");
64200
+ if (pathPart && !pathPart.includes("://") && hasExt) {
64201
+ const startLine = Number(startStr);
64202
+ const endLine = endStr !== undefined ? Number(endStr) : undefined;
64203
+ if (Number.isFinite(startLine) && startLine >= 1) {
64204
+ out.push({ raw, path: pathPart, startLine, endLine });
64205
+ }
64206
+ }
64207
+ }
64208
+ m = re.exec(body);
64209
+ }
64210
+ return out;
64211
+ }
63767
64212
  function hasAdjacentFileLineColumns(body) {
63768
64213
  const lines = body.split(`
63769
64214
  `);
@@ -63959,6 +64404,7 @@ var init_task_check = __esm(() => {
63959
64404
  });
63960
64405
  }
63961
64406
  }
64407
+ await this.checkLineAnchors(doc2, tasksDir, findings);
63962
64408
  const featureId2 = fm.feature_id ?? fm["feature-id"];
63963
64409
  const parentWbs = fm.parent_wbs ?? fm["parent-wbs"];
63964
64410
  const deps = fm.dependencies;
@@ -64194,6 +64640,54 @@ var init_task_check = __esm(() => {
64194
64640
  return null;
64195
64641
  }
64196
64642
  }
64643
+ async checkLineAnchors(doc2, tasksDir, findings) {
64644
+ const projectRoot = resolveProjectRootFromTasksDir(tasksDir);
64645
+ for (const section of ["Testing", "Solution"]) {
64646
+ const body = doc2.getSection(section);
64647
+ if (body === null || isPlaceholderBody(body))
64648
+ continue;
64649
+ const citations = extractBacktickLineAnchors(body);
64650
+ let reported = 0;
64651
+ for (const cite of citations) {
64652
+ if (reported >= 5)
64653
+ break;
64654
+ const abs = join9(projectRoot, cite.path);
64655
+ let exists2 = false;
64656
+ try {
64657
+ exists2 = await this.fs.exists(abs);
64658
+ } catch {
64659
+ exists2 = false;
64660
+ }
64661
+ if (!exists2) {
64662
+ findings.push({
64663
+ layer: "L4",
64664
+ code: FINDING_CODES.L4_STALE_LINE_ANCHOR,
64665
+ severity: "warning",
64666
+ section,
64667
+ message: `Stale line anchor \`${cite.raw}\` \u2014 file not found at ${cite.path} (from project root)`
64668
+ });
64669
+ reported++;
64670
+ continue;
64671
+ }
64672
+ try {
64673
+ const raw = await this.fs.readFile(abs);
64674
+ const lineCount = raw.split(`
64675
+ `).length;
64676
+ const end = cite.endLine ?? cite.startLine;
64677
+ if (cite.startLine < 1 || end > lineCount) {
64678
+ findings.push({
64679
+ layer: "L4",
64680
+ code: FINDING_CODES.L4_STALE_LINE_ANCHOR,
64681
+ severity: "warning",
64682
+ section,
64683
+ message: `Stale line anchor \`${cite.raw}\` \u2014 line ${cite.startLine}${cite.endLine ? `-${cite.endLine}` : ""} outside file (${lineCount} lines)`
64684
+ });
64685
+ reported++;
64686
+ }
64687
+ } catch {}
64688
+ }
64689
+ }
64690
+ }
64197
64691
  async findChildren(tasksDir, wbs) {
64198
64692
  const kids = [];
64199
64693
  for (const dir of this.locatorFor(tasksDir).folderDirs()) {
@@ -64597,9 +65091,24 @@ function renderCreatedTaskContent(params) {
64597
65091
  if (params.tags !== undefined && params.tags.length > 0) {
64598
65092
  content = patchFrontmatterField(content, "tags", `[${params.tags.map((tag) => JSON.stringify(tag)).join(", ")}]`);
64599
65093
  }
65094
+ const sectionPatches = {};
64600
65095
  if ((params.requirements ?? "").trim() !== "") {
65096
+ sectionPatches.Requirements = bulletizeRequirements(params.requirements ?? "");
65097
+ }
65098
+ if ((params.design ?? "").trim() !== "") {
65099
+ sectionPatches.Design = (params.design ?? "").trim();
65100
+ }
65101
+ if ((params.plan ?? "").trim() !== "") {
65102
+ sectionPatches.Plan = (params.plan ?? "").trim();
65103
+ }
65104
+ if ((params.acceptanceCriteria ?? "").trim() !== "") {
65105
+ sectionPatches["Acceptance Criteria"] = (params.acceptanceCriteria ?? "").trim();
65106
+ }
65107
+ if (Object.keys(sectionPatches).length > 0) {
64601
65108
  const doc2 = MarkdownDocument.parse(content, "task");
64602
- doc2.replaceSection("Requirements", bulletizeRequirements(params.requirements ?? ""));
65109
+ for (const [section, body] of Object.entries(sectionPatches)) {
65110
+ doc2.replaceSection(section, body);
65111
+ }
64603
65112
  content = doc2.serialize();
64604
65113
  }
64605
65114
  return content;
@@ -65116,7 +65625,7 @@ ${issues}`);
65116
65625
  if (!background && item.feature_id !== undefined && item.feature_id !== null) {
65117
65626
  background = await this.deriveBackground(item.feature_id);
65118
65627
  }
65119
- const hasSpec = background !== "" || (item.requirements ?? "").trim() !== "";
65628
+ const hasSpec = background !== "" || (item.requirements ?? "").trim() !== "" || (item.design ?? "").trim() !== "" || (item.plan ?? "").trim() !== "" || (item.acceptance_criteria ?? "").trim() !== "";
65120
65629
  const status = hasSpec ? "todo" : "backlog";
65121
65630
  const variant = item.template ?? (item.feature_id !== undefined && item.feature_id !== null ? "feature-impl" : DEFAULT_TASK_VARIANT);
65122
65631
  return this.writeService.createAllocated(folder, async () => {
@@ -65138,7 +65647,10 @@ ${issues}`);
65138
65647
  parentWbs: item.parent_wbs ?? undefined,
65139
65648
  priority: item.priority,
65140
65649
  tags: item.tags,
65141
- requirements: item.requirements
65650
+ requirements: item.requirements,
65651
+ design: item.design,
65652
+ plan: item.plan,
65653
+ acceptanceCriteria: item.acceptance_criteria
65142
65654
  });
65143
65655
  const ref2 = { kind: "task", id: wbs, filePath, folder };
65144
65656
  return { ref: ref2, content: content2 };
@@ -65162,6 +65674,15 @@ ${issues}`);
65162
65674
  if ((item.requirements ?? "").trim() !== "") {
65163
65675
  taskBodies.Requirements = bulletizeRequirements(item.requirements ?? "");
65164
65676
  }
65677
+ if ((item.design ?? "").trim() !== "") {
65678
+ taskBodies.Design = (item.design ?? "").trim();
65679
+ }
65680
+ if ((item.plan ?? "").trim() !== "") {
65681
+ taskBodies.Plan = (item.plan ?? "").trim();
65682
+ }
65683
+ if ((item.acceptance_criteria ?? "").trim() !== "") {
65684
+ taskBodies["Acceptance Criteria"] = (item.acceptance_criteria ?? "").trim();
65685
+ }
65165
65686
  const content = buildTaskSkeleton({
65166
65687
  wbs,
65167
65688
  title: item.name,
@@ -66274,6 +66795,247 @@ var init_token_ledger_watcher = __esm(() => {
66274
66795
  init_token_ledger_service();
66275
66796
  });
66276
66797
 
66798
+ // ../../packages/app/src/workflow/steering.ts
66799
+ class WorkflowSteeringController {
66800
+ onAck;
66801
+ secrets;
66802
+ allowedActors;
66803
+ onState;
66804
+ active;
66805
+ seen = new Set;
66806
+ constructor(onAck, secrets = [], allowedActors = new Set(["operator"]), onState) {
66807
+ this.onAck = onAck;
66808
+ this.secrets = secrets;
66809
+ this.allowedActors = allowedActors;
66810
+ this.onState = onState;
66811
+ }
66812
+ get snapshot() {
66813
+ const active = this.active;
66814
+ return active === undefined ? undefined : {
66815
+ runId: active.runId,
66816
+ actionId: active.actionId,
66817
+ state: active.state,
66818
+ version: active.version
66819
+ };
66820
+ }
66821
+ begin(runId, actionId, policy) {
66822
+ this.active = {
66823
+ runId,
66824
+ actionId,
66825
+ state: "running",
66826
+ version: 1,
66827
+ attempts: 1,
66828
+ lastOk: false,
66829
+ policy,
66830
+ controller: new AbortController
66831
+ };
66832
+ this.publishState(this.active);
66833
+ return this.active.controller.signal;
66834
+ }
66835
+ async boundary(ok) {
66836
+ const active = this.requireActive();
66837
+ active.lastOk = ok;
66838
+ if (active.controller.signal.aborted)
66839
+ return { operation: "abort" };
66840
+ if (!active.policy.boundary)
66841
+ return { operation: "continue" };
66842
+ active.state = "boundary";
66843
+ active.version += 1;
66844
+ this.publishState(active);
66845
+ return await new Promise((resolve2) => {
66846
+ const settle = (decision) => {
66847
+ clearTimeout(timer);
66848
+ resolve2(decision);
66849
+ };
66850
+ const timer = setTimeout(() => {
66851
+ if (active.resolve !== settle)
66852
+ return;
66853
+ active.resolve = undefined;
66854
+ this.acceptDefault(active, resolve2);
66855
+ }, active.policy.timeoutMs);
66856
+ timer.unref?.();
66857
+ active.resolve = settle;
66858
+ });
66859
+ }
66860
+ nextAttempt() {
66861
+ const active = this.requireActive();
66862
+ active.attempts += 1;
66863
+ active.state = "running";
66864
+ active.version += 1;
66865
+ active.controller = new AbortController;
66866
+ this.publishState(active);
66867
+ return active.controller.signal;
66868
+ }
66869
+ complete() {
66870
+ const active = this.active;
66871
+ if (active === undefined)
66872
+ return;
66873
+ active.state = "completed";
66874
+ active.version += 1;
66875
+ active.resolve = undefined;
66876
+ this.publishState(active);
66877
+ }
66878
+ submit(command) {
66879
+ const active = this.active;
66880
+ if (command.commandId.trim() === "")
66881
+ return this.reject(command, active, "command id is required");
66882
+ if (this.seen.has(command.commandId))
66883
+ return this.reject(command, active, "duplicate command");
66884
+ this.seen.add(command.commandId);
66885
+ if (active === undefined)
66886
+ return this.reject(command, active, "no active action");
66887
+ if (!this.allowedActors.has(command.actor))
66888
+ return this.reject(command, active, "unauthorized actor");
66889
+ const deadlineMs = Date.parse(command.deadlineAt);
66890
+ if (!Number.isFinite(deadlineMs))
66891
+ return this.reject(command, active, "invalid command deadline");
66892
+ if (deadlineMs < Date.now())
66893
+ return this.reject(command, active, "command deadline elapsed");
66894
+ if (command.runId !== active.runId || command.actionId !== active.actionId) {
66895
+ return this.reject(command, active, "target does not match the active action");
66896
+ }
66897
+ if (command.expectedState !== active.state || command.expectedVersion !== active.version) {
66898
+ return this.reject(command, active, "stale state or version");
66899
+ }
66900
+ if (active.state === "completed") {
66901
+ return this.reject(command, active, "completed action history is immutable");
66902
+ }
66903
+ if (command.operation === "abort") {
66904
+ active.controller.abort();
66905
+ active.resolve?.({ operation: "abort" });
66906
+ active.resolve = undefined;
66907
+ return this.accept(command, active);
66908
+ }
66909
+ if (active.state !== "boundary" || active.resolve === undefined) {
66910
+ return this.reject(command, active, "action is not paused at a steering boundary");
66911
+ }
66912
+ if (command.operation === "retry") {
66913
+ const retry = active.policy.retry;
66914
+ if (active.lastOk)
66915
+ return this.reject(command, active, "retry requires a failed attempt");
66916
+ if (retry === undefined || retry.idempotent !== true) {
66917
+ return this.reject(command, active, "unsafe retry: no explicit idempotent retry policy");
66918
+ }
66919
+ if (active.attempts >= retry.maxAttempts) {
66920
+ return this.reject(command, active, "retry limit reached");
66921
+ }
66922
+ }
66923
+ if (command.operation === "note" && (command.note === undefined || command.note.trim() === "")) {
66924
+ return this.reject(command, active, "note text is required");
66925
+ }
66926
+ const note = command.operation === "note" && command.note !== undefined ? redactAndBound(command.note, this.secrets, 1024) : undefined;
66927
+ active.resolve({ operation: command.operation, ...note !== undefined ? { note } : {} });
66928
+ active.resolve = undefined;
66929
+ return this.accept(command, active, note);
66930
+ }
66931
+ submitLine(line, deadlineMs = 30000) {
66932
+ const active = this.active;
66933
+ if (active === undefined)
66934
+ return;
66935
+ const trimmed = line.trim();
66936
+ const [rawOperation, ...rest] = trimmed.split(/\s+/);
66937
+ if (!["continue", "note", "retry", "abort"].includes(rawOperation ?? ""))
66938
+ return;
66939
+ const operation = rawOperation;
66940
+ return this.submit({
66941
+ commandId: crypto.randomUUID(),
66942
+ runId: active.runId,
66943
+ actionId: active.actionId,
66944
+ expectedState: active.state,
66945
+ expectedVersion: active.version,
66946
+ operation,
66947
+ ...operation === "note" ? { note: rest.join(" ") } : {},
66948
+ actor: "operator",
66949
+ deadlineAt: new Date(Date.now() + deadlineMs).toISOString()
66950
+ });
66951
+ }
66952
+ acceptDefault(active, resolve2) {
66953
+ const command = {
66954
+ commandId: crypto.randomUUID(),
66955
+ runId: active.runId,
66956
+ actionId: active.actionId,
66957
+ expectedState: active.state,
66958
+ expectedVersion: active.version,
66959
+ operation: "continue",
66960
+ actor: "system-timeout",
66961
+ deadlineAt: new Date().toISOString()
66962
+ };
66963
+ const ack = {
66964
+ schemaVersion: 1,
66965
+ commandId: command.commandId,
66966
+ runId: command.runId,
66967
+ actionId: command.actionId,
66968
+ operation: command.operation,
66969
+ actor: command.actor,
66970
+ accepted: true,
66971
+ state: active.state,
66972
+ version: active.version,
66973
+ reason: "boundary timeout defaulted to continue",
66974
+ at: new Date().toISOString()
66975
+ };
66976
+ this.onAck?.(ack);
66977
+ resolve2({ operation: "continue" });
66978
+ }
66979
+ accept(command, active, note) {
66980
+ return this.publish({
66981
+ schemaVersion: 1,
66982
+ commandId: command.commandId,
66983
+ runId: command.runId,
66984
+ actionId: command.actionId,
66985
+ operation: command.operation,
66986
+ actor: command.actor,
66987
+ accepted: true,
66988
+ state: active.state,
66989
+ version: active.version,
66990
+ ...note !== undefined ? { note } : {},
66991
+ at: new Date().toISOString()
66992
+ });
66993
+ }
66994
+ reject(command, active, reason) {
66995
+ return this.publish({
66996
+ schemaVersion: 1,
66997
+ commandId: command.commandId,
66998
+ runId: command.runId,
66999
+ actionId: command.actionId,
67000
+ operation: command.operation,
67001
+ actor: command.actor,
67002
+ accepted: false,
67003
+ state: active?.state ?? "completed",
67004
+ version: active?.version ?? 0,
67005
+ reason,
67006
+ at: new Date().toISOString()
67007
+ });
67008
+ }
67009
+ publish(ack) {
67010
+ this.onAck?.(ack);
67011
+ return ack;
67012
+ }
67013
+ requireActive() {
67014
+ if (this.active === undefined)
67015
+ throw new Error("no active steering action");
67016
+ return this.active;
67017
+ }
67018
+ publishState(active) {
67019
+ this.onState?.({
67020
+ runId: active.runId,
67021
+ actionId: active.actionId,
67022
+ state: active.state,
67023
+ version: active.version
67024
+ });
67025
+ }
67026
+ }
67027
+ function parseSteeringPolicy(options) {
67028
+ const boundary2 = options.steeringBoundary === true;
67029
+ const timeoutMs = typeof options.steeringTimeoutMs === "number" && Number.isFinite(options.steeringTimeoutMs) && Number.isInteger(options.steeringTimeoutMs) && options.steeringTimeoutMs > 0 ? Math.min(options.steeringTimeoutMs, MAX_STEERING_TIMEOUT_MS) : 30000;
67030
+ const rawRetry = options.retryPolicy;
67031
+ const retry = typeof rawRetry === "object" && rawRetry !== null && "idempotent" in rawRetry && rawRetry.idempotent === true && "maxAttempts" in rawRetry && typeof rawRetry.maxAttempts === "number" && Number.isFinite(rawRetry.maxAttempts) && Number.isInteger(rawRetry.maxAttempts) && rawRetry.maxAttempts > 1 ? { idempotent: true, maxAttempts: Math.min(rawRetry.maxAttempts, MAX_STEERING_ATTEMPTS) } : undefined;
67032
+ return { boundary: boundary2, timeoutMs, ...retry !== undefined ? { retry } : {} };
67033
+ }
67034
+ var MAX_STEERING_TIMEOUT_MS = 300000, MAX_STEERING_ATTEMPTS = 10;
67035
+ var init_steering = __esm(() => {
67036
+ init_agent_execution();
67037
+ });
67038
+
66277
67039
  // ../../packages/app/src/workflow/actions/agent-run.ts
66278
67040
  import { execFile } from "child_process";
66279
67041
  import { existsSync as existsSync7 } from "fs";
@@ -66282,9 +67044,13 @@ import { dirname as dirname11, isAbsolute as isAbsolute2, join as join12 } from
66282
67044
  import { promisify as promisify3 } from "util";
66283
67045
 
66284
67046
  class AgentRunActionRunner {
67047
+ observabilityBus;
67048
+ steeringController;
66285
67049
  kind = KIND;
66286
67050
  agentService;
66287
- constructor(agentService) {
67051
+ constructor(agentService, observabilityBus, steeringController) {
67052
+ this.observabilityBus = observabilityBus;
67053
+ this.steeringController = steeringController;
66288
67054
  this.agentService = agentService;
66289
67055
  }
66290
67056
  async execute(options, context4) {
@@ -66327,7 +67093,44 @@ class AgentRunActionRunner {
66327
67093
  const expectFile = asOptionalString(options.expectFile);
66328
67094
  const capture = asOptionalBoolean(options.capture) || answerFile !== undefined;
66329
67095
  const agentLabel = agent ?? "<default>";
66330
- const traced = await this.agentService.runTraced(input, flags);
67096
+ const observer = this.observabilityBus === undefined ? undefined : (event2) => {
67097
+ this.observabilityBus?.emit("workflow.agent", event2);
67098
+ };
67099
+ const actionId = context4.actionId ?? `${context4.runId}:${context4.stateOrNodeId}`;
67100
+ const steeringPolicy = parseSteeringPolicy(options);
67101
+ let steeringSignal = this.steeringController?.begin(context4.runId, actionId, steeringPolicy);
67102
+ let steeringNote;
67103
+ let traced;
67104
+ while (true) {
67105
+ traced = await this.agentService.runTraced(input, flags, undefined, {
67106
+ correlation: {
67107
+ runId: context4.runId,
67108
+ executionId: crypto.randomUUID(),
67109
+ actionId
67110
+ },
67111
+ ...observer !== undefined ? { observer } : {},
67112
+ ...steeringSignal !== undefined ? { signal: steeringSignal } : {}
67113
+ });
67114
+ if (this.steeringController === undefined)
67115
+ break;
67116
+ const decision = await this.steeringController.boundary(traced.exitCode === 0);
67117
+ if (decision.operation === "retry") {
67118
+ steeringSignal = this.steeringController.nextAttempt();
67119
+ continue;
67120
+ }
67121
+ if (decision.operation === "note")
67122
+ steeringNote = decision.note;
67123
+ if (decision.operation === "abort" && traced.exitCode === 0) {
67124
+ traced = {
67125
+ ...traced,
67126
+ exitCode: 3,
67127
+ signal: "STEERING_ABORT",
67128
+ message: "aborted at steering boundary"
67129
+ };
67130
+ }
67131
+ break;
67132
+ }
67133
+ this.steeringController?.complete();
66331
67134
  const { exitCode, stdout: answer } = traced;
66332
67135
  const ok = exitCode === 0;
66333
67136
  const invocation = traced.invocation;
@@ -66355,7 +67158,10 @@ class AgentRunActionRunner {
66355
67158
  ok,
66356
67159
  data: buildResultData(exitCode, agentLabel, capture, answer, invocation),
66357
67160
  error: error51,
66358
- setVars: ok ? { __agentSession: "open" } : undefined
67161
+ setVars: ok ? {
67162
+ __agentSession: "open",
67163
+ ...steeringNote !== undefined ? { __steeringNote: steeringNote } : {}
67164
+ } : undefined
66359
67165
  };
66360
67166
  }
66361
67167
  }
@@ -66463,6 +67269,7 @@ ${text4.slice(text4.length - maxChars)}`;
66463
67269
  }
66464
67270
  var execFileAsync, PARTIAL_ARTIFACT_TAIL_CHARS = 4000, KIND = "agent.run";
66465
67271
  var init_agent_run = __esm(() => {
67272
+ init_steering();
66466
67273
  execFileAsync = promisify3(execFile);
66467
67274
  });
66468
67275
 
@@ -66991,7 +67798,7 @@ var init_rule_check = __esm(() => {
66991
67798
  // ../../packages/app/src/workflow/builtins.ts
66992
67799
  function registerSpurBuiltins(host, options) {
66993
67800
  const fileSystem = options.fileSystem ?? createNodeFileSystem3();
66994
- host.registerAction(new AgentRunActionRunner(options.agentService), "builtin");
67801
+ host.registerAction(new AgentRunActionRunner(options.agentService, options.observabilityBus, options.steeringController), "builtin");
66995
67802
  host.registerAction(new RuleCheckActionRunner(options.ruleService), "builtin");
66996
67803
  host.registerAction(new FileExistsActionRunner(fileSystem), "builtin");
66997
67804
  host.registerAction(new FileReadActionRunner(fileSystem), "builtin");
@@ -67017,56 +67824,125 @@ var init_builtins2 = __esm(() => {
67017
67824
  });
67018
67825
 
67019
67826
  // ../../packages/app/src/workflow/observability.ts
67827
+ function bounded(value) {
67828
+ const redacted = value.replace(SECRET_PATTERN2, "[REDACTED]");
67829
+ return redacted.length <= MAX_FIELD_LENGTH ? redacted : `${redacted.slice(0, MAX_FIELD_LENGTH)}\u2026`;
67830
+ }
67831
+ function projectActionMetadata(kind, options) {
67832
+ if (options === undefined)
67833
+ return;
67834
+ const metadata = {};
67835
+ if (typeof options.agent === "string" && options.agent !== "")
67836
+ metadata.agent = bounded(options.agent);
67837
+ if (typeof options.model === "string" && options.model !== "")
67838
+ metadata.model = bounded(options.model);
67839
+ if (typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs)) {
67840
+ metadata.timeoutMs = Math.max(0, options.timeoutMs);
67841
+ }
67842
+ const input = typeof options.input === "string" ? options.input.trim() : "";
67843
+ if (kind === "agent.run" && input !== "") {
67844
+ const command = input.startsWith("/") ? input.split(/\s+/, 1)[0] : undefined;
67845
+ metadata.invocation = command === undefined ? `[prompt ${input.length} chars]` : bounded(command);
67846
+ } else if (kind === "shell" && typeof options.command === "string") {
67847
+ metadata.invocation = "[shell command redacted]";
67848
+ }
67849
+ return Object.keys(metadata).length === 0 ? undefined : metadata;
67850
+ }
67851
+ function projectResult(result) {
67852
+ if (result === undefined)
67853
+ return;
67854
+ if (typeof result !== "object" || result === null)
67855
+ return { usage: "unavailable" };
67856
+ const error51 = "error" in result && typeof result.error === "string" ? bounded(result.error) : undefined;
67857
+ return { ...error51 !== undefined ? { error: error51 } : {}, usage: "unavailable" };
67858
+ }
67859
+
67020
67860
  class ObservableWorkflowAdapter {
67021
67861
  inner;
67022
67862
  bus;
67863
+ sequences = new Map;
67864
+ workflowNames = new Map;
67865
+ actions = new Map;
67023
67866
  constructor(inner, bus) {
67024
67867
  this.inner = inner;
67025
67868
  this.bus = bus;
67026
67869
  }
67027
67870
  async createRun(record2) {
67028
67871
  await this.inner.createRun(record2);
67872
+ this.workflowNames.set(record2.id, record2.workflow_name);
67029
67873
  await this.bus.emit("workflow.run.started", {
67030
- runId: record2.id,
67031
- workflowName: record2.workflow_name,
67032
- at: now()
67874
+ ...this.envelope(record2.id),
67875
+ workflowName: record2.workflow_name
67033
67876
  });
67034
67877
  }
67035
67878
  async finalizeRun(runId, status, completedAt) {
67036
67879
  await this.inner.finalizeRun(runId, status, completedAt);
67037
- await this.bus.emit("workflow.run.finalized", { runId, status, at: completedAt });
67880
+ await this.bus.emit("workflow.run.finalized", { ...this.envelope(runId, completedAt), status });
67038
67881
  }
67039
67882
  async savePhase(runId, phase, status) {
67040
67883
  await this.inner.savePhase(runId, phase, status);
67041
- await this.bus.emit("workflow.phase", { runId, phase, status, at: now() });
67884
+ await this.bus.emit("workflow.phase", { ...this.envelope(runId), phase, status });
67042
67885
  }
67043
67886
  async saveTransition(runId, from, to, trigger) {
67044
67887
  await this.inner.saveTransition(runId, from, to, trigger);
67045
- await this.bus.emit("workflow.transition", { runId, from, to, trigger, at: now() });
67888
+ await this.bus.emit("workflow.transition", { ...this.envelope(runId), from, to, trigger });
67046
67889
  }
67047
67890
  async commitTransition(runId, from, to, trigger, _state, _data, phase) {
67048
67891
  await this.inner.commitTransition(runId, from, to, trigger, _state, _data, phase);
67049
- await this.bus.emit("workflow.transition", { runId, from, to, trigger, at: now() });
67892
+ await this.bus.emit("workflow.transition", { ...this.envelope(runId), from, to, trigger });
67050
67893
  if (phase) {
67051
- await this.bus.emit("workflow.phase", { runId, phase: phase.phase, status: phase.status, at: now() });
67894
+ await this.bus.emit("workflow.phase", {
67895
+ ...this.envelope(runId),
67896
+ phase: phase.phase,
67897
+ status: phase.status
67898
+ });
67052
67899
  }
67053
67900
  }
67054
- async saveActionStart(runId, node, kind) {
67055
- const actionId = await this.inner.saveActionStart(runId, node, kind);
67056
- await this.bus.emit("workflow.action.started", { runId, actionId, node, kind, at: now() });
67901
+ async saveActionStart(runId, node, kind, options) {
67902
+ const actionId = await this.inner.saveActionStart(runId, node, kind, options);
67903
+ this.actions.set(actionId, { runId, node, kind });
67904
+ const metadata = projectActionMetadata(kind, options);
67905
+ await this.bus.emit("workflow.action.started", {
67906
+ ...this.envelope(runId),
67907
+ actionId,
67908
+ node,
67909
+ kind,
67910
+ ...metadata !== undefined ? { metadata } : {}
67911
+ });
67057
67912
  return actionId;
67058
67913
  }
67059
67914
  async saveActionFinalize(actionId, status, durationMs, ok, result, redactor) {
67060
67915
  await this.inner.saveActionFinalize(actionId, status, durationMs, ok, result, redactor);
67916
+ const action = this.actions.get(actionId);
67917
+ if (action === undefined) {
67918
+ return;
67919
+ }
67920
+ this.actions.delete(actionId);
67921
+ const projected = projectResult(result);
67061
67922
  await this.bus.emit("workflow.action.finished", {
67062
- runId: "",
67923
+ ...this.envelope(action.runId),
67063
67924
  actionId,
67064
67925
  status,
67065
67926
  durationMs,
67066
67927
  ok,
67067
- at: now()
67928
+ node: action.node,
67929
+ kind: action.kind,
67930
+ ...projected !== undefined ? { result: projected } : {}
67068
67931
  });
67069
67932
  }
67933
+ envelope(runId, at = now()) {
67934
+ const sequence = (this.sequences.get(runId) ?? 0) + 1;
67935
+ this.sequences.set(runId, sequence);
67936
+ const workflowName = this.workflowNames.get(runId);
67937
+ return {
67938
+ schemaVersion: 1,
67939
+ eventId: crypto.randomUUID(),
67940
+ sequence,
67941
+ runId,
67942
+ ...workflowName !== undefined ? { workflowName } : {},
67943
+ at
67944
+ };
67945
+ }
67070
67946
  saveWorkflowState(runId, state, data) {
67071
67947
  return this.inner.saveWorkflowState(runId, state, data);
67072
67948
  }
@@ -67088,11 +67964,17 @@ class ObservableWorkflowAdapter {
67088
67964
  loadCurrentState(runId) {
67089
67965
  return this.inner.loadCurrentState(runId);
67090
67966
  }
67967
+ loadLatestStateSnapshot(runId) {
67968
+ return this.inner.loadLatestStateSnapshot(runId);
67969
+ }
67091
67970
  listPausedRuns(options) {
67092
67971
  return this.inner.listPausedRuns(options);
67093
67972
  }
67094
67973
  }
67095
- var now = () => new Date().toISOString();
67974
+ var now = () => new Date().toISOString(), MAX_FIELD_LENGTH = 256, SECRET_PATTERN2;
67975
+ var init_observability = __esm(() => {
67976
+ SECRET_PATTERN2 = /(?:sk-[a-z0-9_-]{8,}|(?:api[_-]?key|token|secret|password)\s*[:=]\s*\S+|bearer\s+\S+)/gi;
67977
+ });
67096
67978
 
67097
67979
  // ../../packages/app/src/services/workflow-service.ts
67098
67980
  import { access as access2, lstat, readdir as readdir3, readFile as readFile2, realpath } from "fs/promises";
@@ -67187,14 +68069,16 @@ class WorkflowAppService {
67187
68069
  const eventsBus = this.ctx.events?.();
67188
68070
  const svc = await this.createEngineService({
67189
68071
  recordSelfPid: opts.recordSelfPid === true,
67190
- events: eventsBus
68072
+ events: eventsBus,
68073
+ steeringController: opts.steeringController
67191
68074
  });
67192
68075
  const runId = opts.runId ?? crypto.randomUUID();
67193
68076
  const isDry = opts.dryRun === true;
68077
+ const runVars = { ...opts.vars ?? {}, __runId: runId };
67194
68078
  const result = await svc.runFile(file2, {
67195
68079
  workdir: this.ctx.cwd,
67196
68080
  runId,
67197
- ...opts.vars ? { vars: opts.vars } : {},
68081
+ vars: runVars,
67198
68082
  ...isDry ? { dryRun: true } : {},
67199
68083
  ...eventsBus !== undefined ? { events: bridgeEventBus(eventsBus) } : {}
67200
68084
  });
@@ -67202,6 +68086,7 @@ class WorkflowAppService {
67202
68086
  const db2 = await this.ctx.getDb();
67203
68087
  await new RunDao(db2).stampMetadata(runId, { dryRun: true });
67204
68088
  }
68089
+ await this.stampFailureReason(runId, result);
67205
68090
  await this.maybeLinkPipelineRun(file2, runId, opts);
67206
68091
  return result;
67207
68092
  }
@@ -67282,8 +68167,16 @@ class WorkflowAppService {
67282
68167
  throw new Error(`Cannot resume run "${runId}": workflow definition "${target.workflow_name}" not found in the workflow search paths.`);
67283
68168
  }
67284
68169
  const result = await svc.resumeRun(workflow, runId, { workdir: this.ctx.cwd });
68170
+ await this.stampFailureReason(runId, result);
67285
68171
  return result;
67286
68172
  }
68173
+ async stampFailureReason(runId, result) {
68174
+ if (result.status !== "failed" || typeof result.reason !== "string" || result.reason === "") {
68175
+ return;
68176
+ }
68177
+ const db2 = await this.ctx.getDb();
68178
+ await new RunDao(db2).stampFailureReason(runId, result.reason);
68179
+ }
67287
68180
  async resolveWorkflowDefByName(name) {
67288
68181
  const listing = await this.list();
67289
68182
  const entry = listing.entries.find((e) => e.name === name && e.valid);
@@ -67409,19 +68302,21 @@ class WorkflowAppService {
67409
68302
  }
67410
68303
  async createEngineService(opts = {}) {
67411
68304
  const host = createDefaultWorkflowEngineHost();
68305
+ const bus = this.ctx.observabilityBus?.();
67412
68306
  registerSpurBuiltins(host, {
67413
68307
  agentService: this.ctx.agentService(),
67414
68308
  ruleService: this.ctx.ruleService(),
67415
68309
  hitlResponder: this.ctx.hitlResponder(),
67416
68310
  httpRequester: this.ctx.httpRequester?.(),
67417
- hostAllowlist: this.ctx.hostAllowlist?.()
68311
+ hostAllowlist: this.ctx.hostAllowlist?.(),
68312
+ ...bus !== undefined ? { observabilityBus: bus } : {},
68313
+ ...opts.steeringController !== undefined ? { steeringController: opts.steeringController } : {}
67418
68314
  });
67419
68315
  const db2 = await this.ctx.getDb();
67420
68316
  let persistence2 = new DbWorkflowPersistenceAdapter(db2);
67421
68317
  if (opts.recordSelfPid === true) {
67422
68318
  persistence2 = withSelfPidRecording(persistence2, db2);
67423
68319
  }
67424
- const bus = this.ctx.observabilityBus?.();
67425
68320
  const adapter = bus ? new ObservableWorkflowAdapter(persistence2, bus) : persistence2;
67426
68321
  return new WorkflowService(host, adapter);
67427
68322
  }
@@ -67487,9 +68382,13 @@ async function extractWorkflowMeta(filePath) {
67487
68382
  }
67488
68383
  function rowToTraceEntry(row) {
67489
68384
  let isDryRun = false;
68385
+ let failureReason;
67490
68386
  try {
67491
68387
  const meta3 = JSON.parse(row.metadata_json);
67492
68388
  isDryRun = meta3.dryRun === true;
68389
+ if (typeof meta3.failureReason === "string" && meta3.failureReason !== "") {
68390
+ failureReason = meta3.failureReason;
68391
+ }
67493
68392
  } catch {}
67494
68393
  return {
67495
68394
  runId: row.id,
@@ -67498,7 +68397,8 @@ function rowToTraceEntry(row) {
67498
68397
  status: row.status,
67499
68398
  startedAt: row.started_at,
67500
68399
  completedAt: row.completed_at,
67501
- isDryRun
68400
+ isDryRun,
68401
+ ...failureReason !== undefined ? { failureReason } : {}
67502
68402
  };
67503
68403
  }
67504
68404
  var TASK_PIPELINE_WORKFLOW = "task-pipeline", EMBEDDED_SCHEMA_PREFIX = "\x00embedded-spur", SPUR_SCHEMA_MANIFEST = "@gobing-ai/spur/package.json", PIPELINE_LINK_KIND = "pipeline";
@@ -67507,6 +68407,7 @@ var init_workflow_service = __esm(() => {
67507
68407
  init_dist7();
67508
68408
  init_dist5();
67509
68409
  init_builtins2();
68410
+ init_observability();
67510
68411
  });
67511
68412
 
67512
68413
  // ../../packages/app/src/workflow/lifecycle-adapter.ts
@@ -67654,19 +68555,72 @@ var init_lifecycle_adapter = __esm(() => {
67654
68555
  });
67655
68556
 
67656
68557
  // ../../packages/app/src/workflow/step-reporter.ts
67657
- function renderStepLine(event2) {
68558
+ function renderStepLine(event2, options = {}) {
68559
+ const detail = options.detail ?? "invocation";
68560
+ if (isAgentExecution(event2)) {
68561
+ if (event2.kind === "output") {
68562
+ if (detail === "minimal")
68563
+ return null;
68564
+ const label = event2.stream === "stderr" ? "stderr" : "stdout";
68565
+ return `[run ${event2.runId}] ${label}> ${event2.chunk.replace(/\s+$/, "")}`;
68566
+ }
68567
+ if (event2.kind === "heartbeat") {
68568
+ if (detail === "minimal")
68569
+ return null;
68570
+ const budget = event2.timeoutMs === undefined ? "unbounded" : `${formatDuration(Math.max(0, event2.timeoutMs - event2.elapsedMs))} remaining`;
68571
+ return `[run ${event2.runId}] \u2026 agent execution \xB7 elapsed=${formatDuration(event2.elapsedMs)} \xB7 budget=${budget}`;
68572
+ }
68573
+ if (event2.kind === "dropped") {
68574
+ return detail === "minimal" ? null : `[run ${event2.runId}] \u2026 output pressure \xB7 dropped=${event2.chunks} chunks`;
68575
+ }
68576
+ if (event2.kind === "started") {
68577
+ if (detail === "minimal")
68578
+ return null;
68579
+ const model = event2.model === undefined ? "" : `(${event2.model})`;
68580
+ const full2 = detail === "full" ? ` \xB7 execution=${event2.executionId}` : "";
68581
+ return `[run ${event2.runId}] agent=${event2.agent}${model} => ${event2.invocation}${full2}`;
68582
+ }
68583
+ const mark = event2.outcome === "done" ? "\u2713" : "\u2717";
68584
+ const full = detail === "full" ? ` \xB7 execution=${event2.executionId}` : "";
68585
+ return detail === "minimal" ? null : `[run ${event2.runId}] ${mark} agent ${event2.outcome} (${formatDuration(event2.durationMs)}) \xB7 usage ${event2.usage}${event2.reason ? ` \xB7 ${event2.reason}` : ""}${full}`;
68586
+ }
67658
68587
  if (isActionFinished(event2)) {
67659
68588
  const mark = event2.ok ? "\u2713" : "\u2717";
67660
- return ` ${mark} ${event2.status} (${formatDuration(event2.durationMs)})`;
68589
+ if (detail === "minimal")
68590
+ return ` ${mark} ${event2.status} (${formatDuration(event2.durationMs)})`;
68591
+ const failure = event2.result?.error === undefined ? "" : ` \xB7 ${event2.result.error}`;
68592
+ const full = detail === "full" ? ` \xB7 action=${event2.actionId} \xB7 seq=${event2.sequence}` : "";
68593
+ return `[run ${event2.runId}] ${mark} ${event2.node}/${event2.kind} (${formatDuration(event2.durationMs)}) \xB7 usage ${event2.result?.usage ?? "unavailable"}${failure}${full}`;
67661
68594
  }
67662
68595
  if (isActionStarted(event2)) {
67663
- return ` \u2192 ${event2.node}: ${event2.kind}\u2026`;
68596
+ if (detail === "minimal")
68597
+ return ` \u2192 ${event2.node}: ${event2.kind}\u2026`;
68598
+ const agent = event2.metadata?.agent ?? "unavailable";
68599
+ const model = event2.metadata?.model ?? "unavailable";
68600
+ const invocation = event2.metadata?.invocation ?? "unavailable";
68601
+ const timeout = event2.metadata?.timeoutMs === undefined ? "unbounded" : formatDuration(event2.metadata.timeoutMs);
68602
+ const full = detail === "full" ? ` \xB7 action=${event2.actionId} \xB7 seq=${event2.sequence}` : "";
68603
+ return `[run ${event2.runId}] \u2192 ${event2.node}/${event2.kind} \xB7 agent=${agent} \xB7 model=${model} => ${invocation} \xB7 timeout=${timeout}${full}`;
67664
68604
  }
67665
68605
  if (isPhase(event2)) {
67666
- return `\u25B6 ${event2.phase} [${event2.status}]`;
68606
+ return detail === "minimal" ? `\u25B6 ${event2.phase} [${event2.status}]` : `[run ${event2.runId}] \u25B6 ${event2.phase} [${event2.status}]`;
68607
+ }
68608
+ if (isTransition(event2)) {
68609
+ if (detail !== "full")
68610
+ return null;
68611
+ return `[run ${event2.runId}] \u21AA ${event2.from} \u2192 ${event2.to}${event2.trigger ? ` [${event2.trigger}]` : ""} \xB7 seq=${event2.sequence}`;
67667
68612
  }
67668
68613
  return null;
67669
68614
  }
68615
+ function renderActionHeartbeat(event2, elapsedMs, options = {}) {
68616
+ const detail = options.detail ?? "invocation";
68617
+ if (detail === "minimal")
68618
+ return null;
68619
+ const elapsed = formatDuration(elapsedMs);
68620
+ const budget = event2.metadata?.timeoutMs === undefined ? "unbounded" : `${formatDuration(Math.max(0, event2.metadata.timeoutMs - elapsedMs))} remaining`;
68621
+ const full = detail === "full" ? ` \xB7 action=${event2.actionId}` : "";
68622
+ return `[run ${event2.runId}] \u2026 ${event2.node}/${event2.kind} \xB7 elapsed=${elapsed} \xB7 budget=${budget}${full}`;
68623
+ }
67670
68624
  function renderRunPlan(def) {
67671
68625
  const steps = def.kind === "transition-flow" ? def.nodes.map((n2) => n2.id) : def.states.map((s) => s.id);
67672
68626
  return `plan: ${steps.join(" \u2192 ")}`;
@@ -67679,7 +68633,49 @@ function formatDuration(ms) {
67679
68633
  const seconds = totalSeconds % 60;
67680
68634
  return `${minutes}m ${seconds}s`;
67681
68635
  }
67682
- var isActionStarted = (e) => ("kind" in e) && ("node" in e), isActionFinished = (e) => ("durationMs" in e) && ("ok" in e), isPhase = (e) => ("phase" in e);
68636
+ var isAgentExecution = (e) => ("executionId" in e), isActionStarted = (e) => ("kind" in e) && ("node" in e), isActionFinished = (e) => ("durationMs" in e) && ("ok" in e), isPhase = (e) => ("phase" in e), isTransition = (e) => ("from" in e) && ("to" in e);
68637
+
68638
+ // ../../packages/app/src/workflow/trace-writer.ts
68639
+ import { appendFile, mkdir as mkdir2 } from "fs/promises";
68640
+ import { dirname as dirname12, join as join14 } from "path";
68641
+
68642
+ class WorkflowTraceWriter {
68643
+ path;
68644
+ sequence = 0;
68645
+ pending = Promise.resolve();
68646
+ constructor(cwd, runId) {
68647
+ const safeRunId = runId.replace(/[^A-Za-z0-9._-]/g, "_");
68648
+ this.path = join14(cwd, ".spur", "runs", "workflow", `${safeRunId}.jsonl`);
68649
+ }
68650
+ attach(bus) {
68651
+ bus.on("workflow.run.started", (event2) => this.enqueue("workflow.run.started", event2));
68652
+ bus.on("workflow.run.finalized", (event2) => this.enqueue("workflow.run.finalized", event2));
68653
+ bus.on("workflow.phase", (event2) => this.enqueue("workflow.phase", event2));
68654
+ bus.on("workflow.transition", (event2) => this.enqueue("workflow.transition", event2));
68655
+ bus.on("workflow.action.started", (event2) => this.enqueue("workflow.action.started", event2));
68656
+ bus.on("workflow.action.finished", (event2) => this.enqueue("workflow.action.finished", event2));
68657
+ bus.on("workflow.agent", (event2) => this.enqueue("workflow.agent", event2));
68658
+ bus.on("workflow.steering", (event2) => this.enqueue("workflow.steering", event2));
68659
+ }
68660
+ async flush() {
68661
+ await this.pending;
68662
+ }
68663
+ enqueue(type, event2) {
68664
+ this.sequence += 1;
68665
+ const line = `${JSON.stringify({
68666
+ traceSchemaVersion: 1,
68667
+ traceSequence: this.sequence,
68668
+ type,
68669
+ event: event2
68670
+ })}
68671
+ `;
68672
+ this.pending = this.pending.then(async () => {
68673
+ await mkdir2(dirname12(this.path), { recursive: true });
68674
+ await appendFile(this.path, line, "utf8");
68675
+ });
68676
+ }
68677
+ }
68678
+ var init_trace_writer = () => {};
67683
68679
 
67684
68680
  // ../../packages/app/src/index.ts
67685
68681
  var exports_src2 = {};
@@ -67693,11 +68689,14 @@ __export(exports_src2, {
67693
68689
  renderSolutionFromDiff: () => renderSolutionFromDiff,
67694
68690
  renderRunPlan: () => renderRunPlan,
67695
68691
  renderReview: () => renderReview,
68692
+ renderActionHeartbeat: () => renderActionHeartbeat,
67696
68693
  registerSystemEventTap: () => registerSystemEventTap,
67697
68694
  registerSpurBuiltins: () => registerSpurBuiltins,
68695
+ redactAndBound: () => redactAndBound,
67698
68696
  readVerdictArtifact: () => readVerdictArtifact,
67699
68697
  readVerdict: () => readVerdict,
67700
68698
  parseVerdict: () => parseVerdict,
68699
+ parseSteeringPolicy: () => parseSteeringPolicy,
67701
68700
  parsePsOutput: () => parsePsOutput,
67702
68701
  parseLedgerLine: () => parseLedgerLine,
67703
68702
  parseEtimeToSeconds: () => parseEtimeToSeconds,
@@ -67713,11 +68712,14 @@ __export(exports_src2, {
67713
68712
  evaluateDoneTransition: () => evaluateDoneTransition,
67714
68713
  deriveVerdict: () => deriveVerdict,
67715
68714
  createPsProcessInspector: () => createPsProcessInspector,
68715
+ configuredSecretValues: () => configuredSecretValues,
67716
68716
  computeAggregate: () => computeAggregate,
67717
68717
  classifyTaskOutcome: () => classifyTaskOutcome,
67718
68718
  clampToolUseLimit: () => clampToolUseLimit,
67719
68719
  bridgeEventBus: () => bridgeEventBus,
67720
68720
  aggregateBatchVerdicts: () => aggregateBatchVerdicts,
68721
+ WorkflowTraceWriter: () => WorkflowTraceWriter,
68722
+ WorkflowSteeringController: () => WorkflowSteeringController,
67721
68723
  WorkflowAppService: () => WorkflowAppService,
67722
68724
  UnsupportedProcessPlatformError: () => UnsupportedProcessPlatformError,
67723
68725
  TokenLedgerWatcher: () => TokenLedgerWatcher,
@@ -67773,11 +68775,13 @@ __export(exports_src2, {
67773
68775
  BusPlanningEventEmitter: () => BusPlanningEventEmitter,
67774
68776
  AgentService: () => AgentService,
67775
68777
  AgentRunActionRunner: () => AgentRunActionRunner,
68778
+ AgentExecutionLifecycle: () => AgentExecutionLifecycle,
67776
68779
  ALL_FINDING_CODES: () => ALL_FINDING_CODES
67777
68780
  });
67778
68781
  var init_src3 = __esm(() => {
67779
68782
  init_planning_folders();
67780
68783
  init_errors5();
68784
+ init_agent_execution();
67781
68785
  init_agent_service();
67782
68786
  init_corpus_migrator();
67783
68787
  init_event_names();
@@ -67810,6 +68814,9 @@ var init_src3 = __esm(() => {
67810
68814
  init_rule_check();
67811
68815
  init_builtins2();
67812
68816
  init_lifecycle_adapter();
68817
+ init_observability();
68818
+ init_steering();
68819
+ init_trace_writer();
67813
68820
  });
67814
68821
 
67815
68822
  // ../../node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
@@ -67890,19 +68897,19 @@ var {
67890
68897
  init_src();
67891
68898
  init_loader();
67892
68899
 
67893
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/application-node.js
68900
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/application-node.js
67894
68901
  init_dist4();
67895
68902
  init_dist5();
67896
68903
  import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "fs";
67897
68904
  import { dirname as dirname5 } from "path";
67898
68905
 
67899
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/application/index.js
68906
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/application/index.js
67900
68907
  init_default_observers();
67901
68908
  init_event_bus();
67902
68909
  init_file_observer();
67903
68910
  init_logger3();
67904
68911
 
67905
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
68912
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
67906
68913
  class NoopSchedulerAdapter {
67907
68914
  constructor() {}
67908
68915
  register(_cron, _action) {}
@@ -67910,7 +68917,7 @@ class NoopSchedulerAdapter {
67910
68917
  async stop() {}
67911
68918
  }
67912
68919
 
67913
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
68920
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
67914
68921
  function initScheduler(adapter, cronEntries) {
67915
68922
  const resolved = adapter ?? new NoopSchedulerAdapter;
67916
68923
  if (cronEntries) {
@@ -67921,7 +68928,7 @@ function initScheduler(adapter, cronEntries) {
67921
68928
  return resolved;
67922
68929
  }
67923
68930
 
67924
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
68931
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
67925
68932
  init_logger3();
67926
68933
  init_metrics();
67927
68934
  init_sdk();
@@ -68014,7 +69021,7 @@ function dbPlugin(db2) {
68014
69021
  };
68015
69022
  }
68016
69023
 
68017
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
69024
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
68018
69025
  init_logger3();
68019
69026
 
68020
69027
  class PluginHost {
@@ -68102,7 +69109,7 @@ class PluginHost {
68102
69109
  }
68103
69110
  }
68104
69111
 
68105
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/application/index.js
69112
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/application/index.js
68106
69113
  async function performShutdown(state, reason) {
68107
69114
  if (state.stopped)
68108
69115
  return;
@@ -68213,10 +69220,10 @@ async function runApplication(options) {
68213
69220
  }
68214
69221
  }
68215
69222
 
68216
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/application-node.js
69223
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/application-node.js
68217
69224
  init_scheduler_node();
68218
69225
 
68219
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
69226
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
68220
69227
  var import_api14 = __toESM(require_src(), 1);
68221
69228
 
68222
69229
  // ../../node_modules/.bun/@opentelemetry+exporter-metrics-otlp-http@0.218.0+e40b0dfdd726a224/node_modules/@opentelemetry/exporter-metrics-otlp-http/build/esm/OTLPMetricExporterBase.js
@@ -71232,7 +72239,7 @@ class OTLPTraceExporter extends import_otlp_exporter_base2.OTLPExporterBase {
71232
72239
  }), JsonTraceSerializer));
71233
72240
  }
71234
72241
  }
71235
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
72242
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
71236
72243
  var import_resources2 = __toESM(require_src4(), 1);
71237
72244
  var import_sdk_trace_node = __toESM(require_src8(), 1);
71238
72245
  var import_semantic_conventions = __toESM(require_src2(), 1);
@@ -71283,7 +72290,7 @@ async function shutdownNodeTelemetry() {
71283
72290
  await Promise.all(pending);
71284
72291
  }
71285
72292
 
71286
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.11+08507d81f591b81d/node_modules/@gobing-ai/ts-infra/dist/application-node.js
72293
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.14+a32276a722fab3c8/node_modules/@gobing-ai/ts-infra/dist/application-node.js
71287
72294
  class ConfigValidationError extends Error {
71288
72295
  constructor(message) {
71289
72296
  super(message);
@@ -75374,7 +76381,7 @@ init_loader();
75374
76381
  init_src2();
75375
76382
  import { existsSync as existsSync8 } from "fs";
75376
76383
  import { homedir as homedir4 } from "os";
75377
- import { join as join14, resolve as resolve3 } from "path";
76384
+ import { join as join15, resolve as resolve3 } from "path";
75378
76385
 
75379
76386
  // src/workflow/resolve-spur-bin.ts
75380
76387
  import { basename as basename2 } from "path";
@@ -75392,22 +76399,22 @@ function resolveSpurBin() {
75392
76399
  }
75393
76400
 
75394
76401
  // src/workflow/make-lifecycle-adapter.ts
75395
- var GLOBAL_CONFIG_DIR = join14(".config", "spur");
76402
+ var GLOBAL_CONFIG_DIR = join15(".config", "spur");
75396
76403
  function globalConfigRoot(context4) {
75397
76404
  const override = context4.env.SPUR_GLOBAL_RULES_DIR;
75398
- return override !== undefined && override.length > 0 ? resolve3(context4.cwd, override) : join14(homedir4(), GLOBAL_CONFIG_DIR);
76405
+ return override !== undefined && override.length > 0 ? resolve3(context4.cwd, override) : join15(homedir4(), GLOBAL_CONFIG_DIR);
75399
76406
  }
75400
76407
  function resolveWorkflowPath(context4, profile) {
75401
76408
  const bundledRoot = bundledConfigRoot();
75402
76409
  if (bundledRoot !== null) {
75403
- const bundledPath = join14(bundledRoot, "workflows", `${profile.workflowName}.yaml`);
76410
+ const bundledPath = join15(bundledRoot, "workflows", `${profile.workflowName}.yaml`);
75404
76411
  if (existsSync8(bundledPath))
75405
76412
  return bundledPath;
75406
76413
  }
75407
- const projectPath = join14(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
76414
+ const projectPath = join15(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
75408
76415
  if (existsSync8(projectPath))
75409
76416
  return projectPath;
75410
- const globalPath = join14(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
76417
+ const globalPath = join15(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
75411
76418
  if (existsSync8(globalPath))
75412
76419
  return globalPath;
75413
76420
  return null;
@@ -75662,6 +76669,7 @@ function registerFeatureCommand(program2, context4) {
75662
76669
  strict,
75663
76670
  featuresDir,
75664
76671
  tasksDir,
76672
+ runDir: context4.fs.resolve(".spur/run"),
75665
76673
  severityOverrides: resolved.severityOverrides
75666
76674
  });
75667
76675
  results.push(result);
@@ -75734,7 +76742,13 @@ async function makeService(context4, folderOverride) {
75734
76742
  ...lifecycle ? { lifecycle } : {},
75735
76743
  emitter: makePlanningEmitter(context4)
75736
76744
  });
75737
- return new FeatureService({ fs: context4.fs, writeService, featuresDir, tasksDir });
76745
+ return new FeatureService({
76746
+ fs: context4.fs,
76747
+ writeService,
76748
+ featuresDir,
76749
+ tasksDir,
76750
+ foldersConfig: resolved.foldersConfig
76751
+ });
75738
76752
  }
75739
76753
  async function assertFeatureCheckPass(context4, id, folderOverride, strict) {
75740
76754
  const resolved = await resolvePlanningFolders(context4.fs);
@@ -75802,13 +76816,13 @@ init_loader();
75802
76816
  init_src2();
75803
76817
  init_dist10();
75804
76818
  import { homedir as homedir5 } from "os";
75805
- import { join as join15, resolve as resolve4 } from "path";
76819
+ import { join as join16, resolve as resolve4 } from "path";
75806
76820
 
75807
76821
  // src/config.ts
75808
76822
  var CLI_CONFIG = {
75809
76823
  binaryName: "spur",
75810
76824
  binaryLabel: "spur",
75811
- binaryVersion: "0.3.24",
76825
+ binaryVersion: "0.3.26",
75812
76826
  configDir: ".spur",
75813
76827
  configFile: ".spur/config.yaml",
75814
76828
  databaseFile: ".spur/spur.db"
@@ -75859,8 +76873,8 @@ var SCAFFOLD_MANIFEST = [
75859
76873
  ];
75860
76874
 
75861
76875
  // src/commands/init.ts
75862
- var GLOBAL_CONFIG_DIR2 = join15(".config", "spur");
75863
- var GLOBAL_RULES_DIR2 = join15(GLOBAL_CONFIG_DIR2, "rules");
76876
+ var GLOBAL_CONFIG_DIR2 = join16(".config", "spur");
76877
+ var GLOBAL_RULES_DIR2 = join16(GLOBAL_CONFIG_DIR2, "rules");
75864
76878
  var GLOBAL_CONFIG_EXAMPLE = "config.example.yaml";
75865
76879
  var GLOBAL_CONFIG_FILE2 = "config.yaml";
75866
76880
  var INDEXED_CONTEXT_MARKER = "## Indexed context";
@@ -75891,7 +76905,7 @@ If \`.spur/context/\` is absent, proceed normally. Never block work on its absen
75891
76905
  `;
75892
76906
  function globalRulesRoot(context4) {
75893
76907
  const override = context4.env.SPUR_GLOBAL_RULES_DIR;
75894
- return override !== undefined && override.length > 0 ? resolve4(context4.cwd, override) : join15(homedir5(), GLOBAL_RULES_DIR2);
76908
+ return override !== undefined && override.length > 0 ? resolve4(context4.cwd, override) : join16(homedir5(), GLOBAL_RULES_DIR2);
75895
76909
  }
75896
76910
  async function writeIfNew(context4, path9, content, force, result) {
75897
76911
  if (!force && await context4.fs.exists(path9)) {
@@ -75908,11 +76922,11 @@ async function seedGlobalRules(context4) {
75908
76922
  const target = globalRulesRoot(context4);
75909
76923
  let written = 0;
75910
76924
  for (const relPath of await listBundledRuleFiles()) {
75911
- const destination = join15(target, relPath);
76925
+ const destination = join16(target, relPath);
75912
76926
  if (await context4.fs.exists(destination))
75913
76927
  continue;
75914
- await context4.fs.ensureDir(join15(target, ...relPath.split("/").slice(0, -1)));
75915
- await context4.fs.writeFile(destination, await context4.fs.readFile(join15(source, relPath)));
76928
+ await context4.fs.ensureDir(join16(target, ...relPath.split("/").slice(0, -1)));
76929
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join16(source, relPath)));
75916
76930
  written += 1;
75917
76931
  }
75918
76932
  return written;
@@ -75922,20 +76936,20 @@ async function seedGlobalConfig(context4) {
75922
76936
  if (source === null)
75923
76937
  return 0;
75924
76938
  const globalOverride = context4.env.SPUR_GLOBAL_RULES_DIR;
75925
- const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve4(context4.cwd, globalOverride) : join15(homedir5(), GLOBAL_CONFIG_DIR2);
76939
+ const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve4(context4.cwd, globalOverride) : join16(homedir5(), GLOBAL_CONFIG_DIR2);
75926
76940
  let written = 0;
75927
76941
  for (const relPath of listBundledConfigFiles()) {
75928
76942
  if (relPath === GLOBAL_CONFIG_EXAMPLE)
75929
76943
  continue;
75930
- const destination = join15(target, relPath);
76944
+ const destination = join16(target, relPath);
75931
76945
  if (await context4.fs.exists(destination))
75932
76946
  continue;
75933
- await context4.fs.ensureDir(join15(target, ...relPath.split("/").slice(0, -1)));
75934
- await context4.fs.writeFile(destination, await context4.fs.readFile(join15(source, relPath)));
76947
+ await context4.fs.ensureDir(join16(target, ...relPath.split("/").slice(0, -1)));
76948
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join16(source, relPath)));
75935
76949
  written += 1;
75936
76950
  }
75937
- const examplePath = join15(source, GLOBAL_CONFIG_EXAMPLE);
75938
- const globalConfigPath = join15(target, GLOBAL_CONFIG_FILE2);
76951
+ const examplePath = join16(source, GLOBAL_CONFIG_EXAMPLE);
76952
+ const globalConfigPath = join16(target, GLOBAL_CONFIG_FILE2);
75939
76953
  if (await context4.fs.exists(examplePath) && !await context4.fs.exists(globalConfigPath)) {
75940
76954
  await context4.fs.ensureDir(target);
75941
76955
  await context4.fs.writeFile(globalConfigPath, await context4.fs.readFile(examplePath));
@@ -75949,7 +76963,7 @@ function registerInitCommand(program2, context4) {
75949
76963
  const force = options.force === true;
75950
76964
  const minimal = options.minimal === true;
75951
76965
  const projectName = options.name ?? "default";
75952
- const configPath = join15(context4.cwd, CLI_CONFIG.configFile);
76966
+ const configPath = join16(context4.cwd, CLI_CONFIG.configFile);
75953
76967
  if (!force && await context4.fs.exists(configPath)) {
75954
76968
  const message = `Already initialized: ${CLI_CONFIG.configFile}. Use --force to overwrite.`;
75955
76969
  context4.output.write(json3 ? toJson2({ ok: false, reason: "already-initialized", config: CLI_CONFIG.configFile }) : message);
@@ -75962,7 +76976,7 @@ function registerInitCommand(program2, context4) {
75962
76976
  `# Generated by \`spur init\``,
75963
76977
  "",
75964
76978
  '$schema: "@gobing-ai/spur/schemas/spur-config.schema.json"',
75965
- `version: "1"`,
76979
+ `version: "1.1"`,
75966
76980
  `name: ${projectName}`,
75967
76981
  "",
75968
76982
  "bootstrap:",
@@ -75984,13 +76998,13 @@ function registerInitCommand(program2, context4) {
75984
76998
  ].join(`
75985
76999
  `)}
75986
77000
  `;
75987
- await context4.fs.ensureDir(join15(context4.cwd, CLI_CONFIG.configDir));
77001
+ await context4.fs.ensureDir(join16(context4.cwd, CLI_CONFIG.configDir));
75988
77002
  await context4.fs.writeFile(configPath, configYaml);
75989
77003
  result.created.push(configPath);
75990
- const agentsDir = join15(context4.cwd, CLI_CONFIG.configDir, "agents");
77004
+ const agentsDir = join16(context4.cwd, CLI_CONFIG.configDir, "agents");
75991
77005
  await context4.fs.ensureDir(agentsDir);
75992
- await writeIfNew(context4, join15(agentsDir, ".gitkeep"), "", force, result);
75993
- const gitignorePath = join15(context4.cwd, ".gitignore");
77006
+ await writeIfNew(context4, join16(agentsDir, ".gitkeep"), "", force, result);
77007
+ const gitignorePath = join16(context4.cwd, ".gitignore");
75994
77008
  const contextEntry = ".spur/context/";
75995
77009
  if (await context4.fs.exists(gitignorePath)) {
75996
77010
  const existing = await context4.fs.readFile(gitignorePath);
@@ -76012,20 +77026,20 @@ ${contextEntry}
76012
77026
  for (const relPath of listBundledProjectSeedFiles()) {
76013
77027
  if (relPath.startsWith("templates/docs/"))
76014
77028
  continue;
76015
- const sourcePath = join15(configRoot, relPath);
77029
+ const sourcePath = join16(configRoot, relPath);
76016
77030
  if (!await context4.fs.exists(sourcePath))
76017
77031
  continue;
76018
- const targetPath = join15(context4.cwd, CLI_CONFIG.configDir, relPath);
76019
- await context4.fs.ensureDir(join15(targetPath, ".."));
77032
+ const targetPath = join16(context4.cwd, CLI_CONFIG.configDir, relPath);
77033
+ await context4.fs.ensureDir(join16(targetPath, ".."));
76020
77034
  await writeIfNew(context4, targetPath, await context4.fs.readFile(sourcePath), force, result);
76021
77035
  }
76022
77036
  for (const entry of SCAFFOLD_MANIFEST) {
76023
- const sourcePath = join15(configRoot, entry.source);
77037
+ const sourcePath = join16(configRoot, entry.source);
76024
77038
  if (!await context4.fs.exists(sourcePath))
76025
77039
  continue;
76026
- const baseDir = entry.root === true ? context4.cwd : join15(context4.cwd, CLI_CONFIG.configDir);
76027
- const targetPath = join15(baseDir, entry.target);
76028
- await context4.fs.ensureDir(join15(targetPath, ".."));
77040
+ const baseDir = entry.root === true ? context4.cwd : join16(context4.cwd, CLI_CONFIG.configDir);
77041
+ const targetPath = join16(baseDir, entry.target);
77042
+ await context4.fs.ensureDir(join16(targetPath, ".."));
76029
77043
  const entryForce = entry.preserve === true ? false : force;
76030
77044
  let body = await context4.fs.readFile(sourcePath);
76031
77045
  if (entry.target === "AGENTS.md") {
@@ -76038,7 +77052,7 @@ ${contextEntry}
76038
77052
  }
76039
77053
  }
76040
77054
  }
76041
- const agentsMdPath = join15(context4.cwd, "AGENTS.md");
77055
+ const agentsMdPath = join16(context4.cwd, "AGENTS.md");
76042
77056
  if (await context4.fs.exists(agentsMdPath)) {
76043
77057
  const existing = await context4.fs.readFile(agentsMdPath);
76044
77058
  if (!existing.includes(INDEXED_CONTEXT_MARKER)) {
@@ -76216,10 +77230,10 @@ function parseInterval2(raw) {
76216
77230
 
76217
77231
  // src/commands/migrate.ts
76218
77232
  init_src2();
76219
- import { join as join16 } from "path";
77233
+ import { join as join17 } from "path";
76220
77234
  function registerMigrateCommand(program2, context4) {
76221
77235
  program2.command("migrate").summary("apply CLI-owned schema migrations").option("--json", "Output machine-readable JSON").action(async (options) => {
76222
- const migrations = await loadSqlMigrations(join16(context4.cwd, "drizzle")).catch(() => {
77236
+ const migrations = await loadSqlMigrations(join17(context4.cwd, "drizzle")).catch(() => {
76223
77237
  return;
76224
77238
  });
76225
77239
  const applied = await applyCliMigrations(await context4.getDb(), migrations);
@@ -76471,7 +77485,7 @@ function formatTraceDetail(detail) {
76471
77485
 
76472
77486
  // src/commands/serve.ts
76473
77487
  init_src();
76474
- import { join as join20 } from "path";
77488
+ import { join as join21 } from "path";
76475
77489
 
76476
77490
  // ../server/src/index.ts
76477
77491
  init_src();
@@ -76481,11 +77495,11 @@ init_src3();
76481
77495
  init_src();
76482
77496
  init_loader();
76483
77497
  init_src2();
76484
- import { dirname as dirname13, isAbsolute as isAbsolute3, join as join19 } from "path";
77498
+ import { dirname as dirname14, isAbsolute as isAbsolute3, join as join20 } from "path";
76485
77499
  init_dist5();
76486
77500
 
76487
77501
  // ../server/src/bootstrap.ts
76488
- import { join as join17 } from "path";
77502
+ import { join as join18 } from "path";
76489
77503
 
76490
77504
  // ../../node_modules/.bun/radash@12.1.1/node_modules/radash/dist/esm/async.mjs
76491
77505
  var guard = (func, shouldGuard) => {
@@ -85125,7 +86139,7 @@ function createApp(appRt, opts) {
85125
86139
  app.use("*", async (c3, next) => {
85126
86140
  const pathname = c3.req.path === "/" ? "/index.html" : c3.req.path;
85127
86141
  try {
85128
- const file2 = Bun.file(join17(webDistPath, pathname));
86142
+ const file2 = Bun.file(join18(webDistPath, pathname));
85129
86143
  if (await file2.exists()) {
85130
86144
  const headers = new Headers({ "content-type": file2.type });
85131
86145
  return new Response(file2.stream(), { headers });
@@ -85138,7 +86152,7 @@ function createApp(appRt, opts) {
85138
86152
  return c3.json({ error: "Not Found" }, 404);
85139
86153
  }
85140
86154
  try {
85141
- const indexFile = Bun.file(join17(webDistPath, "index.html"));
86155
+ const indexFile = Bun.file(join18(webDistPath, "index.html"));
85142
86156
  if (await indexFile.exists()) {
85143
86157
  return new Response(indexFile.stream(), {
85144
86158
  headers: { "content-type": "text/html; charset=utf-8" }
@@ -85159,7 +86173,7 @@ init_src3();
85159
86173
  init_src();
85160
86174
  init_src2();
85161
86175
  init_dist5();
85162
- import { dirname as dirname12, join as join18 } from "path";
86176
+ import { dirname as dirname13, join as join19 } from "path";
85163
86177
  var NOOP_OUTPUT = { write: (_s) => {}, error: (_s) => {} };
85164
86178
 
85165
86179
  class LazyPlanningEventEmitter {
@@ -85194,7 +86208,7 @@ class NotConfiguredError extends Error {
85194
86208
  function createServerContext(appRt, options) {
85195
86209
  const cwd = options.cwd;
85196
86210
  const fs3 = options.fs;
85197
- const dbUrl = options.dbUrl ?? join18(cwd, DEFAULT_DATABASE_URL);
86211
+ const dbUrl = options.dbUrl ?? join19(cwd, DEFAULT_DATABASE_URL);
85198
86212
  const eventsBus = options.eventsBus ?? appRt.events;
85199
86213
  const jobQueueEnabled = options.jobQueueEnabled ?? false;
85200
86214
  const folders = options.folders ?? DEFAULT_PLANNING_FOLDERS;
@@ -85228,7 +86242,7 @@ function createServerContext(appRt, options) {
85228
86242
  if (!dbPromise) {
85229
86243
  const created = (async () => {
85230
86244
  if (dbUrl !== IN_MEMORY_DATABASE_URL) {
85231
- await fs3.ensureDir(dirname12(dbUrl));
86245
+ await fs3.ensureDir(dirname13(dbUrl));
85232
86246
  }
85233
86247
  return createMigratedDbViaRuntime({ url: dbUrl });
85234
86248
  })();
@@ -85265,6 +86279,7 @@ function createServerContext(appRt, options) {
85265
86279
  writeService: new PlanningWriteService({ fs: fs3, projectName: "spur", emitter: lazyEmitter }),
85266
86280
  featuresDir: folders.featuresDir,
85267
86281
  tasksDir: folders.tasksDir,
86282
+ foldersConfig: folders.foldersConfig,
85268
86283
  projectName: "spur"
85269
86284
  });
85270
86285
  }
@@ -85494,15 +86509,15 @@ async function runTaskActionJob(ctx, env, payload, createAgentService = createTa
85494
86509
  }
85495
86510
  }
85496
86511
  async function resolveWebDistPath(configuredPath) {
85497
- const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join19(process.cwd(), configuredPath)] : [
85498
- join19(process.cwd(), "dist/web"),
85499
- join19(import.meta.dir, "web"),
85500
- join19(dirname13(process.execPath), "web"),
85501
- join19(dirname13(process.execPath), "../web"),
85502
- join19(import.meta.dir, "../../../dist/web")
86512
+ const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join20(process.cwd(), configuredPath)] : [
86513
+ join20(process.cwd(), "dist/web"),
86514
+ join20(import.meta.dir, "web"),
86515
+ join20(dirname14(process.execPath), "web"),
86516
+ join20(dirname14(process.execPath), "../web"),
86517
+ join20(import.meta.dir, "../../../dist/web")
85503
86518
  ];
85504
86519
  for (const candidate of candidates) {
85505
- if (await Bun.file(join19(candidate, "index.html")).exists()) {
86520
+ if (await Bun.file(join20(candidate, "index.html")).exists()) {
85506
86521
  return candidate;
85507
86522
  }
85508
86523
  }
@@ -85518,7 +86533,7 @@ async function startServer(options, deps = defaultDeps) {
85518
86533
  async start(appRt) {
85519
86534
  const fs3 = deps.createNodeFileSystem(process.cwd());
85520
86535
  if (options.dbUrl && options.dbUrl !== IN_MEMORY_DATABASE_URL) {
85521
- await fs3.ensureDir(dirname13(options.dbUrl));
86536
+ await fs3.ensureDir(dirname14(options.dbUrl));
85522
86537
  }
85523
86538
  let scheduler3;
85524
86539
  if (bootConfig.scheduler.enabled) {
@@ -85632,7 +86647,7 @@ if (false) {}
85632
86647
 
85633
86648
  // src/commands/serve.ts
85634
86649
  function resolveServeDbUrl(cwd, env, configuredUrl) {
85635
- return env.DATABASE_URL === undefined ? join20(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
86650
+ return env.DATABASE_URL === undefined ? join21(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
85636
86651
  }
85637
86652
  function registerServeCommand(program2, context4) {
85638
86653
  program2.command("serve").summary("start the Spur web server (local fallback)").option("--port <n>", "Server port (env: PORT, default: 3000)", parseInt).option("--host <addr>", "Bind address (env: HOST, default: localhost)").option("--no-open", "Skip opening the browser").option("--cwd <path>", "Working directory", context4.cwd).option("--json", "Output { port, url, pid } and exit").action(async (options) => {
@@ -85671,7 +86686,7 @@ function registerServeCommand(program2, context4) {
85671
86686
  }
85672
86687
 
85673
86688
  // src/commands/status.ts
85674
- import { join as join21 } from "path";
86689
+ import { join as join22 } from "path";
85675
86690
 
85676
86691
  // src/errors.ts
85677
86692
  class CommandError extends Error {
@@ -85742,8 +86757,8 @@ function registerStatusCommand(program2, context4) {
85742
86757
  }
85743
86758
  async function runStatusCore(path9, options, context4) {
85744
86759
  const [packageJsonExists, spurConfigExists, git, agentSpecs] = await Promise.all([
85745
- context4.fs.exists(join21(context4.cwd, "package.json")),
85746
- context4.fs.exists(join21(context4.cwd, ".spur", "config.yaml")),
86760
+ context4.fs.exists(join22(context4.cwd, "package.json")),
86761
+ context4.fs.exists(join22(context4.cwd, ".spur", "config.yaml")),
85747
86762
  gitContext(context4.cwd),
85748
86763
  listAgentSpecIds(context4)
85749
86764
  ]);
@@ -85771,14 +86786,14 @@ async function runStatusCore(path9, options, context4) {
85771
86786
  return status.ok ? 0 : 1;
85772
86787
  }
85773
86788
  async function listAgentSpecIds(context4) {
85774
- const dir = join21(context4.cwd, ".spur", "agents");
86789
+ const dir = join22(context4.cwd, ".spur", "agents");
85775
86790
  if (!await context4.fs.exists(dir))
85776
86791
  return [];
85777
86792
  const entries = await context4.fs.readDir(dir);
85778
86793
  return entries.filter((entry) => entry.endsWith(".yaml") || entry.endsWith(".yml")).map((entry) => entry.replace(/\.ya?ml$/, "")).sort();
85779
86794
  }
85780
86795
  async function readTargetStatus(context4, targetPath) {
85781
- const resolved = join21(context4.cwd, targetPath);
86796
+ const resolved = join22(context4.cwd, targetPath);
85782
86797
  const stat2 = await context4.fs.stat(resolved);
85783
86798
  if (stat2 === null)
85784
86799
  throw new CommandError(`status failed: path does not exist at ${resolved}`);
@@ -85790,7 +86805,7 @@ init_src3();
85790
86805
  init_loader();
85791
86806
  init_src2();
85792
86807
  import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
85793
- import { join as join22 } from "path";
86808
+ import { join as join23 } from "path";
85794
86809
  // schemas/section-matrix.schema.json
85795
86810
  var section_matrix_schema_default = {
85796
86811
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -85875,7 +86890,7 @@ var spur_config_schema_default = {
85875
86890
  },
85876
86891
  version: {
85877
86892
  type: "string",
85878
- description: "Config schema version. Currently '1'."
86893
+ description: "Config schema version (string, not integer). Current recommended: '1.1' (ADR-033 executor tiers + planning blocks). '1' remains accepted for backward compatibility."
85879
86894
  },
85880
86895
  name: {
85881
86896
  type: "string",
@@ -85992,15 +87007,15 @@ var spur_config_schema_default = {
85992
87007
  },
85993
87008
  tier: {
85994
87009
  type: "string",
85995
- enum: ["cheap", "standard", "capable"],
85996
- description: "Capability tier for stage-registry adaptive model routing (ADR-033). A stage starts on the cheapest eligible executor meeting its model_policy min_tier and escalates along the fallback chain on objective signals."
87010
+ enum: ["cheap", "standard", "capable-1", "capable-2", "capable-3"],
87011
+ description: "Capability tier for stage-registry adaptive model routing (ADR-033, 0343). Live values: cheap | standard | capable-1 | capable-2 | capable-3 (1=low output quality, 3=high within the capable band). A stage starts on the cheapest eligible executor meeting its model_policy min_tier. Bare legacy `capable` is accepted at runtime (zod preprocess \u2192 capable-1) during the deprecation window but is not part of this editor enum."
85997
87012
  }
85998
87013
  }
85999
87014
  }
86000
87015
  },
86001
87016
  "default-by-phase": {
86002
87017
  type: "object",
86003
- description: "Map of dev phase (e.g. dev-run, dev-review) to executor selector. A configured phase mapping is authoritative \u2014 a broken mapping fails fast and does NOT fall back to `default`.",
87018
+ description: "DEPRECATED (ADR-033). Backward-compat map of dev phase (e.g. dev-run, dev-review) to executor selector. Prefer executor `tier` + stage-registry model_policy. When present, a matching phase mapping is still authoritative (fail-fast; no fall back to `default`) and shadows stage routing for that phase.",
86004
87019
  additionalProperties: {
86005
87020
  type: "string"
86006
87021
  }
@@ -86474,7 +87489,7 @@ ${result.content}`);
86474
87489
  let forcedDoneVerdict;
86475
87490
  if (status === "done") {
86476
87491
  const current = await svc.show(wbs);
86477
- const verdictDir = options.verdictDir ?? join22(context4.cwd, ".spur", "run");
87492
+ const verdictDir = options.verdictDir ?? join23(context4.cwd, ".spur", "run");
86478
87493
  const loaded = await readVerdictArtifact(context4.fs, verdictDir, wbs);
86479
87494
  const guardOutcome = evaluateDoneTransition({
86480
87495
  wbs,
@@ -86498,10 +87513,10 @@ ${result.content}`);
86498
87513
  context4.setExitCode(1);
86499
87514
  return;
86500
87515
  }
86501
- if (guardOutcome.reason === "forced" && loaded.artifact !== undefined) {
87516
+ if (guardOutcome.reason === "forced") {
86502
87517
  forcedDone = true;
86503
87518
  forcedDoneReason = options.reason;
86504
- forcedDoneVerdict = loaded.artifact.verdict;
87519
+ forcedDoneVerdict = loaded.artifact?.verdict ?? "UNKNOWN";
86505
87520
  }
86506
87521
  }
86507
87522
  const result = await svc.updateStatus(wbs, status);
@@ -87015,7 +88030,7 @@ function loadTemplateContent(projectRoot, variant) {
87015
88030
  return templateContentCache.get(variant);
87016
88031
  if (templateMissSet.has(variant))
87017
88032
  return;
87018
- const localPath = join22(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
88033
+ const localPath = join23(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
87019
88034
  if (existsSync9(localPath)) {
87020
88035
  const content = readFileSync8(localPath, "utf8");
87021
88036
  templateContentCache.set(variant, content);
@@ -87023,7 +88038,7 @@ function loadTemplateContent(projectRoot, variant) {
87023
88038
  }
87024
88039
  const root = bundledConfigRoot();
87025
88040
  if (root !== null) {
87026
- const templatePath = join22(root, "templates", "task", `${variant}.md`);
88041
+ const templatePath = join23(root, "templates", "task", `${variant}.md`);
87027
88042
  if (existsSync9(templatePath)) {
87028
88043
  const content = readFileSync8(templatePath, "utf8");
87029
88044
  templateContentCache.set(variant, content);
@@ -87039,13 +88054,13 @@ function loadTemplateBodies(projectRoot, variant) {
87039
88054
  if (cached2 !== undefined)
87040
88055
  return cached2;
87041
88056
  let bodies = {};
87042
- const localPath = join22(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
88057
+ const localPath = join23(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
87043
88058
  if (existsSync9(localPath)) {
87044
88059
  bodies = extractTemplateBodies(readFileSync8(localPath, "utf8"));
87045
88060
  } else {
87046
88061
  const root = bundledConfigRoot();
87047
88062
  if (root !== null) {
87048
- const templatePath = join22(root, "templates", "task", `${variant}.md`);
88063
+ const templatePath = join23(root, "templates", "task", `${variant}.md`);
87049
88064
  if (existsSync9(templatePath)) {
87050
88065
  bodies = extractTemplateBodies(readFileSync8(templatePath, "utf8"));
87051
88066
  }
@@ -87087,7 +88102,7 @@ async function loadSectionMatrix(projectRoot) {
87087
88102
  return promise2;
87088
88103
  }
87089
88104
  async function loadSectionMatrixUncached(projectRoot) {
87090
- const localPath = join22(projectRoot, ".spur", "tasks", "section-matrix.yaml");
88105
+ const localPath = join23(projectRoot, ".spur", "tasks", "section-matrix.yaml");
87091
88106
  if (existsSync9(localPath)) {
87092
88107
  const data = await loadStructuredSpurConfig(localPath, {
87093
88108
  validateJsonSchema: true,
@@ -87097,7 +88112,7 @@ async function loadSectionMatrixUncached(projectRoot) {
87097
88112
  }
87098
88113
  const root = bundledConfigRoot();
87099
88114
  if (root !== null) {
87100
- const matrixPath = join22(root, "tasks", "section-matrix.yaml");
88115
+ const matrixPath = join23(root, "tasks", "section-matrix.yaml");
87101
88116
  if (existsSync9(matrixPath)) {
87102
88117
  const data = await loadStructuredSpurConfig(matrixPath, {
87103
88118
  validateJsonSchema: true,
@@ -87357,6 +88372,8 @@ init_dist7();
87357
88372
  init_dist6();
87358
88373
  import { spawn as spawn2 } from "child_process";
87359
88374
  import { resolve as resolve5 } from "path";
88375
+ import { createInterface } from "readline";
88376
+ import { setTimeout as sleep3 } from "timers/promises";
87360
88377
  function parseVars(raw2) {
87361
88378
  if (raw2 === undefined) {
87362
88379
  return;
@@ -87379,6 +88396,11 @@ function parseVars(raw2) {
87379
88396
  }
87380
88397
  return vars;
87381
88398
  }
88399
+ function submitSteeringLine(controller, output2, line) {
88400
+ const ack = controller.submitLine(line);
88401
+ if (ack === undefined)
88402
+ output2.error(`[steer] ignored command: ${line}`);
88403
+ }
87382
88404
  async function resolveWorkflowPaths(cwd) {
87383
88405
  try {
87384
88406
  const config4 = await loadSpurConfig(cwd, { embeddedSchemas: EMBEDDED_SPUR_SCHEMAS });
@@ -87411,19 +88433,47 @@ ${result.errors.map((m) => ` - ${m}`).join(`
87411
88433
  }
87412
88434
  context4.setExitCode(result.valid ? 0 : 1);
87413
88435
  });
87414
- workflow.command("run").description("Execute a workflow definition.").argument("<file>", "Workflow YAML file").option("--run-id <id>", "Persisted run id for workflow run").option("--vars <json>", `Per-run variable overrides as a JSON object, e.g. '{"taskId":"0042"}'`).option("--dry-run", "Validate and walk transitions without executing actions").option("--async", "Start the workflow in the background and exit immediately \u2014 monitor with `spur workflow trace <run-id>`").option("--no-plan", "Suppress the run-start plan preview (synchronous runs only)").option("--json", "Output machine-readable JSON where supported").action(async (file2, options) => {
88436
+ workflow.command("run").description("Execute a workflow definition.").argument("<file>", "Workflow YAML file").option("--run-id <id>", "Persisted run id for workflow run").option("--vars <json>", `Per-run variable overrides as a JSON object, e.g. '{"taskId":"0042"}'`).option("--dry-run", "Validate and walk transitions without executing actions").option("--async", "Start the workflow in the background and exit immediately \u2014 monitor with `spur workflow trace <run-id>`").option("--no-plan", "Suppress the run-start plan preview (synchronous runs only)").option("--quiet", "Suppress plan and per-step progress; keep the final summary").option("--silent", "Suppress all routine output; errors still set a non-zero exit status").option("--verbose", "Include transitions and correlation diagnostics in human progress").option("--detail <level>", "Human detail level: minimal, invocation, or full").option("--trace-file", "Append a redacted schema-versioned JSONL trace under .spur/runs/workflow/").option("--steer", "Accept local in-process steering commands on stdin at declared action boundaries").option("--json", "Output machine-readable JSON where supported").action(async (file2, options) => {
88437
+ const json3 = options.json === true;
88438
+ const silent = !json3 && options.silent === true;
88439
+ const quiet = !json3 && options.quiet === true;
88440
+ if (!json3 && options.quiet === true && options.verbose === true) {
88441
+ context4.output.error("--quiet and --verbose are mutually exclusive");
88442
+ context4.setExitCode(2);
88443
+ return;
88444
+ }
88445
+ if (!json3 && options.silent === true && (options.quiet === true || options.verbose === true)) {
88446
+ context4.output.error("--silent cannot be combined with --quiet or --verbose");
88447
+ context4.setExitCode(2);
88448
+ return;
88449
+ }
88450
+ if (options.steer === true && (json3 || options.async === true)) {
88451
+ context4.output.error("--steer is synchronous and in-process; it cannot be combined with --json or --async");
88452
+ context4.setExitCode(2);
88453
+ return;
88454
+ }
88455
+ const requestedDetail = options.detail;
88456
+ if (requestedDetail !== undefined && !["minimal", "invocation", "full"].includes(requestedDetail)) {
88457
+ context4.output.error("--detail must be one of: minimal, invocation, full");
88458
+ context4.setExitCode(2);
88459
+ return;
88460
+ }
88461
+ const detail = options.verbose === true ? "full" : requestedDetail ?? "invocation";
87415
88462
  if (options.async) {
87416
- const runId = options.runId || crypto.randomUUID();
88463
+ const runId2 = options.runId || crypto.randomUUID();
87417
88464
  const spurParts = resolveSpurBin().split(" ");
87418
88465
  const spurBin = spurParts[0] ?? process.execPath;
87419
88466
  const spurArgs = spurParts.slice(1);
87420
- const cmd = [...spurArgs, "workflow", "run", file2, "--run-id", runId];
88467
+ const cmd = [...spurArgs, "workflow", "run", file2, "--run-id", runId2];
87421
88468
  if (options.vars) {
87422
88469
  cmd.push("--vars", options.vars);
87423
88470
  }
87424
88471
  if (options.dryRun) {
87425
88472
  cmd.push("--dry-run");
87426
88473
  }
88474
+ if (options.traceFile) {
88475
+ cmd.push("--trace-file");
88476
+ }
87427
88477
  try {
87428
88478
  const child = spawn2(spurBin, cmd, {
87429
88479
  stdio: "ignore",
@@ -87433,50 +88483,121 @@ ${result.errors.map((m) => ` - ${m}`).join(`
87433
88483
  child.unref();
87434
88484
  } catch {
87435
88485
  const result2 = await makeSvc(options.json).run(file2, {
87436
- runId,
88486
+ runId: runId2,
87437
88487
  vars: { spurBin: resolveSpurBin(), ...parseVars(options.vars) },
87438
88488
  dryRun: options.dryRun || undefined
87439
88489
  });
87440
- context4.output.write(options.json ? toJson2(result2) : `workflow ${result2.status}: ${result2.workflowName} -> ${result2.finalState} (async spawn failed, ran sync)`);
88490
+ if (json3)
88491
+ context4.output.write(toJson2(result2));
88492
+ else if (!silent) {
88493
+ context4.output.write(`workflow ${result2.status}: ${result2.workflowName} -> ${result2.finalState} (async spawn failed, ran sync)`);
88494
+ }
87441
88495
  context4.setExitCode(result2.status === "done" ? 0 : 1);
87442
88496
  return;
87443
88497
  }
87444
- const asyncResult = { runId, status: "started", workflowName: file2 };
87445
- context4.output.write(options.json ? toJson2(asyncResult) : `Started async run: ${runId}
87446
- Monitor with: spur workflow trace ${runId}`);
88498
+ const asyncResult = { runId: runId2, status: "started", workflowName: file2 };
88499
+ if (json3)
88500
+ context4.output.write(toJson2(asyncResult));
88501
+ else if (!silent) {
88502
+ context4.output.write(`Started async run: ${runId2}
88503
+ Monitor with: spur workflow trace ${runId2} --follow`);
88504
+ }
87447
88505
  context4.setExitCode(0);
87448
88506
  return;
87449
88507
  }
87450
88508
  const vars = { spurBin: resolveSpurBin(), ...parseVars(options.vars) };
87451
- const human = options.json !== true;
88509
+ const runId = options.runId || crypto.randomUUID();
88510
+ const humanProgress = !json3 && !quiet && !silent;
87452
88511
  let bus;
87453
- if (human) {
88512
+ let traceWriter;
88513
+ const heartbeats = new Map;
88514
+ if (humanProgress || options.traceFile === true || options.steer === true) {
88515
+ bus = new EventBus;
88516
+ }
88517
+ if (options.traceFile === true && bus !== undefined) {
88518
+ traceWriter = new WorkflowTraceWriter(context4.cwd, runId);
88519
+ traceWriter.attach(bus);
88520
+ }
88521
+ if (humanProgress && bus !== undefined) {
88522
+ context4.output.write(`Run: ${runId}`);
87454
88523
  if (options.plan !== false) {
87455
88524
  try {
87456
88525
  const def = await loadWorkflowDef(resolve5(context4.cwd, file2), { validateSchema: false });
87457
88526
  context4.output.write(renderRunPlan(def));
87458
88527
  } catch {}
87459
88528
  }
87460
- bus = new EventBus;
87461
88529
  const report = (event2) => {
87462
- const line = renderStepLine(event2);
88530
+ const line = renderStepLine(event2, { detail });
87463
88531
  if (line !== null)
87464
88532
  context4.output.write(line);
87465
88533
  };
87466
88534
  bus.on("workflow.phase", report);
87467
- bus.on("workflow.action.started", report);
87468
- bus.on("workflow.action.finished", report);
88535
+ if (detail === "full")
88536
+ bus.on("workflow.transition", report);
88537
+ bus.on("workflow.action.started", (event2) => {
88538
+ report(event2);
88539
+ const startedAt2 = Date.parse(event2.at);
88540
+ const timer = setInterval(() => {
88541
+ const line = renderActionHeartbeat(event2, Math.max(0, Date.now() - startedAt2), { detail });
88542
+ if (line !== null)
88543
+ context4.output.write(line);
88544
+ }, 30000);
88545
+ timer.unref?.();
88546
+ heartbeats.set(event2.actionId, timer);
88547
+ });
88548
+ bus.on("workflow.action.finished", (event2) => {
88549
+ const timer = heartbeats.get(event2.actionId);
88550
+ if (timer !== undefined)
88551
+ clearInterval(timer);
88552
+ heartbeats.delete(event2.actionId);
88553
+ report(event2);
88554
+ });
88555
+ bus.on("workflow.agent", (event2) => {
88556
+ if (event2.kind === "started" && event2.actionId !== undefined) {
88557
+ const timer = heartbeats.get(event2.actionId);
88558
+ if (timer !== undefined)
88559
+ clearInterval(timer);
88560
+ heartbeats.delete(event2.actionId);
88561
+ }
88562
+ report(event2);
88563
+ });
88564
+ }
88565
+ const steeringController = options.steer === true ? new WorkflowSteeringController((ack) => {
88566
+ bus?.emit("workflow.steering", ack);
88567
+ context4.output.write(`[steer] ${ack.accepted ? "ack" : "nack"} ${ack.operation} \xB7 ${ack.reason ?? `version=${ack.version}`}`);
88568
+ }, configuredSecretValues(context4.env), new Set(["operator"]), (snapshot) => {
88569
+ if (snapshot.state === "boundary") {
88570
+ context4.output.write(`[steer] boundary action=${snapshot.actionId} version=${snapshot.version} \xB7 commands: continue | note <text> | retry | abort`);
88571
+ }
88572
+ }) : undefined;
88573
+ const steeringInput = steeringController === undefined ? undefined : createInterface({ input: process.stdin, terminal: process.stdin.isTTY === true });
88574
+ if (steeringInput !== undefined && steeringController !== undefined) {
88575
+ steeringInput.on("line", submitSteeringLine.bind(undefined, steeringController, context4.output));
88576
+ }
88577
+ let result;
88578
+ try {
88579
+ result = await makeSvc(json3, bus).run(file2, {
88580
+ runId,
88581
+ vars,
88582
+ dryRun: options.dryRun || undefined,
88583
+ recordSelfPid: process.env.SPUR_ASYNC_WORKER === "1",
88584
+ ...steeringController !== undefined ? { steeringController } : {}
88585
+ });
88586
+ } finally {
88587
+ for (const timer of heartbeats.values())
88588
+ clearInterval(timer);
88589
+ heartbeats.clear();
88590
+ await traceWriter?.flush();
88591
+ steeringInput?.close();
88592
+ }
88593
+ if (json3)
88594
+ context4.output.write(toJson2(result));
88595
+ else if (!silent) {
88596
+ context4.output.write(`workflow ${result.status}: ${result.workflowName} -> ${result.finalState}${typeof result.reason === "string" ? ` \u2014 ${result.reason}` : ""}`);
87469
88597
  }
87470
- const result = await makeSvc(options.json, bus).run(file2, {
87471
- runId: options.runId || undefined,
87472
- vars,
87473
- dryRun: options.dryRun || undefined,
87474
- recordSelfPid: process.env.SPUR_ASYNC_WORKER === "1"
87475
- });
87476
- context4.output.write(options.json ? toJson2(result) : `workflow ${result.status}: ${result.workflowName} -> ${result.finalState}`);
87477
88598
  context4.setExitCode(result.status === "done" ? 0 : 1);
87478
88599
  });
87479
- workflow.command("continue").description("Resume a paused (HITL) workflow run. Omit run-id to resume the most recent paused run.").argument("[run-id]", "Run ID to resume (default: the most recent paused run)").option("--yes", "Resume without prompting for confirmation").option("--json", "Output machine-readable JSON where supported").action(async (runId, options) => {
88600
+ workflow.command("continue").description("Resume a paused (HITL) workflow run. Omit run-id to resume the most recent paused run.").argument("[run-id]", "Run ID to resume (default: the most recent paused run)").option("--yes", "Skip the CLI resume confirmation (does not set the persisted HITL answer)").option("--json", "Output machine-readable JSON where supported").action(async (runId, options) => {
87480
88601
  const json3 = options.json === true;
87481
88602
  const svc = makeSvc(json3);
87482
88603
  try {
@@ -87562,7 +88683,7 @@ Monitor with: spur workflow trace ${runId}`);
87562
88683
  context4.output.write(formatListHuman(result));
87563
88684
  }
87564
88685
  });
87565
- workflow.command("trace").description("Show persisted workflow run history.").argument("[run-id]", "Run ID for per-run timeline detail").option("--workflow <name>", "Filter by workflow name").option("--status <status>", "Filter by status: done, failed, running").option("--since <iso-date>", "Filter runs started on or after this date").option("--last <n>", "Limit results (default 20)", "20").option("--json", "Output machine-readable JSON where supported").action(async (runId, options) => {
88686
+ workflow.command("trace").description("Show persisted workflow run history.").argument("[run-id]", "Run ID for per-run timeline detail").option("--workflow <name>", "Filter by workflow name").option("--status <status>", "Filter by status: done, failed, running").option("--since <iso-date>", "Filter runs started on or after this date").option("--last <n>", "Limit results (default 20)", "20").option("--follow", "Replay a run timeline and poll persisted state until it becomes terminal").option("--poll <ms>", "Follow polling interval in milliseconds", "1000").option("--json", "Output machine-readable JSON where supported").action(async (runId, options) => {
87566
88687
  const svc = makeSvc();
87567
88688
  const last = parseInt(options.last, 10);
87568
88689
  if (Number.isNaN(last) || last < 1) {
@@ -87570,11 +88691,31 @@ Monitor with: spur workflow trace ${runId}`);
87570
88691
  context4.setExitCode(1);
87571
88692
  return;
87572
88693
  }
88694
+ const pollMs = parseInt(options.poll, 10);
88695
+ if (Number.isNaN(pollMs) || pollMs < 50) {
88696
+ context4.output.error("--poll must be an integer of at least 50ms");
88697
+ context4.setExitCode(1);
88698
+ return;
88699
+ }
88700
+ if (options.follow === true && runId === undefined) {
88701
+ context4.output.error("--follow requires a run-id");
88702
+ context4.setExitCode(1);
88703
+ return;
88704
+ }
88705
+ if (options.follow === true && options.json === true) {
88706
+ context4.output.error("--follow is a human streaming mode and cannot be combined with --json");
88707
+ context4.setExitCode(1);
88708
+ return;
88709
+ }
87573
88710
  if (options.status !== undefined && !["done", "failed", "running"].includes(options.status)) {
87574
88711
  context4.output.error("--status must be one of: done, failed, running");
87575
88712
  context4.setExitCode(1);
87576
88713
  return;
87577
88714
  }
88715
+ if (options.follow === true && runId !== undefined) {
88716
+ await followTrace(svc, runId, pollMs, (line) => context4.output.write(line));
88717
+ return;
88718
+ }
87578
88719
  const result = runId ? await svc.trace(runId) : await svc.trace({
87579
88720
  workflow: options.workflow,
87580
88721
  status: options.status,
@@ -87637,22 +88778,14 @@ function formatTraceList2(result) {
87637
88778
  function formatTraceTimeline(result) {
87638
88779
  const { run, events: events2 } = result;
87639
88780
  const dryLabel = run.isDryRun ? " [DRY RUN]" : "";
88781
+ const reasonLabel = run.failureReason ? ` \u2014 ${run.failureReason}` : "";
87640
88782
  const lines = [
87641
- `Run: ${run.runId} \u2014 ${run.workflowName} (${run.mode}) \u2014 ${run.status}${dryLabel}`,
88783
+ `Run: ${run.runId} \u2014 ${run.workflowName} (${run.mode}) \u2014 ${run.status}${dryLabel}${reasonLabel}`,
87642
88784
  `Started: ${run.startedAt} Completed: ${run.completedAt ?? "-"} Events: ${events2.length}`,
87643
88785
  ""
87644
88786
  ];
87645
88787
  for (const event2 of events2) {
87646
- if (event2.kind === "phase") {
87647
- const ts = event2.startedAt ?? event2.completedAt ?? "";
87648
- lines.push(` ${event2.phase.padEnd(20)} ${event2.status.padEnd(10)} ${ts}`);
87649
- } else if (event2.kind === "transition") {
87650
- const guard2 = event2.trigger ? ` [${event2.trigger}]` : "";
87651
- lines.push(` \u2192 ${event2.to}${guard2}`);
87652
- } else {
87653
- const costSuffix = formatActionCost(event2);
87654
- lines.push(` \u26A1 ${event2.actionKind.padEnd(15)} ${event2.duration.padEnd(6)}${event2.label}${costSuffix}`);
87655
- }
88788
+ lines.push(formatTimelineEvent(event2));
87656
88789
  }
87657
88790
  const hasUnjoinedCost = events2.some((e) => e.kind === "action" && e.cost !== undefined && e.cost.totals.records === 0);
87658
88791
  if (hasUnjoinedCost) {
@@ -87661,6 +88794,56 @@ function formatTraceTimeline(result) {
87661
88794
  return lines.join(`
87662
88795
  `).trimEnd();
87663
88796
  }
88797
+ function formatTimelineEvent(event2) {
88798
+ if (event2.kind === "phase") {
88799
+ const ts = event2.startedAt ?? event2.completedAt ?? "";
88800
+ return ` ${event2.phase.padEnd(20)} ${event2.status.padEnd(10)} ${ts}`;
88801
+ }
88802
+ if (event2.kind === "transition") {
88803
+ const guard2 = event2.trigger ? ` [${event2.trigger}]` : "";
88804
+ return ` \u2192 ${event2.to}${guard2}`;
88805
+ }
88806
+ const costSuffix = formatActionCost(event2);
88807
+ return ` \u26A1 ${event2.actionKind.padEnd(15)} ${event2.duration.padEnd(6)}${event2.label}${costSuffix}`;
88808
+ }
88809
+ async function followTrace(service, runId, pollMs, write, wait = (ms) => sleep3(ms)) {
88810
+ let missingAttempts = 0;
88811
+ let timeline;
88812
+ while (true) {
88813
+ try {
88814
+ timeline = await service.trace(runId);
88815
+ break;
88816
+ } catch (error51) {
88817
+ if (!String(error51).includes("Run not found") || missingAttempts >= 20)
88818
+ throw error51;
88819
+ missingAttempts++;
88820
+ await wait(pollMs);
88821
+ }
88822
+ }
88823
+ write(formatTraceTimeline(timeline));
88824
+ const seen = new Set(timeline.events.map((event2) => JSON.stringify(event2)));
88825
+ if (isTerminalTraceStatus(timeline.run.status))
88826
+ return;
88827
+ while (true) {
88828
+ await wait(pollMs);
88829
+ const next = await service.trace(runId);
88830
+ for (const event2 of next.events) {
88831
+ const fingerprint2 = JSON.stringify(event2);
88832
+ if (seen.has(fingerprint2))
88833
+ continue;
88834
+ seen.add(fingerprint2);
88835
+ write(formatTimelineEvent(event2));
88836
+ }
88837
+ if (isTerminalTraceStatus(next.run.status)) {
88838
+ const reason = next.run.failureReason ? ` \u2014 ${next.run.failureReason}` : "";
88839
+ write(`Run finalized: ${next.run.status}${reason}`);
88840
+ return;
88841
+ }
88842
+ }
88843
+ }
88844
+ function isTerminalTraceStatus(status) {
88845
+ return status !== "running" && status !== "pending";
88846
+ }
87664
88847
  function formatActionCost(event2) {
87665
88848
  if (event2.kind !== "action")
87666
88849
  return "";
@@ -87681,7 +88864,7 @@ init_src3();
87681
88864
  init_src();
87682
88865
  init_src2();
87683
88866
  init_dist5();
87684
- import { dirname as dirname14, join as join23, resolve as resolve6 } from "path";
88867
+ import { dirname as dirname15, join as join24, resolve as resolve6 } from "path";
87685
88868
  import { isatty as isatty4 } from "tty";
87686
88869
 
87687
88870
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -89095,10 +90278,10 @@ function createCliContext(options) {
89095
90278
  function noopSetExitCode(_code) {}
89096
90279
  async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, dbUrl) {
89097
90280
  const config4 = buildConfigFromEnv(env);
89098
- const configuredUrl = env.DATABASE_URL === undefined ? join23(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
90281
+ const configuredUrl = env.DATABASE_URL === undefined ? join24(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
89099
90282
  const url2 = dbUrl ?? configuredUrl;
89100
90283
  if (url2 !== IN_MEMORY_DATABASE_URL) {
89101
- await createNodeFileSystem3().ensureDir(dirname14(url2));
90284
+ await createNodeFileSystem3().ensureDir(dirname15(url2));
89102
90285
  }
89103
90286
  return createMigratedDb({ url: url2 });
89104
90287
  }
@@ -89183,7 +90366,7 @@ function bannerText() {
89183
90366
  }
89184
90367
  async function runCli() {
89185
90368
  const argv = process.argv.slice(2);
89186
- if (!argv.includes("--json")) {
90369
+ if (!argv.some((arg) => arg === "--json" || arg === "--quiet" || arg === "--silent")) {
89187
90370
  consoleOutput.write(bannerText());
89188
90371
  }
89189
90372
  return main();