@gobing-ai/spur 0.3.9 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/config/rules/boundary/sp-runtime-path.yaml +4 -0
  2. package/config/rules/typescript/guarded-happy-dom-register.yaml +14 -36
  3. package/config/workflows/feature-dev.yaml +5 -5
  4. package/config/workflows/idea-pipeline.yaml +2 -2
  5. package/config/workflows/task-pipeline.yaml +1 -1
  6. package/package.json +9 -9
  7. package/schemas/spur-config.schema.json +64 -0
  8. package/spur.js +2012 -383
  9. package/web/_astro/BoardApp.CXm9NttC.js +1 -0
  10. package/web/_astro/{BoardApp.DjpO2XHn.js → BoardApp.DDpBMmZh.js} +106 -105
  11. package/web/_astro/{TaskDetail.DilpuD7R.js → TaskDetail.BuXwnD5s.js} +1 -1
  12. package/web/_astro/{arc.KcqIior8.js → arc.ROFFfvlC.js} +1 -1
  13. package/web/_astro/{architectureDiagram-3BPJPVTR.BTFU70BY.js → architectureDiagram-3BPJPVTR.BF8jS1C7.js} +1 -1
  14. package/web/_astro/{blockDiagram-GPEHLZMM.apx49Oy9.js → blockDiagram-GPEHLZMM.BAZd0UR-.js} +1 -1
  15. package/web/_astro/{c4Diagram-AAUBKEIU.BM-J4juX.js → c4Diagram-AAUBKEIU.BQiuu65q.js} +1 -1
  16. package/web/_astro/channel.e58tDmJn.js +1 -0
  17. package/web/_astro/{chunk-2J33WTMH.K6z7IYZU.js → chunk-2J33WTMH.CaZ7Cj2C.js} +1 -1
  18. package/web/_astro/{chunk-4BX2VUAB.BDYhxKa0.js → chunk-4BX2VUAB.Dl95s7jh.js} +1 -1
  19. package/web/_astro/{chunk-55IACEB6.BnNOxqnI.js → chunk-55IACEB6.BS6cwIjQ.js} +1 -1
  20. package/web/_astro/{chunk-727SXJPM.DNeg6N7v.js → chunk-727SXJPM.BodG8be9.js} +1 -1
  21. package/web/_astro/{chunk-AQP2D5EJ.BjILBkba.js → chunk-AQP2D5EJ.D7bElS24.js} +1 -1
  22. package/web/_astro/{chunk-FMBD7UC4.DQ5UvvsV.js → chunk-FMBD7UC4.B4QCK-dI.js} +1 -1
  23. package/web/_astro/{chunk-ND2GUHAM.Yn1OvRJs.js → chunk-ND2GUHAM.X1msYFei.js} +1 -1
  24. package/web/_astro/{chunk-QZHKN3VN.UErqHgqw.js → chunk-QZHKN3VN.B2c4-Dz1.js} +1 -1
  25. package/web/_astro/{classDiagram-4FO5ZUOK.BmjVF7iZ.js → classDiagram-4FO5ZUOK.b8-sWDxa.js} +1 -1
  26. package/web/_astro/{classDiagram-v2-Q7XG4LA2.BmjVF7iZ.js → classDiagram-v2-Q7XG4LA2.b8-sWDxa.js} +1 -1
  27. package/web/_astro/{cose-bilkent-S5V4N54A.iKBxnkbb.js → cose-bilkent-S5V4N54A.CT4xXx1C.js} +1 -1
  28. package/web/_astro/{dagre-BM42HDAG.OwnCCrs6.js → dagre-BM42HDAG.DAukBvJI.js} +1 -1
  29. package/web/_astro/{diagram-2AECGRRQ.DCdcffxE.js → diagram-2AECGRRQ.iAkt-am3.js} +1 -1
  30. package/web/_astro/{diagram-5GNKFQAL.Ai-LvmVW.js → diagram-5GNKFQAL.BbKJ0fPo.js} +1 -1
  31. package/web/_astro/{diagram-KO2AKTUF.B6e21QDN.js → diagram-KO2AKTUF.DmAKP2Me.js} +1 -1
  32. package/web/_astro/{diagram-LMA3HP47.oPfqy1fq.js → diagram-LMA3HP47.CJzAaFxI.js} +1 -1
  33. package/web/_astro/{diagram-OG6HWLK6.Dh5QRDCE.js → diagram-OG6HWLK6.z2Yhlt_S.js} +1 -1
  34. package/web/_astro/{erDiagram-TEJ5UH35.DpBiOcO3.js → erDiagram-TEJ5UH35.C1inBaHt.js} +1 -1
  35. package/web/_astro/{flowDiagram-I6XJVG4X.NbMxFlVk.js → flowDiagram-I6XJVG4X.D6y2SP1V.js} +1 -1
  36. package/web/_astro/{ganttDiagram-6RSMTGT7.JgZ3fDME.js → ganttDiagram-6RSMTGT7.BWgsQaJO.js} +1 -1
  37. package/web/_astro/{gitGraphDiagram-PVQCEYII.oMjFeZRt.js → gitGraphDiagram-PVQCEYII.So8AZT3S.js} +1 -1
  38. package/web/_astro/index.BaoJPQzM.css +1 -0
  39. package/web/_astro/{infoDiagram-5YYISTIA.kaio3YzK.js → infoDiagram-5YYISTIA.alTk5ecq.js} +1 -1
  40. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CXQfMyeF.js → ishikawaDiagram-YF4QCWOH.X82FajaS.js} +1 -1
  41. package/web/_astro/{journeyDiagram-JHISSGLW.AvNKMzx6.js → journeyDiagram-JHISSGLW.74uvU6ld.js} +1 -1
  42. package/web/_astro/{kanban-definition-UN3LZRKU.kv3cZGdE.js → kanban-definition-UN3LZRKU.D6BjF9UG.js} +1 -1
  43. package/web/_astro/{linear.CfLoHWjz.js → linear.BpRIYzdb.js} +1 -1
  44. package/web/_astro/{mermaid.core.BSV8pBn-.js → mermaid.core.fdUDKzul.js} +4 -4
  45. package/web/_astro/{mindmap-definition-RKZ34NQL.CbL_3b32.js → mindmap-definition-RKZ34NQL.Df5SdMrH.js} +1 -1
  46. package/web/_astro/{pieDiagram-4H26LBE5.5BXdOLRb.js → pieDiagram-4H26LBE5.xNCa7QSz.js} +1 -1
  47. package/web/_astro/{quadrantDiagram-W4KKPZXB.krXYbhlh.js → quadrantDiagram-W4KKPZXB.C_3DSB9b.js} +1 -1
  48. package/web/_astro/{requirementDiagram-4Y6WPE33.COO4LapZ.js → requirementDiagram-4Y6WPE33.C2MFScI8.js} +1 -1
  49. package/web/_astro/{sankeyDiagram-5OEKKPKP.BvL0Jbdx.js → sankeyDiagram-5OEKKPKP.DEy6YHUG.js} +1 -1
  50. package/web/_astro/{sequenceDiagram-3UESZ5HK.Dk7Tu15E.js → sequenceDiagram-3UESZ5HK.CdQjeOkf.js} +1 -1
  51. package/web/_astro/{stateDiagram-AJRCARHV.Cqh_KmEW.js → stateDiagram-AJRCARHV.C-j_0D_L.js} +1 -1
  52. package/web/_astro/{stateDiagram-v2-BHNVJYJU.WapPgDCy.js → stateDiagram-v2-BHNVJYJU.BMzYaYSQ.js} +1 -1
  53. package/web/_astro/{timeline-definition-PNZ67QCA.CEVdiX0n.js → timeline-definition-PNZ67QCA.BaAa5dDC.js} +1 -1
  54. package/web/_astro/{vennDiagram-CIIHVFJN.Cd9A63eF.js → vennDiagram-CIIHVFJN.GZL7T0cb.js} +1 -1
  55. package/web/_astro/{wardley-L42UT6IY.DEiaHiIT.js → wardley-L42UT6IY.STDdK5oO.js} +1 -1
  56. package/web/_astro/{wardleyDiagram-YWT4CUSO.B7nGP61E.js → wardleyDiagram-YWT4CUSO.BJLlSFei.js} +1 -1
  57. package/web/_astro/{xychartDiagram-2RQKCTM6.Bq8CHmxC.js → xychartDiagram-2RQKCTM6.CRGBFqsD.js} +1 -1
  58. package/web/index.html +2 -2
  59. package/web/_astro/BoardApp.Bcfvp2GH.js +0 -1
  60. package/web/_astro/channel.vSp82e1U.js +0 -1
  61. package/web/_astro/index.CA3GTZM6.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.8/node_modules/@gobing-ai/ts-utils/dist/errors.js
50
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.10/node_modules/@gobing-ai/ts-utils/dist/errors.js
51
51
  function isAppError(error) {
52
52
  return error instanceof AppError;
53
53
  }
@@ -75,7 +75,7 @@ var init_errors = __esm(() => {
75
75
  };
76
76
  });
77
77
 
