@wrongstack/core 0.5.3 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/{agent-bridge-EiUFe3if.d.ts → agent-bridge-B07AYFBk.d.ts} +1 -1
  2. package/dist/{compactor-BP4xhKVi.d.ts → compactor-BWhJXxsW.d.ts} +1 -1
  3. package/dist/{config-BOD_HQBw.d.ts → config-BgM0BIpz.d.ts} +1 -1
  4. package/dist/{context-PH4DvBZV.d.ts → context-CLZXPPYk.d.ts} +18 -1
  5. package/dist/coordination/index.d.ts +10 -9
  6. package/dist/coordination/index.js +269 -15
  7. package/dist/coordination/index.js.map +1 -1
  8. package/dist/defaults/index.d.ts +20 -19
  9. package/dist/defaults/index.js +459 -17
  10. package/dist/defaults/index.js.map +1 -1
  11. package/dist/director-state-BmYi3DGA.d.ts +108 -0
  12. package/dist/{events-oxn-Wkub.d.ts → events-qnDZbrtb.d.ts} +67 -2
  13. package/dist/execution/index.d.ts +12 -12
  14. package/dist/extension/index.d.ts +6 -6
  15. package/dist/{index-CcbWbcpy.d.ts → index-BDnUCRvL.d.ts} +113 -6
  16. package/dist/{index-a12jc7-r.d.ts → index-DPLJw_ZI.d.ts} +5 -5
  17. package/dist/index.d.ts +329 -27
  18. package/dist/index.js +2405 -27
  19. package/dist/index.js.map +1 -1
  20. package/dist/infrastructure/index.d.ts +6 -6
  21. package/dist/kernel/index.d.ts +9 -9
  22. package/dist/kernel/index.js +98 -1
  23. package/dist/kernel/index.js.map +1 -1
  24. package/dist/{mcp-servers-uPmBxZ1B.d.ts → mcp-servers-CSMfaBuL.d.ts} +3 -3
  25. package/dist/models/index.d.ts +2 -2
  26. package/dist/{multi-agent-D6S4Z7H8.d.ts → multi-agent-Cv8wk47i.d.ts} +2 -2
  27. package/dist/observability/index.d.ts +2 -2
  28. package/dist/{path-resolver-CprD5DhS.d.ts → path-resolver-DiCUvEg6.d.ts} +2 -2
  29. package/dist/{director-state-CVzkjKRZ.d.ts → plan-templates-DaxTCPfk.d.ts} +38 -77
  30. package/dist/{provider-runner-DGisz_lG.d.ts → provider-runner-3SHqk9zB.d.ts} +3 -3
  31. package/dist/{retry-policy-DUJ8-Qc_.d.ts → retry-policy-LLUxJmYY.d.ts} +1 -1
  32. package/dist/sdd/index.d.ts +3 -3
  33. package/dist/{secret-scrubber-CB11A2P7.d.ts → secret-scrubber-BhJTNr9v.d.ts} +4 -2
  34. package/dist/{secret-scrubber-EqFa0SyI.d.ts → secret-scrubber-Z_VXuXQT.d.ts} +1 -1
  35. package/dist/security/index.d.ts +13 -3
  36. package/dist/security/index.js +34 -1
  37. package/dist/security/index.js.map +1 -1
  38. package/dist/{selector-yqyxt-Ii.d.ts → selector-DB2-byKH.d.ts} +1 -1
  39. package/dist/{session-reader-1tOyoY1s.d.ts → session-reader-4jxsYLZ8.d.ts} +1 -1
  40. package/dist/storage/index.d.ts +7 -6
  41. package/dist/storage/index.js +222 -3
  42. package/dist/storage/index.js.map +1 -1
  43. package/dist/{system-prompt-BJlzKGO6.d.ts → system-prompt-DI4Dtc1I.d.ts} +1 -1
  44. package/dist/{tool-executor-B6kRcWeF.d.ts → tool-executor-DSvmOBe6.d.ts} +4 -4
  45. package/dist/types/index.d.ts +15 -15
  46. package/dist/types/index.js +9 -1
  47. package/dist/types/index.js.map +1 -1
  48. package/dist/utils/index.d.ts +2 -2
  49. package/dist/{wstack-paths-BGu2INTm.d.ts → wstack-paths-86YPFktR.d.ts} +1 -1
  50. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { B as BridgeTransport, l as BridgeMessage, A as AgentBridge, m as AgentBridgeConfig } from './multi-agent-D6S4Z7H8.js';
