@cydm/pie 1.0.11 → 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-H6PTIABA.js";
5
- import "../../../chunks/chunk-QACYLY3B.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-H6PTIABA.js";
11
- import "../../../chunks/chunk-QACYLY3B.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-GNHANWYT.js";
4
+ } from "../../../chunks/chunk-YLOLJRLJ.js";
5
5
  import {
6
6
  createSharedFileSystemTools,
7
7
  createSubagentCapability
8
- } from "../../../chunks/chunk-H6PTIABA.js";
9
- import "../../../chunks/chunk-QACYLY3B.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-H6PTIABA.js";
11
- import "../../../chunks/chunk-QACYLY3B.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);
@@ -8,7 +8,7 @@ import {
8
8
  getFileSystem,
9
9
  getPlatformConfig,
10
10
  streamSimple
11
- } from "./chunk-QACYLY3B.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}.${Date.now()}.${Math.random().toString(36).slice(2)}.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
@@ -8,10 +8,10 @@ import {
8
8
  createSharedWebSearchTool,
9
9
  interpretShellExit,
10
10
  requestInteraction
11
- } from "./chunk-H6PTIABA.js";
11
+ } from "./chunk-SW6G4XW2.js";
12
12
  import {
13
13
  Type
14
- } from "./chunk-QACYLY3B.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-QACYLY3B.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-GNHANWYT.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-H6PTIABA.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-QACYLY3B.js";
89
+ } from "./chunks/chunk-D7NAXU7F.js";
90
90
  import {
91
91
  resolveCliProjectRoot
92
92
  } from "./chunks/chunk-NTYHFBUA.js";
@@ -65347,7 +65347,7 @@ var InteractiveMode = class {
65347
65347
  if (savedLevel) {
65348
65348
  this.thinkingLevel = savedLevel;
65349
65349
  }
65350
- const { Agent } = await import("./chunks/src-M32UEGIU.js");
65350
+ const { Agent } = await import("./chunks/src-LZC56DRG.js");
65351
65351
  const activeSession = this.sessionManager.getActiveSession();
65352
65352
  this.agent = new Agent({
65353
65353
  initialState: {
@@ -67340,7 +67340,7 @@ async function startChat(initialPrompt, testCommand) {
67340
67340
  `);
67341
67341
  console.log("Assistant: ");
67342
67342
  }
67343
- const { Agent } = await import("./chunks/src-M32UEGIU.js");
67343
+ const { Agent } = await import("./chunks/src-LZC56DRG.js");
67344
67344
  let agent;
67345
67345
  const printModeExtensions = await loadPrintModeExtensions({
67346
67346
  cwd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/pie",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Pie AI Agent CLI",
5
5
  "type": "module",
6
6
  "bin": {