@gobing-ai/spur 0.3.29 → 0.3.31

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 (71) hide show
  1. package/config/rules/strict/runtime-boundaries.yaml +2 -1
  2. package/config/templates/AGENTS.md +3 -8
  3. package/config/templates/docs/04_DESIGN.md +8 -5
  4. package/config/templates/docs/99_PROJECT_CONSTITUTION.md +4 -2
  5. package/config/workflows/basic.yaml +92 -14
  6. package/config/workflows/docs-pipeline.yaml +71 -25
  7. package/config/workflows/feature-dev.yaml +104 -35
  8. package/config/workflows/feature-lifecycle.yaml +10 -2
  9. package/config/workflows/idea-pipeline.yaml +118 -54
  10. package/config/workflows/planning-pipeline.yaml +78 -30
  11. package/config/workflows/task-lifecycle.yaml +10 -2
  12. package/config/workflows/task-pipeline.yaml +214 -56
  13. package/config/workflows/wayfinder-resolution.yaml +64 -27
  14. package/config/workflows/wrapup-pipeline.yaml +79 -39
  15. package/package.json +9 -9
  16. package/schemas/state-machine-workflow.schema.json +5 -0
  17. package/spur.js +1306 -764
  18. package/web/_astro/BoardApp.CBVEjvSW.js +1 -0
  19. package/web/_astro/{BoardApp.BwAdAgK9.js → BoardApp.CyyIiK76.js} +74 -74
  20. package/web/_astro/TaskDetail.BfUuRsfM.js +1 -0
  21. package/web/_astro/{arc.CO-I_PZe.js → arc.C7fql4LL.js} +1 -1
  22. package/web/_astro/{architectureDiagram-3BPJPVTR.Si-A1Ncl.js → architectureDiagram-3BPJPVTR.IJPsRX-V.js} +1 -1
  23. package/web/_astro/{blockDiagram-GPEHLZMM.CeNy_ta6.js → blockDiagram-GPEHLZMM.B1AUwBxq.js} +1 -1
  24. package/web/_astro/{c4Diagram-AAUBKEIU.BgN_scEU.js → c4Diagram-AAUBKEIU.BuSJPR3z.js} +1 -1
  25. package/web/_astro/channel.D3uZSASb.js +1 -0
  26. package/web/_astro/{chunk-2J33WTMH.C3oDtmdi.js → chunk-2J33WTMH.CaOPTr9l.js} +1 -1
  27. package/web/_astro/{chunk-4BX2VUAB.Bv8Fxh4H.js → chunk-4BX2VUAB.DQzxExn8.js} +1 -1
  28. package/web/_astro/{chunk-55IACEB6.BT-TqtV6.js → chunk-55IACEB6.IIb103c7.js} +1 -1
  29. package/web/_astro/{chunk-727SXJPM.DkGMsI0B.js → chunk-727SXJPM.DOYz1K1b.js} +1 -1
  30. package/web/_astro/{chunk-AQP2D5EJ.B_-SqGnF.js → chunk-AQP2D5EJ.CFcfW-wt.js} +1 -1
  31. package/web/_astro/{chunk-FMBD7UC4.DwR3skMv.js → chunk-FMBD7UC4.C7Hn0jo3.js} +1 -1
  32. package/web/_astro/{chunk-ND2GUHAM.BaTQutFl.js → chunk-ND2GUHAM.Ba83VQ1m.js} +1 -1
  33. package/web/_astro/{chunk-QZHKN3VN.BJMSqqJp.js → chunk-QZHKN3VN.CizNbIIP.js} +1 -1
  34. package/web/_astro/{classDiagram-4FO5ZUOK.SaqCNUPF.js → classDiagram-4FO5ZUOK.2NYYPXHq.js} +1 -1
  35. package/web/_astro/{classDiagram-v2-Q7XG4LA2.SaqCNUPF.js → classDiagram-v2-Q7XG4LA2.2NYYPXHq.js} +1 -1
  36. package/web/_astro/{cose-bilkent-S5V4N54A.BkmjA_E2.js → cose-bilkent-S5V4N54A.DwBqVzml.js} +1 -1
  37. package/web/_astro/{dagre-BM42HDAG.CNUvWhrX.js → dagre-BM42HDAG.DqnYsHWG.js} +1 -1
  38. package/web/_astro/{diagram-2AECGRRQ.C68Cg9uE.js → diagram-2AECGRRQ.D8TKhgy-.js} +1 -1
  39. package/web/_astro/{diagram-5GNKFQAL.DbHkPLEn.js → diagram-5GNKFQAL.BUD6Prj5.js} +1 -1
  40. package/web/_astro/{diagram-KO2AKTUF.Dt0EdErs.js → diagram-KO2AKTUF.Cvg7hmND.js} +1 -1
  41. package/web/_astro/{diagram-LMA3HP47.Bixs6mnm.js → diagram-LMA3HP47.FUG_B9eS.js} +1 -1
  42. package/web/_astro/{diagram-OG6HWLK6.B4KBI6KT.js → diagram-OG6HWLK6.XsBZQ0hQ.js} +1 -1
  43. package/web/_astro/{erDiagram-TEJ5UH35.C_4i9Xvx.js → erDiagram-TEJ5UH35.M_LSGgLQ.js} +1 -1
  44. package/web/_astro/{flowDiagram-I6XJVG4X.CfGFczAY.js → flowDiagram-I6XJVG4X.DZikZBRa.js} +1 -1
  45. package/web/_astro/{ganttDiagram-6RSMTGT7.C2AIvtmg.js → ganttDiagram-6RSMTGT7.DTKuEmXY.js} +1 -1
  46. package/web/_astro/{gitGraphDiagram-PVQCEYII.HlXuGqQg.js → gitGraphDiagram-PVQCEYII.Dt-E9XmY.js} +1 -1
  47. package/web/_astro/index.yAse9IaO.css +1 -0
  48. package/web/_astro/{infoDiagram-5YYISTIA.BWQJsJ4Z.js → infoDiagram-5YYISTIA.D5snevU1.js} +1 -1
  49. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CCHgIHik.js → ishikawaDiagram-YF4QCWOH.DmXdBf9W.js} +1 -1
  50. package/web/_astro/{journeyDiagram-JHISSGLW.D9M6YwOJ.js → journeyDiagram-JHISSGLW.HPJSRkkU.js} +1 -1
  51. package/web/_astro/{kanban-definition-UN3LZRKU.K20D-a1_.js → kanban-definition-UN3LZRKU.BxCqCnL1.js} +1 -1
  52. package/web/_astro/{linear.DeP5Qsol.js → linear.BnXQUpS-.js} +1 -1
  53. package/web/_astro/{mermaid.core.ClzxNMPU.js → mermaid.core.D-ZeOmpg.js} +4 -4
  54. package/web/_astro/{mindmap-definition-RKZ34NQL.CGn9RUNj.js → mindmap-definition-RKZ34NQL.DxrftiFR.js} +1 -1
  55. package/web/_astro/{pieDiagram-4H26LBE5.CoA92Csb.js → pieDiagram-4H26LBE5.D-ZcWxwg.js} +1 -1
  56. package/web/_astro/{quadrantDiagram-W4KKPZXB.CJ_UPjM1.js → quadrantDiagram-W4KKPZXB.C-dVJ7GW.js} +1 -1
  57. package/web/_astro/{requirementDiagram-4Y6WPE33.KkEPNNUU.js → requirementDiagram-4Y6WPE33.lalE_R8X.js} +1 -1
  58. package/web/_astro/{sankeyDiagram-5OEKKPKP.CoCWbQgh.js → sankeyDiagram-5OEKKPKP.C4uPynAF.js} +1 -1
  59. package/web/_astro/{sequenceDiagram-3UESZ5HK.DUFpV3EP.js → sequenceDiagram-3UESZ5HK.uBOenkqh.js} +1 -1
  60. package/web/_astro/{stateDiagram-AJRCARHV.CgWX0_9m.js → stateDiagram-AJRCARHV.CQOusSP2.js} +1 -1
  61. package/web/_astro/{stateDiagram-v2-BHNVJYJU.BKUXeGSf.js → stateDiagram-v2-BHNVJYJU.Bw0ZdjYb.js} +1 -1
  62. package/web/_astro/{timeline-definition-PNZ67QCA.CXayAguY.js → timeline-definition-PNZ67QCA.DbkPA5ce.js} +1 -1
  63. package/web/_astro/{vennDiagram-CIIHVFJN.DPak_Elh.js → vennDiagram-CIIHVFJN.CIKhzwoA.js} +1 -1
  64. package/web/_astro/{wardley-L42UT6IY.t3ZlDKd0.js → wardley-L42UT6IY.0P-tqaFs.js} +1 -1
  65. package/web/_astro/{wardleyDiagram-YWT4CUSO.CwPSVASQ.js → wardleyDiagram-YWT4CUSO.DrwTvM_M.js} +1 -1
  66. package/web/_astro/{xychartDiagram-2RQKCTM6.CJfrQgpF.js → xychartDiagram-2RQKCTM6.BgJsQVms.js} +1 -1
  67. package/web/index.html +2 -2
  68. package/web/_astro/BoardApp.Bk3T0o6s.js +0 -1
  69. package/web/_astro/TaskDetail.L36slEqE.js +0 -1
  70. package/web/_astro/channel.CYdGnFHM.js +0 -1
  71. package/web/_astro/index.D5Wqk2Tw.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.15/node_modules/@gobing-ai/ts-utils/dist/errors.js
50
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.18/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.15/node_modules/@gobing-ai/ts-utils/dist/api-response.js
61
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.18/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.15/node_modules/@gobing-ai/ts-utils/dist/cursor.js
84
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.18/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.15/node_modules/@gobing-ai/ts-utils/dist/object.js
87
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.18/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
  }
@@ -102,7 +102,7 @@ function deepMerge(target, source) {
102
102
  return result;
103
103
  }
104
104
 
105
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.15/node_modules/@gobing-ai/ts-utils/dist/output.js
105
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.18/node_modules/@gobing-ai/ts-utils/dist/output.js
106
106
  function processStream(name) {
107
107
  const proc = globalThis.process;
108
108
  const stream = proc?.[name];
@@ -123,7 +123,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
123
123
  }
124
124
  var defaultStdoutTarget, defaultStderrTarget;
125
125
 