1
+ import { B as BridgeTransport, l as BridgeMessage, A as AgentBridge, m as AgentBridgeConfig } from './multi-agent-Cv8wk47i.js';
2
2
 
3
3
  /**
4
4
  * In-memory pub/sub transport for agent-to-agent messaging.
@@ -1,4 +1,4 @@
1
- import { a1 as Context } from './context-PH4DvBZV.js';
1
+ import { a2 as Context } from './context-CLZXPPYk.js';
2
2
 
3
3
  interface CompactRepairReport {
4
4
  removedToolUses: string[];
@@ -1,5 +1,5 @@
1
1
  import { W as WireFamily } from './models-registry-Y2xbog0E.js';
2
- import { P as Permission } from './context-PH4DvBZV.js';
2
+ import { P as Permission } from './context-CLZXPPYk.js';
3
3
 
4
4
  type ContextWindowModeId = 'balanced' | 'frugal' | 'deep' | 'archival';
5
5
  type ContextWindowAggressiveOn = 'hard' | 'soft' | 'warn';
@@ -194,6 +194,16 @@ declare function isSessionError(err: unknown): err is SessionError;
194
194
  declare function isAgentError(err: unknown): err is AgentError;
195
195
 
196
196
  type Permission = 'auto' | 'confirm' | 'deny';
197
+ /**
198
+ * Risk tier for tools in YOLO mode. Even in YOLO, tools classified as
199
+ * `destructive` still prompt for confirmation unless `--force-all-yolo`
200
+ * is set.
201
+ *
202
+ * - `safe` — read-only, no side effects (read, glob, grep, etc.)
203
+ * - `standard` — non-destructive writes and mutations (write, edit, bash with safe commands)
204
+ * - `destructive` — irreversible or broadside effects (recursive deletes, db drops, etc.)
205
+ */
206
+ type RiskTier = 'safe' | 'standard' | 'destructive';
197
207
  interface JSONSchema {
198
208
  type?: string;
199
209
  properties?: Record<string, JSONSchema>;
@@ -243,6 +253,13 @@ interface Tool<I = unknown, O = unknown> {
243
253
  inputSchema: JSONSchema;
244
254
  permission: Permission;
245
255
  mutating: boolean;
256
+ /**
257
+ * Risk tier for selective YOLO gating. When YOLO is active, `destructive`
258
+ * tools still emit `confirm` unless `forceAllYolo` is set. Defaults to
259
+ * `standard` when omitted — callers should always check `riskTier` after
260
+ * the basic permission decision.
261
+ */
262
+ riskTier?: RiskTier;
246
263
  /**
247
264
  * Input-field name that the permission policy should match trust rules
248
265
  * against. Without this, the policy falls back to a heuristic
@@ -937,4 +954,4 @@ declare class Context implements RunEnv {
937
954
  usage(): Usage;
938
955
  }
939
956
 
940
- export { isWrongStackError as $, AgentError as A, type ToolStreamEvent as B, type Capabilities as C, type ToolUseBlock as D, type ErrorCode as E, type FileSnapshot as F, asBlocks as G, asText as H, type ImageBlock as I, type JSONSchema as J, isAgentError as K, isConfigError as L, type Message as M, isImageBlock as N, isPluginError as O, type Permission as P, isSessionError as Q, type Request as R, type SessionData as S, type TextBlock as T, type Usage as U, isTextBlock as V, WrongStackError as W, isThinkingBlock as X, isToolError as Y, isToolResultBlock as Z, isToolUseBlock as _, ConfigError as a, toWrongStackError as a0, Context as a1, type TokenCounter as a2, type CacheStats as a3, type ContextInit as a4, ConversationState as a5, type ReadonlyConversationState as a6, type RunEnv as a7, type RunOptions as a8, type StateChange as a9, type StateChangeHandler as aa, type TodoItem as ab, extractRunEnv as ac, wrapAsState as ad, type ContentBlock as b, type ErrorSeverity as c, type ErrorSubsystem as d, type MessageRole as e, PluginError as f, type Provider as g, ProviderError as h, type ProviderErrorBody as i, type Response as j, type ResumedSession as k, SessionError as l, type SessionEvent as m, type SessionMetadata as n, type SessionStore as o, type SessionSummary as p, type SessionWriter as q, type StopReason as r, type StreamEvent as s, type ThinkingBlock as t, type Tool as u, type ToolCallContext as v, ToolError as w, type ToolFinalEvent as x, type ToolProgressEvent as y, type ToolResultBlock as z };
957
+ export { isToolUseBlock as $, AgentError as A, type ToolResultBlock as B, type Capabilities as C, type ToolStreamEvent as D, type ErrorCode as E, type FileSnapshot as F, type ToolUseBlock as G, asBlocks as H, type ImageBlock as I, type JSONSchema as J, asText as K, isAgentError as L, type Message as M, isConfigError as N, isImageBlock as O, type Permission as P, isPluginError as Q, type Request as R, type SessionData as S, type TextBlock as T, type Usage as U, isSessionError as V, WrongStackError as W, isTextBlock as X, isThinkingBlock as Y, isToolError as Z, isToolResultBlock as _, ConfigError as a, isWrongStackError as a0, toWrongStackError as a1, Context as a2, type TokenCounter as a3, type CacheStats as a4, type TodoItem as a5, ConversationState as a6, type ContextInit as a7, type ReadonlyConversationState as a8, type RunEnv as a9, type RunOptions as aa, type StateChange as ab, type StateChangeHandler as ac, extractRunEnv as ad, wrapAsState as ae, type ContentBlock as b, type ErrorSeverity as c, type ErrorSubsystem as d, type MessageRole as e, PluginError as f, type Provider as g, ProviderError as h, type ProviderErrorBody as i, type Response as j, type ResumedSession as k, type RiskTier as l, SessionError as m, type SessionEvent as n, type SessionMetadata as o, type SessionStore as p, type SessionSummary as q, type SessionWriter as r, type StopReason as s, type StreamEvent as t, type ThinkingBlock as u, type Tool as v, type ToolCallContext as w, ToolError as x, type ToolFinalEvent as y, type ToolProgressEvent as z };
@@ -1,13 +1,14 @@
1
- export { A as ALL_FLEET_AGENTS, a as AUDIT_LOG_AGENT, b as AgentFactory, c as AgentFactoryResult, d as AgentRunnerOptions, B as BUG_HUNTER_AGENT, C as CreateDelegateToolOptions, D as DEFAULT_DIRECTOR_PREAMBLE, e as DEFAULT_SUBAGENT_BASELINE, f as DefaultMultiAgentCoordinator, g as DelegateHost, h as Director, i as DirectorBudgetError, j as DirectorPromptParts, k as DirectorSessionFactory, l as DirectorSessionFactoryOptions, F as FLEET_ROSTER, n as FleetBus, o as FleetEvent, p as FleetHandler, q as FleetUsage, r as FleetUsageAggregator, M as MultiAgentCoordinatorOptions, R as REFACTOR_PLANNER_AGENT, S as SECURITY_SCANNER_AGENT, s as SubagentPromptParts, t as SubagentUsageSnapshot, v as composeDirectorPrompt, w as composeSubagentPrompt, x as createDelegateTool, y as makeAgentSubagentRunner, z as makeDirectorSessionFactory, E as rosterSummaryFromConfigs } from '../index-CcbWbcpy.js';
2
- export { n as BudgetExceededError, o as BudgetKind, p as BudgetLimits, s as BudgetThresholdDecision, t as BudgetThresholdHandler, u as BudgetThresholdSignal, q as BudgetUsage, r as SubagentBudget } from '../multi-agent-D6S4Z7H8.js';
3
- export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-EiUFe3if.js';
4
- import '../context-PH4DvBZV.js';
5
- import '../events-oxn-Wkub.js';
1
+ export { A as ALL_FLEET_AGENTS, a as AUDIT_LOG_AGENT, b as AgentFactory, c as AgentFactoryResult, d as AgentRunnerOptions, B as BUG_HUNTER_AGENT, C as CreateDelegateToolOptions, D as DEFAULT_DIRECTOR_PREAMBLE, e as DEFAULT_SUBAGENT_BASELINE, f as DefaultMultiAgentCoordinator, g as DelegateHost, h as Director, i as DirectorBudgetError, G as DirectorCostCapError, j as DirectorPromptParts, k as DirectorSessionFactory, l as DirectorSessionFactoryOptions, F as FLEET_ROSTER, n as FleetBus, o as FleetEvent, p as FleetHandler, q as FleetUsage, r as FleetUsageAggregator, M as MultiAgentCoordinatorOptions, R as REFACTOR_PLANNER_AGENT, S as SECURITY_SCANNER_AGENT, s as SubagentPromptParts, t as SubagentUsageSnapshot, v as composeDirectorPrompt, w as composeSubagentPrompt, x as createDelegateTool, y as makeAgentSubagentRunner, z as makeDirectorSessionFactory, E as rosterSummaryFromConfigs } from '../index-BDnUCRvL.js';
2
+ export { n as BudgetExceededError, o as BudgetKind, p as BudgetLimits, s as BudgetThresholdDecision, t as BudgetThresholdHandler, u as BudgetThresholdSignal, q as BudgetUsage, r as SubagentBudget } from '../multi-agent-Cv8wk47i.js';
3
+ export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-B07AYFBk.js';
4
+ import '../director-state-BmYi3DGA.js';
5
+ import '../context-CLZXPPYk.js';
6
+ import '../events-qnDZbrtb.js';
6
7
  import 'node:events';
7
- import '../index-a12jc7-r.js';
8
+ import '../index-DPLJw_ZI.js';
8
9
  import '../logger-BMQgxvdy.js';
9
- import '../system-prompt-BJlzKGO6.js';
10
+ import '../system-prompt-DI4Dtc1I.js';
10
11
  import '../observability-BhnVLBLS.js';
11
- import '../secret-scrubber-CB11A2P7.js';
12
- import '../config-BOD_HQBw.js';
12
+ import '../secret-scrubber-BhJTNr9v.js';
13
+ import '../config-BgM0BIpz.js';
13
14
  import '../models-registry-Y2xbog0E.js';
@@ -3,7 +3,12 @@ import * as fsp4 from 'fs/promises';
3
3
  import * as path4 from 'path';
4
4
  import { EventEmitter } from 'events';
5
5
 
6
- // src/coordination/director.ts
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
7
12
  async function atomicWrite(targetPath, content, opts = {}) {
8
13
  const dir = path4.dirname(targetPath);
9
14
  await fsp4.mkdir(dir, { recursive: true });
@@ -70,15 +75,48 @@ async function renameWithRetry(from, to) {
70
75
  }
71
76
 
72
77
  // src/storage/director-state.ts
78
+ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
79
+ let existing;
80
+ try {
81
+ existing = await fsp4.readFile(lockPath, "utf8");
82
+ } catch {
83
+ }
84
+ if (existing) {
85
+ try {
86
+ const lock2 = JSON.parse(existing);
87
+ try {
88
+ process.kill(lock2.pid, 0);
89
+ return false;
90
+ } catch {
91
+ }
92
+ } catch {
93
+ }
94
+ }
95
+ const lock = {
96
+ pid: processId,
97
+ hostname: __require("os").hostname(),
98
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
99
+ };
100
+ await atomicWrite(lockPath, JSON.stringify(lock), { mode: 384 });
101
+ return true;
102
+ }
103
+ async function releaseDirectorStateLock(lockPath) {
104
+ try {
105
+ await fsp4.unlink(lockPath);
106
+ } catch {
107
+ }
108
+ }
73
109
  var DirectorStateCheckpoint = class {
74
110
  snapshot;
75
111
  filePath;
112
+ lockPath;
76
113
  timer = null;
77
114
  debounceMs;
78
115
  writing = false;
79
116
  rewriteRequested = false;
80
117
  constructor(filePath, init, debounceMs = 250) {
81
118
  this.filePath = filePath;
119
+ this.lockPath = `${filePath}.lock`;
82
120
  this.debounceMs = debounceMs;
83
121
  this.snapshot = {
84
122
  version: 1,
@@ -88,10 +126,36 @@ var DirectorStateCheckpoint = class {
88
126
  maxSpawns: init.maxSpawns,
89
127
  spawnDepth: init.spawnDepth,
90
128
  maxSpawnDepth: init.maxSpawnDepth,
129
+ directorBudget: init.directorBudget,
91
130
  subagents: [],
92
131
  tasks: []
93
132
  };
94
133
  }
134
+ /**
135
+ * Attempt to acquire the lock for this checkpoint. Call this before
136
+ * resuming a crashed director run. If it returns false, another
137
+ * director process is still running this fleet — do not resume.
138
+ */
139
+ async acquireLock() {
140
+ return acquireDirectorStateLock(this.lockPath);
141
+ }
142
+ /**
143
+ * Release the lock on graceful shutdown. Call `flush()` first to ensure
144
+ * the final checkpoint state is on disk before removing the lock.
145
+ * Without this, the next resume will see a stale-lock and refuse.
146
+ */
147
+ async releaseLock() {
148
+ return releaseDirectorStateLock(this.lockPath);
149
+ }
150
+ /**
151
+ * Resume from a snapshot previously loaded via `loadDirectorState()`.
152
+ * Use this when `--resume <runId>` is triggered — the snapshot has
153
+ * the full fleet state (subagents, tasks) from before the crash; the
154
+ * checkpoint continues from there.
155
+ */
156
+ resume(snapshot) {
157
+ this.snapshot = snapshot;
158
+ }
95
159
  current() {
96
160
  return this.snapshot;
97
161
  }
@@ -1570,6 +1634,9 @@ function makeSpawnTool(director, roster) {
1570
1634
  if (err instanceof DirectorBudgetError) {
1571
1635
  return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
1572
1636
  }
1637
+ if (err instanceof DirectorCostCapError) {
1638
+ return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
1639
+ }
1573
1640
  return { error: err instanceof Error ? err.message : String(err) };
1574
1641
  }
1575
1642
  }
@@ -1707,6 +1774,65 @@ function makeFleetUsageTool(director) {
1707
1774
  }
1708
1775
  };
