@wrongstack/core 0.73.1 → 0.82.6

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 (79) hide show
  1. package/dist/{agent-bridge-C0Ze7Ldm.d.ts → agent-bridge-C9P_HPez.d.ts} +2 -2
  2. package/dist/{agent-subagent-runner-BmITbs1Q.d.ts → agent-subagent-runner-2Aq0jOSj.d.ts} +107 -102
  3. package/dist/{compactor-D_ExJajC.d.ts → compactor-CJq7LQev.d.ts} +3 -3
  4. package/dist/{config-Dy0CK_o6.d.ts → config-_DZ7dN-T.d.ts} +77 -75
  5. package/dist/{context-y87Jc5ei.d.ts → context-ToHAp4-U.d.ts} +119 -90
  6. package/dist/coordination/index.d.ts +16 -16
  7. package/dist/coordination/index.js +382 -43
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/defaults/index.d.ts +31 -31
  10. package/dist/defaults/index.js +524 -110
  11. package/dist/defaults/index.js.map +1 -1
  12. package/dist/{director-state-BmYi3DGA.d.ts → director-state-CgIc30qi.d.ts} +19 -19
  13. package/dist/{events-BBAlxBuw.d.ts → events-DnRqXaZ3.d.ts} +77 -39
  14. package/dist/execution/index.d.ts +53 -53
  15. package/dist/execution/index.js +67 -23
  16. package/dist/execution/index.js.map +1 -1
  17. package/dist/extension/index.d.ts +9 -9
  18. package/dist/extension/index.js +8 -1
  19. package/dist/extension/index.js.map +1 -1
  20. package/dist/{goal-store-C7jcumEh.d.ts → goal-store-DvWLNu52.d.ts} +4 -4
  21. package/dist/{index-yQbZ2NQx.d.ts → index-BNOLadHw.d.ts} +28 -28
  22. package/dist/{index-BN6i2Nfg.d.ts → index-N0_c4bHQ.d.ts} +45 -45
  23. package/dist/index.d.ts +233 -160
  24. package/dist/index.js +825 -160
  25. package/dist/index.js.map +1 -1
  26. package/dist/infrastructure/index.d.ts +9 -9
  27. package/dist/infrastructure/index.js +29 -7
  28. package/dist/infrastructure/index.js.map +1 -1
  29. package/dist/kernel/index.d.ts +14 -14
  30. package/dist/kernel/index.js +7 -0
  31. package/dist/kernel/index.js.map +1 -1
  32. package/dist/logger-B72yyPc6.d.ts +12 -0
  33. package/dist/{logger-bOzkF5LL.d.ts → logger-C_27pj9i.d.ts} +12 -4
  34. package/dist/{mcp-servers-T0O6UN_w.d.ts → mcp-servers-Dck3T85_.d.ts} +20 -20
  35. package/dist/{mode-BO4SEUIv.d.ts → mode-CHo2XtHs.d.ts} +4 -4
  36. package/dist/models/index.d.ts +10 -10
  37. package/dist/models/index.js +8 -2
  38. package/dist/models/index.js.map +1 -1
  39. package/dist/{models-registry-BcYJDKLm.d.ts → models-registry-Be3osGt5.d.ts} +28 -28
  40. package/dist/{models-registry-Cuq1C8V9.d.ts → models-registry-Boz639EI.d.ts} +12 -12
  41. package/dist/{multi-agent-coordinator-BSBbZt0e.d.ts → multi-agent-coordinator-DllpCVkF.d.ts} +12 -12
  42. package/dist/{null-fleet-bus-BCIRT_nV.d.ts → null-fleet-bus-BY0AN-sr.d.ts} +129 -120
  43. package/dist/observability/index.d.ts +41 -41
  44. package/dist/observability/index.js.map +1 -1
  45. package/dist/{observability-BhnVLBLS.d.ts → observability-CoSNZdhX.d.ts} +4 -4
  46. package/dist/{parallel-eternal-engine-CjAYGaCw.d.ts → parallel-eternal-engine-D402RASp.d.ts} +49 -49
  47. package/dist/{path-resolver-BnqXa9Ze.d.ts → path-resolver-UPFTsDyD.d.ts} +6 -6
  48. package/dist/{permission-V5BLOrY6.d.ts → permission-14CChMmO.d.ts} +10 -8
  49. package/dist/{permission-policy-CBVx-d-8.d.ts → permission-policy-gW5htOo1.d.ts} +7 -7
  50. package/dist/{plan-templates-DBgrTGPu.d.ts → plan-templates-DRvPgkfZ.d.ts} +70 -32
  51. package/dist/{provider-runner-n3KkHT_w.d.ts → provider-runner-COAJM8tC.d.ts} +6 -6
  52. package/dist/{retry-policy-CG3qvH_e.d.ts → retry-policy-DSu6O6rD.d.ts} +4 -4
  53. package/dist/sdd/index.d.ts +47 -47
  54. package/dist/sdd/index.js +47 -22
  55. package/dist/sdd/index.js.map +1 -1
  56. package/dist/security/index.d.ts +6 -6
  57. package/dist/security/index.js +7 -1
  58. package/dist/security/index.js.map +1 -1
  59. package/dist/{selector-RvBR_YRW.d.ts → selector-11-fm95U.d.ts} +2 -2
  60. package/dist/{session-event-bridge-CDHxcmQU.d.ts → session-event-bridge-D0u-x576.d.ts} +7 -7
  61. package/dist/{session-reader-BIpwM60D.d.ts → session-reader-BQU-toaN.d.ts} +23 -23
  62. package/dist/{skill-CxuWrsKK.d.ts → skill-BJeF2DwY.d.ts} +1 -1
  63. package/dist/skills/index.d.ts +9 -9
  64. package/dist/skills/index.js +15 -3
  65. package/dist/skills/index.js.map +1 -1
  66. package/dist/storage/index.d.ts +15 -15
  67. package/dist/storage/index.js +398 -80
  68. package/dist/storage/index.js.map +1 -1
  69. package/dist/{system-prompt-CA11g6Jo.d.ts → system-prompt-C0rLCeyn.d.ts} +16 -11
  70. package/dist/{task-graph-D1YQbpxF.d.ts → task-graph-CikNdRTG.d.ts} +22 -22
  71. package/dist/types/index.d.ts +25 -25
  72. package/dist/types/index.js +61 -12
  73. package/dist/types/index.js.map +1 -1
  74. package/dist/utils/index.d.ts +46 -45
  75. package/dist/utils/index.js +64 -13
  76. package/dist/utils/index.js.map +1 -1
  77. package/dist/{wstack-paths-eMXnY1_X.d.ts → wstack-paths-BQMvEllz.d.ts} +10 -3
  78. package/package.json +1 -1
  79. package/dist/logger-DDd5C--Z.d.ts +0 -12
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { readFile, readdir, stat, mkdir } from 'fs/promises';
5
5
  import * as path6 from 'path';
6
6
  import { join, extname, relative, isAbsolute, resolve, sep } from 'path';
7
7
  import * as fs2 from 'fs';
8
- import * as os6 from 'os';
8
+ import * as os7 from 'os';
9
9
  import { execFile, spawn } from 'child_process';
10
10
  import { promisify } from 'util';
11
11
  import { EventEmitter } from 'events';
