@wrongstack/core 0.5.5 → 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.
@@ -1,13 +1,14 @@
1
1
  export { D as DefaultLogger, a as DefaultLoggerOptions } from '../logger-BH6AE0W9.js';
2
- export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, j as DirectorStateCheckpoint, k as DirectorStateSnapshot, l as DirectorSubagentState, m as DirectorTaskState, M as MemoryStoreOptions, n as MigrationContext, o as MigrationResult, P as PersistedQueueItem, p as PlanFile, q as PlanItem, Q as QueueStore, R as RecoveryLock, r as RecoveryLockOptions, S as SessionAnalyzer, s as SessionStoreOptions, T as TodosCheckpointFile, t as addPlanItem, u as attachPlanCheckpoint, v as attachTodosCheckpoint, w as clearPlan, x as emptyPlan, y as formatPlan, z as loadDirectorState, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../director-state-BUxlqkOa.js';
2
+ export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, M as MemoryStoreOptions, j as MigrationContext, k as MigrationResult, P as PersistedQueueItem, l as PlanFile, m as PlanItem, n as PlanTemplate, Q as QueueStore, R as RecoveryLock, o as RecoveryLockOptions, S as SessionAnalyzer, p as SessionStoreOptions, T as TodosCheckpointFile, q as addPlanItem, r as attachPlanCheckpoint, s as attachTodosCheckpoint, t as clearPlan, u as deriveTodosFromPlanItem, v as emptyPlan, w as formatPlan, x as formatPlanTemplates, y as getPlanTemplate, z as listPlanTemplates, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../plan-templates-DaxTCPfk.js';
3
3
  export { D as DefaultSessionReader } from '../session-reader-4jxsYLZ8.js';
4
+ export { D as DirectorStateCheckpoint, a as DirectorStateSnapshot, b as DirectorSubagentState, c as DirectorTaskState, l as loadDirectorState } from '../director-state-BmYi3DGA.js';
4
5
  export { D as DefaultSecretScrubber, a as DefaultSecretVault, S as SecretVaultOptions, d as decryptConfigSecrets, e as encryptConfigSecrets, m as migratePlaintextSecrets, r as rewriteConfigEncrypted } from '../secret-scrubber-Z_VXuXQT.js';
5
6
  export { AutoApprovePermissionPolicy, DefaultPermissionPolicy, PermissionPolicyOptions } from '../security/index.js';
6
7
  export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, T as ToolExecutor } from '../tool-executor-DSvmOBe6.js';
7
8
  export { AutoCompactionMiddleware, AutonomousRunner, AutonomousRunnerOptions, DefaultSkillLoader, DoneCheckResult, DoneConditionChecker, IntelligentCompactor, IntelligentCompactorOptions, SelectiveCompactor, SelectiveCompactorOptions, SkillLoaderOptions } from '../execution/index.js';
8
9
  import { P as ProviderRunner, R as RunProviderOptions } from '../provider-runner-3SHqk9zB.js';
9
10
  import { j as Response } from '../context-CLZXPPYk.js';
10
- 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, m as FLEET_ROSTER_BUDGETS, 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, u as applyRosterBudget, v as composeDirectorPrompt, w as composeSubagentPrompt, x as createDelegateTool, y as makeAgentSubagentRunner, z as makeDirectorSessionFactory, E as rosterSummaryFromConfigs } from '../index-De4R4rQ7.js';
11
+ 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, m as FLEET_ROSTER_BUDGETS, 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, u as applyRosterBudget, v as composeDirectorPrompt, w as composeSubagentPrompt, x as createDelegateTool, y as makeAgentSubagentRunner, z as makeDirectorSessionFactory, E as rosterSummaryFromConfigs } from '../index-BDnUCRvL.js';
11
12
  export { n as BudgetExceededError, o as BudgetKind, p as BudgetLimits, q as BudgetUsage, r as SubagentBudget } from '../multi-agent-Cv8wk47i.js';
12
13
  export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-B07AYFBk.js';
13
14
  export { D as DefaultModelsRegistry, a as DefaultModelsRegistryOptions, c as classifyFamily } from '../models-registry-DqzwpBQy.js';
@@ -6,7 +6,12 @@ import * as fsp from 'fs/promises';
6
6
  import * as os from 'os';
7
7
  import { EventEmitter } from 'events';
8
8
 
9
- // src/infrastructure/logger.ts
9
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
10
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
11
+ }) : x)(function(x) {
12
+ if (typeof require !== "undefined") return require.apply(this, arguments);
13
+ throw Error('Dynamic require of "' + x + '" is not supported');
14
+ });
10
15
 
11
16
  // src/utils/color.ts
12
17
  var isColorTty = () => {
@@ -2153,9 +2158,149 @@ function matchIndex(plan, idOrIndex) {
2153
2158
  const lower = idOrIndex.toLowerCase();
2154
2159
  return plan.items.findIndex((it) => it.title.toLowerCase().includes(lower));
2155
2160
  }
2161
+ function deriveTodosFromPlanItem(plan, idOrIndex, subtasks) {
2162
+ const idx = matchIndex(plan, idOrIndex);
2163
+ if (idx === -1) return null;
2164
+ const item = plan.items[idx];
2165
+ if (!item) return null;
2166
+ let updatedPlan = plan;
2167
+ if (item.status !== "done") {
2168
+ updatedPlan = setPlanItemStatus(plan, idOrIndex, "in_progress");
2169
+ }
2170
+ const todos = [];
2171
+ todos.push({
2172
+ id: `todo_${Date.now()}_plan`,
2173
+ content: item.title,
2174
+ status: "in_progress",
2175
+ activeForm: item.title
2176
+ });
2177
+ if (subtasks && subtasks.length > 0) {
2178
+ for (const st of subtasks) {
2179
+ todos.push({
2180
+ id: `todo_${Date.now()}_${randomUUID().slice(0, 6)}`,
2181
+ content: st,
2182
+ status: "pending"
2183
+ });
2184
+ }
2185
+ }
2186
+ return { plan: updatedPlan, todos };
2187
+ }
2156
2188
  function attachPlanCheckpoint(_state, _filePath, _sessionId) {
2157
2189
  return () => void 0;
2158
2190
  }
2191
+
2192
+ // src/storage/plan-templates.ts
2193
+ var templates = {
2194
+ "new-feature": {
2195
+ name: "new-feature",
2196
+ description: "Standard workflow for adding a new feature",
2197
+ category: "development",
2198
+ items: [
2199
+ { title: "Write specification / design doc", details: "Define scope, acceptance criteria, edge cases" },
2200
+ { title: "Set up feature branch", details: "git checkout -b feature/..." },
2201
+ { title: "Implement core logic", details: "TDD preferred \u2014 write tests first" },
2202
+ { title: "Add unit tests", details: ">= 80% coverage for new code" },
2203
+ { title: "Add integration tests", details: "End-to-end happy path + error paths" },
2204
+ { title: "Update documentation", details: "README, API docs, changelog" },
2205
+ { title: "Code review", details: "Self-review before requesting review" },
2206
+ { title: "Merge and deploy", details: "CI green, tag release" }
2207
+ ]
2208
+ },
2209
+ "bug-fix": {
2210
+ name: "bug-fix",
2211
+ description: "Systematic approach to fixing bugs",
2212
+ category: "maintenance",
2213
+ items: [
2214
+ { title: "Reproduce the bug", details: "Minimal reproduction case" },
2215
+ { title: "Root cause analysis", details: "Trace through logs, debugger" },
2216
+ { title: "Write failing test", details: "Test must fail before fix" },
2217
+ { title: "Implement fix", details: "Smallest possible change" },
2218
+ { title: "Verify fix", details: "Test passes, reproduction no longer fails" },
2219
+ { title: "Regression test", details: "Ensure no related tests broken" },
2220
+ { title: "Document in changelog", details: "Brief description + issue link" }
2221
+ ]
2222
+ },
2223
+ "refactor": {
2224
+ name: "refactor",
2225
+ description: "Safe refactoring workflow",
2226
+ category: "maintenance",
2227
+ items: [
2228
+ { title: "Identify refactoring target", details: "Code smell, performance bottleneck, or tech debt" },
2229
+ { title: "Ensure test coverage", details: "Existing tests must pass before and after" },
2230
+ { title: "Write characterization tests", details: "Capture current behavior if tests weak" },
2231
+ { title: "Apply refactoring", details: "Small steps, frequent commits" },
2232
+ { title: "Run full test suite", details: "All tests must pass" },
2233
+ { title: "Performance check", details: "Ensure no regression" },
2234
+ { title: "Code review", details: "Explain the why, not just the what" }
2235
+ ]
2236
+ },
2237
+ "release": {
2238
+ name: "release",
2239
+ description: "Preparing a new release",
2240
+ category: "release",
2241
+ items: [
2242
+ { title: "Version bump", details: "package.json, lockfiles, tags" },
2243
+ { title: "Update changelog", details: "All changes since last release" },
2244
+ { title: "Run full test suite", details: "Unit + integration + e2e" },
2245
+ { title: "Build artifacts", details: "Docker images, bundles, binaries" },
2246
+ { title: "Staging smoke tests", details: "Deploy to staging, verify" },
2247
+ { title: "Production deploy", details: "Blue-green or canary" },
2248
+ { title: "Post-deploy verification", details: "Health checks, error rates" },
2249
+ { title: "Announce release", details: "Slack, email, GitHub release notes" }
2250
+ ]
2251
+ },
2252
+ "security-audit": {
2253
+ name: "security-audit",
2254
+ description: "Security review and hardening",
2255
+ category: "infrastructure",
2256
+ items: [
2257
+ { title: "Dependency audit", details: "npm audit, Snyk, Dependabot alerts" },
2258
+ { title: "Secret scan", details: "git-secrets, truffleHog, manual review" },
2259
+ { title: "Access control review", details: "IAM, roles, least privilege" },
2260
+ { title: "Input validation audit", details: "SQL injection, XSS, path traversal" },
2261
+ { title: "Authentication review", details: "Session management, MFA, password policy" },
2262
+ { title: "Logging and monitoring", details: "PII in logs, audit trails" },
2263
+ { title: "Incident response plan", details: "Runbooks, contacts, escalation" }
2264
+ ]
2265
+ },
2266
+ "onboarding": {
2267
+ name: "onboarding",
2268
+ description: "New developer onboarding checklist",
2269
+ category: "infrastructure",
2270
+ items: [
2271
+ { title: "Repository access", details: "GitHub/GitLab permissions" },
2272
+ { title: "Local environment setup", details: "Docker, dependencies, env files" },
2273
+ { title: "Run tests locally", details: "Verify green suite" },
2274
+ { title: "Read architecture docs", details: "ADR, README, onboarding guide" },
2275
+ { title: "First commit", details: "Docs fix or small improvement" },
2276
+ { title: "Pair programming session", details: "Walk through codebase with buddy" },
2277
+ { title: "Deploy to staging", details: "Verify CI/CD access" }
2278
+ ]
2279
+ }
2280
+ };
2281
+ function listPlanTemplates() {
2282
+ return Object.values(templates);
2283
+ }
2284
+ function getPlanTemplate(name) {
2285
+ return templates[name];
2286
+ }
2287
+ function formatPlanTemplates() {
2288
+ const cats = /* @__PURE__ */ new Map();
2289
+ for (const t of Object.values(templates)) {
2290
+ const arr = cats.get(t.category) ?? [];
2291
+ arr.push(t);
2292
+ cats.set(t.category, arr);
2293
+ }
2294
+ const lines = ["Available plan templates:"];
2295
+ for (const [cat, items] of cats) {
2296
+ lines.push(`
2297
+ ${cat}:`);
2298
+ for (const t of items) {
2299
+ lines.push(` ${t.name.padEnd(18)} \u2014 ${t.description}`);
2300
+ }
2301
+ }
2302
+ return lines.join("\n");
2303
+ }
2159
2304
  async function loadDirectorState(filePath) {
2160
2305
  let raw;
2161
2306
  try {
@@ -2171,15 +2316,48 @@ async function loadDirectorState(filePath) {
2171
2316
  return null;
2172
2317
  }
2173
2318
  }
2319
+ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
2320
+ let existing;
2321
+ try {
2322
+ existing = await fsp.readFile(lockPath, "utf8");
2323
+ } catch {
2324
+ }
2325
+ if (existing) {
2326
+ try {
2327
+ const lock2 = JSON.parse(existing);
2328
+ try {
2329
+ process.kill(lock2.pid, 0);
2330
+ return false;
2331
+ } catch {
2332
+ }
2333
+ } catch {
2334
+ }
2335
+ }
2336
+ const lock = {
2337
+ pid: processId,
2338
+ hostname: __require("os").hostname(),
2339
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
2340
+ };
2341
+ await atomicWrite(lockPath, JSON.stringify(lock), { mode: 384 });
2342
+ return true;
2343
+ }
2344
+ async function releaseDirectorStateLock(lockPath) {
2345
+ try {
2346
+ await fsp.unlink(lockPath);
2347
+ } catch {
2348
+ }
2349
+ }
2174
2350
  var DirectorStateCheckpoint = class {
2175
2351
  snapshot;
2176
2352
  filePath;
2353
+ lockPath;
2177
2354
  timer = null;
2178
2355
  debounceMs;
2179
2356
  writing = false;
2180
2357
  rewriteRequested = false;
2181
2358
  constructor(filePath, init, debounceMs = 250) {
2182
2359
  this.filePath = filePath;
2360
+ this.lockPath = `${filePath}.lock`;
2183
2361
  this.debounceMs = debounceMs;
2184
2362
  this.snapshot = {
2185
2363
  version: 1,
@@ -2189,10 +2367,36 @@ var DirectorStateCheckpoint = class {
2189
2367
  maxSpawns: init.maxSpawns,
2190
2368
  spawnDepth: init.spawnDepth,
2191
2369
  maxSpawnDepth: init.maxSpawnDepth,
2370
+ directorBudget: init.directorBudget,
2192
2371
  subagents: [],
2193
2372
  tasks: []
2194
2373
  };
2195
2374
  }
2375
+ /**
2376
+ * Attempt to acquire the lock for this checkpoint. Call this before
2377
+ * resuming a crashed director run. If it returns false, another
2378
+ * director process is still running this fleet — do not resume.
2379
+ */
2380
+ async acquireLock() {
2381
+ return acquireDirectorStateLock(this.lockPath);
2382
+ }
2383
+ /**
2384
+ * Release the lock on graceful shutdown. Call `flush()` first to ensure
2385
+ * the final checkpoint state is on disk before removing the lock.
2386
+ * Without this, the next resume will see a stale-lock and refuse.
2387
+ */
2388
+ async releaseLock() {
2389
+ return releaseDirectorStateLock(this.lockPath);
2390
+ }
2391
+ /**
2392
+ * Resume from a snapshot previously loaded via `loadDirectorState()`.
2393
+ * Use this when `--resume <runId>` is triggered — the snapshot has
2394
+ * the full fleet state (subagents, tasks) from before the crash; the
2395
+ * checkpoint continues from there.
2396
+ */
2397
+ resume(snapshot) {
2398
+ this.snapshot = snapshot;
2399
+ }
2196
2400
  current() {
2197
2401
  return this.snapshot;
2198
2402
  }
@@ -6230,6 +6434,9 @@ function makeSpawnTool(director, roster) {
6230
6434
  if (err instanceof DirectorBudgetError) {
6231
6435
  return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
6232
6436
  }
6437
+ if (err instanceof DirectorCostCapError) {
6438
+ return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
6439
+ }
6233
6440
  return { error: err instanceof Error ? err.message : String(err) };
6234
6441
  }
6235
6442
  }
@@ -6367,6 +6574,65 @@ function makeFleetUsageTool(director) {
6367
6574
  }
6368
6575
  };
6369
6576
  }
6577
+ function makeFleetSessionTool(director) {
6578
+ return {
6579
+ name: "fleet_session",
6580
+ 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.",
6581
+ permission: "auto",
6582
+ mutating: false,
6583
+ inputSchema: {
6584
+ type: "object",
6585
+ properties: {
6586
+ subagentId: { type: "string", description: "Subagent id to read the transcript of." },
6587
+ /** Number of trailing lines to return (last N JSONL lines). Default: all. */
6588
+ tail: { type: "number", description: "Number of trailing JSONL lines to return. Omit for the full transcript." }
6589
+ },
6590
+ required: ["subagentId"]
6591
+ },
6592
+ async execute(input) {
6593
+ const i = input;
6594
+ const result = await director.readSession(i.subagentId, i.tail);
6595
+ if (!result) {
6596
+ return {
6597
+ error: `fleet_session: transcript unavailable for "${i.subagentId}". Is sessionsRoot configured?`
6598
+ };
6599
+ }
6600
+ return result;
6601
+ }
6602
+ };
6603
+ }
6604
+ function makeFleetHealthTool(director) {
6605
+ return {
6606
+ name: "fleet_health",
6607
+ 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.",
6608
+ permission: "auto",
6609
+ mutating: false,
6610
+ inputSchema: { type: "object", properties: {}, required: [] },
6611
+ async execute() {
6612
+ const status = director.status();
6613
+ const snapshot = director.snapshot();
6614
+ const subagents = status.subagents ?? [];
6615
+ const perSubagent = snapshot.perSubagent ?? {};
6616
+ return {
6617
+ subagents: subagents.map((s) => {
6618
+ const usage = perSubagent[s.id];
6619
+ return {
6620
+ id: s.id,
6621
+ status: s.status,
6622
+ lastEventAt: usage?.lastEventAt,
6623
+ // Budget pressure: fraction of each limit consumed if we have it.
6624
+ // BudgetWarning events carry used/limit ratios; surface them here.
6625
+ budgetPressure: {
6626
+ iterations: usage?.iterations,
6627
+ toolCalls: usage?.toolCalls,
6628
+ costUsd: usage?.cost
6629
+ }
6630
+ };
6631
+ })
6632
+ };
6633
+ }
6634
+ };
6635
+ }
6370
6636
 
6371
6637
  // src/coordination/director.ts
6372
6638
  var DirectorBudgetError = class extends Error {
@@ -6383,6 +6649,20 @@ var DirectorBudgetError = class extends Error {
6383
6649
  this.observed = observed;
6384
6650
  }
6385
6651
  };
6652
+ var DirectorCostCapError = class extends Error {
6653
+ kind;
6654
+ limit;
6655
+ observed;
6656
+ constructor(limit, observed) {
6657
+ super(
6658
+ `Director cost cap exceeded: total fleet spend ${observed.toFixed(4)} exceeds maxCostUsd ${limit.toFixed(4)}`
6659
+ );
6660
+ this.name = "DirectorCostCapError";
6661
+ this.kind = "max_cost_usd";
6662
+ this.limit = limit;
6663
+ this.observed = observed;
6664
+ }
6665
+ };
6386
6666
  var Director = class {
6387
6667
  id;
6388
6668
  fleet;
@@ -6437,6 +6717,14 @@ var Director = class {
6437
6717
  /** Debounce timer for periodic manifest writes. */
6438
6718
  manifestTimer = null;
6439
6719
  manifestDebounceMs;
6720
+ /** Fleet-wide cost cap. Infinity means no cap. */
6721
+ maxCostUsd;
6722
+ /** Max auto-extensions per subagent per budget kind before denying. */
6723
+ maxBudgetExtensions;
6724
+ /** Sessions root for direct subagent JSONL reads (fleet_session tool). */
6725
+ sessionsRoot;
6726
+ /** Director run id for JSONL path resolution. */
6727
+ directorRunId;
6440
6728
  /** Resolves task descriptions back from `assign()` so completion events
6441
6729
  * can also carry a human-readable title. */
6442
6730
  taskDescriptions = /* @__PURE__ */ new Map();
@@ -6463,12 +6751,17 @@ var Director = class {
6463
6751
  this.spawnDepth = opts.spawnDepth ?? 0;
6464
6752
  this.sessionWriter = opts.sessionWriter ?? null;
6465
6753
  this.manifestDebounceMs = opts.manifestDebounceMs ?? 2e3;
6754
+ this.maxCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
6755
+ this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 2;
6756
+ this.sessionsRoot = opts.sessionsRoot;
6757
+ this.directorRunId = opts.directorRunId ?? this.id;
6466
6758
  this.stateCheckpoint = opts.stateCheckpointPath ? new DirectorStateCheckpoint(opts.stateCheckpointPath, {
6467
6759
  directorRunId: this.id,
6468
6760
  maxSpawns: opts.maxSpawns,
6469
6761
  spawnDepth: this.spawnDepth,
6470
- maxSpawnDepth: this.maxSpawnDepth
6471
- }) : null;
6762
+ maxSpawnDepth: this.maxSpawnDepth,
6763
+ directorBudget: opts.directorBudget
6764
+ }, opts.checkpointDebounceMs ?? 250) : null;
6472
6765
  if (this.sharedScratchpadPath) {
6473
6766
  void fsp.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(() => void 0);
6474
6767
  }
@@ -6529,7 +6822,7 @@ var Director = class {
6529
6822
  const payload = e.payload;
6530
6823
  const guardKey = `${e.subagentId}:${payload.kind}`;
6531
6824
  const prior = extendCounts.get(guardKey) ?? 0;
6532
- if (prior >= 2) {
6825
+ if (prior >= this.maxBudgetExtensions) {
6533
6826
  payload.deny();
6534
6827
  extendCounts.delete(guardKey);
6535
6828
  return;
@@ -6590,6 +6883,12 @@ var Director = class {
6590
6883
  if (this.spawnCount >= this.maxSpawns) {
6591
6884
  throw new DirectorBudgetError("max_spawns", this.maxSpawns, this.spawnCount + 1);
6592
6885
  }
6886
+ if (this.maxCostUsd < Number.POSITIVE_INFINITY) {
6887
+ const totalCost = this.usage.snapshot().total?.cost ?? 0;
6888
+ if (totalCost >= this.maxCostUsd) {
6889
+ throw new DirectorCostCapError(this.maxCostUsd, totalCost);
6890
+ }
6891
+ }
6593
6892
  const result = await this.coordinator.spawn(config);
6594
6893
  this.spawnCount += 1;
6595
6894
  this.subagentMeta.set(result.subagentId, {
@@ -6769,6 +7068,7 @@ var Director = class {
6769
7068
  if (this.stateCheckpoint) {
6770
7069
  this.stateCheckpoint.setUsage(this.usage.snapshot());
6771
7070
  await this.stateCheckpoint.flush().catch((err) => this.logShutdownError("state_checkpoint_flush", err));
7071
+ await this.stateCheckpoint.releaseLock().catch((err) => this.logShutdownError("state_checkpoint_lock_release", err));
6772
7072
  }
6773
7073
  }
6774
7074
  /**
@@ -6872,6 +7172,58 @@ var Director = class {
6872
7172
  completedResults() {
6873
7173
  return Array.from(this.completed.values());
6874
7174
  }
7175
+ /**
7176
+ * Inject a previously-saved checkpoint snapshot. Call this right after
7177
+ * constructing a Director during a `--resume` run so the in-memory state
7178
+ * (subagents, tasks, waiters) reflects the pre-crash reality instead of
7179
+ * starting from a blank slate. The director then resumes from there —
7180
+ * completing any in-flight tasks and ignoring tasks that already reached
7181
+ * a terminal state in the prior run.
7182
+ */
7183
+ setCheckpointState(snapshot) {
7184
+ this.stateCheckpoint?.resume(snapshot);
7185
+ }
7186
+ /**
7187
+ * Read a subagent's JSONL transcript directly from disk (no bridge
7188
+ * round-trip needed). Returns the last assistant text, stop reason,
7189
+ * tool-use count, and line count — or null if the file is unavailable.
7190
+ * Requires `sessionsRoot` to be set on construction.
7191
+ */
7192
+ async readSession(subagentId, tail) {
7193
+ if (!this.sessionsRoot) return null;
7194
+ const filePath = path3.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
7195
+ let raw;
7196
+ try {
7197
+ raw = await fsp.readFile(filePath, "utf8");
7198
+ } catch {
7199
+ return null;
7200
+ }
7201
+ const lines = raw.split("\n").filter((l) => l.trim());
7202
+ const targetLines = tail ? lines.slice(-tail) : lines;
7203
+ let lastAssistantText;
7204
+ let lastStopReason;
7205
+ let toolUses = 0;
7206
+ for (const line of targetLines) {
7207
+ try {
7208
+ const ev = JSON.parse(line);
7209
+ if (ev.type === "assistant" && typeof ev.text === "string") {
7210
+ lastAssistantText = ev.text;
7211
+ } else if (ev.type === "stop" && ev.stopReason) {
7212
+ lastStopReason = ev.stopReason;
7213
+ } else if (ev.type === "tool_use") {
7214
+ toolUses++;
7215
+ }
7216
+ } catch {
7217
+ }
7218
+ }
7219
+ return {
7220
+ lastAssistantText,
7221
+ lastStopReason,
7222
+ toolUsesObserved: toolUses,
7223
+ events: targetLines.length,
7224
+ path: filePath
7225
+ };
7226
+ }
6875
7227
  snapshot() {
6876
7228
  return this.usage.snapshot();
6877
7229
  }
@@ -6950,10 +7302,28 @@ var Director = class {
6950
7302
  makeRollUpTool(this),
6951
7303
  makeTerminateTool(this),
6952
7304
  makeFleetStatusTool(this),
6953
- makeFleetUsageTool(this)
7305
+ makeFleetUsageTool(this),
7306
+ makeFleetSessionTool(this),
7307
+ makeFleetHealthTool(this)
6954
7308
  ];
6955
7309
  return t;
6956
7310
  }
7311
+ /**
7312
+ * Attempt to acquire the checkpoint lock. Must be called before
7313
+ * resuming — if another director process is alive, this returns
7314
+ * false and the caller should not proceed with the resume.
7315
+ */
7316
+ async acquireCheckpointLock() {
7317
+ return this.stateCheckpoint ? this.stateCheckpoint.acquireLock() : true;
7318
+ }
7319
+ /**
7320
+ * Resume from a prior checkpoint snapshot (loaded via
7321
+ * `loadDirectorState()`). Re-attach to the fleet mid-flight so
7322
+ * subsequent spawn/assign calls update the checkpoint normally.
7323
+ */
7324
+ resumeFromCheckpoint(snapshot) {
7325
+ this.stateCheckpoint?.resume(snapshot);
7326
+ }
6957
7327
  };
6958
7328
  function createDelegateTool(opts) {
6959
7329
  const defaultTimeoutMs = opts.defaultTimeoutMs ?? 4 * 60 * 60 * 1e3;
@@ -7059,7 +7429,7 @@ function createDelegateTool(opts) {
7059
7429
  if (typeof i.maxToolCalls === "number" && i.maxToolCalls > 0) {
7060
7430
  cfg.maxToolCalls = i.maxToolCalls;
7061
7431
  }
7062
- const SUBAGENT_TIMEOUT_BUFFER_MS = 3e4;
7432
+ const SUBAGENT_TIMEOUT_BUFFER_MS = opts.subagentTimeoutBufferMs ?? 3e4;
7063
7433
  const desiredSubTimeout = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
7064
7434
  if (!cfg.timeoutMs || cfg.timeoutMs > desiredSubTimeout) {
7065
7435
  cfg.timeoutMs = desiredSubTimeout;
@@ -7111,7 +7481,7 @@ function createDelegateTool(opts) {
7111
7481
  toolCalls: result.toolCalls,
7112
7482
  durationMs: result.durationMs,
7113
7483
  ...partial ? { partial } : {},
7114
- ...hintForKind(errorKind, retryable, backoffMs) ? { hint: hintForKind(errorKind, retryable, backoffMs) } : {}
7484
+ ...hintForKind(errorKind, retryable, backoffMs, partial) ? { hint: hintForKind(errorKind, retryable, backoffMs, partial) } : {}
7115
7485
  };
7116
7486
  } catch (err) {
7117
7487
  return {
@@ -7131,7 +7501,7 @@ function instantiateRosterConfig2(role, base) {
7131
7501
  id: `${role}-${randomUUID().slice(0, 8)}`
7132
7502
  };
7133
7503
  }
7134
- function hintForKind(kind, retryable, backoffMs) {
7504
+ function hintForKind(kind, retryable, backoffMs, partial) {
7135
7505
  if (!kind) return void 0;
7136
7506
  switch (kind) {
7137
7507
  case "provider_rate_limit":
@@ -7147,16 +7517,40 @@ function hintForKind(kind, retryable, backoffMs) {
7147
7517
  case "budget_iterations":
7148
7518
  case "budget_tool_calls":
7149
7519
  case "budget_tokens":
7150
- case "budget_cost":
7151
- 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.";
7152
- case "budget_timeout":
7153
- return "Subagent hit its wall-clock budget. Raise `timeoutMs` on the next delegate or split the task.";
7520
+ case "budget_cost": {
7521
+ 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.";
7522
+ if (partial?.lastAssistantText) {
7523
+ return `${base}
7524
+
7525
+ Partial output produced before budget hit:
7526
+ ${partial.lastAssistantText}`;
7527
+ }
7528
+ return base;
7529
+ }
7530
+ case "budget_timeout": {
7531
+ const base = "Subagent hit its wall-clock budget. Raise `timeoutMs` on the next delegate or split the task.";
7532
+ if (partial?.lastAssistantText) {
7533
+ return `${base}
7534
+
7535
+ Partial output produced before timeout:
7536
+ ${partial.lastAssistantText}`;
7537
+ }
7538
+ return base;
7539
+ }
7154
7540
  case "aborted_by_parent":
7155
7541
  return "Subagent was aborted (user Ctrl+C, parent unwound, or sibling failure cascade). Not retryable until the abort condition is resolved.";
7156
7542
  case "empty_response":
7157
7543
  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.";
7158
- case "tool_failed":
7159
- return "A tool inside the subagent returned ok:false. Inspect `partial.lastAssistantText` for the agent reasoning, then retry with corrected inputs.";
7544
+ case "tool_failed": {
7545
+ const base = "A tool inside the subagent returned ok:false. Retry with corrected inputs.";
7546
+ if (partial?.lastAssistantText) {
7547
+ return `${base}
7548
+
7549
+ Agent reasoning before failure:
7550
+ ${partial.lastAssistantText}`;
7551
+ }
7552
+ return base;
7553
+ }
7160
7554
  case "bridge_failed":
7161
7555
  return "Parent-child bridge transport failed. This is rare \u2014 restart the session and retry.";
7162
7556
  default:
@@ -11286,6 +11680,6 @@ var allServers = () => ({
11286
11680
  "minimax-vision": { ...miniMaxVisionServer(), enabled: false }
11287
11681
  });
11288
11682
 
11289
- export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorBudgetError, DirectorStateCheckpoint, DoneConditionChecker, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, decryptConfigSecrets2 as decryptConfigSecrets, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, getTemplate, githubServer, googleMapsServer, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeDirectorSessionFactory, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
11683
+ export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorBudgetError, DirectorStateCheckpoint, DoneConditionChecker, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, decryptConfigSecrets2 as decryptConfigSecrets, deriveTodosFromPlanItem, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeDirectorSessionFactory, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
11290
11684
  //# sourceMappingURL=index.js.map
11291
11685
  //# sourceMappingURL=index.js.map