1709
1776
  }
1777
+ function makeFleetSessionTool(director) {
1778
+ return {
1779
+ name: "fleet_session",
1780
+ description: "Read a subagent's JSONL transcript and extract its last assistant text, stop reason, and tool-use count. Use this to see what a running or timed-out subagent actually produced.",
1781
+ permission: "auto",
1782
+ mutating: false,
1783
+ inputSchema: {
1784
+ type: "object",
1785
+ properties: {
1786
+ subagentId: { type: "string", description: "Subagent id to read the transcript of." },
1787
+ /** Number of trailing lines to return (last N JSONL lines). Default: all. */
1788
+ tail: { type: "number", description: "Number of trailing JSONL lines to return. Omit for the full transcript." }
1789
+ },
1790
+ required: ["subagentId"]
1791
+ },
1792
+ async execute(input) {
1793
+ const i = input;
1794
+ const result = await director.readSession(i.subagentId, i.tail);
1795
+ if (!result) {
1796
+ return {
1797
+ error: `fleet_session: transcript unavailable for "${i.subagentId}". Is sessionsRoot configured?`
1798
+ };
1799
+ }
1800
+ return result;
1801
+ }
1802
+ };
1803
+ }
1804
+ function makeFleetHealthTool(director) {
1805
+ return {
1806
+ name: "fleet_health",
1807
+ description: "Per-subagent health report: budget pressure (pct of limits consumed), last activity timestamp, and current status. Use to decide whether to assign more work to a subagent or spawn a fresh one.",
1808
+ permission: "auto",
1809
+ mutating: false,
1810
+ inputSchema: { type: "object", properties: {}, required: [] },
1811
+ async execute() {
1812
+ const status = director.status();
1813
+ const snapshot = director.snapshot();
1814
+ const subagents = status.subagents ?? [];
1815
+ const perSubagent = snapshot.perSubagent ?? {};
1816
+ return {
1817
+ subagents: subagents.map((s) => {
1818
+ const usage = perSubagent[s.id];
1819
+ return {
1820
+ id: s.id,
1821
+ status: s.status,
1822
+ lastEventAt: usage?.lastEventAt,
1823
+ // Budget pressure: fraction of each limit consumed if we have it.
1824
+ // BudgetWarning events carry used/limit ratios; surface them here.
1825
+ budgetPressure: {
1826
+ iterations: usage?.iterations,
1827
+ toolCalls: usage?.toolCalls,
1828
+ costUsd: usage?.cost
1829
+ }
1830
+ };
1831
+ })
1832
+ };
1833
+ }
1834
+ };
1835
+ }
1710
1836
 
1711
1837
  // src/coordination/director.ts
1712
1838
  var DirectorBudgetError = class extends Error {
@@ -1723,6 +1849,20 @@ var DirectorBudgetError = class extends Error {
1723
1849
  this.observed = observed;
1724
1850
  }
1725
1851
  };
1852
+ var DirectorCostCapError = class extends Error {
1853
+ kind;
1854
+ limit;
1855
+ observed;
1856
+ constructor(limit, observed) {
1857
+ super(
1858
+ `Director cost cap exceeded: total fleet spend ${observed.toFixed(4)} exceeds maxCostUsd ${limit.toFixed(4)}`
1859
+ );
1860
+ this.name = "DirectorCostCapError";
1861
+ this.kind = "max_cost_usd";
1862
+ this.limit = limit;
1863
+ this.observed = observed;
1864
+ }
1865
+ };
1726
1866
  var Director = class {
1727
1867
  id;
1728
1868
  fleet;
@@ -1777,6 +1917,14 @@ var Director = class {
1777
1917
  /** Debounce timer for periodic manifest writes. */
1778
1918
  manifestTimer = null;
1779
1919
  manifestDebounceMs;
1920
+ /** Fleet-wide cost cap. Infinity means no cap. */
1921
+ maxCostUsd;
1922
+ /** Max auto-extensions per subagent per budget kind before denying. */
1923
+ maxBudgetExtensions;
1924
+ /** Sessions root for direct subagent JSONL reads (fleet_session tool). */
1925
+ sessionsRoot;
1926
+ /** Director run id for JSONL path resolution. */
1927
+ directorRunId;
1780
1928
  /** Resolves task descriptions back from `assign()` so completion events
1781
1929
  * can also carry a human-readable title. */
1782
1930
  taskDescriptions = /* @__PURE__ */ new Map();
@@ -1803,12 +1951,17 @@ var Director = class {
1803
1951
  this.spawnDepth = opts.spawnDepth ?? 0;
1804
1952
  this.sessionWriter = opts.sessionWriter ?? null;
1805
1953
  this.manifestDebounceMs = opts.manifestDebounceMs ?? 2e3;
1954
+ this.maxCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
1955
+ this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 2;
1956
+ this.sessionsRoot = opts.sessionsRoot;
1957
+ this.directorRunId = opts.directorRunId ?? this.id;
1806
1958
  this.stateCheckpoint = opts.stateCheckpointPath ? new DirectorStateCheckpoint(opts.stateCheckpointPath, {
1807
1959
  directorRunId: this.id,
1808
1960
  maxSpawns: opts.maxSpawns,
1809
1961
  spawnDepth: this.spawnDepth,
1810
- maxSpawnDepth: this.maxSpawnDepth
1811
- }) : null;
1962
+ maxSpawnDepth: this.maxSpawnDepth,
1963
+ directorBudget: opts.directorBudget
1964
+ }, opts.checkpointDebounceMs ?? 250) : null;
1812
1965
  if (this.sharedScratchpadPath) {
1813
1966
  void fsp4.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(() => void 0);
1814
1967
  }
@@ -1869,7 +2022,7 @@ var Director = class {
1869
2022
  const payload = e.payload;
1870
2023
  const guardKey = `${e.subagentId}:${payload.kind}`;
1871
2024
  const prior = extendCounts.get(guardKey) ?? 0;
1872
- if (prior >= 2) {
2025
+ if (prior >= this.maxBudgetExtensions) {
1873
2026
  payload.deny();
1874
2027
  extendCounts.delete(guardKey);
1875
2028
  return;
@@ -1930,6 +2083,12 @@ var Director = class {
1930
2083
  if (this.spawnCount >= this.maxSpawns) {
1931
2084
  throw new DirectorBudgetError("max_spawns", this.maxSpawns, this.spawnCount + 1);
1932
2085
  }
2086
+ if (this.maxCostUsd < Number.POSITIVE_INFINITY) {
2087
+ const totalCost = this.usage.snapshot().total?.cost ?? 0;
2088
+ if (totalCost >= this.maxCostUsd) {
2089
+ throw new DirectorCostCapError(this.maxCostUsd, totalCost);
2090
+ }
2091
+ }
1933
2092
  const result = await this.coordinator.spawn(config);
1934
2093
  this.spawnCount += 1;
1935
2094
  this.subagentMeta.set(result.subagentId, {
@@ -2109,6 +2268,7 @@ var Director = class {
2109
2268
  if (this.stateCheckpoint) {
2110
2269
  this.stateCheckpoint.setUsage(this.usage.snapshot());
2111
2270
  await this.stateCheckpoint.flush().catch((err) => this.logShutdownError("state_checkpoint_flush", err));
2271
+ await this.stateCheckpoint.releaseLock().catch((err) => this.logShutdownError("state_checkpoint_lock_release", err));
2112
2272
  }
2113
2273
  }
2114
2274
  /**
@@ -2212,6 +2372,58 @@ var Director = class {
2212
2372
  completedResults() {
2213
2373
  return Array.from(this.completed.values());
2214
2374
  }
2375
+ /**
2376
+ * Inject a previously-saved checkpoint snapshot. Call this right after
2377
+ * constructing a Director during a `--resume` run so the in-memory state
2378
+ * (subagents, tasks, waiters) reflects the pre-crash reality instead of
2379
+ * starting from a blank slate. The director then resumes from there —
2380
+ * completing any in-flight tasks and ignoring tasks that already reached
2381
+ * a terminal state in the prior run.
2382
+ */
2383
+ setCheckpointState(snapshot) {
2384
+ this.stateCheckpoint?.resume(snapshot);
2385
+ }
2386
+ /**
2387
+ * Read a subagent's JSONL transcript directly from disk (no bridge
2388
+ * round-trip needed). Returns the last assistant text, stop reason,
2389
+ * tool-use count, and line count — or null if the file is unavailable.
2390
+ * Requires `sessionsRoot` to be set on construction.
2391
+ */
2392
+ async readSession(subagentId, tail) {
2393
+ if (!this.sessionsRoot) return null;
2394
+ const filePath = path4.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
2395
+ let raw;
2396
+ try {
2397
+ raw = await fsp4.readFile(filePath, "utf8");
2398
+ } catch {
2399
+ return null;
2400
+ }
2401
+ const lines = raw.split("\n").filter((l) => l.trim());
2402
+ const targetLines = tail ? lines.slice(-tail) : lines;
2403
+ let lastAssistantText;
2404
+ let lastStopReason;
2405
+ let toolUses = 0;
2406
+ for (const line of targetLines) {
2407
+ try {
2408
+ const ev = JSON.parse(line);
2409
+ if (ev.type === "assistant" && typeof ev.text === "string") {
2410
+ lastAssistantText = ev.text;
2411
+ } else if (ev.type === "stop" && ev.stopReason) {
2412
+ lastStopReason = ev.stopReason;
2413
+ } else if (ev.type === "tool_use") {
2414
+ toolUses++;
2415
+ }
2416
+ } catch {
2417
+ }
2418
+ }
2419
+ return {
2420
+ lastAssistantText,
2421
+ lastStopReason,
2422
+ toolUsesObserved: toolUses,
2423
+ events: targetLines.length,
2424
+ path: filePath
2425
+ };
2426
+ }
2215
2427
  snapshot() {
2216
2428
  return this.usage.snapshot();
2217
2429
  }
@@ -2290,10 +2502,28 @@ var Director = class {
2290
2502
  makeRollUpTool(this),
2291
2503
  makeTerminateTool(this),
2292
2504
  makeFleetStatusTool(this),
2293
- makeFleetUsageTool(this)
2505
+ makeFleetUsageTool(this),
2506
+ makeFleetSessionTool(this),
2507
+ makeFleetHealthTool(this)
2294
2508
  ];
2295
2509
  return t;
2296
2510
  }
2511
+ /**
2512
+ * Attempt to acquire the checkpoint lock. Must be called before
2513
+ * resuming — if another director process is alive, this returns
2514
+ * false and the caller should not proceed with the resume.
2515
+ */
2516
+ async acquireCheckpointLock() {
2517
+ return this.stateCheckpoint ? this.stateCheckpoint.acquireLock() : true;
2518
+ }
2519
+ /**
2520
+ * Resume from a prior checkpoint snapshot (loaded via
2521
+ * `loadDirectorState()`). Re-attach to the fleet mid-flight so
2522
+ * subsequent spawn/assign calls update the checkpoint normally.
2523
+ */
2524
+ resumeFromCheckpoint(snapshot) {
2525
+ this.stateCheckpoint?.resume(snapshot);
2526
+ }
2297
2527
  };
2298
2528
  function createDelegateTool(opts) {
2299
2529
  const defaultTimeoutMs = opts.defaultTimeoutMs ?? 4 * 60 * 60 * 1e3;
@@ -2399,7 +2629,7 @@ function createDelegateTool(opts) {
2399
2629
  if (typeof i.maxToolCalls === "number" && i.maxToolCalls > 0) {
2400
2630
  cfg.maxToolCalls = i.maxToolCalls;
2401
2631
  }
2402
- const SUBAGENT_TIMEOUT_BUFFER_MS = 3e4;
2632
+ const SUBAGENT_TIMEOUT_BUFFER_MS = opts.subagentTimeoutBufferMs ?? 3e4;
2403
2633
  const desiredSubTimeout = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
2404
2634
  if (!cfg.timeoutMs || cfg.timeoutMs > desiredSubTimeout) {
2405
2635
  cfg.timeoutMs = desiredSubTimeout;
@@ -2451,7 +2681,7 @@ function createDelegateTool(opts) {
2451
2681
  toolCalls: result.toolCalls,
2452
2682
  durationMs: result.durationMs,
2453
2683
  ...partial ? { partial } : {},
2454
- ...hintForKind(errorKind, retryable, backoffMs) ? { hint: hintForKind(errorKind, retryable, backoffMs) } : {}
2684
+ ...hintForKind(errorKind, retryable, backoffMs, partial) ? { hint: hintForKind(errorKind, retryable, backoffMs, partial) } : {}
2455
2685
  };
2456
2686
  } catch (err) {
2457
2687
  return {
@@ -2471,7 +2701,7 @@ function instantiateRosterConfig2(role, base) {
2471
2701
  id: `${role}-${randomUUID().slice(0, 8)}`
2472
2702
  };
2473
2703
  }
2474
- function hintForKind(kind, retryable, backoffMs) {
2704
+ function hintForKind(kind, retryable, backoffMs, partial) {
2475
2705
  if (!kind) return void 0;
2476
2706
  switch (kind) {
2477
2707
  case "provider_rate_limit":
@@ -2487,16 +2717,40 @@ function hintForKind(kind, retryable, backoffMs) {
2487
2717
  case "budget_iterations":
2488
2718
  case "budget_tool_calls":
2489
2719
  case "budget_tokens":
2490
- case "budget_cost":
2491
- return "Subagent exhausted its budget. The coordinator may auto-extend; otherwise raise the matching `max*` field (e.g. maxToolCalls: 600) on the next delegate, or split the task.";
2492
- case "budget_timeout":
2493
- return "Subagent hit its wall-clock budget. Raise `timeoutMs` on the next delegate or split the task.";
2720
+ case "budget_cost": {
2721
+ const base = "Subagent exhausted its budget. The coordinator may auto-extend; otherwise raise the matching `max*` field (e.g. maxToolCalls: 600) on the next delegate, or split the task.";
2722
+ if (partial?.lastAssistantText) {
2723
+ return `${base}
2724
+
2725
+ Partial output produced before budget hit:
2726
+ ${partial.lastAssistantText}`;
2727
+ }
2728
+ return base;
2729
+ }
2730
+ case "budget_timeout": {
2731
+ const base = "Subagent hit its wall-clock budget. Raise `timeoutMs` on the next delegate or split the task.";
2732
+ if (partial?.lastAssistantText) {
2733
+ return `${base}
2734
+
2735
+ Partial output produced before timeout:
2736
+ ${partial.lastAssistantText}`;
2737
+ }
2738
+ return base;
2739
+ }
2494
2740
  case "aborted_by_parent":
2495
2741
  return "Subagent was aborted (user Ctrl+C, parent unwound, or sibling failure cascade). Not retryable until the abort condition is resolved.";
2496
2742
  case "empty_response":
2497
2743
  return "Subagent ended its turn with no text and no tool calls. Almost always a prompt / config issue \u2014 clarify the task or check the model.";
2498
- case "tool_failed":
2499
- return "A tool inside the subagent returned ok:false. Inspect `partial.lastAssistantText` for the agent reasoning, then retry with corrected inputs.";
2744
+ case "tool_failed": {
2745
+ const base = "A tool inside the subagent returned ok:false. Retry with corrected inputs.";
2746
+ if (partial?.lastAssistantText) {
2747
+ return `${base}
2748
+
2749
+ Agent reasoning before failure:
2750
+ ${partial.lastAssistantText}`;
2751
+ }
2752
+ return base;
2753
+ }
2500
2754
  case "bridge_failed":
2501
2755
  return "Parent-child bridge transport failed. This is rare \u2014 restart the session and retry.";
2502
2756
  default:
@@ -3229,6 +3483,6 @@ function makeDirectorSessionFactory(opts) {
3229
3483
  };
3230
3484
  }
3231
3485
 
3232
- export { ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, BUG_HUNTER_AGENT, BudgetExceededError, BudgetThresholdSignal, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultMultiAgentCoordinator, Director, DirectorBudgetError, FLEET_ROSTER, FleetBus, FleetUsageAggregator, InMemoryAgentBridge, InMemoryBridgeTransport, REFACTOR_PLANNER_AGENT, SECURITY_SCANNER_AGENT, SubagentBudget, composeDirectorPrompt, composeSubagentPrompt, createDelegateTool, createMessage, makeAgentSubagentRunner, makeDirectorSessionFactory, rosterSummaryFromConfigs };
3486
+ export { ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, BUG_HUNTER_AGENT, BudgetExceededError, BudgetThresholdSignal, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultMultiAgentCoordinator, Director, DirectorBudgetError, DirectorCostCapError, FLEET_ROSTER, FleetBus, FleetUsageAggregator, InMemoryAgentBridge, InMemoryBridgeTransport, REFACTOR_PLANNER_AGENT, SECURITY_SCANNER_AGENT, SubagentBudget, composeDirectorPrompt, composeSubagentPrompt, createDelegateTool, createMessage, makeAgentSubagentRunner, makeDirectorSessionFactory, rosterSummaryFromConfigs };
3233
3487
  //# sourceMappingURL=index.js.map
3234
3488
  //# sourceMappingURL=index.js.map