@cydm/pie 1.0.18 → 1.0.20

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.
package/dist/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
3
3
  import {
4
+ VERSION,
4
5
  createCliHostCapabilities,
5
6
  createCliWebResearchHealthStore,
6
7
  getAgentDir,
@@ -14,11 +15,12 @@ import {
14
15
  getSettingsPath,
15
16
  getThemesDir,
16
17
  migrateConfigFromAgentDir
17
- } from "./chunks/chunk-MHFUWY7I.js";
18
+ } from "./chunks/chunk-ZYOTRKU7.js";
18
19
  import {
19
20
  AGENTS_CONTEXT_FILE_NAME,
20
21
  AgentSessionController,
21
22
  BUILTIN_TOOL_CAPABILITY_METADATA,
23
+ FileSessionStore,
22
24
  SessionTraceSnapshotWriter,
23
25
  abortExecutionState,
24
26
  attachAgentEventsToSessionTrace,
@@ -31,6 +33,7 @@ import {
31
33
  createEmptyExecutionState,
32
34
  createExecutionStateFromTodos,
33
35
  createExecutionStateStore,
36
+ createFileObservationState,
34
37
  createPolicyEnforcedTools,
35
38
  createReadFileUnderstandingHandler,
36
39
  createSessionManager,
@@ -44,6 +47,7 @@ import {
44
47
  evaluateTodoClosureAfterFailedTurn,
45
48
  findFirstKeptEntryId,
46
49
  formatSkillSummariesForPrompt,
50
+ generateEntryId,
47
51
  getAutoCompactTokenLimit,
48
52
  hasInteractionHandler,
49
53
  maybeAdvanceTodoExecutionState,
@@ -55,8 +59,8 @@ import {
55
59
  selectToolsForRuntimePolicy,
56
60
  shouldPreserveExecutionStateForUserText,
57
61
  supersedeExecutionState
58
- } from "./chunks/chunk-G4GV2CRT.js";
59
- import "./chunks/chunk-VE2HDCNB.js";
62
+ } from "./chunks/chunk-NHR6EBM2.js";
63
+ import "./chunks/chunk-L5BJNCNG.js";
60
64
  import {
61
65
  Deref,
62
66
  Errors,
@@ -90,7 +94,7 @@ import {
90
94
  setLogger,
91
95
  sortToolModelCandidatesByCapability,
92
96
  type_exports
93
- } from "./chunks/chunk-5DA2D3K2.js";
97
+ } from "./chunks/chunk-VESPMEDG.js";
94
98
  import {
95
99
  resolveCliProjectRoot
96
100
  } from "./chunks/chunk-NTYHFBUA.js";
@@ -1220,12 +1224,12 @@ var require_supports_color = __commonJS({
1220
1224
  "use strict";
1221
1225
  var os6 = __require("os");
1222
1226
  var tty = __require("tty");
1223
- var hasFlag = require_has_flag();
1227
+ var hasFlag2 = require_has_flag();
1224
1228
  var { env } = process;
1225
1229
  var forceColor;
1226
- if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
1230
+ if (hasFlag2("no-color") || hasFlag2("no-colors") || hasFlag2("color=false") || hasFlag2("color=never")) {
1227
1231
  forceColor = 0;
1228
- } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
1232
+ } else if (hasFlag2("color") || hasFlag2("colors") || hasFlag2("color=true") || hasFlag2("color=always")) {
1229
1233
  forceColor = 1;
1230
1234
  }
1231
1235
  if ("FORCE_COLOR" in env) {
@@ -1252,10 +1256,10 @@ var require_supports_color = __commonJS({
1252
1256
  if (forceColor === 0) {
1253
1257
  return 0;
1254
1258
  }
1255
- if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
1259
+ if (hasFlag2("color=16m") || hasFlag2("color=full") || hasFlag2("color=truecolor")) {
1256
1260
  return 3;
1257
1261
  }
1258
- if (hasFlag("color=256")) {
1262
+ if (hasFlag2("color=256")) {
1259
1263
  return 2;
1260
1264
  }
1261
1265
  if (haveStream && !streamIsTTY && forceColor === void 0) {
@@ -14067,7 +14071,7 @@ var require_http = __commonJS({
14067
14071
  return joined;
14068
14072
  }
14069
14073
  function http(hljs) {
14070
- const VERSION = "HTTP/(2|1\\.[01])";
14074
+ const VERSION2 = "HTTP/(2|1\\.[01])";
14071
14075
  const HEADER_NAME = /[A-Za-z][A-Za-z0-9-]*/;
14072
14076
  const HEADER = {
14073
14077
  className: "attribute",
@@ -14100,12 +14104,12 @@ var require_http = __commonJS({
14100
14104
  contains: [
14101
14105
  // response
14102
14106
  {
14103
- begin: "^(?=" + VERSION + " \\d{3})",
14107
+ begin: "^(?=" + VERSION2 + " \\d{3})",
14104
14108
  end: /$/,
14105
14109
  contains: [
14106
14110
  {
14107
14111
  className: "meta",
14108
- begin: VERSION
14112
+ begin: VERSION2
14109
14113
  },
14110
14114
  {
14111
14115
  className: "number",
@@ -14120,7 +14124,7 @@ var require_http = __commonJS({
14120
14124
  },
14121
14125
  // request
14122
14126
  {
14123
- begin: "(?=^[A-Z]+ (.*?) " + VERSION + "$)",
14127
+ begin: "(?=^[A-Z]+ (.*?) " + VERSION2 + "$)",
14124
14128
  end: /$/,
14125
14129
  contains: [
14126
14130
  {
@@ -14132,7 +14136,7 @@ var require_http = __commonJS({
14132
14136
  },
14133
14137
  {
14134
14138
  className: "meta",
14135
- begin: VERSION
14139
+ begin: VERSION2
14136
14140
  },
14137
14141
  {
14138
14142
  className: "keyword",
@@ -43942,7 +43946,7 @@ var require_dist = __commonJS({
43942
43946
  });
43943
43947
 
43944
43948
  // src/cli.ts
43945
- import * as fs25 from "fs";
43949
+ import * as fs26 from "fs";
43946
43950
  import * as path26 from "path";
43947
43951
 
43948
43952
  // src/cli-args.ts
@@ -45480,6 +45484,356 @@ function parseModelsCommandArgs(args) {
45480
45484
  return parsed;
45481
45485
  }
45482
45486
 
45487
+ // src/commands/sessions.ts
45488
+ import fs6 from "node:fs";
45489
+ async function runSessionsCommand(args) {
45490
+ const command = args[0] || "help";
45491
+ const rest = args.slice(1);
45492
+ try {
45493
+ if (command === "list") {
45494
+ await listSessions(rest);
45495
+ return;
45496
+ }
45497
+ if (command === "read") {
45498
+ await readSession(rest);
45499
+ return;
45500
+ }
45501
+ if (command === "rename") {
45502
+ await renameSession(rest);
45503
+ return;
45504
+ }
45505
+ if (command === "rewind") {
45506
+ await rewindSession(rest);
45507
+ return;
45508
+ }
45509
+ if (command === "fork") {
45510
+ await forkSession(rest);
45511
+ return;
45512
+ }
45513
+ if (command === "help" || command === "--help" || command === "-h") {
45514
+ printSessionsUsage();
45515
+ return;
45516
+ }
45517
+ throw new Error(`Unknown sessions command: ${command}`);
45518
+ } catch (error) {
45519
+ if (hasFlag(args, "--json")) {
45520
+ console.log(JSON.stringify({ ok: false, error: error instanceof Error ? error.message : String(error) }));
45521
+ } else {
45522
+ console.error(error instanceof Error ? error.message : String(error));
45523
+ }
45524
+ process.exitCode = 1;
45525
+ }
45526
+ }
45527
+ async function listSessions(args) {
45528
+ const json = hasFlag(args, "--json");
45529
+ const limit = numericFlag(args, "--limit", 50);
45530
+ const cwd = stringFlag(args, "--cwd");
45531
+ const cursor = stringFlag(args, "--cursor");
45532
+ const store = new FileSessionStore(getSessionsDir());
45533
+ const cursorState = decodeListCursor(cursor);
45534
+ const queryKey = listCursorQueryKey({ cwd });
45535
+ const after = cursorState.q === queryKey ? cursorState.after : void 0;
45536
+ const page = await store.listMetadataPage({
45537
+ limit,
45538
+ after,
45539
+ filter: (metadata) => !cwd || cwdMatches(typeof metadata.cwd === "string" ? metadata.cwd : void 0, cwd)
45540
+ });
45541
+ const sessions = page.metadata.map(sessionSummary);
45542
+ const hasMore = page.hasMore;
45543
+ const lastSession = sessions.at(-1);
45544
+ const nextCursor = hasMore && lastSession ? encodeListCursor({ v: 2, q: queryKey, after: { updatedAt: lastSession.updatedAt, id: lastSession.id } }) : void 0;
45545
+ if (json) {
45546
+ console.log(JSON.stringify({ ok: true, sessions, hasMore, nextCursor }, null, 2));
45547
+ return;
45548
+ }
45549
+ if (sessions.length === 0) {
45550
+ console.log("No sessions.");
45551
+ return;
45552
+ }
45553
+ for (const session of sessions) {
45554
+ console.log(`${session.id} ${session.name} ${new Date(session.updatedAt).toISOString()}${session.cwd ? ` ${session.cwd}` : ""}`);
45555
+ }
45556
+ }
45557
+ async function readSession(args) {
45558
+ const json = hasFlag(args, "--json");
45559
+ const sessionId = positionalArgs(args, /* @__PURE__ */ new Set(["--limit", "--before"]))[0];
45560
+ if (!sessionId) throw new Error("Usage: pie sessions read <sessionId> [--json] [--limit <n>] [--before <cursor>]");
45561
+ const limit = numericFlag(args, "--limit", 200);
45562
+ const before = stringFlag(args, "--before");
45563
+ const store = new FileSessionStore(getSessionsDir());
45564
+ const data = await store.load(sessionId);
45565
+ if (!data) throw new Error(`Session not found: ${sessionId}`);
45566
+ const events = activeTranscriptEvents(activePathEntries(data));
45567
+ const end = resolveBeforeCursor(events, before);
45568
+ const start = Math.max(0, end - limit);
45569
+ const page = events.slice(start, end);
45570
+ const response = {
45571
+ ok: true,
45572
+ session: sessionSummary(data.metadata),
45573
+ currentHead: data.metadata.activeEntryId,
45574
+ activeEntryId: data.metadata.activeEntryId,
45575
+ events: page,
45576
+ hasMoreBefore: start > 0,
45577
+ nextBefore: start > 0 ? String(start) : void 0
45578
+ };
45579
+ if (json) {
45580
+ console.log(JSON.stringify(response, null, 2));
45581
+ return;
45582
+ }
45583
+ console.log(`${response.session.id}: ${response.session.name}`);
45584
+ for (const entry of page) {
45585
+ console.log(`${entry.logicalSeq} ${entry.type}${entry.role ? `:${entry.role}` : ""} ${entry.content ?? ""}`);
45586
+ }
45587
+ }
45588
+ async function renameSession(args) {
45589
+ const json = hasFlag(args, "--json");
45590
+ const cwd = stringFlag(args, "--cwd");
45591
+ const positionals = positionalArgs(args, /* @__PURE__ */ new Set(["--cwd"]));
45592
+ const sessionId = positionals[0];
45593
+ const name = positionals.slice(1).join(" ").trim();
45594
+ if (!sessionId || !name) throw new Error("Usage: pie sessions rename <sessionId> <name> [--json] [--cwd <path>]");
45595
+ const store = new FileSessionStore(getSessionsDir());
45596
+ const data = await store.load(sessionId);
45597
+ if (!data) throw new Error(`Session not found: ${sessionId}`);
45598
+ await store.save(sessionId, data.entries, { ...data.metadata, name, ...cwd ? { cwd } : {}, updatedAt: Date.now() });
45599
+ const updated = await store.getMetadata(sessionId);
45600
+ if (!updated) throw new Error(`Session not found after rename: ${sessionId}`);
45601
+ const response = { ok: true, session: sessionSummary(updated) };
45602
+ if (json) {
45603
+ console.log(JSON.stringify(response, null, 2));
45604
+ return;
45605
+ }
45606
+ console.log(`Renamed ${sessionId} to "${name}".`);
45607
+ }
45608
+ async function rewindSession(args) {
45609
+ const json = hasFlag(args, "--json");
45610
+ const sessionId = positionalArgs(args, /* @__PURE__ */ new Set(["--to"]))[0];
45611
+ const entryId = stringFlag(args, "--to");
45612
+ if (!sessionId || !entryId) throw new Error("Usage: pie sessions rewind <sessionId> --to <entryId> [--json]");
45613
+ const store = new FileSessionStore(getSessionsDir());
45614
+ const data = await store.load(sessionId);
45615
+ if (!data) throw new Error(`Session not found: ${sessionId}`);
45616
+ if (!data.entries.some((entry) => entry.id === entryId)) throw new Error(`Entry not found: ${entryId}`);
45617
+ await store.save(sessionId, data.entries, { ...data.metadata, activeEntryId: entryId, updatedAt: Date.now() });
45618
+ const updated = await store.getMetadata(sessionId);
45619
+ if (!updated) throw new Error(`Session not found after rewind: ${sessionId}`);
45620
+ const response = {
45621
+ ok: true,
45622
+ session: sessionSummary(updated),
45623
+ activeEntryId: entryId,
45624
+ currentHead: entryId
45625
+ };
45626
+ if (json) {
45627
+ console.log(JSON.stringify(response, null, 2));
45628
+ return;
45629
+ }
45630
+ console.log(`Rewound ${sessionId} to ${entryId}.`);
45631
+ }
45632
+ async function forkSession(args) {
45633
+ const json = hasFlag(args, "--json");
45634
+ const sourceSessionId = positionalArgs(args, /* @__PURE__ */ new Set(["--from", "--target", "--name", "--cwd"]))[0];
45635
+ const sourceEntryId = stringFlag(args, "--from");
45636
+ const targetSessionId = stringFlag(args, "--target");
45637
+ const name = stringFlag(args, "--name");
45638
+ const cwd = stringFlag(args, "--cwd");
45639
+ if (!sourceSessionId || !sourceEntryId || !targetSessionId || !name) {
45640
+ throw new Error("Usage: pie sessions fork <sessionId> --from <entryId> --target <newSessionId> --name <name> [--cwd <path>] [--json]");
45641
+ }
45642
+ const store = new FileSessionStore(getSessionsDir());
45643
+ const source = await store.load(sourceSessionId);
45644
+ if (!source) throw new Error(`Session not found: ${sourceSessionId}`);
45645
+ if (await store.exists(targetSessionId)) throw new Error(`Target session already exists: ${targetSessionId}`);
45646
+ const pathEntries = pathToEntry(source, sourceEntryId);
45647
+ if (pathEntries.length === 0 || pathEntries[pathEntries.length - 1]?.id !== sourceEntryId) {
45648
+ throw new Error(`Entry not found: ${sourceEntryId}`);
45649
+ }
45650
+ const now = Date.now();
45651
+ const idMap = /* @__PURE__ */ new Map();
45652
+ for (const entry of pathEntries) idMap.set(entry.id, generateEntryId());
45653
+ const forkedEntries = pathEntries.map((entry) => {
45654
+ const nextId = idMap.get(entry.id);
45655
+ if (!nextId) throw new Error(`Failed to map entry: ${entry.id}`);
45656
+ const parentId = entry.parentId ? idMap.get(entry.parentId) ?? null : null;
45657
+ return {
45658
+ ...cloneJson(entry),
45659
+ id: nextId,
45660
+ parentId,
45661
+ timestamp: entry.timestamp
45662
+ };
45663
+ });
45664
+ const activeEntryId = idMap.get(sourceEntryId) ?? null;
45665
+ await store.save(targetSessionId, forkedEntries, {
45666
+ name,
45667
+ createdAt: now,
45668
+ updatedAt: now,
45669
+ activeEntryId,
45670
+ cwd: cwd ?? source.metadata.cwd,
45671
+ sourceSessionId,
45672
+ sourceEntryId,
45673
+ sourceActiveEntryId: source.metadata.activeEntryId ?? void 0,
45674
+ forkBaseEntryId: activeEntryId ?? void 0
45675
+ });
45676
+ const updated = await store.getMetadata(targetSessionId);
45677
+ if (!updated) throw new Error(`Session not found after fork: ${targetSessionId}`);
45678
+ const response = {
45679
+ ok: true,
45680
+ session: sessionSummary(updated),
45681
+ sourceSessionId,
45682
+ sourceEntryId,
45683
+ sourceActiveEntryId: source.metadata.activeEntryId,
45684
+ forkBaseEntryId: activeEntryId,
45685
+ activeEntryId,
45686
+ currentHead: activeEntryId
45687
+ };
45688
+ if (json) {
45689
+ console.log(JSON.stringify(response, null, 2));
45690
+ return;
45691
+ }
45692
+ console.log(`Forked ${sourceSessionId} at ${sourceEntryId} into ${targetSessionId}.`);
45693
+ }
45694
+ function printSessionsUsage() {
45695
+ console.log(`Usage:
45696
+ pie sessions list [--json] [--limit <n>] [--cursor <cursor>] [--cwd <path>]
45697
+ pie sessions read <sessionId> [--json] [--limit <n>] [--before <cursor>]
45698
+ pie sessions rename <sessionId> <name> [--json] [--cwd <path>]
45699
+ pie sessions rewind <sessionId> --to <entryId> [--json]
45700
+ pie sessions fork <sessionId> --from <entryId> --target <newSessionId> --name <name> [--cwd <path>] [--json]`);
45701
+ }
45702
+ function hasFlag(args, flag) {
45703
+ return args.includes(flag);
45704
+ }
45705
+ function stringFlag(args, flag) {
45706
+ const index = args.indexOf(flag);
45707
+ if (index < 0) return void 0;
45708
+ const value = args[index + 1];
45709
+ return value && !value.startsWith("-") ? value : void 0;
45710
+ }
45711
+ function numericFlag(args, flag, fallback) {
45712
+ const value = stringFlag(args, flag);
45713
+ if (!value) return fallback;
45714
+ const parsed = Number(value);
45715
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
45716
+ }
45717
+ function positionalArgs(args, valueFlags) {
45718
+ const result = [];
45719
+ for (let index = 0; index < args.length; index += 1) {
45720
+ const arg = args[index];
45721
+ if (arg.startsWith("--")) {
45722
+ if (valueFlags.has(arg)) index += 1;
45723
+ continue;
45724
+ }
45725
+ result.push(arg);
45726
+ }
45727
+ return result;
45728
+ }
45729
+ function sessionSummary(metadata) {
45730
+ return {
45731
+ id: metadata.id,
45732
+ name: metadata.name,
45733
+ createdAt: metadata.createdAt,
45734
+ updatedAt: metadata.updatedAt,
45735
+ cwd: typeof metadata.cwd === "string" ? metadata.cwd : void 0,
45736
+ entryCount: metadata.entryCount,
45737
+ messageCount: metadata.messageCount,
45738
+ activeEntryId: metadata.activeEntryId,
45739
+ rootEntryId: metadata.rootEntryId,
45740
+ sourceSessionId: typeof metadata.sourceSessionId === "string" ? metadata.sourceSessionId : void 0,
45741
+ sourceEntryId: typeof metadata.sourceEntryId === "string" ? metadata.sourceEntryId : void 0,
45742
+ sourceActiveEntryId: typeof metadata.sourceActiveEntryId === "string" ? metadata.sourceActiveEntryId : void 0,
45743
+ forkBaseEntryId: typeof metadata.forkBaseEntryId === "string" ? metadata.forkBaseEntryId : void 0
45744
+ };
45745
+ }
45746
+ function cwdMatches(sessionCwd, requestedCwd) {
45747
+ if (!sessionCwd) return false;
45748
+ if (sessionCwd === requestedCwd) return true;
45749
+ return realpathOrInput(sessionCwd) === realpathOrInput(requestedCwd);
45750
+ }
45751
+ function realpathOrInput(value) {
45752
+ try {
45753
+ return fs6.realpathSync.native(value);
45754
+ } catch {
45755
+ return value;
45756
+ }
45757
+ }
45758
+ function activeTranscriptEvents(entries) {
45759
+ return entries.map((entry, index) => {
45760
+ const role = isRecord2(entry.message) && typeof entry.message.role === "string" ? entry.message.role : void 0;
45761
+ return {
45762
+ logicalSeq: index + 1,
45763
+ checkpointId: entry.id,
45764
+ entryId: entry.id,
45765
+ id: entry.id,
45766
+ type: entry.type,
45767
+ timestamp: entry.timestamp,
45768
+ occurredAt: entry.timestamp,
45769
+ role,
45770
+ content: textFromMessage(entry.message),
45771
+ message: entry.message ? cloneJson(entry.message) : void 0
45772
+ };
45773
+ });
45774
+ }
45775
+ function activePathEntries(data) {
45776
+ const activeEntryId = data.metadata.activeEntryId;
45777
+ if (!activeEntryId) return [];
45778
+ return pathToEntry(data, activeEntryId);
45779
+ }
45780
+ function pathToEntry(data, entryId) {
45781
+ const byId = new Map(data.entries.map((entry) => [entry.id, entry]));
45782
+ const path27 = [];
45783
+ let current = entryId;
45784
+ while (current) {
45785
+ const entry = byId.get(current);
45786
+ if (!entry) return [];
45787
+ path27.unshift(entry);
45788
+ current = entry.parentId;
45789
+ }
45790
+ return path27;
45791
+ }
45792
+ function resolveBeforeCursor(events, cursor) {
45793
+ if (!cursor) return events.length;
45794
+ const numeric = Number(cursor);
45795
+ if (Number.isInteger(numeric) && numeric >= 0) {
45796
+ return Math.max(0, Math.min(events.length, numeric));
45797
+ }
45798
+ const index = events.findIndex((event) => event.entryId === cursor || event.checkpointId === cursor);
45799
+ return index >= 0 ? index : events.length;
45800
+ }
45801
+ function cloneJson(value) {
45802
+ return JSON.parse(JSON.stringify(value));
45803
+ }
45804
+ function listCursorQueryKey(input) {
45805
+ return JSON.stringify({ cwd: input.cwd ? realpathOrInput(input.cwd) : "" });
45806
+ }
45807
+ function encodeListCursor(state) {
45808
+ return `list:${Buffer.from(JSON.stringify(state), "utf8").toString("base64url")}`;
45809
+ }
45810
+ function decodeListCursor(cursor) {
45811
+ if (!cursor?.startsWith("list:")) return { v: 2 };
45812
+ try {
45813
+ const parsed = JSON.parse(Buffer.from(cursor.slice("list:".length), "base64url").toString("utf8"));
45814
+ if (!isRecord2(parsed) || parsed.v !== 2) return { v: 2 };
45815
+ const after = isRecord2(parsed.after) && typeof parsed.after.id === "string" && typeof parsed.after.updatedAt === "number" && Number.isFinite(parsed.after.updatedAt) ? { id: parsed.after.id, updatedAt: parsed.after.updatedAt } : void 0;
45816
+ return {
45817
+ v: 2,
45818
+ q: typeof parsed.q === "string" ? parsed.q : void 0,
45819
+ ...after ? { after } : {}
45820
+ };
45821
+ } catch {
45822
+ return { v: 2 };
45823
+ }
45824
+ }
45825
+ function textFromMessage(message) {
45826
+ if (!isRecord2(message)) return void 0;
45827
+ const content = message.content;
45828
+ if (typeof content === "string") return content;
45829
+ if (!Array.isArray(content)) return void 0;
45830
+ const text = content.map((block) => isRecord2(block) && block.type === "text" && typeof block.text === "string" ? block.text : "").filter(Boolean).join("\n").trim();
45831
+ return text || void 0;
45832
+ }
45833
+ function isRecord2(value) {
45834
+ return !!value && typeof value === "object" && !Array.isArray(value);
45835
+ }
45836
+
45483
45837
  // ../../packages/tui/src/fuzzy.ts
45484
45838
  function fuzzyMatch(query, text) {
45485
45839
  const queryLower = query.toLowerCase();
@@ -47030,7 +47384,7 @@ var KillRing = class {
47030
47384
  };
47031
47385
 
47032
47386
  // ../../packages/tui/src/tui.ts
47033
- import * as fs6 from "node:fs";
47387
+ import * as fs7 from "node:fs";
47034
47388
  import * as os2 from "node:os";
47035
47389
  import * as path5 from "node:path";
47036
47390
 
@@ -47709,10 +48063,10 @@ var TUI = class extends Container {
47709
48063
  const logRedraw = (reason) => {
47710
48064
  if (!debugRedraw) return;
47711
48065
  const logPath = path5.join(os2.homedir(), ".pie", "logs", "pie-cli.log");
47712
- fs6.mkdirSync(path5.dirname(logPath), { recursive: true });
48066
+ fs7.mkdirSync(path5.dirname(logPath), { recursive: true });
47713
48067
  const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] [DEBUG] [ui] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})
47714
48068
  `;
47715
- fs6.appendFileSync(logPath, msg);
48069
+ fs7.appendFileSync(logPath, msg);
47716
48070
  };
47717
48071
  if (this.previousLines.length === 0 && !widthChanged) {
47718
48072
  logRedraw("first render");
@@ -47815,8 +48169,8 @@ var TUI = class extends Container {
47815
48169
  ...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),
47816
48170
  ""
47817
48171
  ].join("\n");
47818
- fs6.mkdirSync(path5.dirname(crashLogPath), { recursive: true });
47819
- fs6.writeFileSync(crashLogPath, crashData);
48172
+ fs7.mkdirSync(path5.dirname(crashLogPath), { recursive: true });
48173
+ fs7.writeFileSync(crashLogPath, crashData);
47820
48174
  this.stop();
47821
48175
  const errorMsg = [
47822
48176
  `Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,
@@ -47846,7 +48200,7 @@ var TUI = class extends Container {
47846
48200
  buffer += "\x1B[?2026l";
47847
48201
  if (process.env.PIE_TUI_DEBUG === "1") {
47848
48202
  const debugDir = "/tmp/tui";
47849
- fs6.mkdirSync(debugDir, { recursive: true });
48203
+ fs7.mkdirSync(debugDir, { recursive: true });
47850
48204
  const debugPath = path5.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
47851
48205
  const debugData = [
47852
48206
  `firstChanged: ${firstChanged}`,
@@ -47870,7 +48224,7 @@ var TUI = class extends Container {
47870
48224
  "=== buffer ===",
47871
48225
  JSON.stringify(buffer)
47872
48226
  ].join("\n");
47873
- fs6.writeFileSync(debugPath, debugData);
48227
+ fs7.writeFileSync(debugPath, debugData);
47874
48228
  }
47875
48229
  this.terminal.write(buffer);
47876
48230
  this.cursorRow = Math.max(0, newLines.length - 1);
@@ -52045,7 +52399,7 @@ var StdinBuffer = class extends EventEmitter {
52045
52399
  };
52046
52400
 
52047
52401
  // ../../packages/tui/src/terminal.ts
52048
- import * as fs7 from "node:fs";
52402
+ import * as fs8 from "node:fs";
52049
52403
  import koffi from "koffi";
52050
52404
  var ProcessTerminal = class {
52051
52405
  wasRaw = false;
@@ -52206,7 +52560,7 @@ var ProcessTerminal = class {
52206
52560
  process.stdout.write(data);
52207
52561
  if (this.writeLogPath) {
52208
52562
  try {
52209
- fs7.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
52563
+ fs8.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
52210
52564
  } catch {
52211
52565
  }
52212
52566
  }
@@ -52378,7 +52732,7 @@ var KeybindingsManager = class _KeybindingsManager {
52378
52732
  };
52379
52733
 
52380
52734
  // src/project-knowledge.ts
52381
- import fs8 from "node:fs";
52735
+ import fs9 from "node:fs";
52382
52736
  import path6 from "node:path";
52383
52737
  function collectAncestorAgentsFiles(cwd) {
52384
52738
  const resolvedCwd = path6.resolve(cwd || process.cwd());
@@ -52398,13 +52752,13 @@ function collectAncestorAgentsFiles(cwd) {
52398
52752
  }
52399
52753
  const files = [];
52400
52754
  for (const candidate of candidates) {
52401
- if (!fs8.existsSync(candidate)) {
52755
+ if (!fs9.existsSync(candidate)) {
52402
52756
  continue;
52403
52757
  }
52404
52758
  try {
52405
52759
  files.push({
52406
52760
  path: path6.relative(resolvedCwd, candidate) || AGENTS_CONTEXT_FILE_NAME,
52407
- content: fs8.readFileSync(candidate, "utf-8")
52761
+ content: fs9.readFileSync(candidate, "utf-8")
52408
52762
  });
52409
52763
  } catch {
52410
52764
  }
@@ -52442,7 +52796,7 @@ function buildCliFileAccessOptions(params) {
52442
52796
  }
52443
52797
 
52444
52798
  // src/theme/theme.ts
52445
- import * as fs9 from "node:fs";
52799
+ import * as fs10 from "node:fs";
52446
52800
  import * as path8 from "node:path";
52447
52801
 
52448
52802
  // ../../node_modules/@sinclair/typebox/build/esm/compiler/compiler.mjs
@@ -53333,8 +53687,8 @@ function getBuiltinThemes() {
53333
53687
  const darkPath = path8.join(themesDir, "dark.json");
53334
53688
  const lightPath = path8.join(themesDir, "light.json");
53335
53689
  BUILTIN_THEMES = {
53336
- dark: JSON.parse(fs9.readFileSync(darkPath, "utf-8")),
53337
- light: JSON.parse(fs9.readFileSync(lightPath, "utf-8"))
53690
+ dark: JSON.parse(fs10.readFileSync(darkPath, "utf-8")),
53691
+ light: JSON.parse(fs10.readFileSync(lightPath, "utf-8"))
53338
53692
  };
53339
53693
  }
53340
53694
  return BUILTIN_THEMES;
@@ -53342,8 +53696,8 @@ function getBuiltinThemes() {
53342
53696
  function getAvailableThemes() {
53343
53697
  const themes = new Set(Object.keys(getBuiltinThemes()));
53344
53698
  const customThemesDir = getCustomThemesDir();
53345
- if (fs9.existsSync(customThemesDir)) {
53346
- const files = fs9.readdirSync(customThemesDir);
53699
+ if (fs10.existsSync(customThemesDir)) {
53700
+ const files = fs10.readdirSync(customThemesDir);
53347
53701
  for (const file of files) {
53348
53702
  if (file.endsWith(".json")) {
53349
53703
  themes.add(file.slice(0, -5));
@@ -53404,7 +53758,7 @@ function loadThemeJson(name) {
53404
53758
  }
53405
53759
  const registeredTheme = registeredThemes.get(name);
53406
53760
  if (registeredTheme?.sourcePath) {
53407
- const content2 = fs9.readFileSync(registeredTheme.sourcePath, "utf-8");
53761
+ const content2 = fs10.readFileSync(registeredTheme.sourcePath, "utf-8");
53408
53762
  return parseThemeJsonContent(registeredTheme.sourcePath, content2);
53409
53763
  }
53410
53764
  if (registeredTheme) {
@@ -53412,10 +53766,10 @@ function loadThemeJson(name) {
53412
53766
  }
53413
53767
  const customThemesDir = getCustomThemesDir();
53414
53768
  const themePath = path8.join(customThemesDir, `${name}.json`);
53415
- if (!fs9.existsSync(themePath)) {
53769
+ if (!fs10.existsSync(themePath)) {
53416
53770
  throw new Error(`Theme not found: ${name}`);
53417
53771
  }
53418
- const content = fs9.readFileSync(themePath, "utf-8");
53772
+ const content = fs10.readFileSync(themePath, "utf-8");
53419
53773
  return parseThemeJsonContent(name, content);
53420
53774
  }
53421
53775
  function createTheme(themeJson, mode, sourcePath) {
@@ -53529,11 +53883,11 @@ function startThemeWatcher() {
53529
53883
  }
53530
53884
  const customThemesDir = getCustomThemesDir();
53531
53885
  const themeFile = path8.join(customThemesDir, `${currentThemeName}.json`);
53532
- if (!fs9.existsSync(themeFile)) {
53886
+ if (!fs10.existsSync(themeFile)) {
53533
53887
  return;
53534
53888
  }
53535
53889
  try {
53536
- themeWatcher = fs9.watch(themeFile, (eventType) => {
53890
+ themeWatcher = fs10.watch(themeFile, (eventType) => {
53537
53891
  if (eventType === "change") {
53538
53892
  setTimeout(() => {
53539
53893
  try {
@@ -53546,7 +53900,7 @@ function startThemeWatcher() {
53546
53900
  }, 100);
53547
53901
  } else if (eventType === "rename") {
53548
53902
  setTimeout(() => {
53549
- if (!fs9.existsSync(themeFile)) {
53903
+ if (!fs10.existsSync(themeFile)) {
53550
53904
  currentThemeName = "dark";
53551
53905
  setGlobalTheme(loadTheme("dark"));
53552
53906
  if (themeWatcher) {
@@ -53717,7 +54071,7 @@ function getEditorTheme() {
53717
54071
  }
53718
54072
 
53719
54073
  // src/skills/loader.ts
53720
- import * as fs10 from "fs";
54074
+ import * as fs11 from "fs";
53721
54075
  import * as path9 from "path";
53722
54076
  function parseSkillDescription(content) {
53723
54077
  const frontmatterMatch = content.match(/^---\n[\s\S]*?description:\s*["']?(.+?)["']?(?:\n|$)/m);
@@ -53736,18 +54090,18 @@ function parseSkillDescription(content) {
53736
54090
  function loadSkillsFromDir(dir, source) {
53737
54091
  const skills = [];
53738
54092
  const diagnostics = [];
53739
- if (!fs10.existsSync(dir)) {
54093
+ if (!fs11.existsSync(dir)) {
53740
54094
  return { skills, diagnostics };
53741
54095
  }
53742
- const entries = fs10.readdirSync(dir, { withFileTypes: true });
54096
+ const entries = fs11.readdirSync(dir, { withFileTypes: true });
53743
54097
  for (const entry of entries) {
53744
54098
  if (entry.name.startsWith(".")) continue;
53745
54099
  const fullPath = path9.join(dir, entry.name);
53746
54100
  if (entry.isDirectory()) {
53747
54101
  const skillMdPath = path9.join(fullPath, "SKILL.md");
53748
- if (fs10.existsSync(skillMdPath)) {
54102
+ if (fs11.existsSync(skillMdPath)) {
53749
54103
  try {
53750
- const content = fs10.readFileSync(skillMdPath, "utf-8");
54104
+ const content = fs11.readFileSync(skillMdPath, "utf-8");
53751
54105
  const description = parseSkillDescription(content);
53752
54106
  skills.push({
53753
54107
  name: entry.name,
@@ -53768,7 +54122,7 @@ function loadSkillsFromDir(dir, source) {
53768
54122
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
53769
54123
  const name = entry.name.slice(0, -3);
53770
54124
  try {
53771
- const content = fs10.readFileSync(fullPath, "utf-8");
54125
+ const content = fs11.readFileSync(fullPath, "utf-8");
53772
54126
  const description = parseSkillDescription(content);
53773
54127
  skills.push({
53774
54128
  name,
@@ -53965,7 +54319,7 @@ function validateSkillName(name) {
53965
54319
 
53966
54320
  // src/capabilities/read-file-understanding.ts
53967
54321
  import * as path18 from "node:path";
53968
- import * as fs18 from "node:fs/promises";
54322
+ import * as fs19 from "node:fs/promises";
53969
54323
 
53970
54324
  // src/core/provider-capabilities.ts
53971
54325
  var PLATFORM_DISPLAY_NAMES = {
@@ -53991,7 +54345,7 @@ function getProviderDisplayName(platform2) {
53991
54345
  }
53992
54346
 
53993
54347
  // src/files/adapters/kimi-adapter.ts
53994
- import * as fs11 from "node:fs";
54348
+ import * as fs12 from "node:fs";
53995
54349
  import * as path10 from "node:path";
53996
54350
 
53997
54351
  // src/files/errors.ts
@@ -54132,14 +54486,14 @@ var KimiFileAdapter = class {
54132
54486
  const fileName = options.sourceName || path10.basename(filePath);
54133
54487
  const mimeType = options.mimeType || this.guessMimeType(fileName);
54134
54488
  const purpose = this.detectPurpose(filePath, options.purpose, mimeType);
54135
- const stats = fs11.statSync(filePath);
54489
+ const stats = fs12.statSync(filePath);
54136
54490
  if (stats.size > this.capabilities.maxFileSize) {
54137
54491
  throw new FileManagerError(
54138
54492
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
54139
54493
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds Kimi limit of 100MB`
54140
54494
  );
54141
54495
  }
54142
- const fileBuffer = fs11.readFileSync(filePath);
54496
+ const fileBuffer = fs12.readFileSync(filePath);
54143
54497
  const file = new File([fileBuffer], fileName, { type: mimeType });
54144
54498
  const formData = new FormData();
54145
54499
  formData.append("file", file);
@@ -54353,7 +54707,7 @@ var KimiFileAdapter = class {
54353
54707
  };
54354
54708
 
54355
54709
  // src/files/adapters/gemini-adapter.ts
54356
- import * as fs12 from "node:fs";
54710
+ import * as fs13 from "node:fs";
54357
54711
  import * as path11 from "node:path";
54358
54712
  import { Readable } from "node:stream";
54359
54713
  var GeminiFileAdapter = class {
@@ -54411,7 +54765,7 @@ var GeminiFileAdapter = class {
54411
54765
  // Upload
54412
54766
  // ============================================================================
54413
54767
  async upload(filePath, options = {}) {
54414
- const stats = fs12.statSync(filePath);
54768
+ const stats = fs13.statSync(filePath);
54415
54769
  if (stats.size > this.capabilities.maxFileSize) {
54416
54770
  throw new FileManagerError(
54417
54771
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
@@ -54450,7 +54804,7 @@ var GeminiFileAdapter = class {
54450
54804
  "No upload URL received"
54451
54805
  );
54452
54806
  }
54453
- const fileStream = Readable.toWeb(fs12.createReadStream(filePath));
54807
+ const fileStream = Readable.toWeb(fs13.createReadStream(filePath));
54454
54808
  const uploadResponse = await fetch(uploadUrl, {
54455
54809
  method: "POST",
54456
54810
  headers: {
@@ -54654,7 +55008,7 @@ var GeminiFileAdapter = class {
54654
55008
  };
54655
55009
 
54656
55010
  // src/files/adapters/openai-compatible-files-adapter.ts
54657
- import * as fs13 from "node:fs";
55011
+ import * as fs14 from "node:fs";
54658
55012
  import * as path12 from "node:path";
54659
55013
  var OpenAICompatibleFilesAdapter = class {
54660
55014
  constructor(apiKey, baseUrl, extraHeaders = {}) {
@@ -54683,14 +55037,14 @@ var OpenAICompatibleFilesAdapter = class {
54683
55037
  async upload(filePath, options = {}) {
54684
55038
  const fileName = options.sourceName || path12.basename(filePath);
54685
55039
  const mimeType = options.mimeType || guessMimeType(fileName);
54686
- const stats = fs13.statSync(filePath);
55040
+ const stats = fs14.statSync(filePath);
54687
55041
  if (stats.size > this.capabilities.maxFileSize) {
54688
55042
  throw new FileManagerError(
54689
55043
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
54690
55044
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds OpenAI-compatible Files limit of ${this.capabilities.maxFileSize / 1024 / 1024}MB`
54691
55045
  );
54692
55046
  }
54693
- const file = new File([fs13.readFileSync(filePath)], fileName, { type: mimeType });
55047
+ const file = new File([fs14.readFileSync(filePath)], fileName, { type: mimeType });
54694
55048
  const formData = new FormData();
54695
55049
  formData.append("file", file);
54696
55050
  formData.append("purpose", options.purpose && options.purpose !== "auto" ? options.purpose : "file-extract");
@@ -54823,12 +55177,12 @@ function guessMimeType(filename) {
54823
55177
  }
54824
55178
 
54825
55179
  // src/files/file-manager.ts
54826
- import * as fs17 from "node:fs";
55180
+ import * as fs18 from "node:fs";
54827
55181
  import * as path17 from "node:path";
54828
55182
  import * as crypto2 from "node:crypto";
54829
55183
 
54830
55184
  // src/files/file-cache.ts
54831
- import * as fs14 from "node:fs";
55185
+ import * as fs15 from "node:fs";
54832
55186
  import * as path14 from "node:path";
54833
55187
  import * as crypto from "node:crypto";
54834
55188
 
@@ -54989,22 +55343,22 @@ var FileCache = class _FileCache {
54989
55343
  // Directory Management
54990
55344
  // ============================================================================
54991
55345
  ensureDirectories() {
54992
- if (!fs14.existsSync(this.baseDir)) {
54993
- fs14.mkdirSync(this.baseDir, { recursive: true });
55346
+ if (!fs15.existsSync(this.baseDir)) {
55347
+ fs15.mkdirSync(this.baseDir, { recursive: true });
54994
55348
  }
54995
- if (!fs14.existsSync(this.dataDir)) {
54996
- fs14.mkdirSync(this.dataDir, { recursive: true });
55349
+ if (!fs15.existsSync(this.dataDir)) {
55350
+ fs15.mkdirSync(this.dataDir, { recursive: true });
54997
55351
  }
54998
55352
  }
54999
55353
  // ============================================================================
55000
55354
  // Index Management
55001
55355
  // ============================================================================
55002
55356
  loadIndex() {
55003
- if (!fs14.existsSync(this.indexPath)) {
55357
+ if (!fs15.existsSync(this.indexPath)) {
55004
55358
  return { version: CACHE_VERSION, files: {}, pathHints: {} };
55005
55359
  }
55006
55360
  try {
55007
- const data = JSON.parse(fs14.readFileSync(this.indexPath, "utf-8"));
55361
+ const data = JSON.parse(fs15.readFileSync(this.indexPath, "utf-8"));
55008
55362
  if (data.version !== CACHE_VERSION) {
55009
55363
  cacheLogger.warn(`Index version mismatch: ${data.version} vs ${CACHE_VERSION}`);
55010
55364
  }
@@ -55020,7 +55374,7 @@ var FileCache = class _FileCache {
55020
55374
  }
55021
55375
  saveIndex() {
55022
55376
  try {
55023
- fs14.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
55377
+ fs15.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
55024
55378
  } catch (err) {
55025
55379
  cacheLogger.error(" Failed to save index:", err);
55026
55380
  throw err;
@@ -55032,7 +55386,7 @@ var FileCache = class _FileCache {
55032
55386
  async computeHash(filePath) {
55033
55387
  return new Promise((resolve4, reject) => {
55034
55388
  const hash = crypto.createHash("sha256");
55035
- const stream = fs14.createReadStream(filePath);
55389
+ const stream = fs15.createReadStream(filePath);
55036
55390
  stream.on("data", (chunk) => hash.update(chunk));
55037
55391
  stream.on("end", () => resolve4(hash.digest("hex")));
55038
55392
  stream.on("error", reject);
@@ -55047,8 +55401,8 @@ var FileCache = class _FileCache {
55047
55401
  getStoragePath(hash) {
55048
55402
  const subdir = hash.slice(0, 2);
55049
55403
  const fullDir = path14.join(this.dataDir, subdir);
55050
- if (!fs14.existsSync(fullDir)) {
55051
- fs14.mkdirSync(fullDir, { recursive: true });
55404
+ if (!fs15.existsSync(fullDir)) {
55405
+ fs15.mkdirSync(fullDir, { recursive: true });
55052
55406
  }
55053
55407
  return path14.join(fullDir, hash);
55054
55408
  }
@@ -55060,11 +55414,11 @@ var FileCache = class _FileCache {
55060
55414
  const hash = await this.computeHash(sourcePath);
55061
55415
  const storagePath = this.getStoragePath(hash);
55062
55416
  this.rememberPathHint(sourcePath, hash, name);
55063
- if (fs14.existsSync(storagePath)) {
55417
+ if (fs15.existsSync(storagePath)) {
55064
55418
  return { hash, localPath: storagePath };
55065
55419
  }
55066
- fs14.copyFileSync(sourcePath, storagePath);
55067
- const stat2 = fs14.statSync(storagePath);
55420
+ fs15.copyFileSync(sourcePath, storagePath);
55421
+ const stat2 = fs15.statSync(storagePath);
55068
55422
  this.index.files[hash] = {
55069
55423
  hash,
55070
55424
  name,
@@ -55081,10 +55435,10 @@ var FileCache = class _FileCache {
55081
55435
  async storeBuffer(data, name, mimeType) {
55082
55436
  const hash = this.computeHashSync(data);
55083
55437
  const storagePath = this.getStoragePath(hash);
55084
- if (fs14.existsSync(storagePath)) {
55438
+ if (fs15.existsSync(storagePath)) {
55085
55439
  return { hash, localPath: storagePath };
55086
55440
  }
55087
- fs14.writeFileSync(storagePath, data);
55441
+ fs15.writeFileSync(storagePath, data);
55088
55442
  this.index.files[hash] = {
55089
55443
  hash,
55090
55444
  name,
@@ -55156,7 +55510,7 @@ var FileCache = class _FileCache {
55156
55510
  getPathHint(filePath) {
55157
55511
  try {
55158
55512
  const resolvedPath = this.getResolvedHintPath(filePath);
55159
- const stat2 = fs14.statSync(resolvedPath);
55513
+ const stat2 = fs15.statSync(resolvedPath);
55160
55514
  if (!stat2.isFile()) return void 0;
55161
55515
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
55162
55516
  const key = this.getPathHintKey(resolvedPath);
@@ -55186,7 +55540,7 @@ var FileCache = class _FileCache {
55186
55540
  rememberPathHint(filePath, hash, name) {
55187
55541
  try {
55188
55542
  const resolvedPath = this.getResolvedHintPath(filePath);
55189
- const stat2 = fs14.statSync(resolvedPath);
55543
+ const stat2 = fs15.statSync(resolvedPath);
55190
55544
  if (!stat2.isFile()) return;
55191
55545
  const entry = this.index.files[hash];
55192
55546
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
@@ -55245,8 +55599,8 @@ var FileCache = class _FileCache {
55245
55599
  entry = entry || this.index.files[hash];
55246
55600
  if (!entry) return;
55247
55601
  const localPath = path14.join(this.dataDir, entry.localPath);
55248
- if (fs14.existsSync(localPath)) {
55249
- fs14.unlinkSync(localPath);
55602
+ if (fs15.existsSync(localPath)) {
55603
+ fs15.unlinkSync(localPath);
55250
55604
  }
55251
55605
  delete this.index.files[hash];
55252
55606
  if (this.index.pathHints) {
@@ -55261,8 +55615,8 @@ var FileCache = class _FileCache {
55261
55615
  clear() {
55262
55616
  for (const entry of Object.values(this.index.files)) {
55263
55617
  const localPath = path14.join(this.dataDir, entry.localPath);
55264
- if (fs14.existsSync(localPath)) {
55265
- fs14.unlinkSync(localPath);
55618
+ if (fs15.existsSync(localPath)) {
55619
+ fs15.unlinkSync(localPath);
55266
55620
  }
55267
55621
  }
55268
55622
  this.index = { version: CACHE_VERSION, files: {}, pathHints: {} };
@@ -55350,7 +55704,7 @@ var FileCache = class _FileCache {
55350
55704
  getResolvedHintPath(filePath) {
55351
55705
  const resolvedPath = resolvePath(filePath);
55352
55706
  try {
55353
- return fs14.realpathSync.native ? fs14.realpathSync.native(resolvedPath) : fs14.realpathSync(resolvedPath);
55707
+ return fs15.realpathSync.native ? fs15.realpathSync.native(resolvedPath) : fs15.realpathSync(resolvedPath);
55354
55708
  } catch {
55355
55709
  return resolvedPath;
55356
55710
  }
@@ -55358,7 +55712,7 @@ var FileCache = class _FileCache {
55358
55712
  };
55359
55713
 
55360
55714
  // src/files/session-file-manager.ts
55361
- import * as fs15 from "node:fs";
55715
+ import * as fs16 from "node:fs";
55362
55716
  import * as path15 from "node:path";
55363
55717
  var INITIAL_REFRESH_BACKOFF_MS = 6e4;
55364
55718
  var MAX_REFRESH_BACKOFF_MS = 60 * 60 * 1e3;
@@ -55383,15 +55737,15 @@ var SessionFileManager = class {
55383
55737
  // Directory Management
55384
55738
  // ============================================================================
55385
55739
  ensureDirectories() {
55386
- if (!fs15.existsSync(this.sessionsDir)) {
55387
- fs15.mkdirSync(this.sessionsDir, { recursive: true });
55740
+ if (!fs16.existsSync(this.sessionsDir)) {
55741
+ fs16.mkdirSync(this.sessionsDir, { recursive: true });
55388
55742
  }
55389
55743
  }
55390
55744
  // ============================================================================
55391
55745
  // State Management
55392
55746
  // ============================================================================
55393
55747
  loadState() {
55394
- if (!fs15.existsSync(this.statePath)) {
55748
+ if (!fs16.existsSync(this.statePath)) {
55395
55749
  return {
55396
55750
  sessionId: this.sessionId,
55397
55751
  lastSyncedAt: 0,
@@ -55399,7 +55753,7 @@ var SessionFileManager = class {
55399
55753
  };
55400
55754
  }
55401
55755
  try {
55402
- return JSON.parse(fs15.readFileSync(this.statePath, "utf-8"));
55756
+ return JSON.parse(fs16.readFileSync(this.statePath, "utf-8"));
55403
55757
  } catch (err) {
55404
55758
  sessionLogger.error(" Failed to load state:", err);
55405
55759
  return {
@@ -55412,12 +55766,12 @@ var SessionFileManager = class {
55412
55766
  saveState() {
55413
55767
  try {
55414
55768
  if (Object.keys(this.state.files).length === 0) {
55415
- if (fs15.existsSync(this.statePath)) {
55416
- fs15.unlinkSync(this.statePath);
55769
+ if (fs16.existsSync(this.statePath)) {
55770
+ fs16.unlinkSync(this.statePath);
55417
55771
  }
55418
55772
  return;
55419
55773
  }
55420
- fs15.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
55774
+ fs16.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
55421
55775
  } catch (err) {
55422
55776
  sessionLogger.error(" Failed to save state:", err);
55423
55777
  }
@@ -55563,7 +55917,7 @@ var SessionFileManager = class {
55563
55917
  return { success: false, coolingDown: true };
55564
55918
  }
55565
55919
  const localPath = this.fileCache.getLocalPath(entry.hash);
55566
- if (!localPath || !fs15.existsSync(localPath)) {
55920
+ if (!localPath || !fs16.existsSync(localPath)) {
55567
55921
  sessionLogger.warn(`Local file not found for ${fileId}`);
55568
55922
  entry.status = "expired";
55569
55923
  entry.error = "Local file missing";
@@ -55714,15 +56068,15 @@ var SessionFileManager = class {
55714
56068
  // Static Utilities
55715
56069
  // ============================================================================
55716
56070
  static cleanupOldSessions(sessionsDir, maxAge = 30 * 24 * 60 * 60 * 1e3) {
55717
- if (!fs15.existsSync(sessionsDir)) return;
56071
+ if (!fs16.existsSync(sessionsDir)) return;
55718
56072
  const now = Date.now();
55719
- const files = fs15.readdirSync(sessionsDir);
56073
+ const files = fs16.readdirSync(sessionsDir);
55720
56074
  for (const file of files) {
55721
56075
  if (!file.endsWith(".json")) continue;
55722
56076
  const filePath = path15.join(sessionsDir, file);
55723
- const stat2 = fs15.statSync(filePath);
56077
+ const stat2 = fs16.statSync(filePath);
55724
56078
  if (now - stat2.mtime.getTime() > maxAge) {
55725
- fs15.unlinkSync(filePath);
56079
+ fs16.unlinkSync(filePath);
55726
56080
  sessionLogger.debug(`Cleaned up old session: ${file}`);
55727
56081
  }
55728
56082
  }
@@ -55730,7 +56084,7 @@ var SessionFileManager = class {
55730
56084
  };
55731
56085
 
55732
56086
  // src/files/ffmpeg-processor.ts
55733
- import * as fs16 from "node:fs";
56087
+ import * as fs17 from "node:fs";
55734
56088
  import * as path16 from "node:path";
55735
56089
  import { spawn } from "node:child_process";
55736
56090
  var FFmpegProcessor = class {
@@ -55866,7 +56220,7 @@ var FFmpegProcessor = class {
55866
56220
  onProgress?.(percent);
55867
56221
  }
55868
56222
  });
55869
- const outputStat = fs16.statSync(outputPath);
56223
+ const outputStat = fs17.statSync(outputPath);
55870
56224
  return {
55871
56225
  type: "video",
55872
56226
  output: outputPath,
@@ -55898,7 +56252,7 @@ var FFmpegProcessor = class {
55898
56252
  async extractKeyframes(inputPath, outputDir, info, opts, onProgress) {
55899
56253
  const interval = Math.floor(info.duration / opts.keyframeCount);
55900
56254
  const framesDir = path16.join(outputDir, `keyframes_${Date.now()}`);
55901
- fs16.mkdirSync(framesDir, { recursive: true });
56255
+ fs17.mkdirSync(framesDir, { recursive: true });
55902
56256
  const outputPattern = path16.join(framesDir, "frame_%03d.jpg");
55903
56257
  const args = [
55904
56258
  "-i",
@@ -55917,10 +56271,10 @@ var FFmpegProcessor = class {
55917
56271
  onProgress?.(percent);
55918
56272
  }
55919
56273
  });
55920
- let frames = fs16.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path16.join(framesDir, f));
56274
+ let frames = fs17.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path16.join(framesDir, f));
55921
56275
  if (frames.length < opts.keyframeCount / 2) {
55922
- fs16.rmSync(framesDir, { recursive: true, force: true });
55923
- fs16.mkdirSync(framesDir, { recursive: true });
56276
+ fs17.rmSync(framesDir, { recursive: true, force: true });
56277
+ fs17.mkdirSync(framesDir, { recursive: true });
55924
56278
  const uniformArgs = [
55925
56279
  "-i",
55926
56280
  inputPath,
@@ -55936,10 +56290,10 @@ var FFmpegProcessor = class {
55936
56290
  onProgress?.(percent);
55937
56291
  }
55938
56292
  });
55939
- frames = fs16.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path16.join(framesDir, f));
56293
+ frames = fs17.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path16.join(framesDir, f));
55940
56294
  }
55941
56295
  const totalOutputSize = frames.reduce(
55942
- (sum, f) => sum + fs16.statSync(f).size,
56296
+ (sum, f) => sum + fs17.statSync(f).size,
55943
56297
  0
55944
56298
  );
55945
56299
  return {
@@ -56159,8 +56513,8 @@ var FileManager = class {
56159
56513
  directoryListingCache = /* @__PURE__ */ new Map();
56160
56514
  authFingerprint;
56161
56515
  ensureDirectories() {
56162
- if (!fs17.existsSync(this.tempDir)) {
56163
- fs17.mkdirSync(this.tempDir, { recursive: true });
56516
+ if (!fs18.existsSync(this.tempDir)) {
56517
+ fs18.mkdirSync(this.tempDir, { recursive: true });
56164
56518
  }
56165
56519
  }
56166
56520
  // ============================================================================
@@ -56191,7 +56545,7 @@ var FileManager = class {
56191
56545
  async stageLocal(filePath, options = {}) {
56192
56546
  const resolvedPath = resolvePath(filePath);
56193
56547
  const sourceName = options.sourceName || path17.basename(resolvedPath);
56194
- if (!fs17.existsSync(resolvedPath)) {
56548
+ if (!fs18.existsSync(resolvedPath)) {
56195
56549
  throw new FileManagerError(
56196
56550
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
56197
56551
  `File not found: ${filePath}`
@@ -56206,7 +56560,7 @@ var FileManager = class {
56206
56560
  this.fileCache.rememberPathHint(resolvedPath, hash, sourceName);
56207
56561
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
56208
56562
  const entry = this.fileCache.getByHash(hash);
56209
- const size = entry?.size ?? fs17.statSync(resolvedPath).size;
56563
+ const size = entry?.size ?? fs18.statSync(resolvedPath).size;
56210
56564
  return {
56211
56565
  success: true,
56212
56566
  hash,
@@ -56221,7 +56575,7 @@ var FileManager = class {
56221
56575
  async upload(filePath, options = {}) {
56222
56576
  const resolvedPath = resolvePath(filePath);
56223
56577
  const sourceName = options.sourceName || path17.basename(resolvedPath);
56224
- if (!fs17.existsSync(resolvedPath)) {
56578
+ if (!fs18.existsSync(resolvedPath)) {
56225
56579
  throw new FileManagerError(
56226
56580
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
56227
56581
  `File not found: ${filePath}`
@@ -56302,7 +56656,7 @@ var FileManager = class {
56302
56656
  // ============================================================================
56303
56657
  async uploadPic(filePath, options = {}) {
56304
56658
  const resolvedPath = resolvePath(filePath);
56305
- if (!fs17.existsSync(resolvedPath)) {
56659
+ if (!fs18.existsSync(resolvedPath)) {
56306
56660
  throw new FileManagerError(
56307
56661
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
56308
56662
  `File not found: ${filePath}`
@@ -56332,7 +56686,7 @@ var FileManager = class {
56332
56686
  this.fileCache.rememberPathHint(resolvedPath, result.hash, path17.basename(resolvedPath));
56333
56687
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
56334
56688
  try {
56335
- fs17.unlinkSync(optimizedPath);
56689
+ fs18.unlinkSync(optimizedPath);
56336
56690
  } catch {
56337
56691
  }
56338
56692
  return result;
@@ -56342,7 +56696,7 @@ var FileManager = class {
56342
56696
  // ============================================================================
56343
56697
  async uploadVideo(filePath, options = {}) {
56344
56698
  const resolvedPath = resolvePath(filePath);
56345
- if (!fs17.existsSync(resolvedPath)) {
56699
+ if (!fs18.existsSync(resolvedPath)) {
56346
56700
  throw new FileManagerError(
56347
56701
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
56348
56702
  `File not found: ${filePath}`
@@ -56736,13 +57090,13 @@ var FileManager = class {
56736
57090
  cleanupTempFiles(output) {
56737
57091
  try {
56738
57092
  if (typeof output === "string") {
56739
- if (fs17.existsSync(output)) {
56740
- fs17.unlinkSync(output);
57093
+ if (fs18.existsSync(output)) {
57094
+ fs18.unlinkSync(output);
56741
57095
  }
56742
57096
  } else {
56743
57097
  for (const file of output) {
56744
- if (fs17.existsSync(file)) {
56745
- fs17.unlinkSync(file);
57098
+ if (fs18.existsSync(file)) {
57099
+ fs18.unlinkSync(file);
56746
57100
  }
56747
57101
  }
56748
57102
  }
@@ -56774,7 +57128,7 @@ var FileManager = class {
56774
57128
  }];
56775
57129
  }
56776
57130
  const localPath = this.fileCache.getLocalPath(entry.hash);
56777
- if (localPath && fs17.existsSync(localPath)) {
57131
+ if (localPath && fs18.existsSync(localPath)) {
56778
57132
  return [{
56779
57133
  fileId,
56780
57134
  name: cacheEntry.name,
@@ -56871,7 +57225,7 @@ var FileManager = class {
56871
57225
  directories: []
56872
57226
  };
56873
57227
  try {
56874
- const entries = fs17.readdirSync(resolvedDir, { withFileTypes: true });
57228
+ const entries = fs18.readdirSync(resolvedDir, { withFileTypes: true });
56875
57229
  for (const entry of entries) {
56876
57230
  if (!entry.name || entry.name.startsWith(".")) {
56877
57231
  continue;
@@ -56885,7 +57239,7 @@ var FileManager = class {
56885
57239
  let isFile = entry.isFile();
56886
57240
  if (entry.isSymbolicLink()) {
56887
57241
  try {
56888
- const targetStat = fs17.statSync(fullPath);
57242
+ const targetStat = fs18.statSync(fullPath);
56889
57243
  isDirectory = targetStat.isDirectory();
56890
57244
  isFile = targetStat.isFile();
56891
57245
  } catch {
@@ -56903,7 +57257,7 @@ var FileManager = class {
56903
57257
  if (!type) {
56904
57258
  continue;
56905
57259
  }
56906
- const stat2 = fs17.statSync(fullPath);
57260
+ const stat2 = fs18.statSync(fullPath);
56907
57261
  listing.files.push({
56908
57262
  name: entry.name,
56909
57263
  path: fullPath,
@@ -57002,7 +57356,7 @@ function isInlineMediaRequest(request) {
57002
57356
  return request.kind === "image" || request.kind === "video";
57003
57357
  }
57004
57358
  async function prepareInlineMediaContent(params) {
57005
- const stat2 = await fs18.stat(params.request.absolutePath);
57359
+ const stat2 = await fs19.stat(params.request.absolutePath);
57006
57360
  const limitMb = getCapabilityLimitMb(params.model, params.request.kind);
57007
57361
  const limitBytes = limitMb * 1024 * 1024;
57008
57362
  if (stat2.size > limitBytes) {
@@ -57010,7 +57364,7 @@ async function prepareInlineMediaContent(params) {
57010
57364
  `${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${path18.basename(params.request.displayPath)} is ${(stat2.size / 1024 / 1024).toFixed(1)}MB. Configure a model with a file upload adapter, or compress/trim the file before reading it.`
57011
57365
  );
57012
57366
  }
57013
- const data = await fs18.readFile(params.request.absolutePath, "base64");
57367
+ const data = await fs19.readFile(params.request.absolutePath, "base64");
57014
57368
  const content = params.request.kind === "video" ? [{ type: "video", data, mimeType: params.request.mimeType }] : [{ type: "image", data, mimeType: params.request.mimeType }];
57015
57369
  return {
57016
57370
  content,
@@ -57380,22 +57734,22 @@ var ExecutionStateManager = class {
57380
57734
  };
57381
57735
 
57382
57736
  // src/session-trace.ts
57383
- import * as fs19 from "node:fs";
57737
+ import * as fs20 from "node:fs";
57384
57738
  import * as path19 from "node:path";
57385
57739
  function saveTraceFileBestEffort(tracePath, content) {
57386
57740
  const tempPath = `${tracePath}.${process.pid}.${Date.now()}.tmp`;
57387
57741
  try {
57388
- fs19.writeFileSync(tempPath, content, "utf8");
57742
+ fs20.writeFileSync(tempPath, content, "utf8");
57389
57743
  try {
57390
- fs19.renameSync(tempPath, tracePath);
57744
+ fs20.renameSync(tempPath, tracePath);
57391
57745
  return;
57392
57746
  } catch {
57393
57747
  try {
57394
- fs19.copyFileSync(tempPath, tracePath);
57748
+ fs20.copyFileSync(tempPath, tracePath);
57395
57749
  } catch {
57396
57750
  } finally {
57397
57751
  try {
57398
- fs19.unlinkSync(tempPath);
57752
+ fs20.unlinkSync(tempPath);
57399
57753
  } catch {
57400
57754
  }
57401
57755
  }
@@ -57409,9 +57763,9 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
57409
57763
  getSessionId: () => sessionManager.getActiveSessionId(),
57410
57764
  loadTrace: (sessionId) => {
57411
57765
  const tracePath = path19.join(sessionsDir, `${sessionId}.trace.json`);
57412
- if (!fs19.existsSync(tracePath)) return null;
57766
+ if (!fs20.existsSync(tracePath)) return null;
57413
57767
  try {
57414
- return JSON.parse(fs19.readFileSync(tracePath, "utf8"));
57768
+ return JSON.parse(fs20.readFileSync(tracePath, "utf8"));
57415
57769
  } catch {
57416
57770
  return null;
57417
57771
  }
@@ -60128,7 +60482,7 @@ async function handleForkCommand(host) {
60128
60482
  }
60129
60483
 
60130
60484
  // src/commands/interactive-skill-commands.ts
60131
- import * as fs20 from "fs";
60485
+ import * as fs21 from "fs";
60132
60486
  import * as os4 from "os";
60133
60487
  import * as path20 from "path";
60134
60488
 
@@ -60472,7 +60826,7 @@ function expandSkillCommand(host, text) {
60472
60826
  const skill = host.skills.find((s) => s.name === skillName);
60473
60827
  if (!skill) return text;
60474
60828
  try {
60475
- const content = fs20.readFileSync(skill.filePath, "utf-8");
60829
+ const content = fs21.readFileSync(skill.filePath, "utf-8");
60476
60830
  const body = host.stripFrontmatter(content).trim();
60477
60831
  const skillBlock = `<skill name="${skill.name}" location="${skill.filePath}">
60478
60832
  References are relative to ${skill.baseDir}.
@@ -60542,13 +60896,13 @@ async function handleSkillsCreate(host, args) {
60542
60896
  const skillDir = path20.join(skillsDir, name);
60543
60897
  const skillFile = path20.join(skillDir, "SKILL.md");
60544
60898
  console.error(`[SkillsCreate] Creating at: ${skillFile}`);
60545
- if (fs20.existsSync(skillDir)) {
60899
+ if (fs21.existsSync(skillDir)) {
60546
60900
  host.showError(`Skill "${name}" already exists at ${skillDir}`);
60547
60901
  return;
60548
60902
  }
60549
- fs20.mkdirSync(skillDir, { recursive: true });
60903
+ fs21.mkdirSync(skillDir, { recursive: true });
60550
60904
  const template = createSkillTemplate(name, description);
60551
- fs20.writeFileSync(skillFile, template, "utf-8");
60905
+ fs21.writeFileSync(skillFile, template, "utf-8");
60552
60906
  console.error(`[SkillsCreate] Successfully created skill`);
60553
60907
  host.chatContainer.addChild(new Spacer(1));
60554
60908
  host.chatContainer.addChild(new Text(theme.fg("accent", `\u2713 Created skill: ${name}`), 1, 0));
@@ -61258,6 +61612,7 @@ async function handleCompactCommand(host) {
61258
61612
  host.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore);
61259
61613
  const compactedMessages = host.sessionManager.getMessages();
61260
61614
  host.replaceAgentMessagesAndMarkSynced(compactedMessages);
61615
+ host.resetFileObservationState();
61261
61616
  host.streamingComponent = void 0;
61262
61617
  host.pendingTools.clear();
61263
61618
  host.chatContainer.clear();
@@ -62018,7 +62373,7 @@ function setupInteractiveEditorSubmitHandler(host) {
62018
62373
  }
62019
62374
 
62020
62375
  // src/input/interactive-file-pipeline.ts
62021
- import * as fs23 from "fs";
62376
+ import * as fs24 from "fs";
62022
62377
  import * as path23 from "path";
62023
62378
 
62024
62379
  // src/components/file-picker.ts
@@ -62240,7 +62595,7 @@ var FilePickerComponent = class extends Container {
62240
62595
  };
62241
62596
 
62242
62597
  // src/files/commands/file-commands.ts
62243
- import * as fs21 from "node:fs";
62598
+ import * as fs22 from "node:fs";
62244
62599
  import * as path21 from "node:path";
62245
62600
  var FileCommands = class {
62246
62601
  context;
@@ -62257,7 +62612,7 @@ var FileCommands = class {
62257
62612
  return;
62258
62613
  }
62259
62614
  const filePath = resolvePath(parsed.path);
62260
- if (!fs21.existsSync(filePath)) {
62615
+ if (!fs22.existsSync(filePath)) {
62261
62616
  this.context.showError(`File not found: ${parsed.path}`);
62262
62617
  return;
62263
62618
  }
@@ -62296,7 +62651,7 @@ var FileCommands = class {
62296
62651
  return;
62297
62652
  }
62298
62653
  const resolvedPath = resolvePath(filePath);
62299
- if (!fs21.existsSync(resolvedPath)) {
62654
+ if (!fs22.existsSync(resolvedPath)) {
62300
62655
  this.context.showError(`File not found: ${filePath}`);
62301
62656
  return;
62302
62657
  }
@@ -62327,7 +62682,7 @@ var FileCommands = class {
62327
62682
  return;
62328
62683
  }
62329
62684
  const resolvedPath = resolvePath(parsed.path);
62330
- if (!fs21.existsSync(resolvedPath)) {
62685
+ if (!fs22.existsSync(resolvedPath)) {
62331
62686
  this.context.showError(`File not found: ${parsed.path}`);
62332
62687
  return;
62333
62688
  }
@@ -62805,7 +63160,7 @@ var FileStatusMonitor = class {
62805
63160
  };
62806
63161
 
62807
63162
  // src/files/mention/mention-handler.ts
62808
- import * as fs22 from "node:fs";
63163
+ import * as fs23 from "node:fs";
62809
63164
  import * as path22 from "node:path";
62810
63165
  var MentionHandler = class {
62811
63166
  fileManager;
@@ -63175,8 +63530,8 @@ var MentionHandler = class {
63175
63530
  }
63176
63531
  if (this.isPath(query)) {
63177
63532
  const resolvedPath = resolvePath(query);
63178
- if (fs22.existsSync(resolvedPath)) {
63179
- const stats = fs22.statSync(resolvedPath);
63533
+ if (fs23.existsSync(resolvedPath)) {
63534
+ const stats = fs23.statSync(resolvedPath);
63180
63535
  if (stats.isFile()) {
63181
63536
  const type = FileCache.getFileTypeFromName(resolvedPath);
63182
63537
  const name = path22.basename(resolvedPath);
@@ -63200,7 +63555,7 @@ var MentionHandler = class {
63200
63555
  return void 0;
63201
63556
  }
63202
63557
  const queryPath = this.isPath(query) ? resolvePath(query) : void 0;
63203
- const filter = queryPath ? fs22.existsSync(queryPath) && fs22.statSync(queryPath).isDirectory() ? "" : path22.basename(queryPath) : query;
63558
+ const filter = queryPath ? fs23.existsSync(queryPath) && fs23.statSync(queryPath).isDirectory() ? "" : path22.basename(queryPath) : query;
63204
63559
  const entries = this.fileManager.listPathEntries(currentDir, filter);
63205
63560
  const options = [];
63206
63561
  const homeDir = process.env.HOME || "";
@@ -63241,7 +63596,7 @@ var MentionHandler = class {
63241
63596
  getBrowserDirectory(query = this.currentQuery) {
63242
63597
  if (this.isPath(query)) {
63243
63598
  const resolvedPath = resolvePath(query);
63244
- if (fs22.existsSync(resolvedPath) && fs22.statSync(resolvedPath).isDirectory()) {
63599
+ if (fs23.existsSync(resolvedPath) && fs23.statSync(resolvedPath).isDirectory()) {
63245
63600
  return resolvedPath;
63246
63601
  }
63247
63602
  return path22.dirname(resolvedPath);
@@ -63605,13 +63960,13 @@ function convertPreparedAttachmentItems(items) {
63605
63960
  break;
63606
63961
  case "image": {
63607
63962
  if (!item.data && !item.path) return void 0;
63608
- const data = item.data ?? fs23.readFileSync(item.path, "base64");
63963
+ const data = item.data ?? fs24.readFileSync(item.path, "base64");
63609
63964
  converted.push({ type: "image", data, mimeType: item.mimeType });
63610
63965
  break;
63611
63966
  }
63612
63967
  case "video": {
63613
63968
  if (!item.data && !item.path) return void 0;
63614
- const data = item.data ?? fs23.readFileSync(item.path, "base64");
63969
+ const data = item.data ?? fs24.readFileSync(item.path, "base64");
63615
63970
  converted.push({ type: "video", data, mimeType: item.mimeType });
63616
63971
  break;
63617
63972
  }
@@ -64017,6 +64372,10 @@ function buildCodingAgentGuidelinesSection(tools = []) {
64017
64372
  if (hasGrep || hasFind || hasList) {
64018
64373
  guidelines.push("Prefer grep_text, find_files, and list_dir for workspace exploration when they are sufficient.");
64019
64374
  }
64375
+ if (hasGrep) {
64376
+ guidelines.push("Use grep_text outputMode='files_with_matches' to find candidate files, outputMode='count' to estimate impact, and outputMode='content' when you need matching lines and context.");
64377
+ guidelines.push("After a broad grep_text search, narrow the path, glob, pattern, outputMode, offset, or limit instead of repeating the same broad search.");
64378
+ }
64020
64379
  if (hasWebResearch) {
64021
64380
  guidelines.push("Use web_research for general public web research, current information, official docs, news, releases, issues, or webpage summaries; it searches, fetches, and returns cited sources.");
64022
64381
  guidelines.push("When web_research returns fetched sources that answer the request, synthesize the answer from that pack instead of calling web_search or web_fetch again.");
@@ -64036,20 +64395,26 @@ function buildCodingAgentGuidelinesSection(tools = []) {
64036
64395
  guidelines.push("Read the current file before edit_file changes, then use a precise unique replacement.");
64037
64396
  }
64038
64397
  if (hasRead) {
64398
+ guidelines.push("Use read_file offset/limit for large files; if read_file says a range is unchanged, do not repeat the same read and choose a different range or search instead.");
64039
64399
  guidelines.push("Use read_file directly for media and documents when the file-understanding route is available.");
64040
64400
  }
64041
64401
  if (hasEdit) {
64042
- guidelines.push("If edit_file fails because text is missing or not unique, read the current file and retry with a larger exact block.");
64402
+ guidelines.push("If edit_file fails because text is missing, read the current file and retry with exact text copied from the latest file contents.");
64403
+ guidelines.push("If edit_file fails because text is not unique, read the current file and retry with a larger exact block, or set replaceAll to true if every occurrence should be replaced.");
64043
64404
  }
64044
64405
  if (hasWrite) {
64045
- guidelines.push("Use write_file for new files or complete rewrites when a targeted edit is not appropriate.");
64406
+ guidelines.push("Use write_file for new files or true complete rewrites; before overwriting an existing file, read the current full file with read_file, and prefer edit_file for targeted changes.");
64046
64407
  }
64047
64408
  if (hasBash) {
64048
64409
  guidelines.push("Pass only executable shell commands to bash, not numbered plan items, headings, or prose.");
64410
+ if (hasWrite || hasEdit) {
64411
+ guidelines.push("Do not use shell redirection, cat > file, tee, or heredoc to create or overwrite files when write_file or edit_file can do it; never use Bash to bypass write_file overwrite guards.");
64412
+ }
64049
64413
  guidelines.push("If bash times out or truncates output, adjust the command or inspect the reported full output path instead of repeating the same command.");
64050
64414
  }
64051
64415
  if (hasTodo) {
64052
- guidelines.push("Use manage_todo_list for multi-step work: create the list, complete only the current item, then let the tool advance the next item.");
64416
+ guidelines.push("Use manage_todo_list only for multi-step work: create the list, complete only the current item when it is genuinely done, and let the tool advance the next item.");
64417
+ guidelines.push("Do not complete a todo item while implementation is partial, tests or verification are failing, or the required verification has not run.");
64053
64418
  }
64054
64419
  guidelines.push(
64055
64420
  "Once the root cause or required change is clear, make a small concrete edit instead of continuing unrelated exploration.",
@@ -65056,6 +65421,7 @@ function createInteractiveAgentSessionController(host) {
65056
65421
  host.footer.setState({ status: "ready" });
65057
65422
  return;
65058
65423
  }
65424
+ host.resetFileObservationState();
65059
65425
  const contextUsage = host.calculateContextUsage();
65060
65426
  const contextWindow = host.options.model?.contextWindow ?? 0;
65061
65427
  const contextPercent = contextWindow > 0 && contextUsage.tokens !== null ? contextUsage.tokens / contextWindow * 100 : 0;
@@ -65086,7 +65452,7 @@ var RUNTIME_MODE_CONTEXT_MARKER = "<runtime-mode-context>";
65086
65452
  var RUNTIME_MODE_CONTEXT_END_MARKER = "</runtime-mode-context>";
65087
65453
  var STALE_SYSTEM_REMINDER_RE = /<system-reminder>\s*# Plan Mode[\s\S]*?<\/system-reminder>\s*/gi;
65088
65454
  var STALE_RUNTIME_CONTEXT_RE = /<runtime-mode-context>[\s\S]*?<\/runtime-mode-context>\s*/gi;
65089
- function isRecord2(value) {
65455
+ function isRecord3(value) {
65090
65456
  return !!value && typeof value === "object" && !Array.isArray(value);
65091
65457
  }
65092
65458
  function cleanText(text) {
@@ -65102,7 +65468,7 @@ function cleanText(text) {
65102
65468
  return { text: withoutPlanReminder, stripped };
65103
65469
  }
65104
65470
  function stripUserMessage(message) {
65105
- if (!isRecord2(message) || message.role !== "user") {
65471
+ if (!isRecord3(message) || message.role !== "user") {
65106
65472
  return { message, stripped: 0 };
65107
65473
  }
65108
65474
  const content = message.content;
@@ -65122,13 +65488,13 @@ function stripUserMessage(message) {
65122
65488
  }
65123
65489
  let stripped = 0;
65124
65490
  const nextContent = content.map((block) => {
65125
- if (!isRecord2(block) || block.type !== "text" || typeof block.text !== "string") {
65491
+ if (!isRecord3(block) || block.type !== "text" || typeof block.text !== "string") {
65126
65492
  return block;
65127
65493
  }
65128
65494
  const cleaned = cleanText(block.text);
65129
65495
  stripped += cleaned.stripped;
65130
65496
  return { ...block, text: cleaned.text };
65131
- }).filter((block) => !(isRecord2(block) && block.type === "text" && String(block.text ?? "").length === 0));
65497
+ }).filter((block) => !(isRecord3(block) && block.type === "text" && String(block.text ?? "").length === 0));
65132
65498
  if (stripped === 0) return { message, stripped: 0 };
65133
65499
  return {
65134
65500
  message: {
@@ -65144,7 +65510,7 @@ function stripRuntimeModeContext(messages) {
65144
65510
  for (const message of messages) {
65145
65511
  const result = stripUserMessage(message);
65146
65512
  stripped += result.stripped;
65147
- if (isRecord2(result.message) && result.message.role === "user") {
65513
+ if (isRecord3(result.message) && result.message.role === "user") {
65148
65514
  const content = result.message.content;
65149
65515
  if (typeof content === "string" && content.trim().length === 0) {
65150
65516
  continue;
@@ -65186,7 +65552,7 @@ function buildRuntimeModeContext(state) {
65186
65552
  function findLatestUserIndex(messages) {
65187
65553
  for (let index = messages.length - 1; index >= 0; index--) {
65188
65554
  const message = messages[index];
65189
- if (isRecord2(message) && message.role === "user") {
65555
+ if (isRecord3(message) && message.role === "user") {
65190
65556
  return index;
65191
65557
  }
65192
65558
  }
@@ -65665,7 +66031,7 @@ var AttachmentResolver = class {
65665
66031
  };
65666
66032
 
65667
66033
  // src/extensions/loader.ts
65668
- import * as fs24 from "node:fs";
66034
+ import * as fs25 from "node:fs";
65669
66035
  import * as os5 from "os";
65670
66036
  import * as path24 from "path";
65671
66037
  import { pathToFileURL } from "node:url";
@@ -65849,7 +66215,7 @@ function normalizeExtensionImportPath(extensionPath) {
65849
66215
  }
65850
66216
  async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, hasUI, actions) {
65851
66217
  const resolvedPath = resolvePath2(extensionPath, cwd);
65852
- if (!fs24.existsSync(resolvedPath)) {
66218
+ if (!fs25.existsSync(resolvedPath)) {
65853
66219
  return { extension: null, error: `Extension not found: ${extensionPath}` };
65854
66220
  }
65855
66221
  try {
@@ -65870,12 +66236,12 @@ async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, h
65870
66236
  }
65871
66237
  }
65872
66238
  function discoverExtensionsInDir(dir) {
65873
- if (!fs24.existsSync(dir)) {
66239
+ if (!fs25.existsSync(dir)) {
65874
66240
  return [];
65875
66241
  }
65876
66242
  const discovered = [];
65877
66243
  try {
65878
- const entries = fs24.readdirSync(dir, { withFileTypes: true });
66244
+ const entries = fs25.readdirSync(dir, { withFileTypes: true });
65879
66245
  for (const entry of entries) {
65880
66246
  const entryPath = path24.join(dir, entry.name);
65881
66247
  if (entry.isFile() && (entry.name.endsWith(".cjs") || entry.name.endsWith(".js") || entry.name.endsWith(".ts"))) {
@@ -65884,13 +66250,13 @@ function discoverExtensionsInDir(dir) {
65884
66250
  }
65885
66251
  if (entry.isDirectory()) {
65886
66252
  const packageJsonPath = path24.join(entryPath, "package.json");
65887
- if (fs24.existsSync(packageJsonPath)) {
66253
+ if (fs25.existsSync(packageJsonPath)) {
65888
66254
  try {
65889
- const pkg = JSON.parse(fs24.readFileSync(packageJsonPath, "utf-8"));
66255
+ const pkg = JSON.parse(fs25.readFileSync(packageJsonPath, "utf-8"));
65890
66256
  const manifest = pkg.pie;
65891
66257
  if (manifest?.main) {
65892
66258
  const mainPath = path24.resolve(entryPath, manifest.main);
65893
- if (fs24.existsSync(mainPath)) {
66259
+ if (fs25.existsSync(mainPath)) {
65894
66260
  discovered.push({
65895
66261
  entryPath: mainPath,
65896
66262
  manifestName: manifest.name || pkg.name
@@ -65902,17 +66268,17 @@ function discoverExtensionsInDir(dir) {
65902
66268
  }
65903
66269
  }
65904
66270
  const indexCjs = path24.join(entryPath, "index.cjs");
65905
- if (fs24.existsSync(indexCjs)) {
66271
+ if (fs25.existsSync(indexCjs)) {
65906
66272
  discovered.push({ entryPath: indexCjs });
65907
66273
  continue;
65908
66274
  }
65909
66275
  const indexJs = path24.join(entryPath, "index.js");
65910
- if (fs24.existsSync(indexJs)) {
66276
+ if (fs25.existsSync(indexJs)) {
65911
66277
  discovered.push({ entryPath: indexJs });
65912
66278
  continue;
65913
66279
  }
65914
66280
  const indexTs = path24.join(entryPath, "index.ts");
65915
- if (fs24.existsSync(indexTs)) {
66281
+ if (fs25.existsSync(indexTs)) {
65916
66282
  discovered.push({ entryPath: indexTs });
65917
66283
  continue;
65918
66284
  }
@@ -65961,11 +66327,11 @@ async function loadExtensions(configuredPaths, cwd, uiContext, abortFn, isIdleFn
65961
66327
  }
65962
66328
  for (const p of configuredPaths) {
65963
66329
  const resolved = resolvePath2(p, cwd);
65964
- if (!fs24.existsSync(resolved)) {
66330
+ if (!fs25.existsSync(resolved)) {
65965
66331
  errors.push({ path: p, error: `Extension path not found: ${p}` });
65966
66332
  continue;
65967
66333
  }
65968
- if (!fs24.statSync(resolved).isDirectory()) {
66334
+ if (!fs25.statSync(resolved).isDirectory()) {
65969
66335
  errors.push({ path: p, error: `Extension path must be a directory: ${p}` });
65970
66336
  continue;
65971
66337
  }
@@ -66810,6 +67176,7 @@ var InteractiveMode = class {
66810
67176
  allowlistedDirs
66811
67177
  }),
66812
67178
  configDir: this.options.configDir,
67179
+ fileObservationState: this.options.fileObservationState,
66813
67180
  getAgentModel: () => this.options.model,
66814
67181
  getSessionId: () => this.sessionManager.getActiveSessionId() || void 0,
66815
67182
  resolveToolModel: (purpose) => this.options.modelRegistry.resolveToolModel(purpose, this.options.model),
@@ -66837,6 +67204,9 @@ var InteractiveMode = class {
66837
67204
  )
66838
67205
  };
66839
67206
  }
67207
+ resetFileObservationState() {
67208
+ this.options.fileObservationState.clear();
67209
+ }
66840
67210
  getRuntimeModeState() {
66841
67211
  const pendingTransition = this.getPendingRuntimeModeTransition();
66842
67212
  const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || "local";
@@ -66945,7 +67315,7 @@ var InteractiveMode = class {
66945
67315
  if (savedLevel) {
66946
67316
  this.thinkingLevel = savedLevel;
66947
67317
  }
66948
- const { Agent } = await import("./chunks/src-6WPNVGT2.js");
67318
+ const { Agent } = await import("./chunks/src-2FHZO63Y.js");
66949
67319
  const activeSession = this.sessionManager.getActiveSession();
66950
67320
  this.agent = new Agent({
66951
67321
  initialState: {
@@ -67347,10 +67717,12 @@ async function composeCliRuntime(params) {
67347
67717
  inputSummary: `provider=${settingsManager.getDefaultProvider() || "unset"} model=${settingsManager.getDefaultModel() || "unset"}`,
67348
67718
  outputSummary: `provider=${provider} model=${modelId} configured=${!initialModel.unconfigured}`
67349
67719
  });
67350
- const cwd = process.cwd();
67720
+ const cwd = params.cwd ?? process.cwd();
67351
67721
  const sessionManager = createSessionManager({ sessionsDir: paths.sessionsDir });
67352
67722
  if (params.explicitSessionId) {
67353
- const loaded = await sessionManager.loadSession(params.explicitSessionId);
67723
+ const loaded = await sessionManager.loadSession(params.explicitSessionId, {
67724
+ warnIfMissing: params.warnIfExplicitSessionMissing
67725
+ });
67354
67726
  if (!loaded) {
67355
67727
  await sessionManager.createSession(void 0, void 0, params.explicitSessionId);
67356
67728
  } else {
@@ -67374,7 +67746,13 @@ async function composeCliRuntime(params) {
67374
67746
  await sessionManager.createSession();
67375
67747
  }
67376
67748
  syncSessionModelMetadata(sessionManager, model, settingsManager.getDefaultThinkingLevel() || "off");
67749
+ const activeSession = sessionManager.getActiveSession();
67750
+ if (activeSession && activeSession.metadata.cwd !== cwd) {
67751
+ activeSession.metadata.cwd = cwd;
67752
+ await sessionManager.save();
67753
+ }
67377
67754
  const sessionId = sessionManager.getActiveSession()?.id;
67755
+ const fileObservationState = createFileObservationState();
67378
67756
  if (sessionId) {
67379
67757
  if (process.env.PIE_DEBUG && !fileLogger.isEnabled()) {
67380
67758
  fileLogger.enable();
@@ -67403,6 +67781,7 @@ async function composeCliRuntime(params) {
67403
67781
  const fileSystemToolOptions = {
67404
67782
  ...buildCliFileAccessOptions({ cwd, configDir: paths.configDir, skills, allowlistedDirs: [paths.configDir] }),
67405
67783
  configDir: paths.configDir,
67784
+ fileObservationState,
67406
67785
  getAgentModel: getCurrentModel,
67407
67786
  getSessionId: () => sessionManager.getActiveSessionId() || void 0,
67408
67787
  resolveToolModel: (purpose) => modelRegistry.resolveToolModel(purpose, getCurrentModel()),
@@ -67475,6 +67854,7 @@ async function composeCliRuntime(params) {
67475
67854
  skillsSection,
67476
67855
  knowledgeSection,
67477
67856
  tools,
67857
+ fileObservationState,
67478
67858
  extensionPaths: params.extensionPaths,
67479
67859
  compositionTrace,
67480
67860
  createInteractiveOptions() {
@@ -67482,6 +67862,7 @@ async function composeCliRuntime(params) {
67482
67862
  model,
67483
67863
  apiKey,
67484
67864
  tools,
67865
+ fileObservationState,
67485
67866
  sessionManager,
67486
67867
  skills,
67487
67868
  cwd,
@@ -67612,7 +67993,7 @@ async function runPrintMode(params) {
67612
67993
  `);
67613
67994
  console.log("Assistant: ");
67614
67995
  }
67615
- const { Agent: AgentClass } = await import("./chunks/src-6WPNVGT2.js");
67996
+ const { Agent: AgentClass } = await import("./chunks/src-2FHZO63Y.js");
67616
67997
  let agent;
67617
67998
  const printModeExtensions = await loadPrintModeExtensions({
67618
67999
  cwd: runtime.cwd,
@@ -67704,6 +68085,8 @@ async function runPrintMode(params) {
67704
68085
  console.error(event.failure.kind === "context_overflow" ? "Context overflow detected, compacting..." : "Auto-compacting context before retry...");
67705
68086
  } else if (event.type === "auto_compaction_start") {
67706
68087
  console.error(event.reason === "overflow" ? "Context overflow detected, compacting..." : "Auto-compacting context...");
68088
+ } else if (event.type === "auto_compaction_end" && !event.errorMessage) {
68089
+ runtime.fileObservationState.clear();
67707
68090
  } else if (event.type === "turn_retry_started") {
67708
68091
  console.error(`Retrying request (${event.attempt}/${event.maxRetries})...`);
67709
68092
  } else if (event.type === "turn_retry_succeeded") {
@@ -67830,7 +68213,7 @@ function toJsonValue(value, depth = 0) {
67830
68213
  }
67831
68214
  return result;
67832
68215
  }
67833
- function isRecord3(value) {
68216
+ function isRecord4(value) {
67834
68217
  return !!value && typeof value === "object" && !Array.isArray(value);
67835
68218
  }
67836
68219
  function parseInput(line) {
@@ -67840,7 +68223,7 @@ function parseInput(line) {
67840
68223
  } catch {
67841
68224
  return null;
67842
68225
  }
67843
- if (!isRecord3(parsed) || typeof parsed.type !== "string") return null;
68226
+ if (!isRecord4(parsed) || typeof parsed.type !== "string") return null;
67844
68227
  if (parsed.type === "shutdown") {
67845
68228
  return { type: "shutdown", reason: typeof parsed.reason === "string" ? parsed.reason : void 0 };
67846
68229
  }
@@ -67859,7 +68242,7 @@ function parseInput(line) {
67859
68242
  turnId: parsed.turnId,
67860
68243
  prompt: parsed.prompt,
67861
68244
  cwd: typeof parsed.cwd === "string" ? parsed.cwd : void 0,
67862
- metadata: isRecord3(parsed.metadata) ? parsed.metadata : void 0
68245
+ metadata: isRecord4(parsed.metadata) ? parsed.metadata : void 0
67863
68246
  };
67864
68247
  }
67865
68248
  return null;
@@ -67893,15 +68276,15 @@ function readProgressText(value) {
67893
68276
  function extractJsonEventsToolProgressText(partialResult) {
67894
68277
  const plainText = readProgressText(partialResult).trim();
67895
68278
  if (plainText) return plainText;
67896
- if (!isRecord3(partialResult)) return "";
68279
+ if (!isRecord4(partialResult)) return "";
67897
68280
  const content = partialResult.content;
67898
68281
  if (Array.isArray(content)) {
67899
- return content.map((block) => isRecord3(block) && block.type === "text" ? readProgressText(block.text) : "").filter(Boolean).join("\n").trim();
68282
+ return content.map((block) => isRecord4(block) && block.type === "text" ? readProgressText(block.text) : "").filter(Boolean).join("\n").trim();
67900
68283
  }
67901
68284
  const directText = readProgressText(partialResult.text) || readProgressText(partialResult.message);
67902
68285
  if (directText) return directText.trim();
67903
68286
  const details = partialResult.details;
67904
- if (isRecord3(details)) {
68287
+ if (isRecord4(details)) {
67905
68288
  return (readProgressText(details.text) || readProgressText(details.message)).trim();
67906
68289
  }
67907
68290
  return "";
@@ -67988,12 +68371,14 @@ async function loadJsonModeExtensions(params) {
67988
68371
  async function runJsonEventsMode(params) {
67989
68372
  const sessionId = params.explicitSessionId || params.runtime?.sessionManager.getActiveSession()?.id || `pie-json-${Date.now()}`;
67990
68373
  let activeTurn = null;
68374
+ let runtime = params.runtime;
67991
68375
  let agent;
67992
68376
  let controller;
67993
68377
  let disposeAgentSubscription;
67994
68378
  let disposeSemanticSubscription;
67995
68379
  let trace;
67996
68380
  let lastRetryEvent;
68381
+ let mockActiveEntryId;
67997
68382
  const noProgressTimeoutMs = Number(process.env.PIE_JSON_EVENTS_NO_PROGRESS_MS || 6e5);
67998
68383
  const mockResponseDelayMs = Number(process.env.PIE_TEST_MOCK_RESPONSE_DELAY_MS || 0);
67999
68384
  writeEvent({ type: "agent.ready", sessionId });
@@ -68013,6 +68398,7 @@ async function runJsonEventsMode(params) {
68013
68398
  }
68014
68399
  function display(chunk, options) {
68015
68400
  if (!activeTurn || !chunk) return;
68401
+ activeTurn.outputStarted = true;
68016
68402
  if (options?.appendToSummary !== false) {
68017
68403
  activeTurn.summary += chunk;
68018
68404
  }
@@ -68035,6 +68421,78 @@ async function runJsonEventsMode(params) {
68035
68421
  activeTurn.pendingAssistantOutput = "";
68036
68422
  }
68037
68423
  }
68424
+ function activeHeadEntryId() {
68425
+ return mockActiveEntryId ?? runtime?.sessionManager.getActiveEntryId() ?? void 0;
68426
+ }
68427
+ function persistedMockMetadata(existing, activeEntryId, rootEntryId, cwd) {
68428
+ const metadata = {};
68429
+ if (existing) {
68430
+ for (const [key, value] of Object.entries(existing)) {
68431
+ if (["id", "createdAt", "updatedAt", "entryCount", "messageCount", "activeEntryId", "rootEntryId"].includes(key)) {
68432
+ continue;
68433
+ }
68434
+ metadata[key] = value;
68435
+ }
68436
+ }
68437
+ metadata.name = typeof existing?.name === "string" ? existing.name : `Session ${sessionId.slice(0, 8)}`;
68438
+ if (cwd || existing?.cwd || runtime?.cwd) {
68439
+ metadata.cwd = cwd ?? existing?.cwd ?? runtime?.cwd;
68440
+ }
68441
+ metadata.activeEntryId = activeEntryId;
68442
+ metadata.rootEntryId = existing?.rootEntryId ?? rootEntryId;
68443
+ return metadata;
68444
+ }
68445
+ async function persistMockTurn(message, assistantText) {
68446
+ const store = new FileSessionStore(getSessionsDir());
68447
+ const existing = await store.load(message.sessionId ?? sessionId);
68448
+ const startedAt = activeTurn?.startedAt ?? Date.now();
68449
+ const userEntryId = generateEntryId();
68450
+ const assistantEntryId = generateEntryId();
68451
+ const parentId = existing?.metadata.activeEntryId ?? null;
68452
+ const userEntry = {
68453
+ id: userEntryId,
68454
+ parentId,
68455
+ type: "message",
68456
+ timestamp: startedAt,
68457
+ message: {
68458
+ role: "user",
68459
+ content: message.prompt,
68460
+ timestamp: startedAt
68461
+ }
68462
+ };
68463
+ const assistantTimestamp = Date.now();
68464
+ const assistantMessage = {
68465
+ role: "assistant",
68466
+ content: [{ type: "text", text: assistantText }],
68467
+ api: "mock",
68468
+ provider: "mock",
68469
+ model: "mock",
68470
+ usage: {
68471
+ input: 0,
68472
+ output: 0,
68473
+ cacheRead: 0,
68474
+ cacheWrite: 0,
68475
+ totalTokens: 0,
68476
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
68477
+ },
68478
+ stopReason: "stop",
68479
+ timestamp: assistantTimestamp
68480
+ };
68481
+ const assistantEntry = {
68482
+ id: assistantEntryId,
68483
+ parentId: userEntryId,
68484
+ type: "message",
68485
+ timestamp: assistantTimestamp,
68486
+ message: assistantMessage
68487
+ };
68488
+ const entries = [...existing?.entries ?? [], userEntry, assistantEntry];
68489
+ await store.save(
68490
+ message.sessionId ?? sessionId,
68491
+ entries,
68492
+ persistedMockMetadata(existing?.metadata, assistantEntryId, existing?.metadata.rootEntryId ?? userEntryId, message.cwd)
68493
+ );
68494
+ return assistantEntryId;
68495
+ }
68038
68496
  function flushAssistantOutput(fallbackText = "") {
68039
68497
  if (!activeTurn) return;
68040
68498
  const chunk = activeTurn.pendingAssistantOutput || fallbackText;
@@ -68047,21 +68505,38 @@ async function runJsonEventsMode(params) {
68047
68505
  const turn = activeTurn;
68048
68506
  if (!turn || turn.finalized) return;
68049
68507
  turn.finalized = true;
68508
+ const headEntryId = activeHeadEntryId();
68509
+ const base = {
68510
+ sessionId: turn.sessionId,
68511
+ turnId: turn.turnId,
68512
+ headEntryId,
68513
+ activeEntryId: headEntryId
68514
+ };
68050
68515
  switch (kind) {
68051
68516
  case "completed":
68052
- writeEvent({ type: "turn.completed", sessionId: turn.sessionId, turnId: turn.turnId, summary: (detail ?? turn.summary).trim() });
68517
+ writeEvent({ type: "turn.completed", ...base, summary: (detail ?? turn.summary).trim() });
68053
68518
  break;
68054
68519
  case "failed":
68055
- writeEvent({ type: "turn.failed", sessionId: turn.sessionId, turnId: turn.turnId, error: detail || "turn failed" });
68520
+ writeEvent({ type: "turn.failed", ...base, error: detail || "turn failed" });
68056
68521
  break;
68057
68522
  case "cancelled":
68058
- writeEvent({ type: "turn.cancelled", sessionId: turn.sessionId, turnId: turn.turnId, reason: detail || "interrupted" });
68523
+ writeEvent({ type: "turn.cancelled", ...base, reason: detail || "interrupted" });
68059
68524
  break;
68060
68525
  case "stalled":
68061
- writeEvent({ type: "turn.stalled", sessionId: turn.sessionId, turnId: turn.turnId, reason: detail || "no_progress_timeout" });
68526
+ writeEvent({ type: "turn.stalled", ...base, reason: detail || "no_progress_timeout" });
68062
68527
  break;
68063
68528
  }
68064
68529
  }
68530
+ function emitSettled(turn) {
68531
+ const headEntryId = activeHeadEntryId();
68532
+ writeEvent({
68533
+ type: "turn.settled",
68534
+ sessionId: turn.sessionId,
68535
+ turnId: turn.turnId,
68536
+ headEntryId,
68537
+ activeEntryId: headEntryId
68538
+ });
68539
+ }
68065
68540
  function rememberTerminal(kind, detail, options) {
68066
68541
  if (!activeTurn || activeTurn.finalized) return;
68067
68542
  if (activeTurn.pendingTerminal && options?.overwrite === false) return;
@@ -68120,13 +68595,11 @@ async function runJsonEventsMode(params) {
68120
68595
  }
68121
68596
  function handleControllerEvent(event) {
68122
68597
  trace?.noteRuntimeEvent(event.type, event);
68598
+ if (event.type === "auto_compaction_end" && !event.errorMessage) {
68599
+ runtime?.fileObservationState.clear();
68600
+ }
68123
68601
  if (event.type === "turn_settled" && activeTurn) {
68124
- finalizePendingTerminal();
68125
- writeEvent({
68126
- type: "turn.settled",
68127
- sessionId: activeTurn.sessionId,
68128
- turnId: activeTurn.turnId
68129
- });
68602
+ touch();
68130
68603
  return;
68131
68604
  }
68132
68605
  if (!activeTurn || activeTurn.finalized) return;
@@ -68226,16 +68699,35 @@ async function runJsonEventsMode(params) {
68226
68699
  rememberTerminal("cancelled", event.reason, { overwrite: false });
68227
68700
  }
68228
68701
  }
68229
- async function ensureRuntime() {
68230
- if (params.mockResponse !== void 0 || controller) return;
68231
- const runtime = params.runtime;
68702
+ async function disposeRuntime() {
68703
+ disposeAgentSubscription?.();
68704
+ disposeAgentSubscription = void 0;
68705
+ disposeSemanticSubscription?.();
68706
+ disposeSemanticSubscription = void 0;
68707
+ controller?.dispose();
68708
+ controller = void 0;
68709
+ agent = void 0;
68710
+ try {
68711
+ await runtime?.sessionManager.save();
68712
+ } catch {
68713
+ }
68714
+ trace?.flush();
68715
+ trace = void 0;
68716
+ }
68717
+ async function ensureRuntime(requestedCwd) {
68718
+ if (params.mockResponse !== void 0) return;
68719
+ const effectiveCwd = requestedCwd ?? process.cwd();
68720
+ if (params.createRuntime && (!runtime || runtime.cwd !== effectiveCwd)) {
68721
+ await disposeRuntime();
68722
+ runtime = await params.createRuntime({ cwd: effectiveCwd, sessionId });
68723
+ }
68232
68724
  if (!runtime) {
68233
68725
  throw new Error("JSON events mode requires a CLI runtime");
68234
68726
  }
68235
- if (runtime.initialModel.unconfigured) {
68727
+ if (runtime.initialModel.unconfigured || controller) {
68236
68728
  return;
68237
68729
  }
68238
- const { Agent: AgentClass } = await import("./chunks/src-6WPNVGT2.js");
68730
+ const { Agent: AgentClass } = await import("./chunks/src-2FHZO63Y.js");
68239
68731
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
68240
68732
  const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
68241
68733
  recordCliCompositionStep(runtime.compositionTrace, {
@@ -68341,6 +68833,7 @@ async function runJsonEventsMode(params) {
68341
68833
  interrupted: false,
68342
68834
  stalled: false,
68343
68835
  finalized: false,
68836
+ outputStarted: false,
68344
68837
  summary: "",
68345
68838
  pendingAssistantOutput: ""
68346
68839
  };
@@ -68354,30 +68847,43 @@ async function runJsonEventsMode(params) {
68354
68847
  return;
68355
68848
  }
68356
68849
  display(params.mockResponse);
68850
+ try {
68851
+ mockActiveEntryId = await persistMockTurn(message, params.mockResponse);
68852
+ } catch (error) {
68853
+ finalize("failed", error instanceof Error ? error.message : String(error));
68854
+ if (activeTurn === turn) emitSettled(turn);
68855
+ if (activeTurn === turn) activeTurn = null;
68856
+ return;
68857
+ }
68357
68858
  finalize("completed");
68859
+ if (activeTurn === turn) emitSettled(turn);
68358
68860
  if (activeTurn === turn) activeTurn = null;
68359
68861
  return;
68360
68862
  }
68361
68863
  if (params.startupError) {
68362
68864
  finalize("failed", params.startupError);
68865
+ if (activeTurn === turn) emitSettled(turn);
68363
68866
  if (activeTurn === turn) activeTurn = null;
68364
68867
  return;
68365
68868
  }
68366
68869
  try {
68367
- await ensureRuntime();
68870
+ await ensureRuntime(message.cwd);
68368
68871
  } catch (error) {
68369
68872
  finalize("failed", error instanceof Error ? error.message : String(error));
68873
+ if (activeTurn === turn) emitSettled(turn);
68370
68874
  if (activeTurn === turn) activeTurn = null;
68371
68875
  return;
68372
68876
  }
68373
- const runtime = params.runtime;
68374
- if (runtime?.initialModel.unconfigured) {
68375
- finalize("failed", runtime.initialModel.warning || "No models are configured.");
68877
+ const activeRuntime = runtime;
68878
+ if (activeRuntime?.initialModel.unconfigured) {
68879
+ finalize("failed", activeRuntime.initialModel.warning || "No models are configured.");
68880
+ if (activeTurn === turn) emitSettled(turn);
68376
68881
  if (activeTurn === turn) activeTurn = null;
68377
68882
  return;
68378
68883
  }
68379
68884
  if (!controller || !agent) {
68380
68885
  finalize("failed", "JSON events runtime was not initialized");
68886
+ if (activeTurn === turn) emitSettled(turn);
68381
68887
  if (activeTurn === turn) activeTurn = null;
68382
68888
  return;
68383
68889
  }
@@ -68399,31 +68905,36 @@ async function runJsonEventsMode(params) {
68399
68905
  trace?.noteWaitForIdleStart({ mode: "json-events" });
68400
68906
  await controller.waitForSettled();
68401
68907
  trace?.noteWaitForIdleSettled({ mode: "json-events" });
68908
+ await activeRuntime?.sessionManager.save();
68402
68909
  finalizePendingTerminal();
68403
68910
  if (!activeTurn?.finalized) {
68404
68911
  const finalError = assistantErrorFromAgent(agent);
68405
68912
  if (activeTurn?.interrupted) {
68406
68913
  finalize("cancelled", "user_interrupt");
68407
- return;
68408
- }
68409
- if (finalError) {
68914
+ } else if (finalError) {
68410
68915
  finalize("failed", finalError);
68411
- return;
68916
+ } else {
68917
+ const text = assistantTextFromAgent(agent);
68918
+ flushAssistantOutput(text);
68919
+ finalize("completed", text || activeTurn?.summary.trim());
68412
68920
  }
68413
- const text = assistantTextFromAgent(agent);
68414
- flushAssistantOutput(text);
68415
- finalize("completed", text || activeTurn?.summary.trim());
68416
68921
  }
68922
+ if (activeTurn === turn) emitSettled(turn);
68417
68923
  } catch (error) {
68418
68924
  const messageText = error instanceof Error ? error.message : String(error);
68419
68925
  trace?.noteStalled(messageText, { mode: "json-events" });
68926
+ try {
68927
+ await activeRuntime?.sessionManager.save();
68928
+ } catch {
68929
+ }
68420
68930
  if (!activeTurn?.finalized) {
68421
68931
  finalize(activeTurn?.interrupted ? "cancelled" : "failed", activeTurn?.interrupted ? "user_interrupt" : messageText);
68422
68932
  }
68933
+ if (activeTurn === turn) emitSettled(turn);
68423
68934
  } finally {
68424
68935
  clearInterval(progressTimer);
68425
68936
  trace?.flush();
68426
- await runtime?.sessionManager.save();
68937
+ await activeRuntime?.sessionManager.save();
68427
68938
  if (activeTurn === turn) activeTurn = null;
68428
68939
  }
68429
68940
  }
@@ -68455,12 +68966,29 @@ async function runJsonEventsMode(params) {
68455
68966
  });
68456
68967
  return;
68457
68968
  }
68969
+ if (params.mockResponse !== void 0) {
68970
+ if (activeTurn.outputStarted) return;
68971
+ activeTurn.interrupted = true;
68972
+ finalize("cancelled", message.reason || "user_interrupt");
68973
+ emitSettled(activeTurn);
68974
+ activeTurn = null;
68975
+ return;
68976
+ }
68458
68977
  activeTurn.interrupted = true;
68459
68978
  controller?.abort();
68979
+ }
68980
+ function shutdownActiveTurn(reason) {
68981
+ if (!activeTurn || activeTurn.finalized) return;
68460
68982
  if (params.mockResponse !== void 0) {
68461
- finalize("cancelled", message.reason || "user_interrupt");
68983
+ if (activeTurn.outputStarted) return;
68984
+ activeTurn.interrupted = true;
68985
+ finalize("cancelled", reason || "shutdown");
68986
+ emitSettled(activeTurn);
68462
68987
  activeTurn = null;
68988
+ return;
68463
68989
  }
68990
+ activeTurn.interrupted = true;
68991
+ controller?.abort();
68464
68992
  }
68465
68993
  const input = readline.createInterface({ input: process.stdin });
68466
68994
  let activeTurnPromise = null;
@@ -68472,15 +69000,7 @@ async function runJsonEventsMode(params) {
68472
69000
  continue;
68473
69001
  }
68474
69002
  if (message.type === "shutdown") {
68475
- if (activeTurn && !activeTurn.finalized) {
68476
- activeTurn.interrupted = true;
68477
- controller?.abort();
68478
- if (!controller) {
68479
- finalize("cancelled", message.reason || "shutdown");
68480
- } else {
68481
- rememberTerminal("cancelled", message.reason || "shutdown");
68482
- }
68483
- }
69003
+ shutdownActiveTurn(message.reason);
68484
69004
  break;
68485
69005
  }
68486
69006
  if (message.type === "turn.interrupt") {
@@ -68505,11 +69025,7 @@ async function runJsonEventsMode(params) {
68505
69025
  }
68506
69026
  }
68507
69027
  await activeTurnPromise;
68508
- disposeAgentSubscription?.();
68509
- disposeSemanticSubscription?.();
68510
- controller?.dispose();
68511
- await params.runtime?.sessionManager.save();
68512
- trace?.flush();
69028
+ await disposeRuntime();
68513
69029
  }
68514
69030
 
68515
69031
  // src/cli.ts
@@ -68518,8 +69034,8 @@ var logError = (msg, err) => {
68518
69034
  const logPath = getRuntimeLogPath();
68519
69035
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
68520
69036
  const stack = err instanceof Error ? err.stack || "" : "";
68521
- fs25.mkdirSync(path26.dirname(logPath), { recursive: true });
68522
- fs25.appendFileSync(logPath, `[${timestamp}] ${msg}
69037
+ fs26.mkdirSync(path26.dirname(logPath), { recursive: true });
69038
+ fs26.appendFileSync(logPath, `[${timestamp}] ${msg}
68523
69039
  ${stack}
68524
69040
 
68525
69041
  `);
@@ -68538,6 +69054,7 @@ Commands:
68538
69054
  doctor Diagnose local Pie configuration and runtime dependencies
68539
69055
  models init Create a starter ~/.pie/models.json
68540
69056
  models validate Validate ~/.pie/models.json
69057
+ sessions List, read, rename, rewind, and fork Pie sessions
68541
69058
  permissions Explain Pie tool and shell safety defaults
68542
69059
  help Show this help message
68543
69060
 
@@ -68662,7 +69179,7 @@ async function createCliTestStreamFnFromEnv() {
68662
69179
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) {
68663
69180
  return void 0;
68664
69181
  }
68665
- const { createTestStreamFnFromSequenceEnv } = await import("./chunks/test-stream-ZSKNLUEJ.js");
69182
+ const { createTestStreamFnFromSequenceEnv } = await import("./chunks/test-stream-UW74PA6T.js");
68666
69183
  return createTestStreamFnFromSequenceEnv();
68667
69184
  }
68668
69185
  async function startChat(initialPrompt, testCommand) {
@@ -68681,23 +69198,15 @@ async function startChat(initialPrompt, testCommand) {
68681
69198
  });
68682
69199
  return;
68683
69200
  }
68684
- let runtime2;
68685
- try {
68686
- runtime2 = await composeCliRuntime({ explicitSessionId, extensionPaths });
68687
- } catch (error) {
68688
- if (error instanceof CliMissingApiKeyError) {
68689
- await runJsonEventsMode({
68690
- explicitSessionId,
68691
- startupError: error.message
68692
- });
68693
- return;
68694
- }
68695
- throw error;
68696
- }
68697
69201
  await runJsonEventsMode({
68698
- runtime: runtime2,
68699
69202
  explicitSessionId,
68700
- streamFn: await createCliTestStreamFnFromEnv()
69203
+ streamFn: await createCliTestStreamFnFromEnv(),
69204
+ createRuntime: async ({ cwd, sessionId }) => composeCliRuntime({
69205
+ explicitSessionId: explicitSessionId ?? sessionId,
69206
+ extensionPaths,
69207
+ cwd,
69208
+ warnIfExplicitSessionMissing: false
69209
+ })
68701
69210
  });
68702
69211
  });
68703
69212
  return;
@@ -68768,6 +69277,10 @@ async function startChat(initialPrompt, testCommand) {
68768
69277
  }
68769
69278
  async function main() {
68770
69279
  const args = process.argv.slice(2);
69280
+ if (args[0] === "--version" || args[0] === "-v") {
69281
+ console.log(VERSION);
69282
+ return;
69283
+ }
68771
69284
  if (args[0] === "doctor") {
68772
69285
  await runDoctorCommand(args.slice(1));
68773
69286
  return;
@@ -68781,6 +69294,10 @@ async function main() {
68781
69294
  }
68782
69295
  return;
68783
69296
  }
69297
+ if (args[0] === "sessions") {
69298
+ await runSessionsCommand(args.slice(1));
69299
+ return;
69300
+ }
68784
69301
  if (args[0] === "permissions") {
68785
69302
  console.log(formatPermissionsHelp());
68786
69303
  return;