@wrongstack/core 0.9.19 → 0.10.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 (73) hide show
  1. package/README.md +37 -33
  2. package/dist/{agent-bridge-DMVOX0cF.d.ts → agent-bridge-DBBGP5O4.d.ts} +1 -1
  3. package/dist/{agent-subagent-runner-C4qt9e5Y.d.ts → agent-subagent-runner-KwufTWwn.d.ts} +3 -4
  4. package/dist/compactor-D1RHFRmF.d.ts +41 -0
  5. package/dist/{config-CWva0qoL.d.ts → config-CJXBka2r.d.ts} +38 -2
  6. package/dist/{context-BRNbHmRM.d.ts → context-7u93AcGD.d.ts} +140 -0
  7. package/dist/coordination/index.d.ts +13 -13
  8. package/dist/coordination/index.js +786 -200
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/{default-config-Uzla85H-.d.ts → default-config-DEXI4jsl.d.ts} +10 -1
  11. package/dist/defaults/index.d.ts +24 -24
  12. package/dist/defaults/index.js +1612 -528
  13. package/dist/defaults/index.js.map +1 -1
  14. package/dist/{events-CiG9qUM_.d.ts → events-Bw1K5E6K.d.ts} +49 -1
  15. package/dist/execution/index.d.ts +46 -32
  16. package/dist/execution/index.js +663 -169
  17. package/dist/execution/index.js.map +1 -1
  18. package/dist/extension/index.d.ts +6 -6
  19. package/dist/extension/index.js.map +1 -1
  20. package/dist/goal-store-BeRsj7YX.d.ts +188 -0
  21. package/dist/{index-p95HQ22A.d.ts → index-DIt5TIaF.d.ts} +8 -8
  22. package/dist/{index-aizK8olO.d.ts → index-DgQWnZxP.d.ts} +11 -8
  23. package/dist/index.d.ts +338 -41
  24. package/dist/index.js +2747 -787
  25. package/dist/index.js.map +1 -1
  26. package/dist/infrastructure/index.d.ts +6 -6
  27. package/dist/infrastructure/index.js +36 -0
  28. package/dist/infrastructure/index.js.map +1 -1
  29. package/dist/kernel/index.d.ts +9 -9
  30. package/dist/kernel/index.js +57 -8
  31. package/dist/kernel/index.js.map +1 -1
  32. package/dist/{mcp-servers-BkVEqkRe.d.ts → mcp-servers-BgINZzuo.d.ts} +25 -3
  33. package/dist/models/index.d.ts +3 -3
  34. package/dist/models/index.js +164 -11
  35. package/dist/models/index.js.map +1 -1
  36. package/dist/models-registry-gwMAo6E3.d.ts +86 -0
  37. package/dist/{multi-agent-3ZnTB1aT.d.ts → multi-agent-C1O8EFzb.d.ts} +77 -24
  38. package/dist/{multi-agent-coordinator-bRaI_aD1.d.ts → multi-agent-coordinator-DoVSBFNx.d.ts} +20 -2
  39. package/dist/{null-fleet-bus-DKM3Iy9d.d.ts → null-fleet-bus-T-s3JaOt.d.ts} +413 -110
  40. package/dist/observability/index.d.ts +2 -2
  41. package/dist/{path-resolver-TcJfc29Y.d.ts → path-resolver-BfyK-I7w.d.ts} +2 -2
  42. package/dist/{permission-bPuzAy4x.d.ts → permission-B6sldrSp.d.ts} +1 -1
  43. package/dist/{permission-policy-BUQSutpl.d.ts → permission-policy-CtNscWOA.d.ts} +10 -9
  44. package/dist/{plan-templates-fkQTyz3U.d.ts → plan-templates-BWs6Je7j.d.ts} +8 -8
  45. package/dist/{provider-runner-BEpikbbN.d.ts → provider-runner-BmPe2RuU.d.ts} +3 -3
  46. package/dist/{retry-policy-BYkq0ugs.d.ts → retry-policy-KF18W4dg.d.ts} +1 -1
  47. package/dist/sdd/index.d.ts +9 -10
  48. package/dist/sdd/index.js +350 -122
  49. package/dist/sdd/index.js.map +1 -1
  50. package/dist/security/index.d.ts +65 -4
  51. package/dist/security/index.js +67 -19
  52. package/dist/security/index.js.map +1 -1
  53. package/dist/{selector-pox8abg0.d.ts → selector-DmXxpFyM.d.ts} +1 -1
  54. package/dist/{session-reader-CSWcb5Ga.d.ts → session-reader-CCSBfQmd.d.ts} +2 -2
  55. package/dist/skills/index.d.ts +1 -1
  56. package/dist/skills/index.js +1 -1
  57. package/dist/skills/index.js.map +1 -1
  58. package/dist/storage/index.d.ts +392 -8
  59. package/dist/storage/index.js +796 -40
  60. package/dist/storage/index.js.map +1 -1
  61. package/dist/{system-prompt-Bs-Wliab.d.ts → system-prompt-CM6zOhd2.d.ts} +19 -1
  62. package/dist/{tool-executor-Boo3dekH.d.ts → tool-executor-D7RxLtg4.d.ts} +9 -4
  63. package/dist/types/index.d.ts +16 -16
  64. package/dist/types/index.js +404 -14
  65. package/dist/types/index.js.map +1 -1
  66. package/dist/utils/index.d.ts +40 -8
  67. package/dist/utils/index.js +127 -57
  68. package/dist/utils/index.js.map +1 -1
  69. package/dist/{wstack-paths-BCgmTNlG.d.ts → wstack-paths-eMXnY1_X.d.ts} +8 -0
  70. package/package.json +1 -1
  71. package/dist/compactor-DVTKL7XD.d.ts +0 -23
  72. package/dist/goal-store-C7jcumEh.d.ts +0 -96
  73. package/dist/models-registry-OG_30xqZ.d.ts +0 -46