@@ -419,6 +419,13 @@ var Container = class {
419
419
  has(token) {
420
420
  return this.entries.has(token);
421
421
  }
422
+ /**
423
+ * Resolve a token if it is bound, otherwise return undefined.
424
+ * Unlike resolve(), this does not throw if the token is unbound.
425
+ */
426
+ safeResolve(token) {
427
+ return this.has(token) ? this.resolve(token) : void 0;
428
+ }
422
429
  ownerOf(token) {
423
430
  return this.entries.get(token)?.owner;
424
431
  }
@@ -1338,9 +1345,20 @@ function setRawMode(input, mode) {
1338
1345
  input.setRawMode(mode);
1339
1346
  return true;
1340
1347
  }
1348
+ var activeOutputGuard = null;
1349
+ function setOutputLineGuard(guard) {
1350
+ activeOutputGuard = guard;
1351
+ }
1341
1352
  function writeTo(s, stream) {
1342
1353
  if (!stream || typeof stream.write !== "function") return false;
1354
+ const guard = activeOutputGuard;
1355
+ if (!guard) {
1356
+ stream.write(s);
1357
+ return true;
1358
+ }
1359
+ guard.suspend();
1343
1360
  stream.write(s);
1361
+ guard.resume();
1344
1362
  return true;
1345
1363
  }
1346
1364
  function writeOut(s, stream = process.stdout) {
@@ -1404,11 +1422,13 @@ var DefaultLogger = class _DefaultLogger {
1404
1422
  file;
1405
1423
  bindings;
1406
1424
  pretty;
1425
+ stderr;
1407
1426
  constructor(opts = {}) {
1408
1427
  this.level = opts.level ?? process.env.WRONGSTACK_LOG_LEVEL ?? "info";
1409
1428
  this.file = opts.file;
1410
1429
  this.bindings = opts.bindings ?? {};
1411
1430
  this.pretty = opts.pretty ?? true;
1431
+ this.stderr = opts.stderr !== false;
1412
1432
  if (this.file) {
1413
1433
  try {
1414
1434
  fs2.mkdirSync(path6.dirname(this.file), { recursive: true });
@@ -1436,6 +1456,7 @@ var DefaultLogger = class _DefaultLogger {
1436
1456
  level: this.level,
1437
1457
  file: this.file,
1438
1458
  pretty: this.pretty,
1459
+ stderr: this.stderr,
1439
1460
  bindings: { ...this.bindings, ...bindings }
1440
1461
  });
1441
1462
  }
@@ -1455,6 +1476,7 @@ var DefaultLogger = class _DefaultLogger {
1455
1476
  } catch {
1456
1477
  }
1457
1478
  }
1479
+ if (!this.stderr) return;
1458
1480
  if (r <= LEVEL_RANK.warn || this.level === "debug" || this.level === "trace") {
1459
1481
  const head = `${color.dim(ts)} ${COLORS[level](level.toUpperCase().padEnd(5))} ${msg}`;
1460
1482
  if (ctx !== void 0) {
@@ -1511,7 +1533,7 @@ var DefaultTokenCounter = class {
1511
1533
  } else if (this.registry && this.providerId && model) {
1512
1534
  if (this.priceCache.size >= PRICE_CACHE_MAX_SIZE) {
1513
1535
  const keys = [...this.priceCache.keys()];
1514
- this.priceCache.delete(keys[0]);
1536
+ this.priceCache.delete(keys[0] ?? "");
1515
1537
  }
1516
1538
  void this.registry.getModel(this.providerId, model).then((m) => {
1517
1539
  if (m) {
@@ -1536,7 +1558,7 @@ var DefaultTokenCounter = class {
1536
1558
  const price = priceFromModel(resolved);
1537
1559
  if (this.priceCache.size >= PRICE_CACHE_MAX_SIZE) {
1538
1560
  const keys = [...this.priceCache.keys()];
1539
- this.priceCache.delete(keys[0]);
1561
+ this.priceCache.delete(keys[0] ?? "");
1540
1562
  }
1541
1563
  this.priceCache.set(resolved.modelId, price);
1542
1564
  this.applyPrice(usage, price);
@@ -1604,6 +1626,12 @@ function round4(n) {
1604
1626
  }
1605
1627
 
1606
1628
  // src/utils/token-estimate.ts
1629
+ function expectDefined(value) {
1630
+ if (value === null || value === void 0) {
1631
+ throw new Error("Expected value to be defined");
1632
+ }
1633
+ return value;
1634
+ }
1607
1635
  var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
1608
1636
  var _cal = {
1609
1637
  ratio: 1,
@@ -1624,7 +1652,7 @@ function getCachedEstimate(key, compute) {
1624
1652
  if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
1625
1653
  const keys = [...ESTIMATE_CACHE.keys()];
1626
1654
  for (let i = 0; i < Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4); i++) {
1627
- ESTIMATE_CACHE.delete(keys[i]);
1655
+ ESTIMATE_CACHE.delete(expectDefined(keys[i]));
1628
1656
  }
1629
1657
  }
1630
1658
  const estimate = compute();
@@ -1737,6 +1765,12 @@ function resetCalibration() {
1737
1765
  }
1738
1766
 
1739
1767
  // src/utils/message-invariants.ts
1768
+ function expectDefined2(value) {
1769
+ if (value === null || value === void 0) {
1770
+ throw new Error("Expected value to be defined");
1771
+ }
1772
+ return value;
1773
+ }
1740
1774
  function repairToolUseAdjacency(messages) {
1741
1775
  const removedToolUses = [];
1742
1776
  const removedToolResults = [];
@@ -1744,7 +1778,7 @@ function repairToolUseAdjacency(messages) {
1744
1778
  let changed = false;
1745
1779
  const out = [];
1746
1780
  for (let i = 0; i < messages.length; i++) {
1747
- const original = messages[i];
1781
+ const original = expectDefined2(messages[i]);
1748
1782
  let msg = original;
1749
1783
  if (hasToolUse(msg)) {
1750
1784
  const nextIds = toolResultIds(messages[i + 1]);
@@ -2000,7 +2034,11 @@ var PROJECT_MARKERS = [
2000
2034
  "go.mod",
2001
2035
  "Cargo.toml",
2002
2036
  "pyproject.toml",
2003
- ".wrongstack"
2037
+ // Use AGENTS.md, not the bare .wrongstack directory. A bare .wrongstack/
2038
+ // directory can be the global config directory (~/.wrongstack), which is
2039
+ // NOT a project marker. Only .wrongstack/AGENTS.md signals a real
2040
+ // WrongStack project.
2041
+ ".wrongstack/AGENTS.md"
2004
2042
  ];
2005
2043
  var DefaultPathResolver = class {
2006
2044
  projectRoot;
@@ -2012,7 +2050,12 @@ var DefaultPathResolver = class {
2012
2050
  detectProjectRoot(start) {
2013
2051
  let dir = path6.resolve(start);
2014
2052
  const root = path6.parse(dir).root;
2053
+ const home = path6.resolve(os7.homedir());
2054
+ const startPath = path6.resolve(start);
2015
2055
  while (dir !== root) {
2056
+ if (dir === home && dir !== startPath) {
2057
+ break;
2058
+ }
2016
2059
  for (const marker of PROJECT_MARKERS) {
2017
2060
  try {
2018
2061
  fs2.accessSync(path6.join(dir, marker));
@@ -2024,7 +2067,7 @@ var DefaultPathResolver = class {
2024
2067
  if (parent === dir) break;
2025
2068
  dir = parent;
2026
2069
  }
2027
- return path6.resolve(start);
2070
+ return startPath;
2028
2071
  }
2029
2072
  resolve(input) {
2030
2073
  const abs = path6.isAbsolute(input) ? input : path6.resolve(this.cwd, input);
@@ -2893,6 +2936,12 @@ Remember: your job is to make the user a better developer, not just to complete
2893
2936
  ];
2894
2937
 
2895
2938
  // src/types/context-window.ts
2939
+ function expectDefined3(value) {
2940
+ if (value === null || value === void 0) {
2941
+ throw new Error("Expected value to be defined");
2942
+ }
2943
+ return value;
2944
+ }
2896
2945
  var DEFAULT_CONTEXT_WINDOW_MODE_ID = "balanced";
2897
2946
  var CONTEXT_WINDOW_MODES = Object.freeze([
2898
2947
  {
@@ -2949,7 +2998,7 @@ function isContextWindowModeId(id) {
2949
2998
  }
2950
2999
  function resolveContextWindowPolicy(config = {}, overrideMode) {
2951
3000
  const requested = overrideMode ?? config.mode ?? DEFAULT_CONTEXT_WINDOW_MODE_ID;
2952
- const mode = getContextWindowMode(requested) ?? getContextWindowMode(DEFAULT_CONTEXT_WINDOW_MODE_ID);
3001
+ const mode = getContextWindowMode(requested) ?? expectDefined3(getContextWindowMode(DEFAULT_CONTEXT_WINDOW_MODE_ID));
2953
3002
  if (mode.id !== DEFAULT_CONTEXT_WINDOW_MODE_ID) {
2954
3003
  return mode;
2955
3004
  }
@@ -3000,7 +3049,7 @@ var InMemoryBridgeTransport = class {
3000
3049
  }
3001
3050
  subscribe(agentId, handler) {
3002
3051
  if (!this.subs.has(agentId)) this.subs.set(agentId, /* @__PURE__ */ new Set());
3003
- this.subs.get(agentId).add(handler);
3052
+ this.subs.get(agentId)?.add(handler);
3004
3053
  return () => this.subs.get(agentId)?.delete(handler);
3005
3054
  }
3006
3055
  close(agentId) {
@@ -3429,6 +3478,12 @@ function sizeSignals(toolName, content) {
3429
3478
  }
3430
3479
 
3431
3480
  // src/execution/tool-executor.ts
3481
+ function expectDefined4(value) {
3482
+ if (value === null || value === void 0) {
3483
+ throw new Error("Expected value to be defined");
3484
+ }
3485
+ return value;
3486
+ }
3432
3487
  var ToolExecutor = class {
3433
3488
  constructor(registry, opts) {
3434
3489
  this.registry = registry;
@@ -3717,6 +3772,9 @@ ${post.additionalContext}` };
3717
3772
  async runStreamedTool(tool, input, ctx, signal, toolUseId) {
3718
3773
  let finalOutput;
3719
3774
  let sawFinal = false;
3775
+ if (!tool.executeStream) {
3776
+ throw new Error(`Tool "${tool.name}" does not support streaming execution`);
3777
+ }
3720
3778
  const stream = tool.executeStream(input, ctx, { signal });
3721
3779
  for await (const ev of stream) {
3722
3780
  if (ev.type === "final") {
@@ -3821,7 +3879,7 @@ function hasMalformedArguments(input) {
3821
3879
  function extractMalformedRaw(input) {
3822
3880
  if (!hasMalformedArguments(input)) return void 0;
3823
3881
  const obj = input;
3824
- const value = obj[Object.keys(obj)[0]];
3882
+ const value = obj[expectDefined4(Object.keys(obj)[0])];
3825
3883
  if (value === void 0 || value === null) return void 0;
3826
3884
  if (typeof value === "string") return value;
3827
3885
  try {
@@ -3868,6 +3926,12 @@ function compileUserRegex(pattern, flags) {
3868
3926
  }
3869
3927
 
3870
3928
  // src/storage/session-reader.ts
3929
+ function expectDefined5(value) {
3930
+ if (value === null || value === void 0) {
3931
+ throw new Error("Expected value to be defined");
3932
+ }
3933
+ return value;
3934
+ }
3871
3935
  var DefaultSessionReader = class {
3872
3936
  store;
3873
3937
  constructor(opts) {
@@ -3929,7 +3993,7 @@ var DefaultSessionReader = class {
3929
3993
  continue;
3930
3994
  }
3931
3995
  for (let i = 0; i < data.events.length; i++) {
3932
- const ev = data.events[i];
3996
+ const ev = expectDefined5(data.events[i]);
3933
3997
  if (allowedTypes && !allowedTypes.has(ev.type)) continue;
3934
3998
  const text = eventText(ev);
3935
3999
  if (text === null) continue;
@@ -4197,7 +4261,7 @@ function escapeControlCharsInStrings(s) {
4197
4261
  let inString = false;
4198
4262
  let out = "";
4199
4263
  for (let i = 0; i < s.length; i++) {
4200
- const c = s[i];
4264
+ const c = s.charAt(i);
4201
4265
  if (c === '"' && (i === 0 || s[i - 1] !== "\\")) {
4202
4266
  inString = !inString;
4203
4267
  out += c;
@@ -4235,12 +4299,12 @@ function stripSingleLineComments(s) {
4235
4299
  const chars = [];
4236
4300
  let i = 0;
4237
4301
  while (i < s.length) {
4238
- const c = s[i];
4239
- if (c === '"' && (i === 0 || s[i - 1] !== "\\")) {
4302
+ const c = s.charAt(i);
4303
+ if (c === '"' && (i === 0 || s.charAt(i - 1) !== "\\")) {
4240
4304
  inString = !inString;
4241
4305
  chars.push(c);
4242
- } else if (c === "/" && s[i + 1] === "/" && !inString) {
4243
- while (i < s.length && s[i] !== "\n") i++;
4306
+ } else if (c === "/" && s.charAt(i + 1) === "/" && !inString) {
4307
+ while (i < s.length && s.charAt(i) !== "\n") i++;
4244
4308
  } else {
4245
4309
  chars.push(c);
4246
4310
  }
@@ -4297,6 +4361,12 @@ function formatTodosList(todos) {
4297
4361
  }
4298
4362
 
4299
4363
  // src/utils/glob-match.ts
4364
+ function expectDefined6(value) {
4365
+ if (value === null || value === void 0) {
4366
+ throw new Error("Expected value to be defined");
4367
+ }
4368
+ return value;
4369
+ }
4300
4370
  function escapeRegex(s) {
4301
4371
  return s.replace(/[.+^${}()|\\]/g, "\\$&");
4302
4372
  }
@@ -4308,7 +4378,7 @@ function getCachedGlob(pattern) {
4308
4378
  if (COMPILED_GLOB_CACHE.size >= CACHE_MAX_SIZE) {
4309
4379
  const keys = [...COMPILED_GLOB_CACHE.keys()];
4310
4380
  for (let i = 0; i < Math.floor(CACHE_MAX_SIZE / 4); i++) {
4311
- COMPILED_GLOB_CACHE.delete(keys[i]);
4381
+ COMPILED_GLOB_CACHE.delete(expectDefined6(keys[i]));
4312
4382
  }
4313
4383
  }
4314
4384
  const re = compileGlob(pattern);
@@ -4526,11 +4596,20 @@ function unifiedDiff(oldText, newText, opts = {}) {
4526
4596
  function projectHash(absRoot) {
4527
4597
  return createHash("sha256").update(path6.resolve(absRoot)).digest("hex").slice(0, 12);
4528
4598
  }
4599
+ function projectSlug(absRoot) {
4600
+ const base = slugify(path6.basename(absRoot));
4601
+ const hash = createHash("sha256").update(path6.resolve(absRoot)).digest("hex").slice(0, 6);
4602
+ return `${base}-${hash}`;
4603
+ }
4604
+ function slugify(name) {
4605
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
4606
+ }
4529
4607
  function resolveWstackPaths(opts) {
4530
- const home = opts.userHome ?? os6.homedir();
4608
+ const home = opts.userHome ?? os7.homedir();
4531
4609
  const globalRoot = opts.globalRoot ?? path6.join(home, ".wrongstack");
4532
4610
  const hash = projectHash(opts.projectRoot);
4533
- const projectDir = path6.join(globalRoot, "projects", hash);
4611
+ const slug = projectSlug(opts.projectRoot);
4612
+ const projectDir = path6.join(globalRoot, "projects", slug);
4534
4613
  return {
4535
4614
  globalRoot,
4536
4615
  configDir: globalRoot,
@@ -4555,6 +4634,7 @@ function resolveWstackPaths(opts) {
4555
4634
  inProjectSkills: path6.join(opts.projectRoot, ".wrongstack", "skills"),
4556
4635
  inProjectWorktrees: path6.join(opts.projectRoot, ".wrongstack", "worktrees"),
4557
4636
  projectHash: hash,
4637
+ projectSlug: slug,
4558
4638
  projectGoal: path6.join(projectDir, "goal.json"),
4559
4639
  projectSpecs: path6.join(projectDir, "specs"),
4560
4640
  projectTaskGraphs: path6.join(projectDir, "task-graphs"),
@@ -4653,6 +4733,12 @@ function buildChildEnv(optsOrSessionId) {
4653
4733
  if (opts.sessionId) out["WRONGSTACK_SESSION_ID"] = opts.sessionId;
4654
4734
  return out;
4655
4735
  }
4736
+ function expectDefined7(value) {
4737
+ if (value === null || value === void 0) {
4738
+ throw new Error("Expected value to be defined");
4739
+ }
4740
+ return value;
4741
+ }
4656
4742
  var GLOB_CHARS = /* @__PURE__ */ new Set(["*", "?", "["]);
4657
4743
  var IS_WINDOWS = process.platform === "win32";
4658
4744
  var SEP = IS_WINDOWS ? "\\" : "/";
@@ -4666,7 +4752,7 @@ function globToRegex(pat) {
4666
4752
  let i = 0;
4667
4753
  let re = "^";
4668
4754
  while (i < pat.length) {
4669
- const c = pat[i];
4755
+ const c = expectDefined7(pat[i]);
4670
4756
  if (c === "*") {
4671
4757
  if (pat[i + 1] === "*") {
4672
4758
  re += ".*";
@@ -4705,7 +4791,7 @@ function globToRegex(pat) {
4705
4791
  }
4706
4792
  function baseDir(pat) {
4707
4793
  let i = pat.length - 1;
4708
- while (i >= 0 && !GLOB_CHARS.has(pat[i]) && pat[i] !== SEP && pat[i] !== "/") i--;
4794
+ while (i >= 0 && !GLOB_CHARS.has(expectDefined7(pat[i])) && pat[i] !== SEP && pat[i] !== "/") i--;
4709
4795
  const cut = i >= 0 ? pat.lastIndexOf(SEP, i) : pat.lastIndexOf("/", i);
4710
4796
  return cut < 0 ? "." : pat.slice(0, cut);
4711
4797
  }
@@ -4770,6 +4856,12 @@ async function expandGlob(pattern) {
4770
4856
  }
4771
4857
 
4772
4858
  // src/utils/json-repair.ts
4859
+ function expectDefined8(value) {
4860
+ if (value === null || value === void 0) {
4861
+ throw new Error("Expected value to be defined");
4862
+ }
4863
+ return value;
4864
+ }
4773
4865
  function completePartialObject(s) {
4774
4866
  if (!s.trim().startsWith("{")) return s;
4775
4867
  if (tryParse(s).ok) return s;
@@ -4781,7 +4873,7 @@ function completePartialObject(s) {
4781
4873
  let contentEnd = 0;
4782
4874
  let stringBraceDepth = 0;
4783
4875
  for (let i = 0; i < s.length; i++) {
4784
- const ch = s[i];
4876
+ const ch = expectDefined8(s[i]);
4785
4877
  if (inString) {
4786
4878
  contentEnd = i + 1;
4787
4879
  if (escaped) {
@@ -4877,7 +4969,23 @@ function mergeCustomModelDefs(providerCustomModels, configModels) {
4877
4969
 
4878
4970
  // src/storage/session-store.ts
4879
4971
  init_atomic_write();
4880
- var DefaultSessionStore = class {
4972
+ function expectDefined9(value) {
4973
+ if (value === null || value === void 0) {
4974
+ throw new Error("Expected value to be defined");
4975
+ }
4976
+ return value;
4977
+ }
4978
+ function sanitizeModel(model) {
4979
+ return model.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
4980
+ }
4981
+ function generateSessionId(startedAt, model) {
4982
+ const date = startedAt.slice(0, 10);
4983
+ const time = startedAt.slice(11, 19).replace(/:/g, "-");
4984
+ const suffix = randomBytes(2).toString("hex");
4985
+ const modelPart = model ? `_${sanitizeModel(model)}` : "";
4986
+ return `${date}/${time}Z${modelPart}_${suffix}`;
4987
+ }
4988
+ var DefaultSessionStore = class _DefaultSessionStore {
4881
4989
  dir;
4882
4990
  events;
4883
4991
  secretScrubber;
@@ -4886,19 +4994,29 @@ var DefaultSessionStore = class {
4886
4994
  this.events = opts.events;
4887
4995
  this.secretScrubber = opts.secretScrubber;
4888
4996
  }
4997
+ /** Absolute path to the session index file. */
4998
+ get indexFile() {
4999
+ return path6.join(this.dir, "_index.jsonl");
5000
+ }
4889
5001
  /** Join session ID to its absolute path within the store directory. */
4890
5002
  sessionPath(id, ext) {
4891
5003
  return path6.join(this.dir, `${id}${ext}`);
4892
5004
  }
4893
- async ensureShardDir(_id) {
4894
- await ensureDir(this.dir);
4895
- return this.dir;
5005
+ /**
5006
+ * Ensure the directory implied by the session ID exists. When the ID
5007
+ * contains a date prefix like `2026-06-06/...`, this creates the date
5008
+ * subdirectory so sessions group naturally by day.
5009
+ */
5010
+ async ensureShardDir(id) {
5011
+ const dirPath = path6.dirname(path6.join(this.dir, id));
5012
+ await ensureDir(dirPath);
5013
+ return dirPath;
4896
5014
  }
4897
5015
  async create(meta) {
4898
5016
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
4899
- const id = meta.id ?? `${startedAt.replace(/[:.]/g, "-")}-${randomBytes(2).toString("hex")}`;
5017
+ const id = meta.id && meta.id.length > 0 ? meta.id : generateSessionId(startedAt, meta.model ?? meta.provider);
4900
5018
  const shardDir = await this.ensureShardDir(id);
4901
- const file = path6.join(shardDir, `${id}.jsonl`);
5019
+ const file = path6.join(shardDir, `${path6.basename(id)}.jsonl`);
4902
5020
  let handle;
4903
5021
  try {
4904
5022
  handle = await fsp3.open(file, "a", 384);
@@ -4912,7 +5030,8 @@ var DefaultSessionStore = class {
4912
5030
  return new FileSessionWriter(id, handle, startedAt, meta, this.events, {
4913
5031
  dir: shardDir,
4914
5032
  filePath: file,
4915
- secretScrubber: this.secretScrubber
5033
+ secretScrubber: this.secretScrubber,
5034
+ onClose: (s) => this.appendToIndex(s)
4916
5035
  });
4917
5036
  } catch (err) {
4918
5037
  await handle.close().catch(() => {
@@ -4943,7 +5062,7 @@ var DefaultSessionStore = class {
4943
5062
  provider: data.metadata.provider
4944
5063
  },
4945
5064
  this.events,
4946
- { resumed: true, dir: this.dir, filePath: file, secretScrubber: this.secretScrubber }
5065
+ { resumed: true, dir: this.dir, filePath: file, secretScrubber: this.secretScrubber, onClose: (s) => this.appendToIndex(s) }
4947
5066
  );
4948
5067
  return { writer, data };
4949
5068
  } catch (err) {
@@ -4973,6 +5092,15 @@ var DefaultSessionStore = class {
4973
5092
  async list(limit = 20) {
4974
5093
  try {
4975
5094
  await ensureDir(this.dir);
5095
+ const indexed = await this.readIndex();
5096
+ if (indexed.length > 0) {
5097
+ indexed.sort((a, b) => {
5098
+ if (a.startedAt < b.startedAt) return 1;
5099
+ if (a.startedAt > b.startedAt) return -1;
5100
+ return a.id.localeCompare(b.id);
5101
+ });
5102
+ return indexed.slice(0, limit);
5103
+ }
4976
5104
  const ids = await this.collectSessionIds(this.dir);
4977
5105
  const sessions = await Promise.all(ids.map((id) => this.summaryFor(id).catch(() => null)));
4978
5106
  const out = sessions.filter((s) => s !== null);
@@ -4986,16 +5114,121 @@ var DefaultSessionStore = class {
4986
5114
  return [];
4987
5115
  }
4988
5116
  }
4989
- /** Recursively collect all session IDs from shard subdirectories. */
4990
- async collectSessionIds(dir) {
5117
+ // ── Session index (_index.jsonl) ─────────────────────────────────────────
5118
+ //
5119
+ // One JSON line per closed session, appended atomically on close().
5120
+ // When a session is deleted, a tombstone {action:"delete",id:"..."} is
5121
+ // appended. On read, tombstones filter out matching session entries.
5122
+ // This keeps listing O(lines-in-index) instead of O(files-on-disk).
5123
+ //
5124
+ // The index auto-compacts every N appends to prevent unbounded growth
5125
+ // from tombstones and duplicate entries (resume cycles).
5126
+ indexAppendCount = 0;
5127
+ static COMPACT_EVERY = 30;
5128
+ /** Append a session summary to the index. */
5129
+ async appendToIndex(summary) {
5130
+ try {
5131
+ await ensureDir(this.dir);
5132
+ const line = JSON.stringify(summary) + "\n";
5133
+ await fsp3.appendFile(this.indexFile, line, "utf8");
5134
+ this.indexAppendCount++;
5135
+ if (this.indexAppendCount >= _DefaultSessionStore.COMPACT_EVERY) {
5136
+ await this.compactIndex();
5137
+ this.indexAppendCount = 0;
5138
+ }
5139
+ } catch {
5140
+ }
5141
+ }
5142
+ /** Append a tombstone entry for a deleted session. */
5143
+ async writeTombstone(id) {
5144
+ try {
5145
+ await ensureDir(this.dir);
5146
+ const line = JSON.stringify({ action: "delete", id }) + "\n";
5147
+ await fsp3.appendFile(this.indexFile, line, "utf8");
5148
+ this.indexAppendCount++;
5149
+ } catch {
5150
+ }
5151
+ }
5152
+ /**
5153
+ * Compact the index: read all entries, drop tombstones, deduplicate
5154
+ * (keep latest per session), and rewrite. Atomic via temp+rename.
5155
+ */
5156
+ async compactIndex() {
5157
+ const entries = await this.readIndex();
5158
+ if (entries.length === 0) return;
5159
+ const tmp = `${this.indexFile}.compact.tmp`;
5160
+ const lines = entries.map((s) => JSON.stringify(s)).join("\n") + "\n";
5161
+ await fsp3.writeFile(tmp, lines, "utf8");
5162
+ await fsp3.rename(tmp, this.indexFile);
5163
+ }
5164
+ /**
5165
+ * Read the index file and return deduplicated session summaries.
5166
+ * Entries with a matching tombstone are filtered out.
5167
+ * Returns empty array when the index doesn't exist or is corrupt.
5168
+ */
5169
+ async readIndex() {
5170
+ let raw;
5171
+ try {
5172
+ raw = await fsp3.readFile(this.indexFile, "utf8");
5173
+ } catch {
5174
+ return [];
5175
+ }
5176
+ const deleted = /* @__PURE__ */ new Set();
5177
+ const seen = /* @__PURE__ */ new Map();
5178
+ for (const line of raw.split("\n")) {
5179
+ if (!line.trim()) continue;
5180
+ try {
5181
+ const entry = JSON.parse(line);
5182
+ if (entry.action === "delete" && entry.id) {
5183
+ deleted.add(entry.id);
5184
+ seen.delete(entry.id);
5185
+ continue;
5186
+ }
5187
+ if (entry.id && !deleted.has(entry.id)) {
5188
+ seen.set(entry.id, entry);
5189
+ }
5190
+ } catch {
5191
+ }
5192
+ }
5193
+ return Array.from(seen.values());
5194
+ }
5195
+ /**
5196
+ * Rebuild the index from disk by scanning all sessions and writing a
5197
+ * fresh _index.jsonl. Useful after manual cleanup or index corruption.
5198
+ */
5199
+ async rebuildIndex() {
5200
+ const ids = await this.collectSessionIds(this.dir);
5201
+ const summaries = await Promise.all(ids.map((id) => this.summaryFor(id).catch(() => null)));
5202
+ const valid = summaries.filter((s) => s !== null);
5203
+ const tmp = `${this.indexFile}.tmp`;
5204
+ const lines = valid.map((s) => JSON.stringify(s)).join("\n") + "\n";
5205
+ await fsp3.writeFile(tmp, lines, "utf8");
5206
+ await fsp3.rename(tmp, this.indexFile);
5207
+ return valid.length;
5208
+ }
5209
+ /** Recursively collect session IDs from date-shard subdirectories.
5210
+ * IDs include the date-prefix path (e.g. "2026-06-06/17-46-57Z_…").
5211
+ * Skips `.jsonl`/`.summary.json` root files, dot-files, and
5212
+ * sub-directories that belong to fleet/subagent sessions. */
5213
+ async collectSessionIds(dir, prefix = "", depth = 0) {
4991
5214
  const ids = [];
4992
- const entries = await fsp3.readdir(dir, { withFileTypes: true });
5215
+ let entries;
5216
+ try {
5217
+ entries = await fsp3.readdir(dir, { withFileTypes: true });
5218
+ } catch {
5219
+ return ids;
5220
+ }
4993
5221
  for (const entry of entries) {
4994
- const full = path6.join(dir, entry.name);
5222
+ if (entry.name.startsWith(".") && entry.name !== ".wrongstack") continue;
5223
+ if (entry.name === "shared" || entry.name === "subagents" || entry.name === "attachments")
5224
+ continue;
4995
5225
  if (entry.isDirectory()) {
4996
- ids.push(...await this.collectSessionIds(full));
5226
+ const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
5227
+ ids.push(...await this.collectSessionIds(path6.join(dir, entry.name), childPrefix, depth + 1));
4997
5228
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
4998
- ids.push(entry.name.replace(/\.jsonl$/, ""));
5229
+ if (entry.name === "_index.jsonl") continue;
5230
+ const base = entry.name.replace(/\.jsonl$/, "");
5231
+ ids.push(prefix ? `${prefix}/${base}` : base);
4999
5232
  }
5000
5233
  }
5001
5234
  return ids;
@@ -5018,9 +5251,70 @@ var DefaultSessionStore = class {
5018
5251
  return summary;
5019
5252
  }
5020
5253
  }
5021
- async delete(id) {
5022
- await fsp3.unlink(this.sessionPath(id, ".jsonl"));
5254
+ /**
5255
+ * Delete a session and all associated files: JSONL, summary, plan/todos
5256
+ * sidecars, and the session directory (fleet.json, shared/, subagents/).
5257
+ */
5258
+ async deleteSession(id) {
5259
+ await fsp3.unlink(this.sessionPath(id, ".jsonl")).catch(() => void 0);
5023
5260
  await fsp3.unlink(this.sessionPath(id, ".summary.json")).catch(() => void 0);
5261
+ const shardDir = path6.dirname(path6.join(this.dir, id));
5262
+ const base = path6.basename(id);
5263
+ for (const ext of [".plan.json", ".todos.json"]) {
5264
+ await fsp3.unlink(path6.join(shardDir, `${base}${ext}`)).catch(() => void 0);
5265
+ }
5266
+ const sessDir = path6.join(shardDir, base);
5267
+ await fsp3.rm(sessDir, { recursive: true, force: true }).catch(() => void 0);
5268
+ await this.writeTombstone(id);
5269
+ }
5270
+ async delete(id) {
5271
+ await this.deleteSession(id);
5272
+ }
5273
+ async prune(maxAgeDays = 30) {
5274
+ const cutoff = Date.now() - maxAgeDays * 864e5;
5275
+ let deleted = 0;
5276
+ let activeSessionId = null;
5277
+ try {
5278
+ const raw = await fsp3.readFile(path6.join(this.dir, "active.json"), "utf8");
5279
+ const active = JSON.parse(raw);
5280
+ activeSessionId = active.sessionId ?? null;
5281
+ } catch {
5282
+ }
5283
+ const entries = await fsp3.readdir(this.dir, { withFileTypes: true }).catch(() => []);
5284
+ for (const entry of entries) {
5285
+ if (!entry.isDirectory()) continue;
5286
+ const dateDir = path6.join(this.dir, entry.name);
5287
+ const files = await fsp3.readdir(dateDir, { withFileTypes: true }).catch(() => []);
5288
+ for (const file of files) {
5289
+ if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
5290
+ const jsonlPath = path6.join(dateDir, file.name);
5291
+ try {
5292
+ const stat10 = await fsp3.stat(jsonlPath);
5293
+ if (stat10.mtimeMs >= cutoff) continue;
5294
+ } catch {
5295
+ continue;
5296
+ }
5297
+ const id = `${entry.name}/${file.name.replace(/\.jsonl$/, "")}`;
5298
+ if (activeSessionId && id === activeSessionId) continue;
5299
+ await this.deleteSession(id);
5300
+ deleted++;
5301
+ }
5302
+ }
5303
+ if (deleted > 0) {
5304
+ await this.compactIndex().catch(() => void 0);
5305
+ }
5306
+ for (const entry of entries) {
5307
+ if (!entry.isDirectory()) continue;
5308
+ const dateDir = path6.join(this.dir, entry.name);
5309
+ try {
5310
+ const remaining = await fsp3.readdir(dateDir);
5311
+ if (remaining.length === 0) {
5312
+ await fsp3.rmdir(dateDir).catch(() => void 0);
5313
+ }
5314
+ } catch {
5315
+ }
5316
+ }
5317
+ return deleted;
5024
5318
  }
5025
5319
  async clearHistory(id) {
5026
5320
  await this.ensureShardDir(id);
@@ -5042,13 +5336,42 @@ var DefaultSessionStore = class {
5042
5336
  const data = await this.load(id);
5043
5337
  const firstUser = data.events.find((e) => e.type === "user_input");
5044
5338
  const title = firstUser && firstUser.type === "user_input" ? userInputTitle(firstUser.content) : "(empty session)";
5339
+ let iterationCount = 0;
5340
+ let toolCallCount = 0;
5341
+ let toolErrorCount = 0;
5342
+ let fileChangeCount = 0;
5343
+ const toolBreakdown = {};
5344
+ let outcome = void 0;
5345
+ const lastEvent = data.events[data.events.length - 1];
5346
+ for (const e of data.events) {
5347
+ if (e.type === "in_flight_start") iterationCount++;
5348
+ else if (e.type === "tool_call_start") {
5349
+ toolCallCount++;
5350
+ toolBreakdown[e.name] = (toolBreakdown[e.name] ?? 0) + 1;
5351
+ } else if (e.type === "tool_result" && e.isError) toolErrorCount++;
5352
+ else if (e.type === "file_snapshot") fileChangeCount += e.files.length;
5353
+ }
5354
+ if (lastEvent?.type === "session_end") {
5355
+ outcome = "completed";
5356
+ } else if (lastEvent?.type === "in_flight_start") {
5357
+ outcome = "aborted";
5358
+ } else if (data.events.some((e) => e.type === "error")) {
5359
+ outcome = "error";
5360
+ }
5045
5361
  return {
5046
5362
  id,
5047
5363
  title,
5048
5364
  startedAt: data.metadata.startedAt,
5365
+ endedAt: data.metadata.endedAt,
5049
5366
  model: data.metadata.model ?? "unknown",
5050
5367
  provider: data.metadata.provider ?? "unknown",
5051
- tokenTotal: data.usage.input + data.usage.output
5368
+ tokenTotal: data.usage.input + data.usage.output,
5369
+ iterationCount: iterationCount > 0 ? iterationCount : void 0,
5370
+ toolCallCount: toolCallCount > 0 ? toolCallCount : void 0,
5371
+ toolErrorCount: toolErrorCount > 0 ? toolErrorCount : void 0,
5372
+ fileChangeCount: fileChangeCount > 0 ? fileChangeCount : void 0,
5373
+ toolBreakdown: Object.keys(toolBreakdown).length > 0 ? toolBreakdown : {},
5374
+ outcome
5052
5375
  };
5053
5376
  } catch {
5054
5377
  return {
@@ -5147,9 +5470,10 @@ var FileSessionWriter = class {
5147
5470
  this.meta = meta;
5148
5471
  this.events = events;
5149
5472
  this.resumed = opts.resumed ?? false;
5150
- this.manifestFile = opts.dir ? path6.join(opts.dir, `${id}.summary.json`) : "";
5473
+ this.manifestFile = opts.dir ? path6.join(opts.dir, `${path6.basename(id)}.summary.json`) : "";
5151
5474
  this.filePath = opts.filePath ?? "";
5152
5475
  this.secretScrubber = opts.secretScrubber;
5476
+ this.onCloseCb = opts.onClose;
5153
5477
  this.summary = {
5154
5478
  id,
5155
5479
  title: "(empty session)",
@@ -5179,6 +5503,15 @@ var FileSessionWriter = class {
5179
5503
  appendFailCount = 0;
5180
5504
  lastAppendWarnAt = 0;
5181
5505
  secretScrubber;
5506
+ onCloseCb;
5507
+ // ── Enriched summary tracking ──────────────────────────────────────────
5508
+ iterationCount = 0;
5509
+ toolCallCount = 0;
5510
+ toolErrorCount = 0;
5511
+ toolBreakdown = {};
5512
+ fileChangeCount = 0;
5513
+ compactionCount = 0;
5514
+ outcome = void 0;
5182
5515
  /**
5183
5516
  * Scrub secrets out of conversation-turn events before they are observed
5184
5517
  * for the summary, written to the JSONL log, or surfaced on resume. Only
@@ -5256,8 +5589,22 @@ var FileSessionWriter = class {
5256
5589
  observeForSummary(event) {
5257
5590
  if (event.type === "tool_use") {
5258
5591
  this.openToolUses.add(event.id);
5592
+ } else if (event.type === "tool_call_start") {
5593
+ this.toolCallCount++;
5594
+ this.toolBreakdown[event.name] = (this.toolBreakdown[event.name] ?? 0) + 1;
5259
5595
  } else if (event.type === "tool_result") {
5260
5596
  this.openToolUses.delete(event.id);
5597
+ if (event.isError) {
5598
+ this.toolErrorCount++;
5599
+ this.outcome = "error";
5600
+ }
5601
+ } else if (event.type === "file_snapshot") {
5602
+ this.fileChangeCount += event.files.length;
5603
+ } else if (event.type === "compaction") {
5604
+ this.compactionCount++;
5605
+ }
5606
+ if (event.type === "error" || event.type === "provider_error") {
5607
+ this.outcome = "error";
5261
5608
  }
5262
5609
  if (event.type === "user_input" && this.summary.title === "(empty session)") {
5263
5610
  this.summary = { ...this.summary, title: userInputTitle(event.content) };
@@ -5268,18 +5615,35 @@ var FileSessionWriter = class {
5268
5615
  } else if (event.type === "session_end") {
5269
5616
  const total = event.usage.input + event.usage.output;
5270
5617
  if (total > 0) this.summary = { ...this.summary, tokenTotal: total };
5618
+ } else if (event.type === "in_flight_start") {
5619
+ this.iterationCount++;
5271
5620
  }
5272
5621
  }
5273
5622
  async close() {
5274
5623
  if (this.closing) return;
5275
5624
  this.closing = true;
5276
5625
  this.closed = true;
5626
+ this.summary = {
5627
+ ...this.summary,
5628
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
5629
+ iterationCount: this.iterationCount,
5630
+ toolCallCount: this.toolCallCount,
5631
+ toolErrorCount: this.toolErrorCount,
5632
+ fileChangeCount: this.fileChangeCount,
5633
+ compactionCount: this.compactionCount > 0 ? this.compactionCount : void 0,
5634
+ toolBreakdown: { ...this.toolBreakdown },
5635
+ outcome: this.outcome ?? "completed"
5636
+ };
5277
5637
  if (this.manifestFile) {
5278
5638
  try {
5279
5639
  await atomicWrite(this.manifestFile, JSON.stringify(this.summary), { mode: 384 });
5280
5640
  } catch {
5281
5641
  }
5282
5642
  }
5643
+ try {
5644
+ await this.onCloseCb?.(this.summary);
5645
+ } catch {
5646
+ }
5283
5647
  try {
5284
5648
  await this.handle.close();
5285
5649
  } catch {
@@ -5321,7 +5685,7 @@ var FileSessionWriter = class {
5321
5685
  let targetCheckpointLine = -1;
5322
5686
  let afterTarget = false;
5323
5687
  for (let i = 0; i < lines.length; i++) {
5324
- const line = lines[i];
5688
+ const line = expectDefined9(lines[i]);
5325
5689
  if (!line.trim()) continue;
5326
5690
  let event;
5327
5691
  try {
@@ -6244,7 +6608,7 @@ var RecoveryLock = class {
6244
6608
  constructor(opts) {
6245
6609
  this.file = path6.join(opts.dir, LOCK_FILE);
6246
6610
  this.pid = opts.pid ?? process.pid;
6247
- this.hostname = opts.hostname ?? os6.hostname();
6611
+ this.hostname = opts.hostname ?? os7.hostname();
6248
6612
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
6249
6613
  this.sessionStore = opts.sessionStore;
6250
6614
  this.probe = opts.isPidAlive ?? defaultIsPidAlive;
@@ -6458,8 +6822,11 @@ var SessionAnalyzer = class {
6458
6822
  }
6459
6823
  calcDuration(events) {
6460
6824
  if (events.length < 2) return 0;
6461
- const first = new Date(events[0].ts).getTime();
6462
- const last = new Date(events[events.length - 1].ts).getTime();
6825
+ const firstEvent = events[0];
6826
+ const lastEvent = events[events.length - 1];
6827
+ if (!firstEvent || !lastEvent) return 0;
6828
+ const first = new Date(firstEvent.ts).getTime();
6829
+ const last = new Date(lastEvent.ts).getTime();
6463
6830
  return last - first;
6464
6831
  }
6465
6832
  };
@@ -6572,7 +6939,7 @@ async function loadTodosCheckpoint(filePath) {
6572
6939
  const parsed = JSON.parse(raw);
6573
6940
  if (parsed?.version !== 1 || !Array.isArray(parsed.todos)) return null;
6574
6941
  return parsed.todos.filter(
6575
- (t2) => !!t2 && typeof t2.id === "string" && typeof t2.content === "string" && typeof t2.status === "string"
6942
+ (t2) => !!t2 && typeof t2.id === "string" && typeof t2.content === "string" && typeof t2.status === "string" && (t2.activeForm === void 0 || typeof t2.activeForm === "string")
6576
6943
  );
6577
6944
  } catch {
6578
6945
  return null;
@@ -7568,7 +7935,7 @@ function parseDescription(raw) {
7568
7935
  const scope = [];
7569
7936
  const coversMatch = /(?:covers|for|including)\s+([^.]+)/i.exec(desc);
7570
7937
  if (coversMatch) {
7571
- const items = coversMatch[1].replace(/[·•]/g, ",").split(",").map((s) => s.trim()).filter(Boolean);
7938
+ const items = coversMatch[1] ?? "".replace(/[·•]/g, ",").split(",").map((s) => s.trim()).filter(Boolean);
7572
7939
  scope.push(...items);
7573
7940
  }
7574
7941
  return { trigger, scope };
@@ -8023,7 +8390,7 @@ var IntelligentCompactor = class {
8023
8390
  maxTokens: 1024
8024
8391
  };
8025
8392
  const ac = ctx.signal ? void 0 : new AbortController();
8026
- const signal = ctx.signal ?? ac.signal;
8393
+ const signal = ctx.signal ?? ac?.signal;
8027
8394
  const res = await this.provider.complete(req, { signal });
8028
8395
  const textBlocks = res.content.filter(isTextBlock);
8029
8396
  return textBlocks.map((b) => b.text).join("\n").trim() || "(empty summary)";
@@ -8126,6 +8493,12 @@ var IntelligentCompactor = class {
8126
8493
  };
8127
8494
 
8128
8495
  // src/models/llm-selector.ts
8496
+ function expectDefined10(value) {
8497
+ if (value === null || value === void 0) {
8498
+ throw new Error("Expected value to be defined");
8499
+ }
8500
+ return value;
8501
+ }
8129
8502
  var DEFAULT_SYSTEM_PROMPT = `You are a context pruning assistant. Given a conversation history and a token budget, decide which message ranges are worth keeping verbatim and which should be collapsed into summaries.
8130
8503
 
8131
8504
  Output a JSON object with this structure:
@@ -8166,7 +8539,7 @@ function formatMessages(messages, maxChars = 8e3) {
8166
8539
  const lines = [];
8167
8540
  let used = 0;
8168
8541
  for (let i = 0; i < messages.length; i++) {
8169
- const m = messages[i];
8542
+ const m = expectDefined10(messages[i]);
8170
8543
  const role = m.role.padEnd(10, " ");
8171
8544
  let text;
8172
8545
  if (typeof m.content === "string") {
@@ -8231,7 +8604,7 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
8231
8604
  let tokenCount = 0;
8232
8605
  let startIdx = 0;
8233
8606
  for (let i = messages.length - 1; i >= 0; i--) {
8234
- const m = messages[i];
8607
+ const m = expectDefined10(messages[i]);
8235
8608
  const cost = typeof m.content === "string" ? Math.ceil(m.content.length / 4) : m.content.reduce(
8236
8609
  (acc, b) => acc + (b.type === "text" ? Math.ceil(b.text.length / 4) : Math.ceil(JSON.stringify(b).length / 4)),
8237
8610
  0
@@ -8442,6 +8815,7 @@ Summarize the following message range:`;
8442
8815
  let boundary = preserveIdx;
8443
8816
  for (let i = preserveIdx; i < messages.length && i < preserveIdx + 6; i++) {
8444
8817
  const m = messages[i];
8818
+ if (!m) continue;
8445
8819
  if (m.role === "user" && this.hasTextContent(m)) {
8446
8820
  boundary = i;
8447
8821
  break;
@@ -8868,7 +9242,7 @@ init_atomic_write();
8868
9242
  var MAX_JOURNAL_ENTRIES = 500;
8869
9243
  function goalFilePath(projectRoot) {
8870
9244
  const hash = createHash("sha256").update(path6.resolve(projectRoot)).digest("hex").slice(0, 12);
8871
- return path6.join(os6.homedir(), ".wrongstack", "projects", hash, "goal.json");
9245
+ return path6.join(os7.homedir(), ".wrongstack", "projects", hash, "goal.json");
8872
9246
  }
8873
9247
  async function loadGoal(filePath) {
8874
9248
  let raw;
@@ -9706,16 +10080,16 @@ var SubagentBudget = class _SubagentBudget {
9706
10080
  }
9707
10081
  if (exceeded.length === 0) return [];
9708
10082
  if (!this._onThreshold) {
9709
- const first2 = exceeded[0];
10083
+ const first2 = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
9710
10084
  throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
9711
10085
  }
9712
10086
  if (this._mode === "sync") {
9713
- const first2 = exceeded[0];
10087
+ const first2 = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
9714
10088
  throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
9715
10089
  }
9716
10090
  const bus = this._events;
9717
10091
  if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
9718
- const first2 = exceeded[0];
10092
+ const first2 = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
9719
10093
  throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
9720
10094
  }
9721
10095
  for (const entry of exceeded) {
@@ -9723,8 +10097,9 @@ var SubagentBudget = class _SubagentBudget {
9723
10097
  const decision2 = this._negotiateExtension(entry.kind, exceeded);
9724
10098
  this._pendingNegotiations.set(entry.kind, decision2);
9725
10099
  }
9726
- const first = exceeded[0];
10100
+ const first = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
9727
10101
  const decision = this._pendingNegotiations.get(first.kind);
10102
+ if (!decision) throw new Error(`No pending negotiation for ${first.kind}`);
9728
10103
  throw new BudgetThresholdSignal(first.kind, first.limit, first.used, decision);
9729
10104
  }
9730
10105
  /**
@@ -9746,8 +10121,11 @@ var SubagentBudget = class _SubagentBudget {
9746
10121
  * a fresh signal.
9747
10122
  */
9748
10123
  async _negotiateExtension(kind, exceeded) {
10124
+ if (!this._onThreshold) {
10125
+ return "stop";
10126
+ }
9749
10127
  try {
9750
- const first = exceeded[0];
10128
+ const first = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
9751
10129
  const result = this._onThreshold({
9752
10130
  kind: first.kind,
9753
10131
  used: first.used,
@@ -12230,6 +12608,11 @@ function getAgentDefinition(role) {
12230
12608
 
12231
12609
  // src/coordination/dispatcher.ts
12232
12610
  var DEFAULT_DISPATCH_ROLE = "executor";
12611
+ var FALLBACK_DEFINITION = {
12612
+ config: { role: "unknown", name: "Unknown Agent" },
12613
+ budget: {},
12614
+ capability: { phase: "meta", summary: "", keywords: [] }
12615
+ };
12233
12616
  function normalize2(text) {
12234
12617
  return ` ${text.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim()} `;
12235
12618
  }
@@ -12257,7 +12640,7 @@ function scoreAgents(task, catalog = AGENT_CATALOG) {
12257
12640
  }
12258
12641
  function heuristicConfidence(candidates) {
12259
12642
  if (candidates.length === 0) return 0;
12260
- const top = candidates[0].score;
12643
+ const top = candidates[0]?.score ?? 0;
12261
12644
  const second = candidates[1]?.score ?? 0;
12262
12645
  const strength = Math.min(1, top / 3);
12263
12646
  const margin = (top - second + 1) / (top + 1);
@@ -12273,7 +12656,7 @@ async function dispatchAgent(task, opts = {}) {
12273
12656
  if (top && confidence >= threshold) {
12274
12657
  return {
12275
12658
  role: top.role,
12276
- definition: catalog[top.role],
12659
+ definition: catalog[top.role] ?? FALLBACK_DEFINITION,
12277
12660
  confidence,
12278
12661
  method: "heuristic",
12279
12662
  reason: `Matched keywords: ${top.matched.slice(0, 4).join(", ")}`,
@@ -12281,7 +12664,7 @@ async function dispatchAgent(task, opts = {}) {
12281
12664
  };
12282
12665
  }
12283
12666
  if (opts.classifier) {
12284
- const pool = (candidates.length > 0 ? candidates.slice(0, maxCandidates).map((c) => catalog[c.role]) : ALL_AGENT_DEFINITIONS).map((d) => ({
12667
+ const pool = (candidates.length > 0 ? candidates.slice(0, maxCandidates).map((c) => catalog[c.role] ?? FALLBACK_DEFINITION) : ALL_AGENT_DEFINITIONS).map((d) => ({
12285
12668
  role: d.config.role,
12286
12669
  name: d.config.name,
12287
12670
  summary: d.capability.summary
@@ -12291,7 +12674,7 @@ async function dispatchAgent(task, opts = {}) {
12291
12674
  if (choice && catalog[choice.role]) {
12292
12675
  return {
12293
12676
  role: choice.role,
12294
- definition: catalog[choice.role],
12677
+ definition: catalog[choice.role] ?? FALLBACK_DEFINITION,
12295
12678
  confidence: 1,
12296
12679
  method: "llm",
12297
12680
  reason: choice.reason ?? "Selected by LLM classifier",
@@ -12304,17 +12687,17 @@ async function dispatchAgent(task, opts = {}) {
12304
12687
  if (top) {
12305
12688
  return {
12306
12689
  role: top.role,
12307
- definition: catalog[top.role],
12690
+ definition: catalog[top.role] ?? FALLBACK_DEFINITION,
12308
12691
  confidence,
12309
12692
  method: "heuristic",
12310
12693
  reason: `Weak match (${top.matched.slice(0, 3).join(", ") || "low signal"})`,
12311
12694
  alternatives: candidates.slice(1, maxCandidates)
12312
12695
  };
12313
12696
  }
12314
- const fallbackRole = catalog[DEFAULT_DISPATCH_ROLE] ? DEFAULT_DISPATCH_ROLE : Object.keys(catalog)[0];
12697
+ const fallbackRole = catalog[DEFAULT_DISPATCH_ROLE] ? DEFAULT_DISPATCH_ROLE : Object.keys(catalog)[0] ?? DEFAULT_DISPATCH_ROLE;
12315
12698
  return {
12316
12699
  role: fallbackRole,
12317
- definition: catalog[fallbackRole],
12700
+ definition: catalog[fallbackRole] ?? FALLBACK_DEFINITION,
12318
12701
  confidence: 0,
12319
12702
  method: "fallback",
12320
12703
  reason: "No keyword signal; defaulting to the generalist Executor",
@@ -13127,6 +13510,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
13127
13510
  takeNextDispatchableTask() {
13128
13511
  for (let i = 0; i < this.pendingTasks.length; i++) {
13129
13512
  const task = this.pendingTasks[i];
13513
+ if (!task) continue;
13130
13514
  const subagentId = task.subagentId ? this.isIdleSubagent(task.subagentId) ? task.subagentId : null : this.findIdleSubagent();
13131
13515
  if (!subagentId) continue;
13132
13516
  this.pendingTasks.splice(i, 1);
@@ -13318,14 +13702,14 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
13318
13702
  const idleExceeded = idleLimit !== void 0 && budget.idleMs() >= idleLimit;
13319
13703
  if (idleExceeded && !wallExceeded) {
13320
13704
  this.subagents.get(ctx.subagentId)?.abortController.abort();
13321
- reject(new BudgetExceededError("timeout", idleLimit, budget.idleMs()));
13705
+ reject(new BudgetExceededError("timeout", idleLimit ?? 0, budget.idleMs()));
13322
13706
  return;
13323
13707
  }
13324
13708
  if (!wallExceeded) {
13325
13709
  scheduleNext();
13326
13710
  return;
13327
13711
  }
13328
- const limit = wallLimit;
13712
+ const limit = wallLimit ?? 0;
13329
13713
  if (!budget.onThreshold) {
13330
13714
  this.subagents.get(ctx.subagentId)?.abortController.abort();
13331
13715
  reject(new BudgetExceededError("timeout", limit, elapsed));
@@ -13484,6 +13868,12 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
13484
13868
  };
13485
13869
 
13486
13870
  // src/execution/parallel-eternal-engine.ts
13871
+ function expectDefined11(value) {
13872
+ if (value === null || value === void 0) {
13873
+ throw new Error("Expected value to be defined");
13874
+ }
13875
+ return value;
13876
+ }
13487
13877
  function sleep2(ms) {
13488
13878
  return new Promise((resolve13) => setTimeout(resolve13, ms));
13489
13879
  }
@@ -13642,7 +14032,7 @@ var ParallelEternalEngine = class {
13642
14032
  // Fan-out
13643
14033
  // -------------------------------------------------------------------------
13644
14034
  async fanOut(goal, tasks) {
13645
- const coordinator = this.coordinator;
14035
+ const coordinator = expectDefined11(this.coordinator);
13646
14036
  const slotCount = Math.min(this.slots, tasks.length);
13647
14037
  const routes = this.dispatchEnabled ? await Promise.all(
13648
14038
  tasks.slice(0, slotCount).map(
@@ -13674,7 +14064,7 @@ ${recentJournal}` : "No prior iterations.",
13674
14064
  const routeInfo = [];
13675
14065
  const spawnPromises = [];
13676
14066
  for (let i = 0; i < slotCount; i++) {
13677
- const task = tasks[i];
14067
+ const task = expectDefined11(tasks[i]);
13678
14068
  const route = routes[i] ?? null;
13679
14069
  const subagentId = `parallel-${this.iterations}-${i}`;
13680
14070
  const taskId = randomUUID();
@@ -14177,7 +14567,7 @@ var CollabSession = class extends EventEmitter {
14177
14567
  this.emit("session.error", error);
14178
14568
  throw error;
14179
14569
  }
14180
- for (const result of results.flat()) {
14570
+ for (const result of results?.flat() ?? []) {
14181
14571
  await this.parseAndEmit(result);
14182
14572
  }
14183
14573
  const report = this.assembleReport();
@@ -14238,7 +14628,7 @@ var CollabSession = class extends EventEmitter {
14238
14628
  }
14239
14629
  budgetForRole(role) {
14240
14630
  if (this.options.budgetOverrides?.[role]) {
14241
- return this.options.budgetOverrides[role];
14631
+ return this.options.budgetOverrides[role] ?? { maxIterations: 0, maxToolCalls: 0, timeoutMs: 0 };
14242
14632
  }
14243
14633
  const defaults = {
14244
14634
  "bug-hunter": { maxIterations: 2e3, maxToolCalls: 5e3, timeoutMs: 10 * 60 * 1e3 },
@@ -14691,7 +15081,7 @@ function makeSpawnTool(director, roster) {
14691
15081
  });
14692
15082
  const dispatchRole = dispatchResult.role;
14693
15083
  if (roster?.[dispatchRole]) {
14694
- cfg = instantiateRosterConfig(dispatchRole, roster[dispatchRole]);
15084
+ cfg = instantiateRosterConfig(dispatchRole, roster[dispatchRole] ?? {});
14695
15085
  } else {
14696
15086
  const def = dispatchResult.definition;
14697
15087
  cfg = {
@@ -16628,6 +17018,7 @@ function createDelegateTool(opts) {
16628
17018
  if (typeof i.task !== "string" || !i.task.trim()) {
16629
17019
  return { ok: false, error: "`task` is required." };
16630
17020
  }
17021
+ const target = i.role ?? i.name ?? "subagent";
16631
17022
  try {
16632
17023
  let director = await opts.host.ensureDirector();
16633
17024
  if (!director) {
@@ -16688,6 +17079,7 @@ function createDelegateTool(opts) {
16688
17079
  if (!cfg.timeoutMs) {
16689
17080
  cfg.timeoutMs = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
16690
17081
  }
17082
+ opts.events?.emit("delegate.started", { target, task: i.task });
16691
17083
  const subagentId = await director.spawn(cfg);
16692
17084
  const taskId = await director.assign({
16693
17085
  id: `${randomUUID()}`,
@@ -16722,6 +17114,17 @@ function createDelegateTool(opts) {
16722
17114
  });
16723
17115
  if ("__timeout" in result) {
16724
17116
  const partial2 = await readSubagentPartial(opts, subagentId);
17117
+ opts.events?.emit("delegate.completed", {
17118
+ target,
17119
+ task: i.task,
17120
+ ok: false,
17121
+ status: "host_timeout",
17122
+ summary: `[${target}] timed out \u2014 no result within ${Math.round(timeoutMs / 1e3)}s`,
17123
+ durationMs: timeoutMs,
17124
+ iterations: partial2?.events ?? 0,
17125
+ toolCalls: partial2?.toolUsesObserved ?? 0,
17126
+ subagentId
17127
+ });
16725
17128
  return {
16726
17129
  ok: false,
16727
17130
  stopReason: "host_timeout",
@@ -16738,6 +17141,24 @@ function createDelegateTool(opts) {
16738
17141
  const retryable = result.error?.retryable;
16739
17142
  const backoffMs = result.error?.backoffMs;
16740
17143
  const summary = buildDelegateSummary(i.role, result);
17144
+ let costUsd;
17145
+ try {
17146
+ costUsd = dir.snapshot().perSubagent[result.subagentId]?.cost;
17147
+ } catch {
17148
+ costUsd = void 0;
17149
+ }
17150
+ opts.events?.emit("delegate.completed", {
17151
+ target,
17152
+ task: i.task,
17153
+ ok: result.status === "success",
17154
+ status: result.status,
17155
+ summary,
17156
+ durationMs: result.durationMs,
17157
+ iterations: result.iterations,
17158
+ toolCalls: result.toolCalls,
17159
+ costUsd,
17160
+ subagentId: result.subagentId
17161
+ });
16741
17162
  return {
16742
17163
  ok: result.status === "success",
16743
17164
  status: result.status,
@@ -16759,10 +17180,21 @@ function createDelegateTool(opts) {
16759
17180
  summary
16760
17181
  };
16761
17182
  } catch (err) {
17183
+ const message = err instanceof Error ? err.message : String(err);
17184
+ opts.events?.emit("delegate.completed", {
17185
+ target,
17186
+ task: i.task,
17187
+ ok: false,
17188
+ status: "error",
17189
+ summary: `[${target}] failed \u2014 ${message}`,
17190
+ durationMs: 0,
17191
+ iterations: 0,
17192
+ toolCalls: 0
17193
+ });
16762
17194
  return {
16763
17195
  ok: false,
16764
17196
  stopReason: "error",
16765
- error: err instanceof Error ? err.message : String(err)
17197
+ error: message
16766
17198
  };
16767
17199
  }
16768
17200
  }
@@ -16958,7 +17390,10 @@ function attachAutoExtend(events, policy = {}) {
16958
17390
  if (kind === "timeout" || kind === "idle_timeout") {
16959
17391
  if (progress > lastTimeoutProgress) {
16960
17392
  lastTimeoutProgress = progress;
16961
- const next2 = Math.min(Math.ceil(limit * (1 + factor)), ceiling.timeoutMs);
17393
+ const next2 = Math.min(
17394
+ Math.ceil(limit * (1 + factor)),
17395
+ ceiling.timeoutMs ?? DEFAULT_CEILING.timeoutMs
17396
+ );
16962
17397
  extend({ timeoutMs: next2 });
16963
17398
  } else {
16964
17399
  deny();
@@ -16972,7 +17407,7 @@ function attachAutoExtend(events, policy = {}) {
16972
17407
  }
16973
17408
  extendCounts.set(kind, count + 1);
16974
17409
  const field = FIELD_BY_KIND[kind];
16975
- const cap = ceiling[field];
17410
+ const cap = ceiling[field] ?? DEFAULT_CEILING[field];
16976
17411
  const next = Math.min(Math.ceil(limit * (1 + factor)), cap);
16977
17412
  extend({ [field]: next });
16978
17413
  })
@@ -17617,7 +18052,7 @@ var TaskTracker = class {
17617
18052
  if (filter.type?.length && !filter.type.includes(n.type)) return false;
17618
18053
  if (filter.assignee?.length && n.assignee && !filter.assignee.includes(n.assignee))
17619
18054
  return false;
17620
- if (filter.tags?.length && n.tags && !n.tags.some((t2) => filter.tags.includes(t2)))
18055
+ if (filter.tags?.length && n.tags && !n.tags.some((t2) => filter.tags?.includes(t2)))
17621
18056
  return false;
17622
18057
  if (filter.specRequirementId && n.specRequirementId !== filter.specRequirementId)
17623
18058
  return false;
@@ -18131,6 +18566,12 @@ var TaskGraphStore = class {
18131
18566
  };
18132
18567
 
18133
18568
  // src/sdd/spec-builder.ts
18569
+ function expectDefined12(value) {
18570
+ if (value === null || value === void 0) {
18571
+ throw new Error("Expected value to be defined");
18572
+ }
18573
+ return value;
18574
+ }
18134
18575
  function buildQuestioningPrompt(session, min, max) {
18135
18576
  const answered = session.answers.length;
18136
18577
  const remaining = Math.max(0, min - answered);
@@ -18176,7 +18617,7 @@ function buildQuestioningPrompt(session, min, max) {
18176
18617
  if (answered > 0) {
18177
18618
  lines.push("", "**Conversation so far:**");
18178
18619
  for (let i = 0; i < answered; i++) {
18179
- const a = session.answers[i];
18620
+ const a = expectDefined12(session.answers[i]);
18180
18621
  lines.push(``, `Q${i + 1}: ${a.question}`, `A${i + 1}: ${a.answer}`);
18181
18622
  }
18182
18623
  }
@@ -18918,6 +19359,12 @@ function truncate2(str, maxLen) {
18918
19359
  }
18919
19360
 
18920
19361
  // src/sdd/critical-path.ts
19362
+ function expectDefined13(value) {
19363
+ if (value === null || value === void 0) {
19364
+ throw new Error("Expected value to be defined");
19365
+ }
19366
+ return value;
19367
+ }
18921
19368
  function analyzeCriticalPath(graph) {
18922
19369
  const nodes = Array.from(graph.nodes.values());
18923
19370
  const topoOrder = topologicalSort(graph);
@@ -18926,9 +19373,9 @@ function analyzeCriticalPath(graph) {
18926
19373
  for (const edge of graph.edges) {
18927
19374
  if (edge.type === "depends_on") {
18928
19375
  if (!blockedByMap.has(edge.from)) blockedByMap.set(edge.from, /* @__PURE__ */ new Set());
18929
- blockedByMap.get(edge.from).add(edge.to);
19376
+ blockedByMap.get(edge.from)?.add(edge.to);
18930
19377
  if (!blocksMap.has(edge.to)) blocksMap.set(edge.to, /* @__PURE__ */ new Set());
18931
- blocksMap.get(edge.to).add(edge.from);
19378
+ blocksMap.get(edge.to)?.add(edge.from);
18932
19379
  }
18933
19380
  }
18934
19381
  const readyTasks = [];
@@ -18993,7 +19440,7 @@ function getTransitiveBlocked(_graph, taskId, blocksMap) {
18993
19440
  const visited = /* @__PURE__ */ new Set();
18994
19441
  const queue = [taskId];
18995
19442
  while (queue.length > 0) {
18996
- const current = queue.shift();
19443
+ const current = expectDefined13(queue.shift());
18997
19444
  const blocked = blocksMap.get(current);
18998
19445
  if (!blocked) continue;
18999
19446
  for (const id of blocked) {
@@ -19018,7 +19465,7 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
19018
19465
  for (const [taskId, blockers] of blockedByMap) {
19019
19466
  for (const blockerId of blockers) {
19020
19467
  if (!blocksMap.has(blockerId)) blocksMap.set(blockerId, /* @__PURE__ */ new Set());
19021
- blocksMap.get(blockerId).add(taskId);
19468
+ blocksMap.get(blockerId)?.add(taskId);
19022
19469
  }
19023
19470
  }
19024
19471
  const n = allIds.length;
@@ -19039,7 +19486,7 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
19039
19486
  if (!changed) break;
19040
19487
  }
19041
19488
  let maxDist = 0;
19042
- let maxId = allIds[0];
19489
+ let maxId = expectDefined13(allIds[0]);
19043
19490
  for (const id of allIds) {
19044
19491
  const d = dist.get(id) ?? 0;
19045
19492
  if (d > maxDist) {
@@ -19508,6 +19955,12 @@ var SddTaskDecomposer = class {
19508
19955
  return nodes.some((n) => n.status === "blocked");
19509
19956
  }
19510
19957
  };
19958
+ function expectDefined14(value) {
19959
+ if (value === null || value === void 0) {
19960
+ throw new Error("Expected value to be defined");
19961
+ }
19962
+ return value;
19963
+ }
19511
19964
  var SddParallelRun = class {
19512
19965
  constructor(opts) {
19513
19966
  this.opts = opts;
@@ -19608,8 +20061,10 @@ var SddParallelRun = class {
19608
20061
  "\u2022 Do not ask before routine in-project tool use; if a permission gate appears, wait for that flow.",
19609
20062
  "\u2022 Keep output concise \u2014 summarize changes, do not transcribe files."
19610
20063
  ].join("\n");
20064
+ if (!this.coordinator) throw new Error("SDD parallel runner requires a coordinator");
20065
+ const coordinator = this.coordinator;
19611
20066
  const spawns = subagentIds.map(
19612
- (subagentId) => this.coordinator.spawn({
20067
+ (subagentId) => coordinator.spawn({
19613
20068
  id: subagentId,
19614
20069
  name: subagentId,
19615
20070
  role: "executor",
@@ -19617,12 +20072,12 @@ var SddParallelRun = class {
19617
20072
  })
19618
20073
  );
19619
20074
  const spawnResults = await Promise.all(spawns);
19620
- if (!spawnResults.every((r) => r.subagentId)) {
20075
+ if (!spawnResults.every((r) => Boolean(r.subagentId))) {
19621
20076
  throw new Error("One or more subagent spawns failed");
19622
20077
  }
19623
20078
  const assignPromises = tasks.map((task, i) => {
19624
20079
  const spec = {
19625
- id: taskIds[i],
20080
+ id: taskIds[i] ?? task.id,
19626
20081
  description: [
19627
20082
  directivePreamble,
19628
20083
  "",
@@ -19631,15 +20086,15 @@ var SddParallelRun = class {
19631
20086
  "",
19632
20087
  task.description
19633
20088
  ].join("\n"),
19634
- subagentId: subagentIds[i],
20089
+ subagentId: subagentIds[i] ?? spawnResults[i]?.subagentId ?? task.id,
19635
20090
  timeoutMs: this.timeoutMs
19636
20091
  };
19637
- return this.coordinator.assign(spec);
20092
+ return this.coordinator?.assign(spec);
19638
20093
  });
19639
20094
  await Promise.all(assignPromises);
19640
20095
  let results;
19641
20096
  try {
19642
- results = await this.coordinator.awaitTasks(taskIds);
20097
+ results = await coordinator.awaitTasks(taskIds);
19643
20098
  } catch (err) {
19644
20099
  results = taskIds.map((id) => ({
19645
20100
  subagentId: "",
@@ -19654,8 +20109,8 @@ var SddParallelRun = class {
19654
20109
  const successCount = results.filter((r) => r.status === "success").length;
19655
20110
  const failCount = results.length - successCount;
19656
20111
  for (let i = 0; i < results.length; i++) {
19657
- const result = results[i];
19658
- const taskId = taskIds[i];
20112
+ const result = expectDefined14(results[i]);
20113
+ const taskId = expectDefined14(taskIds[i]);
19659
20114
  if (result.status === "success") {
19660
20115
  this.opts.tracker.updateNodeStatus(taskId, "completed");
19661
20116
  } else {
@@ -20762,6 +21217,12 @@ var allServers = () => ({
20762
21217
  "zai-vision": { ...zaiVisionServer(), enabled: false },
20763
21218
  "minimax-vision": { ...miniMaxVisionServer(), enabled: false }
20764
21219
  });
21220
+ function expectDefined15(value) {
21221
+ if (value === null || value === void 0) {
21222
+ throw new Error("Expected value to be defined");
21223
+ }
21224
+ return value;
21225
+ }
20765
21226
  function parseSkillRef(input) {
20766
21227
  const trimmed = input.trim().replace(/^https?:\/\/github\.com\//, "").replace(/\.git$/, "");
20767
21228
  const atIdx = trimmed.indexOf("@");
@@ -20778,7 +21239,7 @@ function parseSkillRef(input) {
20778
21239
  if (parts.length < 2) {
20779
21240
  throw new Error(`Invalid skill reference "${input}". Expected format: user/repo or user/repo@ref`);
20780
21241
  }
20781
- return { owner: parts[0], repo: parts[1], ref };
21242
+ return { owner: expectDefined15(parts[0]), repo: expectDefined15(parts[1]), ref };
20782
21243
  }
20783
21244
  var MAX_TARBALL_SIZE = 50 * 1024 * 1024;
20784
21245
  async function downloadGitHubTarball(parsed) {
@@ -20810,7 +21271,7 @@ async function downloadGitHubTarball(parsed) {
20810
21271
  `Tarball too large (${(Number.parseInt(contentLength, 10) / 1024 / 1024).toFixed(1)}MB). Max: ${MAX_TARBALL_SIZE / 1024 / 1024}MB`
20811
21272
  );
20812
21273
  }
20813
- const tempDir = await fsp3.mkdtemp(path6.join(os6.tmpdir(), "wskill-"));
21274
+ const tempDir = await fsp3.mkdtemp(path6.join(os7.tmpdir(), "wskill-"));
20814
21275
  try {
20815
21276
  if (!response.body) {
20816
21277
  throw new Error("Empty response body from GitHub API");
@@ -20947,6 +21408,12 @@ var SkillManifestStore = class {
20947
21408
  };
20948
21409
 
20949
21410
  // src/skills/skill-installer.ts
21411
+ function expectDefined16(value) {
21412
+ if (value === null || value === void 0) {
21413
+ throw new Error("Expected value to be defined");
21414
+ }
21415
+ return value;
21416
+ }
20950
21417
  var MAX_SKILL_FILE_SIZE = 100 * 1024;
20951
21418
  var SkillInstaller = class {
20952
21419
  opts;
@@ -21068,10 +21535,10 @@ var SkillInstaller = class {
21068
21535
  for (const entry of targets) {
21069
21536
  const key = `${entry.source}@${entry.ref}`;
21070
21537
  if (!bySource.has(key)) bySource.set(key, []);
21071
- bySource.get(key).push(entry);
21538
+ bySource.get(key)?.push(entry);
21072
21539
  }
21073
21540
  for (const [, entries] of bySource) {
21074
- const first = entries[0];
21541
+ const first = expectDefined16(entries[0]);
21075
21542
  const scope = first.scope;
21076
21543
  const isGlobal = scope === "user";
21077
21544
  try {
@@ -21241,6 +21708,12 @@ async function collectFiles(dir, baseDir2) {
21241
21708
 
21242
21709
  // src/storage/annotations-store.ts
21243
21710
  init_atomic_write();
21711
+ function expectDefined17(value) {
21712
+ if (value === null || value === void 0) {
21713
+ throw new Error("Expected value to be defined");
21714
+ }
21715
+ return value;
21716
+ }
21244
21717
  var FILE_VERSION = 1;
21245
21718
  var MAX_TEXT_LENGTH = 2e3;
21246
21719
  var MAX_ANNOTATIONS = 1e3;
@@ -21332,7 +21805,7 @@ var AnnotationsStore = class {
21332
21805
  return;
21333
21806
  }
21334
21807
  const next = {
21335
- ...all[idx],
21808
+ ...expectDefined17(all[idx]),
21336
21809
  resolved: true,
21337
21810
  resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
21338
21811
  resolvedBy: input.resolvedBy
@@ -21568,6 +22041,12 @@ var ReplayLogStore = class {
21568
22041
  return next;
21569
22042
  }
21570
22043
  };
22044
+ function expectDefined18(value) {
22045
+ if (value === null || value === void 0) {
22046
+ throw new Error("Expected value to be defined");
22047
+ }
22048
+ return value;
22049
+ }
21571
22050
  var SessionRecovery = class {
21572
22051
  constructor(dir) {
21573
22052
  this.dir = dir;
@@ -21608,7 +22087,7 @@ var SessionRecovery = class {
21608
22087
  const lines = raw.split("\n").filter((l) => l.trim());
21609
22088
  for (let i = lines.length - 1; i >= 0; i--) {
21610
22089
  try {
21611
- const ev = JSON.parse(lines[i]);
22090
+ const ev = JSON.parse(expectDefined18(lines[i]));
21612
22091
  if (ev.type === "in_flight_start") {
21613
22092
  return {
21614
22093
  sessionId,
@@ -21660,13 +22139,13 @@ var SessionRecovery = class {
21660
22139
  let lastCheckpoint = null;
21661
22140
  let lastCheckpointIdx = -1;
21662
22141
  for (let i = 0; i < events.length; i++) {
21663
- if (events[i].type === "checkpoint") {
21664
- lastCheckpoint = events[i];
22142
+ if (events[i]?.type === "checkpoint") {
22143
+ lastCheckpoint = expectDefined18(events[i]);
21665
22144
  lastCheckpointIdx = i;
21666
22145
  }
21667
22146
  }
21668
22147
  const pendingEvents = lastCheckpointIdx >= 0 ? events.slice(lastCheckpointIdx + 1) : events;
21669
- const lastEv = events[events.length - 1];
22148
+ const lastEv = expectDefined18(events[events.length - 1]);
21670
22149
  const inFlightStart = lastEv.type === "in_flight_start" ? lastEv : null;
21671
22150
  const context = inFlightStart && inFlightStart.type === "in_flight_start" ? inFlightStart.context : null;
21672
22151
  return {
@@ -21709,6 +22188,12 @@ var SessionRecovery = class {
21709
22188
  return path6.join(this.dir, `${sessionId}.jsonl`);
21710
22189
  }
21711
22190
  };
22191
+ function expectDefined19(value) {
22192
+ if (value === null || value === void 0) {
22193
+ throw new Error("Expected value to be defined");
22194
+ }
22195
+ return value;
22196
+ }
21712
22197
  var GENESIS_PREV = "0".repeat(64);
21713
22198
  var DEFAULT_FSYNC_EVERY = 100;
21714
22199
  var ToolAuditLog = class {
@@ -21775,7 +22260,7 @@ var ToolAuditLog = class {
21775
22260
  async verify(sessionId) {
21776
22261
  const entries = await this.readAll(sessionId);
21777
22262
  if (entries.length === 0) return { ok: true, entries: 0 };
21778
- if (entries[0].prevHash !== GENESIS_PREV) {
22263
+ if (entries[0]?.prevHash !== GENESIS_PREV) {
21779
22264
  return {
21780
22265
  ok: false,
21781
22266
  brokenAt: 0,
@@ -21784,7 +22269,7 @@ var ToolAuditLog = class {
21784
22269
  }
21785
22270
  let prevHash = GENESIS_PREV;
21786
22271
  for (let i = 0; i < entries.length; i++) {
21787
- const e = entries[i];
22272
+ const e = expectDefined19(entries[i]);
21788
22273
  if (e.prevHash !== prevHash) {
21789
22274
  return {
21790
22275
  ok: false,
@@ -21903,6 +22388,12 @@ function sortKeys2(value) {
21903
22388
 
21904
22389
  // src/storage/session-rewinder.ts
21905
22390
  init_atomic_write();
22391
+ function expectDefined20(value) {
22392
+ if (value === null || value === void 0) {
22393
+ throw new Error("Expected value to be defined");
22394
+ }
22395
+ return value;
22396
+ }
21906
22397
  var DefaultSessionRewinder = class {
21907
22398
  constructor(sessionsDir, projectRoot) {
21908
22399
  this.sessionsDir = sessionsDir;
@@ -21941,7 +22432,7 @@ var DefaultSessionRewinder = class {
21941
22432
  const events = parseEvents(raw);
21942
22433
  let targetIdx = -1;
21943
22434
  for (let i = 0; i < events.length; i++) {
21944
- const event = events[i];
22435
+ const event = expectDefined20(events[i]);
21945
22436
  if (event.type === "checkpoint") {
21946
22437
  const checkpointEvent = event;
21947
22438
  if (checkpointEvent.promptIndex === checkpointIndex) {
@@ -21955,7 +22446,7 @@ var DefaultSessionRewinder = class {
21955
22446
  }
21956
22447
  const snapshotsToRevert = [];
21957
22448
  for (let i = targetIdx + 1; i < events.length; i++) {
21958
- const event = events[i];
22449
+ const event = expectDefined20(events[i]);
21959
22450
  if (event.type === "checkpoint") {
21960
22451
  break;
21961
22452
  }
@@ -22137,6 +22628,12 @@ var DefaultPromptStore = class {
22137
22628
  };
22138
22629
  }
22139
22630
  };
22631
+ function expectDefined21(value) {
22632
+ if (value === null || value === void 0) {
22633
+ throw new Error("Expected value to be defined");
22634
+ }
22635
+ return value;
22636
+ }
22140
22637
  var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
22141
22638
  var CloudSync = class {
22142
22639
  constructor(paths, getConfig, setConfig) {
@@ -22179,8 +22676,8 @@ var CloudSync = class {
22179
22676
  const cfg = this.getConfig();
22180
22677
  if (!cfg?.enabled) return { ok: false, action: "push", categories: [], message: "Not enabled." };
22181
22678
  const parts = cfg.repo.split("/");
22182
- const owner = parts[0];
22183
- const repoName = parts[1];
22679
+ const owner = expectDefined21(parts[0]);
22680
+ const repoName = expectDefined21(parts[1]);
22184
22681
  const branch = "main";
22185
22682
  const baseTreeSha = this.state?.sha;
22186
22683
  const { treeEntries, rev } = await this.buildLocalTree(cfg.categories);
@@ -22232,8 +22729,8 @@ var CloudSync = class {
22232
22729
  const cfg = this.getConfig();
22233
22730
  if (!cfg?.enabled) return { ok: false, action: "pull", categories: [], message: "Not enabled." };
22234
22731
  const pullParts = cfg.repo.split("/");
22235
- const owner = pullParts[0];
22236
- const repoName = pullParts[1];
22732
+ const owner = expectDefined21(pullParts[0]);
22733
+ const repoName = expectDefined21(pullParts[1]);
22237
22734
  const branchData = await this.getRef(token, owner, repoName, "main");
22238
22735
  const currentSha = branchData.object.sha;
22239
22736
  const commitData = await this.getCommit(token, owner, repoName, currentSha);
@@ -22288,7 +22785,7 @@ var CloudSync = class {
22288
22785
  // ── GitHub API helpers ──────────────────────────────────────────────
22289
22786
  async githubFetch(token, owner, repo, method, pathSegment, body) {
22290
22787
  const url = `https://api.github.com/repos/${owner}/${repo}${pathSegment}`;
22291
- const res = await fetch(url, {
22788
+ const init = {
22292
22789
  signal: AbortSignal.timeout(15e3),
22293
22790
  method,
22294
22791
  headers: {
@@ -22296,9 +22793,10 @@ var CloudSync = class {
22296
22793
  Accept: "application/vnd.github+json",
22297
22794
  "X-GitHub-Api-Version": "2022-11-28",
22298
22795
  "Content-Type": "application/json"
22299
- },
22300
- body: body !== void 0 ? JSON.stringify(body) : void 0
22301
- });
22796
+ }
22797
+ };
22798
+ if (body !== void 0) init.body = JSON.stringify(body);
22799
+ const res = await fetch(url, init);
22302
22800
  if (!res.ok) {
22303
22801
  const errText = await res.text();
22304
22802
  throw new Error(`GitHub API ${method} ${pathSegment} failed (${res.status}): ${errText}`);
@@ -23433,7 +23931,7 @@ var ReportGenerator = class {
23433
23931
  if (groups[finding.category] === void 0) {
23434
23932
  groups[finding.category] = [];
23435
23933
  }
23436
- groups[finding.category].push(finding);
23934
+ groups[finding.category]?.push(finding);
23437
23935
  }
23438
23936
  return groups;
23439
23937
  }
@@ -23578,6 +24076,12 @@ var defaultGitignoreUpdater = new GitignoreUpdater();
23578
24076
 
23579
24077
  // src/security-scanner/orchestrator.ts
23580
24078
  init_atomic_write();
24079
+ function expectDefined22(value) {
24080
+ if (value === null || value === void 0) {
24081
+ throw new Error("Expected value to be defined");
24082
+ }
24083
+ return value;
24084
+ }
23581
24085
  var SecurityScannerOrchestrator = class {
23582
24086
  constructor(retryPolicy, errorHandler) {
23583
24087
  this.retryPolicy = retryPolicy;
@@ -23627,7 +24131,7 @@ var SecurityScannerOrchestrator = class {
23627
24131
  if (detectionResult.detectedStacks.length === 0) {
23628
24132
  throw new Error(`No supported tech stack detected in ${projectRoot}`);
23629
24133
  }
23630
- const techStack = detectionResult.detectedStacks[0];
24134
+ const techStack = expectDefined22(detectionResult.detectedStacks[0]);
23631
24135
  const generatedSkill = await this.generateSkillLLM(provider, model, projectRoot, techStack);
23632
24136
  const scanResult = await this.scanWithLLM(provider, model, projectRoot, generatedSkill, techStack, options);
23633
24137
  const synthesizedReport = await this.synthesizeReportLLM(provider, model, projectRoot, techStack, scanResult);
@@ -23708,7 +24212,7 @@ Return ONLY the JSON object, no markdown, no explanation.`;
23708
24212
  const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
23709
24213
  const jsonMatch = text.match(/\{[\s\S]*\}/);
23710
24214
  if (jsonMatch) {
23711
- const sanitized = sanitizeJsonString(jsonMatch[0]) || jsonMatch[0];
24215
+ const sanitized = sanitizeJsonString(expectDefined22(jsonMatch[0])) || expectDefined22(jsonMatch[0]);
23712
24216
  const skillData = JSON.parse(sanitized);
23713
24217
  return {
23714
24218
  name: skillData.name || `security-scanner-${techStack.stack}`,
@@ -23828,7 +24332,7 @@ Return ONLY the JSON array. If no issues found, return [].`;
23828
24332
  const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
23829
24333
  const jsonMatch = text.match(/\[[\s\S]*\]/);
23830
24334
  if (jsonMatch) {
23831
- const sanitized = sanitizeJsonString(jsonMatch[0]) || jsonMatch[0];
24335
+ const sanitized = sanitizeJsonString(expectDefined22(jsonMatch[0])) || expectDefined22(jsonMatch[0]);
23832
24336
  const parsed = JSON.parse(sanitized);
23833
24337
  return parsed.map((item, idx) => ({
23834
24338
  id: `llm-finding-${idx}-${Date.now()}`,
@@ -24068,7 +24572,7 @@ ${dirs.join(", ")}`);
24068
24572
  if (detectionResult.detectedStacks.length === 0) {
24069
24573
  throw new Error(`No supported tech stack detected in ${projectRoot}`);
24070
24574
  }
24071
- const techStack = detectionResult.detectedStacks[0];
24575
+ const techStack = expectDefined22(detectionResult.detectedStacks[0]);
24072
24576
  return {
24073
24577
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
24074
24578
  projectRoot,
@@ -24257,16 +24761,16 @@ Use \`/security report <number>\` to view a specific report.` };
24257
24761
  }
24258
24762
  const index = Number.parseInt(reportId, 10) - 1;
24259
24763
  if (!Number.isNaN(index) && reports[index]) {
24260
- const { readFile: readFile37 } = await import('fs/promises');
24261
- const content = await readFile37(join(reportsDir, reports[index]), "utf-8");
24764
+ const { readFile: readFile38 } = await import('fs/promises');
24765
+ const content = await readFile38(join(reportsDir, reports[index]), "utf-8");
24262
24766
  return { message: `# Security Report
24263
24767
 
24264
24768
  ${content}` };
24265
24769
  }
24266
24770
  const match = reports.find((r) => r.includes(reportId));
24267
24771
  if (match) {
24268
- const { readFile: readFile37 } = await import('fs/promises');
24269
- const content = await readFile37(join(reportsDir, match), "utf-8");
24772
+ const { readFile: readFile38 } = await import('fs/promises');
24773
+ const content = await readFile38(join(reportsDir, match), "utf-8");
24270
24774
  return { message: `# Security Report
24271
24775
 
24272
24776
  ${content}` };
@@ -24676,6 +25180,12 @@ var FleetManager = class {
24676
25180
  this.usage.dispose();
24677
25181
  }
24678
25182
  };
25183
+ function expectDefined23(value) {
25184
+ if (value === null || value === void 0) {
25185
+ throw new Error("Expected value to be defined");
25186
+ }
25187
+ return value;
25188
+ }
24679
25189
  function createMcpControlTool(opts) {
24680
25190
  const { getConfig, configPath, registry } = opts;
24681
25191
  const inputSchema = {
@@ -24721,11 +25231,11 @@ async function mcpControlDispatch(input, deps) {
24721
25231
  case "search":
24722
25232
  return renderSearch(query ?? "", deps);
24723
25233
  case "enable":
24724
- return runEnable(server, deps);
25234
+ return server ? runEnable(server, deps) : "`server` is required for enable.";
24725
25235
  case "disable":
24726
- return runDisable(server, deps);
25236
+ return server ? runDisable(server, deps) : "`server` is required for disable.";
24727
25237
  case "restart":
24728
- return runRestart(server, deps);
25238
+ return server ? runRestart(server, deps) : "`server` is required for restart.";
24729
25239
  default:
24730
25240
  return `Unknown action "${action}". Use one of: list, search, enable, disable, restart.`;
24731
25241
  }
@@ -24827,7 +25337,7 @@ async function runDisable(name, deps) {
24827
25337
  const mcpServers = {
24828
25338
  ...full.mcpServers ?? {}
24829
25339
  };
24830
- const existing = mcpServers[name];
25340
+ const existing = expectDefined23(mcpServers[name]);
24831
25341
  mcpServers[name] = { ...existing, enabled: false };
24832
25342
  full.mcpServers = mcpServers;
24833
25343
  await writeConfig(deps.configPath, full);
@@ -24898,6 +25408,12 @@ function badge(state) {
24898
25408
  }
24899
25409
 
24900
25410
  // src/extension/registry.ts
25411
+ function expectDefined24(value) {
25412
+ if (value === null || value === void 0) {
25413
+ throw new Error("Expected value to be defined");
25414
+ }
25415
+ return value;
25416
+ }
24901
25417
  var ExtensionRegistry = class {
24902
25418
  extensions = [];
24903
25419
  promptContributors = [];
@@ -25063,11 +25579,12 @@ var ExtensionRegistry = class {
25063
25579
  * default runner, each subsequent wrapper wraps the previous.
25064
25580
  */
25065
25581
  wrapProviderRunner(inner) {
25066
- const wrappers = this.extensions.filter((e) => e.wrapProviderRunner).map((e) => ({ name: e.name, wrap: e.wrapProviderRunner }));
25582
+ const wrappers = this.extensions.filter((e) => e.wrapProviderRunner).map((e) => ({ name: e.name, wrap: expectDefined24(e.wrapProviderRunner) }));
25067
25583
  if (wrappers.length === 0) return inner;
25068
25584
  let composed = inner;
25069
25585
  for (let i = wrappers.length - 1; i >= 0; i--) {
25070
25586
  const wrapper = wrappers[i];
25587
+ if (!wrapper) continue;
25071
25588
  const next = composed;
25072
25589
  composed = async (ctx, req) => {
25073
25590
  try {
@@ -25166,7 +25683,7 @@ function createAgentToolHandler(a) {
25166
25683
  const useById = new Map(selectedToolUses.map((u) => [u.id, u]));
25167
25684
  const resultsForMessage = [];
25168
25685
  for (const { result, tool, durationMs } of outputs) {
25169
- if (result.type === "tool_confirm_pending") {
25686
+ if (result.type === "tool_confirm_pending" && tool) {
25170
25687
  const decision = await waitForConfirm({
25171
25688
  tool,
25172
25689
  input: result.input,
@@ -25228,6 +25745,7 @@ function createAgentToolHandler(a) {
25228
25745
  resultsForMessage.push(reRunResult.result);
25229
25746
  continue;
25230
25747
  }
25748
+ if (result.type !== "tool_result") continue;
25231
25749
  resultsForMessage.push(result);
25232
25750
  const use = useById.get(result.tool_use_id);
25233
25751
  if (!use) continue;
@@ -25743,13 +26261,12 @@ var Agent = class {
25743
26261
  return this.container.resolve(TOKENS.PermissionPolicy);
25744
26262
  }
25745
26263
  get renderer() {
25746
- return this.container.has(TOKENS.Renderer) ? this.container.resolve(TOKENS.Renderer) : void 0;
26264
+ return this.container.safeResolve(TOKENS.Renderer);
25747
26265
  }
25748
26266
  disableInteractiveConfirmation() {
25749
26267
  this.toolExecutor.clearConfirmAwaiter();
25750
- const policy = this.permission;
25751
- if (typeof policy.setPromptDelegate === "function") {
25752
- policy.setPromptDelegate(void 0);
26268
+ if (typeof this.permission.setPromptDelegate === "function") {
26269
+ this.permission.setPromptDelegate(void 0);
25753
26270
  }
25754
26271
  }
25755
26272
  register(tool) {
@@ -25779,6 +26296,7 @@ var Agent = class {
25779
26296
  const signal = controller.signal;
25780
26297
  this.ctx.signal = signal;
25781
26298
  controller.onAbort(() => this.ctx.drainAbortHooks());
26299
+ this.ctx.tools = this.tools.list();
25782
26300
  const span = this.tracer?.startSpan("agent.run", {
25783
26301
  "agent.model": opts.model ?? this.ctx.model,
25784
26302
  "agent.executionStrategy": opts.executionStrategy ?? this.executionStrategy
@@ -25795,7 +26313,8 @@ var Agent = class {
25795
26313
  return result;
25796
26314
  } catch (err) {
25797
26315
  const wse = err instanceof AgentError ? err : toWrongStackError(err);
25798
- this.events.emit("error", { err: err instanceof Error ? err : new Error(String(err)), phase: "agent" });
26316
+ const safeError = err instanceof Error ? new Error(err.message) : new Error(String(err));
26317
+ this.events.emit("error", { err: safeError, phase: "agent", _original: err instanceof Error ? err : void 0 });
25799
26318
  if (err instanceof Error) span?.recordError(err);
25800
26319
  span?.setAttribute("agent.status", "failed");
25801
26320
  const result = {
@@ -26071,12 +26590,14 @@ async function bootConfig(options = {}) {
26071
26590
  const cwd = typeof flags["cwd"] === "string" ? path6.resolve(flags["cwd"]) : process.cwd();
26072
26591
  const pathResolver = new DefaultPathResolver(cwd);
26073
26592
  const projectRoot = pathResolver.projectRoot;
26074
- const userHome = os6.homedir();
26593
+ const userHome = os7.homedir();
26075
26594
  const wpaths = resolveWstackPaths({ projectRoot, userHome });
26076
26595
  await fsp3.mkdir(wpaths.globalRoot, { recursive: true });
26077
26596
  await fsp3.mkdir(wpaths.projectDir, { recursive: true });
26078
26597
  await fsp3.mkdir(wpaths.projectSessions, { recursive: true });
26079
26598
  await writeProjectMeta(wpaths, projectRoot);
26599
+ cleanupStaleProjects(wpaths).catch(() => {
26600
+ });
26080
26601
  const vault = new DefaultSecretVault({ keyFile: wpaths.secretsKey });
26081
26602
  for (const file of [wpaths.globalConfig, wpaths.projectLocalConfig]) {
26082
26603
  try {
@@ -26142,6 +26663,7 @@ async function writeProjectMeta(paths, projectRoot) {
26142
26663
  await fsp3.mkdir(paths.projectDir, { recursive: true });
26143
26664
  const meta = {
26144
26665
  hash: paths.projectHash,
26666
+ slug: paths.projectSlug,
26145
26667
  root: projectRoot,
26146
26668
  lastSeen: (/* @__PURE__ */ new Date()).toISOString()
26147
26669
  };
@@ -26149,6 +26671,31 @@ async function writeProjectMeta(paths, projectRoot) {
26149
26671
  } catch {
26150
26672
  }
26151
26673
  }
26674
+ async function cleanupStaleProjects(wpaths) {
26675
+ const projectsRoot = path6.dirname(wpaths.projectDir);
26676
+ let entries;
26677
+ try {
26678
+ entries = await fsp3.readdir(projectsRoot, { withFileTypes: true });
26679
+ } catch {
26680
+ return;
26681
+ }
26682
+ for (const entry of entries) {
26683
+ if (!entry.isDirectory()) continue;
26684
+ const metaPath = path6.join(projectsRoot, entry.name, "meta.json");
26685
+ try {
26686
+ const raw = await fsp3.readFile(metaPath, "utf8");
26687
+ const meta = JSON.parse(raw);
26688
+ if (typeof meta.root === "string") {
26689
+ try {
26690
+ await fsp3.access(meta.root);
26691
+ } catch {
26692
+ await fsp3.rm(path6.join(projectsRoot, entry.name), { recursive: true, force: true });
26693
+ }
26694
+ }
26695
+ } catch {
26696
+ }
26697
+ }
26698
+ }
26152
26699
 
26153
26700
  // src/core/conversation-state.ts
26154
26701
  var ConversationState = class {
@@ -26187,9 +26734,11 @@ var ConversationState = class {
26187
26734
  this.emit({ kind: "messages_replaced", messages: [...messages] });
26188
26735
  }
26189
26736
  replaceTodos(todos) {
26737
+ const allDone = todos.length > 0 && todos.every((t2) => t2.status === "completed");
26738
+ const effective = allDone ? [] : todos;
26190
26739
  this.ctx.todos.length = 0;
26191
- this.ctx.todos.splice(0, 0, ...todos);
26192
- this.emit({ kind: "todos_replaced", todos: [...todos] });
26740
+ this.ctx.todos.splice(0, 0, ...effective);
26741
+ this.emit({ kind: "todos_replaced", todos: [...effective] });
26193
26742
  }
26194
26743
  setMeta(key, value) {
26195
26744
  this.ctx.meta[key] = value;
@@ -26813,7 +27362,7 @@ summarize it, and let the tool result hold only the summary.`);
26813
27362
  const cached = this.envCacheByRoot.get(ctx.projectRoot);
26814
27363
  if (cached) return cached;
26815
27364
  const today = this.opts.todayIso ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
26816
- const platform2 = `${os6.platform()} ${os6.release()}`;
27365
+ const platform2 = `${os7.platform()} ${os7.release()}`;
26817
27366
  const shell = process.env.SHELL ?? process.env.ComSpec ?? "unknown";
26818
27367
  const node = process.version;
26819
27368
  const isGit = await this.dirExists(path6.join(ctx.projectRoot, ".git"));
@@ -27752,6 +28301,104 @@ function wrapApiForCapabilityCheck(plugin, api, log, enforce = false) {
27752
28301
  });
27753
28302
  }
27754
28303
 
28304
+ // src/execution/prompt-enhancer.ts
28305
+ var ENHANCER_SYSTEM_PROMPT = `You are a request refiner embedded in a coding agent. Your ONLY job is to rewrite the user's message into a single, clearer, unambiguous instruction that the coding agent can act on confidently.
28306
+
28307
+ Rules:
28308
+ - Preserve the user's intent and scope EXACTLY. Do not add new requirements, features, constraints, or steps the user did not ask for. Do not remove anything they did ask for.
28309
+ - Do NOT answer, solve, or perform the request. Only restate it more clearly.
28310
+ - Keep all concrete details verbatim: file paths, identifiers, code, error text, numbers, names, URLs.
28311
+ - Resolve obvious ambiguity by making the implied subject explicit, not by inventing specifics. If something is genuinely unspecified, leave it general rather than guessing.
28312
+ - Be concise: one tight instruction (a few sentences at most). No preamble, no explanation, no quotes, no markdown headers.
28313
+ - If the message is already clear and complete, return it essentially unchanged.
28314
+ - Preserve the user's language (if they wrote in Turkish, refine in Turkish).
28315
+
28316
+ When earlier conversation turns are provided, they are CONTEXT ONLY. Use them to resolve references in the user's latest message \u2014 "it", "that", "the same", "the other one", "this file", "again" \u2014 so the refined instruction is self-contained. Refine ONLY the user's latest message; do not answer it, do not act on or restate earlier turns, and do not summarize the conversation.
28317
+
28318
+ Output ONLY the refined request text \u2014 nothing else.`;
28319
+ var AFFIRMATION_RE = /^(y|n|yes|no|yep|nope|ok|okay|sure|go|go ahead|continue|proceed|stop|cancel|done|next|skip|retry|again|please do|do it)\b[.! ]*$/i;
28320
+ function shouldEnhance(text) {
28321
+ const t2 = text.trim();
28322
+ if (!t2) return false;
28323
+ if (t2.startsWith("/")) return false;
28324
+ if (t2.length < 12) return false;
28325
+ if (AFFIRMATION_RE.test(t2)) return false;
28326
+ if (/^[\d\s.,]+$/.test(t2)) return false;
28327
+ const words = t2.split(/\s+/).filter(Boolean);
28328
+ if (words.length < 3) return false;
28329
+ return true;
28330
+ }
28331
+ function normalizedEqual(a, b) {
28332
+ const norm = (s) => s.trim().replace(/\s+/g, " ").toLowerCase();
28333
+ return norm(a) === norm(b);
28334
+ }
28335
+ function buildRefinerInput(text, history) {
28336
+ if (!history || history.length === 0) return text;
28337
+ const lines = history.map((t2) => `${t2.role === "user" ? "User" : "Assistant"}: ${t2.text}`);
28338
+ return [
28339
+ "Recent conversation (context only \u2014 do not act on it):",
28340
+ ...lines,
28341
+ "",
28342
+ "Latest message to refine:",
28343
+ text
28344
+ ].join("\n");
28345
+ }
28346
+ async function enhanceUserPrompt(opts) {
28347
+ const { provider, model, text } = opts;
28348
+ const timeoutMs = opts.timeoutMs ?? 9e4;
28349
+ const maxTokens = opts.maxTokens ?? 2048;
28350
+ const req = {
28351
+ model,
28352
+ system: [{ type: "text", text: ENHANCER_SYSTEM_PROMPT }],
28353
+ messages: [{ role: "user", content: buildRefinerInput(text, opts.history) }],
28354
+ maxTokens
28355
+ // NOTE: deliberately NO `temperature`. The main agent loop never sets it,
28356
+ // and reasoning models (DeepSeek reasoner, o1/o3, …) return HTTP 400 when
28357
+ // `temperature` is present — which would make every refine call fail and
28358
+ // silently fall back to the original (no panel shown).
28359
+ };
28360
+ const timer = new AbortController();
28361
+ const to = setTimeout(() => timer.abort(new Error("enhancer timeout")), timeoutMs);
28362
+ const signal = opts.signal ? AbortSignal.any([opts.signal, timer.signal]) : timer.signal;
28363
+ try {
28364
+ const res = await provider.complete(req, { signal });
28365
+ const refined = res.content.filter(isTextBlock).map((b) => b.text).join("\n").trim();
28366
+ if (!refined) {
28367
+ opts.onError?.("model returned no text");
28368
+ return null;
28369
+ }
28370
+ return refined;
28371
+ } catch (err) {
28372
+ if (opts.signal?.aborted) return null;
28373
+ if (timer.signal.aborted) {
28374
+ opts.onError?.(`timed out after ${Math.round(timeoutMs / 1e3)}s`);
28375
+ return null;
28376
+ }
28377
+ opts.onError?.(err instanceof Error ? err.message : String(err));
28378
+ return null;
28379
+ } finally {
28380
+ clearTimeout(to);
28381
+ }
28382
+ }
28383
+ function messageText(content) {
28384
+ if (typeof content === "string") return content;
28385
+ return content.filter(isTextBlock).map((b) => b.text).join("\n").trim();
28386
+ }
28387
+ function recentTextTurns(messages, maxTurns = 6, maxChars = 1500) {
28388
+ const turns = [];
28389
+ for (let i = messages.length - 1; i >= 0 && turns.length < maxTurns; i--) {
28390
+ const m = messages[i];
28391
+ if (!m || m.role !== "user" && m.role !== "assistant") continue;
28392
+ const text = messageText(m.content);
28393
+ if (!text) continue;
28394
+ turns.unshift({
28395
+ role: m.role,
28396
+ text: text.length > maxChars ? `${text.slice(0, maxChars - 1)}\u2026` : text
28397
+ });
28398
+ }
28399
+ return turns;
28400
+ }
28401
+
27755
28402
  // src/autophase/phase-graph-builder.ts
27756
28403
  var PhaseGraphBuilder = class _PhaseGraphBuilder {
27757
28404
  constructor(opts) {
@@ -27763,7 +28410,7 @@ var PhaseGraphBuilder = class _PhaseGraphBuilder {
27763
28410
  const phases = /* @__PURE__ */ new Map();
27764
28411
  const phaseIds = [];
27765
28412
  for (let i = 0; i < this.opts.phases.length; i++) {
27766
- const tmpl = this.opts.phases[i];
28413
+ const tmpl = this.opts.phases[i] ?? { name: "", description: "", taskTemplates: [], parallelizable: false, priority: "medium", estimateHours: 0 };
27767
28414
  const phaseId = crypto.randomUUID();
27768
28415
  phaseIds.push(phaseId);
27769
28416
  const store = this.opts.externalTaskStore ?? new DefaultTaskStore();
@@ -27788,8 +28435,8 @@ var PhaseGraphBuilder = class _PhaseGraphBuilder {
27788
28435
  description: tmpl.description,
27789
28436
  status: "pending",
27790
28437
  taskGraph,
27791
- dependsOn: i > 0 ? [phaseIds[i - 1]] : [],
27792
- nextPhases: i < this.opts.phases.length - 1 ? [phaseIds[i + 1]] : [],
28438
+ dependsOn: i > 0 ? [phaseIds[i - 1] ?? ""] : [],
28439
+ nextPhases: i < this.opts.phases.length - 1 ? [phaseIds[i + 1] ?? ""] : [],
27793
28440
  parallelizable: tmpl.parallelizable,
27794
28441
  priority: tmpl.priority,
27795
28442
  estimateHours: tmpl.estimateHours,
@@ -27802,15 +28449,16 @@ var PhaseGraphBuilder = class _PhaseGraphBuilder {
27802
28449
  const phaseArray = Array.from(phases.values());
27803
28450
  for (let i = 0; i < phaseArray.length; i++) {
27804
28451
  const phase = phaseArray[i];
27805
- phase.nextPhases = i < phaseArray.length - 1 ? [phaseArray[i + 1].id] : [];
27806
- phase.dependsOn = i > 0 ? [phaseArray[i - 1].id] : [];
28452
+ if (!phase) continue;
28453
+ phase.nextPhases = i < phaseArray.length - 1 ? [phaseArray[i + 1]?.id ?? ""] : [];
28454
+ phase.dependsOn = i > 0 ? [phaseArray[i - 1]?.id ?? ""] : [];
27807
28455
  }
27808
28456
  const graph = {
27809
28457
  id: graphId,
27810
28458
  title: this.opts.title,
27811
28459
  description: this.opts.description ?? "",
27812
28460
  phases,
27813
- rootPhaseIds: phaseIds.length > 0 ? [phaseIds[0]] : [],
28461
+ rootPhaseIds: phaseIds.length > 0 ? [phaseIds[0] ?? ""] : [],
27814
28462
  activePhaseIds: [],
27815
28463
  completedPhaseIds: [],
27816
28464
  failedPhaseIds: [],
@@ -27992,7 +28640,7 @@ var PhaseOrchestrator = class {
27992
28640
  return;
27993
28641
  }
27994
28642
  if (this.opts.stopOnFailure && this.graph.failedPhaseIds.length > 0) {
27995
- const failedPhase = this.graph.phases.get(this.graph.failedPhaseIds[0]);
28643
+ const failedPhase = this.graph.phases.get(this.graph.failedPhaseIds[0] ?? "");
27996
28644
  if (failedPhase) {
27997
28645
  this.onGraphFailed(failedPhase);
27998
28646
  }
@@ -28168,9 +28816,14 @@ var PhaseOrchestrator = class {
28168
28816
  name: phase.name,
28169
28817
  files: info.conflictFiles
28170
28818
  });
28171
- return this.ctx.resolveConflict(phase, info);
28819
+ const resolved = await this.ctx.resolveConflict?.(phase, info);
28820
+ return resolved ?? false;
28172
28821
  } : void 0;
28173
- const result = await this.worktrees.merge(handle, { squash: true, resolve: resolve13 });
28822
+ const mergeOpts = {
28823
+ squash: true
28824
+ };
28825
+ if (resolve13 !== void 0) mergeOpts.resolve = resolve13;
28826
+ const result = await this.worktrees.merge(handle, mergeOpts);
28174
28827
  if (result.resolved) {
28175
28828
  this.emit("phase.conflictResolved", { phaseId: phase.id, name: phase.name });
28176
28829
  }
@@ -28564,9 +29217,6 @@ var AutoPhaseRunner = class {
28564
29217
  this.graph = await builder.build();
28565
29218
  const ctx = {
28566
29219
  executeTask: this.opts.executeTask,
28567
- verifyPhase: this.opts.verifyPhase,
28568
- repairPhase: this.opts.repairPhase,
28569
- resolveConflict: this.opts.resolveConflict,
28570
29220
  brain: this.opts.brain,
28571
29221
  onPhaseComplete: (phase) => {
28572
29222
  this.opts.onPhaseComplete?.(phase);
@@ -28578,6 +29228,9 @@ var AutoPhaseRunner = class {
28578
29228
  this.opts.onTick?.(tickCtx);
28579
29229
  }
28580
29230
  };
29231
+ if (this.opts.verifyPhase !== void 0) ctx.verifyPhase = this.opts.verifyPhase;
29232
+ if (this.opts.repairPhase !== void 0) ctx.repairPhase = this.opts.repairPhase;
29233
+ if (this.opts.resolveConflict !== void 0) ctx.resolveConflict = this.opts.resolveConflict;
28581
29234
  this.orchestrator = new PhaseOrchestrator({
28582
29235
  graph: this.graph,
28583
29236
  ctx,
@@ -28593,8 +29246,8 @@ var AutoPhaseRunner = class {
28593
29246
  });
28594
29247
  if (this.opts.onProgress) {
28595
29248
  this.progressInterval = setInterval(() => {
28596
- const progress = this.orchestrator.getProgress();
28597
- this.opts.onProgress(progress);
29249
+ const progress = this.orchestrator?.getProgress();
29250
+ if (progress) this.opts.onProgress?.(progress);
28598
29251
  }, 2e3);
28599
29252
  }
28600
29253
  if (this.opts.events) {
@@ -28814,7 +29467,7 @@ function firstBalancedArray(text) {
28814
29467
  let inString = false;
28815
29468
  let escaped = false;
28816
29469
  for (let i = start; i < text.length; i++) {
28817
- const ch = text[i];
29470
+ const ch = text[i] ?? "";
28818
29471
  if (inString) {
28819
29472
  if (escaped) {
28820
29473
  escaped = false;
@@ -29324,7 +29977,7 @@ ${merged.stderr}`);
29324
29977
  async tryResolveConflict(handle, conflictFiles, opts) {
29325
29978
  let resolved = false;
29326
29979
  try {
29327
- resolved = await opts.resolve({ conflictFiles, cwd: this.projectRoot });
29980
+ resolved = opts.resolve ? await opts.resolve({ conflictFiles, cwd: this.projectRoot }) : false;
29328
29981
  } catch {
29329
29982
  resolved = false;
29330
29983
  }
@@ -29847,6 +30500,12 @@ var ReplayProviderRunner = class {
29847
30500
  };
29848
30501
 
29849
30502
  // src/plugins/prompts-plugin.ts
30503
+ function expectDefined25(value) {
30504
+ if (value === null || value === void 0) {
30505
+ throw new Error("Expected value to be defined");
30506
+ }
30507
+ return value;
30508
+ }
29850
30509
  function createPromptsPlugin(opts) {
29851
30510
  let store = null;
29852
30511
  return {
@@ -29900,7 +30559,7 @@ ${lines.join("\n")}
29900
30559
  if (!restJoined) return { message: "Usage: /prompts view <title>" };
29901
30560
  const matches = await store.find(restJoined);
29902
30561
  if (matches.length === 0) return { message: `No prompt matching "${restJoined}".` };
29903
- const entry = matches.find((m) => m.title.toLowerCase() === restJoined.toLowerCase()) ?? matches[0];
30562
+ const entry = matches.find((m) => m.title.toLowerCase() === restJoined.toLowerCase()) ?? expectDefined25(matches[0]);
29904
30563
  const tags = entry.tags.length > 0 ? ` [${entry.tags.join(", ")}]` : "";
29905
30564
  return {
29906
30565
  message: `# ${entry.title}${tags}
@@ -29923,7 +30582,7 @@ ${dim2(`id: ${entry.id} | created: ${entry.createdAt}`)}`
29923
30582
  if (!restJoined) return { message: "Usage: /prompts delete <title>" };
29924
30583
  const matches = await store.find(restJoined);
29925
30584
  if (matches.length === 0) return { message: `No prompt matching "${restJoined}".` };
29926
- const exact = matches.find((m) => m.title.toLowerCase() === restJoined.toLowerCase()) ?? matches[0];
30585
+ const exact = matches.find((m) => m.title.toLowerCase() === restJoined.toLowerCase()) ?? expectDefined25(matches[0]);
29927
30586
  const deleted = await store.delete(exact.id);
29928
30587
  return { message: deleted ? `Deleted "${exact.title}".` : "Delete failed." };
29929
30588
  }
@@ -29933,7 +30592,7 @@ ${dim2(`id: ${entry.id} | created: ${entry.createdAt}`)}`
29933
30592
  if (!parsed.title) return { message: 'Usage: /prompts edit "title" "new content"' };
29934
30593
  const matches = await store.find(parsed.title);
29935
30594
  if (matches.length === 0) return { message: `No prompt matching "${parsed.title}".` };
29936
- const exact = matches.find((m) => m.title.toLowerCase() === parsed.title.toLowerCase()) ?? matches[0];
30595
+ const exact = matches.find((m) => m.title.toLowerCase() === parsed.title?.toLowerCase()) ?? expectDefined25(matches[0]);
29937
30596
  exact.content = parsed.content;
29938
30597
  exact.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
29939
30598
  await store.save(exact);
@@ -29945,7 +30604,7 @@ ${dim2(`id: ${entry.id} | created: ${entry.createdAt}`)}`
29945
30604
  if (!parsed.title) return { message: 'Usage: /prompts extend "title" <instructions>' };
29946
30605
  const matches = await store.find(parsed.title);
29947
30606
  if (matches.length === 0) return { message: `No prompt matching "${parsed.title}".` };
29948
- const exact = matches.find((m) => m.title.toLowerCase() === parsed.title.toLowerCase()) ?? matches[0];
30607
+ const exact = matches.find((m) => m.title.toLowerCase() === parsed.title?.toLowerCase()) ?? expectDefined25(matches[0]);
29949
30608
  const prov = ctx.provider;
29950
30609
  if (!prov?.complete) return { message: "LLM not available. Configure a provider first." };
29951
30610
  const enhanced = await prov.complete(ctx.model, [
@@ -29980,9 +30639,9 @@ function parseTitleContent(args) {
29980
30639
  const trimmed = args.trim();
29981
30640
  if (!trimmed) return { title: "", content: "" };
29982
30641
  const doubleMatch = /^"([^"]+)"\s+"([^"]+)"$/.exec(trimmed) || /^'([^']+)'\s+'([^']+)'$/.exec(trimmed);
29983
- if (doubleMatch) return { title: doubleMatch[1], content: doubleMatch[2] };
30642
+ if (doubleMatch) return { title: expectDefined25(doubleMatch[1]), content: expectDefined25(doubleMatch[2]) };
29984
30643
  const singleMatch = /^'([^']+)'\s+(.+)$/.exec(trimmed);
29985
- if (singleMatch) return { title: singleMatch[1], content: singleMatch[2] };
30644
+ if (singleMatch) return { title: expectDefined25(singleMatch[1]), content: expectDefined25(singleMatch[2]) };
29986
30645
  const firstSpace = trimmed.indexOf(" ");
29987
30646
  if (firstSpace === -1) return { title: trimmed, content: "" };
29988
30647
  return { title: trimmed.slice(0, firstSpace), content: trimmed.slice(firstSpace + 1) };
@@ -29993,6 +30652,12 @@ function dim2(s) {
29993
30652
 
29994
30653
  // src/plugins/sync-plugin.ts
29995
30654
  init_atomic_write();
30655
+ function expectDefined26(value) {
30656
+ if (value === null || value === void 0) {
30657
+ throw new Error("Expected value to be defined");
30658
+ }
30659
+ return value;
30660
+ }
29996
30661
  function createSyncPlugin(opts) {
29997
30662
  let cloud = null;
29998
30663
  let configStore;
@@ -30018,11 +30683,11 @@ function createSyncPlugin(opts) {
30018
30683
  cloud = new CloudSync(
30019
30684
  paths,
30020
30685
  () => {
30021
- const cfg = configStore.get();
30686
+ const cfg = configStore?.get();
30022
30687
  return cfg.sync;
30023
30688
  },
30024
30689
  async (cfg) => {
30025
- configStore.update({ sync: cfg });
30690
+ configStore?.update({ sync: cfg });
30026
30691
  }
30027
30692
  );
30028
30693
  void cloud.loadState();
@@ -30066,7 +30731,7 @@ function buildSyncCommand(cloud, configStore, vault, syncConfigPath) {
30066
30731
  if (!repo || !repo.includes("/")) {
30067
30732
  return { message: 'Invalid repo format. Expected "owner/repo".' };
30068
30733
  }
30069
- const storedToken = vault ? vault.encrypt(token) : token;
30734
+ const storedToken = vault ? vault.encrypt(expectDefined26(token)) : expectDefined26(token);
30070
30735
  const syncConfig = {
30071
30736
  enabled: true,
30072
30737
  repo,
@@ -30306,7 +30971,7 @@ async function generateCommitMessageHeuristics(cwd) {
30306
30971
  const commitType = detectCommitType(statsResult.stdout);
30307
30972
  let scope = "";
30308
30973
  if (files.length > 0) {
30309
- const primary = files[0].split("/")[0];
30974
+ const primary = files[0]?.split("/")[0];
30310
30975
  if (primary && primary !== "packages" && primary !== "apps" && primary !== "node_modules") {
30311
30976
  scope = `(${primary})`;
30312
30977
  }
@@ -30552,7 +31217,7 @@ function createSkillsPlugin(opts) {
30552
31217
  };
30553
31218
  }
30554
31219
  function makeInstaller(skillLoader, projectRoot) {
30555
- const globalRoot = path6.join(os6.homedir(), ".wrongstack");
31220
+ const globalRoot = path6.join(os7.homedir(), ".wrongstack");
30556
31221
  return new SkillInstaller({
30557
31222
  manifestPath: path6.join(globalRoot, "installed-skills.json"),
30558
31223
  projectSkillsDir: path6.join(projectRoot, ".wrongstack", "skills"),
@@ -30903,6 +31568,6 @@ ${formatPlan(updated)}`
30903
31568
  };
30904
31569
  }
30905
31570
 
30906
- export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, ALL_SYNC_CATEGORIES, AUDIT_LOG_AGENT, Agent, AgentError, AnnotationsStore, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhasePlanner, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BrainDecisionQueue, BudgetExceededError, CONTEXT_WINDOW_MODES, CORE_RECONSTRUCT_EVENTS, CheckpointManager, CloudSync, CollaborationBus, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SESSION_LOGGING_CONFIG, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultBrainArbiter, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultPromptStore, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, HookRegistry, HookRunner, HumanEscalatingBrainArbiter, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MATRIX_PHASE_KEYS, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, ObservableBrainArbiter, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReplayLogStore, ReplayProviderRunner, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, STANDARD_AUDIT_EVENTS, ScopedEventBus, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SessionRecovery, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolAuditLog, ToolError, ToolExecutor, ToolRegistry, WorktreeManager, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, assertSafePath, atomicWrite, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, bootConfig, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, collabInjectMiddleware, collabPauseMiddleware, color, compileGlob, compileUserRegex, completePartialObject, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, consumeBtwNotes, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createContextManagerTool, createDefaultPipelines, createDelegateTool, createGitPlugin, createMcpControlTool, createMessage, createObservabilityPlugin, createPlanPlugin, createPromptsPlugin, createSecurityPlugin, createSecuritySlashCommand, createSessionEventBridge, createSkillsPlugin, createSyncPlugin, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, dispatchAgent, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateRequestTokensCalibrated, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, expandGlob, extractRunEnv, filesystemServer, findCriticalPath, flagsToConfigPatch, formatContextWindowModeList, formatGoal, formatHumanPrompt, formatPlan, formatPlanTemplates, formatTodosList, getAgentDefinition, getCalibrationState, getContextWindowMode, getPlanTemplate, getTemplate, getTermSize, githubServer, goalFilePath, googleMapsServer, hashRequest, hookMatcherMatches, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isInteractive, isPluginError, isSessionError, isStdinTTY, isStdoutTTY, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isValidMatrixKey, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeContinueToNextIterationTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, matchAny, matchGlob, matrixKeyKind, mergeCustomModelDefs, mergeModelsPayload, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, onResize, parseContinueDirective, parseSkillRef, pendingBtwCount, phaseForRole, projectHash, recordActualUsage, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resetCalibration, resolveAuditLevel, resolveContextWindowPolicy, resolveModelMatrix, resolveSessionLoggingConfig, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, runProviderWithRetry, runShellHook, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, scoreAgents, securitySlashCommand, sentinelServer, setBtwNote, setPlanItemStatus, setRawMode, slackServer, stableStringify, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, writeErr, writeOut, zaiVisionServer };
31571
+ export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, ALL_SYNC_CATEGORIES, AUDIT_LOG_AGENT, Agent, AgentError, AnnotationsStore, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhasePlanner, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BrainDecisionQueue, BudgetExceededError, CONTEXT_WINDOW_MODES, CORE_RECONSTRUCT_EVENTS, CheckpointManager, CloudSync, CollaborationBus, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SESSION_LOGGING_CONFIG, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultBrainArbiter, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultPromptStore, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ENHANCER_SYSTEM_PROMPT, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, HookRegistry, HookRunner, HumanEscalatingBrainArbiter, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MATRIX_PHASE_KEYS, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, ObservableBrainArbiter, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReplayLogStore, ReplayProviderRunner, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, STANDARD_AUDIT_EVENTS, ScopedEventBus, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SessionRecovery, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolAuditLog, ToolError, ToolExecutor, ToolRegistry, WorktreeManager, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, assertSafePath, atomicWrite, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, bootConfig, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, collabInjectMiddleware, collabPauseMiddleware, color, compileGlob, compileUserRegex, completePartialObject, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, consumeBtwNotes, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createContextManagerTool, createDefaultPipelines, createDelegateTool, createGitPlugin, createMcpControlTool, createMessage, createObservabilityPlugin, createPlanPlugin, createPromptsPlugin, createSecurityPlugin, createSecuritySlashCommand, createSessionEventBridge, createSkillsPlugin, createSyncPlugin, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, dispatchAgent, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, enhanceUserPrompt, ensureDir, estimateRequestTokens, estimateRequestTokensCalibrated, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, expandGlob, extractRunEnv, filesystemServer, findCriticalPath, flagsToConfigPatch, formatContextWindowModeList, formatGoal, formatHumanPrompt, formatPlan, formatPlanTemplates, formatTodosList, getAgentDefinition, getCalibrationState, getContextWindowMode, getPlanTemplate, getTemplate, getTermSize, githubServer, goalFilePath, googleMapsServer, hashRequest, hookMatcherMatches, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isInteractive, isPluginError, isSessionError, isStdinTTY, isStdoutTTY, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isValidMatrixKey, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeContinueToNextIterationTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, matchAny, matchGlob, matrixKeyKind, mergeCustomModelDefs, mergeModelsPayload, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, normalizedEqual, onResize, parseContinueDirective, parseSkillRef, pendingBtwCount, phaseForRole, projectHash, projectSlug, recentTextTurns, recordActualUsage, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resetCalibration, resolveAuditLevel, resolveContextWindowPolicy, resolveModelMatrix, resolveSessionLoggingConfig, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, runProviderWithRetry, runShellHook, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, scoreAgents, securitySlashCommand, sentinelServer, setBtwNote, setOutputLineGuard, setPlanItemStatus, setRawMode, shouldEnhance, slackServer, stableStringify, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, writeErr, writeOut, zaiVisionServer };
30907
31572
  //# sourceMappingURL=index.js.map
30908
31573
  //# sourceMappingURL=index.js.map