78
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.8/node_modules/@gobing-ai/ts-utils/dist/api-response.js
78
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.10/node_modules/@gobing-ai/ts-utils/dist/api-response.js
79
79
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
80
80
  var init_api_response = __esm(() => {
81
81
  init_errors();
@@ -98,10 +98,10 @@ var init_api_response = __esm(() => {
98
98
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
99
99
  });
100
100
 
101
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.8/node_modules/@gobing-ai/ts-utils/dist/cursor.js
101
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.10/node_modules/@gobing-ai/ts-utils/dist/cursor.js
102
102
  var init_cursor = () => {};
103
103
 
104
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.8/node_modules/@gobing-ai/ts-utils/dist/object.js
104
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.10/node_modules/@gobing-ai/ts-utils/dist/object.js
105
105
  function isPlainObject(value) {
106
106
  return typeof value === "object" && value !== null && !Array.isArray(value);
107
107
  }
@@ -117,7 +117,7 @@ function deepMerge(target, source) {
117
117
  return result;
118
118
  }
119
119
 
120
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.8/node_modules/@gobing-ai/ts-utils/dist/output.js
120
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.10/node_modules/@gobing-ai/ts-utils/dist/output.js
121
121
  function processStream(name) {
122
122
  const proc = globalThis.process;
123
123
  const stream = proc?.[name];
@@ -138,7 +138,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
138
138
  }
139
139
  var defaultStdoutTarget, defaultStderrTarget;
140
140
 
141
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.8/node_modules/@gobing-ai/ts-utils/dist/index.js
141
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.10/node_modules/@gobing-ai/ts-utils/dist/index.js
142
142
  var init_dist = __esm(() => {
143
143
  init_api_response();
144
144
  init_cursor();
@@ -21760,7 +21760,10 @@ var init_zod = __esm(() => {
21760
21760
  init_external();
21761
21761
  });
21762
21762
 
21763
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/config.js
21763
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/config.js
21764
+ function getProcessEnv() {
21765
+ return process.env;
21766
+ }
21764
21767
  function interpolateEnv(value) {
21765
21768
  return value.replace(ENV_INTERPOLATION_RE, (_match, name) => process.env[name] ?? `\${${name}}`);
21766
21769
  }
@@ -21835,7 +21838,7 @@ var init_config = __esm(() => {
21835
21838
  };
21836
21839
  });
21837
21840
 
21838
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21841
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21839
21842
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
21840
21843
  import { dirname, resolve as resolvePath } from "path";
21841
21844
  function createNodeFileSystem(root) {
@@ -21922,6 +21925,17 @@ function findProjectRoot(startDir) {
21922
21925
  }
21923
21926
  var init_file_system_node = () => {};
21924
21927
 
21928
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21929
+ var DbModuleNotInstalledError;
21930
+ var init_db_errors = __esm(() => {
21931
+ DbModuleNotInstalledError = class DbModuleNotInstalledError extends Error {
21932
+ constructor(message = "@gobing-ai/ts-db is not installed. It is an optional peer of @gobing-ai/ts-runtime, required only for createDbAdapter on node-bun. Install it (`bun add @gobing-ai/ts-db`) or, when bundling, mark `@gobing-ai/ts-db` external.", options) {
21933
+ super(message, options);
21934
+ this.name = "DbModuleNotInstalledError";
21935
+ }
21936
+ };
21937
+ });
21938
+
21925
21939
  // ../../node_modules/.bun/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
21926
21940
  function isPlainObject4(value) {
21927
21941
  if (typeof value !== "object" || value === null) {
@@ -29102,10 +29116,10 @@ var init_execa = __esm(() => {
29102
29116
  } = getIpcExport());
29103
29117
  });
29104
29118
 
29105
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29119
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29106
29120
  import { isatty } from "tty";
29107
29121
 
29108
- class ProcessExecutor {
29122
+ class NodeProcessExecutor {
29109
29123
  config;
29110
29124
  constructor(config2 = {}) {
29111
29125
  this.config = config2;
@@ -29126,13 +29140,21 @@ class ProcessExecutor {
29126
29140
  signal: options.signal
29127
29141
  });
29128
29142
  const startedAt = Date.now();
29143
+ const startedIso = new Date(startedAt).toISOString();
29144
+ const registryId = this.beginRegistry(options.command, args, {
29145
+ label: options.label,
29146
+ source: options.source ?? "one-shot",
29147
+ teamId: options.teamId,
29148
+ agentId: options.agentId,
29149
+ startedAt: startedIso
29150
+ });
29129
29151
  this.emitProcessEvent("process.started", {
29130
29152
  command: options.command,
29131
29153
  args,
29132
29154
  exitCode: null,
29133
29155
  durationMs: 0,
29134
29156
  reason: "exit",
29135
- timestamp: new Date(startedAt).toISOString(),
29157
+ timestamp: startedIso,
29136
29158
  ...options.label !== undefined ? { label: options.label } : {}
29137
29159
  });
29138
29160
  try {
@@ -29146,6 +29168,7 @@ class ProcessExecutor {
29146
29168
  ...result.signalDescription !== undefined ? { signal: result.signalDescription } : {},
29147
29169
  durationMs: result.durationMs
29148
29170
  };
29171
+ this.completeRegistry(registryId, processResult.exitCode);
29149
29172
  this.emitExitedFromResult(options, processResult, result);
29150
29173
  return processResult;
29151
29174
  } catch (error51) {
@@ -29159,6 +29182,7 @@ class ProcessExecutor {
29159
29182
  ...failed.signalDescription !== undefined ? { signal: failed.signalDescription } : failed.signal !== undefined ? { signal: failed.signal } : {},
29160
29183
  durationMs: failed.durationMs ?? Date.now() - startedAt
29161
29184
  };
29185
+ this.completeRegistry(registryId, processResult.exitCode);
29162
29186
  this.emitExitedFromResult(options, processResult, error51, error51);
29163
29187
  if (options.rejectOnError)
29164
29188
  throw error51;
@@ -29172,15 +29196,23 @@ class ProcessExecutor {
29172
29196
  }).catch(() => {
29173
29197
  return;
29174
29198
  });
29199
+ const startedAt = Date.now();
29200
+ const startedIso = new Date(startedAt).toISOString();
29201
+ const registryId = this.beginRegistry(options.command, args, {
29202
+ label: options.label,
29203
+ source: options.source ?? "other",
29204
+ teamId: options.teamId,
29205
+ agentId: options.agentId,
29206
+ startedAt: startedIso
29207
+ });
29175
29208
  try {
29176
- const startedAt = Date.now();
29177
29209
  this.emitProcessEvent("process.started", {
29178
29210
  command: options.command,
29179
29211
  args,
29180
29212
  exitCode: null,
29181
29213
  durationMs: 0,
29182
29214
  reason: "exit",
29183
- timestamp: new Date(startedAt).toISOString(),
29215
+ timestamp: startedIso,
29184
29216
  ...options.label !== undefined ? { label: options.label } : {}
29185
29217
  });
29186
29218
  const subprocess = Bun.spawn({
@@ -29191,13 +29223,20 @@ class ProcessExecutor {
29191
29223
  ...options.cwd !== undefined ? { cwd: options.cwd } : {},
29192
29224
  ...options.env !== undefined ? { env: options.env } : {}
29193
29225
  });
29194
- return new ObservedPipeProcess(new BunPipeProcess(subprocess), this.config.events, {
29226
+ const pipe2 = new BunPipeProcess(subprocess);
29227
+ if (pipe2.pid !== null) {
29228
+ this.config.registry?.update(registryId, { pid: pipe2.pid });
29229
+ }
29230
+ return new ObservedPipeProcess(pipe2, this.config.events, {
29195
29231
  command: options.command,
29196
29232
  args,
29197
29233
  startedAt,
29234
+ registry: this.config.registry,
29235
+ registryId,
29198
29236
  ...options.label !== undefined ? { label: options.label } : {}
29199
29237
  });
29200
29238
  } catch (error51) {
29239
+ this.completeRegistry(registryId, null);
29201
29240
  this.emitProcessEvent("process.exited", {
29202
29241
  command: options.command,
29203
29242
  args,
@@ -29216,6 +29255,28 @@ class ProcessExecutor {
29216
29255
  return await fn();
29217
29256
  return await this.config.tracer.traceAsync(name, async () => await fn());
29218
29257
  }
29258
+ beginRegistry(command, args, meta3) {
29259
+ const registry2 = this.config.registry;
29260
+ if (!registry2)
29261
+ return "";
29262
+ return registry2.begin({
29263
+ command,
29264
+ args,
29265
+ source: meta3.source,
29266
+ startedAt: meta3.startedAt,
29267
+ ...meta3.label !== undefined ? { label: meta3.label } : {},
29268
+ ...meta3.teamId !== undefined ? { teamId: meta3.teamId } : {},
29269
+ ...meta3.agentId !== undefined ? { agentId: meta3.agentId } : {}
29270
+ });
29271
+ }
29272
+ completeRegistry(id, exitCode, pid) {
29273
+ if (!id || !this.config.registry)
29274
+ return;
29275
+ this.config.registry.complete(id, {
29276
+ exitCode,
29277
+ ...pid !== undefined ? { pid } : {}
29278
+ });
29279
+ }
29219
29280
  emitExitedFromResult(options, result, completion, error51) {
29220
29281
  const reason = isTimedOut(completion) ? "timeout" : result.signal !== undefined ? "signal" : error51 ? "error" : "exit";
29221
29282
  this.emitProcessEvent("process.exited", {
@@ -29242,6 +29303,12 @@ class ObservedPipeProcess {
29242
29303
  constructor(inner, events, context) {
29243
29304
  this.inner = inner;
29244
29305
  this.exited = inner.exited.then((exitCode) => {
29306
+ if (context.registry && context.registryId) {
29307
+ context.registry.complete(context.registryId, {
29308
+ exitCode,
29309
+ ...inner.pid !== null ? { pid: inner.pid } : {}
29310
+ });
29311
+ }
29245
29312
  events?.emit("process.exited", {
29246
29313
  command: context.command,
29247
29314
  args: context.args,
@@ -29342,7 +29409,67 @@ var init_process_executor = __esm(() => {
29342
29409
  init_execa();
29343
29410
  });
29344
29411
 
29345
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/context.js
29412
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29413
+ function getNodeFileSystem() {
29414
+ if (!_nodeFileSystem)
29415
+ _nodeFileSystem = createNodeFileSystem();
29416
+ return _nodeFileSystem;
29417
+ }
29418
+ async function loadNodeConfig(options) {
29419
+ const fs = getNodeFileSystem();
29420
+ const raw = await readYamlConfig(fs);
29421
+ return buildConfigFromObject(raw ?? {}, options);
29422
+ }
29423
+ async function readYamlConfig(fs) {
29424
+ const candidates = [getProcessEnv().CONFIG_PATH, "config/config.yaml", "config/config.example.yaml"].filter((p) => typeof p === "string" && p.length > 0);
29425
+ for (const candidate of candidates) {
29426
+ const resolved = fs.resolve(candidate);
29427
+ if (await fs.exists(resolved)) {
29428
+ const content = await fs.readFile(resolved);
29429
+ try {
29430
+ return $parse(content);
29431
+ } catch {}
29432
+ }
29433
+ }
29434
+ return null;
29435
+ }
29436
+ var _nodeFileSystem, nodeBunFactory;
29437
+ var init_runtime_node_bun = __esm(() => {
29438
+ init_dist2();
29439
+ init_config();
29440
+ init_db_errors();
29441
+ init_file_system_node();
29442
+ init_process_executor();
29443
+ nodeBunFactory = {
29444
+ runtimeName: "node-bun",
29445
+ capabilities: {
29446
+ hasFilesystem: true,
29447
+ hasProcessExecution: true,
29448
+ hasPersistentStorage: true,
29449
+ hasSqlDatabase: true
29450
+ },
29451
+ createFileSystem: () => getNodeFileSystem(),
29452
+ createProcessExecutor: (config2) => new NodeProcessExecutor(config2),
29453
+ async loadConfig(options) {
29454
+ return loadNodeConfig(options);
29455
+ },
29456
+ async createDbAdapter(config2) {
29457
+ const tsDbSpec = "@gobing-ai/ts-db";
29458
+ let mod;
29459
+ try {
29460
+ mod = await import(tsDbSpec);
29461
+ } catch (cause) {
29462
+ throw new DbModuleNotInstalledError(undefined, { cause });
29463
+ }
29464
+ if (typeof mod.createDbAdapter !== "function") {
29465
+ throw new DbModuleNotInstalledError("@gobing-ai/ts-db is installed but does not export createDbAdapter \u2014 the installed version may be incompatible or partial.");
29466
+ }
29467
+ return mod.createDbAdapter({ driver: "bun-sqlite", url: config2.url });
29468
+ }
29469
+ };
29470
+ });
29471
+
29472
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/context.js
29346
29473
  class RuntimeContext {
29347
29474
  scope;
29348
29475
  runtimeName;
@@ -29360,7 +29487,7 @@ class RuntimeContext {
29360
29487
  this.register("config", options.services?.config ?? buildConfigFromObject({}));
29361
29488
  this.register("fileSystem", options.services?.fileSystem ?? createNodeFileSystem());
29362
29489
  if (this.capabilities.hasProcessExecution && options.services?.processExecutor === undefined) {
29363
- this.register("processExecutor", new ProcessExecutor);
29490
+ this.register("processExecutor", nodeBunFactory.createProcessExecutor());
29364
29491
  }
29365
29492
  for (const [key, value] of Object.entries(options.services ?? {})) {
29366
29493
  if (value !== undefined) {
@@ -29409,10 +29536,10 @@ function isDisposable(value) {
29409
29536
  var init_context = __esm(() => {
29410
29537
  init_config();
29411
29538
  init_file_system_node();
29412
- init_process_executor();
29539
+ init_runtime_node_bun();
29413
29540
  });
29414
29541
 
29415
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/path.js
29542
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/path.js
29416
29543
  function normalizeSeparators(path6) {
29417
29544
  return path6.replaceAll("\\", "/");
29418
29545
  }
@@ -29473,17 +29600,17 @@ var init_path = __esm(() => {
29473
29600
  SEP = globalThis.process?.platform === "win32" ? "\\" : "/";
29474
29601
  });
29475
29602
 
29476
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29603
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29477
29604
  var REMOTE_SCHEMA_MAX_BYTES;
29478
29605
  var init_schema_validation = __esm(() => {
29479
29606
  init_dist2();
29480
29607
  REMOTE_SCHEMA_MAX_BYTES = 5 * 1024 * 1024;
29481
29608
  });
29482
29609
 
29483
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/types.js
29610
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/types.js
29484
29611
  var init_types = () => {};
29485
29612
 
29486
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/index.js
29613
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/index.js
29487
29614
  var init_dist3 = __esm(() => {
29488
29615
  init_config();
29489
29616
  init_context();
@@ -29492,7 +29619,7 @@ var init_dist3 = __esm(() => {
29492
29619
  init_types();
29493
29620
  });
29494
29621
 
29495
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+25c63b82bf4f1018/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29622
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+170d5985e987c687/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29496
29623
  import { Database } from "bun:sqlite";
29497
29624
  var init_bun_sqlite = () => {};
29498
29625
 
@@ -33684,7 +33811,7 @@ var init_bun_sqlite2 = __esm(() => {
33684
33811
  init_session2();
33685
33812
  });
33686
33813
 
33687
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33814
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33688
33815
  var inboxMessages;
33689
33816
  var init_inbox_messages = __esm(() => {
33690
33817
  init_sqlite_core();
@@ -33703,7 +33830,7 @@ var init_inbox_messages = __esm(() => {
33703
33830
  }, (table2) => [index("idx_inbox_messages_to_status").on(table2.toId, table2.status)]);
33704
33831
  });
33705
33832
 
33706
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33833
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33707
33834
  function nowTimestamp() {
33708
33835
  return Date.now();
33709
33836
  }
@@ -33732,7 +33859,7 @@ var init_common3 = __esm(() => {
33732
33859
  appendOnlyColumns = buildAppendOnlyColumns();
33733
33860
  });
33734
33861
 
33735
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33862
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33736
33863
  var queueJobs;
33737
33864
  var init_queue_jobs = __esm(() => {
33738
33865
  init_sqlite_core();
@@ -33752,7 +33879,7 @@ var init_queue_jobs = __esm(() => {
33752
33879
  }, (table2) => [index("queue_jobs_ready_idx").on(table2.status, table2.nextRetryAt, table2.createdAt)]);
33753
33880
  });
33754
33881
 
33755
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33882
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33756
33883
  var exports_runtime = {};
33757
33884
  __export(exports_runtime, {
33758
33885
  queueJobs: () => queueJobs,
@@ -33763,7 +33890,7 @@ var init_runtime = __esm(() => {
33763
33890
  init_queue_jobs();
33764
33891
  });
33765
33892
 
33766
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33893
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33767
33894
  var exports_bun_sqlite = {};
33768
33895
  __export(exports_bun_sqlite, {
33769
33896
  BunSqliteAdapter: () => BunSqliteAdapter
@@ -34052,7 +34179,7 @@ var init_d1 = __esm(() => {
34052
34179
  init_session3();
34053
34180
  });
34054
34181
 
34055
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34182
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34056
34183
  var exports_d1 = {};
34057
34184
  __export(exports_d1, {
34058
34185
  D1Adapter: () => D1Adapter
@@ -34116,7 +34243,7 @@ var init_d12 = __esm(() => {
34116
34243
  init_runtime();
34117
34244
  });
34118
34245
 
34119
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/adapter.js
34246
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/adapter.js
34120
34247
  async function createDbAdapter(config3) {
34121
34248
  switch (config3.driver) {
34122
34249
  case "bun-sqlite": {
@@ -34156,7 +34283,7 @@ var init_drizzle_orm = __esm(() => {
34156
34283
  init_view_common();
34157
34284
  });
34158
34285
 
34159
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34286
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34160
34287
  function compilePredicate(predicate) {
34161
34288
  if ("and" in predicate) {
34162
34289
  const parts = predicate.and.map(compilePredicate).filter((p) => p !== undefined);
@@ -34194,7 +34321,7 @@ var init_query_spec = __esm(() => {
34194
34321
  };
34195
34322
  });
34196
34323
 
34197
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34324
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34198
34325
  function asSelectQuery(query) {
34199
34326
  return query;
34200
34327
  }
@@ -34236,7 +34363,7 @@ var init_base_dao = __esm(() => {
34236
34363
  init_query_spec();
34237
34364
  });
34238
34365
 
34239
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34366
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34240
34367
  var embeddedMigrations;
34241
34368
  var init_embedded_migrations = __esm(() => {
34242
34369
  embeddedMigrations = [
@@ -34268,7 +34395,7 @@ var init_embedded_migrations = __esm(() => {
34268
34395
  ];
34269
34396
  });
34270
34397
 
34271
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34398
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34272
34399
  var EntityDao;
34273
34400
  var init_entity_dao = __esm(() => {
34274
34401
  init_drizzle_orm();
@@ -34430,18 +34557,24 @@ var init_entity_dao = __esm(() => {
34430
34557
  };
34431
34558
  });
34432
34559
 
34433
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34560
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34561
+ function isPromiseLike(value) {
34562
+ return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
34563
+ }
34434
34564
  var InboxMessageDao;
34435
34565
  var init_inbox_message_dao = __esm(() => {
34436
34566
  init_drizzle_orm();
34437
34567
  init_entity_dao();
34438
34568
  init_inbox_messages();
34439
34569
  InboxMessageDao = class InboxMessageDao extends EntityDao {
34440
- constructor(adapter) {
34570
+ events;
34571
+ constructor(adapter, options = {}) {
34441
34572
  super(adapter, inboxMessages, [inboxMessages.id], "inbox_messages");
34573
+ this.events = options.events;
34442
34574
  }
34443
34575
  async enqueue(fromId, toId, body, inReplyTo) {
34444
34576
  const id = crypto.randomUUID();
34577
+ const now = this.now();
34445
34578
  await this.create({
34446
34579
  id,
34447
34580
  fromId,
@@ -34449,8 +34582,17 @@ var init_inbox_message_dao = __esm(() => {
34449
34582
  body,
34450
34583
  status: "queued",
34451
34584
  injectAttempts: 0,
34585
+ createdAt: now,
34586
+ updatedAt: now,
34452
34587
  ...inReplyTo !== undefined ? { inReplyTo } : {}
34453
34588
  });
34589
+ this.emitEvent("message.enqueued", {
34590
+ id,
34591
+ fromId,
34592
+ toId,
34593
+ ...inReplyTo !== undefined ? { inReplyTo } : {},
34594
+ timestamp: now
34595
+ });
34454
34596
  return id;
34455
34597
  }
34456
34598
  async drainPending(toId) {
@@ -34467,19 +34609,48 @@ var init_inbox_message_dao = __esm(() => {
34467
34609
  ORDER BY created_at
34468
34610
  )
34469
34611
  AND ${inboxMessages.status} = 'queued'`).returning();
34612
+ for (const row of rows) {
34613
+ this.emitEvent("message.injected", {
34614
+ id: row.id,
34615
+ fromId: row.fromId,
34616
+ toId: row.toId,
34617
+ inReplyTo: row.inReplyTo,
34618
+ injectAttempts: row.injectAttempts,
34619
+ timestamp: now
34620
+ });
34621
+ }
34470
34622
  return rows;
34471
34623
  }
34472
34624
  async markDelivered(msgId) {
34473
- await this.update(msgId, {
34625
+ const now = this.now();
34626
+ const updated = await this.update(msgId, {
34474
34627
  status: "delivered",
34475
- deliveredAt: this.now()
34628
+ deliveredAt: now
34476
34629
  });
34630
+ if (updated) {
34631
+ this.emitEvent("message.delivered", {
34632
+ id: updated.id,
34633
+ fromId: updated.fromId,
34634
+ toId: updated.toId,
34635
+ deliveredAt: now,
34636
+ timestamp: now
34637
+ });
34638
+ }
34477
34639
  }
34478
34640
  async markFailed(msgId, error51) {
34479
- await this.update(msgId, {
34641
+ const updated = await this.update(msgId, {
34480
34642
  status: "failed",
34481
34643
  injectError: error51
34482
34644
  });
34645
+ if (updated) {
34646
+ this.emitEvent("message.failed", {
34647
+ id: updated.id,
34648
+ fromId: updated.fromId,
34649
+ toId: updated.toId,
34650
+ error: error51,
34651
+ timestamp: updated.updatedAt
34652
+ });
34653
+ }
34483
34654
  }
34484
34655
  async inbox(toId, limit, offset) {
34485
34656
  return this.list({
@@ -34500,6 +34671,16 @@ var init_inbox_message_dao = __esm(() => {
34500
34671
  async getById(id) {
34501
34672
  return this.findBy(inboxMessages.id, id);
34502
34673
  }
34674
+ emitEvent(event, ...args) {
34675
+ if (!this.events)
34676
+ return;
34677
+ try {
34678
+ const pending = this.events.emit(event, ...args);
34679
+ if (isPromiseLike(pending)) {
34680
+ Promise.resolve(pending).catch(() => {});
34681
+ }
34682
+ } catch {}
34683
+ }
34503
34684
  };
34504
34685
  });
34505
34686
 
@@ -34549,7 +34730,7 @@ var init_migrator2 = __esm(() => {
34549
34730
  init_migrator();
34550
34731
  });
34551
34732
 
34552
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/migrate.js
34733
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/migrate.js
34553
34734
  async function ensureJournalTable(adapter, table3) {
34554
34735
  await adapter.exec(`CREATE TABLE IF NOT EXISTS "${table3}" (` + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "hash text NOT NULL, " + "created_at numeric" + ")");
34555
34736
  }
@@ -34624,7 +34805,7 @@ var init_migrate = __esm(() => {
34624
34805
  init_embedded_migrations();
34625
34806
  });
34626
34807
 
34627
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34808
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34628
34809
  var QueueJobDao;
34629
34810
  var init_queue_job_dao = __esm(() => {
34630
34811
  init_drizzle_orm();
@@ -34765,7 +34946,7 @@ var init_queue_job_dao = __esm(() => {
34765
34946
  };
34766
34947
  });
34767
34948
 
34768
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/index.js
34949
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/index.js
34769
34950
  var exports_dist = {};
34770
34951
  __export(exports_dist, {
34771
34952
  embeddedMigrations: () => embeddedMigrations,
@@ -36904,6 +37085,18 @@ var require_extra_typings = __commonJS((exports, module) => {
36904
37085
  function folderPathWithDefault(defaultPath) {
36905
37086
  return exports_external.preprocess((v) => v == null ? undefined : v, exports_external.string().default(defaultPath));
36906
37087
  }
37088
+ function normalizeMember(member) {
37089
+ return typeof member === "string" ? { executor: member } : { ...member };
37090
+ }
37091
+ function resolveExecutor(name, agentConfig, opts) {
37092
+ const exec = agentConfig?.executors?.find((entry) => entry.name === name);
37093
+ if (exec !== undefined)
37094
+ return { agent: exec.agent, model: exec.model };
37095
+ if (opts?.isCanonicalAgent === undefined || opts.isCanonicalAgent(name)) {
37096
+ return { agent: name };
37097
+ }
37098
+ throw new Error(`Unknown executor or agent reference: "${name}"`);
37099
+ }
36907
37100
  function parseEnvBoolean(value) {
36908
37101
  if (value === undefined || value === "")
36909
37102
  return;
@@ -36932,7 +37125,7 @@ function buildConfigFromEnv(env = process.env) {
36932
37125
  }
36933
37126
  });
36934
37127
  }
36935
- var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, AgentExecutorConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, RedactionConfigSchema, spurConfigSchema, configSchema2;
37128
+ var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, AgentExecutorConfigSchema, AGENT_ID_REGEX, TeamMemberConfigSchema, TeamConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, RedactionConfigSchema, spurConfigSchema, configSchema2;
36936
37129
  var init_src = __esm(() => {
36937
37130
  init_zod();
36938
37131
  SPUR_ENV_VARS = {
@@ -36959,24 +37152,81 @@ var init_src = __esm(() => {
36959
37152
  agent: exports_external.string().min(1),
36960
37153
  model: exports_external.string().min(1).optional()
36961
37154
  });
37155
+ AGENT_ID_REGEX = /^[a-z][a-z0-9_-]{1,63}$/;
37156
+ TeamMemberConfigSchema = exports_external.union([
37157
+ exports_external.string().min(1),
37158
+ exports_external.object({
37159
+ executor: exports_external.string().min(1),
37160
+ id: exports_external.string().min(1).optional(),
37161
+ purpose: exports_external.string().optional(),
37162
+ workspace: exports_external.string().min(1).optional(),
37163
+ model: exports_external.string().min(1).optional(),
37164
+ autonomy: exports_external.string().optional(),
37165
+ systemPrompt: exports_external.string().optional(),
37166
+ command: exports_external.array(exports_external.string().min(1)).optional(),
37167
+ autostart: exports_external.boolean().optional()
37168
+ })
37169
+ ]);
37170
+ TeamConfigSchema = exports_external.object({
37171
+ name: exports_external.string().min(1),
37172
+ work_dir: exports_external.string().min(1),
37173
+ autostart: exports_external.boolean().optional(),
37174
+ members: exports_external.array(TeamMemberConfigSchema).min(1)
37175
+ });
36962
37176
  AgentConfigSchema = exports_external.object({
36963
37177
  default: exports_external.string().optional(),
36964
37178
  executors: exports_external.array(AgentExecutorConfigSchema).optional(),
36965
- "default-by-phase": exports_external.record(exports_external.string(), exports_external.string()).optional()
37179
+ "default-by-phase": exports_external.record(exports_external.string(), exports_external.string()).optional(),
37180
+ team: exports_external.record(exports_external.string(), TeamConfigSchema).optional()
36966
37181
  }).superRefine((value, ctx) => {
36967
37182
  const executors = value.executors;
36968
- if (executors === undefined)
36969
- return;
36970
- const seen = new Set;
36971
- for (const [index2, executor] of executors.entries()) {
36972
- if (seen.has(executor.name)) {
36973
- ctx.addIssue({
36974
- code: exports_external.ZodIssueCode.custom,
36975
- message: `Duplicate executor name: ${executor.name}`,
36976
- path: ["executors", index2, "name"]
36977
- });
37183
+ if (executors !== undefined) {
37184
+ const seen = new Set;
37185
+ for (const [index2, executor] of executors.entries()) {
37186
+ if (seen.has(executor.name)) {
37187
+ ctx.addIssue({
37188
+ code: exports_external.ZodIssueCode.custom,
37189
+ message: `Duplicate executor name: ${executor.name}`,
37190
+ path: ["executors", index2, "name"]
37191
+ });
37192
+ }
37193
+ seen.add(executor.name);
36978
37194
  }
36979
- seen.add(executor.name);
37195
+ }
37196
+ const team = value.team;
37197
+ if (team === undefined)
37198
+ return;
37199
+ const seenComposed = new Set;
37200
+ for (const [teamId, teamConfig] of Object.entries(team)) {
37201
+ const seenLocal = new Set;
37202
+ teamConfig.members.forEach((member, index2) => {
37203
+ const ref = normalizeMember(member);
37204
+ const localId = ref.id ?? ref.executor;
37205
+ if (seenLocal.has(localId)) {
37206
+ ctx.addIssue({
37207
+ code: exports_external.ZodIssueCode.custom,
37208
+ message: `Duplicate team member id: ${localId} in team "${teamId}"`,
37209
+ path: ["team", teamId, "members", index2]
37210
+ });
37211
+ }
37212
+ seenLocal.add(localId);
37213
+ const composedId = `${teamId}-${localId}`;
37214
+ if (!AGENT_ID_REGEX.test(composedId)) {
37215
+ ctx.addIssue({
37216
+ code: exports_external.ZodIssueCode.custom,
37217
+ message: `Invalid composed agent id "${composedId}": team key "${teamId}" + member "${localId}" must match ^[a-z][a-z0-9_-]{1,63}$ (2-64 chars, lowercase).`,
37218
+ path: ["team", teamId, "members", index2]
37219
+ });
37220
+ }
37221
+ if (seenComposed.has(composedId)) {
37222
+ ctx.addIssue({
37223
+ code: exports_external.ZodIssueCode.custom,
37224
+ message: `Composed agent id "${composedId}" collides across teams \u2014 every <teamId>-<localId> must be globally unique (a hyphenated team key can overlap another team's member id).`,
37225
+ path: ["team", teamId, "members", index2]
37226
+ });
37227
+ }
37228
+ seenComposed.add(composedId);
37229
+ });
36980
37230
  }
36981
37231
  });
36982
37232
  RulesConfigSchema = exports_external.object({
@@ -37018,7 +37268,7 @@ var init_src = __esm(() => {
37018
37268
  });
37019
37269
  });
37020
37270
 
37021
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/config.js
37271
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/config.js
37022
37272
  function parseYamlObject(text3) {
37023
37273
  let parsed;
37024
37274
  try {
@@ -37042,7 +37292,7 @@ function getNodeEnv() {
37042
37292
  function isTestEnv() {
37043
37293
  return getNodeEnv() === "test";
37044
37294
  }
37045
- function getProcessEnv() {
37295
+ function getProcessEnv2() {
37046
37296
  return process.env;
37047
37297
  }
37048
37298
  function getDatabaseUrl() {
@@ -37145,7 +37395,7 @@ var init_config2 = __esm(() => {
37145
37395
  };
37146
37396
  });
37147
37397
 
37148
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37398
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37149
37399
  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";
37150
37400
  import { dirname as dirname2, resolve as resolvePath3 } from "path";
37151
37401
  function createNodeFileSystem3(root) {
@@ -37232,16 +37482,16 @@ function findProjectRoot3(startDir) {
37232
37482
  }
37233
37483
  var init_file_system_node2 = () => {};
37234
37484
 
37235
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37236
- var D1NotConfiguredError2, DbModuleNotInstalledError2;
37237
- var init_db_errors = __esm(() => {
37485
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37486
+ var D1NotConfiguredError2, DbModuleNotInstalledError3;
37487
+ var init_db_errors2 = __esm(() => {
37238
37488
  D1NotConfiguredError2 = class D1NotConfiguredError2 extends Error {
37239
37489
  constructor(message = "D1 DbAdapter is not yet implemented; see the ts-db D1 round.") {
37240
37490
  super(message);
37241
37491
  this.name = "D1NotConfiguredError";
37242
37492
  }
37243
37493
  };
37244
- DbModuleNotInstalledError2 = class DbModuleNotInstalledError2 extends Error {
37494
+ DbModuleNotInstalledError3 = class DbModuleNotInstalledError3 extends Error {
37245
37495
  constructor(message = "@gobing-ai/ts-db is not installed. It is an optional peer of @gobing-ai/ts-runtime, required only for createDbAdapter on node-bun. Install it (`bun add @gobing-ai/ts-db`) or, when bundling, mark `@gobing-ai/ts-db` external.", options) {
37246
37496
  super(message, options);
37247
37497
  this.name = "DbModuleNotInstalledError";
@@ -37249,7 +37499,7 @@ var init_db_errors = __esm(() => {
37249
37499
  };
37250
37500
  });
37251
37501
 
37252
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37502
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37253
37503
  function createCfFileSystem2() {
37254
37504
  return {
37255
37505
  getProjectRoot: () => "/bundle",
@@ -37288,7 +37538,7 @@ function createCfFileSystem2() {
37288
37538
  }
37289
37539
  var UNSUPPORTED = "FileSystem is not available on Cloudflare Workers. Use D1, KV, or R2 for persistent storage.";
37290
37540
 
37291
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37541
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37292
37542
  var exports_runtime_cf = {};
37293
37543
  __export(exports_runtime_cf, {
37294
37544
  cloudflareWorkersFactory: () => cloudflareWorkersFactory2
@@ -37297,7 +37547,7 @@ var CONFIG_YAML_BINDING = "CONFIG_YAML", cloudflareWorkersFactory2;
37297
37547
  var init_runtime_cf = __esm(() => {
37298
37548
  init_dist2();
37299
37549
  init_config2();
37300
- init_db_errors();
37550
+ init_db_errors2();
37301
37551
  cloudflareWorkersFactory2 = {
37302
37552
  runtimeName: "cloudflare-workers",
37303
37553
  capabilities: {
@@ -37326,10 +37576,10 @@ var init_runtime_cf = __esm(() => {
37326
37576
  };
37327
37577
  });
37328
37578
 
37329
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37579
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37330
37580
  import { isatty as isatty2 } from "tty";
37331
37581
 
37332
- class ProcessExecutor3 {
37582
+ class NodeProcessExecutor3 {
37333
37583
  config;
37334
37584
  constructor(config3 = {}) {
37335
37585
  this.config = config3;
@@ -37350,13 +37600,21 @@ class ProcessExecutor3 {
37350
37600
  signal: options.signal
37351
37601
  });
37352
37602
  const startedAt = Date.now();
37603
+ const startedIso = new Date(startedAt).toISOString();
37604
+ const registryId = this.beginRegistry(options.command, args, {
37605
+ label: options.label,
37606
+ source: options.source ?? "one-shot",
37607
+ teamId: options.teamId,
37608
+ agentId: options.agentId,
37609
+ startedAt: startedIso
37610
+ });
37353
37611
  this.emitProcessEvent("process.started", {
37354
37612
  command: options.command,
37355
37613
  args,
37356
37614
  exitCode: null,
37357
37615
  durationMs: 0,
37358
37616
  reason: "exit",
37359
- timestamp: new Date(startedAt).toISOString(),
37617
+ timestamp: startedIso,
37360
37618
  ...options.label !== undefined ? { label: options.label } : {}
37361
37619
  });
37362
37620
  try {
@@ -37370,6 +37628,7 @@ class ProcessExecutor3 {
37370
37628
  ...result.signalDescription !== undefined ? { signal: result.signalDescription } : {},
37371
37629
  durationMs: result.durationMs
37372
37630
  };
37631
+ this.completeRegistry(registryId, processResult.exitCode);
37373
37632
  this.emitExitedFromResult(options, processResult, result);
37374
37633
  return processResult;
37375
37634
  } catch (error51) {
@@ -37383,6 +37642,7 @@ class ProcessExecutor3 {
37383
37642
  ...failed.signalDescription !== undefined ? { signal: failed.signalDescription } : failed.signal !== undefined ? { signal: failed.signal } : {},
37384
37643
  durationMs: failed.durationMs ?? Date.now() - startedAt
37385
37644
  };
37645
+ this.completeRegistry(registryId, processResult.exitCode);
37386
37646
  this.emitExitedFromResult(options, processResult, error51, error51);
37387
37647
  if (options.rejectOnError)
37388
37648
  throw error51;
@@ -37396,15 +37656,23 @@ class ProcessExecutor3 {
37396
37656
  }).catch(() => {
37397
37657
  return;
37398
37658
  });
37659
+ const startedAt = Date.now();
37660
+ const startedIso = new Date(startedAt).toISOString();
37661
+ const registryId = this.beginRegistry(options.command, args, {
37662
+ label: options.label,
37663
+ source: options.source ?? "other",
37664
+ teamId: options.teamId,
37665
+ agentId: options.agentId,
37666
+ startedAt: startedIso
37667
+ });
37399
37668
  try {
37400
- const startedAt = Date.now();
37401
37669
  this.emitProcessEvent("process.started", {
37402
37670
  command: options.command,
37403
37671
  args,
37404
37672
  exitCode: null,
37405
37673
  durationMs: 0,
37406
37674
  reason: "exit",
37407
- timestamp: new Date(startedAt).toISOString(),
37675
+ timestamp: startedIso,
37408
37676
  ...options.label !== undefined ? { label: options.label } : {}
37409
37677
  });
37410
37678
  const subprocess = Bun.spawn({
@@ -37415,13 +37683,20 @@ class ProcessExecutor3 {
37415
37683
  ...options.cwd !== undefined ? { cwd: options.cwd } : {},
37416
37684
  ...options.env !== undefined ? { env: options.env } : {}
37417
37685
  });
37418
- return new ObservedPipeProcess2(new BunPipeProcess2(subprocess), this.config.events, {
37686
+ const pipe2 = new BunPipeProcess2(subprocess);
37687
+ if (pipe2.pid !== null) {
37688
+ this.config.registry?.update(registryId, { pid: pipe2.pid });
37689
+ }
37690
+ return new ObservedPipeProcess2(pipe2, this.config.events, {
37419
37691
  command: options.command,
37420
37692
  args,
37421
37693
  startedAt,
37694
+ registry: this.config.registry,
37695
+ registryId,
37422
37696
  ...options.label !== undefined ? { label: options.label } : {}
37423
37697
  });
37424
37698
  } catch (error51) {
37699
+ this.completeRegistry(registryId, null);
37425
37700
  this.emitProcessEvent("process.exited", {
37426
37701
  command: options.command,
37427
37702
  args,
@@ -37440,6 +37715,28 @@ class ProcessExecutor3 {
37440
37715
  return await fn();
37441
37716
  return await this.config.tracer.traceAsync(name, async () => await fn());
37442
37717
  }
37718
+ beginRegistry(command, args, meta3) {
37719
+ const registry2 = this.config.registry;
37720
+ if (!registry2)
37721
+ return "";
37722
+ return registry2.begin({
37723
+ command,
37724
+ args,
37725
+ source: meta3.source,
37726
+ startedAt: meta3.startedAt,
37727
+ ...meta3.label !== undefined ? { label: meta3.label } : {},
37728
+ ...meta3.teamId !== undefined ? { teamId: meta3.teamId } : {},
37729
+ ...meta3.agentId !== undefined ? { agentId: meta3.agentId } : {}
37730
+ });
37731
+ }
37732
+ completeRegistry(id, exitCode, pid) {
37733
+ if (!id || !this.config.registry)
37734
+ return;
37735
+ this.config.registry.complete(id, {
37736
+ exitCode,
37737
+ ...pid !== undefined ? { pid } : {}
37738
+ });
37739
+ }
37443
37740
  emitExitedFromResult(options, result, completion, error51) {
37444
37741
  const reason = isTimedOut2(completion) ? "timeout" : result.signal !== undefined ? "signal" : error51 ? "error" : "exit";
37445
37742
  this.emitProcessEvent("process.exited", {
@@ -37466,6 +37763,12 @@ class ObservedPipeProcess2 {
37466
37763
  constructor(inner, events, context2) {
37467
37764
  this.inner = inner;
37468
37765
  this.exited = inner.exited.then((exitCode) => {
37766
+ if (context2.registry && context2.registryId) {
37767
+ context2.registry.complete(context2.registryId, {
37768
+ exitCode,
37769
+ ...inner.pid !== null ? { pid: inner.pid } : {}
37770
+ });
37771
+ }
37469
37772
  events?.emit("process.exited", {
37470
37773
  command: context2.command,
37471
37774
  args: context2.args,
@@ -37607,34 +37910,33 @@ function isTimedOut2(error51) {
37607
37910
  function errorMessage2(error51) {
37608
37911
  return error51 instanceof Error ? error51.message : String(error51);
37609
37912
  }
37610
- var NodeProcessExecutor2;
37913
+ var ProcessExecutor2;
37611
37914
  var init_process_executor2 = __esm(() => {
37612
37915
  init_execa();
37613
- NodeProcessExecutor2 = class NodeProcessExecutor2 extends ProcessExecutor3 {
37614
- };
37916
+ ProcessExecutor2 = NodeProcessExecutor3;
37615
37917
  });
37616
37918
 
37617
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
37919
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
37618
37920
  var exports_runtime_node_bun = {};
37619
37921
  __export(exports_runtime_node_bun, {
37620
- nodeBunFactory: () => nodeBunFactory2,
37922
+ nodeBunFactory: () => nodeBunFactory3,
37621
37923
  _resetNodeFileSystem: () => _resetNodeFileSystem2
37622
37924
  });
37623
- function getNodeFileSystem() {
37624
- if (!_nodeFileSystem)
37625
- _nodeFileSystem = createNodeFileSystem3();
37626
- return _nodeFileSystem;
37925
+ function getNodeFileSystem2() {
37926
+ if (!_nodeFileSystem2)
37927
+ _nodeFileSystem2 = createNodeFileSystem3();
37928
+ return _nodeFileSystem2;
37627
37929
  }
37628
37930
  function _resetNodeFileSystem2() {
37629
- _nodeFileSystem = undefined;
37931
+ _nodeFileSystem2 = undefined;
37630
37932
  }
37631
- async function loadNodeConfig(options) {
37632
- const fs2 = getNodeFileSystem();
37633
- const raw = await readYamlConfig(fs2);
37933
+ async function loadNodeConfig2(options) {
37934
+ const fs2 = getNodeFileSystem2();
37935
+ const raw = await readYamlConfig2(fs2);
37634
37936
  return buildConfigFromObject2(raw ?? {}, options);
37635
37937
  }
37636
- async function readYamlConfig(fs2) {
37637
- const candidates = [getProcessEnv().CONFIG_PATH, "config/config.yaml", "config/config.example.yaml"].filter((p) => typeof p === "string" && p.length > 0);
37938
+ async function readYamlConfig2(fs2) {
37939
+ const candidates = [getProcessEnv2().CONFIG_PATH, "config/config.yaml", "config/config.example.yaml"].filter((p) => typeof p === "string" && p.length > 0);
37638
37940
  for (const candidate of candidates) {
37639
37941
  const resolved = fs2.resolve(candidate);
37640
37942
  if (await fs2.exists(resolved)) {
@@ -37646,14 +37948,14 @@ async function readYamlConfig(fs2) {
37646
37948
  }
37647
37949
  return null;
37648
37950
  }
37649
- var _nodeFileSystem, nodeBunFactory2;
37650
- var init_runtime_node_bun = __esm(() => {
37951
+ var _nodeFileSystem2, nodeBunFactory3;
37952
+ var init_runtime_node_bun2 = __esm(() => {
37651
37953
  init_dist2();
37652
37954
  init_config2();
37653
- init_db_errors();
37955
+ init_db_errors2();
37654
37956
  init_file_system_node2();
37655
37957
  init_process_executor2();
37656
- nodeBunFactory2 = {
37958
+ nodeBunFactory3 = {
37657
37959
  runtimeName: "node-bun",
37658
37960
  capabilities: {
37659
37961
  hasFilesystem: true,
@@ -37661,10 +37963,10 @@ var init_runtime_node_bun = __esm(() => {
37661
37963
  hasPersistentStorage: true,
37662
37964
  hasSqlDatabase: true
37663
37965
  },
37664
- createFileSystem: () => getNodeFileSystem(),
37665
- createProcessExecutor: (config3) => new ProcessExecutor3(config3),
37966
+ createFileSystem: () => getNodeFileSystem2(),
37967
+ createProcessExecutor: (config3) => new NodeProcessExecutor3(config3),
37666
37968
  async loadConfig(options) {
37667
- return loadNodeConfig(options);
37969
+ return loadNodeConfig2(options);
37668
37970
  },
37669
37971
  async createDbAdapter(config3) {
37670
37972
  const tsDbSpec = "@gobing-ai/ts-db";
@@ -37672,17 +37974,17 @@ var init_runtime_node_bun = __esm(() => {
37672
37974
  try {
37673
37975
  mod = await import(tsDbSpec);
37674
37976
  } catch (cause) {
37675
- throw new DbModuleNotInstalledError2(undefined, { cause });
37977
+ throw new DbModuleNotInstalledError3(undefined, { cause });
37676
37978
  }
37677
37979
  if (typeof mod.createDbAdapter !== "function") {
37678
- throw new DbModuleNotInstalledError2("@gobing-ai/ts-db is installed but does not export createDbAdapter \u2014 the installed version may be incompatible or partial.");
37980
+ throw new DbModuleNotInstalledError3("@gobing-ai/ts-db is installed but does not export createDbAdapter \u2014 the installed version may be incompatible or partial.");
37679
37981
  }
37680
37982
  return mod.createDbAdapter({ driver: "bun-sqlite", url: config3.url });
37681
37983
  }
37682
37984
  };
37683
37985
  });
37684
37986
 
37685
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/platform.js
37987
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/platform.js
37686
37988
  function isCloudflareWorkerRuntime2() {
37687
37989
  return globalThis.navigator?.userAgent?.startsWith("Cloudflare-Workers") ?? false;
37688
37990
  }
@@ -37694,8 +37996,8 @@ async function loadRuntimeFactory2() {
37694
37996
  const { cloudflareWorkersFactory: cloudflareWorkersFactory3 } = await Promise.resolve().then(() => (init_runtime_cf(), exports_runtime_cf));
37695
37997
  factory = cloudflareWorkersFactory3;
37696
37998
  } else {
37697
- const { nodeBunFactory: nodeBunFactory3 } = await Promise.resolve().then(() => (init_runtime_node_bun(), exports_runtime_node_bun));
37698
- factory = nodeBunFactory3;
37999
+ const { nodeBunFactory: nodeBunFactory4 } = await Promise.resolve().then(() => (init_runtime_node_bun2(), exports_runtime_node_bun));
38000
+ factory = nodeBunFactory4;
37699
38001
  }
37700
38002
  _factory = factory;
37701
38003
  return factory;
@@ -37712,7 +38014,7 @@ function _resetRuntimeFactory2() {
37712
38014
  }
37713
38015
  var _factory, _runtimeName;
37714
38016
 
37715
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/context.js
38017
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/context.js
37716
38018
  class RuntimeContext2 {
37717
38019
  scope;
37718
38020
  runtimeName;
@@ -37730,7 +38032,7 @@ class RuntimeContext2 {
37730
38032
  this.register("config", options.services?.config ?? buildConfigFromObject2({}));
37731
38033
  this.register("fileSystem", options.services?.fileSystem ?? createNodeFileSystem3());
37732
38034
  if (this.capabilities.hasProcessExecution && options.services?.processExecutor === undefined) {
37733
- this.register("processExecutor", new ProcessExecutor3);
38035
+ this.register("processExecutor", nodeBunFactory3.createProcessExecutor());
37734
38036
  }
37735
38037
  for (const [key, value] of Object.entries(options.services ?? {})) {
37736
38038
  if (value !== undefined) {
@@ -37799,10 +38101,10 @@ function createRuntimeContext(options = {}) {
37799
38101
  var init_context2 = __esm(() => {
37800
38102
  init_config2();
37801
38103
  init_file_system_node2();
37802
- init_process_executor2();
38104
+ init_runtime_node_bun2();
37803
38105
  });
37804
38106
 
37805
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/path.js
38107
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/path.js
37806
38108
  function normalizeSeparators2(path7) {
37807
38109
  return path7.replaceAll("\\", "/");
37808
38110
  }
@@ -37925,7 +38227,7 @@ var init_path2 = __esm(() => {
37925
38227
  SEP2 = globalThis.process?.platform === "win32" ? "\\" : "/";
37926
38228
  });
37927
38229
 
37928
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38230
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/fs.js
37929
38231
  async function ensureDirForFile2(path7, fs2 = createNodeFileSystem3()) {
37930
38232
  await fs2.ensureDir(dirnamePath(path7));
37931
38233
  }
@@ -37976,7 +38278,131 @@ var init_fs = __esm(() => {
37976
38278
  init_path2();
37977
38279
  });
37978
38280
 
37979
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38281
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38282
+ function allocateId() {
38283
+ nextIdSeq += 1;
38284
+ return `pe_${Date.now().toString(36)}_${nextIdSeq.toString(36)}`;
38285
+ }
38286
+
38287
+ class InMemoryProcessRegistry2 {
38288
+ maxEntries;
38289
+ byId = new Map;
38290
+ order = [];
38291
+ listeners = new Set;
38292
+ constructor(options = {}) {
38293
+ this.maxEntries = options.maxEntries ?? 1000;
38294
+ }
38295
+ listExecutions(filter) {
38296
+ const out = [];
38297
+ for (const id of this.order) {
38298
+ const exec = this.byId.get(id);
38299
+ if (!exec)
38300
+ continue;
38301
+ if (filter?.source !== undefined && exec.source !== filter.source)
38302
+ continue;
38303
+ if (filter?.running === true && exec.status !== "running")
38304
+ continue;
38305
+ if (filter?.running === false && exec.status !== "exited")
38306
+ continue;
38307
+ if (filter?.teamId !== undefined && exec.teamId !== filter.teamId)
38308
+ continue;
38309
+ if (filter?.agentId !== undefined && exec.agentId !== filter.agentId)
38310
+ continue;
38311
+ out.push(exec);
38312
+ }
38313
+ return out;
38314
+ }
38315
+ getExecution(id) {
38316
+ return this.byId.get(id);
38317
+ }
38318
+ subscribe(listener) {
38319
+ this.listeners.add(listener);
38320
+ return () => {
38321
+ this.listeners.delete(listener);
38322
+ };
38323
+ }
38324
+ begin(input) {
38325
+ const id = allocateId();
38326
+ const execution = {
38327
+ id,
38328
+ command: input.command,
38329
+ args: Object.freeze([...input.args ?? []]),
38330
+ source: input.source ?? "other",
38331
+ startedAt: input.startedAt ?? new Date().toISOString(),
38332
+ status: "running",
38333
+ ...input.label !== undefined ? { label: input.label } : {},
38334
+ ...input.teamId !== undefined ? { teamId: input.teamId } : {},
38335
+ ...input.agentId !== undefined ? { agentId: input.agentId } : {},
38336
+ ...input.pid !== undefined ? { pid: input.pid } : {}
38337
+ };
38338
+ this.byId.set(id, execution);
38339
+ this.order.push(id);
38340
+ this.enforceCap();
38341
+ this.emit({ type: "started", execution });
38342
+ return id;
38343
+ }
38344
+ update(id, patch) {
38345
+ const current = this.byId.get(id);
38346
+ if (!current)
38347
+ return;
38348
+ const next = {
38349
+ ...current,
38350
+ ...patch.pid !== undefined ? { pid: patch.pid } : {},
38351
+ ...patch.label !== undefined ? { label: patch.label } : {}
38352
+ };
38353
+ this.byId.set(id, next);
38354
+ this.emit({ type: "updated", execution: next });
38355
+ }
38356
+ complete(id, update2 = {}) {
38357
+ const current = this.byId.get(id);
38358
+ if (!current)
38359
+ return;
38360
+ if (current.status === "exited") {
38361
+ if (update2.pid !== undefined && current.pid === undefined) {
38362
+ const patched = { ...current, pid: update2.pid };
38363
+ this.byId.set(id, patched);
38364
+ this.emit({ type: "updated", execution: patched });
38365
+ }
38366
+ return;
38367
+ }
38368
+ const next = {
38369
+ ...current,
38370
+ status: "exited",
38371
+ exitedAt: update2.exitedAt ?? new Date().toISOString(),
38372
+ exitCode: update2.exitCode !== undefined ? update2.exitCode : null,
38373
+ ...update2.pid !== undefined ? { pid: update2.pid } : {}
38374
+ };
38375
+ this.byId.set(id, next);
38376
+ this.emit({ type: "exited", execution: next });
38377
+ }
38378
+ clear() {
38379
+ this.byId.clear();
38380
+ this.order.length = 0;
38381
+ }
38382
+ emit(event) {
38383
+ for (const listener of this.listeners) {
38384
+ try {
38385
+ listener(event);
38386
+ } catch {}
38387
+ }
38388
+ }
38389
+ enforceCap() {
38390
+ while (this.order.length > this.maxEntries) {
38391
+ let dropIdx = this.order.findIndex((id) => this.byId.get(id)?.status === "exited");
38392
+ if (dropIdx < 0)
38393
+ dropIdx = 0;
38394
+ const [removed] = this.order.splice(dropIdx, 1);
38395
+ if (removed !== undefined)
38396
+ this.byId.delete(removed);
38397
+ }
38398
+ }
38399
+ }
38400
+ function createInMemoryProcessRegistry2(options) {
38401
+ return new InMemoryProcessRegistry2(options);
38402
+ }
38403
+ var nextIdSeq = 0;
38404
+
38405
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
37980
38406
  async function loadStructuredConfig(path7, options = {}) {
37981
38407
  const content = await (options.fileSystem ?? createNodeFileSystem3()).readFile(path7);
37982
38408
  return await parseStructuredConfig(content, path7, options);
@@ -38253,10 +38679,10 @@ var init_schema_validation2 = __esm(() => {
38253
38679
  defaultResolve = typeof Bun !== "undefined" ? (specifier, from) => Bun.resolveSync(specifier, from) : undefined;
38254
38680
  });
38255
38681
 
38256
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/types.js
38682
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/types.js
38257
38683
  var init_types2 = () => {};
38258
38684
 
38259
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/index.js
38685
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/index.js
38260
38686
  var exports_dist2 = {};
38261
38687
  __export(exports_dist2, {
38262
38688
  writeJsonFile: () => writeJsonFile2,
@@ -38271,7 +38697,7 @@ __export(exports_dist2, {
38271
38697
  parseStructuredConfig: () => parseStructuredConfig,
38272
38698
  parseConfigYaml: () => parseConfigYaml,
38273
38699
  normalizeSeparators: () => normalizeSeparators2,
38274
- nodeBunFactory: () => nodeBunFactory2,
38700
+ nodeBunFactory: () => nodeBunFactory3,
38275
38701
  loadStructuredConfig: () => loadStructuredConfig,
38276
38702
  loadRuntimeFactory: () => loadRuntimeFactory2,
38277
38703
  joinPath: () => joinPath2,
@@ -38280,7 +38706,7 @@ __export(exports_dist2, {
38280
38706
  isAbsolutePath: () => isAbsolutePath2,
38281
38707
  interpolateTree: () => interpolateTree2,
38282
38708
  interpolateEnv: () => interpolateEnv2,
38283
- getProcessEnv: () => getProcessEnv,
38709
+ getProcessEnv: () => getProcessEnv2,
38284
38710
  getProcessCwd: () => getProcessCwd2,
38285
38711
  getNodeEnv: () => getNodeEnv,
38286
38712
  getHomeDir: () => getHomeDir,
@@ -38293,6 +38719,7 @@ __export(exports_dist2, {
38293
38719
  createRuntimeContext: () => createRuntimeContext,
38294
38720
  createNodeFileSystem: () => createNodeFileSystem3,
38295
38721
  createLogStream: () => createLogStream2,
38722
+ createInMemoryProcessRegistry: () => createInMemoryProcessRegistry2,
38296
38723
  createCfFileSystem: () => createCfFileSystem2,
38297
38724
  configSchema: () => configSchema3,
38298
38725
  cloudflareWorkersFactory: () => cloudflareWorkersFactory2,
@@ -38307,9 +38734,10 @@ __export(exports_dist2, {
38307
38734
  StructuredConfigSchemaError: () => StructuredConfigSchemaError,
38308
38735
  SEP: () => SEP2,
38309
38736
  RuntimeContext: () => RuntimeContext2,
38310
- ProcessExecutor: () => ProcessExecutor3,
38311
- NodeProcessExecutor: () => NodeProcessExecutor2,
38312
- DbModuleNotInstalledError: () => DbModuleNotInstalledError2,
38737
+ ProcessExecutor: () => ProcessExecutor2,
38738
+ NodeProcessExecutor: () => NodeProcessExecutor3,
38739
+ InMemoryProcessRegistry: () => InMemoryProcessRegistry2,
38740
+ DbModuleNotInstalledError: () => DbModuleNotInstalledError3,
38313
38741
  D1NotConfiguredError: () => D1NotConfiguredError2,
38314
38742
  ConfigLoadError: () => ConfigLoadError2,
38315
38743
  BunSyncProcessExecutor: () => BunSyncProcessExecutor2,
@@ -38317,12 +38745,12 @@ __export(exports_dist2, {
38317
38745
  });
38318
38746
  var init_dist5 = __esm(() => {
38319
38747
  init_context2();
38320
- init_db_errors();
38748
+ init_db_errors2();
38321
38749
  init_file_system_node2();
38322
38750
  init_fs();
38323
38751
  init_process_executor2();
38324
38752
  init_runtime_cf();
38325
- init_runtime_node_bun();
38753
+ init_runtime_node_bun2();
38326
38754
  init_process_executor2();
38327
38755
  init_config2();
38328
38756
  init_context2();
@@ -38467,6 +38895,27 @@ async function loadSpurConfig(cwd = process.cwd(), opts) {
38467
38895
  promise2.catch(() => spurConfigCache.delete(key));
38468
38896
  return promise2;
38469
38897
  }
38898
+ function expandTilde(path8) {
38899
+ if (path8 === "~")
38900
+ return homedir();
38901
+ if (path8.startsWith("~/"))
38902
+ return join2(homedir(), path8.slice(2));
38903
+ return path8;
38904
+ }
38905
+ function expandTeamTildes(config4) {
38906
+ const teams = config4.agent?.team;
38907
+ if (teams === undefined)
38908
+ return config4;
38909
+ const expanded = {};
38910
+ for (const [teamId, team] of Object.entries(teams)) {
38911
+ expanded[teamId] = {
38912
+ ...team,
38913
+ work_dir: expandTilde(team.work_dir),
38914
+ members: team.members.map((member) => typeof member === "string" || member.workspace === undefined ? member : { ...member, workspace: expandTilde(member.workspace) })
38915
+ };
38916
+ }
38917
+ return { ...config4, agent: { ...config4.agent, team: expanded } };
38918
+ }
38470
38919
  async function loadSpurConfigFile(configPath, opts, validateJsonSchema2) {
38471
38920
  let raw;
38472
38921
  if (validateJsonSchema2) {
@@ -38490,7 +38939,7 @@ async function loadSpurConfigFile(configPath, opts, validateJsonSchema2) {
38490
38939
  const text3 = await nodeFs.readFile(resolved);
38491
38940
  raw = $parse(text3) ?? {};
38492
38941
  }
38493
- return spurConfigSchema.parse(raw);
38942
+ return expandTeamTildes(spurConfigSchema.parse(raw));
38494
38943
  }
38495
38944
  async function loadStructuredSpurConfig(configPath, opts) {
38496
38945
  const validateJsonSchema2 = opts?.validateJsonSchema ?? true;
@@ -40382,7 +40831,7 @@ var init_mod = __esm(() => {
40382
40831
  init_config3();
40383
40832
  });
40384
40833
 
40385
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/logger.js
40834
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/logger.js
40386
40835
  function toLogTapeLevel(level) {
40387
40836
  return level === "warn" ? "warning" : level;
40388
40837
  }
@@ -41935,7 +42384,7 @@ var require_src = __commonJS((exports) => {
41935
42384
  };
41936
42385
  });
41937
42386
 
41938
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42387
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
41939
42388
  function getTelemetryConfig(configPartial = {}) {
41940
42389
  return {
41941
42390
  enabled: configPartial.enabled ?? CONFIG_DEFAULTS.enabled,
@@ -41971,7 +42420,7 @@ var init_sdk = __esm(() => {
41971
42420
  resolvedConfig = getTelemetryConfig();
41972
42421
  });
41973
42422
 
41974
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42423
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
41975
42424
  function isSuppressed(tracer2) {
41976
42425
  return tracer2 === undefined && !getResolvedConfig().enabled;
41977
42426
  }
@@ -42011,7 +42460,7 @@ var init_tracing2 = __esm(() => {
42011
42460
  import_api2 = __toESM(require_src(), 1);
42012
42461
  });
42013
42462
 
42014
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42463
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42015
42464
  function getMeter() {
42016
42465
  return import_api3.metrics.getMeter(METER_NAME, METER_VERSION);
42017
42466
  }
@@ -42108,7 +42557,7 @@ var init_metrics = __esm(() => {
42108
42557
  instruments = {};
42109
42558
  });
42110
42559
 
42111
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42560
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42112
42561
  function busLogger() {
42113
42562
  if (!_busLogger)
42114
42563
  _busLogger = getLogger2("event-bus");
@@ -42353,7 +42802,7 @@ var init_event_bus = __esm(() => {
42353
42802
  init_metrics();
42354
42803
  });
42355
42804
 
42356
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
42805
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
42357
42806
  function obsLogger() {
42358
42807
  if (!_obsLogger)
42359
42808
  _obsLogger = getLogger2("event-bus.observers");
@@ -42417,7 +42866,105 @@ var init_default_observers = __esm(() => {
42417
42866
  init_event_bus();
42418
42867
  });
42419
42868
 
42420
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
42869
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
42870
+ function parentDir(filePath) {
42871
+ const idx = filePath.lastIndexOf("/");
42872
+ return idx <= 0 ? "." : filePath.slice(0, idx);
42873
+ }
42874
+ function isPromiseLike2(value) {
42875
+ return value !== null && typeof value === "object" && "then" in value;
42876
+ }
42877
+ function attachFileObserver(lifecycleBus, filePath, writer) {
42878
+ const logger2 = getLogger2("event-bus.file-observer");
42879
+ const ensureResult = writer.ensureDir(parentDir(filePath));
42880
+ let ready = !isPromiseLike2(ensureResult);
42881
+ let pending = isPromiseLike2(ensureResult);
42882
+ let setupFailed = false;
42883
+ let sequence = 0;
42884
+ let writeChain = isPromiseLike2(ensureResult) ? Promise.resolve(ensureResult).then(() => {
42885
+ ready = true;
42886
+ }).catch((error51) => {
42887
+ setupFailed = true;
42888
+ logger2.warn("failed to prepare event bus file observer directory", {
42889
+ filePath,
42890
+ error: error51 instanceof Error ? error51.message : String(error51)
42891
+ });
42892
+ }) : Promise.resolve();
42893
+ function setPending(next) {
42894
+ const current = ++sequence;
42895
+ pending = true;
42896
+ writeChain = next.catch((error51) => {
42897
+ logger2.warn("failed to append event bus lifecycle event", {
42898
+ filePath,
42899
+ error: error51 instanceof Error ? error51.message : String(error51)
42900
+ });
42901
+ }).finally(() => {
42902
+ if (sequence === current)
42903
+ pending = false;
42904
+ });
42905
+ }
42906
+ function writeLine2(line) {
42907
+ const content = `${JSON.stringify(line)}
42908
+ `;
42909
+ if (setupFailed)
42910
+ return;
42911
+ if (ready && !pending) {
42912
+ const result = writer.appendFile(filePath, content);
42913
+ if (isPromiseLike2(result)) {
42914
+ setPending(Promise.resolve(result));
42915
+ }
42916
+ return;
42917
+ }
42918
+ setPending(writeChain.then(() => {
42919
+ if (setupFailed)
42920
+ return;
42921
+ return writer.appendFile(filePath, content);
42922
+ }));
42923
+ }
42924
+ lifecycleBus.on("bus.emit.done", (d) => {
42925
+ const payload = d.detail !== null && typeof d.detail === "object" && !Array.isArray(d.detail) ? d.detail : undefined;
42926
+ writeLine2({
42927
+ ts: new Date().toISOString(),
42928
+ lifecycle: "bus.emit.done",
42929
+ event: d.event,
42930
+ syncCount: d.syncCount,
42931
+ asyncCount: d.asyncCount,
42932
+ emitDurationMs: d.emitDurationMs,
42933
+ errors: d.errors,
42934
+ ...payload && Object.keys(payload).length > 0 ? { payload } : {}
42935
+ });
42936
+ });
42937
+ lifecycleBus.on("bus.emit.noop", (d) => {
42938
+ writeLine2({
42939
+ ts: new Date().toISOString(),
42940
+ lifecycle: "bus.emit.noop",
42941
+ event: d.event
42942
+ });
42943
+ });
42944
+ lifecycleBus.on("bus.handler.error", (d) => {
42945
+ writeLine2({
42946
+ ts: new Date().toISOString(),
42947
+ lifecycle: "bus.handler.error",
42948
+ event: d.event,
42949
+ mode: d.mode,
42950
+ error: d.error
42951
+ });
42952
+ });
42953
+ lifecycleBus.on("bus.handler.async.enqueued", (d) => {
42954
+ writeLine2({
42955
+ ts: new Date().toISOString(),
42956
+ lifecycle: "bus.handler.async.enqueued",
42957
+ event: d.event,
42958
+ jobId: d.jobId,
42959
+ handlerCount: d.handlerCount
42960
+ });
42961
+ });
42962
+ }
42963
+ var init_file_observer = __esm(() => {
42964
+ init_logger3();
42965
+ });
42966
+
42967
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
42421
42968
  function parseInterval(cron) {
42422
42969
  const trimmed = cron.trim();
42423
42970
  const num = Number(trimmed);
@@ -42491,7 +43038,7 @@ var init_node3 = __esm(() => {
42491
43038
  init_metrics();
42492
43039
  });
42493
43040
 
42494
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43041
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
42495
43042
  var exports_scheduler_node = {};
42496
43043
  __export(exports_scheduler_node, {
42497
43044
  NodeSchedulerAdapter: () => NodeSchedulerAdapter
@@ -45425,10 +45972,10 @@ var require_default_service_name = __commonJS((exports) => {
45425
45972
  var require_utils5 = __commonJS((exports) => {
45426
45973
  Object.defineProperty(exports, "__esModule", { value: true });
45427
45974
  exports.isPromiseLike = undefined;
45428
- var isPromiseLike = (val) => {
45975
+ var isPromiseLike3 = (val) => {
45429
45976
  return val !== null && typeof val === "object" && typeof val.then === "function";
45430
45977
  };
45431
- exports.isPromiseLike = isPromiseLike;
45978
+ exports.isPromiseLike = isPromiseLike3;
45432
45979
  });
45433
45980
 
45434
45981
  // ../../node_modules/.bun/@opentelemetry+resources@2.7.1+e40b0dfdd726a224/node_modules/@opentelemetry/resources/build/src/ResourceImpl.js
@@ -48747,7 +49294,12 @@ var init_errors5 = __esm(() => {
48747
49294
  };
48748
49295
  });
48749
49296
 
48750
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/api-client.js
49297
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
49298
+ var init_event_bus2 = __esm(() => {
49299
+ init_event_bus();
49300
+ });
49301
+
49302
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/api-client.js
48751
49303
  function sanitizeUrlForObservability(url2) {
48752
49304
  try {
48753
49305
  const parsed = new URL(url2);
@@ -48809,7 +49361,7 @@ class APIClient {
48809
49361
  this.defaultHeaders = config4.defaultHeaders ?? {};
48810
49362
  this.timeout = config4.timeout ?? 30000;
48811
49363
  this.fetchFn = config4.fetch ?? globalThis.fetch;
48812
- this.events = config4.events;
49364
+ this.events = config4.events ?? (config4.lifecycleBus ? new EventBus({ lifecycleBus: config4.lifecycleBus }) : undefined);
48813
49365
  }
48814
49366
  buildUrl(path9) {
48815
49367
  return `${this.baseUrl}${path9.startsWith("/") ? path9 : `/${path9}`}`;
@@ -48960,6 +49512,7 @@ class APIClient {
48960
49512
  }
48961
49513
  var import_api15, import_semantic_conventions2, APIError;
48962
49514
  var init_api_client = __esm(() => {
49515
+ init_event_bus2();
48963
49516
  init_metrics();
48964
49517
  init_tracing2();
48965
49518
  import_api15 = __toESM(require_src(), 1);
@@ -48976,17 +49529,12 @@ var init_api_client = __esm(() => {
48976
49529
  };
48977
49530
  });
48978
49531
 
48979
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
48980
- var init_event_bus2 = __esm(() => {
48981
- init_event_bus();
48982
- });
48983
-
48984
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
49532
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
48985
49533
  var init_telemetry = __esm(() => {
48986
49534
  init_tracing2();
48987
49535
  });
48988
49536
 
48989
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/index.js
49537
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/index.js
48990
49538
  var init_dist6 = __esm(() => {
48991
49539
  init_api_client();
48992
49540
  init_event_bus2();
@@ -48994,7 +49542,7 @@ var init_dist6 = __esm(() => {
48994
49542
  init_telemetry();
48995
49543
  });
48996
49544
 
48997
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
49545
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
48998
49546
  function resolveAgentName(input) {
48999
49547
  if (isCanonicalName(input))
49000
49548
  return input;
@@ -49245,7 +49793,7 @@ var init_shims = __esm(() => {
49245
49793
  ALIAS_TO_CANONICAL = Object.fromEntries(Object.values(AGENT_SHIMS).flatMap((shim) => (shim.aliases ?? []).map((alias3) => [alias3, shim.name])));
49246
49794
  });
49247
49795
 
49248
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
49796
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
49249
49797
  function buildIdentityPreamble(ctx) {
49250
49798
  const sections = [
49251
49799
  `You are agent \`${ctx.agentId}\` (${ctx.agentType}) in workspace \`${ctx.workspace}\`.`
@@ -49305,7 +49853,7 @@ var init_identity = __esm(() => {
49305
49853
  init_dist5();
49306
49854
  });
49307
49855
 
49308
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
49856
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
49309
49857
  function isClaudeStyleSlashCommand(input) {
49310
49858
  return SLASH_COMMAND_RE.test(input);
49311
49859
  }
@@ -49333,19 +49881,22 @@ var init_slash_command = __esm(() => {
49333
49881
  SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
49334
49882
  });
49335
49883
 
49336
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
49884
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
49337
49885
  class AiRunner {
49338
49886
  processExecutor;
49339
49887
  defaultCwd;
49340
49888
  defaultTimeout;
49341
49889
  logger;
49342
49890
  events;
49891
+ processEvents;
49343
49892
  constructor(options = {}) {
49344
- this.processExecutor = options.processExecutor ?? new NodeProcessExecutor2({
49345
- ...options.processEvents !== undefined ? {
49893
+ const processEvents = options.processEvents ?? (options.lifecycleBus ? new EventBus({ lifecycleBus: options.lifecycleBus }) : undefined);
49894
+ const events = options.events ?? (options.lifecycleBus ? new EventBus({ lifecycleBus: options.lifecycleBus }) : undefined);
49895
+ this.processExecutor = options.processExecutor ?? nodeBunFactory3.createProcessExecutor({
49896
+ ...processEvents !== undefined ? {
49346
49897
  events: {
49347
49898
  emit: (event, detail) => {
49348
- options.processEvents?.emit(event, detail);
49899
+ processEvents?.emit(event, detail);
49349
49900
  }
49350
49901
  }
49351
49902
  } : {},
@@ -49356,7 +49907,8 @@ class AiRunner {
49356
49907
  this.defaultCwd = options.defaultCwd;
49357
49908
  this.defaultTimeout = options.defaultTimeout;
49358
49909
  this.logger = options.logger ?? getLogger2("ai-runner");
49359
- this.events = options.events;
49910
+ this.events = events;
49911
+ this.processEvents = processEvents;
49360
49912
  }
49361
49913
  runHelpCommand(agent, options = {}) {
49362
49914
  return this.invoke(agent, "help", getAgentShim(agent).getHelpCommand(), options, true);
@@ -49447,7 +49999,7 @@ var init_ai_runner = __esm(() => {
49447
49999
  init_slash_command();
49448
50000
  });
49449
50001
 
49450
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
50002
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
49451
50003
  class AgentDetector {
49452
50004
  runner;
49453
50005
  timeout;
@@ -49523,7 +50075,7 @@ var init_agent_detector = __esm(() => {
49523
50075
  VERSION_PATTERN = /(?<version>\d+\.\d+(?:\.\d+)?)/;
49524
50076
  });
49525
50077
 
49526
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
50078
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
49527
50079
  function validateAgentId(id) {
49528
50080
  if (!/^[a-z][a-z0-9_-]{1,63}$/.test(id)) {
49529
50081
  throw new ValueError(`Invalid agent id "${id}": expected 2-64 chars, lowercase alphanumeric, "_" or "-"`);
@@ -49620,12 +50172,12 @@ var init_agent_spec = __esm(() => {
49620
50172
  };
49621
50173
  });
49622
50174
 
49623
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
50175
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
49624
50176
  function isNonEmpty(value) {
49625
50177
  return value !== undefined && value.trim().length > 0;
49626
50178
  }
49627
50179
  async function isAuthenticated(agent, ctx) {
49628
- const env = ctx.env ?? getProcessEnv();
50180
+ const env = ctx.env ?? getProcessEnv2();
49629
50181
  const fs3 = ctx.fileSystem;
49630
50182
  const timeout = ctx.timeout ?? DEFAULT_AUTH_TIMEOUT_MS;
49631
50183
  const home = env.HOME || env.USERPROFILE || "";
@@ -49725,7 +50277,7 @@ var init_auth_shims = __esm(() => {
49725
50277
  };
49726
50278
  });
49727
50279
 
49728
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
50280
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
49729
50281
  class ModelHealthProbeRegistry {
49730
50282
  probes = new Map;
49731
50283
  register(providerPrefix, probe) {
@@ -49833,7 +50385,7 @@ var init_model_health_probe = __esm(() => {
49833
50385
  };
49834
50386
  });
49835
50387
 
49836
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
50388
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
49837
50389
  class DoctorRunner {
49838
50390
  detector;
49839
50391
  runner;
@@ -49848,7 +50400,7 @@ class DoctorRunner {
49848
50400
  this.runner = options.runner ?? new AiRunner;
49849
50401
  this.detector = options.agentDetector ?? new AgentDetector({ runner: this.runner });
49850
50402
  this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS2;
49851
- this.env = options.env ?? getProcessEnv();
50403
+ this.env = options.env ?? getProcessEnv2();
49852
50404
  this.fs = options.fileSystem ?? createNodeFileSystem3();
49853
50405
  this.logger = options.logger ?? getLogger2("doctor");
49854
50406
  this.executors = options.executors ?? [];
@@ -49970,15 +50522,15 @@ var init_doctor_runner = __esm(() => {
49970
50522
  init_model_health_probe();
49971
50523
  });
49972
50524
 
49973
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
50525
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
49974
50526
  var init_events = () => {};
49975
50527
 
49976
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
50528
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
49977
50529
  function formatMessage(msg) {
49978
50530
  return `[task from=${msg.fromId ?? "operator"} id=${msg.id}] ${msg.body}`;
49979
50531
  }
49980
50532
 
49981
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
50533
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
49982
50534
  import { Buffer as Buffer5 } from "buffer";
49983
50535
 
49984
50536
  class TeamAgentProcess {
@@ -49997,7 +50549,7 @@ class TeamAgentProcess {
49997
50549
  this.command = options.command;
49998
50550
  this.env = options.env;
49999
50551
  this.cwd = options.cwd ?? options.spec.workspace;
50000
- this.processExecutor = options.processExecutor ?? new ProcessExecutor3;
50552
+ this.processExecutor = options.processExecutor ?? nodeBunFactory3.createProcessExecutor();
50001
50553
  this.logger = options.logger ?? getLogger2("team-agent");
50002
50554
  }
50003
50555
  async start() {
@@ -50112,7 +50664,7 @@ var init_team_agent_process = __esm(() => {
50112
50664
  init_dist5();
50113
50665
  });
50114
50666
 
50115
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
50667
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
50116
50668
  class TeamOrchestrator {
50117
50669
  configDir;
50118
50670
  inbox;
@@ -50124,7 +50676,7 @@ class TeamOrchestrator {
50124
50676
  this.configDir = configDir;
50125
50677
  this.inbox = inbox;
50126
50678
  this.processFactory = options.processFactory ?? ((processOptions) => new TeamAgentProcess(processOptions));
50127
- this.events = options.events ?? new EventBus;
50679
+ this.events = options.events ?? (options.lifecycleBus ? new EventBus({ lifecycleBus: options.lifecycleBus }) : new EventBus);
50128
50680
  }
50129
50681
  async loadSpecs() {
50130
50682
  this.specs = await loadAgentSpecs(this.configDir);
@@ -50241,7 +50793,7 @@ var init_team_orchestrator = __esm(() => {
50241
50793
  init_team_agent_process();
50242
50794
  });
50243
50795
 
50244
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.8+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
50796
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.10+443204d2f30aef7a/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
50245
50797
  var exports_dist3 = {};
50246
50798
  __export(exports_dist3, {
50247
50799
  validateAgentId: () => validateAgentId,
@@ -50310,7 +50862,12 @@ class AgentService {
50310
50862
  }
50311
50863
  async resolve(flags, deps) {
50312
50864
  const outputPolicy = { mode: "buffered" };
50313
- const runner = deps?.runner ?? new AiRunner({ processExecutor: new NodeProcessExecutor2({ output: outputPolicy }) });
50865
+ const runner = deps?.runner ?? new AiRunner({
50866
+ processExecutor: new NodeProcessExecutor3({
50867
+ output: outputPolicy,
50868
+ ...this.ctx.processRegistry !== undefined ? { registry: this.ctx.processRegistry } : {}
50869
+ })
50870
+ });
50314
50871
  const detector = deps?.detector ?? new AgentDetector({ runner });
50315
50872
  const doctorRunner = deps?.doctorRunner ?? new DoctorRunner({ agentDetector: detector, runner, env: this.ctx.env });
50316
50873
  return this.resolveAgent(undefined, flags, doctorRunner);
@@ -50405,7 +50962,10 @@ class AgentService {
50405
50962
  const jsonOutput = silent || booleanFlag(flags, "json");
50406
50963
  const outputPolicy = jsonOutput ? { mode: "buffered" } : { mode: "stream", isTTY: isatty3(1) };
50407
50964
  const runner = deps?.runner ?? new AiRunner({
50408
- processExecutor: new NodeProcessExecutor2({ output: outputPolicy }),
50965
+ processExecutor: new NodeProcessExecutor3({
50966
+ output: outputPolicy,
50967
+ ...this.ctx.processRegistry !== undefined ? { registry: this.ctx.processRegistry } : {}
50968
+ }),
50409
50969
  ...this.ctx.events !== undefined ? { events: bridgeEventBus(this.ctx.events) } : {},
50410
50970
  ...this.ctx.events !== undefined ? { processEvents: bridgeEventBus(this.ctx.events) } : {}
50411
50971
  });
@@ -51156,7 +51716,10 @@ function tryParseFeature(content) {
51156
51716
  if (!content.includes("Feature:") && !content.includes("Scenario:")) {
51157
51717
  return null;
51158
51718
  }
51159
- return parseFeature(content);
51719
+ const toParse = content.includes("Feature:") || !content.includes("Scenario:") ? content : `Feature: __coverage_wrapper__
51720
+
51721
+ ${content}`;
51722
+ return parseFeature(toParse);
51160
51723
  }
51161
51724
  var init_coverage = () => {};
51162
51725
 
@@ -51698,7 +52261,7 @@ var init_drizzle_zod = __esm(() => {
51698
52261
  };
51699
52262
  });
51700
52263
 
51701
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
52264
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
51702
52265
  function sqlExpressionToText(value) {
51703
52266
  if (typeof value !== "object" || value === null || !("queryChunks" in value)) {
51704
52267
  return;
@@ -51721,7 +52284,7 @@ function getDrizzleTableName(table3) {
51721
52284
  return String(table3[nameSym]);
51722
52285
  }
51723
52286
 
51724
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
52287
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
51725
52288
  function quoteIdent(name) {
51726
52289
  return `"${name.replace(/"/g, '""')}"`;
51727
52290
  }
@@ -51815,7 +52378,7 @@ var init_ddl = __esm(() => {
51815
52378
  init_sqlite_core();
51816
52379
  });
51817
52380
 
51818
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
52381
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
51819
52382
  function defineTable(name, columns2) {
51820
52383
  const table3 = sqliteTable(name, columns2);
51821
52384
  let insert2;
@@ -51849,7 +52412,7 @@ var init_define_table = __esm(() => {
51849
52412
  init_ddl();
51850
52413
  });
51851
52414
 
51852
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.8+6416bade0e3e2531/node_modules/@gobing-ai/ts-db/dist/schema/index.js
52415
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.10+86b80a818ad2648a/node_modules/@gobing-ai/ts-db/dist/schema/index.js
51853
52416
  var init_schema = __esm(() => {
51854
52417
  init_sqlite_core();
51855
52418
  init_define_table();
@@ -52404,7 +52967,7 @@ var init_dao = __esm(() => {
52404
52967
  init_workspace_dao();
52405
52968
  });
52406
52969
 
52407
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
52970
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
52408
52971
  var WorkflowValidationError, FSMError, RunCollisionError, WorkflowResumeError;
52409
52972
  var init_errors6 = __esm(() => {
52410
52973
  WorkflowValidationError = class WorkflowValidationError extends Error {
@@ -52439,7 +53002,7 @@ var init_errors6 = __esm(() => {
52439
53002
  };
52440
53003
  });
52441
53004
 
52442
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
53005
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
52443
53006
  function runtimeBuiltins(workflowName, stateOrNodeId, runId, transitionsTaken, mode) {
52444
53007
  return {
52445
53008
  workflow: workflowName,
@@ -52452,7 +53015,7 @@ function runtimeBuiltins(workflowName, stateOrNodeId, runId, transitionsTaken, m
52452
53015
  runtime: mode
52453
53016
  };
52454
53017
  }
52455
- function allowedEnv(names, source = getProcessEnv()) {
53018
+ function allowedEnv(names, source = getProcessEnv2()) {
52456
53019
  return Object.fromEntries(names.flatMap((name) => source[name] === undefined ? [] : [[name, source[name]]]));
52457
53020
  }
52458
53021
 
@@ -52470,7 +53033,7 @@ class RunLifecycle {
52470
53033
  this.runId = runId;
52471
53034
  this.externalKey = externalKey;
52472
53035
  this.persistence = deps.persistence;
52473
- this.events = deps.events;
53036
+ this.events = deps.events ?? (deps.lifecycleBus ? new EventBus({ lifecycleBus: deps.lifecycleBus }) : undefined);
52474
53037
  this.logger = (deps.logger ?? getLogger2("workflow")).child({ runId, workflow: workflowName, mode });
52475
53038
  }
52476
53039
  static forExternalTransition(workflowName, runId, deps, externalKey) {
@@ -52688,7 +53251,7 @@ var init_run_lifecycle = __esm(() => {
52688
53251
  ];
52689
53252
  });
52690
53253
 
52691
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
53254
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
52692
53255
  var RESERVED_VAR_NAMES, IDENTIFIER, VarsSchema, EnvSchema, ActionDefSchema, GuardDefSchema, StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema, WorkflowDefSchema;
52693
53256
  var init_schema2 = __esm(() => {
52694
53257
  init_zod();
@@ -52772,7 +53335,7 @@ var init_schema2 = __esm(() => {
52772
53335
  WorkflowDefSchema = exports_external.union([StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema]);
52773
53336
  });
52774
53337
 
52775
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
53338
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
52776
53339
  async function loadWorkflowDef(path9, options = {}) {
52777
53340
  return parseWorkflowDef(await loadStructuredConfig(path9, options), path9);
52778
53341
  }
@@ -52931,7 +53494,7 @@ var init_config4 = __esm(() => {
52931
53494
  RUNTIME_TEMPLATE_NAMESPACES = new Set(RUNTIME_BUILTIN_KEYS);
52932
53495
  });
52933
53496
 
52934
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
53497
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
52935
53498
  class CapabilityRegistry {
52936
53499
  kind;
52937
53500
  capabilities = new Map;
@@ -52962,7 +53525,7 @@ class CapabilityRegistry {
52962
53525
  }
52963
53526
  }
52964
53527
 
52965
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
53528
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
52966
53529
  function assertRelativeExtensionPath(path9, options = {}) {
52967
53530
  const where = options.sourceName !== undefined ? ` declared by "${options.sourceName}"` : "";
52968
53531
  if (/^([/\\]|[A-Za-z]:[/\\])/.test(path9)) {
@@ -52973,23 +53536,27 @@ function assertRelativeExtensionPath(path9, options = {}) {
52973
53536
  }
52974
53537
  }
52975
53538
 
52976
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
53539
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
52977
53540
  var init_extension_loader = () => {};
52978
53541
 
52979
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
53542
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
52980
53543
  var init_extension = __esm(() => {
52981
53544
  init_extension_loader();
52982
53545
  });
52983
53546
 
52984
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.8+e943d2626789fd3c/node_modules/@gobing-ai/ts-runtime/dist/extension.js
53547
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.10+f5990ac4de041c52/node_modules/@gobing-ai/ts-runtime/dist/extension.js
52985
53548
  var init_extension2 = __esm(() => {
52986
53549
  init_extension();
52987
53550
  });
52988
53551
 
52989
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
53552
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
52990
53553
  class WorkflowEngineHost {
53554
+ lifecycleBus;
52991
53555
  actions = new CapabilityRegistry("workflow action");
52992
53556
  guards = new CapabilityRegistry("workflow guard");
53557
+ constructor(lifecycleBus) {
53558
+ this.lifecycleBus = lifecycleBus;
53559
+ }
52993
53560
  registerAction(action, origin2 = "extension") {
52994
53561
  this.actions.register(action.kind, action, origin2);
52995
53562
  return this;
@@ -53032,11 +53599,11 @@ class WorkflowEngineHost {
53032
53599
  }
53033
53600
  }
53034
53601
  function createDefaultWorkflowEngineHost(options = {}) {
53035
- const host = new WorkflowEngineHost;
53602
+ const host = new WorkflowEngineHost(options.lifecycleBus);
53036
53603
  host.registerAction(new NoteActionRunner, "builtin");
53037
- host.registerAction(new ShellActionRunner(options.processExecutor ?? new NodeProcessExecutor2), "builtin");
53604
+ host.registerAction(new ShellActionRunner(options.processExecutor ?? nodeBunFactory3.createProcessExecutor()), "builtin");
53038
53605
  host.registerAction(new EventEmitActionRunner, "builtin");
53039
- host.registerGuard(new ShellGuardRunner(options.processExecutor ?? new NodeProcessExecutor2), "builtin");
53606
+ host.registerGuard(new ShellGuardRunner(options.processExecutor ?? nodeBunFactory3.createProcessExecutor()), "builtin");
53040
53607
  host.registerGuard({ kind: "always", evaluate: async () => true }, "builtin");
53041
53608
  host.registerGuard({ kind: "never", evaluate: async () => false }, "builtin");
53042
53609
  host.registerGuard({
@@ -53151,7 +53718,7 @@ var init_host = __esm(() => {
53151
53718
  init_errors6();
53152
53719
  });
53153
53720
 
53154
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
53721
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
53155
53722
  var WORKFLOW_ENGINE_SCHEMA_SQL;
53156
53723
  var init_schema_sql = __esm(() => {
53157
53724
  WORKFLOW_ENGINE_SCHEMA_SQL = `
@@ -53224,7 +53791,7 @@ CREATE TABLE IF NOT EXISTS action_runs (
53224
53791
  `.trim();
53225
53792
  });
53226
53793
 
53227
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
53794
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
53228
53795
  async function applyWorkflowEngineSchema(db2) {
53229
53796
  for (const statement of WORKFLOW_ENGINE_SCHEMA_SQL.split(";")) {
53230
53797
  const sql4 = statement.trim();
@@ -53492,7 +54059,7 @@ var init_persistence = __esm(() => {
53492
54059
  init_schema_sql();
53493
54060
  });
53494
54061
 
53495
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
54062
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
53496
54063
  function mergeVars(workflowVars = {}, overrideVars = {}) {
53497
54064
  return { ...workflowVars, ...overrideVars };
53498
54065
  }
@@ -53552,7 +54119,7 @@ var init_variables = __esm(() => {
53552
54119
  TEMPLATE_REF = /\$\{([^}]+)\}/g;
53553
54120
  });
53554
54121
 
53555
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
54122
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
53556
54123
  async function runActionStep(action, vars, deps) {
53557
54124
  const { host, persistence, lifecycle, stateOrNodeId, runId } = deps;
53558
54125
  const resolved = resolveTemplates(action.options ?? {}, {
@@ -53609,7 +54176,7 @@ var init_action_step = __esm(() => {
53609
54176
  init_variables();
53610
54177
  });
53611
54178
 
53612
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
54179
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
53613
54180
  class StateMachineDriver {
53614
54181
  options;
53615
54182
  constructor(options) {
@@ -53743,7 +54310,7 @@ var init_state_machine = __esm(() => {
53743
54310
  EMPTY_OUTCOME = { outcome: "completed", result: undefined };
53744
54311
  });
53745
54312
 
53746
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
54313
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
53747
54314
  class TransitionFlowDriver {
53748
54315
  options;
53749
54316
  constructor(options) {
@@ -53861,23 +54428,35 @@ var init_transition_flow = __esm(() => {
53861
54428
  init_variables();
53862
54429
  });
53863
54430
 
53864
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
54431
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
53865
54432
  class WorkflowService {
53866
54433
  host;
53867
54434
  persistence;
53868
54435
  runLocks = new Map;
53869
- constructor(host, persistence) {
54436
+ lifecycleBus;
54437
+ constructor(host, persistence, lifecycleBus) {
53870
54438
  this.host = host;
53871
54439
  this.persistence = persistence;
54440
+ this.lifecycleBus = lifecycleBus ?? host.lifecycleBus;
54441
+ }
54442
+ resolveEvents(events2) {
54443
+ return events2 ?? (this.lifecycleBus ? new EventBus({ lifecycleBus: this.lifecycleBus }) : undefined);
53872
54444
  }
53873
54445
  async load(path9) {
53874
54446
  return await loadWorkflowDef(path9);
53875
54447
  }
53876
54448
  async run(workflow, options = {}) {
54449
+ const events2 = this.resolveEvents(options.events);
53877
54450
  if (workflow.kind === "transition-flow") {
53878
- return await new TransitionFlowDriver({ host: this.host, persistence: this.persistence }).run(workflow, options);
54451
+ return await new TransitionFlowDriver({ host: this.host, persistence: this.persistence }).run(workflow, {
54452
+ ...options,
54453
+ events: events2
54454
+ });
53879
54455
  }
53880
- return await new StateMachineDriver({ host: this.host, persistence: this.persistence }).run(workflow, options);
54456
+ return await new StateMachineDriver({ host: this.host, persistence: this.persistence }).run(workflow, {
54457
+ ...options,
54458
+ events: events2
54459
+ });
53881
54460
  }
53882
54461
  async runFile(path9, options = {}) {
53883
54462
  return await this.run(await this.load(path9), options);
@@ -53920,7 +54499,7 @@ class WorkflowService {
53920
54499
  const run = await this.persistence.loadRun(runId);
53921
54500
  const extKey = run?.external_key ?? undefined;
53922
54501
  const result = await this.persistence.reseedRun(runId, newState);
53923
- options?.events?.emit("workflow.run.reseeded", {
54502
+ this.resolveEvents(options?.events)?.emit("workflow.run.reseeded", {
53924
54503
  runId,
53925
54504
  fromState: result.fromState ?? "",
53926
54505
  toState: result.toState,
@@ -53941,17 +54520,18 @@ class WorkflowService {
53941
54520
  }
53942
54521
  const extKey = run.external_key ?? undefined;
53943
54522
  await this.persistence.finalizeRun(runId, "running", "");
53944
- options?.events?.emit("workflow.run.resumed", { runId, node: currentState, externalKey: extKey });
54523
+ const events2 = this.resolveEvents(options?.events);
54524
+ events2?.emit("workflow.run.resumed", { runId, node: currentState, externalKey: extKey });
53945
54525
  if (workflow.kind === "transition-flow") {
53946
54526
  return await new TransitionFlowDriver({
53947
54527
  host: this.host,
53948
54528
  persistence: this.persistence
53949
- }).resume(workflow, runId, currentState, extKey, options);
54529
+ }).resume(workflow, runId, currentState, extKey, { ...options, events: events2 });
53950
54530
  }
53951
54531
  return await new StateMachineDriver({
53952
54532
  host: this.host,
53953
54533
  persistence: this.persistence
53954
- }).resume(workflow, runId, currentState, extKey, options);
54534
+ }).resume(workflow, runId, currentState, extKey, { ...options, events: events2 });
53955
54535
  }
53956
54536
  async listPausedRuns(options) {
53957
54537
  return await this.persistence.listPausedRuns(options);
@@ -53984,10 +54564,11 @@ class WorkflowService {
53984
54564
  detail: `No state recorded for run "${runId}"`
53985
54565
  };
53986
54566
  }
53987
- const lifecycle = RunLifecycle.forExternalTransition(workflow.name, runId, { persistence: this.persistence, events: options?.events }, extKey);
54567
+ const events2 = this.resolveEvents(options?.events);
54568
+ const lifecycle = RunLifecycle.forExternalTransition(workflow.name, runId, { persistence: this.persistence, events: events2 }, extKey);
53988
54569
  const transition = workflow.transitions.find((t) => t.from === currentState && t.to === toState);
53989
54570
  if (transition === undefined) {
53990
- return this.denyTransition(options, runId, currentState, toState, extKey, {
54571
+ return this.denyTransition(events2, runId, currentState, toState, extKey, {
53991
54572
  reason: "no-such-transition",
53992
54573
  detail: `No transition from "${currentState}" to "${toState}"`
53993
54574
  });
@@ -54005,7 +54586,7 @@ class WorkflowService {
54005
54586
  });
54006
54587
  lifecycle.guardEvaluated(currentState, toState, transition.guard.kind, guardResult.passed);
54007
54588
  if (!guardResult.passed) {
54008
- return this.denyTransition(options, runId, currentState, toState, extKey, {
54589
+ return this.denyTransition(events2, runId, currentState, toState, extKey, {
54009
54590
  reason: "guard-failed",
54010
54591
  detail: `Guard "${transition.guard.kind}" denied transition from "${currentState}" to "${toState}"`,
54011
54592
  guardKind: transition.guard.kind,
@@ -54015,7 +54596,7 @@ class WorkflowService {
54015
54596
  }
54016
54597
  const trigger = transition.trigger ?? null;
54017
54598
  await lifecycle.commitHop(currentState, toState, trigger, 0);
54018
- options?.events?.emit("workflow.transition.requested", {
54599
+ events2?.emit("workflow.transition.requested", {
54019
54600
  runId,
54020
54601
  from: currentState,
54021
54602
  to: toState,
@@ -54024,8 +54605,8 @@ class WorkflowService {
54024
54605
  });
54025
54606
  return { allowed: true, fromState: currentState, toState };
54026
54607
  }
54027
- denyTransition(options, runId, from, to, externalKey, denial) {
54028
- options?.events?.emit("workflow.transition.denied", {
54608
+ denyTransition(events2, runId, from, to, externalKey, denial) {
54609
+ events2?.emit("workflow.transition.denied", {
54029
54610
  runId,
54030
54611
  from,
54031
54612
  to,
@@ -54036,6 +54617,7 @@ class WorkflowService {
54036
54617
  }
54037
54618
  }
54038
54619
  var init_service = __esm(() => {
54620
+ init_dist6();
54039
54621
  init_config4();
54040
54622
  init_errors6();
54041
54623
  init_run_lifecycle();
@@ -54044,7 +54626,7 @@ var init_service = __esm(() => {
54044
54626
  init_variables();
54045
54627
  });
54046
54628
 
54047
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
54629
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
54048
54630
  var init_dist8 = __esm(() => {
54049
54631
  init_config4();
54050
54632
  init_host();
@@ -54053,7 +54635,7 @@ var init_dist8 = __esm(() => {
54053
54635
  init_service();
54054
54636
  });
54055
54637
 
54056
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.8+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
54638
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.10+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
54057
54639
  var HistoryImportError;
54058
54640
  var init_errors7 = __esm(() => {
54059
54641
  HistoryImportError = class HistoryImportError extends Error {
@@ -54066,7 +54648,7 @@ var init_errors7 = __esm(() => {
54066
54648
  };
54067
54649
  });
54068
54650
 
54069
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.8+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
54651
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.10+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
54070
54652
  import { createHash } from "crypto";
54071
54653
  function stableJson(value) {
54072
54654
  if (Array.isArray(value)) {
@@ -54083,7 +54665,7 @@ function sha256(value) {
54083
54665
  }
54084
54666
  var init_hash = () => {};
54085
54667
 
54086
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.8+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
54668
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.10+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
54087
54669
  function redactValue(value, rules = DEFAULT_REDACTION_RULES) {
54088
54670
  if (typeof value === "string") {
54089
54671
  return rules.reduce((current, rule) => current.replace(rule.pattern, rule.replacement), value);
@@ -54120,7 +54702,7 @@ var init_redaction = __esm(() => {
54120
54702
  ];
54121
54703
  });
54122
54704
 
54123
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.8+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
54705
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.10+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
54124
54706
  var HISTORY_IMPORT_SCHEMA_SQL;
54125
54707
  var init_schema_sql2 = __esm(() => {
54126
54708
  HISTORY_IMPORT_SCHEMA_SQL = `
@@ -54207,7 +54789,7 @@ CREATE TABLE IF NOT EXISTS history_etl_openclaw (
54207
54789
  `.trim();
54208
54790
  });
54209
54791
 
54210
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.8+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
54792
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.10+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
54211
54793
  function firstString(...values) {
54212
54794
  for (const value of values) {
54213
54795
  if (typeof value === "string" && value.length > 0)
@@ -54295,7 +54877,7 @@ var init_sources = __esm(() => {
54295
54877
  };
54296
54878
  });
54297
54879
 
54298
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.8+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
54880
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.10+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
54299
54881
  async function applyHistoryImportSchema(db2) {
54300
54882
  for (const statement of HISTORY_IMPORT_SCHEMA_SQL.split(";")) {
54301
54883
  const sql4 = statement.trim();
@@ -54532,13 +55114,13 @@ var init_importer = __esm(() => {
54532
55114
  VALID_TABLE_NAME = /^history_etl_[a-z_]+$/;
54533
55115
  });
54534
55116
 
54535
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.8+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
55117
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.10+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
54536
55118
  var init_dist9 = __esm(() => {
54537
55119
  init_importer();
54538
55120
  init_schema_sql2();
54539
55121
  });
54540
55122
 
54541
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
55123
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
54542
55124
  function collectExtensions(sourceName, sourceDir, extensions) {
54543
55125
  if (extensions === undefined)
54544
55126
  return [];
@@ -54554,7 +55136,7 @@ var init_extensions = __esm(() => {
54554
55136
  init_dist5();
54555
55137
  });
54556
55138
 
54557
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
55139
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
54558
55140
  function createFinding(rule, message, filePath, extras = {}) {
54559
55141
  return {
54560
55142
  ruleId: rule.id,
@@ -54625,7 +55207,7 @@ var init_types3 = __esm(() => {
54625
55207
  });
54626
55208
  });
54627
55209
 
54628
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
55210
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
54629
55211
  async function loadPreset(name, options) {
54630
55212
  const merged = await buildMergedRoots(options.roots.map((root) => resolvePath4(root)), options.fileSystem);
54631
55213
  const presetPath = findMergedPreset(merged, name);
@@ -54840,7 +55422,7 @@ var init_loader2 = __esm(() => {
54840
55422
  FIX_MODE_AUTHORITY = { none: 0, suggest: 1, auto: 2 };
54841
55423
  });
54842
55424
 
54843
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
55425
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
54844
55426
  function normalizeFindingPath(filePath) {
54845
55427
  if (!filePath || isAbsolutePath2(filePath))
54846
55428
  return null;
@@ -54905,7 +55487,7 @@ var init_test_stub_fixer = __esm(() => {
54905
55487
  realFileSystem = createNodeFileSystem3();
54906
55488
  });
54907
55489
 
54908
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
55490
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
54909
55491
  function registerBuiltinFixers(host, exec) {
54910
55492
  const regexFixer = new RegexFixerProvider;
54911
55493
  const pathFixer = new PathFixerProvider;
@@ -55108,7 +55690,7 @@ var init_fixers = __esm(() => {
55108
55690
  };
55109
55691
  });
55110
55692
 
55111
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
55693
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
55112
55694
  function stringArray(value) {
55113
55695
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
55114
55696
  }
@@ -55146,7 +55728,7 @@ function parseInlineFlags(source) {
55146
55728
  return { flags, rest: source.slice(match[0].length) };
55147
55729
  }
55148
55730
 
55149
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
55731
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
55150
55732
  function matchesAny(path9, patterns) {
55151
55733
  if (patterns === undefined || patterns.length === 0)
55152
55734
  return true;
@@ -55194,7 +55776,7 @@ function escapeRegExp(value) {
55194
55776
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
55195
55777
  }
55196
55778
 
55197
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
55779
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
55198
55780
  async function discoverFiles2(options) {
55199
55781
  const fs3 = options.fs ?? createNodeFileSystem3();
55200
55782
  const allFiles = await walkDir2(options.workdir, fs3, DEFAULT_EXCLUDES);
@@ -55222,12 +55804,12 @@ var init_file_discovery = __esm(() => {
55222
55804
  DEFAULT_EXCLUDES = new Set([".git", "node_modules", "dist", ".coverage", ".astro", ".wrangler"]);
55223
55805
  });
55224
55806
 
55225
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
55807
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
55226
55808
  var init_file_utils = __esm(() => {
55227
55809
  init_file_discovery();
55228
55810
  });
55229
55811
 
55230
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
55812
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
55231
55813
  class AgentDetectionEvaluator {
55232
55814
  detector;
55233
55815
  constructor(detector = new AgentDetector) {
@@ -55255,7 +55837,7 @@ var init_agent_detection_evaluator = __esm(() => {
55255
55837
  init_file_utils();
55256
55838
  });
55257
55839
 
55258
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
55840
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
55259
55841
  class CoverageGateEvaluator {
55260
55842
  constructor() {}
55261
55843
  async evaluate(rule, context4) {
@@ -55339,10 +55921,10 @@ var init_coverage_gate_evaluator = __esm(() => {
55339
55921
  init_file_utils();
55340
55922
  });
55341
55923
 
55342
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
55924
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
55343
55925
  class ExitCodeEvaluator {
55344
55926
  executor;
55345
- constructor(executor = new NodeProcessExecutor2) {
55927
+ constructor(executor = nodeBunFactory3.createProcessExecutor()) {
55346
55928
  this.executor = executor;
55347
55929
  }
55348
55930
  async evaluate(rule, context4) {
@@ -55375,7 +55957,7 @@ var init_exit_code_evaluator = __esm(() => {
55375
55957
  init_file_utils();
55376
55958
  });
55377
55959
 
55378
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
55960
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
55379
55961
  class ForbiddenImportEvaluator {
55380
55962
  constructor() {}
55381
55963
  async evaluate(rule, context4) {
@@ -55456,7 +56038,7 @@ var init_forbidden_import_evaluator = __esm(() => {
55456
56038
  init_file_utils();
55457
56039
  });
55458
56040
 
55459
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
56041
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
55460
56042
  class ImportBoundaryEvaluator {
55461
56043
  async evaluate(rule, context4) {
55462
56044
  const config4 = rule.evaluator.config ?? {};
@@ -55549,7 +56131,7 @@ var init_import_boundary_evaluator = __esm(() => {
55549
56131
  init_file_utils();
55550
56132
  });
55551
56133
 
55552
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
56134
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
55553
56135
  class PathEvaluator {
55554
56136
  constructor() {}
55555
56137
  async evaluate(rule, context4) {
@@ -55610,7 +56192,7 @@ var init_path_evaluator = __esm(() => {
55610
56192
  init_file_utils();
55611
56193
  });
55612
56194
 
55613
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
56195
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
55614
56196
  class RegexEvaluator {
55615
56197
  constructor() {}
55616
56198
  async evaluate(rule, context4) {
@@ -55688,10 +56270,10 @@ var init_regex_evaluator = __esm(() => {
55688
56270
  init_file_utils();
55689
56271
  });
55690
56272
 
55691
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
56273
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
55692
56274
  class RipgrepEvaluator {
55693
56275
  executor;
55694
- constructor(executor = new NodeProcessExecutor2) {
56276
+ constructor(executor = nodeBunFactory3.createProcessExecutor()) {
55695
56277
  this.executor = executor;
55696
56278
  }
55697
56279
  async evaluate(rule, context4) {
@@ -55781,7 +56363,7 @@ var init_ripgrep_evaluator = __esm(() => {
55781
56363
  init_file_utils();
55782
56364
  });
55783
56365
 
55784
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
56366
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
55785
56367
  class SchemaArtifactEvaluator {
55786
56368
  constructor() {}
55787
56369
  async evaluate(rule, context4) {
@@ -55859,7 +56441,7 @@ var init_schema_artifact_evaluator = __esm(() => {
55859
56441
  init_file_utils();
55860
56442
  });
55861
56443
 
55862
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
56444
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
55863
56445
  class SecretsScannerEvaluator {
55864
56446
  constructor() {}
55865
56447
  async evaluate(rule, context4) {
@@ -55927,10 +56509,10 @@ var init_secrets_scanner_evaluator = __esm(() => {
55927
56509
  ALL_CATEGORIES = Object.keys(BUILTIN_PATTERNS);
55928
56510
  });
55929
56511
 
55930
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
56512
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
55931
56513
  class SgEvaluator {
55932
56514
  executor;
55933
- constructor(executor = new NodeProcessExecutor2) {
56515
+ constructor(executor = nodeBunFactory3.createProcessExecutor()) {
55934
56516
  this.executor = executor;
55935
56517
  }
55936
56518
  async evaluate(rule, context4) {
@@ -56024,7 +56606,7 @@ var init_sg_evaluator = __esm(() => {
56024
56606
  init_file_utils();
56025
56607
  });
56026
56608
 
56027
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
56609
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
56028
56610
  class TypeScriptTestPathResolver {
56029
56611
  name = "typescript";
56030
56612
  constructor() {}
@@ -56107,7 +56689,7 @@ function testify(rel) {
56107
56689
  return `${dir}test_${base2}`;
56108
56690
  }
56109
56691
 
56110
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
56692
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
56111
56693
  class TestLocationEvaluator {
56112
56694
  resolvers;
56113
56695
  constructor(resolvers) {
@@ -56182,7 +56764,7 @@ var init_test_location_evaluator = __esm(() => {
56182
56764
  TYPESCRIPT_FALLBACK = new TypeScriptTestPathResolver;
56183
56765
  });
56184
56766
 
56185
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
56767
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
56186
56768
  class TsdocExportEvaluator {
56187
56769
  constructor() {}
56188
56770
  async evaluate(rule, context4) {
@@ -56267,7 +56849,7 @@ var init_tsdoc_export_evaluator = __esm(() => {
56267
56849
  };
56268
56850
  });
56269
56851
 
56270
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
56852
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
56271
56853
  class JsonFormatter {
56272
56854
  constructor() {}
56273
56855
  format(result) {
@@ -56275,7 +56857,7 @@ class JsonFormatter {
56275
56857
  }
56276
56858
  }
56277
56859
 
56278
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
56860
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
56279
56861
  class TextFormatter {
56280
56862
  constructor() {}
56281
56863
  format(result) {
@@ -56289,7 +56871,7 @@ class TextFormatter {
56289
56871
  }
56290
56872
  }
56291
56873
 
56292
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
56874
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
56293
56875
  function registerBuiltins(host, executor) {
56294
56876
  const path9 = new PathEvaluator;
56295
56877
  host.evaluators.register("regex", new RegexEvaluator, "builtin");
@@ -56329,7 +56911,7 @@ var init_builtins = __esm(() => {
56329
56911
  init_tsdoc_export_evaluator();
56330
56912
  });
56331
56913
 
56332
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
56914
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
56333
56915
  class RuleEngineHost {
56334
56916
  evaluators;
56335
56917
  formatters;
@@ -56346,7 +56928,7 @@ var init_rule_engine_host = __esm(() => {
56346
56928
  init_extension2();
56347
56929
  });
56348
56930
 
56349
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
56931
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
56350
56932
  class RuleEngine {
56351
56933
  host;
56352
56934
  events;
@@ -56359,7 +56941,7 @@ class RuleEngine {
56359
56941
  this.host = options.host ?? new RuleEngineHost;
56360
56942
  registerBuiltins(this.host, options.processExecutor);
56361
56943
  registerBuiltinFixers(this.host, options.processExecutor);
56362
- this.events = options.events;
56944
+ this.events = options.events ?? (options.lifecycleBus ? new EventBus({ lifecycleBus: options.lifecycleBus }) : undefined);
56363
56945
  this.logger = options.logger ?? getLogger2("rule-engine");
56364
56946
  this.persistence = options.persistence;
56365
56947
  this.runId = options.runId ?? crypto.randomUUID();
@@ -56517,7 +57099,7 @@ var init_engine = __esm(() => {
56517
57099
  init_types3();
56518
57100
  });
56519
57101
 
56520
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
57102
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
56521
57103
  async function bundledRulesRoot() {
56522
57104
  if (cachedRoot2 !== undefined)
56523
57105
  return cachedRoot2;
@@ -56568,7 +57150,7 @@ var init_bundled_rules = __esm(() => {
56568
57150
  init_dist5();
56569
57151
  });
56570
57152
 
56571
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
57153
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
56572
57154
  class DbRulePersistenceAdapter {
56573
57155
  db;
56574
57156
  constructor(db2) {
@@ -56602,7 +57184,7 @@ class DbRulePersistenceAdapter {
56602
57184
  }
56603
57185
  }
56604
57186
 
56605
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
57187
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
56606
57188
  var RULE_ENGINE_SCHEMA_SQL = `
56607
57189
  CREATE TABLE IF NOT EXISTS rule_runs (
56608
57190
  id TEXT PRIMARY KEY,
@@ -56648,10 +57230,10 @@ CREATE TABLE IF NOT EXISTS rule_eval_runs (
56648
57230
  CREATE INDEX IF NOT EXISTS idx_rule_eval_runs_run_id ON rule_eval_runs (run_id);
56649
57231
  `;
56650
57232
 
56651
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
57233
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
56652
57234
  var init_persistence2 = () => {};
56653
57235
 
56654
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.8+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
57236
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.10+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
56655
57237
  var init_dist10 = __esm(() => {
56656
57238
  init_extensions();
56657
57239
  init_loader2();
@@ -56850,7 +57432,7 @@ ${SYSTEM_EVENTS_SCHEMA_SQL}
56850
57432
  ];
56851
57433
  });
56852
57434
 
56853
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
57435
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
56854
57436
  function queueLogger() {
56855
57437
  if (!_queueLogger)
56856
57438
  _queueLogger = getLogger2("job-queue");
@@ -57078,7 +57660,7 @@ var init_db_job_queue = __esm(() => {
57078
57660
  init_tracing2();
57079
57661
  });
57080
57662
 
57081
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
57663
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
57082
57664
  var exports_job_queue_db = {};
57083
57665
  __export(exports_job_queue_db, {
57084
57666
  DBQueueConsumer: () => DBQueueConsumer,
@@ -60515,7 +61097,7 @@ var init_rule_service = __esm(() => {
60515
61097
  function defaultWrapperArgv(agentId) {
60516
61098
  return {
60517
61099
  command: process.execPath,
60518
- args: [process.argv[1] ?? "apps/cli/src/index.ts", "agent", "run", "--agent", agentId, "--drain", "--continue"]
61100
+ args: [process.argv[1] ?? "apps/cli/src/index.ts", "agent", "loop", "--agent", agentId]
60519
61101
  };
60520
61102
  }
60521
61103
 
@@ -60528,6 +61110,8 @@ class SupervisorService {
60528
61110
  ringBuffers = new Map;
60529
61111
  specsPromise;
60530
61112
  frameSeq = 0;
61113
+ restartAttempts = new Map;
61114
+ restartTimers = new Map;
60531
61115
  constructor(options) {
60532
61116
  this.processExecutor = options.processExecutor;
60533
61117
  this.eventBus = options.eventBus;
@@ -60565,12 +61149,17 @@ class SupervisorService {
60565
61149
  throw new Error(`No agent spec found for "${agentId}"`);
60566
61150
  }
60567
61151
  const { command, args } = this.resolveCommand(spec);
61152
+ const teamTag = spec.tags.find((t) => t.startsWith("team:"));
61153
+ const teamId = teamTag ? teamTag.slice("team:".length) : null;
60568
61154
  const frames = [];
60569
61155
  this.ringBuffers.set(agentId, frames);
60570
61156
  const pipeOpts = {
60571
61157
  command,
60572
61158
  args,
60573
61159
  label: `agent:${agentId}`,
61160
+ source: "supervisor",
61161
+ agentId,
61162
+ ...teamId ? { teamId } : {},
60574
61163
  env: Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined))
60575
61164
  };
60576
61165
  const handle = this.processExecutor.runStreaming(pipeOpts);
@@ -60580,22 +61169,35 @@ class SupervisorService {
60580
61169
  pid,
60581
61170
  status: "running",
60582
61171
  startedAt: new Date().toISOString(),
60583
- ringBuffer: frames
61172
+ ringBuffer: frames,
61173
+ teamId
60584
61174
  };
60585
61175
  this.processes.set(agentId, { handle, entry });
61176
+ this.restartAttempts.delete(agentId);
60586
61177
  this.pipeStream(handle.stdout, "stdout", agentId, frames);
60587
61178
  this.pipeStream(handle.stderr, "stderr", agentId, frames);
60588
61179
  this.emit("process.spawned", { agentId, pid });
60589
- handle.exited.then((code) => {
60590
- entry.status = "exited";
61180
+ handle.exited.then(async (code) => {
60591
61181
  entry.exitCode = code;
60592
- const keepForMs = 60000;
60593
- setTimeout(() => {
60594
- if (this.processes.get(agentId)?.entry === entry) {
60595
- this.processes.delete(agentId);
60596
- }
60597
- }, keepForMs);
60598
61182
  this.emit("process.exited", { agentId, pid, exitCode: code });
61183
+ if (code === 0 || entry.status === "stopped") {
61184
+ entry.status = "exited";
61185
+ this.scheduleCleanup(agentId, entry);
61186
+ return;
61187
+ }
61188
+ const attempts = (this.restartAttempts.get(agentId) ?? 0) + 1;
61189
+ this.restartAttempts.set(agentId, attempts);
61190
+ if (attempts > MAX_RESTART_ATTEMPTS) {
61191
+ entry.status = "errored";
61192
+ this.scheduleCleanup(agentId, entry);
61193
+ return;
61194
+ }
61195
+ entry.status = "errored";
61196
+ const delay = attempts >= RESTART_BACKOFF_SCHEDULE.length ? MAX_RESTART_BACKOFF : RESTART_BACKOFF_SCHEDULE[attempts - 1] ?? 1000;
61197
+ this.restartTimers.set(agentId, setTimeout(() => {
61198
+ this.restartTimers.delete(agentId);
61199
+ this.start(agentId).catch(() => {});
61200
+ }, delay));
60599
61201
  });
60600
61202
  return entry;
60601
61203
  }
@@ -60618,6 +61220,12 @@ class SupervisorService {
60618
61220
  await proc.handle.exited.catch(() => {});
60619
61221
  }
60620
61222
  proc.entry.status = "stopped";
61223
+ const timer = this.restartTimers.get(agentId);
61224
+ if (timer) {
61225
+ clearTimeout(timer);
61226
+ this.restartTimers.delete(agentId);
61227
+ }
61228
+ this.restartAttempts.delete(agentId);
60621
61229
  this.emit("process.stopped", { agentId, pid: proc.entry.pid });
60622
61230
  }
60623
61231
  async startAutostart(ids) {
@@ -60638,12 +61246,22 @@ class SupervisorService {
60638
61246
  const running = Array.from(this.processes.keys()).filter((id) => this.processes.get(id)?.entry.status === "running");
60639
61247
  await Promise.all(running.map((id) => this.stop(id)));
60640
61248
  }
61249
+ scheduleCleanup(agentId, entry) {
61250
+ const keepForMs = 60000;
61251
+ setTimeout(() => {
61252
+ if (this.processes.get(agentId)?.entry === entry) {
61253
+ this.processes.delete(agentId);
61254
+ }
61255
+ }, keepForMs);
61256
+ }
60641
61257
  async loadSpecs() {
60642
61258
  this.specsPromise ??= Promise.resolve().then(() => (init_dist7(), exports_dist3)).then((m) => m.loadAgentSpecs(this.configDir));
60643
61259
  return this.specsPromise;
60644
61260
  }
60645
61261
  resolveCommand(spec) {
60646
- const raw = spec.command;
61262
+ const configCommand = Array.isArray(spec.config?.command) ? spec.config.command : undefined;
61263
+ const topLevel = spec.command;
61264
+ const raw = configCommand ?? topLevel;
60647
61265
  if (raw && raw.length > 0) {
60648
61266
  return { command: raw[0] ?? "", args: raw.slice(1) };
60649
61267
  }
@@ -60690,7 +61308,10 @@ class SupervisorService {
60690
61308
  } catch {}
60691
61309
  }
60692
61310
  }
60693
- var DEFAULT_RING_BUFFER_SIZE = 500;
61311
+ var DEFAULT_RING_BUFFER_SIZE = 500, MAX_RESTART_ATTEMPTS = 5, RESTART_BACKOFF_SCHEDULE, MAX_RESTART_BACKOFF = 30000;
61312
+ var init_supervisor_service = __esm(() => {
61313
+ RESTART_BACKOFF_SCHEDULE = [1000, 2000, 4000, 8000, 16000];
61314
+ });
60694
61315
 
60695
61316
  // ../../packages/app/src/services/system-event-tap.ts
60696
61317
  function registerSystemEventTap(bus, dao2, logger3, options = {}) {
@@ -60765,6 +61386,41 @@ var init_system_event_tap = __esm(() => {
60765
61386
  init_event_names();
60766
61387
  });
60767
61388
 
61389
+ // ../../packages/app/src/services/system-event-emitter.ts
61390
+ class SystemEventEmitter {
61391
+ dao;
61392
+ logger;
61393
+ constructor(dao2, logger3) {
61394
+ this.dao = dao2;
61395
+ this.logger = logger3;
61396
+ }
61397
+ async emit(event2) {
61398
+ const entry = systemEventCatalogEntry(event2.event);
61399
+ if (!entry)
61400
+ return;
61401
+ try {
61402
+ await this.dao.insert({
61403
+ id: createId("sev"),
61404
+ event_name: entry.name,
61405
+ occurred_at: event2.at,
61406
+ actor: extractSystemEventActor(event2),
61407
+ payload_json: safeStringify(normalizeSystemEventPayload(entry, event2))
61408
+ });
61409
+ await this.dao.prune(SYSTEM_EVENTS_CAP);
61410
+ } catch (error51) {
61411
+ this.logger.warn("system_events emitter: persist failed", {
61412
+ event: event2.event,
61413
+ error: error51 instanceof Error ? `${error51.name}: ${error51.message}` : String(error51)
61414
+ });
61415
+ }
61416
+ }
61417
+ }
61418
+ var init_system_event_emitter = __esm(() => {
61419
+ init_src2();
61420
+ init_event_names();
61421
+ init_system_event_tap();
61422
+ });
61423
+
60768
61424
  // ../../packages/app/src/services/task-check.ts
60769
61425
  import { dirname as dirname9, join as join9 } from "path";
60770
61426
  function isPlaceholderBody(body) {
@@ -62336,6 +62992,27 @@ class TeamService {
62336
62992
  count: rows.length
62337
62993
  };
62338
62994
  }
62995
+ async drainPending(agentId) {
62996
+ validateAgentId(agentId);
62997
+ const dao2 = await this.inboxDao();
62998
+ const rows = await dao2.drainPending(agentId);
62999
+ return {
63000
+ messages: rows.map((row) => ({
63001
+ id: row.id,
63002
+ fromId: row.fromId,
63003
+ body: row.body,
63004
+ status: row.status,
63005
+ createdAt: new Date(row.createdAt).toISOString(),
63006
+ inReplyTo: row.inReplyTo
63007
+ })),
63008
+ count: rows.length
63009
+ };
63010
+ }
63011
+ async countPending(agentId) {
63012
+ validateAgentId(agentId);
63013
+ const dao2 = await this.inboxDao();
63014
+ return dao2.countPending(agentId);
63015
+ }
62339
63016
  async listRecent(limit = 50) {
62340
63017
  const dao2 = await this.inboxRecentDao();
62341
63018
  const rows = await dao2.listRecent(limit);
@@ -62436,6 +63113,131 @@ class TeamService {
62436
63113
  peers
62437
63114
  });
62438
63115
  }
63116
+ async listTeams() {
63117
+ const specs = await loadAgentSpecs(this.configDir);
63118
+ const config4 = await this.loadTeamConfig();
63119
+ const teams = new Map;
63120
+ if (config4?.agent?.team) {
63121
+ for (const [teamId, teamConfig] of Object.entries(config4.agent.team)) {
63122
+ teams.set(teamId, {
63123
+ teamId,
63124
+ name: teamConfig.name,
63125
+ members: [],
63126
+ specs: []
63127
+ });
63128
+ }
63129
+ }
63130
+ const untethered = [];
63131
+ for (const spec of specs) {
63132
+ const teamTag = spec.tags?.find((t) => t.startsWith("team:"));
63133
+ if (teamTag) {
63134
+ const teamId = teamTag.slice("team:".length);
63135
+ const entry = teams.get(teamId);
63136
+ if (entry) {
63137
+ entry.specs.push(spec);
63138
+ } else {
63139
+ teams.set(teamId, {
63140
+ teamId,
63141
+ name: teamId,
63142
+ members: [],
63143
+ specs: [spec]
63144
+ });
63145
+ }
63146
+ } else {
63147
+ untethered.push(spec);
63148
+ }
63149
+ }
63150
+ if (untethered.length > 0) {
63151
+ teams.set("__untethered__", {
63152
+ teamId: "__untethered__",
63153
+ name: "Untethered",
63154
+ members: [],
63155
+ specs: untethered
63156
+ });
63157
+ }
63158
+ return Array.from(teams.values());
63159
+ }
63160
+ async materializeTeam(teamId, opts) {
63161
+ const config4 = await this.loadTeamConfig();
63162
+ const teamConfig = config4?.agent?.team?.[teamId];
63163
+ if (!teamConfig) {
63164
+ throw new Error(`Team "${teamId}" not found in agent.team config`);
63165
+ }
63166
+ const agentConfig = config4?.agent;
63167
+ const specs = await loadAgentSpecs(this.configDir);
63168
+ const existingTeamSpecs = specs.filter((s) => s.tags?.includes(`team:${teamId}`) && s.tags?.includes("spur:generated"));
63169
+ const desiredMembers = teamConfig.members.map((m) => normalizeMember(m));
63170
+ const desiredIds = new Set;
63171
+ const toUpsert = [];
63172
+ for (const member of desiredMembers) {
63173
+ const localId = member.id ?? member.executor;
63174
+ const composedId = `${teamId}-${localId}`;
63175
+ desiredIds.add(composedId);
63176
+ const existing = specs.find((s) => s.id === composedId);
63177
+ if (existing && !existing.tags?.includes("spur:generated"))
63178
+ continue;
63179
+ const resolved = resolveExecutor(member.executor, agentConfig);
63180
+ const spec = {
63181
+ id: composedId,
63182
+ name: member.purpose ?? composedId,
63183
+ type: resolved.agent,
63184
+ workspace: member.workspace ?? teamConfig.work_dir,
63185
+ purpose: member.purpose && member.purpose.length > 0 ? member.purpose : `${resolved.agent} agent`,
63186
+ tags: [`team:${teamId}`, "spur:generated"],
63187
+ config: {
63188
+ ...resolved.model !== undefined ? { model: resolved.model } : {},
63189
+ ...member.systemPrompt !== undefined ? { systemPrompt: member.systemPrompt } : {},
63190
+ ...member.command !== undefined ? { command: member.command } : {},
63191
+ ...member.autonomy !== undefined ? { autonomy: member.autonomy } : {}
63192
+ },
63193
+ ...member.autostart !== undefined ? { autoStart: member.autostart } : {}
63194
+ };
63195
+ toUpsert.push(spec);
63196
+ }
63197
+ const orphaned = existingTeamSpecs.filter((s) => !desiredIds.has(s.id));
63198
+ if (opts?.check) {
63199
+ return {
63200
+ teamId,
63201
+ upserted: toUpsert.map((s) => s.id),
63202
+ orphaned: orphaned.map((s) => s.id),
63203
+ written: false
63204
+ };
63205
+ }
63206
+ for (const spec of toUpsert) {
63207
+ await saveAgentSpec(spec, this.configDir);
63208
+ }
63209
+ for (const spec of orphaned) {
63210
+ await deleteAgentSpec(spec.id, this.configDir);
63211
+ }
63212
+ return {
63213
+ teamId,
63214
+ upserted: toUpsert.map((s) => s.id),
63215
+ orphaned: orphaned.map((s) => s.id),
63216
+ written: true
63217
+ };
63218
+ }
63219
+ async teardownTeam(teamId, opts) {
63220
+ const specs = await loadAgentSpecs(this.configDir);
63221
+ const teamSpecs = specs.filter((s) => s.tags?.includes(`team:${teamId}`));
63222
+ const generated = teamSpecs.filter((s) => s.tags?.includes("spur:generated"));
63223
+ if (opts?.purge) {
63224
+ for (const spec of generated) {
63225
+ await deleteAgentSpec(spec.id, this.configDir);
63226
+ }
63227
+ }
63228
+ return {
63229
+ teamId,
63230
+ purged: opts?.purge ? generated.map((s) => s.id) : [],
63231
+ stopped: teamSpecs.map((s) => s.id)
63232
+ };
63233
+ }
63234
+ async loadTeamConfig() {
63235
+ try {
63236
+ return await loadSpurConfig(this.ctx.cwd);
63237
+ } catch {
63238
+ return null;
63239
+ }
63240
+ }
62439
63241
  async inboxDao() {
62440
63242
  const db2 = await this.ctx.getDb();
62441
63243
  return new InboxMessageDao(db2);
@@ -62476,17 +63278,312 @@ class TeamService {
62476
63278
  return null;
62477
63279
  }
62478
63280
  }
63281
+ function resolveAutostartSet(config4, envAutostart) {
63282
+ const ids = new Set;
63283
+ const teams = config4?.agent?.team;
63284
+ if (teams) {
63285
+ for (const [teamId, teamConfig] of Object.entries(teams)) {
63286
+ for (const member of teamConfig.members) {
63287
+ const ref = normalizeMember(member);
63288
+ const localId = ref.id ?? ref.executor;
63289
+ const composedId = `${teamId}-${localId}`;
63290
+ const effective = ref.autostart ?? teamConfig.autostart ?? false;
63291
+ if (effective)
63292
+ ids.add(composedId);
63293
+ }
63294
+ }
63295
+ }
63296
+ if (envAutostart) {
63297
+ for (const id of envAutostart.split(",").map((s) => s.trim()).filter(Boolean)) {
63298
+ ids.add(id);
63299
+ }
63300
+ }
63301
+ return Array.from(ids).sort();
63302
+ }
62479
63303
  var init_team_service = __esm(() => {
63304
+ init_src();
63305
+ init_loader();
62480
63306
  init_src2();
62481
63307
  init_dist7();
62482
63308
  init_planning_folders();
62483
63309
  });
62484
63310
 
63311
+ // ../../packages/app/src/services/token-ledger-service.ts
63312
+ import { closeSync as closeSync2, existsSync as existsSync5, fstatSync, openSync as openSync2, readSync } from "fs";
63313
+ import { join as join11 } from "path";
63314
+ function isSparseToolActivity(events2) {
63315
+ return events2.length === 0 || !events2.some((e) => TOOL_ACTIVITY_TYPES.has(e.type));
63316
+ }
63317
+ function clampToolUseLimit(raw) {
63318
+ if (raw === undefined || !Number.isFinite(raw) || raw <= 0) {
63319
+ return TOKEN_LEDGER_DEFAULT_LIMIT;
63320
+ }
63321
+ return Math.min(Math.floor(raw), TOKEN_LEDGER_MAX_LIMIT);
63322
+ }
63323
+ function parseLedgerLine(line) {
63324
+ const trimmed = line.trim();
63325
+ if (!trimmed)
63326
+ return null;
63327
+ try {
63328
+ const obj = JSON.parse(trimmed);
63329
+ if (typeof obj.ts !== "string" || typeof obj.session !== "string" || typeof obj.type !== "string") {
63330
+ return null;
63331
+ }
63332
+ const event2 = {
63333
+ ts: obj.ts,
63334
+ session: obj.session,
63335
+ type: obj.type
63336
+ };
63337
+ if (typeof obj.file === "string")
63338
+ event2.file = obj.file;
63339
+ if (typeof obj.summary === "string")
63340
+ event2.summary = obj.summary;
63341
+ if (typeof obj.tokens === "number" && Number.isFinite(obj.tokens) && obj.tokens >= 0) {
63342
+ event2.tokens = obj.tokens;
63343
+ }
63344
+ if (typeof obj.action === "string")
63345
+ event2.action = obj.action;
63346
+ if (typeof obj.sessionId === "string")
63347
+ event2.sessionId = obj.sessionId;
63348
+ if (typeof obj.agent === "string")
63349
+ event2.agent = obj.agent;
63350
+ if (typeof obj.model === "string")
63351
+ event2.model = obj.model;
63352
+ if (obj.totals !== null && typeof obj.totals === "object") {
63353
+ const t = obj.totals;
63354
+ if (typeof t.reads === "number" && typeof t.writes === "number" && typeof t.tokens === "number") {
63355
+ event2.totals = { reads: t.reads, writes: t.writes, tokens: t.tokens };
63356
+ }
63357
+ }
63358
+ return event2;
63359
+ } catch {
63360
+ return null;
63361
+ }
63362
+ }
63363
+ function tailTokenLedgerFile(filePath, limit, chunkSize = DEFAULT_CHUNK, before) {
63364
+ if (!existsSync5(filePath)) {
63365
+ return { events: [], truncated: false };
63366
+ }
63367
+ const target = limit + 1;
63368
+ const fd = openSync2(filePath, "r");
63369
+ try {
63370
+ const { size } = fstatSync(fd);
63371
+ if (size === 0)
63372
+ return { events: [], truncated: false };
63373
+ let pos = size;
63374
+ let carry = "";
63375
+ const events2 = [];
63376
+ while (pos > 0 && events2.length < target) {
63377
+ const n2 = Math.min(chunkSize, pos);
63378
+ pos -= n2;
63379
+ const buf = Buffer.alloc(n2);
63380
+ readSync(fd, buf, 0, n2, pos);
63381
+ const text4 = buf.toString("utf8") + carry;
63382
+ const parts = text4.split(`
63383
+ `);
63384
+ if (pos > 0) {
63385
+ carry = parts.shift() ?? "";
63386
+ } else {
63387
+ carry = "";
63388
+ }
63389
+ for (let i2 = parts.length - 1;i2 >= 0; i2--) {
63390
+ const evt = parseLedgerLine(parts[i2] ?? "");
63391
+ if (!evt)
63392
+ continue;
63393
+ if (before !== undefined && evt.ts >= before)
63394
+ continue;
63395
+ events2.push(evt);
63396
+ if (events2.length >= target)
63397
+ break;
63398
+ }
63399
+ }
63400
+ const truncated = events2.length > limit;
63401
+ return {
63402
+ events: events2.slice(0, limit),
63403
+ truncated
63404
+ };
63405
+ } finally {
63406
+ closeSync2(fd);
63407
+ }
63408
+ }
63409
+
63410
+ class TokenLedgerService {
63411
+ ledgerPath;
63412
+ chunkSize;
63413
+ constructor(options) {
63414
+ this.ledgerPath = options.ledgerPath ?? join11(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
63415
+ this.chunkSize = options.chunkSize ?? DEFAULT_CHUNK;
63416
+ }
63417
+ get path() {
63418
+ return this.ledgerPath;
63419
+ }
63420
+ snapshot(limitRawOrOpts, maybeBefore) {
63421
+ let limitRaw;
63422
+ let before;
63423
+ if (typeof limitRawOrOpts === "object" && limitRawOrOpts !== null) {
63424
+ limitRaw = limitRawOrOpts.limit;
63425
+ before = limitRawOrOpts.before;
63426
+ } else {
63427
+ limitRaw = limitRawOrOpts;
63428
+ before = maybeBefore;
63429
+ }
63430
+ if (before !== undefined && (typeof before !== "string" || before.length === 0)) {
63431
+ before = undefined;
63432
+ }
63433
+ const limit = clampToolUseLimit(limitRaw);
63434
+ const capturedAt = new Date().toISOString();
63435
+ const { events: raw, truncated } = tailTokenLedgerFile(this.ledgerPath, limit, this.chunkSize, before);
63436
+ const events2 = raw.map((e, seq) => ({ ...e, seq }));
63437
+ const sparseToolActivity = isSparseToolActivity(events2);
63438
+ const oldest = events2.length > 0 ? events2[events2.length - 1] : undefined;
63439
+ const nextBefore = truncated && oldest ? oldest.ts : null;
63440
+ return {
63441
+ events: events2,
63442
+ count: events2.length,
63443
+ limit,
63444
+ truncated,
63445
+ path: this.ledgerPath,
63446
+ capturedAt,
63447
+ sparseToolActivity,
63448
+ nextBefore
63449
+ };
63450
+ }
63451
+ }
63452
+ var TOOL_ACTIVITY_TYPES, TOKEN_LEDGER_DEFAULT_LIMIT = 200, TOKEN_LEDGER_MAX_LIMIT = 1000, TOKEN_LEDGER_RELATIVE_PATH, DEFAULT_CHUNK;
63453
+ var init_token_ledger_service = __esm(() => {
63454
+ TOOL_ACTIVITY_TYPES = new Set(["read", "write", "bash", "grep", "glob"]);
63455
+ TOKEN_LEDGER_RELATIVE_PATH = join11(".spur", "context", "token-ledger.jsonl");
63456
+ DEFAULT_CHUNK = 64 * 1024;
63457
+ });
63458
+
63459
+ // ../../packages/app/src/services/token-ledger-watcher.ts
63460
+ import { closeSync as closeSync3, existsSync as existsSync6, fstatSync as fstatSync2, openSync as openSync3, readSync as readSync2, watch } from "fs";
63461
+
63462
+ class TokenLedgerWatcher {
63463
+ ledgerPath;
63464
+ debounceMs;
63465
+ listeners = new Set;
63466
+ watcher;
63467
+ offset = 0;
63468
+ debounceTimer;
63469
+ started = false;
63470
+ carry = "";
63471
+ constructor(options) {
63472
+ this.ledgerPath = options.ledgerPath;
63473
+ this.debounceMs = options.debounceMs ?? 50;
63474
+ }
63475
+ start() {
63476
+ if (this.started)
63477
+ return;
63478
+ this.started = true;
63479
+ this.offset = this.currentSize();
63480
+ try {
63481
+ const target = existsSync6(this.ledgerPath) ? this.ledgerPath : this.parentDir();
63482
+ this.watcher = watch(target, () => this.schedulePoll());
63483
+ } catch {
63484
+ this.watcher = undefined;
63485
+ }
63486
+ }
63487
+ stop() {
63488
+ this.started = false;
63489
+ if (this.debounceTimer)
63490
+ clearTimeout(this.debounceTimer);
63491
+ this.debounceTimer = undefined;
63492
+ try {
63493
+ this.watcher?.close();
63494
+ } catch {}
63495
+ this.watcher = undefined;
63496
+ this.listeners.clear();
63497
+ }
63498
+ subscribe(listener) {
63499
+ this.listeners.add(listener);
63500
+ if (!this.started)
63501
+ this.start();
63502
+ return () => {
63503
+ this.listeners.delete(listener);
63504
+ if (this.listeners.size === 0)
63505
+ this.stop();
63506
+ };
63507
+ }
63508
+ get subscriberCount() {
63509
+ return this.listeners.size;
63510
+ }
63511
+ parentDir() {
63512
+ const idx = Math.max(this.ledgerPath.lastIndexOf("/"), this.ledgerPath.lastIndexOf("\\"));
63513
+ return idx > 0 ? this.ledgerPath.slice(0, idx) : ".";
63514
+ }
63515
+ currentSize() {
63516
+ if (!existsSync6(this.ledgerPath))
63517
+ return 0;
63518
+ try {
63519
+ const fd = openSync3(this.ledgerPath, "r");
63520
+ try {
63521
+ return fstatSync2(fd).size;
63522
+ } finally {
63523
+ closeSync3(fd);
63524
+ }
63525
+ } catch {
63526
+ return 0;
63527
+ }
63528
+ }
63529
+ schedulePoll() {
63530
+ if (this.debounceTimer)
63531
+ clearTimeout(this.debounceTimer);
63532
+ this.debounceTimer = setTimeout(() => {
63533
+ this.debounceTimer = undefined;
63534
+ this.pollNewBytes();
63535
+ }, this.debounceMs);
63536
+ }
63537
+ pollNewBytes() {
63538
+ if (!existsSync6(this.ledgerPath)) {
63539
+ this.offset = 0;
63540
+ this.carry = "";
63541
+ return;
63542
+ }
63543
+ let size;
63544
+ try {
63545
+ const fd = openSync3(this.ledgerPath, "r");
63546
+ try {
63547
+ size = fstatSync2(fd).size;
63548
+ if (size < this.offset) {
63549
+ this.offset = 0;
63550
+ this.carry = "";
63551
+ }
63552
+ if (size === this.offset)
63553
+ return;
63554
+ const len = size - this.offset;
63555
+ const buf = Buffer.alloc(len);
63556
+ readSync2(fd, buf, 0, len, this.offset);
63557
+ this.offset = size;
63558
+ const text4 = this.carry + buf.toString("utf8");
63559
+ const parts = text4.split(`
63560
+ `);
63561
+ this.carry = parts.pop() ?? "";
63562
+ for (const line of parts) {
63563
+ const evt = parseLedgerLine(line);
63564
+ if (!evt)
63565
+ continue;
63566
+ for (const listener of this.listeners) {
63567
+ try {
63568
+ listener(evt);
63569
+ } catch {}
63570
+ }
63571
+ }
63572
+ } finally {
63573
+ closeSync3(fd);
63574
+ }
63575
+ } catch {}
63576
+ }
63577
+ }
63578
+ var init_token_ledger_watcher = __esm(() => {
63579
+ init_token_ledger_service();
63580
+ });
63581
+
62485
63582
  // ../../packages/app/src/workflow/actions/agent-run.ts
62486
63583
  import { execFile } from "child_process";
62487
- import { existsSync as existsSync5 } from "fs";
63584
+ import { existsSync as existsSync7 } from "fs";
62488
63585
  import { mkdir, writeFile } from "fs/promises";
62489
- import { dirname as dirname10, isAbsolute as isAbsolute2, join as join11 } from "path";
63586
+ import { dirname as dirname10, isAbsolute as isAbsolute2, join as join12 } from "path";
62490
63587
  import { promisify as promisify3 } from "util";
62491
63588
 
62492
63589
  class AgentRunActionRunner {
@@ -62540,13 +63637,13 @@ class AgentRunActionRunner {
62540
63637
  const { exitCode: exitCode2, answer } = captured;
62541
63638
  const ok2 = exitCode2 === 0;
62542
63639
  if (answerFile !== undefined) {
62543
- const target = isAbsolute2(answerFile) ? answerFile : join11(cwd, answerFile);
63640
+ const target = isAbsolute2(answerFile) ? answerFile : join12(cwd, answerFile);
62544
63641
  await mkdir(dirname10(target), { recursive: true });
62545
63642
  await writeFile(target, answer, "utf8");
62546
63643
  }
62547
63644
  if (ok2 && expectFile !== undefined) {
62548
- const target = isAbsolute2(expectFile) ? expectFile : join11(cwd, expectFile);
62549
- if (!existsSync5(target)) {
63645
+ const target = isAbsolute2(expectFile) ? expectFile : join12(cwd, expectFile);
63646
+ if (!existsSync7(target)) {
62550
63647
  return {
62551
63648
  ok: false,
62552
63649
  data: { exitCode: exitCode2, agent: agentLabel, answer },
@@ -62567,8 +63664,8 @@ class AgentRunActionRunner {
62567
63664
  const exitCode = await this.agentService.run(input, flags);
62568
63665
  const ok = exitCode === 0;
62569
63666
  if (ok && expectFile !== undefined) {
62570
- const target = isAbsolute2(expectFile) ? expectFile : join11(cwd, expectFile);
62571
- if (!existsSync5(target)) {
63667
+ const target = isAbsolute2(expectFile) ? expectFile : join12(cwd, expectFile);
63668
+ if (!existsSync7(target)) {
62572
63669
  return {
62573
63670
  ok: false,
62574
63671
  data: { exitCode, agent: agentLabel },
@@ -62645,7 +63742,7 @@ async function writePartialWorkArtifact(context4, agentLabel, model, captured, c
62645
63742
  ""
62646
63743
  ].join(`
62647
63744
  `);
62648
- const target = join11(cwd, ".spur", "run", `${context4.runId}-${context4.stateOrNodeId}-partial.md`);
63745
+ const target = join12(cwd, ".spur", "run", `${context4.runId}-${context4.stateOrNodeId}-partial.md`);
62649
63746
  await mkdir(dirname10(target), { recursive: true });
62650
63747
  await writeFile(target, body, "utf8");
62651
63748
  } catch {}
@@ -63309,7 +64406,7 @@ var now = () => new Date().toISOString();
63309
64406
  // ../../packages/app/src/services/workflow-service.ts
63310
64407
  import { access as access2, lstat, readdir as readdir3, readFile as readFile2, realpath } from "fs/promises";
63311
64408
  import { homedir as homedir3 } from "os";
63312
- import { join as join12, resolve as resolve3 } from "path";
64409
+ import { join as join13, resolve as resolve3 } from "path";
63313
64410
  function signalSubprocess(pid) {
63314
64411
  try {
63315
64412
  process.kill(-pid, "SIGTERM");
@@ -63513,7 +64610,7 @@ class WorkflowAppService {
63513
64610
  }
63514
64611
  async list(workflowPaths = [".spur/workflows/"]) {
63515
64612
  const projectRoot = this.ctx.cwd;
63516
- const globalRoot = join12(homedir3(), ".config", "spur");
64613
+ const globalRoot = join13(homedir3(), ".config", "spur");
63517
64614
  const layers = [];
63518
64615
  const entries = [];
63519
64616
  const scannedPaths = new Set;
@@ -63849,8 +64946,10 @@ var isActionStarted = (e) => ("kind" in e) && ("node" in e), isActionFinished =
63849
64946
  // ../../packages/app/src/index.ts
63850
64947
  var exports_src2 = {};
63851
64948
  __export(exports_src2, {
64949
+ tailTokenLedgerFile: () => tailTokenLedgerFile,
63852
64950
  systemEventCatalogEntry: () => systemEventCatalogEntry,
63853
64951
  resolvePlanningFolders: () => resolvePlanningFolders,
64952
+ resolveAutostartSet: () => resolveAutostartSet,
63854
64953
  renderTesting: () => renderTesting,
63855
64954
  renderStepLine: () => renderStepLine,
63856
64955
  renderSolutionFromDiff: () => renderSolutionFromDiff,
@@ -63861,6 +64960,7 @@ __export(exports_src2, {
63861
64960
  readVerdict: () => readVerdict,
63862
64961
  parseVerdict: () => parseVerdict,
63863
64962
  parsePsOutput: () => parsePsOutput,
64963
+ parseLedgerLine: () => parseLedgerLine,
63864
64964
  parseEtimeToSeconds: () => parseEtimeToSeconds,
63865
64965
  normalizeSystemEventPayload: () => normalizeSystemEventPayload,
63866
64966
  hitlConfirmDefault: () => hitlConfirmDefault,
@@ -63868,14 +64968,21 @@ __export(exports_src2, {
63868
64968
  extractSystemEventActor: () => extractSystemEventActor,
63869
64969
  deriveVerdict: () => deriveVerdict,
63870
64970
  createPsProcessInspector: () => createPsProcessInspector,
64971
+ clampToolUseLimit: () => clampToolUseLimit,
63871
64972
  bridgeEventBus: () => bridgeEventBus,
63872
64973
  WorkflowAppService: () => WorkflowAppService,
63873
64974
  UnsupportedProcessPlatformError: () => UnsupportedProcessPlatformError,
64975
+ TokenLedgerWatcher: () => TokenLedgerWatcher,
64976
+ TokenLedgerService: () => TokenLedgerService,
63874
64977
  TeamService: () => TeamService,
63875
64978
  TaskService: () => TaskService,
63876
64979
  TaskCheckService: () => TaskCheckService,
64980
+ TOKEN_LEDGER_RELATIVE_PATH: () => TOKEN_LEDGER_RELATIVE_PATH,
64981
+ TOKEN_LEDGER_MAX_LIMIT: () => TOKEN_LEDGER_MAX_LIMIT,
64982
+ TOKEN_LEDGER_DEFAULT_LIMIT: () => TOKEN_LEDGER_DEFAULT_LIMIT,
63877
64983
  TASK_LIFECYCLE_PROFILE: () => TASK_LIFECYCLE_PROFILE,
63878
64984
  TASK_ACTION_COMMANDS: () => TASK_ACTION_COMMANDS,
64985
+ SystemEventEmitter: () => SystemEventEmitter,
63879
64986
  SupervisorService: () => SupervisorService,
63880
64987
  SYSTEM_EVENT_STREAMED_NAMES: () => SYSTEM_EVENT_STREAMED_NAMES,
63881
64988
  SYSTEM_EVENT_PREFIXES: () => SYSTEM_EVENT_PREFIXES,
@@ -63927,11 +65034,15 @@ var init_src3 = __esm(() => {
63927
65034
  init_process_inspector();
63928
65035
  init_process_inventory_service();
63929
65036
  init_rule_service();
65037
+ init_supervisor_service();
65038
+ init_system_event_emitter();
63930
65039
  init_system_event_tap();
63931
65040
  init_task_check();
63932
65041
  init_task_record();
63933
65042
  init_task_service();
63934
65043
  init_team_service();
65044
+ init_token_ledger_service();
65045
+ init_token_ledger_watcher();
63935
65046
  init_workflow_service();
63936
65047
  init_agent_run();
63937
65048
  init_file_exists();
@@ -64020,18 +65131,19 @@ var {
64020
65131
  init_src();
64021
65132
  init_loader();
64022
65133
 
64023
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/application-node.js
65134
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/application-node.js
64024
65135
  init_dist4();
64025
65136
  init_dist5();
64026
65137
  import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "fs";
64027
65138
  import { dirname as dirname5 } from "path";
64028
65139
 
64029
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/application/index.js
65140
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/application/index.js
64030
65141
  init_default_observers();
64031
65142
  init_event_bus();
65143
+ init_file_observer();
64032
65144
  init_logger3();
64033
65145
 
64034
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
65146
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
64035
65147
  class NoopSchedulerAdapter {
64036
65148
  constructor() {}
64037
65149
  register(_cron, _action) {}
@@ -64039,7 +65151,7 @@ class NoopSchedulerAdapter {
64039
65151
  async stop() {}
64040
65152
  }
64041
65153
 
64042
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
65154
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
64043
65155
  function initScheduler(adapter, cronEntries) {
64044
65156
  const resolved = adapter ?? new NoopSchedulerAdapter;
64045
65157
  if (cronEntries) {
@@ -64050,7 +65162,7 @@ function initScheduler(adapter, cronEntries) {
64050
65162
  return resolved;
64051
65163
  }
64052
65164
 
64053
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
65165
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
64054
65166
  init_logger3();
64055
65167
  init_metrics();
64056
65168
  init_sdk();
@@ -64143,7 +65255,7 @@ function dbPlugin(db2) {
64143
65255
  };
64144
65256
  }
64145
65257
 
64146
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
65258
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
64147
65259
  init_logger3();
64148
65260
 
64149
65261
  class PluginHost {
@@ -64231,7 +65343,7 @@ class PluginHost {
64231
65343
  }
64232
65344
  }
64233
65345
 
64234
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/application/index.js
65346
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/application/index.js
64235
65347
  async function performShutdown(state, reason) {
64236
65348
  if (state.stopped)
64237
65349
  return;
@@ -64266,6 +65378,9 @@ async function runApplication(options) {
64266
65378
  const eventsEnabled = options.config?.events?.enabled ?? true;
64267
65379
  const eventsLifecycle = options.config?.events?.lifecycle ?? true;
64268
65380
  const eventsDefaultObservers = options.config?.events?.defaultObservers ?? true;
65381
+ const eventsFileObserver = options.config?.events?.fileObserver ?? true;
65382
+ const fileObserverWriter = options.services?.fileObserverWriter;
65383
+ const eventsFilePath = options.config?.events?.filePath ?? (fileObserverWriter !== undefined ? "logs/system-events.jsonl" : undefined);
64269
65384
  const state = {
64270
65385
  app: undefined,
64271
65386
  stopped: false,
@@ -64278,6 +65393,13 @@ async function runApplication(options) {
64278
65393
  if (lifecycleBus && eventsDefaultObservers) {
64279
65394
  attachDefaultObservers(lifecycleBus);
64280
65395
  }
65396
+ let fileObserverAttached = false;
65397
+ let fileObserverPath;
65398
+ if (lifecycleBus && eventsFileObserver && eventsFilePath !== undefined && fileObserverWriter !== undefined) {
65399
+ attachFileObserver(lifecycleBus, eventsFilePath, fileObserverWriter);
65400
+ fileObserverAttached = true;
65401
+ fileObserverPath = eventsFilePath;
65402
+ }
64281
65403
  const events = options.services?.events ?? options.config?.events?.bus ?? new EventBus({ lifecycleBus });
64282
65404
  const db2 = options.services?.db;
64283
65405
  let scheduler3;
@@ -64291,7 +65413,13 @@ async function runApplication(options) {
64291
65413
  pluginHost.register(telemetryPlugin(telemetryConfig));
64292
65414
  const resolvedConfig2 = {
64293
65415
  logging: loggingConfig,
64294
- events: { enabled: eventsEnabled, lifecycle: eventsLifecycle, defaultObservers: eventsDefaultObservers },
65416
+ events: {
65417
+ enabled: eventsEnabled,
65418
+ lifecycle: eventsLifecycle,
65419
+ defaultObservers: eventsDefaultObservers,
65420
+ fileObserver: fileObserverAttached,
65421
+ ...fileObserverPath !== undefined ? { filePath: fileObserverPath } : {}
65422
+ },
64295
65423
  telemetry: telemetryConfig,
64296
65424
  scheduler: schedulerConfig
64297
65425
  };
@@ -64326,10 +65454,10 @@ async function runApplication(options) {
64326
65454
  }
64327
65455
  }
64328
65456
 
64329
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/application-node.js
65457
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/application-node.js
64330
65458
  init_scheduler_node();
64331
65459
 
64332
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
65460
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
64333
65461
  var import_api14 = __toESM(require_src(), 1);
64334
65462
 
64335
65463
  // ../../node_modules/.bun/@opentelemetry+exporter-metrics-otlp-http@0.218.0+e40b0dfdd726a224/node_modules/@opentelemetry/exporter-metrics-otlp-http/build/esm/OTLPMetricExporterBase.js
@@ -67345,7 +68473,7 @@ class OTLPTraceExporter extends import_otlp_exporter_base2.OTLPExporterBase {
67345
68473
  }), JsonTraceSerializer));
67346
68474
  }
67347
68475
  }
67348
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
68476
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
67349
68477
  var import_resources2 = __toESM(require_src4(), 1);
67350
68478
  var import_sdk_trace_node = __toESM(require_src8(), 1);
67351
68479
  var import_semantic_conventions = __toESM(require_src2(), 1);
@@ -67396,7 +68524,7 @@ async function shutdownNodeTelemetry() {
67396
68524
  await Promise.all(pending);
67397
68525
  }
67398
68526
 
67399
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.8+e2482bee662d08ad/node_modules/@gobing-ai/ts-infra/dist/application-node.js
68527
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.10+8e607bbe3266e5fa/node_modules/@gobing-ai/ts-infra/dist/application-node.js
67400
68528
  class ConfigValidationError extends Error {
67401
68529
  constructor(message) {
67402
68530
  super(message);
@@ -67476,10 +68604,12 @@ async function runNodeApplication(options) {
67476
68604
  const yamlLog = yamlBootstrap.logging;
67477
68605
  const yamlTel = yamlBootstrap.telemetry;
67478
68606
  const yamlSched = yamlBootstrap.scheduler;
68607
+ const yamlEvents = yamlBootstrap.events;
67479
68608
  const databaseOpts = yamlBootstrap.database ?? {};
67480
68609
  const loggingOpts = { ...yamlLog, ...options.config?.logging };
67481
68610
  const telemetryOpts = { ...yamlTel, ...options.config?.telemetry };
67482
68611
  const schedulerOpts = { ...yamlSched, ...options.config?.scheduler };
68612
+ const eventsOpts = { ...yamlEvents, ...options.config?.events };
67483
68613
  const logFilePath = yamlBootstrap.logging?.filePath;
67484
68614
  const loggingConfig = typeof logFilePath === "string" ? { ...loggingOpts, fileSink: createFileSink(logFilePath) } : loggingOpts;
67485
68615
  const schedulerConfig = {};
@@ -67524,10 +68654,31 @@ async function runNodeApplication(options) {
67524
68654
  throw new ConfigValidationError(`database.enabled is true but driver ${driver3 ? `"${driver3}"` : "is missing"} is not supported ` + `(expected "bun-sqlite"). Provide a supported driver or inject a DbAdapter via services.db.`);
67525
68655
  }
67526
68656
  }
68657
+ const injectedFileSystem = createNodeFileSystem3();
68658
+ const fileObserverWriter = options.services?.fileObserverWriter ?? {
68659
+ ensureDir: (dir) => {
68660
+ mkdirSync3(dir, { recursive: true });
68661
+ },
68662
+ appendFile: (path8, content) => {
68663
+ appendFileSync4(path8, content);
68664
+ }
68665
+ };
68666
+ const eventsFilePath = eventsOpts.filePath ?? injectedFileSystem.resolve("logs", "system-events.jsonl");
68667
+ const eventsConfig = {
68668
+ ...eventsOpts,
68669
+ filePath: eventsFilePath,
68670
+ ...eventsOpts.fileObserver === false ? {} : { fileObserver: true }
68671
+ };
67527
68672
  return await runApplication({
67528
- config: { ...options.config, logging: loggingConfig, telemetry: telemetryOpts, scheduler: schedulerConfig },
68673
+ config: {
68674
+ ...options.config,
68675
+ logging: loggingConfig,
68676
+ telemetry: telemetryOpts,
68677
+ scheduler: schedulerConfig,
68678
+ events: eventsConfig
68679
+ },
67529
68680
  appConfig: loadedAppConfig,
67530
- services: { ...options.services, ...dbAdapter ? { db: dbAdapter } : {} },
68681
+ services: { ...options.services, fileObserverWriter, ...dbAdapter ? { db: dbAdapter } : {} },
67531
68682
  start: options.start,
67532
68683
  stop: options.stop,
67533
68684
  plugins: plugins.length ? plugins : undefined
@@ -71198,6 +72349,20 @@ function registerAgentCommand(program2, context4) {
71198
72349
  const code = await runAgentRun(prompt, context4, flags);
71199
72350
  context4.setExitCode(code);
71200
72351
  });
72352
+ agent.command("loop").description("Run the persistent self-draining loop for a team member (used by the supervisor).").requiredOption("--agent <id>", "Agent spec id / message recipient").option("--poll <ms>", "Idle poll interval in milliseconds", String(DEFAULT_LOOP_POLL_MS)).action(async (options) => {
72353
+ const controller = new AbortController;
72354
+ const onSignal = () => controller.abort();
72355
+ process.on("SIGINT", onSignal);
72356
+ process.on("SIGTERM", onSignal);
72357
+ try {
72358
+ const flags = commanderOptionsToFlags(options);
72359
+ const code = await runAgentLoop(context4, flags, { signal: controller.signal });
72360
+ context4.setExitCode(code);
72361
+ } finally {
72362
+ process.off("SIGINT", onSignal);
72363
+ process.off("SIGTERM", onSignal);
72364
+ }
72365
+ });
71201
72366
  agent.command("create").description("Write a team agent spec to .spur/agents/<id>.yaml.").option("--type <agent-type>", "Agent spec type for create").option("--tags <a,b>", "Team identity tags").option("--system-prompt <text>", "Team identity system prompt").option("--name <name>", "Agent name").option("--workspace <path>", "Workspace path").option("--purpose <text>", "Team identity purpose").option("--auto-start", "Auto-start flag").option("--model <name>", "Agent model argument").option("--autonomy <level>", "Autonomy level").option("--no-identity-preamble", "Disable identity preamble").option("--json", "Output machine-readable JSON").argument("<id>", "Agent spec id").action(async (id, options) => {
71202
72367
  const flags = commanderOptionsToFlags(options);
71203
72368
  const code = await runAgentCreate(id, context4, flags);
@@ -71362,7 +72527,7 @@ async function drainIntoPrompt(prompt, context4, flags) {
71362
72527
  const team = new TeamService(context4);
71363
72528
  const spec = (await team.listAgentSpecs()).find((entry) => entry.id === recipient);
71364
72529
  const flagsOut = spec === undefined ? flags : { ...flags, agent: spec.type };
71365
- const inbox = await team.getInbox(recipient);
72530
+ const inbox = await team.drainPending(recipient);
71366
72531
  if (inbox.count === 0)
71367
72532
  return { prompt, flags: flagsOut };
71368
72533
  const header = inbox.messages.map((m) => `- ${m.fromId ?? "operator"}: ${m.body}`).join(`
@@ -71374,17 +72539,83 @@ ${header}`;
71374
72539
  ${prompt}`;
71375
72540
  return { prompt: merged, flags: flagsOut };
71376
72541
  }
72542
+ var DEFAULT_LOOP_POLL_MS = 2000;
72543
+ function parseLoopPoll(raw) {
72544
+ if (typeof raw !== "string")
72545
+ return DEFAULT_LOOP_POLL_MS;
72546
+ const n2 = Number.parseInt(raw, 10);
72547
+ return Number.isFinite(n2) && n2 > 0 ? n2 : DEFAULT_LOOP_POLL_MS;
72548
+ }
72549
+ function loopSleep(ms, signal) {
72550
+ return new Promise((resolve4) => {
72551
+ if (signal?.aborted) {
72552
+ resolve4();
72553
+ return;
72554
+ }
72555
+ const timer = setTimeout(resolve4, ms);
72556
+ signal?.addEventListener("abort", () => {
72557
+ clearTimeout(timer);
72558
+ resolve4();
72559
+ }, { once: true });
72560
+ });
72561
+ }
72562
+ async function runAgentLoop(context4, flags, runtime = {}, deps) {
72563
+ const recipient = typeof flags.agent === "string" ? flags.agent : "";
72564
+ if (recipient === "" || recipient === "auto") {
72565
+ context4.output.error("agent loop requires an explicit --agent <id>");
72566
+ return 2;
72567
+ }
72568
+ const pollMs = parseLoopPoll(flags.poll);
72569
+ const sleep2 = runtime.sleep ?? ((ms) => loopSleep(ms, runtime.signal));
72570
+ const svc = context4.agentService();
72571
+ let iteration = 0;
72572
+ while (!runtime.signal?.aborted && (runtime.maxIterations === undefined || iteration < runtime.maxIterations)) {
72573
+ const { prompt, flags: rewritten } = await drainIntoPrompt(undefined, context4, { ...flags, drain: true });
72574
+ if (prompt !== undefined) {
72575
+ await svc.run(prompt, rewritten, deps);
72576
+ } else {
72577
+ await sleep2(pollMs);
72578
+ }
72579
+ iteration++;
72580
+ }
72581
+ return 0;
72582
+ }
71377
72583
 
71378
72584
  // src/commands/feature.ts
71379
72585
  init_src3();
71380
72586
 
72587
+ // src/planning-emitter.ts
72588
+ init_src3();
72589
+ init_src2();
72590
+ function makeWarnLogger(context4) {
72591
+ return {
72592
+ warn: (msg, data) => {
72593
+ context4.output.error(`${msg}${data ? ` ${JSON.stringify(data)}` : ""}`);
72594
+ }
72595
+ };
72596
+ }
72597
+ function makePlanningEmitter(context4) {
72598
+ let cached2;
72599
+ const logger3 = makeWarnLogger(context4);
72600
+ return {
72601
+ async emit(event2) {
72602
+ try {
72603
+ cached2 ??= new SystemEventEmitter(new SystemEventDao(await context4.getDb()), logger3);
72604
+ await cached2.emit(event2);
72605
+ } catch (error51) {
72606
+ context4.output.error(`system_events emitter: ${error51 instanceof Error ? error51.message : String(error51)}`);
72607
+ }
72608
+ }
72609
+ };
72610
+ }
72611
+
71381
72612
  // src/workflow/make-lifecycle-adapter.ts
71382
72613
  init_src3();
71383
72614
  init_loader();
71384
72615
  init_src2();
71385
- import { existsSync as existsSync6 } from "fs";
72616
+ import { existsSync as existsSync8 } from "fs";
71386
72617
  import { homedir as homedir4 } from "os";
71387
- import { join as join13, resolve as resolve4 } from "path";
72618
+ import { join as join14, resolve as resolve4 } from "path";
71388
72619
 
71389
72620
  // src/workflow/resolve-spur-bin.ts
71390
72621
  import { basename as basename2 } from "path";
@@ -71402,23 +72633,23 @@ function resolveSpurBin() {
71402
72633
  }
71403
72634
 
71404
72635
  // src/workflow/make-lifecycle-adapter.ts
71405
- var GLOBAL_CONFIG_DIR = join13(".config", "spur");
72636
+ var GLOBAL_CONFIG_DIR = join14(".config", "spur");
71406
72637
  function globalConfigRoot(context4) {
71407
72638
  const override = context4.env.SPUR_GLOBAL_RULES_DIR;
71408
- return override !== undefined && override.length > 0 ? resolve4(context4.cwd, override) : join13(homedir4(), GLOBAL_CONFIG_DIR);
72639
+ return override !== undefined && override.length > 0 ? resolve4(context4.cwd, override) : join14(homedir4(), GLOBAL_CONFIG_DIR);
71409
72640
  }
71410
72641
  function resolveWorkflowPath(context4, profile) {
71411
72642
  const bundledRoot = bundledConfigRoot();
71412
72643
  if (bundledRoot !== null) {
71413
- const bundledPath = join13(bundledRoot, "workflows", `${profile.workflowName}.yaml`);
71414
- if (existsSync6(bundledPath))
72644
+ const bundledPath = join14(bundledRoot, "workflows", `${profile.workflowName}.yaml`);
72645
+ if (existsSync8(bundledPath))
71415
72646
  return bundledPath;
71416
72647
  }
71417
- const projectPath = join13(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
71418
- if (existsSync6(projectPath))
72648
+ const projectPath = join14(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
72649
+ if (existsSync8(projectPath))
71419
72650
  return projectPath;
71420
- const globalPath = join13(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
71421
- if (existsSync6(globalPath))
72651
+ const globalPath = join14(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
72652
+ if (existsSync8(globalPath))
71422
72653
  return globalPath;
71423
72654
  return null;
71424
72655
  }
@@ -71701,7 +72932,8 @@ async function makeService(context4, folderOverride) {
71701
72932
  const lifecycle = makeLifecycleAdapter(context4, FEATURE_LIFECYCLE_PROFILE);
71702
72933
  const writeService = new PlanningWriteService({
71703
72934
  fs: context4.fs,
71704
- ...lifecycle ? { lifecycle } : {}
72935
+ ...lifecycle ? { lifecycle } : {},
72936
+ emitter: makePlanningEmitter(context4)
71705
72937
  });
71706
72938
  return new FeatureService({ fs: context4.fs, writeService, featuresDir, tasksDir });
71707
72939
  }
@@ -71771,13 +73003,13 @@ init_loader();
71771
73003
  init_src2();
71772
73004
  init_dist10();
71773
73005
  import { homedir as homedir5 } from "os";
71774
- import { join as join14, resolve as resolve5 } from "path";
73006
+ import { join as join15, resolve as resolve5 } from "path";
71775
73007
 
71776
73008
  // src/config.ts
71777
73009
  var CLI_CONFIG = {
71778
73010
  binaryName: "spur",
71779
73011
  binaryLabel: "spur",
71780
- binaryVersion: "0.3.9",
73012
+ binaryVersion: "0.3.11",
71781
73013
  configDir: ".spur",
71782
73014
  configFile: ".spur/config.yaml",
71783
73015
  databaseFile: ".spur/spur.db"
@@ -71828,8 +73060,8 @@ var SCAFFOLD_MANIFEST = [
71828
73060
  ];
71829
73061
 
71830
73062
  // src/commands/init.ts
71831
- var GLOBAL_CONFIG_DIR2 = join14(".config", "spur");
71832
- var GLOBAL_RULES_DIR2 = join14(GLOBAL_CONFIG_DIR2, "rules");
73063
+ var GLOBAL_CONFIG_DIR2 = join15(".config", "spur");
73064
+ var GLOBAL_RULES_DIR2 = join15(GLOBAL_CONFIG_DIR2, "rules");
71833
73065
  var GLOBAL_CONFIG_EXAMPLE = "config.example.yaml";
71834
73066
  var GLOBAL_CONFIG_FILE2 = "config.yaml";
71835
73067
  var INDEXED_CONTEXT_MARKER = "## Indexed context";
@@ -71856,7 +73088,7 @@ If \`.spur/context/\` is absent, proceed normally. Never block work on its absen
71856
73088
  `;
71857
73089
  function globalRulesRoot(context4) {
71858
73090
  const override = context4.env.SPUR_GLOBAL_RULES_DIR;
71859
- return override !== undefined && override.length > 0 ? resolve5(context4.cwd, override) : join14(homedir5(), GLOBAL_RULES_DIR2);
73091
+ return override !== undefined && override.length > 0 ? resolve5(context4.cwd, override) : join15(homedir5(), GLOBAL_RULES_DIR2);
71860
73092
  }
71861
73093
  async function writeIfNew(context4, path9, content, force, result) {
71862
73094
  if (!force && await context4.fs.exists(path9)) {
@@ -71873,11 +73105,11 @@ async function seedGlobalRules(context4) {
71873
73105
  const target = globalRulesRoot(context4);
71874
73106
  let written = 0;
71875
73107
  for (const relPath of await listBundledRuleFiles()) {
71876
- const destination = join14(target, relPath);
73108
+ const destination = join15(target, relPath);
71877
73109
  if (await context4.fs.exists(destination))
71878
73110
  continue;
71879
- await context4.fs.ensureDir(join14(target, ...relPath.split("/").slice(0, -1)));
71880
- await context4.fs.writeFile(destination, await context4.fs.readFile(join14(source, relPath)));
73111
+ await context4.fs.ensureDir(join15(target, ...relPath.split("/").slice(0, -1)));
73112
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join15(source, relPath)));
71881
73113
  written += 1;
71882
73114
  }
71883
73115
  return written;
@@ -71887,20 +73119,20 @@ async function seedGlobalConfig(context4) {
71887
73119
  if (source === null)
71888
73120
  return 0;
71889
73121
  const globalOverride = context4.env.SPUR_GLOBAL_RULES_DIR;
71890
- const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve5(context4.cwd, globalOverride) : join14(homedir5(), GLOBAL_CONFIG_DIR2);
73122
+ const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve5(context4.cwd, globalOverride) : join15(homedir5(), GLOBAL_CONFIG_DIR2);
71891
73123
  let written = 0;
71892
73124
  for (const relPath of listBundledConfigFiles()) {
71893
73125
  if (relPath === GLOBAL_CONFIG_EXAMPLE)
71894
73126
  continue;
71895
- const destination = join14(target, relPath);
73127
+ const destination = join15(target, relPath);
71896
73128
  if (await context4.fs.exists(destination))
71897
73129
  continue;
71898
- await context4.fs.ensureDir(join14(target, ...relPath.split("/").slice(0, -1)));
71899
- await context4.fs.writeFile(destination, await context4.fs.readFile(join14(source, relPath)));
73130
+ await context4.fs.ensureDir(join15(target, ...relPath.split("/").slice(0, -1)));
73131
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join15(source, relPath)));
71900
73132
  written += 1;
71901
73133
  }
71902
- const examplePath = join14(source, GLOBAL_CONFIG_EXAMPLE);
71903
- const globalConfigPath = join14(target, GLOBAL_CONFIG_FILE2);
73134
+ const examplePath = join15(source, GLOBAL_CONFIG_EXAMPLE);
73135
+ const globalConfigPath = join15(target, GLOBAL_CONFIG_FILE2);
71904
73136
  if (await context4.fs.exists(examplePath) && !await context4.fs.exists(globalConfigPath)) {
71905
73137
  await context4.fs.ensureDir(target);
71906
73138
  await context4.fs.writeFile(globalConfigPath, await context4.fs.readFile(examplePath));
@@ -71914,7 +73146,7 @@ function registerInitCommand(program2, context4) {
71914
73146
  const force = options.force === true;
71915
73147
  const minimal = options.minimal === true;
71916
73148
  const projectName = options.name ?? "default";
71917
- const configPath = join14(context4.cwd, CLI_CONFIG.configFile);
73149
+ const configPath = join15(context4.cwd, CLI_CONFIG.configFile);
71918
73150
  if (!force && await context4.fs.exists(configPath)) {
71919
73151
  const message = `Already initialized: ${CLI_CONFIG.configFile}. Use --force to overwrite.`;
71920
73152
  context4.output.write(json3 ? toJson2({ ok: false, reason: "already-initialized", config: CLI_CONFIG.configFile }) : message);
@@ -71949,13 +73181,13 @@ function registerInitCommand(program2, context4) {
71949
73181
  ].join(`
71950
73182
  `)}
71951
73183
  `;
71952
- await context4.fs.ensureDir(join14(context4.cwd, CLI_CONFIG.configDir));
73184
+ await context4.fs.ensureDir(join15(context4.cwd, CLI_CONFIG.configDir));
71953
73185
  await context4.fs.writeFile(configPath, configYaml);
71954
73186
  result.created.push(configPath);
71955
- const agentsDir = join14(context4.cwd, CLI_CONFIG.configDir, "agents");
73187
+ const agentsDir = join15(context4.cwd, CLI_CONFIG.configDir, "agents");
71956
73188
  await context4.fs.ensureDir(agentsDir);
71957
- await writeIfNew(context4, join14(agentsDir, ".gitkeep"), "", force, result);
71958
- const gitignorePath = join14(context4.cwd, ".gitignore");
73189
+ await writeIfNew(context4, join15(agentsDir, ".gitkeep"), "", force, result);
73190
+ const gitignorePath = join15(context4.cwd, ".gitignore");
71959
73191
  const contextEntry = ".spur/context/";
71960
73192
  if (await context4.fs.exists(gitignorePath)) {
71961
73193
  const existing = await context4.fs.readFile(gitignorePath);
@@ -71975,20 +73207,20 @@ ${contextEntry}
71975
73207
  const configRoot = bundledConfigRoot();
71976
73208
  if (configRoot !== null) {
71977
73209
  for (const relPath of listBundledProjectSeedFiles()) {
71978
- const sourcePath = join14(configRoot, relPath);
73210
+ const sourcePath = join15(configRoot, relPath);
71979
73211
  if (!await context4.fs.exists(sourcePath))
71980
73212
  continue;
71981
- const targetPath = join14(context4.cwd, CLI_CONFIG.configDir, relPath);
71982
- await context4.fs.ensureDir(join14(targetPath, ".."));
73213
+ const targetPath = join15(context4.cwd, CLI_CONFIG.configDir, relPath);
73214
+ await context4.fs.ensureDir(join15(targetPath, ".."));
71983
73215
  await writeIfNew(context4, targetPath, await context4.fs.readFile(sourcePath), force, result);
71984
73216
  }
71985
73217
  for (const entry of SCAFFOLD_MANIFEST) {
71986
- const sourcePath = join14(configRoot, entry.source);
73218
+ const sourcePath = join15(configRoot, entry.source);
71987
73219
  if (!await context4.fs.exists(sourcePath))
71988
73220
  continue;
71989
- const baseDir = entry.root === true ? context4.cwd : join14(context4.cwd, CLI_CONFIG.configDir);
71990
- const targetPath = join14(baseDir, entry.target);
71991
- await context4.fs.ensureDir(join14(targetPath, ".."));
73221
+ const baseDir = entry.root === true ? context4.cwd : join15(context4.cwd, CLI_CONFIG.configDir);
73222
+ const targetPath = join15(baseDir, entry.target);
73223
+ await context4.fs.ensureDir(join15(targetPath, ".."));
71992
73224
  const entryForce = entry.preserve === true ? false : force;
71993
73225
  let body = await context4.fs.readFile(sourcePath);
71994
73226
  if (entry.target === "AGENTS.md") {
@@ -71998,7 +73230,7 @@ ${contextEntry}
71998
73230
  }
71999
73231
  }
72000
73232
  }
72001
- const agentsMdPath = join14(context4.cwd, "AGENTS.md");
73233
+ const agentsMdPath = join15(context4.cwd, "AGENTS.md");
72002
73234
  if (await context4.fs.exists(agentsMdPath)) {
72003
73235
  const existing = await context4.fs.readFile(agentsMdPath);
72004
73236
  if (!existing.includes(INDEXED_CONTEXT_MARKER)) {
@@ -72176,10 +73408,10 @@ function parseInterval2(raw) {
72176
73408
 
72177
73409
  // src/commands/migrate.ts
72178
73410
  init_src2();
72179
- import { join as join15 } from "path";
73411
+ import { join as join16 } from "path";
72180
73412
  function registerMigrateCommand(program2, context4) {
72181
73413
  program2.command("migrate").summary("apply CLI-owned schema migrations").option("--json", "Output machine-readable JSON").action(async (options) => {
72182
- const migrations = await loadSqlMigrations(join15(context4.cwd, "drizzle")).catch(() => {
73414
+ const migrations = await loadSqlMigrations(join16(context4.cwd, "drizzle")).catch(() => {
72183
73415
  return;
72184
73416
  });
72185
73417
  const applied = await applyCliMigrations(await context4.getDb(), migrations);
@@ -72431,7 +73663,7 @@ function formatTraceDetail(detail) {
72431
73663
 
72432
73664
  // src/commands/serve.ts
72433
73665
  init_src();
72434
- import { join as join19 } from "path";
73666
+ import { join as join20 } from "path";
72435
73667
 
72436
73668
  // ../server/src/index.ts
72437
73669
  init_src();
@@ -72441,11 +73673,11 @@ init_src3();
72441
73673
  init_src();
72442
73674
  init_loader();
72443
73675
  init_src2();
72444
- import { dirname as dirname12, isAbsolute as isAbsolute3, join as join18 } from "path";
73676
+ import { dirname as dirname12, isAbsolute as isAbsolute3, join as join19 } from "path";
72445
73677
  init_dist5();
72446
73678
 
72447
73679
  // ../server/src/bootstrap.ts
72448
- import { join as join16 } from "path";
73680
+ import { join as join17 } from "path";
72449
73681
 
72450
73682
  // ../../node_modules/.bun/radash@12.1.1/node_modules/radash/dist/esm/async.mjs
72451
73683
  var guard = (func, shouldGuard) => {
@@ -78549,23 +79781,128 @@ function parseLimit(raw2, fallback) {
78549
79781
 
78550
79782
  // ../server/src/modules/observability/index.ts
78551
79783
  init_src3();
79784
+ var ledgerWatcher;
79785
+ var watcherPath;
79786
+ function getLedgerWatcher(path9) {
79787
+ if (!ledgerWatcher || watcherPath !== path9) {
79788
+ ledgerWatcher?.stop();
79789
+ ledgerWatcher = new TokenLedgerWatcher({ ledgerPath: path9 });
79790
+ watcherPath = path9;
79791
+ ledgerWatcher.start();
79792
+ }
79793
+ return ledgerWatcher;
79794
+ }
79795
+ function toolUseSsePayload(event2) {
79796
+ return {
79797
+ type: "tool-use",
79798
+ occurredAt: event2.ts,
79799
+ event: event2
79800
+ };
79801
+ }
79802
+ function handleProcesses(ctx) {
79803
+ return async (c3) => {
79804
+ try {
79805
+ const snapshot = await ctx.processInventory().snapshot();
79806
+ return c3.json(snapshot);
79807
+ } catch (err) {
79808
+ if (err instanceof UnsupportedProcessPlatformError) {
79809
+ return c3.json({ error: err.message, code: err.code }, 501);
79810
+ }
79811
+ const message = err instanceof Error ? err.message : String(err);
79812
+ return c3.json({ error: message }, 500);
79813
+ }
79814
+ };
79815
+ }
79816
+ function handleToolUseGet(ctx) {
79817
+ return (c3) => {
79818
+ try {
79819
+ const limitParam = c3.req.query("limit");
79820
+ let limitRaw;
79821
+ if (limitParam !== undefined) {
79822
+ const parsed = Number.parseInt(limitParam, 10);
79823
+ if (!Number.isNaN(parsed))
79824
+ limitRaw = parsed;
79825
+ }
79826
+ const before = c3.req.query("before") ?? undefined;
79827
+ const limit = clampToolUseLimit(limitRaw);
79828
+ const snapshot = ctx.tokenLedger().snapshot({ limit, before });
79829
+ return c3.json(snapshot);
79830
+ } catch (err) {
79831
+ const message = err instanceof Error ? err.message : String(err);
79832
+ return c3.json({ error: message }, 500);
79833
+ }
79834
+ };
79835
+ }
79836
+ function handleToolUseStream(ctx) {
79837
+ return (c3) => {
79838
+ const closed = { current: false };
79839
+ let heartbeatInterval;
79840
+ let unsubscribe;
79841
+ const signal = c3.req.raw.signal;
79842
+ let closeController = () => {};
79843
+ const teardown = () => {
79844
+ if (closed.current)
79845
+ return;
79846
+ closed.current = true;
79847
+ if (heartbeatInterval)
79848
+ clearInterval(heartbeatInterval);
79849
+ try {
79850
+ unsubscribe?.();
79851
+ } catch {}
79852
+ signal.removeEventListener("abort", teardown);
79853
+ closeController();
79854
+ };
79855
+ const stream = new ReadableStream({
79856
+ start(controller) {
79857
+ const encoder = new TextEncoder;
79858
+ closeController = () => {
79859
+ try {
79860
+ controller.close();
79861
+ } catch {}
79862
+ };
79863
+ if (signal.aborted) {
79864
+ teardown();
79865
+ return;
79866
+ }
79867
+ signal.addEventListener("abort", teardown);
79868
+ heartbeatInterval = setInterval(sendSseKeepalive, 15000, closed, controller, encoder);
79869
+ enqueueSseFrame(closed, controller, encoder, {
79870
+ type: "connected",
79871
+ occurredAt: new Date().toISOString()
79872
+ });
79873
+ try {
79874
+ const path9 = ctx.tokenLedger().path;
79875
+ const watcher = getLedgerWatcher(path9);
79876
+ unsubscribe = watcher.subscribe((event2) => {
79877
+ if (!enqueueSseFrame(closed, controller, encoder, toolUseSsePayload(event2)))
79878
+ teardown();
79879
+ });
79880
+ } catch {
79881
+ enqueueSseFrame(closed, controller, encoder, {
79882
+ type: "error",
79883
+ error: "ledger watch unavailable",
79884
+ occurredAt: new Date().toISOString()
79885
+ });
79886
+ }
79887
+ },
79888
+ cancel() {
79889
+ teardown();
79890
+ }
79891
+ });
79892
+ return c3.newResponse(stream, 200, {
79893
+ "Content-Type": "text/event-stream",
79894
+ "Cache-Control": "no-cache"
79895
+ });
79896
+ };
79897
+ }
78552
79898
  var observabilityModule = {
78553
79899
  name: "observability",
78554
79900
  mount(app, ctx) {
78555
79901
  if (!ctx)
78556
79902
  return;
78557
- app.get("/api/observability/processes", async (c3) => {
78558
- try {
78559
- const snapshot = await ctx.processInventory().snapshot();
78560
- return c3.json(snapshot);
78561
- } catch (err) {
78562
- if (err instanceof UnsupportedProcessPlatformError) {
78563
- return c3.json({ error: err.message, code: err.code }, 501);
78564
- }
78565
- const message = err instanceof Error ? err.message : String(err);
78566
- return c3.json({ error: message }, 500);
78567
- }
78568
- });
79903
+ app.get("/api/observability/processes", handleProcesses(ctx));
79904
+ app.get("/api/observability/tool-use", handleToolUseGet(ctx));
79905
+ app.get("/api/observability/tool-use/stream", handleToolUseStream(ctx));
78569
79906
  }
78570
79907
  };
78571
79908
 
@@ -78686,9 +80023,29 @@ var teamModule = {
78686
80023
  pid: p2.pid,
78687
80024
  status: p2.status,
78688
80025
  startedAt: p2.startedAt,
78689
- exitCode: p2.exitCode ?? null
80026
+ exitCode: p2.exitCode ?? null,
80027
+ teamId: p2.teamId ?? null
78690
80028
  }));
78691
- return c3.json({ processes, count: processes.length });
80029
+ const executions = ctx.processRegistry().listExecutions().map((e) => ({
80030
+ id: e.id,
80031
+ label: e.label ?? e.command,
80032
+ command: e.command,
80033
+ args: [...e.args],
80034
+ pid: e.pid ?? null,
80035
+ status: e.status,
80036
+ startedAt: e.startedAt,
80037
+ exitedAt: e.exitedAt ?? null,
80038
+ exitCode: e.exitCode ?? null,
80039
+ source: e.source,
80040
+ teamId: e.teamId ?? null,
80041
+ agentId: e.agentId ?? null
80042
+ }));
80043
+ return c3.json({
80044
+ processes,
80045
+ count: processes.length,
80046
+ executions,
80047
+ executionsCount: executions.length
80048
+ });
78692
80049
  });
78693
80050
  app.post("/api/team/agents/:id/start", async (c3) => {
78694
80051
  const id = c3.req.param("id");
@@ -78805,6 +80162,79 @@ var teamModule = {
78805
80162
  "Cache-Control": "no-cache"
78806
80163
  });
78807
80164
  });
80165
+ app.get("/api/team/teams", async (c3) => {
80166
+ if (!ctx.teamService)
80167
+ return c3.json({ error: "team API requires Bun server context" }, 503);
80168
+ const svc = ctx.teamService();
80169
+ const supervisor = ctx.supervisor();
80170
+ const teams = await svc.listTeams();
80171
+ const processes = supervisor.list();
80172
+ const enriched = teams.map((team) => ({
80173
+ teamId: team.teamId,
80174
+ name: team.name,
80175
+ members: team.specs.map((spec) => {
80176
+ const proc = processes.find((p2) => p2.agentId === spec.id);
80177
+ return {
80178
+ id: spec.id,
80179
+ type: spec.type,
80180
+ status: proc?.status ?? "unknown",
80181
+ autoStart: spec.autoStart === true,
80182
+ ...proc?.pid !== undefined ? { pid: proc.pid } : {}
80183
+ };
80184
+ })
80185
+ }));
80186
+ return c3.json({ teams: enriched, count: enriched.length });
80187
+ });
80188
+ app.post("/api/team/:team/up", async (c3) => {
80189
+ if (!ctx.teamService)
80190
+ return c3.json({ error: "team API requires Bun server context" }, 503);
80191
+ const teamId = c3.req.param("team");
80192
+ const check2 = c3.req.query("check") === "true";
80193
+ const svc = ctx.teamService();
80194
+ const materialized = await svc.materializeTeam(teamId, { check: check2 });
80195
+ if (check2) {
80196
+ return c3.json({ materialized, started: [] });
80197
+ }
80198
+ const supervisor = ctx.supervisor();
80199
+ const autostartIds = new Set((await svc.listAgentSpecs()).filter((spec) => spec.autoStart === true).map((spec) => spec.id));
80200
+ const started = [];
80201
+ for (const id of materialized.upserted) {
80202
+ if (!autostartIds.has(id))
80203
+ continue;
80204
+ try {
80205
+ const entry = await supervisor.start(id);
80206
+ started.push({ id, ok: true, ...entry.pid !== null ? { pid: entry.pid } : {} });
80207
+ } catch {
80208
+ started.push({ id, ok: false });
80209
+ }
80210
+ }
80211
+ return c3.json({ materialized, started });
80212
+ });
80213
+ app.post("/api/team/:team/down", async (c3) => {
80214
+ if (!ctx.teamService)
80215
+ return c3.json({ error: "team API requires Bun server context" }, 503);
80216
+ const teamId = c3.req.param("team");
80217
+ const purge = c3.req.query("purge") === "true";
80218
+ const svc = ctx.teamService();
80219
+ const supervisor = ctx.supervisor();
80220
+ const teams = await svc.listTeams();
80221
+ const team = teams.find((t) => t.teamId === teamId);
80222
+ const stopped = [];
80223
+ if (team) {
80224
+ for (const spec of team.specs) {
80225
+ const proc = supervisor.get(spec.id);
80226
+ if (proc?.status === "running") {
80227
+ await supervisor.stop(spec.id);
80228
+ stopped.push(spec.id);
80229
+ }
80230
+ }
80231
+ }
80232
+ const result = await svc.teardownTeam(teamId, { purge });
80233
+ return c3.json({ stopped, purged: result.purged });
80234
+ });
80235
+ app.get("/api/team/health", (c3) => {
80236
+ return c3.json({ ok: true });
80237
+ });
78808
80238
  }
78809
80239
  };
78810
80240
 
@@ -80803,7 +82233,7 @@ function createApp(appRt, opts) {
80803
82233
  app.use("*", async (c3, next) => {
80804
82234
  const pathname = c3.req.path === "/" ? "/index.html" : c3.req.path;
80805
82235
  try {
80806
- const file2 = Bun.file(join16(webDistPath, pathname));
82236
+ const file2 = Bun.file(join17(webDistPath, pathname));
80807
82237
  if (await file2.exists()) {
80808
82238
  const headers = new Headers({ "content-type": file2.type });
80809
82239
  return new Response(file2.stream(), { headers });
@@ -80816,7 +82246,7 @@ function createApp(appRt, opts) {
80816
82246
  return c3.json({ error: "Not Found" }, 404);
80817
82247
  }
80818
82248
  try {
80819
- const indexFile = Bun.file(join16(webDistPath, "index.html"));
82249
+ const indexFile = Bun.file(join17(webDistPath, "index.html"));
80820
82250
  if (await indexFile.exists()) {
80821
82251
  return new Response(indexFile.stream(), {
80822
82252
  headers: { "content-type": "text/html; charset=utf-8" }
@@ -80837,7 +82267,7 @@ init_src3();
80837
82267
  init_src();
80838
82268
  init_src2();
80839
82269
  init_dist5();
80840
- import { dirname as dirname11, join as join17 } from "path";
82270
+ import { dirname as dirname11, join as join18 } from "path";
80841
82271
  var NOOP_OUTPUT = { write: (_s) => {}, error: (_s) => {} };
80842
82272
 
80843
82273
  class LazyPlanningEventEmitter {
@@ -80872,7 +82302,7 @@ class NotConfiguredError extends Error {
80872
82302
  function createServerContext(appRt, options) {
80873
82303
  const cwd = options.cwd;
80874
82304
  const fs3 = options.fs;
80875
- const dbUrl = options.dbUrl ?? join17(cwd, DEFAULT_DATABASE_URL);
82305
+ const dbUrl = options.dbUrl ?? join18(cwd, DEFAULT_DATABASE_URL);
80876
82306
  const eventsBus = options.eventsBus ?? appRt.events;
80877
82307
  const jobQueueEnabled = options.jobQueueEnabled ?? false;
80878
82308
  const folders = options.folders ?? DEFAULT_PLANNING_FOLDERS;
@@ -80890,6 +82320,8 @@ function createServerContext(appRt, options) {
80890
82320
  let teamSvc;
80891
82321
  let supervisorSvc;
80892
82322
  let processInventorySvc;
82323
+ let processRegistrySvc;
82324
+ let tokenLedgerSvc;
80893
82325
  let agentSvc;
80894
82326
  let ruleSvc;
80895
82327
  let workflowSvc;
@@ -80959,9 +82391,13 @@ function createServerContext(appRt, options) {
80959
82391
  }
80960
82392
  return teamSvc;
80961
82393
  },
82394
+ processRegistry() {
82395
+ processRegistrySvc ??= createInMemoryProcessRegistry2();
82396
+ return processRegistrySvc;
82397
+ },
80962
82398
  supervisor() {
80963
82399
  if (!supervisorSvc) {
80964
- const pe = new ProcessExecutor3;
82400
+ const pe = new NodeProcessExecutor3({ registry: this.processRegistry() });
80965
82401
  supervisorSvc = new SupervisorService({
80966
82402
  processExecutor: pe,
80967
82403
  eventBus: bridgeEventBus(eventsBus),
@@ -80980,12 +82416,19 @@ function createServerContext(appRt, options) {
80980
82416
  }
80981
82417
  return processInventorySvc;
80982
82418
  },
82419
+ tokenLedger() {
82420
+ if (!tokenLedgerSvc) {
82421
+ tokenLedgerSvc = new TokenLedgerService({ cwd });
82422
+ }
82423
+ return tokenLedgerSvc;
82424
+ },
80983
82425
  agentService() {
80984
82426
  agentSvc ??= new AgentService({
80985
82427
  cwd,
80986
82428
  env: options.env ?? {},
80987
82429
  output: NOOP_OUTPUT,
80988
- events: bridgeEventBus(eventsBus)
82430
+ events: bridgeEventBus(eventsBus),
82431
+ processRegistry: this.processRegistry()
80989
82432
  });
80990
82433
  return agentSvc;
80991
82434
  },
@@ -81159,15 +82602,15 @@ async function runTaskActionJob(ctx, env, payload, createAgentService = createTa
81159
82602
  }
81160
82603
  }
81161
82604
  async function resolveWebDistPath(configuredPath) {
81162
- const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join18(process.cwd(), configuredPath)] : [
81163
- join18(process.cwd(), "dist/web"),
81164
- join18(import.meta.dir, "web"),
81165
- join18(dirname12(process.execPath), "web"),
81166
- join18(dirname12(process.execPath), "../web"),
81167
- join18(import.meta.dir, "../../../dist/web")
82605
+ const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join19(process.cwd(), configuredPath)] : [
82606
+ join19(process.cwd(), "dist/web"),
82607
+ join19(import.meta.dir, "web"),
82608
+ join19(dirname12(process.execPath), "web"),
82609
+ join19(dirname12(process.execPath), "../web"),
82610
+ join19(import.meta.dir, "../../../dist/web")
81168
82611
  ];
81169
82612
  for (const candidate of candidates) {
81170
- if (await Bun.file(join18(candidate, "index.html")).exists()) {
82613
+ if (await Bun.file(join19(candidate, "index.html")).exists()) {
81171
82614
  return candidate;
81172
82615
  }
81173
82616
  }
@@ -81205,11 +82648,13 @@ async function startServer(options, deps = defaultDeps) {
81205
82648
  bootConfig
81206
82649
  });
81207
82650
  let jobWorker;
81208
- if (bootConfig.teamAutostart.length > 0) {
82651
+ const autostartConfig = await loadSpurConfig(process.cwd()).catch(() => null);
82652
+ const autostartIds = resolveAutostartSet(autostartConfig, env.SPUR_TEAM_AUTOSTART);
82653
+ if (autostartIds.length > 0) {
81209
82654
  try {
81210
82655
  const supervisor = ctx.supervisor();
81211
- await supervisor.startAutostart(bootConfig.teamAutostart);
81212
- appRt.logger.info("Autostart agents spawned", { ids: bootConfig.teamAutostart });
82656
+ await supervisor.startAutostart(autostartIds);
82657
+ appRt.logger.info("Autostart agents spawned", { ids: autostartIds });
81213
82658
  } catch (error51) {
81214
82659
  appRt.logger.error("Autostart failed \u2014 server will continue but supervised agents are not running", {
81215
82660
  error: String(error51)
@@ -81295,7 +82740,7 @@ if (false) {}
81295
82740
 
81296
82741
  // src/commands/serve.ts
81297
82742
  function resolveServeDbUrl(cwd, env, configuredUrl) {
81298
- return env.DATABASE_URL === undefined ? join19(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
82743
+ return env.DATABASE_URL === undefined ? join20(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
81299
82744
  }
81300
82745
  function registerServeCommand(program2, context4) {
81301
82746
  program2.command("serve").summary("start the Spur web server (local fallback)").option("--port <n>", "Server port (env: PORT, default: 3000)", parseInt).option("--host <addr>", "Bind address (env: HOST, default: localhost)").option("--no-open", "Skip opening the browser").option("--cwd <path>", "Working directory", context4.cwd).option("--json", "Output { port, url, pid } and exit").action(async (options) => {
@@ -81334,7 +82779,7 @@ function registerServeCommand(program2, context4) {
81334
82779
  }
81335
82780
 
81336
82781
  // src/commands/status.ts
81337
- import { join as join20 } from "path";
82782
+ import { join as join21 } from "path";
81338
82783
 
81339
82784
  // src/errors.ts
81340
82785
  class CommandError extends Error {
@@ -81362,7 +82807,7 @@ function errorMessage4(error51) {
81362
82807
  // src/git-context.ts
81363
82808
  init_dist5();
81364
82809
  async function gitContext(cwd) {
81365
- const executor = new NodeProcessExecutor2({ defaultTimeout: 5000, defaultMaxOutput: 128000 });
82810
+ const executor = new NodeProcessExecutor3({ defaultTimeout: 5000, defaultMaxOutput: 128000 });
81366
82811
  const root = await executor.run({
81367
82812
  command: "git",
81368
82813
  args: ["rev-parse", "--show-toplevel"],
@@ -81405,8 +82850,8 @@ function registerStatusCommand(program2, context4) {
81405
82850
  }
81406
82851
  async function runStatusCore(path9, options, context4) {
81407
82852
  const [packageJsonExists, spurConfigExists, git, agentSpecs] = await Promise.all([
81408
- context4.fs.exists(join20(context4.cwd, "package.json")),
81409
- context4.fs.exists(join20(context4.cwd, ".spur", "config.yaml")),
82853
+ context4.fs.exists(join21(context4.cwd, "package.json")),
82854
+ context4.fs.exists(join21(context4.cwd, ".spur", "config.yaml")),
81410
82855
  gitContext(context4.cwd),
81411
82856
  listAgentSpecIds(context4)
81412
82857
  ]);
@@ -81434,14 +82879,14 @@ async function runStatusCore(path9, options, context4) {
81434
82879
  return status.ok ? 0 : 1;
81435
82880
  }
81436
82881
  async function listAgentSpecIds(context4) {
81437
- const dir = join20(context4.cwd, ".spur", "agents");
82882
+ const dir = join21(context4.cwd, ".spur", "agents");
81438
82883
  if (!await context4.fs.exists(dir))
81439
82884
  return [];
81440
82885
  const entries = await context4.fs.readDir(dir);
81441
82886
  return entries.filter((entry) => entry.endsWith(".yaml") || entry.endsWith(".yml")).map((entry) => entry.replace(/\.ya?ml$/, "")).sort();
81442
82887
  }
81443
82888
  async function readTargetStatus(context4, targetPath) {
81444
- const resolved = join20(context4.cwd, targetPath);
82889
+ const resolved = join21(context4.cwd, targetPath);
81445
82890
  const stat2 = await context4.fs.stat(resolved);
81446
82891
  if (stat2 === null)
81447
82892
  throw new CommandError(`status failed: path does not exist at ${resolved}`);
@@ -81452,8 +82897,8 @@ async function readTargetStatus(context4, targetPath) {
81452
82897
  init_src3();
81453
82898
  init_loader();
81454
82899
  init_src2();
81455
- import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
81456
- import { join as join21 } from "path";
82900
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
82901
+ import { join as join22 } from "path";
81457
82902
  // schemas/section-matrix.schema.json
81458
82903
  var section_matrix_schema_default = {
81459
82904
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -81662,6 +83107,70 @@ var spur_config_schema_default = {
81662
83107
  additionalProperties: {
81663
83108
  type: "string"
81664
83109
  }
83110
+ },
83111
+ team: {
83112
+ type: "object",
83113
+ description: "Declarative agent teams keyed by team id (the map key is the teamId). Each team materializes a roster of agent specs (feature M). Mirrors @gobing-ai/spur-config TeamConfigSchema (Zod is SSOT).",
83114
+ additionalProperties: {
83115
+ type: "object",
83116
+ required: ["name", "work_dir", "members"],
83117
+ properties: {
83118
+ name: {
83119
+ type: "string",
83120
+ minLength: 1,
83121
+ description: "Human-readable team label."
83122
+ },
83123
+ work_dir: {
83124
+ type: "string",
83125
+ minLength: 1,
83126
+ description: "Default member workspace. A leading `~` is tilde-expanded at load."
83127
+ },
83128
+ autostart: {
83129
+ type: "boolean",
83130
+ description: "Team-wide autostart default; per-member autostart overrides (effective = member.autostart ?? team.autostart ?? false)."
83131
+ },
83132
+ members: {
83133
+ type: "array",
83134
+ minItems: 1,
83135
+ description: "Roster of member references (>= 1). A bare string is shorthand for { executor: <string> }; the composed agent id is <teamId>-<id ?? executor>.",
83136
+ items: {
83137
+ oneOf: [
83138
+ { type: "string", minLength: 1 },
83139
+ {
83140
+ type: "object",
83141
+ required: ["executor"],
83142
+ properties: {
83143
+ executor: {
83144
+ type: "string",
83145
+ minLength: 1,
83146
+ description: "Executor name \u2014 resolved against agent.executors first, else a raw canonical agent type."
83147
+ },
83148
+ id: {
83149
+ type: "string",
83150
+ minLength: 1,
83151
+ description: "Local member id; composed id is <teamId>-<id ?? executor> (must match ^[a-z][a-z0-9_-]{1,63}$)."
83152
+ },
83153
+ purpose: { type: "string" },
83154
+ workspace: {
83155
+ type: "string",
83156
+ minLength: 1,
83157
+ description: "Per-member workspace override. A leading `~` is tilde-expanded at load."
83158
+ },
83159
+ model: { type: "string", minLength: 1 },
83160
+ autonomy: { type: "string" },
83161
+ systemPrompt: { type: "string" },
83162
+ command: {
83163
+ type: "array",
83164
+ items: { type: "string", minLength: 1 }
83165
+ },
83166
+ autostart: { type: "boolean" }
83167
+ }
83168
+ }
83169
+ ]
83170
+ }
83171
+ }
83172
+ }
83173
+ }
81665
83174
  }
81666
83175
  }
81667
83176
  },
@@ -82308,7 +83817,8 @@ async function makeService2(context4, folderOverride, noLifecycle = false) {
82308
83817
  const lifecycle = noLifecycle ? undefined : makeLifecycleAdapter(context4, TASK_LIFECYCLE_PROFILE);
82309
83818
  const writeService = new PlanningWriteService({
82310
83819
  fs: context4.fs,
82311
- ...lifecycle ? { lifecycle } : {}
83820
+ ...lifecycle ? { lifecycle } : {},
83821
+ emitter: makePlanningEmitter(context4)
82312
83822
  });
82313
83823
  return new TaskService({
82314
83824
  fs: context4.fs,
@@ -82327,16 +83837,16 @@ function loadTemplateContent(projectRoot, variant) {
82327
83837
  return templateContentCache.get(variant);
82328
83838
  if (templateMissSet.has(variant))
82329
83839
  return;
82330
- const localPath = join21(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
82331
- if (existsSync7(localPath)) {
83840
+ const localPath = join22(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
83841
+ if (existsSync9(localPath)) {
82332
83842
  const content = readFileSync8(localPath, "utf8");
82333
83843
  templateContentCache.set(variant, content);
82334
83844
  return content;
82335
83845
  }
82336
83846
  const root = bundledConfigRoot();
82337
83847
  if (root !== null) {
82338
- const templatePath = join21(root, "templates", "task", `${variant}.md`);
82339
- if (existsSync7(templatePath)) {
83848
+ const templatePath = join22(root, "templates", "task", `${variant}.md`);
83849
+ if (existsSync9(templatePath)) {
82340
83850
  const content = readFileSync8(templatePath, "utf8");
82341
83851
  templateContentCache.set(variant, content);
82342
83852
  return content;
@@ -82351,14 +83861,14 @@ function loadTemplateBodies(projectRoot, variant) {
82351
83861
  if (cached2 !== undefined)
82352
83862
  return cached2;
82353
83863
  let bodies = {};
82354
- const localPath = join21(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
82355
- if (existsSync7(localPath)) {
83864
+ const localPath = join22(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
83865
+ if (existsSync9(localPath)) {
82356
83866
  bodies = extractTemplateBodies(readFileSync8(localPath, "utf8"));
82357
83867
  } else {
82358
83868
  const root = bundledConfigRoot();
82359
83869
  if (root !== null) {
82360
- const templatePath = join21(root, "templates", "task", `${variant}.md`);
82361
- if (existsSync7(templatePath)) {
83870
+ const templatePath = join22(root, "templates", "task", `${variant}.md`);
83871
+ if (existsSync9(templatePath)) {
82362
83872
  bodies = extractTemplateBodies(readFileSync8(templatePath, "utf8"));
82363
83873
  }
82364
83874
  }
@@ -82392,8 +83902,8 @@ async function loadSectionMatrix(projectRoot) {
82392
83902
  return promise2;
82393
83903
  }
82394
83904
  async function loadSectionMatrixUncached(projectRoot) {
82395
- const localPath = join21(projectRoot, ".spur", "tasks", "section-matrix.yaml");
82396
- if (existsSync7(localPath)) {
83905
+ const localPath = join22(projectRoot, ".spur", "tasks", "section-matrix.yaml");
83906
+ if (existsSync9(localPath)) {
82397
83907
  const data = await loadStructuredSpurConfig(localPath, {
82398
83908
  validateJsonSchema: true,
82399
83909
  embeddedSchemas: EMBEDDED_SPUR_SCHEMAS
@@ -82402,8 +83912,8 @@ async function loadSectionMatrixUncached(projectRoot) {
82402
83912
  }
82403
83913
  const root = bundledConfigRoot();
82404
83914
  if (root !== null) {
82405
- const matrixPath = join21(root, "tasks", "section-matrix.yaml");
82406
- if (existsSync7(matrixPath)) {
83915
+ const matrixPath = join22(root, "tasks", "section-matrix.yaml");
83916
+ if (existsSync9(matrixPath)) {
82407
83917
  const data = await loadStructuredSpurConfig(matrixPath, {
82408
83918
  validateJsonSchema: true,
82409
83919
  embeddedSchemas: EMBEDDED_SPUR_SCHEMAS
@@ -82436,8 +83946,16 @@ function registerTeamCommand(program2, context4) {
82436
83946
  const code = await runTeamAssign(taskId, agentId, context4);
82437
83947
  context4.setExitCode(code);
82438
83948
  });
82439
- noun.command("status").description("List agent specs and their run status.").option("--json", "Output machine-readable JSON").action(async (options) => {
82440
- const code = await runTeamStatus(options, context4);
83949
+ noun.command("status").description("List agent specs and their run status; --by-team groups by team (0258 R4).").option("--json", "Output machine-readable JSON").option("--by-team", "Group specs by their agent.team.<id> membership").option("--server <url>", "Server API URL for live run status", DEFAULT_SERVER).action(async (options) => {
83950
+ const code = options.byTeam ? await runTeamStatusGrouped(options, context4) : await runTeamStatus(options, context4);
83951
+ context4.setExitCode(code);
83952
+ });
83953
+ noun.command("up").description("Materialize a team roster into agent specs; best-effort start when spur serve is reachable.").argument("<team>", "Team id (agent.team.<team>)").option("--check", "Dry-run: show the add/prune diff without writing").option("--server <url>", "Server API URL", DEFAULT_SERVER).option("--json", "Output machine-readable JSON").action(async (team, options) => {
83954
+ const code = await runTeamUp(team, options, context4);
83955
+ context4.setExitCode(code);
83956
+ });
83957
+ noun.command("down").description("Tear down a team: stop members; --purge also removes generated specs.").argument("<team>", "Team id").option("--purge", "Also delete spur:generated specs (never manual / ref:)").option("--server <url>", "Server API URL", DEFAULT_SERVER).option("--json", "Output machine-readable JSON").action(async (team, options) => {
83958
+ const code = await runTeamDown(team, options, context4);
82441
83959
  context4.setExitCode(code);
82442
83960
  });
82443
83961
  noun.command("start").description("Start a supervised agent process (requires spur serve).").argument("<agent-id>", "Agent spec id").option("--server <url>", "Server API URL", DEFAULT_SERVER).option("--json", "Output machine-readable JSON").action(async (agentId, options) => {
@@ -82459,18 +83977,59 @@ async function runTeamStatus(options, context4) {
82459
83977
  const svc = new TeamService(context4);
82460
83978
  const json3 = options.json === true;
82461
83979
  const status = await svc.getStatus();
82462
- if (json3) {
82463
- context4.output.write(toJson2(status));
82464
- return 0;
82465
- }
82466
83980
  if (status.agents.length === 0) {
82467
83981
  context4.output.write("No agent specs found in .spur/agents/");
82468
83982
  return 0;
82469
83983
  }
83984
+ const live = await fetchServerProcesses(options.server);
83985
+ if (live === null) {
83986
+ context4.output.error(`Cannot reach server at ${options.server} \u2014 showing local specs as stopped. Is spur serve running?`);
83987
+ } else {
83988
+ for (const agent of status.agents) {
83989
+ const proc = live.get(agent.id);
83990
+ if (proc) {
83991
+ agent.status = proc.status;
83992
+ agent.pid = proc.pid ?? undefined;
83993
+ }
83994
+ }
83995
+ }
83996
+ if (json3) {
83997
+ context4.output.write(toJson2(status));
83998
+ return 0;
83999
+ }
82470
84000
  context4.output.write(status.agents.map(formatStatusLine).join(`
82471
84001
  `));
82472
84002
  return 0;
82473
84003
  }
84004
+ function mapServerStatus(status) {
84005
+ switch (status) {
84006
+ case "running":
84007
+ return "running";
84008
+ case "errored":
84009
+ return "errored";
84010
+ case "stopped":
84011
+ case "exited":
84012
+ return "stopped";
84013
+ default:
84014
+ return "unknown";
84015
+ }
84016
+ }
84017
+ async function fetchServerProcesses(server) {
84018
+ try {
84019
+ const url2 = `${server}/team/processes`;
84020
+ const res = await teamFetch(url2, { method: "GET" });
84021
+ if (!res.ok)
84022
+ return null;
84023
+ const body = await res.json();
84024
+ const map3 = new Map;
84025
+ for (const proc of body.processes ?? []) {
84026
+ map3.set(proc.agentId, { status: mapServerStatus(proc.status), pid: proc.pid ?? null });
84027
+ }
84028
+ return map3;
84029
+ } catch {
84030
+ return null;
84031
+ }
84032
+ }
82474
84033
  async function performTeamStart(agentId, options) {
82475
84034
  try {
82476
84035
  const url2 = `${options.server}/team/agents/${encodeURIComponent(agentId)}/start`;
@@ -82535,6 +84094,76 @@ function formatStatusLine(agent) {
82535
84094
  const pid = agent.pid === undefined ? "" : ` pid=${agent.pid}`;
82536
84095
  return `${agent.status} ${agent.id} ${agent.type} ${agent.purpose}${pid}`;
82537
84096
  }
84097
+ async function runTeamStatusGrouped(options, context4) {
84098
+ const teams = await new TeamService(context4).listTeams();
84099
+ if (options.json === true) {
84100
+ context4.output.write(toJson2({ teams }));
84101
+ return 0;
84102
+ }
84103
+ if (teams.length === 0) {
84104
+ context4.output.write("No teams or agent specs found");
84105
+ return 0;
84106
+ }
84107
+ context4.output.write(teams.map(formatTeamBlock).join(`
84108
+ `));
84109
+ return 0;
84110
+ }
84111
+ function formatTeamBlock(team) {
84112
+ const header = team.name && team.name !== team.teamId ? `# ${team.teamId} (${team.name})` : `# ${team.teamId}`;
84113
+ const rows = team.specs.map((spec) => ` ${spec.id} ${spec.type} ${spec.purpose}`);
84114
+ return [header, ...rows].join(`
84115
+ `);
84116
+ }
84117
+ async function runTeamUp(team, options, context4) {
84118
+ const svc = new TeamService(context4);
84119
+ let result;
84120
+ try {
84121
+ result = await svc.materializeTeam(team, { check: options.check === true });
84122
+ } catch (error51) {
84123
+ context4.output.error(error51 instanceof Error ? error51.message : String(error51));
84124
+ return 1;
84125
+ }
84126
+ const started = [];
84127
+ if (options.check !== true && result.upserted.length > 0) {
84128
+ const specs = await svc.listAgentSpecs();
84129
+ const autostart = specs.filter((spec) => spec.autoStart === true && result.upserted.includes(spec.id));
84130
+ for (const spec of autostart) {
84131
+ const res = await performTeamStart(spec.id, { server: options.server });
84132
+ if ("ok" in res && res.ok === true)
84133
+ started.push(spec.id);
84134
+ }
84135
+ }
84136
+ if (options.json === true) {
84137
+ context4.output.write(toJson2({ ...result, started }));
84138
+ } else {
84139
+ const verb = options.check === true ? "would materialize" : "materialized";
84140
+ const startNote = started.length > 0 ? `, started ${started.length}` : "";
84141
+ context4.output.write(`team ${team}: ${verb} ${result.upserted.length} member(s), prune ${result.orphaned.length}${startNote}`);
84142
+ }
84143
+ return 0;
84144
+ }
84145
+ async function runTeamDown(team, options, context4) {
84146
+ const svc = new TeamService(context4);
84147
+ let result;
84148
+ try {
84149
+ result = await svc.teardownTeam(team, { purge: options.purge === true });
84150
+ } catch (error51) {
84151
+ context4.output.error(error51 instanceof Error ? error51.message : String(error51));
84152
+ return 1;
84153
+ }
84154
+ const stopped = [];
84155
+ for (const id of result.stopped) {
84156
+ const res = await performTeamStop(id, { server: options.server });
84157
+ if ("ok" in res && res.ok === true)
84158
+ stopped.push(id);
84159
+ }
84160
+ if (options.json === true) {
84161
+ context4.output.write(toJson2({ ...result, stopped }));
84162
+ } else {
84163
+ context4.output.write(`team ${team}: stopped ${stopped.length}, purged ${result.purged.length}`);
84164
+ }
84165
+ return 0;
84166
+ }
82538
84167
 
82539
84168
  // src/commands/workflow.ts
82540
84169
  init_src3();
@@ -82848,7 +84477,7 @@ init_src3();
82848
84477
  init_src();
82849
84478
  init_src2();
82850
84479
  init_dist5();
82851
- import { dirname as dirname13, join as join22, resolve as resolve7 } from "path";
84480
+ import { dirname as dirname13, join as join23, resolve as resolve7 } from "path";
82852
84481
  import { isatty as isatty4 } from "tty";
82853
84482
 
82854
84483
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -84262,7 +85891,7 @@ function createCliContext(options) {
84262
85891
  function noopSetExitCode(_code) {}
84263
85892
  async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, dbUrl) {
84264
85893
  const config4 = buildConfigFromEnv(env);
84265
- const configuredUrl = env.DATABASE_URL === undefined ? join22(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
85894
+ const configuredUrl = env.DATABASE_URL === undefined ? join23(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
84266
85895
  const url2 = dbUrl ?? configuredUrl;
84267
85896
  if (url2 !== IN_MEMORY_DATABASE_URL) {
84268
85897
  await createNodeFileSystem3().ensureDir(dirname13(url2));