@gobing-ai/spur 0.3.35 → 0.3.36

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
@@ -47,7 +47,7 @@ var __export = (target, all) => {
47
47
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
48
48
  var __require = import.meta.require;
49
49
 
50
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.22/node_modules/@gobing-ai/ts-utils/dist/errors.js
50
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.23/node_modules/@gobing-ai/ts-utils/dist/errors.js
51
51
  var ErrorCode;
52
52
  var init_errors = __esm(() => {
53
53
  ErrorCode = {
@@ -58,7 +58,7 @@ var init_errors = __esm(() => {
58
58
  };
59
59
  });
60
60
 
61
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.22/node_modules/@gobing-ai/ts-utils/dist/api-response.js
61
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.23/node_modules/@gobing-ai/ts-utils/dist/api-response.js
62
62
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
63
63
  var init_api_response = __esm(() => {
64
64
  init_errors();
@@ -81,10 +81,10 @@ var init_api_response = __esm(() => {
81
81
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
82
82
  });
83
83
 
84
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.22/node_modules/@gobing-ai/ts-utils/dist/cursor.js
84
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.23/node_modules/@gobing-ai/ts-utils/dist/cursor.js
85
85
  var init_cursor = () => {};
86
86
 
87
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.22/node_modules/@gobing-ai/ts-utils/dist/object.js
87
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.23/node_modules/@gobing-ai/ts-utils/dist/object.js
88
88
  function isPlainObject(value) {
89
89
  return typeof value === "object" && value !== null && !Array.isArray(value);
90
90
  }
@@ -102,7 +102,7 @@ function deepMerge(target, source) {
102
102
  return result;
103
103
  }
104
104
 
105
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.22/node_modules/@gobing-ai/ts-utils/dist/output.js
105
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.23/node_modules/@gobing-ai/ts-utils/dist/output.js
106
106
  function processStream(name) {
107
107
  const proc = globalThis.process;
108
108
  const stream = proc?.[name];
@@ -123,7 +123,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
123
123
  }
124
124
  var defaultStdoutTarget, defaultStderrTarget;
125
125
 
126
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.22/node_modules/@gobing-ai/ts-utils/dist/index.js
126
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.23/node_modules/@gobing-ai/ts-utils/dist/index.js
127
127
  var init_dist = __esm(() => {
128
128
  init_api_response();
129
129
  init_cursor();
@@ -21745,7 +21745,7 @@ var init_zod = __esm(() => {
21745
21745
  init_external();
21746
21746
  });
21747
21747
 
21748
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/config.js
21748
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/config.js
21749
21749
  function getProcessEnv() {
21750
21750
  return process.env;
21751
21751
  }
@@ -21823,7 +21823,7 @@ var init_config = __esm(() => {
21823
21823
  };
21824
21824
  });
21825
21825
 
21826
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21826
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21827
21827
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
21828
21828
  import { dirname, resolve as resolvePath } from "path";
21829
21829
  function createNodeFileSystem(root, paths) {
@@ -21910,7 +21910,7 @@ function findProjectRoot(startDir) {
21910
21910
  }
21911
21911
  var init_file_system_node = () => {};
21912
21912
 
21913
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21913
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21914
21914
  var DbModuleNotInstalledError;
21915
21915
  var init_db_errors = __esm(() => {
21916
21916
  DbModuleNotInstalledError = class DbModuleNotInstalledError extends Error {
@@ -29121,7 +29121,7 @@ var init_execa = __esm(() => {
29121
29121
  } = getIpcExport());
29122
29122
  });
29123
29123
 
29124
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29124
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29125
29125
  import { isatty } from "tty";
29126
29126
 
29127
29127
  class NodeProcessExecutor {
@@ -29460,7 +29460,7 @@ var init_process_executor = __esm(() => {
29460
29460
  init_execa();
29461
29461
  });
29462
29462
 
29463
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29463
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29464
29464
  function getNodeFileSystem() {
29465
29465
  if (!_nodeFileSystem)
29466
29466
  _nodeFileSystem = createNodeFileSystem();
@@ -29520,7 +29520,7 @@ var init_runtime_node_bun = __esm(() => {
29520
29520
  };
29521
29521
  });
29522
29522
 
29523
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/context.js
29523
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/context.js
29524
29524
  class RuntimeContext {
29525
29525
  scope;
29526
29526
  runtimeName;
@@ -29590,7 +29590,7 @@ var init_context = __esm(() => {
29590
29590
  init_runtime_node_bun();
29591
29591
  });
29592
29592
 
29593
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/path.js
29593
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/path.js
29594
29594
  function normalizeSeparators(path6) {
29595
29595
  return path6.replaceAll("\\", "/");
29596
29596
  }
@@ -29651,17 +29651,17 @@ var init_path = __esm(() => {
29651
29651
  SEP = globalThis.process?.platform === "win32" ? "\\" : "/";
29652
29652
  });
29653
29653
 
29654
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29654
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29655
29655
  var REMOTE_SCHEMA_MAX_BYTES;
29656
29656
  var init_schema_validation = __esm(() => {
29657
29657
  init_dist2();
29658
29658
  REMOTE_SCHEMA_MAX_BYTES = 5 * 1024 * 1024;
29659
29659
  });
29660
29660
 
29661
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/types.js
29661
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/types.js
29662
29662
  var init_types = () => {};
29663
29663
 
29664
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/index.js
29664
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/index.js
29665
29665
  var init_dist3 = __esm(() => {
29666
29666
  init_config();
29667
29667
  init_context();
@@ -29670,7 +29670,7 @@ var init_dist3 = __esm(() => {
29670
29670
  init_types();
29671
29671
  });
29672
29672
 
29673
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+2fb2e08999400036/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29673
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+7af9b447ef75eadf/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29674
29674
  import { Database } from "bun:sqlite";
29675
29675
  var init_bun_sqlite = () => {};
29676
29676
 
@@ -33862,7 +33862,7 @@ var init_bun_sqlite2 = __esm(() => {
33862
33862
  init_session2();
33863
33863
  });
33864
33864
 
33865
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33865
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33866
33866
  var inboxMessages;
33867
33867
  var init_inbox_messages = __esm(() => {
33868
33868
  init_sqlite_core();
@@ -33881,7 +33881,7 @@ var init_inbox_messages = __esm(() => {
33881
33881
  }, (table2) => [index("idx_inbox_messages_to_status").on(table2.toId, table2.status)]);
33882
33882
  });
33883
33883
 
33884
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33884
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33885
33885
  function nowTimestamp() {
33886
33886
  return Date.now();
33887
33887
  }
@@ -33910,7 +33910,7 @@ var init_common3 = __esm(() => {
33910
33910
  appendOnlyColumns = buildAppendOnlyColumns();
33911
33911
  });
33912
33912
 
33913
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33913
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33914
33914
  var queueJobs;
33915
33915
  var init_queue_jobs = __esm(() => {
33916
33916
  init_sqlite_core();
@@ -33930,7 +33930,7 @@ var init_queue_jobs = __esm(() => {
33930
33930
  }, (table2) => [index("queue_jobs_ready_idx").on(table2.status, table2.nextRetryAt, table2.createdAt)]);
33931
33931
  });
33932
33932
 
33933
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33933
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33934
33934
  var exports_runtime = {};
33935
33935
  __export(exports_runtime, {
33936
33936
  queueJobs: () => queueJobs,
@@ -33941,7 +33941,7 @@ var init_runtime = __esm(() => {
33941
33941
  init_queue_jobs();
33942
33942
  });
33943
33943
 
33944
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33944
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33945
33945
  var exports_bun_sqlite = {};
33946
33946
  __export(exports_bun_sqlite, {
33947
33947
  BunSqliteAdapter: () => BunSqliteAdapter
@@ -34232,7 +34232,7 @@ var init_d1 = __esm(() => {
34232
34232
  init_session3();
34233
34233
  });
34234
34234
 
34235
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34235
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34236
34236
  var exports_d1 = {};
34237
34237
  __export(exports_d1, {
34238
34238
  D1Adapter: () => D1Adapter
@@ -34296,7 +34296,7 @@ var init_d12 = __esm(() => {
34296
34296
  init_runtime();
34297
34297
  });
34298
34298
 
34299
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/adapter.js
34299
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/adapter.js
34300
34300
  async function createDbAdapter(config3) {
34301
34301
  switch (config3.driver) {
34302
34302
  case "bun-sqlite": {
@@ -34336,7 +34336,7 @@ var init_drizzle_orm = __esm(() => {
34336
34336
  init_view_common();
34337
34337
  });
34338
34338
 
34339
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34339
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34340
34340
  function compilePredicate(predicate) {
34341
34341
  if ("and" in predicate) {
34342
34342
  const parts = predicate.and.map(compilePredicate).filter((p) => p !== undefined);
@@ -34374,7 +34374,7 @@ var init_query_spec = __esm(() => {
34374
34374
  };
34375
34375
  });
34376
34376
 
34377
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34377
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34378
34378
  function asSelectQuery(query) {
34379
34379
  return query;
34380
34380
  }
@@ -34416,7 +34416,7 @@ var init_base_dao = __esm(() => {
34416
34416
  init_query_spec();
34417
34417
  });
34418
34418
 
34419
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34419
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34420
34420
  var embeddedMigrations;
34421
34421
  var init_embedded_migrations = __esm(() => {
34422
34422
  embeddedMigrations = [
@@ -34448,7 +34448,7 @@ var init_embedded_migrations = __esm(() => {
34448
34448
  ];
34449
34449
  });
34450
34450
 
34451
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34451
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34452
34452
  var EntityDao;
34453
34453
  var init_entity_dao = __esm(() => {
34454
34454
  init_drizzle_orm();
@@ -34610,7 +34610,7 @@ var init_entity_dao = __esm(() => {
34610
34610
  };
34611
34611
  });
34612
34612
 
34613
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34613
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34614
34614
  function isPromiseLike(value) {
34615
34615
  return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
34616
34616
  }
@@ -34783,7 +34783,7 @@ var init_migrator2 = __esm(() => {
34783
34783
  init_migrator();
34784
34784
  });
34785
34785
 
34786
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/migrate.js
34786
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/migrate.js
34787
34787
  async function ensureJournalTable(adapter, table3) {
34788
34788
  await adapter.exec(`CREATE TABLE IF NOT EXISTS "${table3}" (` + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "hash text NOT NULL, " + "created_at numeric" + ")");
34789
34789
  }
@@ -34858,7 +34858,7 @@ var init_migrate = __esm(() => {
34858
34858
  init_embedded_migrations();
34859
34859
  });
34860
34860
 
34861
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34861
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34862
34862
  var QueueJobDao;
34863
34863
  var init_queue_job_dao = __esm(() => {
34864
34864
  init_drizzle_orm();
@@ -34999,7 +34999,7 @@ var init_queue_job_dao = __esm(() => {
34999
34999
  };
35000
35000
  });
35001
35001
 
35002
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/index.js
35002
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/index.js
35003
35003
  var exports_dist = {};
35004
35004
  __export(exports_dist, {
35005
35005
  embeddedMigrations: () => embeddedMigrations,
@@ -37487,7 +37487,7 @@ var init_src = __esm(() => {
37487
37487
  });
37488
37488
  });
37489
37489
 
37490
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/config.js
37490
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/config.js
37491
37491
  function parseYamlObject(text3) {
37492
37492
  let parsed;
37493
37493
  try {
@@ -37614,7 +37614,7 @@ var init_config2 = __esm(() => {
37614
37614
  };
37615
37615
  });
37616
37616
 
37617
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37617
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37618
37618
  import { appendFileSync as appendFileSync3, cpSync as cpSync2, createReadStream as createReadStream3, createWriteStream as createWriteStream3, existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync4, realpathSync as realpathSync2, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
37619
37619
  import { dirname as dirname2, resolve as resolvePath3 } from "path";
37620
37620
  function createNodeFileSystem3(root, paths) {
@@ -37701,7 +37701,7 @@ function findProjectRoot3(startDir) {
37701
37701
  }
37702
37702
  var init_file_system_node2 = () => {};
37703
37703
 
37704
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37704
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37705
37705
  var D1NotConfiguredError2, DbModuleNotInstalledError3;
37706
37706
  var init_db_errors2 = __esm(() => {
37707
37707
  D1NotConfiguredError2 = class D1NotConfiguredError2 extends Error {
@@ -37718,7 +37718,7 @@ var init_db_errors2 = __esm(() => {
37718
37718
  };
37719
37719
  });
37720
37720
 
37721
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37721
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37722
37722
  function createCfFileSystem2() {
37723
37723
  return {
37724
37724
  getProjectRoot: () => "/bundle",
@@ -37757,7 +37757,7 @@ function createCfFileSystem2() {
37757
37757
  }
37758
37758
  var UNSUPPORTED = "FileSystem is not available on Cloudflare Workers. Use D1, KV, or R2 for persistent storage.";
37759
37759
 
37760
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37760
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37761
37761
  var exports_runtime_cf = {};
37762
37762
  __export(exports_runtime_cf, {
37763
37763
  cloudflareWorkersFactory: () => cloudflareWorkersFactory2
@@ -37795,7 +37795,7 @@ var init_runtime_cf = __esm(() => {
37795
37795
  };
37796
37796
  });
37797
37797
 
37798
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37798
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37799
37799
  import { isatty as isatty2 } from "tty";
37800
37800
 
37801
37801
  class NodeProcessExecutor3 {
@@ -38181,7 +38181,7 @@ var init_process_executor2 = __esm(() => {
38181
38181
  ProcessExecutor2 = NodeProcessExecutor3;
38182
38182
  });
38183
38183
 
38184
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38184
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38185
38185
  var exports_runtime_node_bun = {};
38186
38186
  __export(exports_runtime_node_bun, {
38187
38187
  nodeBunFactory: () => nodeBunFactory3,
@@ -38249,7 +38249,7 @@ var init_runtime_node_bun2 = __esm(() => {
38249
38249
  };
38250
38250
  });
38251
38251
 
38252
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38252
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38253
38253
  function isCloudflareWorkerRuntime2() {
38254
38254
  return globalThis.navigator?.userAgent?.startsWith("Cloudflare-Workers") ?? false;
38255
38255
  }
@@ -38279,7 +38279,7 @@ function _resetRuntimeFactory2() {
38279
38279
  }
38280
38280
  var _factory, _runtimeName;
38281
38281
 
38282
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/context.js
38282
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/context.js
38283
38283
  class RuntimeContext2 {
38284
38284
  scope;
38285
38285
  runtimeName;
@@ -38369,7 +38369,7 @@ var init_context2 = __esm(() => {
38369
38369
  init_runtime_node_bun2();
38370
38370
  });
38371
38371
 
38372
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/path.js
38372
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/path.js
38373
38373
  function normalizeSeparators2(path7) {
38374
38374
  return path7.replaceAll("\\", "/");
38375
38375
  }
@@ -38492,7 +38492,7 @@ var init_path2 = __esm(() => {
38492
38492
  SEP2 = globalThis.process?.platform === "win32" ? "\\" : "/";
38493
38493
  });
38494
38494
 
38495
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38495
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38496
38496
  async function ensureDirForFile2(path7, fs2 = createNodeFileSystem3()) {
38497
38497
  await fs2.ensureDir(dirnamePath(path7));
38498
38498
  }
@@ -38543,7 +38543,7 @@ var init_fs = __esm(() => {
38543
38543
  init_path2();
38544
38544
  });
38545
38545
 
38546
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38546
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38547
38547
  function allocateId() {
38548
38548
  nextIdSeq += 1;
38549
38549
  return `pe_${Date.now().toString(36)}_${nextIdSeq.toString(36)}`;
@@ -38667,7 +38667,7 @@ function createInMemoryProcessRegistry2(options) {
38667
38667
  }
38668
38668
  var nextIdSeq = 0;
38669
38669
 
38670
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/runtime-paths.js
38670
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/runtime-paths.js
38671
38671
  function ambientRuntimePaths2() {
38672
38672
  const cwd = getProcessCwd2();
38673
38673
  return { cwd, home: getHomeDir() ?? cwd };
@@ -38677,7 +38677,7 @@ var init_runtime_paths = __esm(() => {
38677
38677
  init_path2();
38678
38678
  });
38679
38679
 
38680
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38680
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38681
38681
  async function loadStructuredConfig(path7, options = {}) {
38682
38682
  const content = await (options.fileSystem ?? createNodeFileSystem3()).readFile(path7);
38683
38683
  return await parseStructuredConfig(content, path7, options);
@@ -38954,10 +38954,10 @@ var init_schema_validation2 = __esm(() => {
38954
38954
  defaultResolve = typeof Bun !== "undefined" ? (specifier, from) => Bun.resolveSync(specifier, from) : undefined;
38955
38955
  });
38956
38956
 
38957
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/types.js
38957
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/types.js
38958
38958
  var init_types2 = () => {};
38959
38959
 
38960
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/index.js
38960
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/index.js
38961
38961
  var exports_dist2 = {};
38962
38962
  __export(exports_dist2, {
38963
38963
  writeJsonFile: () => writeJsonFile2,
@@ -41108,7 +41108,7 @@ var init_mod = __esm(() => {
41108
41108
  init_config3();
41109
41109
  });
41110
41110
 
41111
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/logger.js
41111
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/logger.js
41112
41112
  function toLogTapeLevel(level) {
41113
41113
  return level === "warn" ? "warning" : level;
41114
41114
  }
@@ -42661,7 +42661,7 @@ var require_src = __commonJS((exports) => {
42661
42661
  };
42662
42662
  });
42663
42663
 
42664
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42664
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42665
42665
  function getTelemetryConfig(configPartial = {}) {
42666
42666
  return {
42667
42667
  enabled: configPartial.enabled ?? CONFIG_DEFAULTS.enabled,
@@ -42697,7 +42697,7 @@ var init_sdk = __esm(() => {
42697
42697
  resolvedConfig = getTelemetryConfig();
42698
42698
  });
42699
42699
 
42700
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42700
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42701
42701
  function isSuppressed(tracer2) {
42702
42702
  return tracer2 === undefined && !getResolvedConfig().enabled;
42703
42703
  }
@@ -42737,7 +42737,7 @@ var init_tracing2 = __esm(() => {
42737
42737
  import_api2 = __toESM(require_src(), 1);
42738
42738
  });
42739
42739
 
42740
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42740
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42741
42741
  function getMeter() {
42742
42742
  return import_api3.metrics.getMeter(METER_NAME, METER_VERSION);
42743
42743
  }
@@ -42834,7 +42834,7 @@ var init_metrics = __esm(() => {
42834
42834
  instruments = {};
42835
42835
  });
42836
42836
 
42837
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42837
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42838
42838
  function busLogger() {
42839
42839
  if (!_busLogger)
42840
42840
  _busLogger = getLogger2("event-bus");
@@ -43079,7 +43079,7 @@ var init_event_bus = __esm(() => {
43079
43079
  init_metrics();
43080
43080
  });
43081
43081
 
43082
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
43082
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
43083
43083
  function obsLogger() {
43084
43084
  if (!_obsLogger)
43085
43085
  _obsLogger = getLogger2("event-bus.observers");
@@ -43143,7 +43143,7 @@ var init_default_observers = __esm(() => {
43143
43143
  init_event_bus();
43144
43144
  });
43145
43145
 
43146
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
43146
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
43147
43147
  function parentDir(filePath) {
43148
43148
  const idx = filePath.lastIndexOf("/");
43149
43149
  return idx <= 0 ? "." : filePath.slice(0, idx);
@@ -43241,7 +43241,7 @@ var init_file_observer = __esm(() => {
43241
43241
  init_logger3();
43242
43242
  });
43243
43243
 
43244
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/internals/drain.js
43244
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/internals/drain.js
43245
43245
  function settleWithin(promise2, deadline) {
43246
43246
  const remaining = deadline - Date.now();
43247
43247
  if (remaining <= 0)
@@ -43256,7 +43256,7 @@ function settleWithin(promise2, deadline) {
43256
43256
  return settled;
43257
43257
  }
43258
43258
 
43259
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43259
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43260
43260
  function parseInterval(cron) {
43261
43261
  const trimmed = cron.trim();
43262
43262
  const num = Number(trimmed);
@@ -43349,7 +43349,7 @@ var init_node3 = __esm(() => {
43349
43349
  init_metrics();
43350
43350
  });
43351
43351
 
43352
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43352
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43353
43353
  var exports_scheduler_node = {};
43354
43354
  __export(exports_scheduler_node, {
43355
43355
  NodeSchedulerAdapter: () => NodeSchedulerAdapter
@@ -50209,6 +50209,23 @@ var init_workflow_run_log_sink = __esm(() => {
50209
50209
  ];
50210
50210
  });
50211
50211
 
50212
+ // ../../packages/domain/src/analytics/artifact.ts
50213
+ import { createHash } from "crypto";
50214
+ function selectorDigest(selector) {
50215
+ const canonical = {
50216
+ runId: selector.runId ?? null,
50217
+ sessionId: selector.sessionId ?? null,
50218
+ since: selector.since ?? null,
50219
+ sources: selector.sources ? [...selector.sources].sort() : null,
50220
+ taskWbs: selector.taskWbs ?? null,
50221
+ until: selector.until ?? null
50222
+ };
50223
+ const json2 = JSON.stringify(canonical);
50224
+ return createHash("sha256").update(json2).digest("hex").slice(0, 8);
50225
+ }
50226
+ var HISTORY_ARTIFACT_SCHEMA_VERSION = 1;
50227
+ var init_artifact = () => {};
50228
+
50212
50229
  // ../../packages/domain/src/analytics/models.ts
50213
50230
  function resolvePricing(model) {
50214
50231
  if (model === undefined || model.length === 0)
@@ -50255,51 +50272,6 @@ function computeRecordCost(record2) {
50255
50272
  const costUsd = record2.inputTokens / 1e6 * pricing.inputPricePer1M + record2.outputTokens / 1e6 * pricing.outputPricePer1M;
50256
50273
  return { ...record2, costUsd };
50257
50274
  }
50258
- function emptyTotals() {
50259
- return {
50260
- inputTokens: 0,
50261
- outputTokens: 0,
50262
- cacheReadTokens: 0,
50263
- cacheCreationTokens: 0,
50264
- costUsd: 0,
50265
- records: 0,
50266
- recordsWithUsage: 0
50267
- };
50268
- }
50269
- function accumulate(bucket, record2) {
50270
- bucket.inputTokens += record2.inputTokens;
50271
- bucket.outputTokens += record2.outputTokens;
50272
- bucket.cacheReadTokens += record2.cacheReadTokens;
50273
- bucket.cacheCreationTokens += record2.cacheCreationTokens;
50274
- bucket.costUsd += record2.costUsd;
50275
- bucket.records += 1;
50276
- if (record2.usageReported)
50277
- bucket.recordsWithUsage += 1;
50278
- }
50279
- function aggregateCosts(records) {
50280
- const summary = {
50281
- totals: emptyTotals(),
50282
- bySource: {},
50283
- byModel: {},
50284
- daily: []
50285
- };
50286
- const dailyMap = new Map;
50287
- for (const record2 of records) {
50288
- accumulate(summary.totals, record2);
50289
- summary.bySource[record2.source] ??= emptyTotals();
50290
- accumulate(summary.bySource[record2.source], record2);
50291
- summary.byModel[record2.model] ??= emptyTotals();
50292
- accumulate(summary.byModel[record2.model], record2);
50293
- let dailyEntry = dailyMap.get(record2.date);
50294
- if (dailyEntry === undefined) {
50295
- dailyEntry = { date: record2.date, ...emptyTotals() };
50296
- dailyMap.set(record2.date, dailyEntry);
50297
- }
50298
- accumulate(dailyEntry, record2);
50299
- }
50300
- summary.daily = [...dailyMap.values()].sort(byDateAsc);
50301
- return summary;
50302
- }
50303
50275
  function cacheHitRatio(totals) {
50304
50276
  if (totals.recordsWithUsage === 0)
50305
50277
  return null;
@@ -50334,9 +50306,6 @@ function formatSummary(summary) {
50334
50306
  function formatRatio(ratio) {
50335
50307
  return ratio === null ? "n/a" : `${(ratio * 100).toFixed(1)}%`;
50336
50308
  }
50337
- function byDateAsc(a2, b) {
50338
- return a2.date.localeCompare(b.date);
50339
- }
50340
50309
  function byCostDesc([, a2], [, b]) {
50341
50310
  return b.costUsd - a2.costUsd;
50342
50311
  }
@@ -50344,6 +50313,177 @@ var init_costs = __esm(() => {
50344
50313
  init_models();
50345
50314
  });
50346
50315
 
50316
+ // ../../packages/domain/src/analytics/forensic-query.ts
50317
+ function buildMessageWhere(sel) {
50318
+ const clauses = [];
50319
+ const params = [];
50320
+ if (sel.since != null) {
50321
+ clauses.push("m.ts >= ?");
50322
+ params.push(sel.since);
50323
+ }
50324
+ if (sel.until != null) {
50325
+ clauses.push("m.ts <= ?");
50326
+ params.push(sel.until);
50327
+ }
50328
+ if (sel.sources != null && sel.sources.length > 0) {
50329
+ clauses.push(`m.source IN (${sel.sources.map(() => "?").join(", ")})`);
50330
+ params.push(...sel.sources);
50331
+ }
50332
+ if (sel.sessionId != null) {
50333
+ clauses.push("m.session_id = ?");
50334
+ params.push(sel.sessionId);
50335
+ }
50336
+ if (sel.runId != null) {
50337
+ clauses.push("m.provenance = 'spur-run'");
50338
+ clauses.push("m.run_id = ?");
50339
+ params.push(sel.runId);
50340
+ }
50341
+ if (sel.taskWbs != null) {
50342
+ clauses.push("m.provenance = 'spur-run'");
50343
+ clauses.push("m.task_wbs = ?");
50344
+ params.push(sel.taskWbs);
50345
+ }
50346
+ return { where: clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "", params };
50347
+ }
50348
+ async function messageRollup(db2, sel) {
50349
+ const { where, params } = buildMessageWhere(sel);
50350
+ return db2.queryAll(`SELECT m.source AS source, m.model AS model, DATE(m.ts) AS day,
50351
+ COUNT(*) AS messages,
50352
+ SUM(m.input_tokens) AS inputTokens,
50353
+ SUM(m.output_tokens) AS outputTokens,
50354
+ SUM(m.cache_read_tokens) AS cacheReadTokens,
50355
+ SUM(m.cache_write_tokens) AS cacheWriteTokens,
50356
+ SUM(m.cost_usd) AS costUsd,
50357
+ SUM(CASE WHEN m.input_tokens IS NOT NULL OR m.output_tokens IS NOT NULL THEN 1 ELSE 0 END) AS recordsWithUsage
50358
+ FROM history_message m
50359
+ ${where}
50360
+ GROUP BY m.source, m.model, DATE(m.ts)`, ...params);
50361
+ }
50362
+ async function toolRollup(db2, sel) {
50363
+ const { where, params } = buildMessageWhere(sel);
50364
+ return db2.queryAll(`SELECT m.source AS source, m.model AS model, DATE(m.ts) AS day,
50365
+ COUNT(*) AS toolCalls,
50366
+ SUM(tc.duration_ms) AS durationMs,
50367
+ SUM(tc.duration_ms IS NULL) AS durationUnmeasured
50368
+ FROM history_tool_call tc
50369
+ JOIN history_message m ON m.record_hash = tc.message_hash
50370
+ ${where}
50371
+ GROUP BY m.source, m.model, DATE(m.ts)`, ...params);
50372
+ }
50373
+ async function byTool(db2, sel, top) {
50374
+ const { where, params } = buildMessageWhere(sel);
50375
+ return db2.queryAll(`SELECT tc.tool_name AS toolName,
50376
+ COUNT(*) AS calls,
50377
+ SUM(tc.status = 'error') AS errors,
50378
+ SUM(tc.duration_ms) AS durationMsTotal,
50379
+ CAST(AVG(tc.duration_ms) AS INT) AS durationMsMean,
50380
+ MAX(tc.duration_ms) AS durationMsMax,
50381
+ SUM(tc.duration_ms IS NULL) AS durationUnmeasured,
50382
+ SUM(tc.result_bytes) AS resultBytes
50383
+ FROM history_tool_call tc
50384
+ JOIN history_message m ON m.record_hash = tc.message_hash
50385
+ ${where}
50386
+ GROUP BY tc.tool_name
50387
+ ORDER BY durationMsTotal DESC
50388
+ LIMIT ?`, ...params, top);
50389
+ }
50390
+ async function bySession(db2, sel, top) {
50391
+ const { where, params } = buildMessageWhere(sel);
50392
+ const msgRows = await db2.queryAll(`SELECT m.session_id AS sessionId, m.source AS source,
50393
+ MIN(m.ts) AS startedAt,
50394
+ COUNT(*) AS messages,
50395
+ SUM(m.input_tokens + m.output_tokens) AS tokens,
50396
+ SUM(m.cost_usd) AS costUsd
50397
+ FROM history_message m
50398
+ ${where}
50399
+ GROUP BY m.session_id, m.source
50400
+ ORDER BY tokens DESC
50401
+ LIMIT ?`, ...params, top);
50402
+ if (msgRows.length === 0)
50403
+ return [];
50404
+ const toolRows = await db2.queryAll(`SELECT m.session_id AS sessionId, m.source AS source,
50405
+ tc.tool_name AS toolName,
50406
+ COUNT(*) AS cnt
50407
+ FROM history_tool_call tc
50408
+ JOIN history_message m ON m.record_hash = tc.message_hash
50409
+ ${where}
50410
+ GROUP BY m.session_id, m.source, tc.tool_name`, ...params);
50411
+ const toolMap = new Map;
50412
+ for (const row of toolRows) {
50413
+ const key = `${row.sessionId}\x00${row.source}`;
50414
+ let tools = toolMap.get(key);
50415
+ if (!tools) {
50416
+ tools = new Map;
50417
+ toolMap.set(key, tools);
50418
+ }
50419
+ tools.set(row.toolName, (tools.get(row.toolName) ?? 0) + row.cnt);
50420
+ }
50421
+ return msgRows.map((msg) => {
50422
+ const key = `${msg.sessionId}\x00${msg.source}`;
50423
+ const tools = toolMap.get(key);
50424
+ let toolCalls = 0;
50425
+ let topTool = null;
50426
+ let maxCount = -1;
50427
+ if (tools) {
50428
+ for (const [name, count3] of tools) {
50429
+ toolCalls += count3;
50430
+ if (topTool === null || count3 > maxCount || count3 === maxCount && name < topTool) {
50431
+ maxCount = count3;
50432
+ topTool = name;
50433
+ }
50434
+ }
50435
+ }
50436
+ return {
50437
+ sessionId: msg.sessionId,
50438
+ source: msg.source,
50439
+ startedAt: msg.startedAt,
50440
+ messages: msg.messages,
50441
+ toolCalls,
50442
+ topTool,
50443
+ tokens: msg.tokens,
50444
+ costUsd: msg.costUsd
50445
+ };
50446
+ });
50447
+ }
50448
+ async function loops(db2, sel) {
50449
+ const { where, params } = buildMessageWhere(sel);
50450
+ const extra = where === "" ? "WHERE tc.args_digest IS NOT NULL" : `${where} AND tc.args_digest IS NOT NULL`;
50451
+ return db2.queryAll(`SELECT tc.session_id AS sessionId, tc.tool_name AS toolName,
50452
+ tc.args_digest AS argsDigest,
50453
+ COUNT(*) AS repeats,
50454
+ MIN(tc.seq) AS firstSeq,
50455
+ MAX(tc.seq) AS lastSeq
50456
+ FROM history_tool_call tc
50457
+ JOIN history_message m ON m.record_hash = tc.message_hash
50458
+ ${extra}
50459
+ GROUP BY tc.session_id, tc.tool_name, tc.args_digest
50460
+ HAVING COUNT(*) >= 3
50461
+ ORDER BY repeats DESC`, ...params);
50462
+ }
50463
+ async function drift(db2, sel) {
50464
+ const { where, params } = buildMessageWhere(sel);
50465
+ const extra = where === "" ? "WHERE m.disposition = 'unknown'" : `${where} AND m.disposition = 'unknown'`;
50466
+ return db2.queryAll(`SELECT m.source AS source, m.record_type AS recordType, COUNT(*) AS n
50467
+ FROM history_message m
50468
+ ${extra}
50469
+ GROUP BY m.source, m.record_type
50470
+ ORDER BY n DESC`, ...params);
50471
+ }
50472
+ async function sourceSummary(db2, sel) {
50473
+ const { where, params } = buildMessageWhere(sel);
50474
+ return db2.queryAll(`SELECT m.source AS source,
50475
+ COUNT(DISTINCT m.source_file) AS files,
50476
+ COUNT(*) AS messages,
50477
+ MAX(m.imported_at) AS lastImportedAt
50478
+ FROM history_message m
50479
+ ${where}
50480
+ GROUP BY m.source`, ...params);
50481
+ }
50482
+ async function countCheckpointsBySource(db2, source) {
50483
+ const row = await db2.queryFirst("SELECT COUNT(*) AS cnt FROM history_import_checkpoint WHERE source = ?", source);
50484
+ return row?.cnt ?? 0;
50485
+ }
50486
+
50347
50487
  // ../../packages/domain/src/analytics/query.ts
50348
50488
  function parsePayload(raw, table3) {
50349
50489
  try {
@@ -50358,18 +50498,6 @@ async function queryEtlRecords(db2, sourceTable, since) {
50358
50498
  const rows = since !== undefined ? await db2.queryAll(`SELECT payload_json FROM ${sourceTable} WHERE imported_at >= ?`, since) : await db2.queryAll(`SELECT payload_json FROM ${sourceTable}`);
50359
50499
  return rows.map((row) => parsePayload(row.payload_json, sourceTable));
50360
50500
  }
50361
- async function queryAllEtlRecords(db2, since) {
50362
- const results = [];
50363
- for (const table3 of SOURCE_TABLES) {
50364
- const source = table3.replace("history_etl_", "");
50365
- const rows = since !== undefined ? await db2.queryAll(`SELECT payload_json FROM ${table3} WHERE imported_at >= ?`, since) : await db2.queryAll(`SELECT payload_json FROM ${table3}`);
50366
- for (const row of rows) {
50367
- const payload = parsePayload(row.payload_json, table3);
50368
- results.push(etlToCostRecord(payload, source));
50369
- }
50370
- }
50371
- return results;
50372
- }
50373
50501
  function extractClaudeTokens(payload) {
50374
50502
  const usage = payload.usage;
50375
50503
  const absent = {
@@ -50393,26 +50521,6 @@ function extractClaudeTokens(payload) {
50393
50521
  usageReported: true
50394
50522
  };
50395
50523
  }
50396
- function etlToCostRecord(payload, source) {
50397
- const tokens = extractClaudeTokens(payload);
50398
- if (tokens.inputTokens === 0 && tokens.outputTokens === 0) {
50399
- const contentLength = payload.content?.length ?? 0;
50400
- if (contentLength > 0) {
50401
- tokens.outputTokens = Math.ceil(contentLength / 4);
50402
- }
50403
- }
50404
- return {
50405
- source,
50406
- date: payload.created_at?.slice(0, 10) ?? "unknown",
50407
- model: payload.model ?? "unknown",
50408
- inputTokens: tokens.inputTokens,
50409
- outputTokens: tokens.outputTokens,
50410
- cacheReadTokens: tokens.cacheReadTokens,
50411
- cacheCreationTokens: tokens.cacheCreationTokens,
50412
- usageReported: tokens.usageReported,
50413
- costUsd: 0
50414
- };
50415
- }
50416
50524
  var SOURCE_TABLES;
50417
50525
  var init_query2 = __esm(() => {
50418
50526
  SOURCE_TABLES = [
@@ -50422,10 +50530,144 @@ var init_query2 = __esm(() => {
50422
50530
  "history_etl_gemini",
50423
50531
  "history_etl_opencode",
50424
50532
  "history_etl_antigravity",
50425
- "history_etl_openclaw"
50533
+ "history_etl_openclaw",
50534
+ "history_etl_omp",
50535
+ "history_etl_grok",
50536
+ "history_etl_agy"
50426
50537
  ];
50427
50538
  });
50428
50539
 
50540
+ // ../../packages/domain/src/analytics/render-report.ts
50541
+ function assertArtifactVersion(actualVersion, artifactPath, expectedVersion = HISTORY_ARTIFACT_SCHEMA_VERSION) {
50542
+ if (actualVersion !== expectedVersion) {
50543
+ throw new ArtifactVersionError(artifactPath, expectedVersion, actualVersion);
50544
+ }
50545
+ }
50546
+ function fmtDur(ms) {
50547
+ return ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${Math.round(ms)}ms`;
50548
+ }
50549
+ function fmtDurOrNa(ms, bucket) {
50550
+ const allUnmeasured = bucket.toolCalls > 0 && bucket.durationUnmeasured === bucket.toolCalls;
50551
+ return allUnmeasured ? "n/a" : fmtDur(ms);
50552
+ }
50553
+ function fmtBytes(bytes) {
50554
+ if (bytes >= 1e6)
50555
+ return `${(bytes / 1e6).toFixed(1)} MB`;
50556
+ if (bytes >= 1000)
50557
+ return `${(bytes / 1000).toFixed(1)} KB`;
50558
+ return `${bytes} B`;
50559
+ }
50560
+ function artifactToSummary(artifact) {
50561
+ return {
50562
+ totals: artifact.totals,
50563
+ bySource: artifact.bySource,
50564
+ byModel: artifact.byModel,
50565
+ daily: artifact.daily
50566
+ };
50567
+ }
50568
+ function renderByTool(artifact) {
50569
+ const lines = ["Per-tool time \xB7 calls \xB7 result bytes:"];
50570
+ if (artifact.byTool.length === 0) {
50571
+ lines.push(" (no tool calls in selection)");
50572
+ return lines;
50573
+ }
50574
+ for (const t of artifact.byTool) {
50575
+ const bucket = { durationUnmeasured: t.durationUnmeasured, toolCalls: t.calls };
50576
+ lines.push(` ${t.toolName.slice(0, 26).padEnd(26)} ` + `${String(t.calls).padStart(6)} calls ${String(t.errors).padStart(5)} err ` + `${fmtDurOrNa(t.durationMsTotal, bucket).padStart(8)} total ` + `${fmtDurOrNa(t.durationMsMean, bucket).padStart(7)} mean ` + `${fmtDurOrNa(t.durationMsMax, bucket).padStart(7)} max ` + `${fmtBytes(t.resultBytes).padStart(9)}`);
50577
+ }
50578
+ return lines;
50579
+ }
50580
+ function renderLoops(artifact) {
50581
+ const lines = [`Detected loops (${artifact.loops.length}):`];
50582
+ if (artifact.loops.length === 0) {
50583
+ lines.push(" (none detected)");
50584
+ return lines;
50585
+ }
50586
+ for (const l of artifact.loops) {
50587
+ lines.push(` ${l.toolName.slice(0, 22).padEnd(22)} x${String(l.repeats).padStart(3)} ` + `${l.sessionId.slice(0, 16)} args ${l.argsDigest} seq ${l.firstSeq}-${l.lastSeq}`);
50588
+ }
50589
+ return lines;
50590
+ }
50591
+ function renderBySession(artifact) {
50592
+ const lines = [`Session leaderboard (${artifact.bySession.length}):`];
50593
+ if (artifact.bySession.length === 0) {
50594
+ lines.push(" (no sessions in selection)");
50595
+ return lines;
50596
+ }
50597
+ for (const s of artifact.bySession) {
50598
+ const tokens = (s.tokens / 1e6).toFixed(1);
50599
+ lines.push(` ${s.sessionId.slice(0, 18).padEnd(18)} ` + `${s.source.slice(0, 8).padEnd(8)} ` + `${String(s.messages).padStart(5)} msg ${String(s.toolCalls).padStart(5)} calls ` + `${tokens.padStart(6)}M tok $${s.costUsd.toFixed(2).padStart(7)}` + (s.topTool ? ` top: ${s.topTool}` : ""));
50600
+ }
50601
+ return lines;
50602
+ }
50603
+ function renderCoverage(artifact) {
50604
+ const lines = ["Coverage:"];
50605
+ if (artifact.coverage.length === 0) {
50606
+ lines.push(" (no sources)");
50607
+ return lines;
50608
+ }
50609
+ for (const c3 of artifact.coverage) {
50610
+ lines.push(` ${c3.source.slice(0, 12).padEnd(12)} ${c3.status.padEnd(7)} ` + `${String(c3.files).padStart(5)} files ${String(c3.messages).padStart(6)} msg ` + `${String(c3.toolCalls).padStart(6)} calls ${String(c3.unknownRecords).padStart(5)} unknown`);
50611
+ }
50612
+ return lines;
50613
+ }
50614
+ function renderReport(artifact) {
50615
+ const lines = [];
50616
+ lines.push(`History report \u2014 generated ${artifact.generatedAt}`);
50617
+ lines.push(`spur ${artifact.spurVersion} \xB7 schema v${artifact.schemaVersion}`);
50618
+ lines.push("");
50619
+ lines.push(formatSummary(artifactToSummary(artifact)));
50620
+ lines.push("");
50621
+ lines.push(...renderByTool(artifact));
50622
+ lines.push("");
50623
+ lines.push(...renderLoops(artifact));
50624
+ lines.push("");
50625
+ lines.push(...renderBySession(artifact));
50626
+ lines.push("");
50627
+ lines.push(...renderCoverage(artifact));
50628
+ return lines.join(`
50629
+ `);
50630
+ }
50631
+ function renderMarkdown(artifact) {
50632
+ const header = `<!-- Generated by spur history report \xB7 schema v${artifact.schemaVersion} \xB7 ${artifact.generatedAt} -->`;
50633
+ const body = renderReport(artifact);
50634
+ return `${header}
50635
+
50636
+ \`\`\`
50637
+ ${body}
50638
+ \`\`\`
50639
+ `;
50640
+ }
50641
+ function isStale(generatedAt, now2, thresholdHours = STALENESS_THRESHOLD_HOURS) {
50642
+ const ageMs = now2.getTime() - new Date(generatedAt).getTime();
50643
+ return ageMs > thresholdHours * 60 * 60 * 1000;
50644
+ }
50645
+ function stalenessBanner(generatedAt, now2, thresholdHours = STALENESS_THRESHOLD_HOURS) {
50646
+ if (!isStale(generatedAt, now2, thresholdHours))
50647
+ return null;
50648
+ const ageHours = (now2.getTime() - new Date(generatedAt).getTime()) / (60 * 60 * 1000);
50649
+ const readable2 = ageHours >= 24 ? `${(ageHours / 24).toFixed(1)} days` : `${Math.round(ageHours)} hours`;
50650
+ return `\u26A0 STALE ARTIFACT \u2014 generated ${readable2} ago (threshold ${thresholdHours}h).
50651
+ ` + "Re-run `spur history analyze` to refresh. This banner means the daily loop may have stopped.\n";
50652
+ }
50653
+ var ArtifactVersionError, STALENESS_THRESHOLD_HOURS = 36;
50654
+ var init_render_report = __esm(() => {
50655
+ init_artifact();
50656
+ init_costs();
50657
+ ArtifactVersionError = class ArtifactVersionError extends Error {
50658
+ artifactPath;
50659
+ expectedVersion;
50660
+ actualVersion;
50661
+ constructor(artifactPath, expectedVersion, actualVersion) {
50662
+ super(`Artifact ${artifactPath} has schemaVersion ${actualVersion}; this renderer understands version ${expectedVersion} only. ` + "Re-run `spur history analyze` to regenerate, or install a newer Spur.");
50663
+ this.name = "ArtifactVersionError";
50664
+ this.artifactPath = artifactPath;
50665
+ this.expectedVersion = expectedVersion;
50666
+ this.actualVersion = actualVersion;
50667
+ }
50668
+ };
50669
+ });
50670
+
50429
50671
  // ../../packages/domain/src/analytics/run-cost.ts
50430
50672
  function extractSessionId(action) {
50431
50673
  if (!action.result_json)
@@ -50503,17 +50745,56 @@ function actionCost(matchedRecords, source) {
50503
50745
  }
50504
50746
  const costRecords = [];
50505
50747
  for (const payload of matchedRecords) {
50506
- const record2 = etlToCostRecord(payload, source);
50507
- costRecords.push(computeRecordCost(record2));
50748
+ costRecords.push(computeRecordCost(payloadToCostRecord(payload, source)));
50508
50749
  }
50509
- const summary = aggregateCosts(costRecords);
50510
- const cacheHit = cacheHitRatio(summary.totals);
50750
+ const totals = foldTotals(costRecords);
50751
+ const cacheHit = cacheHitRatio(totals);
50511
50752
  return {
50512
- totals: summary.totals,
50753
+ totals,
50513
50754
  cacheHit,
50514
50755
  estimated: false
50515
50756
  };
50516
50757
  }
50758
+ function foldTotals(records) {
50759
+ const totals = {
50760
+ inputTokens: 0,
50761
+ outputTokens: 0,
50762
+ cacheReadTokens: 0,
50763
+ cacheWriteTokens: 0,
50764
+ costUsd: 0,
50765
+ records: 0,
50766
+ recordsWithUsage: 0,
50767
+ messages: 0,
50768
+ toolCalls: 0,
50769
+ durationMs: 0,
50770
+ durationUnmeasured: 0
50771
+ };
50772
+ for (const record2 of records) {
50773
+ totals.inputTokens += record2.inputTokens;
50774
+ totals.outputTokens += record2.outputTokens;
50775
+ totals.cacheReadTokens += record2.cacheReadTokens;
50776
+ totals.cacheWriteTokens += record2.cacheCreationTokens;
50777
+ totals.costUsd += record2.costUsd;
50778
+ totals.records += 1;
50779
+ if (record2.usageReported)
50780
+ totals.recordsWithUsage += 1;
50781
+ }
50782
+ return totals;
50783
+ }
50784
+ function payloadToCostRecord(payload, source) {
50785
+ const tokens = extractClaudeTokens(payload);
50786
+ return {
50787
+ source,
50788
+ date: payload.created_at?.slice(0, 10) ?? "unknown",
50789
+ model: payload.model ?? "unknown",
50790
+ inputTokens: tokens.inputTokens,
50791
+ outputTokens: tokens.outputTokens,
50792
+ cacheReadTokens: tokens.cacheReadTokens,
50793
+ cacheCreationTokens: tokens.cacheCreationTokens,
50794
+ usageReported: tokens.usageReported,
50795
+ costUsd: 0
50796
+ };
50797
+ }
50517
50798
  function actionCostEstimated(matchedRecords, source) {
50518
50799
  const cost = actionCost(matchedRecords, source);
50519
50800
  return matchedRecords.length === 0 ? cost : { ...cost, estimated: true };
@@ -50527,10 +50808,14 @@ var init_run_cost = __esm(() => {
50527
50808
  inputTokens: 0,
50528
50809
  outputTokens: 0,
50529
50810
  cacheReadTokens: 0,
50530
- cacheCreationTokens: 0,
50811
+ cacheWriteTokens: 0,
50531
50812
  costUsd: 0,
50532
50813
  records: 0,
50533
- recordsWithUsage: 0
50814
+ recordsWithUsage: 0,
50815
+ messages: 0,
50816
+ toolCalls: 0,
50817
+ durationMs: 0,
50818
+ durationUnmeasured: 0
50534
50819
  },
50535
50820
  cacheHit: null,
50536
50821
  estimated: false
@@ -50539,9 +50824,11 @@ var init_run_cost = __esm(() => {
50539
50824
 
50540
50825
  // ../../packages/domain/src/analytics/index.ts
50541
50826
  var init_analytics = __esm(() => {
50827
+ init_artifact();
50542
50828
  init_costs();
50543
50829
  init_models();
50544
50830
  init_query2();
50831
+ init_render_report();
50545
50832
  init_run_cost();
50546
50833
  });
50547
50834
 
@@ -51495,7 +51782,7 @@ var init_drizzle_zod = __esm(() => {
51495
51782
  };
51496
51783
  });
51497
51784
 
51498
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
51785
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
51499
51786
  function sqlExpressionToText(value) {
51500
51787
  if (typeof value !== "object" || value === null || !("queryChunks" in value)) {
51501
51788
  return;
@@ -51518,7 +51805,7 @@ function getDrizzleTableName(table3) {
51518
51805
  return String(table3[nameSym]);
51519
51806
  }
51520
51807
 
51521
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
51808
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
51522
51809
  function quoteIdent(name) {
51523
51810
  return `"${name.replace(/"/g, '""')}"`;
51524
51811
  }
@@ -51612,7 +51899,7 @@ var init_ddl = __esm(() => {
51612
51899
  init_sqlite_core();
51613
51900
  });
51614
51901
 
51615
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
51902
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
51616
51903
  function defineTable(name, columns2) {
51617
51904
  const table3 = sqliteTable(name, columns2);
51618
51905
  let insert2;
@@ -51646,7 +51933,7 @@ var init_define_table = __esm(() => {
51646
51933
  init_ddl();
51647
51934
  });
51648
51935
 
51649
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.22+ba90974056df6a6a/node_modules/@gobing-ai/ts-db/dist/schema/index.js
51936
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.23+d18ad408e4d1e377/node_modules/@gobing-ai/ts-db/dist/schema/index.js
51650
51937
  var init_schema = __esm(() => {
51651
51938
  init_sqlite_core();
51652
51939
  init_define_table();
@@ -52271,7 +52558,7 @@ var init_dao = __esm(() => {
52271
52558
  init_workspace_dao();
52272
52559
  });
52273
52560
 
52274
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
52561
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
52275
52562
  var WorkflowValidationError, FSMError, RunCollisionError, WorkflowResumeError;
52276
52563
  var init_errors6 = __esm(() => {
52277
52564
  WorkflowValidationError = class WorkflowValidationError extends Error {
@@ -52306,12 +52593,12 @@ var init_errors6 = __esm(() => {
52306
52593
  };
52307
52594
  });
52308
52595
 
52309
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
52596
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
52310
52597
  var init_event_bus2 = __esm(() => {
52311
52598
  init_event_bus();
52312
52599
  });
52313
52600
 
52314
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/api-client.js
52601
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/api-client.js
52315
52602
  function sanitizeUrlForObservability(url2) {
52316
52603
  try {
52317
52604
  const parsed = new URL(url2);
@@ -52541,12 +52828,12 @@ var init_api_client = __esm(() => {
52541
52828
  };
52542
52829
  });
52543
52830
 
52544
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
52831
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
52545
52832
  var init_telemetry = __esm(() => {
52546
52833
  init_tracing2();
52547
52834
  });
52548
52835
 
52549
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/index.js
52836
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/index.js
52550
52837
  var init_dist6 = __esm(() => {
52551
52838
  init_api_client();
52552
52839
  init_event_bus2();
@@ -52554,7 +52841,7 @@ var init_dist6 = __esm(() => {
52554
52841
  init_telemetry();
52555
52842
  });
52556
52843
 
52557
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
52844
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
52558
52845
  function runtimeBuiltins(workflowName, stateOrNodeId, runId, transitionsTaken, mode) {
52559
52846
  return {
52560
52847
  workflow: workflowName,
@@ -52813,7 +53100,7 @@ var init_run_lifecycle = __esm(() => {
52813
53100
  ];
52814
53101
  });
52815
53102
 
52816
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
53103
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
52817
53104
  var RESERVED_VAR_NAMES, IDENTIFIER, VarsSchema, EnvSchema, ActionDefSchema, GuardDefSchema, StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema, WorkflowDefSchema;
52818
53105
  var init_schema2 = __esm(() => {
52819
53106
  init_zod();
@@ -52898,7 +53185,7 @@ var init_schema2 = __esm(() => {
52898
53185
  WorkflowDefSchema = exports_external.union([StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema]);
52899
53186
  });
52900
53187
 
52901
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
53188
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
52902
53189
  async function loadWorkflowDef(path9, options = {}) {
52903
53190
  return parseWorkflowDef(await loadStructuredConfig(path9, options), path9);
52904
53191
  }
@@ -53065,7 +53352,7 @@ var init_config4 = __esm(() => {
53065
53352
  RUNTIME_TEMPLATE_NAMESPACES = new Set(RUNTIME_BUILTIN_KEYS);
53066
53353
  });
53067
53354
 
53068
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
53355
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
53069
53356
  class CapabilityRegistry {
53070
53357
  kind;
53071
53358
  capabilities = new Map;
@@ -53096,7 +53383,7 @@ class CapabilityRegistry {
53096
53383
  }
53097
53384
  }
53098
53385
 
53099
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
53386
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
53100
53387
  function assertRelativeExtensionPath(path9, options = {}) {
53101
53388
  const where = options.sourceName !== undefined ? ` declared by "${options.sourceName}"` : "";
53102
53389
  if (/^([/\\]|[A-Za-z]:[/\\])/.test(path9)) {
@@ -53107,20 +53394,20 @@ function assertRelativeExtensionPath(path9, options = {}) {
53107
53394
  }
53108
53395
  }
53109
53396
 
53110
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
53397
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
53111
53398
  var init_extension_loader = () => {};
53112
53399
 
53113
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
53400
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
53114
53401
  var init_extension = __esm(() => {
53115
53402
  init_extension_loader();
53116
53403
  });
53117
53404
 
53118
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.22+b5a3efec10d9c5ce/node_modules/@gobing-ai/ts-runtime/dist/extension.js
53405
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.23+b3390312fcba4228/node_modules/@gobing-ai/ts-runtime/dist/extension.js
53119
53406
  var init_extension2 = __esm(() => {
53120
53407
  init_extension();
53121
53408
  });
53122
53409
 
53123
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
53410
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
53124
53411
  class WorkflowEngineHost {
53125
53412
  lifecycleBus;
53126
53413
  actions = new CapabilityRegistry("workflow action");
@@ -53289,7 +53576,7 @@ var init_host = __esm(() => {
53289
53576
  init_errors6();
53290
53577
  });
53291
53578
 
53292
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
53579
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
53293
53580
  var WORKFLOW_ENGINE_SCHEMA_SQL;
53294
53581
  var init_schema_sql = __esm(() => {
53295
53582
  WORKFLOW_ENGINE_SCHEMA_SQL = `
@@ -53362,7 +53649,7 @@ CREATE TABLE IF NOT EXISTS action_runs (
53362
53649
  `.trim();
53363
53650
  });
53364
53651
 
53365
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
53652
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
53366
53653
  async function applyWorkflowEngineSchema(db2) {
53367
53654
  for (const statement of WORKFLOW_ENGINE_SCHEMA_SQL.split(";")) {
53368
53655
  const sql4 = statement.trim();
@@ -53651,7 +53938,7 @@ var init_persistence = __esm(() => {
53651
53938
  init_schema_sql();
53652
53939
  });
53653
53940
 
53654
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
53941
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
53655
53942
  function mergeVars(workflowVars = {}, overrideVars = {}) {
53656
53943
  return { ...workflowVars, ...overrideVars };
53657
53944
  }
@@ -53711,7 +53998,7 @@ var init_variables = __esm(() => {
53711
53998
  TEMPLATE_REF = /\$\{([^}]+)\}/g;
53712
53999
  });
53713
54000
 
53714
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
54001
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
53715
54002
  async function runActionStep(action, vars, deps) {
53716
54003
  const { host, persistence, lifecycle, stateOrNodeId, runId } = deps;
53717
54004
  const resolved = resolveTemplates(action.options ?? {}, {
@@ -53769,7 +54056,7 @@ var init_action_step = __esm(() => {
53769
54056
  init_variables();
53770
54057
  });
53771
54058
 
53772
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
54059
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
53773
54060
  class StateMachineDriver {
53774
54061
  options;
53775
54062
  constructor(options) {
@@ -53905,7 +54192,7 @@ var init_state_machine = __esm(() => {
53905
54192
  EMPTY_OUTCOME = { outcome: "completed", result: undefined };
53906
54193
  });
53907
54194
 
53908
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
54195
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
53909
54196
  class TransitionFlowDriver {
53910
54197
  options;
53911
54198
  constructor(options) {
@@ -54024,7 +54311,7 @@ var init_transition_flow = __esm(() => {
54024
54311
  init_variables();
54025
54312
  });
54026
54313
 
54027
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
54314
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
54028
54315
  class WorkflowService {
54029
54316
  host;
54030
54317
  persistence;
@@ -54241,7 +54528,7 @@ var init_service = __esm(() => {
54241
54528
  init_variables();
54242
54529
  });
54243
54530
 
54244
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
54531
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
54245
54532
  var init_dist7 = __esm(() => {
54246
54533
  init_config4();
54247
54534
  init_host();
@@ -54250,8 +54537,8 @@ var init_dist7 = __esm(() => {
54250
54537
  init_service();
54251
54538
  });
54252
54539
 
54253
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
54254
- import { createHash } from "crypto";
54540
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
54541
+ import { createHash as createHash2 } from "crypto";
54255
54542
  function stableJson(value) {
54256
54543
  if (Array.isArray(value)) {
54257
54544
  return `[${value.map((entry) => entry === undefined ? "null" : stableJson(entry)).join(",")}]`;
@@ -54263,11 +54550,11 @@ function stableJson(value) {
54263
54550
  return JSON.stringify(value) ?? "null";
54264
54551
  }
54265
54552
  function sha256(value) {
54266
- return createHash("sha256").update(stableJson(value)).digest("hex");
54553
+ return createHash2("sha256").update(stableJson(value)).digest("hex");
54267
54554
  }
54268
54555
  var init_hash = () => {};
54269
54556
 
54270
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
54557
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/errors.js
54271
54558
  var HistoryImportError;
54272
54559
  var init_errors7 = __esm(() => {
54273
54560
  HistoryImportError = class HistoryImportError extends Error {
@@ -54280,7 +54567,7 @@ var init_errors7 = __esm(() => {
54280
54567
  };
54281
54568
  });
54282
54569
 
54283
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
54570
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/schema-sql.js
54284
54571
  var HISTORY_IMPORT_SCHEMA_SQL;
54285
54572
  var init_schema_sql2 = __esm(() => {
54286
54573
  HISTORY_IMPORT_SCHEMA_SQL = `
@@ -54424,7 +54711,7 @@ CREATE INDEX IF NOT EXISTS idx_history_tool_call_message_hash
54424
54711
  `.trim();
54425
54712
  });
54426
54713
 
54427
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/mappers.js
54714
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/mappers.js
54428
54715
  function identityFieldMap(keys) {
54429
54716
  const map2 = {};
54430
54717
  for (const key of keys) {
@@ -55357,7 +55644,7 @@ var init_mappers = __esm(() => {
55357
55644
  GROK_SCHEMA = passthroughSchema;
55358
55645
  });
55359
55646
 
55360
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
55647
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/sources.js
55361
55648
  function firstString(...values) {
55362
55649
  for (const value of values) {
55363
55650
  if (typeof value === "string" && value.length > 0)
@@ -55511,7 +55798,7 @@ var init_sources = __esm(() => {
55511
55798
  };
55512
55799
  });
55513
55800
 
55514
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/jsonl-importer-dao.js
55801
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/jsonl-importer-dao.js
55515
55802
  function targetTableFor(table3) {
55516
55803
  if (!VALID_TABLE_NAME.test(table3)) {
55517
55804
  throw new HistoryImportError(`Invalid history ETL target table: ${table3}`, { table: table3 });
@@ -55662,7 +55949,7 @@ var init_jsonl_importer_dao = __esm(() => {
55662
55949
  _ensuredTables = new Set;
55663
55950
  });
55664
55951
 
55665
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
55952
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/redaction.js
55666
55953
  function redactValue(value, rules = DEFAULT_REDACTION_RULES) {
55667
55954
  if (typeof value === "string") {
55668
55955
  return rules.reduce((current, rule) => current.replace(rule.pattern, rule.replacement), value);
@@ -55699,7 +55986,7 @@ var init_redaction = __esm(() => {
55699
55986
  ];
55700
55987
  });
55701
55988
 
55702
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
55989
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/importer.js
55703
55990
  async function runJsonlImport(source, options) {
55704
55991
  const definition = resolveSourceDefinition(source);
55705
55992
  const resolvedSource = definition.source;
@@ -55862,7 +56149,7 @@ function normalizeRecord(definition, raw, context4) {
55862
56149
  }
55863
56150
  async function discoverFiles(definition, roots, files, fileSystem, paths) {
55864
56151
  if (files !== undefined && files.length > 0) {
55865
- return files.map((file2) => resolvePath4(file2)).sort();
56152
+ return files.map((file2) => resolvePath4(file2)).map((file2) => normalizeSourceFilePath(file2, fileSystem)).sort();
55866
56153
  }
55867
56154
  const ambient = paths ?? ambientRuntimePaths2();
55868
56155
  const resolvedRoots = roots !== undefined ? roots.map((root) => resolvePath4(ambient.cwd, root)) : definition.defaultRoots.map((root) => resolvePath4(ambient.home, root));
@@ -55875,16 +56162,25 @@ async function discoverFiles(definition, roots, files, fileSystem, paths) {
55875
56162
  continue;
55876
56163
  if (stat.isFile()) {
55877
56164
  if (matchesPattern(root, definition.filePatterns))
55878
- found.add(root);
56165
+ found.add(normalizeSourceFilePath(root, fileSystem));
55879
56166
  continue;
55880
56167
  }
55881
56168
  for (const file2 of await walkDir2(root, fileSystem)) {
55882
56169
  if (matchesPattern(file2, definition.filePatterns))
55883
- found.add(file2);
56170
+ found.add(normalizeSourceFilePath(file2, fileSystem));
55884
56171
  }
55885
56172
  }
55886
56173
  return [...found].sort();
55887
56174
  }
56175
+ function normalizeSourceFilePath(path9, fileSystem) {
56176
+ if (!fileSystem.realPath)
56177
+ return path9;
56178
+ try {
56179
+ return fileSystem.realPath(path9);
56180
+ } catch {
56181
+ return path9;
56182
+ }
56183
+ }
55888
56184
  function matchesPattern(path9, patterns) {
55889
56185
  return patterns.some((pattern) => {
55890
56186
  if (pattern === "*.jsonl")
@@ -55912,13 +56208,13 @@ var init_importer = __esm(() => {
55912
56208
  init_sources();
55913
56209
  });
55914
56210
 
55915
- // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.22+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
56211
+ // ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.23+d5c29f764bf0e6e0/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/index.js
55916
56212
  var init_dist8 = __esm(() => {
55917
56213
  init_importer();
55918
56214
  init_schema_sql2();
55919
56215
  });
55920
56216
 
55921
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
56217
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
55922
56218
  function collectExtensions(sourceName, sourceDir, extensions) {
55923
56219
  if (extensions === undefined)
55924
56220
  return [];
@@ -55934,7 +56230,7 @@ var init_extensions = __esm(() => {
55934
56230
  init_dist5();
55935
56231
  });
55936
56232
 
55937
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
56233
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
55938
56234
  function createFinding(rule, message, filePath, extras = {}) {
55939
56235
  return {
55940
56236
  ruleId: rule.id,
@@ -56005,7 +56301,7 @@ var init_types3 = __esm(() => {
56005
56301
  });
56006
56302
  });
56007
56303
 
56008
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
56304
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
56009
56305
  async function loadPreset(name, options) {
56010
56306
  const merged = await buildMergedRoots(options.roots.map((root) => resolvePath4(root)), options.fileSystem);
56011
56307
  const presetPath = findMergedPreset(merged, name);
@@ -56220,7 +56516,7 @@ var init_loader2 = __esm(() => {
56220
56516
  FIX_MODE_AUTHORITY = { none: 0, suggest: 1, auto: 2 };
56221
56517
  });
56222
56518
 
56223
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
56519
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
56224
56520
  function normalizeFindingPath(filePath) {
56225
56521
  if (!filePath || isAbsolutePath2(filePath))
56226
56522
  return null;
@@ -56285,7 +56581,7 @@ var init_test_stub_fixer = __esm(() => {
56285
56581
  realFileSystem = createNodeFileSystem3();
56286
56582
  });
56287
56583
 
56288
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
56584
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
56289
56585
  function registerBuiltinFixers(host, exec) {
56290
56586
  const regexFixer = new RegexFixerProvider;
56291
56587
  const pathFixer = new PathFixerProvider;
@@ -56488,7 +56784,7 @@ var init_fixers = __esm(() => {
56488
56784
  };
56489
56785
  });
56490
56786
 
56491
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
56787
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
56492
56788
  function getAgentSessionCapability(agent) {
56493
56789
  return AGENT_SESSION_CAPABILITY[agent];
56494
56790
  }
@@ -56780,7 +57076,7 @@ var init_shims = __esm(() => {
56780
57076
  ALIAS_TO_CANONICAL = Object.fromEntries(Object.values(AGENT_SHIMS).flatMap((shim) => (shim.aliases ?? []).map((alias3) => [alias3, shim.name])));
56781
57077
  });
56782
57078
 
56783
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
57079
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
56784
57080
  function buildIdentityPreamble(ctx) {
56785
57081
  const sections = [
56786
57082
  `You are agent \`${ctx.agentId}\` (${ctx.agentType}) in workspace \`${ctx.workspace}\`.`
@@ -56840,7 +57136,7 @@ var init_identity = __esm(() => {
56840
57136
  init_dist5();
56841
57137
  });
56842
57138
 
56843
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
57139
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
56844
57140
  function isClaudeStyleSlashCommand(input) {
56845
57141
  return SLASH_COMMAND_RE.test(input);
56846
57142
  }
@@ -56868,7 +57164,7 @@ var init_slash_command = __esm(() => {
56868
57164
  SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
56869
57165
  });
56870
57166
 
56871
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
57167
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
56872
57168
  function buildCorrelationEnv(correlation) {
56873
57169
  return {
56874
57170
  [AGENT_RUN_ID_ENV]: correlation.runId,
@@ -57004,7 +57300,7 @@ var init_ai_runner = __esm(() => {
57004
57300
  init_slash_command();
57005
57301
  });
57006
57302
 
57007
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
57303
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
57008
57304
  class AgentDetector {
57009
57305
  runner;
57010
57306
  timeout;
@@ -57080,7 +57376,7 @@ var init_agent_detector = __esm(() => {
57080
57376
  VERSION_PATTERN = /(?<version>\d+\.\d+(?:\.\d+)?)/;
57081
57377
  });
57082
57378
 
57083
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
57379
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
57084
57380
  function validateAgentId(id) {
57085
57381
  if (!/^[a-z][a-z0-9_-]{1,63}$/.test(id)) {
57086
57382
  throw new ValueError(`Invalid agent id "${id}": expected 2-64 chars, lowercase alphanumeric, "_" or "-"`);
@@ -57177,7 +57473,7 @@ var init_agent_spec = __esm(() => {
57177
57473
  };
57178
57474
  });
57179
57475
 
57180
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
57476
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
57181
57477
  function isNonEmpty(value) {
57182
57478
  return value !== undefined && value.trim().length > 0;
57183
57479
  }
@@ -57282,7 +57578,7 @@ var init_auth_shims = __esm(() => {
57282
57578
  };
57283
57579
  });
57284
57580
 
57285
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
57581
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
57286
57582
  class ModelHealthProbeRegistry {
57287
57583
  probes = new Map;
57288
57584
  register(providerPrefix, probe) {
@@ -57390,7 +57686,7 @@ var init_model_health_probe = __esm(() => {
57390
57686
  };
57391
57687
  });
57392
57688
 
57393
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
57689
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
57394
57690
  class DoctorRunner {
57395
57691
  detector;
57396
57692
  runner;
@@ -57527,15 +57823,15 @@ var init_doctor_runner = __esm(() => {
57527
57823
  init_model_health_probe();
57528
57824
  });
57529
57825
 
57530
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
57826
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
57531
57827
  var init_events = () => {};
57532
57828
 
57533
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
57829
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
57534
57830
  function formatMessage(msg) {
57535
57831
  return `[task from=${msg.fromId ?? "operator"} id=${msg.id}] ${msg.body}`;
57536
57832
  }
57537
57833
 
57538
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
57834
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
57539
57835
  import { Buffer as Buffer5 } from "buffer";
57540
57836
 
57541
57837
  class TeamAgentProcess {
@@ -57669,7 +57965,7 @@ var init_team_agent_process = __esm(() => {
57669
57965
  init_dist5();
57670
57966
  });
57671
57967
 
57672
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
57968
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
57673
57969
  class TeamOrchestrator {
57674
57970
  configDir;
57675
57971
  inbox;
@@ -57798,7 +58094,7 @@ var init_team_orchestrator = __esm(() => {
57798
58094
  init_team_agent_process();
57799
58095
  });
57800
58096
 
57801
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.22+329d9eaeac30e7d8/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
58097
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.23+60034aec79d6ac9d/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
57802
58098
  var exports_dist3 = {};
57803
58099
  __export(exports_dist3, {
57804
58100
  validateAgentId: () => validateAgentId,
@@ -57850,7 +58146,7 @@ var init_dist9 = __esm(() => {
57850
58146
  init_team_orchestrator();
57851
58147
  });
57852
58148
 
57853
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
58149
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
57854
58150
  function stringArray(value) {
57855
58151
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
57856
58152
  }
@@ -57888,7 +58184,7 @@ function parseInlineFlags(source) {
57888
58184
  return { flags, rest: source.slice(match[0].length) };
57889
58185
  }
57890
58186
 
57891
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
58187
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
57892
58188
  function matchesAny(path9, patterns) {
57893
58189
  if (patterns === undefined || patterns.length === 0)
57894
58190
  return true;
@@ -57936,7 +58232,7 @@ function escapeRegExp(value) {
57936
58232
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
57937
58233
  }
57938
58234
 
57939
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
58235
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
57940
58236
  async function discoverFiles2(options) {
57941
58237
  const fs3 = options.fs ?? createNodeFileSystem3();
57942
58238
  const allFiles = await walkDir2(options.workdir, fs3, DEFAULT_EXCLUDES);
@@ -57964,12 +58260,12 @@ var init_file_discovery = __esm(() => {
57964
58260
  DEFAULT_EXCLUDES = new Set([".git", "node_modules", "dist", ".coverage", ".astro", ".wrangler"]);
57965
58261
  });
57966
58262
 
57967
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
58263
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
57968
58264
  var init_file_utils = __esm(() => {
57969
58265
  init_file_discovery();
57970
58266
  });
57971
58267
 
57972
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
58268
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
57973
58269
  class AgentDetectionEvaluator {
57974
58270
  detector;
57975
58271
  constructor(detector = new AgentDetector) {
@@ -57997,7 +58293,7 @@ var init_agent_detection_evaluator = __esm(() => {
57997
58293
  init_file_utils();
57998
58294
  });
57999
58295
 
58000
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
58296
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
58001
58297
  class CoverageGateEvaluator {
58002
58298
  constructor() {}
58003
58299
  async evaluate(rule, context4) {
@@ -58081,7 +58377,7 @@ var init_coverage_gate_evaluator = __esm(() => {
58081
58377
  init_file_utils();
58082
58378
  });
58083
58379
 
58084
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
58380
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
58085
58381
  class ExitCodeEvaluator {
58086
58382
  executor;
58087
58383
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -58117,7 +58413,7 @@ var init_exit_code_evaluator = __esm(() => {
58117
58413
  init_file_utils();
58118
58414
  });
58119
58415
 
58120
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
58416
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
58121
58417
  class ForbiddenImportEvaluator {
58122
58418
  constructor() {}
58123
58419
  async evaluate(rule, context4) {
@@ -58198,7 +58494,7 @@ var init_forbidden_import_evaluator = __esm(() => {
58198
58494
  init_file_utils();
58199
58495
  });
58200
58496
 
58201
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
58497
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
58202
58498
  class ImportBoundaryEvaluator {
58203
58499
  async evaluate(rule, context4) {
58204
58500
  const config4 = rule.evaluator.config ?? {};
@@ -58291,7 +58587,7 @@ var init_import_boundary_evaluator = __esm(() => {
58291
58587
  init_file_utils();
58292
58588
  });
58293
58589
 
58294
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
58590
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
58295
58591
  class PathEvaluator {
58296
58592
  constructor() {}
58297
58593
  async evaluate(rule, context4) {
@@ -58352,7 +58648,7 @@ var init_path_evaluator = __esm(() => {
58352
58648
  init_file_utils();
58353
58649
  });
58354
58650
 
58355
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
58651
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
58356
58652
  class RegexEvaluator {
58357
58653
  constructor() {}
58358
58654
  async evaluate(rule, context4) {
@@ -58430,7 +58726,7 @@ var init_regex_evaluator = __esm(() => {
58430
58726
  init_file_utils();
58431
58727
  });
58432
58728
 
58433
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
58729
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
58434
58730
  class RipgrepEvaluator {
58435
58731
  executor;
58436
58732
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -58523,7 +58819,7 @@ var init_ripgrep_evaluator = __esm(() => {
58523
58819
  init_file_utils();
58524
58820
  });
58525
58821
 
58526
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
58822
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
58527
58823
  class SchemaArtifactEvaluator {
58528
58824
  constructor() {}
58529
58825
  async evaluate(rule, context4) {
@@ -58601,7 +58897,7 @@ var init_schema_artifact_evaluator = __esm(() => {
58601
58897
  init_file_utils();
58602
58898
  });
58603
58899
 
58604
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
58900
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
58605
58901
  class SecretsScannerEvaluator {
58606
58902
  constructor() {}
58607
58903
  async evaluate(rule, context4) {
@@ -58669,7 +58965,7 @@ var init_secrets_scanner_evaluator = __esm(() => {
58669
58965
  ALL_CATEGORIES = Object.keys(BUILTIN_PATTERNS);
58670
58966
  });
58671
58967
 
58672
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
58968
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
58673
58969
  class SgEvaluator {
58674
58970
  executor;
58675
58971
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -58766,7 +59062,7 @@ var init_sg_evaluator = __esm(() => {
58766
59062
  init_file_utils();
58767
59063
  });
58768
59064
 
58769
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
59065
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
58770
59066
  class TypeScriptTestPathResolver {
58771
59067
  name = "typescript";
58772
59068
  constructor() {}
@@ -58849,7 +59145,7 @@ function testify(rel) {
58849
59145
  return `${dir}test_${base2}`;
58850
59146
  }
58851
59147
 
58852
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
59148
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
58853
59149
  class TestLocationEvaluator {
58854
59150
  resolvers;
58855
59151
  constructor(resolvers) {
@@ -58924,7 +59220,7 @@ var init_test_location_evaluator = __esm(() => {
58924
59220
  TYPESCRIPT_FALLBACK = new TypeScriptTestPathResolver;
58925
59221
  });
58926
59222
 
58927
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
59223
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
58928
59224
  class TsdocExportEvaluator {
58929
59225
  constructor() {}
58930
59226
  async evaluate(rule, context4) {
@@ -59009,7 +59305,7 @@ var init_tsdoc_export_evaluator = __esm(() => {
59009
59305
  };
59010
59306
  });
59011
59307
 
59012
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
59308
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
59013
59309
  class JsonFormatter {
59014
59310
  constructor() {}
59015
59311
  format(result) {
@@ -59017,7 +59313,7 @@ class JsonFormatter {
59017
59313
  }
59018
59314
  }
59019
59315
 
59020
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
59316
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
59021
59317
  class TextFormatter {
59022
59318
  constructor() {}
59023
59319
  format(result) {
@@ -59031,7 +59327,7 @@ class TextFormatter {
59031
59327
  }
59032
59328
  }
59033
59329
 
59034
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
59330
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
59035
59331
  function registerBuiltins(host, executor) {
59036
59332
  const path9 = new PathEvaluator;
59037
59333
  host.evaluators.register("regex", new RegexEvaluator, "builtin");
@@ -59071,7 +59367,7 @@ var init_builtins = __esm(() => {
59071
59367
  init_tsdoc_export_evaluator();
59072
59368
  });
59073
59369
 
59074
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
59370
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
59075
59371
  class RuleEngineHost {
59076
59372
  evaluators;
59077
59373
  formatters;
@@ -59088,7 +59384,7 @@ var init_rule_engine_host = __esm(() => {
59088
59384
  init_extension2();
59089
59385
  });
59090
59386
 
59091
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
59387
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
59092
59388
  class RuleEngine {
59093
59389
  host;
59094
59390
  events;
@@ -59259,7 +59555,7 @@ var init_engine = __esm(() => {
59259
59555
  init_types3();
59260
59556
  });
59261
59557
 
59262
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
59558
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
59263
59559
  async function bundledRulesRoot() {
59264
59560
  if (cachedRoot2 !== undefined)
59265
59561
  return cachedRoot2;
@@ -59310,7 +59606,7 @@ var init_bundled_rules = __esm(() => {
59310
59606
  init_dist5();
59311
59607
  });
59312
59608
 
59313
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
59609
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
59314
59610
  class DbRulePersistenceAdapter {
59315
59611
  db;
59316
59612
  constructor(db2) {
@@ -59344,7 +59640,7 @@ class DbRulePersistenceAdapter {
59344
59640
  }
59345
59641
  }
59346
59642
 
59347
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
59643
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
59348
59644
  var RULE_ENGINE_SCHEMA_SQL = `
59349
59645
  CREATE TABLE IF NOT EXISTS rule_runs (
59350
59646
  id TEXT PRIMARY KEY,
@@ -59390,10 +59686,10 @@ CREATE TABLE IF NOT EXISTS rule_eval_runs (
59390
59686
  CREATE INDEX IF NOT EXISTS idx_rule_eval_runs_run_id ON rule_eval_runs (run_id);
59391
59687
  `;
59392
59688
 
59393
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
59689
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
59394
59690
  var init_persistence2 = () => {};
59395
59691
 
59396
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.22+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
59692
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.23+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
59397
59693
  var init_dist10 = __esm(() => {
59398
59694
  init_extensions();
59399
59695
  init_loader2();
@@ -59564,6 +59860,8 @@ ALTER TABLE system_events ADD COLUMN sequence INTEGER;
59564
59860
 
59565
59861
  CREATE INDEX IF NOT EXISTS idx_system_events_run_id ON system_events (run_id);
59566
59862
  CREATE INDEX IF NOT EXISTS idx_system_events_entity ON system_events (entity_kind, entity_id);
59863
+ `, HISTORY_MESSAGE_RUN_INDEX_SCHEMA_SQL = `
59864
+ CREATE INDEX IF NOT EXISTS idx_history_message_provenance_run ON history_message (provenance, run_id);
59567
59865
  `, CLI_MIGRATIONS, CLI_MIGRATION_FILE_MARKER = "_spur_cli_";
59568
59866
  var init_migrations = __esm(() => {
59569
59867
  init_dist7();
@@ -59609,11 +59907,12 @@ ${SYSTEM_EVENTS_SCHEMA_SQL}
59609
59907
  id: "0008_spur_cli_system_events_correlation",
59610
59908
  sql: SYSTEM_EVENTS_CORRELATION_COLUMNS_SCHEMA_SQL,
59611
59909
  addColumnIfMissing: { table: "system_events", column: "sequence" }
59612
- }
59910
+ },
59911
+ { id: "0009_spur_cli_history_message_run_idx", sql: HISTORY_MESSAGE_RUN_INDEX_SCHEMA_SQL }
59613
59912
  ];
59614
59913
  });
59615
59914
 
59616
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
59915
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
59617
59916
  function queueLogger() {
59618
59917
  if (!_queueLogger)
59619
59918
  _queueLogger = getLogger2("job-queue");
@@ -59890,7 +60189,7 @@ var init_db_job_queue = __esm(() => {
59890
60189
  init_tracing2();
59891
60190
  });
59892
60191
 
59893
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
60192
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
59894
60193
  var exports_job_queue_db = {};
59895
60194
  __export(exports_job_queue_db, {
59896
60195
  DBQueueConsumer: () => DBQueueConsumer,
@@ -59939,9 +60238,9 @@ var init_db2 = __esm(() => {
59939
60238
  });
59940
60239
 
59941
60240
  // ../../packages/domain/src/envelope/fingerprint.ts
59942
- import { createHash as createHash2 } from "crypto";
60241
+ import { createHash as createHash3 } from "crypto";
59943
60242
  function computeContentHash(content) {
59944
- return createHash2("sha256").update(content, "utf-8").digest("hex");
60243
+ return createHash3("sha256").update(content, "utf-8").digest("hex");
59945
60244
  }
59946
60245
  var init_fingerprint = () => {};
59947
60246
 
@@ -60690,7 +60989,7 @@ function attributeWithoutTelemetry(layers, capturedLayers) {
60690
60989
  }
60691
60990
 
60692
60991
  // ../../packages/domain/src/envelope/invalidation.ts
60693
- import { createHash as createHash3 } from "crypto";
60992
+ import { createHash as createHash4 } from "crypto";
60694
60993
  function computeInvalidationFingerprint(trigger) {
60695
60994
  if (trigger.kind === "tool-output")
60696
60995
  return null;
@@ -60714,7 +61013,7 @@ function computeInvalidationFingerprint(trigger) {
60714
61013
  default:
60715
61014
  return null;
60716
61015
  }
60717
- return createHash3("sha256").update(raw, "utf-8").digest("hex");
61016
+ return createHash4("sha256").update(raw, "utf-8").digest("hex");
60718
61017
  }
60719
61018
  function checkLayerStale(layer, freshFingerprint) {
60720
61019
  if (freshFingerprint === null) {
@@ -60890,7 +61189,7 @@ function isProcessAlive(pid) {
60890
61189
  return false;
60891
61190
  }
60892
61191
  }
60893
- function isStale(meta3, ttlMs) {
61192
+ function isStale2(meta3, ttlMs) {
60894
61193
  if (meta3.pid > 0 && !isProcessAlive(meta3.pid))
60895
61194
  return true;
60896
61195
  if (Date.now() - meta3.ts > ttlMs)
@@ -60946,7 +61245,7 @@ function acquireLock(path9, _fs, ttlMs, label) {
60946
61245
  }
60947
61246
  const raw = readLockFileSync(path9);
60948
61247
  const existing = raw === null ? { pid: 0, ts: 0 } : parseLockContent(raw);
60949
- if (raw !== null && !isStale(existing, ttlMs)) {
61248
+ if (raw !== null && !isStale2(existing, ttlMs)) {
60950
61249
  throw new Error(`Cannot acquire ${label} lock at ${path9}: held by pid ${existing.pid} (age ${Date.now() - existing.ts}ms)`);
60951
61250
  }
60952
61251
  staleWarning = `Broke stale ${label} lock at ${path9} (pid ${existing.pid}, age ${Date.now() - existing.ts}ms)`;
@@ -61013,7 +61312,7 @@ function inspectLock(folder, entityId, fs3, ttlMs = DEFAULT_LOCK_TTL_MS) {
61013
61312
  if (!meta3)
61014
61313
  return null;
61015
61314
  return {
61016
- stale: isStale(meta3, ttlMs),
61315
+ stale: isStale2(meta3, ttlMs),
61017
61316
  age: Date.now() - meta3.ts,
61018
61317
  pid: meta3.pid
61019
61318
  };
@@ -61933,6 +62232,7 @@ __export(exports_src, {
61933
62232
  validateStageRegistry: () => validateStageRegistry,
61934
62233
  validateStageRecord: () => validateStageRecord,
61935
62234
  validateAcceptanceCriteria: () => validateAcceptanceCriteria,
62235
+ toolRollup: () => toolRollup,
61936
62236
  taskStatusIcon: () => taskStatusIcon,
61937
62237
  taskSnapshotSchema: () => taskSnapshotSchema,
61938
62238
  taskFrontmatterSchema: () => taskFrontmatterSchema,
@@ -61940,6 +62240,7 @@ __export(exports_src, {
61940
62240
  taskBatchItemSchema: () => taskBatchItemSchema,
61941
62241
  subprocessExecutionSchema: () => subprocessExecutionSchema,
61942
62242
  stripAcFence: () => stripAcFence,
62243
+ stalenessBanner: () => stalenessBanner,
61943
62244
  stageSchemaVersionSchema: () => stageSchemaVersionSchema,
61944
62245
  stageRetryPolicySchema: () => stageRetryPolicySchema,
61945
62246
  stageRecordSchema: () => stageRecordSchema,
@@ -61949,17 +62250,20 @@ __export(exports_src, {
61949
62250
  stageContextLayerSchema: () => stageContextLayerSchema,
61950
62251
  stageArtifactSchema: () => stageArtifactSchema,
61951
62252
  stablePrefixesMatch: () => stablePrefixesMatch,
62253
+ sourceSummary: () => sourceSummary,
61952
62254
  serializeStablePrefix: () => serializeStablePrefix,
61953
62255
  serializeLayer: () => serializeLayer,
61954
62256
  serializeEnvelope: () => serializeEnvelope,
62257
+ selectorDigest: () => selectorDigest,
61955
62258
  sectionMatrixSchema: () => sectionMatrixSchema,
61956
62259
  scaffoldFeatureScenarios: () => scaffoldFeatureScenarios,
61957
62260
  resolvePricing: () => resolvePricing,
61958
62261
  renderTaskTemplate: () => renderTaskTemplate,
61959
62262
  renderScenarioStub: () => renderScenarioStub,
62263
+ renderReport: () => renderReport,
62264
+ renderMarkdown: () => renderMarkdown,
61960
62265
  readLockMetadata: () => readLockMetadata,
61961
62266
  queryEtlRecords: () => queryEtlRecords,
61962
- queryAllEtlRecords: () => queryAllEtlRecords,
61963
62267
  projectSnapshotSchema: () => projectSnapshotSchema,
61964
62268
  passAllResolver: () => passAllResolver,
61965
62269
  parseStageRecord: () => parseStageRecord,
@@ -61973,13 +62277,16 @@ __export(exports_src, {
61973
62277
  normalizeTaskStatus: () => normalizeTaskStatus,
61974
62278
  normalizeFeatureStatus: () => normalizeFeatureStatus,
61975
62279
  normalizeCapabilityTier: () => normalizeCapabilityTier,
62280
+ messageRollup: () => messageRollup,
61976
62281
  mergeStubs: () => mergeStubs,
61977
62282
  matrixEntrySchema: () => matrixEntrySchema,
61978
62283
  matchEtlPayloads: () => matchEtlPayloads,
61979
62284
  matchEtlForAction: () => matchEtlForAction,
62285
+ loops: () => loops,
61980
62286
  loadSqlMigrations: () => loadSqlMigrations,
61981
62287
  loadAllEtlPayloads: () => loadAllEtlPayloads,
61982
62288
  isTierEligible: () => isTierEligible,
62289
+ isStale: () => isStale,
61983
62290
  isCompatibleStageVersion: () => isCompatibleStageVersion,
61984
62291
  irreversibleExecutionSchema: () => irreversibleExecutionSchema,
61985
62292
  inspectLock: () => inspectLock,
@@ -61994,6 +62301,7 @@ __export(exports_src, {
61994
62301
  getNextFallback: () => getNextFallback,
61995
62302
  getCanonicalStage: () => getCanonicalStage,
61996
62303
  formatSummary: () => formatSummary,
62304
+ formatRatio: () => formatRatio,
61997
62305
  featureStatusIcon: () => featureStatusIcon,
61998
62306
  featureSnapshotSchema: () => featureSnapshotSchema,
61999
62307
  featureFrontmatterSchema: () => featureFrontmatterSchema,
@@ -62003,13 +62311,13 @@ __export(exports_src, {
62003
62311
  extractHistoryEvents: () => extractHistoryEvents,
62004
62312
  extractClaudeTokens: () => extractClaudeTokens,
62005
62313
  executionKindSchema: () => executionKindSchema,
62006
- etlToCostRecord: () => etlToCostRecord,
62007
62314
  escapeYamlValue: () => escapeYamlValue,
62008
62315
  escapeYamlArrayElement: () => escapeYamlArrayElement,
62009
62316
  envelopeSizeBudgetSchema: () => envelopeSizeBudgetSchema,
62010
62317
  envelopeSchema: () => envelopeSchema,
62011
62318
  envelopeProvenanceSchema: () => envelopeProvenanceSchema,
62012
62319
  envelopeLayerSchema: () => envelopeLayerSchema,
62320
+ drift: () => drift,
62013
62321
  deterministicExecutionSchema: () => deterministicExecutionSchema,
62014
62322
  dbHealthCheck: () => dbHealthCheck,
62015
62323
  createQueueConsumer: () => createQueueConsumer,
@@ -62018,6 +62326,7 @@ __export(exports_src, {
62018
62326
  createJobQueue: () => createJobQueue,
62019
62327
  createId: () => createId,
62020
62328
  createBoundaryContext: () => createBoundaryContext,
62329
+ countCheckpointsBySource: () => countCheckpointsBySource,
62021
62330
  computeSnapshotHash: () => computeSnapshotHash,
62022
62331
  computeRecordCost: () => computeRecordCost,
62023
62332
  computeInvalidationFingerprint: () => computeInvalidationFingerprint,
@@ -62028,18 +62337,22 @@ __export(exports_src, {
62028
62337
  capabilityTierSchema: () => capabilityTierSchema,
62029
62338
  canonicalJson: () => canonicalJson,
62030
62339
  cacheHitRatio: () => cacheHitRatio,
62340
+ byTool: () => byTool,
62341
+ bySession: () => bySession,
62031
62342
  bumpStageSchemaMinor: () => bumpStageSchemaMinor,
62032
62343
  bumpStageSchemaMajor: () => bumpStageSchemaMajor,
62033
62344
  buildTaskSkeleton: () => buildTaskSkeleton,
62034
62345
  buildStageLayers: () => buildStageLayers,
62346
+ buildMessageWhere: () => buildMessageWhere,
62035
62347
  attributeWithoutTelemetry: () => attributeWithoutTelemetry,
62036
62348
  attributeFreshVsReused: () => attributeFreshVsReused,
62037
62349
  atomicWriteAsync: () => atomicWriteAsync,
62038
62350
  atomicWrite: () => atomicWrite,
62351
+ assertArtifactVersion: () => assertArtifactVersion,
62352
+ artifactToSummary: () => artifactToSummary,
62039
62353
  artifactFingerprintsMatch: () => artifactFingerprintsMatch,
62040
62354
  applyCliMigrations: () => applyCliMigrations,
62041
62355
  appendDisclosurePlaceholders: () => appendDisclosurePlaceholders,
62042
- aggregateCosts: () => aggregateCosts,
62043
62356
  actionCostEstimated: () => actionCostEstimated,
62044
62357
  actionCost: () => actionCost,
62045
62358
  acquireEntityLock: () => acquireEntityLock,
@@ -62062,6 +62375,7 @@ __export(exports_src, {
62062
62375
  StageRegistryError: () => StageRegistryError,
62063
62376
  SYSTEM_EVENTS_SCHEMA_SQL: () => SYSTEM_EVENTS_SCHEMA_SQL,
62064
62377
  SYSTEM_EVENTS_CORRELATION_COLUMNS_SCHEMA_SQL: () => SYSTEM_EVENTS_CORRELATION_COLUMNS_SCHEMA_SQL,
62378
+ STALENESS_THRESHOLD_HOURS: () => STALENESS_THRESHOLD_HOURS,
62065
62379
  STAGE_REGISTRY_SCHEMA_VERSION: () => STAGE_REGISTRY_SCHEMA_VERSION,
62066
62380
  STAGE_ID_PATTERN: () => STAGE_ID_PATTERN,
62067
62381
  STABLE_LAYER_NAMES: () => STABLE_LAYER_NAMES,
@@ -62085,6 +62399,7 @@ __export(exports_src, {
62085
62399
  InboxRecentDao: () => InboxRecentDao,
62086
62400
  InboxMessageDao: () => InboxMessageDao,
62087
62401
  INBOX_MESSAGES_SCHEMA_SQL: () => INBOX_MESSAGES_SCHEMA_SQL,
62402
+ HISTORY_ARTIFACT_SCHEMA_VERSION: () => HISTORY_ARTIFACT_SCHEMA_VERSION,
62088
62403
  FEATURE_STATUS_ICONS: () => FEATURE_STATUS_ICONS,
62089
62404
  FEATURE_STATUSES: () => FEATURE_STATUSES,
62090
62405
  FEATURE_ID_PATTERN: () => FEATURE_ID_PATTERN,
@@ -62100,6 +62415,7 @@ __export(exports_src, {
62100
62415
  CLI_MIGRATIONS: () => CLI_MIGRATIONS,
62101
62416
  CAPABILITY_TIERS: () => CAPABILITY_TIERS,
62102
62417
  CACHEABILITY_CLASSES: () => CACHEABILITY_CLASSES,
62418
+ ArtifactVersionError: () => ArtifactVersionError,
62103
62419
  ArtifactDao: () => ArtifactDao,
62104
62420
  ActionRunDao: () => ActionRunDao,
62105
62421
  AUTHORITY_LANES: () => AUTHORITY_LANES,
@@ -63471,6 +63787,9 @@ var init_event_names = __esm(() => {
63471
63787
  event("team.member.assigned", "team", "team"),
63472
63788
  event("team.member.started", "team", "team"),
63473
63789
  event("team.member.stopped", "team", "team"),
63790
+ event("history.import.completed", "history", "history-import"),
63791
+ event("history.analyze.completed", "history", "history-analyze"),
63792
+ event("history.daily.failed", "history", "history-daily"),
63474
63793
  event("rule.run.start", "rule", "rule"),
63475
63794
  event("rule.eval.start", "rule", "rule"),
63476
63795
  event("rule.eval.done", "rule", "rule"),
@@ -65001,6 +65320,19 @@ var init_feature_service = __esm(() => {
65001
65320
  });
65002
65321
 
65003
65322
  // ../../packages/app/src/services/history-service.ts
65323
+ import {
65324
+ existsSync as existsSync5,
65325
+ mkdirSync as mkdirSync6,
65326
+ readdirSync as readdirSync5,
65327
+ readFileSync as readFileSync8,
65328
+ readlinkSync,
65329
+ rmSync as rmSync3,
65330
+ symlinkSync,
65331
+ unlinkSync as unlinkSync2,
65332
+ writeFileSync as writeFileSync4
65333
+ } from "fs";
65334
+ import { dirname as dirname9, isAbsolute, join as join10, resolve } from "path";
65335
+
65004
65336
  class HistoryService {
65005
65337
  ctx;
65006
65338
  constructor(ctx) {
@@ -65017,12 +65349,372 @@ class HistoryService {
65017
65349
  dryRun: opts.dryRun ?? false
65018
65350
  });
65019
65351
  }
65020
- async analyze(since) {
65352
+ async analyze(selector, opts = {}) {
65353
+ const top = opts.top ?? 20;
65354
+ const db2 = await this.ctx.getDb();
65355
+ const [mRows, tRows, toolRows, sessionRows, loopRows, driftRows, sourceRows] = await Promise.all([
65356
+ messageRollup(db2, selector),
65357
+ toolRollup(db2, selector),
65358
+ byTool(db2, selector, top),
65359
+ bySession(db2, selector, top),
65360
+ loops(db2, selector),
65361
+ drift(db2, selector),
65362
+ sourceSummary(db2, selector)
65363
+ ]);
65364
+ const totals = foldTotals2(mRows, tRows);
65365
+ const bySource = foldGrouped(mRows, tRows, (m) => m.source, (t) => t.source);
65366
+ const byModel = foldGrouped(mRows, tRows, (m) => m.model ?? "unknown", (t) => t.model ?? "unknown");
65367
+ const byDay = foldGrouped(mRows, tRows, (m) => m.day ?? "", (t) => t.day ?? "");
65368
+ const daily = Object.entries(byDay).map(([date6, totals2]) => ({ date: date6, ...totals2 })).sort((a2, b) => a2.date.localeCompare(b.date));
65369
+ const coverage = buildCoverage(sourceRows, tRows, driftRows, opts.coverageErrors, opts.importCoverage);
65370
+ const artifact = {
65371
+ schemaVersion: HISTORY_ARTIFACT_SCHEMA_VERSION,
65372
+ generatedAt: new Date().toISOString(),
65373
+ spurVersion: opts.spurVersion ?? "",
65374
+ selector: { ...selector, sources: selector.sources ? [...selector.sources] : null },
65375
+ coverage,
65376
+ totals,
65377
+ bySource,
65378
+ byModel,
65379
+ daily,
65380
+ byTool: toolRows.map((r) => ({
65381
+ toolName: r.toolName,
65382
+ calls: r.calls,
65383
+ errors: r.errors,
65384
+ durationMsTotal: r.durationMsTotal ?? 0,
65385
+ durationMsMean: r.durationMsMean ?? 0,
65386
+ durationMsMax: r.durationMsMax ?? 0,
65387
+ durationUnmeasured: r.durationUnmeasured,
65388
+ resultBytes: r.resultBytes ?? 0
65389
+ })),
65390
+ bySession: sessionRows.map((r) => ({
65391
+ sessionId: r.sessionId,
65392
+ source: r.source,
65393
+ startedAt: r.startedAt,
65394
+ messages: r.messages,
65395
+ toolCalls: r.toolCalls,
65396
+ tokens: r.tokens ?? 0,
65397
+ costUsd: r.costUsd ?? 0,
65398
+ topTool: r.topTool
65399
+ })),
65400
+ loops: loopRows,
65401
+ warnings: [...buildWarnings(driftRows, coverage), ...opts.extraWarnings ?? []]
65402
+ };
65403
+ if (opts.out !== undefined || opts.cwd !== undefined) {
65404
+ writeArtifact(artifact, { out: opts.out, cwd: opts.cwd ?? process.cwd() });
65405
+ }
65406
+ return artifact;
65407
+ }
65408
+ async importAll(opts = {}) {
65409
+ const sources = (opts.sources ?? SOURCES).map((s2) => parseSource(s2));
65410
+ const timeoutMs = opts.sourceTimeout ?? DEFAULT_SOURCE_TIMEOUT_MS;
65411
+ const entries = [];
65412
+ const warnings = [];
65413
+ for (const source of sources) {
65414
+ const { coverageEntry, sourceWarnings } = await this.importOneIsolated(source, opts, timeoutMs);
65415
+ entries.push(coverageEntry);
65416
+ warnings.push(...sourceWarnings);
65417
+ }
65418
+ return { entries, exitCode: computeExitCode(entries), warnings };
65419
+ }
65420
+ async daily(opts = {}) {
65421
+ const cwd = opts.cwd ?? process.cwd();
65422
+ const fanOut = await this.importAll({
65423
+ sources: opts.sources,
65424
+ sourceTimeout: opts.sourceTimeout,
65425
+ root: opts.root
65426
+ });
65427
+ const selector = {
65428
+ since: opts.since ?? null,
65429
+ until: opts.until ?? null,
65430
+ sources: null,
65431
+ sessionId: null,
65432
+ runId: null,
65433
+ taskWbs: null
65434
+ };
65435
+ const artifact = await this.analyze(selector, {
65436
+ spurVersion: opts.spurVersion,
65437
+ cwd,
65438
+ importCoverage: fanOut.entries,
65439
+ extraWarnings: fanOut.warnings
65440
+ });
65441
+ const pruned = pruneReports(cwd, REPORT_RETENTION_DAYS);
65442
+ return { fanOut, artifact, pruned };
65443
+ }
65444
+ async importOneIsolated(source, opts, timeoutMs) {
65021
65445
  const db2 = await this.ctx.getDb();
65022
- const records = await queryAllEtlRecords(db2, since !== undefined && since.length > 0 ? since : undefined);
65023
- const priced = records.map((record2) => computeRecordCost(record2));
65024
- return aggregateCosts(priced);
65446
+ const sourceWarnings = [];
65447
+ const checkpointCount = await countCheckpointsBySource(db2, source);
65448
+ const wasNonEmpty = checkpointCount > 0;
65449
+ try {
65450
+ const importPromise = this.import(source, {
65451
+ file: opts.file,
65452
+ root: opts.root,
65453
+ mode: opts.mode ?? (opts.file !== undefined && opts.file.length > 0 ? "force-file" : "incremental"),
65454
+ dryRun: opts.dryRun
65455
+ });
65456
+ const abort = new AbortController;
65457
+ const timer = setTimeout(() => abort.abort(new Error(`source '${source}' exceeded ${timeoutMs}ms timeout`)), timeoutMs);
65458
+ const timeoutPromise = new Promise((_, reject) => {
65459
+ abort.signal.addEventListener("abort", () => reject(abort.signal.reason));
65460
+ });
65461
+ let result;
65462
+ try {
65463
+ result = await Promise.race([importPromise, timeoutPromise]);
65464
+ } finally {
65465
+ clearTimeout(timer);
65466
+ }
65467
+ const status = result.scannedFiles === 0 ? "empty" : "ok";
65468
+ if (status === "empty" && wasNonEmpty) {
65469
+ sourceWarnings.push({
65470
+ code: "source-was-nonempty",
65471
+ source,
65472
+ detail: `source '${source}' previously had checkpoint rows but discovered 0 files`
65473
+ });
65474
+ }
65475
+ const coverageEntry = {
65476
+ source,
65477
+ status,
65478
+ files: result.scannedFiles,
65479
+ messages: result.importedRecords,
65480
+ toolCalls: 0,
65481
+ unknownRecords: result.unknownRecords,
65482
+ lastImportedAt: null,
65483
+ parseErrors: result.parseErrors.length,
65484
+ validationErrors: result.validationErrors.length,
65485
+ parseErrorSamples: result.parseErrors.slice(0, MAX_ERROR_SAMPLES).map(formatIssue),
65486
+ validationErrorSamples: result.validationErrors.slice(0, MAX_ERROR_SAMPLES).map(formatIssue)
65487
+ };
65488
+ return { coverageEntry, sourceWarnings };
65489
+ } catch (e) {
65490
+ const detail = e.message;
65491
+ sourceWarnings.push({ code: "source-failed", source, detail });
65492
+ return {
65493
+ coverageEntry: {
65494
+ source,
65495
+ status: "failed",
65496
+ files: 0,
65497
+ messages: 0,
65498
+ toolCalls: 0,
65499
+ unknownRecords: 0,
65500
+ lastImportedAt: null,
65501
+ parseErrors: 0,
65502
+ validationErrors: 0,
65503
+ parseErrorSamples: [],
65504
+ validationErrorSamples: []
65505
+ },
65506
+ sourceWarnings
65507
+ };
65508
+ }
65509
+ }
65510
+ }
65511
+ function emptyTotals() {
65512
+ return {
65513
+ inputTokens: 0,
65514
+ outputTokens: 0,
65515
+ cacheReadTokens: 0,
65516
+ cacheWriteTokens: 0,
65517
+ costUsd: 0,
65518
+ records: 0,
65519
+ recordsWithUsage: 0,
65520
+ messages: 0,
65521
+ toolCalls: 0,
65522
+ durationMs: 0,
65523
+ durationUnmeasured: 0
65524
+ };
65525
+ }
65526
+ function foldMessage(bucket, row) {
65527
+ bucket.messages += row.messages;
65528
+ bucket.records += row.messages;
65529
+ bucket.inputTokens += row.inputTokens ?? 0;
65530
+ bucket.outputTokens += row.outputTokens ?? 0;
65531
+ bucket.cacheReadTokens += row.cacheReadTokens ?? 0;
65532
+ bucket.cacheWriteTokens += row.cacheWriteTokens ?? 0;
65533
+ bucket.costUsd += row.costUsd ?? 0;
65534
+ bucket.recordsWithUsage += row.recordsWithUsage;
65535
+ }
65536
+ function foldTool(bucket, row) {
65537
+ bucket.toolCalls += row.toolCalls;
65538
+ bucket.durationMs += row.durationMs ?? 0;
65539
+ bucket.durationUnmeasured += row.durationUnmeasured;
65540
+ }
65541
+ function foldTotals2(mRows, tRows) {
65542
+ const totals = emptyTotals();
65543
+ for (const row of mRows)
65544
+ foldMessage(totals, row);
65545
+ for (const row of tRows)
65546
+ foldTool(totals, row);
65547
+ return totals;
65548
+ }
65549
+ function foldGrouped(mRows, tRows, mKey, tKey) {
65550
+ const map2 = {};
65551
+ for (const row of mRows) {
65552
+ const key = mKey(row);
65553
+ const bucket = map2[key] ?? emptyTotals();
65554
+ map2[key] = bucket;
65555
+ foldMessage(bucket, row);
65556
+ }
65557
+ for (const row of tRows) {
65558
+ const key = tKey(row);
65559
+ const bucket = map2[key] ?? emptyTotals();
65560
+ map2[key] = bucket;
65561
+ foldTool(bucket, row);
65025
65562
  }
65563
+ return map2;
65564
+ }
65565
+ function buildCoverage(sourceRows, tRows, driftRows, coverageErrors, importCoverage) {
65566
+ if (importCoverage !== undefined) {
65567
+ const toolCounts2 = {};
65568
+ for (const row of tRows)
65569
+ toolCounts2[row.source] = (toolCounts2[row.source] ?? 0) + row.toolCalls;
65570
+ const unknownCounts2 = {};
65571
+ for (const row of driftRows)
65572
+ unknownCounts2[row.source] = (unknownCounts2[row.source] ?? 0) + row.n;
65573
+ const sqlBySource = new Map;
65574
+ for (const row of sourceRows)
65575
+ sqlBySource.set(row.source, row);
65576
+ return importCoverage.map((imp) => {
65577
+ if (imp.status === "ok") {
65578
+ const sql4 = sqlBySource.get(imp.source);
65579
+ return {
65580
+ source: imp.source,
65581
+ status: "ok",
65582
+ files: sql4?.files ?? imp.files,
65583
+ messages: sql4?.messages ?? imp.messages,
65584
+ toolCalls: toolCounts2[imp.source] ?? 0,
65585
+ unknownRecords: unknownCounts2[imp.source] ?? 0,
65586
+ lastImportedAt: sql4?.lastImportedAt ?? null,
65587
+ parseErrors: imp.parseErrors,
65588
+ validationErrors: imp.validationErrors,
65589
+ parseErrorSamples: imp.parseErrorSamples,
65590
+ validationErrorSamples: imp.validationErrorSamples
65591
+ };
65592
+ }
65593
+ return imp;
65594
+ });
65595
+ }
65596
+ const toolCounts = {};
65597
+ for (const row of tRows)
65598
+ toolCounts[row.source] = (toolCounts[row.source] ?? 0) + row.toolCalls;
65599
+ const unknownCounts = {};
65600
+ for (const row of driftRows)
65601
+ unknownCounts[row.source] = (unknownCounts[row.source] ?? 0) + row.n;
65602
+ return sourceRows.map((s2) => {
65603
+ const err = coverageErrors?.[s2.source] ?? { parseErrors: [], validationErrors: [] };
65604
+ return {
65605
+ source: s2.source,
65606
+ status: s2.messages > 0 ? "ok" : "empty",
65607
+ files: s2.files,
65608
+ messages: s2.messages,
65609
+ toolCalls: toolCounts[s2.source] ?? 0,
65610
+ unknownRecords: unknownCounts[s2.source] ?? 0,
65611
+ lastImportedAt: s2.lastImportedAt,
65612
+ parseErrors: err.parseErrors.length,
65613
+ validationErrors: err.validationErrors.length,
65614
+ parseErrorSamples: err.parseErrors,
65615
+ validationErrorSamples: err.validationErrors
65616
+ };
65617
+ });
65618
+ }
65619
+ function buildWarnings(driftRows, coverage) {
65620
+ const warnings = [];
65621
+ const driftBySource = new Map;
65622
+ for (const row of driftRows)
65623
+ driftBySource.set(row.source, (driftBySource.get(row.source) ?? 0) + row.n);
65624
+ for (const [source, n2] of driftBySource) {
65625
+ warnings.push({ code: "unknown-drift", source, detail: `${n2} records with unknown disposition` });
65626
+ }
65627
+ for (const entry of coverage) {
65628
+ if (entry.status === "empty") {
65629
+ warnings.push({ code: "source-empty", source: entry.source, detail: "0 messages discovered" });
65630
+ }
65631
+ }
65632
+ return warnings;
65633
+ }
65634
+ function writeArtifact(artifact, opts) {
65635
+ const { artifactPath, sidecarPath } = resolveArtifactPaths(artifact, opts);
65636
+ const { bounded: bounded2, overflow } = boundCoverage(artifact.coverage);
65637
+ mkdirSync6(dirname9(artifactPath), { recursive: true });
65638
+ writeFileSync4(artifactPath, JSON.stringify({ ...artifact, coverage: bounded2 }, null, 2));
65639
+ if (overflow.length > 0) {
65640
+ mkdirSync6(dirname9(sidecarPath), { recursive: true });
65641
+ writeFileSync4(sidecarPath, `${overflow.map((line) => JSON.stringify(line)).join(`
65642
+ `)}
65643
+ `);
65644
+ }
65645
+ if (opts.out === undefined) {
65646
+ updateLatestPointer(opts, artifactPath);
65647
+ }
65648
+ return { artifactPath, sidecarPath };
65649
+ }
65650
+ function resolveArtifactPaths(artifact, opts) {
65651
+ if (opts.out !== undefined) {
65652
+ const out = resolve(opts.out);
65653
+ return { artifactPath: out, sidecarPath: `${out.replace(/\.json$/, "")}.errors.jsonl` };
65654
+ }
65655
+ const base2 = resolve(opts.cwd, ".spur", "reports", "history");
65656
+ const dateDir = join10(base2, artifact.generatedAt.slice(0, 10));
65657
+ const name = `analyze-${selectorDigest(artifact.selector)}`;
65658
+ return { artifactPath: join10(dateDir, `${name}.json`), sidecarPath: join10(dateDir, `${name}.errors.jsonl`) };
65659
+ }
65660
+ function boundCoverage(coverage) {
65661
+ const overflow = [];
65662
+ const bounded2 = coverage.map((entry) => {
65663
+ const pe = entry.parseErrorSamples;
65664
+ const ve = entry.validationErrorSamples;
65665
+ for (const sample of pe.slice(MAX_ERROR_SAMPLES)) {
65666
+ overflow.push({ source: entry.source, kind: "parse", sample });
65667
+ }
65668
+ for (const sample of ve.slice(MAX_ERROR_SAMPLES)) {
65669
+ overflow.push({ source: entry.source, kind: "validation", sample });
65670
+ }
65671
+ return {
65672
+ ...entry,
65673
+ parseErrorSamples: pe.slice(0, MAX_ERROR_SAMPLES),
65674
+ validationErrorSamples: ve.slice(0, MAX_ERROR_SAMPLES)
65675
+ };
65676
+ });
65677
+ return { bounded: bounded2, overflow };
65678
+ }
65679
+ function updateLatestPointer(opts, artifactPath) {
65680
+ const base2 = resolve(opts.cwd, ".spur", "reports", "history");
65681
+ const latest = join10(base2, "latest.json");
65682
+ mkdirSync6(base2, { recursive: true });
65683
+ if (existsSync5(latest))
65684
+ unlinkSync2(latest);
65685
+ symlinkSync(artifactPath, latest);
65686
+ }
65687
+ function resolveArtifactPath(explicitPath, cwd) {
65688
+ if (explicitPath !== undefined && explicitPath.length > 0) {
65689
+ return { path: resolve(explicitPath), resolution: "explicit" };
65690
+ }
65691
+ const latest = resolve(cwd, ".spur", "reports", "history", "latest.json");
65692
+ if (!existsSync5(latest)) {
65693
+ throw new Error(`No artifact path given and no latest pointer at ${latest}. ` + "Run `spur history analyze` first, or pass an explicit artifact path.");
65694
+ }
65695
+ const target = readlinkSync(latest);
65696
+ const resolved = isAbsolute(target) ? target : resolve(dirname9(latest), target);
65697
+ if (!existsSync5(resolved)) {
65698
+ throw new Error(`Latest pointer ${latest} \u2192 ${resolved}, but the target does not exist.`);
65699
+ }
65700
+ return { path: resolved, resolution: "pointer" };
65701
+ }
65702
+ function runHistoryReport(opts) {
65703
+ const { path: artifactPath, resolution } = resolveArtifactPath(opts.path, opts.cwd);
65704
+ const raw = readFileSync8(artifactPath, "utf8");
65705
+ let parsed;
65706
+ try {
65707
+ parsed = JSON.parse(raw);
65708
+ } catch (e) {
65709
+ throw new Error(`Artifact ${artifactPath} is not valid JSON: ${e.message}`);
65710
+ }
65711
+ const artifact = parsed;
65712
+ assertArtifactVersion(artifact.schemaVersion ?? -1, artifactPath);
65713
+ const report = renderReport(artifact);
65714
+ const markdown = renderMarkdown(artifact);
65715
+ const markdownPath = artifactPath.endsWith(".json") ? artifactPath.replace(/\.json$/, ".md") : `${artifactPath}.md`;
65716
+ writeFileSync4(markdownPath, markdown);
65717
+ return { report, artifactPath, resolution, markdownPath, artifact };
65026
65718
  }
65027
65719
  function parseSource(value) {
65028
65720
  if (SOURCES.includes(value)) {
@@ -65036,7 +65728,43 @@ function parseMode(value) {
65036
65728
  }
65037
65729
  throw new Error(`Invalid history import mode "${value}". Expected one of: ${MODES.join(", ")}`);
65038
65730
  }
65039
- var SOURCES, MODES;
65731
+ function computeExitCode(entries) {
65732
+ const failed = entries.filter((e) => e.status === "failed").length;
65733
+ if (failed === 0)
65734
+ return 0;
65735
+ if (failed === entries.length)
65736
+ return 1;
65737
+ return 2;
65738
+ }
65739
+ function formatIssue(issue2) {
65740
+ return `${issue2.sourceFile}:${issue2.sourceLine}: ${issue2.reason}`;
65741
+ }
65742
+ function pruneReports(cwd, retentionDays = REPORT_RETENTION_DAYS, now2 = new Date) {
65743
+ const dir = join10(cwd, ".spur", "reports", "history");
65744
+ let entries;
65745
+ try {
65746
+ entries = readdirSync5(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
65747
+ } catch {
65748
+ return [];
65749
+ }
65750
+ const cutoff = new Date(now2);
65751
+ cutoff.setHours(0, 0, 0, 0);
65752
+ cutoff.setDate(cutoff.getDate() - retentionDays);
65753
+ const pruned = [];
65754
+ for (const name of entries) {
65755
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(name))
65756
+ continue;
65757
+ const entryDate = new Date(`${name}T00:00:00`);
65758
+ if (entryDate >= cutoff)
65759
+ continue;
65760
+ try {
65761
+ rmSync3(join10(dir, name), { recursive: true, force: true });
65762
+ pruned.push(name);
65763
+ } catch {}
65764
+ }
65765
+ return pruned.sort((a2, b) => a2.localeCompare(b));
65766
+ }
65767
+ var SOURCES, MODES, MAX_ERROR_SAMPLES = 20, DEFAULT_SOURCE_TIMEOUT_MS = 600000, REPORT_RETENTION_DAYS = 90;
65040
65768
  var init_history_service = __esm(() => {
65041
65769
  init_src2();
65042
65770
  init_dist8();
@@ -65596,41 +66324,41 @@ var init_process_inventory_service = __esm(() => {
65596
66324
  });
65597
66325
 
65598
66326
  // ../../packages/app/src/services/project-registry.ts
65599
- import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
66327
+ import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync9, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
65600
66328
  import { connect, createServer } from "net";
65601
66329
  import { homedir as homedir3 } from "os";
65602
- import { dirname as dirname9, join as join10, resolve } from "path";
66330
+ import { dirname as dirname10, join as join11, resolve as resolve2 } from "path";
65603
66331
  function normalizeProjectPath(pathInput) {
65604
66332
  const trimmed = pathInput.trim();
65605
66333
  let expanded = trimmed;
65606
66334
  if (trimmed === "~") {
65607
66335
  expanded = homedir3();
65608
66336
  } else if (trimmed.startsWith("~/")) {
65609
- expanded = join10(homedir3(), trimmed.slice(2));
66337
+ expanded = join11(homedir3(), trimmed.slice(2));
65610
66338
  } else {
65611
- expanded = resolve(trimmed);
66339
+ expanded = resolve2(trimmed);
65612
66340
  }
65613
66341
  try {
65614
- if (existsSync5(expanded)) {
66342
+ if (existsSync6(expanded)) {
65615
66343
  return realpathSync3(expanded);
65616
66344
  }
65617
66345
  } catch {}
65618
66346
  return expanded;
65619
66347
  }
65620
66348
  async function isPortLiveOnHost(port, host, timeoutMs) {
65621
- return new Promise((resolve2) => {
66349
+ return new Promise((resolve3) => {
65622
66350
  const socket = connect({ port, host, timeout: timeoutMs });
65623
66351
  socket.on("connect", () => {
65624
66352
  socket.destroy();
65625
- resolve2(true);
66353
+ resolve3(true);
65626
66354
  });
65627
66355
  socket.on("timeout", () => {
65628
66356
  socket.destroy();
65629
- resolve2(false);
66357
+ resolve3(false);
65630
66358
  });
65631
66359
  socket.on("error", () => {
65632
66360
  socket.destroy();
65633
- resolve2(false);
66361
+ resolve3(false);
65634
66362
  });
65635
66363
  });
65636
66364
  }
@@ -65646,12 +66374,12 @@ async function isPortLive(port, timeoutMs = 200) {
65646
66374
  async function isPortAvailable(port) {
65647
66375
  if (port <= 0 || port > 65535)
65648
66376
  return false;
65649
- return new Promise((resolve2) => {
66377
+ return new Promise((resolve3) => {
65650
66378
  const server = createServer();
65651
66379
  server.unref();
65652
- server.on("error", () => resolve2(false));
66380
+ server.on("error", () => resolve3(false));
65653
66381
  server.listen({ port, host: "127.0.0.1" }, () => {
65654
- server.close(() => resolve2(true));
66382
+ server.close(() => resolve3(true));
65655
66383
  });
65656
66384
  });
65657
66385
  }
@@ -65664,15 +66392,15 @@ class ProjectRegistry {
65664
66392
  this.lockDir = `${this.filePath}.lock`;
65665
66393
  }
65666
66394
  async withLock(fn) {
65667
- const lockParent = dirname9(this.lockDir);
65668
- if (!existsSync5(lockParent)) {
65669
- mkdirSync6(lockParent, { recursive: true });
66395
+ const lockParent = dirname10(this.lockDir);
66396
+ if (!existsSync6(lockParent)) {
66397
+ mkdirSync7(lockParent, { recursive: true });
65670
66398
  }
65671
66399
  const maxTries = 50;
65672
66400
  let acquired = false;
65673
66401
  for (let i2 = 0;i2 < maxTries; i2++) {
65674
66402
  try {
65675
- mkdirSync6(this.lockDir);
66403
+ mkdirSync7(this.lockDir);
65676
66404
  acquired = true;
65677
66405
  break;
65678
66406
  } catch {
@@ -65681,8 +66409,8 @@ class ProjectRegistry {
65681
66409
  }
65682
66410
  if (!acquired) {
65683
66411
  try {
65684
- rmSync3(this.lockDir, { recursive: true, force: true });
65685
- mkdirSync6(this.lockDir);
66412
+ rmSync4(this.lockDir, { recursive: true, force: true });
66413
+ mkdirSync7(this.lockDir);
65686
66414
  acquired = true;
65687
66415
  } catch {
65688
66416
  throw new Error(`Failed to acquire lock for project registry: ${this.lockDir}`);
@@ -65693,17 +66421,17 @@ class ProjectRegistry {
65693
66421
  } finally {
65694
66422
  if (acquired) {
65695
66423
  try {
65696
- rmSync3(this.lockDir, { recursive: true, force: true });
66424
+ rmSync4(this.lockDir, { recursive: true, force: true });
65697
66425
  } catch {}
65698
66426
  }
65699
66427
  }
65700
66428
  }
65701
66429
  readRaw() {
65702
- if (!existsSync5(this.filePath)) {
66430
+ if (!existsSync6(this.filePath)) {
65703
66431
  return { schema_version: 1, projects: [] };
65704
66432
  }
65705
66433
  try {
65706
- const raw = readFileSync8(this.filePath, "utf-8");
66434
+ const raw = readFileSync9(this.filePath, "utf-8");
65707
66435
  const json3 = JSON.parse(raw);
65708
66436
  return projectsFileSchema.parse(json3);
65709
66437
  } catch {
@@ -65711,13 +66439,13 @@ class ProjectRegistry {
65711
66439
  }
65712
66440
  }
65713
66441
  writeRaw(data) {
65714
- const parentDir2 = dirname9(this.filePath);
65715
- if (!existsSync5(parentDir2)) {
65716
- mkdirSync6(parentDir2, { recursive: true });
66442
+ const parentDir2 = dirname10(this.filePath);
66443
+ if (!existsSync6(parentDir2)) {
66444
+ mkdirSync7(parentDir2, { recursive: true });
65717
66445
  }
65718
66446
  const tmpFile = `${this.filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
65719
66447
  const content = JSON.stringify(data, null, 2);
65720
- writeFileSync4(tmpFile, content, "utf-8");
66448
+ writeFileSync5(tmpFile, content, "utf-8");
65721
66449
  renameSync4(tmpFile, this.filePath);
65722
66450
  }
65723
66451
  async healTildePaths() {
@@ -65848,8 +66576,8 @@ var init_project_registry = __esm(() => {
65848
66576
  });
65849
66577
 
65850
66578
  // ../../packages/app/src/services/project-start.ts
65851
- import { existsSync as existsSync6 } from "fs";
65852
- import { basename as basename2, resolve as resolve2 } from "path";
66579
+ import { existsSync as existsSync7 } from "fs";
66580
+ import { basename as basename2, resolve as resolve3 } from "path";
65853
66581
  function shQuote(value) {
65854
66582
  return `'${value.replace(/'/g, `'\\''`)}'`;
65855
66583
  }
@@ -65865,7 +66593,7 @@ function setDetachedServeSpawnForTests(spawn2) {
65865
66593
  testDetachedServeSpawn = spawn2;
65866
66594
  }
65867
66595
  function resolveSpurServeCommand() {
65868
- if (process.env.SPUR_CLI_PATH && existsSync6(process.env.SPUR_CLI_PATH)) {
66596
+ if (process.env.SPUR_CLI_PATH && existsSync7(process.env.SPUR_CLI_PATH)) {
65869
66597
  return [process.execPath, process.env.SPUR_CLI_PATH];
65870
66598
  }
65871
66599
  const argv1 = process.argv[1];
@@ -65875,8 +66603,8 @@ function resolveSpurServeCommand() {
65875
66603
  return [process.execPath, argv1];
65876
66604
  }
65877
66605
  }
65878
- const monorepoCli = resolve2(process.cwd(), "apps/cli/src/index.ts");
65879
- if (existsSync6(monorepoCli)) {
66606
+ const monorepoCli = resolve3(process.cwd(), "apps/cli/src/index.ts");
66607
+ if (existsSync7(monorepoCli)) {
65880
66608
  return [process.execPath, monorepoCli];
65881
66609
  }
65882
66610
  const fromPath = typeof Bun !== "undefined" && typeof Bun.which === "function" ? Bun.which("spur") : null;
@@ -65889,14 +66617,14 @@ async function startRegisteredProject(registry2, target, options = {}) {
65889
66617
  let entry = await registry2.getByName(target) ?? await registry2.getByPath(target);
65890
66618
  if (!entry) {
65891
66619
  const absPath = normalizeProjectPath(target);
65892
- if (existsSync6(absPath)) {
66620
+ if (existsSync7(absPath)) {
65893
66621
  entry = await registry2.upsert({ path: absPath, name: basename2(absPath), port: 0 });
65894
66622
  } else {
65895
66623
  throw new Error(`Project not found in registry: "${target}"`);
65896
66624
  }
65897
66625
  }
65898
66626
  const projectPath = normalizeProjectPath(entry.path);
65899
- if (!existsSync6(projectPath)) {
66627
+ if (!existsSync7(projectPath)) {
65900
66628
  throw new Error(`Project path does not exist: "${entry.path}" (resolved to ${projectPath}). Update ~/.config/spur/projects.json.`);
65901
66629
  }
65902
66630
  if (projectPath !== entry.path) {
@@ -65987,7 +66715,7 @@ var init_project_start = __esm(() => {
65987
66715
 
65988
66716
  // ../../packages/app/src/services/rule-service.ts
65989
66717
  import { homedir as homedir4 } from "os";
65990
- import { delimiter, join as join11, relative as relative2, resolve as resolve3 } from "path";
66718
+ import { delimiter, join as join12, relative as relative2, resolve as resolve4 } from "path";
65991
66719
 
65992
66720
  class RuleService {
65993
66721
  context;
@@ -66166,22 +66894,22 @@ ${ruleIds.join(`
66166
66894
  if (envValue !== undefined && envValue.length > 0) {
66167
66895
  for (const entry of envValue.split(delimiter)) {
66168
66896
  if (entry.length > 0) {
66169
- layers.push({ id: "env-override", path: resolve3(cwd, entry), priority: -10 });
66897
+ layers.push({ id: "env-override", path: resolve4(cwd, entry), priority: -10 });
66170
66898
  }
66171
66899
  }
66172
66900
  }
66173
- layers.push({ id: "local", path: resolve3(cwd, LOCAL_RULES_DIR), priority: 0 });
66901
+ layers.push({ id: "local", path: resolve4(cwd, LOCAL_RULES_DIR), priority: 0 });
66174
66902
  const globalOverride = env.SPUR_GLOBAL_RULES_DIR;
66175
66903
  const hasGlobalOverride = globalOverride !== undefined && globalOverride.length > 0;
66176
66904
  layers.push({
66177
66905
  id: "global",
66178
- path: hasGlobalOverride ? resolve3(cwd, globalOverride) : join11(homedir4(), GLOBAL_RULES_DIR),
66906
+ path: hasGlobalOverride ? resolve4(cwd, globalOverride) : join12(homedir4(), GLOBAL_RULES_DIR),
66179
66907
  priority: 10
66180
66908
  });
66181
66909
  if (opts.includeBundled && !hasGlobalOverride) {
66182
66910
  const bundledConfig = bundledConfigRoot();
66183
66911
  if (bundledConfig !== null) {
66184
- layers.push({ id: "bundled-config", path: join11(bundledConfig, "rules"), priority: 15 });
66912
+ layers.push({ id: "bundled-config", path: join12(bundledConfig, "rules"), priority: 15 });
66185
66913
  }
66186
66914
  const bundled = await bundledRulesRoot();
66187
66915
  if (bundled !== null)
@@ -66331,7 +67059,7 @@ ${ruleIds.join(`
66331
67059
  async collectValidationErrors(source, validateSchema) {
66332
67060
  const { cwd, fs: fs3 } = this.context;
66333
67061
  if (source.kind === "file") {
66334
- const absolute = resolve3(cwd, source.value);
67062
+ const absolute = resolve4(cwd, source.value);
66335
67063
  if (!await fs3.exists(absolute))
66336
67064
  return [`File not found: ${absolute}`];
66337
67065
  try {
@@ -66355,7 +67083,7 @@ ${ruleIds.join(`
66355
67083
  const { fs: fs3 } = this.context;
66356
67084
  for (const root of await this.ruleRoots()) {
66357
67085
  for (const ext of ["yaml", "yml", "json"]) {
66358
- if (await fs3.exists(join11(root, `${name}.${ext}`)))
67086
+ if (await fs3.exists(join12(root, `${name}.${ext}`)))
66359
67087
  return true;
66360
67088
  }
66361
67089
  }
@@ -66391,7 +67119,7 @@ ${ruleIds.join(`
66391
67119
  for (const layer of await this.existingRuleSourceLayers()) {
66392
67120
  const entries = await this.context.fs.readDir(layer.path);
66393
67121
  const named = entries.map((entry) => ({ entry, name: entry.match(/^([\w-]+)\.(?:ya?ml|json)$/i)?.[1] ?? "" })).filter(({ name }) => name.length > 0);
66394
- const stats = await Promise.all(named.map(({ entry }) => this.context.fs.stat(join11(layer.path, entry))));
67122
+ const stats = await Promise.all(named.map(({ entry }) => this.context.fs.stat(join12(layer.path, entry))));
66395
67123
  named.forEach(({ name }, i2) => {
66396
67124
  if (stats[i2]?.isFile())
66397
67125
  candidates.add(name);
@@ -66413,7 +67141,7 @@ ${ruleIds.join(`
66413
67141
  for (const layer of layers) {
66414
67142
  for (const file2 of await this.listRuleFilesInLayer(layer.path)) {
66415
67143
  if (!merged.has(file2))
66416
- merged.set(file2, { absolutePath: join11(layer.path, file2), source: layer.id });
67144
+ merged.set(file2, { absolutePath: join12(layer.path, file2), source: layer.id });
66417
67145
  }
66418
67146
  }
66419
67147
  const files = [];
@@ -66481,7 +67209,7 @@ ${ruleIds.join(`
66481
67209
  for (const entry of entries.sort()) {
66482
67210
  if (entry === "presets")
66483
67211
  continue;
66484
- const stat = await this.context.fs.stat(join11(root, entry));
67212
+ const stat = await this.context.fs.stat(join12(root, entry));
66485
67213
  if (stat?.isDirectory())
66486
67214
  dirs.push(entry);
66487
67215
  }
@@ -66489,12 +67217,12 @@ ${ruleIds.join(`
66489
67217
  }
66490
67218
  async listRuleFiles(root, relativeDir) {
66491
67219
  const { fs: fs3 } = this.context;
66492
- const dir = join11(root, relativeDir);
67220
+ const dir = join12(root, relativeDir);
66493
67221
  const entries = await fs3.readDir(dir);
66494
67222
  const files = [];
66495
67223
  for (const entry of entries.sort()) {
66496
- const relativePath2 = relativeDir.length === 0 ? entry : join11(relativeDir, entry);
66497
- const absolutePath = join11(root, relativePath2);
67224
+ const relativePath2 = relativeDir.length === 0 ? entry : join12(relativeDir, entry);
67225
+ const absolutePath = join12(root, relativePath2);
66498
67226
  const stat = await fs3.stat(absolutePath);
66499
67227
  if (stat?.isDirectory()) {
66500
67228
  files.push(...await this.listRuleFiles(root, relativePath2));
@@ -66519,8 +67247,8 @@ var init_rule_service = __esm(() => {
66519
67247
  init_src2();
66520
67248
  init_dist6();
66521
67249
  init_dist10();
66522
- LOCAL_RULES_DIR = join11(".spur", "rules");
66523
- GLOBAL_RULES_DIR = join11(".config", "spur", "rules");
67250
+ LOCAL_RULES_DIR = join12(".spur", "rules");
67251
+ GLOBAL_RULES_DIR = join12(".config", "spur", "rules");
66524
67252
  SEVERITY_RANK2 = {
66525
67253
  info: 0,
66526
67254
  warning: 1,
@@ -66879,10 +67607,10 @@ class SupervisorService {
66879
67607
  proc.handle.kill("SIGTERM");
66880
67608
  let timedOut = false;
66881
67609
  const exitPromise = proc.handle.exited;
66882
- const timeout = new Promise((resolve4) => {
67610
+ const timeout = new Promise((resolve5) => {
66883
67611
  setTimeout(() => {
66884
67612
  timedOut = true;
66885
- resolve4();
67613
+ resolve5();
66886
67614
  }, 3000);
66887
67615
  });
66888
67616
  await Promise.race([exitPromise, timeout]);
@@ -67154,7 +67882,7 @@ var init_system_event_emitter = __esm(() => {
67154
67882
  });
67155
67883
 
67156
67884
  // ../../packages/app/src/services/task-check.ts
67157
- import { dirname as dirname10, join as join12 } from "path";
67885
+ import { dirname as dirname11, join as join13 } from "path";
67158
67886
  function isPlaceholderBody(body) {
67159
67887
  const stripped = body.replace(/<!--[\s\S]*?-->/g, "").replace(/^\s*>\s*TBD\s*$/gim, "").trim();
67160
67888
  return stripped.length === 0;
@@ -67215,9 +67943,9 @@ function isProseOnlyReview(body) {
67215
67943
  function resolveProjectRootFromTasksDir(tasksDir) {
67216
67944
  const norm = tasksDir.replace(/\\/g, "/");
67217
67945
  if (/\/docs\/tasks\d*$/.test(norm) || /\/docs\/tasks$/.test(norm)) {
67218
- return dirname10(dirname10(tasksDir));
67946
+ return dirname11(dirname11(tasksDir));
67219
67947
  }
67220
- return dirname10(tasksDir);
67948
+ return dirname11(tasksDir);
67221
67949
  }
67222
67950
  function extractBacktickLineAnchors(body) {
67223
67951
  const out = [];
@@ -67302,9 +68030,9 @@ var init_task_check = __esm(() => {
67302
68030
  const entry = this.resolveMatrixEntry(variant, status);
67303
68031
  this.runL2(doc2, entry, findings);
67304
68032
  this.runL3(doc2, entry, status, findings);
67305
- const tasksDir = dirname10(filePath);
67306
- const featuresDir = join12(dirname10(tasksDir), "features");
67307
- await this.runL4(doc2, fm, status, findings, featuresDir, tasksDir);
68033
+ const tasksDir = dirname11(filePath);
68034
+ const featuresDir = join13(dirname11(tasksDir), "features");
68035
+ await this.runL4(doc2, fm, status, findings, featuresDir, tasksDir, wbs);
67308
68036
  await this.runL4Rollup(doc2, wbs, status, findings, tasksDir);
67309
68037
  if (status !== "done" && status !== "cancelled") {
67310
68038
  await this.runL4Readiness(doc2, fm, wbs, status, findings, tasksDir);
@@ -67491,7 +68219,10 @@ var init_task_check = __esm(() => {
67491
68219
  }
67492
68220
  }
67493
68221
  }
67494
- async runL4(doc2, fm, status, findings, featuresDir, tasksDir) {
68222
+ async runL4(doc2, fm, status, findings, featuresDir, tasksDir, wbs) {
68223
+ if (status === "testing" || status === "done") {
68224
+ await this.checkVerdictArtifact(wbs, tasksDir, findings);
68225
+ }
67495
68226
  const template = typeof fm.template === "string" ? fm.template : DEFAULT_TASK_VARIANT;
67496
68227
  if (template === DEFAULT_TASK_VARIANT) {
67497
68228
  const designBody = doc2.getSection("Design");
@@ -67642,9 +68373,11 @@ var init_task_check = __esm(() => {
67642
68373
  });
67643
68374
  }
67644
68375
  }
68376
+ const declaredSet = new Set(declaredDeps);
67645
68377
  const directDeps = [...new Set([...declaredDeps, ...proseDeps.map((d) => d.wbs)])].filter((dep) => dep !== wbs);
67646
68378
  for (const depWbs of directDeps) {
67647
- await this.checkDependencyReadiness(depWbs, wbs, findings, tasksDir, new Set([wbs]), false);
68379
+ const proseSeeded = !declaredSet.has(depWbs);
68380
+ await this.checkDependencyReadiness(depWbs, wbs, findings, tasksDir, new Set([wbs]), false, proseSeeded);
67648
68381
  }
67649
68382
  this.checkGateLanguage(doc2, findings);
67650
68383
  }
@@ -67663,33 +68396,51 @@ var init_task_check = __esm(() => {
67663
68396
  }
67664
68397
  extractProsePrerequisites(doc2) {
67665
68398
  const refs = [];
68399
+ const headRe = /(?:depends on|depends upon|gated on|blocked by|waiting for)\b[^.;\n]{0,40}?\b(\d{4})\b/gi;
68400
+ const listRe = /\s*(?:,|and)\s*(?:tasks?\s+)?(\d{4})\b/gi;
67666
68401
  for (const section of ["Background", "Requirements", "Design", "Acceptance Criteria", "Plan"]) {
67667
68402
  const body = doc2.getSection(section);
67668
68403
  if (body === null)
67669
68404
  continue;
68405
+ let inFence = false;
67670
68406
  for (const line of body.split(`
67671
68407
  `)) {
67672
- 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);
67673
- if (!isPrereq)
68408
+ if (/^\s*```/.test(line)) {
68409
+ inFence = !inFence;
68410
+ continue;
68411
+ }
68412
+ if (inFence)
68413
+ continue;
68414
+ if (/^\s*\|/.test(line))
67674
68415
  continue;
67675
- for (const match of line.matchAll(/\b(\d{4})\b/g)) {
67676
- const wbs = match[1];
68416
+ const cleaned = line.replace(/`[^`]*`/g, " ");
68417
+ headRe.lastIndex = 0;
68418
+ for (let head = headRe.exec(cleaned);head !== null; head = headRe.exec(cleaned)) {
68419
+ const wbs = head[1];
67677
68420
  if (wbs !== undefined)
67678
68421
  refs.push({ wbs, section });
68422
+ listRe.lastIndex = headRe.lastIndex;
68423
+ for (let cont = listRe.exec(cleaned);cont !== null; cont = listRe.exec(cleaned)) {
68424
+ const cw = cont[1];
68425
+ if (cw !== undefined)
68426
+ refs.push({ wbs: cw, section });
68427
+ }
67679
68428
  }
67680
68429
  }
67681
68430
  }
67682
68431
  return refs;
67683
68432
  }
67684
- async checkDependencyReadiness(depWbs, rootWbs, findings, tasksDir, seen, transitive) {
68433
+ async checkDependencyReadiness(depWbs, rootWbs, findings, tasksDir, seen, transitive, proseSeeded = false) {
67685
68434
  if (seen.has(depWbs)) {
67686
- findings.push({
67687
- layer: "L4",
67688
- code: FINDING_CODES.L4_PREREQUISITE_CYCLE,
67689
- severity: "warning",
67690
- section: "",
67691
- message: `Prerequisite cycle detected while checking ${rootWbs}: ${[...seen, depWbs].join(" -> ")}`
67692
- });
68435
+ if (!proseSeeded) {
68436
+ findings.push({
68437
+ layer: "L4",
68438
+ code: FINDING_CODES.L4_PREREQUISITE_CYCLE,
68439
+ severity: "warning",
68440
+ section: "",
68441
+ message: `Prerequisite cycle detected while checking ${rootWbs}: ${[...seen, depWbs].join(" -> ")}`
68442
+ });
68443
+ }
67693
68444
  return;
67694
68445
  }
67695
68446
  const dep = await this.readTaskSnapshot(tasksDir, depWbs);
@@ -67707,7 +68458,7 @@ var init_task_check = __esm(() => {
67707
68458
  const nextSeen = new Set(seen);
67708
68459
  nextSeen.add(depWbs);
67709
68460
  for (const childDep of dep.dependencies) {
67710
- await this.checkDependencyReadiness(childDep, rootWbs, findings, tasksDir, nextSeen, true);
68461
+ await this.checkDependencyReadiness(childDep, rootWbs, findings, tasksDir, nextSeen, true, proseSeeded);
67711
68462
  }
67712
68463
  }
67713
68464
  checkGateLanguage(doc2, findings) {
@@ -67753,7 +68504,7 @@ var init_task_check = __esm(() => {
67753
68504
  for (const cite of citations) {
67754
68505
  if (reported >= 5)
67755
68506
  break;
67756
- const abs = join12(projectRoot, cite.path);
68507
+ const abs = join13(projectRoot, cite.path);
67757
68508
  let exists2 = false;
67758
68509
  try {
67759
68510
  exists2 = await this.fs.exists(abs);
@@ -67867,6 +68618,38 @@ var init_task_check = __esm(() => {
67867
68618
  async findTaskFile(tasksDir, wbs) {
67868
68619
  return await this.locatorFor(tasksDir).findPathByWbs(wbs);
67869
68620
  }
68621
+ async checkVerdictArtifact(wbs, tasksDir, findings) {
68622
+ const projectRoot = resolveProjectRootFromTasksDir(tasksDir);
68623
+ const runDir = join13(projectRoot, ".spur", "run");
68624
+ const loaded = await readVerdictArtifact(this.fs, runDir, wbs);
68625
+ if (loaded.artifact === undefined) {
68626
+ if (loaded.readError && loaded.readError !== "artifact is missing") {
68627
+ findings.push({
68628
+ layer: "L4",
68629
+ code: FINDING_CODES.L4_MALFORMED_VERDICT_ARTIFACT,
68630
+ severity: "error",
68631
+ section: "Testing",
68632
+ message: `Verdict artifact at ${loaded.path} is malformed: ${loaded.readError}`
68633
+ });
68634
+ }
68635
+ return;
68636
+ }
68637
+ const artifact = loaded.artifact;
68638
+ const reqs = artifact.requirements ?? [];
68639
+ const acs = artifact.acceptanceCriteria ?? [];
68640
+ const isUnknown = artifact.verdict === "UNKNOWN";
68641
+ const isEmpty = reqs.length === 0 && acs.length === 0;
68642
+ if (isUnknown || isEmpty) {
68643
+ const reason = isUnknown ? "verdict is UNKNOWN" : "requirements and AC are empty";
68644
+ findings.push({
68645
+ layer: "L4",
68646
+ code: FINDING_CODES.L4_MALFORMED_VERDICT_ARTIFACT,
68647
+ severity: "error",
68648
+ section: "Testing",
68649
+ message: `Verdict artifact at ${loaded.path} is malformed: ${reason}`
68650
+ });
68651
+ }
68652
+ }
67870
68653
  };
67871
68654
  });
67872
68655
 
@@ -68070,7 +68853,7 @@ var init_task_record = __esm(() => {
68070
68853
  });
68071
68854
 
68072
68855
  // ../../packages/app/src/services/task-scaffold.ts
68073
- import { dirname as dirname11 } from "path";
68856
+ import { dirname as dirname12 } from "path";
68074
68857
 
68075
68858
  class TaskScaffoldService {
68076
68859
  ctx;
@@ -68113,7 +68896,7 @@ class TaskScaffoldService {
68113
68896
  fileExists = false;
68114
68897
  }
68115
68898
  const mergeResult = mergeStubs(existingContent, stubs);
68116
- const dir = dirname11(targetFile);
68899
+ const dir = dirname12(targetFile);
68117
68900
  await this.ctx.fs.ensureDir(dir);
68118
68901
  if (mergeResult.created > 0 || !fileExists) {
68119
68902
  await this.ctx.fs.writeFile(targetFile, mergeResult.content);
@@ -68145,7 +68928,7 @@ var init_task_scaffold = __esm(() => {
68145
68928
  });
68146
68929
 
68147
68930
  // ../../packages/app/src/services/task-service.ts
68148
- import { isAbsolute, relative as relative3 } from "path";
68931
+ import { dirname as dirname13, isAbsolute as isAbsolute2, join as join14, relative as relative3 } from "path";
68149
68932
  function patchFrontmatterField(rendered, key, value) {
68150
68933
  const openIdx = rendered.indexOf("---");
68151
68934
  if (openIdx === -1)
@@ -68615,7 +69398,56 @@ class TaskService {
68615
69398
  const raw = await this.ctx.fs.readFile(sourceFile);
68616
69399
  const body = stripLeadingSectionHeader2(raw, sectionName);
68617
69400
  const ref = { kind: "task", id: wbs, filePath, folder: this.ctx.tasksDir };
68618
- return this.writeService.updateSection(ref, sectionName, body);
69401
+ const result = await this.writeService.updateSection(ref, sectionName, body);
69402
+ if (sectionName === "Acceptance Criteria") {
69403
+ const warnings = await this.checkAcSubsetWarning(filePath, body);
69404
+ if (warnings.length > 0) {
69405
+ return {
69406
+ ...result,
69407
+ warnings: [...result.warnings ?? [], ...warnings]
69408
+ };
69409
+ }
69410
+ }
69411
+ return result;
69412
+ }
69413
+ async checkAcSubsetWarning(taskFilePath, acBody) {
69414
+ try {
69415
+ const raw = await this.ctx.fs.readFile(taskFilePath);
69416
+ const doc2 = MarkdownDocument.parse(raw, "task");
69417
+ const fm = doc2.frontmatterData ?? {};
69418
+ const featureId2 = fm.feature_id ?? fm["feature-id"];
69419
+ if (!featureId2 || featureId2.length === 0)
69420
+ return [];
69421
+ const tasksDir = dirname13(taskFilePath);
69422
+ const featuresDir = join14(tasksDir, "..", "features");
69423
+ const featurePath = await (async () => {
69424
+ try {
69425
+ for (const name of await this.ctx.fs.readDir(featuresDir)) {
69426
+ if (name.startsWith(`${featureId2}_`) && name.endsWith(".md")) {
69427
+ return `${featuresDir}/${name}`;
69428
+ }
69429
+ }
69430
+ } catch {}
69431
+ return null;
69432
+ })();
69433
+ if (featurePath === null)
69434
+ return [];
69435
+ const featureRaw = await this.ctx.fs.readFile(featurePath);
69436
+ const featureDoc = MarkdownDocument.parse(featureRaw, "feature");
69437
+ const featureAc = stripAcFence(featureDoc.getSection("Acceptance Criteria") ?? "");
69438
+ if (!featureAc.trim())
69439
+ return [];
69440
+ const taskAc = stripAcFence(acBody);
69441
+ const taskChecklist = parseChecklist(taskAc);
69442
+ const coverage = checkAcCoverage(featureAc, taskAc, taskChecklist);
69443
+ const warnings = [];
69444
+ for (const scenario of coverage.uncovered) {
69445
+ warnings.push(`Task scenario "${scenario}" is not in feature "${featureId2}"'s AC (DD-09 subset rule)`);
69446
+ }
69447
+ return warnings;
69448
+ } catch {
69449
+ return [];
69450
+ }
68619
69451
  }
68620
69452
  async record(wbs, opts = {}) {
68621
69453
  const filePath = await this.resolveTaskFile(wbs);
@@ -69014,7 +69846,7 @@ ${block}` : block);
69014
69846
  const root = this.ctx.fs.resolve(".");
69015
69847
  const candidate = this.ctx.fs.resolve(folder);
69016
69848
  const rel = relative3(root, candidate);
69017
- if (rel.startsWith("..") || isAbsolute(rel)) {
69849
+ if (rel.startsWith("..") || isAbsolute2(rel)) {
69018
69850
  throw new Error(`Invalid folder: ${folder} escapes the planning workspace`);
69019
69851
  }
69020
69852
  return candidate;
@@ -69346,7 +70178,7 @@ var init_task_verdict = __esm(() => {
69346
70178
  });
69347
70179
 
69348
70180
  // ../../packages/app/src/services/team-service.ts
69349
- import { join as join13 } from "path";
70181
+ import { join as join15 } from "path";
69350
70182
 
69351
70183
  class TeamService {
69352
70184
  ctx;
@@ -69354,7 +70186,7 @@ class TeamService {
69354
70186
  orchestratorPromise;
69355
70187
  constructor(ctx) {
69356
70188
  this.ctx = ctx;
69357
- this.configDir = join13(ctx.cwd, ".spur", "agents");
70189
+ this.configDir = join15(ctx.cwd, ".spur", "agents");
69358
70190
  }
69359
70191
  async sendMessage(fromId, toId, body, replyTo) {
69360
70192
  validateAgentId(toId);
@@ -69764,7 +70596,7 @@ class TeamService {
69764
70596
  async resolveTaskFile(taskId) {
69765
70597
  const fs3 = this.ctx.fs;
69766
70598
  const { foldersConfig } = await resolvePlanningFolders(fs3);
69767
- const dirs = [...new Set([foldersConfig.active_folder, ...Object.keys(foldersConfig.folders)])].map((dir) => join13(this.ctx.cwd, dir));
70599
+ const dirs = [...new Set([foldersConfig.active_folder, ...Object.keys(foldersConfig.folders)])].map((dir) => join15(this.ctx.cwd, dir));
69768
70600
  return await TaskLocator.forDirs(fs3, dirs).findPathByWbs(taskId);
69769
70601
  }
69770
70602
  }
@@ -69800,8 +70632,8 @@ var init_team_service = __esm(() => {
69800
70632
  });
69801
70633
 
69802
70634
  // ../../packages/app/src/services/token-ledger-service.ts
69803
- import { closeSync as closeSync3, existsSync as existsSync7, fstatSync, openSync as openSync3, readSync } from "fs";
69804
- import { join as join14 } from "path";
70635
+ import { closeSync as closeSync3, existsSync as existsSync8, fstatSync, openSync as openSync3, readSync } from "fs";
70636
+ import { join as join16 } from "path";
69805
70637
  function isSparseToolActivity(events2) {
69806
70638
  return events2.length === 0 || !events2.some((e) => TOOL_ACTIVITY_TYPES.has(e.type));
69807
70639
  }
@@ -69852,7 +70684,7 @@ function parseLedgerLine(line) {
69852
70684
  }
69853
70685
  }
69854
70686
  function tailTokenLedgerFile(filePath, limit, chunkSize = DEFAULT_CHUNK, before) {
69855
- if (!existsSync7(filePath)) {
70687
+ if (!existsSync8(filePath)) {
69856
70688
  return { events: [], truncated: false };
69857
70689
  }
69858
70690
  const target = limit + 1;
@@ -69902,7 +70734,7 @@ class TokenLedgerService {
69902
70734
  ledgerPath;
69903
70735
  chunkSize;
69904
70736
  constructor(options) {
69905
- this.ledgerPath = options.ledgerPath ?? join14(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
70737
+ this.ledgerPath = options.ledgerPath ?? join16(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
69906
70738
  this.chunkSize = options.chunkSize ?? DEFAULT_CHUNK;
69907
70739
  }
69908
70740
  get path() {
@@ -69943,12 +70775,12 @@ class TokenLedgerService {
69943
70775
  var TOOL_ACTIVITY_TYPES, TOKEN_LEDGER_DEFAULT_LIMIT = 200, TOKEN_LEDGER_MAX_LIMIT = 1000, TOKEN_LEDGER_RELATIVE_PATH, DEFAULT_CHUNK;
69944
70776
  var init_token_ledger_service = __esm(() => {
69945
70777
  TOOL_ACTIVITY_TYPES = new Set(["read", "write", "bash", "grep", "glob"]);
69946
- TOKEN_LEDGER_RELATIVE_PATH = join14(".spur", "context", "token-ledger.jsonl");
70778
+ TOKEN_LEDGER_RELATIVE_PATH = join16(".spur", "context", "token-ledger.jsonl");
69947
70779
  DEFAULT_CHUNK = 64 * 1024;
69948
70780
  });
69949
70781
 
69950
70782
  // ../../packages/app/src/services/token-ledger-watcher.ts
69951
- import { closeSync as closeSync4, existsSync as existsSync8, fstatSync as fstatSync2, openSync as openSync4, readSync as readSync2, watch } from "fs";
70783
+ import { closeSync as closeSync4, existsSync as existsSync9, fstatSync as fstatSync2, openSync as openSync4, readSync as readSync2, watch } from "fs";
69952
70784
 
69953
70785
  class TokenLedgerWatcher {
69954
70786
  ledgerPath;
@@ -69969,7 +70801,7 @@ class TokenLedgerWatcher {
69969
70801
  this.started = true;
69970
70802
  this.offset = this.currentSize();
69971
70803
  try {
69972
- const target = existsSync8(this.ledgerPath) ? this.ledgerPath : this.parentDir();
70804
+ const target = existsSync9(this.ledgerPath) ? this.ledgerPath : this.parentDir();
69973
70805
  this.watcher = watch(target, () => this.schedulePoll());
69974
70806
  } catch {
69975
70807
  this.watcher = undefined;
@@ -70004,7 +70836,7 @@ class TokenLedgerWatcher {
70004
70836
  return idx > 0 ? this.ledgerPath.slice(0, idx) : ".";
70005
70837
  }
70006
70838
  currentSize() {
70007
- if (!existsSync8(this.ledgerPath))
70839
+ if (!existsSync9(this.ledgerPath))
70008
70840
  return 0;
70009
70841
  try {
70010
70842
  const fd = openSync4(this.ledgerPath, "r");
@@ -70026,7 +70858,7 @@ class TokenLedgerWatcher {
70026
70858
  }, this.debounceMs);
70027
70859
  }
70028
70860
  pollNewBytes() {
70029
- if (!existsSync8(this.ledgerPath)) {
70861
+ if (!existsSync9(this.ledgerPath)) {
70030
70862
  this.offset = 0;
70031
70863
  this.carry = "";
70032
70864
  return;
@@ -70117,16 +70949,16 @@ class WorkflowSteeringController {
70117
70949
  active.state = "boundary";
70118
70950
  active.version += 1;
70119
70951
  this.publishState(active);
70120
- return await new Promise((resolve4) => {
70952
+ return await new Promise((resolve5) => {
70121
70953
  const settle = (decision) => {
70122
70954
  clearTimeout(timer);
70123
- resolve4(decision);
70955
+ resolve5(decision);
70124
70956
  };
70125
70957
  const timer = setTimeout(() => {
70126
70958
  if (active.resolve !== settle)
70127
70959
  return;
70128
70960
  active.resolve = undefined;
70129
- this.acceptDefault(active, resolve4);
70961
+ this.acceptDefault(active, resolve5);
70130
70962
  }, active.policy.timeoutMs);
70131
70963
  timer.unref?.();
70132
70964
  active.resolve = settle;
@@ -70224,7 +71056,7 @@ class WorkflowSteeringController {
70224
71056
  deadlineAt: new Date(Date.now() + deadlineMs).toISOString()
70225
71057
  });
70226
71058
  }
70227
- acceptDefault(active, resolve4) {
71059
+ acceptDefault(active, resolve5) {
70228
71060
  const command = {
70229
71061
  commandId: crypto.randomUUID(),
70230
71062
  runId: active.runId,
@@ -70249,7 +71081,7 @@ class WorkflowSteeringController {
70249
71081
  at: new Date().toISOString()
70250
71082
  };
70251
71083
  this.onAck?.(ack);
70252
- resolve4({ operation: "continue" });
71084
+ resolve5({ operation: "continue" });
70253
71085
  }
70254
71086
  accept(command, active, note) {
70255
71087
  return this.publish({
@@ -70312,7 +71144,7 @@ var init_steering = __esm(() => {
70312
71144
  });
70313
71145
 
70314
71146
  // ../../packages/app/src/workflow/actions/agent-run.ts
70315
- import { dirname as dirname12, isAbsolute as isAbsolute2, join as join15 } from "path";
71147
+ import { dirname as dirname14, isAbsolute as isAbsolute3, join as join17 } from "path";
70316
71148
 
70317
71149
  class AgentRunActionRunner {
70318
71150
  observabilityBus;
@@ -70342,11 +71174,11 @@ class AgentRunActionRunner {
70342
71174
  let sessionDir = asOptionalString(context4.vars.__agentSessionDir);
70343
71175
  if (affinityOn) {
70344
71176
  if (!sessionDir || prevAgent && prevAgent !== targetAgentDir) {
70345
- sessionDir = join15(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
71177
+ sessionDir = join17(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
70346
71178
  }
70347
71179
  } else {
70348
71180
  if (!sessionDir) {
70349
- sessionDir = join15(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
71181
+ sessionDir = join17(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
70350
71182
  }
70351
71183
  }
70352
71184
  const storedSessionId = asOptionalString(context4.vars.__agentSessionId);
@@ -70447,13 +71279,13 @@ class AgentRunActionRunner {
70447
71279
  const ok = exitCode === 0;
70448
71280
  const invocation = traced.invocation;
70449
71281
  if (capture && answerFile !== undefined) {
70450
- const target = isAbsolute2(answerFile) ? answerFile : join15(cwd, answerFile);
71282
+ const target = isAbsolute3(answerFile) ? answerFile : join17(cwd, answerFile);
70451
71283
  const fs3 = createNodeFileSystem3(cwd);
70452
- await fs3.ensureDir(dirname12(target));
71284
+ await fs3.ensureDir(dirname14(target));
70453
71285
  await fs3.writeFile(target, answer);
70454
71286
  }
70455
71287
  if (ok && expectFile !== undefined) {
70456
- const target = isAbsolute2(expectFile) ? expectFile : join15(cwd, expectFile);
71288
+ const target = isAbsolute3(expectFile) ? expectFile : join17(cwd, expectFile);
70457
71289
  const fs3 = createNodeFileSystem3(cwd);
70458
71290
  if (!await fs3.exists(target)) {
70459
71291
  return {
@@ -70479,7 +71311,7 @@ class AgentRunActionRunner {
70479
71311
  const resolvedAgent = invocation?.agent ?? targetAgentDir;
70480
71312
  let resolvedSessionDir = sessionDir;
70481
71313
  if (ok && affinityOn && resolvedAgent !== targetAgentDir && !context4.vars.__agentSessionDir) {
70482
- resolvedSessionDir = join15(cwd, ".spur", "run", context4.runId, "agent-sessions", resolvedAgent);
71314
+ resolvedSessionDir = join17(cwd, ".spur", "run", context4.runId, "agent-sessions", resolvedAgent);
70483
71315
  }
70484
71316
  let discoveredSessionId = storedSessionId;
70485
71317
  if (ok && affinityOn && resolvedSessionDir && !discoveredSessionId) {
@@ -70487,9 +71319,9 @@ class AgentRunActionRunner {
70487
71319
  }
70488
71320
  if (ok && affinityOn && resolvedSessionDir) {
70489
71321
  try {
70490
- const sidecarPath = join15(cwd, ".spur", "run", `${context4.runId}-agent-session.json`);
71322
+ const sidecarPath = join17(cwd, ".spur", "run", `${context4.runId}-agent-session.json`);
70491
71323
  const fs3 = createNodeFileSystem3(cwd);
70492
- await fs3.ensureDir(dirname12(sidecarPath));
71324
+ await fs3.ensureDir(dirname14(sidecarPath));
70493
71325
  await fs3.writeFile(sidecarPath, JSON.stringify({
70494
71326
  agent: resolvedAgent,
70495
71327
  sessionId: discoveredSessionId ?? null,
@@ -70527,7 +71359,7 @@ async function discoverSessionId(sessionDir) {
70527
71359
  let newestFile;
70528
71360
  let newestMtime = 0;
70529
71361
  for (const entry of jsonEntries) {
70530
- const fullPath = join15(sessionDir, entry);
71362
+ const fullPath = join17(sessionDir, entry);
70531
71363
  const st = await fs3.stat(fullPath);
70532
71364
  if (st?.isFile() && st.mtimeMs > newestMtime) {
70533
71365
  newestMtime = st.mtimeMs;
@@ -70622,9 +71454,9 @@ async function writePartialWorkArtifact(context4, agentLabel, model, traced, cwd
70622
71454
  try {
70623
71455
  const fs4 = createNodeFileSystem3(cwd);
70624
71456
  const locator = TaskLocator.forDirs(fs4, [
70625
- join15(cwd, "docs", "tasks3"),
70626
- join15(cwd, "docs", "tasks2"),
70627
- join15(cwd, "docs", "tasks")
71457
+ join17(cwd, "docs", "tasks3"),
71458
+ join17(cwd, "docs", "tasks2"),
71459
+ join17(cwd, "docs", "tasks")
70628
71460
  ]);
70629
71461
  const hit = await locator.findByWbs(wbs);
70630
71462
  if (hit) {
@@ -70679,9 +71511,9 @@ async function writePartialWorkArtifact(context4, agentLabel, model, traced, cwd
70679
71511
  completedSection
70680
71512
  ].join(`
70681
71513
  `);
70682
- const target = join15(cwd, ".spur", "run", `${context4.runId}-${context4.stateOrNodeId}-partial.md`);
71514
+ const target = join17(cwd, ".spur", "run", `${context4.runId}-${context4.stateOrNodeId}-partial.md`);
70683
71515
  const fs3 = createNodeFileSystem3(cwd);
70684
- await fs3.ensureDir(dirname12(target));
71516
+ await fs3.ensureDir(dirname14(target));
70685
71517
  await fs3.writeFile(target, body);
70686
71518
  } catch {}
70687
71519
  }
@@ -71451,7 +72283,7 @@ var init_builtins2 = __esm(() => {
71451
72283
 
71452
72284
  // ../../packages/app/src/services/workflow-service.ts
71453
72285
  import { homedir as homedir5 } from "os";
71454
- import { join as join16, resolve as resolve4 } from "path";
72286
+ import { join as join18, resolve as resolve5 } from "path";
71455
72287
  function signalSubprocess(pid) {
71456
72288
  if (!Number.isInteger(pid) || pid <= 1)
71457
72289
  return false;
@@ -71521,7 +72353,7 @@ class WorkflowAppService {
71521
72353
  };
71522
72354
  }
71523
72355
  async validate(file2, opts = {}) {
71524
- const absolute = resolve4(this.ctx.cwd, file2);
72356
+ const absolute = resolve5(this.ctx.cwd, file2);
71525
72357
  if (!await fileExists(absolute)) {
71526
72358
  return { ok: false, valid: false, file: file2, errors: [`File not found: ${absolute}`] };
71527
72359
  }
@@ -71579,7 +72411,7 @@ class WorkflowAppService {
71579
72411
  ...opts.vars ?? {},
71580
72412
  __runId: runId
71581
72413
  };
71582
- const absolute = resolve4(this.ctx.cwd, file2);
72414
+ const absolute = resolve5(this.ctx.cwd, file2);
71583
72415
  const embedded = this.embeddedSchemaOptions();
71584
72416
  const workflow = await loadWorkflowDef(absolute, {
71585
72417
  validateSchema: true,
@@ -71606,7 +72438,7 @@ class WorkflowAppService {
71606
72438
  return;
71607
72439
  let workflowName;
71608
72440
  try {
71609
- const def = await loadWorkflowDef(resolve4(this.ctx.cwd, file2), { validateSchema: false });
72441
+ const def = await loadWorkflowDef(resolve5(this.ctx.cwd, file2), { validateSchema: false });
71610
72442
  workflowName = def.name;
71611
72443
  } catch {
71612
72444
  return;
@@ -71651,7 +72483,7 @@ class WorkflowAppService {
71651
72483
  };
71652
72484
  }
71653
72485
  async cleanRunLogs(retentionDays = 30, dryRun = false) {
71654
- const runDir = join16(this.ctx.cwd, ".spur", "run");
72486
+ const runDir = join18(this.ctx.cwd, ".spur", "run");
71655
72487
  const fs3 = createNodeFileSystem3();
71656
72488
  const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
71657
72489
  const reclaimed = [];
@@ -71663,7 +72495,7 @@ class WorkflowAppService {
71663
72495
  return { retentionDays, dryRun, reclaimed, failures };
71664
72496
  }
71665
72497
  for (const name of entries) {
71666
- const path9 = join16(runDir, name);
72498
+ const path9 = join18(runDir, name);
71667
72499
  const stat = await fs3.stat(path9);
71668
72500
  if (stat === null || !stat.isFile() || stat.mtimeMs >= cutoffMs)
71669
72501
  continue;
@@ -71731,7 +72563,7 @@ class WorkflowAppService {
71731
72563
  if (entry === undefined)
71732
72564
  return null;
71733
72565
  for (const layer of listing.layers) {
71734
- const abs = resolve4(layer.path, entry.path);
72566
+ const abs = resolve5(layer.path, entry.path);
71735
72567
  if (await fileExists(abs)) {
71736
72568
  try {
71737
72569
  return await loadWorkflowDef(abs, { validateSchema: false });
@@ -71742,12 +72574,12 @@ class WorkflowAppService {
71742
72574
  }
71743
72575
  async list(workflowPaths = [".spur/workflows/"]) {
71744
72576
  const projectRoot = this.ctx.cwd;
71745
- const globalRoot = join16(homedir5(), ".config", "spur");
72577
+ const globalRoot = join18(homedir5(), ".config", "spur");
71746
72578
  const layers = [];
71747
72579
  const entries = [];
71748
72580
  const scannedPaths = new Set;
71749
72581
  for (const relPath of workflowPaths) {
71750
- const absPath = resolve4(projectRoot, relPath);
72582
+ const absPath = resolve5(projectRoot, relPath);
71751
72583
  layers.push({ id: "project", path: absPath });
71752
72584
  scannedPaths.add(absPath);
71753
72585
  try {
@@ -71756,7 +72588,7 @@ class WorkflowAppService {
71756
72588
  } catch {}
71757
72589
  }
71758
72590
  for (const relPath of workflowPaths) {
71759
- const absPath = resolve4(globalRoot, relPath);
72591
+ const absPath = resolve5(globalRoot, relPath);
71760
72592
  if (scannedPaths.has(absPath))
71761
72593
  continue;
71762
72594
  layers.push({ id: "global", path: absPath });
@@ -71978,8 +72810,8 @@ async function resolveOutputLogConfig(cwd) {
71978
72810
  }
71979
72811
  }
71980
72812
  async function outputArtifactForRun(cwd, runId) {
71981
- const relative4 = join16(".spur", "run", `${runId}.log`);
71982
- return await fileExists(join16(cwd, relative4)) ? relative4 : undefined;
72813
+ const relative4 = join18(".spur", "run", `${runId}.log`);
72814
+ return await fileExists(join18(cwd, relative4)) ? relative4 : undefined;
71983
72815
  }
71984
72816
  async function scanWorkflowFiles(rootPath, source) {
71985
72817
  const entries = [];
@@ -71992,7 +72824,7 @@ async function scanWorkflowFiles(rootPath, source) {
71992
72824
  async function walk3(dirPath) {
71993
72825
  const names = await fs3.readDir(dirPath);
71994
72826
  for (const name of names) {
71995
- const fullPath = resolve4(dirPath, name);
72827
+ const fullPath = resolve5(dirPath, name);
71996
72828
  const st = await fs3.stat(fullPath);
71997
72829
  if (!st)
71998
72830
  continue;
@@ -72215,7 +73047,7 @@ var init_lifecycle_adapter = __esm(() => {
72215
73047
  });
72216
73048
 
72217
73049
  // ../../packages/app/src/workflow/trace-writer.ts
72218
- import { dirname as dirname13, join as join17 } from "path";
73050
+ import { dirname as dirname15, join as join19 } from "path";
72219
73051
 
72220
73052
  class WorkflowTraceWriter {
72221
73053
  path;
@@ -72223,7 +73055,7 @@ class WorkflowTraceWriter {
72223
73055
  pending = Promise.resolve();
72224
73056
  constructor(cwd, runId) {
72225
73057
  const safeRunId = runId.replace(/[^A-Za-z0-9._-]/g, "_");
72226
- this.path = join17(cwd, ".spur", "runs", "workflow", `${safeRunId}.jsonl`);
73058
+ this.path = join19(cwd, ".spur", "runs", "workflow", `${safeRunId}.jsonl`);
72227
73059
  }
72228
73060
  attach(bus) {
72229
73061
  bus.on("workflow.run.started", (event2) => this.enqueue("workflow.run.started", event2));
@@ -72249,7 +73081,7 @@ class WorkflowTraceWriter {
72249
73081
  `;
72250
73082
  this.pending = this.pending.then(async () => {
72251
73083
  const fs3 = createNodeFileSystem3();
72252
- await fs3.ensureDir(dirname13(this.path));
73084
+ await fs3.ensureDir(dirname15(this.path));
72253
73085
  await fs3.appendFile(this.path, line);
72254
73086
  });
72255
73087
  }
@@ -72266,12 +73098,14 @@ __export(exports_src2, {
72266
73098
  summarizeActionResult: () => summarizeActionResult,
72267
73099
  startRegisteredProject: () => startRegisteredProject,
72268
73100
  setDetachedServeSpawnForTests: () => setDetachedServeSpawnForTests,
73101
+ runHistoryReport: () => runHistoryReport,
72269
73102
  resolveWorkflowLogRetentionDays: () => resolveWorkflowLogRetentionDays,
72270
73103
  resolveSpurServeCommand: () => resolveSpurServeCommand,
72271
73104
  resolveRetentionQuotas: () => resolveRetentionQuotas,
72272
73105
  resolvePlanningFolders: () => resolvePlanningFolders,
72273
73106
  resolveOutputLogConfig: () => resolveOutputLogConfig,
72274
73107
  resolveAutostartSet: () => resolveAutostartSet,
73108
+ resolveArtifactPath: () => resolveArtifactPath,
72275
73109
  renderTesting: () => renderTesting,
72276
73110
  renderStepLine: () => renderStepLine,
72277
73111
  renderSolutionFromDiff: () => renderSolutionFromDiff,
@@ -72283,6 +73117,7 @@ __export(exports_src2, {
72283
73117
  redactAndBound: () => redactAndBound,
72284
73118
  readVerdictArtifact: () => readVerdictArtifact,
72285
73119
  readVerdict: () => readVerdict,
73120
+ pruneReports: () => pruneReports,
72286
73121
  parseVerdict: () => parseVerdict,
72287
73122
  parseSteeringPolicy: () => parseSteeringPolicy,
72288
73123
  parsePsOutput: () => parsePsOutput,
@@ -72298,6 +73133,7 @@ __export(exports_src2, {
72298
73133
  hitlAutoApproveEnabled: () => hitlAutoApproveEnabled,
72299
73134
  hasPopulatedPriorityTable: () => hasPopulatedPriorityTable,
72300
73135
  formatNoopMessage: () => formatNoopMessage,
73136
+ formatIssue: () => formatIssue,
72301
73137
  formatDenialMessage: () => formatDenialMessage,
72302
73138
  extractSystemEventCorrelation: () => extractSystemEventCorrelation,
72303
73139
  extractSystemEventActor: () => extractSystemEventActor,
@@ -72309,6 +73145,7 @@ __export(exports_src2, {
72309
73145
  decodeRunListCursor: () => decodeRunListCursor,
72310
73146
  createPsProcessInspector: () => createPsProcessInspector,
72311
73147
  configuredSecretValues: () => configuredSecretValues,
73148
+ computeExitCode: () => computeExitCode,
72312
73149
  computeAggregate: () => computeAggregate,
72313
73150
  classifyTaskOutcome: () => classifyTaskOutcome,
72314
73151
  clampToolUseLimit: () => clampToolUseLimit,
@@ -72514,19 +73351,19 @@ var {
72514
73351
  init_src();
72515
73352
  init_loader();
72516
73353
 
72517
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/application-node.js
73354
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/application-node.js
72518
73355
  init_dist4();
72519
73356
  init_dist5();
72520
73357
  import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "fs";
72521
73358
  import { dirname as dirname5 } from "path";
72522
73359
 
72523
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/application/index.js
73360
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/application/index.js
72524
73361
  init_default_observers();
72525
73362
  init_event_bus();
72526
73363
  init_file_observer();
72527
73364
  init_logger3();
72528
73365
 
72529
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
73366
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
72530
73367
  class NoopSchedulerAdapter {
72531
73368
  constructor() {}
72532
73369
  register(_cron, _action) {}
@@ -72534,7 +73371,7 @@ class NoopSchedulerAdapter {
72534
73371
  async stop() {}
72535
73372
  }
72536
73373
 
72537
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
73374
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
72538
73375
  function initScheduler(adapter, cronEntries) {
72539
73376
  const resolved = adapter ?? new NoopSchedulerAdapter;
72540
73377
  if (cronEntries) {
@@ -72545,7 +73382,7 @@ function initScheduler(adapter, cronEntries) {
72545
73382
  return resolved;
72546
73383
  }
72547
73384
 
72548
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
73385
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
72549
73386
  init_logger3();
72550
73387
  init_metrics();
72551
73388
  init_sdk();
@@ -72638,7 +73475,7 @@ function dbPlugin(db2) {
72638
73475
  };
72639
73476
  }
72640
73477
 
72641
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
73478
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
72642
73479
  init_logger3();
72643
73480
 
72644
73481
  class PluginHost {
@@ -72726,7 +73563,7 @@ class PluginHost {
72726
73563
  }
72727
73564
  }
72728
73565
 
72729
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/application/index.js
73566
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/application/index.js
72730
73567
  async function performShutdown(state, reason) {
72731
73568
  if (state.stopped)
72732
73569
  return;
@@ -72837,10 +73674,10 @@ async function runApplication(options) {
72837
73674
  }
72838
73675
  }
72839
73676
 
72840
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/application-node.js
73677
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/application-node.js
72841
73678
  init_scheduler_node();
72842
73679
 
72843
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
73680
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
72844
73681
  var import_api14 = __toESM(require_src(), 1);
72845
73682
 
72846
73683
  // ../../node_modules/.bun/@opentelemetry+exporter-metrics-otlp-http@0.218.0+e40b0dfdd726a224/node_modules/@opentelemetry/exporter-metrics-otlp-http/build/esm/OTLPMetricExporterBase.js
@@ -75856,7 +76693,7 @@ class OTLPTraceExporter extends import_otlp_exporter_base2.OTLPExporterBase {
75856
76693
  }), JsonTraceSerializer));
75857
76694
  }
75858
76695
  }
75859
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
76696
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
75860
76697
  var import_resources2 = __toESM(require_src4(), 1);
75861
76698
  var import_sdk_trace_node = __toESM(require_src8(), 1);
75862
76699
  var import_semantic_conventions = __toESM(require_src2(), 1);
@@ -75907,7 +76744,7 @@ async function shutdownNodeTelemetry() {
75907
76744
  await Promise.all(pending);
75908
76745
  }
75909
76746
 
75910
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.22+8dad431b1c8f298c/node_modules/@gobing-ai/ts-infra/dist/application-node.js
76747
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.23+ce44f9a234a378c3/node_modules/@gobing-ai/ts-infra/dist/application-node.js
75911
76748
  class ConfigValidationError extends Error {
75912
76749
  constructor(message) {
75913
76750
  super(message);
@@ -79987,15 +80824,15 @@ function parseLoopPoll(raw) {
79987
80824
  return Number.isFinite(n2) && n2 > 0 ? n2 : DEFAULT_LOOP_POLL_MS;
79988
80825
  }
79989
80826
  function loopSleep(ms, signal) {
79990
- return new Promise((resolve5) => {
80827
+ return new Promise((resolve6) => {
79991
80828
  if (signal?.aborted) {
79992
- resolve5();
80829
+ resolve6();
79993
80830
  return;
79994
80831
  }
79995
- const timer = setTimeout(resolve5, ms);
80832
+ const timer = setTimeout(resolve6, ms);
79996
80833
  signal?.addEventListener("abort", () => {
79997
80834
  clearTimeout(timer);
79998
- resolve5();
80835
+ resolve6();
79999
80836
  }, { once: true });
80000
80837
  });
80001
80838
  }
@@ -80053,9 +80890,9 @@ function makePlanningEmitter(context4) {
80053
80890
  init_src3();
80054
80891
  init_loader();
80055
80892
  init_src2();
80056
- import { existsSync as existsSync9 } from "fs";
80893
+ import { existsSync as existsSync10 } from "fs";
80057
80894
  import { homedir as homedir6 } from "os";
80058
- import { join as join18, resolve as resolve5 } from "path";
80895
+ import { join as join20, resolve as resolve6 } from "path";
80059
80896
 
80060
80897
  // src/workflow/resolve-spur-bin.ts
80061
80898
  import { basename as basename3 } from "path";
@@ -80073,23 +80910,23 @@ function resolveSpurBin() {
80073
80910
  }
80074
80911
 
80075
80912
  // src/workflow/make-lifecycle-adapter.ts
80076
- var GLOBAL_CONFIG_DIR = join18(".config", "spur");
80913
+ var GLOBAL_CONFIG_DIR = join20(".config", "spur");
80077
80914
  function globalConfigRoot(context4) {
80078
80915
  const override = context4.env.SPUR_GLOBAL_RULES_DIR;
80079
- return override !== undefined && override.length > 0 ? resolve5(context4.cwd, override) : join18(homedir6(), GLOBAL_CONFIG_DIR);
80916
+ return override !== undefined && override.length > 0 ? resolve6(context4.cwd, override) : join20(homedir6(), GLOBAL_CONFIG_DIR);
80080
80917
  }
80081
80918
  function resolveWorkflowPath(context4, profile) {
80082
80919
  const bundledRoot = bundledConfigRoot();
80083
80920
  if (bundledRoot !== null) {
80084
- const bundledPath = join18(bundledRoot, "workflows", `${profile.workflowName}.yaml`);
80085
- if (existsSync9(bundledPath))
80921
+ const bundledPath = join20(bundledRoot, "workflows", `${profile.workflowName}.yaml`);
80922
+ if (existsSync10(bundledPath))
80086
80923
  return bundledPath;
80087
80924
  }
80088
- const projectPath = join18(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
80089
- if (existsSync9(projectPath))
80925
+ const projectPath = join20(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
80926
+ if (existsSync10(projectPath))
80090
80927
  return projectPath;
80091
- const globalPath = join18(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
80092
- if (existsSync9(globalPath))
80928
+ const globalPath = join20(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
80929
+ if (existsSync10(globalPath))
80093
80930
  return globalPath;
80094
80931
  return null;
80095
80932
  }
@@ -80474,46 +81311,229 @@ async function assertFeatureCheckPass(context4, id, folderOverride, strict, asSt
80474
81311
  // src/commands/history.ts
80475
81312
  init_src3();
80476
81313
  init_src2();
81314
+ init_dist6();
81315
+
81316
+ // src/config.ts
81317
+ var CLI_CONFIG = {
81318
+ binaryName: "spur",
81319
+ binaryLabel: "spur",
81320
+ binaryVersion: "0.3.36",
81321
+ configDir: ".spur",
81322
+ configFile: ".spur/config.yaml",
81323
+ databaseFile: ".spur/spur.db"
81324
+ };
81325
+
81326
+ // src/commands/history.ts
80477
81327
  function registerHistoryCommand(program2, context4) {
80478
81328
  const noun = program2.command("history").summary("import and analyze coding-agent history");
80479
- noun.command("import").description("Import agent conversation JSONL.").option("--source <source>", "pi|claude|codex|gemini|opencode|antigravity|openclaw|omp|grok|agy", "pi").option("--file <path>", "Import one JSONL file").option("--root <path>", "Scan a history root").option("--mode <mode>", "full|incremental|force-file").option("--dry-run", "Scan without persisting imported records").option("--json", "Output machine-readable JSON where supported").action(async (options) => {
81329
+ noun.command("import").description("Import agent conversation JSONL. `--source all` fans out across all sources with " + "per-source failure isolation (task 0470). A single source is the n=1 case of " + "the same contract \u2014 never two import paths.").option("--source <source>", "pi|claude|codex|gemini|opencode|antigravity|openclaw|omp|grok|agy|all", "all").option("--file <path>", "Import one JSONL file (single-source only)").option("--root <path>", "Scan a history root").option("--mode <mode>", "full|incremental|force-file").option("--dry-run", "Scan without persisting imported records").option("--source-timeout <ms>", "Per-source timeout in milliseconds (default 600000 = 10 min)", "600000").option("--json", "Output machine-readable JSON where supported").action(async (options) => {
80480
81330
  const svc = new HistoryService({ getDb: () => context4.getDb() });
80481
- const r = await svc.import(options.source ?? "pi", {
81331
+ const source = options.source ?? "all";
81332
+ if (options.file && source === "all") {
81333
+ context4.output.write(options.json ? toJson2({ status: "error", message: '--file requires a single --source, not "all".' }) : 'spur history import: --file requires a single --source, not "all".');
81334
+ context4.setExitCode(1);
81335
+ return;
81336
+ }
81337
+ const sourceTimeout = Number.parseInt(options.sourceTimeout ?? "600000", 10) || 600000;
81338
+ const mode = options.mode ?? (options.file ? "force-file" : "incremental");
81339
+ if (mode !== "full" && mode !== "incremental" && mode !== "force-file") {
81340
+ const modeMsg = `Invalid history import mode "${mode}". Expected one of: full, incremental, force-file`;
81341
+ if (options.json) {
81342
+ context4.output.write(toJson2({ status: "error", message: modeMsg }));
81343
+ } else {
81344
+ context4.output.error(modeMsg);
81345
+ }
81346
+ context4.setExitCode(1);
81347
+ return;
81348
+ }
81349
+ const fanOut = await svc.importAll({
81350
+ sources: source === "all" ? undefined : [source],
80482
81351
  file: options.file || undefined,
80483
81352
  root: options.root || undefined,
80484
- mode: options.mode ?? (options.file ? "force-file" : "incremental"),
80485
- dryRun: options.dryRun === true
81353
+ mode,
81354
+ dryRun: options.dryRun === true,
81355
+ sourceTimeout
80486
81356
  });
80487
- context4.output.write(options.json ? toJson2(r) : formatImportResult(r));
80488
- const code = r.parseErrors.length === 0 && r.validationErrors.length === 0 ? 0 : 1;
80489
- context4.setExitCode(code);
81357
+ context4.output.write(options.json ? toJson2(fanOut) : formatFanOutResult(fanOut));
81358
+ context4.setExitCode(fanOut.exitCode);
80490
81359
  });
80491
- noun.command("analyze").description("Summarize imported token, cost, and usage data.").option("--since <iso-date>", "Lower bound for analysis").option("--json", "Output machine-readable JSON where supported").action(async (options) => {
81360
+ noun.command("analyze").description("Aggregate imported history with SQL and write a versioned JSON artifact (Q1-Q10 forensic query set).").option("--since <iso>", "Inclusive lower bound on message timestamp").option("--until <iso>", "Inclusive upper bound on message timestamp").option("--source <source>", "pi|claude|codex|gemini|opencode|antigravity|openclaw|omp|grok|agy|all", "all").option("--session <id>", "Narrow to a single session id").option("--run <runId>", "Narrow to a single workflow run id").option("--task <wbs>", "Narrow to a single task WBS").option("--top <n>", "Leaderboard depth for byTool/bySession", "20").option("--out <path>", "Write the artifact to this path instead of the dated reports dir").option("--json", "Emit the artifact as JSON instead of the human summary").action(async (options) => {
80492
81361
  const svc = new HistoryService({ getDb: () => context4.getDb() });
80493
- const summary = await svc.analyze(options.since || undefined);
80494
- context4.output.write(options.json ? toJson2(summary) : formatSummary(summary));
81362
+ const source = options.source ?? "all";
81363
+ const selector = {
81364
+ since: options.since || null,
81365
+ until: options.until || null,
81366
+ sources: source === "all" ? null : [source],
81367
+ sessionId: options.session || null,
81368
+ runId: options.run || null,
81369
+ taskWbs: options.task || null
81370
+ };
81371
+ const artifact = await svc.analyze(selector, {
81372
+ top: Number.parseInt(options.top ?? "20", 10) || 20,
81373
+ spurVersion: CLI_CONFIG.binaryVersion,
81374
+ out: options.out || undefined,
81375
+ cwd: context4.cwd
81376
+ });
81377
+ context4.output.write(options.json ? toJson2(artifact) : formatSummary({
81378
+ totals: artifact.totals,
81379
+ bySource: artifact.bySource,
81380
+ byModel: artifact.byModel,
81381
+ daily: artifact.daily
81382
+ }));
80495
81383
  });
80496
- noun.command("report").description("Reserved richer report surface; not yet implemented (see docs/04_DESIGN.md \xA7spur history report).").option("--json", "Output machine-readable JSON where supported").action(async (options) => {
80497
- const message = `spur history report is reserved but not yet implemented (P8).
80498
- ` + `See docs/04_DESIGN.md for the planned surface.
80499
- ` + `Workaround: use "spur history analyze" for aggregate summaries, or
80500
- ` + '"spur history import" to load session data, then query the database directly.';
80501
- context4.output.write(options.json ? toJson2({ status: "not-implemented", message }) : message);
80502
- context4.setExitCode(0);
81384
+ noun.command("report").description("Render a previously-generated history artifact as a spend + forensic report. " + "Never opens the database \u2014 pure renderer of the analyze JSON.").argument("[path]", "Artifact JSON path (defaults to the latest.json pointer)").option("--json", "Emit the parsed artifact as JSON instead of the human report").action(async (pathArg, options) => {
81385
+ try {
81386
+ const { report, artifactPath, resolution, artifact } = runHistoryReport({
81387
+ path: pathArg,
81388
+ cwd: context4.cwd,
81389
+ now: new Date
81390
+ });
81391
+ if (options.json) {
81392
+ context4.output.write(toJson2(artifact));
81393
+ context4.setExitCode(0);
81394
+ return;
81395
+ }
81396
+ if (resolution === "pointer") {
81397
+ const banner = stalenessBanner(artifact.generatedAt, new Date);
81398
+ if (banner !== null)
81399
+ context4.output.write(banner);
81400
+ }
81401
+ context4.output.write(report);
81402
+ context4.output.write(`
81403
+ (artifact: ${artifactPath})
81404
+ `);
81405
+ context4.setExitCode(0);
81406
+ } catch (e) {
81407
+ const message = `spur history report failed: ${e.message}`;
81408
+ context4.output.write(options.json ? toJson2({ status: "error", message }) : message);
81409
+ context4.setExitCode(1);
81410
+ }
81411
+ });
81412
+ noun.command("daily").description("Run-once daily pipeline: import-all (fan-out, per-source isolation) \u2192 analyze \u2192 write " + "artifact \u2192 prune reports older than 90 days (task 0470 R6). Import uses checkpoint " + "resume, so a missed night self-heals on the next run with no gap and no double-count.").option("--since <iso>", "Inclusive lower bound on message timestamp for the report (not the import)").option("--until <iso>", "Inclusive upper bound on message timestamp for the report").option("--source-timeout <ms>", "Per-source import timeout in milliseconds (default 600000 = 10 min)", "600000").option("--root <path>", "History root override (default: per-source platform dir)").option("--json", "Emit the daily result as JSON").action(async (options) => {
81413
+ const svc = new HistoryService({ getDb: () => context4.getDb() });
81414
+ const sourceTimeout = Number.parseInt(options.sourceTimeout ?? "600000", 10) || 600000;
81415
+ const bus = new EventBus;
81416
+ const ledger = await attachSystemEventLedger(bus, context4);
81417
+ const startMs = Date.now();
81418
+ let result = null;
81419
+ let failure = null;
81420
+ try {
81421
+ result = await svc.daily({
81422
+ since: options.since || undefined,
81423
+ until: options.until || undefined,
81424
+ sourceTimeout,
81425
+ spurVersion: CLI_CONFIG.binaryVersion,
81426
+ cwd: context4.cwd,
81427
+ root: options.root || undefined
81428
+ });
81429
+ } catch (e) {
81430
+ failure = { exitCode: 1, detail: e instanceof Error ? e.message : String(e) };
81431
+ }
81432
+ const durationMs = Date.now() - startMs;
81433
+ try {
81434
+ if (failure !== null) {
81435
+ await bus.emit("history.daily.failed", {
81436
+ source: "history",
81437
+ renderer: "history-daily",
81438
+ detail: failure.detail,
81439
+ exitCode: failure.exitCode,
81440
+ durationMs
81441
+ });
81442
+ context4.setExitCode(1);
81443
+ } else if (result !== null) {
81444
+ const exitCode = result.fanOut.exitCode;
81445
+ let artifactPath;
81446
+ try {
81447
+ artifactPath = resolveArtifactPath(undefined, context4.cwd).path;
81448
+ } catch {
81449
+ artifactPath = undefined;
81450
+ }
81451
+ const entries = result.fanOut.entries;
81452
+ const sources = entries.length;
81453
+ const okSources = entries.filter((e) => e.status === "ok").length;
81454
+ const failedSources = entries.filter((e) => e.status === "failed").length;
81455
+ const files = entries.reduce((sum, e) => sum + e.files, 0);
81456
+ const messages2 = entries.reduce((sum, e) => sum + e.messages, 0);
81457
+ if (exitCode === 0) {
81458
+ await bus.emit("history.import.completed", {
81459
+ source: "history",
81460
+ renderer: "history-import",
81461
+ sources,
81462
+ okSources,
81463
+ failedSources,
81464
+ files,
81465
+ messages: messages2,
81466
+ durationMs,
81467
+ artifactPath
81468
+ });
81469
+ await bus.emit("history.analyze.completed", {
81470
+ source: "history",
81471
+ renderer: "history-analyze",
81472
+ artifactPath,
81473
+ totals: result.artifact.totals
81474
+ });
81475
+ } else {
81476
+ const failing = entries.filter((e) => e.status === "failed");
81477
+ await bus.emit("history.daily.failed", {
81478
+ source: "history",
81479
+ renderer: "history-daily",
81480
+ exitCode,
81481
+ sources,
81482
+ okSources,
81483
+ failedSources,
81484
+ detail: failing.length > 0 ? failing.map((e) => `${e.source}: ${e.parseErrors + e.validationErrors} errors`).join("; ") : "daily fan-out reported non-zero exit with no failing source",
81485
+ durationMs,
81486
+ artifactPath
81487
+ });
81488
+ }
81489
+ context4.setExitCode(exitCode);
81490
+ }
81491
+ } finally {
81492
+ ledger.unsubscribe();
81493
+ await ledger.flush();
81494
+ }
81495
+ if (failure !== null) {
81496
+ context4.output.write(options.json ? toJson2({ error: failure.detail }) : `history daily failed: ${failure.detail}`);
81497
+ return;
81498
+ }
81499
+ if (result === null) {
81500
+ context4.setExitCode(1);
81501
+ return;
81502
+ }
81503
+ context4.output.write(options.json ? toJson2(result) : formatDailyResult(result));
80503
81504
  });
80504
81505
  }
80505
- function formatImportResult(r) {
80506
- return [
80507
- `history import ${r.source}`,
80508
- `mode: ${r.mode}`,
80509
- `files: ${r.scannedFiles}`,
80510
- `lines: ${r.processedLines}`,
80511
- `imported: ${r.importedRecords}`,
80512
- `duplicates: ${r.skippedDuplicates}`,
80513
- `unknown: ${r.unknownRecords}`,
80514
- `parse_errors: ${r.parseErrors.length}`,
80515
- `validation_errors: ${r.validationErrors.length}`
80516
- ].join(`
81506
+ function formatFanOutResult(r) {
81507
+ const lines = ["history import (fan-out)", "sources:"];
81508
+ for (const e of r.entries) {
81509
+ lines.push(` ${e.source}: ${e.status} (files=${e.files} messages=${e.messages})`);
81510
+ }
81511
+ if (r.warnings.length > 0) {
81512
+ lines.push("warnings:");
81513
+ for (const w of r.warnings) {
81514
+ lines.push(` [${w.code}] ${w.source ?? "-"}: ${w.detail}`);
81515
+ }
81516
+ }
81517
+ lines.push(`exit_code: ${r.exitCode}`);
81518
+ return lines.join(`
81519
+ `);
81520
+ }
81521
+ function formatDailyResult(r) {
81522
+ const lines = ["history daily"];
81523
+ lines.push("import:");
81524
+ for (const e of r.fanOut.entries) {
81525
+ lines.push(` ${e.source}: ${e.status} (files=${e.files} messages=${e.messages})`);
81526
+ }
81527
+ if (r.fanOut.warnings.length > 0) {
81528
+ lines.push("warnings:");
81529
+ for (const w of r.fanOut.warnings) {
81530
+ lines.push(` [${w.code}] ${w.source ?? "-"}: ${w.detail}`);
81531
+ }
81532
+ }
81533
+ lines.push(`artifact totals: messages=${r.artifact.totals.messages} toolCalls=${r.artifact.totals.toolCalls}`);
81534
+ lines.push(`pruned: ${r.pruned.length} report dir(s) older than 90 days`);
81535
+ lines.push(`exit_code: ${r.fanOut.exitCode}`);
81536
+ return lines.join(`
80517
81537
  `);
80518
81538
  }
80519
81539
 
@@ -80522,17 +81542,7 @@ init_loader();
80522
81542
  init_src2();
80523
81543
  init_dist10();
80524
81544
  import { homedir as homedir7 } from "os";
80525
- import { join as join19, resolve as resolve6 } from "path";
80526
-
80527
- // src/config.ts
80528
- var CLI_CONFIG = {
80529
- binaryName: "spur",
80530
- binaryLabel: "spur",
80531
- binaryVersion: "0.3.35",
80532
- configDir: ".spur",
80533
- configFile: ".spur/config.yaml",
80534
- databaseFile: ".spur/spur.db"
80535
- };
81545
+ import { join as join21, resolve as resolve7 } from "path";
80536
81546
 
80537
81547
  // src/config/scaffold-manifest.ts
80538
81548
  var SCAFFOLD_MANIFEST = [
@@ -80579,8 +81589,8 @@ var SCAFFOLD_MANIFEST = [
80579
81589
  ];
80580
81590
 
80581
81591
  // src/commands/init.ts
80582
- var GLOBAL_CONFIG_DIR2 = join19(".config", "spur");
80583
- var GLOBAL_RULES_DIR2 = join19(GLOBAL_CONFIG_DIR2, "rules");
81592
+ var GLOBAL_CONFIG_DIR2 = join21(".config", "spur");
81593
+ var GLOBAL_RULES_DIR2 = join21(GLOBAL_CONFIG_DIR2, "rules");
80584
81594
  var GLOBAL_CONFIG_EXAMPLE = "config.example.yaml";
80585
81595
  var GLOBAL_CONFIG_FILE2 = "config.yaml";
80586
81596
  var INDEXED_CONTEXT_MARKER = "## Indexed context";
@@ -80611,7 +81621,7 @@ If \`.spur/context/\` is absent, proceed normally. Never block work on its absen
80611
81621
  `;
80612
81622
  function globalRulesRoot(context4) {
80613
81623
  const override = context4.env.SPUR_GLOBAL_RULES_DIR;
80614
- return override !== undefined && override.length > 0 ? resolve6(context4.cwd, override) : join19(homedir7(), GLOBAL_RULES_DIR2);
81624
+ return override !== undefined && override.length > 0 ? resolve7(context4.cwd, override) : join21(homedir7(), GLOBAL_RULES_DIR2);
80615
81625
  }
80616
81626
  async function writeIfNew(context4, path9, content, force, result) {
80617
81627
  if (!force && await context4.fs.exists(path9)) {
@@ -80628,11 +81638,11 @@ async function seedGlobalRules(context4) {
80628
81638
  const target = globalRulesRoot(context4);
80629
81639
  let written = 0;
80630
81640
  for (const relPath of await listBundledRuleFiles()) {
80631
- const destination = join19(target, relPath);
81641
+ const destination = join21(target, relPath);
80632
81642
  if (await context4.fs.exists(destination))
80633
81643
  continue;
80634
- await context4.fs.ensureDir(join19(target, ...relPath.split("/").slice(0, -1)));
80635
- await context4.fs.writeFile(destination, await context4.fs.readFile(join19(source, relPath)));
81644
+ await context4.fs.ensureDir(join21(target, ...relPath.split("/").slice(0, -1)));
81645
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join21(source, relPath)));
80636
81646
  written += 1;
80637
81647
  }
80638
81648
  return written;
@@ -80642,20 +81652,20 @@ async function seedGlobalConfig(context4) {
80642
81652
  if (source === null)
80643
81653
  return 0;
80644
81654
  const globalOverride = context4.env.SPUR_GLOBAL_RULES_DIR;
80645
- const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve6(context4.cwd, globalOverride) : join19(homedir7(), GLOBAL_CONFIG_DIR2);
81655
+ const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve7(context4.cwd, globalOverride) : join21(homedir7(), GLOBAL_CONFIG_DIR2);
80646
81656
  let written = 0;
80647
81657
  for (const relPath of listBundledConfigFiles()) {
80648
81658
  if (relPath === GLOBAL_CONFIG_EXAMPLE)
80649
81659
  continue;
80650
- const destination = join19(target, relPath);
81660
+ const destination = join21(target, relPath);
80651
81661
  if (await context4.fs.exists(destination))
80652
81662
  continue;
80653
- await context4.fs.ensureDir(join19(target, ...relPath.split("/").slice(0, -1)));
80654
- await context4.fs.writeFile(destination, await context4.fs.readFile(join19(source, relPath)));
81663
+ await context4.fs.ensureDir(join21(target, ...relPath.split("/").slice(0, -1)));
81664
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join21(source, relPath)));
80655
81665
  written += 1;
80656
81666
  }
80657
- const examplePath = join19(source, GLOBAL_CONFIG_EXAMPLE);
80658
- const globalConfigPath = join19(target, GLOBAL_CONFIG_FILE2);
81667
+ const examplePath = join21(source, GLOBAL_CONFIG_EXAMPLE);
81668
+ const globalConfigPath = join21(target, GLOBAL_CONFIG_FILE2);
80659
81669
  if (await context4.fs.exists(examplePath) && !await context4.fs.exists(globalConfigPath)) {
80660
81670
  await context4.fs.ensureDir(target);
80661
81671
  await context4.fs.writeFile(globalConfigPath, await context4.fs.readFile(examplePath));
@@ -80669,7 +81679,7 @@ function registerInitCommand(program2, context4) {
80669
81679
  const force = options.force === true;
80670
81680
  const minimal = options.minimal === true;
80671
81681
  const projectName = options.name ?? "default";
80672
- const configPath = join19(context4.cwd, CLI_CONFIG.configFile);
81682
+ const configPath = join21(context4.cwd, CLI_CONFIG.configFile);
80673
81683
  if (!force && await context4.fs.exists(configPath)) {
80674
81684
  const message = `Already initialized: ${CLI_CONFIG.configFile}. Use --force to overwrite.`;
80675
81685
  context4.output.write(json3 ? toJson2({ ok: false, reason: "already-initialized", config: CLI_CONFIG.configFile }) : message);
@@ -80704,13 +81714,13 @@ function registerInitCommand(program2, context4) {
80704
81714
  ].join(`
80705
81715
  `)}
80706
81716
  `;
80707
- await context4.fs.ensureDir(join19(context4.cwd, CLI_CONFIG.configDir));
81717
+ await context4.fs.ensureDir(join21(context4.cwd, CLI_CONFIG.configDir));
80708
81718
  await context4.fs.writeFile(configPath, configYaml);
80709
81719
  result.created.push(configPath);
80710
- const agentsDir = join19(context4.cwd, CLI_CONFIG.configDir, "agents");
81720
+ const agentsDir = join21(context4.cwd, CLI_CONFIG.configDir, "agents");
80711
81721
  await context4.fs.ensureDir(agentsDir);
80712
- await writeIfNew(context4, join19(agentsDir, ".gitkeep"), "", force, result);
80713
- const gitignorePath = join19(context4.cwd, ".gitignore");
81722
+ await writeIfNew(context4, join21(agentsDir, ".gitkeep"), "", force, result);
81723
+ const gitignorePath = join21(context4.cwd, ".gitignore");
80714
81724
  const contextEntry = ".spur/context/";
80715
81725
  if (await context4.fs.exists(gitignorePath)) {
80716
81726
  const existing = await context4.fs.readFile(gitignorePath);
@@ -80732,20 +81742,20 @@ ${contextEntry}
80732
81742
  for (const relPath of listBundledProjectSeedFiles()) {
80733
81743
  if (relPath.startsWith("templates/docs/"))
80734
81744
  continue;
80735
- const sourcePath = join19(configRoot, relPath);
81745
+ const sourcePath = join21(configRoot, relPath);
80736
81746
  if (!await context4.fs.exists(sourcePath))
80737
81747
  continue;
80738
- const targetPath = join19(context4.cwd, CLI_CONFIG.configDir, relPath);
80739
- await context4.fs.ensureDir(join19(targetPath, ".."));
81748
+ const targetPath = join21(context4.cwd, CLI_CONFIG.configDir, relPath);
81749
+ await context4.fs.ensureDir(join21(targetPath, ".."));
80740
81750
  await writeIfNew(context4, targetPath, await context4.fs.readFile(sourcePath), force, result);
80741
81751
  }
80742
81752
  for (const entry of SCAFFOLD_MANIFEST) {
80743
- const sourcePath = join19(configRoot, entry.source);
81753
+ const sourcePath = join21(configRoot, entry.source);
80744
81754
  if (!await context4.fs.exists(sourcePath))
80745
81755
  continue;
80746
- const baseDir = entry.root === true ? context4.cwd : join19(context4.cwd, CLI_CONFIG.configDir);
80747
- const targetPath = join19(baseDir, entry.target);
80748
- await context4.fs.ensureDir(join19(targetPath, ".."));
81756
+ const baseDir = entry.root === true ? context4.cwd : join21(context4.cwd, CLI_CONFIG.configDir);
81757
+ const targetPath = join21(baseDir, entry.target);
81758
+ await context4.fs.ensureDir(join21(targetPath, ".."));
80749
81759
  const entryForce = entry.preserve === true ? false : force;
80750
81760
  let body = await context4.fs.readFile(sourcePath);
80751
81761
  if (entry.target === "AGENTS.md") {
@@ -80758,7 +81768,7 @@ ${contextEntry}
80758
81768
  }
80759
81769
  }
80760
81770
  }
80761
- const agentsMdPath = join19(context4.cwd, "AGENTS.md");
81771
+ const agentsMdPath = join21(context4.cwd, "AGENTS.md");
80762
81772
  if (await context4.fs.exists(agentsMdPath)) {
80763
81773
  const existing = await context4.fs.readFile(agentsMdPath);
80764
81774
  if (!existing.includes(INDEXED_CONTEXT_MARKER)) {
@@ -80915,15 +81925,15 @@ async function runMessageWatch(svc, output2, options, runtime = {}) {
80915
81925
  }
80916
81926
  }
80917
81927
  function defaultSleep(ms, signal) {
80918
- return new Promise((resolve7) => {
81928
+ return new Promise((resolve8) => {
80919
81929
  if (signal?.aborted) {
80920
- resolve7();
81930
+ resolve8();
80921
81931
  return;
80922
81932
  }
80923
- const timer = setTimeout(resolve7, ms);
81933
+ const timer = setTimeout(resolve8, ms);
80924
81934
  signal?.addEventListener("abort", () => {
80925
81935
  clearTimeout(timer);
80926
- resolve7();
81936
+ resolve8();
80927
81937
  }, { once: true });
80928
81938
  });
80929
81939
  }
@@ -80936,10 +81946,10 @@ function parseInterval2(raw) {
80936
81946
 
80937
81947
  // src/commands/migrate.ts
80938
81948
  init_src2();
80939
- import { join as join20 } from "path";
81949
+ import { join as join22 } from "path";
80940
81950
  function registerMigrateCommand(program2, context4) {
80941
81951
  program2.command("migrate").summary("apply CLI-owned schema migrations").option("--json", "Output machine-readable JSON").action(async (options) => {
80942
- const migrations = await loadSqlMigrations(join20(context4.cwd, "drizzle")).catch(() => {
81952
+ const migrations = await loadSqlMigrations(join22(context4.cwd, "drizzle")).catch(() => {
80943
81953
  return;
80944
81954
  });
80945
81955
  const applied = await applyCliMigrations(await context4.getDb(), migrations);
@@ -80951,12 +81961,12 @@ function registerMigrateCommand(program2, context4) {
80951
81961
  // src/commands/projects.ts
80952
81962
  init_src3();
80953
81963
  init_dist5();
80954
- import { basename as basename4, resolve as resolve7 } from "path";
81964
+ import { basename as basename4, resolve as resolve8 } from "path";
80955
81965
  function registerProjectsCommand(program2, context4) {
80956
81966
  const projectsCmd = program2.command("projects").summary("manage the Spur multi-project registry");
80957
81967
  projectsCmd.command("add").argument("<path>", "Project root directory path").option("--name <name>", "Display name for the project").option("--json", "Output JSON response").action(async (pathArg, options) => {
80958
81968
  try {
80959
- const absolutePath = resolve7(context4.cwd, pathArg);
81969
+ const absolutePath = resolve8(context4.cwd, pathArg);
80960
81970
  if (!await context4.fs.exists(absolutePath)) {
80961
81971
  throw new Error(`Directory does not exist: ${absolutePath}`);
80962
81972
  }
@@ -81355,7 +82365,7 @@ function formatTraceDetail(detail) {
81355
82365
 
81356
82366
  // src/commands/serve.ts
81357
82367
  init_src();
81358
- import { join as join24 } from "path";
82368
+ import { join as join26 } from "path";
81359
82369
 
81360
82370
  // ../server/src/index.ts
81361
82371
  init_src();
@@ -81365,11 +82375,11 @@ init_src3();
81365
82375
  init_src();
81366
82376
  init_loader();
81367
82377
  init_src2();
81368
- import { basename as basename6, dirname as dirname15, isAbsolute as isAbsolute3, join as join23 } from "path";
82378
+ import { basename as basename6, dirname as dirname17, isAbsolute as isAbsolute4, join as join25 } from "path";
81369
82379
  init_dist5();
81370
82380
 
81371
82381
  // ../server/src/bootstrap.ts
81372
- import { join as join21 } from "path";
82382
+ import { join as join23 } from "path";
81373
82383
 
81374
82384
  // ../../node_modules/.bun/radash@12.1.1/node_modules/radash/dist/esm/async.mjs
81375
82385
  var guard = (func, shouldGuard) => {
@@ -81642,8 +82652,8 @@ class EventPublisher {
81642
82652
  if (bufferedEvents.length > 0) {
81643
82653
  return { done: false, value: bufferedEvents.shift() };
81644
82654
  }
81645
- return new Promise((resolve8, reject) => {
81646
- pullResolvers.push([resolve8, reject]);
82655
+ return new Promise((resolve9, reject) => {
82656
+ pullResolvers.push([resolve9, reject]);
81647
82657
  });
81648
82658
  }, async () => {
81649
82659
  unsubscribe();
@@ -90266,7 +91276,7 @@ function createApp(appRt, opts) {
90266
91276
  app.use("*", async (c3, next) => {
90267
91277
  const pathname = c3.req.path === "/" ? "/index.html" : c3.req.path;
90268
91278
  try {
90269
- const file2 = Bun.file(join21(webDistPath, pathname));
91279
+ const file2 = Bun.file(join23(webDistPath, pathname));
90270
91280
  if (await file2.exists()) {
90271
91281
  const headers = new Headers({ "content-type": file2.type });
90272
91282
  return new Response(file2.stream(), { headers });
@@ -90279,7 +91289,7 @@ function createApp(appRt, opts) {
90279
91289
  return c3.json({ error: "Not Found" }, 404);
90280
91290
  }
90281
91291
  try {
90282
- const indexFile = Bun.file(join21(webDistPath, "index.html"));
91292
+ const indexFile = Bun.file(join23(webDistPath, "index.html"));
90283
91293
  if (await indexFile.exists()) {
90284
91294
  return new Response(indexFile.stream(), {
90285
91295
  headers: { "content-type": "text/html; charset=utf-8" }
@@ -90300,7 +91310,7 @@ init_src3();
90300
91310
  init_src();
90301
91311
  init_src2();
90302
91312
  init_dist5();
90303
- import { dirname as dirname14, join as join22 } from "path";
91313
+ import { dirname as dirname16, join as join24 } from "path";
90304
91314
  var NOOP_OUTPUT = { write: (_s) => {}, error: (_s) => {} };
90305
91315
 
90306
91316
  class LazyPlanningEventEmitter {
@@ -90335,7 +91345,7 @@ class NotConfiguredError extends Error {
90335
91345
  function createServerContext(appRt, options) {
90336
91346
  const cwd = options.cwd;
90337
91347
  const fs3 = options.fs;
90338
- const dbUrl = options.dbUrl ?? join22(cwd, DEFAULT_DATABASE_URL);
91348
+ const dbUrl = options.dbUrl ?? join24(cwd, DEFAULT_DATABASE_URL);
90339
91349
  const eventsBus = options.eventsBus ?? appRt.events;
90340
91350
  const jobQueueEnabled = options.jobQueueEnabled ?? false;
90341
91351
  const folders = options.folders ?? DEFAULT_PLANNING_FOLDERS;
@@ -90370,7 +91380,7 @@ function createServerContext(appRt, options) {
90370
91380
  if (!dbPromise) {
90371
91381
  const created = (async () => {
90372
91382
  if (dbUrl !== IN_MEMORY_DATABASE_URL) {
90373
- await fs3.ensureDir(dirname14(dbUrl));
91383
+ await fs3.ensureDir(dirname16(dbUrl));
90374
91384
  }
90375
91385
  return createMigratedDbViaRuntime({ url: dbUrl });
90376
91386
  })();
@@ -90695,15 +91705,15 @@ async function handleFeatureActionJob(ctx, env, payload) {
90695
91705
  await runFeatureActionJob(ctx, env, payload);
90696
91706
  }
90697
91707
  async function resolveWebDistPath(configuredPath) {
90698
- const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join23(process.cwd(), configuredPath)] : [
90699
- join23(process.cwd(), "dist/web"),
90700
- join23(import.meta.dir, "web"),
90701
- join23(dirname15(process.execPath), "web"),
90702
- join23(dirname15(process.execPath), "../web"),
90703
- join23(import.meta.dir, "../../../dist/web")
91708
+ const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute4(configuredPath) ? configuredPath : join25(process.cwd(), configuredPath)] : [
91709
+ join25(process.cwd(), "dist/web"),
91710
+ join25(import.meta.dir, "web"),
91711
+ join25(dirname17(process.execPath), "web"),
91712
+ join25(dirname17(process.execPath), "../web"),
91713
+ join25(import.meta.dir, "../../../dist/web")
90704
91714
  ];
90705
91715
  for (const candidate of candidates) {
90706
- if (await Bun.file(join23(candidate, "index.html")).exists()) {
91716
+ if (await Bun.file(join25(candidate, "index.html")).exists()) {
90707
91717
  return candidate;
90708
91718
  }
90709
91719
  }
@@ -90719,7 +91729,7 @@ async function startServer(options, deps = defaultDeps) {
90719
91729
  async start(appRt) {
90720
91730
  const fs3 = deps.createNodeFileSystem(process.cwd());
90721
91731
  if (options.dbUrl && options.dbUrl !== IN_MEMORY_DATABASE_URL) {
90722
- await fs3.ensureDir(dirname15(options.dbUrl));
91732
+ await fs3.ensureDir(dirname17(options.dbUrl));
90723
91733
  }
90724
91734
  let scheduler3;
90725
91735
  if (bootConfig.scheduler.enabled) {
@@ -90862,7 +91872,7 @@ if (false) {}
90862
91872
 
90863
91873
  // src/commands/serve.ts
90864
91874
  function resolveServeDbUrl(cwd, env, configuredUrl) {
90865
- return env.DATABASE_URL === undefined ? join24(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
91875
+ return env.DATABASE_URL === undefined ? join26(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
90866
91876
  }
90867
91877
  function registerServeCommand(program2, context4) {
90868
91878
  program2.command("serve").summary("start the Spur web server (local fallback)").option("--port <n>", "Server port (env: PORT, default: 3000)", parseInt).option("--host <addr>", "Bind address (env: HOST, default: localhost)").option("--no-open", "Skip opening the browser").option("--cwd <path>", "Working directory", context4.cwd).option("--json", "Output { port, url, pid } and exit").action(async (options) => {
@@ -90901,7 +91911,7 @@ function registerServeCommand(program2, context4) {
90901
91911
  }
90902
91912
 
90903
91913
  // src/commands/status.ts
90904
- import { join as join25 } from "path";
91914
+ import { join as join27 } from "path";
90905
91915
 
90906
91916
  // src/errors.ts
90907
91917
  class CommandError extends Error {
@@ -90972,8 +91982,8 @@ function registerStatusCommand(program2, context4) {
90972
91982
  }
90973
91983
  async function runStatusCore(path9, options, context4) {
90974
91984
  const [packageJsonExists, spurConfigExists, git, agentSpecs] = await Promise.all([
90975
- context4.fs.exists(join25(context4.cwd, "package.json")),
90976
- context4.fs.exists(join25(context4.cwd, ".spur", "config.yaml")),
91985
+ context4.fs.exists(join27(context4.cwd, "package.json")),
91986
+ context4.fs.exists(join27(context4.cwd, ".spur", "config.yaml")),
90977
91987
  gitContext(context4.cwd),
90978
91988
  listAgentSpecIds(context4)
90979
91989
  ]);
@@ -91001,14 +92011,14 @@ async function runStatusCore(path9, options, context4) {
91001
92011
  return status.ok ? 0 : 1;
91002
92012
  }
91003
92013
  async function listAgentSpecIds(context4) {
91004
- const dir = join25(context4.cwd, ".spur", "agents");
92014
+ const dir = join27(context4.cwd, ".spur", "agents");
91005
92015
  if (!await context4.fs.exists(dir))
91006
92016
  return [];
91007
92017
  const entries = await context4.fs.readDir(dir);
91008
92018
  return entries.filter((entry) => entry.endsWith(".yaml") || entry.endsWith(".yml")).map((entry) => entry.replace(/\.ya?ml$/, "")).sort();
91009
92019
  }
91010
92020
  async function readTargetStatus(context4, targetPath) {
91011
- const resolved = join25(context4.cwd, targetPath);
92021
+ const resolved = join27(context4.cwd, targetPath);
91012
92022
  const stat = await context4.fs.stat(resolved);
91013
92023
  if (stat === null)
91014
92024
  throw new CommandError(`status failed: path does not exist at ${resolved}`);
@@ -91020,8 +92030,8 @@ init_src3();
91020
92030
  init_loader();
91021
92031
  init_src2();
91022
92032
  init_dist5();
91023
- import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
91024
- import { join as join26 } from "path";
92033
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
92034
+ import { join as join28 } from "path";
91025
92035
  // schemas/section-matrix.schema.json
91026
92036
  var section_matrix_schema_default = {
91027
92037
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -91760,7 +92770,7 @@ ${result.content}`);
91760
92770
  let forcedDoneVerdict;
91761
92771
  if (status === "done") {
91762
92772
  const current = await svc.show(wbs);
91763
- const verdictDir = options.verdictDir ?? join26(context4.cwd, ".spur", "run");
92773
+ const verdictDir = options.verdictDir ?? join28(context4.cwd, ".spur", "run");
91764
92774
  const loaded = await readVerdictArtifact(context4.fs, verdictDir, wbs);
91765
92775
  const guardOutcome = evaluateDoneTransition({
91766
92776
  wbs,
@@ -92321,17 +93331,17 @@ function loadTemplateContent(projectRoot, variant) {
92321
93331
  return templateContentCache.get(variant);
92322
93332
  if (templateMissSet.has(variant))
92323
93333
  return;
92324
- const localPath = join26(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
92325
- if (existsSync10(localPath)) {
92326
- const content = readFileSync9(localPath, "utf8");
93334
+ const localPath = join28(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
93335
+ if (existsSync11(localPath)) {
93336
+ const content = readFileSync10(localPath, "utf8");
92327
93337
  templateContentCache.set(variant, content);
92328
93338
  return content;
92329
93339
  }
92330
93340
  const root = bundledConfigRoot();
92331
93341
  if (root !== null) {
92332
- const templatePath = join26(root, "templates", "task", `${variant}.md`);
92333
- if (existsSync10(templatePath)) {
92334
- const content = readFileSync9(templatePath, "utf8");
93342
+ const templatePath = join28(root, "templates", "task", `${variant}.md`);
93343
+ if (existsSync11(templatePath)) {
93344
+ const content = readFileSync10(templatePath, "utf8");
92335
93345
  templateContentCache.set(variant, content);
92336
93346
  return content;
92337
93347
  }
@@ -92345,15 +93355,15 @@ function loadTemplateBodies(projectRoot, variant) {
92345
93355
  if (cached2 !== undefined)
92346
93356
  return cached2;
92347
93357
  let bodies = {};
92348
- const localPath = join26(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
92349
- if (existsSync10(localPath)) {
92350
- bodies = extractTemplateBodies(readFileSync9(localPath, "utf8"));
93358
+ const localPath = join28(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
93359
+ if (existsSync11(localPath)) {
93360
+ bodies = extractTemplateBodies(readFileSync10(localPath, "utf8"));
92351
93361
  } else {
92352
93362
  const root = bundledConfigRoot();
92353
93363
  if (root !== null) {
92354
- const templatePath = join26(root, "templates", "task", `${variant}.md`);
92355
- if (existsSync10(templatePath)) {
92356
- bodies = extractTemplateBodies(readFileSync9(templatePath, "utf8"));
93364
+ const templatePath = join28(root, "templates", "task", `${variant}.md`);
93365
+ if (existsSync11(templatePath)) {
93366
+ bodies = extractTemplateBodies(readFileSync10(templatePath, "utf8"));
92357
93367
  }
92358
93368
  }
92359
93369
  }
@@ -92404,7 +93414,7 @@ async function loadSectionMatrixUncached(projectRoot) {
92404
93414
  }
92405
93415
  const root = bundledConfigRoot();
92406
93416
  if (root !== null) {
92407
- const matrixPath = join26(root, "tasks", "section-matrix.yaml");
93417
+ const matrixPath = join28(root, "tasks", "section-matrix.yaml");
92408
93418
  if (await fs3.exists(matrixPath)) {
92409
93419
  const data = await loadStructuredSpurConfig(matrixPath, {
92410
93420
  validateJsonSchema: true,
@@ -92689,7 +93699,7 @@ init_dist7();
92689
93699
  init_dist6();
92690
93700
  init_dist5();
92691
93701
  import { closeSync as closeSync5, fstatSync as fstatSync3, openSync as openSync5, readSync as readSync3 } from "fs";
92692
- import { join as join27, resolve as resolve8 } from "path";
93702
+ import { join as join29, resolve as resolve9 } from "path";
92693
93703
  import { createInterface } from "readline";
92694
93704
  import { setTimeout as sleep3 } from "timers/promises";
92695
93705
  function shQuote2(value2) {
@@ -92857,13 +93867,13 @@ Monitor with: spur workflow trace ${runId2} --follow`);
92857
93867
  let planPreview;
92858
93868
  if (options.plan !== false) {
92859
93869
  try {
92860
- const def = await loadWorkflowDef(resolve8(context4.cwd, file2), { validateSchema: false });
93870
+ const def = await loadWorkflowDef(resolve9(context4.cwd, file2), { validateSchema: false });
92861
93871
  planPreview = renderRunPlan(def);
92862
93872
  } catch {}
92863
93873
  }
92864
93874
  const runLog = options.log === false ? undefined : new WorkflowRunLogSink({
92865
93875
  bus,
92866
- dir: join27(context4.cwd, ".spur", "run"),
93876
+ dir: join29(context4.cwd, ".spur", "run"),
92867
93877
  runId,
92868
93878
  ...planPreview !== undefined ? { planPreview } : {},
92869
93879
  ...await resolveOutputLogConfig(context4.cwd)
@@ -93274,7 +94284,7 @@ function readRunLogChunk(logPath, offset) {
93274
94284
  }
93275
94285
  }
93276
94286
  async function followRunLog(service, runId, dir, pollMs, write, wait = (ms) => sleep3(ms)) {
93277
- const logPath = join27(dir, ".spur", "run", `${runId}.log`);
94287
+ const logPath = join29(dir, ".spur", "run", `${runId}.log`);
93278
94288
  let offset = 0;
93279
94289
  let everRead = false;
93280
94290
  while (true) {
@@ -93321,7 +94331,7 @@ init_src3();
93321
94331
  init_src();
93322
94332
  init_src2();
93323
94333
  init_dist5();
93324
- import { dirname as dirname16, join as join28, resolve as resolve9 } from "path";
94334
+ import { dirname as dirname18, join as join30, resolve as resolve10 } from "path";
93325
94335
  import { isatty as isatty4 } from "tty";
93326
94336
 
93327
94337
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -94704,7 +95714,7 @@ class DefaultHitlResponder {
94704
95714
 
94705
95715
  // src/context.ts
94706
95716
  function createCliContext(options) {
94707
- const cwd = resolve9(options.cwd ?? process.cwd());
95717
+ const cwd = resolve10(options.cwd ?? process.cwd());
94708
95718
  const env = options.env ?? process.env;
94709
95719
  const fs3 = createNodeFileSystem3(cwd);
94710
95720
  let dbPromise;
@@ -94743,10 +95753,10 @@ function createCliContext(options) {
94743
95753
  function noopSetExitCode(_code) {}
94744
95754
  async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, dbUrl) {
94745
95755
  const config4 = buildConfigFromEnv(env);
94746
- const configuredUrl = env.DATABASE_URL === undefined ? join28(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
95756
+ const configuredUrl = env.DATABASE_URL === undefined ? join30(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
94747
95757
  const url2 = dbUrl ?? configuredUrl;
94748
95758
  if (url2 !== IN_MEMORY_DATABASE_URL) {
94749
- await createNodeFileSystem3().ensureDir(dirname16(url2));
95759
+ await createNodeFileSystem3().ensureDir(dirname18(url2));
94750
95760
  }
94751
95761
  return createMigratedDb({ url: url2 });
94752
95762
  }