@@ -66,8 +66,10 @@ var ERROR_CODES = {
66
66
  // Container / Registry
67
67
  CONTAINER_TOKEN_ALREADY_BOUND: "CONTAINER_TOKEN_ALREADY_BOUND",
68
68
  CONTAINER_TOKEN_NOT_BOUND: "CONTAINER_TOKEN_NOT_BOUND",
69
+ CONTAINER_CIRCULAR_DEPENDENCY: "CONTAINER_CIRCULAR_DEPENDENCY",
69
70
  REGISTRY_DUPLICATE: "REGISTRY_DUPLICATE",
70
71
  REGISTRY_NOT_FOUND: "REGISTRY_NOT_FOUND",
72
+ REGISTRY_INVALID: "REGISTRY_INVALID",
71
73
  // File system
72
74
  FS_READ_FAILED: "FS_READ_FAILED",
73
75
  FS_WRITE_FAILED: "FS_WRITE_FAILED",
@@ -315,6 +317,14 @@ var DEFAULT_CONTEXT_CONFIG = Object.freeze({
315
317
  var DEFAULT_AUTONOMY_CONFIG = Object.freeze({
316
318
  autoProceedDelayMs: 45e3
317
319
  });
320
+ var DEFAULT_SESSION_LOGGING_CONFIG = Object.freeze({
321
+ auditLevel: "standard",
322
+ sampling: {
323
+ toolProgress: {
324
+ sampleRate: 8
325
+ }
326
+ }
327
+ });
318
328
 
319
329
  // src/types/secret-vault.ts
320
330
  var ENCRYPTED_PREFIX = "enc:v1:";
@@ -867,6 +877,54 @@ function estimateToolResultTokens(content) {
867
877
  function estimateTextTokens(text) {
868
878
  return RoughTokenEstimate(text);
869
879
  }
880
+ function estimateToolDefTokens(tool) {
881
+ return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
882
+ }
883
+ function estimateRequestTokens(messages, systemPrompt, tools) {
884
+ let messagesTokens = 0;
885
+ if (typeof messages === "string") {
886
+ messagesTokens = RoughTokenEstimate(messages);
887
+ } else if (Array.isArray(messages)) {
888
+ for (const m of messages) {
889
+ if (typeof m === "object" && m !== null && "content" in m) {
890
+ const content = m.content;
891
+ if (typeof content === "string") {
892
+ messagesTokens += RoughTokenEstimate(content);
893
+ } else if (Array.isArray(content)) {
894
+ for (const b of content) {
895
+ if (typeof b === "object" && b !== null) {
896
+ if (b.type === "text") {
897
+ messagesTokens += RoughTokenEstimate(b.text);
898
+ } else {
899
+ messagesTokens += RoughTokenEstimate(JSON.stringify(b));
900
+ }
901
+ }
902
+ }
903
+ }
904
+ }
905
+ }
906
+ }
907
+ let systemTokens = 0;
908
+ if (typeof systemPrompt === "string") {
909
+ systemTokens = RoughTokenEstimate(systemPrompt);
910
+ } else if (Array.isArray(systemPrompt)) {
911
+ for (const b of systemPrompt) {
912
+ if (typeof b === "object" && b !== null && b.type === "text") {
913
+ systemTokens += RoughTokenEstimate(b.text);
914
+ }
915
+ }
916
+ }
917
+ let toolsTokens = 0;
918
+ for (const t of tools) {
919
+ toolsTokens += estimateToolDefTokens(t);
920
+ }
921
+ return {
922
+ messages: messagesTokens,
923
+ systemPrompt: systemTokens,
924
+ tools: toolsTokens,
925
+ total: messagesTokens + systemTokens + toolsTokens
926
+ };
927
+ }
870
928
 
871
929
  // src/utils/message-invariants.ts
872
930
  function repairToolUseAdjacency(messages) {
@@ -972,6 +1030,7 @@ var HybridCompactor = class {
972
1030
  }
973
1031
  async compact(ctx, opts = {}) {
974
1032
  const beforeTokens = this.estimateMessages(ctx.messages);
1033
+ const beforeFull = this.estimateFullRequest(ctx);
975
1034
  const reductions = [];
976
1035
  const policy = readContextWindowPolicy(ctx);
977
1036
  const preserveK = policy?.preserveK ?? this.preserveK;
@@ -987,9 +1046,12 @@ var HybridCompactor = class {
987
1046
  ctx.state.replaceMessages(repaired.messages);
988
1047
  }
989
1048
  const afterTokens = this.estimateMessages(ctx.messages);
1049
+ const afterFull = this.estimateFullRequest(ctx);
990
1050
  return {
991
1051
  before: beforeTokens,
992
1052
  after: afterTokens,
1053
+ fullRequestTokensBefore: beforeFull,
1054
+ fullRequestTokensAfter: afterFull,
993
1055
  reductions,
994
1056
  repaired: repaired.report.changed ? {
995
1057
  removedToolUses: repaired.report.removedToolUses,
@@ -998,6 +1060,14 @@ var HybridCompactor = class {
998
1060
  } : void 0
999
1061
  };
1000
1062
  }
1063
+ /**
1064
+ * Estimate the full API request token count: messages + systemPrompt + toolDefs.
1065
+ * This is the accurate figure for context-window pressure monitoring.
1066
+ */
1067
+ estimateFullRequest(ctx) {
1068
+ const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);
1069
+ return breakdown.total;
1070
+ }
1001
1071
  eliseOldToolResults(ctx, preserveK = this.preserveK, eliseThreshold = this.eliseThreshold) {
1002
1072
  const messages = ctx.messages;
1003
1073
  let pairCount = 0;
@@ -1421,6 +1491,71 @@ var DefaultSecretScrubber = class {
1421
1491
  return visit(obj);
1422
1492
  }
1423
1493
  };
1494
+
1495
+ // src/utils/merge-models-payload.ts
1496
+ function mergeModelsPayload(base, overlay) {
1497
+ const out = {};
1498
+ for (const [id, provider] of Object.entries(base)) {
1499
+ out[id] = cloneProvider(provider);
1500
+ }
1501
+ for (const [id, ovProvider] of Object.entries(overlay)) {
1502
+ const existing = out[id];
1503
+ out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
1504
+ }
1505
+ return out;
1506
+ }
1507
+ function mergeProvider(base, overlay) {
1508
+ const models = {};
1509
+ for (const [mid, m] of Object.entries(base.models ?? {})) {
1510
+ models[mid] = { ...m };
1511
+ }
1512
+ for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
1513
+ const existing = models[mid];
1514
+ models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
1515
+ }
1516
+ return {
1517
+ ...base,
1518
+ // Overlay scalar fields win when explicitly provided; otherwise keep base.
1519
+ ...stripUndefined({
1520
+ id: overlay.id,
1521
+ name: overlay.name,
1522
+ npm: overlay.npm,
1523
+ api: overlay.api,
1524
+ env: overlay.env,
1525
+ doc: overlay.doc
1526
+ }),
1527
+ models
1528
+ };
1529
+ }
1530
+ function mergeModel(base, overlay) {
1531
+ const merged = { ...base, ...overlay };
1532
+ if (base.limit || overlay.limit) {
1533
+ merged.limit = { ...base.limit, ...overlay.limit };
1534
+ }
1535
+ if (base.cost || overlay.cost) {
1536
+ merged.cost = { ...base.cost, ...overlay.cost };
1537
+ }
1538
+ if (base.modalities || overlay.modalities) {
1539
+ merged.modalities = { ...base.modalities, ...overlay.modalities };
1540
+ }
1541
+ return merged;
1542
+ }
1543
+ function cloneProvider(p) {
1544
+ const models = {};
1545
+ for (const [mid, m] of Object.entries(p.models ?? {})) {
1546
+ models[mid] = { ...m };
1547
+ }
1548
+ return { ...p, models };
1549
+ }
1550
+ function stripUndefined(obj) {
1551
+ const out = {};
1552
+ for (const [k, v] of Object.entries(obj)) {
1553
+ if (v !== void 0) out[k] = v;
1554
+ }
1555
+ return out;
1556
+ }
1557
+
1558
+ // src/models/models-registry.ts
1424
1559
  var DEFAULT_URL = "https://models.dev/api.json";
1425
1560
  var DEFAULT_TTL_SECONDS = 24 * 3600;
1426
1561
  var FAMILY_BY_NPM = {
@@ -1448,7 +1583,10 @@ function classifyFamily(npm) {
1448
1583
  return FAMILY_BY_NPM[npm] ?? "unsupported";
1449
1584
  }
1450
1585
  var DefaultModelsRegistry = class {
1586
+ /** Merged (base + overlay) payload — what every reader sees. */
1451
1587
  payload;
1588
+ /** Memoised overlay payload (in-memory / fetched / file). */
1589
+ overlayPayload;
1452
1590
  fetchedAt;
1453
1591
  cacheFile;
1454
1592
  url;
@@ -1456,6 +1594,10 @@ var DefaultModelsRegistry = class {
1456
1594
  fetchImpl;
1457
1595
  seed;
1458
1596
  maxStaleAgeMs;
1597
+ overlay;
1598
+ overlayUrl;
1599
+ overlayFile;
1600
+ overlayCacheFile;
1459
1601
  constructor(opts) {
1460
1602
  this.cacheFile = opts.cacheFile;
1461
1603
  this.url = opts.url ?? DEFAULT_URL;
@@ -1464,6 +1606,10 @@ var DefaultModelsRegistry = class {
1464
1606
  this.seed = opts.seed;
1465
1607
  const maxStaleSeconds = opts.maxStaleAgeSeconds ?? 7 * 24 * 3600;
1466
1608
  this.maxStaleAgeMs = maxStaleSeconds * 1e3;
1609
+ this.overlay = opts.overlay;
1610
+ this.overlayUrl = opts.overlayUrl;
1611
+ this.overlayFile = opts.overlayFile;
1612
+ this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path4.join(path4.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
1467
1613
  }
1468
1614
  async load(opts = {}) {
1469
1615
  if (this.payload && !opts.force) return this.payload;
@@ -1472,27 +1618,45 @@ var DefaultModelsRegistry = class {
1472
1618
  this.fetchedAt = /* @__PURE__ */ new Date();
1473
1619
  return this.payload;
1474
1620
  }
1621
+ const overlay = await this.loadOverlay(opts);
1622
+ const base = await this.loadBase(opts, Object.keys(overlay).length > 0);
1623
+ this.payload = mergeModelsPayload(base, overlay);
1624
+ return this.payload;
1625
+ }
1626
+ /**
1627
+ * Load the models.dev base payload: fresh cache → network → stale cache.
1628
+ * On total failure, degrade to `{}` (so a non-empty overlay still drives
1629
+ * the catalog) rather than throwing — unless there's no curated overlay to
1630
+ * fall back on, in which case the original error propagates so pure-
1631
+ * models.dev setups still surface the problem.
1632
+ */
1633
+ async loadBase(opts = {}, overlayAvailable = false) {
1475
1634
  if (!opts.force) {
1476
- const cached = await this.readCache();
1635
+ const cached = await this.readCacheAt(this.cacheFile);
1477
1636
  if (cached && this.isFresh(cached.fetchedAt)) {
1478
- this.payload = cached.payload;
1479
1637
  this.fetchedAt = new Date(cached.fetchedAt);
1480
1638
  return cached.payload;
1481
1639
  }
1482
1640
  }
1483
1641
  try {
1484
- return await this.refresh();
1642
+ return await this.refreshBase();
1485
1643
  } catch (err) {
1486
- const cached = await this.readCache();
1644
+ const cached = await this.readCacheAt(this.cacheFile);
1487
1645
  if (cached && this.isWithinMaxStaleAge(cached.fetchedAt)) {
1488
- this.payload = cached.payload;
1489
1646
  this.fetchedAt = new Date(cached.fetchedAt);
1490
1647
  return cached.payload;
1491
1648
  }
1649
+ if (overlayAvailable) {
1650
+ console.warn(
1651
+ `ModelsRegistry: models.dev unavailable (${err instanceof Error ? err.message : String(err)}); serving curated overlay only.`
1652
+ );
1653
+ return {};
1654
+ }
1492
1655
  throw err;
1493
1656
  }
1494
1657
  }
1495
- async refresh() {
1658
+ /** Fetch + cache the models.dev base. Throws on failure (used by `refresh`). */
1659
+ async refreshBase() {
1496
1660
  const res = await this.fetchImpl(this.url, {
1497
1661
  method: "GET",
1498
1662
  headers: { accept: "application/json" }
@@ -1501,7 +1665,6 @@ var DefaultModelsRegistry = class {
1501
1665
  throw new Error(`ModelsRegistry: HTTP ${res.status} fetching ${this.url}`);
1502
1666
  }
1503
1667
  const json = await res.json();
1504
- this.payload = json;
1505
1668
  this.fetchedAt = /* @__PURE__ */ new Date();
1506
1669
  const envelope = {
1507
1670
  fetchedAt: this.fetchedAt.toISOString(),
@@ -1511,6 +1674,68 @@ var DefaultModelsRegistry = class {
1511
1674
  await atomicWrite(this.cacheFile, JSON.stringify(envelope));
1512
1675
  return json;
1513
1676
  }
1677
+ /**
1678
+ * Resolve the curated overlay, memoised. Order: in-memory `overlay` →
1679
+ * fetched `overlayUrl` (cached, same TTL/stale rules) → `overlayFile` on
1680
+ * disk. Never throws — a missing/broken overlay yields `{}`.
1681
+ */
1682
+ async loadOverlay(opts = {}) {
1683
+ if (this.overlayPayload && !opts.force) return this.overlayPayload;
1684
+ if (this.overlay) {
1685
+ this.overlayPayload = this.overlay;
1686
+ return this.overlayPayload;
1687
+ }
1688
+ const fetched = await this.loadOverlayFromUrl(opts);
1689
+ if (fetched) {
1690
+ this.overlayPayload = fetched;
1691
+ return fetched;
1692
+ }
1693
+ const fromFile = await this.readOverlayFile();
1694
+ this.overlayPayload = fromFile ?? {};
1695
+ return this.overlayPayload;
1696
+ }
1697
+ async loadOverlayFromUrl(opts) {
1698
+ if (!this.overlayUrl || !this.overlayCacheFile) return void 0;
1699
+ if (!opts.force) {
1700
+ const cached = await this.readCacheAt(this.overlayCacheFile);
1701
+ if (cached && this.isFresh(cached.fetchedAt)) return cached.payload;
1702
+ }
1703
+ try {
1704
+ const res = await this.fetchImpl(this.overlayUrl, {
1705
+ method: "GET",
1706
+ headers: { accept: "application/json" }
1707
+ });
1708
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
1709
+ const json = await res.json();
1710
+ const envelope = {
1711
+ fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
1712
+ url: this.overlayUrl,
1713
+ payload: json
1714
+ };
1715
+ await atomicWrite(this.overlayCacheFile, JSON.stringify(envelope)).catch(() => {
1716
+ });
1717
+ return json;
1718
+ } catch {
1719
+ const cached = await this.readCacheAt(this.overlayCacheFile);
1720
+ if (cached && this.isWithinMaxStaleAge(cached.fetchedAt)) return cached.payload;
1721
+ return void 0;
1722
+ }
1723
+ }
1724
+ async readOverlayFile() {
1725
+ if (!this.overlayFile) return void 0;
1726
+ try {
1727
+ const raw = await fs.readFile(this.overlayFile, "utf8");
1728
+ return JSON.parse(raw);
1729
+ } catch {
1730
+ return void 0;
1731
+ }
1732
+ }
1733
+ async refresh() {
1734
+ const base = await this.refreshBase();
1735
+ const overlay = await this.loadOverlay({ force: true });
1736
+ this.payload = mergeModelsPayload(base, overlay);
1737
+ return this.payload;
1738
+ }
1514
1739
  async listProviders() {
1515
1740
  const payload = await this.load();
1516
1741
  return Object.values(payload).map((p) => this.resolveProvider(p));
@@ -1551,7 +1776,7 @@ var DefaultModelsRegistry = class {
1551
1776
  }
1552
1777
  async ageSeconds() {
1553
1778
  if (!this.fetchedAt) {
1554
- const cached = await this.readCache();
1779
+ const cached = await this.readCacheAt(this.cacheFile);
1555
1780
  if (!cached) return Number.POSITIVE_INFINITY;
1556
1781
  return (Date.now() - new Date(cached.fetchedAt).getTime()) / 1e3;
1557
1782
  }
@@ -1575,9 +1800,9 @@ var DefaultModelsRegistry = class {
1575
1800
  isWithinMaxStaleAge(fetchedAtIso) {
1576
1801
  return Date.now() - new Date(fetchedAtIso).getTime() < this.maxStaleAgeMs;
1577
1802
  }
1578
- async readCache() {
1803
+ async readCacheAt(file) {
1579
1804
  try {
1580
- const raw = await fs.readFile(this.cacheFile, "utf8");
1805
+ const raw = await fs.readFile(file, "utf8");
1581
1806
  return JSON.parse(raw);
1582
1807
  } catch {
1583
1808
  return void 0;
@@ -2149,6 +2374,141 @@ function topologicalSort(graph) {
2149
2374
  return result;
2150
2375
  }
2151
2376
 
2377
+ // src/security/capabilities.ts
2378
+ var ToolCapabilities = {
2379
+ /** Can execute arbitrary commands in the user's shell (the `bash` tool). */
2380
+ SHELL_ARBITRARY: "shell.arbitrary",
2381
+ /** Can write / modify / delete files inside the project. */
2382
+ FS_WRITE: "fs.write",
2383
+ /** Can write files outside the current project root (very high risk). */
2384
+ FS_WRITE_OUTSIDE_PROJECT: "fs.write.outside-project",
2385
+ /** Proxies tools from external MCP servers (unknown capability). */
2386
+ MCP_PROXY: "mcp.proxy",
2387
+ /** Can spawn or manage subagents / multi-agent tasks. */
2388
+ SUBAGENT_SPAWN: "subagent.spawn",
2389
+ /** Can mutate global or session configuration / trust state. */
2390
+ CONFIG_MUTATE: "config.mutate",
2391
+ /** Can install packages or run package managers with side effects. */
2392
+ PACKAGE_INSTALL: "package.install"
2393
+ };
2394
+ var DANGEROUS_FOR_SUBAGENTS = [
2395
+ ToolCapabilities.SHELL_ARBITRARY,
2396
+ ToolCapabilities.FS_WRITE,
2397
+ ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
2398
+ ToolCapabilities.MCP_PROXY,
2399
+ ToolCapabilities.SUBAGENT_SPAWN,
2400
+ ToolCapabilities.CONFIG_MUTATE,
2401
+ ToolCapabilities.PACKAGE_INSTALL
2402
+ ];
2403
+ function hasDangerousCapabilityForSubagents(toolOrCaps) {
2404
+ if (!toolOrCaps) return false;
2405
+ const input = toolOrCaps;
2406
+ const caps = Array.isArray(input) ? input : input?.capabilities ?? [];
2407
+ return caps.some((c) => DANGEROUS_FOR_SUBAGENTS.includes(c));
2408
+ }
2409
+ function getDangerousCapabilities(toolOrCaps) {
2410
+ if (!toolOrCaps) return [];
2411
+ const input = toolOrCaps;
2412
+ const caps = Array.isArray(input) ? input : input?.capabilities ?? [];
2413
+ return caps.filter(
2414
+ (c) => DANGEROUS_FOR_SUBAGENTS.includes(c)
2415
+ );
2416
+ }
2417
+
2418
+ // src/utils/json-schema-validate.ts
2419
+ function validateAgainstSchema(value, schema) {
2420
+ const errors = [];
2421
+ walk2(value, schema, "", errors);
2422
+ return { ok: errors.length === 0, errors };
2423
+ }
2424
+ function walk2(value, schema, path6, errors) {
2425
+ if (schema.enum !== void 0) {
2426
+ if (!schema.enum.some((e) => deepEqual(e, value))) {
2427
+ errors.push({
2428
+ path: path6 || "<root>",
2429
+ message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
2430
+ });
2431
+ return;
2432
+ }
2433
+ }
2434
+ if (typeof schema.type === "string") {
2435
+ if (!checkType(value, schema.type)) {
2436
+ errors.push({
2437
+ path: path6 || "<root>",
2438
+ message: `expected ${schema.type}, got ${describeType(value)}`
2439
+ });
2440
+ return;
2441
+ }
2442
+ }
2443
+ if (schema.type === "object" && isPlainObject(value)) {
2444
+ const obj = value;
2445
+ for (const req of schema.required ?? []) {
2446
+ if (!(req in obj)) {
2447
+ errors.push({ path: joinPath(path6, req), message: "required property missing" });
2448
+ }
2449
+ }
2450
+ if (schema.properties) {
2451
+ for (const [key, subSchema] of Object.entries(schema.properties)) {
2452
+ if (key in obj) {
2453
+ walk2(obj[key], subSchema, joinPath(path6, key), errors);
2454
+ }
2455
+ }
2456
+ }
2457
+ }
2458
+ if (schema.type === "array" && Array.isArray(value) && schema.items) {
2459
+ value.forEach((item, i) => walk2(item, schema.items, `${path6}[${i}]`, errors));
2460
+ }
2461
+ }
2462
+ function checkType(value, type) {
2463
+ switch (type) {
2464
+ case "string":
2465
+ return typeof value === "string";
2466
+ case "number":
2467
+ return typeof value === "number" && !Number.isNaN(value);
2468
+ case "integer":
2469
+ return typeof value === "number" && Number.isInteger(value);
2470
+ case "boolean":
2471
+ return typeof value === "boolean";
2472
+ case "null":
2473
+ return value === null;
2474
+ case "array":
2475
+ return Array.isArray(value);
2476
+ case "object":
2477
+ return isPlainObject(value);
2478
+ default:
2479
+ return true;
2480
+ }
2481
+ }
2482
+ function isPlainObject(v) {
2483
+ return typeof v === "object" && v !== null && !Array.isArray(v);
2484
+ }
2485
+ function describeType(v) {
2486
+ if (v === null) return "null";
2487
+ if (Array.isArray(v)) return "array";
2488
+ return typeof v;
2489
+ }
2490
+ function joinPath(parent, key) {
2491
+ if (!parent) return key;
2492
+ return `${parent}.${key}`;
2493
+ }
2494
+ function deepEqual(a, b) {
2495
+ if (a === b) return true;
2496
+ if (typeof a !== typeof b) return false;
2497
+ if (a === null || b === null) return a === b;
2498
+ if (Array.isArray(a) && Array.isArray(b)) {
2499
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
2500
+ }
2501
+ if (typeof a === "object" && typeof b === "object") {
2502
+ const ak = Object.keys(a);
2503
+ const bk = Object.keys(b);
2504
+ if (ak.length !== bk.length) return false;
2505
+ return ak.every(
2506
+ (k) => deepEqual(a[k], b[k])
2507
+ );
2508
+ }
2509
+ return false;
2510
+ }
2511
+
2152
2512
  // src/utils/tool-output-serializer.ts
2153
2513
  function createToolOutputSerializer(opts = {}) {
2154
2514
  const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
@@ -2230,18 +2590,45 @@ var ToolExecutor = class {
2230
2590
  budget = this.decrementBudget(result, budget);
2231
2591
  return { result, tool, durationMs: Date.now() - start };
2232
2592
  }
2593
+ const validation = validateAgainstSchema(use.input, tool.inputSchema);
2594
+ if (!validation.ok) {
2595
+ const errorDetails = validation.errors.map((e) => ` - ${e.path || "input"}: ${e.message}`).join("\n");
2596
+ const result = {
2597
+ type: "tool_result",
2598
+ tool_use_id: use.id,
2599
+ content: `Invalid arguments for tool "${tool.name}".
2600
+
2601
+ Validation errors:
2602
+ ${errorDetails}
2603
+
2604
+ Please call the tool again with arguments that match its inputSchema. You can use the "tool-help" tool with name="${tool.name}" to see the exact expected schema.`,
2605
+ is_error: true
2606
+ };
2607
+ budget = this.decrementBudget(result, budget);
2608
+ return { result, tool, durationMs: Date.now() - start };
2609
+ }
2610
+ const toolDangerousCaps = getDangerousCapabilities(tool);
2611
+ if (toolDangerousCaps.length > 0) {
2612
+ if (this.opts.events) ;
2613
+ }
2233
2614
  if (hasMalformedArguments(use.input)) {
2234
2615
  const result = this.malformedInputResult(use, extractMalformedRaw(use.input));
2235
2616
  budget = this.decrementBudget(result, budget);
2236
2617
  return { result, tool, durationMs: Date.now() - start };
2237
2618
  }
2238
2619
  const decision = await this.opts.permissionPolicy.evaluate(tool, use.input, ctx);
2239
- if (decision.permission === "deny") {
2620
+ let effectivePermission = decision.permission;
2621
+ const policy = this.opts.permissionPolicy;
2622
+ const yolo = policy.getYolo?.() === true || policy.getForceAllYolo?.() === true;
2623
+ if (toolDangerousCaps.length > 0 && effectivePermission === "auto" && !yolo) {
2624
+ effectivePermission = "confirm";
2625
+ }
2626
+ if (effectivePermission === "deny") {
2240
2627
  const result = this.deniedResult(use, decision.reason);
2241
2628
  budget = this.decrementBudget(result, budget);
2242
2629
  return { result, tool, durationMs: Date.now() - start };
2243
2630
  }
2244
- if (decision.permission === "confirm") {
2631
+ if (effectivePermission === "confirm") {
2245
2632
  if (this.opts.confirmAwaiter) {
2246
2633
  const choice = await this.opts.confirmAwaiter(tool, use.input, use.id, tool.name);
2247
2634
  if (choice !== "yes" && choice !== "always") {
@@ -2266,10 +2653,13 @@ var ToolExecutor = class {
2266
2653
  return { result: pending, tool, durationMs: Date.now() - start };
2267
2654
  }
2268
2655
  }
2656
+ const toolCapsForAudit = hasDangerousCapabilityForSubagents(tool) ? tool.capabilities ?? [] : [];
2269
2657
  const span = this.opts.tracer?.startSpan(`tool.${tool.name}`, {
2270
2658
  "tool.name": tool.name,
2271
2659
  "tool.mutating": tool.mutating,
2272
- "tool.permission": tool.permission
2660
+ "tool.permission": tool.permission,
2661
+ "tool.capabilities": JSON.stringify(tool.capabilities ?? []),
2662
+ "tool.has_dangerous_capabilities": toolCapsForAudit.length > 0
2273
2663
  });
2274
2664
  try {
2275
2665
  const result = await this.executeTool(tool, use, ctx, budget);
@@ -2814,6 +3204,6 @@ function renderPlainText(meta, events) {
2814
3204
  return lines.join("\n");
2815
3205
  }
2816
3206
 
2817
- export { AgentError, CONTEXT_WINDOW_MODES, ConfigError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_TOOLS_CONFIG, DefaultErrorHandler, DefaultLogger, DefaultModelsRegistry, DefaultPathResolver, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultTokenCounter, ERROR_CODES, FsError, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, PluginError, ProviderError, SessionError, ToolError, ToolExecutor, WrongStackError, asBlocks, asText, buildRecoveryStrategies, classifyFamily, computeTaskProgress, createMessage, decryptConfigSecrets, encryptConfigSecrets, findCriticalPath, formatContextWindowModeList, getContextWindowMode, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, migratePlaintextSecrets, resolveContextWindowPolicy, rewriteConfigEncrypted, toWrongStackError, topologicalSort };
3207
+ export { AgentError, CONTEXT_WINDOW_MODES, ConfigError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SESSION_LOGGING_CONFIG, DEFAULT_SPEC_TEMPLATE, DEFAULT_TOOLS_CONFIG, DefaultErrorHandler, DefaultLogger, DefaultModelsRegistry, DefaultPathResolver, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultTokenCounter, ERROR_CODES, FsError, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, PluginError, ProviderError, SessionError, ToolError, ToolExecutor, WrongStackError, asBlocks, asText, buildRecoveryStrategies, classifyFamily, computeTaskProgress, createMessage, decryptConfigSecrets, encryptConfigSecrets, findCriticalPath, formatContextWindowModeList, getContextWindowMode, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, migratePlaintextSecrets, resolveContextWindowPolicy, rewriteConfigEncrypted, toWrongStackError, topologicalSort };
2818
3208
  //# sourceMappingURL=index.js.map
2819
3209
  //# sourceMappingURL=index.js.map