@cydm/pie 1.0.10 → 1.0.12

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,8 +1,8 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createAskUserCapability
4
- } from "../../../chunks/chunk-EJGQAAKS.js";
5
- import "../../../chunks/chunk-A5JSJAPK.js";
4
+ } from "../../../chunks/chunk-SW6G4XW2.js";
5
+ import "../../../chunks/chunk-D7NAXU7F.js";
6
6
  import "../../../chunks/chunk-TG2EQLX2.js";
7
7
 
8
8
  // builtin/extensions/ask-user/index.ts
@@ -7,8 +7,8 @@ import {
7
7
  isPlanModeSafeCommand,
8
8
  markCompletedPlanSteps,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-EJGQAAKS.js";
11
- import "../../../chunks/chunk-A5JSJAPK.js";
10
+ } from "../../../chunks/chunk-SW6G4XW2.js";
11
+ import "../../../chunks/chunk-D7NAXU7F.js";
12
12
  import "../../../chunks/chunk-TG2EQLX2.js";
13
13
 
14
14
  // builtin/extensions/plan-mode/index.ts
@@ -1,12 +1,12 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  createCliHostCapabilities
4
- } from "../../../chunks/chunk-R2HMYSEK.js";
4
+ } from "../../../chunks/chunk-YLOLJRLJ.js";
5
5
  import {
6
6
  createSharedFileSystemTools,
7
7
  createSubagentCapability
8
- } from "../../../chunks/chunk-EJGQAAKS.js";
9
- import "../../../chunks/chunk-A5JSJAPK.js";
8
+ } from "../../../chunks/chunk-SW6G4XW2.js";
9
+ import "../../../chunks/chunk-D7NAXU7F.js";
10
10
  import "../../../chunks/chunk-TG2EQLX2.js";
11
11
 
12
12
  // builtin/extensions/subagent/index.ts
@@ -7,8 +7,8 @@ import {
7
7
  executeManageTodoList,
8
8
  executionStateToTodos,
9
9
  restoreExecutionState
10
- } from "../../../chunks/chunk-EJGQAAKS.js";
11
- import "../../../chunks/chunk-A5JSJAPK.js";
10
+ } from "../../../chunks/chunk-SW6G4XW2.js";
11
+ import "../../../chunks/chunk-D7NAXU7F.js";
12
12
  import "../../../chunks/chunk-TG2EQLX2.js";
13
13
 
14
14
  // builtin/extensions/todo/index.ts