126
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.15/node_modules/@gobing-ai/ts-utils/dist/index.js
126
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.18/node_modules/@gobing-ai/ts-utils/dist/index.js
127
127
  var init_dist = __esm(() => {
128
128
  init_api_response();
129
129
  init_cursor();
@@ -21745,7 +21745,7 @@ var init_zod = __esm(() => {
21745
21745
  init_external();
21746
21746
  });
21747
21747
 
21748
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/config.js
21748
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/config.js
21749
21749
  function getProcessEnv() {
21750
21750
  return process.env;
21751
21751
  }
@@ -21823,7 +21823,7 @@ var init_config = __esm(() => {
21823
21823
  };
21824
21824
  });
21825
21825
 
21826
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21826
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21827
21827
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
21828
21828
  import { dirname, resolve as resolvePath } from "path";
21829
21829
  function createNodeFileSystem(root, paths) {
@@ -21910,7 +21910,7 @@ function findProjectRoot(startDir) {
21910
21910
  }
21911
21911
  var init_file_system_node = () => {};
21912
21912
 
21913
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21913
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21914
21914
  var DbModuleNotInstalledError;
21915
21915
  var init_db_errors = __esm(() => {
21916
21916
  DbModuleNotInstalledError = class DbModuleNotInstalledError extends Error {
@@ -29101,7 +29101,7 @@ var init_execa = __esm(() => {
29101
29101
  } = getIpcExport());
29102
29102
  });
29103
29103
 
29104
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29104
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29105
29105
  import { isatty } from "tty";
29106
29106
 
29107
29107
  class NodeProcessExecutor {
@@ -29144,6 +29144,14 @@ class NodeProcessExecutor {
29144
29144
  });
29145
29145
  try {
29146
29146
  const subprocess = execa(options.command, args, execaOptions);
29147
+ if (subprocess.pid !== undefined) {
29148
+ this.config.registry?.update(registryId, { pid: subprocess.pid });
29149
+ if (options.onSpawn !== undefined) {
29150
+ try {
29151
+ options.onSpawn(subprocess.pid);
29152
+ } catch {}
29153
+ }
29154
+ }
29147
29155
  const stopGroupCancellation = observeProcessGroupCancellation(subprocess, options.signal);
29148
29156
  observeOutput(subprocess.stdout, "stdout", options.onOutput);
29149
29157
  observeOutput(subprocess.stderr, "stderr", options.onOutput);
@@ -29431,7 +29439,7 @@ var init_process_executor = __esm(() => {
29431
29439
  init_execa();
29432
29440
  });
29433
29441
 
29434
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29442
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29435
29443
  function getNodeFileSystem() {
29436
29444
  if (!_nodeFileSystem)
29437
29445
  _nodeFileSystem = createNodeFileSystem();
@@ -29491,7 +29499,7 @@ var init_runtime_node_bun = __esm(() => {
29491
29499
  };
29492
29500
  });
29493
29501
 
29494
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/context.js
29502
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/context.js
29495
29503
  class RuntimeContext {
29496
29504
  scope;
29497
29505
  runtimeName;
@@ -29561,7 +29569,7 @@ var init_context = __esm(() => {
29561
29569
  init_runtime_node_bun();
29562
29570
  });
29563
29571
 
29564
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/path.js
29572
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/path.js
29565
29573
  function normalizeSeparators(path6) {
29566
29574
  return path6.replaceAll("\\", "/");
29567
29575
  }
@@ -29622,17 +29630,17 @@ var init_path = __esm(() => {
29622
29630
  SEP = globalThis.process?.platform === "win32" ? "\\" : "/";
29623
29631
  });
29624
29632
 
29625
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29633
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29626
29634
  var REMOTE_SCHEMA_MAX_BYTES;
29627
29635
  var init_schema_validation = __esm(() => {
29628
29636
  init_dist2();
29629
29637
  REMOTE_SCHEMA_MAX_BYTES = 5 * 1024 * 1024;
29630
29638
  });
29631
29639
 
29632
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/types.js
29640
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/types.js
29633
29641
  var init_types = () => {};
29634
29642
 
29635
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/index.js
29643
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/index.js
29636
29644
  var init_dist3 = __esm(() => {
29637
29645
  init_config();
29638
29646
  init_context();
@@ -29641,7 +29649,7 @@ var init_dist3 = __esm(() => {
29641
29649
  init_types();
29642
29650
  });
29643
29651
 
29644
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+3805a7059a817025/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29652
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+3ba223a3e166c92f/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29645
29653
  import { Database } from "bun:sqlite";
29646
29654
  var init_bun_sqlite = () => {};
29647
29655
 
@@ -33833,7 +33841,7 @@ var init_bun_sqlite2 = __esm(() => {
33833
33841
  init_session2();
33834
33842
  });
33835
33843
 
33836
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33844
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33837
33845
  var inboxMessages;
33838
33846
  var init_inbox_messages = __esm(() => {
33839
33847
  init_sqlite_core();
@@ -33852,7 +33860,7 @@ var init_inbox_messages = __esm(() => {
33852
33860
  }, (table2) => [index("idx_inbox_messages_to_status").on(table2.toId, table2.status)]);
33853
33861
  });
33854
33862
 
33855
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33863
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33856
33864
  function nowTimestamp() {
33857
33865
  return Date.now();
33858
33866
  }
@@ -33881,7 +33889,7 @@ var init_common3 = __esm(() => {
33881
33889
  appendOnlyColumns = buildAppendOnlyColumns();
33882
33890
  });
33883
33891
 
33884
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33892
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33885
33893
  var queueJobs;
33886
33894
  var init_queue_jobs = __esm(() => {
33887
33895
  init_sqlite_core();
@@ -33901,7 +33909,7 @@ var init_queue_jobs = __esm(() => {
33901
33909
  }, (table2) => [index("queue_jobs_ready_idx").on(table2.status, table2.nextRetryAt, table2.createdAt)]);
33902
33910
  });
33903
33911
 
33904
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33912
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33905
33913
  var exports_runtime = {};
33906
33914
  __export(exports_runtime, {
33907
33915
  queueJobs: () => queueJobs,
@@ -33912,7 +33920,7 @@ var init_runtime = __esm(() => {
33912
33920
  init_queue_jobs();
33913
33921
  });
33914
33922
 
33915
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33923
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33916
33924
  var exports_bun_sqlite = {};
33917
33925
  __export(exports_bun_sqlite, {
33918
33926
  BunSqliteAdapter: () => BunSqliteAdapter
@@ -33941,6 +33949,7 @@ class BunSqliteAdapter {
33941
33949
  this.sqlite.run(pragmas.journalMode);
33942
33950
  this.sqlite.run(pragmas.synchronous);
33943
33951
  this.sqlite.run(pragmas.foreignKeys);
33952
+ this.sqlite.run(pragmas.busyTimeout);
33944
33953
  this.drizzleDb = drizzle({ client: this.sqlite, schema: exports_runtime });
33945
33954
  }
33946
33955
  get db() {
@@ -33987,7 +33996,8 @@ var init_bun_sqlite3 = __esm(() => {
33987
33996
  DEFAULT_PRAGMAS = {
33988
33997
  journalMode: "PRAGMA journal_mode = WAL",
33989
33998
  synchronous: "PRAGMA synchronous = NORMAL",
33990
- foreignKeys: "PRAGMA foreign_keys = ON"
33999
+ foreignKeys: "PRAGMA foreign_keys = ON",
34000
+ busyTimeout: "PRAGMA busy_timeout = 5000"
33991
34001
  };
33992
34002
  });
33993
34003
 
@@ -34201,7 +34211,7 @@ var init_d1 = __esm(() => {
34201
34211
  init_session3();
34202
34212
  });
34203
34213
 
34204
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34214
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34205
34215
  var exports_d1 = {};
34206
34216
  __export(exports_d1, {
34207
34217
  D1Adapter: () => D1Adapter
@@ -34265,7 +34275,7 @@ var init_d12 = __esm(() => {
34265
34275
  init_runtime();
34266
34276
  });
34267
34277
 
34268
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/adapter.js
34278
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/adapter.js
34269
34279
  async function createDbAdapter(config3) {
34270
34280
  switch (config3.driver) {
34271
34281
  case "bun-sqlite": {
@@ -34305,7 +34315,7 @@ var init_drizzle_orm = __esm(() => {
34305
34315
  init_view_common();
34306
34316
  });
34307
34317
 
34308
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34318
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34309
34319
  function compilePredicate(predicate) {
34310
34320
  if ("and" in predicate) {
34311
34321
  const parts = predicate.and.map(compilePredicate).filter((p) => p !== undefined);
@@ -34343,7 +34353,7 @@ var init_query_spec = __esm(() => {
34343
34353
  };
34344
34354
  });
34345
34355
 
34346
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34356
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34347
34357
  function asSelectQuery(query) {
34348
34358
  return query;
34349
34359
  }
@@ -34385,7 +34395,7 @@ var init_base_dao = __esm(() => {
34385
34395
  init_query_spec();
34386
34396
  });
34387
34397
 
34388
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34398
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34389
34399
  var embeddedMigrations;
34390
34400
  var init_embedded_migrations = __esm(() => {
34391
34401
  embeddedMigrations = [
@@ -34417,7 +34427,7 @@ var init_embedded_migrations = __esm(() => {
34417
34427
  ];
34418
34428
  });
34419
34429
 
34420
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34430
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34421
34431
  var EntityDao;
34422
34432
  var init_entity_dao = __esm(() => {
34423
34433
  init_drizzle_orm();
@@ -34579,7 +34589,7 @@ var init_entity_dao = __esm(() => {
34579
34589
  };
34580
34590
  });
34581
34591
 
34582
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34592
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34583
34593
  function isPromiseLike(value) {
34584
34594
  return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
34585
34595
  }
@@ -34752,7 +34762,7 @@ var init_migrator2 = __esm(() => {
34752
34762
  init_migrator();
34753
34763
  });
34754
34764
 
34755
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/migrate.js
34765
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/migrate.js
34756
34766
  async function ensureJournalTable(adapter, table3) {
34757
34767
  await adapter.exec(`CREATE TABLE IF NOT EXISTS "${table3}" (` + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "hash text NOT NULL, " + "created_at numeric" + ")");
34758
34768
  }
@@ -34827,7 +34837,7 @@ var init_migrate = __esm(() => {
34827
34837
  init_embedded_migrations();
34828
34838
  });
34829
34839
 
34830
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34840
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34831
34841
  var QueueJobDao;
34832
34842
  var init_queue_job_dao = __esm(() => {
34833
34843
  init_drizzle_orm();
@@ -34968,7 +34978,7 @@ var init_queue_job_dao = __esm(() => {
34968
34978
  };
34969
34979
  });
34970
34980
 
34971
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/index.js
34981
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/index.js
34972
34982
  var exports_dist = {};
34973
34983
  __export(exports_dist, {
34974
34984
  embeddedMigrations: () => embeddedMigrations,
@@ -37273,7 +37283,7 @@ function buildConfigFromEnv(env = process.env) {
37273
37283
  }
37274
37284
  });
37275
37285
  }
37276
- 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, AgentOutputConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, RedactionConfigSchema, spurConfigSchema, configSchema2;
37286
+ 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, AgentOutputConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, WorkflowConfigSchema, RedactionConfigSchema, spurConfigSchema, configSchema2;
37277
37287
  var init_src = __esm(() => {
37278
37288
  init_zod();
37279
37289
  init_finding_codes();
@@ -37417,6 +37427,9 @@ var init_src = __esm(() => {
37417
37427
  WorkflowsConfigSchema = exports_external.object({
37418
37428
  paths: exports_external.array(exports_external.string()).optional()
37419
37429
  });
37430
+ WorkflowConfigSchema = exports_external.object({
37431
+ logRetentionDays: exports_external.number().int().positive().default(30)
37432
+ });
37420
37433
  RedactionConfigSchema = exports_external.object({
37421
37434
  enabled: exports_external.boolean().optional()
37422
37435
  });
@@ -37426,6 +37439,7 @@ var init_src = __esm(() => {
37426
37439
  agent: AgentConfigSchema.optional(),
37427
37440
  rules: RulesConfigSchema.optional(),
37428
37441
  workflows: WorkflowsConfigSchema.optional(),
37442
+ workflow: WorkflowConfigSchema.optional(),
37429
37443
  redaction: RedactionConfigSchema.optional(),
37430
37444
  tasks: tasksConfigSchema.optional(),
37431
37445
  features: featuresConfigSchema.optional()
@@ -37450,7 +37464,7 @@ var init_src = __esm(() => {
37450
37464
  });
37451
37465
  });
37452
37466
 
37453
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/config.js
37467
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/config.js
37454
37468
  function parseYamlObject(text3) {
37455
37469
  let parsed;
37456
37470
  try {
@@ -37577,7 +37591,7 @@ var init_config2 = __esm(() => {
37577
37591
  };
37578
37592
  });
37579
37593
 
37580
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37594
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37581
37595
  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";
37582
37596
  import { dirname as dirname2, resolve as resolvePath3 } from "path";
37583
37597
  function createNodeFileSystem3(root, paths) {
@@ -37664,7 +37678,7 @@ function findProjectRoot3(startDir) {
37664
37678
  }
37665
37679
  var init_file_system_node2 = () => {};
37666
37680
 
37667
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37681
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37668
37682
  var D1NotConfiguredError2, DbModuleNotInstalledError3;
37669
37683
  var init_db_errors2 = __esm(() => {
37670
37684
  D1NotConfiguredError2 = class D1NotConfiguredError2 extends Error {
@@ -37681,7 +37695,7 @@ var init_db_errors2 = __esm(() => {
37681
37695
  };
37682
37696
  });
37683
37697
 
37684
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37698
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37685
37699
  function createCfFileSystem2() {
37686
37700
  return {
37687
37701
  getProjectRoot: () => "/bundle",
@@ -37720,7 +37734,7 @@ function createCfFileSystem2() {
37720
37734
  }
37721
37735
  var UNSUPPORTED = "FileSystem is not available on Cloudflare Workers. Use D1, KV, or R2 for persistent storage.";
37722
37736
 
37723
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37737
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37724
37738
  var exports_runtime_cf = {};
37725
37739
  __export(exports_runtime_cf, {
37726
37740
  cloudflareWorkersFactory: () => cloudflareWorkersFactory2
@@ -37758,7 +37772,7 @@ var init_runtime_cf = __esm(() => {
37758
37772
  };
37759
37773
  });
37760
37774
 
37761
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37775
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37762
37776
  import { isatty as isatty2 } from "tty";
37763
37777
 
37764
37778
  class NodeProcessExecutor3 {
@@ -37801,6 +37815,14 @@ class NodeProcessExecutor3 {
37801
37815
  });
37802
37816
  try {
37803
37817
  const subprocess = execa(options.command, args, execaOptions);
37818
+ if (subprocess.pid !== undefined) {
37819
+ this.config.registry?.update(registryId, { pid: subprocess.pid });
37820
+ if (options.onSpawn !== undefined) {
37821
+ try {
37822
+ options.onSpawn(subprocess.pid);
37823
+ } catch {}
37824
+ }
37825
+ }
37804
37826
  const stopGroupCancellation = observeProcessGroupCancellation2(subprocess, options.signal);
37805
37827
  observeOutput2(subprocess.stdout, "stdout", options.onOutput);
37806
37828
  observeOutput2(subprocess.stderr, "stderr", options.onOutput);
@@ -38135,7 +38157,7 @@ var init_process_executor2 = __esm(() => {
38135
38157
  ProcessExecutor2 = NodeProcessExecutor3;
38136
38158
  });
38137
38159
 
38138
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38160
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38139
38161
  var exports_runtime_node_bun = {};
38140
38162
  __export(exports_runtime_node_bun, {
38141
38163
  nodeBunFactory: () => nodeBunFactory3,
@@ -38203,7 +38225,7 @@ var init_runtime_node_bun2 = __esm(() => {
38203
38225
  };
38204
38226
  });
38205
38227
 
38206
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38228
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38207
38229
  function isCloudflareWorkerRuntime2() {
38208
38230
  return globalThis.navigator?.userAgent?.startsWith("Cloudflare-Workers") ?? false;
38209
38231
  }
@@ -38233,7 +38255,7 @@ function _resetRuntimeFactory2() {
38233
38255
  }
38234
38256
  var _factory, _runtimeName;
38235
38257
 
38236
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/context.js
38258
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/context.js
38237
38259
  class RuntimeContext2 {
38238
38260
  scope;
38239
38261
  runtimeName;
@@ -38323,7 +38345,7 @@ var init_context2 = __esm(() => {
38323
38345
  init_runtime_node_bun2();
38324
38346
  });
38325
38347
 
38326
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/path.js
38348
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/path.js
38327
38349
  function normalizeSeparators2(path7) {
38328
38350
  return path7.replaceAll("\\", "/");
38329
38351
  }
@@ -38446,7 +38468,7 @@ var init_path2 = __esm(() => {
38446
38468
  SEP2 = globalThis.process?.platform === "win32" ? "\\" : "/";
38447
38469
  });
38448
38470
 
38449
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38471
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38450
38472
  async function ensureDirForFile2(path7, fs2 = createNodeFileSystem3()) {
38451
38473
  await fs2.ensureDir(dirnamePath(path7));
38452
38474
  }
@@ -38497,7 +38519,7 @@ var init_fs = __esm(() => {
38497
38519
  init_path2();
38498
38520
  });
38499
38521
 
38500
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38522
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38501
38523
  function allocateId() {
38502
38524
  nextIdSeq += 1;
38503
38525
  return `pe_${Date.now().toString(36)}_${nextIdSeq.toString(36)}`;
@@ -38621,7 +38643,7 @@ function createInMemoryProcessRegistry2(options) {
38621
38643
  }
38622
38644
  var nextIdSeq = 0;
38623
38645
 
38624
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/runtime-paths.js
38646
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/runtime-paths.js
38625
38647
  function ambientRuntimePaths2() {
38626
38648
  const cwd = getProcessCwd2();
38627
38649
  return { cwd, home: getHomeDir() ?? cwd };
@@ -38631,7 +38653,7 @@ var init_runtime_paths = __esm(() => {
38631
38653
  init_path2();
38632
38654
  });
38633
38655
 
38634
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38656
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38635
38657
  async function loadStructuredConfig(path7, options = {}) {
38636
38658
  const content = await (options.fileSystem ?? createNodeFileSystem3()).readFile(path7);
38637
38659
  return await parseStructuredConfig(content, path7, options);
@@ -38908,10 +38930,10 @@ var init_schema_validation2 = __esm(() => {
38908
38930
  defaultResolve = typeof Bun !== "undefined" ? (specifier, from) => Bun.resolveSync(specifier, from) : undefined;
38909
38931
  });
38910
38932
 
38911
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/types.js
38933
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/types.js
38912
38934
  var init_types2 = () => {};
38913
38935
 
38914
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/index.js
38936
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/index.js
38915
38937
  var exports_dist2 = {};
38916
38938
  __export(exports_dist2, {
38917
38939
  writeJsonFile: () => writeJsonFile2,
@@ -41062,7 +41084,7 @@ var init_mod = __esm(() => {
41062
41084
  init_config3();
41063
41085
  });
41064
41086
 
41065
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/logger.js
41087
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/logger.js
41066
41088
  function toLogTapeLevel(level) {
41067
41089
  return level === "warn" ? "warning" : level;
41068
41090
  }
@@ -42615,7 +42637,7 @@ var require_src = __commonJS((exports) => {
42615
42637
  };
42616
42638
  });
42617
42639
 
42618
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42640
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42619
42641
  function getTelemetryConfig(configPartial = {}) {
42620
42642
  return {
42621
42643
  enabled: configPartial.enabled ?? CONFIG_DEFAULTS.enabled,
@@ -42651,7 +42673,7 @@ var init_sdk = __esm(() => {
42651
42673
  resolvedConfig = getTelemetryConfig();
42652
42674
  });
42653
42675
 
42654
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42676
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42655
42677
  function isSuppressed(tracer2) {
42656
42678
  return tracer2 === undefined && !getResolvedConfig().enabled;
42657
42679
  }
@@ -42691,7 +42713,7 @@ var init_tracing2 = __esm(() => {
42691
42713
  import_api2 = __toESM(require_src(), 1);
42692
42714
  });
42693
42715
 
42694
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42716
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42695
42717
  function getMeter() {
42696
42718
  return import_api3.metrics.getMeter(METER_NAME, METER_VERSION);
42697
42719
  }
@@ -42788,7 +42810,7 @@ var init_metrics = __esm(() => {
42788
42810
  instruments = {};
42789
42811
  });
42790
42812
 
42791
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42813
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42792
42814
  function busLogger() {
42793
42815
  if (!_busLogger)
42794
42816
  _busLogger = getLogger2("event-bus");
@@ -43033,7 +43055,7 @@ var init_event_bus = __esm(() => {
43033
43055
  init_metrics();
43034
43056
  });
43035
43057
 
43036
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
43058
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
43037
43059
  function obsLogger() {
43038
43060
  if (!_obsLogger)
43039
43061
  _obsLogger = getLogger2("event-bus.observers");
@@ -43097,7 +43119,7 @@ var init_default_observers = __esm(() => {
43097
43119
  init_event_bus();
43098
43120
  });
43099
43121
 
43100
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
43122
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
43101
43123
  function parentDir(filePath) {
43102
43124
  const idx = filePath.lastIndexOf("/");
43103
43125
  return idx <= 0 ? "." : filePath.slice(0, idx);
@@ -43195,7 +43217,7 @@ var init_file_observer = __esm(() => {
43195
43217
  init_logger3();
43196
43218
  });
43197
43219
 
43198
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/internals/drain.js
43220
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/internals/drain.js
43199
43221
  function settleWithin(promise2, deadline) {
43200
43222
  const remaining = deadline - Date.now();
43201
43223
  if (remaining <= 0)
@@ -43210,7 +43232,7 @@ function settleWithin(promise2, deadline) {
43210
43232
  return settled;
43211
43233
  }
43212
43234
 
43213
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43235
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43214
43236
  function parseInterval(cron) {
43215
43237
  const trimmed = cron.trim();
43216
43238
  const num = Number(trimmed);
@@ -43303,7 +43325,7 @@ var init_node3 = __esm(() => {
43303
43325
  init_metrics();
43304
43326
  });
43305
43327
 
43306
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43328
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43307
43329
  var exports_scheduler_node = {};
43308
43330
  __export(exports_scheduler_node, {
43309
43331
  NodeSchedulerAdapter: () => NodeSchedulerAdapter
@@ -49572,6 +49594,7 @@ class AgentExecutionLifecycle {
49572
49594
  heartbeat;
49573
49595
  startedAt = 0;
49574
49596
  timeoutMs;
49597
+ pid;
49575
49598
  outputCarry = { stdout: "", stderr: "" };
49576
49599
  constructor(observer, correlation, secrets, heartbeatMs = 30000) {
49577
49600
  this.observer = observer;
@@ -49585,6 +49608,10 @@ class AgentExecutionLifecycle {
49585
49608
  get identity() {
49586
49609
  return this.correlation;
49587
49610
  }
49611
+ setPid(pid) {
49612
+ if (Number.isInteger(pid) && pid > 0)
49613
+ this.pid = pid;
49614
+ }
49588
49615
  start(detail) {
49589
49616
  this.startedAt = Date.now();
49590
49617
  this.timeoutMs = detail.timeoutMs;
@@ -49682,6 +49709,7 @@ class AgentExecutionLifecycle {
49682
49709
  runId: this.correlation.runId,
49683
49710
  executionId: this.correlation.executionId,
49684
49711
  ...this.correlation.actionId !== undefined ? { actionId: this.correlation.actionId } : {},
49712
+ ...this.pid !== undefined ? { pid: this.pid } : {},
49685
49713
  at: new Date().toISOString()
49686
49714
  };
49687
49715
  }
@@ -49721,6 +49749,436 @@ var init_agent_execution = __esm(() => {
49721
49749
  SECRET_PATTERN = /(?:sk-[a-z0-9_-]{8,}|(?:api[_-]?key|token|secret|password)\s*[:=]\s*\S+|bearer\s+\S+)/gi;
49722
49750
  });
49723
49751
 
49752
+ // ../../packages/app/src/workflow/observability.ts
49753
+ function bounded(value, maxLength = MAX_FIELD_LENGTH) {
49754
+ const redacted = value.replace(SECRET_PATTERN2, "[REDACTED]");
49755
+ return redacted.length <= maxLength ? redacted : `${redacted.slice(0, maxLength)}\u2026`;
49756
+ }
49757
+ function projectActionMetadata(kind, options) {
49758
+ if (options === undefined)
49759
+ return;
49760
+ const metadata = {};
49761
+ if (typeof options.agent === "string" && options.agent !== "")
49762
+ metadata.agent = bounded(options.agent);
49763
+ if (typeof options.model === "string" && options.model !== "")
49764
+ metadata.model = bounded(options.model);
49765
+ if (typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs)) {
49766
+ metadata.timeoutMs = Math.max(0, options.timeoutMs);
49767
+ }
49768
+ const input = typeof options.input === "string" ? options.input.trim() : "";
49769
+ if (kind === "agent.run" && input !== "") {
49770
+ const command = input.startsWith("/") ? input.split(/\s+/, 1)[0] : undefined;
49771
+ metadata.invocation = command === undefined ? `[prompt ${input.length} chars]` : bounded(command);
49772
+ } else if (kind === "shell" && typeof options.command === "string" && options.command.trim() !== "") {
49773
+ metadata.invocation = bounded(sanitizeCommand(options.command), 80);
49774
+ } else if (kind === "note" && typeof options.message === "string" && options.message.trim() !== "") {
49775
+ metadata.invocation = bounded(options.message.trim(), 80);
49776
+ }
49777
+ return Object.keys(metadata).length === 0 ? undefined : metadata;
49778
+ }
49779
+ function sanitizeCommand(cmd) {
49780
+ const trimmed = cmd.replace(/\n+/g, " ").replace(/\s+/g, " ").trim();
49781
+ if (/(?:authorization|bearer|password|secret|token|api_key|private_key)/i.test(trimmed)) {
49782
+ return "[shell command redacted]";
49783
+ }
49784
+ return trimmed;
49785
+ }
49786
+ function projectResult(result) {
49787
+ if (result === undefined)
49788
+ return;
49789
+ if (typeof result !== "object" || result === null)
49790
+ return { usage: "unavailable" };
49791
+ const obj = result;
49792
+ const error51 = typeof obj.error === "string" ? bounded(obj.error) : undefined;
49793
+ const stderr = typeof obj.stderr === "string" && obj.stderr.trim() !== "" ? bounded(obj.stderr.trim(), 120) : undefined;
49794
+ const stdout = typeof obj.stdout === "string" && obj.stdout.trim() !== "" ? bounded(obj.stdout.trim(), 120) : undefined;
49795
+ const detail = error51 ?? stderr ?? stdout;
49796
+ return { ...detail !== undefined ? { error: detail } : {}, usage: "unavailable" };
49797
+ }
49798
+
49799
+ class ObservableWorkflowAdapter {
49800
+ inner;
49801
+ bus;
49802
+ sequences = new Map;
49803
+ workflowNames = new Map;
49804
+ actions = new Map;
49805
+ constructor(inner, bus) {
49806
+ this.inner = inner;
49807
+ this.bus = bus;
49808
+ }
49809
+ async createRun(record2) {
49810
+ await this.inner.createRun(record2);
49811
+ this.workflowNames.set(record2.id, record2.workflow_name);
49812
+ await this.bus.emit("workflow.run.started", {
49813
+ ...this.envelope(record2.id),
49814
+ workflowName: record2.workflow_name
49815
+ });
49816
+ }
49817
+ async finalizeRun(runId, status, completedAt) {
49818
+ await this.inner.finalizeRun(runId, status, completedAt);
49819
+ await this.bus.emit("workflow.run.finalized", { ...this.envelope(runId, completedAt), status });
49820
+ }
49821
+ async savePhase(runId, phase, status) {
49822
+ await this.inner.savePhase(runId, phase, status);
49823
+ await this.bus.emit("workflow.phase", { ...this.envelope(runId), phase, status });
49824
+ }
49825
+ async saveTransition(runId, from, to, trigger) {
49826
+ await this.inner.saveTransition(runId, from, to, trigger);
49827
+ await this.bus.emit("workflow.transition", { ...this.envelope(runId), from, to, trigger });
49828
+ }
49829
+ async commitTransition(runId, from, to, trigger, _state, _data, phase) {
49830
+ await this.inner.commitTransition(runId, from, to, trigger, _state, _data, phase);
49831
+ await this.bus.emit("workflow.transition", { ...this.envelope(runId), from, to, trigger });
49832
+ if (phase) {
49833
+ await this.bus.emit("workflow.phase", {
49834
+ ...this.envelope(runId),
49835
+ phase: phase.phase,
49836
+ status: phase.status
49837
+ });
49838
+ }
49839
+ }
49840
+ async saveActionStart(runId, node, kind, options) {
49841
+ const actionId = await this.inner.saveActionStart(runId, node, kind, options);
49842
+ this.actions.set(actionId, { runId, node, kind });
49843
+ const metadata = projectActionMetadata(kind, options);
49844
+ await this.bus.emit("workflow.action.started", {
49845
+ ...this.envelope(runId),
49846
+ actionId,
49847
+ node,
49848
+ kind,
49849
+ ...metadata !== undefined ? { metadata } : {}
49850
+ });
49851
+ return actionId;
49852
+ }
49853
+ async saveActionFinalize(actionId, status, durationMs, ok, result, redactor) {
49854
+ await this.inner.saveActionFinalize(actionId, status, durationMs, ok, result, redactor);
49855
+ const action = this.actions.get(actionId);
49856
+ if (action === undefined) {
49857
+ return;
49858
+ }
49859
+ this.actions.delete(actionId);
49860
+ const projected = projectResult(result);
49861
+ await this.bus.emit("workflow.action.finished", {
49862
+ ...this.envelope(action.runId),
49863
+ actionId,
49864
+ status,
49865
+ durationMs,
49866
+ ok,
49867
+ node: action.node,
49868
+ kind: action.kind,
49869
+ ...projected !== undefined ? { result: projected } : {}
49870
+ });
49871
+ }
49872
+ envelope(runId, at = now()) {
49873
+ const sequence = (this.sequences.get(runId) ?? 0) + 1;
49874
+ this.sequences.set(runId, sequence);
49875
+ const workflowName = this.workflowNames.get(runId);
49876
+ return {
49877
+ schemaVersion: 1,
49878
+ eventId: crypto.randomUUID(),
49879
+ sequence,
49880
+ runId,
49881
+ ...workflowName !== undefined ? { workflowName } : {},
49882
+ at
49883
+ };
49884
+ }
49885
+ saveWorkflowState(runId, state, data) {
49886
+ return this.inner.saveWorkflowState(runId, state, data);
49887
+ }
49888
+ loadRun(runId) {
49889
+ return this.inner.loadRun(runId);
49890
+ }
49891
+ listRuns() {
49892
+ return this.inner.listRuns();
49893
+ }
49894
+ findRunByKey(workflowName, externalKey) {
49895
+ return this.inner.findRunByKey(workflowName, externalKey);
49896
+ }
49897
+ createOrAttachRun(record2) {
49898
+ return this.inner.createOrAttachRun(record2);
49899
+ }
49900
+ reseedRun(runId, newState) {
49901
+ return this.inner.reseedRun(runId, newState);
49902
+ }
49903
+ loadCurrentState(runId) {
49904
+ return this.inner.loadCurrentState(runId);
49905
+ }
49906
+ loadLatestStateSnapshot(runId) {
49907
+ return this.inner.loadLatestStateSnapshot(runId);
49908
+ }
49909
+ listPausedRuns(options) {
49910
+ return this.inner.listPausedRuns(options);
49911
+ }
49912
+ }
49913
+ var now = () => new Date().toISOString(), MAX_FIELD_LENGTH = 256, SECRET_PATTERN2;
49914
+ var init_observability = __esm(() => {
49915
+ SECRET_PATTERN2 = /(?:sk-[a-z0-9_-]{8,}|(?:api[_-]?key|token|secret|password)\s*[:=]\s*\S+|bearer\s+\S+)/gi;
49916
+ });
49917
+
49918
+ // ../../packages/app/src/workflow/step-reporter.ts
49919
+ function runPrefix(runId, options) {
49920
+ if (options.showRunId === false)
49921
+ return "";
49922
+ return `[run ${runId.slice(0, 8)}] `;
49923
+ }
49924
+ function renderStepLine(event, options = {}) {
49925
+ const detail = options.detail ?? "invocation";
49926
+ const pfx = runPrefix(event.runId, options);
49927
+ if (isAgentExecution(event)) {
49928
+ if (event.kind === "output") {
49929
+ if (detail === "minimal")
49930
+ return null;
49931
+ const label = event.stream === "stderr" ? "stderr" : "stdout";
49932
+ return `${pfx} ${label}> ${event.chunk.replace(/\s+$/, "")}`;
49933
+ }
49934
+ if (event.kind === "heartbeat") {
49935
+ if (detail === "minimal")
49936
+ return null;
49937
+ const budget = event.timeoutMs === undefined ? "unbounded" : `${formatDuration(Math.max(0, event.timeoutMs - event.elapsedMs))} remaining`;
49938
+ const pidPart = event.pid === undefined ? "" : ` \xB7 pid=${event.pid}`;
49939
+ return `${pfx} \u2026 agent execution \xB7 elapsed=${formatDuration(event.elapsedMs)} \xB7 budget=${budget}${pidPart}`;
49940
+ }
49941
+ if (event.kind === "dropped") {
49942
+ return detail === "minimal" ? null : `${pfx}\u2026 output pressure \xB7 dropped=${event.chunks} chunks`;
49943
+ }
49944
+ if (event.kind === "started") {
49945
+ if (detail === "minimal")
49946
+ return null;
49947
+ const model = event.model === undefined ? "" : `(${event.model})`;
49948
+ const pidPart = event.pid === undefined ? "" : ` \xB7 pid=${event.pid}`;
49949
+ const full2 = detail === "full" ? ` \xB7 execution=${event.executionId}` : "";
49950
+ return `${pfx} agent=${event.agent}${model} => ${event.invocation}${pidPart}${full2}`;
49951
+ }
49952
+ const mark = event.outcome === "done" ? "\u2713" : "\u2717";
49953
+ const full = detail === "full" ? ` \xB7 execution=${event.executionId}` : "";
49954
+ const exitPart = event.exitCode !== null && event.exitCode !== undefined ? ` \xB7 exit ${event.exitCode}` : "";
49955
+ return detail === "minimal" ? null : `${pfx}${mark} agent ${event.outcome} (${formatDuration(event.durationMs)})${exitPart} \xB7 usage ${event.usage}${event.reason ? ` \xB7 ${event.reason}` : ""}${full}`;
49956
+ }
49957
+ if (isActionOutput(event)) {
49958
+ if (detail === "minimal")
49959
+ return null;
49960
+ const label = event.stream === "stderr" ? "stderr" : "stdout";
49961
+ return `${pfx} ${label}> ${event.chunk.replace(/\s+$/, "")}`;
49962
+ }
49963
+ if (isActionFinished(event)) {
49964
+ const mark = event.ok ? "\u2713" : "\u2717";
49965
+ if (detail === "minimal")
49966
+ return ` ${mark} ${event.status} (${formatDuration(event.durationMs)})`;
49967
+ const failure = event.result?.error === undefined ? "" : ` \xB7 ${event.result.error}`;
49968
+ const usagePart = event.result?.usage !== undefined && event.result.usage !== "unavailable" ? ` \xB7 usage ${event.result.usage}` : "";
49969
+ const full = detail === "full" ? ` \xB7 action=${event.actionId} \xB7 seq=${event.sequence}` : "";
49970
+ return `${pfx}${mark} ${event.node}/${event.kind} (${formatDuration(event.durationMs)})${usagePart}${failure}${full}`;
49971
+ }
49972
+ if (isActionStarted(event)) {
49973
+ if (detail === "minimal")
49974
+ return ` \u2192 ${event.node}: ${event.kind}\u2026`;
49975
+ const agentPart = event.metadata?.agent && event.metadata.agent !== "unavailable" ? ` \xB7 agent=${event.metadata.agent}` : "";
49976
+ const modelPart = event.metadata?.model && event.metadata.model !== "unavailable" ? ` \xB7 model=${event.metadata.model}` : "";
49977
+ const invocationPart = event.metadata?.invocation && event.metadata.invocation !== "unavailable" ? ` => ${event.metadata.invocation}` : "";
49978
+ const timeout = event.metadata?.timeoutMs === undefined ? "unbounded" : formatDuration(event.metadata.timeoutMs);
49979
+ const full = detail === "full" ? ` \xB7 action=${event.actionId} \xB7 seq=${event.sequence}` : "";
49980
+ return `${pfx}\u2192 ${event.node}/${event.kind}${agentPart}${modelPart}${invocationPart} \xB7 timeout=${timeout}${full}`;
49981
+ }
49982
+ if (isPhase(event)) {
49983
+ return detail === "minimal" ? `\u25B6 ${event.phase} [${event.status}]` : `${pfx}\u25B6 ${event.phase} [${event.status}]`;
49984
+ }
49985
+ if (isTransition(event)) {
49986
+ if (detail === "minimal")
49987
+ return null;
49988
+ const seqPart = detail === "full" ? ` \xB7 seq=${event.sequence}` : "";
49989
+ return `${pfx}\u21AA ${event.from} \u2192 ${event.to}${event.trigger ? ` [${event.trigger}]` : ""}${seqPart}`;
49990
+ }
49991
+ return null;
49992
+ }
49993
+ function renderActionHeartbeat(event, elapsedMs, options = {}) {
49994
+ const detail = options.detail ?? "invocation";
49995
+ if (detail === "minimal")
49996
+ return null;
49997
+ const elapsed = formatDuration(elapsedMs);
49998
+ const budget = event.metadata?.timeoutMs === undefined ? "unbounded" : `${formatDuration(Math.max(0, event.metadata.timeoutMs - elapsedMs))} remaining`;
49999
+ const full = detail === "full" ? ` \xB7 action=${event.actionId}` : "";
50000
+ return `${runPrefix(event.runId, options)}\u2026 ${event.node}/${event.kind} \xB7 elapsed=${elapsed} \xB7 budget=${budget}${full}`;
50001
+ }
50002
+ function renderRunPlan(def) {
50003
+ const steps = def.kind === "transition-flow" ? def.nodes.map((n2) => n2.id) : def.states.map((s) => s.id);
50004
+ return `plan: ${steps.join(" \u2192 ")}`;
50005
+ }
50006
+ function formatDuration(ms) {
50007
+ const totalSeconds = Math.round(ms / 1000);
50008
+ if (totalSeconds < 60)
50009
+ return `${totalSeconds}s`;
50010
+ const minutes = Math.floor(totalSeconds / 60);
50011
+ const seconds = totalSeconds % 60;
50012
+ return `${minutes}m ${seconds}s`;
50013
+ }
50014
+ var isAgentExecution = (e) => ("executionId" in e), isActionOutput = (e) => ("stream" in e) && ("chunk" in 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);
50015
+
50016
+ // ../../packages/app/src/observability/workflow-run-log-sink.ts
50017
+ import { closeSync, mkdirSync as mkdirSync4, openSync, writeSync } from "fs";
50018
+ import { join as join5 } from "path";
50019
+
50020
+ class WorkflowRunLogSink {
50021
+ filePath;
50022
+ maxBytes;
50023
+ maxLines;
50024
+ planPreview;
50025
+ fd;
50026
+ bytes = 0;
50027
+ lines = 0;
50028
+ truncated = false;
50029
+ closed = false;
50030
+ headerWritten = false;
50031
+ bus;
50032
+ handlers;
50033
+ constructor(options) {
50034
+ this.filePath = join5(options.dir, `${options.runId}.log`);
50035
+ this.maxBytes = options.maxBytes ?? DEFAULT_RUN_LOG_MAX_BYTES;
50036
+ this.maxLines = options.maxLines;
50037
+ this.planPreview = options.planPreview;
50038
+ try {
50039
+ mkdirSync4(options.dir, { recursive: true });
50040
+ this.fd = openSync(this.filePath, "a");
50041
+ } catch {
50042
+ this.fd = undefined;
50043
+ }
50044
+ this.bus = options.bus;
50045
+ this.handlers = {
50046
+ "workflow.run.started": (event) => this.onRunStarted(event),
50047
+ "workflow.phase": (event) => this.onProgress(event),
50048
+ "workflow.transition": (event) => this.onProgress(event),
50049
+ "workflow.action.started": (event) => this.onProgress(event),
50050
+ "workflow.action.finished": (event) => this.onProgress(event),
50051
+ "workflow.action.output": (event) => this.onProgress(event),
50052
+ "workflow.agent": (event) => this.onAgent(event),
50053
+ "workflow.steering": (event) => this.onSteering(event),
50054
+ "workflow.run.finalized": (event) => this.onRunFinalized(event)
50055
+ };
50056
+ this.register(true);
50057
+ }
50058
+ get isTruncated() {
50059
+ return this.truncated;
50060
+ }
50061
+ close() {
50062
+ if (this.closed)
50063
+ return;
50064
+ this.closed = true;
50065
+ this.register(false);
50066
+ if (this.fd !== undefined) {
50067
+ try {
50068
+ closeSync(this.fd);
50069
+ } catch {}
50070
+ this.fd = undefined;
50071
+ }
50072
+ }
50073
+ register(attach) {
50074
+ for (const name of RUN_LOG_EVENT_NAMES) {
50075
+ if (attach)
50076
+ this.bus.on(name, this.handlers[name]);
50077
+ else
50078
+ this.bus.off(name, this.handlers[name]);
50079
+ }
50080
+ }
50081
+ onRunStarted(event) {
50082
+ if (this.headerWritten)
50083
+ return;
50084
+ this.headerWritten = true;
50085
+ this.append(`# spur workflow run ${event.runId} \u2014 ${event.workflowName} \u2014 started ${event.at}
50086
+ `);
50087
+ if (this.planPreview !== undefined)
50088
+ this.append(`# ${this.planPreview}
50089
+ `);
50090
+ }
50091
+ onProgress(event) {
50092
+ const line = renderStepLine(event, { detail: "full", showRunId: true });
50093
+ if (line === null)
50094
+ return;
50095
+ this.append(`[${event.at}] ${line}
50096
+ `);
50097
+ }
50098
+ onRunFinalized(event) {
50099
+ this.append(`
50100
+ === workflow run ${event.runId} finished \u2014 status ${event.status} \u2014 ${event.at} ===
50101
+ `);
50102
+ }
50103
+ onSteering(ack) {
50104
+ const note = ack.note === undefined ? "" : ` \xB7 ${bounded(ack.note, MAX_STEERING_NOTE_CHARS)}`;
50105
+ this.append(`[${ack.at}] [steer] ${ack.accepted ? "ack" : "nack"} ${ack.operation}${note}
50106
+ `);
50107
+ }
50108
+ onAgent(event) {
50109
+ if (this.fd === undefined || this.closed)
50110
+ return;
50111
+ switch (event.kind) {
50112
+ case "output":
50113
+ this.append(`[${event.at}] ${event.stream}: ${event.chunk}
50114
+ `);
50115
+ break;
50116
+ case "started":
50117
+ this.append(`# agent output \u2014 run ${event.runId} \u2014 ${event.agent} \u2014 ${event.at}
50118
+ `);
50119
+ this.append(`# invocation: ${event.invocation}
50120
+ `);
50121
+ break;
50122
+ case "dropped":
50123
+ this.append(`
50124
+ === [dropped] ${event.chunks} chunk(s) discarded by the lifecycle relay under backpressure ===
50125
+ `);
50126
+ break;
50127
+ case "finished":
50128
+ this.append(`
50129
+ === run ${event.outcome} (exit ${event.exitCode}) after ${event.durationMs}ms ===
50130
+ `);
50131
+ break;
50132
+ default:
50133
+ break;
50134
+ }
50135
+ }
50136
+ append(text3) {
50137
+ if (this.fd === undefined || this.closed || this.truncated)
50138
+ return;
50139
+ const textBytes = Buffer.byteLength(text3);
50140
+ const textLines = countNewlines(text3);
50141
+ if (this.bytes + textBytes > this.maxBytes || this.maxLines !== undefined && this.lines + textLines > this.maxLines) {
50142
+ this.truncated = true;
50143
+ try {
50144
+ writeSync(this.fd, TRUNCATION_MARKER);
50145
+ } catch {}
50146
+ return;
50147
+ }
50148
+ try {
50149
+ writeSync(this.fd, text3);
50150
+ this.bytes += textBytes;
50151
+ this.lines += textLines;
50152
+ } catch {}
50153
+ }
50154
+ }
50155
+ function countNewlines(text3) {
50156
+ let count3 = 0;
50157
+ for (let i2 = 0;i2 < text3.length; i2 += 1) {
50158
+ if (text3.charCodeAt(i2) === 10)
50159
+ count3 += 1;
50160
+ }
50161
+ return count3;
50162
+ }
50163
+ var DEFAULT_RUN_LOG_MAX_BYTES, MAX_STEERING_NOTE_CHARS = 1024, TRUNCATION_MARKER = `
50164
+ === [truncated] consolidated run log reached its configured bound; further lines were not written ===
50165
+ `, RUN_LOG_EVENT_NAMES;
50166
+ var init_workflow_run_log_sink = __esm(() => {
50167
+ init_observability();
50168
+ DEFAULT_RUN_LOG_MAX_BYTES = 1024 * 1024;
50169
+ RUN_LOG_EVENT_NAMES = [
50170
+ "workflow.run.started",
50171
+ "workflow.phase",
50172
+ "workflow.transition",
50173
+ "workflow.action.started",
50174
+ "workflow.action.finished",
50175
+ "workflow.action.output",
50176
+ "workflow.agent",
50177
+ "workflow.steering",
50178
+ "workflow.run.finalized"
50179
+ ];
50180
+ });
50181
+
49724
50182
  // ../../packages/domain/src/analytics/models.ts
49725
50183
  function resolvePricing(model) {
49726
50184
  if (model === undefined || model.length === 0)
@@ -51007,7 +51465,7 @@ var init_drizzle_zod = __esm(() => {
51007
51465
  };
51008
51466
  });
51009
51467
 
51010
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
51468
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
51011
51469
  function sqlExpressionToText(value) {
51012
51470
  if (typeof value !== "object" || value === null || !("queryChunks" in value)) {
51013
51471
  return;
@@ -51030,7 +51488,7 @@ function getDrizzleTableName(table3) {
51030
51488
  return String(table3[nameSym]);
51031
51489
  }
51032
51490
 
51033
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
51491
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
51034
51492
  function quoteIdent(name) {
51035
51493
  return `"${name.replace(/"/g, '""')}"`;
51036
51494
  }
@@ -51124,7 +51582,7 @@ var init_ddl = __esm(() => {
51124
51582
  init_sqlite_core();
51125
51583
  });
51126
51584
 
51127
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
51585
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
51128
51586
  function defineTable(name, columns2) {
51129
51587
  const table3 = sqliteTable(name, columns2);
51130
51588
  let insert2;
@@ -51158,7 +51616,7 @@ var init_define_table = __esm(() => {
51158
51616
  init_ddl();
51159
51617
  });
51160
51618
 
51161
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.15+7b9696e001f6f9db/node_modules/@gobing-ai/ts-db/dist/schema/index.js
51619
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.18+c31add66cbc22fb3/node_modules/@gobing-ai/ts-db/dist/schema/index.js
51162
51620
  var init_schema = __esm(() => {
51163
51621
  init_sqlite_core();
51164
51622
  init_define_table();
@@ -51783,7 +52241,7 @@ var init_dao = __esm(() => {
51783
52241
  init_workspace_dao();
51784
52242
  });
51785
52243
 
51786
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
52244
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
51787
52245
  var WorkflowValidationError, FSMError, RunCollisionError, WorkflowResumeError;
51788
52246
  var init_errors6 = __esm(() => {
51789
52247
  WorkflowValidationError = class WorkflowValidationError extends Error {
@@ -51818,12 +52276,12 @@ var init_errors6 = __esm(() => {
51818
52276
  };
51819
52277
  });
51820
52278
 
51821
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
52279
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
51822
52280
  var init_event_bus2 = __esm(() => {
51823
52281
  init_event_bus();
51824
52282
  });
51825
52283
 
51826
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/api-client.js
52284
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/api-client.js
51827
52285
  function sanitizeUrlForObservability(url2) {
51828
52286
  try {
51829
52287
  const parsed = new URL(url2);
@@ -52053,12 +52511,12 @@ var init_api_client = __esm(() => {
52053
52511
  };
52054
52512
  });
52055
52513
 
52056
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
52514
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
52057
52515
  var init_telemetry = __esm(() => {
52058
52516
  init_tracing2();
52059
52517
  });
52060
52518
 
52061
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/index.js
52519
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/index.js
52062
52520
  var init_dist6 = __esm(() => {
52063
52521
  init_api_client();
52064
52522
  init_event_bus2();
@@ -52066,7 +52524,7 @@ var init_dist6 = __esm(() => {
52066
52524
  init_telemetry();
52067
52525
  });
52068
52526
 
52069
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
52527
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
52070
52528
  function runtimeBuiltins(workflowName, stateOrNodeId, runId, transitionsTaken, mode) {
52071
52529
  return {
52072
52530
  workflow: workflowName,
@@ -52325,7 +52783,7 @@ var init_run_lifecycle = __esm(() => {
52325
52783
  ];
52326
52784
  });
52327
52785
 
52328
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
52786
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
52329
52787
  var RESERVED_VAR_NAMES, IDENTIFIER, VarsSchema, EnvSchema, ActionDefSchema, GuardDefSchema, StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema, WorkflowDefSchema;
52330
52788
  var init_schema2 = __esm(() => {
52331
52789
  init_zod();
@@ -52361,6 +52819,7 @@ var init_schema2 = __esm(() => {
52361
52819
  description: exports_external.string().optional(),
52362
52820
  initialState: exports_external.string().min(1),
52363
52821
  terminalStates: exports_external.array(exports_external.string().min(1)).optional(),
52822
+ failureStates: exports_external.array(exports_external.string().min(1)).optional(),
52364
52823
  iterationBound: exports_external.number().int().positive().optional(),
52365
52824
  defaultOnError: exports_external.enum(["fail", "continue"]).optional(),
52366
52825
  vars: VarsSchema.optional(),
@@ -52409,7 +52868,7 @@ var init_schema2 = __esm(() => {
52409
52868
  WorkflowDefSchema = exports_external.union([StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema]);
52410
52869
  });
52411
52870
 
52412
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
52871
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
52413
52872
  async function loadWorkflowDef(path9, options = {}) {
52414
52873
  return parseWorkflowDef(await loadStructuredConfig(path9, options), path9);
52415
52874
  }
@@ -52425,8 +52884,16 @@ function validateStateMachine(workflow) {
52425
52884
  const ids = workflow.states.map((state) => state.id);
52426
52885
  const states = new Set(ids);
52427
52886
  const terminals = new Set(workflow.terminalStates ?? []);
52887
+ const failures = new Set(workflow.failureStates ?? []);
52428
52888
  for (const id of duplicates(ids))
52429
52889
  errors6.push(`State "${id}" is declared more than once`);
52890
+ for (const failure of failures) {
52891
+ if (!states.has(failure))
52892
+ errors6.push(`Failure state "${failure}" is not declared`);
52893
+ else if (!terminals.has(failure)) {
52894
+ errors6.push(`Failure state "${failure}" must also be declared as a terminal state`);
52895
+ }
52896
+ }
52430
52897
  if (!states.has(workflow.initialState)) {
52431
52898
  errors6.push(`Initial state "${workflow.initialState}" is not declared`);
52432
52899
  } else if (terminals.has(workflow.initialState)) {
@@ -52568,7 +53035,7 @@ var init_config4 = __esm(() => {
52568
53035
  RUNTIME_TEMPLATE_NAMESPACES = new Set(RUNTIME_BUILTIN_KEYS);
52569
53036
  });
52570
53037
 
52571
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
53038
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
52572
53039
  class CapabilityRegistry {
52573
53040
  kind;
52574
53041
  capabilities = new Map;
@@ -52599,7 +53066,7 @@ class CapabilityRegistry {
52599
53066
  }
52600
53067
  }
52601
53068
 
52602
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
53069
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
52603
53070
  function assertRelativeExtensionPath(path9, options = {}) {
52604
53071
  const where = options.sourceName !== undefined ? ` declared by "${options.sourceName}"` : "";
52605
53072
  if (/^([/\\]|[A-Za-z]:[/\\])/.test(path9)) {
@@ -52610,20 +53077,20 @@ function assertRelativeExtensionPath(path9, options = {}) {
52610
53077
  }
52611
53078
  }
52612
53079
 
52613
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
53080
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
52614
53081
  var init_extension_loader = () => {};
52615
53082
 
52616
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
53083
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
52617
53084
  var init_extension = __esm(() => {
52618
53085
  init_extension_loader();
52619
53086
  });
52620
53087
 
52621
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.15+df0d32ac93e36a8d/node_modules/@gobing-ai/ts-runtime/dist/extension.js
53088
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.18+0c3519262b4dbb18/node_modules/@gobing-ai/ts-runtime/dist/extension.js
52622
53089
  var init_extension2 = __esm(() => {
52623
53090
  init_extension();
52624
53091
  });
52625
53092
 
52626
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
53093
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
52627
53094
  class WorkflowEngineHost {
52628
53095
  lifecycleBus;
52629
53096
  actions = new CapabilityRegistry("workflow action");
@@ -52792,7 +53259,7 @@ var init_host = __esm(() => {
52792
53259
  init_errors6();
52793
53260
  });
52794
53261
 
52795
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
53262
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
52796
53263
  var WORKFLOW_ENGINE_SCHEMA_SQL;
52797
53264
  var init_schema_sql = __esm(() => {
52798
53265
  WORKFLOW_ENGINE_SCHEMA_SQL = `
@@ -52865,7 +53332,7 @@ CREATE TABLE IF NOT EXISTS action_runs (
52865
53332
  `.trim();
52866
53333
  });
52867
53334
 
52868
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
53335
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
52869
53336
  async function applyWorkflowEngineSchema(db2) {
52870
53337
  for (const statement of WORKFLOW_ENGINE_SCHEMA_SQL.split(";")) {
52871
53338
  const sql4 = statement.trim();
@@ -52909,17 +53376,17 @@ class DbWorkflowPersistenceAdapter {
52909
53376
  }
52910
53377
  async commitTransition(runId, from, to, trigger, state, data, phase) {
52911
53378
  await this.ensureSchema();
52912
- const now = Date.now();
53379
+ const now2 = Date.now();
52913
53380
  const ops = [
52914
- this.transitionRow(runId, from, to, trigger, now),
52915
- this.stateRow(runId, state, data, now)
53381
+ this.transitionRow(runId, from, to, trigger, now2),
53382
+ this.stateRow(runId, state, data, now2)
52916
53383
  ];
52917
53384
  if (phase) {
52918
- ops.push(this.phaseRow(runId, phase.phase, phase.status, now));
53385
+ ops.push(this.phaseRow(runId, phase.phase, phase.status, now2));
52919
53386
  }
52920
53387
  await this.db.batch(ops);
52921
53388
  }
52922
- transitionRow(runId, from, to, trigger, now) {
53389
+ transitionRow(runId, from, to, trigger, now2) {
52923
53390
  return {
52924
53391
  sql: `INSERT INTO transition_runs (id, run_id, from_state, to_state, trigger, status, created_at, updated_at)
52925
53392
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
@@ -52930,19 +53397,19 @@ class DbWorkflowPersistenceAdapter {
52930
53397
  to,
52931
53398
  trigger,
52932
53399
  "done",
52933
- now,
52934
- now
53400
+ now2,
53401
+ now2
52935
53402
  ]
52936
53403
  };
52937
53404
  }
52938
- stateRow(runId, state, data, now) {
53405
+ stateRow(runId, state, data, now2) {
52939
53406
  return {
52940
53407
  sql: `INSERT INTO workflow_states (id, run_id, state, data_json, created_at, updated_at)
52941
53408
  VALUES (?, ?, ?, ?, ?, ?)`,
52942
- params: [`${runId}:state:${state}:${crypto.randomUUID()}`, runId, state, JSON.stringify(data), now, now]
53409
+ params: [`${runId}:state:${state}:${crypto.randomUUID()}`, runId, state, JSON.stringify(data), now2, now2]
52943
53410
  };
52944
53411
  }
52945
- phaseRow(runId, phase, status, now) {
53412
+ phaseRow(runId, phase, status, now2) {
52946
53413
  return {
52947
53414
  sql: `INSERT INTO phase_runs (id, run_id, phase, status, started_at, completed_at, created_at, updated_at)
52948
53415
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
@@ -52951,25 +53418,25 @@ class DbWorkflowPersistenceAdapter {
52951
53418
  runId,
52952
53419
  phase,
52953
53420
  status,
52954
- new Date(now).toISOString(),
52955
- status === "running" ? null : new Date(now).toISOString(),
52956
- now,
52957
- now
53421
+ new Date(now2).toISOString(),
53422
+ status === "running" ? null : new Date(now2).toISOString(),
53423
+ now2,
53424
+ now2
52958
53425
  ]
52959
53426
  };
52960
53427
  }
52961
53428
  async saveActionStart(runId, node, kind, _options) {
52962
53429
  const id = crypto.randomUUID();
52963
- const now = Date.now();
53430
+ const now2 = Date.now();
52964
53431
  await this.db.run(`INSERT INTO action_runs (id, run_id, node, kind, status, started_at, created_at, updated_at)
52965
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, id, runId, node, kind, "running", new Date(now).toISOString(), now, now);
53432
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, id, runId, node, kind, "running", new Date(now2).toISOString(), now2, now2);
52966
53433
  return id;
52967
53434
  }
52968
53435
  async saveActionFinalize(actionId, status, durationMs, ok, result, _redactor) {
52969
- const now = Date.now();
53436
+ const now2 = Date.now();
52970
53437
  await this.db.run(`UPDATE action_runs
52971
53438
  SET status = ?, duration_ms = ?, ok = ?, result_json = ?, completed_at = ?, updated_at = ?
52972
- WHERE id = ?`, status, durationMs, ok ? 1 : 0, result !== undefined ? JSON.stringify(result) : null, new Date(now).toISOString(), now, actionId);
53439
+ WHERE id = ?`, status, durationMs, ok ? 1 : 0, result !== undefined ? JSON.stringify(result) : null, new Date(now2).toISOString(), now2, actionId);
52973
53440
  }
52974
53441
  async loadRun(runId) {
52975
53442
  await this.ensureSchema();
@@ -53005,10 +53472,10 @@ class DbWorkflowPersistenceAdapter {
53005
53472
  return { ...record2 };
53006
53473
  }
53007
53474
  async reseedRun(runId, newState) {
53008
- const now = Date.now();
53475
+ const now2 = Date.now();
53009
53476
  await this.ensureSchema();
53010
53477
  const previous = await this.db.queryFirst("SELECT state FROM workflow_states WHERE run_id = ? ORDER BY created_at DESC, rowid DESC LIMIT 1", runId);
53011
- await this.saveWorkflowState(runId, newState, { reseeded: true, reseededAt: new Date(now).toISOString() });
53478
+ await this.saveWorkflowState(runId, newState, { reseeded: true, reseededAt: new Date(now2).toISOString() });
53012
53479
  await this.saveTransition(runId, previous?.state ?? "", newState, "__reseed__");
53013
53480
  return { fromState: previous?.state ?? null, toState: newState };
53014
53481
  }
@@ -53154,7 +53621,7 @@ var init_persistence = __esm(() => {
53154
53621
  init_schema_sql();
53155
53622
  });
53156
53623
 
53157
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
53624
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
53158
53625
  function mergeVars(workflowVars = {}, overrideVars = {}) {
53159
53626
  return { ...workflowVars, ...overrideVars };
53160
53627
  }
@@ -53214,7 +53681,7 @@ var init_variables = __esm(() => {
53214
53681
  TEMPLATE_REF = /\$\{([^}]+)\}/g;
53215
53682
  });
53216
53683
 
53217
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
53684
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
53218
53685
  async function runActionStep(action, vars, deps) {
53219
53686
  const { host, persistence, lifecycle, stateOrNodeId, runId } = deps;
53220
53687
  const resolved = resolveTemplates(action.options ?? {}, {
@@ -53272,7 +53739,7 @@ var init_action_step = __esm(() => {
53272
53739
  init_variables();
53273
53740
  });
53274
53741
 
53275
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
53742
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
53276
53743
  class StateMachineDriver {
53277
53744
  options;
53278
53745
  constructor(options) {
@@ -53288,6 +53755,7 @@ class StateMachineDriver {
53288
53755
  const runId = lifecycle.runId;
53289
53756
  const states = new Map(workflow.states.map((state) => [state.id, state]));
53290
53757
  const terminal = new Set(workflow.terminalStates ?? []);
53758
+ const failure = new Set(workflow.failureStates ?? []);
53291
53759
  let vars = mergeVars(workflow.vars, options.vars);
53292
53760
  const env = allowedEnv(workflow.env?.allow ?? [], options.env);
53293
53761
  let current = resumeFromState !== undefined ? states.get(resumeFromState) : states.get(workflow.initialState);
@@ -53325,7 +53793,7 @@ class StateMachineDriver {
53325
53793
  if (enter.result?.setVars)
53326
53794
  vars = mergeSetVars(vars, enter.result.setVars);
53327
53795
  if (enter.outcome === "terminal") {
53328
- return await lifecycle.done(current.id, transitionsTaken);
53796
+ return failure.has(current.id) ? await lifecycle.fail(current.id, transitionsTaken, `terminal:${current.id}`) : await lifecycle.done(current.id, transitionsTaken);
53329
53797
  }
53330
53798
  if (enter.outcome === "fail") {
53331
53799
  return await lifecycle.fail(current.id, transitionsTaken, lastActionResult?.error);
@@ -53336,13 +53804,14 @@ class StateMachineDriver {
53336
53804
  }
53337
53805
  const outbound = workflow.transitions.filter((transition) => transition.from === current?.id);
53338
53806
  if (terminal.has(current.id) || outbound.length === 0) {
53339
- return await lifecycle.done(current.id, transitionsTaken);
53807
+ return failure.has(current.id) ? await lifecycle.fail(current.id, transitionsTaken, `terminal:${current.id}`) : await lifecycle.done(current.id, transitionsTaken);
53340
53808
  }
53341
53809
  const nextTransition = await firstPassingTransition(outbound, this.options.host, {
53342
53810
  runId,
53343
53811
  current: current.id,
53344
53812
  vars,
53345
- lastActionResult
53813
+ lastActionResult,
53814
+ workdir: options.workdir
53346
53815
  }, lifecycle);
53347
53816
  if (nextTransition === undefined) {
53348
53817
  return await lifecycle.fail(current.id, transitionsTaken, "no-passing-transition");
@@ -53406,7 +53875,7 @@ var init_state_machine = __esm(() => {
53406
53875
  EMPTY_OUTCOME = { outcome: "completed", result: undefined };
53407
53876
  });
53408
53877
 
53409
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
53878
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
53410
53879
  class TransitionFlowDriver {
53411
53880
  options;
53412
53881
  constructor(options) {
@@ -53481,7 +53950,8 @@ class TransitionFlowDriver {
53481
53950
  runId,
53482
53951
  current: current.id,
53483
53952
  vars,
53484
- lastActionResult
53953
+ lastActionResult,
53954
+ workdir: options.workdir
53485
53955
  }, lifecycle);
53486
53956
  if (edge === undefined) {
53487
53957
  return await lifecycle.fail(current.id, transitionsTaken, "no-passing-edge");
@@ -53524,7 +53994,7 @@ var init_transition_flow = __esm(() => {
53524
53994
  init_variables();
53525
53995
  });
53526
53996
 
53527
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
53997
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
53528
53998
  class WorkflowService {
53529
53999
  host;
53530
54000
  persistence;
@@ -53741,7 +54211,7 @@ var init_service = __esm(() => {
53741
54211
  init_variables();
53742
54212
  });
53743
54213
 
53744
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
54214
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
53745
54215
  var init_dist7 = __esm(() => {
53746
54216
  init_config4();
53747
54217
  init_host();
@@ -53750,20 +54220,7 @@ var init_dist7 = __esm(() => {
53750
54220
  init_service();
53751
54221
  });
53752
54222
 
53753
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.15+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
53754
- var HistoryImportError;
53755
- var init_errors7 = __esm(() => {
53756
- HistoryImportError = class HistoryImportError extends Error {
53757
- details;
53758
- constructor(message, details) {
53759
- super(message);
53760
- this.details = details;
53761
- this.name = "HistoryImportError";
53762
- }
53763
- };
53764
- });
53765
-
53766
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.15+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
54223
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
53767
54224
  import { createHash } from "crypto";
53768
54225
  function stableJson(value) {
53769
54226
  if (Array.isArray(value)) {
@@ -53780,44 +54237,20 @@ function sha256(value) {
53780
54237
  }
53781
54238
  var init_hash = () => {};
53782
54239
 
53783
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.15+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
53784
- function redactValue(value, rules = DEFAULT_REDACTION_RULES) {
53785
- if (typeof value === "string") {
53786
- return rules.reduce((current, rule) => current.replace(rule.pattern, rule.replacement), value);
53787
- }
53788
- if (Array.isArray(value)) {
53789
- return value.map((entry) => redactValue(entry, rules));
53790
- }
53791
- if (value !== null && typeof value === "object") {
53792
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, redactValue(entry, rules)]));
53793
- }
53794
- return value;
53795
- }
53796
- function redactRecord(record2, rules = DEFAULT_REDACTION_RULES) {
53797
- return redactValue(record2, rules);
53798
- }
53799
- var DEFAULT_REDACTION_RULES;
53800
- var init_redaction = __esm(() => {
53801
- DEFAULT_REDACTION_RULES = [
53802
- {
53803
- name: "api-key",
53804
- pattern: /\b(?:sk|pk|ghp|github_pat|xox[baprs])-[-_a-zA-Z0-9]{12,}\b/g,
53805
- replacement: "[REDACTED:token]"
53806
- },
53807
- {
53808
- name: "assignment-secret",
53809
- pattern: /\b(?:api[_-]?key|token|secret|password)\s*[:=]\s*["']?[^"',\s}]+/gi,
53810
- replacement: "[REDACTED:secret]"
53811
- },
53812
- {
53813
- name: "email",
53814
- pattern: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
53815
- replacement: "[REDACTED:email]"
54240
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
54241
+ var HistoryImportError;
54242
+ var init_errors7 = __esm(() => {
54243
+ HistoryImportError = class HistoryImportError extends Error {
54244
+ details;
54245
+ constructor(message, details) {
54246
+ super(message);
54247
+ this.details = details;
54248
+ this.name = "HistoryImportError";
53816
54249
  }
53817
- ];
54250
+ };
53818
54251
  });
53819
54252
 
53820
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.15+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
54253
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
53821
54254
  var HISTORY_IMPORT_SCHEMA_SQL;
53822
54255
  var init_schema_sql2 = __esm(() => {
53823
54256
  HISTORY_IMPORT_SCHEMA_SQL = `
@@ -53904,7 +54337,7 @@ CREATE TABLE IF NOT EXISTS history_etl_openclaw (
53904
54337
  `.trim();
53905
54338
  });
53906
54339
 
53907
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.15+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
54340
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
53908
54341
  function firstString(...values) {
53909
54342
  for (const value of values) {
53910
54343
  if (typeof value === "string" && value.length > 0)
@@ -54041,7 +54474,26 @@ var init_sources = __esm(() => {
54041
54474
  };
54042
54475
  });
54043
54476
 
54044
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.15+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
54477
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/jsonl-importer-dao.js
54478
+ function targetTableFor(table3) {
54479
+ if (!VALID_TABLE_NAME.test(table3)) {
54480
+ throw new HistoryImportError(`Invalid history ETL target table: ${table3}`, { table: table3 });
54481
+ }
54482
+ return table3;
54483
+ }
54484
+ function timestamp(now2) {
54485
+ return (now2?.() ?? new Date).toISOString();
54486
+ }
54487
+ function ETL_TABLE_DDL(table3) {
54488
+ return `CREATE TABLE IF NOT EXISTS ${table3} (
54489
+ record_hash TEXT PRIMARY KEY,
54490
+ source_file TEXT NOT NULL,
54491
+ source_line INTEGER NOT NULL,
54492
+ split_index INTEGER NOT NULL,
54493
+ payload_json TEXT NOT NULL,
54494
+ imported_at TEXT NOT NULL
54495
+ );`;
54496
+ }
54045
54497
  async function applyHistoryImportSchema(db2) {
54046
54498
  for (const statement of HISTORY_IMPORT_SCHEMA_SQL.split(";")) {
54047
54499
  const sql4 = statement.trim();
@@ -54059,16 +54511,80 @@ async function ensureTargetTables(db2, definition) {
54059
54511
  await db2.exec(ETL_TABLE_DDL(table3));
54060
54512
  }
54061
54513
  }
54062
- function ETL_TABLE_DDL(table3) {
54063
- return `CREATE TABLE IF NOT EXISTS ${table3} (
54064
- record_hash TEXT PRIMARY KEY,
54065
- source_file TEXT NOT NULL,
54066
- source_line INTEGER NOT NULL,
54067
- split_index INTEGER NOT NULL,
54068
- payload_json TEXT NOT NULL,
54069
- imported_at TEXT NOT NULL
54070
- );`;
54514
+ async function readCheckpoint(db2, source, sourceFile) {
54515
+ const row = await db2.queryFirst("SELECT last_imported_line FROM history_import_checkpoint WHERE source = ? AND source_file = ?", source, sourceFile);
54516
+ return row?.last_imported_line ?? 0;
54517
+ }
54518
+ async function resetCheckpoints(db2, source, files) {
54519
+ for (const file2 of files) {
54520
+ await db2.run("DELETE FROM history_import_checkpoint WHERE source = ? AND source_file = ?", source, file2);
54521
+ }
54522
+ }
54523
+ async function writeCheckpoint(db2, source, sourceFile, line, now2) {
54524
+ await db2.run(`INSERT INTO history_import_checkpoint (source, source_file, last_imported_line, updated_at)
54525
+ VALUES (?, ?, ?, ?)
54526
+ ON CONFLICT(source, source_file) DO UPDATE SET
54527
+ last_imported_line = excluded.last_imported_line,
54528
+ updated_at = excluded.updated_at`, source, sourceFile, line, timestamp(now2));
54529
+ }
54530
+ async function ledgerExists(db2, recordHash) {
54531
+ const row = await db2.queryFirst("SELECT record_hash FROM history_import_ledger WHERE record_hash = ?", recordHash);
54532
+ return row !== undefined && row !== null;
54533
+ }
54534
+ async function insertRecord(db2, targetTable, recordHash, sourceFile, sourceLine, splitIndex, payload, now2) {
54535
+ const table3 = targetTableFor(targetTable);
54536
+ await db2.run(`INSERT INTO ${table3} (record_hash, source_file, source_line, split_index, payload_json, imported_at)
54537
+ VALUES (?, ?, ?, ?, ?, ?)
54538
+ ON CONFLICT(record_hash) DO NOTHING`, recordHash, sourceFile, sourceLine, splitIndex, JSON.stringify(payload), timestamp(now2));
54539
+ }
54540
+ async function insertLedger(db2, recordHash, source, sourceFile, sourceLine, splitIndex, targetTable, now2) {
54541
+ await db2.run(`INSERT INTO history_import_ledger (record_hash, source, source_file, source_line, split_index, target_table, imported_at)
54542
+ VALUES (?, ?, ?, ?, ?, ?, ?)`, recordHash, source, sourceFile, sourceLine, splitIndex, targetTable, timestamp(now2));
54071
54543
  }
54544
+ var init_jsonl_importer_dao = __esm(() => {
54545
+ init_errors7();
54546
+ init_schema_sql2();
54547
+ init_sources();
54548
+ });
54549
+
54550
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
54551
+ function redactValue(value, rules = DEFAULT_REDACTION_RULES) {
54552
+ if (typeof value === "string") {
54553
+ return rules.reduce((current, rule) => current.replace(rule.pattern, rule.replacement), value);
54554
+ }
54555
+ if (Array.isArray(value)) {
54556
+ return value.map((entry) => redactValue(entry, rules));
54557
+ }
54558
+ if (value !== null && typeof value === "object") {
54559
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, redactValue(entry, rules)]));
54560
+ }
54561
+ return value;
54562
+ }
54563
+ function redactRecord(record2, rules = DEFAULT_REDACTION_RULES) {
54564
+ return redactValue(record2, rules);
54565
+ }
54566
+ var DEFAULT_REDACTION_RULES;
54567
+ var init_redaction = __esm(() => {
54568
+ DEFAULT_REDACTION_RULES = [
54569
+ {
54570
+ name: "api-key",
54571
+ pattern: /\b(?:sk|pk|ghp|github_pat|xox[baprs])-[-_a-zA-Z0-9]{12,}\b/g,
54572
+ replacement: "[REDACTED:token]"
54573
+ },
54574
+ {
54575
+ name: "assignment-secret",
54576
+ pattern: /\b(?:api[_-]?key|token|secret|password)\s*[:=]\s*["']?[^"',\s}]+/gi,
54577
+ replacement: "[REDACTED:secret]"
54578
+ },
54579
+ {
54580
+ name: "email",
54581
+ pattern: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
54582
+ replacement: "[REDACTED:email]"
54583
+ }
54584
+ ];
54585
+ });
54586
+
54587
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
54072
54588
  async function runJsonlImport(source, options) {
54073
54589
  const definition = resolveSourceDefinition(source);
54074
54590
  const resolvedSource = definition.source;
@@ -54240,45 +54756,6 @@ function matchesPattern(path9, patterns) {
54240
54756
  return path9.endsWith(pattern.replace(/^\*/, ""));
54241
54757
  });
54242
54758
  }
54243
- async function readCheckpoint(db2, source, sourceFile) {
54244
- const row = await db2.queryFirst("SELECT last_imported_line FROM history_import_checkpoint WHERE source = ? AND source_file = ?", source, sourceFile);
54245
- return row?.last_imported_line ?? 0;
54246
- }
54247
- async function resetCheckpoints(db2, source, files) {
54248
- for (const file2 of files) {
54249
- await db2.run("DELETE FROM history_import_checkpoint WHERE source = ? AND source_file = ?", source, file2);
54250
- }
54251
- }
54252
- async function writeCheckpoint(db2, source, sourceFile, line, now) {
54253
- await db2.run(`INSERT INTO history_import_checkpoint (source, source_file, last_imported_line, updated_at)
54254
- VALUES (?, ?, ?, ?)
54255
- ON CONFLICT(source, source_file) DO UPDATE SET
54256
- last_imported_line = excluded.last_imported_line,
54257
- updated_at = excluded.updated_at`, source, sourceFile, line, timestamp(now));
54258
- }
54259
- async function ledgerExists(db2, recordHash) {
54260
- const row = await db2.queryFirst("SELECT record_hash FROM history_import_ledger WHERE record_hash = ?", recordHash);
54261
- return row !== undefined && row !== null;
54262
- }
54263
- async function insertRecord(db2, targetTable, recordHash, sourceFile, sourceLine, splitIndex, payload, now) {
54264
- const table3 = targetTableFor(targetTable);
54265
- await db2.run(`INSERT INTO ${table3} (record_hash, source_file, source_line, split_index, payload_json, imported_at)
54266
- VALUES (?, ?, ?, ?, ?, ?)
54267
- ON CONFLICT(record_hash) DO NOTHING`, recordHash, sourceFile, sourceLine, splitIndex, JSON.stringify(payload), timestamp(now));
54268
- }
54269
- async function insertLedger(db2, recordHash, source, sourceFile, sourceLine, splitIndex, targetTable, now) {
54270
- await db2.run(`INSERT INTO history_import_ledger (record_hash, source, source_file, source_line, split_index, target_table, imported_at)
54271
- VALUES (?, ?, ?, ?, ?, ?, ?)`, recordHash, source, sourceFile, sourceLine, splitIndex, targetTable, timestamp(now));
54272
- }
54273
- function targetTableFor(table3) {
54274
- if (!VALID_TABLE_NAME.test(table3)) {
54275
- throw new HistoryImportError(`Invalid history ETL target table: ${table3}`, { table: table3 });
54276
- }
54277
- return table3;
54278
- }
54279
- function timestamp(now) {
54280
- return (now?.() ?? new Date).toISOString();
54281
- }
54282
54759
  async function* readLines(fileSystem, file2) {
54283
54760
  if (fileSystem.readFileStream) {
54284
54761
  yield* fileSystem.readFileStream(file2);
@@ -54291,20 +54768,19 @@ async function* readLines(fileSystem, file2) {
54291
54768
  }
54292
54769
  var init_importer = __esm(() => {
54293
54770
  init_dist5();
54294
- init_errors7();
54295
54771
  init_hash();
54772
+ init_jsonl_importer_dao();
54296
54773
  init_redaction();
54297
- init_schema_sql2();
54298
54774
  init_sources();
54299
54775
  });
54300
54776
 
54301
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.15+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
54777
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.18+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
54302
54778
  var init_dist8 = __esm(() => {
54303
54779
  init_importer();
54304
54780
  init_schema_sql2();
54305
54781
  });
54306
54782
 
54307
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
54783
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
54308
54784
  function collectExtensions(sourceName, sourceDir, extensions) {
54309
54785
  if (extensions === undefined)
54310
54786
  return [];
@@ -54320,7 +54796,7 @@ var init_extensions = __esm(() => {
54320
54796
  init_dist5();
54321
54797
  });
54322
54798
 
54323
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
54799
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
54324
54800
  function createFinding(rule, message, filePath, extras = {}) {
54325
54801
  return {
54326
54802
  ruleId: rule.id,
@@ -54391,7 +54867,7 @@ var init_types3 = __esm(() => {
54391
54867
  });
54392
54868
  });
54393
54869
 
54394
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
54870
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
54395
54871
  async function loadPreset(name, options) {
54396
54872
  const merged = await buildMergedRoots(options.roots.map((root) => resolvePath4(root)), options.fileSystem);
54397
54873
  const presetPath = findMergedPreset(merged, name);
@@ -54606,7 +55082,7 @@ var init_loader2 = __esm(() => {
54606
55082
  FIX_MODE_AUTHORITY = { none: 0, suggest: 1, auto: 2 };
54607
55083
  });
54608
55084
 
54609
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
55085
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
54610
55086
  function normalizeFindingPath(filePath) {
54611
55087
  if (!filePath || isAbsolutePath2(filePath))
54612
55088
  return null;
@@ -54671,7 +55147,7 @@ var init_test_stub_fixer = __esm(() => {
54671
55147
  realFileSystem = createNodeFileSystem3();
54672
55148
  });
54673
55149
 
54674
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
55150
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
54675
55151
  function registerBuiltinFixers(host, exec) {
54676
55152
  const regexFixer = new RegexFixerProvider;
54677
55153
  const pathFixer = new PathFixerProvider;
@@ -54874,7 +55350,7 @@ var init_fixers = __esm(() => {
54874
55350
  };
54875
55351
  });
54876
55352
 
54877
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
55353
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
54878
55354
  function resolveAgentName(input) {
54879
55355
  if (isCanonicalName(input))
54880
55356
  return input;
@@ -55125,7 +55601,7 @@ var init_shims = __esm(() => {
55125
55601
  ALIAS_TO_CANONICAL = Object.fromEntries(Object.values(AGENT_SHIMS).flatMap((shim) => (shim.aliases ?? []).map((alias3) => [alias3, shim.name])));
55126
55602
  });
55127
55603
 
55128
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
55604
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
55129
55605
  function buildIdentityPreamble(ctx) {
55130
55606
  const sections = [
55131
55607
  `You are agent \`${ctx.agentId}\` (${ctx.agentType}) in workspace \`${ctx.workspace}\`.`
@@ -55185,7 +55661,7 @@ var init_identity = __esm(() => {
55185
55661
  init_dist5();
55186
55662
  });
55187
55663
 
55188
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
55664
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
55189
55665
  function isClaudeStyleSlashCommand(input) {
55190
55666
  return SLASH_COMMAND_RE.test(input);
55191
55667
  }
@@ -55213,7 +55689,7 @@ var init_slash_command = __esm(() => {
55213
55689
  SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
55214
55690
  });
55215
55691
 
55216
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
55692
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
55217
55693
  function buildCorrelationEnv(correlation) {
55218
55694
  return {
55219
55695
  [AGENT_RUN_ID_ENV]: correlation.runId,
@@ -55349,7 +55825,7 @@ var init_ai_runner = __esm(() => {
55349
55825
  init_slash_command();
55350
55826
  });
55351
55827
 
55352
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
55828
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
55353
55829
  class AgentDetector {
55354
55830
  runner;
55355
55831
  timeout;
@@ -55425,7 +55901,7 @@ var init_agent_detector = __esm(() => {
55425
55901
  VERSION_PATTERN = /(?<version>\d+\.\d+(?:\.\d+)?)/;
55426
55902
  });
55427
55903
 
55428
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
55904
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
55429
55905
  function validateAgentId(id) {
55430
55906
  if (!/^[a-z][a-z0-9_-]{1,63}$/.test(id)) {
55431
55907
  throw new ValueError(`Invalid agent id "${id}": expected 2-64 chars, lowercase alphanumeric, "_" or "-"`);
@@ -55522,7 +55998,7 @@ var init_agent_spec = __esm(() => {
55522
55998
  };
55523
55999
  });
55524
56000
 
55525
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
56001
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
55526
56002
  function isNonEmpty(value) {
55527
56003
  return value !== undefined && value.trim().length > 0;
55528
56004
  }
@@ -55627,7 +56103,7 @@ var init_auth_shims = __esm(() => {
55627
56103
  };
55628
56104
  });
55629
56105
 
55630
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
56106
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
55631
56107
  class ModelHealthProbeRegistry {
55632
56108
  probes = new Map;
55633
56109
  register(providerPrefix, probe) {
@@ -55735,7 +56211,7 @@ var init_model_health_probe = __esm(() => {
55735
56211
  };
55736
56212
  });
55737
56213
 
55738
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
56214
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
55739
56215
  class DoctorRunner {
55740
56216
  detector;
55741
56217
  runner;
@@ -55872,15 +56348,15 @@ var init_doctor_runner = __esm(() => {
55872
56348
  init_model_health_probe();
55873
56349
  });
55874
56350
 
55875
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
56351
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
55876
56352
  var init_events = () => {};
55877
56353
 
55878
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
56354
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
55879
56355
  function formatMessage(msg) {
55880
56356
  return `[task from=${msg.fromId ?? "operator"} id=${msg.id}] ${msg.body}`;
55881
56357
  }
55882
56358
 
55883
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
56359
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
55884
56360
  import { Buffer as Buffer5 } from "buffer";
55885
56361
 
55886
56362
  class TeamAgentProcess {
@@ -56014,7 +56490,7 @@ var init_team_agent_process = __esm(() => {
56014
56490
  init_dist5();
56015
56491
  });
56016
56492
 
56017
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
56493
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
56018
56494
  class TeamOrchestrator {
56019
56495
  configDir;
56020
56496
  inbox;
@@ -56143,7 +56619,7 @@ var init_team_orchestrator = __esm(() => {
56143
56619
  init_team_agent_process();
56144
56620
  });
56145
56621
 
56146
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.15+1d3d52e40c4aad1a/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
56622
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.18+aa81d3e2be8bffb2/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
56147
56623
  var exports_dist3 = {};
56148
56624
  __export(exports_dist3, {
56149
56625
  validateAgentId: () => validateAgentId,
@@ -56194,7 +56670,7 @@ var init_dist9 = __esm(() => {
56194
56670
  init_team_orchestrator();
56195
56671
  });
56196
56672
 
56197
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
56673
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
56198
56674
  function stringArray(value) {
56199
56675
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
56200
56676
  }
@@ -56232,7 +56708,7 @@ function parseInlineFlags(source) {
56232
56708
  return { flags, rest: source.slice(match[0].length) };
56233
56709
  }
56234
56710
 
56235
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
56711
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
56236
56712
  function matchesAny(path9, patterns) {
56237
56713
  if (patterns === undefined || patterns.length === 0)
56238
56714
  return true;
@@ -56280,7 +56756,7 @@ function escapeRegExp(value) {
56280
56756
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
56281
56757
  }
56282
56758
 
56283
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
56759
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
56284
56760
  async function discoverFiles2(options) {
56285
56761
  const fs3 = options.fs ?? createNodeFileSystem3();
56286
56762
  const allFiles = await walkDir2(options.workdir, fs3, DEFAULT_EXCLUDES);
@@ -56308,12 +56784,12 @@ var init_file_discovery = __esm(() => {
56308
56784
  DEFAULT_EXCLUDES = new Set([".git", "node_modules", "dist", ".coverage", ".astro", ".wrangler"]);
56309
56785
  });
56310
56786
 
56311
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
56787
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
56312
56788
  var init_file_utils = __esm(() => {
56313
56789
  init_file_discovery();
56314
56790
  });
56315
56791
 
56316
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
56792
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
56317
56793
  class AgentDetectionEvaluator {
56318
56794
  detector;
56319
56795
  constructor(detector = new AgentDetector) {
@@ -56341,7 +56817,7 @@ var init_agent_detection_evaluator = __esm(() => {
56341
56817
  init_file_utils();
56342
56818
  });
56343
56819
 
56344
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
56820
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
56345
56821
  class CoverageGateEvaluator {
56346
56822
  constructor() {}
56347
56823
  async evaluate(rule, context4) {
@@ -56425,7 +56901,7 @@ var init_coverage_gate_evaluator = __esm(() => {
56425
56901
  init_file_utils();
56426
56902
  });
56427
56903
 
56428
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
56904
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
56429
56905
  class ExitCodeEvaluator {
56430
56906
  executor;
56431
56907
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -56461,7 +56937,7 @@ var init_exit_code_evaluator = __esm(() => {
56461
56937
  init_file_utils();
56462
56938
  });
56463
56939
 
56464
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
56940
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
56465
56941
  class ForbiddenImportEvaluator {
56466
56942
  constructor() {}
56467
56943
  async evaluate(rule, context4) {
@@ -56542,7 +57018,7 @@ var init_forbidden_import_evaluator = __esm(() => {
56542
57018
  init_file_utils();
56543
57019
  });
56544
57020
 
56545
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
57021
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
56546
57022
  class ImportBoundaryEvaluator {
56547
57023
  async evaluate(rule, context4) {
56548
57024
  const config4 = rule.evaluator.config ?? {};
@@ -56635,7 +57111,7 @@ var init_import_boundary_evaluator = __esm(() => {
56635
57111
  init_file_utils();
56636
57112
  });
56637
57113
 
56638
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
57114
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
56639
57115
  class PathEvaluator {
56640
57116
  constructor() {}
56641
57117
  async evaluate(rule, context4) {
@@ -56696,7 +57172,7 @@ var init_path_evaluator = __esm(() => {
56696
57172
  init_file_utils();
56697
57173
  });
56698
57174
 
56699
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
57175
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
56700
57176
  class RegexEvaluator {
56701
57177
  constructor() {}
56702
57178
  async evaluate(rule, context4) {
@@ -56774,7 +57250,7 @@ var init_regex_evaluator = __esm(() => {
56774
57250
  init_file_utils();
56775
57251
  });
56776
57252
 
56777
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
57253
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
56778
57254
  class RipgrepEvaluator {
56779
57255
  executor;
56780
57256
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -56867,7 +57343,7 @@ var init_ripgrep_evaluator = __esm(() => {
56867
57343
  init_file_utils();
56868
57344
  });
56869
57345
 
56870
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
57346
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
56871
57347
  class SchemaArtifactEvaluator {
56872
57348
  constructor() {}
56873
57349
  async evaluate(rule, context4) {
@@ -56945,7 +57421,7 @@ var init_schema_artifact_evaluator = __esm(() => {
56945
57421
  init_file_utils();
56946
57422
  });
56947
57423
 
56948
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
57424
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
56949
57425
  class SecretsScannerEvaluator {
56950
57426
  constructor() {}
56951
57427
  async evaluate(rule, context4) {
@@ -57013,7 +57489,7 @@ var init_secrets_scanner_evaluator = __esm(() => {
57013
57489
  ALL_CATEGORIES = Object.keys(BUILTIN_PATTERNS);
57014
57490
  });
57015
57491
 
57016
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
57492
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
57017
57493
  class SgEvaluator {
57018
57494
  executor;
57019
57495
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -57110,7 +57586,7 @@ var init_sg_evaluator = __esm(() => {
57110
57586
  init_file_utils();
57111
57587
  });
57112
57588
 
57113
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
57589
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
57114
57590
  class TypeScriptTestPathResolver {
57115
57591
  name = "typescript";
57116
57592
  constructor() {}
@@ -57193,7 +57669,7 @@ function testify(rel) {
57193
57669
  return `${dir}test_${base2}`;
57194
57670
  }
57195
57671
 
57196
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
57672
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
57197
57673
  class TestLocationEvaluator {
57198
57674
  resolvers;
57199
57675
  constructor(resolvers) {
@@ -57268,7 +57744,7 @@ var init_test_location_evaluator = __esm(() => {
57268
57744
  TYPESCRIPT_FALLBACK = new TypeScriptTestPathResolver;
57269
57745
  });
57270
57746
 
57271
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
57747
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
57272
57748
  class TsdocExportEvaluator {
57273
57749
  constructor() {}
57274
57750
  async evaluate(rule, context4) {
@@ -57353,7 +57829,7 @@ var init_tsdoc_export_evaluator = __esm(() => {
57353
57829
  };
57354
57830
  });
57355
57831
 
57356
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
57832
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
57357
57833
  class JsonFormatter {
57358
57834
  constructor() {}
57359
57835
  format(result) {
@@ -57361,7 +57837,7 @@ class JsonFormatter {
57361
57837
  }
57362
57838
  }
57363
57839
 
57364
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
57840
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
57365
57841
  class TextFormatter {
57366
57842
  constructor() {}
57367
57843
  format(result) {
@@ -57375,7 +57851,7 @@ class TextFormatter {
57375
57851
  }
57376
57852
  }
57377
57853
 
57378
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
57854
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
57379
57855
  function registerBuiltins(host, executor) {
57380
57856
  const path9 = new PathEvaluator;
57381
57857
  host.evaluators.register("regex", new RegexEvaluator, "builtin");
@@ -57415,7 +57891,7 @@ var init_builtins = __esm(() => {
57415
57891
  init_tsdoc_export_evaluator();
57416
57892
  });
57417
57893
 
57418
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
57894
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
57419
57895
  class RuleEngineHost {
57420
57896
  evaluators;
57421
57897
  formatters;
@@ -57432,7 +57908,7 @@ var init_rule_engine_host = __esm(() => {
57432
57908
  init_extension2();
57433
57909
  });
57434
57910
 
57435
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
57911
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
57436
57912
  class RuleEngine {
57437
57913
  host;
57438
57914
  events;
@@ -57603,7 +58079,7 @@ var init_engine = __esm(() => {
57603
58079
  init_types3();
57604
58080
  });
57605
58081
 
57606
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
58082
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
57607
58083
  async function bundledRulesRoot() {
57608
58084
  if (cachedRoot2 !== undefined)
57609
58085
  return cachedRoot2;
@@ -57654,41 +58130,41 @@ var init_bundled_rules = __esm(() => {
57654
58130
  init_dist5();
57655
58131
  });
57656
58132
 
57657
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
58133
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
57658
58134
  class DbRulePersistenceAdapter {
57659
58135
  db;
57660
58136
  constructor(db2) {
57661
58137
  this.db = db2;
57662
58138
  }
57663
58139
  async insertRun(input) {
57664
- const now = new Date().toISOString();
58140
+ const now2 = new Date().toISOString();
57665
58141
  await this.db.run(`INSERT INTO rule_runs (id, preset, source_kind, source_value, status, rule_count,
57666
58142
  fail_on, stop_on_first, fix_mode, dry_run, metadata_json, started_at, created_at, updated_at)
57667
- VALUES (?, ?, ?, ?, 'running', ?, ?, ?, ?, ?, ?, ?, ?, ?)`, input.id, input.preset ?? null, input.sourceKind, input.sourceValue ?? null, input.ruleCount, input.failOn ?? null, input.stopOnFirst ?? null, input.fixMode, input.dryRun ? 1 : 0, input.metadataJson ?? "{}", now, now, now);
58143
+ VALUES (?, ?, ?, ?, 'running', ?, ?, ?, ?, ?, ?, ?, ?, ?)`, input.id, input.preset ?? null, input.sourceKind, input.sourceValue ?? null, input.ruleCount, input.failOn ?? null, input.stopOnFirst ?? null, input.fixMode, input.dryRun ? 1 : 0, input.metadataJson ?? "{}", now2, now2, now2);
57668
58144
  }
57669
58145
  async updateRunStatus(runId, status, findingCount, fixCount, appliedFixCount, durationMs) {
57670
- const now = new Date().toISOString();
58146
+ const now2 = new Date().toISOString();
57671
58147
  await this.db.run(`UPDATE rule_runs
57672
58148
  SET status = ?, finding_count = ?, fix_count = ?, applied_fix_count = ?,
57673
58149
  duration_ms = ?, completed_at = ?, updated_at = ?
57674
- WHERE id = ?`, status, findingCount, fixCount, appliedFixCount, durationMs, now, now, runId);
58150
+ WHERE id = ?`, status, findingCount, fixCount, appliedFixCount, durationMs, now2, now2, runId);
57675
58151
  }
57676
58152
  async insertEvalRun(input) {
57677
- const now = new Date().toISOString();
58153
+ const now2 = new Date().toISOString();
57678
58154
  await this.db.run(`INSERT INTO rule_eval_runs (id, run_id, rule_id, severity, evaluator, status,
57679
58155
  started_at, created_at, updated_at)
57680
- VALUES (?, ?, ?, ?, ?, 'running', ?, ?, ?)`, input.id, input.runId, input.ruleId, input.severity, input.evaluator, now, now, now);
58156
+ VALUES (?, ?, ?, ?, ?, 'running', ?, ?, ?)`, input.id, input.runId, input.ruleId, input.severity, input.evaluator, now2, now2, now2);
57681
58157
  }
57682
58158
  async updateEvalRun(input) {
57683
- const now = new Date().toISOString();
58159
+ const now2 = new Date().toISOString();
57684
58160
  await this.db.run(`UPDATE rule_eval_runs
57685
58161
  SET status = ?, finding_count = ?, fix_count = ?, duration_ms = ?,
57686
58162
  error = ?, findings_json = ?, fixes_json = ?, completed_at = ?, updated_at = ?
57687
- WHERE run_id = ? AND rule_id = ?`, input.status, input.findingCount, input.fixCount, input.durationMs, input.error ?? null, input.findingsJson ?? null, input.fixesJson ?? null, now, now, input.runId, input.ruleId);
58163
+ WHERE run_id = ? AND rule_id = ?`, input.status, input.findingCount, input.fixCount, input.durationMs, input.error ?? null, input.findingsJson ?? null, input.fixesJson ?? null, now2, now2, input.runId, input.ruleId);
57688
58164
  }
57689
58165
  }
57690
58166
 
57691
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
58167
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
57692
58168
  var RULE_ENGINE_SCHEMA_SQL = `
57693
58169
  CREATE TABLE IF NOT EXISTS rule_runs (
57694
58170
  id TEXT PRIMARY KEY,
@@ -57734,10 +58210,10 @@ CREATE TABLE IF NOT EXISTS rule_eval_runs (
57734
58210
  CREATE INDEX IF NOT EXISTS idx_rule_eval_runs_run_id ON rule_eval_runs (run_id);
57735
58211
  `;
57736
58212
 
57737
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
58213
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
57738
58214
  var init_persistence2 = () => {};
57739
58215
 
57740
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.15+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
58216
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.18+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
57741
58217
  var init_dist10 = __esm(() => {
57742
58218
  init_extensions();
57743
58219
  init_loader2();
@@ -57806,7 +58282,7 @@ var init_schema3 = __esm(() => {
57806
58282
  });
57807
58283
 
57808
58284
  // ../../packages/domain/src/migrations.ts
57809
- import { join as join5 } from "path";
58285
+ import { join as join6 } from "path";
57810
58286
  async function applyCliMigrations(adapter, migrations = CLI_MIGRATIONS) {
57811
58287
  await adapter.exec('CREATE TABLE IF NOT EXISTS "__spur_cli_migrations" (id TEXT PRIMARY KEY, applied_at INTEGER NOT NULL)');
57812
58288
  let applied = 0;
@@ -57834,7 +58310,7 @@ async function loadSqlMigrations(folder) {
57834
58310
  for (const entry of entries) {
57835
58311
  migrations.push({
57836
58312
  id: entry.replace(/\.sql$/, ""),
57837
- sql: await fs3.readFile(join5(folder, entry))
58313
+ sql: await fs3.readFile(join6(folder, entry))
57838
58314
  });
57839
58315
  }
57840
58316
  return migrations.length > 0 ? migrations : CLI_MIGRATIONS;
@@ -57957,7 +58433,7 @@ ${SYSTEM_EVENTS_SCHEMA_SQL}
57957
58433
  ];
57958
58434
  });
57959
58435
 
57960
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
58436
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
57961
58437
  function queueLogger() {
57962
58438
  if (!_queueLogger)
57963
58439
  _queueLogger = getLogger2("job-queue");
@@ -58234,7 +58710,7 @@ var init_db_job_queue = __esm(() => {
58234
58710
  init_tracing2();
58235
58711
  });
58236
58712
 
58237
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
58713
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
58238
58714
  var exports_job_queue_db = {};
58239
58715
  __export(exports_job_queue_db, {
58240
58716
  DBQueueConsumer: () => DBQueueConsumer,
@@ -58256,6 +58732,7 @@ async function createMigratedDbViaRuntime(config4) {
58256
58732
  const { loadRuntimeFactory: loadRuntimeFactory3 } = await Promise.resolve().then(() => (init_dist5(), exports_dist2));
58257
58733
  const factory = await loadRuntimeFactory3();
58258
58734
  const runtimeAdapter = await factory.createDbAdapter(config4);
58735
+ await runtimeAdapter.exec("PRAGMA busy_timeout = 5000");
58259
58736
  await applyCliMigrations(runtimeAdapter);
58260
58737
  return runtimeAdapter;
58261
58738
  }
@@ -59204,13 +59681,13 @@ var init_envelope = __esm(() => {
59204
59681
  });
59205
59682
 
59206
59683
  // ../../packages/domain/src/planning/locks.ts
59207
- import { closeSync, fsyncSync, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync7, renameSync as renameSync3, unlinkSync, writeSync } from "fs";
59208
- import { dirname as dirname7, join as join6 } from "path";
59684
+ import { closeSync as closeSync2, fsyncSync, mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync7, renameSync as renameSync3, unlinkSync, writeSync as writeSync2 } from "fs";
59685
+ import { dirname as dirname7, join as join7 } from "path";
59209
59686
  function lockPathForEntity(folder, entityId) {
59210
- return join6(folder, `.${entityId}.lock`);
59687
+ return join7(folder, `.${entityId}.lock`);
59211
59688
  }
59212
59689
  function createLockPath(folder) {
59213
- return join6(folder, ".create.lock");
59690
+ return join7(folder, ".create.lock");
59214
59691
  }
59215
59692
  function parseLockContent(raw) {
59216
59693
  const str = typeof raw === "string" ? raw : raw.toString();
@@ -59273,14 +59750,14 @@ function acquireLock(path9, _fs, ttlMs, label) {
59273
59750
  },
59274
59751
  staleWarning
59275
59752
  });
59276
- mkdirSync4(dirname7(path9), { recursive: true });
59753
+ mkdirSync5(dirname7(path9), { recursive: true });
59277
59754
  for (let attempt = 0;attempt < 2; attempt++) {
59278
59755
  try {
59279
- const fd = openSync(path9, "wx");
59756
+ const fd = openSync2(path9, "wx");
59280
59757
  try {
59281
- writeSync(fd, content);
59758
+ writeSync2(fd, content);
59282
59759
  } finally {
59283
- closeSync(fd);
59760
+ closeSync2(fd);
59284
59761
  }
59285
59762
  return makeResult();
59286
59763
  } catch (err) {
@@ -59302,20 +59779,20 @@ function acquireLock(path9, _fs, ttlMs, label) {
59302
59779
  function fsyncPath(path9, swallowErrors = false) {
59303
59780
  let fd;
59304
59781
  try {
59305
- fd = openSync(path9, "r");
59782
+ fd = openSync2(path9, "r");
59306
59783
  fsyncSync(fd);
59307
59784
  } catch (err) {
59308
59785
  if (!swallowErrors)
59309
59786
  throw err;
59310
59787
  } finally {
59311
59788
  if (fd !== undefined)
59312
- closeSync(fd);
59789
+ closeSync2(fd);
59313
59790
  }
59314
59791
  }
59315
59792
  function atomicWrite(dest, content, entityId, fs3, projectName = "spur") {
59316
59793
  const dir = dirname7(dest);
59317
59794
  const rand = Math.random().toString(36).slice(2, 10);
59318
- const tempPath = join6(dir, `.${projectName}.${entityId}.${rand}.tmp`);
59795
+ const tempPath = join7(dir, `.${projectName}.${entityId}.${rand}.tmp`);
59319
59796
  fs3.writeFile(tempPath, content);
59320
59797
  fsyncPath(tempPath);
59321
59798
  renameSync3(tempPath, dest);
@@ -59324,7 +59801,7 @@ function atomicWrite(dest, content, entityId, fs3, projectName = "spur") {
59324
59801
  async function atomicWriteAsync(dest, content, entityId, fs3, projectName = "spur") {
59325
59802
  const dir = dirname7(dest);
59326
59803
  const rand = Math.random().toString(36).slice(2, 10);
59327
- const tempPath = join6(dir, `.${projectName}.${entityId}.${rand}.tmp`);
59804
+ const tempPath = join7(dir, `.${projectName}.${entityId}.${rand}.tmp`);
59328
59805
  await fs3.writeFile(tempPath, content);
59329
59806
  fsyncPath(tempPath);
59330
59807
  renameSync3(tempPath, dest);
@@ -59339,7 +59816,7 @@ function cleanupTempFiles(folder, entityId, fs3, projectName = "spur") {
59339
59816
  let count3 = 0;
59340
59817
  for (const entry of entries) {
59341
59818
  if (entry.startsWith(prefix) && entry.endsWith(suffix)) {
59342
- fs3.deleteFile(join6(folder, entry));
59819
+ fs3.deleteFile(join7(folder, entry));
59343
59820
  count3++;
59344
59821
  }
59345
59822
  }
@@ -60609,11 +61086,12 @@ class AgentService {
60609
61086
  const forceBuffered = silent || nonInteractive;
60610
61087
  const outputPolicy = forceBuffered ? { mode: "buffered" } : jsonOutput ? { mode: "buffered" } : { mode: "stream", isTTY: isatty3(1) };
60611
61088
  const outputMode = outputPolicy.mode;
61089
+ let publishPid;
60612
61090
  const runner = deps?.runner ?? new AiRunner({
60613
- processExecutor: new NodeProcessExecutor3({
61091
+ processExecutor: new PidObservingProcessExecutor({
60614
61092
  output: outputPolicy,
60615
61093
  ...this.ctx.processRegistry !== undefined ? { registry: this.ctx.processRegistry } : {}
60616
- }),
61094
+ }, (pid) => publishPid?.(pid)),
60617
61095
  ...this.ctx.events !== undefined ? { events: bridgeEventBus(this.ctx.events) } : {},
60618
61096
  ...this.ctx.events !== undefined ? { processEvents: bridgeEventBus(this.ctx.events) } : {}
60619
61097
  });
@@ -60642,6 +61120,7 @@ class AgentService {
60642
61120
  const onTerminate = () => controller.abort();
60643
61121
  const onExternalAbort = () => controller.abort();
60644
61122
  const lifecycle = new AgentExecutionLifecycle(options.execution?.observer, options.execution?.correlation, configuredSecretValues(this.ctx.env), options.execution?.heartbeatMs);
61123
+ publishPid = (pid) => lifecycle.setPid(pid);
60645
61124
  process.on("SIGTERM", onTerminate);
60646
61125
  process.on("SIGINT", onTerminate);
60647
61126
  options.execution?.signal?.addEventListener("abort", onExternalAbort, { once: true });
@@ -60809,7 +61288,7 @@ class AgentService {
60809
61288
  return {
60810
61289
  ok: false,
60811
61290
  exitCode: 2,
60812
- message: "'inline' selects in-session execution and cannot be passed to 'spur agent run', which always starts a subprocess. Run the backing skill directly in the current session, or use '--agent auto' for subprocess dispatch with a tier-resolved executor."
61291
+ message: "'inline' selects in-session execution and cannot be passed to 'spur agent run', which always starts a subprocess. Run the backing skill directly in the current session, or redirect pipeline stages via agent.default / '--agent auto' / '--agent <name>' (ADR-046)."
60813
61292
  };
60814
61293
  }
60815
61294
  return this.resolveExecutorSelector(raw, doctorRunner, "explicit");
@@ -61141,12 +61620,28 @@ function classifyObjectiveFailure(result) {
61141
61620
  }
61142
61621
  return;
61143
61622
  }
61144
- var TRACE_SAFE_SLASH_COMMAND, TRACE_SAFE_SLASH_TOKEN, SENSITIVE_FLAG, SENSITIVE_INLINE_FLAG;
61623
+ var PidObservingProcessExecutor, TRACE_SAFE_SLASH_COMMAND, TRACE_SAFE_SLASH_TOKEN, SENSITIVE_FLAG, SENSITIVE_INLINE_FLAG;
61145
61624
  var init_agent_service = __esm(() => {
61146
61625
  init_src2();
61147
61626
  init_dist9();
61148
61627
  init_dist5();
61149
61628
  init_agent_execution();
61629
+ PidObservingProcessExecutor = class PidObservingProcessExecutor extends NodeProcessExecutor3 {
61630
+ publishPid;
61631
+ constructor(config4, publishPid) {
61632
+ super(config4);
61633
+ this.publishPid = publishPid;
61634
+ }
61635
+ async run(options) {
61636
+ return super.run({
61637
+ ...options,
61638
+ onSpawn: (pid) => {
61639
+ options.onSpawn?.(pid);
61640
+ this.publishPid(pid);
61641
+ }
61642
+ });
61643
+ }
61644
+ };
61150
61645
  TRACE_SAFE_SLASH_COMMAND = /^(?:\/skill:(?:sp|rd3)-|\/(?:sp|rd3)[:-]|\$(?:sp|rd3)-)[A-Za-z0-9._-]+(?:\s|$)/;
61151
61646
  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)$/;
61152
61647
  SENSITIVE_FLAG = /^--?(?:api[-_]?key|authorization|credential|password|secret|token)$/i;
@@ -61154,7 +61649,7 @@ var init_agent_service = __esm(() => {
61154
61649
  });
61155
61650
 
61156
61651
  // ../../packages/app/src/services/corpus-migrator.ts
61157
- import { join as join7, relative } from "path";
61652
+ import { join as join8, relative } from "path";
61158
61653
  function applyM1(data, flags) {
61159
61654
  const raw = data.status;
61160
61655
  if (typeof raw !== "string")
@@ -61454,7 +61949,7 @@ class CorpusMigrator {
61454
61949
  }
61455
61950
  async discoverFiles() {
61456
61951
  const entries = await this.fs.readDir(this.corpusDir);
61457
- return entries.filter((name) => name.endsWith(".md")).filter((name) => name !== "kanban.md").map((name) => join7(this.corpusDir, name)).sort();
61952
+ return entries.filter((name) => name.endsWith(".md")).filter((name) => name !== "kanban.md").map((name) => join8(this.corpusDir, name)).sort();
61458
61953
  }
61459
61954
  async migrateFile(filePath, dryRun, gitDates = new Map) {
61460
61955
  const flags = [];
@@ -61761,7 +62256,7 @@ function normalizeSystemEventPayload(entry, eventPayload, secretValues = []) {
61761
62256
  }
61762
62257
  function redactSecretValue(value, secretValues) {
61763
62258
  if (typeof value === "string")
61764
- return redactAndBound(value, secretValues, MAX_FIELD_LENGTH);
62259
+ return redactAndBound(value, secretValues, MAX_FIELD_LENGTH2);
61765
62260
  if (Array.isArray(value))
61766
62261
  return value.map((item) => redactSecretValue(item, secretValues));
61767
62262
  if (value !== null && typeof value === "object") {
@@ -61775,7 +62270,7 @@ function redactSecretValues(payload, secretValues) {
61775
62270
  }
61776
62271
  return payload;
61777
62272
  }
61778
- var SYSTEM_EVENT_CATALOG, SYSTEM_EVENT_NAMES, SYSTEM_EVENT_PERSISTED_NAMES, SYSTEM_EVENT_STREAMED_NAMES, SYSTEM_EVENT_PREFIXES, SYSTEM_EVENT_DEFAULT_NAMES, SYSTEM_EVENT_DIAGNOSTIC_NAMES, PLANNING_EVENT_NAMES, SYSTEM_EVENT_CATALOG_METADATA, MAX_FIELD_LENGTH = 256;
62273
+ var SYSTEM_EVENT_CATALOG, SYSTEM_EVENT_NAMES, SYSTEM_EVENT_PERSISTED_NAMES, SYSTEM_EVENT_STREAMED_NAMES, SYSTEM_EVENT_PREFIXES, SYSTEM_EVENT_DEFAULT_NAMES, SYSTEM_EVENT_DIAGNOSTIC_NAMES, PLANNING_EVENT_NAMES, SYSTEM_EVENT_CATALOG_METADATA, MAX_FIELD_LENGTH2 = 256;
61779
62274
  var init_event_names = __esm(() => {
61780
62275
  init_agent_execution();
61781
62276
  SYSTEM_EVENT_CATALOG = [
@@ -61999,7 +62494,7 @@ __export(exports_feature_check, {
61999
62494
  FeatureCheckService: () => FeatureCheckService,
62000
62495
  DEFAULT_FEATURE_MATRIX: () => DEFAULT_FEATURE_MATRIX
62001
62496
  });
62002
- import { dirname as dirname8, join as join8 } from "path";
62497
+ import { dirname as dirname8, join as join9 } from "path";
62003
62498
  function isGroupFeature(fm) {
62004
62499
  const tags = fm.tags;
62005
62500
  return Array.isArray(tags) && tags.includes("group") ? "group" : "standard";
@@ -62097,9 +62592,9 @@ function decodeVerdictRows(source, sectionName, required2) {
62097
62592
  function defaultVerdictRunDir(tasksDir) {
62098
62593
  const norm = tasksDir.replace(/\\/g, "/");
62099
62594
  if (/\/docs\/tasks\d*$/.test(norm) || /\/docs\/tasks$/.test(norm)) {
62100
- return join8(dirname8(dirname8(tasksDir)), ".spur", "run");
62595
+ return join9(dirname8(dirname8(tasksDir)), ".spur", "run");
62101
62596
  }
62102
- return join8(dirname8(tasksDir), ".spur", "run");
62597
+ return join9(dirname8(tasksDir), ".spur", "run");
62103
62598
  }
62104
62599
  function rowMatchesScenario(id, sc) {
62105
62600
  const stripped = id.replace(/^\[[^\]]*\]\s*/, "").replace(/^Scenario:\s*/i, "").replace(/^\[[^\]]*\]\s*/, "").trim();
@@ -62198,7 +62693,7 @@ var init_feature_check = __esm(() => {
62198
62693
  await this.checkOneActiveGoal(fm, featureId2, options.featuresDir, findings, options.asStatus);
62199
62694
  await this.checkChildrenLimit(featureId2, options.featuresDir, findings);
62200
62695
  }
62201
- const dogfoodDir = options?.dogfoodDir ?? (options?.featuresDir ? join8(dirname8(options.featuresDir), "dogfood") : undefined);
62696
+ const dogfoodDir = options?.dogfoodDir ?? (options?.featuresDir ? join9(dirname8(options.featuresDir), "dogfood") : undefined);
62202
62697
  const runDir = options?.runDir ?? (options?.tasksDir ? defaultVerdictRunDir(options.tasksDir) : undefined);
62203
62698
  await this.runL4(doc2, featureId2, status, options?.tasksDir, dogfoodDir, runDir, findings);
62204
62699
  return { id: featureId2, ...this.summarizeWithStatus(status, findings, strict, options?.severityOverrides) };
@@ -63057,7 +63552,7 @@ class FeatureService {
63057
63552
  }
63058
63553
  }
63059
63554
  async applyMove(all, movedSet, mapping, affectedTasks, movedCount) {
63060
- const now = new Date().toISOString();
63555
+ const now2 = new Date().toISOString();
63061
63556
  const created = [];
63062
63557
  const removed = [];
63063
63558
  try {
@@ -63068,8 +63563,8 @@ class FeatureService {
63068
63563
  const raw = await this.ctx.fs.readFile(f.filePath);
63069
63564
  const doc2 = MarkdownDocument.parse(raw, "feature");
63070
63565
  doc2.setFrontmatterField("id", `"${newId}"`);
63071
- doc2.setFrontmatterField("updated_at", now);
63072
- appendFeatureHistory(doc2, now, `moved ${f.id} \u2192 ${newId}`);
63566
+ doc2.setFrontmatterField("updated_at", now2);
63567
+ appendFeatureHistory(doc2, now2, `moved ${f.id} \u2192 ${newId}`);
63073
63568
  const slug = basename(f.filePath).replace(/^[A-Z][1-9]*_/, "").replace(/\.md$/, "");
63074
63569
  const newPath = `${this.ctx.featuresDir}/${newId}_${slug}.md`;
63075
63570
  removed.push({ path: f.filePath, content: raw });
@@ -63085,7 +63580,7 @@ class FeatureService {
63085
63580
  const raw = await this.ctx.fs.readFile(task.path);
63086
63581
  const doc2 = MarkdownDocument.parse(raw, "task");
63087
63582
  doc2.setFrontmatterField("feature_id", newFid);
63088
- doc2.setFrontmatterField("updated_at", now);
63583
+ doc2.setFrontmatterField("updated_at", now2);
63089
63584
  removed.push({ path: task.path, content: raw });
63090
63585
  await atomicWriteAsync(task.path, doc2.serialize(), task.wbs, this.ctx.fs, this.ctx.projectName ?? "spur");
63091
63586
  }
@@ -63206,7 +63701,7 @@ class FeatureService {
63206
63701
  throw new Error(`Parent ${parentId} has reached the 9-child limit`);
63207
63702
  }
63208
63703
  templateContent(id, name) {
63209
- const now = new Date().toISOString();
63704
+ const now2 = new Date().toISOString();
63210
63705
  return `---
63211
63706
  schema_version: 1
63212
63707
  id: "${id}"
@@ -63214,8 +63709,8 @@ name: "${name}"
63214
63709
  status: backlog
63215
63710
  priority: P2
63216
63711
  tags: []
63217
- created_at: "${now}"
63218
- updated_at: "${now}"
63712
+ created_at: "${now2}"
63713
+ updated_at: "${now2}"
63219
63714
  ---
63220
63715
 
63221
63716
  # ${id}: ${name}
@@ -63558,10 +64053,10 @@ class PlanningWriteService {
63558
64053
  fromStatus = resolved.from;
63559
64054
  toStatus = resolved.to;
63560
64055
  }
63561
- const now = new Date().toISOString();
63562
- doc2.setFrontmatterField("updated_at", now);
64056
+ const now2 = new Date().toISOString();
64057
+ doc2.setFrontmatterField("updated_at", now2);
63563
64058
  if (statusChanged && fromStatus !== undefined && toStatus !== undefined) {
63564
- appendHistoryLine(doc2, now, fromStatus, toStatus, mutation.actor ?? "system");
64059
+ appendHistoryLine(doc2, now2, fromStatus, toStatus, mutation.actor ?? "system");
63565
64060
  }
63566
64061
  const serialized = doc2.serialize();
63567
64062
  await atomicWriteAsync(ref.filePath, serialized, ref.id, this.fs, this.projectName);
@@ -63569,7 +64064,7 @@ class PlanningWriteService {
63569
64064
  const event2 = {
63570
64065
  event: eventName,
63571
64066
  entity: { kind: domain2, id: ref.id },
63572
- at: now,
64067
+ at: now2,
63573
64068
  ...fromStatus !== undefined ? { from: fromStatus } : {},
63574
64069
  ...toStatus !== undefined ? { to: toStatus } : {}
63575
64070
  };
@@ -63884,17 +64379,17 @@ var init_process_inventory_service = __esm(() => {
63884
64379
  });
63885
64380
 
63886
64381
  // ../../packages/app/src/services/project-registry.ts
63887
- import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync8, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
64382
+ import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
63888
64383
  import { connect, createServer } from "net";
63889
64384
  import { homedir as homedir3 } from "os";
63890
- import { dirname as dirname9, join as join9, resolve } from "path";
64385
+ import { dirname as dirname9, join as join10, resolve } from "path";
63891
64386
  function normalizeProjectPath(pathInput) {
63892
64387
  const trimmed = pathInput.trim();
63893
64388
  let expanded = trimmed;
63894
64389
  if (trimmed === "~") {
63895
64390
  expanded = homedir3();
63896
64391
  } else if (trimmed.startsWith("~/")) {
63897
- expanded = join9(homedir3(), trimmed.slice(2));
64392
+ expanded = join10(homedir3(), trimmed.slice(2));
63898
64393
  } else {
63899
64394
  expanded = resolve(trimmed);
63900
64395
  }
@@ -63954,13 +64449,13 @@ class ProjectRegistry {
63954
64449
  async withLock(fn) {
63955
64450
  const lockParent = dirname9(this.lockDir);
63956
64451
  if (!existsSync5(lockParent)) {
63957
- mkdirSync5(lockParent, { recursive: true });
64452
+ mkdirSync6(lockParent, { recursive: true });
63958
64453
  }
63959
64454
  const maxTries = 50;
63960
64455
  let acquired = false;
63961
64456
  for (let i2 = 0;i2 < maxTries; i2++) {
63962
64457
  try {
63963
- mkdirSync5(this.lockDir);
64458
+ mkdirSync6(this.lockDir);
63964
64459
  acquired = true;
63965
64460
  break;
63966
64461
  } catch {
@@ -63970,7 +64465,7 @@ class ProjectRegistry {
63970
64465
  if (!acquired) {
63971
64466
  try {
63972
64467
  rmSync3(this.lockDir, { recursive: true, force: true });
63973
- mkdirSync5(this.lockDir);
64468
+ mkdirSync6(this.lockDir);
63974
64469
  acquired = true;
63975
64470
  } catch {
63976
64471
  throw new Error(`Failed to acquire lock for project registry: ${this.lockDir}`);
@@ -64001,7 +64496,7 @@ class ProjectRegistry {
64001
64496
  writeRaw(data) {
64002
64497
  const parentDir2 = dirname9(this.filePath);
64003
64498
  if (!existsSync5(parentDir2)) {
64004
- mkdirSync5(parentDir2, { recursive: true });
64499
+ mkdirSync6(parentDir2, { recursive: true });
64005
64500
  }
64006
64501
  const tmpFile = `${this.filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
64007
64502
  const content = JSON.stringify(data, null, 2);
@@ -64275,7 +64770,7 @@ var init_project_start = __esm(() => {
64275
64770
 
64276
64771
  // ../../packages/app/src/services/rule-service.ts
64277
64772
  import { homedir as homedir4 } from "os";
64278
- import { delimiter, join as join10, relative as relative2, resolve as resolve3 } from "path";
64773
+ import { delimiter, join as join11, relative as relative2, resolve as resolve3 } from "path";
64279
64774
 
64280
64775
  class RuleService {
64281
64776
  context;
@@ -64463,13 +64958,13 @@ ${ruleIds.join(`
64463
64958
  const hasGlobalOverride = globalOverride !== undefined && globalOverride.length > 0;
64464
64959
  layers.push({
64465
64960
  id: "global",
64466
- path: hasGlobalOverride ? resolve3(cwd, globalOverride) : join10(homedir4(), GLOBAL_RULES_DIR),
64961
+ path: hasGlobalOverride ? resolve3(cwd, globalOverride) : join11(homedir4(), GLOBAL_RULES_DIR),
64467
64962
  priority: 10
64468
64963
  });
64469
64964
  if (opts.includeBundled && !hasGlobalOverride) {
64470
64965
  const bundledConfig = bundledConfigRoot();
64471
64966
  if (bundledConfig !== null) {
64472
- layers.push({ id: "bundled-config", path: join10(bundledConfig, "rules"), priority: 15 });
64967
+ layers.push({ id: "bundled-config", path: join11(bundledConfig, "rules"), priority: 15 });
64473
64968
  }
64474
64969
  const bundled = await bundledRulesRoot();
64475
64970
  if (bundled !== null)
@@ -64643,7 +65138,7 @@ ${ruleIds.join(`
64643
65138
  const { fs: fs3 } = this.context;
64644
65139
  for (const root of await this.ruleRoots()) {
64645
65140
  for (const ext of ["yaml", "yml", "json"]) {
64646
- if (await fs3.exists(join10(root, `${name}.${ext}`)))
65141
+ if (await fs3.exists(join11(root, `${name}.${ext}`)))
64647
65142
  return true;
64648
65143
  }
64649
65144
  }
@@ -64679,7 +65174,7 @@ ${ruleIds.join(`
64679
65174
  for (const layer of await this.existingRuleSourceLayers()) {
64680
65175
  const entries = await this.context.fs.readDir(layer.path);
64681
65176
  const named = entries.map((entry) => ({ entry, name: entry.match(/^([\w-]+)\.(?:ya?ml|json)$/i)?.[1] ?? "" })).filter(({ name }) => name.length > 0);
64682
- const stats = await Promise.all(named.map(({ entry }) => this.context.fs.stat(join10(layer.path, entry))));
65177
+ const stats = await Promise.all(named.map(({ entry }) => this.context.fs.stat(join11(layer.path, entry))));
64683
65178
  named.forEach(({ name }, i2) => {
64684
65179
  if (stats[i2]?.isFile())
64685
65180
  candidates.add(name);
@@ -64701,7 +65196,7 @@ ${ruleIds.join(`
64701
65196
  for (const layer of layers) {
64702
65197
  for (const file2 of await this.listRuleFilesInLayer(layer.path)) {
64703
65198
  if (!merged.has(file2))
64704
- merged.set(file2, { absolutePath: join10(layer.path, file2), source: layer.id });
65199
+ merged.set(file2, { absolutePath: join11(layer.path, file2), source: layer.id });
64705
65200
  }
64706
65201
  }
64707
65202
  const files = [];
@@ -64769,7 +65264,7 @@ ${ruleIds.join(`
64769
65264
  for (const entry of entries.sort()) {
64770
65265
  if (entry === "presets")
64771
65266
  continue;
64772
- const stat = await this.context.fs.stat(join10(root, entry));
65267
+ const stat = await this.context.fs.stat(join11(root, entry));
64773
65268
  if (stat?.isDirectory())
64774
65269
  dirs.push(entry);
64775
65270
  }
@@ -64777,12 +65272,12 @@ ${ruleIds.join(`
64777
65272
  }
64778
65273
  async listRuleFiles(root, relativeDir) {
64779
65274
  const { fs: fs3 } = this.context;
64780
- const dir = join10(root, relativeDir);
65275
+ const dir = join11(root, relativeDir);
64781
65276
  const entries = await fs3.readDir(dir);
64782
65277
  const files = [];
64783
65278
  for (const entry of entries.sort()) {
64784
- const relativePath2 = relativeDir.length === 0 ? entry : join10(relativeDir, entry);
64785
- const absolutePath = join10(root, relativePath2);
65279
+ const relativePath2 = relativeDir.length === 0 ? entry : join11(relativeDir, entry);
65280
+ const absolutePath = join11(root, relativePath2);
64786
65281
  const stat = await fs3.stat(absolutePath);
64787
65282
  if (stat?.isDirectory()) {
64788
65283
  files.push(...await this.listRuleFiles(root, relativePath2));
@@ -64807,8 +65302,8 @@ var init_rule_service = __esm(() => {
64807
65302
  init_src2();
64808
65303
  init_dist6();
64809
65304
  init_dist10();
64810
- LOCAL_RULES_DIR = join10(".spur", "rules");
64811
- GLOBAL_RULES_DIR = join10(".config", "spur", "rules");
65305
+ LOCAL_RULES_DIR = join11(".spur", "rules");
65306
+ GLOBAL_RULES_DIR = join11(".config", "spur", "rules");
64812
65307
  SEVERITY_RANK2 = {
64813
65308
  info: 0,
64814
65309
  warning: 1,
@@ -64876,7 +65371,7 @@ function summarizeActionResult(resultJson, secretValues = []) {
64876
65371
  return redactValue3(parsed, secretValues);
64877
65372
  }
64878
65373
  function redactString(value, secretValues) {
64879
- return redactAndBound(value, secretValues, MAX_FIELD_LENGTH2);
65374
+ return redactAndBound(value, secretValues, MAX_FIELD_LENGTH3);
64880
65375
  }
64881
65376
  function redactValue3(value, secretValues) {
64882
65377
  if (value === null || value === undefined)
@@ -64999,7 +65494,7 @@ class RunStoreService {
64999
65494
  return { wbs, links, count: links.length };
65000
65495
  }
65001
65496
  }
65002
- var RUN_STORE_LIST_DEFAULT_LIMIT = 50, RUN_STORE_LIST_MAX_LIMIT = 200, RUN_STORE_WBS_DEFAULT_LIMIT = 50, RUN_STORE_WBS_MAX_LIMIT = 200, MAX_FIELD_LENGTH2 = 256, SENSITIVE_KEYS, RunStoreNotFoundError, RunStoreBadCursorError;
65497
+ var RUN_STORE_LIST_DEFAULT_LIMIT = 50, RUN_STORE_LIST_MAX_LIMIT = 200, RUN_STORE_WBS_DEFAULT_LIMIT = 50, RUN_STORE_WBS_MAX_LIMIT = 200, MAX_FIELD_LENGTH3 = 256, SENSITIVE_KEYS, RunStoreNotFoundError, RunStoreBadCursorError;
65003
65498
  var init_run_store_service = __esm(() => {
65004
65499
  init_src2();
65005
65500
  init_agent_execution();
@@ -65442,7 +65937,7 @@ var init_system_event_emitter = __esm(() => {
65442
65937
  });
65443
65938
 
65444
65939
  // ../../packages/app/src/services/task-check.ts
65445
- import { dirname as dirname10, join as join11 } from "path";
65940
+ import { dirname as dirname10, join as join12 } from "path";
65446
65941
  function isPlaceholderBody(body) {
65447
65942
  const stripped = body.replace(/<!--[\s\S]*?-->/g, "").replace(/^\s*>\s*TBD\s*$/gim, "").trim();
65448
65943
  return stripped.length === 0;
@@ -65591,7 +66086,7 @@ var init_task_check = __esm(() => {
65591
66086
  this.runL2(doc2, entry, findings);
65592
66087
  this.runL3(doc2, entry, status, findings);
65593
66088
  const tasksDir = dirname10(filePath);
65594
- const featuresDir = join11(dirname10(tasksDir), "features");
66089
+ const featuresDir = join12(dirname10(tasksDir), "features");
65595
66090
  await this.runL4(doc2, fm, status, findings, featuresDir, tasksDir);
65596
66091
  await this.runL4Rollup(doc2, wbs, status, findings, tasksDir);
65597
66092
  if (status !== "done" && status !== "cancelled") {
@@ -65987,7 +66482,7 @@ var init_task_check = __esm(() => {
65987
66482
  for (const cite of citations) {
65988
66483
  if (reported >= 5)
65989
66484
  break;
65990
- const abs = join11(projectRoot, cite.path);
66485
+ const abs = join12(projectRoot, cite.path);
65991
66486
  let exists2 = false;
65992
66487
  try {
65993
66488
  exists2 = await this.fs.exists(abs);
@@ -66530,7 +67025,7 @@ class TaskService {
66530
67025
  }
66531
67026
  async findDuplicateFollowUp(featureId2, title, withinSec) {
66532
67027
  const siblings = await this.list({ featureId: featureId2 });
66533
- const now = Date.now();
67028
+ const now2 = Date.now();
66534
67029
  const lowerTitle = title.toLowerCase();
66535
67030
  for (const t of siblings) {
66536
67031
  if ((t.name ?? "").toLowerCase() !== lowerTitle)
@@ -66541,7 +67036,7 @@ class TaskService {
66541
67036
  const createdMs = Date.parse(createdAt);
66542
67037
  if (Number.isNaN(createdMs))
66543
67038
  continue;
66544
- const ageSec = (now - createdMs) / 1000;
67039
+ const ageSec = (now2 - createdMs) / 1000;
66545
67040
  if (ageSec >= 0 && ageSec <= withinSec) {
66546
67041
  return { wbs: t.wbs, name: t.name };
66547
67042
  }
@@ -66566,7 +67061,7 @@ class TaskService {
66566
67061
  }
66567
67062
  const slug = this.slugify(params.title);
66568
67063
  const { wbs, filePath } = await this.allocateWbsChecked(slug);
66569
- const now = new Date().toISOString();
67064
+ const now2 = new Date().toISOString();
66570
67065
  const rawTemplate = this.ctx.resolveTemplate?.(variant);
66571
67066
  if (rawTemplate !== undefined) {
66572
67067
  const content2 = renderCreatedTaskContent({
@@ -66574,7 +67069,7 @@ class TaskService {
66574
67069
  name: params.title,
66575
67070
  wbs,
66576
67071
  background,
66577
- createdAt: now,
67072
+ createdAt: now2,
66578
67073
  status,
66579
67074
  variant,
66580
67075
  featureId: params.featureId,
@@ -66588,8 +67083,8 @@ class TaskService {
66588
67083
  `name: "${params.title}"`,
66589
67084
  `status: ${status}`,
66590
67085
  `template: ${variant}`,
66591
- `created_at: ${now}`,
66592
- `updated_at: ${now}`,
67086
+ `created_at: ${now2}`,
67087
+ `updated_at: ${now2}`,
66593
67088
  params.featureId !== undefined ? `feature_id: ${params.featureId}` : null,
66594
67089
  params.parentWbs !== undefined ? `parent_wbs: "${params.parentWbs}"` : null
66595
67090
  ].filter(Boolean).join(`
@@ -66970,7 +67465,7 @@ ${issues}`);
66970
67465
  return this.writeService.createAllocated(folder, async () => {
66971
67466
  const slug = this.slugify(item.name);
66972
67467
  const { wbs, filePath } = await this.allocateWbsChecked(slug);
66973
- const now = new Date().toISOString();
67468
+ const now2 = new Date().toISOString();
66974
67469
  const rawTemplate = this.ctx.resolveTemplate?.(variant);
66975
67470
  if (rawTemplate !== undefined) {
66976
67471
  const content2 = renderCreatedTaskContent({
@@ -66978,7 +67473,7 @@ ${issues}`);
66978
67473
  name: item.name,
66979
67474
  wbs,
66980
67475
  background,
66981
- createdAt: now,
67476
+ createdAt: now2,
66982
67477
  status,
66983
67478
  variant,
66984
67479
  featureId: item.feature_id ?? undefined,
@@ -66998,8 +67493,8 @@ ${issues}`);
66998
67493
  `name: "${item.name}"`,
66999
67494
  `status: ${status}`,
67000
67495
  `template: ${variant}`,
67001
- `created_at: ${now}`,
67002
- `updated_at: ${now}`,
67496
+ `created_at: ${now2}`,
67497
+ `updated_at: ${now2}`,
67003
67498
  item.feature_id !== undefined ? `feature_id: ${item.feature_id}` : null,
67004
67499
  item.parent_wbs !== undefined ? `parent_wbs: "${item.parent_wbs}"` : null,
67005
67500
  item.priority !== undefined ? `priority: ${item.priority}` : null,
@@ -67523,7 +68018,7 @@ var init_task_verdict = __esm(() => {
67523
68018
  });
67524
68019
 
67525
68020
  // ../../packages/app/src/services/team-service.ts
67526
- import { join as join12 } from "path";
68021
+ import { join as join13 } from "path";
67527
68022
 
67528
68023
  class TeamService {
67529
68024
  ctx;
@@ -67531,7 +68026,7 @@ class TeamService {
67531
68026
  orchestratorPromise;
67532
68027
  constructor(ctx) {
67533
68028
  this.ctx = ctx;
67534
- this.configDir = join12(ctx.cwd, ".spur", "agents");
68029
+ this.configDir = join13(ctx.cwd, ".spur", "agents");
67535
68030
  }
67536
68031
  async sendMessage(fromId, toId, body, replyTo) {
67537
68032
  validateAgentId(toId);
@@ -67941,7 +68436,7 @@ class TeamService {
67941
68436
  async resolveTaskFile(taskId) {
67942
68437
  const fs3 = this.ctx.fs;
67943
68438
  const { foldersConfig } = await resolvePlanningFolders(fs3);
67944
- const dirs = [...new Set([foldersConfig.active_folder, ...Object.keys(foldersConfig.folders)])].map((dir) => join12(this.ctx.cwd, dir));
68439
+ const dirs = [...new Set([foldersConfig.active_folder, ...Object.keys(foldersConfig.folders)])].map((dir) => join13(this.ctx.cwd, dir));
67945
68440
  return await TaskLocator.forDirs(fs3, dirs).findPathByWbs(taskId);
67946
68441
  }
67947
68442
  }
@@ -67977,8 +68472,8 @@ var init_team_service = __esm(() => {
67977
68472
  });
67978
68473
 
67979
68474
  // ../../packages/app/src/services/token-ledger-service.ts
67980
- import { closeSync as closeSync2, existsSync as existsSync7, fstatSync, openSync as openSync2, readSync } from "fs";
67981
- import { join as join13 } from "path";
68475
+ import { closeSync as closeSync3, existsSync as existsSync7, fstatSync, openSync as openSync3, readSync } from "fs";
68476
+ import { join as join14 } from "path";
67982
68477
  function isSparseToolActivity(events2) {
67983
68478
  return events2.length === 0 || !events2.some((e) => TOOL_ACTIVITY_TYPES.has(e.type));
67984
68479
  }
@@ -68033,7 +68528,7 @@ function tailTokenLedgerFile(filePath, limit, chunkSize = DEFAULT_CHUNK, before)
68033
68528
  return { events: [], truncated: false };
68034
68529
  }
68035
68530
  const target = limit + 1;
68036
- const fd = openSync2(filePath, "r");
68531
+ const fd = openSync3(filePath, "r");
68037
68532
  try {
68038
68533
  const { size } = fstatSync(fd);
68039
68534
  if (size === 0)
@@ -68071,7 +68566,7 @@ function tailTokenLedgerFile(filePath, limit, chunkSize = DEFAULT_CHUNK, before)
68071
68566
  truncated
68072
68567
  };
68073
68568
  } finally {
68074
- closeSync2(fd);
68569
+ closeSync3(fd);
68075
68570
  }
68076
68571
  }
68077
68572
 
@@ -68079,7 +68574,7 @@ class TokenLedgerService {
68079
68574
  ledgerPath;
68080
68575
  chunkSize;
68081
68576
  constructor(options) {
68082
- this.ledgerPath = options.ledgerPath ?? join13(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
68577
+ this.ledgerPath = options.ledgerPath ?? join14(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
68083
68578
  this.chunkSize = options.chunkSize ?? DEFAULT_CHUNK;
68084
68579
  }
68085
68580
  get path() {
@@ -68120,12 +68615,12 @@ class TokenLedgerService {
68120
68615
  var TOOL_ACTIVITY_TYPES, TOKEN_LEDGER_DEFAULT_LIMIT = 200, TOKEN_LEDGER_MAX_LIMIT = 1000, TOKEN_LEDGER_RELATIVE_PATH, DEFAULT_CHUNK;
68121
68616
  var init_token_ledger_service = __esm(() => {
68122
68617
  TOOL_ACTIVITY_TYPES = new Set(["read", "write", "bash", "grep", "glob"]);
68123
- TOKEN_LEDGER_RELATIVE_PATH = join13(".spur", "context", "token-ledger.jsonl");
68618
+ TOKEN_LEDGER_RELATIVE_PATH = join14(".spur", "context", "token-ledger.jsonl");
68124
68619
  DEFAULT_CHUNK = 64 * 1024;
68125
68620
  });
68126
68621
 
68127
68622
  // ../../packages/app/src/services/token-ledger-watcher.ts
68128
- import { closeSync as closeSync3, existsSync as existsSync8, fstatSync as fstatSync2, openSync as openSync3, readSync as readSync2, watch } from "fs";
68623
+ import { closeSync as closeSync4, existsSync as existsSync8, fstatSync as fstatSync2, openSync as openSync4, readSync as readSync2, watch } from "fs";
68129
68624
 
68130
68625
  class TokenLedgerWatcher {
68131
68626
  ledgerPath;
@@ -68184,11 +68679,11 @@ class TokenLedgerWatcher {
68184
68679
  if (!existsSync8(this.ledgerPath))
68185
68680
  return 0;
68186
68681
  try {
68187
- const fd = openSync3(this.ledgerPath, "r");
68682
+ const fd = openSync4(this.ledgerPath, "r");
68188
68683
  try {
68189
68684
  return fstatSync2(fd).size;
68190
68685
  } finally {
68191
- closeSync3(fd);
68686
+ closeSync4(fd);
68192
68687
  }
68193
68688
  } catch {
68194
68689
  return 0;
@@ -68210,7 +68705,7 @@ class TokenLedgerWatcher {
68210
68705
  }
68211
68706
  let size;
68212
68707
  try {
68213
- const fd = openSync3(this.ledgerPath, "r");
68708
+ const fd = openSync4(this.ledgerPath, "r");
68214
68709
  try {
68215
68710
  size = fstatSync2(fd).size;
68216
68711
  if (size < this.offset) {
@@ -68238,7 +68733,7 @@ class TokenLedgerWatcher {
68238
68733
  }
68239
68734
  }
68240
68735
  } finally {
68241
- closeSync3(fd);
68736
+ closeSync4(fd);
68242
68737
  }
68243
68738
  } catch {}
68244
68739
  }
@@ -68247,110 +68742,6 @@ var init_token_ledger_watcher = __esm(() => {
68247
68742
  init_token_ledger_service();
68248
68743
  });
68249
68744
 
68250
- // ../../packages/app/src/observability/run-output-sink.ts
68251
- import { closeSync as closeSync4, mkdirSync as mkdirSync6, openSync as openSync4, writeSync as writeSync2 } from "fs";
68252
- import { join as join14 } from "path";
68253
-
68254
- class RunOutputSink {
68255
- filePath;
68256
- maxBytes;
68257
- maxLines;
68258
- fd;
68259
- bytes = 0;
68260
- lines = 0;
68261
- truncated = false;
68262
- closed = false;
68263
- constructor(options) {
68264
- this.filePath = join14(options.dir, `${options.runId}-output.log`);
68265
- this.maxBytes = options.maxBytes ?? DEFAULT_OUTPUT_MAX_BYTES;
68266
- this.maxLines = options.maxLines;
68267
- try {
68268
- mkdirSync6(options.dir, { recursive: true });
68269
- this.fd = openSync4(this.filePath, "a");
68270
- } catch {
68271
- this.fd = undefined;
68272
- }
68273
- }
68274
- get isTruncated() {
68275
- return this.truncated;
68276
- }
68277
- observe(event2) {
68278
- if (this.fd === undefined || this.closed)
68279
- return;
68280
- switch (event2.kind) {
68281
- case "output":
68282
- this.appendChunk(event2.at, event2.stream, event2.chunk);
68283
- break;
68284
- case "started":
68285
- this.append(`# agent output \u2014 run ${event2.runId} \u2014 ${event2.agent} \u2014 ${event2.at}
68286
- `);
68287
- this.append(`# invocation: ${event2.invocation}
68288
- `);
68289
- break;
68290
- case "dropped":
68291
- this.append(`
68292
- === [dropped] ${event2.chunks} chunk(s) discarded by the lifecycle relay under backpressure ===
68293
- `);
68294
- break;
68295
- case "finished":
68296
- this.append(`
68297
- === run ${event2.outcome} (exit ${event2.exitCode}) after ${event2.durationMs}ms ===
68298
- `);
68299
- break;
68300
- default:
68301
- break;
68302
- }
68303
- }
68304
- close() {
68305
- if (this.closed)
68306
- return;
68307
- this.closed = true;
68308
- if (this.fd !== undefined) {
68309
- try {
68310
- closeSync4(this.fd);
68311
- } catch {}
68312
- this.fd = undefined;
68313
- }
68314
- }
68315
- appendChunk(at, stream, chunk) {
68316
- if (this.truncated)
68317
- return;
68318
- const text4 = `[${at}] ${stream}: ${chunk}
68319
- `;
68320
- const chunkBytes = Buffer.byteLength(text4);
68321
- const chunkLines = countNewlines(text4);
68322
- if (this.bytes + chunkBytes > this.maxBytes || this.maxLines !== undefined && this.lines + chunkLines > this.maxLines) {
68323
- this.truncated = true;
68324
- this.append(TRUNCATION_MARKER);
68325
- return;
68326
- }
68327
- this.append(text4);
68328
- }
68329
- append(text4) {
68330
- if (this.fd === undefined || this.closed)
68331
- return;
68332
- try {
68333
- writeSync2(this.fd, text4);
68334
- this.bytes += Buffer.byteLength(text4);
68335
- this.lines += countNewlines(text4);
68336
- } catch {}
68337
- }
68338
- }
68339
- function countNewlines(text4) {
68340
- let count3 = 0;
68341
- for (let i2 = 0;i2 < text4.length; i2 += 1) {
68342
- if (text4.charCodeAt(i2) === 10)
68343
- count3 += 1;
68344
- }
68345
- return count3;
68346
- }
68347
- var DEFAULT_OUTPUT_MAX_BYTES, TRUNCATION_MARKER = `
68348
- === [truncated] agent output capture reached its configured bound; further chunks were not written ===
68349
- `;
68350
- var init_run_output_sink = __esm(() => {
68351
- DEFAULT_OUTPUT_MAX_BYTES = 1024 * 1024;
68352
- });
68353
-
68354
68745
  // ../../packages/app/src/workflow/steering.ts
68355
68746
  class WorkflowSteeringController {
68356
68747
  onAck;
@@ -68598,13 +68989,11 @@ import { dirname as dirname12, isAbsolute as isAbsolute2, join as join15 } from
68598
68989
  class AgentRunActionRunner {
68599
68990
  observabilityBus;
68600
68991
  steeringController;
68601
- outputLog;
68602
68992
  kind = KIND;
68603
68993
  agentService;
68604
- constructor(agentService, observabilityBus, steeringController, outputLog) {
68994
+ constructor(agentService, observabilityBus, steeringController) {
68605
68995
  this.observabilityBus = observabilityBus;
68606
68996
  this.steeringController = steeringController;
68607
- this.outputLog = outputLog;
68608
68997
  this.agentService = agentService;
68609
68998
  }
68610
68999
  async execute(options, context4) {
@@ -68646,17 +69035,10 @@ class AgentRunActionRunner {
68646
69035
  flags.continue = continueFlag;
68647
69036
  const answerFile = asOptionalString(options.answerFile);
68648
69037
  const expectFile = asOptionalString(options.expectFile);
69038
+ const requireDiff = asOptionalBoolean(options.requireDiff);
68649
69039
  const capture = asOptionalBoolean(options.capture) || answerFile !== undefined;
68650
69040
  const agentLabel = agent ?? "<default>";
68651
- const outputLog = this.outputLog;
68652
- const sink = outputLog === undefined ? undefined : new RunOutputSink({
68653
- dir: join15(cwd, ".spur", "run"),
68654
- runId: context4.runId,
68655
- ...outputLog.maxBytes !== undefined ? { maxBytes: outputLog.maxBytes } : {},
68656
- ...outputLog.maxLines !== undefined ? { maxLines: outputLog.maxLines } : {}
68657
- });
68658
- const observer = this.observabilityBus === undefined && sink === undefined ? undefined : (event2) => {
68659
- sink?.observe(event2);
69041
+ const observer = this.observabilityBus === undefined ? undefined : (event2) => {
68660
69042
  this.observabilityBus?.emit("workflow.agent", event2);
68661
69043
  };
68662
69044
  const actionId = context4.actionId ?? `${context4.runId}:${context4.stateOrNodeId}`;
@@ -68725,11 +69107,19 @@ class AgentRunActionRunner {
68725
69107
  };
68726
69108
  }
68727
69109
  }
69110
+ const stepLabel = context4.stateOrNodeId;
69111
+ if (ok && requireDiff === true && !await gitHasNonCorpusChanges(cwd)) {
69112
+ return {
69113
+ ok: false,
69114
+ data: buildResultData(exitCode, agentLabel, capture, answer, invocation),
69115
+ error: `agent.run '${stepLabel}' (${agentLabel}) exited 0 but produced zero non-corpus file changes \u2014 empty implement (no-op). The implement agent must change at least one file outside docs/tasks3|docs/features; fix the implement input and re-run the pipeline.`
69116
+ };
69117
+ }
68728
69118
  if (!ok) {
68729
69119
  await writePartialWorkArtifact(context4, agentLabel, model, traced, cwd);
68730
69120
  }
68731
- const stepLabel = context4.stateOrNodeId;
68732
- const error51 = ok ? undefined : traced.signal !== undefined ? timeoutMs !== undefined ? `agent.run '${stepLabel}' (${agentLabel}) terminated by signal ${traced.signal} (configured timeout: ${timeoutMs}ms; timeout or cancellation); see partial-work artifact` : `agent.run '${stepLabel}' (${agentLabel}) was cancelled by signal ${traced.signal}; see partial-work artifact` : traced.message !== undefined ? `agent.run '${stepLabel}' (${agentLabel}) dispatch failed: ${traced.message}` : `agent.run '${stepLabel}' (${agentLabel}) exited with code ${exitCode}`;
69121
+ const partialWorkHint = `partial work (if any) preserved at .spur/run/${context4.runId}-${stepLabel}-partial.md; resume from that tree per the timed-out-implement runbook (plugins/sp/skills/spur-dev/references/execution-workflow.md)`;
69122
+ const error51 = ok ? undefined : traced.signal !== undefined ? timeoutMs !== undefined ? `agent.run '${stepLabel}' (${agentLabel}) terminated by signal ${traced.signal} (configured timeout: ${timeoutMs}ms; timeout or cancellation); ${partialWorkHint}` : `agent.run '${stepLabel}' (${agentLabel}) was cancelled by signal ${traced.signal}; ${partialWorkHint}` : traced.message !== undefined ? `agent.run '${stepLabel}' (${agentLabel}) dispatch failed: ${traced.message}` : `agent.run '${stepLabel}' (${agentLabel}) exited with code ${exitCode}; ${partialWorkHint}`;
68733
69123
  return {
68734
69124
  ok,
68735
69125
  data: buildResultData(exitCode, agentLabel, capture, answer, invocation),
@@ -68739,9 +69129,7 @@ class AgentRunActionRunner {
68739
69129
  ...steeringNote !== undefined ? { __steeringNote: steeringNote } : {}
68740
69130
  } : undefined
68741
69131
  };
68742
- } finally {
68743
- sink?.close();
68744
- }
69132
+ } finally {}
68745
69133
  }
68746
69134
  }
68747
69135
  function buildResultData(exitCode, agentLabel, capture, answer, invocation) {
@@ -68848,6 +69236,21 @@ async function gitDiffStat(cwd) {
68848
69236
  return "";
68849
69237
  }
68850
69238
  }
69239
+ async function gitHasNonCorpusChanges(cwd) {
69240
+ try {
69241
+ const result = await new NodeProcessExecutor3().run({
69242
+ command: "git",
69243
+ args: ["status", "--porcelain", "--", ".", ":(exclude)docs/tasks3/*", ":(exclude)docs/features/*"],
69244
+ cwd,
69245
+ maxOutput: 1024 * 1024,
69246
+ forceBuffered: true,
69247
+ rejectOnError: false
69248
+ });
69249
+ return result.exitCode === 0 && result.stdout.trim() !== "";
69250
+ } catch {
69251
+ return false;
69252
+ }
69253
+ }
68851
69254
  function tail(text4, maxChars) {
68852
69255
  if (text4.length <= maxChars)
68853
69256
  return text4;
@@ -68857,7 +69260,6 @@ ${text4.slice(text4.length - maxChars)}`;
68857
69260
  var PARTIAL_ARTIFACT_TAIL_CHARS = 4000, KIND = "agent.run";
68858
69261
  var init_agent_run = __esm(() => {
68859
69262
  init_dist5();
68860
- init_run_output_sink();
68861
69263
  init_steering();
68862
69264
  });
68863
69265
 
@@ -69383,10 +69785,179 @@ var init_rule_check = __esm(() => {
69383
69785
  init_utils3();
69384
69786
  });
69385
69787
 
69788
+ // ../../packages/app/src/workflow/actions/shell.ts
69789
+ function stringOption2(options, key, fallback) {
69790
+ const value = options[key];
69791
+ if (typeof value === "string")
69792
+ return value;
69793
+ if (fallback !== undefined)
69794
+ return fallback;
69795
+ throw new Error(`Action option "${key}" must be a string`);
69796
+ }
69797
+ function arrayOption2(options, key) {
69798
+ const value = options[key];
69799
+ if (value === undefined)
69800
+ return [];
69801
+ if (Array.isArray(value) && value.every((entry) => typeof entry === "string"))
69802
+ return value;
69803
+ throw new Error(`Action option "${key}" must be a string array`);
69804
+ }
69805
+
69806
+ class StreamingShellActionRunner {
69807
+ processExecutor;
69808
+ observabilityBus;
69809
+ kind = KIND11;
69810
+ constructor(processExecutor, observabilityBus) {
69811
+ this.processExecutor = processExecutor;
69812
+ this.observabilityBus = observabilityBus;
69813
+ }
69814
+ async execute(options, context4) {
69815
+ const command = stringOption2(options, "command");
69816
+ const explicitArgs = arrayOption2(options, "args");
69817
+ const usesShell = explicitArgs.length === 0;
69818
+ const spawn2 = usesShell ? { command: "/bin/sh", args: ["-c", command] } : { command, args: explicitArgs };
69819
+ const cwd = stringOption2(options, "cwd", context4.workdir);
69820
+ const env = {};
69821
+ for (const [key, value] of Object.entries({ ...process.env, ...context4.vars })) {
69822
+ if (value !== undefined)
69823
+ env[key] = value;
69824
+ }
69825
+ const pipe2 = this.processExecutor.runStreaming({
69826
+ command: spawn2.command,
69827
+ args: spawn2.args,
69828
+ ...cwd !== undefined ? { cwd } : {},
69829
+ env
69830
+ });
69831
+ let stdout = "";
69832
+ let stderr = "";
69833
+ const readers = [];
69834
+ const consume = (stream, readable2) => {
69835
+ if (readable2 === null)
69836
+ return;
69837
+ const reader = readable2.getReader();
69838
+ const decoder = new TextDecoder;
69839
+ readers.push((async () => {
69840
+ for (;; ) {
69841
+ const { done, value } = await reader.read();
69842
+ if (done)
69843
+ break;
69844
+ const chunk = decoder.decode(value, { stream: true });
69845
+ if (chunk === "")
69846
+ continue;
69847
+ if (stream === "stdout")
69848
+ stdout += chunk;
69849
+ else
69850
+ stderr += chunk;
69851
+ if (this.observabilityBus !== undefined) {
69852
+ const event2 = {
69853
+ schemaVersion: 1,
69854
+ eventId: crypto.randomUUID(),
69855
+ sequence: 0,
69856
+ runId: context4.runId,
69857
+ at: new Date().toISOString(),
69858
+ kind: KIND11,
69859
+ node: context4.stateOrNodeId,
69860
+ stream,
69861
+ chunk: bounded(chunk)
69862
+ };
69863
+ this.observabilityBus.emit("workflow.action.output", event2);
69864
+ }
69865
+ }
69866
+ const tail2 = decoder.decode();
69867
+ if (tail2 !== "") {
69868
+ if (stream === "stdout")
69869
+ stdout += tail2;
69870
+ else
69871
+ stderr += tail2;
69872
+ if (this.observabilityBus !== undefined) {
69873
+ this.observabilityBus.emit("workflow.action.output", {
69874
+ schemaVersion: 1,
69875
+ eventId: crypto.randomUUID(),
69876
+ sequence: 0,
69877
+ runId: context4.runId,
69878
+ at: new Date().toISOString(),
69879
+ kind: KIND11,
69880
+ node: context4.stateOrNodeId,
69881
+ stream,
69882
+ chunk: bounded(tail2)
69883
+ });
69884
+ }
69885
+ }
69886
+ })());
69887
+ };
69888
+ consume("stdout", pipe2.stdout);
69889
+ consume("stderr", pipe2.stderr);
69890
+ const exitCode = await pipe2.exited;
69891
+ await Promise.allSettled(readers);
69892
+ return {
69893
+ ok: exitCode === 0,
69894
+ data: { stdout, stderr, exitCode },
69895
+ ...exitCode === 0 ? {} : { error: `Command "${command}" exited with ${exitCode}` }
69896
+ };
69897
+ }
69898
+ }
69899
+ var KIND11 = "shell";
69900
+ var init_shell = __esm(() => {
69901
+ init_observability();
69902
+ });
69903
+
69904
+ // ../../packages/app/src/workflow/guards/shell.ts
69905
+ function stringOption3(options, key, fallback) {
69906
+ const value = options[key];
69907
+ if (typeof value === "string")
69908
+ return value;
69909
+ if (fallback !== undefined)
69910
+ return fallback;
69911
+ throw new Error(`Guard option "${key}" must be a string`);
69912
+ }
69913
+ function arrayOption3(options, key) {
69914
+ const value = options[key];
69915
+ if (value === undefined)
69916
+ return [];
69917
+ if (Array.isArray(value) && value.every((entry) => typeof entry === "string"))
69918
+ return value;
69919
+ throw new Error(`Guard option "${key}" must be a string array`);
69920
+ }
69921
+
69922
+ class EnvShellGuardRunner {
69923
+ processExecutor;
69924
+ kind = KIND12;
69925
+ constructor(processExecutor) {
69926
+ this.processExecutor = processExecutor;
69927
+ }
69928
+ async evaluate(options, context4) {
69929
+ const command = stringOption3(options, "command");
69930
+ const explicitArgs = arrayOption3(options, "args");
69931
+ const usesShell = explicitArgs.length === 0;
69932
+ const spawn2 = usesShell ? { command: "/bin/sh", args: ["-c", command] } : { command, args: explicitArgs };
69933
+ const cwd = options.cwd === undefined ? context4.workdir : stringOption3(options, "cwd");
69934
+ const env = {};
69935
+ for (const [key, value] of Object.entries({ ...process.env, ...context4.vars })) {
69936
+ if (value !== undefined)
69937
+ env[key] = String(value);
69938
+ }
69939
+ const result = await this.processExecutor.run({
69940
+ command: spawn2.command,
69941
+ args: spawn2.args,
69942
+ ...cwd !== undefined ? { cwd } : {},
69943
+ env,
69944
+ rejectOnError: false,
69945
+ forceBuffered: true
69946
+ });
69947
+ return {
69948
+ passed: result.exitCode === 0,
69949
+ report: { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode }
69950
+ };
69951
+ }
69952
+ }
69953
+ var KIND12 = "shell";
69954
+
69386
69955
  // ../../packages/app/src/workflow/builtins.ts
69387
69956
  function registerSpurBuiltins(host, options) {
69388
69957
  const fileSystem = options.fileSystem ?? createNodeFileSystem3();
69389
- host.registerAction(new AgentRunActionRunner(options.agentService, options.observabilityBus, options.steeringController, options.outputLog), "builtin");
69958
+ host.registerAction(new AgentRunActionRunner(options.agentService, options.observabilityBus, options.steeringController), "builtin");
69959
+ host.registerAction(new StreamingShellActionRunner(options.processExecutor ?? new NodeProcessExecutor3, options.observabilityBus), "builtin");
69960
+ host.registerGuard(new EnvShellGuardRunner(options.processExecutor ?? new NodeProcessExecutor3), "builtin");
69390
69961
  host.registerAction(new RuleCheckActionRunner(options.ruleService), "builtin");
69391
69962
  host.registerAction(new FileExistsActionRunner(fileSystem), "builtin");
69392
69963
  host.registerAction(new FileReadActionRunner(fileSystem), "builtin");
@@ -69409,159 +69980,7 @@ var init_builtins2 = __esm(() => {
69409
69980
  init_file_read_into_var();
69410
69981
  init_http_request();
69411
69982
  init_rule_check();
69412
- });
69413
-
69414
- // ../../packages/app/src/workflow/observability.ts
69415
- function bounded(value) {
69416
- const redacted = value.replace(SECRET_PATTERN2, "[REDACTED]");
69417
- return redacted.length <= MAX_FIELD_LENGTH3 ? redacted : `${redacted.slice(0, MAX_FIELD_LENGTH3)}\u2026`;
69418
- }
69419
- function projectActionMetadata(kind, options) {
69420
- if (options === undefined)
69421
- return;
69422
- const metadata = {};
69423
- if (typeof options.agent === "string" && options.agent !== "")
69424
- metadata.agent = bounded(options.agent);
69425
- if (typeof options.model === "string" && options.model !== "")
69426
- metadata.model = bounded(options.model);
69427
- if (typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs)) {
69428
- metadata.timeoutMs = Math.max(0, options.timeoutMs);
69429
- }
69430
- const input = typeof options.input === "string" ? options.input.trim() : "";
69431
- if (kind === "agent.run" && input !== "") {
69432
- const command = input.startsWith("/") ? input.split(/\s+/, 1)[0] : undefined;
69433
- metadata.invocation = command === undefined ? `[prompt ${input.length} chars]` : bounded(command);
69434
- } else if (kind === "shell" && typeof options.command === "string") {
69435
- metadata.invocation = "[shell command redacted]";
69436
- }
69437
- return Object.keys(metadata).length === 0 ? undefined : metadata;
69438
- }
69439
- function projectResult(result) {
69440
- if (result === undefined)
69441
- return;
69442
- if (typeof result !== "object" || result === null)
69443
- return { usage: "unavailable" };
69444
- const error51 = "error" in result && typeof result.error === "string" ? bounded(result.error) : undefined;
69445
- return { ...error51 !== undefined ? { error: error51 } : {}, usage: "unavailable" };
69446
- }
69447
-
69448
- class ObservableWorkflowAdapter {
69449
- inner;
69450
- bus;
69451
- sequences = new Map;
69452
- workflowNames = new Map;
69453
- actions = new Map;
69454
- constructor(inner, bus) {
69455
- this.inner = inner;
69456
- this.bus = bus;
69457
- }
69458
- async createRun(record2) {
69459
- await this.inner.createRun(record2);
69460
- this.workflowNames.set(record2.id, record2.workflow_name);
69461
- await this.bus.emit("workflow.run.started", {
69462
- ...this.envelope(record2.id),
69463
- workflowName: record2.workflow_name
69464
- });
69465
- }
69466
- async finalizeRun(runId, status, completedAt) {
69467
- await this.inner.finalizeRun(runId, status, completedAt);
69468
- await this.bus.emit("workflow.run.finalized", { ...this.envelope(runId, completedAt), status });
69469
- }
69470
- async savePhase(runId, phase, status) {
69471
- await this.inner.savePhase(runId, phase, status);
69472
- await this.bus.emit("workflow.phase", { ...this.envelope(runId), phase, status });
69473
- }
69474
- async saveTransition(runId, from, to, trigger) {
69475
- await this.inner.saveTransition(runId, from, to, trigger);
69476
- await this.bus.emit("workflow.transition", { ...this.envelope(runId), from, to, trigger });
69477
- }
69478
- async commitTransition(runId, from, to, trigger, _state, _data, phase) {
69479
- await this.inner.commitTransition(runId, from, to, trigger, _state, _data, phase);
69480
- await this.bus.emit("workflow.transition", { ...this.envelope(runId), from, to, trigger });
69481
- if (phase) {
69482
- await this.bus.emit("workflow.phase", {
69483
- ...this.envelope(runId),
69484
- phase: phase.phase,
69485
- status: phase.status
69486
- });
69487
- }
69488
- }
69489
- async saveActionStart(runId, node, kind, options) {
69490
- const actionId = await this.inner.saveActionStart(runId, node, kind, options);
69491
- this.actions.set(actionId, { runId, node, kind });
69492
- const metadata = projectActionMetadata(kind, options);
69493
- await this.bus.emit("workflow.action.started", {
69494
- ...this.envelope(runId),
69495
- actionId,
69496
- node,
69497
- kind,
69498
- ...metadata !== undefined ? { metadata } : {}
69499
- });
69500
- return actionId;
69501
- }
69502
- async saveActionFinalize(actionId, status, durationMs, ok, result, redactor) {
69503
- await this.inner.saveActionFinalize(actionId, status, durationMs, ok, result, redactor);
69504
- const action = this.actions.get(actionId);
69505
- if (action === undefined) {
69506
- return;
69507
- }
69508
- this.actions.delete(actionId);
69509
- const projected = projectResult(result);
69510
- await this.bus.emit("workflow.action.finished", {
69511
- ...this.envelope(action.runId),
69512
- actionId,
69513
- status,
69514
- durationMs,
69515
- ok,
69516
- node: action.node,
69517
- kind: action.kind,
69518
- ...projected !== undefined ? { result: projected } : {}
69519
- });
69520
- }
69521
- envelope(runId, at = now()) {
69522
- const sequence = (this.sequences.get(runId) ?? 0) + 1;
69523
- this.sequences.set(runId, sequence);
69524
- const workflowName = this.workflowNames.get(runId);
69525
- return {
69526
- schemaVersion: 1,
69527
- eventId: crypto.randomUUID(),
69528
- sequence,
69529
- runId,
69530
- ...workflowName !== undefined ? { workflowName } : {},
69531
- at
69532
- };
69533
- }
69534
- saveWorkflowState(runId, state, data) {
69535
- return this.inner.saveWorkflowState(runId, state, data);
69536
- }
69537
- loadRun(runId) {
69538
- return this.inner.loadRun(runId);
69539
- }
69540
- listRuns() {
69541
- return this.inner.listRuns();
69542
- }
69543
- findRunByKey(workflowName, externalKey) {
69544
- return this.inner.findRunByKey(workflowName, externalKey);
69545
- }
69546
- createOrAttachRun(record2) {
69547
- return this.inner.createOrAttachRun(record2);
69548
- }
69549
- reseedRun(runId, newState) {
69550
- return this.inner.reseedRun(runId, newState);
69551
- }
69552
- loadCurrentState(runId) {
69553
- return this.inner.loadCurrentState(runId);
69554
- }
69555
- loadLatestStateSnapshot(runId) {
69556
- return this.inner.loadLatestStateSnapshot(runId);
69557
- }
69558
- listPausedRuns(options) {
69559
- return this.inner.listPausedRuns(options);
69560
- }
69561
- }
69562
- var now = () => new Date().toISOString(), MAX_FIELD_LENGTH3 = 256, SECRET_PATTERN2;
69563
- var init_observability = __esm(() => {
69564
- SECRET_PATTERN2 = /(?:sk-[a-z0-9_-]{8,}|(?:api[_-]?key|token|secret|password)\s*[:=]\s*\S+|bearer\s+\S+)/gi;
69983
+ init_shell();
69565
69984
  });
69566
69985
 
69567
69986
  // ../../packages/app/src/services/workflow-service.ts
@@ -69665,8 +70084,18 @@ class WorkflowAppService {
69665
70084
  });
69666
70085
  const runId = opts.runId ?? crypto.randomUUID();
69667
70086
  const isDry = opts.dryRun === true;
69668
- const runVars = { ...opts.vars ?? {}, __runId: runId };
69669
- const result = await svc.runFile(file2, {
70087
+ const runVars = {
70088
+ ...await resolveDefaultAgentVar(this.ctx.cwd, opts.vars),
70089
+ ...opts.vars ?? {},
70090
+ __runId: runId
70091
+ };
70092
+ const absolute = resolve4(this.ctx.cwd, file2);
70093
+ const embedded = this.embeddedSchemaOptions();
70094
+ const workflow = await loadWorkflowDef(absolute, {
70095
+ validateSchema: true,
70096
+ ...embedded !== undefined ? embedded : {}
70097
+ });
70098
+ const result = await svc.run(workflow, {
69670
70099
  workdir: this.ctx.cwd,
69671
70100
  runId,
69672
70101
  vars: runVars,
@@ -69687,7 +70116,7 @@ class WorkflowAppService {
69687
70116
  return;
69688
70117
  let workflowName;
69689
70118
  try {
69690
- const def = await loadWorkflowDef(resolve4(this.ctx.cwd, file2));
70119
+ const def = await loadWorkflowDef(resolve4(this.ctx.cwd, file2), { validateSchema: false });
69691
70120
  workflowName = def.name;
69692
70121
  } catch {
69693
70122
  return;
@@ -69731,6 +70160,37 @@ class WorkflowAppService {
69731
70160
  cleaned: stale.map((r) => ({ runId: r.id, startedAt: r.started_at }))
69732
70161
  };
69733
70162
  }
70163
+ async cleanRunLogs(retentionDays = 30, dryRun = false) {
70164
+ const runDir = join16(this.ctx.cwd, ".spur", "run");
70165
+ const fs3 = createNodeFileSystem3();
70166
+ const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
70167
+ const reclaimed = [];
70168
+ const failures = [];
70169
+ let entries;
70170
+ try {
70171
+ entries = (await fs3.readDir(runDir)).filter((name) => name.endsWith(".log"));
70172
+ } catch {
70173
+ return { retentionDays, dryRun, reclaimed, failures };
70174
+ }
70175
+ for (const name of entries) {
70176
+ const path9 = join16(runDir, name);
70177
+ const stat = await fs3.stat(path9);
70178
+ if (stat === null || !stat.isFile() || stat.mtimeMs >= cutoffMs)
70179
+ continue;
70180
+ const entry = { runId: name.slice(0, -".log".length), path: path9, mtime: new Date(stat.mtimeMs).toISOString() };
70181
+ if (dryRun) {
70182
+ reclaimed.push(entry);
70183
+ continue;
70184
+ }
70185
+ try {
70186
+ await fs3.deleteFile(path9);
70187
+ reclaimed.push(entry);
70188
+ } catch (err) {
70189
+ failures.push({ path: path9, error: String(err) });
70190
+ }
70191
+ }
70192
+ return { retentionDays, dryRun, reclaimed, failures };
70193
+ }
69734
70194
  async cancel(runId) {
69735
70195
  const db2 = await this.ctx.getDb();
69736
70196
  const dao2 = new RunDao(db2);
@@ -69746,20 +70206,23 @@ class WorkflowAppService {
69746
70206
  const finalized = after?.status === "failed" && before.status !== "failed";
69747
70207
  return { runId, finalized, status: after?.status ?? "not_found", killed };
69748
70208
  }
69749
- async continuePaused(runId) {
70209
+ async continuePaused(runId, opts) {
69750
70210
  const eventsBus = this.ctx.events?.();
69751
70211
  const svc = await this.createEngineService({ events: eventsBus });
69752
70212
  const run = await svc.listPausedRuns();
69753
70213
  const target = run.find((r) => r.id === runId);
69754
70214
  if (target === undefined) {
69755
- throw new Error(`Run "${runId}" is not paused (or does not exist) \u2014 nothing to continue.`);
70215
+ throw new Error(`Run "${runId}" is not paused (or does not exist) - nothing to continue.`);
69756
70216
  }
69757
70217
  const workflow = await this.resolveWorkflowDefByName(target.workflow_name);
69758
70218
  if (workflow === null) {
69759
70219
  throw new Error(`Cannot resume run "${runId}": workflow definition "${target.workflow_name}" not found in the workflow search paths.`);
69760
70220
  }
70221
+ const hitlVar = opts?.hitlVar ?? "__hitlAnswer";
70222
+ const resumeVars = opts?.hitlAnswer !== undefined ? { [hitlVar]: opts.hitlAnswer } : undefined;
69761
70223
  const result = await svc.resumeRun(workflow, runId, {
69762
70224
  workdir: this.ctx.cwd,
70225
+ ...resumeVars !== undefined ? { vars: resumeVars } : {},
69763
70226
  ...eventsBus !== undefined ? { events: bridgeEventBus(eventsBus) } : {}
69764
70227
  });
69765
70228
  await this.stampFailureReason(runId, result);
@@ -69911,8 +70374,8 @@ class WorkflowAppService {
69911
70374
  httpRequester: this.ctx.httpRequester?.(),
69912
70375
  hostAllowlist: this.ctx.hostAllowlist?.(),
69913
70376
  ...bus !== undefined ? { observabilityBus: bus } : {},
69914
- ...opts.steeringController !== undefined ? { steeringController: opts.steeringController } : {},
69915
- outputLog: await resolveOutputLogConfig(this.ctx.cwd)
70377
+ ...processExec !== undefined ? { processExecutor: processExec } : {},
70378
+ ...opts.steeringController !== undefined ? { steeringController: opts.steeringController } : {}
69916
70379
  });
69917
70380
  const db2 = await this.ctx.getDb();
69918
70381
  let persistence2 = new DbWorkflowPersistenceAdapter(db2);
@@ -69927,6 +70390,23 @@ async function fileExists(path9) {
69927
70390
  const fs3 = createNodeFileSystem3();
69928
70391
  return await fs3.exists(path9);
69929
70392
  }
70393
+ async function resolveDefaultAgentVar(cwd, callerVars) {
70394
+ if (callerVars?.agent !== undefined)
70395
+ return {};
70396
+ try {
70397
+ const configured = (await loadSpurConfig(cwd)).agent?.default;
70398
+ return typeof configured === "string" && configured.length > 0 ? { agent: configured } : {};
70399
+ } catch {
70400
+ return {};
70401
+ }
70402
+ }
70403
+ async function resolveWorkflowLogRetentionDays(cwd) {
70404
+ try {
70405
+ return (await loadSpurConfig(cwd)).workflow?.logRetentionDays ?? 30;
70406
+ } catch {
70407
+ return 30;
70408
+ }
70409
+ }
69930
70410
  async function resolveOutputLogConfig(cwd) {
69931
70411
  try {
69932
70412
  const output2 = (await loadSpurConfig(cwd)).agent?.output;
@@ -69941,7 +70421,7 @@ async function resolveOutputLogConfig(cwd) {
69941
70421
  }
69942
70422
  }
69943
70423
  async function outputArtifactForRun(cwd, runId) {
69944
- const relative4 = join16(".spur", "run", `${runId}-output.log`);
70424
+ const relative4 = join16(".spur", "run", `${runId}.log`);
69945
70425
  return await fileExists(join16(cwd, relative4)) ? relative4 : undefined;
69946
70426
  }
69947
70427
  async function scanWorkflowFiles(rootPath, source) {
@@ -70041,7 +70521,9 @@ class LifecycleAdapter {
70041
70521
  async requestTransition(ref, currentStatus, to) {
70042
70522
  const { profile } = this.opts;
70043
70523
  const db2 = await this.opts.getDb();
70044
- const svc = new WorkflowService(createDefaultWorkflowEngineHost(), new DbWorkflowPersistenceAdapter(db2));
70524
+ const host = createDefaultWorkflowEngineHost();
70525
+ host.registerGuard(new EnvShellGuardRunner(new NodeProcessExecutor3), "builtin");
70526
+ const svc = new WorkflowService(host, new DbWorkflowPersistenceAdapter(db2));
70045
70527
  const workflow = this.bindGuardVar(await this.loadWorkflow(), ref.id);
70046
70528
  const externalKey = `${profile.entityPrefix}:${ref.id}`;
70047
70529
  const now2 = new Date().toISOString();
@@ -70175,87 +70657,6 @@ var init_lifecycle_adapter = __esm(() => {
70175
70657
  };
70176
70658
  });
70177
70659
 
70178
- // ../../packages/app/src/workflow/step-reporter.ts
70179
- function renderStepLine(event2, options = {}) {
70180
- const detail = options.detail ?? "invocation";
70181
- if (isAgentExecution(event2)) {
70182
- if (event2.kind === "output") {
70183
- if (detail === "minimal")
70184
- return null;
70185
- const label = event2.stream === "stderr" ? "stderr" : "stdout";
70186
- return `[run ${event2.runId}] ${label}> ${event2.chunk.replace(/\s+$/, "")}`;
70187
- }
70188
- if (event2.kind === "heartbeat") {
70189
- if (detail === "minimal")
70190
- return null;
70191
- const budget = event2.timeoutMs === undefined ? "unbounded" : `${formatDuration(Math.max(0, event2.timeoutMs - event2.elapsedMs))} remaining`;
70192
- return `[run ${event2.runId}] \u2026 agent execution \xB7 elapsed=${formatDuration(event2.elapsedMs)} \xB7 budget=${budget}`;
70193
- }
70194
- if (event2.kind === "dropped") {
70195
- return detail === "minimal" ? null : `[run ${event2.runId}] \u2026 output pressure \xB7 dropped=${event2.chunks} chunks`;
70196
- }
70197
- if (event2.kind === "started") {
70198
- if (detail === "minimal")
70199
- return null;
70200
- const model = event2.model === undefined ? "" : `(${event2.model})`;
70201
- const full2 = detail === "full" ? ` \xB7 execution=${event2.executionId}` : "";
70202
- return `[run ${event2.runId}] agent=${event2.agent}${model} => ${event2.invocation}${full2}`;
70203
- }
70204
- const mark = event2.outcome === "done" ? "\u2713" : "\u2717";
70205
- const full = detail === "full" ? ` \xB7 execution=${event2.executionId}` : "";
70206
- return detail === "minimal" ? null : `[run ${event2.runId}] ${mark} agent ${event2.outcome} (${formatDuration(event2.durationMs)}) \xB7 usage ${event2.usage}${event2.reason ? ` \xB7 ${event2.reason}` : ""}${full}`;
70207
- }
70208
- if (isActionFinished(event2)) {
70209
- const mark = event2.ok ? "\u2713" : "\u2717";
70210
- if (detail === "minimal")
70211
- return ` ${mark} ${event2.status} (${formatDuration(event2.durationMs)})`;
70212
- const failure = event2.result?.error === undefined ? "" : ` \xB7 ${event2.result.error}`;
70213
- const full = detail === "full" ? ` \xB7 action=${event2.actionId} \xB7 seq=${event2.sequence}` : "";
70214
- return `[run ${event2.runId}] ${mark} ${event2.node}/${event2.kind} (${formatDuration(event2.durationMs)}) \xB7 usage ${event2.result?.usage ?? "unavailable"}${failure}${full}`;
70215
- }
70216
- if (isActionStarted(event2)) {
70217
- if (detail === "minimal")
70218
- return ` \u2192 ${event2.node}: ${event2.kind}\u2026`;
70219
- const agent = event2.metadata?.agent ?? "unavailable";
70220
- const model = event2.metadata?.model ?? "unavailable";
70221
- const invocation = event2.metadata?.invocation ?? "unavailable";
70222
- const timeout = event2.metadata?.timeoutMs === undefined ? "unbounded" : formatDuration(event2.metadata.timeoutMs);
70223
- const full = detail === "full" ? ` \xB7 action=${event2.actionId} \xB7 seq=${event2.sequence}` : "";
70224
- return `[run ${event2.runId}] \u2192 ${event2.node}/${event2.kind} \xB7 agent=${agent} \xB7 model=${model} => ${invocation} \xB7 timeout=${timeout}${full}`;
70225
- }
70226
- if (isPhase(event2)) {
70227
- return detail === "minimal" ? `\u25B6 ${event2.phase} [${event2.status}]` : `[run ${event2.runId}] \u25B6 ${event2.phase} [${event2.status}]`;
70228
- }
70229
- if (isTransition(event2)) {
70230
- if (detail !== "full")
70231
- return null;
70232
- return `[run ${event2.runId}] \u21AA ${event2.from} \u2192 ${event2.to}${event2.trigger ? ` [${event2.trigger}]` : ""} \xB7 seq=${event2.sequence}`;
70233
- }
70234
- return null;
70235
- }
70236
- function renderActionHeartbeat(event2, elapsedMs, options = {}) {
70237
- const detail = options.detail ?? "invocation";
70238
- if (detail === "minimal")
70239
- return null;
70240
- const elapsed = formatDuration(elapsedMs);
70241
- const budget = event2.metadata?.timeoutMs === undefined ? "unbounded" : `${formatDuration(Math.max(0, event2.metadata.timeoutMs - elapsedMs))} remaining`;
70242
- const full = detail === "full" ? ` \xB7 action=${event2.actionId}` : "";
70243
- return `[run ${event2.runId}] \u2026 ${event2.node}/${event2.kind} \xB7 elapsed=${elapsed} \xB7 budget=${budget}${full}`;
70244
- }
70245
- function renderRunPlan(def) {
70246
- const steps = def.kind === "transition-flow" ? def.nodes.map((n2) => n2.id) : def.states.map((s) => s.id);
70247
- return `plan: ${steps.join(" \u2192 ")}`;
70248
- }
70249
- function formatDuration(ms) {
70250
- const totalSeconds = Math.round(ms / 1000);
70251
- if (totalSeconds < 60)
70252
- return `${totalSeconds}s`;
70253
- const minutes = Math.floor(totalSeconds / 60);
70254
- const seconds = totalSeconds % 60;
70255
- return `${minutes}m ${seconds}s`;
70256
- }
70257
- 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);
70258
-
70259
70660
  // ../../packages/app/src/workflow/trace-writer.ts
70260
70661
  import { dirname as dirname13, join as join17 } from "path";
70261
70662
 
@@ -70308,9 +70709,11 @@ __export(exports_src2, {
70308
70709
  summarizeActionResult: () => summarizeActionResult,
70309
70710
  startRegisteredProject: () => startRegisteredProject,
70310
70711
  setDetachedServeSpawnForTests: () => setDetachedServeSpawnForTests,
70712
+ resolveWorkflowLogRetentionDays: () => resolveWorkflowLogRetentionDays,
70311
70713
  resolveSpurServeCommand: () => resolveSpurServeCommand,
70312
70714
  resolveRetentionQuotas: () => resolveRetentionQuotas,
70313
70715
  resolvePlanningFolders: () => resolvePlanningFolders,
70716
+ resolveOutputLogConfig: () => resolveOutputLogConfig,
70314
70717
  resolveAutostartSet: () => resolveAutostartSet,
70315
70718
  renderTesting: () => renderTesting,
70316
70719
  renderStepLine: () => renderStepLine,
@@ -70356,6 +70759,7 @@ __export(exports_src2, {
70356
70759
  aggregateBatchVerdicts: () => aggregateBatchVerdicts,
70357
70760
  WorkflowTraceWriter: () => WorkflowTraceWriter,
70358
70761
  WorkflowSteeringController: () => WorkflowSteeringController,
70762
+ WorkflowRunLogSink: () => WorkflowRunLogSink,
70359
70763
  WorkflowAppService: () => WorkflowAppService,
70360
70764
  WbsCollisionError: () => WbsCollisionError,
70361
70765
  UnsupportedProcessPlatformError: () => UnsupportedProcessPlatformError,
@@ -70417,6 +70821,7 @@ __export(exports_src2, {
70417
70821
  DuplicateFollowUpError: () => DuplicateFollowUpError,
70418
70822
  DependencyMutationError: () => DependencyMutationError,
70419
70823
  DEFAULT_SYSTEM_EVENT_RETENTION_QUOTA: () => DEFAULT_SYSTEM_EVENT_RETENTION_QUOTA,
70824
+ DEFAULT_RUN_LOG_MAX_BYTES: () => DEFAULT_RUN_LOG_MAX_BYTES,
70420
70825
  DEFAULT_FEATURE_MATRIX: () => DEFAULT_FEATURE_MATRIX,
70421
70826
  CorpusMigrator: () => CorpusMigrator,
70422
70827
  BusPlanningEventEmitter: () => BusPlanningEventEmitter,
@@ -70429,6 +70834,7 @@ var init_src3 = __esm(() => {
70429
70834
  init_planning_folders();
70430
70835
  init_errors5();
70431
70836
  init_agent_execution();
70837
+ init_workflow_run_log_sink();
70432
70838
  init_agent_service();
70433
70839
  init_corpus_migrator();
70434
70840
  init_event_names();
@@ -70548,19 +70954,19 @@ var {
70548
70954
  init_src();
70549
70955
  init_loader();
70550
70956
 
70551
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/application-node.js
70957
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/application-node.js
70552
70958
  init_dist4();
70553
70959
  init_dist5();
70554
70960
  import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "fs";
70555
70961
  import { dirname as dirname5 } from "path";
70556
70962
 
70557
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/application/index.js
70963
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/application/index.js
70558
70964
  init_default_observers();
70559
70965
  init_event_bus();
70560
70966
  init_file_observer();
70561
70967
  init_logger3();
70562
70968
 
70563
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
70969
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
70564
70970
  class NoopSchedulerAdapter {
70565
70971
  constructor() {}
70566
70972
  register(_cron, _action) {}
@@ -70568,7 +70974,7 @@ class NoopSchedulerAdapter {
70568
70974
  async stop() {}
70569
70975
  }
70570
70976
 
70571
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
70977
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
70572
70978
  function initScheduler(adapter, cronEntries) {
70573
70979
  const resolved = adapter ?? new NoopSchedulerAdapter;
70574
70980
  if (cronEntries) {
@@ -70579,7 +70985,7 @@ function initScheduler(adapter, cronEntries) {
70579
70985
  return resolved;
70580
70986
  }
70581
70987
 
70582
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
70988
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
70583
70989
  init_logger3();
70584
70990
  init_metrics();
70585
70991
  init_sdk();
@@ -70672,7 +71078,7 @@ function dbPlugin(db2) {
70672
71078
  };
70673
71079
  }
70674
71080
 
70675
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
71081
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
70676
71082
  init_logger3();
70677
71083
 
70678
71084
  class PluginHost {
@@ -70760,7 +71166,7 @@ class PluginHost {
70760
71166
  }
70761
71167
  }
70762
71168
 
70763
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/application/index.js
71169
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/application/index.js
70764
71170
  async function performShutdown(state, reason) {
70765
71171
  if (state.stopped)
70766
71172
  return;
@@ -70871,10 +71277,10 @@ async function runApplication(options) {
70871
71277
  }
70872
71278
  }
70873
71279
 
70874
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/application-node.js
71280
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/application-node.js
70875
71281
  init_scheduler_node();
70876
71282
 
70877
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
71283
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
70878
71284
  var import_api14 = __toESM(require_src(), 1);
70879
71285
 
70880
71286
  // ../../node_modules/.bun/@opentelemetry+exporter-metrics-otlp-http@0.218.0+e40b0dfdd726a224/node_modules/@opentelemetry/exporter-metrics-otlp-http/build/esm/OTLPMetricExporterBase.js
@@ -73890,7 +74296,7 @@ class OTLPTraceExporter extends import_otlp_exporter_base2.OTLPExporterBase {
73890
74296
  }), JsonTraceSerializer));
73891
74297
  }
73892
74298
  }
73893
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
74299
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
73894
74300
  var import_resources2 = __toESM(require_src4(), 1);
73895
74301
  var import_sdk_trace_node = __toESM(require_src8(), 1);
73896
74302
  var import_semantic_conventions = __toESM(require_src2(), 1);
@@ -73941,7 +74347,7 @@ async function shutdownNodeTelemetry() {
73941
74347
  await Promise.all(pending);
73942
74348
  }
73943
74349
 
73944
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.15+60cc1f0410bb6d88/node_modules/@gobing-ai/ts-infra/dist/application-node.js
74350
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.18+863f28addc1a7cdc/node_modules/@gobing-ai/ts-infra/dist/application-node.js
73945
74351
  class ConfigValidationError extends Error {
73946
74352
  constructor(message) {
73947
74353
  super(message);
@@ -78339,7 +78745,15 @@ function registerFeatureCommand(program2, context4) {
78339
78745
  context4.setExitCode(1);
78340
78746
  }
78341
78747
  });
78342
- feature.command("refresh").summary("Regenerate INDEX.md (ID-encoded tree) and repopulate each feature ## Tasks region.").option("--feature <id>", "Restrict the ## Tasks rewrite to one feature (INDEX.md still regenerated)").option("--folder <path>", "Custom features folder").option("--json", "Output machine-readable JSON").action(async (options) => {
78748
+ feature.command("refresh").summary("Rebuild INDEX.md and each feature ## Tasks table from task edges (docs only \u2014 no status change).").description([
78749
+ "Regenerate derived views so feature markdown matches the task graph:",
78750
+ " \u2022 docs/features/INDEX.md (ID-encoded tree)",
78751
+ " \u2022 each feature ## Tasks auto-gen region (WBS / title / status from feature_id edges)",
78752
+ "",
78753
+ "Does NOT change feature frontmatter status. For lifecycle alignment use `spur feature sync`.",
78754
+ "Use after task create/link/done when the ## Tasks table is stale."
78755
+ ].join(`
78756
+ `)).option("--feature <id>", "Restrict the ## Tasks rewrite to one feature (INDEX.md still regenerated)").option("--folder <path>", "Custom features folder").option("--json", "Output machine-readable JSON").action(async (options) => {
78343
78757
  const svc = await makeService(context4, options.folder);
78344
78758
  try {
78345
78759
  const result = await svc.refresh({ featureId: options.feature });
@@ -78401,7 +78815,16 @@ ${result.id} (${result.status}): ${result.pass ? "PASS" : "FAIL"}`);
78401
78815
  context4.setExitCode(1);
78402
78816
  }
78403
78817
  });
78404
- feature.command("sync").summary("Sync feature status with linked task states.").argument("[id]", "Feature ID to sync (optional if --all is passed)").option("--all", "Sync all features with linked tasks").option("--dry-run", "Report proposed status sync transitions without applying").option("--force", "Force applying reopen proposals without confirmation").option("--folder <path>", "Custom features folder").option("--json", "Output machine-readable JSON").action(async (id, options) => {
78818
+ feature.command("sync").summary("Align feature lifecycle status with linked task states (status only \u2014 runs transition guards).").description([
78819
+ "Derive a feature status proposal from linked task statuses and apply legal hops",
78820
+ "(e.g. all tasks done \u2192 advance toward done; reopened work \u2192 reopen the feature).",
78821
+ "",
78822
+ "Applies real lifecycle transitions \u2014 gates such as dogfood, one-active-goal, and",
78823
+ "L4 AC readiness may deny a hop. Preview with --dry-run first.",
78824
+ "",
78825
+ "Does NOT rewrite INDEX.md or ## Tasks tables. For stale rosters use `spur feature refresh`."
78826
+ ].join(`
78827
+ `)).argument("[id]", "Feature ID to sync (optional if --all is passed)").option("--all", "Sync all features with linked tasks").option("--dry-run", "Report proposed status sync transitions without applying").option("--force", "Force applying reopen proposals without confirmation").option("--folder <path>", "Custom features folder").option("--json", "Output machine-readable JSON").action(async (id, options) => {
78405
78828
  const svc = await makeService(context4, options.folder);
78406
78829
  try {
78407
78830
  if (!options.all && !id) {
@@ -78532,7 +78955,7 @@ import { join as join19, resolve as resolve6 } from "path";
78532
78955
  var CLI_CONFIG = {
78533
78956
  binaryName: "spur",
78534
78957
  binaryLabel: "spur",
78535
- binaryVersion: "0.3.29",
78958
+ binaryVersion: "0.3.31",
78536
78959
  configDir: ".spur",
78537
78960
  configFile: ".spur/config.yaml",
78538
78961
  databaseFile: ".spur/spur.db"
@@ -89397,6 +89820,11 @@ var state_machine_workflow_schema_default = {
89397
89820
  description: { type: "string" },
89398
89821
  initialState: { type: "string", minLength: 1 },
89399
89822
  terminalStates: { type: "array", items: { type: "string", minLength: 1 } },
89823
+ failureStates: {
89824
+ type: "array",
89825
+ items: { type: "string", minLength: 1 },
89826
+ description: "Subset of terminalStates whose reach finalizes the run as failed. Absent \u21D2 every terminal is a success."
89827
+ },
89400
89828
  iterationBound: { type: "integer", exclusiveMinimum: 0 },
89401
89829
  vars: {
89402
89830
  type: "object",
@@ -90683,7 +91111,8 @@ init_loader();
90683
91111
  init_dist7();
90684
91112
  init_dist6();
90685
91113
  init_dist5();
90686
- import { resolve as resolve8 } from "path";
91114
+ import { closeSync as closeSync5, fstatSync as fstatSync3, openSync as openSync5, readSync as readSync3 } from "fs";
91115
+ import { join as join27, resolve as resolve8 } from "path";
90687
91116
  import { createInterface } from "readline";
90688
91117
  import { setTimeout as sleep3 } from "timers/promises";
90689
91118
  function shQuote2(value2) {
@@ -90767,7 +91196,7 @@ ${result.errors.map((m) => ` - ${m}`).join(`
90767
91196
  }
90768
91197
  context4.setExitCode(result.valid ? 0 : 1);
90769
91198
  });
90770
- 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) => {
91199
+ 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("--no-log", "Opt out of writing the consolidated .spur/run/<RUNID>.log").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) => {
90771
91200
  const json3 = options.json === true;
90772
91201
  const silent = !json3 && options.silent === true;
90773
91202
  const quiet = !json3 && options.quiet === true;
@@ -90808,6 +91237,9 @@ ${result.errors.map((m) => ` - ${m}`).join(`
90808
91237
  if (options.traceFile) {
90809
91238
  cmd.push("--trace-file");
90810
91239
  }
91240
+ if (options.log === false) {
91241
+ cmd.push("--no-log");
91242
+ }
90811
91243
  try {
90812
91244
  await spawnAsyncWorkflowWorker(spurBin, cmd);
90813
91245
  } catch {
@@ -90845,27 +91277,38 @@ Monitor with: spur workflow trace ${runId2} --follow`);
90845
91277
  traceWriter = new WorkflowTraceWriter(context4.cwd, runId);
90846
91278
  traceWriter.attach(bus);
90847
91279
  }
91280
+ let planPreview;
91281
+ if (options.plan !== false) {
91282
+ try {
91283
+ const def = await loadWorkflowDef(resolve8(context4.cwd, file2), { validateSchema: false });
91284
+ planPreview = renderRunPlan(def);
91285
+ } catch {}
91286
+ }
91287
+ const runLog = options.log === false ? undefined : new WorkflowRunLogSink({
91288
+ bus,
91289
+ dir: join27(context4.cwd, ".spur", "run"),
91290
+ runId,
91291
+ ...planPreview !== undefined ? { planPreview } : {},
91292
+ ...await resolveOutputLogConfig(context4.cwd)
91293
+ });
90848
91294
  if (humanProgress) {
90849
91295
  context4.output.write(`Run: ${runId}`);
90850
- if (options.plan !== false) {
90851
- try {
90852
- const def = await loadWorkflowDef(resolve8(context4.cwd, file2), { validateSchema: false });
90853
- context4.output.write(renderRunPlan(def));
90854
- } catch {}
90855
- }
91296
+ if (planPreview !== undefined)
91297
+ context4.output.write(planPreview);
91298
+ const stepOptions = { detail, showRunId: false };
90856
91299
  const report = (event2) => {
90857
- const line = renderStepLine(event2, { detail });
91300
+ const line = renderStepLine(event2, stepOptions);
90858
91301
  if (line !== null)
90859
91302
  context4.output.write(line);
90860
91303
  };
90861
91304
  bus.on("workflow.phase", report);
90862
- if (detail === "full")
91305
+ if (detail !== "minimal")
90863
91306
  bus.on("workflow.transition", report);
90864
91307
  bus.on("workflow.action.started", (event2) => {
90865
91308
  report(event2);
90866
91309
  const startedAt3 = Date.parse(event2.at);
90867
91310
  const timer = setInterval(() => {
90868
- const line = renderActionHeartbeat(event2, Math.max(0, Date.now() - startedAt3), { detail });
91311
+ const line = renderActionHeartbeat(event2, Math.max(0, Date.now() - startedAt3), stepOptions);
90869
91312
  if (line !== null)
90870
91313
  context4.output.write(line);
90871
91314
  }, 30000);
@@ -90888,6 +91331,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
90888
91331
  }
90889
91332
  report(event2);
90890
91333
  });
91334
+ bus.on("workflow.action.output", report);
90891
91335
  }
90892
91336
  const steeringController = options.steer === true ? new WorkflowSteeringController((ack) => {
90893
91337
  bus.emit("workflow.steering", ack);
@@ -90915,6 +91359,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
90915
91359
  clearInterval(timer);
90916
91360
  heartbeats.clear();
90917
91361
  await traceWriter?.flush();
91362
+ runLog?.close();
90918
91363
  await ledger.flush();
90919
91364
  ledger.unsubscribe();
90920
91365
  steeringInput?.close();
@@ -90926,8 +91371,18 @@ Monitor with: spur workflow trace ${runId2} --follow`);
90926
91371
  }
90927
91372
  context4.setExitCode(result.status === "done" ? 0 : 1);
90928
91373
  });
90929
- 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) => {
91374
+ 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("--answer <yes|no|cancel>", "Inject a HITL gate answer before guard re-evaluation (0433). Does not imply --yes.").option("--json", "Output machine-readable JSON where supported").action(async (runId, options) => {
90930
91375
  const json3 = options.json === true;
91376
+ let hitlAnswer;
91377
+ if (options.answer !== undefined) {
91378
+ const v = String(options.answer).toLowerCase();
91379
+ if (v !== "yes" && v !== "no" && v !== "cancel") {
91380
+ context4.output.error(`Invalid --answer value "${options.answer}" - must be yes, no, or cancel.`);
91381
+ context4.setExitCode(2);
91382
+ return;
91383
+ }
91384
+ hitlAnswer = v;
91385
+ }
90931
91386
  const bus = new EventBus;
90932
91387
  const ledger = await attachSystemEventLedger(bus, context4);
90933
91388
  const svc = makeSvc(json3, bus);
@@ -90949,13 +91404,15 @@ Monitor with: spur workflow trace ${runId2} --follow`);
90949
91404
  node: "continue"
90950
91405
  });
90951
91406
  if (answer.value !== "yes") {
90952
- context4.output.error(`Aborted \u2014 run ${latest.runId} not resumed.`);
91407
+ context4.output.error(`Aborted - run ${latest.runId} not resumed.`);
90953
91408
  context4.setExitCode(1);
90954
91409
  return;
90955
91410
  }
90956
91411
  }
90957
91412
  }
90958
- const result = await svc.continuePaused(targetId);
91413
+ const result = await svc.continuePaused(targetId, {
91414
+ ...hitlAnswer !== undefined ? { hitlAnswer } : {}
91415
+ });
90959
91416
  context4.output.write(json3 ? toJson2(result) : `workflow ${result.status}: ${result.workflowName} -> ${result.finalState}`);
90960
91417
  context4.setExitCode(result.status === "done" ? 0 : 1);
90961
91418
  } catch (err) {
@@ -90966,7 +91423,9 @@ Monitor with: spur workflow trace ${runId2} --follow`);
90966
91423
  ledger.unsubscribe();
90967
91424
  }
90968
91425
  });
90969
- workflow.command("clean").description("Finalize orphaned runs stuck in running/pending past a staleness threshold (mark as failed). " + "To cancel a single live run by id, use `spur workflow cancel <run-id>` instead.").option("--older-than <minutes>", "Staleness threshold in minutes", "30").option("--force", "Clean ALL non-terminal runs regardless of age (overrides --older-than)").option("--dry-run", "List what would be cleaned without writing").option("--json", "Output machine-readable JSON where supported").action(async (options) => {
91426
+ workflow.command("clean").description("Housekeeping: finalize orphaned runs stuck in running/pending past a staleness threshold " + "(mark as failed) and reclaim retained run logs older than workflow.logRetentionDays. " + "`--logs` scopes to log reclamation only. To cancel a single live run by id, use " + "`spur workflow cancel <run-id>` instead.").option("--older-than <minutes>", "Staleness threshold in minutes (stale-run scope only)", "30").option("--force", "Clean ALL non-terminal runs regardless of age (overrides --older-than)").option("--logs", "Scope to retained run-log reclamation only (skip stale-run finalization)").option("--dry-run", "List what would be cleaned without writing (applies to both scopes)").option("--json", "Output machine-readable JSON where supported").action(async (options) => {
91427
+ const dryRun = options.dryRun === true;
91428
+ const logsOnly = options.logs === true;
90970
91429
  const force = options.force === true;
90971
91430
  const minutes = force ? 0 : Number.parseInt(options.olderThan ?? "30", 10);
90972
91431
  if (!Number.isFinite(minutes) || minutes < 0) {
@@ -90974,19 +91433,35 @@ Monitor with: spur workflow trace ${runId2} --follow`);
90974
91433
  context4.setExitCode(2);
90975
91434
  return;
90976
91435
  }
90977
- const result = await makeSvc(options.json).clean(minutes, options.dryRun === true);
91436
+ const svc = makeSvc(options.json);
91437
+ const result = logsOnly ? undefined : await svc.clean(minutes, dryRun);
91438
+ const retentionDays = await resolveWorkflowLogRetentionDays(context4.cwd);
91439
+ const logResult2 = await svc.cleanRunLogs(retentionDays, dryRun);
90978
91440
  if (options.json) {
90979
- context4.output.write(toJson2(result));
91441
+ context4.output.write(toJson2(logsOnly ? logResult2 : { ...result, logs: logResult2 }));
90980
91442
  } else {
90981
- const verb = result.dryRun ? "Would finalize" : "Finalized";
90982
- if (result.cleaned.length === 0) {
90983
- const ageMsg = force ? "" : ` older than ${minutes}m`;
90984
- context4.output.write(`No stale runs${ageMsg}.`);
90985
- } else {
90986
- const ageMsg = force ? " (all non-terminal)" : ` (>${minutes}m)`;
90987
- context4.output.write(`${verb} ${result.cleaned.length} stale run(s)${ageMsg}:
91443
+ if (result !== undefined) {
91444
+ const verb = dryRun ? "Would finalize" : "Finalized";
91445
+ if (result.cleaned.length === 0) {
91446
+ const ageMsg = force ? "" : ` older than ${minutes}m`;
91447
+ context4.output.write(`No stale runs${ageMsg}.`);
91448
+ } else {
91449
+ const ageMsg = force ? " (all non-terminal)" : ` (>${minutes}m)`;
91450
+ context4.output.write(`${verb} ${result.cleaned.length} stale run(s)${ageMsg}:
90988
91451
  ` + result.cleaned.map((r2) => ` ${r2.runId} (started ${r2.startedAt})`).join(`
90989
91452
  `));
91453
+ }
91454
+ }
91455
+ const logVerb = dryRun ? "Would reclaim" : "Reclaimed";
91456
+ if (logResult2.reclaimed.length === 0) {
91457
+ context4.output.write(`No retained run logs older than ${retentionDays}d.`);
91458
+ } else {
91459
+ context4.output.write(`${logVerb} ${logResult2.reclaimed.length} retained run log(s) (>${retentionDays}d):
91460
+ ` + logResult2.reclaimed.map((l) => ` ${l.runId} (mtime ${l.mtime})`).join(`
91461
+ `));
91462
+ }
91463
+ for (const failure of logResult2.failures) {
91464
+ context4.output.error(`Failed to remove run log ${failure.path}: ${failure.error}`);
90990
91465
  }
90991
91466
  }
90992
91467
  });
@@ -91017,7 +91492,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
91017
91492
  context4.output.write(formatListHuman(result));
91018
91493
  }
91019
91494
  });
91020
- 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) => {
91495
+ 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("--output", "With --follow: stream .spur/run/<RUNID>.log instead of the DB timeline").option("--json", "Output machine-readable JSON where supported").action(async (runId, options) => {
91021
91496
  const svc = makeSvc();
91022
91497
  const last = parseInt(options.last, 10);
91023
91498
  if (Number.isNaN(last) || last < 1) {
@@ -91041,13 +91516,27 @@ Monitor with: spur workflow trace ${runId2} --follow`);
91041
91516
  context4.setExitCode(1);
91042
91517
  return;
91043
91518
  }
91519
+ if (options.output === true && options.follow !== true) {
91520
+ context4.output.error("--output requires --follow");
91521
+ context4.setExitCode(1);
91522
+ return;
91523
+ }
91524
+ if (options.output === true && options.json === true) {
91525
+ context4.output.error("--output is a human streaming mode and cannot be combined with --json");
91526
+ context4.setExitCode(1);
91527
+ return;
91528
+ }
91044
91529
  if (options.status !== undefined && !["done", "failed", "running"].includes(options.status)) {
91045
91530
  context4.output.error("--status must be one of: done, failed, running");
91046
91531
  context4.setExitCode(1);
91047
91532
  return;
91048
91533
  }
91049
91534
  if (options.follow === true && runId !== undefined) {
91050
- await followTrace(svc, runId, pollMs, (line) => context4.output.write(line));
91535
+ if (options.output === true) {
91536
+ await followRunLog(svc, runId, context4.cwd, pollMs, (line) => context4.output.write(line));
91537
+ } else {
91538
+ await followTrace(svc, runId, pollMs, (line) => context4.output.write(line));
91539
+ }
91051
91540
  return;
91052
91541
  }
91053
91542
  const result = runId ? await svc.trace(runId) : await svc.trace({
@@ -91119,7 +91608,7 @@ function formatTraceTimeline(result) {
91119
91608
  ""
91120
91609
  ];
91121
91610
  if (result.outputArtifact !== undefined) {
91122
- lines.push(`Agent output: ${result.outputArtifact} (tail -f for live view)`);
91611
+ lines.push(`Run log: ${result.outputArtifact} (tail -f for live view)`);
91123
91612
  lines.push("");
91124
91613
  }
91125
91614
  for (const event2 of events2) {
@@ -91182,6 +91671,59 @@ async function followTrace(service, runId, pollMs, write, wait = (ms) => sleep3(
91182
91671
  function isTerminalTraceStatus(status) {
91183
91672
  return status !== "running" && status !== "pending";
91184
91673
  }
91674
+ function readRunLogChunk(logPath, offset) {
91675
+ let fd;
91676
+ try {
91677
+ fd = openSync5(logPath, "r");
91678
+ } catch {
91679
+ return { exists: false, lines: [], offset };
91680
+ }
91681
+ try {
91682
+ const size = fstatSync3(fd).size;
91683
+ if (size <= offset)
91684
+ return { exists: true, lines: [], offset };
91685
+ const buffer = Buffer.alloc(size - offset);
91686
+ readSync3(fd, buffer, 0, buffer.length, offset);
91687
+ const text4 = buffer.toString("utf8");
91688
+ const lastNewline = text4.lastIndexOf(`
91689
+ `);
91690
+ const consumed = lastNewline >= 0 ? lastNewline + 1 : 0;
91691
+ const parts = consumed === 0 ? [] : text4.slice(0, consumed).split(`
91692
+ `);
91693
+ const lines = parts.length > 0 && parts.at(-1) === "" ? parts.slice(0, -1) : parts;
91694
+ return { exists: true, lines, offset: offset + consumed };
91695
+ } finally {
91696
+ closeSync5(fd);
91697
+ }
91698
+ }
91699
+ async function followRunLog(service, runId, dir, pollMs, write, wait = (ms) => sleep3(ms)) {
91700
+ const logPath = join27(dir, ".spur", "run", `${runId}.log`);
91701
+ let offset = 0;
91702
+ let everRead = false;
91703
+ while (true) {
91704
+ const chunk = readRunLogChunk(logPath, offset);
91705
+ if (chunk.exists && (chunk.lines.length > 0 || chunk.offset > offset)) {
91706
+ everRead = true;
91707
+ for (const line of chunk.lines)
91708
+ write(line);
91709
+ offset = chunk.offset;
91710
+ }
91711
+ let terminal = false;
91712
+ try {
91713
+ terminal = isTerminalTraceStatus((await service.trace(runId)).run.status);
91714
+ } catch (error51) {
91715
+ if (!String(error51).includes("Run not found"))
91716
+ throw error51;
91717
+ }
91718
+ if (terminal) {
91719
+ if (!everRead) {
91720
+ write(`No run log at ${logPath} \u2014 the run may have been started with --no-log.`);
91721
+ }
91722
+ return;
91723
+ }
91724
+ await wait(pollMs);
91725
+ }
91726
+ }
91185
91727
  function formatActionCost(event2) {
91186
91728
  if (event2.kind !== "action")
91187
91729
  return "";
@@ -91202,7 +91744,7 @@ init_src3();
91202
91744
  init_src();
91203
91745
  init_src2();
91204
91746
  init_dist5();
91205
- import { dirname as dirname16, join as join27, resolve as resolve9 } from "path";
91747
+ import { dirname as dirname16, join as join28, resolve as resolve9 } from "path";
91206
91748
  import { isatty as isatty4 } from "tty";
91207
91749
 
91208
91750
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -92624,7 +93166,7 @@ function createCliContext(options) {
92624
93166
  function noopSetExitCode(_code) {}
92625
93167
  async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, dbUrl) {
92626
93168
  const config4 = buildConfigFromEnv(env);
92627
- const configuredUrl = env.DATABASE_URL === undefined ? join27(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
93169
+ const configuredUrl = env.DATABASE_URL === undefined ? join28(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
92628
93170
  const url2 = dbUrl ?? configuredUrl;
92629
93171
  if (url2 !== IN_MEMORY_DATABASE_URL) {
92630
93172
  await createNodeFileSystem3().ensureDir(dirname16(url2));