@wrongstack/core 0.119.1 → 0.141.0

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 (64) hide show
  1. package/dist/{agent-bridge-PRAbEX-9.d.ts → agent-bridge-r9y6gdn4.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-DXWImnNV.d.ts → agent-subagent-runner-1GeQE_L0.d.ts} +7 -7
  3. package/dist/{brain-NZZqL8sn.d.ts → brain-Cp_3GIS2.d.ts} +14 -3
  4. package/dist/{compactor-C3stu664.d.ts → compactor-BueGt7LG.d.ts} +9 -1
  5. package/dist/{config-DZV9VK9n.d.ts → config-BaVThgnT.d.ts} +1 -1
  6. package/dist/{context-hvXINa6a.d.ts → context-C7G_MtLV.d.ts} +7 -0
  7. package/dist/coordination/index.d.ts +12 -12
  8. package/dist/coordination/index.js +31 -17
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +24 -24
  11. package/dist/defaults/index.js +638 -681
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/execution/index.d.ts +14 -14
  14. package/dist/execution/index.js +326 -317
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/{goal-preamble-COpt55W8.d.ts → goal-preamble-iuIUTQwk.d.ts} +47 -17
  18. package/dist/{index-Cj3le7TI.d.ts → index-BZdezm3g.d.ts} +8 -8
  19. package/dist/{index-4VVHuTZF.d.ts → index-CPweVoFM.d.ts} +5 -5
  20. package/dist/index.d.ts +47 -47
  21. package/dist/index.js +455 -503
  22. package/dist/index.js.map +1 -1
  23. package/dist/infrastructure/index.d.ts +6 -6
  24. package/dist/infrastructure/index.js +64 -19
  25. package/dist/infrastructure/index.js.map +1 -1
  26. package/dist/kernel/index.d.ts +9 -9
  27. package/dist/kernel/index.js.map +1 -1
  28. package/dist/{llm-selector-Bmx4PsVM.d.ts → llm-selector-CP72f1lC.d.ts} +2 -2
  29. package/dist/{mcp-servers-CofNHOqn.d.ts → mcp-servers-Bl5LTvQg.d.ts} +3 -3
  30. package/dist/models/index.d.ts +5 -5
  31. package/dist/models/index.js +53 -20
  32. package/dist/models/index.js.map +1 -1
  33. package/dist/{models-registry-BzlsjKcy.d.ts → models-registry-D90K9UnM.d.ts} +1 -1
  34. package/dist/{multi-agent-coordinator-CmDmUgq2.d.ts → multi-agent-coordinator-QWEzJDlm.d.ts} +1 -1
  35. package/dist/{null-fleet-bus-CyH2YqP4.d.ts → null-fleet-bus-BUyfqh23.d.ts} +13 -10
  36. package/dist/observability/index.d.ts +2 -2
  37. package/dist/{parallel-eternal-engine-uxVm4y4V.d.ts → parallel-eternal-engine-Dj2SYzha.d.ts} +24 -11
  38. package/dist/{path-resolver-gfoGxpdd.d.ts → path-resolver-DRjQBkoO.d.ts} +3 -3
  39. package/dist/{permission-DhLrgA30.d.ts → permission-B7nKnEvQ.d.ts} +1 -1
  40. package/dist/{permission-policy-DGOvne7i.d.ts → permission-policy-8-6zBmfA.d.ts} +2 -13
  41. package/dist/{pipeline-CqF7uju2.d.ts → pipeline-BG7UgbDc.d.ts} +2 -2
  42. package/dist/{plan-templates-DoKhzenv.d.ts → plan-templates-CkKNPU3I.d.ts} +5 -5
  43. package/dist/{provider-runner-BPlI5sPZ.d.ts → provider-runner-BNpuIyOL.d.ts} +3 -3
  44. package/dist/{retry-policy-B4Q-FZgE.d.ts → retry-policy-rutAfVeR.d.ts} +1 -1
  45. package/dist/sdd/index.d.ts +8 -8
  46. package/dist/sdd/index.js +10 -1
  47. package/dist/sdd/index.js.map +1 -1
  48. package/dist/{secret-vault-B7GnL6o9.d.ts → secret-vault-BTcC_T5v.d.ts} +3 -2
  49. package/dist/security/index.d.ts +5 -7
  50. package/dist/security/index.js +4 -35
  51. package/dist/security/index.js.map +1 -1
  52. package/dist/{selector-BakeMnWR.d.ts → selector-4vDFZKt3.d.ts} +1 -1
  53. package/dist/{session-event-bridge-DE5Oekwx.d.ts → session-event-bridge-DWlvglC2.d.ts} +2 -2
  54. package/dist/{session-reader-DFC81-4p.d.ts → session-reader-BAtCxdaw.d.ts} +1 -1
  55. package/dist/storage/index.d.ts +13 -13
  56. package/dist/storage/index.js +98 -101
  57. package/dist/storage/index.js.map +1 -1
  58. package/dist/types/index.d.ts +18 -18
  59. package/dist/types/index.js +152 -102
  60. package/dist/types/index.js.map +1 -1
  61. package/dist/utils/index.d.ts +37 -13
  62. package/dist/utils/index.js +60 -32
  63. package/dist/utils/index.js.map +1 -1
  64. package/package.json +2 -2
@@ -1,9 +1,9 @@
1
1
  import * as crypto2 from 'crypto';
2
- import { randomBytes, randomUUID, createCipheriv, createDecipheriv, createHash } from 'crypto';
2
+ import { randomBytes, createCipheriv, createDecipheriv, randomUUID, createHash } from 'crypto';
3
3
  import * as fsp from 'fs/promises';
4
4
  import * as path11 from 'path';
5
5
  import { isAbsolute, resolve } from 'path';
6
- import * as fs5 from 'fs';
6
+ import * as fs4 from 'fs';
7
7
  import * as os from 'os';
8
8
  import { hostname } from 'os';
9
9
  import { execFile } from 'child_process';
@@ -218,7 +218,7 @@ var DefaultLogger = class _DefaultLogger {
218
218
  this.stderr = opts.stderr !== false;
219
219
  if (this.file) {
220
220
  try {
221
- fs5.mkdirSync(path11.dirname(this.file), { recursive: true });
221
+ fs4.mkdirSync(path11.dirname(this.file), { recursive: true });
222
222
  } catch {
223
223
  }
224
224
  }
@@ -258,7 +258,7 @@ var DefaultLogger = class _DefaultLogger {
258
258
  }
259
259
  if (this.file) {
260
260
  try {
261
- fs5.appendFileSync(this.file, `${JSON.stringify(entry)}
261
+ fs4.appendFileSync(this.file, `${JSON.stringify(entry)}
262
262
  `);
263
263
  } catch {
264
264
  }
@@ -452,8 +452,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
452
452
  onClose: (s) => this.appendToIndex(s)
453
453
  });
454
454
  } catch (err) {
455
- await handle.close().catch(() => {
456
- });
455
+ await handle.close().catch((e) => console.warn(`[session-store] handle.close() failed: ${e}`));
457
456
  throw err;
458
457
  }
459
458
  }
@@ -484,8 +483,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
484
483
  );
485
484
  return { writer, data };
486
485
  } catch (err) {
487
- await handle.close().catch(() => {
488
- });
486
+ await handle.close().catch((e) => console.warn(`[session-store] handle.close() failed: ${e}`));
489
487
  throw err;
490
488
  }
491
489
  }
@@ -674,15 +672,15 @@ var DefaultSessionStore = class _DefaultSessionStore {
674
672
  * sidecars, and the session directory (fleet.json, shared/, subagents/).
675
673
  */
676
674
  async deleteSession(id) {
677
- await fsp.unlink(this.sessionPath(id, ".jsonl")).catch(() => void 0);
678
- await fsp.unlink(this.sessionPath(id, ".summary.json")).catch(() => void 0);
675
+ await fsp.unlink(this.sessionPath(id, ".jsonl")).catch((err) => console.warn(`[session-store] delete .jsonl failed: ${err}`));
676
+ await fsp.unlink(this.sessionPath(id, ".summary.json")).catch((err) => console.warn(`[session-store] delete .summary.json failed: ${err}`));
679
677
  const shardDir = path11.dirname(path11.join(this.dir, id));
680
678
  const base = path11.basename(id);
681
679
  for (const ext of [".plan.json", ".todos.json"]) {
682
- await fsp.unlink(path11.join(shardDir, `${base}${ext}`)).catch(() => void 0);
680
+ await fsp.unlink(path11.join(shardDir, `${base}${ext}`)).catch((err) => console.warn(`[session-store] delete ${ext} failed: ${err}`));
683
681
  }
684
682
  const sessDir = path11.join(shardDir, base);
685
- await fsp.rm(sessDir, { recursive: true, force: true }).catch(() => void 0);
683
+ await fsp.rm(sessDir, { recursive: true, force: true }).catch((err) => console.warn(`[session-store] delete session dir failed: ${err}`));
686
684
  await this.writeTombstone(id);
687
685
  }
688
686
  async delete(id) {
@@ -1985,20 +1983,101 @@ function deepFreeze(obj) {
1985
1983
  return Object.freeze(obj);
1986
1984
  }
1987
1985
 
1988
- // src/security/config-secrets.ts
1989
- function decryptConfigSecrets(cfg, vault) {
1986
+ // src/types/secret-vault.ts
1987
+ var ENCRYPTED_PREFIX = "enc:v1:";
1988
+
1989
+ // src/security/secret-vault.ts
1990
+ init_atomic_write();
1991
+ var KEY_BYTES = 32;
1992
+ var IV_BYTES = 12;
1993
+ var TAG_BYTES = 16;
1994
+ var ALGO = "aes-256-gcm";
1995
+ var DefaultSecretVault = class {
1996
+ keyFile;
1997
+ key;
1998
+ constructor(opts) {
1999
+ this.keyFile = opts.keyFile;
2000
+ }
2001
+ isEncrypted(value) {
2002
+ return typeof value === "string" && value.startsWith(ENCRYPTED_PREFIX);
2003
+ }
2004
+ encrypt(plaintext) {
2005
+ if (this.isEncrypted(plaintext)) return plaintext;
2006
+ const key = this.loadOrCreateKey();
2007
+ const iv = randomBytes(IV_BYTES);
2008
+ const cipher = createCipheriv(ALGO, key, iv);
2009
+ const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
2010
+ const tag = cipher.getAuthTag();
2011
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${tag.toString("base64")}:${ct.toString("base64")}`;
2012
+ }
2013
+ decrypt(value) {
2014
+ if (!this.isEncrypted(value)) return value;
2015
+ const rest = value.slice(ENCRYPTED_PREFIX.length);
2016
+ const parts = rest.split(":");
2017
+ if (parts.length !== 3) {
2018
+ throw new Error("SecretVault: malformed encrypted value");
2019
+ }
2020
+ const [ivB64, tagB64, ctB64] = parts;
2021
+ const iv = Buffer.from(ivB64, "base64");
2022
+ const tag = Buffer.from(tagB64, "base64");
2023
+ const ct = Buffer.from(ctB64, "base64");
2024
+ if (iv.length !== IV_BYTES) throw new Error("SecretVault: bad IV length");
2025
+ if (tag.length !== TAG_BYTES) throw new Error("SecretVault: bad tag length");
2026
+ const key = this.loadOrCreateKey();
2027
+ const decipher = createDecipheriv(ALGO, key, iv);
2028
+ decipher.setAuthTag(tag);
2029
+ const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
2030
+ return pt.toString("utf8");
2031
+ }
2032
+ loadOrCreateKey() {
2033
+ if (this.key) return this.key;
2034
+ try {
2035
+ const buf = fs4.readFileSync(this.keyFile);
2036
+ if (buf.length !== KEY_BYTES) {
2037
+ throw new Error(
2038
+ `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`
2039
+ );
2040
+ }
2041
+ this.key = buf;
2042
+ return this.key;
2043
+ } catch (err) {
2044
+ if (err.code !== "ENOENT") throw err;
2045
+ }
2046
+ fs4.mkdirSync(path11.dirname(this.keyFile), { recursive: true });
2047
+ const key = randomBytes(KEY_BYTES);
2048
+ try {
2049
+ fs4.writeFileSync(this.keyFile, key, { mode: 384, flag: "wx" });
2050
+ } catch (err) {
2051
+ if (err.code !== "EEXIST") throw err;
2052
+ const buf = fs4.readFileSync(this.keyFile);
2053
+ if (buf.length !== KEY_BYTES) {
2054
+ throw new Error(
2055
+ `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`
2056
+ );
2057
+ }
2058
+ this.key = buf;
2059
+ return this.key;
2060
+ }
2061
+ this.key = key;
2062
+ return key;
2063
+ }
2064
+ };
2065
+ function decryptConfigSecrets(cfg, vault, opts) {
2066
+ const warn = opts?.warn ?? ((msg) => console.warn(msg));
1990
2067
  return walk(cfg, vault, (v, key) => {
1991
2068
  try {
1992
2069
  return vault.decrypt(v);
1993
2070
  } catch (err) {
1994
- console.warn(
1995
- `[secret-vault] Failed to decrypt "${key}":`,
1996
- err instanceof Error ? err.message : err
2071
+ warn(
2072
+ `[secret-vault] Failed to decrypt "${key}": ${err instanceof Error ? err.message : err}`
1997
2073
  );
1998
2074
  return "";
1999
2075
  }
2000
2076
  });
2001
2077
  }
2078
+ function encryptConfigSecrets(cfg, vault, _opts) {
2079
+ return walk(cfg, vault, (v) => vault.encrypt(v));
2080
+ }
2002
2081
  function walk(node, vault, transform) {
2003
2082
  if (node === null || node === void 0) return node;
2004
2083
  if (typeof node !== "object") return node;
@@ -2024,6 +2103,114 @@ function isSecretField(name) {
2024
2103
  if (NON_SECRET_OVERRIDES.has(lc)) return false;
2025
2104
  return SECRET_KEY_PATTERN.test(lc);
2026
2105
  }
2106
+ async function rewriteConfigEncrypted(configPath, vault, patch) {
2107
+ let current = {};
2108
+ try {
2109
+ const raw = await fsp.readFile(configPath, "utf8");
2110
+ current = JSON.parse(raw);
2111
+ } catch {
2112
+ }
2113
+ const merged = deepMerge(current, patch ?? {});
2114
+ const encrypted = encryptConfigSecrets(merged, vault);
2115
+ await fsp.mkdir(path11.dirname(configPath), { recursive: true });
2116
+ await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
2117
+ await restrictFilePermissions(configPath);
2118
+ }
2119
+ async function migratePlaintextSecrets(configPath, vault) {
2120
+ let raw;
2121
+ try {
2122
+ raw = await fsp.readFile(configPath, "utf8");
2123
+ } catch {
2124
+ return { migrated: 0, file: configPath };
2125
+ }
2126
+ let parsed;
2127
+ try {
2128
+ parsed = JSON.parse(raw);
2129
+ } catch {
2130
+ return { migrated: 0, file: configPath };
2131
+ }
2132
+ const counter = { n: 0 };
2133
+ const migrated = walkCount(parsed, vault, counter);
2134
+ if (counter.n === 0) return { migrated: 0, file: configPath };
2135
+ await atomicWrite(configPath, JSON.stringify(migrated, null, 2), { mode: 384 });
2136
+ await restrictFilePermissions(configPath);
2137
+ return { migrated: counter.n, file: configPath };
2138
+ }
2139
+ async function restrictFilePermissions(filePath, opts) {
2140
+ const warn = ((msg) => console.warn(msg));
2141
+ if (process.platform === "win32") {
2142
+ try {
2143
+ const { execFile: execFile2 } = await import('child_process');
2144
+ const { promisify: promisify2 } = await import('util');
2145
+ const execFileAsync = promisify2(execFile2);
2146
+ const user = windowsAccountName();
2147
+ if (!user) {
2148
+ warn(
2149
+ `[secret-vault] Could not determine the current Windows user for ${filePath}; skipping icacls hardening.`
2150
+ );
2151
+ return;
2152
+ }
2153
+ await execFileAsync("icacls", [filePath, "/inheritance:r", "/grant:r", `${user}:(F)`]);
2154
+ } catch {
2155
+ warn(
2156
+ `[secret-vault] Could not restrict permissions on ${filePath} \u2014 config file may be readable by other users on this system.`
2157
+ );
2158
+ }
2159
+ } else {
2160
+ try {
2161
+ await fsp.chmod(filePath, 384);
2162
+ } catch {
2163
+ }
2164
+ }
2165
+ }
2166
+ function windowsAccountName() {
2167
+ const username = process.env.USERNAME || process.env.USER;
2168
+ if (!username || username.includes("\0")) return void 0;
2169
+ const domain = process.env.USERDOMAIN;
2170
+ if (domain && !domain.includes("\0")) return `${domain}\\${username}`;
2171
+ return username;
2172
+ }
2173
+ function walkCount(node, vault, counter) {
2174
+ if (node === null || node === void 0) return node;
2175
+ if (typeof node !== "object") return node;
2176
+ if (Array.isArray(node)) {
2177
+ return node.map((item) => walkCount(item, vault, counter));
2178
+ }
2179
+ const out = /* @__PURE__ */ Object.create(null);
2180
+ for (const [k, v] of Object.entries(node)) {
2181
+ if (typeof v === "string" && isSecretField(k) && !vault.isEncrypted(v) && v.length > 0) {
2182
+ out[k] = vault.encrypt(v);
2183
+ counter.n++;
2184
+ } else if (typeof v === "object" && v !== null) {
2185
+ out[k] = walkCount(v, vault, counter);
2186
+ } else {
2187
+ out[k] = v;
2188
+ }
2189
+ }
2190
+ return out;
2191
+ }
2192
+ var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
2193
+ "__proto__",
2194
+ "constructor",
2195
+ "prototype",
2196
+ "__defineGetter__",
2197
+ "__defineSetter__",
2198
+ "__lookupGetter__",
2199
+ "__lookupSetter__"
2200
+ ]);
2201
+ function deepMerge(a, b) {
2202
+ const out = { ...a };
2203
+ for (const [k, v] of Object.entries(b)) {
2204
+ if (FORBIDDEN_PROTO_KEYS.has(k)) continue;
2205
+ const existing = out[k];
2206
+ if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
2207
+ out[k] = deepMerge(existing, v);
2208
+ } else {
2209
+ out[k] = v;
2210
+ }
2211
+ }
2212
+ return out;
2213
+ }
2027
2214
 
2028
2215
  // src/storage/config-loader.ts
2029
2216
  init_atomic_write();
@@ -2209,7 +2396,7 @@ var defaultIndexing = {
2209
2396
  function isPrimitiveArray(a) {
2210
2397
  return a.every((v) => v === null || typeof v !== "object");
2211
2398
  }
2212
- var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
2399
+ var FORBIDDEN_PROTO_KEYS2 = /* @__PURE__ */ new Set([
2213
2400
  "__proto__",
2214
2401
  "constructor",
2215
2402
  "prototype",
@@ -2218,12 +2405,12 @@ var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
2218
2405
  "__lookupGetter__",
2219
2406
  "__lookupSetter__"
2220
2407
  ]);
2221
- function deepMerge(base, patch) {
2408
+ function deepMerge2(base, patch) {
2222
2409
  if (typeof base !== "object" || base === null) return patch ?? base;
2223
2410
  if (typeof patch !== "object" || patch === null) return base;
2224
2411
  const out = { ...base };
2225
2412
  for (const [k, v] of Object.entries(patch)) {
2226
- if (FORBIDDEN_PROTO_KEYS.has(k)) continue;
2413
+ if (FORBIDDEN_PROTO_KEYS2.has(k)) continue;
2227
2414
  const existing = out[k];
2228
2415
  if (Array.isArray(v)) {
2229
2416
  if (Array.isArray(existing) && isPrimitiveArray(v) && isPrimitiveArray(existing)) {
@@ -2237,7 +2424,7 @@ function deepMerge(base, patch) {
2237
2424
  }
2238
2425
  }
2239
2426
  } else if (typeof v === "object" && v !== null && typeof existing === "object" && existing !== null) {
2240
- out[k] = deepMerge(existing, v);
2427
+ out[k] = deepMerge2(existing, v);
2241
2428
  } else if (v !== void 0) {
2242
2429
  out[k] = v;
2243
2430
  }
@@ -2262,9 +2449,9 @@ var DefaultConfigLoader = class {
2262
2449
  this.readJson(this.paths.projectLocalConfig),
2263
2450
  this.readJson(this.paths.inProjectConfig)
2264
2451
  ]);
2265
- cfg = deepMerge(cfg, global);
2266
- cfg = deepMerge(cfg, local);
2267
- cfg = deepMerge(cfg, inProject);
2452
+ cfg = deepMerge2(cfg, global);
2453
+ cfg = deepMerge2(cfg, local);
2454
+ cfg = deepMerge2(cfg, inProject);
2268
2455
  for (const [key, fn] of Object.entries(ENV_MAP)) {
2269
2456
  const v = process.env[key];
2270
2457
  if (v) fn(cfg, v);
@@ -2278,14 +2465,14 @@ var DefaultConfigLoader = class {
2278
2465
  try {
2279
2466
  const patch = await src.read();
2280
2467
  if (patch && Object.keys(patch).length > 0) {
2281
- cfg = deepMerge(cfg, patch);
2468
+ cfg = deepMerge2(cfg, patch);
2282
2469
  }
2283
2470
  } catch (err) {
2284
2471
  console.warn(`Config source "${src.name}" failed`, err);
2285
2472
  }
2286
2473
  }
2287
2474
  if (opts.cliFlags) {
2288
- cfg = deepMerge(cfg, opts.cliFlags);
2475
+ cfg = deepMerge2(cfg, opts.cliFlags);
2289
2476
  }
2290
2477
  if (this.vault) {
2291
2478
  cfg = decryptConfigSecrets(cfg, this.vault);
@@ -3697,239 +3884,12 @@ var DefaultSecretScrubber = class {
3697
3884
  }
3698
3885
  };
3699
3886
 
3700
- // src/types/secret-vault.ts
3701
- var ENCRYPTED_PREFIX = "enc:v1:";
3702
-
3703
- // src/security/secret-vault.ts
3704
- init_atomic_write();
3705
- var KEY_BYTES = 32;
3706
- var IV_BYTES = 12;
3707
- var TAG_BYTES = 16;
3708
- var ALGO = "aes-256-gcm";
3709
- var DefaultSecretVault = class {
3710
- keyFile;
3711
- key;
3712
- constructor(opts) {
3713
- this.keyFile = opts.keyFile;
3714
- }
3715
- isEncrypted(value) {
3716
- return typeof value === "string" && value.startsWith(ENCRYPTED_PREFIX);
3717
- }
3718
- encrypt(plaintext) {
3719
- if (this.isEncrypted(plaintext)) return plaintext;
3720
- const key = this.loadOrCreateKey();
3721
- const iv = randomBytes(IV_BYTES);
3722
- const cipher = createCipheriv(ALGO, key, iv);
3723
- const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
3724
- const tag = cipher.getAuthTag();
3725
- return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${tag.toString("base64")}:${ct.toString("base64")}`;
3726
- }
3727
- decrypt(value) {
3728
- if (!this.isEncrypted(value)) return value;
3729
- const rest = value.slice(ENCRYPTED_PREFIX.length);
3730
- const parts = rest.split(":");
3731
- if (parts.length !== 3) {
3732
- throw new Error("SecretVault: malformed encrypted value");
3733
- }
3734
- const [ivB64, tagB64, ctB64] = parts;
3735
- const iv = Buffer.from(ivB64, "base64");
3736
- const tag = Buffer.from(tagB64, "base64");
3737
- const ct = Buffer.from(ctB64, "base64");
3738
- if (iv.length !== IV_BYTES) throw new Error("SecretVault: bad IV length");
3739
- if (tag.length !== TAG_BYTES) throw new Error("SecretVault: bad tag length");
3740
- const key = this.loadOrCreateKey();
3741
- const decipher = createDecipheriv(ALGO, key, iv);
3742
- decipher.setAuthTag(tag);
3743
- const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
3744
- return pt.toString("utf8");
3745
- }
3746
- loadOrCreateKey() {
3747
- if (this.key) return this.key;
3748
- try {
3749
- const buf = fs5.readFileSync(this.keyFile);
3750
- if (buf.length !== KEY_BYTES) {
3751
- throw new Error(
3752
- `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`
3753
- );
3754
- }
3755
- this.key = buf;
3756
- return this.key;
3757
- } catch (err) {
3758
- if (err.code !== "ENOENT") throw err;
3759
- }
3760
- fs5.mkdirSync(path11.dirname(this.keyFile), { recursive: true });
3761
- const key = randomBytes(KEY_BYTES);
3762
- try {
3763
- fs5.writeFileSync(this.keyFile, key, { mode: 384, flag: "wx" });
3764
- } catch (err) {
3765
- if (err.code !== "EEXIST") throw err;
3766
- const buf = fs5.readFileSync(this.keyFile);
3767
- if (buf.length !== KEY_BYTES) {
3768
- throw new Error(
3769
- `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`
3770
- );
3771
- }
3772
- this.key = buf;
3773
- return this.key;
3774
- }
3775
- this.key = key;
3776
- return key;
3777
- }
3778
- };
3779
- function decryptConfigSecrets2(cfg, vault, opts) {
3780
- const warn = opts?.warn ?? ((msg) => console.warn(msg));
3781
- return walk2(cfg, vault, (v, key) => {
3782
- try {
3783
- return vault.decrypt(v);
3784
- } catch (err) {
3785
- warn(
3786
- `[secret-vault] Failed to decrypt "${key}": ${err instanceof Error ? err.message : err}`
3787
- );
3788
- return "";
3789
- }
3790
- });
3791
- }
3792
- function encryptConfigSecrets(cfg, vault, _opts) {
3793
- return walk2(cfg, vault, (v) => vault.encrypt(v));
3794
- }
3795
- function walk2(node, vault, transform) {
3796
- if (node === null || node === void 0) return node;
3797
- if (typeof node !== "object") return node;
3798
- if (Array.isArray(node)) {
3799
- return node.map((item) => walk2(item, vault, transform));
3800
- }
3801
- const out = /* @__PURE__ */ Object.create(null);
3802
- for (const [k, v] of Object.entries(node)) {
3803
- if (typeof v === "string" && isSecretField2(k)) {
3804
- out[k] = transform(v, k);
3805
- } else if (typeof v === "object" && v !== null) {
3806
- out[k] = walk2(v, vault, transform);
3807
- } else {
3808
- out[k] = v;
3809
- }
3810
- }
3811
- return out;
3812
- }
3813
- var SECRET_KEY_PATTERN2 = /(?:apikey|api_key|authtoken|auth_token|bearer|secret|password|passwd|pwd|refreshtoken|refresh_token|sessionkey|session_key|access[_-]?token|private[_-]?key)/i;
3814
- var NON_SECRET_OVERRIDES2 = /* @__PURE__ */ new Set(["publickey", "public_key"]);
3815
- function isSecretField2(name) {
3816
- const lc = name.toLowerCase();
3817
- if (NON_SECRET_OVERRIDES2.has(lc)) return false;
3818
- return SECRET_KEY_PATTERN2.test(lc);
3819
- }
3820
- async function rewriteConfigEncrypted(configPath, vault, patch) {
3821
- let current = {};
3822
- try {
3823
- const raw = await fsp.readFile(configPath, "utf8");
3824
- current = JSON.parse(raw);
3825
- } catch {
3826
- }
3827
- const merged = deepMerge2(current, patch ?? {});
3828
- const encrypted = encryptConfigSecrets(merged, vault);
3829
- await fsp.mkdir(path11.dirname(configPath), { recursive: true });
3830
- await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
3831
- await restrictFilePermissions(configPath);
3832
- }
3833
- async function migratePlaintextSecrets(configPath, vault) {
3834
- let raw;
3835
- try {
3836
- raw = await fsp.readFile(configPath, "utf8");
3837
- } catch {
3838
- return { migrated: 0, file: configPath };
3839
- }
3840
- let parsed;
3841
- try {
3842
- parsed = JSON.parse(raw);
3843
- } catch {
3844
- return { migrated: 0, file: configPath };
3845
- }
3846
- const counter = { n: 0 };
3847
- const migrated = walkCount(parsed, vault, counter);
3848
- if (counter.n === 0) return { migrated: 0, file: configPath };
3849
- await atomicWrite(configPath, JSON.stringify(migrated, null, 2), { mode: 384 });
3850
- await restrictFilePermissions(configPath);
3851
- return { migrated: counter.n, file: configPath };
3852
- }
3853
- async function restrictFilePermissions(filePath, opts) {
3854
- const warn = ((msg) => console.warn(msg));
3855
- if (process.platform === "win32") {
3856
- try {
3857
- const { execFile: execFile2 } = await import('child_process');
3858
- const { promisify: promisify2 } = await import('util');
3859
- const execFileAsync = promisify2(execFile2);
3860
- const user = windowsAccountName();
3861
- if (!user) {
3862
- warn(
3863
- `[secret-vault] Could not determine the current Windows user for ${filePath}; skipping icacls hardening.`
3864
- );
3865
- return;
3866
- }
3867
- await execFileAsync("icacls", [filePath, "/inheritance:r", "/grant:r", `${user}:(F)`]);
3868
- } catch {
3869
- warn(
3870
- `[secret-vault] Could not restrict permissions on ${filePath} \u2014 config file may be readable by other users on this system.`
3871
- );
3872
- }
3873
- } else {
3874
- try {
3875
- await fsp.chmod(filePath, 384);
3876
- } catch {
3877
- }
3878
- }
3879
- }
3880
- function windowsAccountName() {
3881
- const username = process.env.USERNAME || process.env.USER;
3882
- if (!username || username.includes("\0")) return void 0;
3883
- const domain = process.env.USERDOMAIN;
3884
- if (domain && !domain.includes("\0")) return `${domain}\\${username}`;
3885
- return username;
3886
- }
3887
- function walkCount(node, vault, counter) {
3888
- if (node === null || node === void 0) return node;
3889
- if (typeof node !== "object") return node;
3890
- if (Array.isArray(node)) {
3891
- return node.map((item) => walkCount(item, vault, counter));
3892
- }
3893
- const out = /* @__PURE__ */ Object.create(null);
3894
- for (const [k, v] of Object.entries(node)) {
3895
- if (typeof v === "string" && isSecretField2(k) && !vault.isEncrypted(v) && v.length > 0) {
3896
- out[k] = vault.encrypt(v);
3897
- counter.n++;
3898
- } else if (typeof v === "object" && v !== null) {
3899
- out[k] = walkCount(v, vault, counter);
3900
- } else {
3901
- out[k] = v;
3902
- }
3903
- }
3904
- return out;
3905
- }
3906
- var FORBIDDEN_PROTO_KEYS2 = /* @__PURE__ */ new Set([
3907
- "__proto__",
3908
- "constructor",
3909
- "prototype",
3910
- "__defineGetter__",
3911
- "__defineSetter__",
3912
- "__lookupGetter__",
3913
- "__lookupSetter__"
3914
- ]);
3915
- function deepMerge2(a, b) {
3916
- const out = { ...a };
3917
- for (const [k, v] of Object.entries(b)) {
3918
- if (FORBIDDEN_PROTO_KEYS2.has(k)) continue;
3919
- const existing = out[k];
3920
- if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
3921
- out[k] = deepMerge2(existing, v);
3922
- } else {
3923
- out[k] = v;
3924
- }
3925
- }
3926
- return out;
3927
- }
3928
-
3929
3887
  // src/security/capabilities.ts
3930
3888
  var ToolCapabilities = {
3931
3889
  /** Can execute arbitrary commands in the user's shell (the `bash` tool). */
3932
3890
  SHELL_ARBITRARY: "shell.arbitrary",
3891
+ /** Can execute a restricted set of commands (the `exec` tool). */
3892
+ SHELL_RESTRICTED: "shell.restricted",
3933
3893
  /** Can write / modify / delete files inside the project. */
3934
3894
  FS_WRITE: "fs.write",
3935
3895
  /** Can write files outside the current project root (very high risk). */
@@ -3945,6 +3905,7 @@ var ToolCapabilities = {
3945
3905
  };
3946
3906
  var DANGEROUS_FOR_SUBAGENTS = [
3947
3907
  ToolCapabilities.SHELL_ARBITRARY,
3908
+ ToolCapabilities.SHELL_RESTRICTED,
3948
3909
  ToolCapabilities.FS_WRITE,
3949
3910
  ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
3950
3911
  ToolCapabilities.MCP_PROXY,
@@ -4388,38 +4349,15 @@ var DefaultPermissionPolicy = class {
4388
4349
  }
4389
4350
  };
4390
4351
  var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
4391
- /**
4392
- * Legacy name-based denylist.
4393
- * @deprecated Prefer declaring `capabilities` on the Tool and using capability-based checks.
4394
- */
4395
- static LEGACY_NAME_DENY = /* @__PURE__ */ new Set([
4396
- "bash",
4397
- "write",
4398
- "edit",
4399
- "replace",
4400
- "scaffold",
4401
- "patch",
4402
- "install",
4403
- "exec"
4404
- ]);
4405
- // Note: hasDangerousCapabilityForSubagents is now the shared helper from capabilities.ts
4406
- // The old private method was removed in favor of the centralized utility.
4407
- /**
4408
- * Tools from MCP servers (`mcp__<server>__<tool>`) are external code of
4409
- * unknown capability — they may wrap a shell or filesystem. They are
4410
- * fail-closed here: not auto-approved for subagents by default, so the
4411
- * leader must allow them explicitly per-spawn.
4412
- */
4413
4352
  static isMcpTool(name) {
4414
4353
  return name.startsWith("mcp__");
4415
4354
  }
4416
4355
  async evaluate(tool) {
4417
4356
  const hasDangerousCap = hasDangerousCapabilityForSubagents(tool);
4418
- const legacyNameBlock = _AutoApprovePermissionPolicy.LEGACY_NAME_DENY.has(tool.name);
4419
4357
  const isMcp = _AutoApprovePermissionPolicy.isMcpTool(tool.name);
4420
- const blocked = tool.permission === "deny" || hasDangerousCap || legacyNameBlock || isMcp;
4358
+ const blocked = tool.permission === "deny" || hasDangerousCap || isMcp;
4421
4359
  if (blocked) {
4422
- const reason = hasDangerousCap ? `tool declares dangerous capability (${tool.capabilities?.join(", ")}) \u2014 not auto-approved for subagents` : legacyNameBlock || isMcp ? `tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow it explicitly` : "tool default deny";
4360
+ const reason = hasDangerousCap ? `tool declares dangerous capability (${tool.capabilities?.join(", ")}) \u2014 not auto-approved for subagents` : isMcp ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow it explicitly` : "tool default deny";
4423
4361
  return {
4424
4362
  permission: "deny",
4425
4363
  source: "subagent_guard",
@@ -5088,53 +5026,63 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
5088
5026
  const next = await iter.next();
5089
5027
  if (next.done) break;
5090
5028
  const ev = next.value;
5091
- switch (ev.type) {
5092
- case "message_start":
5093
- handleMessageStart(state, ev.model);
5094
- break;
5095
- case "content_block_start":
5096
- handleContentBlockStart(state, ev);
5097
- break;
5098
- case "content_block_stop":
5099
- handleContentBlockStop(state, ev);
5100
- break;
5101
- case "text_delta":
5102
- handleTextDelta(state, ev.text);
5103
- events.emit("provider.text_delta", { ctx, text: ev.text });
5104
- break;
5105
- case "tool_use_start": {
5106
- const idVal = ev.id;
5107
- const nameVal = ev.name;
5108
- handleToolUseStart(state, { id: idVal, name: nameVal });
5109
- const emittedPayload = { ctx, id: idVal ?? "unknown", name: nameVal ?? "unknown" };
5110
- events.emit("provider.tool_use_start", emittedPayload);
5111
- break;
5112
- }
5113
- case "tool_use_input_delta":
5114
- handleToolUseInputDelta(state, ev);
5115
- break;
5116
- case "tool_use_stop": {
5117
- const stoppedName = state.tools.get(ev.id)?.name ?? "unknown";
5118
- handleToolUseStop(state, ev);
5119
- events.emit("provider.tool_use_stop", { ctx, id: ev.id, name: stoppedName });
5120
- break;
5029
+ try {
5030
+ switch (ev.type) {
5031
+ case "message_start":
5032
+ handleMessageStart(state, ev.model);
5033
+ break;
5034
+ case "content_block_start":
5035
+ handleContentBlockStart(state, ev);
5036
+ break;
5037
+ case "content_block_stop":
5038
+ handleContentBlockStop(state, ev);
5039
+ break;
5040
+ case "text_delta":
5041
+ handleTextDelta(state, ev.text);
5042
+ events.emit("provider.text_delta", { ctx, text: ev.text });
5043
+ break;
5044
+ case "tool_use_start": {
5045
+ const idVal = ev.id;
5046
+ const nameVal = ev.name;
5047
+ handleToolUseStart(state, { id: idVal, name: nameVal });
5048
+ const emittedPayload = { ctx, id: idVal ?? "unknown", name: nameVal ?? "unknown" };
5049
+ events.emit("provider.tool_use_start", emittedPayload);
5050
+ break;
5051
+ }
5052
+ case "tool_use_input_delta":
5053
+ handleToolUseInputDelta(state, ev);
5054
+ break;
5055
+ case "tool_use_stop": {
5056
+ const stoppedName = state.tools.get(ev.id)?.name ?? "unknown";
5057
+ handleToolUseStop(state, ev);
5058
+ events.emit("provider.tool_use_stop", { ctx, id: ev.id, name: stoppedName });
5059
+ break;
5060
+ }
5061
+ case "thinking_start":
5062
+ handleThinkingStart(state, ev);
5063
+ break;
5064
+ case "thinking_delta":
5065
+ handleThinkingDelta(state, ev.text);
5066
+ events.emit("provider.thinking_delta", { ctx, text: ev.text });
5067
+ break;
5068
+ case "thinking_signature":
5069
+ handleThinkingSignature(state, ev.signature);
5070
+ break;
5071
+ case "thinking_stop":
5072
+ handleThinkingStop(state);
5073
+ break;
5074
+ case "message_stop":
5075
+ handleMessageStop(state, ev);
5076
+ break;
5077
+ default:
5078
+ break;
5121
5079
  }
5122
- case "thinking_start":
5123
- handleThinkingStart(state, ev);
5124
- break;
5125
- case "thinking_delta":
5126
- handleThinkingDelta(state, ev.text);
5127
- events.emit("provider.thinking_delta", { ctx, text: ev.text });
5128
- break;
5129
- case "thinking_signature":
5130
- handleThinkingSignature(state, ev.signature);
5131
- break;
5132
- case "thinking_stop":
5133
- handleThinkingStop(state);
5134
- break;
5135
- case "message_stop":
5136
- handleMessageStop(state, ev);
5137
- break;
5080
+ } catch (handlerErr) {
5081
+ events.emit("provider.stream_error", {
5082
+ ctx,
5083
+ eventType: ev.type,
5084
+ msg: handlerErr instanceof Error ? handlerErr.message : String(handlerErr)
5085
+ });
5138
5086
  }
5139
5087
  }
5140
5088
  } catch (err) {
@@ -5147,8 +5095,10 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
5147
5095
  try {
5148
5096
  let drainTimer = null;
5149
5097
  try {
5098
+ const drainPromise = Promise.resolve(iter.return?.()).catch(() => {
5099
+ });
5150
5100
  await Promise.race([
5151
- Promise.resolve(iter.return?.()),
5101
+ drainPromise,
5152
5102
  new Promise((resolve5) => {
5153
5103
  drainTimer = setTimeout(resolve5, STREAM_DRAIN_TIMEOUT_MS);
5154
5104
  })
@@ -5246,6 +5196,17 @@ var DefaultProviderRunner = class {
5246
5196
 
5247
5197
  // src/utils/token-estimate.ts
5248
5198
  var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
5199
+ var CALIBRATION_GLOBAL_KEY = "__global__";
5200
+ var _cals = /* @__PURE__ */ new Map();
5201
+ function calState(key) {
5202
+ let state = _cals.get(key);
5203
+ if (!state) {
5204
+ state = { ratio: 1, count: 0, prevEst: 0 };
5205
+ _cals.set(key, state);
5206
+ }
5207
+ return state;
5208
+ }
5209
+ var MIN_SAMPLES_FOR_CALIBRATION = 3;
5249
5210
  var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
5250
5211
  var ESTIMATE_CACHE_MAX_SIZE = 1e4;
5251
5212
  function getCachedEstimate(key, compute) {
@@ -5277,10 +5238,25 @@ function estimateToolResultTokens(content) {
5277
5238
  function estimateTextTokens(text) {
5278
5239
  return RoughTokenEstimate(text);
5279
5240
  }
5241
+ function estimateMessageTokens(messages) {
5242
+ let total = 0;
5243
+ for (const m of messages) {
5244
+ if (typeof m.content === "string") {
5245
+ total += estimateTextTokens(m.content);
5246
+ } else {
5247
+ for (const b of m.content) {
5248
+ if (b.type === "text") total += estimateTextTokens(b.text);
5249
+ else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
5250
+ else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
5251
+ }
5252
+ }
5253
+ }
5254
+ return total;
5255
+ }
5280
5256
  function estimateToolDefTokens(tool) {
5281
5257
  return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
5282
5258
  }
5283
- function estimateRequestTokens(messages, systemPrompt, tools) {
5259
+ function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = CALIBRATION_GLOBAL_KEY) {
5284
5260
  let messagesTokens = 0;
5285
5261
  if (typeof messages === "string") {
5286
5262
  messagesTokens = RoughTokenEstimate(messages);
@@ -5319,6 +5295,7 @@ function estimateRequestTokens(messages, systemPrompt, tools) {
5319
5295
  toolsTokens += estimateToolDefTokens(t);
5320
5296
  }
5321
5297
  const total = messagesTokens + systemTokens + toolsTokens;
5298
+ calState(calibrationKey).prevEst = total;
5322
5299
  return {
5323
5300
  messages: messagesTokens,
5324
5301
  systemPrompt: systemTokens,
@@ -5326,39 +5303,164 @@ function estimateRequestTokens(messages, systemPrompt, tools) {
5326
5303
  total
5327
5304
  };
5328
5305
  }
5329
- function estimateRequestTokensCalibrated(messages, systemPrompt, tools) {
5330
- const result = estimateRequestTokens(messages, systemPrompt, tools);
5306
+ function estimateRequestTokensCalibrated(messages, systemPrompt, tools, calibrationKey = CALIBRATION_GLOBAL_KEY) {
5307
+ const result = estimateRequestTokens(messages, systemPrompt, tools, calibrationKey);
5308
+ const cal = calState(calibrationKey);
5309
+ if (cal.count >= MIN_SAMPLES_FOR_CALIBRATION) {
5310
+ const safeRatio = Math.min(1.5, Math.max(0.5, cal.ratio));
5311
+ return {
5312
+ messages: Math.round(result.messages * safeRatio),
5313
+ systemPrompt: Math.round(result.systemPrompt * safeRatio),
5314
+ tools: Math.round(result.tools * safeRatio),
5315
+ total: Math.round(result.total * safeRatio)
5316
+ };
5317
+ }
5331
5318
  return result;
5332
5319
  }
5333
5320
 
5321
+ // src/types/blocks.ts
5322
+ function isTextBlock(b) {
5323
+ return b.type === "text";
5324
+ }
5325
+
5326
+ // src/execution/compaction-core.ts
5327
+ var estimateMessages = estimateMessageTokens;
5328
+ function hasTextContent(m) {
5329
+ if (typeof m.content === "string") return m.content.trim().length > 0;
5330
+ return m.content.some((b) => b.type === "text" && b.text.trim().length > 0);
5331
+ }
5332
+ function findPreserveStart(messages, preserveK) {
5333
+ let pairCount = 0;
5334
+ let preserveStart = messages.length;
5335
+ for (let i = messages.length - 1; i >= 0 && pairCount < preserveK; i--) {
5336
+ const m = messages[i];
5337
+ if (!m) continue;
5338
+ if (m.role === "user" || m.role === "assistant") {
5339
+ pairCount++;
5340
+ preserveStart = i;
5341
+ }
5342
+ }
5343
+ for (let i = preserveStart; i < messages.length; i++) {
5344
+ const m = messages[i];
5345
+ if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
5346
+ const hasToolUse2 = m.content.some((b) => b.type === "tool_use");
5347
+ if (hasToolUse2 && i + 1 < messages.length) {
5348
+ const next = messages[i + 1];
5349
+ if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
5350
+ preserveStart = i + 1;
5351
+ }
5352
+ }
5353
+ }
5354
+ return preserveStart;
5355
+ }
5356
+ function eliseOldToolResults(messages, opts) {
5357
+ const preserveStart = findPreserveStart(messages, opts.preserveK);
5358
+ let saved = 0;
5359
+ let changed = false;
5360
+ const next = new Array(messages.length);
5361
+ for (let i = 0; i < messages.length; i++) {
5362
+ const msg = messages[i];
5363
+ if (i >= preserveStart || !msg || !Array.isArray(msg.content)) {
5364
+ next[i] = msg;
5365
+ continue;
5366
+ }
5367
+ const original = msg.content;
5368
+ const newContent = original.map((b) => {
5369
+ if (b.type !== "tool_result") return b;
5370
+ const tokens = estimateToolResultTokens(b.content);
5371
+ if (tokens < opts.eliseThreshold) return b;
5372
+ saved += tokens;
5373
+ const elided = {
5374
+ type: "tool_result",
5375
+ tool_use_id: b.tool_use_id,
5376
+ content: `[elided: ~${tokens} tokens]`,
5377
+ is_error: b.is_error
5378
+ };
5379
+ return elided;
5380
+ });
5381
+ if (newContent.every((b, idx) => b === original[idx])) {
5382
+ next[i] = msg;
5383
+ } else {
5384
+ next[i] = { ...msg, content: newContent };
5385
+ changed = true;
5386
+ }
5387
+ }
5388
+ return { messages: changed ? next : messages, saved, changed };
5389
+ }
5390
+ function buildLosslessDigest(messages) {
5391
+ const lines = [];
5392
+ for (const m of messages) {
5393
+ let text;
5394
+ let omitted = 0;
5395
+ if (typeof m.content === "string") {
5396
+ text = m.content;
5397
+ } else {
5398
+ const parts = [];
5399
+ for (const b of m.content) {
5400
+ if (isTextBlock(b)) parts.push(b.text);
5401
+ else if (b.type === "tool_use" || b.type === "tool_result") omitted++;
5402
+ }
5403
+ text = parts.join(" ");
5404
+ }
5405
+ if (text.trim().length === 0 && omitted === 0) continue;
5406
+ const marker = omitted > 0 ? ` [${omitted} tool call(s) omitted \u2014 see session log]` : "";
5407
+ lines.push(`[${m.role}]: ${text}${marker}`);
5408
+ }
5409
+ return lines.join("\n");
5410
+ }
5411
+ function findSafeBoundary(messages, from, to) {
5412
+ for (let i = to; i >= from; i--) {
5413
+ const m = messages[i];
5414
+ if (!m) continue;
5415
+ if (m.role === "user" && hasTextContent(m)) {
5416
+ return findExchangeStart(messages, i);
5417
+ }
5418
+ }
5419
+ return -1;
5420
+ }
5421
+ function findExchangeStart(messages, userIndex) {
5422
+ for (let i = userIndex - 1; i >= 0; i--) {
5423
+ const m = messages[i];
5424
+ if (!m) continue;
5425
+ if (m.role === "assistant") {
5426
+ const hasToolUse2 = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
5427
+ if (!hasToolUse2) return i + 1;
5428
+ } else if (m.role === "user") {
5429
+ return i;
5430
+ }
5431
+ }
5432
+ return 0;
5433
+ }
5434
+
5334
5435
  // src/execution/compactor.ts
5335
5436
  var HybridCompactor = class {
5336
5437
  preserveK;
5337
5438
  eliseThreshold;
5338
- estimator;
5339
5439
  constructor(opts = {}) {
5340
5440
  this.preserveK = opts.preserveK ?? 5;
5341
5441
  this.eliseThreshold = opts.eliseThreshold ?? 2e3;
5342
- this.estimator = opts.estimator ?? estimateTextTokens;
5343
5442
  }
5344
5443
  async compact(ctx, opts = {}) {
5345
- const beforeTokens = this.estimateMessages(ctx.messages);
5444
+ const beforeTokens = estimateMessages(ctx.messages);
5346
5445
  const beforeFull = this.estimateFullRequest(ctx);
5347
5446
  const reductions = [];
5348
5447
  const policy = readContextWindowPolicy(ctx);
5349
5448
  const preserveK = policy?.preserveK ?? this.preserveK;
5350
5449
  const eliseThreshold = policy?.eliseThreshold ?? this.eliseThreshold;
5351
- const phase1Saved = this.eliseOldToolResults(ctx, preserveK, eliseThreshold);
5352
- if (phase1Saved > 0) reductions.push({ phase: "elision", saved: phase1Saved });
5450
+ const elide = eliseOldToolResults(ctx.messages, { preserveK, eliseThreshold });
5451
+ if (elide.changed) ctx.state.replaceMessages(elide.messages);
5452
+ if (elide.saved > 0) reductions.push({ phase: "elision", saved: elide.saved });
5453
+ let collapsedDigest;
5353
5454
  if (opts.aggressive) {
5354
- const phase2Saved = this.collapseAncientTurns(ctx, preserveK);
5355
- if (phase2Saved > 0) reductions.push({ phase: "summary", saved: phase2Saved });
5455
+ const phase2 = this.collapseAncientTurns(ctx, preserveK);
5456
+ if (phase2.saved > 0) reductions.push({ phase: "summary", saved: phase2.saved });
5457
+ collapsedDigest = phase2.digest;
5356
5458
  }
5357
5459
  const repaired = repairToolUseAdjacency(ctx.messages);
5358
5460
  if (repaired.report.changed) {
5359
5461
  ctx.state.replaceMessages(repaired.messages);
5360
5462
  }
5361
- const afterTokens = this.estimateMessages(ctx.messages);
5463
+ const afterTokens = estimateMessages(ctx.messages);
5362
5464
  const afterFull = this.estimateFullRequest(ctx);
5363
5465
  return {
5364
5466
  before: beforeTokens,
@@ -5366,6 +5468,7 @@ var HybridCompactor = class {
5366
5468
  fullRequestTokensBefore: beforeFull,
5367
5469
  fullRequestTokensAfter: afterFull,
5368
5470
  reductions,
5471
+ collapsedDigest,
5369
5472
  repaired: repaired.report.changed ? {
5370
5473
  removedToolUses: repaired.report.removedToolUses,
5371
5474
  removedToolResults: repaired.report.removedToolResults,
@@ -5378,72 +5481,23 @@ var HybridCompactor = class {
5378
5481
  * This is the accurate figure for context-window pressure monitoring.
5379
5482
  */
5380
5483
  estimateFullRequest(ctx) {
5381
- const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);
5382
- return breakdown.total;
5383
- }
5384
- eliseOldToolResults(ctx, preserveK = this.preserveK, eliseThreshold = this.eliseThreshold) {
5385
- const messages = ctx.messages;
5386
- let pairCount = 0;
5387
- let preserveStart = messages.length;
5388
- for (let i = messages.length - 1; i >= 0 && pairCount < preserveK; i--) {
5389
- const m = messages[i];
5390
- if (!m) continue;
5391
- if (m.role === "user" || m.role === "assistant") {
5392
- pairCount++;
5393
- preserveStart = i;
5394
- }
5395
- }
5396
- for (let i = preserveStart; i < messages.length; i++) {
5397
- const m = messages[i];
5398
- if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
5399
- const hasToolUse2 = m.content.some((b) => b.type === "tool_use");
5400
- if (hasToolUse2 && i + 1 < messages.length) {
5401
- const next = messages[i + 1];
5402
- if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
5403
- preserveStart = i + 1;
5404
- }
5405
- }
5406
- }
5407
- let saved = 0;
5408
- let changed = false;
5409
- const nextMessages = new Array(messages.length);
5410
- for (let i = 0; i < messages.length; i++) {
5411
- const msg = messages[i];
5412
- if (i >= preserveStart) {
5413
- nextMessages[i] = msg;
5414
- continue;
5415
- }
5416
- if (!msg || !Array.isArray(msg.content)) {
5417
- nextMessages[i] = msg;
5418
- continue;
5419
- }
5420
- const newContent = msg.content.map((b) => {
5421
- if (b.type !== "tool_result") return b;
5422
- const tokens = estimateToolResultTokens(b.content);
5423
- if (tokens < eliseThreshold) return b;
5424
- saved += tokens;
5425
- const elided = {
5426
- type: "tool_result",
5427
- tool_use_id: b.tool_use_id,
5428
- content: `[elided: ~${tokens} tokens]`,
5429
- is_error: b.is_error
5430
- };
5431
- return elided;
5432
- });
5433
- if (newContent.length === msg.content.length && newContent.every((b, idx) => b === msg.content[idx])) {
5434
- nextMessages[i] = msg;
5435
- } else {
5436
- nextMessages[i] = { ...msg, content: newContent };
5437
- changed = true;
5438
- }
5439
- }
5440
- if (changed) ctx.state.replaceMessages(nextMessages);
5441
- return saved;
5484
+ return estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []).total;
5442
5485
  }
5486
+ /**
5487
+ * Lossless rule-based collapse of ancient turns into a single digest message.
5488
+ *
5489
+ * Preserves ALL textual content of the collapsed range — user instructions,
5490
+ * assistant decisions/conclusions, and any prior digests (chained forward so
5491
+ * the digest stays lossless across repeated compactions). Only `tool_use` /
5492
+ * `tool_result` protocol blocks are dropped and replaced with a count marker;
5493
+ * their full payload already lives in the session log. No sub-LLM call.
5494
+ *
5495
+ * Returns the token savings and the digest text (for audit logging).
5496
+ */
5443
5497
  collapseAncientTurns(ctx, preserveK = this.preserveK) {
5444
5498
  const messages = ctx.messages;
5445
5499
  const cutTarget = Math.max(0, messages.length - preserveK * 2);
5446
- if (cutTarget <= 0) return 0;
5500
+ if (cutTarget <= 0) return { saved: 0 };
5447
5501
  let boundary = -1;
5448
5502
  for (let i = cutTarget; i < messages.length; i++) {
5449
5503
  const m = messages[i];
@@ -5453,34 +5507,20 @@ var HybridCompactor = class {
5453
5507
  break;
5454
5508
  }
5455
5509
  }
5456
- if (boundary <= 0) return 0;
5510
+ if (boundary <= 0) return { saved: 0 };
5457
5511
  const removed = messages.slice(0, boundary);
5458
- const removedTokens = this.estimateMessages(removed);
5459
- const summary = [
5460
- {
5461
- role: "user",
5462
- content: `[previous_session_summary: ${removed.length} earlier turns compacted. Todo state preserved in context.]`
5463
- },
5464
- { role: "assistant", content: "Continuing from compacted context." }
5465
- ];
5512
+ const removedTokens = estimateMessages(removed);
5513
+ const digest = buildLosslessDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted \u2014 see session log)`;
5514
+ const summaryMsg = {
5515
+ role: "system",
5516
+ content: `[prior_turns_digest: ${digest}]`
5517
+ };
5466
5518
  const tail = ctx.messages.slice(boundary);
5467
- ctx.state.replaceMessages([...summary, ...tail]);
5468
- return Math.max(0, removedTokens - this.estimateMessages(summary));
5469
- }
5470
- estimateMessages(messages) {
5471
- let total = 0;
5472
- for (const m of messages) {
5473
- if (typeof m.content === "string") {
5474
- total += this.estimator(m.content);
5475
- } else {
5476
- for (const b of m.content) {
5477
- if (b.type === "text") total += this.estimator(b.text);
5478
- else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
5479
- else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
5480
- }
5481
- }
5482
- }
5483
- return total;
5519
+ ctx.state.replaceMessages([summaryMsg, ...tail]);
5520
+ return {
5521
+ saved: Math.max(0, removedTokens - estimateMessages([summaryMsg])),
5522
+ digest
5523
+ };
5484
5524
  }
5485
5525
  };
5486
5526
  function readContextWindowPolicy(ctx) {
@@ -5492,15 +5532,6 @@ function readContextWindowPolicy(ctx) {
5492
5532
  }
5493
5533
  return candidate;
5494
5534
  }
5495
- function hasTextContent(m) {
5496
- if (typeof m.content === "string") return m.content.trim().length > 0;
5497
- return m.content.some((b) => b.type === "text" && b.text.trim().length > 0);
5498
- }
5499
-
5500
- // src/types/blocks.ts
5501
- function isTextBlock(b) {
5502
- return b.type === "text";
5503
- }
5504
5535
 
5505
5536
  // src/execution/intelligent-compactor.ts
5506
5537
  var IntelligentCompactor = class {
@@ -5525,23 +5556,25 @@ var IntelligentCompactor = class {
5525
5556
  this.summarizerModel = opts.summarizerModel;
5526
5557
  }
5527
5558
  async compact(ctx, opts = {}) {
5528
- const beforeTokens = this.estimateTokens(ctx.messages);
5559
+ const beforeTokens = estimateMessages(ctx.messages);
5529
5560
  const beforeFull = this.estimateFullRequest(ctx);
5530
5561
  const reductions = [];
5531
5562
  const load = beforeFull / this.maxContext;
5532
5563
  const aggressive = load >= this.hardThreshold ? true : opts.aggressive ?? load >= this.softThreshold;
5533
- const saved1 = this.eliseOldToolResults(ctx);
5564
+ const saved1 = this.elide(ctx);
5534
5565
  if (saved1 > 0) reductions.push({ phase: "elision", saved: saved1 });
5566
+ let collapsedDigest;
5535
5567
  if (aggressive) {
5536
- const saved2 = await this.summarizeAncientTurns(ctx);
5537
- if (saved2 > 0) reductions.push({ phase: "summary", saved: saved2 });
5568
+ const phase2 = await this.summarizeAncientTurns(ctx);
5569
+ if (phase2.saved > 0) reductions.push({ phase: "summary", saved: phase2.saved });
5570
+ collapsedDigest = phase2.digest;
5538
5571
  } else if (load >= this.warnThreshold) {
5539
- const saved2 = this.lightweightCompact(ctx);
5572
+ const saved2 = this.elide(ctx);
5540
5573
  if (saved2 > 0) reductions.push({ phase: "elision", saved: saved2 });
5541
5574
  }
5542
5575
  const repaired = repairToolUseAdjacency(ctx.messages);
5543
5576
  if (repaired.report.changed) ctx.state.replaceMessages(repaired.messages);
5544
- const afterTokens = this.estimateTokens(ctx.messages);
5577
+ const afterTokens = estimateMessages(ctx.messages);
5545
5578
  const afterFull = this.estimateFullRequest(ctx);
5546
5579
  return {
5547
5580
  before: beforeTokens,
@@ -5549,6 +5582,7 @@ var IntelligentCompactor = class {
5549
5582
  fullRequestTokensBefore: beforeFull,
5550
5583
  fullRequestTokensAfter: afterFull,
5551
5584
  reductions,
5585
+ collapsedDigest,
5552
5586
  repaired: repaired.report.changed ? {
5553
5587
  removedToolUses: repaired.report.removedToolUses,
5554
5588
  removedToolResults: repaired.report.removedToolResults,
@@ -5561,75 +5595,39 @@ var IntelligentCompactor = class {
5561
5595
  * This is the accurate figure for context-window pressure monitoring.
5562
5596
  */
5563
5597
  estimateFullRequest(ctx) {
5564
- const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);
5565
- return breakdown.total;
5598
+ return estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []).total;
5599
+ }
5600
+ /** Run shared tool-result elision and commit through ConversationState. */
5601
+ elide(ctx) {
5602
+ const result = eliseOldToolResults(ctx.messages, {
5603
+ preserveK: this.preserveK,
5604
+ eliseThreshold: this.eliseThreshold
5605
+ });
5606
+ if (result.changed) ctx.state.replaceMessages(result.messages);
5607
+ return result.saved;
5566
5608
  }
5567
5609
  async summarizeAncientTurns(ctx) {
5568
5610
  const messages = ctx.messages;
5569
5611
  const cutoff = Math.max(0, messages.length - this.preserveK * 2);
5570
- if (cutoff <= 2) return 0;
5571
- const boundary = this.findSafeBoundary(messages, 0, cutoff);
5572
- if (boundary <= 1) return 0;
5612
+ if (cutoff <= 2) return { saved: 0 };
5613
+ const boundary = findSafeBoundary(messages, 0, cutoff);
5614
+ if (boundary <= 1) return { saved: 0 };
5573
5615
  const toSummarize = messages.slice(0, boundary);
5574
- const removedTokens = this.estimateTokens(toSummarize);
5616
+ const removedTokens = estimateMessages(toSummarize);
5575
5617
  let summaryText;
5576
5618
  try {
5577
5619
  summaryText = await this.callSummarizer(toSummarize, ctx);
5578
5620
  } catch {
5579
- const preservedMessages = [];
5580
- for (const m of toSummarize) {
5581
- if (m.role === "system") continue;
5582
- if (typeof m.content === "string") {
5583
- preservedMessages.push(m);
5584
- } else if (Array.isArray(m.content)) {
5585
- const textParts = m.content.filter(isTextBlock);
5586
- const toolParts = m.content.filter((b) => b.type === "tool_use" || b.type === "tool_result");
5587
- const next = {
5588
- role: m.role,
5589
- content: [
5590
- ...textParts,
5591
- ...toolParts.length > 0 ? [{ type: "text", text: `[${toolParts.length} tool call(s) omitted]` }] : []
5592
- ]
5593
- };
5594
- preservedMessages.push(next);
5595
- }
5596
- }
5597
- summaryText = preservedMessages.map((m) => `[${m.role}]: ${typeof m.content === "string" ? m.content : m.content.filter(isTextBlock).map((b) => b.text).join(" ")}`).join("\n");
5598
- if (!summaryText) summaryText = `${toSummarize.length} earlier turns (semantic content preserved)`;
5621
+ summaryText = buildLosslessDigest(toSummarize) || `${toSummarize.length} earlier turns (semantic content preserved)`;
5599
5622
  }
5600
5623
  const summaryMsg = {
5601
5624
  role: "system",
5602
5625
  content: `[prior_turns_summary: ${summaryText}]`
5603
5626
  };
5604
- const summaryTokens = this.estimateTokens([summaryMsg]);
5627
+ const summaryTokens = estimateMessages([summaryMsg]);
5605
5628
  const tail = ctx.messages.slice(boundary);
5606
5629
  ctx.state.replaceMessages([summaryMsg, ...tail]);
5607
- return Math.max(0, removedTokens - summaryTokens);
5608
- }
5609
- findSafeBoundary(messages, from, to) {
5610
- for (let i = to; i >= from; i--) {
5611
- const m = messages[i];
5612
- if (!m) continue;
5613
- if (m.role === "user" && this.hasTextContent(m)) {
5614
- return this.findExchangeStart(messages, i);
5615
- }
5616
- }
5617
- return -1;
5618
- }
5619
- findExchangeStart(messages, userIndex) {
5620
- for (let i = userIndex - 1; i >= 0; i--) {
5621
- const m = messages[i];
5622
- if (!m) continue;
5623
- if (m.role === "assistant") {
5624
- const hasToolUse2 = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
5625
- if (!hasToolUse2) {
5626
- return i + 1;
5627
- }
5628
- } else if (m.role !== "user") ; else {
5629
- return i;
5630
- }
5631
- }
5632
- return 0;
5630
+ return { saved: Math.max(0, removedTokens - summaryTokens), digest: summaryText };
5633
5631
  }
5634
5632
  async callSummarizer(messages, ctx) {
5635
5633
  const prompt = [
@@ -5664,86 +5662,6 @@ var IntelligentCompactor = class {
5664
5662
  }
5665
5663
  return [{ type: "text", text: lines.join("\n") }];
5666
5664
  }
5667
- lightweightCompact(ctx) {
5668
- return this.eliseOldToolResults(ctx);
5669
- }
5670
- eliseOldToolResults(ctx) {
5671
- const messages = ctx.messages;
5672
- let pairCount = 0;
5673
- let preserveStart = messages.length;
5674
- for (let i = messages.length - 1; i >= 0 && pairCount < this.preserveK; i--) {
5675
- const m = messages[i];
5676
- if (!m) continue;
5677
- if (m.role === "user" || m.role === "assistant") {
5678
- pairCount++;
5679
- preserveStart = i;
5680
- }
5681
- }
5682
- for (let i = preserveStart; i < messages.length; i++) {
5683
- const m = messages[i];
5684
- if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
5685
- const hasToolUse2 = m.content.some((b) => b.type === "tool_use");
5686
- if (hasToolUse2 && i + 1 < messages.length) {
5687
- const next = messages[i + 1];
5688
- if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
5689
- preserveStart = i + 1;
5690
- }
5691
- }
5692
- }
5693
- let saved = 0;
5694
- let changed = false;
5695
- const nextMessages = new Array(messages.length);
5696
- for (let i = 0; i < messages.length; i++) {
5697
- const msg = messages[i];
5698
- if (i >= preserveStart) {
5699
- nextMessages[i] = msg;
5700
- continue;
5701
- }
5702
- if (!msg || !Array.isArray(msg.content)) {
5703
- nextMessages[i] = msg;
5704
- continue;
5705
- }
5706
- const newContent = msg.content.map((b) => {
5707
- if (b.type !== "tool_result") return b;
5708
- const tokens = estimateToolResultTokens(b.content);
5709
- if (tokens < this.eliseThreshold) return b;
5710
- saved += tokens;
5711
- return {
5712
- type: "tool_result",
5713
- tool_use_id: b.tool_use_id,
5714
- content: `[elided: ~${tokens} tokens]`,
5715
- is_error: b.is_error
5716
- };
5717
- });
5718
- if (newContent.length === msg.content.length && newContent.every((b, idx) => b === msg.content[idx])) {
5719
- nextMessages[i] = msg;
5720
- } else {
5721
- nextMessages[i] = { ...msg, content: newContent };
5722
- changed = true;
5723
- }
5724
- }
5725
- if (changed) ctx.state.replaceMessages(nextMessages);
5726
- return saved;
5727
- }
5728
- hasTextContent(m) {
5729
- if (typeof m.content === "string") return m.content.trim().length > 0;
5730
- return m.content.some((b) => b.type === "text" && b.text.trim().length > 0);
5731
- }
5732
- estimateTokens(messages) {
5733
- let total = 0;
5734
- for (const m of messages) {
5735
- if (typeof m.content === "string") {
5736
- total += estimateTextTokens(m.content);
5737
- } else {
5738
- for (const b of m.content) {
5739
- if (b.type === "text") total += estimateTextTokens(b.text);
5740
- else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
5741
- else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
5742
- }
5743
- }
5744
- }
5745
- return total;
5746
- }
5747
5665
  };
5748
5666
 
5749
5667
  // src/models/llm-selector.ts
@@ -5769,20 +5687,6 @@ Rules:
5769
5687
  - If unsure, keep rather than collapse (errors are more costly than waste)
5770
5688
 
5771
5689
  Return ONLY the JSON object, no markdown, no explanation outside the JSON.`;
5772
- function estimateTokens(messages) {
5773
- let total = 0;
5774
- for (const m of messages) {
5775
- if (typeof m.content === "string") {
5776
- total += Math.ceil(m.content.length / 4);
5777
- } else if (Array.isArray(m.content)) {
5778
- for (const b of m.content) {
5779
- if (b.type === "text") total += Math.ceil(b.text.length / 4);
5780
- else total += Math.ceil(JSON.stringify(b).length / 4);
5781
- }
5782
- }
5783
- }
5784
- return total;
5785
- }
5786
5690
  function formatMessages(messages, maxChars = 8e3) {
5787
5691
  const lines = [];
5788
5692
  let used = 0;
@@ -5821,7 +5725,7 @@ var LLMSelector = class {
5821
5725
  async select(messages, maxToKeep) {
5822
5726
  const effectiveBudget = Math.min(maxToKeep, this.maxContextTokens);
5823
5727
  const historyText = formatMessages(messages);
5824
- const totalTokens = estimateTokens(messages);
5728
+ const totalTokens = estimateMessageTokens(messages);
5825
5729
  const systemText = `${this.systemPrompt}
5826
5730
 
5827
5731
  Conversation (${messages.length} messages, ~${totalTokens} tokens, budget: ${effectiveBudget}):
@@ -5853,10 +5757,7 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
5853
5757
  let startIdx = 0;
5854
5758
  for (let i = messages.length - 1; i >= 0; i--) {
5855
5759
  const m = expectDefined(messages[i]);
5856
- const cost = typeof m.content === "string" ? Math.ceil(m.content.length / 4) : m.content.reduce(
5857
- (acc, b) => acc + (b.type === "text" ? Math.ceil(b.text.length / 4) : Math.ceil(JSON.stringify(b).length / 4)),
5858
- 0
5859
- );
5760
+ const cost = estimateMessageTokens([m]);
5860
5761
  if (tokenCount + cost <= budget) {
5861
5762
  tokenCount += cost;
5862
5763
  } else {
@@ -6089,52 +5990,12 @@ Summarize the following message range:`;
6089
5990
  return Math.floor(this.maxContext * 0.75);
6090
5991
  }
6091
5992
  eliseOldToolResults(ctx) {
6092
- const messages = ctx.messages;
6093
- let pairCount = 0;
6094
- let preserveStart = messages.length;
6095
- for (let i = messages.length - 1; i >= 0 && pairCount < this.preserveK; i--) {
6096
- const m = messages[i];
6097
- if (!m) continue;
6098
- if (m.role === "user" || m.role === "assistant") {
6099
- pairCount++;
6100
- preserveStart = i;
6101
- }
6102
- }
6103
- let saved = 0;
6104
- let changed = false;
6105
- const nextMessages = new Array(messages.length);
6106
- for (let i = 0; i < messages.length; i++) {
6107
- const msg = messages[i];
6108
- if (i >= preserveStart) {
6109
- nextMessages[i] = msg;
6110
- continue;
6111
- }
6112
- if (!msg || !Array.isArray(msg.content)) {
6113
- nextMessages[i] = msg;
6114
- continue;
6115
- }
6116
- const newContent = msg.content.map((b) => {
6117
- if (b.type !== "tool_result") return b;
6118
- const text = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
6119
- const tokens = this.roughTokenEstimate(text);
6120
- if (tokens < this.eliseThreshold) return b;
6121
- saved += tokens;
6122
- return {
6123
- type: "tool_result",
6124
- tool_use_id: b.tool_use_id,
6125
- content: `[elided: ~${tokens} tokens]`,
6126
- is_error: b.is_error
6127
- };
6128
- });
6129
- if (newContent.every((b, idx) => b === msg.content[idx])) {
6130
- nextMessages[i] = msg;
6131
- } else {
6132
- nextMessages[i] = { ...msg, content: newContent };
6133
- changed = true;
6134
- }
6135
- }
6136
- if (changed) ctx.state.replaceMessages(nextMessages);
6137
- return saved;
5993
+ const result = eliseOldToolResults(ctx.messages, {
5994
+ preserveK: this.preserveK,
5995
+ eliseThreshold: this.eliseThreshold
5996
+ });
5997
+ if (result.changed) ctx.state.replaceMessages(result.messages);
5998
+ return result.saved;
6138
5999
  }
6139
6000
  hasTextContent(m) {
6140
6001
  if (typeof m.content === "string") return m.content.trim().length > 0;
@@ -6164,8 +6025,80 @@ Summarize the following message range:`;
6164
6025
  }
6165
6026
  };
6166
6027
 
6028
+ // src/execution/strategy-compactor.ts
6029
+ function createStrategyCompactor(opts = {}) {
6030
+ const requested = opts.strategy ?? (opts.llmSelector ? "selective" : "hybrid");
6031
+ const strategy = requested;
6032
+ if (strategy === "intelligent" || strategy === "selective") {
6033
+ return new ProviderBackedCompactor(strategy, opts);
6034
+ }
6035
+ return new HybridCompactor({
6036
+ preserveK: opts.preserveK,
6037
+ eliseThreshold: opts.eliseThreshold
6038
+ });
6039
+ }
6040
+ var ProviderBackedCompactor = class {
6041
+ constructor(strategy, opts) {
6042
+ this.strategy = strategy;
6043
+ this.opts = opts;
6044
+ }
6045
+ strategy;
6046
+ opts;
6047
+ async compact(ctx, compactOpts = {}) {
6048
+ return this.resolveInner(ctx).compact(ctx, compactOpts);
6049
+ }
6050
+ /**
6051
+ * Construct the concrete compactor for this run. Rebuilt per call (cheap, no
6052
+ * I/O) so a model switch — which changes `ctx.provider.capabilities.maxContext`
6053
+ * — is always reflected. Reads the active ContextWindowPolicy from `ctx.meta`
6054
+ * so the LLM compactors honor the same thresholds/preserveK as the policy.
6055
+ */
6056
+ resolveInner(ctx) {
6057
+ const provider = ctx.provider;
6058
+ if (!provider) {
6059
+ return new HybridCompactor({
6060
+ preserveK: this.opts.preserveK,
6061
+ eliseThreshold: this.opts.eliseThreshold
6062
+ });
6063
+ }
6064
+ const policy = readPolicy(ctx);
6065
+ const maxContext = provider.capabilities?.maxContext || void 0;
6066
+ const thresholds = policy?.thresholds;
6067
+ const common = {
6068
+ provider,
6069
+ maxContext,
6070
+ preserveK: this.opts.preserveK ?? policy?.preserveK,
6071
+ eliseThreshold: this.opts.eliseThreshold ?? policy?.eliseThreshold,
6072
+ ...thresholds ? { warnThreshold: thresholds.warn, softThreshold: thresholds.soft, hardThreshold: thresholds.hard } : {}
6073
+ };
6074
+ if (this.strategy === "selective") {
6075
+ return new SelectiveCompactor({
6076
+ ...common,
6077
+ selectorModel: this.opts.summarizerModel,
6078
+ summarizerModel: this.opts.summarizerModel
6079
+ });
6080
+ }
6081
+ return new IntelligentCompactor({
6082
+ ...common,
6083
+ summarizerModel: this.opts.summarizerModel
6084
+ });
6085
+ }
6086
+ };
6087
+ function readPolicy(ctx) {
6088
+ const policy = ctx.meta?.["contextWindowPolicy"];
6089
+ if (!policy || typeof policy !== "object") return null;
6090
+ const candidate = policy;
6091
+ if (typeof candidate.preserveK !== "number" || !candidate.thresholds) return null;
6092
+ return candidate;
6093
+ }
6094
+
6167
6095
  // src/execution/auto-compaction-middleware.ts
6168
6096
  var LEVEL_RANK2 = { warn: 0, soft: 1, hard: 2 };
6097
+ var MAX_DIGEST_LOG_CHARS = 4e3;
6098
+ function truncateDigest(digest) {
6099
+ if (digest.length <= MAX_DIGEST_LOG_CHARS) return digest;
6100
+ return `${digest.slice(0, MAX_DIGEST_LOG_CHARS)}\u2026 [+${digest.length - MAX_DIGEST_LOG_CHARS} chars; full turns in session log]`;
6101
+ }
6169
6102
  var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
6170
6103
  name = "AutoCompaction";
6171
6104
  compactor;
@@ -6226,7 +6159,12 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
6226
6159
  }
6227
6160
  handler() {
6228
6161
  return async (ctx, next) => {
6229
- const tokens = this._estimator ? this._estimator(ctx) : estimateRequestTokensCalibrated(ctx.messages, ctx.systemPrompt, ctx.tools ?? []).total;
6162
+ const tokens = this._estimator ? this._estimator(ctx) : estimateRequestTokensCalibrated(
6163
+ ctx.messages,
6164
+ ctx.systemPrompt,
6165
+ ctx.tools ?? [],
6166
+ `${ctx.provider?.id ?? "unknown"}/${ctx.model}`
6167
+ ).total;
6230
6168
  const load = tokens / this._maxContext;
6231
6169
  const policy = this.policyProvider?.(ctx);
6232
6170
  const thresholds = policy?.thresholds ?? {
@@ -6288,7 +6226,11 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
6288
6226
  after: report.after,
6289
6227
  level: pressure.level,
6290
6228
  aggressive,
6291
- reductions: report.reductions?.map((r) => ({ phase: r.phase, saved: r.saved }))
6229
+ reductions: report.reductions?.map((r) => ({ phase: r.phase, saved: r.saved })),
6230
+ // Record what was collapsed so the audit trail shows the preserved
6231
+ // content, not just token counts. Bounded to keep the log line small;
6232
+ // the full original turns are already in the session JSONL.
6233
+ ...report.collapsedDigest ? { digest: truncateDigest(report.collapsedDigest) } : {}
6292
6234
  });
6293
6235
  ctx.clearFileTracking();
6294
6236
  } catch (err) {
@@ -6323,10 +6265,10 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
6323
6265
  // src/utils/json-schema-validate.ts
6324
6266
  function validateAgainstSchema(value, schema) {
6325
6267
  const errors = [];
6326
- walk3(value, schema, "", errors);
6268
+ walk2(value, schema, "", errors);
6327
6269
  return { ok: errors.length === 0, errors };
6328
6270
  }
6329
- function walk3(value, schema, path19, errors) {
6271
+ function walk2(value, schema, path19, errors) {
6330
6272
  if (schema.enum !== void 0) {
6331
6273
  if (!schema.enum.some((e) => deepEqual(e, value))) {
6332
6274
  errors.push({
@@ -6355,13 +6297,13 @@ function walk3(value, schema, path19, errors) {
6355
6297
  if (schema.properties) {
6356
6298
  for (const [key, subSchema] of Object.entries(schema.properties)) {
6357
6299
  if (key in obj) {
6358
- walk3(obj[key], subSchema, joinPath(path19, key), errors);
6300
+ walk2(obj[key], subSchema, joinPath(path19, key), errors);
6359
6301
  }
6360
6302
  }
6361
6303
  }
6362
6304
  }
6363
6305
  if (schema.type === "array" && Array.isArray(value) && schema.items) {
6364
- value.forEach((item, i) => walk3(item, schema.items, `${path19}[${i}]`, errors));
6306
+ value.forEach((item, i) => walk2(item, schema.items, `${path19}[${i}]`, errors));
6365
6307
  }
6366
6308
  }
6367
6309
  function checkType(value, type) {
@@ -6875,6 +6817,13 @@ function extractMalformedRaw(input) {
6875
6817
  }
6876
6818
  }
6877
6819
 
6820
+ // src/utils/assert-never.ts
6821
+ function assertNever(x, message) {
6822
+ throw new Error(
6823
+ `Unhandled case: ${JSON.stringify(x)}`
6824
+ );
6825
+ }
6826
+
6878
6827
  // src/execution/autonomous-runner.ts
6879
6828
  var DoneConditionChecker = class {
6880
6829
  constructor(condition) {
@@ -6928,6 +6877,12 @@ var DoneConditionChecker = class {
6928
6877
  return { done: true, reason: `max tool calls (${this.condition.maxToolCalls}) reached`, ...state };
6929
6878
  }
6930
6879
  break;
6880
+ case "all_tasks_done":
6881
+ break;
6882
+ case "custom":
6883
+ break;
6884
+ default:
6885
+ return assertNever(this.condition.type);
6931
6886
  }
6932
6887
  return { done: false, iterations: state.iterations, toolCalls: state.toolCalls };
6933
6888
  }
@@ -7150,9 +7105,9 @@ function parseProgressFromText(text) {
7150
7105
  const re = /\[progress:\s*(\d{1,3})%\]\s*(?:[—\-]\s*(.+))?/i;
7151
7106
  const m = text.match(re);
7152
7107
  if (!m) return null;
7153
- const progress = Math.min(100, Math.max(0, Number.parseInt(m[1], 10)));
7108
+ const progress = Math.min(100, Math.max(0, Number.parseInt(m[1] ?? "0", 10)));
7154
7109
  const note = m[2]?.trim() || void 0;
7155
- return { progress, note };
7110
+ return note === void 0 ? { progress } : { progress, note };
7156
7111
  }
7157
7112
  function recordProgress(goal, progress, note) {
7158
7113
  const clamped = Math.min(100, Math.max(0, progress));
@@ -7750,6 +7705,7 @@ ${recentJournal}` : "No prior iterations.",
7750
7705
  note: note.slice(0, 240)
7751
7706
  });
7752
7707
  await saveGoal(this.goalPath, withEntry);
7708
+ this.opts.onEternalStop?.();
7753
7709
  }
7754
7710
  /**
7755
7711
  * Manually clear the goal — equivalent to `/goal clear` typed by the user.
@@ -12886,7 +12842,7 @@ async function expandGlob(pattern) {
12886
12842
  const abs = isAbsolute(pattern);
12887
12843
  const base = abs ? baseDir(pattern) : baseDir(pattern);
12888
12844
  const relPat = base === "." ? pattern : pattern.slice(base.length + 1);
12889
- async function walk4(dir, pat) {
12845
+ async function walk3(dir, pat) {
12890
12846
  let entries;
12891
12847
  try {
12892
12848
  entries = await fsp.readdir(dir);
@@ -12907,12 +12863,12 @@ async function expandGlob(pattern) {
12907
12863
  const before = pat.slice(0, firstGlob);
12908
12864
  const rest = pat.slice(firstGlob);
12909
12865
  if (before.endsWith("**")) {
12910
- await walk4(dir, rest);
12866
+ await walk3(dir, rest);
12911
12867
  for (const e of entries) {
12912
12868
  const full = `${dir}${SEP}${e}`;
12913
12869
  try {
12914
12870
  const stat6 = await fsp.stat(full);
12915
- if (stat6.isDirectory()) await walk4(full, rest);
12871
+ if (stat6.isDirectory()) await walk3(full, rest);
12916
12872
  } catch {
12917
12873
  }
12918
12874
  }
@@ -12930,13 +12886,13 @@ async function expandGlob(pattern) {
12930
12886
  const full = `${dir}${SEP}${seg}`;
12931
12887
  try {
12932
12888
  const stat6 = await fsp.stat(full);
12933
- if (stat6.isDirectory()) await walk4(full, rest);
12889
+ if (stat6.isDirectory()) await walk3(full, rest);
12934
12890
  } catch {
12935
12891
  }
12936
12892
  }
12937
12893
  }
12938
12894
  }
12939
- await walk4(base === "." ? "." : base, relPat);
12895
+ await walk3(base === "." ? "." : base, relPat);
12940
12896
  return [...results];
12941
12897
  }
12942
12898
 
@@ -14532,7 +14488,10 @@ var Director = class _Director {
14532
14488
  workCompleteFlag = false;
14533
14489
  /** Pending /btw notes stashed by the leader agent (see setLeaderBtwNote). */
14534
14490
  _leaderBtwNotes = [];
14535
- /** Active collab sessions tracked by sessionId (see spawnCollab). */
14491
+ /** Active collab sessions tracked by sessionId (see spawnCollab).
14492
+ * The tuple holds the session and its Director-registered listener unsubs.
14493
+ * Calling the unsubs on cancel/premature-cleanup prevents listener accumulation
14494
+ * on CollabSession (EventEmitter) across many spawnCollab() calls. */
14536
14495
  _activeCollabSessions = /* @__PURE__ */ new Map();
14537
14496
  /** Prevents large `ask_subagent` answers from bloating the leader's context window. */
14538
14497
  largeAnswerStore;
@@ -14862,11 +14821,13 @@ var Director = class _Director {
14862
14821
  * The CollabDebugReport will reflect 'cancelled' disposition when awaited.
14863
14822
  */
14864
14823
  cancelCollabSession(sessionId, reason = "Director cancelled") {
14865
- const session = this._activeCollabSessions.get(sessionId);
14866
- if (!session || session.isCancelled()) return;
14867
- session.cancel(reason);
14868
- for (const [_role, subagentId] of session.getSubagentIds()) {
14869
- this.coordinator.stop(subagentId).catch(() => {
14824
+ const entry = this._activeCollabSessions.get(sessionId);
14825
+ if (!entry || entry.session.isCancelled()) return;
14826
+ for (const unsub of entry.unsubs) unsub();
14827
+ entry.session.cancel(reason);
14828
+ for (const [_role, subagentId] of entry.session.getSubagentIds()) {
14829
+ this.coordinator.stop(subagentId).catch((err) => {
14830
+ console.debug(`[director] stop subagent ${subagentId} failed (may have already completed): ${err}`);
14870
14831
  });
14871
14832
  }
14872
14833
  }
@@ -15514,9 +15475,15 @@ var Director = class _Director {
15514
15475
  return options.onBudgetWarning?.(alert) ?? "ignore";
15515
15476
  }
15516
15477
  });
15517
- this._activeCollabSessions.set(session.sessionId, session);
15518
- session.on("session.done", () => this._activeCollabSessions.delete(session.sessionId));
15519
- session.on("session.error", () => this._activeCollabSessions.delete(session.sessionId));
15478
+ const doneHandler = () => this._activeCollabSessions.delete(session.sessionId);
15479
+ const errorHandler = () => this._activeCollabSessions.delete(session.sessionId);
15480
+ session.on("session.done", doneHandler);
15481
+ session.on("session.error", errorHandler);
15482
+ const unsubs = [
15483
+ () => session.off("session.done", doneHandler),
15484
+ () => session.off("session.error", errorHandler)
15485
+ ];
15486
+ this._activeCollabSessions.set(session.sessionId, { session, unsubs });
15520
15487
  return session.start();
15521
15488
  }
15522
15489
  /**
@@ -18938,6 +18905,8 @@ var SpecVersioning = class {
18938
18905
  switch (type) {
18939
18906
  case "functional":
18940
18907
  return "feature";
18908
+ case "non-functional":
18909
+ return "feature";
18941
18910
  case "security":
18942
18911
  return "feature";
18943
18912
  case "performance":
@@ -18945,7 +18914,7 @@ var SpecVersioning = class {
18945
18914
  case "ux":
18946
18915
  return "feature";
18947
18916
  default:
18948
- return "feature";
18917
+ return assertNever(type);
18949
18918
  }
18950
18919
  }
18951
18920
  };
@@ -20096,27 +20065,13 @@ function startOtlpTraceExporter(opts) {
20096
20065
  // src/infrastructure/context-manager.ts
20097
20066
  var CONTEXT_MANAGER_TOOL_NAME = "context_manager";
20098
20067
  function roughEstimate(messages) {
20099
- let total = 0;
20100
- for (const m of messages) {
20101
- if (typeof m.content === "string") {
20102
- total += Math.ceil(m.content.length / 4);
20103
- } else if (Array.isArray(m.content)) {
20104
- for (const b of m.content) {
20105
- if (b.type === "text") total += Math.ceil(b.text.length / 4);
20106
- else if (b.type === "tool_use" || b.type === "tool_result") {
20107
- total += Math.ceil(JSON.stringify(b).length / 4);
20108
- }
20109
- }
20110
- }
20111
- }
20112
- return total;
20068
+ return estimateMessageTokens(messages);
20113
20069
  }
20114
20070
  function createContextManagerTool(opts = {}) {
20115
20071
  const minCompactThreshold = opts.minCompactThreshold ?? 0;
20116
20072
  const noopRetryDeltaTokens = opts.noopRetryDeltaTokens ?? 2e3;
20117
- const maxContext = opts.maxContext ?? 128e3;
20073
+ const configuredMaxContext = opts.maxContext;
20118
20074
  const compactThresholdFraction = opts.compactThresholdFraction ?? 0.5;
20119
- const effectiveThreshold = minCompactThreshold > 0 ? minCompactThreshold : Math.floor(maxContext * compactThresholdFraction);
20120
20075
  let lastNoopTokens = 0;
20121
20076
  return {
20122
20077
  name: CONTEXT_MANAGER_TOOL_NAME,
@@ -20210,6 +20165,8 @@ function createContextManagerTool(opts = {}) {
20210
20165
  }
20211
20166
  const fullEstimate = input.systemPrompt != null && Array.isArray(input.tools) ? estimateRequestTokens(messages, input.systemPrompt, input.tools) : { total: beforeTokens};
20212
20167
  const currentTokens = fullEstimate.total;
20168
+ const runtimeMaxContext = configuredMaxContext ?? ctx.provider?.capabilities?.maxContext ?? 128e3;
20169
+ const runtimeThreshold = minCompactThreshold > 0 ? minCompactThreshold : Math.floor(runtimeMaxContext * compactThresholdFraction);
20213
20170
  if (lastNoopTokens > 0) {
20214
20171
  const delta = currentTokens - lastNoopTokens;
20215
20172
  if (delta < noopRetryDeltaTokens) {
@@ -20222,13 +20179,13 @@ function createContextManagerTool(opts = {}) {
20222
20179
  };
20223
20180
  }
20224
20181
  }
20225
- if (currentTokens < effectiveThreshold) {
20182
+ if (runtimeThreshold > 0 && currentTokens < runtimeThreshold) {
20226
20183
  return {
20227
20184
  action: "compact",
20228
20185
  beforeTokens,
20229
20186
  afterTokens: beforeTokens,
20230
20187
  messageCount: messages.length,
20231
- notes: `Context tokens (${currentTokens}) below compact threshold (${effectiveThreshold}). Skipping.`
20188
+ notes: `Context tokens (${currentTokens}) below compact threshold (${runtimeThreshold}, based on provider maxContext ${runtimeMaxContext}). Skipping.`
20232
20189
  };
20233
20190
  }
20234
20191
  const report = await opts.compactor.compact(ctx);
@@ -20481,6 +20438,6 @@ var allServers = () => ({
20481
20438
  "minimax-vision": { ...miniMaxVisionServer(), enabled: false }
20482
20439
  });
20483
20440
 
20484
- export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SddParallelRun, SddTaskDecomposer, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, createSessionEventBridge, decryptConfigSecrets2 as decryptConfigSecrets, deriveTodosFromPlanItem, dispatchAgent, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getAgentDefinition, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, resolveAuditLevel, resolveSessionLoggingConfig, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, scoreAgents, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
20441
+ export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SddParallelRun, SddTaskDecomposer, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, createSessionEventBridge, createStrategyCompactor, decryptConfigSecrets, deriveTodosFromPlanItem, dispatchAgent, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getAgentDefinition, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, resolveAuditLevel, resolveSessionLoggingConfig, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, scoreAgents, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
20485
20442
  //# sourceMappingURL=index.js.map
20486
20443
  //# sourceMappingURL=index.js.map