@@ -3758,6 +3758,7 @@ var NodeHttpClient = class {
3758
3758
  async request(url, options = {}) {
3759
3759
  const requestStartTime = Date.now();
3760
3760
  const requestId = `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
3761
+ const requestTimeoutMs = options.timeoutMs ?? 6e4;
3761
3762
  logHttp("DEBUG", `Request [${requestId}] started`, {
3762
3763
  url: url.slice(0, 100),
3763
3764
  method: options.method || "GET",
@@ -3857,13 +3858,32 @@ var NodeHttpClient = class {
3857
3858
  let done = false;
3858
3859
  let error = null;
3859
3860
  let waiting = null;
3860
- const flushBuffer = () => {
3861
+ const wake = (value) => {
3862
+ if (!waiting) return;
3863
+ const w = waiting;
3864
+ waiting = null;
3865
+ w(value);
3866
+ };
3867
+ const failStream = (e) => {
3868
+ if (done && error) return;
3869
+ error = e;
3870
+ done = true;
3871
+ wake({ done: true, value: void 0 });
3872
+ logHttp("ERROR", `Request [${requestId}] SSE stream error`, { error: e.message });
3873
+ };
3874
+ const flushBuffer = (final = false) => {
3861
3875
  if (bufferLength === 0) return;
3862
3876
  const buffer = Buffer.concat(bufferChunks, bufferLength);
3863
3877
  const bufferStr = buffer.toString("utf-8");
3864
3878
  const lines = bufferStr.split("\n");
3865
3879
  const lastLine = lines.pop();
3866
- if (lastLine !== void 0) {
3880
+ if (final) {
3881
+ if (lastLine !== void 0 && lastLine.length > 0) {
3882
+ lines.push(lastLine);
3883
+ }
3884
+ bufferChunks = [];
3885
+ bufferLength = 0;
3886
+ } else if (lastLine !== void 0) {
3867
3887
  bufferChunks = [Buffer.from(lastLine)];
3868
3888
  bufferLength = lastLine.length;
3869
3889
  } else {
@@ -3874,10 +3894,17 @@ var NodeHttpClient = class {
3874
3894
  lineQueue.push(line);
3875
3895
  }
3876
3896
  };
3897
+ let abortHandler = null;
3877
3898
  if (signal) {
3878
- signal.addEventListener("abort", () => {
3879
- res.destroy();
3880
- }, { once: true });
3899
+ abortHandler = () => {
3900
+ failStream(new Error("Request was aborted"));
3901
+ res.destroy(new Error("Request was aborted"));
3902
+ };
3903
+ if (signal.aborted) {
3904
+ abortHandler();
3905
+ } else {
3906
+ signal.addEventListener("abort", abortHandler, { once: true });
3907
+ }
3881
3908
  }
3882
3909
  res.on("data", (chunk) => {
3883
3910
  totalBytes += chunk.length;
@@ -3886,22 +3913,18 @@ var NodeHttpClient = class {
3886
3913
  if (bufferLength > 16384 || chunk.includes(10)) {
3887
3914
  flushBuffer();
3888
3915
  }
3889
- if (waiting) {
3890
- const w = waiting;
3891
- waiting = null;
3892
- w({ done: false, value: void 0 });
3893
- }
3916
+ wake({ done: false, value: void 0 });
3894
3917
  });
3895
3918
  res.on("end", () => {
3896
3919
  if (bufferLength > 0) {
3897
- flushBuffer();
3920
+ flushBuffer(true);
3898
3921
  }
3899
- done = true;
3900
- if (waiting) {
3901
- const w = waiting;
3902
- waiting = null;
3903
- w({ done: true, value: void 0 });
3922
+ if (!res.complete) {
3923
+ failStream(new Error("SSE stream ended before response completed"));
3924
+ return;
3904
3925
  }
3926
+ done = true;
3927
+ wake({ done: true, value: void 0 });
3905
3928
  logHttp("DEBUG", `Request [${requestId}] SSE stream ended`, {
3906
3929
  totalBytes,
3907
3930
  lineCount,
@@ -3909,14 +3932,15 @@ var NodeHttpClient = class {
3909
3932
  });
3910
3933
  });
3911
3934
  res.on("error", (e) => {
3912
- error = e;
3913
- done = true;
3914
- if (waiting) {
3915
- const w = waiting;
3916
- waiting = null;
3917
- w({ done: true, value: void 0 });
3935
+ failStream(e);
3936
+ });
3937
+ res.on("aborted", () => {
3938
+ failStream(new Error("SSE stream aborted"));
3939
+ });
3940
+ res.on("close", () => {
3941
+ if (!done || !res.complete) {
3942
+ failStream(new Error("SSE stream closed before end"));
3918
3943
  }
3919
- logHttp("ERROR", `Request [${requestId}] SSE stream error`, { error: e.message });
3920
3944
  });
3921
3945
  try {
3922
3946
  while (true) {
@@ -3936,9 +3960,12 @@ var NodeHttpClient = class {
3936
3960
  const waitResult = await new Promise((r) => {
3937
3961
  waiting = r;
3938
3962
  });
3939
- if (waitResult.done) break;
3963
+ void waitResult;
3940
3964
  }
3941
3965
  } finally {
3966
+ if (signal && abortHandler) {
3967
+ signal.removeEventListener("abort", abortHandler);
3968
+ }
3942
3969
  if (!done && !res.destroyed) {
3943
3970
  res.destroy();
3944
3971
  }
@@ -3965,6 +3992,7 @@ var NodeHttpClient = class {
3965
3992
  logHttp("ERROR", `Request [${requestId}] timeout`);
3966
3993
  req.destroy(new Error("Request timeout"));
3967
3994
  });
3995
+ req.setTimeout(requestTimeoutMs);
3968
3996
  if (options.signal) {
3969
3997
  options.signal.addEventListener("abort", () => {
3970
3998
  logHttp("DEBUG", `Request [${requestId}] aborted`);
@@ -4371,6 +4399,47 @@ var FileSystemGateway = class {
4371
4399
  const fs = nodeRequire("fs");
4372
4400
  fs.writeFileSync(path, content, encoding);
4373
4401
  }
4402
+ /**
4403
+ * Copy a file.
4404
+ */
4405
+ copyFile(source, destination) {
4406
+ if (!this.allowWrites) {
4407
+ throw new Error(`Writes not allowed: ${destination}`);
4408
+ }
4409
+ this.validatePath(source, "copy");
4410
+ this.validatePath(destination, "copy");
4411
+ const platform = detectPlatform();
4412
+ const dir = this.dirname(destination);
4413
+ this.mkdir(dir, { recursive: true });
4414
+ if (platform === "puerts" && typeof CS !== "undefined") {
4415
+ CS.System.IO.File.Copy(source, destination, true);
4416
+ return;
4417
+ }
4418
+ const fs = nodeRequire("fs");
4419
+ fs.copyFileSync(source, destination);
4420
+ }
4421
+ /**
4422
+ * Rename or move a file.
4423
+ */
4424
+ renameFile(source, destination) {
4425
+ if (!this.allowWrites) {
4426
+ throw new Error(`Writes not allowed: ${destination}`);
4427
+ }
4428
+ this.validatePath(source, "rename");
4429
+ this.validatePath(destination, "rename");
4430
+ const platform = detectPlatform();
4431
+ const dir = this.dirname(destination);
4432
+ this.mkdir(dir, { recursive: true });
4433
+ if (platform === "puerts" && typeof CS !== "undefined") {
4434
+ if (CS.System.IO.File.Exists(destination)) {
4435
+ CS.System.IO.File.Delete(destination);
4436
+ }
4437
+ CS.System.IO.File.Move(source, destination);
4438
+ return;
4439
+ }
4440
+ const fs = nodeRequire("fs");
4441
+ fs.renameSync(source, destination);
4442
+ }
4374
4443
  /**
4375
4444
  * Delete file
4376
4445
  */
@@ -4937,6 +5006,52 @@ function mapOpenAIStopReason(reason) {
4937
5006
  }
4938
5007
  }
4939
5008
 
5009
+ // ../../packages/ai/src/providers/assistant-content-validation.ts
5010
+ var EMPTY_ASSISTANT_CONTENT_ERROR = "stream ended without assistant content";
5011
+ var EMPTY_ASSISTANT_CONTENT_ERROR_CODE = "empty_assistant_content";
5012
+ var EmptyAssistantContentError = class extends Error {
5013
+ code = EMPTY_ASSISTANT_CONTENT_ERROR_CODE;
5014
+ constructor(message = EMPTY_ASSISTANT_CONTENT_ERROR) {
5015
+ super(message);
5016
+ this.name = "EmptyAssistantContentError";
5017
+ }
5018
+ };
5019
+ function hasAssistantContent(message) {
5020
+ return message.content.some((block) => {
5021
+ if (block.type === "text") {
5022
+ return block.text.trim().length > 0;
5023
+ }
5024
+ if (block.type === "thinking") {
5025
+ return block.thinking.trim().length > 0;
5026
+ }
5027
+ if (block.type === "toolCall") {
5028
+ return block.name.trim().length > 0;
5029
+ }
5030
+ return false;
5031
+ });
5032
+ }
5033
+ function assertAssistantHasContent(message) {
5034
+ if (!hasAssistantContent(message)) {
5035
+ throw new EmptyAssistantContentError();
5036
+ }
5037
+ }
5038
+ function isEmptyAssistantContentError(error) {
5039
+ return error instanceof EmptyAssistantContentError || typeof error === "object" && error !== null && "code" in error && error.code === EMPTY_ASSISTANT_CONTENT_ERROR_CODE;
5040
+ }
5041
+ function logEmptyAssistantContentError(error, model, options) {
5042
+ if (!isEmptyAssistantContentError(error)) {
5043
+ return;
5044
+ }
5045
+ getLogger().child({ module: "ai.provider" }).warn(EMPTY_ASSISTANT_CONTENT_ERROR, {
5046
+ code: EMPTY_ASSISTANT_CONTENT_ERROR_CODE,
5047
+ provider: model.provider,
5048
+ model: model.id,
5049
+ api: model.api,
5050
+ sessionId: options?.sessionId,
5051
+ metadata: options?.metadata
5052
+ });
5053
+ }
5054
+
4940
5055
  // ../../packages/ai/src/providers/openai-compat.ts
4941
5056
  var streamOpenAICompletions = (model, context, options) => {
4942
5057
  const stream = new AssistantMessageEventStream();
@@ -5172,9 +5287,11 @@ var streamOpenAICompletions = (model, context, options) => {
5172
5287
  if (output.stopReason === "aborted" || output.stopReason === "error") {
5173
5288
  throw new Error("An unknown error occurred");
5174
5289
  }
5290
+ assertAssistantHasContent(output);
5175
5291
  stream.push({ type: "done", reason: output.stopReason, message: output });
5176
5292
  stream.end();
5177
5293
  } catch (error) {
5294
+ logEmptyAssistantContentError(error, model, options);
5178
5295
  output.stopReason = options?.signal?.aborted ? "aborted" : "error";
5179
5296
  output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
5180
5297
  stream.push({ type: "error", reason: output.stopReason, error: output });
@@ -5553,9 +5670,11 @@ var streamAnthropic = (model, context, options) => {
5553
5670
  if (options?.signal?.aborted) {
5554
5671
  throw new Error("Request was aborted");
5555
5672
  }
5673
+ assertAssistantHasContent(output);
5556
5674
  stream.push({ type: "done", reason: output.stopReason, message: output });
5557
5675
  stream.end();
5558
5676
  } catch (error) {
5677
+ logEmptyAssistantContentError(error, model, options);
5559
5678
  for (const block of output.content) delete block.index;
5560
5679
  output.stopReason = options?.signal?.aborted ? "aborted" : "error";
5561
5680
  output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
@@ -9002,35 +9121,78 @@ registerApiProvider({
9002
9121
  });
9003
9122
 
9004
9123
  // ../../packages/agent-core/src/agent-loop.ts
9124
+ function createLoopErrorMessage(error, config, signal) {
9125
+ const message = error instanceof Error ? error.message : String(error);
9126
+ return {
9127
+ role: "assistant",
9128
+ content: [{ type: "text", text: "" }],
9129
+ api: config.model.api,
9130
+ provider: config.model.provider,
9131
+ model: config.model.id,
9132
+ usage: {
9133
+ input: 0,
9134
+ output: 0,
9135
+ cacheRead: 0,
9136
+ cacheWrite: 0,
9137
+ totalTokens: 0,
9138
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
9139
+ },
9140
+ stopReason: signal?.aborted ? "aborted" : "error",
9141
+ errorMessage: message,
9142
+ timestamp: Date.now()
9143
+ };
9144
+ }
9145
+ async function notifyOnError(config, error, phase) {
9146
+ try {
9147
+ await config.hooks?.onError?.(error instanceof Error ? error : new Error(String(error)), { phase });
9148
+ } catch (hookError) {
9149
+ console.warn(`[AgentLoop] onError hook failed during ${phase}:`, hookError);
9150
+ }
9151
+ }
9152
+ function endStreamWithError(stream, newMessages, config, signal, error) {
9153
+ const errorMessage = createLoopErrorMessage(error, config, signal);
9154
+ newMessages.push(errorMessage);
9155
+ stream.push({ type: "message_start", message: errorMessage });
9156
+ stream.push({ type: "message_end", message: errorMessage });
9157
+ stream.push({ type: "turn_end", message: errorMessage, toolResults: [] });
9158
+ stream.push({ type: "agent_end", messages: newMessages });
9159
+ stream.end(newMessages);
9160
+ }
9005
9161
  function agentLoop(prompts, context, config, signal, streamFn) {
9006
9162
  const stream = createAgentStream();
9007
9163
  (async () => {
9008
- try {
9009
- await config.hooks?.beforeAgentStart?.();
9010
- } catch (e) {
9011
- console.warn("[AgentLoop] beforeAgentStart hook failed:", e);
9012
- }
9013
9164
  const newMessages = [...prompts];
9014
- const currentContext = {
9015
- ...context,
9016
- messages: [...context.messages, ...prompts]
9017
- };
9018
- stream.push({ type: "agent_start" });
9019
- stream.push({ type: "turn_start" });
9020
- for (const prompt of prompts) {
9021
- stream.push({ type: "message_start", message: prompt });
9022
- stream.push({ type: "message_end", message: prompt });
9023
- }
9024
9165
  try {
9025
- await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
9166
+ try {
9167
+ await config.hooks?.beforeAgentStart?.();
9168
+ } catch (e) {
9169
+ console.warn("[AgentLoop] beforeAgentStart hook failed:", e);
9170
+ }
9171
+ const currentContext = {
9172
+ ...context,
9173
+ messages: [...context.messages, ...prompts]
9174
+ };
9175
+ stream.push({ type: "agent_start" });
9176
+ stream.push({ type: "turn_start" });
9177
+ for (const prompt of prompts) {
9178
+ stream.push({ type: "message_start", message: prompt });
9179
+ stream.push({ type: "message_end", message: prompt });
9180
+ }
9181
+ try {
9182
+ await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
9183
+ } catch (error) {
9184
+ await notifyOnError(config, error, "runLoop");
9185
+ endStreamWithError(stream, newMessages, config, signal, error);
9186
+ return;
9187
+ }
9188
+ try {
9189
+ await config.hooks?.afterAgentEnd?.(newMessages);
9190
+ } catch (e) {
9191
+ console.warn("[AgentLoop] afterAgentEnd hook failed:", e);
9192
+ }
9026
9193
  } catch (error) {
9027
- config.hooks?.onError?.(error, { phase: "runLoop" });
9028
- throw error;
9029
- }
9030
- try {
9031
- await config.hooks?.afterAgentEnd?.(newMessages);
9032
- } catch (e) {
9033
- console.warn("[AgentLoop] afterAgentEnd hook failed:", e);
9194
+ await notifyOnError(config, error, "agentLoop");
9195
+ endStreamWithError(stream, newMessages, config, signal, error);
9034
9196
  }
9035
9197
  })();
9036
9198
  return stream;
@@ -9044,25 +9206,31 @@ function agentLoopContinue(context, config, signal, streamFn) {
9044
9206
  }
9045
9207
  const stream = createAgentStream();
9046
9208
  (async () => {
9047
- try {
9048
- await config.hooks?.beforeAgentStart?.();
9049
- } catch (e) {
9050
- console.warn("[AgentLoop] beforeAgentStart hook failed:", e);
9051
- }
9052
9209
  const newMessages = [];
9053
- const currentContext = { ...context };
9054
- stream.push({ type: "agent_start" });
9055
- stream.push({ type: "turn_start" });
9056
9210
  try {
9057
- await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
9211
+ try {
9212
+ await config.hooks?.beforeAgentStart?.();
9213
+ } catch (e) {
9214
+ console.warn("[AgentLoop] beforeAgentStart hook failed:", e);
9215
+ }
9216
+ const currentContext = { ...context };
9217
+ stream.push({ type: "agent_start" });
9218
+ stream.push({ type: "turn_start" });
9219
+ try {
9220
+ await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
9221
+ } catch (error) {
9222
+ await notifyOnError(config, error, "runLoop");
9223
+ endStreamWithError(stream, newMessages, config, signal, error);
9224
+ return;
9225
+ }
9226
+ try {
9227
+ await config.hooks?.afterAgentEnd?.(newMessages);
9228
+ } catch (e) {
9229
+ console.warn("[AgentLoop] afterAgentEnd hook failed:", e);
9230
+ }
9058
9231
  } catch (error) {
9059
- config.hooks?.onError?.(error, { phase: "runLoop" });
9060
- throw error;
9061
- }
9062
- try {
9063
- await config.hooks?.afterAgentEnd?.(newMessages);
9064
- } catch (e) {
9065
- console.warn("[AgentLoop] afterAgentEnd hook failed:", e);
9232
+ await notifyOnError(config, error, "agentLoopContinue");
9233
+ endStreamWithError(stream, newMessages, config, signal, error);
9066
9234
  }
9067
9235
  })();
9068
9236
  return stream;
@@ -9098,7 +9266,7 @@ async function runLoop(currentContext, newMessages, config, signal, stream, stre
9098
9266
  try {
9099
9267
  message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);
9100
9268
  } catch (error) {
9101
- config.hooks?.onError?.(error, { phase: "streamAssistantResponse" });
9269
+ await notifyOnError(config, error, "streamAssistantResponse");
9102
9270
  throw error;
9103
9271
  }
9104
9272
  newMessages.push(message);
@@ -9274,10 +9442,14 @@ async function executeToolCalls(tools, assistantMessage, signal, stream, getStee
9274
9442
  details: {}
9275
9443
  };
9276
9444
  isError = true;
9277
- hooks?.onError?.(e instanceof Error ? e : new Error(String(e)), {
9278
- toolName: toolCall.name,
9279
- phase: "toolExecution"
9280
- });
9445
+ try {
9446
+ await hooks?.onError?.(e instanceof Error ? e : new Error(String(e)), {
9447
+ toolName: toolCall.name,
9448
+ phase: "toolExecution"
9449
+ });
9450
+ } catch (hookError) {
9451
+ console.warn(`[AgentLoop] onError hook failed during toolExecution for ${toolCall.name}:`, hookError);
9452
+ }
9281
9453
  }
9282
9454
  }
9283
9455
  try {
@@ -9789,15 +9961,30 @@ var Agent = class {
9789
9961
  this.abortController = void 0;
9790
9962
  }
9791
9963
  }
9964
+ reportObserverError(kind, eventType, error) {
9965
+ console.warn(`[Agent] ${kind} failed while handling ${eventType}:`, error);
9966
+ }
9792
9967
  emit(e) {
9793
9968
  for (const listener of this.listeners) {
9794
- listener(e);
9969
+ try {
9970
+ listener(e);
9971
+ } catch (error) {
9972
+ this.reportObserverError("agent event listener", e.type, error);
9973
+ }
9974
+ }
9975
+ try {
9976
+ this.emitDerivedSemanticEvents(e);
9977
+ } catch (error) {
9978
+ this.reportObserverError("derived semantic event", e.type, error);
9795
9979
  }
9796
- this.emitDerivedSemanticEvents(e);
9797
9980
  }
9798
9981
  emitSemantic(e) {
9799
9982
  for (const listener of this.semanticListeners) {
9800
- listener(e);
9983
+ try {
9984
+ listener(e);
9985
+ } catch (error) {
9986
+ this.reportObserverError("semantic event listener", e.type, error);
9987
+ }
9801
9988
  }
9802
9989
  }
9803
9990
  updateStatusSnapshot(next) {
@@ -8,7 +8,7 @@ import {
8
8
  getFileSystem,
9
9
  getPlatformConfig,
10
10
  streamSimple
11
- } from "./chunk-A5JSJAPK.js";
11
+ } from "./chunk-D7NAXU7F.js";
12
12
  import {
13
13
  __require
14
14
  } from "./chunk-TG2EQLX2.js";
@@ -374,6 +374,182 @@ function createCompactionSummaryMessage(summary, timestamp) {
374
374
  };
375
375
  }
376
376
 
377
+ // ../../packages/agent-framework/src/session/durable-file.ts
378
+ var DEFAULT_FILE_RETRY_DELAYS_MS = [0, 25, 75, 150];
379
+ function durableFilePaths(filePath) {
380
+ return {
381
+ main: filePath,
382
+ backup: `${filePath}.bak`,
383
+ previous: `${filePath}.prev`
384
+ };
385
+ }
386
+ function isTransientFileError(error) {
387
+ const code = typeof error === "object" && error && "code" in error ? String(error.code) : "";
388
+ const message = error instanceof Error ? error.message : String(error);
389
+ return /^(EPERM|EACCES|EBUSY|ENOTEMPTY)$/.test(code) || /\b(EPERM|EACCES|EBUSY|locked|busy)\b/i.test(message);
390
+ }
391
+ function sleep(ms) {
392
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
393
+ }
394
+ async function retryFileOperation(operation, retryDelaysMs) {
395
+ let lastError;
396
+ for (const [index, delayMs] of retryDelaysMs.entries()) {
397
+ if (delayMs > 0) {
398
+ await sleep(delayMs);
399
+ }
400
+ try {
401
+ operation();
402
+ return;
403
+ } catch (error) {
404
+ lastError = error;
405
+ if (!isTransientFileError(error) || index === retryDelaysMs.length - 1) {
406
+ throw error;
407
+ }
408
+ }
409
+ }
410
+ throw lastError;
411
+ }
412
+ function retryDelays(options) {
413
+ return options.retryDelaysMs ?? DEFAULT_FILE_RETRY_DELAYS_MS;
414
+ }
415
+ function tempPathFor(filePath, operation) {
416
+ return `${filePath}.${operation}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
417
+ }
418
+ async function replaceFile(gateway, filePath, content, retryDelaysMs) {
419
+ const tempPath = tempPathFor(filePath, "durable");
420
+ gateway.writeFile(tempPath, content, "utf-8");
421
+ try {
422
+ try {
423
+ await retryFileOperation(() => gateway.renameFile(tempPath, filePath), retryDelaysMs);
424
+ } catch {
425
+ await retryFileOperation(() => gateway.copyFile(tempPath, filePath), retryDelaysMs);
426
+ try {
427
+ gateway.deleteFile(tempPath);
428
+ } catch {
429
+ }
430
+ }
431
+ } catch (error) {
432
+ try {
433
+ gateway.deleteFile(tempPath);
434
+ } catch {
435
+ }
436
+ throw error;
437
+ }
438
+ }
439
+ async function copyExistingFile(gateway, sourcePath, destinationPath, retryDelaysMs) {
440
+ if (!gateway.exists(sourcePath)) {
441
+ return false;
442
+ }
443
+ await retryFileOperation(() => gateway.copyFile(sourcePath, destinationPath), retryDelaysMs);
444
+ return true;
445
+ }
446
+ function readCandidate(options, role, path3) {
447
+ if (!options.gateway.exists(path3)) {
448
+ return null;
449
+ }
450
+ const rawContent = options.gateway.readFile(path3, "utf-8");
451
+ const parsed = options.parse(rawContent, path3);
452
+ const updatedAt = Number.isFinite(parsed.updatedAt) ? parsed.updatedAt : 0;
453
+ return {
454
+ ...parsed,
455
+ updatedAt,
456
+ role,
457
+ path: path3,
458
+ rawContent
459
+ };
460
+ }
461
+ function candidatePriority(role) {
462
+ if (role === "main") return 3;
463
+ if (role === "backup") return 2;
464
+ return 1;
465
+ }
466
+ function chooseBestCandidate(candidates) {
467
+ return [...candidates].sort((a, b) => {
468
+ const updatedAtDiff = b.updatedAt - a.updatedAt;
469
+ if (updatedAtDiff !== 0) return updatedAtDiff;
470
+ return candidatePriority(b.role) - candidatePriority(a.role);
471
+ })[0];
472
+ }
473
+ async function writeDurableFile(options, content) {
474
+ const parsed = options.parse(content, options.filePath);
475
+ const durableContent = parsed.content;
476
+ const paths = durableFilePaths(options.filePath);
477
+ const delays = retryDelays(options);
478
+ if (options.gateway.exists(paths.backup)) {
479
+ await copyExistingFile(options.gateway, paths.backup, paths.previous, delays);
480
+ }
481
+ await replaceFile(options.gateway, paths.backup, durableContent, delays);
482
+ await replaceFile(options.gateway, paths.main, durableContent, delays);
483
+ }
484
+ async function loadDurableFile(options) {
485
+ const paths = durableFilePaths(options.filePath);
486
+ const roles = [
487
+ ["main", paths.main],
488
+ ["backup", paths.backup],
489
+ ["previous", paths.previous]
490
+ ];
491
+ const candidates = [];
492
+ for (const [role, path3] of roles) {
493
+ try {
494
+ const candidate = readCandidate(options, role, path3);
495
+ if (candidate) {
496
+ candidates.push(candidate);
497
+ }
498
+ } catch {
499
+ }
500
+ }
501
+ if (candidates.length === 0) {
502
+ return null;
503
+ }
504
+ const best = chooseBestCandidate(candidates);
505
+ const main = candidates.find((candidate) => candidate.role === "main");
506
+ const backup = candidates.find((candidate) => candidate.role === "backup");
507
+ const needsMainRestore = !main || main.rawContent !== best.content;
508
+ const needsBackupRefresh = !backup || backup.rawContent !== best.content;
509
+ let restoredMain = false;
510
+ let refreshedBackup = false;
511
+ let repairError;
512
+ const delays = retryDelays(options);
513
+ try {
514
+ if (needsBackupRefresh) {
515
+ if (backup && backup.rawContent !== best.content) {
516
+ await replaceFile(options.gateway, paths.previous, backup.content, delays);
517
+ }
518
+ await replaceFile(options.gateway, paths.backup, best.content, delays);
519
+ refreshedBackup = true;
520
+ }
521
+ if (needsMainRestore) {
522
+ await replaceFile(options.gateway, paths.main, best.content, delays);
523
+ restoredMain = true;
524
+ }
525
+ } catch (error) {
526
+ repairError = error;
527
+ }
528
+ return {
529
+ data: best.data,
530
+ content: best.content,
531
+ source: best.role,
532
+ restoredMain,
533
+ refreshedBackup,
534
+ repairError
535
+ };
536
+ }
537
+ function durableFileExists(gateway, filePath) {
538
+ const paths = durableFilePaths(filePath);
539
+ return gateway.exists(paths.main) || gateway.exists(paths.backup) || gateway.exists(paths.previous);
540
+ }
541
+ function deleteDurableFile(gateway, filePath) {
542
+ const paths = durableFilePaths(filePath);
543
+ let deleted = false;
544
+ for (const path3 of [paths.main, paths.backup, paths.previous]) {
545
+ if (gateway.exists(path3)) {
546
+ gateway.deleteFile(path3);
547
+ deleted = true;
548
+ }
549
+ }
550
+ return deleted;
551
+ }
552
+
377
553
  // ../../packages/agent-framework/src/session/store.ts
378
554
  var SESSION_VERSION = 2;
379
555
  function isSessionEntry(value) {
@@ -434,28 +610,6 @@ function migrateV1ToV2(data) {
434
610
  // Keep for backward compatibility
435
611
  };
436
612
  }
437
- function writeFileAtomic(gateway, filePath, content) {
438
- const tempPath = filePath + ".tmp";
439
- gateway.writeFile(tempPath, content, "utf-8");
440
- try {
441
- const req = globalThis.require;
442
- if (typeof req === "function") {
443
- req("fs").renameSync(tempPath, filePath);
444
- } else {
445
- gateway.writeFile(filePath, content, "utf-8");
446
- try {
447
- gateway.deleteFile(tempPath);
448
- } catch {
449
- }
450
- }
451
- } catch {
452
- gateway.writeFile(filePath, content, "utf-8");
453
- try {
454
- gateway.deleteFile(tempPath);
455
- } catch {
456
- }
457
- }
458
- }
459
613
  var FileSessionStore = class {
460
614
  sessionsDir;
461
615
  gateway;
@@ -485,6 +639,33 @@ var FileSessionStore = class {
485
639
  const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
486
640
  return this.gateway.join(this.sessionsDir, `${safeId}.json`);
487
641
  }
642
+ normalizeLoadedData(data) {
643
+ if (data.version === LEGACY_VERSION || !data.version) {
644
+ return { data: migrateV1ToV2(data), shouldPersist: true };
645
+ }
646
+ if (data.version !== SESSION_VERSION) {
647
+ console.warn(
648
+ `[SessionStore] Session version mismatch: ${data.version} vs ${SESSION_VERSION}`
649
+ );
650
+ }
651
+ if (!data.entries) {
652
+ data.entries = [];
653
+ }
654
+ return { data, shouldPersist: false };
655
+ }
656
+ parseSessionContent(content, filePath) {
657
+ if (!content || content.trim().length === 0) {
658
+ throw new Error("empty session file");
659
+ }
660
+ const parsed = JSON.parse(content);
661
+ const normalized = this.normalizeLoadedData(parsed);
662
+ const persistedContent = normalized.shouldPersist ? JSON.stringify(normalized.data, null, 2) : content;
663
+ return {
664
+ data: normalized.data,
665
+ content: persistedContent,
666
+ updatedAt: normalized.data.metadata?.updatedAt ?? 0
667
+ };
668
+ }
488
669
  /**
489
670
  * Save a session to disk (v2 format)
490
671
  */
@@ -514,7 +695,11 @@ var FileSessionStore = class {
514
695
  };
515
696
  const json = JSON.stringify(sessionData, null, 2);
516
697
  const filePath = this.getSessionPath(sessionId);
517
- writeFileAtomic(this.gateway, filePath, json);
698
+ await writeDurableFile({
699
+ gateway: this.gateway,
700
+ filePath,
701
+ parse: (content, path3) => this.parseSessionContent(content, path3)
702
+ }, json);
518
703
  }
519
704
  /**
520
705
  * Legacy save method for backward compatibility
@@ -542,32 +727,23 @@ var FileSessionStore = class {
542
727
  */
543
728
  async load(sessionId) {
544
729
  const filePath = this.getSessionPath(sessionId);
545
- if (!this.gateway.exists(filePath)) {
546
- return null;
547
- }
548
730
  try {
549
- const json = this.gateway.readFile(filePath, "utf-8");
550
- if (!json || json.trim().length === 0) {
551
- console.warn(`[SessionStore] Empty session file: ${sessionId}, removing`);
552
- this.gateway.deleteFile(filePath);
731
+ const loaded = await loadDurableFile({
732
+ gateway: this.gateway,
733
+ filePath,
734
+ parse: (content, path3) => this.parseSessionContent(content, path3)
735
+ });
736
+ if (!loaded) {
553
737
  return null;
554
738
  }
555
- const data = JSON.parse(json);
556
- if (data.version === LEGACY_VERSION || !data.version) {
557
- const migrated = migrateV1ToV2(data);
558
- const migratedJson = JSON.stringify(migrated, null, 2);
559
- writeFileAtomic(this.gateway, filePath, migratedJson);
560
- return migrated;
561
- }
562
- if (data.version !== SESSION_VERSION) {
739
+ if (loaded.restoredMain || loaded.refreshedBackup) {
563
740
  console.warn(
564
- `[SessionStore] Session version mismatch: ${data.version} vs ${SESSION_VERSION}`
741
+ `[SessionStore] Repaired session ${sessionId} from ${loaded.source}` + (loaded.repairError ? ` with repair warning: ${loaded.repairError}` : "")
565
742
  );
743
+ } else if (loaded.repairError) {
744
+ console.warn(`[SessionStore] Loaded session ${sessionId} but sidecar refresh failed: ${loaded.repairError}`);
566
745
  }
567
- if (!data.entries) {
568
- data.entries = [];
569
- }
570
- return data;
746
+ return loaded.data;
571
747
  } catch (e) {
572
748
  console.error(`[SessionStore] Failed to load session: ${sessionId}`, e);
573
749
  return null;
@@ -578,12 +754,8 @@ var FileSessionStore = class {
578
754
  */
579
755
  async delete(sessionId) {
580
756
  const filePath = this.getSessionPath(sessionId);
581
- if (!this.gateway.exists(filePath)) {
582
- return false;
583
- }
584
757
  try {
585
- this.gateway.deleteFile(filePath);
586
- return true;
758
+ return deleteDurableFile(this.gateway, filePath);
587
759
  } catch (e) {
588
760
  console.error(`[SessionStore] Failed to delete session: ${sessionId}`, e);
589
761
  return false;
@@ -594,7 +766,7 @@ var FileSessionStore = class {
594
766
  */
595
767
  async exists(sessionId) {
596
768
  const filePath = this.getSessionPath(sessionId);
597
- return this.gateway.exists(filePath);
769
+ return durableFileExists(this.gateway, filePath);
598
770
  }
599
771
  /**
600
772
  * List all session IDs
@@ -604,7 +776,20 @@ var FileSessionStore = class {
604
776
  return [];
605
777
  }
606
778
  const files = this.gateway.readdir(this.sessionsDir);
607
- return files.filter((f) => f.endsWith(".json")).filter((f) => !f.endsWith("-files.json")).map((f) => f.replace(/\.json$/i, ""));
779
+ const sessionIds = /* @__PURE__ */ new Set();
780
+ for (const file of files) {
781
+ if (file.endsWith("-files.json") || file.endsWith("-files.json.bak") || file.endsWith("-files.json.prev")) {
782
+ continue;
783
+ }
784
+ if (file.endsWith(".json")) {
785
+ sessionIds.add(file.replace(/\.json$/i, ""));
786
+ } else if (file.endsWith(".json.bak")) {
787
+ sessionIds.add(file.replace(/\.json\.bak$/i, ""));
788
+ } else if (file.endsWith(".json.prev")) {
789
+ sessionIds.add(file.replace(/\.json\.prev$/i, ""));
790
+ }
791
+ }
792
+ return [...sessionIds];
608
793
  }
609
794
  /**
610
795
  * List all session metadata
@@ -1230,6 +1415,8 @@ function summarizeToolResultForGuard(result) {
1230
1415
  const text = content.filter((block) => !!block && typeof block === "object" && "type" in block).filter((block) => block.type === "text").map((block) => block.text || "").join("\n").trim();
1231
1416
  return text || stableStringify(result);
1232
1417
  }
1418
+ var RUNAWAY_TOOLCALL_WHITESPACE_DELTA_CHARS = 16384;
1419
+ var RUNAWAY_TOOLCALL_WHITESPACE_DELTA_EVENTS = 40;
1233
1420
  function cloneQueuedInput(input) {
1234
1421
  return {
1235
1422
  ...input,
@@ -1262,6 +1449,10 @@ var AgentSessionController = class {
1262
1449
  pendingAutoCompact;
1263
1450
  queueIdCounter = 0;
1264
1451
  repeatedToolFailures = /* @__PURE__ */ new Map();
1452
+ streamGuard = {
1453
+ whitespaceToolCallDeltaChars: 0,
1454
+ whitespaceToolCallDeltaEvents: 0
1455
+ };
1265
1456
  runtimeGuardTriggered = false;
1266
1457
  constructor(options) {
1267
1458
  this.agent = options.agent;
@@ -1285,6 +1476,9 @@ var AgentSessionController = class {
1285
1476
  this.resetRuntimeGuardState();
1286
1477
  this.emit({ type: "streaming_changed", isStreaming: true });
1287
1478
  }
1479
+ if (event.type === "message_update") {
1480
+ this.recordMessageUpdateForGuard(event);
1481
+ }
1288
1482
  if (event.type === "tool_execution_end") {
1289
1483
  this.recordToolExecutionEndForGuard(event);
1290
1484
  }
@@ -1879,8 +2073,52 @@ var AgentSessionController = class {
1879
2073
  }
1880
2074
  resetRuntimeGuardState() {
1881
2075
  this.repeatedToolFailures.clear();
2076
+ this.streamGuard = {
2077
+ whitespaceToolCallDeltaChars: 0,
2078
+ whitespaceToolCallDeltaEvents: 0
2079
+ };
1882
2080
  this.runtimeGuardTriggered = false;
1883
2081
  }
2082
+ triggerRuntimeGuard(toolName, repeatCount, reason) {
2083
+ if (this.runtimeGuardTriggered) {
2084
+ return;
2085
+ }
2086
+ this.runtimeGuardTriggered = true;
2087
+ this.cancelRetry();
2088
+ this.cancelAutoCompactTimerOnly();
2089
+ this.cancelDispatchTimerOnly();
2090
+ this.cancelAutoContinueTimerOnly();
2091
+ this.emit({ type: "runtime_guard_triggered", toolName, repeatCount, reason });
2092
+ this.agent.abort();
2093
+ }
2094
+ recordMessageUpdateForGuard(event) {
2095
+ if (this.runtimeGuardTriggered) {
2096
+ return;
2097
+ }
2098
+ const assistantEvent = event.assistantMessageEvent;
2099
+ if (assistantEvent.type !== "toolcall_delta") {
2100
+ this.streamGuard.whitespaceToolCallDeltaChars = 0;
2101
+ this.streamGuard.whitespaceToolCallDeltaEvents = 0;
2102
+ return;
2103
+ }
2104
+ if (assistantEvent.delta.trim().length > 0) {
2105
+ this.streamGuard.whitespaceToolCallDeltaChars = 0;
2106
+ this.streamGuard.whitespaceToolCallDeltaEvents = 0;
2107
+ return;
2108
+ }
2109
+ this.streamGuard.whitespaceToolCallDeltaChars += assistantEvent.delta.length;
2110
+ this.streamGuard.whitespaceToolCallDeltaEvents += 1;
2111
+ const content = event.message.role === "assistant" && Array.isArray(event.message.content) ? event.message.content[assistantEvent.contentIndex] : void 0;
2112
+ const partialArgs = typeof content?.partialArgs === "string" ? content.partialArgs : "";
2113
+ const sparsePartialArgs = partialArgs.length >= RUNAWAY_TOOLCALL_WHITESPACE_DELTA_CHARS && partialArgs.replace(/\s/g, "").length / partialArgs.length < 0.05;
2114
+ if (sparsePartialArgs || this.streamGuard.whitespaceToolCallDeltaChars >= RUNAWAY_TOOLCALL_WHITESPACE_DELTA_CHARS && this.streamGuard.whitespaceToolCallDeltaEvents >= RUNAWAY_TOOLCALL_WHITESPACE_DELTA_EVENTS) {
2115
+ this.triggerRuntimeGuard(
2116
+ "assistant_stream",
2117
+ this.streamGuard.whitespaceToolCallDeltaEvents,
2118
+ "runaway_tool_call_arguments"
2119
+ );
2120
+ }
2121
+ }
1884
2122
  recordToolExecutionEndForGuard(event) {
1885
2123
  if (!event.isError) {
1886
2124
  const prefix = `${event.toolName}:`;
@@ -1898,14 +2136,7 @@ var AgentSessionController = class {
1898
2136
  if (repeatCount < 3 || this.runtimeGuardTriggered) {
1899
2137
  return;
1900
2138
  }
1901
- this.runtimeGuardTriggered = true;
1902
- this.cancelRetry();
1903
- this.cancelAutoCompactTimerOnly();
1904
- this.cancelDispatchTimerOnly();
1905
- this.cancelAutoContinueTimerOnly();
1906
- const reason = "repeated_tool_error";
1907
- this.emit({ type: "runtime_guard_triggered", toolName: event.toolName, repeatCount, reason });
1908
- this.agent.abort();
2139
+ this.triggerRuntimeGuard(event.toolName, repeatCount, "repeated_tool_error");
1909
2140
  }
1910
2141
  emit(event) {
1911
2142
  for (const listener of this.listeners) {
@@ -3184,7 +3415,11 @@ var SessionTraceSnapshotWriter = class {
3184
3415
  this.flushTimer = null;
3185
3416
  }
3186
3417
  if (!this.cachedController || !this.cachedSessionId) return;
3187
- this.options.saveTrace(this.cachedController.getSnapshot());
3418
+ try {
3419
+ this.options.saveTrace(this.cachedController.getSnapshot());
3420
+ } catch (error) {
3421
+ console.warn("[SessionTrace] Failed to save session trace:", error);
3422
+ }
3188
3423
  }
3189
3424
  notePendingUserText(text) {
3190
3425
  this.mutate((controller) => {
@@ -3567,7 +3802,7 @@ function inferUncertainty(text, signals) {
3567
3802
  function isParentHandoffRequired(task) {
3568
3803
  return task.needsParentWrite || task.status === "timeout" || task.status === "failed" || task.confidenceSignals.some((signal) => signal.type === "tool_error" || signal.type === "no_tool_use");
3569
3804
  }
3570
- async function runSubagentWithProgress(deps, task, reportProgress) {
3805
+ async function runSubagentWithProgress(deps, task, reportProgress, signal) {
3571
3806
  const startTime = Date.now();
3572
3807
  task.status = "running";
3573
3808
  let timedOut = false;
@@ -3588,6 +3823,9 @@ async function runSubagentWithProgress(deps, task, reportProgress) {
3588
3823
  if (!apiKey) {
3589
3824
  throw new Error("No API key available for subagent execution.");
3590
3825
  }
3826
+ if (signal?.aborted) {
3827
+ throw new Error("Subagent aborted by parent");
3828
+ }
3591
3829
  deps.log(`[Subagent ${task.name}] Plan: ${plan.complexity}/${plan.modelClass}, ${tools.length} tools`);
3592
3830
  deps.debugLog?.("plan", "SubagentPlan", plan);
3593
3831
  const systemPrompt = `You are a specialized subagent focused on one bounded task.
@@ -3611,6 +3849,7 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
3611
3849
  let rejectTimeout = () => void 0;
3612
3850
  let timeout;
3613
3851
  let unsubscribe;
3852
+ let removeAbortListener;
3614
3853
  const timeoutPromise = new Promise((_, reject) => {
3615
3854
  rejectTimeout = reject;
3616
3855
  });
@@ -3620,6 +3859,19 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
3620
3859
  subagent.abort?.();
3621
3860
  rejectTimeout(new Error(timeoutMessage));
3622
3861
  }, plan.timeoutSeconds * 1e3);
3862
+ const abortPromise = new Promise((_, reject) => {
3863
+ if (!signal) return;
3864
+ const abortSubagent = () => {
3865
+ subagent.abort?.();
3866
+ reject(new Error("Subagent aborted by parent"));
3867
+ };
3868
+ if (signal.aborted) {
3869
+ abortSubagent();
3870
+ return;
3871
+ }
3872
+ signal.addEventListener("abort", abortSubagent, { once: true });
3873
+ removeAbortListener = () => signal.removeEventListener("abort", abortSubagent);
3874
+ });
3623
3875
  unsubscribe = subagent.subscribe((event) => {
3624
3876
  if (event.type === "tool_execution_start") {
3625
3877
  toolCalls++;
@@ -3654,12 +3906,14 @@ ${formatSkillsForPrompt(deps.skills ?? [])}`;
3654
3906
  await subagent.prompt(prompt);
3655
3907
  await subagent.waitForIdle?.();
3656
3908
  })(),
3657
- timeoutPromise
3909
+ timeoutPromise,
3910
+ abortPromise
3658
3911
  ]);
3659
3912
  } finally {
3660
3913
  if (timeout) {
3661
3914
  clearTimeout(timeout);
3662
3915
  }
3916
+ removeAbortListener?.();
3663
3917
  unsubscribe?.();
3664
3918
  }
3665
3919
  const messages = subagent.state.messages;
@@ -3795,9 +4049,19 @@ Use this for independent investigation, search, review, or triage work. Provide
3795
4049
  { description: "Array of tasks to run in parallel", minItems: 1, maxItems: 10 }
3796
4050
  )
3797
4051
  }, { additionalProperties: false }),
3798
- async execute(first, second) {
4052
+ async execute(first, second, third, fourth) {
3799
4053
  const args = typeof first === "string" ? second : first;
3800
- const toolContext = typeof first === "string" ? { log: deps.log } : second;
4054
+ const signal = typeof first === "string" ? third : second?.signal;
4055
+ const reportProgress = typeof first === "string" ? fourth ? (update) => {
4056
+ fourth({
4057
+ content: update.message ? [{ type: "text", text: update.message }] : [],
4058
+ details: { increment: update.increment }
4059
+ });
4060
+ } : () => void 0 : second?.reportProgress ?? (() => void 0);
4061
+ const toolContext = {
4062
+ log: typeof first === "string" ? deps.log : second?.log ?? deps.log,
4063
+ reportProgress
4064
+ };
3801
4065
  const normalized = normalizeTaskDefs(args);
3802
4066
  if ("error" in normalized) {
3803
4067
  return {
@@ -3825,7 +4089,7 @@ Use this for independent investigation, search, review, or triage work. Provide
3825
4089
  toolContext.log?.(`Spawning ${tasks.length} parallel subagents: ${tasks.map((task) => task.name).join(", ")}`);
3826
4090
  toolContext.reportProgress?.({ message: `Launching ${tasks.length} parallel subagents...`, increment: 5 });
3827
4091
  const startTime = Date.now();
3828
- await Promise.all(tasks.map((task) => runSubagentWithProgress(deps, task, toolContext.reportProgress ?? (() => void 0))));
4092
+ await Promise.all(tasks.map((task) => runSubagentWithProgress(deps, task, toolContext.reportProgress, signal)));
3829
4093
  const totalDuration = Date.now() - startTime;
3830
4094
  const completed = tasks.filter((task) => task.status === "completed").length;
3831
4095
  const failed = tasks.filter((task) => task.status === "failed" || task.status === "timeout").length;
@@ -8,10 +8,10 @@ import {
8
8
  createSharedWebSearchTool,
9
9
  interpretShellExit,
10
10
  requestInteraction
11
- } from "./chunk-EJGQAAKS.js";
11
+ } from "./chunk-SW6G4XW2.js";
12
12
  import {
13
13
  Type
14
- } from "./chunk-A5JSJAPK.js";
14
+ } from "./chunk-D7NAXU7F.js";
15
15
 
16
16
  // src/config.ts
17
17
  import { existsSync, mkdirSync, readFileSync, renameSync } from "fs";
@@ -3,7 +3,7 @@ import {
3
3
  Agent,
4
4
  agentLoop,
5
5
  agentLoopContinue
6
- } from "./chunk-A5JSJAPK.js";
6
+ } from "./chunk-D7NAXU7F.js";
7
7
  import "./chunk-TG2EQLX2.js";
8
8
  export {
9
9
  Agent,
package/dist/cli.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  getSettingsPath,
15
15
  getThemesDir,
16
16
  migrateConfigFromAgentDir
17
- } from "./chunks/chunk-R2HMYSEK.js";
17
+ } from "./chunks/chunk-YLOLJRLJ.js";
18
18
  import {
19
19
  AGENTS_CONTEXT_FILE_NAME,
20
20
  AgentSessionController,
@@ -52,7 +52,7 @@ import {
52
52
  selectToolsForRuntimePolicy,
53
53
  shouldPreserveExecutionStateForUserText,
54
54
  supersedeExecutionState
55
- } from "./chunks/chunk-EJGQAAKS.js";
55
+ } from "./chunks/chunk-SW6G4XW2.js";
56
56
  import {
57
57
  Deref,
58
58
  Errors,
@@ -86,7 +86,7 @@ import {
86
86
  setLogger,
87
87
  sortToolModelCandidatesByCapability,
88
88
  type_exports
89
- } from "./chunks/chunk-A5JSJAPK.js";
89
+ } from "./chunks/chunk-D7NAXU7F.js";
90
90
  import {
91
91
  resolveCliProjectRoot
92
92
  } from "./chunks/chunk-NTYHFBUA.js";
@@ -56031,6 +56031,27 @@ var ExecutionStateManager = class {
56031
56031
  // src/session-trace.ts
56032
56032
  import * as fs15 from "node:fs";
56033
56033
  import * as path16 from "node:path";
56034
+ function saveTraceFileBestEffort(tracePath, content) {
56035
+ const tempPath = `${tracePath}.${process.pid}.${Date.now()}.tmp`;
56036
+ try {
56037
+ fs15.writeFileSync(tempPath, content, "utf8");
56038
+ try {
56039
+ fs15.renameSync(tempPath, tracePath);
56040
+ return;
56041
+ } catch {
56042
+ try {
56043
+ fs15.copyFileSync(tempPath, tracePath);
56044
+ } catch {
56045
+ } finally {
56046
+ try {
56047
+ fs15.unlinkSync(tempPath);
56048
+ } catch {
56049
+ }
56050
+ }
56051
+ }
56052
+ } catch {
56053
+ }
56054
+ }
56034
56055
  var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
56035
56056
  constructor(sessionsDir, sessionManager) {
56036
56057
  super({
@@ -56046,9 +56067,7 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
56046
56067
  },
56047
56068
  saveTrace: (trace) => {
56048
56069
  const tracePath = path16.join(sessionsDir, `${trace.sessionId}.trace.json`);
56049
- const tempPath = `${tracePath}.tmp`;
56050
- fs15.writeFileSync(tempPath, JSON.stringify(trace, null, 2), "utf8");
56051
- fs15.renameSync(tempPath, tracePath);
56070
+ saveTraceFileBestEffort(tracePath, JSON.stringify(trace, null, 2));
56052
56071
  }
56053
56072
  });
56054
56073
  this.sessionsDir = sessionsDir;
@@ -65328,7 +65347,7 @@ var InteractiveMode = class {
65328
65347
  if (savedLevel) {
65329
65348
  this.thinkingLevel = savedLevel;
65330
65349
  }
65331
- const { Agent } = await import("./chunks/src-3X3HBT2G.js");
65350
+ const { Agent } = await import("./chunks/src-LZC56DRG.js");
65332
65351
  const activeSession = this.sessionManager.getActiveSession();
65333
65352
  this.agent = new Agent({
65334
65353
  initialState: {
@@ -67321,7 +67340,7 @@ async function startChat(initialPrompt, testCommand) {
67321
67340
  `);
67322
67341
  console.log("Assistant: ");
67323
67342
  }
67324
- const { Agent } = await import("./chunks/src-3X3HBT2G.js");
67343
+ const { Agent } = await import("./chunks/src-LZC56DRG.js");
67325
67344
  let agent;
67326
67345
  const printModeExtensions = await loadPrintModeExtensions({
67327
67346
  cwd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/pie",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {