@wrongstack/core 0.5.7 → 0.6.1

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 (47) hide show
  1. package/dist/{agent-bridge-BKNiE1VH.d.ts → agent-bridge-DaCvA_uK.d.ts} +1 -1
  2. package/dist/coordination/index.d.ts +5 -5
  3. package/dist/coordination/index.js +218 -78
  4. package/dist/coordination/index.js.map +1 -1
  5. package/dist/defaults/index.d.ts +10 -9
  6. package/dist/defaults/index.js +1127 -180
  7. package/dist/defaults/index.js.map +1 -1
  8. package/dist/{events-DPQKFX7W.d.ts → events-CzkeaVVl.d.ts} +8 -2
  9. package/dist/execution/index.d.ts +281 -5
  10. package/dist/execution/index.js +785 -3
  11. package/dist/execution/index.js.map +1 -1
  12. package/dist/extension/index.d.ts +2 -2
  13. package/dist/extension/index.js +2 -1
  14. package/dist/extension/index.js.map +1 -1
  15. package/dist/goal-store-DVCfj7Ff.d.ts +95 -0
  16. package/dist/{index-j2WyAyML.d.ts → index-BkKLQjea.d.ts} +34 -2
  17. package/dist/{index-Bf9Bpkdc.d.ts → index-i9rPR53g.d.ts} +11 -4
  18. package/dist/index.d.ts +51 -16
  19. package/dist/index.js +1506 -247
  20. package/dist/index.js.map +1 -1
  21. package/dist/infrastructure/index.d.ts +2 -2
  22. package/dist/kernel/index.d.ts +2 -2
  23. package/dist/kernel/index.js.map +1 -1
  24. package/dist/models/index.js +2 -3
  25. package/dist/models/index.js.map +1 -1
  26. package/dist/{multi-agent-Cpp7FXUl.d.ts → multi-agent-MfI6dmv-.d.ts} +30 -5
  27. package/dist/observability/index.d.ts +1 -1
  28. package/dist/{path-resolver--g_hKJ7V.d.ts → path-resolver-CWINz5XR.d.ts} +1 -1
  29. package/dist/{plan-templates-Bveo2W8n.d.ts → plan-templates-Bne1pB4d.d.ts} +6 -5
  30. package/dist/{provider-runner-hl4Il3xS.d.ts → provider-runner-CZYIzeBp.d.ts} +1 -1
  31. package/dist/sdd/index.d.ts +5 -3
  32. package/dist/sdd/index.js +102 -68
  33. package/dist/sdd/index.js.map +1 -1
  34. package/dist/security/index.js +82 -82
  35. package/dist/security/index.js.map +1 -1
  36. package/dist/skills/index.js +102 -38
  37. package/dist/skills/index.js.map +1 -1
  38. package/dist/storage/index.d.ts +3 -2
  39. package/dist/storage/index.js +134 -22
  40. package/dist/storage/index.js.map +1 -1
  41. package/dist/{tool-executor-DbAFkHdP.d.ts → tool-executor-40Q6shR-.d.ts} +1 -1
  42. package/dist/types/index.d.ts +7 -7
  43. package/dist/types/index.js +116 -103
  44. package/dist/types/index.js.map +1 -1
  45. package/dist/utils/index.js +5 -0
  46. package/dist/utils/index.js.map +1 -1
  47. package/package.json +5 -1
@@ -1,4 +1,4 @@
1
- import { B as BridgeTransport, l as BridgeMessage, A as AgentBridge, m as AgentBridgeConfig } from './multi-agent-Cpp7FXUl.js';
1
+ import { B as BridgeTransport, l as BridgeMessage, A as AgentBridge, m as AgentBridgeConfig } from './multi-agent-MfI6dmv-.js';
2
2
 
3
3
  /**
4
4
  * In-memory pub/sub transport for agent-to-agent messaging.
@@ -1,11 +1,11 @@
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 DirectorPromptParts, j as DirectorSessionFactory, k as DirectorSessionFactoryOptions, F as FLEET_ROSTER, m as FleetBus, K as FleetCostCapError, n as FleetEvent, o as FleetHandler, p as FleetManager, q as FleetManagerOptions, r as FleetSpawnBudgetError, s as FleetUsage, t as FleetUsageAggregator, I as ICoordinator, u as IFleetManager, M as MultiAgentCoordinatorOptions, N as NULL_FLEET_BUS, R as REFACTOR_PLANNER_AGENT, S as SECURITY_SCANNER_AGENT, v as SubagentPromptParts, w as SubagentUsageSnapshot, y as composeDirectorPrompt, z as composeSubagentPrompt, E as createDelegateTool, G as makeAgentSubagentRunner, H as makeDirectorSessionFactory, J as rosterSummaryFromConfigs } from '../index-Bf9Bpkdc.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-Cpp7FXUl.js';
3
- export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-BKNiE1VH.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 DirectorPromptParts, j as DirectorSessionFactory, k as DirectorSessionFactoryOptions, F as FLEET_ROSTER, m as FleetBus, K as FleetCostCapError, n as FleetEvent, o as FleetHandler, p as FleetManager, q as FleetManagerOptions, r as FleetSpawnBudgetError, s as FleetUsage, t as FleetUsageAggregator, I as ICoordinator, u as IFleetManager, M as MultiAgentCoordinatorOptions, N as NULL_FLEET_BUS, R as REFACTOR_PLANNER_AGENT, S as SECURITY_SCANNER_AGENT, v as SubagentPromptParts, w as SubagentUsageSnapshot, y as composeDirectorPrompt, z as composeSubagentPrompt, E as createDelegateTool, G as makeAgentSubagentRunner, H as makeDirectorSessionFactory, J as rosterSummaryFromConfigs } from '../index-i9rPR53g.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-MfI6dmv-.js';
3
+ export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-DaCvA_uK.js';
4
4
  import '../director-state-BmYi3DGA.js';
5
5
  import '../context-CDRyrkKQ.js';
6
- import '../events-DPQKFX7W.js';
6
+ import '../events-CzkeaVVl.js';
7
7
  import 'node:events';
8
- import '../index-j2WyAyML.js';
8
+ import '../index-BkKLQjea.js';
9
9
  import '../logger-BMQgxvdy.js';
10
10
  import '../system-prompt-Dl2QY1_B.js';
11
11
  import '../observability-BhnVLBLS.js';
@@ -73,8 +73,6 @@ async function renameWithRetry(from, to) {
73
73
  }
74
74
  throw lastErr;
75
75
  }
76
-
77
- // src/storage/director-state.ts
78
76
  async function acquireDirectorStateLock(lockPath, processId = process.pid) {
79
77
  let existing;
80
78
  try {
@@ -794,7 +792,7 @@ var BudgetThresholdSignal = class extends Error {
794
792
  this.decision = decision;
795
793
  }
796
794
  };
797
- var SubagentBudget = class {
795
+ var SubagentBudget = class _SubagentBudget {
798
796
  limits;
799
797
  iterations = 0;
800
798
  toolCalls = 0;
@@ -803,6 +801,26 @@ var SubagentBudget = class {
803
801
  costUsd = 0;
804
802
  startTime = null;
805
803
  _onThreshold;
804
+ /**
805
+ * Tracks which budget kinds currently have an extension request
806
+ * in flight. While a kind is here, further `checkLimit` calls for the
807
+ * same kind are no-ops — without this dedup, every `recordIteration`
808
+ * after the limit is reached spawns a fresh decision Promise (until
809
+ * the first one lands and patches limits), flooding the FleetBus
810
+ * with redundant threshold events. Cleared in `checkLimitAsync`'s
811
+ * `finally`.
812
+ */
813
+ pendingExtensions = /* @__PURE__ */ new Set();
814
+ /**
815
+ * Hard cap on how long `checkLimitAsync` waits for the coordinator to
816
+ * respond before defaulting to 'stop'. Without this fallback an absent
817
+ * or hung listener (Director not built / event filter detached mid-run)
818
+ * leaves the budget over-limit and never enforces anything, since
819
+ * `checkLimit` returns synchronously via `void this.checkLimitAsync`.
820
+ * Hardcoded for now — most fleets set their own per-task timeout that
821
+ * dwarfs this anyway. 30 s matches the existing event-emit timeoutMs.
822
+ */
823
+ static DECISION_TIMEOUT_MS = 3e4;
806
824
  /**
807
825
  * Injected by the runner when wiring the budget to its EventBus.
808
826
  * Used by `checkLimitAsync` to emit `budget.threshold_reached` events.
@@ -845,56 +863,92 @@ var SubagentBudget = class {
845
863
  if (kind === "timeout" || !this._onThreshold) {
846
864
  throw new BudgetExceededError(kind, limit, used);
847
865
  }
848
- void this.checkLimitAsync(kind, used, limit);
866
+ const bus = this._events;
867
+ if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
868
+ throw new BudgetExceededError(kind, limit, used);
869
+ }
870
+ if (this.pendingExtensions.has(kind)) return;
871
+ this.pendingExtensions.add(kind);
872
+ const decision = this.negotiateExtension(kind, used, limit);
873
+ throw new BudgetThresholdSignal(kind, limit, used, decision);
849
874
  }
850
875
  /**
851
- * Async threshold negotiation with the coordinator. Fire-and-forget
852
- * any error thrown here becomes an unhandled rejection in the test environment
853
- * because the runner's catch only handles the synchronous throw from `checkLimit`.
876
+ * Drive the threshold handler to a decision. Resolves with `'stop'`
877
+ * (signal the runner to abort) or `{ extend: ... }` (limits already
878
+ * patched in-place; the runner should not abort). Always releases the
879
+ * `pendingExtensions` slot in `finally`.
880
+ *
881
+ * The 'continue' return from a sync handler is treated as
882
+ * `{ extend: {} }` — keep going without patching, next overrun will
883
+ * fire a fresh signal.
854
884
  */
855
- async checkLimitAsync(kind, used, limit) {
856
- const result = this._onThreshold({
857
- kind,
858
- used,
859
- limit,
860
- // Inject a requestDecision helper the handler can call to emit the
861
- // budget.threshold_reached event and wait for the coordinator's verdict.
862
- // The runner wires this by injecting its EventBus into ctx.budget._events.
863
- requestDecision: () => {
864
- return new Promise((resolve) => {
865
- this._events?.emit("budget.threshold_reached", {
866
- kind,
867
- used,
868
- limit,
869
- timeoutMs: 3e4,
870
- extend: (extra) => resolve({ extend: extra }),
871
- deny: () => resolve("stop")
885
+ async negotiateExtension(kind, used, limit) {
886
+ try {
887
+ const result = this._onThreshold({
888
+ kind,
889
+ used,
890
+ limit,
891
+ // Inject a requestDecision helper the handler can call to emit the
892
+ // budget.threshold_reached event and wait for the coordinator's verdict.
893
+ // A hard fallback timer guarantees the promise eventually resolves
894
+ // even if no listener responds — without it, an absent/detached
895
+ // Director would leave the budget permanently in "asking" state.
896
+ requestDecision: () => {
897
+ const bus = this._events;
898
+ if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
899
+ return Promise.resolve("stop");
900
+ }
901
+ return new Promise((resolve) => {
902
+ let resolved = false;
903
+ const respond = (d) => {
904
+ if (resolved) return;
905
+ resolved = true;
906
+ resolve(d);
907
+ };
908
+ const fallback = setTimeout(
909
+ () => respond("stop"),
910
+ _SubagentBudget.DECISION_TIMEOUT_MS
911
+ );
912
+ bus.emit("budget.threshold_reached", {
913
+ kind,
914
+ used,
915
+ limit,
916
+ timeoutMs: _SubagentBudget.DECISION_TIMEOUT_MS,
917
+ extend: (extra) => {
918
+ clearTimeout(fallback);
919
+ respond({ extend: extra });
920
+ },
921
+ deny: () => {
922
+ clearTimeout(fallback);
923
+ respond("stop");
924
+ }
925
+ });
872
926
  });
873
- });
927
+ }
928
+ });
929
+ if (result === "throw") return "stop";
930
+ if (result === "continue") return { extend: {} };
931
+ const decision = await result;
932
+ if (decision === "stop") return "stop";
933
+ const ext = decision.extend;
934
+ if (ext.maxIterations !== void 0) {
935
+ this.limits.maxIterations = ext.maxIterations;
874
936
  }
875
- });
876
- if (result === "throw") {
877
- throw new BudgetExceededError(kind, limit, used);
878
- }
879
- if (result === "continue") {
880
- return;
881
- }
882
- const decision = await result;
883
- if (decision === "stop") {
884
- throw new BudgetExceededError(kind, limit, used);
885
- }
886
- const ext = decision.extend;
887
- if (ext.maxIterations !== void 0) {
888
- this.limits.maxIterations = ext.maxIterations;
889
- }
890
- if (ext.maxToolCalls !== void 0) {
891
- this.limits.maxToolCalls = ext.maxToolCalls;
892
- }
893
- if (ext.maxTokens !== void 0) {
894
- this.limits.maxTokens = ext.maxTokens;
895
- }
896
- if (ext.maxCostUsd !== void 0) {
897
- this.limits.maxCostUsd = ext.maxCostUsd;
937
+ if (ext.maxToolCalls !== void 0) {
938
+ this.limits.maxToolCalls = ext.maxToolCalls;
939
+ }
940
+ if (ext.maxTokens !== void 0) {
941
+ this.limits.maxTokens = ext.maxTokens;
942
+ }
943
+ if (ext.maxCostUsd !== void 0) {
944
+ this.limits.maxCostUsd = ext.maxCostUsd;
945
+ }
946
+ if (ext.timeoutMs !== void 0) {
947
+ this.limits.timeoutMs = ext.timeoutMs;
948
+ }
949
+ return decision;
950
+ } finally {
951
+ this.pendingExtensions.delete(kind);
898
952
  }
899
953
  }
900
954
  recordIteration() {
@@ -1177,6 +1231,19 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
1177
1231
  setRunner(runner) {
1178
1232
  this.runner = runner;
1179
1233
  }
1234
+ /**
1235
+ * Change the in-flight dispatch ceiling at runtime. Lowering does NOT
1236
+ * preempt running tasks — already-dispatched subagents finish their
1237
+ * current task; only future dispatches respect the new cap. Raising
1238
+ * immediately tries to fill the freed slots from the pending queue.
1239
+ */
1240
+ setMaxConcurrent(n) {
1241
+ if (!Number.isFinite(n) || n < 1) {
1242
+ throw new Error(`maxConcurrent must be a finite integer >= 1, got ${n}`);
1243
+ }
1244
+ this.config.maxConcurrent = Math.floor(n);
1245
+ this.tryDispatchNext();
1246
+ }
1180
1247
  async spawn(subagent) {
1181
1248
  const id = subagent.id || randomUUID();
1182
1249
  if (this.subagents.has(id)) {
@@ -1436,14 +1503,65 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
1436
1503
  this.recordCompletion(result);
1437
1504
  }
1438
1505
  async executeWithTimeout(runner, task, ctx, budget) {
1439
- const timeoutMs = budget.limits.timeoutMs;
1440
- if (timeoutMs === void 0) return runner(task, ctx);
1506
+ const initialTimeoutMs = budget.limits.timeoutMs;
1507
+ if (initialTimeoutMs === void 0) return runner(task, ctx);
1508
+ const start = Date.now();
1441
1509
  let timer = null;
1442
1510
  const timeoutPromise = new Promise((_, reject) => {
1443
- timer = setTimeout(() => {
1444
- this.subagents.get(ctx.subagentId)?.abortController.abort();
1445
- reject(new BudgetExceededError("timeout", timeoutMs, Date.now()));
1446
- }, timeoutMs);
1511
+ const armFor = (ms) => {
1512
+ if (timer) clearTimeout(timer);
1513
+ timer = setTimeout(async () => {
1514
+ const elapsed = Date.now() - start;
1515
+ const limit = budget.limits.timeoutMs ?? initialTimeoutMs;
1516
+ if (!budget.onThreshold) {
1517
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
1518
+ reject(new BudgetExceededError("timeout", limit, elapsed));
1519
+ return;
1520
+ }
1521
+ try {
1522
+ const result = budget.onThreshold({
1523
+ kind: "timeout",
1524
+ used: elapsed,
1525
+ limit,
1526
+ requestDecision: () => new Promise((resolveDecision) => {
1527
+ budget._events?.emit("budget.threshold_reached", {
1528
+ kind: "timeout",
1529
+ used: elapsed,
1530
+ limit,
1531
+ timeoutMs: 3e4,
1532
+ extend: (extra) => resolveDecision({ extend: extra }),
1533
+ deny: () => resolveDecision("stop")
1534
+ });
1535
+ })
1536
+ });
1537
+ const decision = typeof result === "string" ? result : await result;
1538
+ if (decision === "continue") {
1539
+ armFor(Math.max(1e3, limit));
1540
+ return;
1541
+ }
1542
+ if (decision === "throw" || decision === "stop") {
1543
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
1544
+ reject(new BudgetExceededError("timeout", limit, elapsed));
1545
+ return;
1546
+ }
1547
+ if (decision.extend.timeoutMs !== void 0) {
1548
+ budget.limits.timeoutMs = decision.extend.timeoutMs;
1549
+ const newLimit = decision.extend.timeoutMs;
1550
+ const remaining = Math.max(1e3, newLimit - elapsed);
1551
+ armFor(remaining);
1552
+ return;
1553
+ }
1554
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
1555
+ reject(new BudgetExceededError("timeout", limit, elapsed));
1556
+ } catch (err) {
1557
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
1558
+ reject(
1559
+ err instanceof BudgetExceededError ? err : new BudgetExceededError("timeout", limit, elapsed)
1560
+ );
1561
+ }
1562
+ }, ms);
1563
+ };
1564
+ armFor(initialTimeoutMs);
1447
1565
  });
1448
1566
  try {
1449
1567
  return await Promise.race([runner(task, ctx), timeoutPromise]);
@@ -1982,7 +2100,9 @@ var Director = class {
1982
2100
  }, opts.checkpointDebounceMs ?? 250) : null;
1983
2101
  this.fleetManager = opts.fleetManager;
1984
2102
  if (this.sharedScratchpadPath) {
1985
- void fsp4.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(() => void 0);
2103
+ void fsp4.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(
2104
+ (err) => this.logShutdownError("shared_scratchpad_mkdir", err)
2105
+ );
1986
2106
  }
1987
2107
  this.transport = new InMemoryBridgeTransport();
1988
2108
  this.bridge = new InMemoryAgentBridge(
@@ -2052,7 +2172,7 @@ var Director = class {
2052
2172
  return;
2053
2173
  }
2054
2174
  extendCounts.set(guardKey, prior + 1);
2055
- setTimeout(() => {
2175
+ setImmediate(() => {
2056
2176
  const extra = {};
2057
2177
  switch (payload.kind) {
2058
2178
  case "iterations":
@@ -2067,9 +2187,12 @@ var Director = class {
2067
2187
  case "cost":
2068
2188
  extra.maxCostUsd = Math.min(payload.limit * 1.5, 10);
2069
2189
  break;
2190
+ case "timeout":
2191
+ extra.timeoutMs = Math.min(Math.ceil(payload.limit * 1.5), 60 * 6e4);
2192
+ break;
2070
2193
  }
2071
2194
  payload.extend(extra);
2072
- }, Math.min(payload.timeoutMs, 3e4));
2195
+ });
2073
2196
  });
2074
2197
  }
2075
2198
  /** Best-effort session-writer append. Swallows failures — the director
@@ -2088,7 +2211,9 @@ var Director = class {
2088
2211
  if (this.manifestTimer) return;
2089
2212
  this.manifestTimer = setTimeout(() => {
2090
2213
  this.manifestTimer = null;
2091
- void this.writeManifest().catch(() => void 0);
2214
+ void this.writeManifest().catch(
2215
+ (err) => this.logShutdownError("manifest_write_debounced", err)
2216
+ );
2092
2217
  }, this.manifestDebounceMs);
2093
2218
  }
2094
2219
  /**
@@ -2279,7 +2404,7 @@ var Director = class {
2279
2404
  usage: this.usage.snapshot()
2280
2405
  };
2281
2406
  await fsp4.mkdir(path4.dirname(this.manifestPath), { recursive: true });
2282
- await fsp4.writeFile(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
2407
+ await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
2283
2408
  return this.manifestPath;
2284
2409
  }
2285
2410
  /**
@@ -2808,9 +2933,11 @@ async function readSubagentPartial(opts, subagentId) {
2808
2933
  candidates.push(path4.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
2809
2934
  } else {
2810
2935
  try {
2811
- const runDirs = await fsp4.readdir(opts.sessionsRoot);
2812
- for (const r of runDirs) {
2813
- candidates.push(path4.join(opts.sessionsRoot, r, `${subagentId}.jsonl`));
2936
+ const entries = await fsp4.readdir(opts.sessionsRoot, { withFileTypes: true });
2937
+ for (const entry of entries) {
2938
+ if (entry.isDirectory()) {
2939
+ candidates.push(path4.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
2940
+ }
2814
2941
  }
2815
2942
  } catch {
2816
2943
  return void 0;
@@ -2860,6 +2987,7 @@ function makeAgentSubagentRunner(opts) {
2860
2987
  const detachFleet = opts.fleetBus?.attach(ctx.subagentId, events, task.id);
2861
2988
  const aborter = new AbortController();
2862
2989
  ctx.budget._events = events;
2990
+ ctx.budget.onThreshold = ({ requestDecision }) => requestDecision();
2863
2991
  let budgetError = null;
2864
2992
  const onBudgetError = (err) => {
2865
2993
  if (err instanceof BudgetThresholdSignal) {
@@ -3116,19 +3244,25 @@ var DefaultSessionStore = class {
3116
3244
  { cause: err }
3117
3245
  );
3118
3246
  }
3119
- const writer = new FileSessionWriter(
3120
- id,
3121
- handle,
3122
- (/* @__PURE__ */ new Date()).toISOString(),
3123
- {
3247
+ try {
3248
+ const writer = new FileSessionWriter(
3124
3249
  id,
3125
- model: data.metadata.model,
3126
- provider: data.metadata.provider
3127
- },
3128
- this.events,
3129
- { resumed: true, dir: this.dir, filePath: file }
3130
- );
3131
- return { writer, data };
3250
+ handle,
3251
+ (/* @__PURE__ */ new Date()).toISOString(),
3252
+ {
3253
+ id,
3254
+ model: data.metadata.model,
3255
+ provider: data.metadata.provider
3256
+ },
3257
+ this.events,
3258
+ { resumed: true, dir: this.dir, filePath: file }
3259
+ );
3260
+ return { writer, data };
3261
+ } catch (err) {
3262
+ await handle.close().catch(() => {
3263
+ });
3264
+ throw err;
3265
+ }
3132
3266
  }
3133
3267
  async load(id) {
3134
3268
  const file = path4.join(this.dir, `${id}.jsonl`);
@@ -3174,7 +3308,7 @@ var DefaultSessionStore = class {
3174
3308
  const full = path4.join(this.dir, `${id}.jsonl`);
3175
3309
  const stat3 = await fsp4.stat(full);
3176
3310
  const summary = await this.summarize(id, stat3.mtime.toISOString());
3177
- await fsp4.writeFile(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
3311
+ await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
3178
3312
  console.warn(
3179
3313
  `[session-store] Failed to write manifest for "${id}":`,
3180
3314
  err instanceof Error ? err.message : String(err)
@@ -3402,7 +3536,7 @@ var FileSessionWriter = class {
3402
3536
  this.closed = true;
3403
3537
  if (this.manifestFile) {
3404
3538
  try {
3405
- await fsp4.writeFile(this.manifestFile, JSON.stringify(this.summary), { mode: 384 });
3539
+ await atomicWrite(this.manifestFile, JSON.stringify(this.summary), { mode: 384 });
3406
3540
  } catch {
3407
3541
  }
3408
3542
  }
@@ -3676,7 +3810,7 @@ var FleetManager = class {
3676
3810
  usage: this.usage.snapshot()
3677
3811
  };
3678
3812
  await fsp4.mkdir(path4.dirname(this.manifestPath), { recursive: true });
3679
- await fsp4.writeFile(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
3813
+ await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
3680
3814
  return this.manifestPath;
3681
3815
  }
3682
3816
  /**
@@ -3696,7 +3830,13 @@ var FleetManager = class {
3696
3830
  if (this.manifestTimer) return;
3697
3831
  this.manifestTimer = setTimeout(() => {
3698
3832
  this.manifestTimer = null;
3699
- void this.writeManifest().catch(() => void 0);
3833
+ void this.writeManifest().catch((err) => {
3834
+ const detail = err instanceof Error ? err.message : String(err);
3835
+ process.emitWarning(
3836
+ `FleetManager manifest write failed: ${detail}`,
3837
+ "FleetManagerWarning"
3838
+ );
3839
+ });
3700
3840
  }, this.manifestDebounceMs);
3701
3841
  }
3702
3842
  /** Best-effort session event writer. Swallows failures. */