@gobing-ai/spur 0.3.1 → 0.3.3

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.
package/spur.js CHANGED
@@ -16900,7 +16900,7 @@ var init_src = __esm(() => {
16900
16900
  });
16901
16901
  });
16902
16902
 
16903
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.2/node_modules/@gobing-ai/ts-utils/dist/errors.js
16903
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.3/node_modules/@gobing-ai/ts-utils/dist/errors.js
16904
16904
  function isAppError(error51) {
16905
16905
  return error51 instanceof AppError;
16906
16906
  }
@@ -16928,7 +16928,7 @@ var init_errors3 = __esm(() => {
16928
16928
  };
16929
16929
  });
16930
16930
 
16931
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.2/node_modules/@gobing-ai/ts-utils/dist/api-response.js
16931
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.3/node_modules/@gobing-ai/ts-utils/dist/api-response.js
16932
16932
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
16933
16933
  var init_api_response = __esm(() => {
16934
16934
  init_errors3();
@@ -16951,10 +16951,10 @@ var init_api_response = __esm(() => {
16951
16951
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
16952
16952
  });
16953
16953
 
16954
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.2/node_modules/@gobing-ai/ts-utils/dist/cursor.js
16954
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.3/node_modules/@gobing-ai/ts-utils/dist/cursor.js
16955
16955
  var init_cursor = () => {};
16956
16956
 
16957
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.2/node_modules/@gobing-ai/ts-utils/dist/object.js
16957
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.3/node_modules/@gobing-ai/ts-utils/dist/object.js
16958
16958
  function isPlainObject2(value) {
16959
16959
  return typeof value === "object" && value !== null && !Array.isArray(value);
16960
16960
  }
@@ -16970,7 +16970,7 @@ function deepMerge(target, source) {
16970
16970
  return result;
16971
16971
  }
16972
16972
 
16973
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.2/node_modules/@gobing-ai/ts-utils/dist/output.js
16973
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.3/node_modules/@gobing-ai/ts-utils/dist/output.js
16974
16974
  function processStream(name) {
16975
16975
  const proc = globalThis.process;
16976
16976
  const stream = proc?.[name];
@@ -16991,7 +16991,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
16991
16991
  }
16992
16992
  var defaultStdoutTarget, defaultStderrTarget;
16993
16993
 
16994
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.2/node_modules/@gobing-ai/ts-utils/dist/index.js
16994
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.3/node_modules/@gobing-ai/ts-utils/dist/index.js
16995
16995
  var init_dist = __esm(() => {
16996
16996
  init_api_response();
16997
16997
  init_cursor();
@@ -23988,7 +23988,7 @@ var init_dist2 = __esm(() => {
23988
23988
  $visitAsync = visit.visitAsync;
23989
23989
  });
23990
23990
 
23991
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/config.js
23991
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/config.js
23992
23992
  function parseYamlObject(text) {
23993
23993
  let parsed;
23994
23994
  try {
@@ -24115,7 +24115,7 @@ var init_config = __esm(() => {
24115
24115
  };
24116
24116
  });
24117
24117
 
24118
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
24118
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
24119
24119
  import { appendFileSync, cpSync, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
24120
24120
  import { dirname, resolve as resolvePath } from "path";
24121
24121
  function createNodeFileSystem(root) {
@@ -24187,7 +24187,7 @@ function findProjectRoot(startDir) {
24187
24187
  }
24188
24188
  var init_file_system_node = () => {};
24189
24189
 
24190
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
24190
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
24191
24191
  var D1NotConfiguredError;
24192
24192
  var init_db_errors = __esm(() => {
24193
24193
  D1NotConfiguredError = class D1NotConfiguredError extends Error {
@@ -24198,7 +24198,7 @@ var init_db_errors = __esm(() => {
24198
24198
  };
24199
24199
  });
24200
24200
 
24201
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
24201
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
24202
24202
  function createCfFileSystem() {
24203
24203
  return {
24204
24204
  getProjectRoot: () => "/bundle",
@@ -24237,7 +24237,7 @@ function createCfFileSystem() {
24237
24237
  }
24238
24238
  var UNSUPPORTED = "FileSystem is not available on Cloudflare Workers. Use D1, KV, or R2 for persistent storage.";
24239
24239
 
24240
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
24240
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
24241
24241
  var exports_runtime_cf = {};
24242
24242
  __export(exports_runtime_cf, {
24243
24243
  cloudflareWorkersFactory: () => cloudflareWorkersFactory
@@ -31455,7 +31455,7 @@ var init_execa = __esm(() => {
31455
31455
  } = getIpcExport());
31456
31456
  });
31457
31457
 
31458
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
31458
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
31459
31459
  import { isatty } from "tty";
31460
31460
 
31461
31461
  class ProcessExecutor {
@@ -31743,7 +31743,7 @@ var init_process_executor = __esm(() => {
31743
31743
  };
31744
31744
  });
31745
31745
 
31746
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
31746
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
31747
31747
  var exports_runtime_node_bun = {};
31748
31748
  __export(exports_runtime_node_bun, {
31749
31749
  nodeBunFactory: () => nodeBunFactory,
@@ -31802,7 +31802,7 @@ var init_runtime_node_bun = __esm(() => {
31802
31802
  };
31803
31803
  });
31804
31804
 
31805
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/platform.js
31805
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/platform.js
31806
31806
  function isCloudflareWorkerRuntime() {
31807
31807
  return globalThis.navigator?.userAgent?.startsWith("Cloudflare-Workers") ?? false;
31808
31808
  }
@@ -31832,7 +31832,7 @@ function _resetRuntimeFactory() {
31832
31832
  }
31833
31833
  var _factory, _runtimeName;
31834
31834
 
31835
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/context.js
31835
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/context.js
31836
31836
  class RuntimeContext {
31837
31837
  scope;
31838
31838
  runtimeName;
@@ -31922,7 +31922,7 @@ var init_context = __esm(() => {
31922
31922
  init_process_executor();
31923
31923
  });
31924
31924
 
31925
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/path.js
31925
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/path.js
31926
31926
  function normalizeSeparators(path6) {
31927
31927
  return path6.replaceAll("\\", "/");
31928
31928
  }
@@ -32030,7 +32030,7 @@ var init_path = __esm(() => {
32030
32030
  SEP = globalThis.process?.platform === "win32" ? "\\" : "/";
32031
32031
  });
32032
32032
 
32033
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/fs.js
32033
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/fs.js
32034
32034
  async function ensureDirForFile(path6, fs = createNodeFileSystem()) {
32035
32035
  await fs.ensureDir(dirnamePath(path6));
32036
32036
  }
@@ -32081,7 +32081,7 @@ var init_fs = __esm(() => {
32081
32081
  init_path();
32082
32082
  });
32083
32083
 
32084
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
32084
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
32085
32085
  async function loadStructuredConfig(path6, options = {}) {
32086
32086
  const content = await (options.fileSystem ?? createNodeFileSystem()).readFile(path6);
32087
32087
  return await parseStructuredConfig(content, path6, options);
@@ -32361,10 +32361,10 @@ var init_schema_validation = __esm(() => {
32361
32361
  defaultResolve = typeof Bun !== "undefined" ? (specifier, from) => Bun.resolveSync(specifier, from) : undefined;
32362
32362
  });
32363
32363
 
32364
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/types.js
32364
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/types.js
32365
32365
  var init_types = () => {};
32366
32366
 
32367
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/index.js
32367
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/index.js
32368
32368
  var exports_dist = {};
32369
32369
  __export(exports_dist, {
32370
32370
  writeJsonFile: () => writeJsonFile,
@@ -32679,7 +32679,7 @@ var init_loader = __esm(() => {
32679
32679
  planningFoldersCache = new WeakMap;
32680
32680
  });
32681
32681
 
32682
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
32682
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
32683
32683
  import { Database } from "bun:sqlite";
32684
32684
  var init_bun_sqlite = () => {};
32685
32685
 
@@ -36871,7 +36871,7 @@ var init_bun_sqlite2 = __esm(() => {
36871
36871
  init_session2();
36872
36872
  });
36873
36873
 
36874
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
36874
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
36875
36875
  var inboxMessages;
36876
36876
  var init_inbox_messages = __esm(() => {
36877
36877
  init_sqlite_core();
@@ -36890,7 +36890,7 @@ var init_inbox_messages = __esm(() => {
36890
36890
  }, (table2) => [index("idx_inbox_messages_to_status").on(table2.toId, table2.status)]);
36891
36891
  });
36892
36892
 
36893
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/common.js
36893
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/common.js
36894
36894
  function nowTimestamp() {
36895
36895
  return Date.now();
36896
36896
  }
@@ -36919,7 +36919,7 @@ var init_common3 = __esm(() => {
36919
36919
  appendOnlyColumns = buildAppendOnlyColumns();
36920
36920
  });
36921
36921
 
36922
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
36922
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
36923
36923
  var queueJobs;
36924
36924
  var init_queue_jobs = __esm(() => {
36925
36925
  init_sqlite_core();
@@ -36939,7 +36939,7 @@ var init_queue_jobs = __esm(() => {
36939
36939
  }, (table2) => [index("queue_jobs_ready_idx").on(table2.status, table2.nextRetryAt, table2.createdAt)]);
36940
36940
  });
36941
36941
 
36942
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
36942
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
36943
36943
  var exports_runtime = {};
36944
36944
  __export(exports_runtime, {
36945
36945
  queueJobs: () => queueJobs,
@@ -36950,7 +36950,7 @@ var init_runtime = __esm(() => {
36950
36950
  init_queue_jobs();
36951
36951
  });
36952
36952
 
36953
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
36953
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
36954
36954
  var exports_bun_sqlite = {};
36955
36955
  __export(exports_bun_sqlite, {
36956
36956
  BunSqliteAdapter: () => BunSqliteAdapter
@@ -37229,7 +37229,7 @@ var init_d1 = __esm(() => {
37229
37229
  init_session3();
37230
37230
  });
37231
37231
 
37232
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
37232
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
37233
37233
  var exports_d1 = {};
37234
37234
  __export(exports_d1, {
37235
37235
  D1Adapter: () => D1Adapter
@@ -37277,7 +37277,7 @@ var init_d12 = __esm(() => {
37277
37277
  init_runtime();
37278
37278
  });
37279
37279
 
37280
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/adapter.js
37280
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/adapter.js
37281
37281
  async function createDbAdapter(config3) {
37282
37282
  switch (config3.driver) {
37283
37283
  case "bun-sqlite": {
@@ -37317,7 +37317,7 @@ var init_drizzle_orm = __esm(() => {
37317
37317
  init_view_common();
37318
37318
  });
37319
37319
 
37320
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/query-spec.js
37320
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/query-spec.js
37321
37321
  function compilePredicate(predicate) {
37322
37322
  if ("and" in predicate) {
37323
37323
  const parts = predicate.and.map(compilePredicate).filter((p) => p !== undefined);
@@ -37355,7 +37355,7 @@ var init_query_spec = __esm(() => {
37355
37355
  };
37356
37356
  });
37357
37357
 
37358
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/base-dao.js
37358
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/base-dao.js
37359
37359
  function asSelectQuery(query) {
37360
37360
  return query;
37361
37361
  }
@@ -37397,7 +37397,7 @@ var init_base_dao = __esm(() => {
37397
37397
  init_query_spec();
37398
37398
  });
37399
37399
 
37400
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
37400
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
37401
37401
  var embeddedMigrations;
37402
37402
  var init_embedded_migrations = __esm(() => {
37403
37403
  embeddedMigrations = [
@@ -37429,7 +37429,7 @@ var init_embedded_migrations = __esm(() => {
37429
37429
  ];
37430
37430
  });
37431
37431
 
37432
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
37432
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
37433
37433
  var EntityDao;
37434
37434
  var init_entity_dao = __esm(() => {
37435
37435
  init_drizzle_orm();
@@ -37591,7 +37591,7 @@ var init_entity_dao = __esm(() => {
37591
37591
  };
37592
37592
  });
37593
37593
 
37594
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
37594
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
37595
37595
  var InboxMessageDao;
37596
37596
  var init_inbox_message_dao = __esm(() => {
37597
37597
  init_drizzle_orm();
@@ -37710,7 +37710,7 @@ var init_migrator2 = __esm(() => {
37710
37710
  init_migrator();
37711
37711
  });
37712
37712
 
37713
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/migrate.js
37713
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/migrate.js
37714
37714
  async function ensureJournalTable(adapter, table3) {
37715
37715
  await adapter.exec(`CREATE TABLE IF NOT EXISTS "${table3}" (` + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "hash text NOT NULL, " + "created_at numeric" + ")");
37716
37716
  }
@@ -37785,7 +37785,7 @@ var init_migrate = __esm(() => {
37785
37785
  init_embedded_migrations();
37786
37786
  });
37787
37787
 
37788
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
37788
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
37789
37789
  var QueueJobDao;
37790
37790
  var init_queue_job_dao = __esm(() => {
37791
37791
  init_drizzle_orm();
@@ -37926,7 +37926,7 @@ var init_queue_job_dao = __esm(() => {
37926
37926
  };
37927
37927
  });
37928
37928
 
37929
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/index.js
37929
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/index.js
37930
37930
  var exports_dist2 = {};
37931
37931
  __export(exports_dist2, {
37932
37932
  embeddedMigrations: () => embeddedMigrations,
@@ -39752,7 +39752,7 @@ var init_mod = __esm(() => {
39752
39752
  init_config2();
39753
39753
  });
39754
39754
 
39755
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/logger.js
39755
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/logger.js
39756
39756
  function toLogTapeLevel(level) {
39757
39757
  return level === "warn" ? "warning" : level;
39758
39758
  }
@@ -41305,7 +41305,7 @@ var require_src = __commonJS((exports) => {
41305
41305
  };
41306
41306
  });
41307
41307
 
41308
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
41308
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
41309
41309
  function getTelemetryConfig(configPartial = {}) {
41310
41310
  return {
41311
41311
  enabled: configPartial.enabled ?? CONFIG_DEFAULTS.enabled,
@@ -41341,7 +41341,7 @@ var init_sdk = __esm(() => {
41341
41341
  resolvedConfig = getTelemetryConfig();
41342
41342
  });
41343
41343
 
41344
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
41344
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
41345
41345
  function isSuppressed(tracer2) {
41346
41346
  return tracer2 === undefined && !getResolvedConfig().enabled;
41347
41347
  }
@@ -41381,7 +41381,7 @@ var init_tracing2 = __esm(() => {
41381
41381
  import_api2 = __toESM(require_src(), 1);
41382
41382
  });
41383
41383
 
41384
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
41384
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
41385
41385
  function getMeter() {
41386
41386
  return import_api3.metrics.getMeter(METER_NAME, METER_VERSION);
41387
41387
  }
@@ -41478,7 +41478,7 @@ var init_metrics = __esm(() => {
41478
41478
  instruments = {};
41479
41479
  });
41480
41480
 
41481
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
41481
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
41482
41482
  function busLogger() {
41483
41483
  if (!_busLogger)
41484
41484
  _busLogger = getLogger2("event-bus");
@@ -41723,7 +41723,7 @@ var init_event_bus = __esm(() => {
41723
41723
  init_metrics();
41724
41724
  });
41725
41725
 
41726
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
41726
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
41727
41727
  function obsLogger() {
41728
41728
  if (!_obsLogger)
41729
41729
  _obsLogger = getLogger2("event-bus.observers");
@@ -41787,7 +41787,7 @@ var init_default_observers = __esm(() => {
41787
41787
  init_event_bus();
41788
41788
  });
41789
41789
 
41790
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
41790
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
41791
41791
  function parseInterval(cron) {
41792
41792
  const trimmed = cron.trim();
41793
41793
  const num = Number(trimmed);
@@ -41861,7 +41861,7 @@ var init_node3 = __esm(() => {
41861
41861
  init_metrics();
41862
41862
  });
41863
41863
 
41864
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
41864
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
41865
41865
  var exports_scheduler_node = {};
41866
41866
  __export(exports_scheduler_node, {
41867
41867
  NodeSchedulerAdapter: () => NodeSchedulerAdapter
@@ -48094,24 +48094,24 @@ var init_planning_folders = __esm(() => {
48094
48094
  init_loader();
48095
48095
  });
48096
48096
 
48097
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
48097
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
48098
48098
  var init_event_bus2 = __esm(() => {
48099
48099
  init_event_bus();
48100
48100
  });
48101
48101
 
48102
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
48102
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
48103
48103
  var init_telemetry = __esm(() => {
48104
48104
  init_tracing2();
48105
48105
  });
48106
48106
 
48107
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/index.js
48107
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/index.js
48108
48108
  var init_dist5 = __esm(() => {
48109
48109
  init_event_bus2();
48110
48110
  init_logger3();
48111
48111
  init_telemetry();
48112
48112
  });
48113
48113
 
48114
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
48114
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
48115
48115
  function resolveAgentName(input) {
48116
48116
  if (isCanonicalName(input))
48117
48117
  return input;
@@ -48341,7 +48341,7 @@ var init_shims = __esm(() => {
48341
48341
  ALIAS_TO_CANONICAL = Object.fromEntries(Object.values(AGENT_SHIMS).flatMap((shim) => (shim.aliases ?? []).map((alias3) => [alias3, shim.name])));
48342
48342
  });
48343
48343
 
48344
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
48344
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
48345
48345
  function buildIdentityPreamble(ctx) {
48346
48346
  const sections = [
48347
48347
  `You are agent \`${ctx.agentId}\` (${ctx.agentType}) in workspace \`${ctx.workspace}\`.`
@@ -48381,9 +48381,27 @@ function buildIdentityPreamble(ctx) {
48381
48381
  `)}
48382
48382
  `;
48383
48383
  }
48384
- var init_identity = () => {};
48384
+ function getGitContext(workspacePath, executor = new BunSyncProcessExecutor) {
48385
+ const branch = runGit(executor, ["-C", workspacePath, "branch", "--show-current"]);
48386
+ if (branch === null || branch === "")
48387
+ return null;
48388
+ const status = runGit(executor, ["-C", workspacePath, "status", "--porcelain"]);
48389
+ const dirtyCount = status === null || status === "" ? 0 : status.split(`
48390
+ `).filter(Boolean).length;
48391
+ return ["Git context:", `branch: ${branch}`, `dirty: ${dirtyCount === 0 ? "false" : `${dirtyCount} files`}`].join(`
48392
+ `);
48393
+ }
48394
+ function runGit(executor, args) {
48395
+ const result = executor.runSync({ command: "git", args, rejectOnError: false, forceBuffered: true });
48396
+ if (result.exitCode !== 0)
48397
+ return null;
48398
+ return result.stdout.trim();
48399
+ }
48400
+ var init_identity = __esm(() => {
48401
+ init_dist3();
48402
+ });
48385
48403
 
48386
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
48404
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
48387
48405
  function isClaudeStyleSlashCommand(input) {
48388
48406
  return SLASH_COMMAND_RE.test(input);
48389
48407
  }
@@ -48411,7 +48429,7 @@ var init_slash_command = __esm(() => {
48411
48429
  SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
48412
48430
  });
48413
48431
 
48414
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
48432
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
48415
48433
  class AiRunner {
48416
48434
  processExecutor;
48417
48435
  defaultCwd;
@@ -48525,7 +48543,7 @@ var init_ai_runner = __esm(() => {
48525
48543
  init_slash_command();
48526
48544
  });
48527
48545
 
48528
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
48546
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
48529
48547
  class AgentDetector {
48530
48548
  runner;
48531
48549
  timeout;
@@ -48601,7 +48619,7 @@ var init_agent_detector = __esm(() => {
48601
48619
  VERSION_PATTERN = /(?<version>\d+\.\d+(?:\.\d+)?)/;
48602
48620
  });
48603
48621
 
48604
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
48622
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
48605
48623
  function validateAgentId(id) {
48606
48624
  if (!/^[a-z][a-z0-9_-]{1,63}$/.test(id)) {
48607
48625
  throw new ValueError(`Invalid agent id "${id}": expected 2-64 chars, lowercase alphanumeric, "_" or "-"`);
@@ -48698,7 +48716,7 @@ var init_agent_spec = __esm(() => {
48698
48716
  };
48699
48717
  });
48700
48718
 
48701
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
48719
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
48702
48720
  function isNonEmpty(value) {
48703
48721
  return value !== undefined && value.trim().length > 0;
48704
48722
  }
@@ -48794,7 +48812,7 @@ var init_auth_shims = __esm(() => {
48794
48812
  };
48795
48813
  });
48796
48814
 
48797
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
48815
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
48798
48816
  class DoctorRunner {
48799
48817
  detector;
48800
48818
  runner;
@@ -48858,15 +48876,15 @@ var init_doctor_runner = __esm(() => {
48858
48876
  init_ai_runner();
48859
48877
  });
48860
48878
 
48861
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
48879
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
48862
48880
  var init_events = () => {};
48863
48881
 
48864
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
48882
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
48865
48883
  function formatMessage(msg) {
48866
48884
  return `[task from=${msg.fromId ?? "operator"} id=${msg.id}] ${msg.body}`;
48867
48885
  }
48868
48886
 
48869
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
48887
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
48870
48888
  import { Buffer as Buffer5 } from "buffer";
48871
48889
 
48872
48890
  class TeamAgentProcess {
@@ -49000,7 +49018,7 @@ var init_team_agent_process = __esm(() => {
49000
49018
  init_dist3();
49001
49019
  });
49002
49020
 
49003
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
49021
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
49004
49022
  class TeamOrchestrator {
49005
49023
  configDir;
49006
49024
  inbox;
@@ -49129,7 +49147,34 @@ var init_team_orchestrator = __esm(() => {
49129
49147
  init_team_agent_process();
49130
49148
  });
49131
49149
 
49132
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.2+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
49150
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.3+2e11ad5b9561782b/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
49151
+ var exports_dist3 = {};
49152
+ __export(exports_dist3, {
49153
+ validateAgentId: () => validateAgentId,
49154
+ translateSlashCommand: () => translateSlashCommand,
49155
+ saveAgentSpec: () => saveAgentSpec,
49156
+ resolveAgentName: () => resolveAgentName,
49157
+ loadAgentSpecs: () => loadAgentSpecs,
49158
+ isClaudeStyleSlashCommand: () => isClaudeStyleSlashCommand,
49159
+ isAuthenticated: () => isAuthenticated,
49160
+ isAgentName: () => isAgentName,
49161
+ getGitContext: () => getGitContext,
49162
+ getAgentShim: () => getAgentShim,
49163
+ formatMessage: () => formatMessage,
49164
+ deleteAgentSpec: () => deleteAgentSpec,
49165
+ buildIdentityPreamble: () => buildIdentityPreamble,
49166
+ buildAgentCommand: () => buildAgentCommand,
49167
+ ValueError: () => ValueError,
49168
+ TeamOrchestrator: () => TeamOrchestrator,
49169
+ TeamAgentProcess: () => TeamAgentProcess,
49170
+ TIER2_AGENTS: () => TIER2_AGENTS,
49171
+ TIER1_PRIORITY: () => TIER1_PRIORITY,
49172
+ DoctorRunner: () => DoctorRunner,
49173
+ DISPLAY_ORDER: () => DISPLAY_ORDER,
49174
+ AiRunner: () => AiRunner,
49175
+ AgentDetector: () => AgentDetector,
49176
+ AGENT_SHIMS: () => AGENT_SHIMS
49177
+ });
49133
49178
  var init_dist6 = __esm(() => {
49134
49179
  init_agent_detector();
49135
49180
  init_agent_spec();
@@ -50487,7 +50532,7 @@ var init_drizzle_zod = __esm(() => {
50487
50532
  };
50488
50533
  });
50489
50534
 
50490
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
50535
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
50491
50536
  function sqlExpressionToText(value) {
50492
50537
  if (typeof value !== "object" || value === null || !("queryChunks" in value)) {
50493
50538
  return;
@@ -50510,7 +50555,7 @@ function getDrizzleTableName(table3) {
50510
50555
  return String(table3[nameSym]);
50511
50556
  }
50512
50557
 
50513
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
50558
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
50514
50559
  function quoteIdent(name) {
50515
50560
  return `"${name.replace(/"/g, '""')}"`;
50516
50561
  }
@@ -50604,7 +50649,7 @@ var init_ddl = __esm(() => {
50604
50649
  init_sqlite_core();
50605
50650
  });
50606
50651
 
50607
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
50652
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
50608
50653
  function defineTable(name, columns2) {
50609
50654
  const table3 = sqliteTable(name, columns2);
50610
50655
  let insert2;
@@ -50638,7 +50683,7 @@ var init_define_table = __esm(() => {
50638
50683
  init_ddl();
50639
50684
  });
50640
50685
 
50641
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.2+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/index.js
50686
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.3+41c9028a9c9e39f8/node_modules/@gobing-ai/ts-db/dist/schema/index.js
50642
50687
  var init_schema = __esm(() => {
50643
50688
  init_sqlite_core();
50644
50689
  init_define_table();
@@ -50721,6 +50766,28 @@ var init_artifact_dao = __esm(() => {
50721
50766
  };
50722
50767
  });
50723
50768
 
50769
+ // ../../packages/domain/src/dao/inbox-recent-dao.ts
50770
+ class InboxRecentDao {
50771
+ db;
50772
+ constructor(db2) {
50773
+ this.db = db2;
50774
+ }
50775
+ async listRecent(limit = 50) {
50776
+ const capped = Math.max(1, Math.min(limit, 500));
50777
+ try {
50778
+ return await this.db.queryAll(`SELECT id, from_id, to_id, body, status, created_at, in_reply_to
50779
+ FROM inbox_messages
50780
+ ORDER BY created_at DESC
50781
+ LIMIT ?1`, capped);
50782
+ } catch (error51) {
50783
+ if (error51 instanceof Error && error51.message.includes("no such table: inbox_messages")) {
50784
+ return [];
50785
+ }
50786
+ throw error51;
50787
+ }
50788
+ }
50789
+ }
50790
+
50724
50791
  // ../../packages/domain/src/schema/phase-runs.ts
50725
50792
  var phaseRunsTable, phaseRuns;
50726
50793
  var init_phase_runs = __esm(() => {
@@ -50948,6 +51015,70 @@ var init_run_dao = __esm(() => {
50948
51015
  };
50949
51016
  });
50950
51017
 
51018
+ // ../../packages/domain/src/dao/system-event-dao.ts
51019
+ class SystemEventDao {
51020
+ db;
51021
+ constructor(db2) {
51022
+ this.db = db2;
51023
+ }
51024
+ async insert(input) {
51025
+ await this.db.run(`INSERT INTO system_events (id, event_name, occurred_at, actor, payload_json)
51026
+ VALUES (?, ?, ?, ?, ?)`, [input.id, input.event_name, input.occurred_at, input.actor ?? null, input.payload_json ?? null]);
51027
+ }
51028
+ async prune(cap) {
51029
+ const before = await this.db.queryFirst("SELECT COUNT(*) AS c FROM system_events");
51030
+ await this.db.run(`DELETE FROM system_events
51031
+ WHERE id IN (
51032
+ SELECT id FROM system_events
51033
+ WHERE id NOT IN (
51034
+ SELECT id FROM system_events
51035
+ ORDER BY occurred_at DESC
51036
+ LIMIT ?1
51037
+ )
51038
+ )`, [cap]);
51039
+ const after = await this.db.queryFirst("SELECT COUNT(*) AS c FROM system_events");
51040
+ return (before?.c ?? 0) - (after?.c ?? 0);
51041
+ }
51042
+ async query(spec = {}) {
51043
+ const limit = spec.limit ?? 100;
51044
+ try {
51045
+ if (spec.name !== undefined && spec.since !== undefined) {
51046
+ return await this.db.queryAll(`SELECT id, event_name, occurred_at, actor, payload_json
51047
+ FROM system_events
51048
+ WHERE event_name = ?1 AND occurred_at > ?2
51049
+ ORDER BY occurred_at DESC
51050
+ LIMIT ?3`, spec.name, spec.since, limit);
51051
+ }
51052
+ if (spec.name !== undefined) {
51053
+ return await this.db.queryAll(`SELECT id, event_name, occurred_at, actor, payload_json
51054
+ FROM system_events
51055
+ WHERE event_name = ?1
51056
+ ORDER BY occurred_at DESC
51057
+ LIMIT ?2`, spec.name, limit);
51058
+ }
51059
+ if (spec.since !== undefined) {
51060
+ return await this.db.queryAll(`SELECT id, event_name, occurred_at, actor, payload_json
51061
+ FROM system_events
51062
+ WHERE occurred_at > ?1
51063
+ ORDER BY occurred_at DESC
51064
+ LIMIT ?2`, spec.since, limit);
51065
+ }
51066
+ return await this.db.queryAll(`SELECT id, event_name, occurred_at, actor, payload_json
51067
+ FROM system_events
51068
+ ORDER BY occurred_at DESC
51069
+ LIMIT ?1`, limit);
51070
+ } catch (error51) {
51071
+ if (error51 instanceof Error && error51.message.includes("no such table: system_events")) {
51072
+ return [];
51073
+ }
51074
+ throw error51;
51075
+ }
51076
+ }
51077
+ async deleteAll() {
51078
+ await this.db.run("DELETE FROM system_events");
51079
+ }
51080
+ }
51081
+
50951
51082
  // ../../packages/domain/src/dao/task-run-link-dao.ts
50952
51083
  class TaskRunLinkDao {
50953
51084
  db;
@@ -51107,7 +51238,7 @@ var init_dao = __esm(() => {
51107
51238
  init_workspace_dao();
51108
51239
  });
51109
51240
 
51110
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
51241
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
51111
51242
  var WorkflowValidationError, FSMError, RunCollisionError, WorkflowResumeError;
51112
51243
  var init_errors5 = __esm(() => {
51113
51244
  WorkflowValidationError = class WorkflowValidationError extends Error {
@@ -51142,7 +51273,7 @@ var init_errors5 = __esm(() => {
51142
51273
  };
51143
51274
  });
51144
51275
 
51145
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
51276
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
51146
51277
  function runtimeBuiltins(workflowName, stateOrNodeId, runId, transitionsTaken, mode) {
51147
51278
  return {
51148
51279
  workflow: workflowName,
@@ -51373,7 +51504,7 @@ var init_run_lifecycle = __esm(() => {
51373
51504
  ];
51374
51505
  });
51375
51506
 
51376
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
51507
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
51377
51508
  var RESERVED_VAR_NAMES, IDENTIFIER, VarsSchema, EnvSchema, ActionDefSchema, GuardDefSchema, StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema, WorkflowDefSchema;
51378
51509
  var init_schema2 = __esm(() => {
51379
51510
  init_zod();
@@ -51457,7 +51588,7 @@ var init_schema2 = __esm(() => {
51457
51588
  WorkflowDefSchema = exports_external.union([StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema]);
51458
51589
  });
51459
51590
 
51460
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
51591
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
51461
51592
  async function loadWorkflowDef(path8, options = {}) {
51462
51593
  return parseWorkflowDef(await loadStructuredConfig(path8, options), path8);
51463
51594
  }
@@ -51616,7 +51747,7 @@ var init_config3 = __esm(() => {
51616
51747
  RUNTIME_TEMPLATE_NAMESPACES = new Set(RUNTIME_BUILTIN_KEYS);
51617
51748
  });
51618
51749
 
51619
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
51750
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
51620
51751
  class CapabilityRegistry {
51621
51752
  kind;
51622
51753
  capabilities = new Map;
@@ -51647,7 +51778,7 @@ class CapabilityRegistry {
51647
51778
  }
51648
51779
  }
51649
51780
 
51650
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
51781
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
51651
51782
  function assertRelativeExtensionPath(path8, options = {}) {
51652
51783
  const where = options.sourceName !== undefined ? ` declared by "${options.sourceName}"` : "";
51653
51784
  if (/^([/\\]|[A-Za-z]:[/\\])/.test(path8)) {
@@ -51658,20 +51789,20 @@ function assertRelativeExtensionPath(path8, options = {}) {
51658
51789
  }
51659
51790
  }
51660
51791
 
51661
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
51792
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
51662
51793
  var init_extension_loader = () => {};
51663
51794
 
51664
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
51795
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
51665
51796
  var init_extension = __esm(() => {
51666
51797
  init_extension_loader();
51667
51798
  });
51668
51799
 
51669
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.2/node_modules/@gobing-ai/ts-runtime/dist/extension.js
51800
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.3/node_modules/@gobing-ai/ts-runtime/dist/extension.js
51670
51801
  var init_extension2 = __esm(() => {
51671
51802
  init_extension();
51672
51803
  });
51673
51804
 
51674
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
51805
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
51675
51806
  class WorkflowEngineHost {
51676
51807
  actions = new CapabilityRegistry("workflow action");
51677
51808
  guards = new CapabilityRegistry("workflow guard");
@@ -51836,7 +51967,7 @@ var init_host = __esm(() => {
51836
51967
  init_errors5();
51837
51968
  });
51838
51969
 
51839
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
51970
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
51840
51971
  var WORKFLOW_ENGINE_SCHEMA_SQL;
51841
51972
  var init_schema_sql = __esm(() => {
51842
51973
  WORKFLOW_ENGINE_SCHEMA_SQL = `
@@ -51909,7 +52040,7 @@ CREATE TABLE IF NOT EXISTS action_runs (
51909
52040
  `.trim();
51910
52041
  });
51911
52042
 
51912
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
52043
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
51913
52044
  async function applyWorkflowEngineSchema(db2) {
51914
52045
  for (const statement of WORKFLOW_ENGINE_SCHEMA_SQL.split(";")) {
51915
52046
  const sql4 = statement.trim();
@@ -52122,7 +52253,7 @@ var init_persistence = __esm(() => {
52122
52253
  init_schema_sql();
52123
52254
  });
52124
52255
 
52125
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
52256
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
52126
52257
  function mergeVars(workflowVars = {}, overrideVars = {}) {
52127
52258
  return { ...workflowVars, ...overrideVars };
52128
52259
  }
@@ -52182,7 +52313,7 @@ var init_variables = __esm(() => {
52182
52313
  TEMPLATE_REF = /\$\{([^}]+)\}/g;
52183
52314
  });
52184
52315
 
52185
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
52316
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
52186
52317
  async function runActionStep(action, vars, deps) {
52187
52318
  const { host, persistence, lifecycle, stateOrNodeId, runId } = deps;
52188
52319
  const resolved = resolveTemplates(action.options ?? {}, {
@@ -52239,7 +52370,7 @@ var init_action_step = __esm(() => {
52239
52370
  init_variables();
52240
52371
  });
52241
52372
 
52242
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
52373
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
52243
52374
  class StateMachineDriver {
52244
52375
  options;
52245
52376
  constructor(options) {
@@ -52367,7 +52498,7 @@ var init_state_machine = __esm(() => {
52367
52498
  EMPTY_OUTCOME = { outcome: "completed", result: undefined };
52368
52499
  });
52369
52500
 
52370
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
52501
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
52371
52502
  class TransitionFlowDriver {
52372
52503
  options;
52373
52504
  constructor(options) {
@@ -52479,7 +52610,7 @@ var init_transition_flow = __esm(() => {
52479
52610
  init_variables();
52480
52611
  });
52481
52612
 
52482
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
52613
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
52483
52614
  class WorkflowService {
52484
52615
  host;
52485
52616
  persistence;
@@ -52663,7 +52794,7 @@ var init_service = __esm(() => {
52663
52794
  init_variables();
52664
52795
  });
52665
52796
 
52666
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
52797
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
52667
52798
  var init_dist7 = __esm(() => {
52668
52799
  init_config3();
52669
52800
  init_host();
@@ -52672,7 +52803,7 @@ var init_dist7 = __esm(() => {
52672
52803
  init_service();
52673
52804
  });
52674
52805
 
52675
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.2+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
52806
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.3+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
52676
52807
  var HistoryImportError;
52677
52808
  var init_errors6 = __esm(() => {
52678
52809
  HistoryImportError = class HistoryImportError extends Error {
@@ -52685,7 +52816,7 @@ var init_errors6 = __esm(() => {
52685
52816
  };
52686
52817
  });
52687
52818
 
52688
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.2+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
52819
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.3+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
52689
52820
  import { createHash } from "crypto";
52690
52821
  function stableJson(value) {
52691
52822
  if (Array.isArray(value)) {
@@ -52702,7 +52833,7 @@ function sha256(value) {
52702
52833
  }
52703
52834
  var init_hash = () => {};
52704
52835
 
52705
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.2+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
52836
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.3+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
52706
52837
  function redactValue(value, rules = DEFAULT_REDACTION_RULES) {
52707
52838
  if (typeof value === "string") {
52708
52839
  return rules.reduce((current, rule) => current.replace(rule.pattern, rule.replacement), value);
@@ -52739,7 +52870,7 @@ var init_redaction = __esm(() => {
52739
52870
  ];
52740
52871
  });
52741
52872
 
52742
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.2+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
52873
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.3+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
52743
52874
  var HISTORY_IMPORT_SCHEMA_SQL;
52744
52875
  var init_schema_sql2 = __esm(() => {
52745
52876
  HISTORY_IMPORT_SCHEMA_SQL = `
@@ -52826,7 +52957,7 @@ CREATE TABLE IF NOT EXISTS history_etl_openclaw (
52826
52957
  `.trim();
52827
52958
  });
52828
52959
 
52829
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.2+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
52960
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.3+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
52830
52961
  function firstString(...values) {
52831
52962
  for (const value of values) {
52832
52963
  if (typeof value === "string" && value.length > 0)
@@ -52914,7 +53045,7 @@ var init_sources = __esm(() => {
52914
53045
  };
52915
53046
  });
52916
53047
 
52917
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.2+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
53048
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.3+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
52918
53049
  async function applyHistoryImportSchema(db2) {
52919
53050
  for (const statement of HISTORY_IMPORT_SCHEMA_SQL.split(";")) {
52920
53051
  const sql4 = statement.trim();
@@ -53140,13 +53271,13 @@ var init_importer = __esm(() => {
53140
53271
  VALID_TABLE_NAME = /^history_etl_[a-z_]+$/;
53141
53272
  });
53142
53273
 
53143
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.2+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
53274
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.3+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
53144
53275
  var init_dist8 = __esm(() => {
53145
53276
  init_importer();
53146
53277
  init_schema_sql2();
53147
53278
  });
53148
53279
 
53149
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
53280
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
53150
53281
  function collectExtensions(sourceName, sourceDir, extensions) {
53151
53282
  if (extensions === undefined)
53152
53283
  return [];
@@ -53162,7 +53293,7 @@ var init_extensions = __esm(() => {
53162
53293
  init_dist3();
53163
53294
  });
53164
53295
 
53165
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
53296
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
53166
53297
  function createFinding(rule, message, filePath, extras = {}) {
53167
53298
  return {
53168
53299
  ruleId: rule.id,
@@ -53233,7 +53364,7 @@ var init_types2 = __esm(() => {
53233
53364
  });
53234
53365
  });
53235
53366
 
53236
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
53367
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
53237
53368
  async function loadPreset(name, options) {
53238
53369
  const merged = await buildMergedRoots(options.roots.map((root) => resolvePath2(root)), options.fileSystem);
53239
53370
  const presetPath = findMergedPreset(merged, name);
@@ -53448,7 +53579,7 @@ var init_loader2 = __esm(() => {
53448
53579
  FIX_MODE_AUTHORITY = { none: 0, suggest: 1, auto: 2 };
53449
53580
  });
53450
53581
 
53451
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
53582
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
53452
53583
  function normalizeFindingPath(filePath) {
53453
53584
  if (!filePath || isAbsolutePath(filePath))
53454
53585
  return null;
@@ -53513,7 +53644,7 @@ var init_test_stub_fixer = __esm(() => {
53513
53644
  realFileSystem = createNodeFileSystem();
53514
53645
  });
53515
53646
 
53516
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
53647
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
53517
53648
  function registerBuiltinFixers(host, exec) {
53518
53649
  const regexFixer = new RegexFixerProvider;
53519
53650
  const pathFixer = new PathFixerProvider;
@@ -53716,7 +53847,7 @@ var init_fixers = __esm(() => {
53716
53847
  };
53717
53848
  });
53718
53849
 
53719
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
53850
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
53720
53851
  function stringArray(value) {
53721
53852
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
53722
53853
  }
@@ -53754,7 +53885,7 @@ function parseInlineFlags(source) {
53754
53885
  return { flags, rest: source.slice(match[0].length) };
53755
53886
  }
53756
53887
 
53757
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
53888
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
53758
53889
  function matchesAny(path8, patterns) {
53759
53890
  if (patterns === undefined || patterns.length === 0)
53760
53891
  return true;
@@ -53802,7 +53933,7 @@ function escapeRegExp(value) {
53802
53933
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
53803
53934
  }
53804
53935
 
53805
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
53936
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
53806
53937
  async function discoverFiles2(options) {
53807
53938
  const fs3 = options.fs ?? createNodeFileSystem();
53808
53939
  const allFiles = await walkDir(options.workdir, fs3, DEFAULT_EXCLUDES);
@@ -53830,12 +53961,12 @@ var init_file_discovery = __esm(() => {
53830
53961
  DEFAULT_EXCLUDES = new Set([".git", "node_modules", "dist", ".coverage", ".astro", ".wrangler"]);
53831
53962
  });
53832
53963
 
53833
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
53964
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
53834
53965
  var init_file_utils = __esm(() => {
53835
53966
  init_file_discovery();
53836
53967
  });
53837
53968
 
53838
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
53969
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
53839
53970
  class AgentDetectionEvaluator {
53840
53971
  detector;
53841
53972
  constructor(detector = new AgentDetector) {
@@ -53863,7 +53994,7 @@ var init_agent_detection_evaluator = __esm(() => {
53863
53994
  init_file_utils();
53864
53995
  });
53865
53996
 
53866
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
53997
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
53867
53998
  class CoverageGateEvaluator {
53868
53999
  constructor() {}
53869
54000
  async evaluate(rule, context3) {
@@ -53947,7 +54078,7 @@ var init_coverage_gate_evaluator = __esm(() => {
53947
54078
  init_file_utils();
53948
54079
  });
53949
54080
 
53950
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
54081
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
53951
54082
  class ExitCodeEvaluator {
53952
54083
  executor;
53953
54084
  constructor(executor = new NodeProcessExecutor) {
@@ -53983,7 +54114,7 @@ var init_exit_code_evaluator = __esm(() => {
53983
54114
  init_file_utils();
53984
54115
  });
53985
54116
 
53986
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
54117
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
53987
54118
  class ForbiddenImportEvaluator {
53988
54119
  constructor() {}
53989
54120
  async evaluate(rule, context3) {
@@ -54064,7 +54195,7 @@ var init_forbidden_import_evaluator = __esm(() => {
54064
54195
  init_file_utils();
54065
54196
  });
54066
54197
 
54067
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
54198
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
54068
54199
  class ImportBoundaryEvaluator {
54069
54200
  async evaluate(rule, context3) {
54070
54201
  const config3 = rule.evaluator.config ?? {};
@@ -54157,7 +54288,7 @@ var init_import_boundary_evaluator = __esm(() => {
54157
54288
  init_file_utils();
54158
54289
  });
54159
54290
 
54160
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
54291
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
54161
54292
  class PathEvaluator {
54162
54293
  constructor() {}
54163
54294
  async evaluate(rule, context3) {
@@ -54218,7 +54349,7 @@ var init_path_evaluator = __esm(() => {
54218
54349
  init_file_utils();
54219
54350
  });
54220
54351
 
54221
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
54352
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
54222
54353
  class RegexEvaluator {
54223
54354
  constructor() {}
54224
54355
  async evaluate(rule, context3) {
@@ -54296,7 +54427,7 @@ var init_regex_evaluator = __esm(() => {
54296
54427
  init_file_utils();
54297
54428
  });
54298
54429
 
54299
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
54430
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
54300
54431
  class RipgrepEvaluator {
54301
54432
  executor;
54302
54433
  constructor(executor = new NodeProcessExecutor) {
@@ -54318,11 +54449,16 @@ class RipgrepEvaluator {
54318
54449
  });
54319
54450
  if (result.exitCode !== 0 && result.exitCode !== 1) {
54320
54451
  const detail = result.stderr.trim();
54452
+ if (isNoFilesSearched(detail))
54453
+ return { findings: [], fixes: [] };
54321
54454
  throw new Error(`rg failed (exit ${result.exitCode})${detail.length > 0 ? `: ${detail}` : ""}`);
54322
54455
  }
54323
54456
  return mode === "require" ? { findings: requireFindings(rule, pattern, result.stdout), fixes: [] } : { findings: forbidFindings(rule, pattern, result.stdout), fixes: [] };
54324
54457
  }
54325
54458
  }
54459
+ function isNoFilesSearched(stderr) {
54460
+ return stderr.includes("No files were searched");
54461
+ }
54326
54462
  function buildArgs(pattern, mode, multiline, include, exclude) {
54327
54463
  const args = [];
54328
54464
  if (multiline)
@@ -54384,7 +54520,7 @@ var init_ripgrep_evaluator = __esm(() => {
54384
54520
  init_file_utils();
54385
54521
  });
54386
54522
 
54387
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
54523
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
54388
54524
  class SchemaArtifactEvaluator {
54389
54525
  constructor() {}
54390
54526
  async evaluate(rule, context3) {
@@ -54462,7 +54598,7 @@ var init_schema_artifact_evaluator = __esm(() => {
54462
54598
  init_file_utils();
54463
54599
  });
54464
54600
 
54465
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
54601
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
54466
54602
  class SecretsScannerEvaluator {
54467
54603
  constructor() {}
54468
54604
  async evaluate(rule, context3) {
@@ -54530,7 +54666,7 @@ var init_secrets_scanner_evaluator = __esm(() => {
54530
54666
  ALL_CATEGORIES = Object.keys(BUILTIN_PATTERNS);
54531
54667
  });
54532
54668
 
54533
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
54669
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
54534
54670
  class SgEvaluator {
54535
54671
  executor;
54536
54672
  constructor(executor = new NodeProcessExecutor) {
@@ -54627,7 +54763,7 @@ var init_sg_evaluator = __esm(() => {
54627
54763
  init_file_utils();
54628
54764
  });
54629
54765
 
54630
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
54766
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
54631
54767
  class TypeScriptTestPathResolver {
54632
54768
  name = "typescript";
54633
54769
  constructor() {}
@@ -54710,7 +54846,7 @@ function testify(rel) {
54710
54846
  return `${dir}test_${base2}`;
54711
54847
  }
54712
54848
 
54713
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
54849
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
54714
54850
  class TestLocationEvaluator {
54715
54851
  resolvers;
54716
54852
  constructor(resolvers) {
@@ -54785,7 +54921,7 @@ var init_test_location_evaluator = __esm(() => {
54785
54921
  TYPESCRIPT_FALLBACK = new TypeScriptTestPathResolver;
54786
54922
  });
54787
54923
 
54788
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
54924
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
54789
54925
  class TsdocExportEvaluator {
54790
54926
  constructor() {}
54791
54927
  async evaluate(rule, context3) {
@@ -54867,7 +55003,7 @@ var init_tsdoc_export_evaluator = __esm(() => {
54867
55003
  };
54868
55004
  });
54869
55005
 
54870
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
55006
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
54871
55007
  class JsonFormatter {
54872
55008
  constructor() {}
54873
55009
  format(result) {
@@ -54875,7 +55011,7 @@ class JsonFormatter {
54875
55011
  }
54876
55012
  }
54877
55013
 
54878
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
55014
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
54879
55015
  class TextFormatter {
54880
55016
  constructor() {}
54881
55017
  format(result) {
@@ -54889,7 +55025,7 @@ class TextFormatter {
54889
55025
  }
54890
55026
  }
54891
55027
 
54892
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
55028
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
54893
55029
  function registerBuiltins(host, executor) {
54894
55030
  const path8 = new PathEvaluator;
54895
55031
  host.evaluators.register("regex", new RegexEvaluator, "builtin");
@@ -54929,7 +55065,7 @@ var init_builtins = __esm(() => {
54929
55065
  init_tsdoc_export_evaluator();
54930
55066
  });
54931
55067
 
54932
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
55068
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
54933
55069
  class RuleEngineHost {
54934
55070
  evaluators;
54935
55071
  formatters;
@@ -54946,7 +55082,7 @@ var init_rule_engine_host = __esm(() => {
54946
55082
  init_extension2();
54947
55083
  });
54948
55084
 
54949
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
55085
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
54950
55086
  class RuleEngine {
54951
55087
  host;
54952
55088
  events;
@@ -55117,7 +55253,7 @@ var init_engine = __esm(() => {
55117
55253
  init_types2();
55118
55254
  });
55119
55255
 
55120
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
55256
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
55121
55257
  async function bundledRulesRoot() {
55122
55258
  if (cachedRoot2 !== undefined)
55123
55259
  return cachedRoot2;
@@ -55168,7 +55304,7 @@ var init_bundled_rules = __esm(() => {
55168
55304
  init_dist3();
55169
55305
  });
55170
55306
 
55171
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
55307
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
55172
55308
  class DbRulePersistenceAdapter {
55173
55309
  db;
55174
55310
  constructor(db2) {
@@ -55202,7 +55338,7 @@ class DbRulePersistenceAdapter {
55202
55338
  }
55203
55339
  }
55204
55340
 
55205
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
55341
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
55206
55342
  var RULE_ENGINE_SCHEMA_SQL = `
55207
55343
  CREATE TABLE IF NOT EXISTS rule_runs (
55208
55344
  id TEXT PRIMARY KEY,
@@ -55248,10 +55384,10 @@ CREATE TABLE IF NOT EXISTS rule_eval_runs (
55248
55384
  CREATE INDEX IF NOT EXISTS idx_rule_eval_runs_run_id ON rule_eval_runs (run_id);
55249
55385
  `;
55250
55386
 
55251
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
55387
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
55252
55388
  var init_persistence2 = () => {};
55253
55389
 
55254
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.2+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
55390
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.3+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
55255
55391
  var init_dist9 = __esm(() => {
55256
55392
  init_extensions();
55257
55393
  init_loader2();
@@ -55329,8 +55465,12 @@ async function applyCliMigrations(adapter, migrations = CLI_MIGRATIONS) {
55329
55465
  const existing = await adapter.queryFirst('SELECT id FROM "__spur_cli_migrations" WHERE id = ?', migration.id);
55330
55466
  if (existing != null)
55331
55467
  continue;
55332
- for (const statement of splitSqlStatements(migration.sql)) {
55333
- await adapter.exec(statement);
55468
+ const addColumnGuard = migration.addColumnIfMissing ?? builtInAddColumnGuard(migration.id);
55469
+ const shouldApplySql = addColumnGuard === undefined || !await columnExists(adapter, addColumnGuard.table, addColumnGuard.column);
55470
+ if (shouldApplySql) {
55471
+ for (const statement of splitSqlStatements(migration.sql)) {
55472
+ await adapter.exec(statement);
55473
+ }
55334
55474
  }
55335
55475
  await adapter.run('INSERT INTO "__spur_cli_migrations" (id, applied_at) VALUES (?, ?)', migration.id, Date.now());
55336
55476
  applied += 1;
@@ -55348,6 +55488,15 @@ async function loadSqlMigrations(folder) {
55348
55488
  }
55349
55489
  return migrations.length > 0 ? migrations : CLI_MIGRATIONS;
55350
55490
  }
55491
+ async function columnExists(adapter, table3, column2) {
55492
+ const rows = await adapter.queryAll(`PRAGMA table_info("${table3}")`);
55493
+ return rows.some((row) => row.name === column2);
55494
+ }
55495
+ function builtInAddColumnGuard(id) {
55496
+ if (id === "0007_spur_cli_runs_external_key")
55497
+ return { table: "runs", column: "external_key" };
55498
+ return;
55499
+ }
55351
55500
  function splitSqlStatements(sql4) {
55352
55501
  return sql4.split(";").map((statement) => statement.trim()).filter(Boolean);
55353
55502
  }
@@ -55384,8 +55533,21 @@ CREATE TABLE IF NOT EXISTS queue_jobs (
55384
55533
  );
55385
55534
 
55386
55535
  CREATE INDEX IF NOT EXISTS queue_jobs_ready_idx ON queue_jobs (status, next_retry_at, created_at);
55536
+ `, SYSTEM_EVENTS_SCHEMA_SQL = `
55537
+ CREATE TABLE IF NOT EXISTS system_events (
55538
+ id TEXT PRIMARY KEY,
55539
+ event_name TEXT NOT NULL,
55540
+ occurred_at TEXT NOT NULL,
55541
+ actor TEXT,
55542
+ payload_json TEXT
55543
+ );
55544
+
55545
+ CREATE INDEX IF NOT EXISTS idx_system_events_occurred_at ON system_events (occurred_at);
55546
+ CREATE INDEX IF NOT EXISTS idx_system_events_event_name ON system_events (event_name);
55387
55547
  `, CLI_SCHEMA_SQL, RUN_PID_COLUMN_SCHEMA_SQL = `
55388
55548
  ALTER TABLE runs ADD COLUMN pid INTEGER;
55549
+ `, RUNS_EXTERNAL_KEY_COLUMN_SCHEMA_SQL = `
55550
+ ALTER TABLE runs ADD COLUMN external_key TEXT;
55389
55551
  `, CLI_MIGRATIONS, CLI_MIGRATION_FILE_MARKER = "_spur_cli_";
55390
55552
  var init_migrations = __esm(() => {
55391
55553
  init_dist7();
@@ -55406,6 +55568,8 @@ ${RULE_ENGINE_SCHEMA_SQL}
55406
55568
  ${INBOX_MESSAGES_SCHEMA_SQL}
55407
55569
 
55408
55570
  ${QUEUE_JOBS_SCHEMA_SQL}
55571
+
55572
+ ${SYSTEM_EVENTS_SCHEMA_SQL}
55409
55573
  `;
55410
55574
  CLI_MIGRATIONS = [
55411
55575
  { id: "0000_spur_cli_foundation", sql: CLI_SCHEMA_SQL },
@@ -55413,11 +55577,17 @@ ${QUEUE_JOBS_SCHEMA_SQL}
55413
55577
  { id: "0002_spur_cli_rule_history", sql: RULE_ENGINE_SCHEMA_SQL },
55414
55578
  { id: "0003_spur_cli_planning", sql: PLANNING_SCHEMA_SQL },
55415
55579
  { id: "0004_spur_cli_queue_jobs", sql: QUEUE_JOBS_SCHEMA_SQL },
55416
- { id: "0005_spur_cli_run_pid", sql: RUN_PID_COLUMN_SCHEMA_SQL }
55580
+ { id: "0005_spur_cli_run_pid", sql: RUN_PID_COLUMN_SCHEMA_SQL },
55581
+ { id: "0006_spur_cli_system_events", sql: SYSTEM_EVENTS_SCHEMA_SQL },
55582
+ {
55583
+ id: "0007_spur_cli_runs_external_key",
55584
+ sql: RUNS_EXTERNAL_KEY_COLUMN_SCHEMA_SQL,
55585
+ addColumnIfMissing: { table: "runs", column: "external_key" }
55586
+ }
55417
55587
  ];
55418
55588
  });
55419
55589
 
55420
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
55590
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
55421
55591
  function queueLogger() {
55422
55592
  if (!_queueLogger)
55423
55593
  _queueLogger = getLogger2("job-queue");
@@ -55627,7 +55797,7 @@ var init_db_job_queue = __esm(() => {
55627
55797
  init_tracing2();
55628
55798
  });
55629
55799
 
55630
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
55800
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
55631
55801
  var exports_job_queue_db = {};
55632
55802
  __export(exports_job_queue_db, {
55633
55803
  DBQueueConsumer: () => DBQueueConsumer,
@@ -56205,6 +56375,10 @@ function normalizeTaskStatus(raw) {
56205
56375
  }
56206
56376
  return resolved;
56207
56377
  }
56378
+ function normalizeTaskStatusSafe(raw) {
56379
+ const key = raw.trim().toLowerCase();
56380
+ return TASK_STATUS_ALIASES[key] ?? "todo";
56381
+ }
56208
56382
  function normalizeFeatureStatus(raw) {
56209
56383
  const key = raw.trim().toLowerCase();
56210
56384
  const resolved = FEATURE_STATUS_ALIASES[key];
@@ -56447,6 +56621,7 @@ __export(exports_src, {
56447
56621
  parseFeature: () => parseFeature,
56448
56622
  parseChecklist: () => parseChecklist,
56449
56623
  normalizeTitle: () => normalizeTitle,
56624
+ normalizeTaskStatusSafe: () => normalizeTaskStatusSafe,
56450
56625
  normalizeTaskStatus: () => normalizeTaskStatus,
56451
56626
  normalizeFeatureStatus: () => normalizeFeatureStatus,
56452
56627
  matrixEntrySchema: () => matrixEntrySchema,
@@ -56488,6 +56663,8 @@ __export(exports_src, {
56488
56663
  TASK_STATUS_ICONS: () => TASK_STATUS_ICONS,
56489
56664
  TASK_STATUSES: () => TASK_STATUSES,
56490
56665
  TASK_CANONICAL_SECTIONS: () => TASK_CANONICAL_SECTIONS,
56666
+ SystemEventDao: () => SystemEventDao,
56667
+ SYSTEM_EVENTS_SCHEMA_SQL: () => SYSTEM_EVENTS_SCHEMA_SQL,
56491
56668
  SECTION_GUIDANCE: () => SECTION_GUIDANCE,
56492
56669
  RunDao: () => RunDao,
56493
56670
  RuleRunDao: () => RuleRunDao,
@@ -56499,6 +56676,7 @@ __export(exports_src, {
56499
56676
  PRIORITIES: () => PRIORITIES,
56500
56677
  MarkdownDocument: () => MarkdownDocument,
56501
56678
  MODEL_PRICING: () => MODEL_PRICING,
56679
+ InboxRecentDao: () => InboxRecentDao,
56502
56680
  InboxMessageDao: () => InboxMessageDao,
56503
56681
  INBOX_MESSAGES_SCHEMA_SQL: () => INBOX_MESSAGES_SCHEMA_SQL,
56504
56682
  FEATURE_STATUS_ICONS: () => FEATURE_STATUS_ICONS,
@@ -56579,12 +56757,18 @@ function applyM3(data, flags) {
56579
56757
  function applyM4(data) {
56580
56758
  delete data.impl_progress;
56581
56759
  delete data.folder;
56760
+ if (data.description === null) {
56761
+ data.description = "";
56762
+ }
56582
56763
  if (data.description !== undefined && data.name !== undefined && String(data.description) === String(data.name)) {
56583
56764
  delete data.description;
56584
56765
  }
56585
56766
  }
56586
56767
  function applyM5(data, wbsFromFile, flags) {
56587
- if (data.parent_wbs !== undefined)
56768
+ if (typeof data.parent_wbs === "number" && Number.isFinite(data.parent_wbs)) {
56769
+ data.parent_wbs = String(data.parent_wbs).padStart(4, "0");
56770
+ }
56771
+ if (data.parent_wbs !== undefined && data.parent_wbs !== null)
56588
56772
  return;
56589
56773
  let resolved;
56590
56774
  const parentId = data.parent_id;
@@ -56697,13 +56881,19 @@ function serializeFrontmatter(data) {
56697
56881
  if (!(key in data))
56698
56882
  continue;
56699
56883
  const value = data[key];
56700
- if (value === undefined || value === null)
56884
+ if (value === undefined)
56701
56885
  continue;
56702
- if (Array.isArray(value)) {
56703
- if (value.length === 0)
56704
- continue;
56705
- const items = value.map((v) => yamlScalar(v)).join(",");
56706
- lines.push(`${key}: [${items}]`);
56886
+ if (value === null && !NULL_PRESERVING_KEYS.has(key))
56887
+ continue;
56888
+ if (value === null) {
56889
+ lines.push(`${key}: null`);
56890
+ } else if (Array.isArray(value)) {
56891
+ if (value.length === 0) {
56892
+ lines.push(`${key}: []`);
56893
+ } else {
56894
+ const items = value.map((v) => yamlScalar(v)).join(",");
56895
+ lines.push(`${key}: [${items}]`);
56896
+ }
56707
56897
  } else if (typeof value !== "object") {
56708
56898
  lines.push(`${key}: ${yamlScalar(value)}`);
56709
56899
  }
@@ -56714,8 +56904,12 @@ function serializeFrontmatter(data) {
56714
56904
  `);
56715
56905
  }
56716
56906
  function yamlScalar(value) {
56907
+ if (typeof value === "number")
56908
+ return String(value);
56717
56909
  const str = String(value);
56718
- if (str.includes(": ") || str.startsWith("#") || str.startsWith(" ") || str.endsWith(" ")) {
56910
+ const looksNumeric = /^\d+$/.test(str);
56911
+ const looksBoolish = /^(yes|no|on|off|true|false|null)$/i.test(str);
56912
+ if (str === "" || looksNumeric || looksBoolish || str.includes(": ") || str.startsWith("#") || str.startsWith(" ") || str.endsWith(" ")) {
56719
56913
  return JSON.stringify(str);
56720
56914
  }
56721
56915
  return str;
@@ -56908,7 +57102,7 @@ class CorpusMigrator {
56908
57102
  };
56909
57103
  }
56910
57104
  }
56911
- var PRIORITY_MAP, FIELD_ORDER;
57105
+ var PRIORITY_MAP, FIELD_ORDER, NULL_PRESERVING_KEYS;
56912
57106
  var init_corpus_migrator = __esm(() => {
56913
57107
  init_src();
56914
57108
  init_src2();
@@ -56926,6 +57120,7 @@ var init_corpus_migrator = __esm(() => {
56926
57120
  low: "P3"
56927
57121
  };
56928
57122
  FIELD_ORDER = [
57123
+ "template",
56929
57124
  "schema_version",
56930
57125
  "name",
56931
57126
  "description",
@@ -56940,6 +57135,7 @@ var init_corpus_migrator = __esm(() => {
56940
57135
  "created_at",
56941
57136
  "updated_at"
56942
57137
  ];
57138
+ NULL_PRESERVING_KEYS = new Set(["parent_wbs"]);
56943
57139
  });
56944
57140
 
56945
57141
  // ../../packages/app/src/services/planning-check-base.ts
@@ -57828,6 +58024,51 @@ var init_history_service = __esm(() => {
57828
58024
  MODES = ["full", "incremental", "force-file"];
57829
58025
  });
57830
58026
 
58027
+ // ../../packages/app/src/services/job-worker-service.ts
58028
+ class JobHandlerRegistry {
58029
+ handlers = new Map;
58030
+ register(kind, handler) {
58031
+ this.handlers.set(kind, handler);
58032
+ return this;
58033
+ }
58034
+ applyTo(consumer) {
58035
+ for (const [kind, handler] of this.handlers) {
58036
+ consumer.register(kind, handler);
58037
+ }
58038
+ }
58039
+ size() {
58040
+ return this.handlers.size;
58041
+ }
58042
+ }
58043
+
58044
+ class JobWorkerService {
58045
+ options;
58046
+ started = false;
58047
+ constructor(options) {
58048
+ this.options = options;
58049
+ }
58050
+ async start() {
58051
+ if (this.started)
58052
+ return;
58053
+ this.options.registry?.applyTo(this.options.consumer);
58054
+ await this.options.consumer.start();
58055
+ this.started = true;
58056
+ }
58057
+ async stop() {
58058
+ if (!this.started)
58059
+ return;
58060
+ await this.options.consumer.stop();
58061
+ this.started = false;
58062
+ }
58063
+ async processOnce() {
58064
+ this.options.registry?.applyTo(this.options.consumer);
58065
+ return this.options.consumer.processOnce();
58066
+ }
58067
+ stats() {
58068
+ return this.options.consumer.stats();
58069
+ }
58070
+ }
58071
+
57831
58072
  // ../../packages/app/src/services/planning-events.ts
57832
58073
  class BusPlanningEventEmitter {
57833
58074
  bus;
@@ -58582,6 +58823,179 @@ var init_rule_service = __esm(() => {
58582
58823
  };
58583
58824
  });
58584
58825
 
58826
+ // ../../packages/app/src/services/supervisor-service.ts
58827
+ function defaultWrapperArgv(agentId) {
58828
+ return {
58829
+ command: process.execPath,
58830
+ args: [process.argv[1] ?? "apps/cli/src/index.ts", "agent", "run", "--agent", agentId, "--drain", "--continue"]
58831
+ };
58832
+ }
58833
+
58834
+ class SupervisorService {
58835
+ processExecutor;
58836
+ eventBus;
58837
+ configDir;
58838
+ ringBufferSize;
58839
+ processes = new Map;
58840
+ ringBuffers = new Map;
58841
+ specsPromise;
58842
+ constructor(options) {
58843
+ this.processExecutor = options.processExecutor;
58844
+ this.eventBus = options.eventBus;
58845
+ this.configDir = options.configDir;
58846
+ this.ringBufferSize = options.ringBufferSize ?? DEFAULT_RING_BUFFER_SIZE;
58847
+ if (options.agentSpecs) {
58848
+ this.specsPromise = Promise.resolve(options.agentSpecs);
58849
+ }
58850
+ }
58851
+ list() {
58852
+ return Array.from(this.processes.values()).map((p) => p.entry);
58853
+ }
58854
+ get(agentId) {
58855
+ return this.processes.get(agentId)?.entry;
58856
+ }
58857
+ getRingBuffer(agentId) {
58858
+ return this.ringBuffers.get(agentId) ?? [];
58859
+ }
58860
+ writeStdin(agentId, line) {
58861
+ const proc = this.processes.get(agentId);
58862
+ if (proc?.entry.status !== "running") {
58863
+ throw new Error(`Agent "${agentId}" is not running`);
58864
+ }
58865
+ proc.handle.writeStdin(`${line}
58866
+ `);
58867
+ }
58868
+ async start(agentId) {
58869
+ const existing = this.processes.get(agentId);
58870
+ if (existing && existing.entry.status === "running") {
58871
+ return existing.entry;
58872
+ }
58873
+ const specs = await this.loadSpecs();
58874
+ const spec = specs.find((s) => s.id === agentId);
58875
+ if (!spec) {
58876
+ throw new Error(`No agent spec found for "${agentId}"`);
58877
+ }
58878
+ const { command, args } = this.resolveCommand(spec);
58879
+ const frames = [];
58880
+ this.ringBuffers.set(agentId, frames);
58881
+ const pipeOpts = {
58882
+ command,
58883
+ args,
58884
+ label: `agent:${agentId}`,
58885
+ env: Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined))
58886
+ };
58887
+ const handle = this.processExecutor.runStreaming(pipeOpts);
58888
+ const pid = handle.pid;
58889
+ const entry = {
58890
+ agentId,
58891
+ pid,
58892
+ status: "running",
58893
+ startedAt: new Date().toISOString(),
58894
+ ringBuffer: frames
58895
+ };
58896
+ this.processes.set(agentId, { handle, entry });
58897
+ this.pipeStream(handle.stdout, "stdout", agentId, frames);
58898
+ this.pipeStream(handle.stderr, "stderr", agentId, frames);
58899
+ this.emit("process.spawned", { agentId, pid });
58900
+ handle.exited.then((code) => {
58901
+ entry.status = "exited";
58902
+ entry.exitCode = code;
58903
+ const keepForMs = 60000;
58904
+ setTimeout(() => {
58905
+ if (this.processes.get(agentId)?.entry === entry) {
58906
+ this.processes.delete(agentId);
58907
+ }
58908
+ }, keepForMs);
58909
+ this.emit("process.exited", { agentId, pid, exitCode: code });
58910
+ });
58911
+ return entry;
58912
+ }
58913
+ async stop(agentId) {
58914
+ const proc = this.processes.get(agentId);
58915
+ if (proc?.entry.status !== "running")
58916
+ return;
58917
+ proc.handle.kill("SIGTERM");
58918
+ let timedOut = false;
58919
+ const exitPromise = proc.handle.exited;
58920
+ const timeout = new Promise((resolve2) => {
58921
+ setTimeout(() => {
58922
+ timedOut = true;
58923
+ resolve2();
58924
+ }, 3000);
58925
+ });
58926
+ await Promise.race([exitPromise, timeout]);
58927
+ if (timedOut) {
58928
+ proc.handle.kill("SIGKILL");
58929
+ await proc.handle.exited.catch(() => {});
58930
+ }
58931
+ proc.entry.status = "stopped";
58932
+ this.emit("process.stopped", { agentId, pid: proc.entry.pid });
58933
+ }
58934
+ async startAutostart(ids) {
58935
+ const results = [];
58936
+ const specs = await this.loadSpecs();
58937
+ const specIds = new Set(specs.map((s) => s.id));
58938
+ for (const id of ids) {
58939
+ if (!specIds.has(id)) {
58940
+ throw new Error(`Autostart agent "${id}" not found \u2014 check .spur/agents/ and team.autostart config`);
58941
+ }
58942
+ }
58943
+ for (const id of ids) {
58944
+ results.push(await this.start(id));
58945
+ }
58946
+ return results;
58947
+ }
58948
+ async stopAll() {
58949
+ const running = Array.from(this.processes.keys()).filter((id) => this.processes.get(id)?.entry.status === "running");
58950
+ await Promise.all(running.map((id) => this.stop(id)));
58951
+ }
58952
+ async loadSpecs() {
58953
+ this.specsPromise ??= Promise.resolve().then(() => (init_dist6(), exports_dist3)).then((m) => m.loadAgentSpecs(this.configDir));
58954
+ return this.specsPromise;
58955
+ }
58956
+ resolveCommand(spec) {
58957
+ const raw = spec.command;
58958
+ if (raw && raw.length > 0) {
58959
+ return { command: raw[0] ?? "", args: raw.slice(1) };
58960
+ }
58961
+ return defaultWrapperArgv(spec.id);
58962
+ }
58963
+ pipeStream(stream, name, _agentId, frames) {
58964
+ if (!stream)
58965
+ return;
58966
+ const reader = stream.getReader();
58967
+ const decoder = new TextDecoder;
58968
+ let partial2 = "";
58969
+ const pump = () => {
58970
+ reader.read().then(({ done, value }) => {
58971
+ if (done)
58972
+ return;
58973
+ partial2 += decoder.decode(value, { stream: true });
58974
+ const lines = partial2.split(`
58975
+ `);
58976
+ partial2 = lines.pop() ?? "";
58977
+ for (const line of lines) {
58978
+ this.pushFrame(frames, { stream: name, ts: new Date().toISOString(), line });
58979
+ }
58980
+ pump();
58981
+ });
58982
+ };
58983
+ pump();
58984
+ }
58985
+ pushFrame(frames, frame) {
58986
+ frames.push(frame);
58987
+ if (frames.length > this.ringBufferSize) {
58988
+ frames.splice(0, frames.length - this.ringBufferSize);
58989
+ }
58990
+ }
58991
+ emit(name, payload) {
58992
+ try {
58993
+ this.eventBus.emit(name, payload);
58994
+ } catch {}
58995
+ }
58996
+ }
58997
+ var DEFAULT_RING_BUFFER_SIZE = 500;
58998
+
58585
58999
  // ../../packages/app/src/services/task-check.ts
58586
59000
  import { dirname as dirname7, join as join8 } from "path";
58587
59001
  function isPlaceholderBody(body) {
@@ -58688,6 +59102,9 @@ var init_task_check = __esm(() => {
58688
59102
  const featuresDir = join8(dirname7(tasksDir), "features");
58689
59103
  await this.runL4(doc2, fm, findings, featuresDir, tasksDir);
58690
59104
  await this.runL4Rollup(doc2, wbs, status, findings, tasksDir);
59105
+ if (status !== "done" && status !== "cancelled") {
59106
+ await this.runL4Readiness(doc2, fm, wbs, status, findings, tasksDir);
59107
+ }
58691
59108
  return { wbs, ...this.summarizeWithStatus(status, findings, strict) };
58692
59109
  }
58693
59110
  runL3(doc2, entry, status, findings) {
@@ -58879,6 +59296,124 @@ var init_task_check = __esm(() => {
58879
59296
  return false;
58880
59297
  return kids.some((c3) => planBody.includes(c3.wbs));
58881
59298
  }
59299
+ async runL4Readiness(doc2, fm, wbs, status, findings, tasksDir) {
59300
+ if (status === "blocked") {
59301
+ findings.push({
59302
+ layer: "L4",
59303
+ severity: "warning",
59304
+ section: "",
59305
+ message: `Task ${wbs} is blocked \u2014 readiness is false until the blocker is resolved or explicitly forced`
59306
+ });
59307
+ }
59308
+ const declaredDeps = this.extractDependencyWbs(fm.dependencies);
59309
+ const proseDeps = this.extractProsePrerequisites(doc2);
59310
+ for (const dep of proseDeps) {
59311
+ if (!declaredDeps.includes(dep.wbs)) {
59312
+ findings.push({
59313
+ layer: "L4",
59314
+ severity: "warning",
59315
+ section: dep.section,
59316
+ message: `Prose prerequisite ${dep.wbs} is not mirrored in frontmatter dependencies[]`
59317
+ });
59318
+ }
59319
+ }
59320
+ const directDeps = [...new Set([...declaredDeps, ...proseDeps.map((d) => d.wbs)])].filter((dep) => dep !== wbs);
59321
+ for (const depWbs of directDeps) {
59322
+ await this.checkDependencyReadiness(depWbs, wbs, findings, tasksDir, new Set([wbs]), false);
59323
+ }
59324
+ this.checkGateLanguage(doc2, findings);
59325
+ }
59326
+ extractDependencyWbs(raw) {
59327
+ if (!Array.isArray(raw))
59328
+ return [];
59329
+ const deps = [];
59330
+ for (const item of raw) {
59331
+ if (typeof item !== "string")
59332
+ continue;
59333
+ const match = /^(\d{4})/.exec(item.trim());
59334
+ if (match?.[1] !== undefined)
59335
+ deps.push(match[1]);
59336
+ }
59337
+ return deps;
59338
+ }
59339
+ extractProsePrerequisites(doc2) {
59340
+ const refs = [];
59341
+ for (const section of ["Background", "Requirements", "Design", "Acceptance Criteria", "Plan"]) {
59342
+ const body = doc2.getSection(section);
59343
+ if (body === null)
59344
+ continue;
59345
+ for (const line of body.split(`
59346
+ `)) {
59347
+ const isPrereq = /\b(depends on|gated on|blocked by|after|requires|waiting for|merged|approved|approval|HITL)\b/i.test(line) || /\b(pre-gate|post-gate|content-gate|capstone)\b/i.test(line);
59348
+ if (!isPrereq)
59349
+ continue;
59350
+ for (const match of line.matchAll(/\b(\d{4})\b/g)) {
59351
+ const wbs = match[1];
59352
+ if (wbs !== undefined)
59353
+ refs.push({ wbs, section });
59354
+ }
59355
+ }
59356
+ }
59357
+ return refs;
59358
+ }
59359
+ async checkDependencyReadiness(depWbs, rootWbs, findings, tasksDir, seen, transitive) {
59360
+ if (seen.has(depWbs)) {
59361
+ findings.push({
59362
+ layer: "L4",
59363
+ severity: "warning",
59364
+ section: "",
59365
+ message: `Prerequisite cycle detected while checking ${rootWbs}: ${[...seen, depWbs].join(" -> ")}`
59366
+ });
59367
+ return;
59368
+ }
59369
+ const dep = await this.readTaskSnapshot(tasksDir, depWbs);
59370
+ if (dep === null)
59371
+ return;
59372
+ if (dep.status !== "done") {
59373
+ findings.push({
59374
+ layer: "L4",
59375
+ severity: "warning",
59376
+ section: "",
59377
+ message: `${transitive ? "Transitive prerequisite" : "Prerequisite"} ${depWbs} is ${dep.status}; task ${rootWbs} is not ready until it is done`
59378
+ });
59379
+ }
59380
+ const nextSeen = new Set(seen);
59381
+ nextSeen.add(depWbs);
59382
+ for (const childDep of dep.dependencies) {
59383
+ await this.checkDependencyReadiness(childDep, rootWbs, findings, tasksDir, nextSeen, true);
59384
+ }
59385
+ }
59386
+ checkGateLanguage(doc2, findings) {
59387
+ for (const section of ["Background", "Requirements", "Design", "Acceptance Criteria", "Plan"]) {
59388
+ const body = doc2.getSection(section);
59389
+ if (body === null)
59390
+ continue;
59391
+ if (/\b(HITL|human[- ]in[- ]the[- ]loop|approval|approved|merge event|merged|content-gate|GATED|capstone)\b/i.test(body)) {
59392
+ findings.push({
59393
+ layer: "L4",
59394
+ severity: "warning",
59395
+ section,
59396
+ message: `${section} contains gate language; model the gate as a frontmatter dependency or verify it before treating the task as ready`
59397
+ });
59398
+ }
59399
+ }
59400
+ }
59401
+ async readTaskSnapshot(tasksDir, wbs) {
59402
+ const path8 = await this.findTaskFile(tasksDir, wbs);
59403
+ if (path8 === null)
59404
+ return null;
59405
+ try {
59406
+ const raw = await this.fs.readFile(path8);
59407
+ const fm = MarkdownDocument.parse(raw, "task").frontmatterData ?? {};
59408
+ return {
59409
+ wbs,
59410
+ status: fm.status ?? "backlog",
59411
+ dependencies: this.extractDependencyWbs(fm.dependencies)
59412
+ };
59413
+ } catch {
59414
+ return null;
59415
+ }
59416
+ }
58882
59417
  async findChildren(tasksDir, wbs) {
58883
59418
  const kids = [];
58884
59419
  let entries;
@@ -59158,7 +59693,7 @@ function gitDiffU0(cwd) {
59158
59693
  var init_task_record = () => {};
59159
59694
 
59160
59695
  // ../../packages/app/src/services/task-service.ts
59161
- import { dirname as dirname8, isAbsolute, relative as relative2, resolve as resolve2 } from "path";
59696
+ import { isAbsolute, relative as relative2, resolve as resolve2 } from "path";
59162
59697
  function patchFrontmatterField(rendered, key, value) {
59163
59698
  const existingRe = new RegExp(`^(?=\\s*${escapeRegex2(key)}:)`, "m");
59164
59699
  if (existingRe.test(rendered)) {
@@ -59188,6 +59723,9 @@ function renderRosterTable(rows) {
59188
59723
  return `${header}
59189
59724
  ${body}`;
59190
59725
  }
59726
+ function isTaskActionName(action) {
59727
+ return Object.hasOwn(TASK_ACTION_COMMANDS, action);
59728
+ }
59191
59729
  function bulletizeRequirements(raw) {
59192
59730
  const text4 = raw.trim();
59193
59731
  if (text4 === "")
@@ -59333,7 +59871,16 @@ class TaskService {
59333
59871
  }
59334
59872
  async fulfillAction(wbs, action, enqueue, options) {
59335
59873
  await this.resolveTaskFile(wbs);
59336
- const runId = await enqueue({ wbs, action, channel: options?.channel, skipDeps: options?.skipDeps });
59874
+ if (!isTaskActionName(action)) {
59875
+ throw new Error(`Unsupported task action: ${action}`);
59876
+ }
59877
+ const runId = await enqueue({
59878
+ wbs,
59879
+ action,
59880
+ command: TASK_ACTION_COMMANDS[action](wbs),
59881
+ channel: options?.channel,
59882
+ skipDeps: options?.skipDeps
59883
+ });
59337
59884
  return { runId, action, status: "queued" };
59338
59885
  }
59339
59886
  async updateSection(wbs, sectionName, sourceFile) {
@@ -59527,85 +60074,13 @@ ${issues}`);
59527
60074
  });
59528
60075
  }
59529
60076
  async refresh() {
59530
- const folders = this.ctx.foldersConfig ? [...new Set([this.ctx.tasksDir, ...Object.keys(this.ctx.foldersConfig.folders)])] : [this.ctx.tasksDir];
59531
- let activeKanban = "";
60077
+ const folders = this.allFolderDirs();
60078
+ let totalTasks = 0;
59532
60079
  for (const folder of folders) {
59533
60080
  const tasks = await this.list({ folder });
59534
- const kanban = this.renderKanban(tasks);
59535
- await this.ctx.fs.writeFile(`${folder}/kanban.md`, kanban);
59536
- if (folder === this.ctx.tasksDir)
59537
- activeKanban = kanban;
59538
- }
59539
- return activeKanban;
59540
- }
59541
- renderKanban(tasks) {
59542
- const statusOrder = {};
59543
- TASK_STATUSES.forEach((s, i2) => {
59544
- statusOrder[s] = i2;
59545
- });
59546
- const byStatus = new Map;
59547
- for (const t of tasks) {
59548
- const status = t.status in statusOrder ? t.status : "backlog";
59549
- const group = byStatus.get(status);
59550
- if (group) {
59551
- group.push(t);
59552
- } else {
59553
- byStatus.set(status, [t]);
59554
- }
59555
- }
59556
- const sortedStatuses = [...byStatus.keys()].sort((a2, b) => {
59557
- const oa = statusOrder[a2] ?? 99;
59558
- const ob = statusOrder[b] ?? 99;
59559
- return oa - ob;
59560
- });
59561
- const lines = ["# Kanban", "", "> Auto-generated by `spur task refresh`. Do not edit.", ""];
59562
- for (const status of sortedStatuses) {
59563
- const group = byStatus.get(status);
59564
- if (!group || group.length === 0)
59565
- continue;
59566
- const displayStatus = status.charAt(0).toUpperCase() + status.slice(1);
59567
- lines.push(`## ${displayStatus}`, "");
59568
- const unparented = [];
59569
- const byParent = new Map;
59570
- for (const t of group) {
59571
- const parentWbs = t.frontmatter.parent_wbs;
59572
- if (parentWbs) {
59573
- const pg = byParent.get(parentWbs);
59574
- if (pg) {
59575
- pg.push(t);
59576
- } else {
59577
- byParent.set(parentWbs, [t]);
59578
- }
59579
- } else {
59580
- unparented.push(t);
59581
- }
59582
- }
59583
- for (const t of unparented.sort((a2, b) => a2.wbs.localeCompare(b.wbs))) {
59584
- const name = t.frontmatter.name ?? t.name;
59585
- lines.push(`- [${t.wbs}](${this.relativePath(t.filePath)}) ${name}`);
59586
- }
59587
- const sortedParents = [...byParent.keys()].sort();
59588
- for (const parentWbs of sortedParents) {
59589
- const children = byParent.get(parentWbs);
59590
- if (!children)
59591
- continue;
59592
- lines.push(`- **${parentWbs}**`);
59593
- for (const t of children.sort((a2, b) => a2.wbs.localeCompare(b.wbs))) {
59594
- const name = t.frontmatter.name ?? t.name;
59595
- lines.push(` - [${t.wbs}](${this.relativePath(t.filePath)}) ${name}`);
59596
- }
59597
- }
59598
- lines.push("");
59599
- }
59600
- return lines.join(`
59601
- `);
59602
- }
59603
- relativePath(filePath) {
59604
- const prefix = this.ctx.tasksDir;
59605
- if (filePath.startsWith(prefix)) {
59606
- return filePath.slice(prefix.length).replace(/^\//, "");
60081
+ totalTasks += tasks.length;
59607
60082
  }
59608
- return filePath;
60083
+ return { folders: folders.length, tasks: totalTasks };
59609
60084
  }
59610
60085
  async refreshRoster(wbs) {
59611
60086
  const filePath = await this.resolveTaskFile(wbs);
@@ -59801,23 +60276,31 @@ ${block}` : block);
59801
60276
  resolveListDir(folder) {
59802
60277
  if (folder === undefined)
59803
60278
  return this.ctx.tasksDir;
59804
- const root = resolve2(dirname8(this.ctx.tasksDir));
59805
- const candidate = resolve2(root, folder);
60279
+ const root = this.ctx.fs.resolve(".");
60280
+ const candidate = this.ctx.fs.resolve(folder);
59806
60281
  const rel = relative2(root, candidate);
59807
60282
  if (rel.startsWith("..") || isAbsolute(rel)) {
59808
60283
  throw new Error(`Invalid folder: ${folder} escapes the planning workspace`);
59809
60284
  }
59810
- return folder;
60285
+ return candidate;
59811
60286
  }
59812
60287
  slugify(title) {
59813
60288
  return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
59814
60289
  }
59815
60290
  }
59816
- var ROSTER_START = "<!-- AUTO-GENERATED by spur task refresh-roster -->", ROSTER_END = "<!-- END AUTO-GENERATED -->", ROSTER_REGION_RE, DEFAULT_CREATION_SECTIONS;
60291
+ var ROSTER_START = "<!-- AUTO-GENERATED by spur task refresh-roster -->", ROSTER_END = "<!-- END AUTO-GENERATED -->", ROSTER_REGION_RE, TASK_ACTION_COMMANDS, DEFAULT_CREATION_SECTIONS;
59817
60292
  var init_task_service = __esm(() => {
59818
60293
  init_src2();
59819
60294
  init_task_record();
59820
60295
  ROSTER_REGION_RE = /<!--[ \t]*AUTO-GENERATED[^>]*-->[\s\S]*?<!--[ \t]*END[ \t]*AUTO-GENERATED[^>]*-->/g;
60296
+ TASK_ACTION_COMMANDS = {
60297
+ refine: (wbs) => `/sp:dev-refine ${wbs} --auto`,
60298
+ plan: (wbs) => `/sp:dev-plan ${wbs} --auto`,
60299
+ run: (wbs) => `/sp:dev-run ${wbs} --auto`,
60300
+ verify: (wbs) => `/sp:dev-verify ${wbs} --auto`,
60301
+ decompose: (wbs) => `/sp:dev-plan "Decompose task ${wbs} into implementation subtasks" --auto`,
60302
+ evaluate: (wbs) => `/sp:dev-review ${wbs} --auto`
60303
+ };
59821
60304
  DEFAULT_CREATION_SECTIONS = {
59822
60305
  backlog: ["Background"],
59823
60306
  todo: ["Background", "Requirements", "Acceptance Criteria", "Q&A", "Design", "Plan"]
@@ -60029,6 +60512,13 @@ class TeamService {
60029
60512
  validateAgentId(fromId);
60030
60513
  const dao2 = await this.inboxDao();
60031
60514
  const msgId = await dao2.enqueue(fromId, toId, body, replyTo);
60515
+ this.emitMessageEvent(replyTo !== undefined ? "message.replied" : "message.sent", {
60516
+ msgId,
60517
+ fromId,
60518
+ toId,
60519
+ threadId: replyTo ?? null,
60520
+ createdAt: new Date().toISOString()
60521
+ });
60032
60522
  return { msgId, toId, status: "queued", injected: false };
60033
60523
  }
60034
60524
  async getInbox(agentId, limit, offset) {
@@ -60047,6 +60537,22 @@ class TeamService {
60047
60537
  count: rows.length
60048
60538
  };
60049
60539
  }
60540
+ async listRecent(limit = 50) {
60541
+ const dao2 = await this.inboxRecentDao();
60542
+ const rows = await dao2.listRecent(limit);
60543
+ return {
60544
+ messages: rows.map((row) => ({
60545
+ id: row.id,
60546
+ fromId: row.from_id,
60547
+ toId: row.to_id,
60548
+ body: row.body,
60549
+ status: row.status,
60550
+ createdAt: new Date(row.created_at).toISOString(),
60551
+ inReplyTo: row.in_reply_to
60552
+ })),
60553
+ count: rows.length
60554
+ };
60555
+ }
60050
60556
  async replyToMessage(msgId, body) {
60051
60557
  const dao2 = await this.inboxDao();
60052
60558
  const original = await dao2.getById(msgId);
@@ -60135,6 +60641,18 @@ class TeamService {
60135
60641
  const db2 = await this.ctx.getDb();
60136
60642
  return new InboxMessageDao(db2);
60137
60643
  }
60644
+ emitMessageEvent(name, payload) {
60645
+ const bus = this.ctx.eventBus;
60646
+ if (!bus)
60647
+ return;
60648
+ try {
60649
+ bus.emit(name, payload);
60650
+ } catch {}
60651
+ }
60652
+ async inboxRecentDao() {
60653
+ const db2 = await this.ctx.getDb();
60654
+ return new InboxRecentDao(db2);
60655
+ }
60138
60656
  orchestrator() {
60139
60657
  this.orchestratorPromise ??= this.inboxDao().then((dao2) => new TeamOrchestrator(this.configDir, dao2));
60140
60658
  return this.orchestratorPromise;
@@ -60169,7 +60687,7 @@ var init_team_service = __esm(() => {
60169
60687
  import { execFile } from "child_process";
60170
60688
  import { existsSync as existsSync4 } from "fs";
60171
60689
  import { mkdir, writeFile } from "fs/promises";
60172
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join10 } from "path";
60690
+ import { dirname as dirname8, isAbsolute as isAbsolute2, join as join10 } from "path";
60173
60691
  import { promisify as promisify3 } from "util";
60174
60692
 
60175
60693
  class AgentRunActionRunner {
@@ -60224,7 +60742,7 @@ class AgentRunActionRunner {
60224
60742
  const ok2 = exitCode2 === 0;
60225
60743
  if (answerFile !== undefined) {
60226
60744
  const target = isAbsolute2(answerFile) ? answerFile : join10(cwd, answerFile);
60227
- await mkdir(dirname9(target), { recursive: true });
60745
+ await mkdir(dirname8(target), { recursive: true });
60228
60746
  await writeFile(target, answer, "utf8");
60229
60747
  }
60230
60748
  if (ok2 && expectFile !== undefined) {
@@ -60326,7 +60844,7 @@ async function writePartialWorkArtifact(context3, agentLabel, captured, cwd) {
60326
60844
  ].join(`
60327
60845
  `);
60328
60846
  const target = join10(cwd, ".spur", "run", `${context3.runId}-${context3.stateOrNodeId}-partial.md`);
60329
- await mkdir(dirname9(target), { recursive: true });
60847
+ await mkdir(dirname8(target), { recursive: true });
60330
60848
  await writeFile(target, body, "utf8");
60331
60849
  } catch {}
60332
60850
  }
@@ -61530,6 +62048,8 @@ __export(exports_src2, {
61530
62048
  TaskService: () => TaskService,
61531
62049
  TaskCheckService: () => TaskCheckService,
61532
62050
  TASK_LIFECYCLE_PROFILE: () => TASK_LIFECYCLE_PROFILE,
62051
+ TASK_ACTION_COMMANDS: () => TASK_ACTION_COMMANDS,
62052
+ SupervisorService: () => SupervisorService,
61533
62053
  RuleService: () => RuleService,
61534
62054
  RuleCheckActionRunner: () => RuleCheckActionRunner,
61535
62055
  ResponseValidateActionRunner: () => ResponseValidateActionRunner,
@@ -61537,6 +62057,8 @@ __export(exports_src2, {
61537
62057
  PlanningWriteService: () => PlanningWriteService,
61538
62058
  ObservableWorkflowAdapter: () => ObservableWorkflowAdapter,
61539
62059
  LifecycleAdapter: () => LifecycleAdapter,
62060
+ JobWorkerService: () => JobWorkerService,
62061
+ JobHandlerRegistry: () => JobHandlerRegistry,
61540
62062
  HitlInputActionRunner: () => HitlInputActionRunner,
61541
62063
  HitlConfirmActionRunner: () => HitlConfirmActionRunner,
61542
62064
  HistoryService: () => HistoryService,
@@ -61654,18 +62176,18 @@ var {
61654
62176
  init_src();
61655
62177
  init_loader();
61656
62178
 
61657
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/application-node.js
62179
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/application-node.js
61658
62180
  init_dist4();
61659
62181
  init_dist3();
61660
62182
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4 } from "fs";
61661
62183
  import { dirname as dirname4 } from "path";
61662
62184
 
61663
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/application/index.js
62185
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/application/index.js
61664
62186
  init_default_observers();
61665
62187
  init_event_bus();
61666
62188
  init_logger3();
61667
62189
 
61668
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
62190
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
61669
62191
  class NoopSchedulerAdapter {
61670
62192
  constructor() {}
61671
62193
  register(_cron, _action) {}
@@ -61673,7 +62195,7 @@ class NoopSchedulerAdapter {
61673
62195
  async stop() {}
61674
62196
  }
61675
62197
 
61676
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
62198
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
61677
62199
  function initScheduler(adapter, cronEntries) {
61678
62200
  const resolved = adapter ?? new NoopSchedulerAdapter;
61679
62201
  if (cronEntries) {
@@ -61684,7 +62206,7 @@ function initScheduler(adapter, cronEntries) {
61684
62206
  return resolved;
61685
62207
  }
61686
62208
 
61687
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
62209
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
61688
62210
  init_logger3();
61689
62211
  init_metrics();
61690
62212
  init_sdk();
@@ -61777,7 +62299,7 @@ function dbPlugin(db2) {
61777
62299
  };
61778
62300
  }
61779
62301
 
61780
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
62302
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
61781
62303
  init_logger3();
61782
62304
 
61783
62305
  class PluginHost {
@@ -61865,7 +62387,7 @@ class PluginHost {
61865
62387
  }
61866
62388
  }
61867
62389
 
61868
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/application/index.js
62390
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/application/index.js
61869
62391
  async function performShutdown(state, reason) {
61870
62392
  if (state.stopped)
61871
62393
  return;
@@ -61960,10 +62482,10 @@ async function runApplication(options) {
61960
62482
  }
61961
62483
  }
61962
62484
 
61963
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/application-node.js
62485
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/application-node.js
61964
62486
  init_scheduler_node();
61965
62487
 
61966
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
62488
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
61967
62489
  var import_api14 = __toESM(require_src(), 1);
61968
62490
 
61969
62491
  // ../../node_modules/.bun/@opentelemetry+exporter-metrics-otlp-http@0.218.0+e40b0dfdd726a224/node_modules/@opentelemetry/exporter-metrics-otlp-http/build/esm/OTLPMetricExporterBase.js
@@ -64979,7 +65501,7 @@ class OTLPTraceExporter extends import_otlp_exporter_base2.OTLPExporterBase {
64979
65501
  }), JsonTraceSerializer));
64980
65502
  }
64981
65503
  }
64982
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
65504
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
64983
65505
  var import_resources2 = __toESM(require_src4(), 1);
64984
65506
  var import_sdk_trace_node = __toESM(require_src8(), 1);
64985
65507
  var import_semantic_conventions = __toESM(require_src2(), 1);
@@ -65030,7 +65552,7 @@ async function shutdownNodeTelemetry() {
65030
65552
  await Promise.all(pending);
65031
65553
  }
65032
65554
 
65033
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.2+be3e9d72efacb189/node_modules/@gobing-ai/ts-infra/dist/application-node.js
65555
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.3+ae9bf3ddb9f87572/node_modules/@gobing-ai/ts-infra/dist/application-node.js
65034
65556
  class ConfigValidationError extends Error {
65035
65557
  constructor(message) {
65036
65558
  super(message);
@@ -69009,7 +69531,8 @@ init_src3();
69009
69531
  init_loader();
69010
69532
  init_src2();
69011
69533
  import { existsSync as existsSync5 } from "fs";
69012
- import { join as join12 } from "path";
69534
+ import { homedir as homedir4 } from "os";
69535
+ import { join as join12, resolve as resolve4 } from "path";
69013
69536
 
69014
69537
  // src/workflow/resolve-spur-bin.ts
69015
69538
  import { basename as basename2 } from "path";
@@ -69027,6 +69550,11 @@ function resolveSpurBin() {
69027
69550
  }
69028
69551
 
69029
69552
  // src/workflow/make-lifecycle-adapter.ts
69553
+ var GLOBAL_CONFIG_DIR = join12(".config", "spur");
69554
+ function globalConfigRoot(context3) {
69555
+ const override = context3.env.SPUR_GLOBAL_RULES_DIR;
69556
+ return override !== undefined && override.length > 0 ? resolve4(context3.cwd, override) : join12(homedir4(), GLOBAL_CONFIG_DIR);
69557
+ }
69030
69558
  function resolveWorkflowPath(context3, profile) {
69031
69559
  const bundledRoot = bundledConfigRoot();
69032
69560
  if (bundledRoot !== null) {
@@ -69037,6 +69565,9 @@ function resolveWorkflowPath(context3, profile) {
69037
69565
  const projectPath = join12(context3.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
69038
69566
  if (existsSync5(projectPath))
69039
69567
  return projectPath;
69568
+ const globalPath = join12(globalConfigRoot(context3), "workflows", `${profile.workflowName}.yaml`);
69569
+ if (existsSync5(globalPath))
69570
+ return globalPath;
69040
69571
  return null;
69041
69572
  }
69042
69573
  function makeLifecycleAdapter(context3, profile) {
@@ -69387,14 +69918,14 @@ function formatImportResult(r) {
69387
69918
  init_loader();
69388
69919
  init_src2();
69389
69920
  init_dist9();
69390
- import { homedir as homedir4 } from "os";
69391
- import { join as join13, resolve as resolve4 } from "path";
69921
+ import { homedir as homedir5 } from "os";
69922
+ import { join as join13, resolve as resolve5 } from "path";
69392
69923
 
69393
69924
  // src/config.ts
69394
69925
  var CLI_CONFIG = {
69395
69926
  binaryName: "spur",
69396
69927
  binaryLabel: "spur",
69397
- binaryVersion: "0.3.1",
69928
+ binaryVersion: "0.3.3",
69398
69929
  configDir: ".spur",
69399
69930
  configFile: ".spur/config.yaml",
69400
69931
  databaseFile: ".spur/spur.db"
@@ -69417,6 +69948,7 @@ var SCAFFOLD_MANIFEST = [
69417
69948
  { source: "templates/task/feature-impl.md", target: "tasks/templates/feature-impl.md" },
69418
69949
  { source: "templates/task/issue.md", target: "tasks/templates/issue.md" },
69419
69950
  { source: "templates/task/review.md", target: "tasks/templates/review.md" },
69951
+ { source: "templates/task/brainstorm.md", target: "tasks/templates/brainstorm.md" },
69420
69952
  { source: "templates/task/meta.md", target: "tasks/templates/meta.md" },
69421
69953
  { source: "templates/feature/default.md", target: "templates/feature/default.md" },
69422
69954
  { source: "templates/bdd/gherkin.md", target: "templates/bdd/gherkin.md" },
@@ -69443,13 +69975,13 @@ var SCAFFOLD_MANIFEST = [
69443
69975
  ];
69444
69976
 
69445
69977
  // src/commands/init.ts
69446
- var GLOBAL_CONFIG_DIR = join13(".config", "spur");
69447
- var GLOBAL_RULES_DIR2 = join13(GLOBAL_CONFIG_DIR, "rules");
69978
+ var GLOBAL_CONFIG_DIR2 = join13(".config", "spur");
69979
+ var GLOBAL_RULES_DIR2 = join13(GLOBAL_CONFIG_DIR2, "rules");
69448
69980
  var GLOBAL_CONFIG_EXAMPLE = "config.example.yaml";
69449
69981
  var GLOBAL_CONFIG_FILE2 = "config.yaml";
69450
69982
  function globalRulesRoot(context3) {
69451
69983
  const override = context3.env.SPUR_GLOBAL_RULES_DIR;
69452
- return override !== undefined && override.length > 0 ? resolve4(context3.cwd, override) : join13(homedir4(), GLOBAL_RULES_DIR2);
69984
+ return override !== undefined && override.length > 0 ? resolve5(context3.cwd, override) : join13(homedir5(), GLOBAL_RULES_DIR2);
69453
69985
  }
69454
69986
  async function writeIfNew(context3, path8, content, force, result) {
69455
69987
  if (!force && await context3.fs.exists(path8)) {
@@ -69480,7 +70012,7 @@ async function seedGlobalConfig(context3) {
69480
70012
  if (source === null)
69481
70013
  return 0;
69482
70014
  const globalOverride = context3.env.SPUR_GLOBAL_RULES_DIR;
69483
- const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve4(context3.cwd, globalOverride) : join13(homedir4(), GLOBAL_CONFIG_DIR);
70015
+ const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve5(context3.cwd, globalOverride) : join13(homedir5(), GLOBAL_CONFIG_DIR2);
69484
70016
  let written = 0;
69485
70017
  for (const relPath of listBundledConfigFiles()) {
69486
70018
  if (relPath === GLOBAL_CONFIG_EXAMPLE)
@@ -69527,7 +70059,7 @@ function registerInitCommand(program2, context3) {
69527
70059
  " logging:",
69528
70060
  " enabled: true",
69529
70061
  " level: info",
69530
- " console: true",
70062
+ " console: false",
69531
70063
  " json: true",
69532
70064
  " file: true",
69533
70065
  ` filePath: ${CLI_CONFIG.configDir}/logs/spur.log`,
@@ -69587,7 +70119,7 @@ function registerInitCommand(program2, context3) {
69587
70119
  context3.output.write(` \u2713 seeded ${rulesSeeded} rule file(s) to ~/${GLOBAL_RULES_DIR2}`);
69588
70120
  }
69589
70121
  if (configSeeded > 0) {
69590
- context3.output.write(` \u2713 seeded ${configSeeded} config file(s) to ~/${GLOBAL_CONFIG_DIR}`);
70122
+ context3.output.write(` \u2713 seeded ${configSeeded} config file(s) to ~/${GLOBAL_CONFIG_DIR2}`);
69591
70123
  }
69592
70124
  }
69593
70125
  });
@@ -69596,6 +70128,7 @@ function registerInitCommand(program2, context3) {
69596
70128
  // src/commands/message.ts
69597
70129
  init_src3();
69598
70130
  var DEFAULT_FROM = "operator";
70131
+ var DEFAULT_WATCH_INTERVAL_MS = 2000;
69599
70132
  function registerMessageCommand(program2, context3) {
69600
70133
  const noun = program2.command("message").summary("send and inspect durable inter-agent messages");
69601
70134
  noun.command("send").description("Enqueue a message for an agent.").argument("<body>", "Message body").requiredOption("--to <id>", "Recipient agent id").option("--from <id>", "Sender id", DEFAULT_FROM).option("--json", "Output machine-readable JSON").action(async (body, options) => {
@@ -69613,6 +70146,29 @@ function registerMessageCommand(program2, context3) {
69613
70146
  const code = await runMessageReply(svc, context3, msgId, body, options);
69614
70147
  context3.setExitCode(code);
69615
70148
  });
70149
+ noun.command("watch").description("Follow an agent inbox \u2014 surface new messages as they arrive (Ctrl-C to exit).").requiredOption("--agent <id>", "Agent id to watch").option("--interval <ms>", "Poll interval in milliseconds", String(DEFAULT_WATCH_INTERVAL_MS)).option("--json", "Output one JSON object per new message (machine-consumable)").action(async (options) => {
70150
+ const svc = new TeamService(context3);
70151
+ const intervalMs = parseInterval2(options.interval);
70152
+ if (intervalMs === null) {
70153
+ context3.output.error(`invalid --interval "${options.interval}" (expected a positive integer ms)`);
70154
+ context3.setExitCode(2);
70155
+ return;
70156
+ }
70157
+ const controller = new AbortController;
70158
+ const onSigInt = () => controller.abort();
70159
+ process.on("SIGINT", onSigInt);
70160
+ try {
70161
+ await runMessageWatch(svc, context3.output, {
70162
+ agent: options.agent,
70163
+ intervalMs,
70164
+ json: options.json ?? false
70165
+ }, {
70166
+ signal: controller.signal
70167
+ });
70168
+ } finally {
70169
+ process.off("SIGINT", onSigInt);
70170
+ }
70171
+ });
69616
70172
  }
69617
70173
  async function runMessageSend(svc, context3, body, options) {
69618
70174
  const trimmed = body.trim();
@@ -69662,6 +70218,50 @@ function formatInboxLine(entry) {
69662
70218
  const body = entry.body.length > 60 ? `${entry.body.slice(0, 57)}...` : entry.body;
69663
70219
  return `${entry.id} ${entry.status} ${from} ${body} ${entry.createdAt}`;
69664
70220
  }
70221
+ async function runMessageWatch(svc, output2, options, runtime = {}) {
70222
+ const sleep2 = runtime.sleep ?? ((ms) => defaultSleep(ms, runtime.signal));
70223
+ const seen = new Set;
70224
+ let iteration = 0;
70225
+ while (true) {
70226
+ if (runtime.signal?.aborted)
70227
+ return;
70228
+ if (runtime.maxIterations !== undefined && iteration >= runtime.maxIterations)
70229
+ return;
70230
+ const inbox = await svc.getInbox(options.agent);
70231
+ for (let i2 = inbox.messages.length - 1;i2 >= 0; i2--) {
70232
+ const msg = inbox.messages[i2];
70233
+ if (!msg || seen.has(msg.id))
70234
+ continue;
70235
+ seen.add(msg.id);
70236
+ if (options.json) {
70237
+ output2.write(toJson2(msg));
70238
+ } else {
70239
+ output2.write(formatInboxLine(msg));
70240
+ }
70241
+ }
70242
+ iteration++;
70243
+ await sleep2(options.intervalMs);
70244
+ }
70245
+ }
70246
+ function defaultSleep(ms, signal) {
70247
+ return new Promise((resolve6) => {
70248
+ if (signal?.aborted) {
70249
+ resolve6();
70250
+ return;
70251
+ }
70252
+ const timer = setTimeout(resolve6, ms);
70253
+ signal?.addEventListener("abort", () => {
70254
+ clearTimeout(timer);
70255
+ resolve6();
70256
+ }, { once: true });
70257
+ });
70258
+ }
70259
+ function parseInterval2(raw) {
70260
+ const n2 = Number.parseInt(raw, 10);
70261
+ if (!Number.isFinite(n2) || n2 <= 0)
70262
+ return null;
70263
+ return n2;
70264
+ }
69665
70265
 
69666
70266
  // src/commands/migrate.ts
69667
70267
  init_src2();
@@ -69926,7 +70526,9 @@ init_src();
69926
70526
 
69927
70527
  // ../server/src/serve.ts
69928
70528
  init_src3();
69929
- import { dirname as dirname10, isAbsolute as isAbsolute3, join as join16 } from "path";
70529
+ init_loader();
70530
+ init_src2();
70531
+ import { dirname as dirname9, isAbsolute as isAbsolute3, join as join16 } from "path";
69930
70532
  init_dist3();
69931
70533
 
69932
70534
  // ../server/src/bootstrap.ts
@@ -70203,8 +70805,8 @@ class EventPublisher {
70203
70805
  if (bufferedEvents.length > 0) {
70204
70806
  return { done: false, value: bufferedEvents.shift() };
70205
70807
  }
70206
- return new Promise((resolve5, reject) => {
70207
- pullResolvers.push([resolve5, reject]);
70808
+ return new Promise((resolve6, reject) => {
70809
+ pullResolvers.push([resolve6, reject]);
70208
70810
  });
70209
70811
  }, async () => {
70210
70812
  unsubscribe();
@@ -75228,6 +75830,29 @@ function mountMiddleware(app, appRt) {
75228
75830
  }
75229
75831
  }
75230
75832
 
75833
+ // ../server/src/modules/events/event-names.ts
75834
+ var PLANNING_EVENT_NAMES = [
75835
+ "task.created",
75836
+ "task.updated",
75837
+ "task.transitioned",
75838
+ "feature.created",
75839
+ "feature.updated",
75840
+ "feature.transitioned",
75841
+ "queue.consumer.started",
75842
+ "queue.consumer.stopped",
75843
+ "queue.job.enqueued",
75844
+ "queue.job.completed",
75845
+ "queue.job.failed",
75846
+ "queue.job.retrying",
75847
+ "queue.stats",
75848
+ "scheduler.job.executed",
75849
+ "message.sent",
75850
+ "message.replied",
75851
+ "process.spawned",
75852
+ "process.exited",
75853
+ "process.stopped"
75854
+ ];
75855
+
75231
75856
  // ../server/src/modules/events/index.ts
75232
75857
  function sendKeepalive(closed, controller, encoder) {
75233
75858
  if (closed.current)
@@ -75276,15 +75901,7 @@ var eventsModule = {
75276
75901
  }
75277
75902
  signal.addEventListener("abort", teardown);
75278
75903
  heartbeatInterval = setInterval(sendKeepalive, 15000, closed, controller, encoder);
75279
- const eventNames = [
75280
- "task.created",
75281
- "task.updated",
75282
- "task.transitioned",
75283
- "feature.created",
75284
- "feature.updated",
75285
- "feature.transitioned"
75286
- ];
75287
- for (const name of eventNames) {
75904
+ for (const name of PLANNING_EVENT_NAMES) {
75288
75905
  const handler = (event) => {
75289
75906
  if (closed.current)
75290
75907
  return;
@@ -75317,9 +75934,38 @@ var eventsModule = {
75317
75934
  "Cache-Control": "no-cache"
75318
75935
  });
75319
75936
  });
75937
+ app.get("/api/events/history", async (c3) => {
75938
+ const nameParam = c3.req.query("name");
75939
+ const sinceParam = c3.req.query("since");
75940
+ const limitParam = c3.req.query("limit");
75941
+ let limit = 100;
75942
+ if (limitParam !== undefined) {
75943
+ const parsed = Number.parseInt(limitParam, 10);
75944
+ if (!Number.isNaN(parsed) && parsed > 0) {
75945
+ limit = Math.min(parsed, 500);
75946
+ }
75947
+ }
75948
+ const dao2 = await ctx.systemEventDao();
75949
+ const rows = await dao2.query({
75950
+ name: nameParam || undefined,
75951
+ since: sinceParam || undefined,
75952
+ limit
75953
+ });
75954
+ const events2 = rows.map((row) => ({
75955
+ id: row.id,
75956
+ eventName: row.event_name,
75957
+ occurredAt: row.occurred_at,
75958
+ actor: row.actor,
75959
+ payload: row.payload_json ? JSON.parse(row.payload_json) : null
75960
+ }));
75961
+ return c3.json({ events: events2, count: events2.length });
75962
+ });
75320
75963
  }
75321
75964
  };
75322
75965
 
75966
+ // ../server/src/modules/feature/handlers.ts
75967
+ init_src3();
75968
+
75323
75969
  // ../../packages/contracts/src/index.ts
75324
75970
  init_zod();
75325
75971
 
@@ -75430,6 +76076,24 @@ var featureContract = {
75430
76076
  tags: ["feature"]
75431
76077
  }).output(apiSuccessSchema(exports_external.object({
75432
76078
  rebuilt: exports_external.number().int().nonnegative()
76079
+ }))),
76080
+ check: oc.route({
76081
+ method: "POST",
76082
+ path: "/features/{id}/check",
76083
+ summary: "Run the four-layer feature check",
76084
+ tags: ["feature"]
76085
+ }).input(exports_external.object({ id: featureIdSchema })).output(apiSuccessSchema(exports_external.object({
76086
+ id: exports_external.string(),
76087
+ status: exports_external.string(),
76088
+ pass: exports_external.boolean(),
76089
+ findings: exports_external.array(exports_external.object({
76090
+ layer: exports_external.enum(["L1", "L2", "L3", "L4"]),
76091
+ severity: exports_external.enum(["error", "warning", "info"]),
76092
+ section: exports_external.string(),
76093
+ message: exports_external.string()
76094
+ })),
76095
+ requiredSections: exports_external.array(exports_external.string()),
76096
+ missingSections: exports_external.array(exports_external.string())
75433
76097
  })))
75434
76098
  };
75435
76099
 
@@ -75510,10 +76174,20 @@ var taskBodyUpdateResponseSchema = apiSuccessSchema(exports_external.object({
75510
76174
  wbs: exports_external.string(),
75511
76175
  filePath: exports_external.string()
75512
76176
  }));
76177
+ var taskActionChannelSchema = exports_external.enum([
76178
+ "claude",
76179
+ "codex",
76180
+ "gemini",
76181
+ "pi",
76182
+ "opencode",
76183
+ "antigravity",
76184
+ "openclaw"
76185
+ ]);
76186
+ var taskActionNameSchema = exports_external.enum(["refine", "plan", "run", "verify", "decompose", "evaluate"]);
75513
76187
  var taskActionInputSchema = exports_external.object({
75514
76188
  wbs: exports_external.string().regex(/^\d{4}$/),
75515
- action: exports_external.enum(["refine", "plan", "run", "verify", "decompose", "evaluate"]),
75516
- channel: exports_external.string().optional(),
76189
+ action: taskActionNameSchema,
76190
+ channel: taskActionChannelSchema.optional(),
75517
76191
  skipDeps: exports_external.boolean().optional()
75518
76192
  });
75519
76193
  var taskActionResponseSchema = apiSuccessSchema(exports_external.object({
@@ -75641,6 +76315,20 @@ function createFeatureHandlers(ctx) {
75641
76315
  refresh: os2.feature.refresh.handler(async () => {
75642
76316
  const { tasksUpdated } = await ctx.featureService().refresh();
75643
76317
  return { ok: true, data: { rebuilt: tasksUpdated } };
76318
+ }),
76319
+ check: os2.feature.check.handler(async ({ input }) => {
76320
+ const folders = ctx.planningFolders();
76321
+ const feature = await ctx.featureService().show(input.id);
76322
+ if (!feature)
76323
+ throw new NotFoundError(`Feature ${input.id} not found`);
76324
+ const svc = new FeatureCheckService(ctx.fs);
76325
+ return {
76326
+ ok: true,
76327
+ data: await svc.check(feature.filePath, input.id, {
76328
+ featuresDir: folders.featuresDir,
76329
+ tasksDir: folders.tasksDir
76330
+ })
76331
+ };
75644
76332
  })
75645
76333
  };
75646
76334
  }
@@ -75679,6 +76367,108 @@ var healthModule = {
75679
76367
  }
75680
76368
  };
75681
76369
 
76370
+ // ../server/src/modules/jobs/index.ts
76371
+ var jobsModule = {
76372
+ name: "jobs",
76373
+ mount(app, ctx) {
76374
+ if (!ctx)
76375
+ return;
76376
+ app.get("/api/jobs/stats", async (c3) => {
76377
+ const queue = await ctx.jobQueue();
76378
+ const stats = await queue.stats();
76379
+ return c3.json({ stats });
76380
+ });
76381
+ }
76382
+ };
76383
+
76384
+ // ../server/src/modules/messages/index.ts
76385
+ var messagesModule = {
76386
+ name: "messages",
76387
+ mount(app, ctx) {
76388
+ if (!ctx)
76389
+ return;
76390
+ app.get("/api/messages/inbox", async (c3) => {
76391
+ const agent = c3.req.query("agent");
76392
+ if (!agent) {
76393
+ return c3.json({ error: "missing required query parameter: agent" }, 400);
76394
+ }
76395
+ const limit = parseLimit(c3.req.query("limit"), 50);
76396
+ const offsetParam = c3.req.query("offset");
76397
+ const offset = offsetParam === undefined ? undefined : parseLimit(offsetParam, 0);
76398
+ const svc = ctx.teamService();
76399
+ const result = await svc.getInbox(agent, limit, offset);
76400
+ return c3.json(result);
76401
+ });
76402
+ app.get("/api/messages", async (c3) => {
76403
+ const limit = parseLimit(c3.req.query("limit"), 50);
76404
+ const svc = ctx.teamService();
76405
+ const result = await svc.listRecent(limit);
76406
+ return c3.json(result);
76407
+ });
76408
+ app.post("/api/messages", async (c3) => {
76409
+ const parsed = await parseJsonBody(c3);
76410
+ if ("error" in parsed)
76411
+ return c3.json({ error: parsed.error }, 400);
76412
+ const { to, body, from } = parsed;
76413
+ if (typeof to !== "string" || to.length === 0)
76414
+ return c3.json({ error: 'field "to" is required' }, 400);
76415
+ if (typeof body !== "string" || body.length === 0)
76416
+ return c3.json({ error: 'field "body" is required' }, 400);
76417
+ if (from !== undefined && (typeof from !== "string" || from.length === 0)) {
76418
+ return c3.json({ error: 'field "from" must be a non-empty string when present' }, 400);
76419
+ }
76420
+ const svc = ctx.teamService();
76421
+ try {
76422
+ const result = await svc.sendMessage(from ?? null, to, body);
76423
+ return c3.json(result, 201);
76424
+ } catch (err) {
76425
+ return c3.json({ error: errMsg(err) }, 400);
76426
+ }
76427
+ });
76428
+ app.post("/api/messages/:id/reply", async (c3) => {
76429
+ const id = c3.req.param("id");
76430
+ const parsed = await parseJsonBody(c3);
76431
+ if ("error" in parsed)
76432
+ return c3.json({ error: parsed.error }, 400);
76433
+ const { body } = parsed;
76434
+ if (typeof body !== "string" || body.length === 0)
76435
+ return c3.json({ error: 'field "body" is required' }, 400);
76436
+ const svc = ctx.teamService();
76437
+ try {
76438
+ const result = await svc.replyToMessage(id, body);
76439
+ return c3.json(result, 201);
76440
+ } catch (err) {
76441
+ return c3.json({ error: errMsg(err) }, 400);
76442
+ }
76443
+ });
76444
+ }
76445
+ };
76446
+ async function parseJsonBody(c3) {
76447
+ let json3;
76448
+ try {
76449
+ json3 = await c3.req.json();
76450
+ } catch {
76451
+ return { error: "request body must be valid JSON" };
76452
+ }
76453
+ if (typeof json3 !== "object" || json3 === null || Array.isArray(json3)) {
76454
+ return { error: "request body must be a JSON object" };
76455
+ }
76456
+ return json3;
76457
+ }
76458
+ function errMsg(err) {
76459
+ if (err instanceof Error)
76460
+ return err.message;
76461
+ return String(err);
76462
+ }
76463
+ function parseLimit(raw2, fallback) {
76464
+ if (raw2 === undefined)
76465
+ return fallback;
76466
+ const parsed = Number.parseInt(raw2, 10);
76467
+ if (Number.isNaN(parsed) || parsed < 0)
76468
+ return fallback;
76469
+ return Math.min(parsed, 500);
76470
+ }
76471
+
75682
76472
  // ../server/src/modules/task/handlers.ts
75683
76473
  init_schema4();
75684
76474
  init_dist();
@@ -75708,7 +76498,7 @@ function createTaskHandlers(ctx) {
75708
76498
  return {
75709
76499
  wbs: t.wbs,
75710
76500
  name: t.name,
75711
- status: normalizeTaskStatus(t.status),
76501
+ status: normalizeTaskStatusSafe(t.status),
75712
76502
  priority: typeof fm.priority === "string" ? fm.priority : undefined,
75713
76503
  featureId: fm.feature_id ?? undefined,
75714
76504
  parentWbs: fm.parent_wbs ?? undefined,
@@ -75728,7 +76518,7 @@ function createTaskHandlers(ctx) {
75728
76518
  data: {
75729
76519
  wbs: result.wbs,
75730
76520
  name: result.name,
75731
- status: normalizeTaskStatus(result.status),
76521
+ status: normalizeTaskStatusSafe(result.status),
75732
76522
  frontmatter: result.frontmatter,
75733
76523
  content: result.content,
75734
76524
  filePath: result.filePath
@@ -75777,8 +76567,171 @@ var taskModule = {
75777
76567
  mount(_app, _ctx) {}
75778
76568
  };
75779
76569
 
76570
+ // ../server/src/modules/team/index.ts
76571
+ function sendHeartbeat(closed, controller, encoder) {
76572
+ if (closed.current)
76573
+ return;
76574
+ try {
76575
+ controller.enqueue(encoder.encode(`: keepalive
76576
+
76577
+ `));
76578
+ } catch {}
76579
+ }
76580
+ function enqueueFrame(closed, controller, encoder, frame) {
76581
+ if (closed.current)
76582
+ return false;
76583
+ try {
76584
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(frame)}
76585
+
76586
+ `));
76587
+ return true;
76588
+ } catch {
76589
+ return false;
76590
+ }
76591
+ }
76592
+ var teamModule = {
76593
+ name: "team",
76594
+ mount(app, ctx) {
76595
+ if (!ctx)
76596
+ return;
76597
+ app.get("/api/team/processes", (c3) => {
76598
+ const supervisor = ctx.supervisor();
76599
+ const processes = supervisor.list().map((p2) => ({
76600
+ agentId: p2.agentId,
76601
+ pid: p2.pid,
76602
+ status: p2.status,
76603
+ startedAt: p2.startedAt,
76604
+ exitCode: p2.exitCode ?? null
76605
+ }));
76606
+ return c3.json({ processes, count: processes.length });
76607
+ });
76608
+ app.post("/api/team/agents/:id/start", async (c3) => {
76609
+ const id = c3.req.param("id");
76610
+ try {
76611
+ const entry = await ctx.supervisor().start(id);
76612
+ return c3.json({ ok: true, pid: entry.pid, status: entry.status }, 201);
76613
+ } catch (err) {
76614
+ return c3.json({ error: err instanceof Error ? err.message : String(err) }, 400);
76615
+ }
76616
+ });
76617
+ app.post("/api/team/agents/:id/stop", async (c3) => {
76618
+ const id = c3.req.param("id");
76619
+ try {
76620
+ await ctx.supervisor().stop(id);
76621
+ return c3.json({ ok: true });
76622
+ } catch (err) {
76623
+ return c3.json({ error: err instanceof Error ? err.message : String(err) }, 400);
76624
+ }
76625
+ });
76626
+ app.post("/api/team/processes/:id/stdin", async (c3) => {
76627
+ const id = c3.req.param("id");
76628
+ let json3;
76629
+ try {
76630
+ json3 = await c3.req.json();
76631
+ } catch {
76632
+ return c3.json({ error: "request body must be valid JSON" }, 400);
76633
+ }
76634
+ const body = json3;
76635
+ if (typeof body.line !== "string" || body.line.length === 0) {
76636
+ return c3.json({ error: 'field "line" is required' }, 400);
76637
+ }
76638
+ try {
76639
+ ctx.supervisor().writeStdin(id, body.line);
76640
+ return c3.json({ ok: true });
76641
+ } catch (err) {
76642
+ return c3.json({ error: err instanceof Error ? err.message : String(err) }, 400);
76643
+ }
76644
+ });
76645
+ app.get("/api/team/processes/:id/stream", (c3) => {
76646
+ const id = c3.req.param("id");
76647
+ const supervisor = ctx.supervisor();
76648
+ const proc = supervisor.get(id);
76649
+ if (!proc) {
76650
+ return c3.json({ error: `Agent "${id}" not found` }, 404);
76651
+ }
76652
+ const closed = { current: false };
76653
+ const signal = c3.req.raw.signal;
76654
+ let heartbeatInterval;
76655
+ let closeController = () => {};
76656
+ const teardown = () => {
76657
+ if (closed.current)
76658
+ return;
76659
+ closed.current = true;
76660
+ if (heartbeatInterval)
76661
+ clearInterval(heartbeatInterval);
76662
+ signal.removeEventListener("abort", teardown);
76663
+ closeController();
76664
+ };
76665
+ const stream = new ReadableStream({
76666
+ start(controller) {
76667
+ const encoder = new TextEncoder;
76668
+ closeController = () => {
76669
+ try {
76670
+ controller.close();
76671
+ } catch {}
76672
+ };
76673
+ if (signal.aborted) {
76674
+ teardown();
76675
+ return;
76676
+ }
76677
+ signal.addEventListener("abort", teardown);
76678
+ heartbeatInterval = setInterval(sendHeartbeat, 15000, closed, controller, encoder);
76679
+ const buffer = supervisor.getRingBuffer(id);
76680
+ for (const frame of buffer) {
76681
+ if (!enqueueFrame(closed, controller, encoder, frame))
76682
+ return;
76683
+ }
76684
+ if (!enqueueFrame(closed, controller, encoder, {
76685
+ stream: "meta",
76686
+ ts: new Date().toISOString(),
76687
+ line: "--replay-done--"
76688
+ }))
76689
+ return;
76690
+ let cursor2 = buffer.length;
76691
+ const pollInterval = setInterval(() => {
76692
+ if (closed.current) {
76693
+ clearInterval(pollInterval);
76694
+ return;
76695
+ }
76696
+ const current = supervisor.getRingBuffer(id);
76697
+ while (cursor2 < current.length) {
76698
+ const frame = current[cursor2];
76699
+ if (frame && !enqueueFrame(closed, controller, encoder, frame)) {
76700
+ clearInterval(pollInterval);
76701
+ return;
76702
+ }
76703
+ cursor2++;
76704
+ }
76705
+ }, 500);
76706
+ const origClose = closeController;
76707
+ closeController = () => {
76708
+ clearInterval(pollInterval);
76709
+ origClose();
76710
+ };
76711
+ },
76712
+ cancel() {
76713
+ closeController = () => {};
76714
+ teardown();
76715
+ }
76716
+ });
76717
+ return c3.newResponse(stream, 200, {
76718
+ "Content-Type": "text/event-stream",
76719
+ "Cache-Control": "no-cache"
76720
+ });
76721
+ });
76722
+ }
76723
+ };
76724
+
75780
76725
  // ../server/src/modules/registry.ts
75781
- var builtins = [healthModule, taskModule, featureModule, eventsModule];
76726
+ var builtins = [
76727
+ healthModule,
76728
+ taskModule,
76729
+ featureModule,
76730
+ eventsModule,
76731
+ messagesModule,
76732
+ jobsModule,
76733
+ teamModule
76734
+ ];
75782
76735
  function registerModules(app, ctx, modules = builtins) {
75783
76736
  for (const mod of modules) {
75784
76737
  try {
@@ -77727,12 +78680,15 @@ function createRouter2(ctx) {
77727
78680
  // ../server/src/bootstrap.ts
77728
78681
  function serverBootstrapConfig(env) {
77729
78682
  const isTest = env.NODE_ENV === "test";
78683
+ const raw2 = env.SPUR_TEAM_AUTOSTART;
78684
+ const teamAutostart = raw2 ? raw2.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : [];
77730
78685
  return {
77731
- logging: { enabled: !isTest, level: env.SPUR_LOG_LEVEL ?? "info" },
78686
+ logging: { enabled: !isTest, level: env.SPUR_LOG_LEVEL ?? "info", console: false },
77732
78687
  telemetry: { enabled: false },
77733
78688
  events: { enabled: true },
77734
- jobqueue: { enabled: false },
77735
- scheduler: { enabled: false }
78689
+ jobqueue: { enabled: !isTest },
78690
+ scheduler: { enabled: !isTest },
78691
+ teamAutostart
77736
78692
  };
77737
78693
  }
77738
78694
  function createApp(appRt, opts) {
@@ -77792,6 +78748,7 @@ function createApp(appRt, opts) {
77792
78748
  init_src3();
77793
78749
  init_src();
77794
78750
  init_src2();
78751
+ init_dist3();
77795
78752
  var DEFAULT_PLANNING_FOLDERS = {
77796
78753
  tasksDir: DEFAULT_TASKS_DIR,
77797
78754
  featuresDir: DEFAULT_FEATURES_DIR,
@@ -77814,7 +78771,11 @@ function createServerContext(appRt, options) {
77814
78771
  let dbPromise;
77815
78772
  let taskSvc;
77816
78773
  let featureSvc;
78774
+ let teamSvc;
78775
+ let supervisorSvc;
78776
+ let systemEventDaoPromise;
77817
78777
  let jobQueuePromise;
78778
+ let queueConsumerPromise;
77818
78779
  return {
77819
78780
  cwd,
77820
78781
  fs: fs3,
@@ -77851,6 +78812,33 @@ function createServerContext(appRt, options) {
77851
78812
  }
77852
78813
  return featureSvc;
77853
78814
  },
78815
+ teamService() {
78816
+ if (!teamSvc) {
78817
+ teamSvc = new TeamService({
78818
+ cwd,
78819
+ env: options.env ?? {},
78820
+ fs: fs3,
78821
+ getDb: () => this.getDb(),
78822
+ eventBus: eventsBus
78823
+ });
78824
+ }
78825
+ return teamSvc;
78826
+ },
78827
+ supervisor() {
78828
+ if (!supervisorSvc) {
78829
+ const pe = new ProcessExecutor;
78830
+ supervisorSvc = new SupervisorService({
78831
+ processExecutor: pe,
78832
+ eventBus: eventsBus,
78833
+ configDir: `${cwd}/.spur/agents`
78834
+ });
78835
+ }
78836
+ return supervisorSvc;
78837
+ },
78838
+ async systemEventDao() {
78839
+ systemEventDaoPromise ??= this.getDb().then((db2) => new SystemEventDao(db2));
78840
+ return systemEventDaoPromise;
78841
+ },
77854
78842
  planningFolders() {
77855
78843
  return folders;
77856
78844
  },
@@ -77868,6 +78856,17 @@ function createServerContext(appRt, options) {
77868
78856
  })();
77869
78857
  return jobQueuePromise;
77870
78858
  },
78859
+ async queueConsumer() {
78860
+ if (!jobQueueEnabled) {
78861
+ throw new NotConfiguredError("queueConsumer");
78862
+ }
78863
+ queueConsumerPromise ??= (async () => {
78864
+ const { createQueueConsumer: createQueueConsumer2 } = await Promise.resolve().then(() => (init_src2(), exports_src));
78865
+ const db2 = await this.getDb();
78866
+ return createQueueConsumer2(db2, { events: eventsBus });
78867
+ })();
78868
+ return queueConsumerPromise;
78869
+ },
77871
78870
  scheduler() {
77872
78871
  if (options.scheduler) {
77873
78872
  return options.scheduler;
@@ -77877,6 +78876,73 @@ function createServerContext(appRt, options) {
77877
78876
  };
77878
78877
  }
77879
78878
 
78879
+ // ../server/src/modules/events/system-event-tap.ts
78880
+ init_src2();
78881
+ var SYSTEM_EVENTS_CAP = 1e4;
78882
+ function registerSystemEventTap(bus, dao2, logger3) {
78883
+ const handlers = new Map;
78884
+ const inFlight = new Set;
78885
+ for (const name of PLANNING_EVENT_NAMES) {
78886
+ const handler = (event) => {
78887
+ const occurredAt = new Date().toISOString();
78888
+ const payloadJson = safeStringify(event);
78889
+ const actor = extractActor(event);
78890
+ const p2 = persist(dao2, name, occurredAt, actor, payloadJson, logger3);
78891
+ inFlight.add(p2);
78892
+ p2.finally(() => inFlight.delete(p2));
78893
+ };
78894
+ handlers.set(name, handler);
78895
+ bus.on(name, handler);
78896
+ }
78897
+ return {
78898
+ unsubscribe: () => {
78899
+ for (const [name, handler] of handlers) {
78900
+ bus.off(name, handler);
78901
+ }
78902
+ handlers.clear();
78903
+ },
78904
+ flush: async () => {
78905
+ while (inFlight.size > 0) {
78906
+ await Promise.allSettled(inFlight);
78907
+ }
78908
+ }
78909
+ };
78910
+ }
78911
+ async function persist(dao2, name, occurredAt, actor, payloadJson, logger3) {
78912
+ try {
78913
+ await dao2.insert({
78914
+ id: createId("sev"),
78915
+ event_name: name,
78916
+ occurred_at: occurredAt,
78917
+ actor,
78918
+ payload_json: payloadJson
78919
+ });
78920
+ await dao2.prune(SYSTEM_EVENTS_CAP);
78921
+ } catch (error51) {
78922
+ logger3.warn("system_events tap: persist failed", { name, error: stringifyError(error51) });
78923
+ }
78924
+ }
78925
+ function safeStringify(event) {
78926
+ try {
78927
+ return JSON.stringify(event ?? null);
78928
+ } catch {
78929
+ return null;
78930
+ }
78931
+ }
78932
+ function extractActor(event) {
78933
+ if (event && typeof event === "object") {
78934
+ const candidate = event.actor;
78935
+ if (typeof candidate === "string")
78936
+ return candidate;
78937
+ }
78938
+ return null;
78939
+ }
78940
+ function stringifyError(error51) {
78941
+ if (error51 instanceof Error)
78942
+ return `${error51.name}: ${error51.message}`;
78943
+ return String(error51);
78944
+ }
78945
+
77880
78946
  // ../server/src/open-url.ts
77881
78947
  async function openUrl(url2) {
77882
78948
  const argv = process.platform === "darwin" ? ["open", url2] : process.platform === "win32" ? ["cmd", "/c", "start", "", url2] : ["xdg-open", url2];
@@ -77884,6 +78950,11 @@ async function openUrl(url2) {
77884
78950
  }
77885
78951
 
77886
78952
  // ../server/src/serve.ts
78953
+ var SYSTEM_EVENTS_PRUNE_JOB = "system-events-prune";
78954
+ var SMOKE_JOB = "smoke";
78955
+ var TASK_ACTION_JOB = "task-action";
78956
+ var SYSTEM_EVENTS_PRUNE_CRON = "300000";
78957
+ var SMOKE_CRON = "600000";
77887
78958
  var defaultDeps = {
77888
78959
  serverBootstrapConfig,
77889
78960
  runNodeApplication,
@@ -77894,12 +78965,65 @@ var defaultDeps = {
77894
78965
  const { NodeSchedulerAdapter: NodeSchedulerAdapter2 } = await Promise.resolve().then(() => (init_scheduler_node(), exports_scheduler_node));
77895
78966
  return new NodeSchedulerAdapter2;
77896
78967
  },
77897
- openUrl
78968
+ openUrl,
78969
+ resolveConfigFile
77898
78970
  };
78971
+ function registerSchedulerEntries(scheduler3, ctx) {
78972
+ scheduler3.register(SYSTEM_EVENTS_PRUNE_CRON, async () => {
78973
+ const queue = await ctx.jobQueue();
78974
+ await queue.enqueue(SYSTEM_EVENTS_PRUNE_JOB, { source: "scheduler" }, { maxRetries: 1 });
78975
+ });
78976
+ scheduler3.register(SMOKE_CRON, async () => {
78977
+ const queue = await ctx.jobQueue();
78978
+ await queue.enqueue(SMOKE_JOB, { source: "scheduler" }, { maxRetries: 1 });
78979
+ });
78980
+ }
78981
+ function parseTaskActionJob(payload) {
78982
+ if (typeof payload !== "object" || payload === null) {
78983
+ throw new Error("Invalid task-action payload: expected object");
78984
+ }
78985
+ const candidate = payload;
78986
+ if (typeof candidate.wbs !== "string" || typeof candidate.action !== "string") {
78987
+ throw new Error("Invalid task-action payload: missing wbs/action");
78988
+ }
78989
+ if (typeof candidate.command !== "string" || candidate.command.trim() === "") {
78990
+ throw new Error("Invalid task-action payload: missing command");
78991
+ }
78992
+ return {
78993
+ wbs: candidate.wbs,
78994
+ action: candidate.action,
78995
+ command: candidate.command,
78996
+ channel: typeof candidate.channel === "string" ? candidate.channel : undefined,
78997
+ skipDeps: typeof candidate.skipDeps === "boolean" ? candidate.skipDeps : undefined
78998
+ };
78999
+ }
79000
+ function createTaskActionAgentService(options) {
79001
+ return new AgentService(options);
79002
+ }
79003
+ async function runTaskActionJob(ctx, env, payload, createAgentService = createTaskActionAgentService) {
79004
+ const job = parseTaskActionJob(payload);
79005
+ const agentService = createAgentService({
79006
+ cwd: ctx.cwd,
79007
+ env,
79008
+ output: {
79009
+ write: () => {},
79010
+ error: () => {}
79011
+ }
79012
+ });
79013
+ const flags = {
79014
+ cwd: ctx.cwd,
79015
+ json: true,
79016
+ ...job.channel !== undefined ? { agent: job.channel } : {}
79017
+ };
79018
+ const exitCode = await agentService.run(job.command, flags);
79019
+ if (exitCode !== 0) {
79020
+ throw new Error(`Task action ${job.action} for ${job.wbs} failed with exit code ${exitCode}`);
79021
+ }
79022
+ }
77899
79023
  async function resolveWebDistPath(configuredPath) {
77900
79024
  const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join16(process.cwd(), configuredPath)] : [
77901
79025
  join16(process.cwd(), "dist/web"),
77902
- join16(dirname10(process.execPath), "../web"),
79026
+ join16(dirname9(process.execPath), "../web"),
77903
79027
  join16(import.meta.dir, "../../../dist/web")
77904
79028
  ];
77905
79029
  for (const candidate of candidates) {
@@ -77912,8 +79036,10 @@ async function resolveWebDistPath(configuredPath) {
77912
79036
  async function startServer(options, deps = defaultDeps) {
77913
79037
  const env = process.env;
77914
79038
  const bootConfig = deps.serverBootstrapConfig(env);
79039
+ const configFile = deps.resolveConfigFile();
77915
79040
  await deps.runNodeApplication({
77916
79041
  config: bootConfig,
79042
+ configLoader: configFile ? { configFile, bootstrapSection: "bootstrap" } : undefined,
77917
79043
  async start(appRt) {
77918
79044
  const fs3 = deps.createNodeFileSystem(process.cwd());
77919
79045
  let scheduler3;
@@ -77926,10 +79052,51 @@ async function startServer(options, deps = defaultDeps) {
77926
79052
  folders: await resolvePlanningFolders(fs3),
77927
79053
  webDistPath: await resolveWebDistPath(options.webDistPath),
77928
79054
  jobQueueEnabled: bootConfig.jobqueue.enabled,
77929
- scheduler: scheduler3
79055
+ scheduler: scheduler3,
79056
+ teamAutostart: bootConfig.teamAutostart
77930
79057
  });
79058
+ let jobWorker;
79059
+ if (bootConfig.teamAutostart.length > 0) {
79060
+ try {
79061
+ const supervisor = ctx.supervisor();
79062
+ await supervisor.startAutostart(bootConfig.teamAutostart);
79063
+ appRt.logger.info("Autostart agents spawned", { ids: bootConfig.teamAutostart });
79064
+ } catch (error51) {
79065
+ appRt.logger.error("Autostart failed \u2014 server will continue but supervised agents are not running", {
79066
+ error: String(error51)
79067
+ });
79068
+ throw error51;
79069
+ }
79070
+ }
79071
+ if (bootConfig.events.enabled) {
79072
+ try {
79073
+ const dao2 = new SystemEventDao(await ctx.getDb());
79074
+ registerSystemEventTap(ctx.eventBus(), dao2, appRt.logger);
79075
+ appRt.logger.debug("system_events tap registered");
79076
+ } catch (error51) {
79077
+ appRt.logger.warn("system_events tap registration failed", { error: String(error51) });
79078
+ }
79079
+ }
77931
79080
  const app = deps.createApp(appRt, { fs: fs3, ctx });
79081
+ if (bootConfig.jobqueue.enabled) {
79082
+ const registry2 = new JobHandlerRegistry;
79083
+ registry2.register(SYSTEM_EVENTS_PRUNE_JOB, async () => {
79084
+ const dao2 = await ctx.systemEventDao();
79085
+ await dao2.prune(SYSTEM_EVENTS_CAP);
79086
+ });
79087
+ registry2.register(SMOKE_JOB, async () => {});
79088
+ registry2.register(TASK_ACTION_JOB, async (payload) => {
79089
+ await runTaskActionJob(ctx, env, payload);
79090
+ });
79091
+ jobWorker = new JobWorkerService({
79092
+ consumer: await ctx.queueConsumer(),
79093
+ registry: registry2
79094
+ });
79095
+ await jobWorker.start();
79096
+ appRt.logger.info("Job worker started");
79097
+ }
77932
79098
  if (scheduler3) {
79099
+ registerSchedulerEntries(scheduler3, ctx);
77933
79100
  await scheduler3.start();
77934
79101
  appRt.logger.info("Scheduler started");
77935
79102
  }
@@ -77940,9 +79107,16 @@ async function startServer(options, deps = defaultDeps) {
77940
79107
  });
77941
79108
  const shutdown = async (signal) => {
77942
79109
  appRt.logger.info("Shutting down server", { signal });
77943
- server.stop(true);
77944
79110
  if (scheduler3)
77945
79111
  await scheduler3.stop();
79112
+ if (jobWorker)
79113
+ await jobWorker.stop();
79114
+ try {
79115
+ await ctx.supervisor().stopAll();
79116
+ } catch (error51) {
79117
+ appRt.logger.warn("Supervisor shutdown error", { error: String(error51) });
79118
+ }
79119
+ server.stop(true);
77946
79120
  await appRt.stop("shutdown");
77947
79121
  process.exit(0);
77948
79122
  };
@@ -77959,7 +79133,6 @@ async function startServer(options, deps = defaultDeps) {
77959
79133
  }
77960
79134
  });
77961
79135
  }
77962
-
77963
79136
  // ../server/src/index.ts
77964
79137
  if (false) {}
77965
79138
 
@@ -78004,7 +79177,17 @@ class CommandError extends Error {
78004
79177
  this.name = "CommandError";
78005
79178
  }
78006
79179
  }
79180
+ function isSqliteBusy(error51) {
79181
+ if (error51 instanceof Error) {
79182
+ const maybeCode = error51.code;
79183
+ return maybeCode === "SQLITE_BUSY" || /\bSQLITE_BUSY\b/i.test(error51.message);
79184
+ }
79185
+ return typeof error51 === "string" && /\bSQLITE_BUSY\b/i.test(error51);
79186
+ }
78007
79187
  function errorMessage3(error51) {
79188
+ if (isSqliteBusy(error51)) {
79189
+ return "SQLite database is busy; another Spur process is holding the lock. Retry after the other command finishes.";
79190
+ }
78008
79191
  return error51 instanceof Error ? error51.message : String(error51);
78009
79192
  }
78010
79193
 
@@ -78108,7 +79291,7 @@ var section_matrix_schema_default = {
78108
79291
  $schema: "http://json-schema.org/draft-07/schema#",
78109
79292
  $id: "https://gobing.ai/spur/schemas/section-matrix.schema.json",
78110
79293
  title: "Section-Status-Matrix Schema",
78111
- description: "Validates config/tasks/section-matrix.yaml \u2014 which sections are required/optional/forbidden per task status. Design \xA73.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",
79294
+ description: "Validates the shipped section-matrix.yaml \u2014 which sections are required/optional/forbidden per task status. Design \xA73.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",
78112
79295
  type: "object",
78113
79296
  required: ["variants"],
78114
79297
  additionalProperties: false,
@@ -78578,6 +79761,35 @@ function renderTaskBoard(tasks, boardTitle, color, columns2) {
78578
79761
  return lines.join(`
78579
79762
  `);
78580
79763
  }
79764
+ var MIGRATION_RULE_IDS = ["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8"];
79765
+ function renderMigrationReport(report, dryRun, corpusDir) {
79766
+ const lines = [
79767
+ `Task corpus migration ${dryRun ? "dry-run" : "apply"} complete`,
79768
+ `Corpus: ${corpusDir}`,
79769
+ `Files scanned: ${report.filesScanned}`,
79770
+ `Files modified: ${report.filesModified}`,
79771
+ `Files skipped: ${report.filesSkipped}`,
79772
+ "",
79773
+ "Rule flag counts:"
79774
+ ];
79775
+ for (const rule of MIGRATION_RULE_IDS) {
79776
+ const count3 = report.flags.filter((flag) => flag.rule === rule).length;
79777
+ lines.push(` ${rule}: ${count3}`);
79778
+ }
79779
+ lines.push("", "Per-file changes:");
79780
+ const changed = report.fileReports.filter((file2) => file2.modified || file2.validationError !== undefined);
79781
+ if (changed.length === 0) {
79782
+ lines.push(" none");
79783
+ } else {
79784
+ for (const file2 of changed) {
79785
+ const state = file2.validationError !== undefined ? `skipped (${file2.validationError})` : "modified";
79786
+ const flags = file2.flags.length > 0 ? `; flags=${file2.flags.map((flag) => flag.rule).join(",")}` : "";
79787
+ lines.push(` ${file2.wbs}: ${state} \u2014 ${file2.path}${flags}`);
79788
+ }
79789
+ }
79790
+ return lines.join(`
79791
+ `);
79792
+ }
78581
79793
  function registerTaskCommand(program2, context3) {
78582
79794
  const task = program2.command("task").summary("manage tasks");
78583
79795
  task.command("create").summary("Create a new task with race-safe WBS allocation.").argument("<title>", "Task title").option("--feature <id>", "Feature ID for traceability and Goal\u2192Background derivation").option("--parent <wbs>", "Parent WBS for sub-task grouping").option("--template <variant>", `Template variant (${TASK_VARIANTS.join("|")})`).option("--folder <path>", "Custom tasks folder").option("--json", "Output machine-readable JSON").action(async (title2, options) => {
@@ -78713,16 +79925,32 @@ ${result.content}`);
78713
79925
  context3.setExitCode(1);
78714
79926
  }
78715
79927
  });
78716
- task.command("refresh").summary("Regenerate kanban.md from the task corpus (pure function, deterministic).").option("--folder <path>", "Custom tasks folder").option("--json", "Output machine-readable JSON").action(async (options) => {
79928
+ task.command("refresh").summary("Re-scan the task corpus and report counts (kanban.md retired \u2014 A17 cutover).").option("--folder <path>", "Custom tasks folder").option("--json", "Output machine-readable JSON").action(async (options) => {
78717
79929
  const svc = await makeService2(context3, options.folder);
78718
79930
  try {
78719
- const kanban = await svc.refresh();
79931
+ const result = await svc.refresh();
79932
+ if (options.json) {
79933
+ context3.output.write(toJson2(result));
79934
+ } else {
79935
+ context3.output.write(`Corpus scanned \u2014 ${result.tasks} tasks across ${result.folders} folder(s)`);
79936
+ }
79937
+ } catch (err) {
79938
+ context3.output.error(String(err));
79939
+ context3.setExitCode(1);
79940
+ }
79941
+ });
79942
+ task.command("migrate").summary("Run the one-time A17 task corpus normalization pass.").option("--dry-run", "Produce the full report without writing files").option("--folder <path>", "Custom tasks folder").option("--json", "Output machine-readable JSON").action(async (options) => {
79943
+ try {
79944
+ const foldersConfig = (await resolvePlanningFolders(context3.fs)).foldersConfig;
79945
+ const activeFolder = context3.fs.resolve(foldersConfig.active_folder);
79946
+ const corpusDir = options.folder ?? activeFolder;
79947
+ const dryRun = options.dryRun === true;
79948
+ const migrator = new CorpusMigrator({ fs: context3.fs, corpusDir });
79949
+ const report = await migrator.migrate({ dryRun });
78720
79950
  if (options.json) {
78721
- const activeFolder = (await resolvePlanningFolders(context3.fs)).foldersConfig.active_folder;
78722
- context3.output.write(toJson2({ kanban_path: `${options.folder ?? activeFolder}/kanban.md` }));
79951
+ context3.output.write(toJson2({ ok: true, dryRun, corpusDir, ...report }));
78723
79952
  } else {
78724
- context3.output.write(`kanban.md regenerated (${kanban.split(`
78725
- `).length} lines)`);
79953
+ context3.output.write(renderMigrationReport(report, dryRun, corpusDir));
78726
79954
  }
78727
79955
  } catch (err) {
78728
79956
  context3.output.error(String(err));
@@ -79028,7 +80256,7 @@ var FALLBACK_MATRIX = {
79028
80256
 
79029
80257
  // src/commands/team.ts
79030
80258
  init_src3();
79031
- var DAEMON_STUB_MESSAGE = "Team daemon not yet available. Use `spur agent run --drain` for deferred message delivery.";
80259
+ var DEFAULT_SERVER = "http://localhost:3000/api";
79032
80260
  function registerTeamCommand(program2, context3) {
79033
80261
  const noun = program2.command("team").summary("coordinate team agent assignments and status");
79034
80262
  noun.command("assign").description("Set the assignee on a task file.").argument("<task-id>", "Task file id").argument("<agent-id>", "Agent spec id").action(async (taskId, agentId) => {
@@ -79039,11 +80267,13 @@ function registerTeamCommand(program2, context3) {
79039
80267
  const code = await runTeamStatus(options, context3);
79040
80268
  context3.setExitCode(code);
79041
80269
  });
79042
- noun.command("start").description("Deferred daemon stub.").action(() => {
79043
- context3.output.write(DAEMON_STUB_MESSAGE);
80270
+ 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) => {
80271
+ const code = await runTeamStart(agentId, options, context3);
80272
+ context3.setExitCode(code);
79044
80273
  });
79045
- noun.command("stop").description("Deferred daemon stub.").action(() => {
79046
- context3.output.write(DAEMON_STUB_MESSAGE);
80274
+ noun.command("stop").description("Stop 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) => {
80275
+ const code = await runTeamStop(agentId, options, context3);
80276
+ context3.setExitCode(code);
79047
80277
  });
79048
80278
  }
79049
80279
  async function runTeamAssign(taskId, agentId, context3) {
@@ -79068,6 +80298,66 @@ async function runTeamStatus(options, context3) {
79068
80298
  `));
79069
80299
  return 0;
79070
80300
  }
80301
+ async function performTeamStart(agentId, options) {
80302
+ try {
80303
+ const url2 = `${options.server}/team/agents/${encodeURIComponent(agentId)}/start`;
80304
+ const res = await fetch(url2, { method: "POST" });
80305
+ const body = await res.json();
80306
+ if (res.ok)
80307
+ return { ok: true, body };
80308
+ return { ok: false, error: body.error ?? `start failed: ${res.status}`, status: res.status };
80309
+ } catch (err) {
80310
+ return { ok: false, transportError: err };
80311
+ }
80312
+ }
80313
+ async function runTeamStart(agentId, options, context3) {
80314
+ const result = await performTeamStart(agentId, options);
80315
+ if ("transportError" in result) {
80316
+ const err = result.transportError;
80317
+ context3.output.error(`Cannot reach server at ${options.server} \u2014 is spur serve running? (${err instanceof Error ? err.message : String(err)})`);
80318
+ return 1;
80319
+ }
80320
+ if (!result.ok) {
80321
+ context3.output.error(result.error);
80322
+ return 1;
80323
+ }
80324
+ if (options.json) {
80325
+ context3.output.write(toJson2(result.body));
80326
+ } else {
80327
+ context3.output.write(`started ${agentId} (pid=${result.body.pid}, status=${result.body.status ?? "?"})`);
80328
+ }
80329
+ return 0;
80330
+ }
80331
+ async function performTeamStop(agentId, options) {
80332
+ try {
80333
+ const url2 = `${options.server}/team/agents/${encodeURIComponent(agentId)}/stop`;
80334
+ const res = await fetch(url2, { method: "POST" });
80335
+ const body = await res.json();
80336
+ if (res.ok)
80337
+ return { ok: true, body };
80338
+ return { ok: false, error: body.error ?? `stop failed: ${res.status}`, status: res.status };
80339
+ } catch (err) {
80340
+ return { ok: false, transportError: err };
80341
+ }
80342
+ }
80343
+ async function runTeamStop(agentId, options, context3) {
80344
+ const result = await performTeamStop(agentId, options);
80345
+ if ("transportError" in result) {
80346
+ const err = result.transportError;
80347
+ context3.output.error(`Cannot reach server at ${options.server} \u2014 is spur serve running? (${err instanceof Error ? err.message : String(err)})`);
80348
+ return 1;
80349
+ }
80350
+ if (!result.ok) {
80351
+ context3.output.error(result.error);
80352
+ return 1;
80353
+ }
80354
+ if (options.json) {
80355
+ context3.output.write(toJson2(result.body));
80356
+ } else {
80357
+ context3.output.write(`stopped ${agentId}`);
80358
+ }
80359
+ return 0;
80360
+ }
79071
80361
  function formatStatusLine(agent) {
79072
80362
  const pid = agent.pid === undefined ? "" : ` pid=${agent.pid}`;
79073
80363
  return `${agent.status} ${agent.id} ${agent.type} ${agent.purpose}${pid}`;
@@ -79079,7 +80369,7 @@ init_loader();
79079
80369
  init_dist7();
79080
80370
  init_dist5();
79081
80371
  import { spawn as spawn2 } from "child_process";
79082
- import { resolve as resolve5 } from "path";
80372
+ import { resolve as resolve6 } from "path";
79083
80373
  function parseVars(raw2) {
79084
80374
  if (raw2 === undefined) {
79085
80375
  return;
@@ -79176,7 +80466,7 @@ Monitor with: spur workflow trace ${runId}`);
79176
80466
  if (human) {
79177
80467
  if (options.plan !== false) {
79178
80468
  try {
79179
- const def = await loadWorkflowDef(resolve5(context3.cwd, file2), { validateSchema: false });
80469
+ const def = await loadWorkflowDef(resolve6(context3.cwd, file2), { validateSchema: false });
79180
80470
  context3.output.write(renderRunPlan(def));
79181
80471
  } catch {}
79182
80472
  }
@@ -79385,7 +80675,7 @@ init_src3();
79385
80675
  init_src();
79386
80676
  init_src2();
79387
80677
  init_dist3();
79388
- import { dirname as dirname11, join as join19, resolve as resolve6 } from "path";
80678
+ import { dirname as dirname10, join as join19, resolve as resolve7 } from "path";
79389
80679
  import { isatty as isatty3 } from "tty";
79390
80680
 
79391
80681
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -80768,7 +82058,7 @@ class DefaultHitlResponder {
80768
82058
 
80769
82059
  // src/context.ts
80770
82060
  function createCliContext(options) {
80771
- const cwd = resolve6(options.cwd ?? process.cwd());
82061
+ const cwd = resolve7(options.cwd ?? process.cwd());
80772
82062
  const env = options.env ?? process.env;
80773
82063
  const fs3 = createNodeFileSystem(cwd);
80774
82064
  let dbPromise;
@@ -80797,7 +82087,7 @@ async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, d
80797
82087
  const configuredUrl = env.DATABASE_URL === undefined ? join19(cwd, CLI_CONFIG.databaseFile) : config3.database.url;
80798
82088
  const url2 = dbUrl ?? configuredUrl;
80799
82089
  if (url2 !== ":memory:") {
80800
- await createNodeFileSystem().ensureDir(dirname11(url2));
82090
+ await createNodeFileSystem().ensureDir(dirname10(url2));
80801
82091
  }
80802
82092
  return createMigratedDb({ url: url2 });
80803
82093
  }
@@ -80817,7 +82107,7 @@ async function main(argv = process.argv.slice(2), options = {}) {
80817
82107
  bootstrapSection: "bootstrap",
80818
82108
  appConfig: { safeParse: (raw2) => spurConfigSchema.safeParse(raw2) }
80819
82109
  },
80820
- config: undefined,
82110
+ config: { logging: { console: false } },
80821
82111
  services: { db: db2 },
80822
82112
  async start(appRt) {
80823
82113
  const context3 = createCliContext({
@@ -80832,12 +82122,8 @@ async function main(argv = process.argv.slice(2), options = {}) {
80832
82122
  });
80833
82123
  await app.stop("shutdown");
80834
82124
  } else {
80835
- const context3 = createCliContext({
80836
- cwd: options.cwd,
80837
- env: options.env,
80838
- output: output2,
80839
- db: db2
80840
- });
82125
+ const ctxOpts = { cwd: options.cwd, env: options.env, output: output2, db: db2 };
82126
+ const context3 = createCliContext(ctxOpts);
80841
82127
  exitCode = await runCommandDispatch(argv, context3, output2);
80842
82128
  }
80843
82129
  } finally {
@@ -80884,15 +82170,19 @@ function bannerText() {
80884
82170
  nodeFiglet.parseFont("Standard", Standard_default);
80885
82171
  return nodeFiglet.textSync(CLI_CONFIG.binaryLabel, { font: "Standard" });
80886
82172
  }
80887
- if (import.meta.main) {
82173
+ async function runCli() {
80888
82174
  const argv = process.argv.slice(2);
80889
82175
  if (!argv.includes("--json")) {
80890
82176
  consoleOutput.write(bannerText());
80891
82177
  }
80892
- const exitCode = await main();
82178
+ return main();
82179
+ }
82180
+ if (import.meta.main) {
82181
+ const exitCode = await runCli();
80893
82182
  process.exit(exitCode);
80894
82183
  }
80895
82184
  export {
82185
+ runCli,
80896
82186
  main,
80897
82187
  bannerText
80898
82188
  };