@gobing-ai/spur 0.3.48 → 0.3.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/config.example.yaml +52 -4
  3. package/config/workflows/pr-review.yaml +338 -0
  4. package/package.json +8 -8
  5. package/plugins/sp/README.md +9 -6
  6. package/plugins/sp/commands/{dev-featurechange.md → dev-feature-change.md} +7 -10
  7. package/plugins/sp/commands/dev-find-issue.md +24 -19
  8. package/plugins/sp/commands/dev-find-next.md +3 -3
  9. package/plugins/sp/commands/dev-gtd.md +11 -12
  10. package/plugins/sp/commands/dev-history-load.md +63 -0
  11. package/plugins/sp/commands/dev-pr-review.md +39 -0
  12. package/plugins/sp/plugin.json +1 -1
  13. package/plugins/sp/references/roles.md +25 -12
  14. package/plugins/sp/scripts/history-load.ts +400 -0
  15. package/plugins/sp/scripts/pr-reviewing.ts +867 -0
  16. package/plugins/sp/scripts/validate-commands.ts +33 -2
  17. package/plugins/sp/skills/code-implementation/SKILL.md +9 -1
  18. package/plugins/sp/skills/code-verification/SKILL.md +27 -28
  19. package/plugins/sp/skills/issue-finding/SKILL.md +6 -5
  20. package/plugins/sp/skills/issue-finding/references/session-formats.md +4 -2
  21. package/plugins/sp/skills/next-feature/SKILL.md +6 -6
  22. package/plugins/sp/skills/next-feature/references/handoff-routing.md +5 -5
  23. package/plugins/sp/skills/next-feature/references/signal-derivation.md +7 -2
  24. package/plugins/sp/skills/pr-reviewing/SKILL.md +285 -0
  25. package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +5 -5
  26. package/plugins/sp/skills/spur-cli/references/features.md +1 -1
  27. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +14 -4
  28. package/schemas/spur-config.schema.json +20 -0
  29. package/spur.js +682 -222
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.32/node_modules/@gobing-ai/ts-utils/dist/errors.js
50
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.35/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.32/node_modules/@gobing-ai/ts-utils/dist/api-response.js
61
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.35/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,13 +81,13 @@ 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.32/node_modules/@gobing-ai/ts-utils/dist/cursor.js
84
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.35/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.32/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
87
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.35/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
88
88
  var init_event_severity = () => {};
89
89
 
90
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.32/node_modules/@gobing-ai/ts-utils/dist/object.js
90
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.35/node_modules/@gobing-ai/ts-utils/dist/object.js
91
91
  function isPlainObject(value) {
92
92
  return typeof value === "object" && value !== null && !Array.isArray(value);
93
93
  }
@@ -105,7 +105,7 @@ function deepMerge(target, source) {
105
105
  return result;
106
106
  }
107
107
 
108
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.32/node_modules/@gobing-ai/ts-utils/dist/output.js
108
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.35/node_modules/@gobing-ai/ts-utils/dist/output.js
109
109
  function processStream(name) {
110
110
  const proc = globalThis.process;
111
111
  const stream = proc?.[name];
@@ -126,7 +126,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
126
126
  }
127
127
  var defaultStdoutTarget, defaultStderrTarget;
128
128
 
129
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.32/node_modules/@gobing-ai/ts-utils/dist/index.js
129
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.35/node_modules/@gobing-ai/ts-utils/dist/index.js
130
130
  var init_dist = __esm(() => {
131
131
  init_api_response();
132
132
  init_cursor();
@@ -21749,7 +21749,7 @@ var init_zod = __esm(() => {
21749
21749
  init_external();
21750
21750
  });
21751
21751
 
21752
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/config.js
21752
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/config.js
21753
21753
  function getProcessEnv() {
21754
21754
  return process.env;
21755
21755
  }
@@ -21827,7 +21827,7 @@ var init_config = __esm(() => {
21827
21827
  };
21828
21828
  });
21829
21829
 
21830
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21830
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21831
21831
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
21832
21832
  import { dirname, resolve as resolvePath } from "path";
21833
21833
  function createNodeFileSystem(root, paths) {
@@ -21914,7 +21914,7 @@ function findProjectRoot(startDir) {
21914
21914
  }
21915
21915
  var init_file_system_node = () => {};
21916
21916
 
21917
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21917
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
21918
21918
  var DbModuleNotInstalledError;
21919
21919
  var init_db_errors = __esm(() => {
21920
21920
  DbModuleNotInstalledError = class DbModuleNotInstalledError extends Error {
@@ -29125,7 +29125,7 @@ var init_execa = __esm(() => {
29125
29125
  } = getIpcExport());
29126
29126
  });
29127
29127
 
29128
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29128
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
29129
29129
  import { isatty } from "tty";
29130
29130
  function processEventSeverity(reason, exitCode) {
29131
29131
  if (reason === "error")
@@ -29489,7 +29489,7 @@ var init_process_executor = __esm(() => {
29489
29489
  init_config();
29490
29490
  });
29491
29491
 
29492
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29492
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
29493
29493
  function getNodeFileSystem() {
29494
29494
  if (!_nodeFileSystem)
29495
29495
  _nodeFileSystem = createNodeFileSystem();
@@ -29549,7 +29549,7 @@ var init_runtime_node_bun = __esm(() => {
29549
29549
  };
29550
29550
  });
29551
29551
 
29552
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/context.js
29552
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/context.js
29553
29553
  class RuntimeContext {
29554
29554
  scope;
29555
29555
  runtimeName;
@@ -29619,7 +29619,7 @@ var init_context = __esm(() => {
29619
29619
  init_runtime_node_bun();
29620
29620
  });
29621
29621
 
29622
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/path.js
29622
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/path.js
29623
29623
  function normalizeSeparators(path6) {
29624
29624
  return path6.replaceAll("\\", "/");
29625
29625
  }
@@ -29680,17 +29680,17 @@ var init_path = __esm(() => {
29680
29680
  SEP = globalThis.process?.platform === "win32" ? "\\" : "/";
29681
29681
  });
29682
29682
 
29683
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29683
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
29684
29684
  var REMOTE_SCHEMA_MAX_BYTES;
29685
29685
  var init_schema_validation = __esm(() => {
29686
29686
  init_dist2();
29687
29687
  REMOTE_SCHEMA_MAX_BYTES = 5 * 1024 * 1024;
29688
29688
  });
29689
29689
 
29690
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/types.js
29690
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/types.js
29691
29691
  var init_types = () => {};
29692
29692
 
29693
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/index.js
29693
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/index.js
29694
29694
  var init_dist3 = __esm(() => {
29695
29695
  init_config();
29696
29696
  init_context();
@@ -29699,7 +29699,7 @@ var init_dist3 = __esm(() => {
29699
29699
  init_types();
29700
29700
  });
29701
29701
 
29702
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+43ec0d6f69eec3df/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29702
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+abdd01d08e213ddb/node_modules/@gobing-ai/ts-runtime/dist/bun-sqlite.js
29703
29703
  import { Database } from "bun:sqlite";
29704
29704
  var init_bun_sqlite = () => {};
29705
29705
 
@@ -33891,7 +33891,7 @@ var init_bun_sqlite2 = __esm(() => {
33891
33891
  init_session2();
33892
33892
  });
33893
33893
 
33894
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33894
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/inbox-messages.js
33895
33895
  var inboxMessages;
33896
33896
  var init_inbox_messages = __esm(() => {
33897
33897
  init_sqlite_core();
@@ -33910,7 +33910,7 @@ var init_inbox_messages = __esm(() => {
33910
33910
  }, (table2) => [index("idx_inbox_messages_to_status").on(table2.toId, table2.status)]);
33911
33911
  });
33912
33912
 
33913
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33913
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/common.js
33914
33914
  function nowTimestamp() {
33915
33915
  return Date.now();
33916
33916
  }
@@ -33939,7 +33939,7 @@ var init_common3 = __esm(() => {
33939
33939
  appendOnlyColumns = buildAppendOnlyColumns();
33940
33940
  });
33941
33941
 
33942
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33942
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/queue-jobs.js
33943
33943
  var queueJobs;
33944
33944
  var init_queue_jobs = __esm(() => {
33945
33945
  init_sqlite_core();
@@ -33959,7 +33959,7 @@ var init_queue_jobs = __esm(() => {
33959
33959
  }, (table2) => [index("queue_jobs_ready_idx").on(table2.status, table2.nextRetryAt, table2.createdAt)]);
33960
33960
  });
33961
33961
 
33962
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33962
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/runtime.js
33963
33963
  var exports_runtime = {};
33964
33964
  __export(exports_runtime, {
33965
33965
  queueJobs: () => queueJobs,
@@ -33970,7 +33970,7 @@ var init_runtime = __esm(() => {
33970
33970
  init_queue_jobs();
33971
33971
  });
33972
33972
 
33973
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33973
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/adapters/bun-sqlite.js
33974
33974
  var exports_bun_sqlite = {};
33975
33975
  __export(exports_bun_sqlite, {
33976
33976
  BunSqliteAdapter: () => BunSqliteAdapter
@@ -34261,7 +34261,7 @@ var init_d1 = __esm(() => {
34261
34261
  init_session3();
34262
34262
  });
34263
34263
 
34264
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34264
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/adapters/d1.js
34265
34265
  var exports_d1 = {};
34266
34266
  __export(exports_d1, {
34267
34267
  D1Adapter: () => D1Adapter
@@ -34325,7 +34325,7 @@ var init_d12 = __esm(() => {
34325
34325
  init_runtime();
34326
34326
  });
34327
34327
 
34328
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/adapter.js
34328
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/adapter.js
34329
34329
  async function createDbAdapter(config3) {
34330
34330
  switch (config3.driver) {
34331
34331
  case "bun-sqlite": {
@@ -34365,7 +34365,7 @@ var init_drizzle_orm = __esm(() => {
34365
34365
  init_view_common();
34366
34366
  });
34367
34367
 
34368
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34368
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/query-spec.js
34369
34369
  function compilePredicate(predicate) {
34370
34370
  if ("and" in predicate) {
34371
34371
  const parts = predicate.and.map(compilePredicate).filter((p) => p !== undefined);
@@ -34403,7 +34403,7 @@ var init_query_spec = __esm(() => {
34403
34403
  };
34404
34404
  });
34405
34405
 
34406
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34406
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/base-dao.js
34407
34407
  function asSelectQuery(query) {
34408
34408
  return query;
34409
34409
  }
@@ -34445,7 +34445,7 @@ var init_base_dao = __esm(() => {
34445
34445
  init_query_spec();
34446
34446
  });
34447
34447
 
34448
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34448
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/embedded-migrations.js
34449
34449
  var embeddedMigrations;
34450
34450
  var init_embedded_migrations = __esm(() => {
34451
34451
  embeddedMigrations = [
@@ -34477,7 +34477,7 @@ var init_embedded_migrations = __esm(() => {
34477
34477
  ];
34478
34478
  });
34479
34479
 
34480
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34480
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/entity-dao.js
34481
34481
  var EntityDao;
34482
34482
  var init_entity_dao = __esm(() => {
34483
34483
  init_drizzle_orm();
@@ -34639,7 +34639,7 @@ var init_entity_dao = __esm(() => {
34639
34639
  };
34640
34640
  });
34641
34641
 
34642
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34642
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/inbox-message-dao.js
34643
34643
  function isPromiseLike(value) {
34644
34644
  return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
34645
34645
  }
@@ -34817,7 +34817,7 @@ var init_migrator2 = __esm(() => {
34817
34817
  init_migrator();
34818
34818
  });
34819
34819
 
34820
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/migrate.js
34820
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/migrate.js
34821
34821
  async function ensureJournalTable(adapter, table3) {
34822
34822
  await adapter.exec(`CREATE TABLE IF NOT EXISTS "${table3}" (` + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "hash text NOT NULL, " + "created_at numeric" + ")");
34823
34823
  }
@@ -34892,7 +34892,7 @@ var init_migrate = __esm(() => {
34892
34892
  init_embedded_migrations();
34893
34893
  });
34894
34894
 
34895
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34895
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/queue-job-dao.js
34896
34896
  var QueueJobDao;
34897
34897
  var init_queue_job_dao = __esm(() => {
34898
34898
  init_drizzle_orm();
@@ -35033,7 +35033,7 @@ var init_queue_job_dao = __esm(() => {
35033
35033
  };
35034
35034
  });
35035
35035
 
35036
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/index.js
35036
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/index.js
35037
35037
  var exports_dist = {};
35038
35038
  __export(exports_dist, {
35039
35039
  embeddedMigrations: () => embeddedMigrations,
@@ -37358,7 +37358,7 @@ function buildConfigFromEnv(env = process.env) {
37358
37358
  }
37359
37359
  });
37360
37360
  }
37361
- var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, EXECUTOR_CAPABILITY_TIERS, executorCapabilityTierSchema, AGENT_ROLE_NAMES, AgentExecutorConfigSchema, AGENT_ID_REGEX, TeamMemberConfigSchema, TeamConfigSchema, AgentOutputConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, WorkflowConfigSchema, RedactionConfigSchema, HistoryRefreshConfigSchema, HistoryConfigSchema, spurConfigSchema, configSchema2;
37361
+ var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, EXECUTOR_CAPABILITY_TIERS, executorCapabilityTierSchema, AGENT_ROLE_NAMES, DEFAULT_AGENT_ROLES, AgentExecutorConfigSchema, AgentRoleConfigSchema, AGENT_ID_REGEX, TeamMemberConfigSchema, TeamConfigSchema, AgentOutputConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, WorkflowConfigSchema, RedactionConfigSchema, HistoryRefreshConfigSchema, HistoryConfigSchema, spurConfigSchema, configSchema2;
37362
37362
  var init_src = __esm(() => {
37363
37363
  init_zod();
37364
37364
  init_finding_codes();
@@ -37402,12 +37402,22 @@ var init_src = __esm(() => {
37402
37402
  return normalizeExecutorTier(value);
37403
37403
  }, exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional());
37404
37404
  AGENT_ROLE_NAMES = ["scribe", "coder", "reviewer", "planner"];
37405
+ DEFAULT_AGENT_ROLES = new Map([
37406
+ ["scribe", { tier: "cheap", stages: ["changelog"] }],
37407
+ ["coder", { tier: "standard", stages: ["implement", "test", "wrap"] }],
37408
+ ["reviewer", { tier: "capable-1", stages: ["verify", "review", "dogfood"] }],
37409
+ ["planner", { tier: "capable-2", stages: ["plan", "refine", "brainstorm"] }]
37410
+ ]);
37405
37411
  AgentExecutorConfigSchema = exports_external.object({
37406
37412
  name: exports_external.string().min(1),
37407
37413
  agent: exports_external.string().min(1),
37408
37414
  model: exports_external.string().min(1).optional(),
37409
37415
  tier: executorCapabilityTierSchema.optional()
37410
37416
  });
37417
+ AgentRoleConfigSchema = exports_external.object({
37418
+ tier: exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional(),
37419
+ stages: exports_external.array(exports_external.string().min(1)).min(1).optional()
37420
+ });
37411
37421
  AGENT_ID_REGEX = /^[a-z][a-z0-9_-]{1,63}$/;
37412
37422
  TeamMemberConfigSchema = exports_external.union([
37413
37423
  exports_external.string().min(1),
@@ -37439,10 +37449,20 @@ var init_src = __esm(() => {
37439
37449
  AgentConfigSchema = exports_external.object({
37440
37450
  default: exports_external.string().optional(),
37441
37451
  executors: exports_external.array(AgentExecutorConfigSchema).optional(),
37452
+ roles: exports_external.record(exports_external.string(), AgentRoleConfigSchema).optional(),
37442
37453
  team: exports_external.record(exports_external.string(), TeamConfigSchema).optional(),
37443
37454
  output: AgentOutputConfigSchema.optional(),
37444
37455
  sessionAffinity: exports_external.boolean().optional()
37445
37456
  }).superRefine((value, ctx) => {
37457
+ for (const key of Object.keys(value.roles ?? {})) {
37458
+ if (!AGENT_ROLE_NAMES.includes(key)) {
37459
+ ctx.addIssue({
37460
+ code: exports_external.ZodIssueCode.custom,
37461
+ path: ["roles", key],
37462
+ message: `Unknown role "${key}" \u2014 expected one of: ${AGENT_ROLE_NAMES.join(", ")}`
37463
+ });
37464
+ }
37465
+ }
37446
37466
  const executors = value.executors;
37447
37467
  const executorNames = new Set;
37448
37468
  if (executors !== undefined) {
@@ -37596,7 +37616,7 @@ var init_src = __esm(() => {
37596
37616
  });
37597
37617
  });
37598
37618
 
37599
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/config.js
37619
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/config.js
37600
37620
  function parseYamlObject(text3) {
37601
37621
  let parsed;
37602
37622
  try {
@@ -37723,7 +37743,7 @@ var init_config2 = __esm(() => {
37723
37743
  };
37724
37744
  });
37725
37745
 
37726
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37746
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
37727
37747
  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";
37728
37748
  import { dirname as dirname2, resolve as resolvePath3 } from "path";
37729
37749
  function createNodeFileSystem3(root, paths) {
@@ -37810,7 +37830,7 @@ function findProjectRoot3(startDir) {
37810
37830
  }
37811
37831
  var init_file_system_node2 = () => {};
37812
37832
 
37813
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37833
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
37814
37834
  var D1NotConfiguredError2, DbModuleNotInstalledError3;
37815
37835
  var init_db_errors2 = __esm(() => {
37816
37836
  D1NotConfiguredError2 = class D1NotConfiguredError2 extends Error {
@@ -37827,7 +37847,7 @@ var init_db_errors2 = __esm(() => {
37827
37847
  };
37828
37848
  });
37829
37849
 
37830
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37850
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/file-system-cf.js
37831
37851
  function createCfFileSystem2() {
37832
37852
  return {
37833
37853
  getProjectRoot: () => "/bundle",
@@ -37866,7 +37886,7 @@ function createCfFileSystem2() {
37866
37886
  }
37867
37887
  var UNSUPPORTED = "FileSystem is not available on Cloudflare Workers. Use D1, KV, or R2 for persistent storage.";
37868
37888
 
37869
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37889
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/runtime-cf.js
37870
37890
  var exports_runtime_cf = {};
37871
37891
  __export(exports_runtime_cf, {
37872
37892
  cloudflareWorkersFactory: () => cloudflareWorkersFactory2
@@ -37904,7 +37924,7 @@ var init_runtime_cf = __esm(() => {
37904
37924
  };
37905
37925
  });
37906
37926
 
37907
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37927
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
37908
37928
  import { isatty as isatty2 } from "tty";
37909
37929
  function processEventSeverity2(reason, exitCode) {
37910
37930
  if (reason === "error")
@@ -38315,7 +38335,7 @@ var init_process_executor2 = __esm(() => {
38315
38335
  ProcessExecutor2 = NodeProcessExecutor3;
38316
38336
  });
38317
38337
 
38318
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38338
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
38319
38339
  var exports_runtime_node_bun = {};
38320
38340
  __export(exports_runtime_node_bun, {
38321
38341
  nodeBunFactory: () => nodeBunFactory3,
@@ -38383,7 +38403,7 @@ var init_runtime_node_bun2 = __esm(() => {
38383
38403
  };
38384
38404
  });
38385
38405
 
38386
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38406
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/platform.js
38387
38407
  function isCloudflareWorkerRuntime2() {
38388
38408
  return globalThis.navigator?.userAgent?.startsWith("Cloudflare-Workers") ?? false;
38389
38409
  }
@@ -38413,7 +38433,7 @@ function _resetRuntimeFactory2() {
38413
38433
  }
38414
38434
  var _factory, _runtimeName;
38415
38435
 
38416
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/context.js
38436
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/context.js
38417
38437
  class RuntimeContext2 {
38418
38438
  scope;
38419
38439
  runtimeName;
@@ -38503,7 +38523,7 @@ var init_context2 = __esm(() => {
38503
38523
  init_runtime_node_bun2();
38504
38524
  });
38505
38525
 
38506
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/path.js
38526
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/path.js
38507
38527
  function normalizeSeparators2(path7) {
38508
38528
  return path7.replaceAll("\\", "/");
38509
38529
  }
@@ -38626,7 +38646,7 @@ var init_path2 = __esm(() => {
38626
38646
  SEP2 = globalThis.process?.platform === "win32" ? "\\" : "/";
38627
38647
  });
38628
38648
 
38629
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38649
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/fs.js
38630
38650
  async function ensureDirForFile2(path7, fs2 = createNodeFileSystem3()) {
38631
38651
  await fs2.ensureDir(dirnamePath(path7));
38632
38652
  }
@@ -38694,7 +38714,7 @@ var init_fs = __esm(() => {
38694
38714
  init_path2();
38695
38715
  });
38696
38716
 
38697
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38717
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/process-registry.js
38698
38718
  function allocateId() {
38699
38719
  nextIdSeq += 1;
38700
38720
  return `pe_${Date.now().toString(36)}_${nextIdSeq.toString(36)}`;
@@ -38818,7 +38838,7 @@ function createInMemoryProcessRegistry2(options) {
38818
38838
  }
38819
38839
  var nextIdSeq = 0;
38820
38840
 
38821
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/runtime-paths.js
38841
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/runtime-paths.js
38822
38842
  function ambientRuntimePaths2() {
38823
38843
  const cwd = getProcessCwd2();
38824
38844
  return { cwd, home: getHomeDir() ?? cwd };
@@ -38828,7 +38848,7 @@ var init_runtime_paths = __esm(() => {
38828
38848
  init_path2();
38829
38849
  });
38830
38850
 
38831
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38851
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/schema-validation.js
38832
38852
  async function loadStructuredConfig(path7, options = {}) {
38833
38853
  const content = await (options.fileSystem ?? createNodeFileSystem3()).readFile(path7);
38834
38854
  return await parseStructuredConfig(content, path7, options);
@@ -39111,10 +39131,10 @@ var init_schema_validation2 = __esm(() => {
39111
39131
  defaultResolve = typeof Bun !== "undefined" ? (specifier, from) => Bun.resolveSync(specifier, from) : undefined;
39112
39132
  });
39113
39133
 
39114
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/types.js
39134
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/types.js
39115
39135
  var init_types2 = () => {};
39116
39136
 
39117
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/index.js
39137
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/index.js
39118
39138
  var exports_dist2 = {};
39119
39139
  __export(exports_dist2, {
39120
39140
  writeJsonFile: () => writeJsonFile2,
@@ -41265,7 +41285,7 @@ var init_mod = __esm(() => {
41265
41285
  init_config3();
41266
41286
  });
41267
41287
 
41268
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/logger.js
41288
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/logger.js
41269
41289
  function toLogTapeLevel(level) {
41270
41290
  return level === "warn" ? "warning" : level;
41271
41291
  }
@@ -42818,7 +42838,7 @@ var require_src = __commonJS((exports) => {
42818
42838
  };
42819
42839
  });
42820
42840
 
42821
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42841
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/telemetry/sdk.js
42822
42842
  function getTelemetryConfig(configPartial = {}) {
42823
42843
  return {
42824
42844
  enabled: configPartial.enabled ?? CONFIG_DEFAULTS.enabled,
@@ -42854,7 +42874,7 @@ var init_sdk = __esm(() => {
42854
42874
  resolvedConfig = getTelemetryConfig();
42855
42875
  });
42856
42876
 
42857
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42877
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
42858
42878
  function isSuppressed(tracer2) {
42859
42879
  return tracer2 === undefined && !getResolvedConfig().enabled;
42860
42880
  }
@@ -42894,7 +42914,7 @@ var init_tracing2 = __esm(() => {
42894
42914
  import_api2 = __toESM(require_src(), 1);
42895
42915
  });
42896
42916
 
42897
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42917
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
42898
42918
  function getMeter() {
42899
42919
  return import_api3.metrics.getMeter(METER_NAME, METER_VERSION);
42900
42920
  }
@@ -42991,7 +43011,7 @@ var init_metrics = __esm(() => {
42991
43011
  instruments = {};
42992
43012
  });
42993
43013
 
42994
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
43014
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/event-bus/event-bus.js
42995
43015
  function busLogger() {
42996
43016
  if (!_busLogger)
42997
43017
  _busLogger = getLogger2("event-bus");
@@ -43244,7 +43264,7 @@ var init_event_bus = __esm(() => {
43244
43264
  init_metrics();
43245
43265
  });
43246
43266
 
43247
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
43267
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/event-bus/default-observers.js
43248
43268
  function obsLogger() {
43249
43269
  if (!_obsLogger)
43250
43270
  _obsLogger = getLogger2("event-bus.observers");
@@ -43308,7 +43328,7 @@ var init_default_observers = __esm(() => {
43308
43328
  init_event_bus();
43309
43329
  });
43310
43330
 
43311
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
43331
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/event-bus/file-observer.js
43312
43332
  function parentDir(filePath) {
43313
43333
  const idx = filePath.lastIndexOf("/");
43314
43334
  return idx <= 0 ? "." : filePath.slice(0, idx);
@@ -43406,7 +43426,7 @@ var init_file_observer = __esm(() => {
43406
43426
  init_logger3();
43407
43427
  });
43408
43428
 
43409
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/internals/drain.js
43429
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/internals/drain.js
43410
43430
  function settleWithin(promise2, deadline) {
43411
43431
  const remaining = deadline - Date.now();
43412
43432
  if (remaining <= 0)
@@ -43421,7 +43441,7 @@ function settleWithin(promise2, deadline) {
43421
43441
  return settled;
43422
43442
  }
43423
43443
 
43424
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43444
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/scheduler/node.js
43425
43445
  function parseInterval(cron) {
43426
43446
  const trimmed = cron.trim();
43427
43447
  const num = Number(trimmed);
@@ -43515,7 +43535,7 @@ var init_node3 = __esm(() => {
43515
43535
  init_metrics();
43516
43536
  });
43517
43537
 
43518
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43538
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/scheduler-node.js
43519
43539
  var exports_scheduler_node = {};
43520
43540
  __export(exports_scheduler_node, {
43521
43541
  NodeSchedulerAdapter: () => NodeSchedulerAdapter
@@ -50356,6 +50376,209 @@ var init_narrow_artifact = __esm(() => {
50356
50376
  };
50357
50377
  });
50358
50378
 
50379
+ // ../../packages/domain/src/analytics/pairings.ts
50380
+ async function pairingSummary(db2, spec = {}) {
50381
+ const [dispatchRows, escRows, foldRows] = await Promise.all([
50382
+ loadDispatchStats(db2, spec),
50383
+ loadEscalations(db2, spec),
50384
+ loadFolds(db2, spec)
50385
+ ]);
50386
+ const rawByKey = new Map;
50387
+ for (const d of dispatchRows) {
50388
+ const key = pairingKey(d.executor, d.role);
50389
+ const existing = rawByKey.get(key);
50390
+ if (existing === undefined) {
50391
+ rawByKey.set(key, { ...d });
50392
+ } else {
50393
+ existing.dispatches += d.dispatches;
50394
+ existing.successes += d.successes;
50395
+ existing.durationTotal += d.durationTotal;
50396
+ existing.durationCount += d.durationCount;
50397
+ }
50398
+ }
50399
+ const byKey = new Map;
50400
+ for (const [key, d] of rawByKey) {
50401
+ byKey.set(key, {
50402
+ executor: d.executor,
50403
+ role: d.role,
50404
+ agent: d.agent,
50405
+ model: d.model,
50406
+ dispatches: d.dispatches,
50407
+ successRate: d.dispatches > 0 ? d.successes / d.dispatches : 0,
50408
+ escalations: {},
50409
+ totalCostUsd: 0,
50410
+ meanDurationMs: d.durationCount > 0 ? d.durationTotal / d.durationCount : 0
50411
+ });
50412
+ }
50413
+ for (const e of escRows) {
50414
+ const entry = byKey.get(pairingKey(e.executor, e.role));
50415
+ if (entry === undefined)
50416
+ continue;
50417
+ entry.escalations[e.trigger] = (entry.escalations[e.trigger] ?? 0) + e.count;
50418
+ }
50419
+ for (const f of foldRows) {
50420
+ const entry = byKey.get(pairingKey(f.executor, f.role));
50421
+ if (entry === undefined)
50422
+ continue;
50423
+ entry.totalCostUsd += f.totalCostUsd;
50424
+ }
50425
+ return [...byKey.values()].sort((a2, b) => a2.executor.localeCompare(b.executor) || a2.role.localeCompare(b.role));
50426
+ }
50427
+ function pairingKey(executor, role) {
50428
+ return `${executor}\x00${role}`;
50429
+ }
50430
+ async function loadDispatchStats(db2, spec) {
50431
+ try {
50432
+ const { where, params } = eventWindow(spec);
50433
+ return await db2.queryAll(`WITH dispatch AS (
50434
+ SELECT id, run_id, occurred_at,
50435
+ json_extract(payload_json, '$.data.executionId') AS execution_id,
50436
+ json_extract(payload_json, '$.data.agent') AS agent,
50437
+ json_extract(payload_json, '$.data.model') AS model,
50438
+ json_extract(payload_json, '$.data.routing.executor') AS executor,
50439
+ json_extract(payload_json, '$.data.routing.role') AS role
50440
+ FROM system_events
50441
+ WHERE event_name = 'agent.invoke.start'
50442
+ ${where}
50443
+ AND json_valid(payload_json) = 1
50444
+ AND json_extract(payload_json, '$.data.routing.executor') IS NOT NULL
50445
+ AND json_extract(payload_json, '$.data.routing.role') IS NOT NULL
50446
+ ),
50447
+ exit_rows AS (
50448
+ SELECT id, occurred_at,
50449
+ json_extract(payload_json, '$.data.executionId') AS execution_id,
50450
+ json_extract(payload_json, '$.data.outcome') AS outcome,
50451
+ json_extract(payload_json, '$.data.durationMs') AS duration_ms
50452
+ FROM system_events
50453
+ WHERE event_name = 'agent.invoke.exit'
50454
+ ${where}
50455
+ AND json_valid(payload_json) = 1
50456
+ AND json_extract(payload_json, '$.data.executionId') IS NOT NULL
50457
+ ),
50458
+ -- One exit per executionId: the latest. An execution emits one exit,
50459
+ -- but picking the latest keeps the FINAL dispatch outcome honest if
50460
+ -- a re-dispatch ever reuses an id.
50461
+ fin AS (
50462
+ SELECT x.* FROM exit_rows x
50463
+ WHERE x.id = (
50464
+ SELECT x2.id FROM exit_rows x2
50465
+ WHERE x2.execution_id = x.execution_id
50466
+ ORDER BY x2.occurred_at DESC, x2.id DESC
50467
+ LIMIT 1
50468
+ )
50469
+ )
50470
+ SELECT d.executor AS executor, d.role AS role, d.agent AS agent, d.model AS model,
50471
+ COUNT(DISTINCT d.id) AS dispatches,
50472
+ COALESCE(SUM(CASE WHEN f.outcome = 'done' THEN 1 ELSE 0 END), 0) AS successes,
50473
+ COALESCE(SUM(f.duration_ms), 0) AS durationTotal,
50474
+ COALESCE(SUM(CASE WHEN f.duration_ms IS NOT NULL THEN 1 ELSE 0 END), 0) AS durationCount
50475
+ FROM dispatch d
50476
+ LEFT JOIN fin f ON f.execution_id = d.execution_id
50477
+ GROUP BY d.executor, d.role, d.agent, d.model`, ...params, ...params);
50478
+ } catch (error51) {
50479
+ if (error51 instanceof Error && error51.message.includes("no such table: system_events")) {
50480
+ return [];
50481
+ }
50482
+ throw error51;
50483
+ }
50484
+ }
50485
+ async function loadEscalations(db2, spec) {
50486
+ try {
50487
+ const { where, params } = eventWindow(spec);
50488
+ return await db2.queryAll(`WITH dispatch AS (
50489
+ SELECT id, run_id, occurred_at,
50490
+ json_extract(payload_json, '$.data.routing.executor') AS executor,
50491
+ json_extract(payload_json, '$.data.routing.role') AS role
50492
+ FROM system_events
50493
+ WHERE event_name = 'agent.invoke.start'
50494
+ ${where}
50495
+ AND json_valid(payload_json) = 1
50496
+ AND json_extract(payload_json, '$.data.routing.executor') IS NOT NULL
50497
+ AND json_extract(payload_json, '$.data.routing.role') IS NOT NULL
50498
+ ),
50499
+ first_dispatch AS (
50500
+ SELECT d.* FROM dispatch d
50501
+ WHERE d.id = (
50502
+ SELECT d2.id FROM dispatch d2
50503
+ WHERE d2.run_id = d.run_id AND d2.executor = d.executor
50504
+ ORDER BY d2.occurred_at, d2.id
50505
+ LIMIT 1
50506
+ )
50507
+ ),
50508
+ esc AS (
50509
+ SELECT id, run_id,
50510
+ json_extract(payload_json, '$.data.fromExecutor') AS from_executor,
50511
+ json_extract(payload_json, '$.data.trigger') AS trigger
50512
+ FROM system_events
50513
+ WHERE event_name = 'agent.invoke.escalated'
50514
+ ${where}
50515
+ AND json_valid(payload_json) = 1
50516
+ AND json_extract(payload_json, '$.data.fromExecutor') IS NOT NULL
50517
+ )
50518
+ SELECT fd.executor AS executor, fd.role AS role, e.trigger AS trigger,
50519
+ COUNT(DISTINCT e.id) AS count
50520
+ FROM esc e
50521
+ JOIN first_dispatch fd ON fd.run_id = e.run_id AND fd.executor = e.from_executor
50522
+ GROUP BY fd.executor, fd.role, e.trigger
50523
+ ORDER BY fd.executor, fd.role, e.trigger`, ...params, ...params);
50524
+ } catch (error51) {
50525
+ if (error51 instanceof Error && error51.message.includes("no such table: system_events")) {
50526
+ return [];
50527
+ }
50528
+ throw error51;
50529
+ }
50530
+ }
50531
+ async function loadFolds(db2, spec) {
50532
+ try {
50533
+ const { where, params } = eventWindow(spec);
50534
+ return await db2.queryAll(`WITH routed AS (
50535
+ SELECT run_id,
50536
+ json_extract(payload_json, '$.data.routing.executor') AS executor,
50537
+ json_extract(payload_json, '$.data.routing.role') AS role
50538
+ FROM system_events
50539
+ WHERE event_name = 'agent.invoke.start'
50540
+ ${where}
50541
+ AND json_valid(payload_json) = 1
50542
+ AND json_extract(payload_json, '$.data.routing.executor') IS NOT NULL
50543
+ AND json_extract(payload_json, '$.data.routing.role') IS NOT NULL
50544
+ ),
50545
+ mapped AS (
50546
+ SELECT r.executor AS executor, r.role AS role, m.run_id AS run_id,
50547
+ m.source AS source, m.session_id AS session_id
50548
+ FROM routed r
50549
+ JOIN history_run_session m ON m.run_id = r.run_id
50550
+ WHERE m.session_id IS NOT NULL
50551
+ )
50552
+ SELECT m.executor AS executor, m.role AS role,
50553
+ COALESCE(SUM(h.cost_usd), 0) AS totalCostUsd
50554
+ FROM mapped m
50555
+ LEFT JOIN history_message h
50556
+ ON h.source = m.source AND h.session_id = m.session_id
50557
+ GROUP BY m.executor, m.role`, ...params);
50558
+ } catch (error51) {
50559
+ if (error51 instanceof Error) {
50560
+ const msg = error51.message;
50561
+ if (msg.includes("no such table: system_events") || msg.includes("no such table: history_run_session") || msg.includes("no such table: history_message")) {
50562
+ return [];
50563
+ }
50564
+ }
50565
+ throw error51;
50566
+ }
50567
+ }
50568
+ function eventWindow(spec) {
50569
+ const clauses = [];
50570
+ const params = [];
50571
+ if (spec.since !== undefined) {
50572
+ clauses.push("occurred_at >= ?");
50573
+ params.push(spec.since);
50574
+ }
50575
+ if (spec.until !== undefined) {
50576
+ clauses.push("occurred_at <= ?");
50577
+ params.push(spec.until);
50578
+ }
50579
+ return { where: clauses.length > 0 ? `AND ${clauses.join(" AND ")}` : "", params };
50580
+ }
50581
+
50359
50582
  // ../../packages/domain/src/analytics/query.ts
50360
50583
  function extractClaudeTokens(payload) {
50361
50584
  const usage = payload.usage;
@@ -50689,6 +50912,118 @@ var init_render_forensics = __esm(() => {
50689
50912
  init_render_report();
50690
50913
  });
50691
50914
 
50915
+ // ../../packages/domain/src/analytics/render-pairings.ts
50916
+ function renderPairings(artifact) {
50917
+ const lines = [];
50918
+ lines.push(...renderPairingsSection(artifact));
50919
+ lines.push(...renderLadderDiffSection(artifact));
50920
+ return lines.join(`
50921
+ `);
50922
+ }
50923
+ function comparePairings(a2, b) {
50924
+ return b.successRate - a2.successRate || totalEscalations(a2) - totalEscalations(b) || a2.totalCostUsd - b.totalCostUsd;
50925
+ }
50926
+ function renderPairingsSection(artifact) {
50927
+ const lines = ["## Pairings", ""];
50928
+ const pairings = artifact.pairings;
50929
+ if (pairings === undefined) {
50930
+ lines.push(SECTION_UNAVAILABLE, "");
50931
+ return lines;
50932
+ }
50933
+ if (pairings.length === 0) {
50934
+ lines.push("(no pairings in selection)", "");
50935
+ return lines;
50936
+ }
50937
+ for (const role of [...new Set(pairings.map((p) => p.role))].sort()) {
50938
+ const rows = pairings.filter((p) => p.role === role).sort(comparePairings);
50939
+ lines.push(`### role: ${role}`, "");
50940
+ lines.push("| executor | agent | model | dispatches | success | escalations | cost | mean dur |", "| --- | --- | --- | ---: | ---: | ---: | ---: | ---: |");
50941
+ for (const p of rows) {
50942
+ lines.push(`| ${p.executor} | ${p.agent} | ${p.model ?? "n/a"} | ${p.dispatches} | ${pct(p.successRate)} | ` + `${fmtEscalations(p)} | ${usd(p.totalCostUsd)} | ${fmtDuration(p.meanDurationMs)} |`);
50943
+ }
50944
+ lines.push("");
50945
+ }
50946
+ return lines;
50947
+ }
50948
+ function fmtEscalations(p) {
50949
+ const total = totalEscalations(p);
50950
+ if (total === 0)
50951
+ return "0";
50952
+ const breakdown = Object.entries(p.escalations).map(([trigger, count3]) => `${trigger}:${count3}`).join(", ");
50953
+ return `${total} (${breakdown})`;
50954
+ }
50955
+ function totalEscalations(p) {
50956
+ return Object.values(p.escalations).reduce((sum, count3) => sum + count3, 0);
50957
+ }
50958
+ function measureExecutor(entry, pairings) {
50959
+ const owned = pairings.filter((p) => p.executor === entry.name);
50960
+ const dispatches = owned.reduce((sum, p) => sum + p.dispatches, 0);
50961
+ const successes = owned.reduce((sum, p) => sum + p.successRate * p.dispatches, 0);
50962
+ return {
50963
+ entry,
50964
+ dispatches,
50965
+ successRate: dispatches > 0 ? successes / dispatches : 0,
50966
+ escalations: owned.reduce((sum, p) => sum + totalEscalations(p), 0),
50967
+ costUsd: owned.reduce((sum, p) => sum + p.totalCostUsd, 0)
50968
+ };
50969
+ }
50970
+ function compareMeasured(a2, b) {
50971
+ return b.successRate - a2.successRate || a2.escalations - b.escalations || a2.costUsd - b.costUsd;
50972
+ }
50973
+ function renderLadderDiffSection(artifact) {
50974
+ const lines = ["## Ladder diff", ""];
50975
+ const pairings = artifact.pairings;
50976
+ const ladder = artifact.ladderSnapshot;
50977
+ if (pairings === undefined || ladder === undefined) {
50978
+ lines.push(SECTION_UNAVAILABLE, "");
50979
+ return lines;
50980
+ }
50981
+ if (ladder.length === 0) {
50982
+ lines.push("(no executor ladder configured)", "");
50983
+ return lines;
50984
+ }
50985
+ for (const tier of [...new Set(ladder.map((e) => e.tier))].sort()) {
50986
+ const entries = ladder.filter((e) => e.tier === tier).sort((a2, b) => a2.order - b.order);
50987
+ const measured = entries.map((e) => measureExecutor(e, pairings));
50988
+ const measuredOrder = [...measured].sort(compareMeasured);
50989
+ lines.push(`### tier: ${tier}`, "");
50990
+ lines.push(`configured: ${entries.map((e) => e.name).join(", ")}`);
50991
+ lines.push(`measured: ${measuredOrder.map((m) => m.entry.name).join(", ")}`);
50992
+ lines.push("");
50993
+ for (let i2 = 1;i2 < measured.length; i2++) {
50994
+ const above = measured[i2 - 1];
50995
+ const below = measured[i2];
50996
+ if (above === undefined || below === undefined)
50997
+ continue;
50998
+ if (above.dispatches < MIN_PAIRING_DISPATCHES || below.dispatches < MIN_PAIRING_DISPATCHES)
50999
+ continue;
51000
+ if (compareMeasured(below, above) < 0) {
51001
+ lines.push(`suggest: promote ${below.entry.name} above ${above.entry.name} ` + `(dispatches=${below.dispatches}, success=${pct(below.successRate)} vs ` + `${pct(above.successRate)}, cost=${usd(below.costUsd)} vs ${usd(above.costUsd)})`);
51002
+ }
51003
+ }
51004
+ for (const m of measured) {
51005
+ if (m.dispatches < MIN_PAIRING_DISPATCHES) {
51006
+ lines.push(`${m.entry.name}: insufficient-evidence (N=${m.dispatches}<${MIN_PAIRING_DISPATCHES})`);
51007
+ }
51008
+ }
51009
+ lines.push("");
51010
+ }
51011
+ return lines;
51012
+ }
51013
+ function pct(rate) {
51014
+ return `${(rate * 100).toFixed(1)}%`;
51015
+ }
51016
+ function usd(cost) {
51017
+ return `$${cost.toFixed(2)}`;
51018
+ }
51019
+ function fmtDuration(ms) {
51020
+ return ms > 0 ? fmtDur(ms) : "n/a";
51021
+ }
51022
+ var MIN_PAIRING_DISPATCHES = 5, SECTION_UNAVAILABLE = "section unavailable (artifact predates the pairings field; re-run spur history analyze)";
51023
+ var init_render_pairings = __esm(() => {
51024
+ init_render_report();
51025
+ });
51026
+
50692
51027
  // ../../packages/domain/src/analytics/report-modes.ts
50693
51028
  function resolveReportMode(mode) {
50694
51029
  const renderer = REPORT_MODES[mode];
@@ -50710,6 +51045,7 @@ ${body}
50710
51045
  var UnknownReportModeError, REPORT_MODES;
50711
51046
  var init_report_modes = __esm(() => {
50712
51047
  init_render_forensics();
51048
+ init_render_pairings();
50713
51049
  init_render_report();
50714
51050
  UnknownReportModeError = class UnknownReportModeError extends Error {
50715
51051
  constructor(mode, registered) {
@@ -50719,7 +51055,8 @@ var init_report_modes = __esm(() => {
50719
51055
  };
50720
51056
  REPORT_MODES = {
50721
51057
  default: renderReport,
50722
- forensics: renderForensics
51058
+ forensics: renderForensics,
51059
+ pairings: renderPairings
50723
51060
  };
50724
51061
  });
50725
51062
 
@@ -51097,7 +51434,7 @@ async function roleTokenSummary(db2, spec = {}) {
51097
51434
  const until = spec.until ?? new Date().toISOString();
51098
51435
  const since = spec.since ?? new Date(Date.parse(until) - ROUTING_SUMMARY_DEFAULT_WINDOW_MS).toISOString();
51099
51436
  const window2 = { since, until };
51100
- const [runsByRole, folds] = await Promise.all([loadAttributedRuns(db2, window2), loadFolds(db2, window2)]);
51437
+ const [runsByRole, folds] = await Promise.all([loadAttributedRuns(db2, window2), loadFolds2(db2, window2)]);
51101
51438
  const byRole = new Map;
51102
51439
  for (const r of runsByRole) {
51103
51440
  byRole.set(r.role, {
@@ -51156,7 +51493,7 @@ async function loadAttributedRuns(db2, window2) {
51156
51493
  throw error51;
51157
51494
  }
51158
51495
  }
51159
- async function loadFolds(db2, window2) {
51496
+ async function loadFolds2(db2, window2) {
51160
51497
  try {
51161
51498
  return await db2.queryAll(`WITH routed AS (
51162
51499
  SELECT id, run_id,
@@ -51333,6 +51670,7 @@ var init_analytics = __esm(() => {
51333
51670
  init_models();
51334
51671
  init_narrow_artifact();
51335
51672
  init_render_forensics();
51673
+ init_render_pairings();
51336
51674
  init_render_report();
51337
51675
  init_report_modes();
51338
51676
  init_retro_correlation();
@@ -52026,7 +52364,7 @@ class ActionRunDao {
52026
52364
  }
52027
52365
  }
52028
52366
 
52029
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
52367
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/drizzle-internals.js
52030
52368
  function sqlExpressionToText(value) {
52031
52369
  if (typeof value !== "object" || value === null || !("queryChunks" in value)) {
52032
52370
  return;
@@ -52049,7 +52387,7 @@ function getDrizzleTableName(table3) {
52049
52387
  return String(table3[nameSym]);
52050
52388
  }
52051
52389
 
52052
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
52390
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/ddl.js
52053
52391
  function quoteIdent(name) {
52054
52392
  return `"${name.replace(/"/g, '""')}"`;
52055
52393
  }
@@ -52421,7 +52759,7 @@ var init_drizzle_zod = __esm(() => {
52421
52759
  };
52422
52760
  });
52423
52761
 
52424
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
52762
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/define-table.js
52425
52763
  function defineTable(name, columns2) {
52426
52764
  const table3 = sqliteTable(name, columns2);
52427
52765
  let insert2;
@@ -52455,7 +52793,7 @@ var init_define_table = __esm(() => {
52455
52793
  init_ddl();
52456
52794
  });
52457
52795
 
52458
- // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.32+901599bf373bc10d/node_modules/@gobing-ai/ts-db/dist/schema/index.js
52796
+ // ../../node_modules/.bun/@gobing-ai+ts-db@0.4.35+88b5cb666b9290be/node_modules/@gobing-ai/ts-db/dist/schema/index.js
52459
52797
  var exports_schema = {};
52460
52798
  __export(exports_schema, {
52461
52799
  text: () => text,
@@ -53057,7 +53395,7 @@ var init_dao = __esm(() => {
53057
53395
  init_workspace_dao();
53058
53396
  });
53059
53397
 
53060
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
53398
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/errors.js
53061
53399
  var WorkflowValidationError, FSMError, RunCollisionError, WorkflowResumeError;
53062
53400
  var init_errors5 = __esm(() => {
53063
53401
  WorkflowValidationError = class WorkflowValidationError extends Error {
@@ -53092,12 +53430,12 @@ var init_errors5 = __esm(() => {
53092
53430
  };
53093
53431
  });
53094
53432
 
53095
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
53433
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/event-bus/index.js
53096
53434
  var init_event_bus2 = __esm(() => {
53097
53435
  init_event_bus();
53098
53436
  });
53099
53437
 
53100
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/api-client.js
53438
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/api-client.js
53101
53439
  function sanitizeUrlForObservability(url2) {
53102
53440
  try {
53103
53441
  const parsed = new URL(url2);
@@ -53328,12 +53666,12 @@ var init_api_client = __esm(() => {
53328
53666
  };
53329
53667
  });
53330
53668
 
53331
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
53669
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
53332
53670
  var init_telemetry = __esm(() => {
53333
53671
  init_tracing2();
53334
53672
  });
53335
53673
 
53336
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/index.js
53674
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/index.js
53337
53675
  var init_dist6 = __esm(() => {
53338
53676
  init_api_client();
53339
53677
  init_event_bus2();
@@ -53341,7 +53679,7 @@ var init_dist6 = __esm(() => {
53341
53679
  init_telemetry();
53342
53680
  });
53343
53681
 
53344
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
53682
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/run-lifecycle.js
53345
53683
  function runtimeBuiltins(workflowName, stateOrNodeId, runId, transitionsTaken, mode) {
53346
53684
  return {
53347
53685
  workflow: workflowName,
@@ -53625,7 +53963,7 @@ var init_run_lifecycle = __esm(() => {
53625
53963
  ];
53626
53964
  });
53627
53965
 
53628
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
53966
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/extension/capability-registry.js
53629
53967
  class CapabilityRegistry {
53630
53968
  kind;
53631
53969
  capabilities = new Map;
@@ -53656,7 +53994,7 @@ class CapabilityRegistry {
53656
53994
  }
53657
53995
  }
53658
53996
 
53659
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
53997
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-path.js
53660
53998
  function assertRelativeExtensionPath(path9, options = {}) {
53661
53999
  const where = options.sourceName !== undefined ? ` declared by "${options.sourceName}"` : "";
53662
54000
  if (/^([/\\]|[A-Za-z]:[/\\])/.test(path9)) {
@@ -53667,7 +54005,7 @@ function assertRelativeExtensionPath(path9, options = {}) {
53667
54005
  }
53668
54006
  }
53669
54007
 
53670
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
54008
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/extension/extension-loader.js
53671
54009
  import { isAbsolute, resolve } from "path";
53672
54010
  async function loadExtensionModules(refs, options, register) {
53673
54011
  if (refs.length === 0)
@@ -53706,17 +54044,17 @@ async function loadExtensionModules(refs, options, register) {
53706
54044
  }
53707
54045
  var init_extension_loader = () => {};
53708
54046
 
53709
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
54047
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/extension/index.js
53710
54048
  var init_extension = __esm(() => {
53711
54049
  init_extension_loader();
53712
54050
  });
53713
54051
 
53714
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.32+68699ef47523a206/node_modules/@gobing-ai/ts-runtime/dist/extension.js
54052
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.35+d182f71dab7ad9ef/node_modules/@gobing-ai/ts-runtime/dist/extension.js
53715
54053
  var init_extension2 = __esm(() => {
53716
54054
  init_extension();
53717
54055
  });
53718
54056
 
53719
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
54057
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema.js
53720
54058
  var RESERVED_VAR_NAMES, IDENTIFIER, VarsSchema, EnvSchema, relativeExtensionPath, WorkflowExtensionsSchema, ActionDefSchema, GuardDefSchema, StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema, WorkflowDefSchema;
53721
54059
  var init_schema2 = __esm(() => {
53722
54060
  init_extension2();
@@ -53818,7 +54156,7 @@ var init_schema2 = __esm(() => {
53818
54156
  WorkflowDefSchema = exports_external.union([StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema]);
53819
54157
  });
53820
54158
 
53821
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
54159
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/config.js
53822
54160
  async function loadWorkflowDef(path9, options = {}) {
53823
54161
  return parseWorkflowDef(await loadStructuredConfig(path9, options), path9);
53824
54162
  }
@@ -53985,7 +54323,7 @@ var init_config4 = __esm(() => {
53985
54323
  RUNTIME_TEMPLATE_NAMESPACES = new Set(RUNTIME_BUILTIN_KEYS);
53986
54324
  });
53987
54325
 
53988
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/extensions.js
54326
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/extensions.js
53989
54327
  function collectWorkflowExtensions(sourceName, sourceDir, extensions) {
53990
54328
  if (extensions === undefined)
53991
54329
  return [];
@@ -54049,7 +54387,7 @@ var init_extensions = __esm(() => {
54049
54387
  init_errors5();
54050
54388
  });
54051
54389
 
54052
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
54390
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/host.js
54053
54391
  class WorkflowEngineHost {
54054
54392
  lifecycleBus;
54055
54393
  actions = new CapabilityRegistry("workflow action");
@@ -54219,7 +54557,7 @@ var init_host = __esm(() => {
54219
54557
  init_errors5();
54220
54558
  });
54221
54559
 
54222
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
54560
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/schema-sql.js
54223
54561
  var WORKFLOW_ENGINE_SCHEMA_SQL;
54224
54562
  var init_schema_sql = __esm(() => {
54225
54563
  WORKFLOW_ENGINE_SCHEMA_SQL = `
@@ -54292,7 +54630,7 @@ CREATE TABLE IF NOT EXISTS action_runs (
54292
54630
  `.trim();
54293
54631
  });
54294
54632
 
54295
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
54633
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/persistence.js
54296
54634
  async function applyWorkflowEngineSchema(db2) {
54297
54635
  for (const statement of WORKFLOW_ENGINE_SCHEMA_SQL.split(";")) {
54298
54636
  const sql4 = statement.trim();
@@ -54608,7 +54946,7 @@ var init_persistence = __esm(() => {
54608
54946
  init_schema_sql();
54609
54947
  });
54610
54948
 
54611
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
54949
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/variables.js
54612
54950
  function mergeVars(workflowVars = {}, overrideVars = {}) {
54613
54951
  return { ...workflowVars, ...overrideVars };
54614
54952
  }
@@ -54668,7 +55006,7 @@ var init_variables = __esm(() => {
54668
55006
  TEMPLATE_REF = /\$\{([^}]+)\}/g;
54669
55007
  });
54670
55008
 
54671
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
55009
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/action-step.js
54672
55010
  async function runActionStep(action, vars, deps) {
54673
55011
  const { host, persistence, lifecycle, stateOrNodeId, runId } = deps;
54674
55012
  const resolved = resolveTemplates(action.options ?? {}, {
@@ -54710,16 +55048,21 @@ async function runActionStep(action, vars, deps) {
54710
55048
  }
54711
55049
  async function runActionSequence(actions, vars, deps) {
54712
55050
  let last;
55051
+ let acc;
54713
55052
  for (const action of actions) {
54714
55053
  const step = await runActionStep(action, vars, deps);
54715
55054
  if (step.result !== undefined)
54716
55055
  last = step.result;
55056
+ if (step.result?.setVars) {
55057
+ acc = mergeSetVars(acc ?? {}, step.result.setVars);
55058
+ vars = mergeSetVars(vars, step.result.setVars);
55059
+ }
54717
55060
  if (step.outcome === "terminal")
54718
- return { outcome: "terminal", result: last };
55061
+ return { outcome: "terminal", result: last, setVars: acc };
54719
55062
  if (step.outcome === "fail")
54720
- return { outcome: "fail", result: last };
55063
+ return { outcome: "fail", result: last, setVars: acc };
54721
55064
  }
54722
- return { outcome: "completed", result: last };
55065
+ return { outcome: "completed", result: last, setVars: acc };
54723
55066
  }
54724
55067
  var init_action_step = __esm(() => {
54725
55068
  init_persistence();
@@ -54727,7 +55070,7 @@ var init_action_step = __esm(() => {
54727
55070
  init_variables();
54728
55071
  });
54729
55072
 
54730
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
55073
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/state-machine.js
54731
55074
  class StateMachineDriver {
54732
55075
  options;
54733
55076
  constructor(options) {
@@ -54778,8 +55121,8 @@ class StateMachineDriver {
54778
55121
  });
54779
55122
  if (enter.result !== undefined)
54780
55123
  lastActionResult = enter.result;
54781
- if (enter.result?.setVars)
54782
- vars = mergeSetVars(vars, enter.result.setVars);
55124
+ if (enter.setVars)
55125
+ vars = mergeSetVars(vars, enter.setVars);
54783
55126
  if (enter.outcome === "terminal") {
54784
55127
  return failure.has(current.id) ? await lifecycle.fail(current.id, transitionsTaken, `terminal:${current.id}`) : await lifecycle.done(current.id, transitionsTaken);
54785
55128
  }
@@ -54819,8 +55162,8 @@ class StateMachineDriver {
54819
55162
  });
54820
55163
  if (exit.result !== undefined)
54821
55164
  lastActionResult = exit.result;
54822
- if (exit.result?.setVars)
54823
- vars = mergeSetVars(vars, exit.result.setVars);
55165
+ if (exit.setVars)
55166
+ vars = mergeSetVars(vars, exit.setVars);
54824
55167
  if (exit.outcome === "fail")
54825
55168
  return await lifecycle.fail(current.id, transitionsTaken, exit.result?.error);
54826
55169
  transitionsTaken += 1;
@@ -54860,10 +55203,10 @@ var init_state_machine = __esm(() => {
54860
55203
  init_errors5();
54861
55204
  init_run_lifecycle();
54862
55205
  init_variables();
54863
- EMPTY_OUTCOME = { outcome: "completed", result: undefined };
55206
+ EMPTY_OUTCOME = { outcome: "completed", result: undefined, setVars: undefined };
54864
55207
  });
54865
55208
 
54866
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
55209
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/transition-flow.js
54867
55210
  class TransitionFlowDriver {
54868
55211
  options;
54869
55212
  constructor(options) {
@@ -54982,7 +55325,7 @@ var init_transition_flow = __esm(() => {
54982
55325
  init_variables();
54983
55326
  });
54984
55327
 
54985
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
55328
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/service.js
54986
55329
  class WorkflowService {
54987
55330
  host;
54988
55331
  persistence;
@@ -55207,7 +55550,7 @@ var init_service = __esm(() => {
55207
55550
  init_variables();
55208
55551
  });
55209
55552
 
55210
- // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
55553
+ // ../../node_modules/.bun/@gobing-ai+ts-dual-workflow-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-dual-workflow-engine/dist/index.js
55211
55554
  var init_dist7 = __esm(() => {
55212
55555
  init_config4();
55213
55556
  init_extensions();
@@ -59289,7 +59632,7 @@ var init_dist12 = __esm(() => {
59289
59632
  init_sources();
59290
59633
  });
59291
59634
 
59292
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
59635
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/extensions.js
59293
59636
  function collectExtensions(sourceName, sourceDir, extensions) {
59294
59637
  if (extensions === undefined)
59295
59638
  return [];
@@ -59303,7 +59646,7 @@ function collectExtensions(sourceName, sourceDir, extensions) {
59303
59646
  }
59304
59647
  var init_extensions2 = () => {};
59305
59648
 
59306
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
59649
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/types.js
59307
59650
  function createFinding(rule, message, filePath, extras = {}) {
59308
59651
  return {
59309
59652
  ruleId: rule.id,
@@ -59374,7 +59717,7 @@ var init_types5 = __esm(() => {
59374
59717
  });
59375
59718
  });
59376
59719
 
59377
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
59720
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/config/loader.js
59378
59721
  async function loadPreset(name, options) {
59379
59722
  const merged = await buildMergedRoots(options.roots.map((root) => resolvePath4(root)), options.fileSystem);
59380
59723
  const presetPath = findMergedPreset(merged, name);
@@ -59589,7 +59932,7 @@ var init_loader2 = __esm(() => {
59589
59932
  FIX_MODE_AUTHORITY = { none: 0, suggest: 1, auto: 2 };
59590
59933
  });
59591
59934
 
59592
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
59935
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/test-stub-fixer.js
59593
59936
  function normalizeFindingPath(filePath) {
59594
59937
  if (!filePath || isAbsolutePath2(filePath))
59595
59938
  return null;
@@ -59654,7 +59997,7 @@ var init_test_stub_fixer = __esm(() => {
59654
59997
  realFileSystem = createNodeFileSystem3();
59655
59998
  });
59656
59999
 
59657
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
60000
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/fixers/fixers.js
59658
60001
  function registerBuiltinFixers(host, exec) {
59659
60002
  const regexFixer = new RegexFixerProvider;
59660
60003
  const pathFixer = new PathFixerProvider;
@@ -59857,7 +60200,7 @@ var init_fixers = __esm(() => {
59857
60200
  };
59858
60201
  });
59859
60202
 
59860
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
60203
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
59861
60204
  function getAgentSessionCapability(agent) {
59862
60205
  return AGENT_SESSION_CAPABILITY[agent];
59863
60206
  }
@@ -60149,7 +60492,7 @@ var init_shims = __esm(() => {
60149
60492
  ALIAS_TO_CANONICAL = Object.fromEntries(Object.values(AGENT_SHIMS).flatMap((shim) => (shim.aliases ?? []).map((alias3) => [alias3, shim.name])));
60150
60493
  });
60151
60494
 
60152
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
60495
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
60153
60496
  function buildIdentityPreamble(ctx) {
60154
60497
  const sections = [
60155
60498
  `You are agent \`${ctx.agentId}\` (${ctx.agentType}) in workspace \`${ctx.workspace}\`.`
@@ -60225,7 +60568,7 @@ var init_identity = __esm(() => {
60225
60568
  init_dist5();
60226
60569
  });
60227
60570
 
60228
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
60571
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/slash-command.js
60229
60572
  function isClaudeStyleSlashCommand(input) {
60230
60573
  return SLASH_COMMAND_RE.test(input);
60231
60574
  }
@@ -60253,7 +60596,7 @@ var init_slash_command = __esm(() => {
60253
60596
  SLASH_COMMAND_RE = /^\/([a-zA-Z0-9._-]+):([a-zA-Z0-9._-]+)(\s.*)?$/;
60254
60597
  });
60255
60598
 
60256
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
60599
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
60257
60600
  function buildCorrelationEnv(correlation) {
60258
60601
  return {
60259
60602
  [AGENT_RUN_ID_ENV]: correlation.runId,
@@ -60391,7 +60734,7 @@ var init_ai_runner = __esm(() => {
60391
60734
  init_slash_command();
60392
60735
  });
60393
60736
 
60394
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
60737
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
60395
60738
  class AgentDetector {
60396
60739
  runner;
60397
60740
  timeout;
@@ -60467,7 +60810,7 @@ var init_agent_detector = __esm(() => {
60467
60810
  VERSION_PATTERN = /(?<version>\d+\.\d+(?:\.\d+)?)/;
60468
60811
  });
60469
60812
 
60470
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
60813
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/agent-spec.js
60471
60814
  function validateAgentId(id) {
60472
60815
  if (!/^[a-z][a-z0-9_-]{1,63}$/.test(id)) {
60473
60816
  throw new ValueError(`Invalid agent id "${id}": expected 2-64 chars, lowercase alphanumeric, "_" or "-"`);
@@ -60566,7 +60909,7 @@ var init_agent_spec = __esm(() => {
60566
60909
  };
60567
60910
  });
60568
60911
 
60569
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
60912
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/agents/auth-shims.js
60570
60913
  function isNonEmpty(value) {
60571
60914
  return value !== undefined && value.trim().length > 0;
60572
60915
  }
@@ -60691,7 +61034,7 @@ var init_auth_shims = __esm(() => {
60691
61034
  };
60692
61035
  });
60693
61036
 
60694
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
61037
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/model-health-probe.js
60695
61038
  class ModelHealthProbeRegistry {
60696
61039
  probes = new Map;
60697
61040
  register(providerPrefix, probe) {
@@ -60799,7 +61142,7 @@ var init_model_health_probe = __esm(() => {
60799
61142
  };
60800
61143
  });
60801
61144
 
60802
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
61145
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/doctor-runner.js
60803
61146
  class DoctorRunner {
60804
61147
  detector;
60805
61148
  runner;
@@ -60936,15 +61279,15 @@ var init_doctor_runner = __esm(() => {
60936
61279
  init_model_health_probe();
60937
61280
  });
60938
61281
 
60939
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
61282
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/events.js
60940
61283
  var init_events = () => {};
60941
61284
 
60942
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
61285
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/messages.js
60943
61286
  function formatMessage(msg) {
60944
61287
  return `[task from=${msg.fromId ?? "operator"} id=${msg.id}] ${msg.body}`;
60945
61288
  }
60946
61289
 
60947
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
61290
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/team-agent-process.js
60948
61291
  import { Buffer as Buffer5 } from "buffer";
60949
61292
 
60950
61293
  class TeamAgentProcess {
@@ -61078,7 +61421,7 @@ var init_team_agent_process = __esm(() => {
61078
61421
  init_dist5();
61079
61422
  });
61080
61423
 
61081
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
61424
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/team-orchestrator.js
61082
61425
  class TeamOrchestrator {
61083
61426
  configDir;
61084
61427
  inbox;
@@ -61219,7 +61562,7 @@ var init_team_orchestrator = __esm(() => {
61219
61562
  init_team_agent_process();
61220
61563
  });
61221
61564
 
61222
- // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.32+aae0f140728a8132/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
61565
+ // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.4.35+c041a695cd33e591/node_modules/@gobing-ai/ts-ai-runner/dist/index.js
61223
61566
  var exports_dist3 = {};
61224
61567
  __export(exports_dist3, {
61225
61568
  validateAgentId: () => validateAgentId,
@@ -61272,7 +61615,7 @@ var init_dist13 = __esm(() => {
61272
61615
  init_team_orchestrator();
61273
61616
  });
61274
61617
 
61275
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
61618
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/config-access.js
61276
61619
  function stringArray(value) {
61277
61620
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : undefined;
61278
61621
  }
@@ -61310,7 +61653,7 @@ function parseInlineFlags(source) {
61310
61653
  return { flags, rest: source.slice(match[0].length) };
61311
61654
  }
61312
61655
 
61313
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
61656
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/glob-match.js
61314
61657
  function matchesAny(path11, patterns) {
61315
61658
  if (patterns === undefined || patterns.length === 0)
61316
61659
  return true;
@@ -61358,7 +61701,7 @@ function escapeRegExp(value) {
61358
61701
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
61359
61702
  }
61360
61703
 
61361
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
61704
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-discovery.js
61362
61705
  async function discoverFiles2(options) {
61363
61706
  const fs3 = options.fs ?? createNodeFileSystem3();
61364
61707
  const allFiles = await walkDir2(options.workdir, fs3, DEFAULT_EXCLUDES);
@@ -61389,12 +61732,12 @@ var init_file_discovery = __esm(() => {
61389
61732
  DEFAULT_EXCLUDES = new Set([".git", "node_modules", "dist", ".coverage", ".astro", ".wrangler"]);
61390
61733
  });
61391
61734
 
61392
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
61735
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/file-utils.js
61393
61736
  var init_file_utils = __esm(() => {
61394
61737
  init_file_discovery();
61395
61738
  });
61396
61739
 
61397
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
61740
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/agent-detection-evaluator.js
61398
61741
  class AgentDetectionEvaluator {
61399
61742
  detector;
61400
61743
  constructor(detector = new AgentDetector) {
@@ -61422,7 +61765,7 @@ var init_agent_detection_evaluator = __esm(() => {
61422
61765
  init_file_utils();
61423
61766
  });
61424
61767
 
61425
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
61768
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/coverage-gate-evaluator.js
61426
61769
  class CoverageGateEvaluator {
61427
61770
  constructor() {}
61428
61771
  async evaluate(rule, context6) {
@@ -61453,12 +61796,12 @@ class CoverageGateEvaluator {
61453
61796
  continue;
61454
61797
  if (isAlwaysExcluded(filePath))
61455
61798
  continue;
61456
- const pct = Math.round(cov.linesHit / cov.linesFound * 100);
61799
+ const pct2 = Math.round(cov.linesHit / cov.linesFound * 100);
61457
61800
  const exemption = exemptions.get(filePath);
61458
61801
  const effectiveThreshold = exemption?.threshold ?? threshold;
61459
- if (pct >= effectiveThreshold)
61802
+ if (pct2 >= effectiveThreshold)
61460
61803
  continue;
61461
- const message = exemption ? `${pct}% line coverage (exemption: ${effectiveThreshold}%, reason: ${exemption.reason})` : `${pct}% line coverage (threshold: ${effectiveThreshold}%)`;
61804
+ const message = exemption ? `${pct2}% line coverage (exemption: ${effectiveThreshold}%, reason: ${exemption.reason})` : `${pct2}% line coverage (threshold: ${effectiveThreshold}%)`;
61462
61805
  findings.push(createFinding(rule, message, filePath, { code: "coverage:below-threshold" }));
61463
61806
  }
61464
61807
  return { findings, fixes: [] };
@@ -61506,7 +61849,7 @@ var init_coverage_gate_evaluator = __esm(() => {
61506
61849
  init_file_utils();
61507
61850
  });
61508
61851
 
61509
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
61852
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/exit-code-evaluator.js
61510
61853
  class ExitCodeEvaluator {
61511
61854
  executor;
61512
61855
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -61542,7 +61885,7 @@ var init_exit_code_evaluator = __esm(() => {
61542
61885
  init_file_utils();
61543
61886
  });
61544
61887
 
61545
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
61888
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/forbidden-import-evaluator.js
61546
61889
  class ForbiddenImportEvaluator {
61547
61890
  constructor() {}
61548
61891
  async evaluate(rule, context6) {
@@ -61623,7 +61966,7 @@ var init_forbidden_import_evaluator = __esm(() => {
61623
61966
  init_file_utils();
61624
61967
  });
61625
61968
 
61626
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
61969
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/import-boundary-evaluator.js
61627
61970
  class ImportBoundaryEvaluator {
61628
61971
  async evaluate(rule, context6) {
61629
61972
  const config6 = rule.evaluator.config ?? {};
@@ -61716,7 +62059,7 @@ var init_import_boundary_evaluator = __esm(() => {
61716
62059
  init_file_utils();
61717
62060
  });
61718
62061
 
61719
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
62062
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/path-evaluator.js
61720
62063
  class PathEvaluator {
61721
62064
  constructor() {}
61722
62065
  async evaluate(rule, context6) {
@@ -61777,7 +62120,7 @@ var init_path_evaluator = __esm(() => {
61777
62120
  init_file_utils();
61778
62121
  });
61779
62122
 
61780
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
62123
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/regex-evaluator.js
61781
62124
  class RegexEvaluator {
61782
62125
  constructor() {}
61783
62126
  async evaluate(rule, context6) {
@@ -61855,7 +62198,7 @@ var init_regex_evaluator = __esm(() => {
61855
62198
  init_file_utils();
61856
62199
  });
61857
62200
 
61858
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
62201
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/ripgrep-evaluator.js
61859
62202
  class RipgrepEvaluator {
61860
62203
  executor;
61861
62204
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -61948,7 +62291,7 @@ var init_ripgrep_evaluator = __esm(() => {
61948
62291
  init_file_utils();
61949
62292
  });
61950
62293
 
61951
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
62294
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/schema-artifact-evaluator.js
61952
62295
  class SchemaArtifactEvaluator {
61953
62296
  constructor() {}
61954
62297
  async evaluate(rule, context6) {
@@ -62026,7 +62369,7 @@ var init_schema_artifact_evaluator = __esm(() => {
62026
62369
  init_file_utils();
62027
62370
  });
62028
62371
 
62029
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
62372
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/secrets-scanner-evaluator.js
62030
62373
  class SecretsScannerEvaluator {
62031
62374
  constructor() {}
62032
62375
  async evaluate(rule, context6) {
@@ -62094,7 +62437,7 @@ var init_secrets_scanner_evaluator = __esm(() => {
62094
62437
  ALL_CATEGORIES = Object.keys(BUILTIN_PATTERNS);
62095
62438
  });
62096
62439
 
62097
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
62440
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/sg-evaluator.js
62098
62441
  class SgEvaluator {
62099
62442
  executor;
62100
62443
  constructor(executor = nodeBunFactory3.createProcessExecutor()) {
@@ -62191,7 +62534,7 @@ var init_sg_evaluator = __esm(() => {
62191
62534
  init_file_utils();
62192
62535
  });
62193
62536
 
62194
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
62537
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/resolvers/test-path-resolver.js
62195
62538
  class TypeScriptTestPathResolver {
62196
62539
  name = "typescript";
62197
62540
  constructor() {}
@@ -62274,7 +62617,7 @@ function testify(rel) {
62274
62617
  return `${dir}test_${base2}`;
62275
62618
  }
62276
62619
 
62277
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
62620
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/test-location-evaluator.js
62278
62621
  class TestLocationEvaluator {
62279
62622
  resolvers;
62280
62623
  constructor(resolvers) {
@@ -62349,7 +62692,7 @@ var init_test_location_evaluator = __esm(() => {
62349
62692
  TYPESCRIPT_FALLBACK = new TypeScriptTestPathResolver;
62350
62693
  });
62351
62694
 
62352
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
62695
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/evaluators/tsdoc-export-evaluator.js
62353
62696
  class TsdocExportEvaluator {
62354
62697
  constructor() {}
62355
62698
  async evaluate(rule, context6) {
@@ -62434,7 +62777,7 @@ var init_tsdoc_export_evaluator = __esm(() => {
62434
62777
  };
62435
62778
  });
62436
62779
 
62437
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
62780
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/json.js
62438
62781
  class JsonFormatter {
62439
62782
  constructor() {}
62440
62783
  format(result) {
@@ -62442,7 +62785,7 @@ class JsonFormatter {
62442
62785
  }
62443
62786
  }
62444
62787
 
62445
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
62788
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/formatters/text.js
62446
62789
  class TextFormatter {
62447
62790
  constructor() {}
62448
62791
  format(result) {
@@ -62456,7 +62799,7 @@ class TextFormatter {
62456
62799
  }
62457
62800
  }
62458
62801
 
62459
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
62802
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/builtins.js
62460
62803
  function registerBuiltins(host, executor) {
62461
62804
  const path11 = new PathEvaluator;
62462
62805
  host.evaluators.register("regex", new RegexEvaluator, "builtin");
@@ -62496,7 +62839,7 @@ var init_builtins = __esm(() => {
62496
62839
  init_tsdoc_export_evaluator();
62497
62840
  });
62498
62841
 
62499
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
62842
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/rule-engine-host.js
62500
62843
  class RuleEngineHost {
62501
62844
  evaluators;
62502
62845
  formatters;
@@ -62513,7 +62856,7 @@ var init_rule_engine_host = __esm(() => {
62513
62856
  init_extension2();
62514
62857
  });
62515
62858
 
62516
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
62859
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/engine.js
62517
62860
  class RuleEngine {
62518
62861
  host;
62519
62862
  events;
@@ -62699,7 +63042,7 @@ var init_engine = __esm(() => {
62699
63042
  init_types5();
62700
63043
  });
62701
63044
 
62702
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
63045
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/host/bundled-rules.js
62703
63046
  async function bundledRulesRoot() {
62704
63047
  if (cachedRoot2 !== undefined)
62705
63048
  return cachedRoot2;
@@ -62750,7 +63093,7 @@ var init_bundled_rules = __esm(() => {
62750
63093
  init_dist5();
62751
63094
  });
62752
63095
 
62753
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
63096
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/db-adapter.js
62754
63097
  class DbRulePersistenceAdapter {
62755
63098
  db;
62756
63099
  constructor(db2) {
@@ -62784,7 +63127,7 @@ class DbRulePersistenceAdapter {
62784
63127
  }
62785
63128
  }
62786
63129
 
62787
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
63130
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/schema.js
62788
63131
  var RULE_ENGINE_SCHEMA_SQL = `
62789
63132
  CREATE TABLE IF NOT EXISTS rule_runs (
62790
63133
  id TEXT PRIMARY KEY,
@@ -62830,10 +63173,10 @@ CREATE TABLE IF NOT EXISTS rule_eval_runs (
62830
63173
  CREATE INDEX IF NOT EXISTS idx_rule_eval_runs_run_id ON rule_eval_runs (run_id);
62831
63174
  `;
62832
63175
 
62833
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
63176
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/persistence/index.js
62834
63177
  var init_persistence2 = () => {};
62835
63178
 
62836
- // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.32+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
63179
+ // ../../node_modules/.bun/@gobing-ai+ts-rule-engine@0.4.35+eb8900f44f4776f9/node_modules/@gobing-ai/ts-rule-engine/dist/index.js
62837
63180
  var init_dist14 = __esm(() => {
62838
63181
  init_extensions2();
62839
63182
  init_loader2();
@@ -63135,7 +63478,7 @@ ${HISTORY_RUN_SESSION_SCHEMA_SQL}
63135
63478
  ];
63136
63479
  });
63137
63480
 
63138
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
63481
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/job-queue/db-job-queue.js
63139
63482
  function queueLogger() {
63140
63483
  if (!_queueLogger)
63141
63484
  _queueLogger = getLogger2("job-queue");
@@ -63418,7 +63761,7 @@ var init_db_job_queue = __esm(() => {
63418
63761
  init_tracing2();
63419
63762
  });
63420
63763
 
63421
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
63764
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/job-queue-db.js
63422
63765
  var exports_job_queue_db = {};
63423
63766
  __export(exports_job_queue_db, {
63424
63767
  DBQueueConsumer: () => DBQueueConsumer,
@@ -65568,6 +65911,7 @@ __export(exports_src, {
65568
65911
  renderTaskTemplate: () => renderTaskTemplate,
65569
65912
  renderScenarioStub: () => renderScenarioStub,
65570
65913
  renderReport: () => renderReport,
65914
+ renderPairings: () => renderPairings,
65571
65915
  renderMarkdown: () => renderMarkdown,
65572
65916
  renderForensics: () => renderForensics,
65573
65917
  readLockMetadata: () => readLockMetadata,
@@ -65579,6 +65923,7 @@ __export(exports_src, {
65579
65923
  parseFeature: () => parseFeature,
65580
65924
  parseExistingAcTags: () => parseExistingAcTags,
65581
65925
  parseChecklist: () => parseChecklist,
65926
+ pairingSummary: () => pairingSummary,
65582
65927
  objectiveEscalationTriggerSchema: () => objectiveEscalationTriggerSchema,
65583
65928
  normalizeTitle: () => normalizeTitle,
65584
65929
  normalizeTaskStatusSafe: () => normalizeTaskStatusSafe,
@@ -65719,6 +66064,7 @@ __export(exports_src, {
65719
66064
  MarkdownDocument: () => MarkdownDocument,
65720
66065
  MUTATION_CLASSES: () => MUTATION_CLASSES,
65721
66066
  MODEL_PRICING: () => MODEL_PRICING,
66067
+ MIN_PAIRING_DISPATCHES: () => MIN_PAIRING_DISPATCHES,
65722
66068
  LEGACY_CAPABLE_ALIAS: () => LEGACY_CAPABLE_ALIAS,
65723
66069
  InlineContext: () => InlineContext,
65724
66070
  InboxRecentDao: () => InboxRecentDao,
@@ -71903,7 +72249,19 @@ class HistoryService {
71903
72249
  const watermarks = await sessionWatermarks(db2, selector);
71904
72250
  const wm = buildWatermarkFilter(watermarks);
71905
72251
  const queryOpts = wm.sql === "" ? undefined : { watermark: wm };
71906
- const [mRows, tRows, toolRows, sessionRows, loopRows, driftRows, sourceRows, spanRows, toolDurRows, todoRows] = await Promise.all([
72252
+ const [
72253
+ mRows,
72254
+ tRows,
72255
+ toolRows,
72256
+ sessionRows,
72257
+ loopRows,
72258
+ driftRows,
72259
+ sourceRows,
72260
+ spanRows,
72261
+ toolDurRows,
72262
+ todoRows,
72263
+ pairings
72264
+ ] = await Promise.all([
71907
72265
  messageRollup(db2, selector, queryOpts),
71908
72266
  toolRollup(db2, selector, queryOpts),
71909
72267
  byTool(db2, selector, top, queryOpts),
@@ -71913,7 +72271,8 @@ class HistoryService {
71913
72271
  sourceSummary(db2, selector),
71914
72272
  sessionSpans(db2, selector, queryOpts),
71915
72273
  sessionToolDurations(db2, selector, queryOpts),
71916
- todoToolCalls(db2, selector, undefined, queryOpts)
72274
+ todoToolCalls(db2, selector, undefined, queryOpts),
72275
+ pairingSummary(db2, { since: selector.since ?? undefined, until: selector.until ?? undefined })
71917
72276
  ]);
71918
72277
  const totals = foldTotals2(mRows, tRows);
71919
72278
  const bySource = foldGrouped(mRows, tRows, (m) => m.source, (t) => t.source);
@@ -71925,6 +72284,7 @@ class HistoryService {
71925
72284
  const stateByKey = new Map;
71926
72285
  for (const w of watermarks)
71927
72286
  stateByKey.set(`${w.sessionId}\x00${w.source}`, w.state);
72287
+ const ladderSnapshot = buildLadderSnapshot(this.ctx.agentConfig);
71928
72288
  const artifact = {
71929
72289
  schemaVersion: HISTORY_ARTIFACT_SCHEMA_VERSION,
71930
72290
  generatedAt: new Date().toISOString(),
@@ -71964,6 +72324,8 @@ class HistoryService {
71964
72324
  ...derivedWarnings(derived),
71965
72325
  ...opts.extraWarnings ?? []
71966
72326
  ],
72327
+ pairings,
72328
+ ladderSnapshot,
71967
72329
  derived
71968
72330
  };
71969
72331
  if (opts.out !== undefined || opts.cwd !== undefined) {
@@ -72227,6 +72589,16 @@ function buildWarnings(driftRows, coverage) {
72227
72589
  }
72228
72590
  return warnings;
72229
72591
  }
72592
+ function buildLadderSnapshot(agentConfig) {
72593
+ const executors = agentConfig?.executors;
72594
+ if (executors === undefined || executors.length === 0)
72595
+ return [];
72596
+ return executors.map((executor, order) => ({
72597
+ name: executor.name,
72598
+ tier: getExecutorTier(executor),
72599
+ order
72600
+ }));
72601
+ }
72230
72602
  function writeArtifact(artifact, opts) {
72231
72603
  const { artifactPath, sidecarPath } = resolveArtifactPaths(artifact, opts);
72232
72604
  const { bounded: bounded2, overflow } = boundCoverage(artifact.coverage);
@@ -72368,6 +72740,7 @@ var SOURCES, FULL_FIDELITY_SOURCES, UNSUPPORTED_SOURCES, MODES, MAX_ERROR_SAMPLE
72368
72740
  var init_history_service = __esm(() => {
72369
72741
  init_src2();
72370
72742
  init_dist12();
72743
+ init_agent_service();
72371
72744
  SOURCES = [
72372
72745
  "pi",
72373
72746
  "claude",
@@ -72434,7 +72807,10 @@ async function enqueueHistoryRefresh(db2, options) {
72434
72807
  }
72435
72808
  async function handleHistoryRefreshJob(deps, payload) {
72436
72809
  const job = parsePayload(payload);
72437
- const svc = deps.service ?? new HistoryService({ getDb: deps.getDb });
72810
+ const svc = deps.service ?? new HistoryService({
72811
+ getDb: deps.getDb,
72812
+ ...deps.agentConfig !== undefined ? { agentConfig: deps.agentConfig } : {}
72813
+ });
72438
72814
  const startMs = Date.now();
72439
72815
  let result;
72440
72816
  try {
@@ -75207,6 +75583,57 @@ var init_task_scaffold = __esm(() => {
75207
75583
  init_task_locator();
75208
75584
  });
75209
75585
 
75586
+ // ../../packages/app/src/services/task-size-precheck.ts
75587
+ function isBelowCapable(tier) {
75588
+ return TIER_RANK[tier ?? "standard"] < TIER_RANK["capable-1"];
75589
+ }
75590
+ function countRItems(content) {
75591
+ const matches = content.match(new RegExp(R_ITEM_RE.source, "gm"));
75592
+ return matches?.length ?? 0;
75593
+ }
75594
+ function countPlanItems(content) {
75595
+ const planMatch = content.match(/^#{2,3}\s+Plan\s*$/m);
75596
+ if (!planMatch)
75597
+ return 0;
75598
+ const planStart = (planMatch.index ?? 0) + planMatch[0].length;
75599
+ const rest = content.slice(planStart);
75600
+ const nextSection = rest.match(/^#{2,3}\s+/m);
75601
+ const planBody = nextSection ? rest.slice(0, nextSection.index ?? 0) : rest;
75602
+ const matches = planBody.match(new RegExp(CHECKLIST_ITEM_RE.source, "gm"));
75603
+ return matches?.length ?? 0;
75604
+ }
75605
+ function evaluateTaskSize(content, limits = DEFAULT_TASK_SIZE_LIMITS, executor) {
75606
+ const reqCount = countRItems(content);
75607
+ const planItemCount = countPlanItems(content);
75608
+ const reasons = [];
75609
+ if (executor !== undefined && isBelowCapable(executor.tier) && (reqCount > LARGE_TASK_THRESHOLDS.maxReqs || planItemCount > LARGE_TASK_THRESHOLDS.maxPlanItems)) {
75610
+ reasons.push(`Task size (${reqCount} R-items / ${planItemCount} Plan items) requires a capable executor, ` + `but ${executor.name} is tier ${executor.tier ?? "standard"}. ` + `Pass \`--agent <capable>\` or \`--vars '{"implementAgent":"<capable>"}'\`, or split the task.`);
75611
+ }
75612
+ if (reqCount > limits.maxReqs) {
75613
+ reasons.push(`Task has ${reqCount} R-items (max ${limits.maxReqs}). ` + `Consider decomposing into smaller tasks or raise maxImplementReqs via --vars.`);
75614
+ }
75615
+ if (planItemCount > limits.maxPlanItems) {
75616
+ reasons.push(`Task has ${planItemCount} Plan items (max ${limits.maxPlanItems}). ` + `Consider simplifying the plan or raise maxImplementPlanItems via --vars.`);
75617
+ }
75618
+ return {
75619
+ reqCount,
75620
+ planItemCount,
75621
+ ok: reasons.length === 0,
75622
+ reasons
75623
+ };
75624
+ }
75625
+ var DEFAULT_TASK_SIZE_LIMITS, LARGE_TASK_THRESHOLDS, R_ITEM_RE, CHECKLIST_ITEM_RE;
75626
+ var init_task_size_precheck = __esm(() => {
75627
+ init_src2();
75628
+ DEFAULT_TASK_SIZE_LIMITS = {
75629
+ maxReqs: 5,
75630
+ maxPlanItems: 8
75631
+ };
75632
+ LARGE_TASK_THRESHOLDS = DEFAULT_TASK_SIZE_LIMITS;
75633
+ R_ITEM_RE = /^\s*-\s*\[[ xX]\]\s*(\*\*)?R\d+\./m;
75634
+ CHECKLIST_ITEM_RE = /^\s*-\s*\[[ xX]\]/m;
75635
+ });
75636
+
75210
75637
  // ../../packages/app/src/services/task-service.ts
75211
75638
  import { dirname as dirname16, isAbsolute as isAbsolute4, join as join15, relative as relative4 } from "path";
75212
75639
  function patchFrontmatterField(rendered, key2, value) {
@@ -75697,6 +76124,15 @@ class TaskService {
75697
76124
  };
75698
76125
  }
75699
76126
  }
76127
+ if (sectionName === "Requirements" || sectionName === "Plan") {
76128
+ const report = evaluateTaskSize(await this.ctx.fs.readFile(filePath));
76129
+ if (!report.ok) {
76130
+ return {
76131
+ ...result,
76132
+ warnings: [...result.warnings ?? [], ...report.reasons]
76133
+ };
76134
+ }
76135
+ }
75700
76136
  return result;
75701
76137
  }
75702
76138
  async checkAcSubsetWarning(taskFilePath, acBody) {
@@ -76152,6 +76588,7 @@ var init_task_service = __esm(() => {
76152
76588
  init_task_check();
76153
76589
  init_task_locator();
76154
76590
  init_task_record();
76591
+ init_task_size_precheck();
76155
76592
  DependencyMutationError = class DependencyMutationError extends Error {
76156
76593
  code;
76157
76594
  constructor(code, message) {
@@ -76342,8 +76779,7 @@ function normalizeAcceptanceCriteriaStatus(raw) {
76342
76779
  return "N/A";
76343
76780
  return null;
76344
76781
  }
76345
- function normalizeEvidenceType(raw) {
76346
- const normalized = raw.toLowerCase().trim();
76782
+ function normalizeEvidenceTypeToken(normalized) {
76347
76783
  if (normalized === "test")
76348
76784
  return "test";
76349
76785
  if (normalized === "command")
@@ -76359,6 +76795,17 @@ function normalizeEvidenceType(raw) {
76359
76795
  return "n/a";
76360
76796
  return null;
76361
76797
  }
76798
+ function normalizeEvidenceType(raw) {
76799
+ const normalized = raw.toLowerCase().trim();
76800
+ const single = normalizeEvidenceTypeToken(normalized);
76801
+ if (single !== null)
76802
+ return single;
76803
+ const tokens = normalized.split(/[+,/]/).map((part) => normalizeEvidenceTypeToken(part.trim())).filter((token) => token !== null);
76804
+ if (tokens.length < 2 || tokens.length !== normalized.split(/[+,/]/).filter((p) => p.trim()).length) {
76805
+ return null;
76806
+ }
76807
+ return EVIDENCE_TYPE_PRECEDENCE.find((candidate) => tokens.includes(candidate)) ?? null;
76808
+ }
76362
76809
  function applyAcceptanceCriteriaEvidenceRule(rows) {
76363
76810
  return rows.map((row) => {
76364
76811
  if (row.status === "MET" && requiresExecutableEvidence(row.id) && row.evidenceType !== "test" && row.evidenceType !== "command") {
@@ -76454,8 +76901,9 @@ function aggregateBatchVerdicts(results) {
76454
76901
  const summary = `${counts.PASS} PASS, ${counts.PARTIAL} PARTIAL, ${counts.FAIL} FAIL, ${notStarted.length} NOT-STARTED (excluded)`;
76455
76902
  return { verdict, rolledUp, notStarted, summary };
76456
76903
  }
76457
- var NOT_STARTED_STATUSES;
76904
+ var EVIDENCE_TYPE_PRECEDENCE, NOT_STARTED_STATUSES;
76458
76905
  var init_task_verdict = __esm(() => {
76906
+ EVIDENCE_TYPE_PRECEDENCE = ["test", "command", "static-ref", "manual-review", "llm-judge", "n/a"];
76459
76907
  NOT_STARTED_STATUSES = {
76460
76908
  backlog: true,
76461
76909
  todo: true,
@@ -76765,7 +77213,7 @@ class TeamService {
76765
77213
  }
76766
77214
  const roleTier = this.ctx.roles?.get(role)?.tier;
76767
77215
  if (roleTier === undefined) {
76768
- throw new Error(`Team "${teamId}" member at index ${index2} declares role "${role}" but no Layer-1 role table is available \u2014 run spur team up from the CLI (roles.md not resolved)`);
77216
+ throw new Error(`Team "${teamId}" member at index ${index2} declares role "${role}" but no Layer-1 role table is available \u2014 run spur team up from the CLI (the role table is threaded only at the CLI boundary)`);
76769
77217
  }
76770
77218
  const eligible = cheapestEligibleExecutors(agentConfig?.executors ?? [], roleTier);
76771
77219
  const winner = eligible[0];
@@ -80160,19 +80608,19 @@ var {
80160
80608
  init_src();
80161
80609
  init_loader();
80162
80610
 
80163
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/application-node.js
80611
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/application-node.js
80164
80612
  init_dist4();
80165
80613
  init_dist5();
80166
80614
  import { appendFileSync as appendFileSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "fs";
80167
80615
  import { dirname as dirname5 } from "path";
80168
80616
 
80169
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/application/index.js
80617
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/application/index.js
80170
80618
  init_default_observers();
80171
80619
  init_event_bus();
80172
80620
  init_file_observer();
80173
80621
  init_logger3();
80174
80622
 
80175
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
80623
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/scheduler/noop.js
80176
80624
  class NoopSchedulerAdapter {
80177
80625
  constructor() {}
80178
80626
  register(_cron, _action) {}
@@ -80180,7 +80628,7 @@ class NoopSchedulerAdapter {
80180
80628
  async stop() {}
80181
80629
  }
80182
80630
 
80183
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
80631
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/scheduler/factory.js
80184
80632
  function initScheduler(adapter, cronEntries) {
80185
80633
  const resolved = adapter ?? new NoopSchedulerAdapter;
80186
80634
  if (cronEntries) {
@@ -80191,7 +80639,7 @@ function initScheduler(adapter, cronEntries) {
80191
80639
  return resolved;
80192
80640
  }
80193
80641
 
80194
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
80642
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/application/plugins/builtins.js
80195
80643
  init_logger3();
80196
80644
  init_metrics();
80197
80645
  init_sdk();
@@ -80284,7 +80732,7 @@ function dbPlugin(db2) {
80284
80732
  };
80285
80733
  }
80286
80734
 
80287
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
80735
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/application/plugins/host.js
80288
80736
  init_logger3();
80289
80737
 
80290
80738
  class PluginHost {
@@ -80372,7 +80820,7 @@ class PluginHost {
80372
80820
  }
80373
80821
  }
80374
80822
 
80375
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/application/index.js
80823
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/application/index.js
80376
80824
  async function performShutdown(state, reason) {
80377
80825
  if (state.stopped)
80378
80826
  return;
@@ -80483,10 +80931,10 @@ async function runApplication(options) {
80483
80931
  }
80484
80932
  }
80485
80933
 
80486
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/application-node.js
80934
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/application-node.js
80487
80935
  init_scheduler_node();
80488
80936
 
80489
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
80937
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
80490
80938
  var import_api14 = __toESM(require_src(), 1);
80491
80939
 
80492
80940
  // ../../node_modules/.bun/@opentelemetry+exporter-metrics-otlp-http@0.218.0+e40b0dfdd726a224/node_modules/@opentelemetry/exporter-metrics-otlp-http/build/esm/OTLPMetricExporterBase.js
@@ -83502,7 +83950,7 @@ class OTLPTraceExporter extends import_otlp_exporter_base2.OTLPExporterBase {
83502
83950
  }), JsonTraceSerializer));
83503
83951
  }
83504
83952
  }
83505
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
83953
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/telemetry/otel-node.js
83506
83954
  var import_resources2 = __toESM(require_src4(), 1);
83507
83955
  var import_sdk_trace_node = __toESM(require_src8(), 1);
83508
83956
  var import_semantic_conventions = __toESM(require_src2(), 1);
@@ -83553,7 +84001,7 @@ async function shutdownNodeTelemetry() {
83553
84001
  await Promise.all(pending);
83554
84002
  }
83555
84003
 
83556
- // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.32+44f400c8972d19fb/node_modules/@gobing-ai/ts-infra/dist/application-node.js
84004
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.35+035a5168ae3a2c26/node_modules/@gobing-ai/ts-infra/dist/application-node.js
83557
84005
  class ConfigValidationError extends Error {
83558
84006
  constructor(message) {
83559
84007
  super(message);
@@ -87472,13 +87920,13 @@ function validateAgentSelector(flags, context6) {
87472
87920
  return null;
87473
87921
  if (raw === "inline")
87474
87922
  return AGENT_INLINE_HEADLESS_MESSAGE;
87475
- if (context6.agentRoles?.has(raw) === true)
87923
+ if (context6.agentRoles.has(raw))
87476
87924
  return null;
87477
87925
  if ((context6.agentConfig?.executors ?? []).some((e) => e.name === raw))
87478
87926
  return null;
87479
87927
  if (isAgentName(raw))
87480
87928
  return null;
87481
- const roleList = context6.agentRoles !== undefined ? [...context6.agentRoles.keys()].join(", ") : "scribe, coder, reviewer, planner";
87929
+ const roleList = [...context6.agentRoles.keys()].join(", ");
87482
87930
  const executors = (context6.agentConfig?.executors ?? []).map((e) => e.name);
87483
87931
  const executorList = executors.length > 0 ? executors.join(", ") : "(none configured)";
87484
87932
  return `Unknown agent: '${raw}'. Accepted: role (${roleList}), configured executor (${executorList}), or 'auto'.`;
@@ -88314,7 +88762,7 @@ import { createRequire } from "module";
88314
88762
  var CLI_CONFIG = {
88315
88763
  binaryName: "spur",
88316
88764
  binaryLabel: "spur",
88317
- binaryVersion: "0.3.48",
88765
+ binaryVersion: "0.3.49",
88318
88766
  configDir: ".spur",
88319
88767
  configFile: ".spur/config.yaml",
88320
88768
  databaseFile: ".spur/spur.db"
@@ -88340,6 +88788,7 @@ importer: @gobing-ai/ts-llm-jsonl-importer@${provenance.importer}`;
88340
88788
  }
88341
88789
  function registerHistoryCommand(program2, context6) {
88342
88790
  const noun = program2.command("history").summary("import and analyze coding-agent history");
88791
+ const makeService2 = () => new HistoryService({ getDb: () => context6.getDb(), agentConfig: context6.agentConfig });
88343
88792
  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) => {
88344
88793
  const source = options.source ?? "all";
88345
88794
  if (options.file && source === "all") {
@@ -88365,7 +88814,7 @@ function registerHistoryCommand(program2, context6) {
88365
88814
  context6.setExitCode(1);
88366
88815
  return;
88367
88816
  }
88368
- const svc = new HistoryService({ getDb: () => context6.getDb() });
88817
+ const svc = makeService2();
88369
88818
  const fanOut = await svc.importAll({
88370
88819
  sources: source === "all" ? undefined : [source],
88371
88820
  file: options.file || undefined,
@@ -88380,7 +88829,7 @@ ${formatFanOutResult(fanOut)}`);
88380
88829
  context6.setExitCode(fanOut.exitCode);
88381
88830
  });
88382
88831
  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) => {
88383
- const svc = new HistoryService({ getDb: () => context6.getDb() });
88832
+ const svc = makeService2();
88384
88833
  const source = options.source ?? "all";
88385
88834
  const selector = {
88386
88835
  since: options.since || null,
@@ -88439,7 +88888,7 @@ ${formatFanOutResult(fanOut)}`);
88439
88888
  }
88440
88889
  });
88441
88890
  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").option("--mode <name>", "Render the artifact as a .md sidecar in this mode after analyze (e.g. forensics)").action(async (options) => {
88442
- const svc = new HistoryService({ getDb: () => context6.getDb() });
88891
+ const svc = makeService2();
88443
88892
  const sourceTimeout = Number.parseInt(options.sourceTimeout ?? "600000", 10) || 600000;
88444
88893
  const bus = new EventBus;
88445
88894
  const ledger = await attachSystemEventLedger(bus, context6);
@@ -88605,6 +89054,7 @@ var SCAFFOLD_MANIFEST = [
88605
89054
  { source: "workflows/planning-pipeline.yaml", target: "workflows/planning-pipeline.yaml" },
88606
89055
  { source: "workflows/idea-pipeline.yaml", target: "workflows/idea-pipeline.yaml" },
88607
89056
  { source: "workflows/wrapup-pipeline.yaml", target: "workflows/wrapup-pipeline.yaml" },
89057
+ { source: "workflows/pr-review.yaml", target: "workflows/pr-review.yaml" },
88608
89058
  { source: "tasks/section-matrix.yaml", target: "tasks/section-matrix.yaml" },
88609
89059
  { source: "templates/task/standard.md", target: "tasks/templates/standard.md" },
88610
89060
  { source: "templates/task/feature-impl.md", target: "tasks/templates/feature-impl.md" },
@@ -99037,8 +99487,8 @@ async function startServer(options, deps = defaultDeps) {
99037
99487
  bootConfig
99038
99488
  });
99039
99489
  let jobWorker;
99040
- const autostartConfig = await loadSpurConfig(process.cwd()).catch(() => null);
99041
- const autostartIds = resolveAutostartSet(autostartConfig, env.SPUR_TEAM_AUTOSTART);
99490
+ const spurConfig = await loadSpurConfig(process.cwd()).catch(() => null);
99491
+ const autostartIds = resolveAutostartSet(spurConfig, env.SPUR_TEAM_AUTOSTART);
99042
99492
  if (autostartIds.length > 0) {
99043
99493
  try {
99044
99494
  const supervisor = ctx.supervisor();
@@ -99081,6 +99531,7 @@ async function startServer(options, deps = defaultDeps) {
99081
99531
  registry2.register(HISTORY_REFRESH_JOB, (payload) => handleHistoryRefreshJob({
99082
99532
  getDb: () => ctx.getDb(),
99083
99533
  cwd: ctx.cwd,
99534
+ ...spurConfig?.agent !== undefined ? { agentConfig: spurConfig.agent } : {},
99084
99535
  bus: ctx.eventBus()
99085
99536
  }, payload));
99086
99537
  jobWorker = new JobWorkerService({
@@ -99531,6 +99982,26 @@ var spur_config_schema_default = {
99531
99982
  }
99532
99983
  }
99533
99984
  },
99985
+ roles: {
99986
+ type: "object",
99987
+ description: "Per-role tier/stage overrides over DEFAULT_AGENT_ROLES (0572 / ADR-061). Keys are the closed role vocabulary (scribe, coder, reviewer, planner); a present field replaces the default for that role, an omitted field keeps it. Mirrors @gobing-ai/spur-config AgentRoleConfigSchema (Zod is SSOT).",
99988
+ additionalProperties: {
99989
+ type: "object",
99990
+ properties: {
99991
+ tier: {
99992
+ type: "string",
99993
+ enum: ["cheap", "standard", "capable-1", "capable-2", "capable-3"],
99994
+ description: "Replacement capability tier for the role. Must not sit below the highest min_tier among the role's folded stages (enforced at the CLI boundary)."
99995
+ },
99996
+ stages: {
99997
+ type: "array",
99998
+ minItems: 1,
99999
+ items: { type: "string", minLength: 1 },
100000
+ description: "Replacement folded-stage list for the role. Ids must come from the canonical stage registry (validated at the CLI boundary). Omit the field to keep the default \u2014 an empty array is rejected."
100001
+ }
100002
+ }
100003
+ }
100004
+ },
99534
100005
  team: {
99535
100006
  type: "object",
99536
100007
  description: "Declarative agent teams keyed by team id (the map key is the teamId). Each team materializes a roster of agent specs (feature M). Mirrors @gobing-ai/spur-config TeamConfigSchema (Zod is SSOT).",
@@ -103461,54 +103932,43 @@ class DefaultHitlResponder {
103461
103932
  }
103462
103933
 
103463
103934
  // src/context.ts
103464
- var fs3 = createNodeFileSystem3();
103465
- var cachedRolesFile;
103466
- function bundledRolesFile() {
103467
- if (cachedRolesFile !== undefined)
103468
- return cachedRolesFile;
103469
- let dir = import.meta.dir;
103470
- while (true) {
103471
- const candidate = join31(dir, "plugins", "sp", "references", "roles.md");
103472
- if (fs3.exists(candidate)) {
103473
- cachedRolesFile = candidate;
103474
- return cachedRolesFile;
103935
+ function resolveAgentRoles(agentConfig) {
103936
+ const overrides = agentConfig?.roles;
103937
+ if (overrides === undefined)
103938
+ return new Map(DEFAULT_AGENT_ROLES);
103939
+ const resolved = new Map;
103940
+ for (const [role, spec] of DEFAULT_AGENT_ROLES) {
103941
+ const override = overrides[role];
103942
+ if (override?.stages !== undefined) {
103943
+ const unknown2 = override.stages.filter((id) => getCanonicalStage(id) === undefined);
103944
+ if (override.stages.length === 0 || unknown2.length > 0) {
103945
+ const detail = unknown2.length > 0 ? `unknown stage id(s): ${unknown2.join(", ")}` : "empty stages array (omit the field to keep the default)";
103946
+ throw new Error(`Invalid agent.roles.${role}.stages \u2014 ${detail}. Stage ids must come from the canonical stage registry.`);
103947
+ }
103948
+ }
103949
+ const tier = override?.tier ?? spec.tier;
103950
+ const stages = override?.stages ?? spec.stages;
103951
+ let floorStage;
103952
+ for (const id of stages) {
103953
+ const record2 = getCanonicalStage(id);
103954
+ if (record2 === undefined)
103955
+ continue;
103956
+ if (floorStage === undefined || TIER_RANK[record2.model_policy.min_tier] > TIER_RANK[floorStage.minTier]) {
103957
+ floorStage = { id, minTier: record2.model_policy.min_tier };
103958
+ }
103475
103959
  }
103476
- const parent = dirname22(dir);
103477
- if (parent === dir)
103478
- break;
103479
- dir = parent;
103480
- }
103481
- cachedRolesFile = null;
103482
- return cachedRolesFile;
103483
- }
103484
- function parseAgentRoles(source) {
103485
- const block2 = source.match(/```yaml\n([\s\S]*?)\n```/)?.[1] ?? source;
103486
- const roles = new Map;
103487
- for (const m2 of block2.matchAll(/- id: (\w+)\s*\n\s*tier: ([\w-]+)(?:[\s\S]*?\n\s*stages: \[([^\]]*)\])?/g)) {
103488
- const id = m2[1];
103489
- const tier = m2[2];
103490
- if (id === undefined || tier === undefined)
103491
- continue;
103492
- const stages = (m2[3] ?? "").split(",").map((s2) => s2.trim()).filter((s2) => s2.length > 0);
103493
- roles.set(id, { tier, stages });
103494
- }
103495
- return roles;
103496
- }
103497
- function loadAgentRoles() {
103498
- const file2 = bundledRolesFile();
103499
- if (file2 === null)
103500
- return;
103501
- try {
103502
- return parseAgentRoles(fs3.readFile(file2));
103503
- } catch {
103504
- return;
103960
+ if (floorStage !== undefined && TIER_RANK[tier] < TIER_RANK[floorStage.minTier]) {
103961
+ throw new Error(`Invalid agent.roles.${role} \u2014 tier '${tier}' sits below the role's stage floor: ` + `stage '${floorStage.id}' requires min_tier '${floorStage.minTier}'. ` + `A role-only dispatch may never start cheaper than its stage floor (roles R4 / ADR-061).`);
103962
+ }
103963
+ resolved.set(role, { tier, stages });
103505
103964
  }
103965
+ return resolved;
103506
103966
  }
103507
103967
  function createCliContext(options) {
103508
103968
  const cwd = resolve14(options.cwd ?? process.cwd());
103509
103969
  const env = options.env ?? process.env;
103510
- const fs4 = createNodeFileSystem3(cwd);
103511
- const agentRoles = options.agentRoles ?? loadAgentRoles();
103970
+ const fs3 = createNodeFileSystem3(cwd);
103971
+ const agentRoles = options.agentRoles ?? resolveAgentRoles(options.agentConfig);
103512
103972
  let dbPromise;
103513
103973
  if (options.db) {
103514
103974
  dbPromise = Promise.resolve(options.db);
@@ -103520,23 +103980,23 @@ function createCliContext(options) {
103520
103980
  return {
103521
103981
  cwd,
103522
103982
  env,
103523
- fs: fs4,
103983
+ fs: fs3,
103524
103984
  setExitCode: options.setExitCode ?? noopSetExitCode,
103525
103985
  output: options.output,
103526
103986
  getDb,
103527
103987
  ...options.agentConfig !== undefined ? { agentConfig: options.agentConfig } : {},
103528
- ...agentRoles !== undefined ? { agentRoles } : {},
103988
+ agentRoles,
103529
103989
  agentService: (serviceOptions) => new AgentService({
103530
103990
  cwd,
103531
103991
  env,
103532
103992
  output: options.output,
103533
103993
  agentConfig: options.agentConfig,
103534
- ...agentRoles !== undefined ? { roles: agentRoles } : {},
103994
+ roles: agentRoles,
103535
103995
  getDb,
103536
103996
  ...serviceOptions?.events !== undefined ? { events: serviceOptions.events } : {},
103537
103997
  ...serviceOptions?.processRegistry !== undefined ? { processRegistry: serviceOptions.processRegistry } : {}
103538
103998
  }),
103539
- ruleService: () => new RuleService({ cwd, env, fs: fs4, output: options.output, getDb }),
103999
+ ruleService: () => new RuleService({ cwd, env, fs: fs3, output: options.output, getDb }),
103540
104000
  hitlResponder: (json3) => {
103541
104001
  if (isatty6(1) && json3 !== true)
103542
104002
  return new ClackHitlResponder;