@cydm/pie 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/builtin/extensions/ask-user/index.js +3 -3
  2. package/dist/builtin/extensions/computer-use/index.js +26 -4
  3. package/dist/builtin/extensions/computer-use/package.json +3 -0
  4. package/dist/builtin/extensions/computer-use/prebuilt/macos/arm64/pie-computer-use +0 -0
  5. package/dist/builtin/extensions/computer-use/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
  6. package/dist/builtin/extensions/computer-use/prebuilt/macos/x64/pie-computer-use +0 -0
  7. package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +2 -1
  8. package/dist/builtin/extensions/computer-use/scripts/setup-helper.mjs +2 -2
  9. package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +204 -0
  10. package/dist/builtin/extensions/mcp-adapter/index.js +48 -13
  11. package/dist/builtin/extensions/plan-mode/index.js +3 -3
  12. package/dist/builtin/extensions/subagent/index.js +4 -4
  13. package/dist/builtin/extensions/todo/index.js +3 -3
  14. package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-runtime.js +1 -1
  15. package/dist/builtin/skills/chrome-devtools-axi/{cli-F2VCSVL4.js → cli-P4VG6ZZG.js} +48 -8
  16. package/dist/builtin/skills/skill-creator/scripts/pie_runner.mjs +33 -12
  17. package/dist/builtin/skills/tui-use/tui-use-daemon.cjs +5 -7
  18. package/dist/chunks/{chunk-UPPICLVS.js → chunk-FKUEIYFQ.js} +8212 -7366
  19. package/dist/chunks/{chunk-P3QPJXS7.js → chunk-XVUV3IM2.js} +108 -36
  20. package/dist/chunks/{chunk-IM43UYVV.js → chunk-YRXXRLMQ.js} +75 -14
  21. package/dist/chunks/{chunk-QJH6YN2W.js → chunk-ZKHMNEXL.js} +1 -1
  22. package/dist/chunks/{src-QSP2OPHU.js → src-SXUQ7OY6.js} +2 -2
  23. package/dist/chunks/{test-stream-CVGWFLSX.js → test-stream-OD3B57AS.js} +1 -1
  24. package/dist/cli.js +1302 -876
  25. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  createCliWebResearchHealthStore,
8
8
  formatSize,
9
9
  truncateHeadTail
10
- } from "./chunks/chunk-P3QPJXS7.js";
10
+ } from "./chunks/chunk-XVUV3IM2.js";
11
11
  import {
12
12
  AGENTS_CONTEXT_FILE_NAME,
13
13
  AgentSessionController,
@@ -40,7 +40,7 @@ import {
40
40
  evaluateTodoClosureAfterFailedTurn,
41
41
  extensionFallbackName,
42
42
  extractExtensionSettings,
43
- findFirstKeptEntryId,
43
+ findFirstKeptEntrySummaryId,
44
44
  formatSkillSummariesForPrompt,
45
45
  generateEntryId,
46
46
  getAutoCompactTokenLimit,
@@ -60,8 +60,8 @@ import {
60
60
  setExtensionEnabledInSettings,
61
61
  shouldPreserveExecutionStateForUserText,
62
62
  supersedeExecutionState
63
- } from "./chunks/chunk-UPPICLVS.js";
64
- import "./chunks/chunk-QJH6YN2W.js";
63
+ } from "./chunks/chunk-FKUEIYFQ.js";
64
+ import "./chunks/chunk-ZKHMNEXL.js";
65
65
  import {
66
66
  Deref,
67
67
  EMPTY_ASSISTANT_CONTENT_ERROR,
@@ -85,7 +85,7 @@ import {
85
85
  setLogger,
86
86
  sortToolModelCandidatesByCapability,
87
87
  type_exports
88
- } from "./chunks/chunk-IM43UYVV.js";
88
+ } from "./chunks/chunk-YRXXRLMQ.js";
89
89
  import {
90
90
  VERSION,
91
91
  getAgentDir,
@@ -994,15 +994,15 @@ var require_route = __commonJS({
994
994
  };
995
995
  }
996
996
  function wrapConversion(toModel, graph) {
997
- const path33 = [graph[toModel].parent, toModel];
997
+ const path34 = [graph[toModel].parent, toModel];
998
998
  let fn = conversions[graph[toModel].parent][toModel];
999
999
  let cur = graph[toModel].parent;
1000
1000
  while (graph[cur].parent) {
1001
- path33.unshift(graph[cur].parent);
1001
+ path34.unshift(graph[cur].parent);
1002
1002
  fn = link(conversions[graph[cur].parent][cur], fn);
1003
1003
  cur = graph[cur].parent;
1004
1004
  }
1005
- fn.conversion = path33;
1005
+ fn.conversion = path34;
1006
1006
  return fn;
1007
1007
  }
1008
1008
  module.exports = function(fromModel) {
@@ -1925,7 +1925,7 @@ var require_core = __commonJS({
1925
1925
  return match && match.index === 0;
1926
1926
  }
1927
1927
  var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
1928
- function join21(regexps, separator = "|") {
1928
+ function join22(regexps, separator = "|") {
1929
1929
  let numCaptures = 0;
1930
1930
  return regexps.map((regex) => {
1931
1931
  numCaptures += 1;
@@ -2229,7 +2229,7 @@ var require_core = __commonJS({
2229
2229
  this.exec = () => null;
2230
2230
  }
2231
2231
  const terminators = this.regexes.map((el) => el[1]);
2232
- this.matcherRe = langRe(join21(terminators), true);
2232
+ this.matcherRe = langRe(join22(terminators), true);
2233
2233
  this.lastIndex = 0;
2234
2234
  }
2235
2235
  /** @param {string} s */
@@ -44042,17 +44042,17 @@ var require_visit = __commonJS({
44042
44042
  visit.BREAK = BREAK;
44043
44043
  visit.SKIP = SKIP;
44044
44044
  visit.REMOVE = REMOVE;
44045
- function visit_(key, node, visitor, path33) {
44046
- const ctrl = callVisitor(key, node, visitor, path33);
44045
+ function visit_(key, node, visitor, path34) {
44046
+ const ctrl = callVisitor(key, node, visitor, path34);
44047
44047
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
44048
- replaceNode(key, path33, ctrl);
44049
- return visit_(key, ctrl, visitor, path33);
44048
+ replaceNode(key, path34, ctrl);
44049
+ return visit_(key, ctrl, visitor, path34);
44050
44050
  }
44051
44051
  if (typeof ctrl !== "symbol") {
44052
44052
  if (identity.isCollection(node)) {
44053
- path33 = Object.freeze(path33.concat(node));
44053
+ path34 = Object.freeze(path34.concat(node));
44054
44054
  for (let i = 0; i < node.items.length; ++i) {
44055
- const ci = visit_(i, node.items[i], visitor, path33);
44055
+ const ci = visit_(i, node.items[i], visitor, path34);
44056
44056
  if (typeof ci === "number")
44057
44057
  i = ci - 1;
44058
44058
  else if (ci === BREAK)
@@ -44063,13 +44063,13 @@ var require_visit = __commonJS({
44063
44063
  }
44064
44064
  }
44065
44065
  } else if (identity.isPair(node)) {
44066
- path33 = Object.freeze(path33.concat(node));
44067
- const ck = visit_("key", node.key, visitor, path33);
44066
+ path34 = Object.freeze(path34.concat(node));
44067
+ const ck = visit_("key", node.key, visitor, path34);
44068
44068
  if (ck === BREAK)
44069
44069
  return BREAK;
44070
44070
  else if (ck === REMOVE)
44071
44071
  node.key = null;
44072
- const cv = visit_("value", node.value, visitor, path33);
44072
+ const cv = visit_("value", node.value, visitor, path34);
44073
44073
  if (cv === BREAK)
44074
44074
  return BREAK;
44075
44075
  else if (cv === REMOVE)
@@ -44090,17 +44090,17 @@ var require_visit = __commonJS({
44090
44090
  visitAsync.BREAK = BREAK;
44091
44091
  visitAsync.SKIP = SKIP;
44092
44092
  visitAsync.REMOVE = REMOVE;
44093
- async function visitAsync_(key, node, visitor, path33) {
44094
- const ctrl = await callVisitor(key, node, visitor, path33);
44093
+ async function visitAsync_(key, node, visitor, path34) {
44094
+ const ctrl = await callVisitor(key, node, visitor, path34);
44095
44095
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
44096
- replaceNode(key, path33, ctrl);
44097
- return visitAsync_(key, ctrl, visitor, path33);
44096
+ replaceNode(key, path34, ctrl);
44097
+ return visitAsync_(key, ctrl, visitor, path34);
44098
44098
  }
44099
44099
  if (typeof ctrl !== "symbol") {
44100
44100
  if (identity.isCollection(node)) {
44101
- path33 = Object.freeze(path33.concat(node));
44101
+ path34 = Object.freeze(path34.concat(node));
44102
44102
  for (let i = 0; i < node.items.length; ++i) {
44103
- const ci = await visitAsync_(i, node.items[i], visitor, path33);
44103
+ const ci = await visitAsync_(i, node.items[i], visitor, path34);
44104
44104
  if (typeof ci === "number")
44105
44105
  i = ci - 1;
44106
44106
  else if (ci === BREAK)
@@ -44111,13 +44111,13 @@ var require_visit = __commonJS({
44111
44111
  }
44112
44112
  }
44113
44113
  } else if (identity.isPair(node)) {
44114
- path33 = Object.freeze(path33.concat(node));
44115
- const ck = await visitAsync_("key", node.key, visitor, path33);
44114
+ path34 = Object.freeze(path34.concat(node));
44115
+ const ck = await visitAsync_("key", node.key, visitor, path34);
44116
44116
  if (ck === BREAK)
44117
44117
  return BREAK;
44118
44118
  else if (ck === REMOVE)
44119
44119
  node.key = null;
44120
- const cv = await visitAsync_("value", node.value, visitor, path33);
44120
+ const cv = await visitAsync_("value", node.value, visitor, path34);
44121
44121
  if (cv === BREAK)
44122
44122
  return BREAK;
44123
44123
  else if (cv === REMOVE)
@@ -44144,23 +44144,23 @@ var require_visit = __commonJS({
44144
44144
  }
44145
44145
  return visitor;
44146
44146
  }
44147
- function callVisitor(key, node, visitor, path33) {
44147
+ function callVisitor(key, node, visitor, path34) {
44148
44148
  if (typeof visitor === "function")
44149
- return visitor(key, node, path33);
44149
+ return visitor(key, node, path34);
44150
44150
  if (identity.isMap(node))
44151
- return visitor.Map?.(key, node, path33);
44151
+ return visitor.Map?.(key, node, path34);
44152
44152
  if (identity.isSeq(node))
44153
- return visitor.Seq?.(key, node, path33);
44153
+ return visitor.Seq?.(key, node, path34);
44154
44154
  if (identity.isPair(node))
44155
- return visitor.Pair?.(key, node, path33);
44155
+ return visitor.Pair?.(key, node, path34);
44156
44156
  if (identity.isScalar(node))
44157
- return visitor.Scalar?.(key, node, path33);
44157
+ return visitor.Scalar?.(key, node, path34);
44158
44158
  if (identity.isAlias(node))
44159
- return visitor.Alias?.(key, node, path33);
44159
+ return visitor.Alias?.(key, node, path34);
44160
44160
  return void 0;
44161
44161
  }
44162
- function replaceNode(key, path33, node) {
44163
- const parent = path33[path33.length - 1];
44162
+ function replaceNode(key, path34, node) {
44163
+ const parent = path34[path34.length - 1];
44164
44164
  if (identity.isCollection(parent)) {
44165
44165
  parent.items[key] = node;
44166
44166
  } else if (identity.isPair(parent)) {
@@ -44768,10 +44768,10 @@ var require_Collection = __commonJS({
44768
44768
  var createNode = require_createNode();
44769
44769
  var identity = require_identity();
44770
44770
  var Node = require_Node();
44771
- function collectionFromPath(schema, path33, value) {
44771
+ function collectionFromPath(schema, path34, value) {
44772
44772
  let v2 = value;
44773
- for (let i = path33.length - 1; i >= 0; --i) {
44774
- const k2 = path33[i];
44773
+ for (let i = path34.length - 1; i >= 0; --i) {
44774
+ const k2 = path34[i];
44775
44775
  if (typeof k2 === "number" && Number.isInteger(k2) && k2 >= 0) {
44776
44776
  const a = [];
44777
44777
  a[k2] = v2;
@@ -44790,7 +44790,7 @@ var require_Collection = __commonJS({
44790
44790
  sourceObjects: /* @__PURE__ */ new Map()
44791
44791
  });
44792
44792
  }
44793
- var isEmptyPath = (path33) => path33 == null || typeof path33 === "object" && !!path33[Symbol.iterator]().next().done;
44793
+ var isEmptyPath = (path34) => path34 == null || typeof path34 === "object" && !!path34[Symbol.iterator]().next().done;
44794
44794
  var Collection = class extends Node.NodeBase {
44795
44795
  constructor(type, schema) {
44796
44796
  super(type);
@@ -44820,11 +44820,11 @@ var require_Collection = __commonJS({
44820
44820
  * be a Pair instance or a `{ key, value }` object, which may not have a key
44821
44821
  * that already exists in the map.
44822
44822
  */
44823
- addIn(path33, value) {
44824
- if (isEmptyPath(path33))
44823
+ addIn(path34, value) {
44824
+ if (isEmptyPath(path34))
44825
44825
  this.add(value);
44826
44826
  else {
44827
- const [key, ...rest] = path33;
44827
+ const [key, ...rest] = path34;
44828
44828
  const node = this.get(key, true);
44829
44829
  if (identity.isCollection(node))
44830
44830
  node.addIn(rest, value);
@@ -44838,8 +44838,8 @@ var require_Collection = __commonJS({
44838
44838
  * Removes a value from the collection.
44839
44839
  * @returns `true` if the item was found and removed.
44840
44840
  */
44841
- deleteIn(path33) {
44842
- const [key, ...rest] = path33;
44841
+ deleteIn(path34) {
44842
+ const [key, ...rest] = path34;
44843
44843
  if (rest.length === 0)
44844
44844
  return this.delete(key);
44845
44845
  const node = this.get(key, true);
@@ -44853,8 +44853,8 @@ var require_Collection = __commonJS({
44853
44853
  * scalar values from their surrounding node; to disable set `keepScalar` to
44854
44854
  * `true` (collections are always returned intact).
44855
44855
  */
44856
- getIn(path33, keepScalar) {
44857
- const [key, ...rest] = path33;
44856
+ getIn(path34, keepScalar) {
44857
+ const [key, ...rest] = path34;
44858
44858
  const node = this.get(key, true);
44859
44859
  if (rest.length === 0)
44860
44860
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -44872,8 +44872,8 @@ var require_Collection = __commonJS({
44872
44872
  /**
44873
44873
  * Checks if the collection includes a value with the key `key`.
44874
44874
  */
44875
- hasIn(path33) {
44876
- const [key, ...rest] = path33;
44875
+ hasIn(path34) {
44876
+ const [key, ...rest] = path34;
44877
44877
  if (rest.length === 0)
44878
44878
  return this.has(key);
44879
44879
  const node = this.get(key, true);
@@ -44883,8 +44883,8 @@ var require_Collection = __commonJS({
44883
44883
  * Sets a value in this collection. For `!!set`, `value` needs to be a
44884
44884
  * boolean to add/remove the item from the set.
44885
44885
  */
44886
- setIn(path33, value) {
44887
- const [key, ...rest] = path33;
44886
+ setIn(path34, value) {
44887
+ const [key, ...rest] = path34;
44888
44888
  if (rest.length === 0) {
44889
44889
  this.set(key, value);
44890
44890
  } else {
@@ -47396,9 +47396,9 @@ var require_Document = __commonJS({
47396
47396
  this.contents.add(value);
47397
47397
  }
47398
47398
  /** Adds a value to the document. */
47399
- addIn(path33, value) {
47399
+ addIn(path34, value) {
47400
47400
  if (assertCollection(this.contents))
47401
- this.contents.addIn(path33, value);
47401
+ this.contents.addIn(path34, value);
47402
47402
  }
47403
47403
  /**
47404
47404
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -47473,14 +47473,14 @@ var require_Document = __commonJS({
47473
47473
  * Removes a value from the document.
47474
47474
  * @returns `true` if the item was found and removed.
47475
47475
  */
47476
- deleteIn(path33) {
47477
- if (Collection.isEmptyPath(path33)) {
47476
+ deleteIn(path34) {
47477
+ if (Collection.isEmptyPath(path34)) {
47478
47478
  if (this.contents == null)
47479
47479
  return false;
47480
47480
  this.contents = null;
47481
47481
  return true;
47482
47482
  }
47483
- return assertCollection(this.contents) ? this.contents.deleteIn(path33) : false;
47483
+ return assertCollection(this.contents) ? this.contents.deleteIn(path34) : false;
47484
47484
  }
47485
47485
  /**
47486
47486
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -47495,10 +47495,10 @@ var require_Document = __commonJS({
47495
47495
  * scalar values from their surrounding node; to disable set `keepScalar` to
47496
47496
  * `true` (collections are always returned intact).
47497
47497
  */
47498
- getIn(path33, keepScalar) {
47499
- if (Collection.isEmptyPath(path33))
47498
+ getIn(path34, keepScalar) {
47499
+ if (Collection.isEmptyPath(path34))
47500
47500
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
47501
- return identity.isCollection(this.contents) ? this.contents.getIn(path33, keepScalar) : void 0;
47501
+ return identity.isCollection(this.contents) ? this.contents.getIn(path34, keepScalar) : void 0;
47502
47502
  }
47503
47503
  /**
47504
47504
  * Checks if the document includes a value with the key `key`.
@@ -47509,10 +47509,10 @@ var require_Document = __commonJS({
47509
47509
  /**
47510
47510
  * Checks if the document includes a value at `path`.
47511
47511
  */
47512
- hasIn(path33) {
47513
- if (Collection.isEmptyPath(path33))
47512
+ hasIn(path34) {
47513
+ if (Collection.isEmptyPath(path34))
47514
47514
  return this.contents !== void 0;
47515
- return identity.isCollection(this.contents) ? this.contents.hasIn(path33) : false;
47515
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path34) : false;
47516
47516
  }
47517
47517
  /**
47518
47518
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -47529,13 +47529,13 @@ var require_Document = __commonJS({
47529
47529
  * Sets a value in this document. For `!!set`, `value` needs to be a
47530
47530
  * boolean to add/remove the item from the set.
47531
47531
  */
47532
- setIn(path33, value) {
47533
- if (Collection.isEmptyPath(path33)) {
47532
+ setIn(path34, value) {
47533
+ if (Collection.isEmptyPath(path34)) {
47534
47534
  this.contents = value;
47535
47535
  } else if (this.contents == null) {
47536
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path33), value);
47536
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path34), value);
47537
47537
  } else if (assertCollection(this.contents)) {
47538
- this.contents.setIn(path33, value);
47538
+ this.contents.setIn(path34, value);
47539
47539
  }
47540
47540
  }
47541
47541
  /**
@@ -49492,9 +49492,9 @@ var require_cst_visit = __commonJS({
49492
49492
  visit.BREAK = BREAK;
49493
49493
  visit.SKIP = SKIP;
49494
49494
  visit.REMOVE = REMOVE;
49495
- visit.itemAtPath = (cst, path33) => {
49495
+ visit.itemAtPath = (cst, path34) => {
49496
49496
  let item = cst;
49497
- for (const [field, index] of path33) {
49497
+ for (const [field, index] of path34) {
49498
49498
  const tok = item?.[field];
49499
49499
  if (tok && "items" in tok) {
49500
49500
  item = tok.items[index];
@@ -49503,23 +49503,23 @@ var require_cst_visit = __commonJS({
49503
49503
  }
49504
49504
  return item;
49505
49505
  };
49506
- visit.parentCollection = (cst, path33) => {
49507
- const parent = visit.itemAtPath(cst, path33.slice(0, -1));
49508
- const field = path33[path33.length - 1][0];
49506
+ visit.parentCollection = (cst, path34) => {
49507
+ const parent = visit.itemAtPath(cst, path34.slice(0, -1));
49508
+ const field = path34[path34.length - 1][0];
49509
49509
  const coll = parent?.[field];
49510
49510
  if (coll && "items" in coll)
49511
49511
  return coll;
49512
49512
  throw new Error("Parent collection not found");
49513
49513
  };
49514
- function _visit(path33, item, visitor) {
49515
- let ctrl = visitor(item, path33);
49514
+ function _visit(path34, item, visitor) {
49515
+ let ctrl = visitor(item, path34);
49516
49516
  if (typeof ctrl === "symbol")
49517
49517
  return ctrl;
49518
49518
  for (const field of ["key", "value"]) {
49519
49519
  const token = item[field];
49520
49520
  if (token && "items" in token) {
49521
49521
  for (let i = 0; i < token.items.length; ++i) {
49522
- const ci = _visit(Object.freeze(path33.concat([[field, i]])), token.items[i], visitor);
49522
+ const ci = _visit(Object.freeze(path34.concat([[field, i]])), token.items[i], visitor);
49523
49523
  if (typeof ci === "number")
49524
49524
  i = ci - 1;
49525
49525
  else if (ci === BREAK)
@@ -49530,10 +49530,10 @@ var require_cst_visit = __commonJS({
49530
49530
  }
49531
49531
  }
49532
49532
  if (typeof ctrl === "function" && field === "key")
49533
- ctrl = ctrl(item, path33);
49533
+ ctrl = ctrl(item, path34);
49534
49534
  }
49535
49535
  }
49536
- return typeof ctrl === "function" ? ctrl(item, path33) : ctrl;
49536
+ return typeof ctrl === "function" ? ctrl(item, path34) : ctrl;
49537
49537
  }
49538
49538
  exports.visit = visit;
49539
49539
  }
@@ -50818,14 +50818,14 @@ var require_parser2 = __commonJS({
50818
50818
  case "scalar":
50819
50819
  case "single-quoted-scalar":
50820
50820
  case "double-quoted-scalar": {
50821
- const fs29 = this.flowScalar(this.type);
50821
+ const fs30 = this.flowScalar(this.type);
50822
50822
  if (atNextItem || it.value) {
50823
- map.items.push({ start, key: fs29, sep: [] });
50823
+ map.items.push({ start, key: fs30, sep: [] });
50824
50824
  this.onKeyLine = true;
50825
50825
  } else if (it.sep) {
50826
- this.stack.push(fs29);
50826
+ this.stack.push(fs30);
50827
50827
  } else {
50828
- Object.assign(it, { key: fs29, sep: [] });
50828
+ Object.assign(it, { key: fs30, sep: [] });
50829
50829
  this.onKeyLine = true;
50830
50830
  }
50831
50831
  return;
@@ -50953,13 +50953,13 @@ var require_parser2 = __commonJS({
50953
50953
  case "scalar":
50954
50954
  case "single-quoted-scalar":
50955
50955
  case "double-quoted-scalar": {
50956
- const fs29 = this.flowScalar(this.type);
50956
+ const fs30 = this.flowScalar(this.type);
50957
50957
  if (!it || it.value)
50958
- fc.items.push({ start: [], key: fs29, sep: [] });
50958
+ fc.items.push({ start: [], key: fs30, sep: [] });
50959
50959
  else if (it.sep)
50960
- this.stack.push(fs29);
50960
+ this.stack.push(fs30);
50961
50961
  else
50962
- Object.assign(it, { key: fs29, sep: [] });
50962
+ Object.assign(it, { key: fs30, sep: [] });
50963
50963
  return;
50964
50964
  }
50965
50965
  case "flow-map-end":
@@ -51268,8 +51268,8 @@ var require_dist2 = __commonJS({
51268
51268
  });
51269
51269
 
51270
51270
  // src/cli.ts
51271
- import * as fs28 from "fs";
51272
- import * as path32 from "path";
51271
+ import * as fs29 from "fs";
51272
+ import * as path33 from "path";
51273
51273
 
51274
51274
  // src/cli-args.ts
51275
51275
  var FLAGS_WITH_VALUES = /* @__PURE__ */ new Set(["--session-id", "--extension-path", "--developer-instructions", "--developer-instructions-file"]);
@@ -55129,9 +55129,11 @@ function runCapabilitiesCommand(args) {
55129
55129
  }
55130
55130
 
55131
55131
  // src/commands/sessions.ts
55132
- import fs7 from "node:fs";
55132
+ import fs8 from "node:fs";
55133
55133
 
55134
55134
  // src/session-control.ts
55135
+ import * as fs7 from "node:fs";
55136
+ import * as path7 from "node:path";
55135
55137
  var SessionControlError = class extends Error {
55136
55138
  constructor(code, message, recoverable = sessionControlErrorRecoverable(code)) {
55137
55139
  super(message);
@@ -55145,27 +55147,70 @@ var SessionControlError = class extends Error {
55145
55147
  function sessionControlErrorRecoverable(code) {
55146
55148
  return code !== "session_unrecoverable" && code !== "session_mismatch";
55147
55149
  }
55148
- async function loadRequiredSession(store, sessionId) {
55149
- const exists = await store.exists(sessionId);
55150
- const data = await store.load(sessionId);
55151
- if (data) return data;
55152
- throw new SessionControlError(
55153
- exists ? "session_unrecoverable" : "session_not_found",
55154
- exists ? `Session could not be recovered: ${sessionId}` : `Session not found: ${sessionId}`
55155
- );
55150
+ var FORK_BATCH_ENTRIES = 64;
55151
+ var FORK_BATCH_BYTES = 256 * 1024;
55152
+ var STAGING_SESSION_ID_PREFIX = "__pie-staging-";
55153
+ function stagingIdFor(targetSessionId) {
55154
+ return `${STAGING_SESSION_ID_PREFIX}${targetSessionId}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
55156
55155
  }
55157
- async function rewindStoredSession(params) {
55158
- const data = await loadRequiredSession(params.store, params.sessionId);
55159
- if (!data.entries.some((entry) => entry.id === params.entryId)) {
55160
- throw new SessionControlError("entry_not_found", `Entry not found: ${params.entryId}`);
55156
+ var PUBLISH_JOURNAL_DIR = ".pie-publish-journal";
55157
+ function safeSessionDirName(sessionId) {
55158
+ return sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
55159
+ }
55160
+ function canonicalSessionDir(sessionsDir, sessionId) {
55161
+ const dir = path7.join(sessionsDir, safeSessionDirName(sessionId));
55162
+ try {
55163
+ if (!fs7.existsSync(dir)) return null;
55164
+ return fs7.realpathSync(dir);
55165
+ } catch {
55166
+ return null;
55161
55167
  }
55168
+ }
55169
+ function publishJournalPath(sessionsDir, safeTargetId) {
55170
+ return path7.join(sessionsDir, PUBLISH_JOURNAL_DIR, `${safeTargetId}.json`);
55171
+ }
55172
+ function writePublishJournal(journalPath, record) {
55173
+ fs7.mkdirSync(path7.dirname(journalPath), { recursive: true });
55174
+ const tempPath = `${journalPath}.tmp`;
55175
+ fs7.writeFileSync(tempPath, JSON.stringify(record, void 0, " "));
55176
+ fs7.renameSync(tempPath, journalPath);
55177
+ }
55178
+ function clearPublishJournal(journalPath) {
55179
+ if (!journalPath) return;
55162
55180
  try {
55163
- await params.store.save(params.sessionId, data.entries, {
55164
- ...data.metadata,
55165
- activeEntryId: params.entryId,
55166
- updatedAt: params.now ?? Date.now()
55167
- });
55168
- const metadata = await params.store.getMetadata(params.sessionId);
55181
+ fs7.rmSync(journalPath, { force: true });
55182
+ } catch {
55183
+ }
55184
+ }
55185
+ function toIoError(error) {
55186
+ if (error instanceof SessionControlError) return error;
55187
+ return new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
55188
+ }
55189
+ function loadRequiredSessionHead(store, sessionId) {
55190
+ const status = store.headStatus(sessionId);
55191
+ if (status === "legacy") {
55192
+ throw new SessionControlError(
55193
+ "session_unsupported_format",
55194
+ `Session uses an unsupported old format: ${sessionId}`
55195
+ );
55196
+ }
55197
+ if (status === "corrupt") {
55198
+ throw new SessionControlError("session_unrecoverable", `Session could not be recovered: ${sessionId}`);
55199
+ }
55200
+ const head = store.readHead(sessionId);
55201
+ if (!head) {
55202
+ throw new SessionControlError("session_not_found", `Session not found: ${sessionId}`);
55203
+ }
55204
+ return head;
55205
+ }
55206
+ async function rewindStoredSession(params) {
55207
+ try {
55208
+ loadRequiredSessionHead(params.store, params.sessionId);
55209
+ if (params.store.getEntrySummary(params.sessionId, params.entryId) === null) {
55210
+ throw new SessionControlError("entry_not_found", `Entry not found: ${params.entryId}`);
55211
+ }
55212
+ params.store.setActiveEntry(params.sessionId, params.entryId);
55213
+ const metadata = params.store.getMetadata(params.sessionId);
55169
55214
  if (!metadata) {
55170
55215
  throw new SessionControlError("session_unrecoverable", `Session could not be recovered after rewind: ${params.sessionId}`, false);
55171
55216
  }
@@ -55176,52 +55221,179 @@ async function rewindStoredSession(params) {
55176
55221
  metadata
55177
55222
  };
55178
55223
  } catch (error) {
55179
- if (error instanceof SessionControlError) throw error;
55180
- throw new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
55224
+ throw toIoError(error);
55181
55225
  }
55182
55226
  }
55183
55227
  async function forkStoredSession(params) {
55228
+ let stagingId;
55184
55229
  try {
55230
+ const sanitizedTargetId = params.targetSessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
55231
+ if (sanitizedTargetId.startsWith(STAGING_SESSION_ID_PREFIX)) {
55232
+ throw new SessionControlError(
55233
+ "invalid_request",
55234
+ `Target session id starts with a reserved internal prefix: ${params.targetSessionId}`
55235
+ );
55236
+ }
55237
+ if (params.sourceSessionId.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase() === sanitizedTargetId.toLowerCase()) {
55238
+ throw new SessionControlError(
55239
+ "invalid_request",
55240
+ "Fork source and target must be different sessions: " + params.sourceSessionId
55241
+ );
55242
+ }
55243
+ if (params.sessionsDir) {
55244
+ const canonicalSourceDir = canonicalSessionDir(params.sessionsDir, params.sourceSessionId);
55245
+ const canonicalTargetDir = canonicalSessionDir(params.sessionsDir, params.targetSessionId);
55246
+ if (canonicalSourceDir !== null && canonicalTargetDir !== null && canonicalSourceDir === canonicalTargetDir) {
55247
+ throw new SessionControlError(
55248
+ "invalid_request",
55249
+ `Fork source and target resolve to the same session directory: ${params.sourceSessionId} -> ${params.targetSessionId}`
55250
+ );
55251
+ }
55252
+ }
55185
55253
  if (!params.force) {
55186
55254
  const existingTarget = await maybeLoadExistingForkTarget(params);
55187
55255
  if (existingTarget) return existingTarget;
55188
55256
  }
55189
- const source = await loadRequiredSession(params.store, params.sourceSessionId);
55190
- const pathEntries = pathToEntry(source, params.sourceEntryId);
55191
- if (pathEntries.length === 0 || pathEntries[pathEntries.length - 1]?.id !== params.sourceEntryId) {
55257
+ const source = loadRequiredSessionHead(params.store, params.sourceSessionId);
55258
+ const pathSummaries = params.store.getPathSummaries(params.sourceSessionId, params.sourceEntryId);
55259
+ if (pathSummaries.length === 0 || pathSummaries[pathSummaries.length - 1]?.id !== params.sourceEntryId) {
55192
55260
  throw new SessionControlError("entry_not_found", `Entry not found: ${params.sourceEntryId}`);
55193
55261
  }
55194
55262
  const now = params.now ?? Date.now();
55263
+ stagingId = stagingIdFor(params.targetSessionId);
55264
+ params.store.createHead(stagingId, {
55265
+ name: params.name,
55266
+ createdAt: now
55267
+ });
55195
55268
  const idMap = /* @__PURE__ */ new Map();
55196
- for (const entry of pathEntries) idMap.set(entry.id, generateEntryId());
55197
- const forkedEntries = pathEntries.map((entry) => {
55198
- const nextId = idMap.get(entry.id);
55199
- if (!nextId) throw new SessionControlError("session_io_error", `Failed to map entry: ${entry.id}`);
55200
- const parentId = entry.parentId ? idMap.get(entry.parentId) ?? null : null;
55201
- return {
55202
- ...cloneJson(entry),
55203
- id: nextId,
55204
- parentId,
55269
+ let seq = 1;
55270
+ let batch = [];
55271
+ let batchBytes = 0;
55272
+ let lastCopiedId = null;
55273
+ let firstCopiedId = null;
55274
+ const flushBatch = () => {
55275
+ if (batch.length === 0) return;
55276
+ params.store.appendEntries(stagingId, batch, null);
55277
+ batch = [];
55278
+ batchBytes = 0;
55279
+ };
55280
+ for (const summary of pathSummaries) {
55281
+ let entry = null;
55282
+ try {
55283
+ entry = params.store.readEntry(params.sourceSessionId, summary.id);
55284
+ } catch {
55285
+ entry = null;
55286
+ }
55287
+ if (!entry) {
55288
+ throw new SessionControlError(
55289
+ "session_unrecoverable",
55290
+ `Fork source entry is not readable: ${summary.id}`,
55291
+ false
55292
+ );
55293
+ }
55294
+ const copy = {
55295
+ ...entry,
55296
+ id: generateEntryId(seq),
55297
+ parentId: lastCopiedId,
55205
55298
  timestamp: entry.timestamp
55206
55299
  };
55207
- });
55208
- const activeEntryId = idMap.get(params.sourceEntryId);
55209
- if (!activeEntryId) {
55210
- throw new SessionControlError("session_io_error", `Failed to map active entry: ${params.sourceEntryId}`);
55300
+ if (copy.compactionData) {
55301
+ const keptId = idMap.get(copy.compactionData.firstKeptEntryId);
55302
+ copy.compactionData = {
55303
+ ...copy.compactionData,
55304
+ firstKeptEntryId: keptId ?? firstCopiedId ?? copy.id
55305
+ };
55306
+ }
55307
+ idMap.set(summary.id, copy.id);
55308
+ if (firstCopiedId === null) {
55309
+ firstCopiedId = copy.id;
55310
+ }
55311
+ const copyBytes = Buffer.byteLength(JSON.stringify(copy), "utf8");
55312
+ if (batch.length > 0 && batchBytes + copyBytes > FORK_BATCH_BYTES) flushBatch();
55313
+ batch.push(copy);
55314
+ batchBytes += copyBytes;
55315
+ lastCopiedId = copy.id;
55316
+ seq += 1;
55317
+ if (batch.length >= FORK_BATCH_ENTRIES || batchBytes >= FORK_BATCH_BYTES) {
55318
+ flushBatch();
55319
+ }
55320
+ }
55321
+ flushBatch();
55322
+ if (!lastCopiedId) {
55323
+ throw new SessionControlError("session_unrecoverable", `Fork source has no readable entries: ${params.sourceSessionId}`, false);
55211
55324
  }
55212
- await params.store.save(params.targetSessionId, forkedEntries, {
55325
+ params.store.setActiveEntry(stagingId, lastCopiedId);
55326
+ params.store.updateMetadata(stagingId, {
55213
55327
  name: params.name,
55214
55328
  createdAt: now,
55215
- updatedAt: now,
55216
- activeEntryId,
55217
55329
  cwd: params.cwd ?? source.metadata.cwd,
55218
55330
  sourceSessionId: params.sourceSessionId,
55219
55331
  sourceEntryId: params.sourceEntryId,
55220
55332
  sourceActiveEntryId: source.metadata.activeEntryId ?? void 0,
55221
- forkBaseEntryId: activeEntryId,
55333
+ forkBaseEntryId: lastCopiedId,
55222
55334
  ...params.requestId ? { sessionControlRequestId: params.requestId } : {}
55223
55335
  });
55224
- const metadata = await params.store.getMetadata(params.targetSessionId);
55336
+ const backupId = `${params.targetSessionId}-previous-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
55337
+ const targetStatus = params.store.headStatus(params.targetSessionId);
55338
+ if (targetStatus === "legacy" || targetStatus === "corrupt") {
55339
+ loadRequiredSessionHead(params.store, params.targetSessionId);
55340
+ }
55341
+ const hadPreviousTarget = targetStatus === "ok";
55342
+ if (hadPreviousTarget && !params.force) {
55343
+ throw new SessionControlError("target_exists", `Target session already exists: ${params.targetSessionId}`);
55344
+ }
55345
+ const safeTargetId = safeSessionDirName(params.targetSessionId);
55346
+ const journalPath = params.sessionsDir ? publishJournalPath(params.sessionsDir, safeTargetId) : null;
55347
+ if (journalPath) {
55348
+ writePublishJournal(journalPath, {
55349
+ v: 1,
55350
+ targetId: safeTargetId,
55351
+ stagingId: safeSessionDirName(stagingId),
55352
+ backupDir: hadPreviousTarget ? safeSessionDirName(backupId) : null,
55353
+ writtenAt: Date.now()
55354
+ });
55355
+ }
55356
+ if (hadPreviousTarget) {
55357
+ try {
55358
+ params.store.moveSession(params.targetSessionId, backupId);
55359
+ } catch (error) {
55360
+ clearPublishJournal(journalPath);
55361
+ throw error;
55362
+ }
55363
+ }
55364
+ try {
55365
+ params.store.moveSession(stagingId, params.targetSessionId);
55366
+ } catch (error) {
55367
+ if (hadPreviousTarget) {
55368
+ try {
55369
+ if (params.store.headStatus(params.targetSessionId) !== "missing") {
55370
+ throw new Error("target path is occupied");
55371
+ }
55372
+ params.store.moveSession(backupId, params.targetSessionId);
55373
+ clearPublishJournal(journalPath);
55374
+ } catch (restoreError) {
55375
+ throw new SessionControlError(
55376
+ "session_io_error",
55377
+ `Fork publication failed; previous session is preserved as ${backupId}. Restore failed: ${String(restoreError)}`,
55378
+ false
55379
+ );
55380
+ }
55381
+ }
55382
+ clearPublishJournal(journalPath);
55383
+ throw error;
55384
+ }
55385
+ let backupDeleted = !hadPreviousTarget;
55386
+ if (hadPreviousTarget) {
55387
+ try {
55388
+ params.store.delete(backupId);
55389
+ backupDeleted = true;
55390
+ } catch {
55391
+ }
55392
+ }
55393
+ if (backupDeleted) {
55394
+ clearPublishJournal(journalPath);
55395
+ }
55396
+ const metadata = params.store.getMetadata(params.targetSessionId);
55225
55397
  if (!metadata) {
55226
55398
  throw new SessionControlError("session_unrecoverable", `Session could not be recovered after fork: ${params.targetSessionId}`, false);
55227
55399
  }
@@ -55232,13 +55404,23 @@ async function forkStoredSession(params) {
55232
55404
  sourceActiveEntryId: source.metadata.activeEntryId ?? null
55233
55405
  });
55234
55406
  } catch (error) {
55235
- if (error instanceof SessionControlError) throw error;
55236
- throw new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
55407
+ throw toIoError(error);
55408
+ } finally {
55409
+ if (stagingId) {
55410
+ try {
55411
+ params.store.delete(stagingId);
55412
+ } catch {
55413
+ }
55414
+ }
55237
55415
  }
55238
55416
  }
55239
55417
  async function maybeLoadExistingForkTarget(params) {
55240
- if (!await params.store.exists(params.targetSessionId)) return null;
55241
- const target = await params.store.load(params.targetSessionId);
55418
+ const status = params.store.headStatus(params.targetSessionId);
55419
+ if (status === "missing") return null;
55420
+ if (status === "legacy") {
55421
+ throw new SessionControlError("session_unsupported_format", `Target session uses an unsupported old format: ${params.targetSessionId}`);
55422
+ }
55423
+ const target = params.store.readHead(params.targetSessionId);
55242
55424
  if (!target) {
55243
55425
  throw new SessionControlError("session_unrecoverable", `Session could not be recovered: ${params.targetSessionId}`, false);
55244
55426
  }
@@ -55269,20 +55451,93 @@ function buildForkResult(params) {
55269
55451
  metadata: params.metadata
55270
55452
  };
55271
55453
  }
55272
- function pathToEntry(data, entryId) {
55273
- const byId = new Map(data.entries.map((entry) => [entry.id, entry]));
55274
- const path33 = [];
55275
- let current = entryId;
55276
- while (current) {
55277
- const entry = byId.get(current);
55278
- if (!entry) return [];
55279
- path33.unshift(entry);
55280
- current = entry.parentId;
55454
+ function recoverInterruptedPublishes(params) {
55455
+ const outcomes = [];
55456
+ const journalDir = path7.join(params.sessionsDir, PUBLISH_JOURNAL_DIR);
55457
+ let entries;
55458
+ try {
55459
+ entries = fs7.readdirSync(journalDir);
55460
+ } catch {
55461
+ return outcomes;
55281
55462
  }
55282
- return path33;
55463
+ for (const entry of entries) {
55464
+ if (!entry.endsWith(".json")) continue;
55465
+ outcomes.push(recoverOnePublishJournal({
55466
+ sessionsDir: params.sessionsDir,
55467
+ journalPath: path7.join(journalDir, entry),
55468
+ warn: params.warn
55469
+ }));
55470
+ }
55471
+ return outcomes;
55283
55472
  }
55284
- function cloneJson(value) {
55285
- return JSON.parse(JSON.stringify(value));
55473
+ function recoverOnePublishJournal(params) {
55474
+ const journalName = path7.basename(params.journalPath);
55475
+ const warn = (message) => {
55476
+ (params.warn ?? ((text) => console.warn(text)))(message);
55477
+ };
55478
+ let record;
55479
+ try {
55480
+ const parsed = JSON.parse(fs7.readFileSync(params.journalPath, "utf8"));
55481
+ const safeId = /^[a-zA-Z0-9_-]+$/;
55482
+ if (parsed?.v !== 1 || !safeId.test(parsed.targetId ?? "") || !safeId.test(parsed.stagingId ?? "") || !((parsed.backupDir ?? null) === null || safeId.test(parsed.backupDir))) {
55483
+ throw new Error("journal record has unexpected shape");
55484
+ }
55485
+ record = parsed;
55486
+ } catch (error) {
55487
+ const message = `[session-control] Unreadable publish journal ${journalName}; left in place for manual inspection: ${String(error)}`;
55488
+ warn(message);
55489
+ return { action: "unreadable-journal", journal: journalName, message };
55490
+ }
55491
+ const dirExists = (id) => {
55492
+ try {
55493
+ return fs7.statSync(path7.join(params.sessionsDir, id)).isDirectory();
55494
+ } catch {
55495
+ return false;
55496
+ }
55497
+ };
55498
+ const removeSessionDir = (id) => {
55499
+ fs7.rmSync(path7.join(params.sessionsDir, id), { recursive: true, force: true });
55500
+ };
55501
+ const removeJournal = () => {
55502
+ fs7.rmSync(params.journalPath, { force: true });
55503
+ };
55504
+ const targetExists = dirExists(record.targetId);
55505
+ const backupExists = record.backupDir ? dirExists(record.backupDir) : false;
55506
+ const stagingExists = dirExists(record.stagingId);
55507
+ try {
55508
+ if (targetExists && !stagingExists) {
55509
+ if (backupExists && record.backupDir) removeSessionDir(record.backupDir);
55510
+ removeJournal();
55511
+ return { action: "publish-completed", targetId: record.targetId };
55512
+ }
55513
+ if (!targetExists && backupExists && record.backupDir) {
55514
+ fs7.renameSync(
55515
+ path7.join(params.sessionsDir, record.backupDir),
55516
+ path7.join(params.sessionsDir, record.targetId)
55517
+ );
55518
+ removeJournal();
55519
+ if (stagingExists) {
55520
+ try {
55521
+ removeSessionDir(record.stagingId);
55522
+ } catch (error) {
55523
+ warn(`[session-control] Restored ${record.targetId} but could not remove its abandoned staging copy ${record.stagingId}: ${String(error)}`);
55524
+ }
55525
+ }
55526
+ return { action: "restored-previous-target", targetId: record.targetId };
55527
+ }
55528
+ if (!targetExists && !backupExists) {
55529
+ if (stagingExists) removeSessionDir(record.stagingId);
55530
+ removeJournal();
55531
+ return stagingExists ? { action: "discarded-incomplete-fork", targetId: record.targetId } : { action: "nothing-to-recover", targetId: record.targetId };
55532
+ }
55533
+ const message = `[session-control] Ambiguous interrupted publish for target ${record.targetId} (target=${targetExists}, backup=${backupExists}, staging=${stagingExists}); nothing was deleted \u2014 inspect ${params.sessionsDir} and ${journalName} manually`;
55534
+ warn(message);
55535
+ return { action: "ambiguous-preserved", targetId: record.targetId, message };
55536
+ } catch (error) {
55537
+ const message = `[session-control] Recovery of publish journal ${journalName} failed; state preserved for manual inspection: ${String(error)}`;
55538
+ warn(message);
55539
+ return { action: "ambiguous-preserved", targetId: record.targetId, message };
55540
+ }
55286
55541
  }
55287
55542
 
55288
55543
  // src/commands/sessions.ts
@@ -55339,6 +55594,7 @@ function toSessionCommandError(error, kind) {
55339
55594
  if (error instanceof SessionControlError) {
55340
55595
  const hints = {
55341
55596
  session_not_found: "list sessions: pie sessions list --json",
55597
+ session_unsupported_format: "old-format sessions cannot be read by this version",
55342
55598
  target_exists: "choose a new --target, or add --force to overwrite"
55343
55599
  };
55344
55600
  return new CommandError(kind, error.code, error.message, { hint: hints[error.code] });
@@ -55427,15 +55683,18 @@ async function readSession(parsed) {
55427
55683
  throw new CommandError("sessions.read", "missing_positional", renderCommandUsage(SESSIONS_READ_SPEC), { usage: true });
55428
55684
  }
55429
55685
  const store = new FileSessionStore(getSessionsDir());
55430
- const data = await loadSession(store, sessionId, "sessions.read");
55431
- const events = activeTranscriptEvents(activePathEntries(data));
55686
+ const data = loadSessionHead(store, sessionId, "sessions.read");
55687
+ const events = await activeTranscriptEvents(store, sessionId, data.metadata.activeEntryId);
55432
55688
  const end = resolveBeforeCursor(events, before);
55433
55689
  const start = Math.max(0, end - limit);
55434
55690
  const page = events.slice(start, end);
55691
+ for (const event of page) {
55692
+ hydrateTranscriptEvent(store, sessionId, event);
55693
+ }
55435
55694
  if (!json) {
55436
55695
  console.log(`${data.metadata.id}: ${data.metadata.name}`);
55437
- for (const entry of page) {
55438
- console.log(`${entry.logicalSeq} ${entry.type}${entry.role ? `:${entry.role}` : ""} ${entry.content ?? ""}`);
55696
+ for (const event of page) {
55697
+ console.log(`${event.logicalSeq} ${event.type}${event.role ? `:${event.role}` : ""} ${event.content ?? ""}`);
55439
55698
  }
55440
55699
  return;
55441
55700
  }
@@ -55481,9 +55740,9 @@ async function renameSession(parsed) {
55481
55740
  throw new CommandError("sessions.rename", "missing_positional", renderCommandUsage(SESSIONS_RENAME_SPEC), { usage: true });
55482
55741
  }
55483
55742
  const store = new FileSessionStore(getSessionsDir());
55484
- const data = await loadSession(store, sessionId, "sessions.rename");
55485
- await store.save(sessionId, data.entries, { ...data.metadata, name, nameSource: "manual", ...cwd ? { cwd } : {}, updatedAt: Date.now() });
55486
- const updated = await store.getMetadata(sessionId);
55743
+ loadSessionHead(store, sessionId, "sessions.rename");
55744
+ store.updateMetadata(sessionId, { name, nameSource: "manual", ...cwd ? { cwd } : {}, updatedAt: Date.now() });
55745
+ const updated = store.getMetadata(sessionId);
55487
55746
  if (!updated) throw new CommandError("sessions.rename", "session_not_found", `Session not found after rename: ${sessionId}`);
55488
55747
  if (json) {
55489
55748
  printSuccessEnvelope("sessions.rename", { session: fullSessionRow(updated) });
@@ -55523,6 +55782,7 @@ async function forkSession(parsed) {
55523
55782
  const store = new FileSessionStore(getSessionsDir());
55524
55783
  const result = await forkStoredSession({
55525
55784
  store,
55785
+ sessionsDir: getSessionsDir(),
55526
55786
  sourceSessionId: sessionId,
55527
55787
  sourceEntryId,
55528
55788
  targetSessionId,
@@ -55542,10 +55802,19 @@ async function forkSession(parsed) {
55542
55802
  }
55543
55803
  console.log(`Forked ${sessionId} at ${sourceEntryId} into ${targetSessionId}.`);
55544
55804
  }
55545
- async function loadSession(store, sessionId, kind) {
55546
- const data = await store.load(sessionId);
55547
- if (!data) throw new CommandError(kind, "session_not_found", `Session not found: ${sessionId}`, { hint: "list sessions: pie sessions list --json" });
55548
- return data;
55805
+ function loadSessionHead(store, sessionId, kind) {
55806
+ const status = store.headStatus(sessionId);
55807
+ if (status === "legacy") {
55808
+ throw new CommandError(kind, "session_unsupported_format", `Session uses an unsupported old format: ${sessionId}`, {
55809
+ hint: "old-format sessions cannot be read by this version"
55810
+ });
55811
+ }
55812
+ if (status === "corrupt") {
55813
+ throw new CommandError(kind, "session_unrecoverable", `Session could not be recovered: ${sessionId}`);
55814
+ }
55815
+ const head = store.readHead(sessionId);
55816
+ if (!head) throw new CommandError(kind, "session_not_found", `Session not found: ${sessionId}`, { hint: "list sessions: pie sessions list --json" });
55817
+ return { metadata: head.metadata };
55549
55818
  }
55550
55819
  function fullSessionRow(metadata) {
55551
55820
  return {
@@ -55599,31 +55868,30 @@ function cwdMatches(sessionCwd, requestedCwd) {
55599
55868
  }
55600
55869
  function realpathOrInput(value) {
55601
55870
  try {
55602
- return fs7.realpathSync.native(value);
55871
+ return fs8.realpathSync.native(value);
55603
55872
  } catch {
55604
55873
  return value;
55605
55874
  }
55606
55875
  }
55607
- function activeTranscriptEvents(entries) {
55608
- return entries.map((entry, index) => {
55609
- const role = isRecord2(entry.message) && typeof entry.message.role === "string" ? entry.message.role : void 0;
55610
- const turnId = isRecord2(entry.message) && typeof entry.message.turnId === "string" ? entry.message.turnId : void 0;
55611
- return {
55612
- logicalSeq: index + 1,
55613
- entryId: entry.id,
55614
- type: entry.type,
55615
- timestamp: entry.timestamp,
55616
- role,
55617
- turnId,
55618
- content: textFromMessage(entry.message),
55619
- message: entry.message ? cloneJson2(entry.message) : void 0
55620
- };
55621
- });
55622
- }
55623
- function activePathEntries(data) {
55624
- const activeEntryId = data.metadata.activeEntryId;
55876
+ async function activeTranscriptEvents(store, sessionId, activeEntryId) {
55625
55877
  if (!activeEntryId) return [];
55626
- return pathToEntry(data, activeEntryId);
55878
+ const summaries = store.getPathSummaries(sessionId, activeEntryId);
55879
+ return summaries.map((summary, index) => ({
55880
+ logicalSeq: index + 1,
55881
+ seq: summary.seq,
55882
+ entryId: summary.id,
55883
+ type: summary.type,
55884
+ timestamp: summary.timestamp,
55885
+ role: summary.role,
55886
+ content: summary.preview || void 0
55887
+ }));
55888
+ }
55889
+ function hydrateTranscriptEvent(store, sessionId, event) {
55890
+ const entry = store.readEntry(sessionId, event.entryId);
55891
+ if (!entry) return;
55892
+ event.turnId = isRecord2(entry.message) && typeof entry.message.turnId === "string" ? entry.message.turnId : void 0;
55893
+ event.content = textFromMessage(entry.message);
55894
+ event.message = entry.message ? cloneJson(entry.message) : void 0;
55627
55895
  }
55628
55896
  function resolveBeforeCursor(events, cursor) {
55629
55897
  if (!cursor) return events.length;
@@ -55634,7 +55902,7 @@ function resolveBeforeCursor(events, cursor) {
55634
55902
  const index = events.findIndex((event) => event.entryId === cursor);
55635
55903
  return index >= 0 ? index : events.length;
55636
55904
  }
55637
- function cloneJson2(value) {
55905
+ function cloneJson(value) {
55638
55906
  return JSON.parse(JSON.stringify(value));
55639
55907
  }
55640
55908
  function listCursorQueryKey(input) {
@@ -55671,9 +55939,9 @@ function isRecord2(value) {
55671
55939
  }
55672
55940
 
55673
55941
  // src/extensions/loader.ts
55674
- import * as fs8 from "node:fs";
55942
+ import * as fs9 from "node:fs";
55675
55943
  import * as os2 from "os";
55676
- import * as path7 from "path";
55944
+ import * as path8 from "path";
55677
55945
  import { pathToFileURL } from "node:url";
55678
55946
 
55679
55947
  // src/command-tree.ts
@@ -55686,19 +55954,19 @@ var CommandTree = class {
55686
55954
  * register(["session", "new"], { description, handler })
55687
55955
  * register(["tools", "subagent", "spawn", "local"], { description, handler })
55688
55956
  */
55689
- register(path33, info) {
55690
- if (path33.length === 0) {
55957
+ register(path34, info) {
55958
+ if (path34.length === 0) {
55691
55959
  throw new Error("Command path cannot be empty");
55692
55960
  }
55693
55961
  let current = this.root;
55694
55962
  const fullPath = [];
55695
- for (let i = 0; i < path33.length; i++) {
55696
- const segment = path33[i];
55963
+ for (let i = 0; i < path34.length; i++) {
55964
+ const segment = path34[i];
55697
55965
  fullPath.push(segment);
55698
55966
  if (!current.children) {
55699
55967
  current.children = [];
55700
55968
  }
55701
- const isLast = i === path33.length - 1;
55969
+ const isLast = i === path34.length - 1;
55702
55970
  let node = current.children.find((n) => n.name === segment);
55703
55971
  if (!node) {
55704
55972
  node = {
@@ -55728,31 +55996,31 @@ var CommandTree = class {
55728
55996
  /**
55729
55997
  * Find a node by path
55730
55998
  */
55731
- find(path33) {
55732
- if (path33.length === 0) {
55999
+ find(path34) {
56000
+ if (path34.length === 0) {
55733
56001
  return this.root;
55734
56002
  }
55735
- const key = path33.join("/");
56003
+ const key = path34.join("/");
55736
56004
  return this.pathCache.get(key) || null;
55737
56005
  }
55738
56006
  /**
55739
56007
  * Get children of a path
55740
56008
  */
55741
- getChildren(path33) {
55742
- const node = this.find(path33);
56009
+ getChildren(path34) {
56010
+ const node = this.find(path34);
55743
56011
  return (node?.children || []).filter((child) => !child.hidden);
55744
56012
  }
55745
56013
  /**
55746
56014
  * Check if a path exists (as category or command)
55747
56015
  */
55748
- exists(path33) {
55749
- return this.find(path33) !== null;
56016
+ exists(path34) {
56017
+ return this.find(path34) !== null;
55750
56018
  }
55751
56019
  /**
55752
56020
  * Check if path is a category (has children)
55753
56021
  */
55754
- isCategory(path33) {
55755
- const node = this.find(path33);
56022
+ isCategory(path34) {
56023
+ const node = this.find(path34);
55756
56024
  return node?.isCategory || false;
55757
56025
  }
55758
56026
  /**
@@ -55831,8 +56099,8 @@ var CommandTree = class {
55831
56099
  * Supports dot notation: "tools.subagent.spawn.local"
55832
56100
  */
55833
56101
  registerFromPath(pathStr, info) {
55834
- const path33 = pathStr.split(/[./]/).filter(Boolean);
55835
- this.register(path33, info);
56102
+ const path34 = pathStr.split(/[./]/).filter(Boolean);
56103
+ this.register(path34, info);
55836
56104
  }
55837
56105
  };
55838
56106
  var commandTree = new CommandTree();
@@ -55995,19 +56263,19 @@ function createExtension(extensionPath, resolvedPath, identity, source) {
55995
56263
  }
55996
56264
  function expandPath(p) {
55997
56265
  if (p.startsWith("~/")) {
55998
- return path7.join(os2.homedir(), p.slice(2));
56266
+ return path8.join(os2.homedir(), p.slice(2));
55999
56267
  }
56000
56268
  if (p.startsWith("~")) {
56001
- return path7.join(os2.homedir(), p.slice(1));
56269
+ return path8.join(os2.homedir(), p.slice(1));
56002
56270
  }
56003
56271
  return p;
56004
56272
  }
56005
56273
  function resolvePath(extPath, cwd) {
56006
56274
  const expanded = expandPath(extPath);
56007
- if (path7.isAbsolute(expanded)) {
56275
+ if (path8.isAbsolute(expanded)) {
56008
56276
  return expanded;
56009
56277
  }
56010
- return path7.resolve(cwd, expanded);
56278
+ return path8.resolve(cwd, expanded);
56011
56279
  }
56012
56280
  async function loadExtensionModule(extensionPath) {
56013
56281
  try {
@@ -56027,14 +56295,14 @@ function normalizeExtensionImportPath(extensionPath) {
56027
56295
  if (/^[a-zA-Z]:[\\/]/.test(extensionPath)) {
56028
56296
  return `file:///${extensionPath.replace(/\\/g, "/")}`;
56029
56297
  }
56030
- if (path7.isAbsolute(extensionPath)) {
56298
+ if (path8.isAbsolute(extensionPath)) {
56031
56299
  return pathToFileURL(extensionPath).href;
56032
56300
  }
56033
56301
  return extensionPath;
56034
56302
  }
56035
56303
  async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, hasUI, actions, discovered) {
56036
56304
  const resolvedPath = resolvePath(extensionPath, cwd);
56037
- if (!fs8.existsSync(resolvedPath)) {
56305
+ if (!fs9.existsSync(resolvedPath)) {
56038
56306
  return { extension: null, error: `Extension not found: ${extensionPath}` };
56039
56307
  }
56040
56308
  try {
@@ -56060,17 +56328,17 @@ async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, h
56060
56328
  }
56061
56329
  }
56062
56330
  function discoverExtensionsInDir(dir, source) {
56063
- if (!fs8.existsSync(dir)) {
56331
+ if (!fs9.existsSync(dir)) {
56064
56332
  return [];
56065
56333
  }
56066
56334
  const discovered = [];
56067
56335
  try {
56068
- const entries = fs8.readdirSync(dir, { withFileTypes: true });
56336
+ const entries = fs9.readdirSync(dir, { withFileTypes: true });
56069
56337
  for (const entry of entries) {
56070
56338
  if (entry.name.endsWith(".disabled")) {
56071
56339
  continue;
56072
56340
  }
56073
- const entryPath = path7.join(dir, entry.name);
56341
+ const entryPath = path8.join(dir, entry.name);
56074
56342
  if (entry.isFile() && (entry.name.endsWith(".cjs") || entry.name.endsWith(".js") || entry.name.endsWith(".ts"))) {
56075
56343
  discovered.push({
56076
56344
  entryPath,
@@ -56080,13 +56348,13 @@ function discoverExtensionsInDir(dir, source) {
56080
56348
  continue;
56081
56349
  }
56082
56350
  if (entry.isDirectory()) {
56083
- const packageJsonPath = path7.join(entryPath, "package.json");
56351
+ const packageJsonPath = path8.join(entryPath, "package.json");
56084
56352
  let packageIdentity;
56085
56353
  let packageDescription;
56086
56354
  let packageMainPath;
56087
- if (fs8.existsSync(packageJsonPath)) {
56355
+ if (fs9.existsSync(packageJsonPath)) {
56088
56356
  try {
56089
- const pkg = JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8"));
56357
+ const pkg = JSON.parse(fs9.readFileSync(packageJsonPath, "utf-8"));
56090
56358
  const manifest = pkg.pie && typeof pkg.pie === "object" && !Array.isArray(pkg.pie) ? pkg.pie : void 0;
56091
56359
  packageIdentity = resolveExtensionIdentity({
56092
56360
  pieName: typeof manifest?.name === "string" ? manifest.name : void 0,
@@ -56095,8 +56363,8 @@ function discoverExtensionsInDir(dir, source) {
56095
56363
  });
56096
56364
  packageDescription = typeof pkg.description === "string" ? pkg.description : void 0;
56097
56365
  if (typeof manifest?.main === "string" && manifest.main.trim().length > 0) {
56098
- const candidate = path7.resolve(entryPath, manifest.main);
56099
- if (fs8.existsSync(candidate)) {
56366
+ const candidate = path8.resolve(entryPath, manifest.main);
56367
+ if (fs9.existsSync(candidate)) {
56100
56368
  packageMainPath = candidate;
56101
56369
  }
56102
56370
  }
@@ -56112,8 +56380,8 @@ function discoverExtensionsInDir(dir, source) {
56112
56380
  });
56113
56381
  continue;
56114
56382
  }
56115
- const indexCjs = path7.join(entryPath, "index.cjs");
56116
- if (fs8.existsSync(indexCjs)) {
56383
+ const indexCjs = path8.join(entryPath, "index.cjs");
56384
+ if (fs9.existsSync(indexCjs)) {
56117
56385
  discovered.push({
56118
56386
  entryPath: indexCjs,
56119
56387
  source,
@@ -56122,8 +56390,8 @@ function discoverExtensionsInDir(dir, source) {
56122
56390
  });
56123
56391
  continue;
56124
56392
  }
56125
- const indexJs = path7.join(entryPath, "index.js");
56126
- if (fs8.existsSync(indexJs)) {
56393
+ const indexJs = path8.join(entryPath, "index.js");
56394
+ if (fs9.existsSync(indexJs)) {
56127
56395
  discovered.push({
56128
56396
  entryPath: indexJs,
56129
56397
  source,
@@ -56132,8 +56400,8 @@ function discoverExtensionsInDir(dir, source) {
56132
56400
  });
56133
56401
  continue;
56134
56402
  }
56135
- const indexTs = path7.join(entryPath, "index.ts");
56136
- if (fs8.existsSync(indexTs)) {
56403
+ const indexTs = path8.join(entryPath, "index.ts");
56404
+ if (fs9.existsSync(indexTs)) {
56137
56405
  discovered.push({
56138
56406
  entryPath: indexTs,
56139
56407
  source,
@@ -56154,21 +56422,21 @@ function collectDiscoveredExtensions(configuredPaths, cwd, options) {
56154
56422
  const errors = [];
56155
56423
  if (!options?.noExtensions) {
56156
56424
  if (!options?.noBuiltinExtensions) {
56157
- const builtinExtDir = path7.join(getBuiltinDir(), "extensions");
56425
+ const builtinExtDir = path8.join(getBuiltinDir(), "extensions");
56158
56426
  discovered.push(...discoverExtensionsInDir(builtinExtDir, "builtin"));
56159
56427
  }
56160
- const globalExtDir = path7.join(os2.homedir(), ".pie", "extensions");
56428
+ const globalExtDir = path8.join(os2.homedir(), ".pie", "extensions");
56161
56429
  discovered.push(...discoverExtensionsInDir(globalExtDir, "global"));
56162
- const localExtDir = path7.join(cwd, ".pie", "extensions");
56430
+ const localExtDir = path8.join(cwd, ".pie", "extensions");
56163
56431
  discovered.push(...discoverExtensionsInDir(localExtDir, "project"));
56164
56432
  }
56165
56433
  for (const p of configuredPaths) {
56166
56434
  const resolved = resolvePath(p, cwd);
56167
- if (!fs8.existsSync(resolved)) {
56435
+ if (!fs9.existsSync(resolved)) {
56168
56436
  errors.push({ path: p, error: `Extension path not found: ${p}` });
56169
56437
  continue;
56170
56438
  }
56171
- if (!fs8.statSync(resolved).isDirectory()) {
56439
+ if (!fs9.statSync(resolved).isDirectory()) {
56172
56440
  errors.push({ path: p, error: `Extension path must be a directory: ${p}` });
56173
56441
  continue;
56174
56442
  }
@@ -57023,8 +57291,8 @@ function wrapSingleLine(line, width) {
57023
57291
  if (!line) {
57024
57292
  return [""];
57025
57293
  }
57026
- const visibleLength2 = visibleWidth(line);
57027
- if (visibleLength2 <= width) {
57294
+ const visibleLength = visibleWidth(line);
57295
+ if (visibleLength <= width) {
57028
57296
  return [line];
57029
57297
  }
57030
57298
  const wrapped = [];
@@ -58056,9 +58324,9 @@ var KillRing = class {
58056
58324
  };
58057
58325
 
58058
58326
  // ../../packages/tui/src/tui.ts
58059
- import * as fs9 from "node:fs";
58327
+ import * as fs10 from "node:fs";
58060
58328
  import * as os3 from "node:os";
58061
- import * as path8 from "node:path";
58329
+ import * as path9 from "node:path";
58062
58330
 
58063
58331
  // ../../packages/tui/src/terminal-image.ts
58064
58332
  var cachedCapabilities = null;
@@ -58738,11 +59006,11 @@ var TUI = class extends Container {
58738
59006
  const debugRedraw = process.env.PIE_DEBUG_REDRAW === "1";
58739
59007
  const logRedraw = (reason) => {
58740
59008
  if (!debugRedraw) return;
58741
- const logPath = path8.join(os3.homedir(), ".pie", "logs", "pie-cli.log");
58742
- fs9.mkdirSync(path8.dirname(logPath), { recursive: true });
59009
+ const logPath = path9.join(os3.homedir(), ".pie", "logs", "pie-cli.log");
59010
+ fs10.mkdirSync(path9.dirname(logPath), { recursive: true });
58743
59011
  const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] [DEBUG] [ui] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})
58744
59012
  `;
58745
- fs9.appendFileSync(logPath, msg);
59013
+ fs10.appendFileSync(logPath, msg);
58746
59014
  };
58747
59015
  if (this.previousLines.length === 0 && !widthChanged) {
58748
59016
  logRedraw("first render");
@@ -58835,7 +59103,7 @@ var TUI = class extends Container {
58835
59103
  const line = newLines[i];
58836
59104
  const isImage = isImageLine(line);
58837
59105
  if (!isImage && visibleWidth(line) > width) {
58838
- const crashLogPath = path8.join(os3.homedir(), ".pie", "pie-crash.log");
59106
+ const crashLogPath = path9.join(os3.homedir(), ".pie", "pie-crash.log");
58839
59107
  const crashData = [
58840
59108
  `Crash at ${(/* @__PURE__ */ new Date()).toISOString()}`,
58841
59109
  `Terminal width: ${width}`,
@@ -58845,8 +59113,8 @@ var TUI = class extends Container {
58845
59113
  ...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),
58846
59114
  ""
58847
59115
  ].join("\n");
58848
- fs9.mkdirSync(path8.dirname(crashLogPath), { recursive: true });
58849
- fs9.writeFileSync(crashLogPath, crashData);
59116
+ fs10.mkdirSync(path9.dirname(crashLogPath), { recursive: true });
59117
+ fs10.writeFileSync(crashLogPath, crashData);
58850
59118
  this.stop();
58851
59119
  const errorMsg = [
58852
59120
  `Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,
@@ -58876,8 +59144,8 @@ var TUI = class extends Container {
58876
59144
  buffer += "\x1B[?2026l";
58877
59145
  if (process.env.PIE_TUI_DEBUG === "1") {
58878
59146
  const debugDir = "/tmp/tui";
58879
- fs9.mkdirSync(debugDir, { recursive: true });
58880
- const debugPath = path8.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
59147
+ fs10.mkdirSync(debugDir, { recursive: true });
59148
+ const debugPath = path9.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
58881
59149
  const debugData = [
58882
59150
  `firstChanged: ${firstChanged}`,
58883
59151
  `viewportTop: ${viewportTop}`,
@@ -58900,7 +59168,7 @@ var TUI = class extends Container {
58900
59168
  "=== buffer ===",
58901
59169
  JSON.stringify(buffer)
58902
59170
  ].join("\n");
58903
- fs9.writeFileSync(debugPath, debugData);
59171
+ fs10.writeFileSync(debugPath, debugData);
58904
59172
  }
58905
59173
  this.terminal.write(buffer);
58906
59174
  this.cursorRow = Math.max(0, newLines.length - 1);
@@ -63189,7 +63457,7 @@ var StdinBuffer = class extends EventEmitter {
63189
63457
  };
63190
63458
 
63191
63459
  // ../../packages/tui/src/terminal.ts
63192
- import * as fs10 from "node:fs";
63460
+ import * as fs11 from "node:fs";
63193
63461
  import koffi from "koffi";
63194
63462
  var ProcessTerminal = class {
63195
63463
  wasRaw = false;
@@ -63352,7 +63620,7 @@ var ProcessTerminal = class {
63352
63620
  process.stdout.write(data);
63353
63621
  if (this.writeLogPath) {
63354
63622
  try {
63355
- fs10.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
63623
+ fs11.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
63356
63624
  } catch {
63357
63625
  }
63358
63626
  }
@@ -64197,8 +64465,8 @@ function restoreInteractiveSessionState(options) {
64197
64465
  }
64198
64466
 
64199
64467
  // src/keybindings.ts
64200
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
64201
- import { join as join7 } from "path";
64468
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
64469
+ import { join as join8 } from "path";
64202
64470
  var DEFAULT_APP_KEYBINDINGS = {
64203
64471
  interrupt: "escape",
64204
64472
  clear: "ctrl+c",
@@ -64262,7 +64530,7 @@ var KeybindingsManager = class _KeybindingsManager {
64262
64530
  * Create from config file and set up editor keybindings.
64263
64531
  */
64264
64532
  static create(agentDir = getAgentDir()) {
64265
- const configPath = join7(agentDir, "keybindings.json");
64533
+ const configPath = join8(agentDir, "keybindings.json");
64266
64534
  const config = _KeybindingsManager.loadFromFile(configPath);
64267
64535
  const manager = new _KeybindingsManager(config);
64268
64536
  const editorConfig = {};
@@ -64280,10 +64548,10 @@ var KeybindingsManager = class _KeybindingsManager {
64280
64548
  static inMemory(config = {}) {
64281
64549
  return new _KeybindingsManager(config);
64282
64550
  }
64283
- static loadFromFile(path33) {
64284
- if (!existsSync8(path33)) return {};
64551
+ static loadFromFile(path34) {
64552
+ if (!existsSync9(path34)) return {};
64285
64553
  try {
64286
- return JSON.parse(readFileSync7(path33, "utf-8"));
64554
+ return JSON.parse(readFileSync8(path34, "utf-8"));
64287
64555
  } catch {
64288
64556
  return {};
64289
64557
  }
@@ -64332,19 +64600,19 @@ var KeybindingsManager = class _KeybindingsManager {
64332
64600
  };
64333
64601
 
64334
64602
  // src/project-knowledge.ts
64335
- import fs11 from "node:fs";
64336
- import path9 from "node:path";
64603
+ import fs12 from "node:fs";
64604
+ import path10 from "node:path";
64337
64605
  function collectAncestorAgentsFiles(cwd) {
64338
- const resolvedCwd = path9.resolve(cwd || process.cwd());
64606
+ const resolvedCwd = path10.resolve(cwd || process.cwd());
64339
64607
  const projectRoot = resolveCliProjectRoot(resolvedCwd);
64340
64608
  const candidates = [];
64341
64609
  let current = resolvedCwd;
64342
64610
  while (true) {
64343
- candidates.unshift(path9.join(current, AGENTS_CONTEXT_FILE_NAME));
64611
+ candidates.unshift(path10.join(current, AGENTS_CONTEXT_FILE_NAME));
64344
64612
  if (current === projectRoot) {
64345
64613
  break;
64346
64614
  }
64347
- const parent = path9.dirname(current);
64615
+ const parent = path10.dirname(current);
64348
64616
  if (parent === current) {
64349
64617
  break;
64350
64618
  }
@@ -64352,13 +64620,13 @@ function collectAncestorAgentsFiles(cwd) {
64352
64620
  }
64353
64621
  const files = [];
64354
64622
  for (const candidate of candidates) {
64355
- if (!fs11.existsSync(candidate)) {
64623
+ if (!fs12.existsSync(candidate)) {
64356
64624
  continue;
64357
64625
  }
64358
64626
  try {
64359
64627
  files.push({
64360
- path: path9.relative(resolvedCwd, candidate) || AGENTS_CONTEXT_FILE_NAME,
64361
- content: fs11.readFileSync(candidate, "utf-8")
64628
+ path: path10.relative(resolvedCwd, candidate) || AGENTS_CONTEXT_FILE_NAME,
64629
+ content: fs12.readFileSync(candidate, "utf-8")
64362
64630
  });
64363
64631
  } catch {
64364
64632
  }
@@ -64370,14 +64638,14 @@ function buildCliProjectContextSection(cwd) {
64370
64638
  }
64371
64639
 
64372
64640
  // src/file-access-context.ts
64373
- import * as path10 from "node:path";
64641
+ import * as path11 from "node:path";
64374
64642
  function uniqueNormalizedPaths(paths) {
64375
64643
  const seen = /* @__PURE__ */ new Set();
64376
64644
  const result = [];
64377
64645
  for (const entry of paths) {
64378
64646
  const trimmed = String(entry || "").trim();
64379
64647
  if (!trimmed) continue;
64380
- const normalized = path10.normalize(trimmed);
64648
+ const normalized = path11.normalize(trimmed);
64381
64649
  if (seen.has(normalized)) continue;
64382
64650
  seen.add(normalized);
64383
64651
  result.push(normalized);
@@ -64396,8 +64664,8 @@ function buildCliFileAccessOptions(params) {
64396
64664
  }
64397
64665
 
64398
64666
  // src/theme/theme.ts
64399
- import * as fs12 from "node:fs";
64400
- import * as path11 from "node:path";
64667
+ import * as fs13 from "node:fs";
64668
+ import * as path12 from "node:path";
64401
64669
 
64402
64670
  // ../../node_modules/@sinclair/typebox/build/esm/compiler/compiler.mjs
64403
64671
  var TypeCheck = class {
@@ -65284,11 +65552,11 @@ var BUILTIN_THEMES;
65284
65552
  function getBuiltinThemes() {
65285
65553
  if (!BUILTIN_THEMES) {
65286
65554
  const themesDir = getThemesDir();
65287
- const darkPath = path11.join(themesDir, "dark.json");
65288
- const lightPath = path11.join(themesDir, "light.json");
65555
+ const darkPath = path12.join(themesDir, "dark.json");
65556
+ const lightPath = path12.join(themesDir, "light.json");
65289
65557
  BUILTIN_THEMES = {
65290
- dark: JSON.parse(fs12.readFileSync(darkPath, "utf-8")),
65291
- light: JSON.parse(fs12.readFileSync(lightPath, "utf-8"))
65558
+ dark: JSON.parse(fs13.readFileSync(darkPath, "utf-8")),
65559
+ light: JSON.parse(fs13.readFileSync(lightPath, "utf-8"))
65292
65560
  };
65293
65561
  }
65294
65562
  return BUILTIN_THEMES;
@@ -65296,8 +65564,8 @@ function getBuiltinThemes() {
65296
65564
  function getAvailableThemes() {
65297
65565
  const themes = new Set(Object.keys(getBuiltinThemes()));
65298
65566
  const customThemesDir = getCustomThemesDir();
65299
- if (fs12.existsSync(customThemesDir)) {
65300
- const files = fs12.readdirSync(customThemesDir);
65567
+ if (fs13.existsSync(customThemesDir)) {
65568
+ const files = fs13.readdirSync(customThemesDir);
65301
65569
  for (const file of files) {
65302
65570
  if (file.endsWith(".json")) {
65303
65571
  themes.add(file.slice(0, -5));
@@ -65358,18 +65626,18 @@ function loadThemeJson(name) {
65358
65626
  }
65359
65627
  const registeredTheme = registeredThemes.get(name);
65360
65628
  if (registeredTheme?.sourcePath) {
65361
- const content2 = fs12.readFileSync(registeredTheme.sourcePath, "utf-8");
65629
+ const content2 = fs13.readFileSync(registeredTheme.sourcePath, "utf-8");
65362
65630
  return parseThemeJsonContent(registeredTheme.sourcePath, content2);
65363
65631
  }
65364
65632
  if (registeredTheme) {
65365
65633
  throw new Error(`Theme "${name}" does not have a source path for export`);
65366
65634
  }
65367
65635
  const customThemesDir = getCustomThemesDir();
65368
- const themePath = path11.join(customThemesDir, `${name}.json`);
65369
- if (!fs12.existsSync(themePath)) {
65636
+ const themePath = path12.join(customThemesDir, `${name}.json`);
65637
+ if (!fs13.existsSync(themePath)) {
65370
65638
  throw new Error(`Theme not found: ${name}`);
65371
65639
  }
65372
- const content = fs12.readFileSync(themePath, "utf-8");
65640
+ const content = fs13.readFileSync(themePath, "utf-8");
65373
65641
  return parseThemeJsonContent(name, content);
65374
65642
  }
65375
65643
  function createTheme(themeJson, mode, sourcePath) {
@@ -65482,12 +65750,12 @@ function startThemeWatcher() {
65482
65750
  return;
65483
65751
  }
65484
65752
  const customThemesDir = getCustomThemesDir();
65485
- const themeFile = path11.join(customThemesDir, `${currentThemeName}.json`);
65486
- if (!fs12.existsSync(themeFile)) {
65753
+ const themeFile = path12.join(customThemesDir, `${currentThemeName}.json`);
65754
+ if (!fs13.existsSync(themeFile)) {
65487
65755
  return;
65488
65756
  }
65489
65757
  try {
65490
- themeWatcher = fs12.watch(themeFile, (eventType) => {
65758
+ themeWatcher = fs13.watch(themeFile, (eventType) => {
65491
65759
  if (eventType === "change") {
65492
65760
  setTimeout(() => {
65493
65761
  try {
@@ -65500,7 +65768,7 @@ function startThemeWatcher() {
65500
65768
  }, 100);
65501
65769
  } else if (eventType === "rename") {
65502
65770
  setTimeout(() => {
65503
- if (!fs12.existsSync(themeFile)) {
65771
+ if (!fs13.existsSync(themeFile)) {
65504
65772
  currentThemeName = "dark";
65505
65773
  setGlobalTheme(loadTheme("dark"));
65506
65774
  if (themeWatcher) {
@@ -65681,9 +65949,9 @@ function getSettingsListTheme() {
65681
65949
 
65682
65950
  // src/skills/loader.ts
65683
65951
  var import_yaml = __toESM(require_dist2(), 1);
65684
- import * as fs13 from "fs";
65952
+ import * as fs14 from "fs";
65685
65953
  import * as os4 from "os";
65686
- import * as path12 from "path";
65954
+ import * as path13 from "path";
65687
65955
  function parseSkillDescription(content) {
65688
65956
  content = content.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n");
65689
65957
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---(?:\n|$)/);
@@ -65707,19 +65975,19 @@ function parseSkillDescription(content) {
65707
65975
  }
65708
65976
  var USER_CONTROLLED_SOURCES = /* @__PURE__ */ new Set(["user-agents", "user"]);
65709
65977
  function pathIsInside(child, parent) {
65710
- const relative3 = path12.relative(parent, child);
65711
- return relative3 !== "" && !relative3.startsWith(`..${path12.sep}`) && relative3 !== ".." && !path12.isAbsolute(relative3);
65978
+ const relative3 = path13.relative(parent, child);
65979
+ return relative3 !== "" && !relative3.startsWith(`..${path13.sep}`) && relative3 !== ".." && !path13.isAbsolute(relative3);
65712
65980
  }
65713
65981
  function resolveSkillSymlink(fullPath, dir, source) {
65714
65982
  let target;
65715
65983
  let stats;
65716
65984
  try {
65717
- target = fs13.realpathSync(fullPath);
65718
- stats = fs13.statSync(target);
65985
+ target = fs14.realpathSync(fullPath);
65986
+ stats = fs14.statSync(target);
65719
65987
  } catch {
65720
65988
  return { error: `broken skill symlink: ${fullPath}` };
65721
65989
  }
65722
- if (!USER_CONTROLLED_SOURCES.has(source) && !pathIsInside(target, fs13.realpathSync(dir))) {
65990
+ if (!USER_CONTROLLED_SOURCES.has(source) && !pathIsInside(target, fs14.realpathSync(dir))) {
65723
65991
  return { error: `skill symlink escapes the "${source}" layer (not loaded): ${fullPath} -> ${target}` };
65724
65992
  }
65725
65993
  return { target, isDirectory: stats.isDirectory(), isFile: stats.isFile() };
@@ -65727,13 +65995,13 @@ function resolveSkillSymlink(fullPath, dir, source) {
65727
65995
  function loadSkillsFromDir(dir, source) {
65728
65996
  const skills = [];
65729
65997
  const diagnostics = [];
65730
- if (!fs13.existsSync(dir)) {
65998
+ if (!fs14.existsSync(dir)) {
65731
65999
  return { skills, diagnostics };
65732
66000
  }
65733
- const entries = fs13.readdirSync(dir, { withFileTypes: true });
66001
+ const entries = fs14.readdirSync(dir, { withFileTypes: true });
65734
66002
  for (const entry of entries) {
65735
66003
  if (entry.name.startsWith(".")) continue;
65736
- const fullPath = path12.join(dir, entry.name);
66004
+ const fullPath = path13.join(dir, entry.name);
65737
66005
  let entryPath = fullPath;
65738
66006
  let entryIsDirectory = entry.isDirectory();
65739
66007
  let entryIsFile = entry.isFile();
@@ -65748,10 +66016,10 @@ function loadSkillsFromDir(dir, source) {
65748
66016
  entryIsFile = resolved.isFile;
65749
66017
  }
65750
66018
  if (entryIsDirectory) {
65751
- const skillMdPath = path12.join(entryPath, "SKILL.md");
65752
- if (fs13.existsSync(skillMdPath)) {
66019
+ const skillMdPath = path13.join(entryPath, "SKILL.md");
66020
+ if (fs14.existsSync(skillMdPath)) {
65753
66021
  try {
65754
- const content = fs13.readFileSync(skillMdPath, "utf-8");
66022
+ const content = fs14.readFileSync(skillMdPath, "utf-8");
65755
66023
  const description = parseSkillDescription(content);
65756
66024
  skills.push({
65757
66025
  name: entry.name,
@@ -65772,7 +66040,7 @@ function loadSkillsFromDir(dir, source) {
65772
66040
  } else if (entryIsFile && entry.name.endsWith(".md")) {
65773
66041
  const name = entry.name.slice(0, -3);
65774
66042
  try {
65775
- const content = fs13.readFileSync(entryPath, "utf-8");
66043
+ const content = fs14.readFileSync(entryPath, "utf-8");
65776
66044
  const description = parseSkillDescription(content);
65777
66045
  skills.push({
65778
66046
  name,
@@ -65780,7 +66048,7 @@ function loadSkillsFromDir(dir, source) {
65780
66048
  content,
65781
66049
  filePath: entryPath,
65782
66050
  source,
65783
- baseDir: path12.dirname(entryPath)
66051
+ baseDir: path13.dirname(entryPath)
65784
66052
  });
65785
66053
  } catch (e) {
65786
66054
  diagnostics.push({
@@ -65794,18 +66062,18 @@ function loadSkillsFromDir(dir, source) {
65794
66062
  return { skills, diagnostics };
65795
66063
  }
65796
66064
  function discoverAgentsSkillsDirs(cwd) {
65797
- const resolvedCwd = path12.resolve(cwd || process.cwd());
66065
+ const resolvedCwd = path13.resolve(cwd || process.cwd());
65798
66066
  const projectRoot = resolveCliProjectRoot(resolvedCwd);
65799
66067
  const projectAgentsDirs = [];
65800
66068
  let current = projectRoot;
65801
66069
  while (true) {
65802
- projectAgentsDirs.push(path12.join(current, ".agents", "skills"));
66070
+ projectAgentsDirs.push(path13.join(current, ".agents", "skills"));
65803
66071
  if (current === resolvedCwd) break;
65804
- const child = path12.relative(current, resolvedCwd).split(path12.sep)[0];
66072
+ const child = path13.relative(current, resolvedCwd).split(path13.sep)[0];
65805
66073
  if (!child) break;
65806
- current = path12.join(current, child);
66074
+ current = path13.join(current, child);
65807
66075
  }
65808
- return { userAgentsDir: path12.join(os4.homedir(), ".agents", "skills"), projectAgentsDirs };
66076
+ return { userAgentsDir: path13.join(os4.homedir(), ".agents", "skills"), projectAgentsDirs };
65809
66077
  }
65810
66078
  function buildSkillDirs(options) {
65811
66079
  const { userAgentsDir, projectAgentsDirs } = discoverAgentsSkillsDirs(options.cwd);
@@ -65976,11 +66244,11 @@ function validateSkillName(name) {
65976
66244
  }
65977
66245
 
65978
66246
  // src/interactive-mode.ts
65979
- import * as path29 from "path";
66247
+ import * as path30 from "path";
65980
66248
 
65981
66249
  // src/capabilities/read-file-understanding.ts
65982
- import * as path21 from "node:path";
65983
- import * as fs21 from "node:fs/promises";
66250
+ import * as path22 from "node:path";
66251
+ import * as fs22 from "node:fs/promises";
65984
66252
 
65985
66253
  // src/core/provider-capabilities.ts
65986
66254
  var PLATFORM_DISPLAY_NAMES = {
@@ -66006,8 +66274,8 @@ function getProviderDisplayName(platform2) {
66006
66274
  }
66007
66275
 
66008
66276
  // src/files/adapters/kimi-adapter.ts
66009
- import * as fs14 from "node:fs";
66010
- import * as path13 from "node:path";
66277
+ import * as fs15 from "node:fs";
66278
+ import * as path14 from "node:path";
66011
66279
 
66012
66280
  // src/files/errors.ts
66013
66281
  var FileErrorMessages = {
@@ -66144,17 +66412,17 @@ var KimiFileAdapter = class {
66144
66412
  // Upload
66145
66413
  // ============================================================================
66146
66414
  async upload(filePath, options = {}) {
66147
- const fileName = options.sourceName || path13.basename(filePath);
66415
+ const fileName = options.sourceName || path14.basename(filePath);
66148
66416
  const mimeType = options.mimeType || this.guessMimeType(fileName);
66149
66417
  const purpose = this.detectPurpose(filePath, options.purpose, mimeType);
66150
- const stats = fs14.statSync(filePath);
66418
+ const stats = fs15.statSync(filePath);
66151
66419
  if (stats.size > this.capabilities.maxFileSize) {
66152
66420
  throw new FileManagerError(
66153
66421
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
66154
66422
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds Kimi limit of 100MB`
66155
66423
  );
66156
66424
  }
66157
- const fileBuffer = fs14.readFileSync(filePath);
66425
+ const fileBuffer = fs15.readFileSync(filePath);
66158
66426
  const file = new File([fileBuffer], fileName, { type: mimeType });
66159
66427
  const formData = new FormData();
66160
66428
  formData.append("file", file);
@@ -66206,7 +66474,7 @@ var KimiFileAdapter = class {
66206
66474
  return "file-extract";
66207
66475
  }
66208
66476
  guessMimeType(filename) {
66209
- const ext = path13.extname(filename).toLowerCase();
66477
+ const ext = path14.extname(filename).toLowerCase();
66210
66478
  switch (ext) {
66211
66479
  case ".jpg":
66212
66480
  case ".jpeg":
@@ -66368,8 +66636,8 @@ var KimiFileAdapter = class {
66368
66636
  };
66369
66637
 
66370
66638
  // src/files/adapters/gemini-adapter.ts
66371
- import * as fs15 from "node:fs";
66372
- import * as path14 from "node:path";
66639
+ import * as fs16 from "node:fs";
66640
+ import * as path15 from "node:path";
66373
66641
  import { Readable } from "node:stream";
66374
66642
  var GeminiFileAdapter = class {
66375
66643
  platform = "gemini";
@@ -66426,7 +66694,7 @@ var GeminiFileAdapter = class {
66426
66694
  // Upload
66427
66695
  // ============================================================================
66428
66696
  async upload(filePath, options = {}) {
66429
- const stats = fs15.statSync(filePath);
66697
+ const stats = fs16.statSync(filePath);
66430
66698
  if (stats.size > this.capabilities.maxFileSize) {
66431
66699
  throw new FileManagerError(
66432
66700
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
@@ -66434,7 +66702,7 @@ var GeminiFileAdapter = class {
66434
66702
  );
66435
66703
  }
66436
66704
  const mimeType = options.mimeType || this.guessMimeType(filePath);
66437
- const displayName = options.sourceName || path14.basename(filePath);
66705
+ const displayName = options.sourceName || path15.basename(filePath);
66438
66706
  const startResponse = await fetch(
66439
66707
  `${this.baseUrl}/upload/v1beta/files?key=${this.apiKey}`,
66440
66708
  {
@@ -66465,7 +66733,7 @@ var GeminiFileAdapter = class {
66465
66733
  "No upload URL received"
66466
66734
  );
66467
66735
  }
66468
- const fileStream = Readable.toWeb(fs15.createReadStream(filePath));
66736
+ const fileStream = Readable.toWeb(fs16.createReadStream(filePath));
66469
66737
  const uploadResponse = await fetch(uploadUrl, {
66470
66738
  method: "POST",
66471
66739
  headers: {
@@ -66669,8 +66937,8 @@ var GeminiFileAdapter = class {
66669
66937
  };
66670
66938
 
66671
66939
  // src/files/adapters/openai-compatible-files-adapter.ts
66672
- import * as fs16 from "node:fs";
66673
- import * as path15 from "node:path";
66940
+ import * as fs17 from "node:fs";
66941
+ import * as path16 from "node:path";
66674
66942
  var OpenAICompatibleFilesAdapter = class {
66675
66943
  constructor(apiKey, baseUrl, extraHeaders = {}) {
66676
66944
  this.apiKey = apiKey;
@@ -66696,16 +66964,16 @@ var OpenAICompatibleFilesAdapter = class {
66696
66964
  ]
66697
66965
  };
66698
66966
  async upload(filePath, options = {}) {
66699
- const fileName = options.sourceName || path15.basename(filePath);
66967
+ const fileName = options.sourceName || path16.basename(filePath);
66700
66968
  const mimeType = options.mimeType || guessMimeType(fileName);
66701
- const stats = fs16.statSync(filePath);
66969
+ const stats = fs17.statSync(filePath);
66702
66970
  if (stats.size > this.capabilities.maxFileSize) {
66703
66971
  throw new FileManagerError(
66704
66972
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
66705
66973
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds OpenAI-compatible Files limit of ${this.capabilities.maxFileSize / 1024 / 1024}MB`
66706
66974
  );
66707
66975
  }
66708
- const file = new File([fs16.readFileSync(filePath)], fileName, { type: mimeType });
66976
+ const file = new File([fs17.readFileSync(filePath)], fileName, { type: mimeType });
66709
66977
  const formData = new FormData();
66710
66978
  formData.append("file", file);
66711
66979
  formData.append("purpose", options.purpose && options.purpose !== "auto" ? options.purpose : "file-extract");
@@ -66822,7 +67090,7 @@ function extractContentText(raw) {
66822
67090
  return raw;
66823
67091
  }
66824
67092
  function guessMimeType(filename) {
66825
- const ext = path15.extname(filename).toLowerCase();
67093
+ const ext = path16.extname(filename).toLowerCase();
66826
67094
  switch (ext) {
66827
67095
  case ".pdf":
66828
67096
  return "application/pdf";
@@ -66838,13 +67106,13 @@ function guessMimeType(filename) {
66838
67106
  }
66839
67107
 
66840
67108
  // src/files/file-manager.ts
66841
- import * as fs20 from "node:fs";
66842
- import * as path20 from "node:path";
67109
+ import * as fs21 from "node:fs";
67110
+ import * as path21 from "node:path";
66843
67111
  import * as crypto2 from "node:crypto";
66844
67112
 
66845
67113
  // src/files/file-cache.ts
66846
- import * as fs17 from "node:fs";
66847
- import * as path17 from "node:path";
67114
+ import * as fs18 from "node:fs";
67115
+ import * as path18 from "node:path";
66848
67116
  import * as crypto from "node:crypto";
66849
67117
 
66850
67118
  // src/files/logger.ts
@@ -66939,7 +67207,7 @@ var DEFAULT_PIC_OPTIONS = {
66939
67207
  };
66940
67208
 
66941
67209
  // src/files/utils.ts
66942
- import * as path16 from "node:path";
67210
+ import * as path17 from "node:path";
66943
67211
  import { homedir as homedir5 } from "node:os";
66944
67212
  var WINDOWS_ABSOLUTE_PATH_RE = /^(?:[a-zA-Z]:[\\/]|[\\/]{2}[^\\/]+[\\/][^\\/]+)/;
66945
67213
  function isWindowsAbsolutePath(filePath) {
@@ -66960,13 +67228,13 @@ function formatBytes(bytes) {
66960
67228
  }
66961
67229
  function resolvePath2(inputPath) {
66962
67230
  if (inputPath.startsWith("~")) {
66963
- return path16.join(getHomeDirectory(), inputPath.slice(1));
67231
+ return path17.join(getHomeDirectory(), inputPath.slice(1));
66964
67232
  }
66965
67233
  if (isWindowsAbsolutePath(inputPath)) {
66966
67234
  return inputPath;
66967
67235
  }
66968
- if (!path16.isAbsolute(inputPath)) {
66969
- return path16.resolve(process.cwd(), inputPath);
67236
+ if (!path17.isAbsolute(inputPath)) {
67237
+ return path17.resolve(process.cwd(), inputPath);
66970
67238
  }
66971
67239
  return inputPath;
66972
67240
  }
@@ -66994,8 +67262,8 @@ var FileCache = class _FileCache {
66994
67262
  maxEntries;
66995
67263
  constructor(baseDir, maxEntries = DEFAULT_MAX_CACHE_ENTRIES) {
66996
67264
  this.baseDir = baseDir;
66997
- this.dataDir = path17.join(baseDir, "data");
66998
- this.indexPath = path17.join(baseDir, "index.json");
67265
+ this.dataDir = path18.join(baseDir, "data");
67266
+ this.indexPath = path18.join(baseDir, "index.json");
66999
67267
  this.maxEntries = maxEntries;
67000
67268
  this.index = this.loadIndex();
67001
67269
  this.ensureDirectories();
@@ -67004,22 +67272,22 @@ var FileCache = class _FileCache {
67004
67272
  // Directory Management
67005
67273
  // ============================================================================
67006
67274
  ensureDirectories() {
67007
- if (!fs17.existsSync(this.baseDir)) {
67008
- fs17.mkdirSync(this.baseDir, { recursive: true });
67275
+ if (!fs18.existsSync(this.baseDir)) {
67276
+ fs18.mkdirSync(this.baseDir, { recursive: true });
67009
67277
  }
67010
- if (!fs17.existsSync(this.dataDir)) {
67011
- fs17.mkdirSync(this.dataDir, { recursive: true });
67278
+ if (!fs18.existsSync(this.dataDir)) {
67279
+ fs18.mkdirSync(this.dataDir, { recursive: true });
67012
67280
  }
67013
67281
  }
67014
67282
  // ============================================================================
67015
67283
  // Index Management
67016
67284
  // ============================================================================
67017
67285
  loadIndex() {
67018
- if (!fs17.existsSync(this.indexPath)) {
67286
+ if (!fs18.existsSync(this.indexPath)) {
67019
67287
  return { version: CACHE_VERSION, files: {}, pathHints: {} };
67020
67288
  }
67021
67289
  try {
67022
- const data = JSON.parse(fs17.readFileSync(this.indexPath, "utf-8"));
67290
+ const data = JSON.parse(fs18.readFileSync(this.indexPath, "utf-8"));
67023
67291
  if (data.version !== CACHE_VERSION) {
67024
67292
  cacheLogger.warn(`Index version mismatch: ${data.version} vs ${CACHE_VERSION}`);
67025
67293
  }
@@ -67035,7 +67303,7 @@ var FileCache = class _FileCache {
67035
67303
  }
67036
67304
  saveIndex() {
67037
67305
  try {
67038
- fs17.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
67306
+ fs18.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
67039
67307
  } catch (err) {
67040
67308
  cacheLogger.error(" Failed to save index:", err);
67041
67309
  throw err;
@@ -67047,7 +67315,7 @@ var FileCache = class _FileCache {
67047
67315
  async computeHash(filePath) {
67048
67316
  return new Promise((resolve7, reject) => {
67049
67317
  const hash = crypto.createHash("sha256");
67050
- const stream = fs17.createReadStream(filePath);
67318
+ const stream = fs18.createReadStream(filePath);
67051
67319
  stream.on("data", (chunk) => hash.update(chunk));
67052
67320
  stream.on("end", () => resolve7(hash.digest("hex")));
67053
67321
  stream.on("error", reject);
@@ -67061,25 +67329,25 @@ var FileCache = class _FileCache {
67061
67329
  // ============================================================================
67062
67330
  getStoragePath(hash) {
67063
67331
  const subdir = hash.slice(0, 2);
67064
- const fullDir = path17.join(this.dataDir, subdir);
67065
- if (!fs17.existsSync(fullDir)) {
67066
- fs17.mkdirSync(fullDir, { recursive: true });
67332
+ const fullDir = path18.join(this.dataDir, subdir);
67333
+ if (!fs18.existsSync(fullDir)) {
67334
+ fs18.mkdirSync(fullDir, { recursive: true });
67067
67335
  }
67068
- return path17.join(fullDir, hash);
67336
+ return path18.join(fullDir, hash);
67069
67337
  }
67070
67338
  getStorageRelativePath(hash) {
67071
67339
  const subdir = hash.slice(0, 2);
67072
- return path17.join(subdir, hash);
67340
+ return path18.join(subdir, hash);
67073
67341
  }
67074
67342
  async storeFile(sourcePath, name, mimeType) {
67075
67343
  const hash = await this.computeHash(sourcePath);
67076
67344
  const storagePath = this.getStoragePath(hash);
67077
67345
  this.rememberPathHint(sourcePath, hash, name);
67078
- if (fs17.existsSync(storagePath)) {
67346
+ if (fs18.existsSync(storagePath)) {
67079
67347
  return { hash, localPath: storagePath };
67080
67348
  }
67081
- fs17.copyFileSync(sourcePath, storagePath);
67082
- const stat2 = fs17.statSync(storagePath);
67349
+ fs18.copyFileSync(sourcePath, storagePath);
67350
+ const stat2 = fs18.statSync(storagePath);
67083
67351
  this.index.files[hash] = {
67084
67352
  hash,
67085
67353
  name,
@@ -67096,10 +67364,10 @@ var FileCache = class _FileCache {
67096
67364
  async storeBuffer(data, name, mimeType) {
67097
67365
  const hash = this.computeHashSync(data);
67098
67366
  const storagePath = this.getStoragePath(hash);
67099
- if (fs17.existsSync(storagePath)) {
67367
+ if (fs18.existsSync(storagePath)) {
67100
67368
  return { hash, localPath: storagePath };
67101
67369
  }
67102
- fs17.writeFileSync(storagePath, data);
67370
+ fs18.writeFileSync(storagePath, data);
67103
67371
  this.index.files[hash] = {
67104
67372
  hash,
67105
67373
  name,
@@ -67131,7 +67399,7 @@ var FileCache = class _FileCache {
67131
67399
  getLocalPath(hash) {
67132
67400
  const entry = this.index.files[hash];
67133
67401
  if (!entry) return void 0;
67134
- return path17.join(this.dataDir, entry.localPath);
67402
+ return path18.join(this.dataDir, entry.localPath);
67135
67403
  }
67136
67404
  exists(hash) {
67137
67405
  return hash in this.index.files;
@@ -67171,7 +67439,7 @@ var FileCache = class _FileCache {
67171
67439
  getPathHint(filePath) {
67172
67440
  try {
67173
67441
  const resolvedPath = this.getResolvedHintPath(filePath);
67174
- const stat2 = fs17.statSync(resolvedPath);
67442
+ const stat2 = fs18.statSync(resolvedPath);
67175
67443
  if (!stat2.isFile()) return void 0;
67176
67444
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
67177
67445
  const key = this.getPathHintKey(resolvedPath);
@@ -67201,7 +67469,7 @@ var FileCache = class _FileCache {
67201
67469
  rememberPathHint(filePath, hash, name) {
67202
67470
  try {
67203
67471
  const resolvedPath = this.getResolvedHintPath(filePath);
67204
- const stat2 = fs17.statSync(resolvedPath);
67472
+ const stat2 = fs18.statSync(resolvedPath);
67205
67473
  if (!stat2.isFile()) return;
67206
67474
  const entry = this.index.files[hash];
67207
67475
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
@@ -67211,7 +67479,7 @@ var FileCache = class _FileCache {
67211
67479
  this.index.pathHints[this.getPathHintKey(resolvedPath)] = {
67212
67480
  path: resolvedPath,
67213
67481
  hash,
67214
- name: name || entry?.name || path17.basename(resolvedPath),
67482
+ name: name || entry?.name || path18.basename(resolvedPath),
67215
67483
  size: stat2.size,
67216
67484
  mtimeMs: normalizedMtimeMs,
67217
67485
  lastSeenAt: Date.now(),
@@ -67259,9 +67527,9 @@ var FileCache = class _FileCache {
67259
67527
  deleteEntry(hash, entry) {
67260
67528
  entry = entry || this.index.files[hash];
67261
67529
  if (!entry) return;
67262
- const localPath = path17.join(this.dataDir, entry.localPath);
67263
- if (fs17.existsSync(localPath)) {
67264
- fs17.unlinkSync(localPath);
67530
+ const localPath = path18.join(this.dataDir, entry.localPath);
67531
+ if (fs18.existsSync(localPath)) {
67532
+ fs18.unlinkSync(localPath);
67265
67533
  }
67266
67534
  delete this.index.files[hash];
67267
67535
  if (this.index.pathHints) {
@@ -67275,9 +67543,9 @@ var FileCache = class _FileCache {
67275
67543
  }
67276
67544
  clear() {
67277
67545
  for (const entry of Object.values(this.index.files)) {
67278
- const localPath = path17.join(this.dataDir, entry.localPath);
67279
- if (fs17.existsSync(localPath)) {
67280
- fs17.unlinkSync(localPath);
67546
+ const localPath = path18.join(this.dataDir, entry.localPath);
67547
+ if (fs18.existsSync(localPath)) {
67548
+ fs18.unlinkSync(localPath);
67281
67549
  }
67282
67550
  }
67283
67551
  this.index = { version: CACHE_VERSION, files: {}, pathHints: {} };
@@ -67330,11 +67598,11 @@ var FileCache = class _FileCache {
67330
67598
  };
67331
67599
  }
67332
67600
  static getMimeType(fileName) {
67333
- const ext = path17.extname(fileName).toLowerCase();
67601
+ const ext = path18.extname(fileName).toLowerCase();
67334
67602
  return MIME_TYPES[ext] || "application/octet-stream";
67335
67603
  }
67336
67604
  static getFileTypeFromName(fileName) {
67337
- const baseName = path17.basename(fileName);
67605
+ const baseName = path18.basename(fileName);
67338
67606
  if (!baseName || baseName.startsWith(".")) {
67339
67607
  return void 0;
67340
67608
  }
@@ -67365,7 +67633,7 @@ var FileCache = class _FileCache {
67365
67633
  getResolvedHintPath(filePath) {
67366
67634
  const resolvedPath = resolvePath2(filePath);
67367
67635
  try {
67368
- return fs17.realpathSync.native ? fs17.realpathSync.native(resolvedPath) : fs17.realpathSync(resolvedPath);
67636
+ return fs18.realpathSync.native ? fs18.realpathSync.native(resolvedPath) : fs18.realpathSync(resolvedPath);
67369
67637
  } catch {
67370
67638
  return resolvedPath;
67371
67639
  }
@@ -67373,8 +67641,8 @@ var FileCache = class _FileCache {
67373
67641
  };
67374
67642
 
67375
67643
  // src/files/session-file-manager.ts
67376
- import * as fs18 from "node:fs";
67377
- import * as path18 from "node:path";
67644
+ import * as fs19 from "node:fs";
67645
+ import * as path19 from "node:path";
67378
67646
  var INITIAL_REFRESH_BACKOFF_MS = 6e4;
67379
67647
  var MAX_REFRESH_BACKOFF_MS = 60 * 60 * 1e3;
67380
67648
  var SessionFileManager = class {
@@ -67388,7 +67656,7 @@ var SessionFileManager = class {
67388
67656
  constructor(sessionId, sessionsDir, fileCache, authFingerprint) {
67389
67657
  this.sessionId = sessionId;
67390
67658
  this.sessionsDir = sessionsDir;
67391
- this.statePath = path18.join(this.sessionsDir, `${sessionId}-files.json`);
67659
+ this.statePath = path19.join(this.sessionsDir, `${sessionId}-files.json`);
67392
67660
  this.fileCache = fileCache;
67393
67661
  this.authFingerprint = authFingerprint;
67394
67662
  this.state = this.loadState();
@@ -67398,15 +67666,15 @@ var SessionFileManager = class {
67398
67666
  // Directory Management
67399
67667
  // ============================================================================
67400
67668
  ensureDirectories() {
67401
- if (!fs18.existsSync(this.sessionsDir)) {
67402
- fs18.mkdirSync(this.sessionsDir, { recursive: true });
67669
+ if (!fs19.existsSync(this.sessionsDir)) {
67670
+ fs19.mkdirSync(this.sessionsDir, { recursive: true });
67403
67671
  }
67404
67672
  }
67405
67673
  // ============================================================================
67406
67674
  // State Management
67407
67675
  // ============================================================================
67408
67676
  loadState() {
67409
- if (!fs18.existsSync(this.statePath)) {
67677
+ if (!fs19.existsSync(this.statePath)) {
67410
67678
  return {
67411
67679
  sessionId: this.sessionId,
67412
67680
  lastSyncedAt: 0,
@@ -67414,7 +67682,7 @@ var SessionFileManager = class {
67414
67682
  };
67415
67683
  }
67416
67684
  try {
67417
- return JSON.parse(fs18.readFileSync(this.statePath, "utf-8"));
67685
+ return JSON.parse(fs19.readFileSync(this.statePath, "utf-8"));
67418
67686
  } catch (err) {
67419
67687
  sessionLogger.error(" Failed to load state:", err);
67420
67688
  return {
@@ -67427,12 +67695,12 @@ var SessionFileManager = class {
67427
67695
  saveState() {
67428
67696
  try {
67429
67697
  if (Object.keys(this.state.files).length === 0) {
67430
- if (fs18.existsSync(this.statePath)) {
67431
- fs18.unlinkSync(this.statePath);
67698
+ if (fs19.existsSync(this.statePath)) {
67699
+ fs19.unlinkSync(this.statePath);
67432
67700
  }
67433
67701
  return;
67434
67702
  }
67435
- fs18.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
67703
+ fs19.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
67436
67704
  } catch (err) {
67437
67705
  sessionLogger.error(" Failed to save state:", err);
67438
67706
  }
@@ -67578,7 +67846,7 @@ var SessionFileManager = class {
67578
67846
  return { success: false, coolingDown: true };
67579
67847
  }
67580
67848
  const localPath = this.fileCache.getLocalPath(entry.hash);
67581
- if (!localPath || !fs18.existsSync(localPath)) {
67849
+ if (!localPath || !fs19.existsSync(localPath)) {
67582
67850
  sessionLogger.warn(`Local file not found for ${fileId}`);
67583
67851
  entry.status = "expired";
67584
67852
  entry.error = "Local file missing";
@@ -67729,15 +67997,15 @@ var SessionFileManager = class {
67729
67997
  // Static Utilities
67730
67998
  // ============================================================================
67731
67999
  static cleanupOldSessions(sessionsDir, maxAge = 30 * 24 * 60 * 60 * 1e3) {
67732
- if (!fs18.existsSync(sessionsDir)) return;
68000
+ if (!fs19.existsSync(sessionsDir)) return;
67733
68001
  const now = Date.now();
67734
- const files = fs18.readdirSync(sessionsDir);
68002
+ const files = fs19.readdirSync(sessionsDir);
67735
68003
  for (const file of files) {
67736
68004
  if (!file.endsWith(".json")) continue;
67737
- const filePath = path18.join(sessionsDir, file);
67738
- const stat2 = fs18.statSync(filePath);
68005
+ const filePath = path19.join(sessionsDir, file);
68006
+ const stat2 = fs19.statSync(filePath);
67739
68007
  if (now - stat2.mtime.getTime() > maxAge) {
67740
- fs18.unlinkSync(filePath);
68008
+ fs19.unlinkSync(filePath);
67741
68009
  sessionLogger.debug(`Cleaned up old session: ${file}`);
67742
68010
  }
67743
68011
  }
@@ -67745,8 +68013,8 @@ var SessionFileManager = class {
67745
68013
  };
67746
68014
 
67747
68015
  // src/files/ffmpeg-processor.ts
67748
- import * as fs19 from "node:fs";
67749
- import * as path19 from "node:path";
68016
+ import * as fs20 from "node:fs";
68017
+ import * as path20 from "node:path";
67750
68018
  import { spawn } from "node:child_process";
67751
68019
  var FFmpegProcessor = class {
67752
68020
  ffmpegPath = "ffmpeg";
@@ -67850,7 +68118,7 @@ var FFmpegProcessor = class {
67850
68118
  }
67851
68119
  async compressVideo(inputPath, outputDir, info, opts, onProgress) {
67852
68120
  const outputName = `compressed_${Date.now()}.mp4`;
67853
- const outputPath = path19.join(outputDir, outputName);
68121
+ const outputPath = path20.join(outputDir, outputName);
67854
68122
  const adaptiveParams = this.calculateAdaptiveParams(info.duration, opts);
67855
68123
  const args = [
67856
68124
  "-i",
@@ -67881,7 +68149,7 @@ var FFmpegProcessor = class {
67881
68149
  onProgress?.(percent);
67882
68150
  }
67883
68151
  });
67884
- const outputStat = fs19.statSync(outputPath);
68152
+ const outputStat = fs20.statSync(outputPath);
67885
68153
  return {
67886
68154
  type: "video",
67887
68155
  output: outputPath,
@@ -67912,9 +68180,9 @@ var FFmpegProcessor = class {
67912
68180
  }
67913
68181
  async extractKeyframes(inputPath, outputDir, info, opts, onProgress) {
67914
68182
  const interval = Math.floor(info.duration / opts.keyframeCount);
67915
- const framesDir = path19.join(outputDir, `keyframes_${Date.now()}`);
67916
- fs19.mkdirSync(framesDir, { recursive: true });
67917
- const outputPattern = path19.join(framesDir, "frame_%03d.jpg");
68183
+ const framesDir = path20.join(outputDir, `keyframes_${Date.now()}`);
68184
+ fs20.mkdirSync(framesDir, { recursive: true });
68185
+ const outputPattern = path20.join(framesDir, "frame_%03d.jpg");
67918
68186
  const args = [
67919
68187
  "-i",
67920
68188
  inputPath,
@@ -67932,10 +68200,10 @@ var FFmpegProcessor = class {
67932
68200
  onProgress?.(percent);
67933
68201
  }
67934
68202
  });
67935
- let frames = fs19.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
68203
+ let frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path20.join(framesDir, f));
67936
68204
  if (frames.length < opts.keyframeCount / 2) {
67937
- fs19.rmSync(framesDir, { recursive: true, force: true });
67938
- fs19.mkdirSync(framesDir, { recursive: true });
68205
+ fs20.rmSync(framesDir, { recursive: true, force: true });
68206
+ fs20.mkdirSync(framesDir, { recursive: true });
67939
68207
  const uniformArgs = [
67940
68208
  "-i",
67941
68209
  inputPath,
@@ -67951,10 +68219,10 @@ var FFmpegProcessor = class {
67951
68219
  onProgress?.(percent);
67952
68220
  }
67953
68221
  });
67954
- frames = fs19.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
68222
+ frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path20.join(framesDir, f));
67955
68223
  }
67956
68224
  const totalOutputSize = frames.reduce(
67957
- (sum, f) => sum + fs19.statSync(f).size,
68225
+ (sum, f) => sum + fs20.statSync(f).size,
67958
68226
  0
67959
68227
  );
67960
68228
  return {
@@ -67975,7 +68243,7 @@ var FFmpegProcessor = class {
67975
68243
  const opts = { ...DEFAULT_PIC_OPTIONS, ...options };
67976
68244
  const ext = opts.format === "webp" ? ".webp" : ".jpg";
67977
68245
  const outputName = `optimized_${Date.now()}${ext}`;
67978
- const outputPath = path19.join(outputDir, outputName);
68246
+ const outputPath = path20.join(outputDir, outputName);
67979
68247
  const args = [
67980
68248
  "-i",
67981
68249
  inputPath,
@@ -68150,8 +68418,8 @@ var DIRECTORY_LISTING_TTL_MS = 1500;
68150
68418
  var FileManager = class {
68151
68419
  constructor(options) {
68152
68420
  this.options = options;
68153
- const baseDir = options.baseDir || path20.join(process.env.HOME || ".", ".pie", "files");
68154
- const sessionsDir = options.sessionsDir || path20.join(process.env.HOME || ".", ".pie", "sessions");
68421
+ const baseDir = options.baseDir || path21.join(process.env.HOME || ".", ".pie", "files");
68422
+ const sessionsDir = options.sessionsDir || path21.join(process.env.HOME || ".", ".pie", "sessions");
68155
68423
  this.fileCache = new FileCache(baseDir);
68156
68424
  this.authFingerprint = options.apiKey ? this.buildAuthFingerprint(options.apiKey) : void 0;
68157
68425
  this.sessionManager = new SessionFileManager(
@@ -68162,7 +68430,7 @@ var FileManager = class {
68162
68430
  );
68163
68431
  this.ffmpeg = new FFmpegProcessor(options.ffmpegPath);
68164
68432
  this.platform = normalizeFileManagerPlatform(options.platform);
68165
- this.tempDir = path20.join(baseDir, "temp");
68433
+ this.tempDir = path21.join(baseDir, "temp");
68166
68434
  this.ensureDirectories();
68167
68435
  }
68168
68436
  options;
@@ -68174,8 +68442,8 @@ var FileManager = class {
68174
68442
  directoryListingCache = /* @__PURE__ */ new Map();
68175
68443
  authFingerprint;
68176
68444
  ensureDirectories() {
68177
- if (!fs20.existsSync(this.tempDir)) {
68178
- fs20.mkdirSync(this.tempDir, { recursive: true });
68445
+ if (!fs21.existsSync(this.tempDir)) {
68446
+ fs21.mkdirSync(this.tempDir, { recursive: true });
68179
68447
  }
68180
68448
  }
68181
68449
  // ============================================================================
@@ -68209,8 +68477,8 @@ var FileManager = class {
68209
68477
  // ============================================================================
68210
68478
  async stageLocal(filePath, options = {}) {
68211
68479
  const resolvedPath = resolvePath2(filePath);
68212
- const sourceName = options.sourceName || path20.basename(resolvedPath);
68213
- if (!fs20.existsSync(resolvedPath)) {
68480
+ const sourceName = options.sourceName || path21.basename(resolvedPath);
68481
+ if (!fs21.existsSync(resolvedPath)) {
68214
68482
  throw new FileManagerError(
68215
68483
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68216
68484
  `File not found: ${filePath}`
@@ -68225,7 +68493,7 @@ var FileManager = class {
68225
68493
  this.fileCache.rememberPathHint(resolvedPath, hash, sourceName);
68226
68494
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
68227
68495
  const entry = this.fileCache.getByHash(hash);
68228
- const size = entry?.size ?? fs20.statSync(resolvedPath).size;
68496
+ const size = entry?.size ?? fs21.statSync(resolvedPath).size;
68229
68497
  return {
68230
68498
  success: true,
68231
68499
  hash,
@@ -68239,8 +68507,8 @@ var FileManager = class {
68239
68507
  }
68240
68508
  async upload(filePath, options = {}) {
68241
68509
  const resolvedPath = resolvePath2(filePath);
68242
- const sourceName = options.sourceName || path20.basename(resolvedPath);
68243
- if (!fs20.existsSync(resolvedPath)) {
68510
+ const sourceName = options.sourceName || path21.basename(resolvedPath);
68511
+ if (!fs21.existsSync(resolvedPath)) {
68244
68512
  throw new FileManagerError(
68245
68513
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68246
68514
  `File not found: ${filePath}`
@@ -68321,7 +68589,7 @@ var FileManager = class {
68321
68589
  // ============================================================================
68322
68590
  async uploadPic(filePath, options = {}) {
68323
68591
  const resolvedPath = resolvePath2(filePath);
68324
- if (!fs20.existsSync(resolvedPath)) {
68592
+ if (!fs21.existsSync(resolvedPath)) {
68325
68593
  throw new FileManagerError(
68326
68594
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68327
68595
  `File not found: ${filePath}`
@@ -68329,7 +68597,7 @@ var FileManager = class {
68329
68597
  }
68330
68598
  const cachedResult = await this.tryReuseCachedSourceUpload(
68331
68599
  resolvedPath,
68332
- options.sourceName || path20.basename(resolvedPath),
68600
+ options.sourceName || path21.basename(resolvedPath),
68333
68601
  options.platform || this.platform
68334
68602
  );
68335
68603
  if (cachedResult) {
@@ -68346,12 +68614,12 @@ var FileManager = class {
68346
68614
  const result = await this.upload(optimizedPath, {
68347
68615
  ...options,
68348
68616
  purpose: "image",
68349
- sourceName: path20.basename(resolvedPath)
68617
+ sourceName: path21.basename(resolvedPath)
68350
68618
  });
68351
- this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
68619
+ this.fileCache.rememberPathHint(resolvedPath, result.hash, path21.basename(resolvedPath));
68352
68620
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
68353
68621
  try {
68354
- fs20.unlinkSync(optimizedPath);
68622
+ fs21.unlinkSync(optimizedPath);
68355
68623
  } catch {
68356
68624
  }
68357
68625
  return result;
@@ -68361,7 +68629,7 @@ var FileManager = class {
68361
68629
  // ============================================================================
68362
68630
  async uploadVideo(filePath, options = {}) {
68363
68631
  const resolvedPath = resolvePath2(filePath);
68364
- if (!fs20.existsSync(resolvedPath)) {
68632
+ if (!fs21.existsSync(resolvedPath)) {
68365
68633
  throw new FileManagerError(
68366
68634
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68367
68635
  `File not found: ${filePath}`
@@ -68369,7 +68637,7 @@ var FileManager = class {
68369
68637
  }
68370
68638
  const cachedResult = await this.tryReuseCachedSourceUpload(
68371
68639
  resolvedPath,
68372
- options.sourceName || path20.basename(resolvedPath),
68640
+ options.sourceName || path21.basename(resolvedPath),
68373
68641
  options.platform || this.platform
68374
68642
  );
68375
68643
  if (cachedResult) {
@@ -68419,9 +68687,9 @@ var FileManager = class {
68419
68687
  result = await this.upload(preprocessResult.output, {
68420
68688
  ...options,
68421
68689
  purpose: "video",
68422
- sourceName: path20.basename(resolvedPath)
68690
+ sourceName: path21.basename(resolvedPath)
68423
68691
  });
68424
- this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
68692
+ this.fileCache.rememberPathHint(resolvedPath, result.hash, path21.basename(resolvedPath));
68425
68693
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
68426
68694
  } else {
68427
68695
  throw new FileManagerError(
@@ -68713,7 +68981,7 @@ var FileManager = class {
68713
68981
  * Detect purpose from file path based on extension
68714
68982
  */
68715
68983
  detectPurpose(filePath) {
68716
- const ext = path20.extname(filePath).toLowerCase();
68984
+ const ext = path21.extname(filePath).toLowerCase();
68717
68985
  switch (ext) {
68718
68986
  case ".mp4":
68719
68987
  case ".mov":
@@ -68755,13 +69023,13 @@ var FileManager = class {
68755
69023
  cleanupTempFiles(output) {
68756
69024
  try {
68757
69025
  if (typeof output === "string") {
68758
- if (fs20.existsSync(output)) {
68759
- fs20.unlinkSync(output);
69026
+ if (fs21.existsSync(output)) {
69027
+ fs21.unlinkSync(output);
68760
69028
  }
68761
69029
  } else {
68762
69030
  for (const file of output) {
68763
- if (fs20.existsSync(file)) {
68764
- fs20.unlinkSync(file);
69031
+ if (fs21.existsSync(file)) {
69032
+ fs21.unlinkSync(file);
68765
69033
  }
68766
69034
  }
68767
69035
  }
@@ -68793,7 +69061,7 @@ var FileManager = class {
68793
69061
  }];
68794
69062
  }
68795
69063
  const localPath = this.fileCache.getLocalPath(entry.hash);
68796
- if (localPath && fs20.existsSync(localPath)) {
69064
+ if (localPath && fs21.existsSync(localPath)) {
68797
69065
  return [{
68798
69066
  fileId,
68799
69067
  name: cacheEntry.name,
@@ -68890,12 +69158,12 @@ var FileManager = class {
68890
69158
  directories: []
68891
69159
  };
68892
69160
  try {
68893
- const entries = fs20.readdirSync(resolvedDir, { withFileTypes: true });
69161
+ const entries = fs21.readdirSync(resolvedDir, { withFileTypes: true });
68894
69162
  for (const entry of entries) {
68895
69163
  if (!entry.name || entry.name.startsWith(".")) {
68896
69164
  continue;
68897
69165
  }
68898
- const fullPath = path20.join(resolvedDir, entry.name);
69166
+ const fullPath = path21.join(resolvedDir, entry.name);
68899
69167
  if (entry.isDirectory()) {
68900
69168
  listing.directories.push({ name: entry.name, path: fullPath });
68901
69169
  continue;
@@ -68904,7 +69172,7 @@ var FileManager = class {
68904
69172
  let isFile = entry.isFile();
68905
69173
  if (entry.isSymbolicLink()) {
68906
69174
  try {
68907
- const targetStat = fs20.statSync(fullPath);
69175
+ const targetStat = fs21.statSync(fullPath);
68908
69176
  isDirectory = targetStat.isDirectory();
68909
69177
  isFile = targetStat.isFile();
68910
69178
  } catch {
@@ -68922,7 +69190,7 @@ var FileManager = class {
68922
69190
  if (!type) {
68923
69191
  continue;
68924
69192
  }
68925
- const stat2 = fs20.statSync(fullPath);
69193
+ const stat2 = fs21.statSync(fullPath);
68926
69194
  listing.files.push({
68927
69195
  name: entry.name,
68928
69196
  path: fullPath,
@@ -68936,7 +69204,7 @@ var FileManager = class {
68936
69204
  return listing;
68937
69205
  }
68938
69206
  invalidateDirectoryListingCacheForPath(filePath) {
68939
- this.directoryListingCache.delete(path20.dirname(resolvePath2(filePath)));
69207
+ this.directoryListingCache.delete(path21.dirname(resolvePath2(filePath)));
68940
69208
  }
68941
69209
  buildAuthFingerprint(apiKey) {
68942
69210
  return crypto2.createHash("sha256").update(apiKey).digest("hex").slice(0, 16);
@@ -68985,8 +69253,8 @@ function createFileManagerForModel(params) {
68985
69253
  sessionId: params.sessionId,
68986
69254
  platform: platform2,
68987
69255
  apiKey: params.apiKey,
68988
- baseDir: path21.join(params.configDir, "files"),
68989
- sessionsDir: path21.join(params.configDir, "sessions")
69256
+ baseDir: path22.join(params.configDir, "files"),
69257
+ sessionsDir: path22.join(params.configDir, "sessions")
68990
69258
  });
68991
69259
  switch (getFileManagerAdapterKind(platform2)) {
68992
69260
  case "kimi":
@@ -69021,15 +69289,15 @@ function isInlineMediaRequest(request) {
69021
69289
  return request.kind === "image" || request.kind === "video";
69022
69290
  }
69023
69291
  async function prepareInlineMediaContent(params) {
69024
- const stat2 = await fs21.stat(params.request.absolutePath);
69292
+ const stat2 = await fs22.stat(params.request.absolutePath);
69025
69293
  const limitMb = getCapabilityLimitMb(params.model, params.request.kind);
69026
69294
  const limitBytes = limitMb * 1024 * 1024;
69027
69295
  if (stat2.size > limitBytes) {
69028
69296
  throw new Error(
69029
- `${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${path21.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.`
69297
+ `${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${path22.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.`
69030
69298
  );
69031
69299
  }
69032
- const data = await fs21.readFile(params.request.absolutePath, "base64");
69300
+ const data = await fs22.readFile(params.request.absolutePath, "base64");
69033
69301
  const content = params.request.kind === "video" ? [{ type: "video", data, mimeType: params.request.mimeType }] : [{ type: "image", data, mimeType: params.request.mimeType }];
69034
69302
  return {
69035
69303
  content,
@@ -69065,7 +69333,7 @@ async function prepareFileContent(configDir, params) {
69065
69333
  });
69066
69334
  if (params.request.kind === "document") {
69067
69335
  const upload2 = await manager.upload(params.request.absolutePath, {
69068
- sourceName: path21.basename(params.request.displayPath),
69336
+ sourceName: path22.basename(params.request.displayPath),
69069
69337
  purpose: "file-extract"
69070
69338
  });
69071
69339
  await waitForReady({ manager, fileId: upload2.fileId, timeoutMs: 12e4, signal: params.request.signal });
@@ -69088,8 +69356,8 @@ async function prepareFileContent(configDir, params) {
69088
69356
  }
69089
69357
  };
69090
69358
  }
69091
- const upload = params.request.kind === "video" ? await manager.uploadVideo(params.request.absolutePath, { sourceName: path21.basename(params.request.displayPath), strategy: "compress" }) : await manager.upload(params.request.absolutePath, {
69092
- sourceName: path21.basename(params.request.displayPath),
69359
+ const upload = params.request.kind === "video" ? await manager.uploadVideo(params.request.absolutePath, { sourceName: path22.basename(params.request.displayPath), strategy: "compress" }) : await manager.upload(params.request.absolutePath, {
69360
+ sourceName: path22.basename(params.request.displayPath),
69093
69361
  purpose: params.request.kind === "image" ? "image" : "file-extract"
69094
69362
  });
69095
69363
  if (params.request.kind !== "video") {
@@ -69510,22 +69778,22 @@ var ExecutionStateManager = class {
69510
69778
  };
69511
69779
 
69512
69780
  // src/session-trace.ts
69513
- import * as fs22 from "node:fs";
69514
- import * as path22 from "node:path";
69781
+ import * as fs23 from "node:fs";
69782
+ import * as path23 from "node:path";
69515
69783
  function saveTraceFileBestEffort(tracePath, content) {
69516
69784
  const tempPath = `${tracePath}.${process.pid}.${Date.now()}.tmp`;
69517
69785
  try {
69518
- fs22.writeFileSync(tempPath, content, "utf8");
69786
+ fs23.writeFileSync(tempPath, content, "utf8");
69519
69787
  try {
69520
- fs22.renameSync(tempPath, tracePath);
69788
+ fs23.renameSync(tempPath, tracePath);
69521
69789
  return;
69522
69790
  } catch {
69523
69791
  try {
69524
- fs22.copyFileSync(tempPath, tracePath);
69792
+ fs23.copyFileSync(tempPath, tracePath);
69525
69793
  } catch {
69526
69794
  } finally {
69527
69795
  try {
69528
- fs22.unlinkSync(tempPath);
69796
+ fs23.unlinkSync(tempPath);
69529
69797
  } catch {
69530
69798
  }
69531
69799
  }
@@ -69538,16 +69806,16 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
69538
69806
  super({
69539
69807
  getSessionId: () => sessionManager.getActiveSessionId(),
69540
69808
  loadTrace: (sessionId) => {
69541
- const tracePath = path22.join(sessionsDir, `${sessionId}.trace.json`);
69542
- if (!fs22.existsSync(tracePath)) return null;
69809
+ const tracePath = path23.join(sessionsDir, `${sessionId}.trace.json`);
69810
+ if (!fs23.existsSync(tracePath)) return null;
69543
69811
  try {
69544
- return JSON.parse(fs22.readFileSync(tracePath, "utf8"));
69812
+ return JSON.parse(fs23.readFileSync(tracePath, "utf8"));
69545
69813
  } catch {
69546
69814
  return null;
69547
69815
  }
69548
69816
  },
69549
69817
  saveTrace: (trace) => {
69550
- const tracePath = path22.join(sessionsDir, `${trace.sessionId}.trace.json`);
69818
+ const tracePath = path23.join(sessionsDir, `${trace.sessionId}.trace.json`);
69551
69819
  saveTraceFileBestEffort(tracePath, JSON.stringify(trace, null, 2));
69552
69820
  }
69553
69821
  });
@@ -69837,7 +70105,7 @@ function normalizeSessionTitle(raw) {
69837
70105
  }
69838
70106
 
69839
70107
  // src/components/extension-selector.ts
69840
- import * as path23 from "node:path";
70108
+ import * as path24 from "node:path";
69841
70109
  var ExtensionSelectorComponent = class extends Container {
69842
70110
  selectList;
69843
70111
  shortcuts;
@@ -69893,8 +70161,8 @@ function selectRuntimeExtensionWinners(infos) {
69893
70161
  return reversed.reverse();
69894
70162
  }
69895
70163
  function unidentifiedLabel(info) {
69896
- const parentName = path23.basename(path23.dirname(info.entryPath));
69897
- const fileName = path23.basename(info.entryPath);
70164
+ const parentName = path24.basename(path24.dirname(info.entryPath));
70165
+ const fileName = path24.basename(info.entryPath);
69898
70166
  return `(unidentified) ${parentName || fileName}`;
69899
70167
  }
69900
70168
  var ExtensionEnablementSelectorComponent = class extends Container {
@@ -70442,7 +70710,7 @@ async function handleDebugPackageCommand(host) {
70442
70710
  import * as os6 from "os";
70443
70711
 
70444
70712
  // src/components/session-selector.ts
70445
- import * as path24 from "node:path";
70713
+ import * as path25 from "node:path";
70446
70714
  function formatDate(timestamp) {
70447
70715
  const date = new Date(timestamp);
70448
70716
  const now = /* @__PURE__ */ new Date();
@@ -70473,7 +70741,7 @@ function getPathFlavor(value, peer) {
70473
70741
  return "posix";
70474
70742
  }
70475
70743
  function getPathApi(flavor) {
70476
- return flavor === "windows" ? path24.win32 : path24.posix;
70744
+ return flavor === "windows" ? path25.win32 : path25.posix;
70477
70745
  }
70478
70746
  function normalizeForComparison(value, flavor) {
70479
70747
  const pathApi = getPathApi(flavor);
@@ -70630,102 +70898,37 @@ var SessionSelectorComponent = class extends Container {
70630
70898
  var RESET = "\x1B[0m";
70631
70899
  var INVERSE = "\x1B[7m";
70632
70900
  var DIM = "\x1B[2m";
70633
- function visibleLength(str2) {
70634
- return visibleWidth(str2);
70635
- }
70901
+ var searchSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
70636
70902
  var TREE_CHARS = {
70637
70903
  branch: "\u251C\u2500\u2500 ",
70638
70904
  corner: "\u2514\u2500\u2500 ",
70639
70905
  pipe: "\u2502 ",
70640
70906
  space: " ",
70641
70907
  active: "\u25CF ",
70642
- inactive: "\u25CB "
70908
+ inactive: "\u25CB ",
70909
+ /** Marks rows whose full ancestry is not visible in the window. */
70910
+ hiddenAncestry: "\u2026"
70643
70911
  };
70644
- function extractContent(entry) {
70645
- if (entry.type === "fork" && entry.forkData) {
70646
- return `fork from "${entry.forkData.name}"`;
70647
- }
70648
- if (entry.type === "compaction" && entry.compactionData) {
70649
- const firstLine = entry.compactionData.summary.split("\n").find((line) => line.trim().length > 0) ?? "context compacted";
70650
- return firstLine;
70651
- }
70652
- if (!entry.message) return "";
70653
- const msg = entry.message;
70654
- const extractTextFromContent = (content) => {
70655
- if (typeof content === "string") return content;
70656
- if (Array.isArray(content)) {
70657
- const parts = [];
70658
- for (const c of content) {
70659
- if (typeof c !== "object" || c === null) continue;
70660
- if ("type" in c) {
70661
- if (c.type === "text") {
70662
- parts.push(c.text || "");
70663
- } else if (c.type === "thinking") {
70664
- parts.push("(thinking...)");
70665
- } else if (c.type === "toolCall") {
70666
- const name = c.name || "tool";
70667
- parts.push(`[${name}]`);
70668
- }
70669
- }
70670
- }
70671
- return parts.join(" ");
70672
- }
70673
- return "";
70674
- };
70675
- if (msg.role === "user") {
70676
- return extractTextFromContent(msg.content) || "(empty)";
70677
- }
70678
- if (msg.role === "assistant") {
70679
- const textContent = extractTextFromContent(msg.content);
70680
- if (textContent) {
70681
- return textContent;
70682
- }
70683
- if (msg.stopReason === "aborted") {
70684
- return "(aborted)";
70685
- }
70686
- if (msg.errorMessage) {
70687
- return `(error: ${msg.errorMessage.slice(0, 50)})`;
70688
- }
70689
- return "(no content)";
70690
- }
70691
- if (msg.role === "toolResult") {
70692
- const content = msg.content;
70693
- let contentPreview = "";
70694
- if (Array.isArray(content)) {
70695
- const textParts = content.filter((c) => typeof c === "object" && c !== null && "type" in c && c.type === "text").map((c) => c.text || "").join("");
70696
- contentPreview = textParts.slice(0, 80);
70697
- if (textParts.length > 80) contentPreview += "...";
70698
- }
70699
- const toolName = msg.toolName || "tool";
70700
- if (contentPreview) {
70701
- return `[${toolName}]: ${contentPreview}`;
70702
- }
70703
- return `[${toolName}]`;
70704
- }
70705
- return `[${msg.role || "unknown"}]`;
70706
- }
70707
- function getRoleName(entry) {
70708
- if (entry.type === "fork") return "fork";
70709
- if (entry.type === "compaction") return "compact";
70710
- if (!entry.message) return "unknown";
70711
- const role = entry.message.role;
70712
- switch (role) {
70713
- case "user":
70714
- return "user";
70715
- case "assistant":
70716
- return "assistant";
70717
- case "toolResult":
70718
- return "tool";
70719
- default:
70720
- return role || "unknown";
70721
- }
70722
- }
70723
- function getRoleColor(role) {
70912
+ var MIN_PAGE_SIZE = 48;
70913
+ var MAX_PAGE_SIZE = 256;
70914
+ var SEGMENT_WIDTH = 4;
70915
+ var MIN_BODY_WIDTH = 12;
70916
+ var PREFIX_DEPTH_ABS_CAP = 24;
70917
+ var SEARCH_SCAN_PAGE_LIMIT = 16;
70918
+ var COLLAPSED_CAP = 256;
70919
+ function roleName(summary) {
70920
+ if (summary.type === "fork") return "fork";
70921
+ if (summary.type === "compaction") return "compact";
70922
+ if (summary.type === "custom") return "custom";
70923
+ return summary.role ?? "entry";
70924
+ }
70925
+ function roleColor(role) {
70724
70926
  switch (role) {
70725
70927
  case "user":
70726
70928
  return theme.fg("accent", role);
70727
70929
  case "assistant":
70728
70930
  return theme.fg("text", role);
70931
+ case "toolResult":
70729
70932
  case "tool":
70730
70933
  return theme.fg("dim", role);
70731
70934
  case "fork":
@@ -70736,57 +70939,47 @@ function getRoleColor(role) {
70736
70939
  return theme.fg("muted", role);
70737
70940
  }
70738
70941
  }
70942
+ function seqFromEntryId(entryId) {
70943
+ if (!entryId) return null;
70944
+ const match = /^e(\d+)-/.exec(entryId);
70945
+ if (!match) return null;
70946
+ const seq = Number(match[1]);
70947
+ return Number.isInteger(seq) && seq > 0 ? seq : null;
70948
+ }
70739
70949
  function createLine(content, width, isSelected) {
70740
- const normalized = content.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ");
70741
- let line;
70742
- if (isSelected) {
70743
- line = INVERSE + normalized + RESET;
70744
- } else {
70745
- line = RESET + normalized;
70746
- }
70747
- const visibleLen = line.replace(/\x1b\[[0-9;]*m/g, "").length;
70748
- if (visibleLen < width) {
70749
- line += " ".repeat(width - visibleLen);
70750
- }
70751
- line += RESET;
70752
- return truncateToWidth(line, width);
70950
+ const normalized = content.replace(/[\r\n]+/g, " ");
70951
+ const body = isSelected ? INVERSE + normalized : normalized;
70952
+ return truncateToWidth(body + RESET, width, "...", true);
70753
70953
  }
70754
- function flattenTree(nodes, parentPrefixes = [], startIndex = 0) {
70755
- const result = [];
70756
- let currentIndex = startIndex;
70757
- for (let i = 0; i < nodes.length; i++) {
70758
- const node = nodes[i];
70759
- const isLast = i === nodes.length - 1;
70760
- result.push({
70761
- node,
70762
- depth: node.depth,
70763
- isLast,
70764
- parentPrefixes: [...parentPrefixes],
70765
- index: currentIndex++
70766
- });
70767
- if (node.children.length > 0) {
70768
- const childPrefix = isLast ? TREE_CHARS.space : TREE_CHARS.pipe;
70769
- const childItems = flattenTree(
70770
- node.children,
70771
- [...parentPrefixes, childPrefix],
70772
- currentIndex
70773
- );
70774
- result.push(...childItems);
70775
- currentIndex += childItems.length;
70776
- }
70777
- }
70778
- return result;
70954
+ function clampPrefixForDisplay(prefix, budget) {
70955
+ if (budget <= 0) return "";
70956
+ if (prefix.length <= budget) return prefix;
70957
+ const keep = Math.floor((budget - 1) / SEGMENT_WIDTH) * SEGMENT_WIDTH;
70958
+ return TREE_CHARS.hiddenAncestry + (keep > 0 ? prefix.slice(-keep) : "");
70779
70959
  }
70780
70960
  var TreeSelectorComponent = class {
70781
- tree;
70782
- flatItems = [];
70783
- filteredItems = [];
70961
+ options;
70962
+ /** The single resident window of headers (bounded by pageSize). */
70963
+ pageSummaries = [];
70964
+ totalEntries;
70965
+ hasPrev = false;
70966
+ hasNext = false;
70967
+ rows = [];
70968
+ filteredRows = [];
70784
70969
  selectedIndex = 0;
70785
70970
  maxVisibleLines;
70971
+ pageSizeValue;
70972
+ prefixDepthCap;
70786
70973
  filterMode = "all";
70787
70974
  searchQuery = "";
70788
- expandedNodes = /* @__PURE__ */ new Set();
70789
- // Node IDs that are expanded
70975
+ statusMessage = null;
70976
+ collapsed = /* @__PURE__ */ new Map();
70977
+ // Bounded-memory instrumentation (tests/telemetry).
70978
+ maxResidentHeadersSeen = 0;
70979
+ maxPrefixCharsSeen = 0;
70980
+ currentTotalPrefixChars = 0;
70981
+ fetchCallCount = 0;
70982
+ headersFetchedTotal = 0;
70790
70983
  onSelect;
70791
70984
  onCancel;
70792
70985
  _focused = false;
@@ -70796,189 +70989,387 @@ var TreeSelectorComponent = class {
70796
70989
  set focused(value) {
70797
70990
  this._focused = value;
70798
70991
  }
70799
- constructor(tree, terminalHeight, onSelect, onCancel, activeEntryId) {
70800
- this.maxVisibleLines = Math.max(15, Math.floor(terminalHeight * 0.6));
70801
- this.onSelect = onSelect;
70802
- this.onCancel = onCancel;
70803
- this.tree = tree;
70804
- this.expandActivePath(activeEntryId);
70805
- this.refreshFlatItems();
70806
- if (activeEntryId) {
70807
- const activeIndex = this.flatItems.findIndex(
70808
- (item) => item.node.id === activeEntryId
70809
- );
70810
- if (activeIndex >= 0) {
70811
- this.selectedIndex = activeIndex;
70992
+ constructor(options) {
70993
+ this.options = options;
70994
+ this.totalEntries = options.totalEntries;
70995
+ this.maxVisibleLines = Math.max(15, Math.floor(options.terminalHeight * 0.6));
70996
+ this.pageSizeValue = Math.max(MIN_PAGE_SIZE, Math.min(MAX_PAGE_SIZE, this.maxVisibleLines * 3));
70997
+ this.prefixDepthCap = Math.max(3, Math.min(PREFIX_DEPTH_ABS_CAP, this.maxVisibleLines));
70998
+ this.onSelect = options.onSelect;
70999
+ this.onCancel = options.onCancel;
71000
+ if (options.totalEntries === 0) {
71001
+ setTimeout(() => options.onCancel(), 100);
71002
+ return;
71003
+ }
71004
+ const activeSeq = this.resolveActiveSeq() ?? options.totalEntries;
71005
+ const afterSeq = Math.max(0, activeSeq - Math.floor(this.pageSizeValue / 2));
71006
+ this.loadWindow(afterSeq);
71007
+ this.selectNearestSeq(activeSeq);
71008
+ }
71009
+ /**
71010
+ * Locate the active entry without loading bodies: prefer the commit
71011
+ * sequence encoded in the entry id, then the deepest active-path seq
71012
+ * (children always commit after parents, so the max is the active leaf).
71013
+ */
71014
+ resolveActiveSeq() {
71015
+ const fromId = seqFromEntryId(this.options.activeEntryId);
71016
+ if (fromId !== null) return fromId;
71017
+ let deepest = 0;
71018
+ for (const seq of this.options.activePathSeqs) {
71019
+ if (seq > deepest) deepest = seq;
71020
+ }
71021
+ return deepest > 0 ? deepest : null;
71022
+ }
71023
+ /** Select the row whose seq equals `target`, else the nearest earlier row. */
71024
+ selectNearestSeq(target) {
71025
+ let chosen = -1;
71026
+ for (let i = 0; i < this.filteredRows.length; i++) {
71027
+ const seq = this.filteredRows[i].summary.seq;
71028
+ if (seq === target) {
71029
+ chosen = i;
71030
+ break;
70812
71031
  }
70813
- } else if (this.flatItems.length > 0) {
70814
- this.selectedIndex = this.flatItems.length - 1;
71032
+ if (seq < target) chosen = i;
70815
71033
  }
70816
- if (tree.length === 0) {
70817
- setTimeout(() => onCancel(), 100);
71034
+ this.selectedIndex = chosen === -1 ? 0 : chosen;
71035
+ }
71036
+ /** Current resident header count (tests/telemetry; one window only). */
71037
+ get loadedCount() {
71038
+ return this.pageSummaries.length;
71039
+ }
71040
+ /** High-water mark of resident headers across the component lifetime. */
71041
+ get maxResidentHeaders() {
71042
+ return this.maxResidentHeadersSeen;
71043
+ }
71044
+ /** High-water mark of per-row prefix characters. */
71045
+ get maxPrefixChars() {
71046
+ return this.maxPrefixCharsSeen;
71047
+ }
71048
+ /** Sum of prefix characters across the current rows. */
71049
+ get totalPrefixChars() {
71050
+ return this.currentTotalPrefixChars;
71051
+ }
71052
+ /** Configured header window size. */
71053
+ get pageSize() {
71054
+ return this.pageSizeValue;
71055
+ }
71056
+ /** Number of fetchSummaries calls issued. */
71057
+ get fetchCount() {
71058
+ return this.fetchCallCount;
71059
+ }
71060
+ /** Cumulative headers returned by fetchSummaries (all pages ever fetched). */
71061
+ get headersFetched() {
71062
+ return this.headersFetchedTotal;
71063
+ }
71064
+ /** Current collapsed-id count (bounded by COLLAPSED_CAP). */
71065
+ get collapsedCount() {
71066
+ return this.collapsed.size;
71067
+ }
71068
+ /** Seq of the selected row, or null when nothing is selected. */
71069
+ get selectedSeq() {
71070
+ return this.filteredRows[this.selectedIndex]?.summary.seq ?? null;
71071
+ }
71072
+ /** First and last seq of the resident window, or null when empty. */
71073
+ get windowSeqRange() {
71074
+ if (this.pageSummaries.length === 0) return null;
71075
+ return [this.pageSummaries[0].seq, this.pageSummaries[this.pageSummaries.length - 1].seq];
71076
+ }
71077
+ /**
71078
+ * Fetch one window of headers and adopt it as the single resident page.
71079
+ * The previous window is replaced (not merged), keeping residency at
71080
+ * O(pageSize). `upperExclusiveSeq` trims overlap when paging backward;
71081
+ * entries trimmed away still count toward hasNext so the forward
71082
+ * direction never strands a short history behind a backward page.
71083
+ * Returns false when the fetch adopted nothing (boundary/gap).
71084
+ */
71085
+ fetchWindow(afterSeq, upperExclusiveSeq) {
71086
+ const page = this.options.fetchSummaries(afterSeq > 0 ? afterSeq : void 0, this.pageSizeValue);
71087
+ this.fetchCallCount++;
71088
+ this.headersFetchedTotal += page.summaries.length;
71089
+ let summaries = page.summaries.length > this.pageSizeValue ? page.summaries.slice(0, this.pageSizeValue) : page.summaries;
71090
+ let trimmedAway = 0;
71091
+ if (upperExclusiveSeq !== null) {
71092
+ const kept = summaries.filter((summary) => summary.seq < upperExclusiveSeq);
71093
+ trimmedAway = summaries.length - kept.length;
71094
+ summaries = kept;
71095
+ }
71096
+ this.hasNext = page.hasMore || trimmedAway > 0;
71097
+ this.totalEntries = page.total;
71098
+ if (summaries.length === 0) {
71099
+ return false;
70818
71100
  }
71101
+ this.pageSummaries = summaries;
71102
+ this.maxResidentHeadersSeen = Math.max(this.maxResidentHeadersSeen, this.pageSummaries.length);
71103
+ this.hasPrev = summaries[0].seq > 1;
71104
+ this.rebuildRows();
71105
+ return true;
70819
71106
  }
70820
- expandAll() {
70821
- const expand = (nodes) => {
70822
- for (const node of nodes) {
70823
- this.expandedNodes.add(node.id);
70824
- if (node.children.length > 0) {
70825
- expand(node.children);
70826
- }
71107
+ loadWindow(afterSeq) {
71108
+ this.fetchWindow(afterSeq, null);
71109
+ }
71110
+ /**
71111
+ * Load the window immediately before the current one. Backs off (up to a
71112
+ * few attempts) around seq gaps, then reports the oldest boundary.
71113
+ */
71114
+ goToPreviousPage() {
71115
+ if (this.pageSummaries.length === 0 || !this.hasPrev) return false;
71116
+ const firstSeq = this.pageSummaries[0].seq;
71117
+ let back = Math.max(0, firstSeq - 1 - this.pageSizeValue);
71118
+ for (let attempt = 0; attempt < 4; attempt++) {
71119
+ if (this.fetchWindow(back, firstSeq)) {
71120
+ this.selectedIndex = Math.max(0, this.filteredRows.length - 1);
71121
+ return true;
70827
71122
  }
70828
- };
70829
- expand(this.tree);
71123
+ if (back === 0) break;
71124
+ back = Math.max(0, back - this.pageSizeValue);
71125
+ }
71126
+ this.hasPrev = false;
71127
+ return false;
70830
71128
  }
70831
- expandActivePath(activeEntryId) {
70832
- const expandAll = (nodes) => {
70833
- for (const node of nodes) {
70834
- this.expandedNodes.add(node.id);
70835
- if (node.children.length > 0) {
70836
- expandAll(node.children);
70837
- }
71129
+ /** Load the window immediately after the current one. */
71130
+ goToNextPage() {
71131
+ if (this.pageSummaries.length === 0 || !this.hasNext) return false;
71132
+ const lastSeq = this.pageSummaries[this.pageSummaries.length - 1].seq;
71133
+ let anchor = lastSeq;
71134
+ for (let attempt = 0; attempt < 4; attempt++) {
71135
+ if (this.fetchWindow(anchor, null)) {
71136
+ this.selectedIndex = 0;
71137
+ return true;
70838
71138
  }
70839
- };
70840
- expandAll(this.tree);
70841
- }
70842
- refreshFlatItems() {
70843
- const filterExpanded = (nodes) => {
70844
- return nodes.filter((node) => {
70845
- if (node.parentId === null) return true;
70846
- return this.expandedNodes.has(node.parentId);
70847
- }).map((node) => ({
70848
- ...node,
70849
- children: this.expandedNodes.has(node.id) ? filterExpanded(node.children) : []
70850
- }));
70851
- };
70852
- const visibleTree = filterExpanded(this.tree);
70853
- this.flatItems = flattenTree(visibleTree);
71139
+ if (!this.hasNext) break;
71140
+ anchor += this.pageSizeValue;
71141
+ }
71142
+ return false;
71143
+ }
71144
+ /**
71145
+ * Iteratively flatten the resident window. Parents always commit before
71146
+ * children, so one forward pass resolves in-window ancestry; an explicit
71147
+ * stack (no recursion) emits DFS rows whose prefixes are capped to
71148
+ * prefixDepthCap segments, so prefix memory stays O(rows).
71149
+ */
71150
+ rebuildRows() {
71151
+ const count = this.pageSummaries.length;
71152
+ const seqToIndex = /* @__PURE__ */ new Map();
71153
+ const depth = new Int32Array(count);
71154
+ const parentIndex = new Int32Array(count).fill(-1);
71155
+ const childLists = new Array(count);
71156
+ for (let i = 0; i < count; i++) {
71157
+ const summary = this.pageSummaries[i];
71158
+ seqToIndex.set(summary.seq, i);
71159
+ const parent = summary.parentSeq === null ? -1 : seqToIndex.get(summary.parentSeq) ?? -1;
71160
+ if (parent >= 0) {
71161
+ depth[i] = depth[parent] + 1;
71162
+ parentIndex[i] = parent;
71163
+ const bucket = childLists[parent];
71164
+ if (bucket) bucket.push(i);
71165
+ else childLists[parent] = [i];
71166
+ }
71167
+ }
71168
+ const capChars = this.prefixDepthCap * SEGMENT_WIDTH;
71169
+ const capSegments = (segments) => segments.length > capChars ? segments.slice(segments.length - capChars) : segments;
71170
+ const roots = [];
71171
+ for (let i = 0; i < count; i++) {
71172
+ if (parentIndex[i] === -1) roots.push(i);
71173
+ }
71174
+ const rows = [];
71175
+ const stack = [];
71176
+ for (let i = roots.length - 1; i >= 0; i--) {
71177
+ stack.push({ index: roots[i], base: "", isLast: i === roots.length - 1 });
71178
+ }
71179
+ while (stack.length > 0) {
71180
+ const item = stack.pop();
71181
+ const summary = this.pageSummaries[item.index];
71182
+ const rowDepth = depth[item.index];
71183
+ const connector = rowDepth === 0 ? "" : item.isLast ? TREE_CHARS.corner : TREE_CHARS.branch;
71184
+ const segments = capSegments(item.base + connector);
71185
+ const ancestryHidden = rowDepth > this.prefixDepthCap || summary.parentSeq !== null && parentIndex[item.index] === -1;
71186
+ const prefix = ancestryHidden ? TREE_CHARS.hiddenAncestry + segments : segments;
71187
+ rows.push({
71188
+ summary,
71189
+ prefix,
71190
+ hasChildren: summary.childCount > 0,
71191
+ inWindowChildren: childLists[item.index] !== void 0
71192
+ });
71193
+ if (prefix.length > this.maxPrefixCharsSeen) this.maxPrefixCharsSeen = prefix.length;
71194
+ if (this.collapsed.has(summary.id)) continue;
71195
+ const children = childLists[item.index];
71196
+ if (children === void 0) continue;
71197
+ const childBase = capSegments(item.base + (item.isLast ? TREE_CHARS.space : TREE_CHARS.pipe));
71198
+ for (let i = children.length - 1; i >= 0; i--) {
71199
+ stack.push({ index: children[i], base: childBase, isLast: i === children.length - 1 });
71200
+ }
71201
+ }
71202
+ this.rows = rows;
71203
+ let totalPrefix = 0;
71204
+ for (const row of rows) totalPrefix += row.prefix.length;
71205
+ this.currentTotalPrefixChars = totalPrefix;
70854
71206
  this.applyFilter();
70855
71207
  }
70856
71208
  applyFilter() {
70857
71209
  if (!this.searchQuery && this.filterMode === "all") {
70858
- this.filteredItems = this.flatItems;
70859
- return;
70860
- }
70861
- const searchTokens = this.searchQuery.toLowerCase().split(/\s+/).filter(Boolean);
70862
- this.filteredItems = this.flatItems.filter((item) => {
70863
- const entry = item.node.entry;
70864
- if (this.filterMode === "user-only") {
70865
- if (entry.type !== "message" || entry.message?.role !== "user") {
71210
+ this.filteredRows = this.rows;
71211
+ } else {
71212
+ const tokens = this.searchQuery.toLowerCase().split(/\s+/).filter(Boolean);
71213
+ this.filteredRows = this.rows.filter((row) => {
71214
+ if (this.filterMode === "user-only" && (row.summary.type !== "message" || row.summary.role !== "user")) {
70866
71215
  return false;
70867
71216
  }
70868
- }
70869
- if (searchTokens.length > 0) {
70870
- const text = extractContent(entry).toLowerCase();
70871
- const role = getRoleName(entry).toLowerCase();
70872
- return searchTokens.every(
70873
- (token) => text.includes(token) || role.includes(token)
70874
- );
70875
- }
70876
- return true;
70877
- });
70878
- this.selectedIndex = Math.max(
70879
- 0,
70880
- Math.min(this.selectedIndex, this.filteredItems.length - 1)
70881
- );
71217
+ if (tokens.length === 0) return true;
71218
+ const text = `${row.summary.preview ?? ""} ${roleName(row.summary)} ${row.summary.customType ?? ""} ${row.summary.label ?? ""} ${row.summary.seq}`.toLowerCase();
71219
+ return tokens.every((token) => text.includes(token));
71220
+ });
71221
+ }
71222
+ this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, this.filteredRows.length - 1));
70882
71223
  }
70883
- buildPrefix(item) {
70884
- const parts = [];
70885
- const prefixes = item.parentPrefixes;
70886
- const MAX_VISIBLE_DEPTH = 3;
70887
- if (prefixes.length > MAX_VISIBLE_DEPTH) {
70888
- parts.push("\u2026 ");
70889
- parts.push(...prefixes.slice(-MAX_VISIBLE_DEPTH));
71224
+ moveUp() {
71225
+ if (this.selectedIndex > 0) {
71226
+ this.selectedIndex--;
71227
+ this.statusMessage = null;
71228
+ return;
71229
+ }
71230
+ if (this.goToPreviousPage()) {
71231
+ this.statusMessage = null;
71232
+ return;
71233
+ }
71234
+ this.selectedIndex = 0;
71235
+ this.statusMessage = "at oldest entry";
71236
+ }
71237
+ moveDown() {
71238
+ if (this.selectedIndex < this.filteredRows.length - 1) {
71239
+ this.selectedIndex++;
71240
+ this.statusMessage = null;
71241
+ return;
71242
+ }
71243
+ if (this.goToNextPage()) {
71244
+ this.statusMessage = null;
71245
+ return;
71246
+ }
71247
+ this.statusMessage = this.filteredRows.length === 0 && this.searchQuery ? "no matches on this page - tab scans ahead" : "at latest entry";
71248
+ }
71249
+ pageNext() {
71250
+ if (this.goToNextPage()) {
71251
+ this.statusMessage = null;
71252
+ } else {
71253
+ this.statusMessage = this.pageSummaries.length === 0 ? "no entries" : "latest page";
71254
+ }
71255
+ }
71256
+ pagePrev() {
71257
+ if (this.goToPreviousPage()) {
71258
+ this.statusMessage = null;
71259
+ } else {
71260
+ this.statusMessage = this.pageSummaries.length === 0 ? "no entries" : "oldest page";
71261
+ }
71262
+ }
71263
+ /**
71264
+ * Bounded "next match": step to the next in-page match, otherwise scan
71265
+ * forward at most SEARCH_SCAN_PAGE_LIMIT pages per press. Never scans
71266
+ * the whole history eagerly and never accumulates fetched pages.
71267
+ */
71268
+ findNextMatch() {
71269
+ if (!this.searchQuery && this.filterMode === "all") {
71270
+ this.pageNext();
71271
+ return;
71272
+ }
71273
+ if (this.filteredRows.length > 1 && this.selectedIndex < this.filteredRows.length - 1) {
71274
+ this.selectedIndex++;
71275
+ this.statusMessage = null;
71276
+ return;
71277
+ }
71278
+ let scanned = 0;
71279
+ while (this.hasNext && scanned < SEARCH_SCAN_PAGE_LIMIT) {
71280
+ if (!this.goToNextPage()) break;
71281
+ scanned++;
71282
+ if (this.filteredRows.length > 0) {
71283
+ this.selectedIndex = 0;
71284
+ this.statusMessage = scanned === 1 ? "match on next page" : `match ${scanned} pages ahead`;
71285
+ return;
71286
+ }
71287
+ }
71288
+ if (!this.hasNext) {
71289
+ this.statusMessage = "no more matches - end of history";
70890
71290
  } else {
70891
- parts.push(...prefixes);
71291
+ this.statusMessage = `no matches in next ${scanned} pages - tab to continue`;
70892
71292
  }
70893
- if (item.depth > 0) {
70894
- parts.push(item.isLast ? TREE_CHARS.corner : TREE_CHARS.branch);
71293
+ }
71294
+ toggleCollapse() {
71295
+ const selected = this.filteredRows[this.selectedIndex];
71296
+ if (!selected) return;
71297
+ if (this.collapsed.has(selected.summary.id)) {
71298
+ this.collapsed.delete(selected.summary.id);
71299
+ } else {
71300
+ if (this.collapsed.size >= COLLAPSED_CAP) {
71301
+ const oldest = this.collapsed.keys().next().value;
71302
+ if (oldest !== void 0) this.collapsed.delete(oldest);
71303
+ }
71304
+ this.collapsed.set(selected.summary.id, true);
70895
71305
  }
70896
- return parts.join("");
71306
+ this.rebuildRows();
70897
71307
  }
70898
71308
  render(width) {
70899
71309
  const lines = [];
70900
71310
  const totalLines = this.maxVisibleLines + 5;
71311
+ const range = this.windowSeqRange;
71312
+ const rangeLabel = range === null ? "empty" : `seqs ${range[0]}-${range[1]} of ${this.totalEntries}`;
70901
71313
  lines.push(createLine(" Conversation Tree", width, false));
70902
71314
  lines.push(
70903
71315
  createLine(
70904
- " \u2191\u2193:move \u2190\u2192:page e:expand/collapse F:fork Enter:navigate Esc:cancel",
71316
+ " \u2191\u2193:move \u2190\u2192:page e:collapse tab:next match F:fork Enter:navigate Esc:cancel",
70905
71317
  width,
70906
71318
  false
70907
71319
  )
70908
71320
  );
70909
71321
  lines.push(
70910
71322
  createLine(
70911
- this.searchQuery ? ` Search: ${this.searchQuery}` : " Type to search",
71323
+ this.searchQuery ? ` Search: ${this.searchQuery} (${this.filteredRows.length} on this page, tab:next match)` : ` Type to search (${rangeLabel})`,
70912
71324
  width,
70913
71325
  false
70914
71326
  )
70915
71327
  );
70916
- lines.push(createLine("", width, false));
70917
- if (this.filteredItems.length === 0) {
70918
- for (let i = 0; i < this.maxVisibleLines; i++) {
71328
+ lines.push(createLine(this.statusMessage ? ` ${this.statusMessage}` : "", width, false));
71329
+ if (this.filteredRows.length === 0) {
71330
+ const notice = this.searchQuery || this.filterMode === "user-only" ? " (no matching entries on this page)" : " (no entries)";
71331
+ lines.push(createLine(notice, width, false));
71332
+ for (let i = 1; i < this.maxVisibleLines; i++) {
70919
71333
  lines.push(createLine("", width, false));
70920
71334
  }
70921
71335
  } else {
70922
- this.selectedIndex = Math.max(
70923
- 0,
70924
- Math.min(this.selectedIndex, this.filteredItems.length - 1)
70925
- );
71336
+ this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, this.filteredRows.length - 1));
70926
71337
  let startIndex = Math.max(
70927
71338
  0,
70928
71339
  Math.min(
70929
71340
  this.selectedIndex - Math.floor(this.maxVisibleLines / 2),
70930
- this.filteredItems.length - this.maxVisibleLines
71341
+ this.filteredRows.length - this.maxVisibleLines
70931
71342
  )
70932
71343
  );
70933
- let endIndex = Math.min(
70934
- startIndex + this.maxVisibleLines,
70935
- this.filteredItems.length
70936
- );
71344
+ const endIndex = Math.min(startIndex + this.maxVisibleLines, this.filteredRows.length);
70937
71345
  if (endIndex - startIndex < this.maxVisibleLines && startIndex > 0) {
70938
71346
  startIndex = Math.max(0, endIndex - this.maxVisibleLines);
70939
71347
  }
70940
71348
  for (let i = startIndex; i < endIndex; i++) {
70941
- const item = this.filteredItems[i];
70942
- const entry = item.node.entry;
70943
- const isSelected = i === this.selectedIndex;
70944
- const prefix = this.buildPrefix(item);
70945
- const findOriginalNode = (nodes, id) => {
70946
- for (const node of nodes) {
70947
- if (node.id === id) return node;
70948
- if (node.children.length > 0) {
70949
- const found = findOriginalNode(node.children, id);
70950
- if (found) return found;
70951
- }
70952
- }
70953
- return null;
70954
- };
70955
- const originalNode = findOriginalNode(this.tree, item.node.id);
70956
- const hasChildren = originalNode ? originalNode.children.length > 0 : false;
70957
- const isExpanded = this.expandedNodes.has(item.node.id);
70958
- const activeIndicator = item.node.isActive ? theme.fg("success", TREE_CHARS.active) : DIM + TREE_CHARS.inactive + RESET;
70959
- const expandIndicator = hasChildren ? isExpanded ? theme.fg("dim", "\u25BC ") : theme.fg("dim", "\u25B6 ") : " ";
70960
- const roleName = getRoleName(entry);
70961
- const roleColored = getRoleColor(roleName);
70962
- const content = extractContent(entry);
70963
- const availableWidth = width - visibleLength(prefix) - visibleLength(activeIndicator) - visibleLength(expandIndicator) - visibleLength(roleColored) - 2;
70964
- const truncatedContent = availableWidth > 0 ? truncateToWidth(content, availableWidth) : "";
70965
- const lineContent = `${prefix}${activeIndicator}${expandIndicator}${roleColored}: ${truncatedContent}`;
70966
- lines.push(createLine(lineContent, width, isSelected));
70967
- }
70968
- const visibleCount = endIndex - startIndex;
70969
- for (let i = visibleCount; i < this.maxVisibleLines; i++) {
71349
+ const row = this.filteredRows[i];
71350
+ const activeIndicator = this.options.activePathSeqs.has(row.summary.seq) ? theme.fg("success", TREE_CHARS.active) : DIM + TREE_CHARS.inactive + RESET;
71351
+ const expandIndicator = row.inWindowChildren ? theme.fg("dim", this.collapsed.has(row.summary.id) ? "\u25B6 " : "\u25BC ") : row.hasChildren ? theme.fg("dim", "\xB7\xB7") : " ";
71352
+ const role = roleColor(roleName(row.summary));
71353
+ const indicatorWidth = visibleWidth(activeIndicator) + visibleWidth(expandIndicator) + visibleWidth(role) + 2;
71354
+ const prefixBudget = Math.max(0, Math.min(Math.floor(width * 0.35), width - indicatorWidth - MIN_BODY_WIDTH));
71355
+ const displayPrefix = clampPrefixForDisplay(row.prefix, prefixBudget);
71356
+ const availableWidth = Math.max(0, width - visibleWidth(displayPrefix) - indicatorWidth);
71357
+ const content = truncateToWidth(row.summary.preview ?? "", availableWidth);
71358
+ lines.push(createLine(`${displayPrefix}${activeIndicator}${expandIndicator}${role}: ${content}`, width, i === this.selectedIndex));
71359
+ }
71360
+ for (let i = endIndex - startIndex; i < this.maxVisibleLines; i++) {
70970
71361
  lines.push(createLine("", width, false));
70971
71362
  }
70972
- const selectedItem = this.filteredItems[this.selectedIndex];
70973
- const activePath = selectedItem?.node.isActive ? " [active]" : "";
70974
- lines.push(
70975
- createLine(
70976
- ` (${this.selectedIndex + 1}/${this.filteredItems.length})${this.filterMode === "user-only" ? " [user]" : ""}${activePath}`,
70977
- width,
70978
- false
70979
- )
70980
- );
70981
71363
  }
71364
+ const selectedRow = this.filteredRows[this.selectedIndex];
71365
+ const activePath = selectedRow && this.options.activePathSeqs.has(selectedRow.summary.seq) ? " [active]" : "";
71366
+ lines.push(
71367
+ createLine(
71368
+ ` (${selectedRow ? this.selectedIndex + 1 : 0}/${this.filteredRows.length})${this.filterMode === "user-only" ? " [user]" : ""}${activePath} \xB7 ${rangeLabel}`,
71369
+ width,
71370
+ false
71371
+ )
71372
+ );
70982
71373
  while (lines.length < totalLines) {
70983
71374
  lines.push(createLine("", width, false));
70984
71375
  }
@@ -70987,51 +71378,24 @@ var TreeSelectorComponent = class {
70987
71378
  handleInput(keyData) {
70988
71379
  const kb = getEditorKeybindings();
70989
71380
  if (kb.matches(keyData, "selectUp")) {
70990
- this.selectedIndex = Math.max(0, this.selectedIndex - 1);
71381
+ this.moveUp();
70991
71382
  } else if (kb.matches(keyData, "selectDown")) {
70992
- this.selectedIndex = Math.min(
70993
- this.filteredItems.length - 1,
70994
- this.selectedIndex + 1
70995
- );
70996
- } else if (kb.matches(keyData, "cursorRight")) {
70997
- this.selectedIndex = Math.min(
70998
- this.filteredItems.length - 1,
70999
- this.selectedIndex + this.maxVisibleLines
71000
- );
71001
- } else if (kb.matches(keyData, "cursorLeft")) {
71002
- this.selectedIndex = Math.max(0, this.selectedIndex - this.maxVisibleLines);
71383
+ this.moveDown();
71384
+ } else if (kb.matches(keyData, "cursorRight") || kb.matches(keyData, "selectPageDown")) {
71385
+ this.pageNext();
71386
+ } else if (kb.matches(keyData, "cursorLeft") || kb.matches(keyData, "selectPageUp")) {
71387
+ this.pagePrev();
71003
71388
  } else if (keyData === "e" || keyData === "E") {
71004
- const selected = this.filteredItems[this.selectedIndex];
71005
- if (selected) {
71006
- const findOriginalNode = (nodes, id) => {
71007
- for (const node of nodes) {
71008
- if (node.id === id) return node;
71009
- if (node.children.length > 0) {
71010
- const found = findOriginalNode(node.children, id);
71011
- if (found) return found;
71012
- }
71013
- }
71014
- return null;
71015
- };
71016
- const originalNode = findOriginalNode(this.tree, selected.node.id);
71017
- if (originalNode && originalNode.children.length > 0) {
71018
- if (this.expandedNodes.has(selected.node.id)) {
71019
- this.expandedNodes.delete(selected.node.id);
71020
- } else {
71021
- this.expandedNodes.add(selected.node.id);
71022
- }
71023
- this.refreshFlatItems();
71024
- }
71025
- }
71389
+ this.toggleCollapse();
71026
71390
  } else if (kb.matches(keyData, "selectConfirm")) {
71027
- const selected = this.filteredItems[this.selectedIndex];
71391
+ const selected = this.filteredRows[this.selectedIndex];
71028
71392
  if (selected && this.onSelect) {
71029
- this.onSelect(selected.node.id, "navigate");
71393
+ this.onSelect(selected.summary.id, "navigate");
71030
71394
  }
71031
71395
  } else if (keyData === "f" || keyData === "F") {
71032
- const selected = this.filteredItems[this.selectedIndex];
71396
+ const selected = this.filteredRows[this.selectedIndex];
71033
71397
  if (selected && this.onSelect) {
71034
- this.onSelect(selected.node.id, "fork");
71398
+ this.onSelect(selected.summary.id, "fork");
71035
71399
  }
71036
71400
  } else if (kb.matches(keyData, "selectCancel")) {
71037
71401
  if (this.searchQuery) {
@@ -71040,12 +71404,15 @@ var TreeSelectorComponent = class {
71040
71404
  } else {
71041
71405
  this.onCancel?.();
71042
71406
  }
71407
+ } else if (matchesKey(keyData, "tab")) {
71408
+ this.findNextMatch();
71043
71409
  } else if (matchesKey(keyData, "ctrl+u")) {
71044
71410
  this.filterMode = this.filterMode === "user-only" ? "all" : "user-only";
71045
71411
  this.applyFilter();
71046
71412
  } else if (kb.matches(keyData, "deleteCharBackward")) {
71047
71413
  if (this.searchQuery.length > 0) {
71048
- this.searchQuery = this.searchQuery.slice(0, -1);
71414
+ const last = searchSegmenter.segment(this.searchQuery).containing(this.searchQuery.length - 1);
71415
+ this.searchQuery = this.searchQuery.slice(0, last?.index ?? 0);
71049
71416
  this.applyFilter();
71050
71417
  }
71051
71418
  } else {
@@ -71060,10 +71427,10 @@ var TreeSelectorComponent = class {
71060
71427
  }
71061
71428
  }
71062
71429
  invalidate() {
71063
- this.refreshFlatItems();
71430
+ this.rebuildRows();
71064
71431
  }
71065
71432
  getSelectedEntryId() {
71066
- return this.filteredItems[this.selectedIndex]?.node.id ?? null;
71433
+ return this.filteredRows[this.selectedIndex]?.summary.id ?? null;
71067
71434
  }
71068
71435
  };
71069
71436
 
@@ -71265,16 +71632,16 @@ var Diff = class {
71265
71632
  }
71266
71633
  }
71267
71634
  }
71268
- addToPath(path33, added, removed, oldPosInc, options) {
71269
- const last = path33.lastComponent;
71635
+ addToPath(path34, added, removed, oldPosInc, options) {
71636
+ const last = path34.lastComponent;
71270
71637
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
71271
71638
  return {
71272
- oldPos: path33.oldPos + oldPosInc,
71639
+ oldPos: path34.oldPos + oldPosInc,
71273
71640
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
71274
71641
  };
71275
71642
  } else {
71276
71643
  return {
71277
- oldPos: path33.oldPos + oldPosInc,
71644
+ oldPos: path34.oldPos + oldPosInc,
71278
71645
  lastComponent: { count: 1, added, removed, previousComponent: last }
71279
71646
  };
71280
71647
  }
@@ -71722,13 +72089,13 @@ function formatSize2(bytes) {
71722
72089
  }
71723
72090
  var DEFAULT_MAX_BYTES = 102400;
71724
72091
  var DEFAULT_MAX_LINES = 100;
71725
- function shortenPath(path33) {
71726
- if (typeof path33 !== "string") return "";
72092
+ function shortenPath(path34) {
72093
+ if (typeof path34 !== "string") return "";
71727
72094
  const home = os5.homedir();
71728
- if (path33.startsWith(home)) {
71729
- return `~${path33.slice(home.length)}`;
72095
+ if (path34.startsWith(home)) {
72096
+ return `~${path34.slice(home.length)}`;
71730
72097
  }
71731
- return path33;
72098
+ return path34;
71732
72099
  }
71733
72100
  function replaceTabs(text) {
71734
72101
  return text.replace(/\t/g, " ");
@@ -71738,6 +72105,18 @@ function str(value) {
71738
72105
  if (value == null) return "";
71739
72106
  return null;
71740
72107
  }
72108
+ function projectResultForDisplay(result) {
72109
+ const content = result.content;
72110
+ if (!Array.isArray(content) || !content.some((block) => typeof block?.data === "string" && block.data.length > 0)) {
72111
+ return result;
72112
+ }
72113
+ return {
72114
+ ...result,
72115
+ content: content.map(
72116
+ (block) => typeof block?.data === "string" && block.data.length > 0 ? { ...block, data: "" } : block
72117
+ )
72118
+ };
72119
+ }
71741
72120
  function partialStr(value, maxLen = 30) {
71742
72121
  if (typeof value === "string") {
71743
72122
  if (value.length === 0) return "...";
@@ -71772,7 +72151,7 @@ var ToolExecutionComponent = class extends Container {
71772
72151
  this.updateDisplay();
71773
72152
  }
71774
72153
  updateResult(result, isPartial = false) {
71775
- this.result = result;
72154
+ this.result = projectResultForDisplay(result);
71776
72155
  this.isPartial = isPartial;
71777
72156
  this.updateDisplay();
71778
72157
  }
@@ -71811,14 +72190,14 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
71811
72190
  }
71812
72191
  } else if (this.toolName === "read_file") {
71813
72192
  const rawPath = str(this.args?.file_path ?? this.args?.path);
71814
- const path33 = rawPath !== null ? shortenPath(rawPath) : null;
72193
+ const path34 = rawPath !== null ? shortenPath(rawPath) : null;
71815
72194
  const offset = typeof this.args?.offset === "number" ? this.args.offset : void 0;
71816
72195
  const limit = typeof this.args?.limit === "number" ? this.args.limit : void 0;
71817
72196
  let pathDisplay;
71818
- if (path33 === null) {
72197
+ if (path34 === null) {
71819
72198
  pathDisplay = invalidArg;
71820
- } else if (path33) {
71821
- pathDisplay = theme.fg("accent", path33);
72199
+ } else if (path34) {
72200
+ pathDisplay = theme.fg("accent", path34);
71822
72201
  } else {
71823
72202
  const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
71824
72203
  pathDisplay = theme.fg("toolOutput", partialPath);
@@ -71865,12 +72244,12 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
71865
72244
  } else if (this.toolName === "write_file") {
71866
72245
  const rawPath = str(this.args?.file_path ?? this.args?.path);
71867
72246
  const fileContent = str(this.args?.content);
71868
- const path33 = rawPath !== null ? shortenPath(rawPath) : null;
72247
+ const path34 = rawPath !== null ? shortenPath(rawPath) : null;
71869
72248
  let pathDisplay;
71870
- if (path33 === null) {
72249
+ if (path34 === null) {
71871
72250
  pathDisplay = invalidArg;
71872
- } else if (path33) {
71873
- pathDisplay = theme.fg("accent", path33);
72251
+ } else if (path34) {
72252
+ pathDisplay = theme.fg("accent", path34);
71874
72253
  } else {
71875
72254
  const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
71876
72255
  pathDisplay = theme.fg("toolOutput", partialPath);
@@ -71907,12 +72286,12 @@ ${theme.fg("error", errorText)}`;
71907
72286
  }
71908
72287
  } else if (this.toolName === "edit_file") {
71909
72288
  const rawPath = str(this.args?.file_path ?? this.args?.path);
71910
- const path33 = rawPath !== null ? shortenPath(rawPath) : null;
72289
+ const path34 = rawPath !== null ? shortenPath(rawPath) : null;
71911
72290
  let pathDisplay;
71912
- if (path33 === null) {
72291
+ if (path34 === null) {
71913
72292
  pathDisplay = invalidArg;
71914
- } else if (path33) {
71915
- pathDisplay = theme.fg("accent", path33);
72293
+ } else if (path34) {
72294
+ pathDisplay = theme.fg("accent", path34);
71916
72295
  } else {
71917
72296
  const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
71918
72297
  pathDisplay = theme.fg("toolOutput", partialPath);
@@ -71937,7 +72316,7 @@ ${theme.fg("error", errorText)}`;
71937
72316
  const diff = this.result.details.diff;
71938
72317
  const firstChangedLine = this.result.details.firstChangedLine;
71939
72318
  if (firstChangedLine) {
71940
- text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path33 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
72319
+ text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path34 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
71941
72320
  }
71942
72321
  const lines = diff.split("\n");
71943
72322
  const maxLines = this.expanded ? lines.length : 15;
@@ -71957,7 +72336,7 @@ ${theme.fg("error", errorText)}`;
71957
72336
  const diff = generateEditDiff(oldText, newText, rawPath);
71958
72337
  const firstChangedLine = findFirstChangedLine(oldText, newText);
71959
72338
  if (firstChangedLine) {
71960
- text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path33 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
72339
+ text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path34 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
71961
72340
  }
71962
72341
  const lines = diff.split("\n");
71963
72342
  const maxLines = this.expanded ? lines.length : 15;
@@ -71976,9 +72355,9 @@ ${theme.fg("error", errorText)}`;
71976
72355
  }
71977
72356
  } else if (this.toolName === "list_dir") {
71978
72357
  const rawPath = str(this.args?.path);
71979
- const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72358
+ const path34 = rawPath !== null ? shortenPath(rawPath || ".") : null;
71980
72359
  const limit = this.args?.limit;
71981
- text = `${theme.fg("toolTitle", theme.bold("list_dir"))} ${path33 === null ? invalidArg : theme.fg("accent", path33)}`;
72360
+ text = `${theme.fg("toolTitle", theme.bold("list_dir"))} ${path34 === null ? invalidArg : theme.fg("accent", path34)}`;
71982
72361
  if (limit !== void 0) {
71983
72362
  text += theme.fg("toolOutput", ` (limit ${limit})`);
71984
72363
  }
@@ -72014,9 +72393,9 @@ ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
72014
72393
  } else if (this.toolName === "find_files") {
72015
72394
  const pattern = str(this.args?.pattern);
72016
72395
  const rawPath = str(this.args?.path);
72017
- const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72396
+ const path34 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72018
72397
  const limit = this.args?.limit;
72019
- text = theme.fg("toolTitle", theme.bold("find_files")) + " " + (pattern === null ? invalidArg : theme.fg("accent", pattern || "")) + theme.fg("toolOutput", ` in ${path33 === null ? invalidArg : path33}`);
72398
+ text = theme.fg("toolTitle", theme.bold("find_files")) + " " + (pattern === null ? invalidArg : theme.fg("accent", pattern || "")) + theme.fg("toolOutput", ` in ${path34 === null ? invalidArg : path34}`);
72020
72399
  if (limit !== void 0) {
72021
72400
  text += theme.fg("toolOutput", ` (limit ${limit})`);
72022
72401
  }
@@ -72052,10 +72431,10 @@ ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
72052
72431
  } else if (this.toolName === "grep_text") {
72053
72432
  const pattern = str(this.args?.pattern);
72054
72433
  const rawPath = str(this.args?.path);
72055
- const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72434
+ const path34 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72056
72435
  const glob = str(this.args?.glob);
72057
72436
  const limit = this.args?.limit;
72058
- text = theme.fg("toolTitle", theme.bold("grep_text")) + " " + (pattern === null ? invalidArg : theme.fg("accent", `/${pattern || ""}/`)) + theme.fg("toolOutput", ` in ${path33 === null ? invalidArg : path33}`);
72437
+ text = theme.fg("toolTitle", theme.bold("grep_text")) + " " + (pattern === null ? invalidArg : theme.fg("accent", `/${pattern || ""}/`)) + theme.fg("toolOutput", ` in ${path34 === null ? invalidArg : path34}`);
72059
72438
  if (glob) {
72060
72439
  text += theme.fg("toolOutput", ` (${glob})`);
72061
72440
  }
@@ -72278,7 +72657,7 @@ async function handleResumeCommand(host) {
72278
72657
  return { component: selector, focus: selector.getSelectList() };
72279
72658
  });
72280
72659
  }
72281
- async function loadSession2(host, sessionId) {
72660
+ async function loadSession(host, sessionId) {
72282
72661
  const beforeSwitch = await host.extensionRunner?.emitSessionBeforeSwitch({
72283
72662
  type: "session:before_switch",
72284
72663
  reason: "resume",
@@ -72475,29 +72854,31 @@ function setWaitingForUser(host, waiting) {
72475
72854
  syncTitleActivity(host);
72476
72855
  }
72477
72856
  async function handleTreeCommand(host) {
72478
- const entries = host.sessionManager.getEntries();
72479
- const tree = host.sessionManager.getTree();
72480
- if (tree.length === 0) {
72481
- host.showStatus(`No entries in current session (entries: ${entries.length})`);
72857
+ const head = host.sessionManager.getEntrySummariesPage({ limit: 1 });
72858
+ if (head.total === 0) {
72859
+ host.showStatus(`No entries in current session (entries: 0)`);
72482
72860
  return;
72483
72861
  }
72484
72862
  host.showSelector((done) => {
72485
72863
  const selector = new TreeSelectorComponent(
72486
- tree,
72487
- host.ui.terminal.rows,
72488
- async (entryId, action) => {
72489
- done();
72490
- if (action === "fork") {
72491
- await host.forkAtEntry(entryId);
72492
- } else {
72493
- await host.navigateToEntry(entryId);
72864
+ {
72865
+ terminalHeight: host.ui.terminal.rows,
72866
+ activeEntryId: host.sessionManager.getActiveEntryId(),
72867
+ activePathSeqs: host.sessionManager.getActivePathSeqs(),
72868
+ totalEntries: head.total,
72869
+ fetchSummaries: (afterSeq, limit) => host.sessionManager.getEntrySummariesPage({ limit, afterSeq }),
72870
+ onSelect: async (entryId, action) => {
72871
+ done();
72872
+ if (action === "fork") {
72873
+ await host.forkAtEntry(entryId);
72874
+ } else {
72875
+ await host.navigateToEntry(entryId);
72876
+ }
72877
+ },
72878
+ onCancel: () => {
72879
+ done();
72494
72880
  }
72495
- },
72496
- () => {
72497
- done();
72498
- },
72499
- host.sessionManager.getActiveEntryId()
72500
- // Start at active entry
72881
+ }
72501
72882
  );
72502
72883
  return { component: selector, focus: selector };
72503
72884
  });
@@ -72514,8 +72895,8 @@ async function forkAtEntry(host, entryId) {
72514
72895
  host.showError("Failed to branch at entry");
72515
72896
  return;
72516
72897
  }
72517
- const path33 = host.sessionManager.getPathToEntry(entryId);
72518
- const pathNames = path33.map((e) => e.message?.role || "entry").join(" \u2192 ");
72898
+ const path34 = host.sessionManager.getPathSummaries(entryId);
72899
+ const pathNames = path34.map((summary) => summary.role || summary.type).join(" \u2192 ");
72519
72900
  const messages = host.sessionManager.getMessages();
72520
72901
  host.syncAgentFromActiveSession(messages);
72521
72902
  await host.syncSessionScopedState(messages);
@@ -72528,7 +72909,7 @@ async function forkAtEntry(host, entryId) {
72528
72909
  host.updatePendingMessagesDisplay();
72529
72910
  host.renderMessageHistory(messages);
72530
72911
  await host.sessionManager.save();
72531
- host.showStatus(`Branched at: ${pathNames} (${path33.length} messages). Continue to add to this branch.`);
72912
+ host.showStatus(`Branched at: ${pathNames} (${path34.length} messages). Continue to add to this branch.`);
72532
72913
  } catch (error) {
72533
72914
  host.showError(
72534
72915
  `Failed to branch: ${error instanceof Error ? error.message : String(error)}`
@@ -72556,10 +72937,10 @@ async function navigateToEntry(host, entryId) {
72556
72937
  host.sessionManager.save().catch((err) => {
72557
72938
  console.error("[Session] Save after navigation failed:", err);
72558
72939
  });
72559
- const path33 = host.sessionManager.getPathToEntry(entryId);
72560
- const entry = host.sessionManager.getEntry(entryId);
72561
- const role = entry?.message?.role || "entry";
72562
- host.showStatus(`Switched to branch: ${role} (${path33.length} messages in path)`);
72940
+ const path34 = host.sessionManager.getPathSummaries(entryId);
72941
+ const summary = host.sessionManager.getEntrySummary(entryId);
72942
+ const role = summary?.role || summary?.type || "entry";
72943
+ host.showStatus(`Switched to branch: ${role} (${path34.length} entries in path)`);
72563
72944
  } catch (error) {
72564
72945
  host.showError(
72565
72946
  `Failed to navigate: ${error instanceof Error ? error.message : String(error)}`
@@ -72654,9 +73035,9 @@ async function handleForkCommand(host) {
72654
73035
  }
72655
73036
 
72656
73037
  // src/commands/interactive-skill-commands.ts
72657
- import * as fs23 from "fs";
73038
+ import * as fs24 from "fs";
72658
73039
  import * as os7 from "os";
72659
- import * as path25 from "path";
73040
+ import * as path26 from "path";
72660
73041
 
72661
73042
  // src/commands/subagent-command.ts
72662
73043
  async function handleSubagentCommand(host, args) {
@@ -72793,9 +73174,9 @@ function handleSkillsCommand(host) {
72793
73174
  });
72794
73175
  }
72795
73176
  function discoverSkills(host) {
72796
- const builtinDir = path25.join(getBuiltinDir(), "skills");
72797
- const userDir = path25.join(os7.homedir(), ".pie", "skills");
72798
- const projectDir = path25.join(process.cwd(), ".pie", "skills");
73177
+ const builtinDir = path26.join(getBuiltinDir(), "skills");
73178
+ const userDir = path26.join(os7.homedir(), ".pie", "skills");
73179
+ const projectDir = path26.join(process.cwd(), ".pie", "skills");
72799
73180
  return loadSkills({ dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: process.cwd() }) });
72800
73181
  }
72801
73182
  function listDiscoveredSkills(host) {
@@ -72927,7 +73308,7 @@ function expandSkillCommand(host, text) {
72927
73308
  const skill = host.skills.find((s) => s.name === skillName);
72928
73309
  if (!skill) return text;
72929
73310
  try {
72930
- const content = fs23.readFileSync(skill.filePath, "utf-8");
73311
+ const content = fs24.readFileSync(skill.filePath, "utf-8");
72931
73312
  const body = host.stripFrontmatter(content).trim();
72932
73313
  const skillBlock = `<skill name="${skill.name}" location="${skill.filePath}">
72933
73314
  References are relative to ${skill.baseDir}.
@@ -72954,9 +73335,9 @@ async function handleSkillToggleCommand(host, args, enabled) {
72954
73335
  host.showError(`Usage: /skills/${enabled ? "enable" : "disable"} <name>`);
72955
73336
  return;
72956
73337
  }
72957
- const builtinDir = path25.join(getBuiltinDir(), "skills");
72958
- const userDir = path25.join(os7.homedir(), ".pie", "skills");
72959
- const projectDir = path25.join(process.cwd(), ".pie", "skills");
73338
+ const builtinDir = path26.join(getBuiltinDir(), "skills");
73339
+ const userDir = path26.join(os7.homedir(), ".pie", "skills");
73340
+ const projectDir = path26.join(process.cwd(), ".pie", "skills");
72960
73341
  const discovered = loadSkills({ dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: process.cwd() }) }).skills;
72961
73342
  if (!discovered.some((skill) => skill.name === name)) {
72962
73343
  host.showError(`Skill not found: ${name}`);
@@ -73022,17 +73403,17 @@ async function handleSkillsCreate(host, args) {
73022
73403
  if (!description) {
73023
73404
  description = `Skill for ${name}`;
73024
73405
  }
73025
- const skillsDir = path25.join(os7.homedir(), ".pie", "skills");
73026
- const skillDir = path25.join(skillsDir, name);
73027
- const skillFile = path25.join(skillDir, "SKILL.md");
73406
+ const skillsDir = path26.join(os7.homedir(), ".pie", "skills");
73407
+ const skillDir = path26.join(skillsDir, name);
73408
+ const skillFile = path26.join(skillDir, "SKILL.md");
73028
73409
  debugLog2(`Creating at: ${skillFile}`);
73029
- if (fs23.existsSync(skillDir)) {
73410
+ if (fs24.existsSync(skillDir)) {
73030
73411
  host.showError(`Skill "${name}" already exists at ${skillDir}`);
73031
73412
  return;
73032
73413
  }
73033
- fs23.mkdirSync(skillDir, { recursive: true });
73414
+ fs24.mkdirSync(skillDir, { recursive: true });
73034
73415
  const template = createSkillTemplate(name, description);
73035
- fs23.writeFileSync(skillFile, template, "utf-8");
73416
+ fs24.writeFileSync(skillFile, template, "utf-8");
73036
73417
  debugLog2("Successfully created skill");
73037
73418
  host.chatContainer.addChild(new Spacer(1));
73038
73419
  host.chatContainer.addChild(new Text(theme.fg("accent", `\u2713 Created skill: ${name}`), 1, 0));
@@ -73968,8 +74349,7 @@ async function handleCompactCommand(host) {
73968
74349
  host.showStatus("Nothing to compact yet");
73969
74350
  return;
73970
74351
  }
73971
- const pathEntries = host.sessionManager.getPathToEntry(activeEntryId);
73972
- const firstKeptEntryId = findFirstKeptEntryId(pathEntries);
74352
+ const firstKeptEntryId = findFirstKeptEntrySummaryId(host.sessionManager.getActiveContextSummaries());
73973
74353
  if (!firstKeptEntryId) {
73974
74354
  host.showStatus("Need at least one real user message before compacting");
73975
74355
  return;
@@ -74885,8 +75265,8 @@ function setupInteractiveEditorSubmitHandler(host) {
74885
75265
  }
74886
75266
 
74887
75267
  // src/input/interactive-file-pipeline.ts
74888
- import * as fs26 from "fs";
74889
- import * as path28 from "path";
75268
+ import * as fs27 from "fs";
75269
+ import * as path29 from "path";
74890
75270
 
74891
75271
  // src/components/file-picker.ts
74892
75272
  var FilePickerComponent = class extends Container {
@@ -75107,8 +75487,8 @@ var FilePickerComponent = class extends Container {
75107
75487
  };
75108
75488
 
75109
75489
  // src/files/commands/file-commands.ts
75110
- import * as fs24 from "node:fs";
75111
- import * as path26 from "node:path";
75490
+ import * as fs25 from "node:fs";
75491
+ import * as path27 from "node:path";
75112
75492
  var FileCommands = class {
75113
75493
  context;
75114
75494
  constructor(context) {
@@ -75124,11 +75504,11 @@ var FileCommands = class {
75124
75504
  return;
75125
75505
  }
75126
75506
  const filePath = resolvePath2(parsed.path);
75127
- if (!fs24.existsSync(filePath)) {
75507
+ if (!fs25.existsSync(filePath)) {
75128
75508
  this.context.showError(`File not found: ${parsed.path}`);
75129
75509
  return;
75130
75510
  }
75131
- this.context.showStatus(`Uploading ${path26.basename(filePath)}...`);
75511
+ this.context.showStatus(`Uploading ${path27.basename(filePath)}...`);
75132
75512
  try {
75133
75513
  const result = await this.context.fileManager.upload(filePath, {
75134
75514
  purpose: parsed.purpose,
@@ -75163,7 +75543,7 @@ var FileCommands = class {
75163
75543
  return;
75164
75544
  }
75165
75545
  const resolvedPath = resolvePath2(filePath);
75166
- if (!fs24.existsSync(resolvedPath)) {
75546
+ if (!fs25.existsSync(resolvedPath)) {
75167
75547
  this.context.showError(`File not found: ${filePath}`);
75168
75548
  return;
75169
75549
  }
@@ -75194,7 +75574,7 @@ var FileCommands = class {
75194
75574
  return;
75195
75575
  }
75196
75576
  const resolvedPath = resolvePath2(parsed.path);
75197
- if (!fs24.existsSync(resolvedPath)) {
75577
+ if (!fs25.existsSync(resolvedPath)) {
75198
75578
  this.context.showError(`File not found: ${parsed.path}`);
75199
75579
  return;
75200
75580
  }
@@ -75672,8 +76052,8 @@ var FileStatusMonitor = class {
75672
76052
  };
75673
76053
 
75674
76054
  // src/files/mention/mention-handler.ts
75675
- import * as fs25 from "node:fs";
75676
- import * as path27 from "node:path";
76055
+ import * as fs26 from "node:fs";
76056
+ import * as path28 from "node:path";
75677
76057
  var MentionHandler = class {
75678
76058
  fileManager;
75679
76059
  onShowPicker;
@@ -75728,7 +76108,7 @@ var MentionHandler = class {
75728
76108
  navigateBrowseParent() {
75729
76109
  const currentDir = this.getBrowserDirectory();
75730
76110
  if (!currentDir) return;
75731
- const parentDir = path27.dirname(currentDir);
76111
+ const parentDir = path28.dirname(currentDir);
75732
76112
  if (parentDir === currentDir) return;
75733
76113
  this.browsingDirectory = parentDir;
75734
76114
  this.showMentionPicker("");
@@ -75748,7 +76128,7 @@ var MentionHandler = class {
75748
76128
  if (option.type === "parent") {
75749
76129
  const currentDir = this.getBrowserDirectory();
75750
76130
  if (currentDir) {
75751
- this.browsingDirectory = path27.dirname(currentDir);
76131
+ this.browsingDirectory = path28.dirname(currentDir);
75752
76132
  this.showMentionPicker("");
75753
76133
  this.isPickerVisible = true;
75754
76134
  }
@@ -75888,7 +76268,7 @@ var MentionHandler = class {
75888
76268
  id: part.content,
75889
76269
  name: part.name || fileInfo.name,
75890
76270
  mimeType: fileInfo.mimeType,
75891
- ext: path27.extname(part.name || fileInfo.name).toLowerCase(),
76271
+ ext: path28.extname(part.name || fileInfo.name).toLowerCase(),
75892
76272
  size: fileInfo.size,
75893
76273
  source: fileInfo.platforms.length > 0 ? "session" : "local",
75894
76274
  fileId: part.content,
@@ -76046,11 +76426,11 @@ var MentionHandler = class {
76046
76426
  }
76047
76427
  if (this.isPath(query)) {
76048
76428
  const resolvedPath = resolvePath2(query);
76049
- if (fs25.existsSync(resolvedPath)) {
76050
- const stats = fs25.statSync(resolvedPath);
76429
+ if (fs26.existsSync(resolvedPath)) {
76430
+ const stats = fs26.statSync(resolvedPath);
76051
76431
  if (stats.isFile()) {
76052
76432
  const type = FileCache.getFileTypeFromName(resolvedPath);
76053
- const name = path27.basename(resolvedPath);
76433
+ const name = path28.basename(resolvedPath);
76054
76434
  if (!seenNames.has(name.toLowerCase())) {
76055
76435
  options.push({
76056
76436
  type: "upload",
@@ -76071,16 +76451,16 @@ var MentionHandler = class {
76071
76451
  return void 0;
76072
76452
  }
76073
76453
  const queryPath = this.isPath(query) ? resolvePath2(query) : void 0;
76074
- const filter = queryPath ? fs25.existsSync(queryPath) && fs25.statSync(queryPath).isDirectory() ? "" : path27.basename(queryPath) : query;
76454
+ const filter = queryPath ? fs26.existsSync(queryPath) && fs26.statSync(queryPath).isDirectory() ? "" : path28.basename(queryPath) : query;
76075
76455
  const entries = this.fileManager.listPathEntries(currentDir, filter);
76076
76456
  const options = [];
76077
76457
  const homeDir = process.env.HOME || "";
76078
76458
  const displayDir = currentDir.startsWith(homeDir) ? `~${currentDir.slice(homeDir.length)}` : currentDir;
76079
- if (path27.dirname(currentDir) !== currentDir) {
76459
+ if (path28.dirname(currentDir) !== currentDir) {
76080
76460
  options.push({
76081
76461
  type: "parent",
76082
76462
  name: "..",
76083
- path: path27.dirname(currentDir),
76463
+ path: path28.dirname(currentDir),
76084
76464
  icon: "\u21A9",
76085
76465
  meta: "Parent directory"
76086
76466
  });
@@ -76112,10 +76492,10 @@ var MentionHandler = class {
76112
76492
  getBrowserDirectory(query = this.currentQuery) {
76113
76493
  if (this.isPath(query)) {
76114
76494
  const resolvedPath = resolvePath2(query);
76115
- if (fs25.existsSync(resolvedPath) && fs25.statSync(resolvedPath).isDirectory()) {
76495
+ if (fs26.existsSync(resolvedPath) && fs26.statSync(resolvedPath).isDirectory()) {
76116
76496
  return resolvedPath;
76117
76497
  }
76118
- return path27.dirname(resolvedPath);
76498
+ return path28.dirname(resolvedPath);
76119
76499
  }
76120
76500
  return this.browsingDirectory;
76121
76501
  }
@@ -76202,8 +76582,8 @@ async function initializeFileManager(host) {
76202
76582
  sessionId,
76203
76583
  platform: platform2,
76204
76584
  apiKey: host.options.apiKey,
76205
- baseDir: path28.join(host.options.configDir, "files"),
76206
- sessionsDir: path28.join(host.options.configDir, "sessions")
76585
+ baseDir: path29.join(host.options.configDir, "files"),
76586
+ sessionsDir: path29.join(host.options.configDir, "sessions")
76207
76587
  });
76208
76588
  switch (getFileManagerAdapterKind(platform2)) {
76209
76589
  case "kimi":
@@ -76483,13 +76863,13 @@ function convertPreparedAttachmentItems(items) {
76483
76863
  break;
76484
76864
  case "image": {
76485
76865
  if (!item.data && !item.path) return void 0;
76486
- const data = item.data ?? fs26.readFileSync(item.path, "base64");
76866
+ const data = item.data ?? fs27.readFileSync(item.path, "base64");
76487
76867
  converted.push({ type: "image", data, mimeType: item.mimeType });
76488
76868
  break;
76489
76869
  }
76490
76870
  case "video": {
76491
76871
  if (!item.data && !item.path) return void 0;
76492
- const data = item.data ?? fs26.readFileSync(item.path, "base64");
76872
+ const data = item.data ?? fs27.readFileSync(item.path, "base64");
76493
76873
  converted.push({ type: "video", data, mimeType: item.mimeType });
76494
76874
  break;
76495
76875
  }
@@ -77075,8 +77455,7 @@ async function createCliAutoCompactionResult(params) {
77075
77455
  if (!activeEntryId) {
77076
77456
  return { aborted: true };
77077
77457
  }
77078
- const pathEntries = params.context.sessionManager.getPathToEntry(activeEntryId);
77079
- const firstKeptEntryId = findFirstKeptEntryId(pathEntries);
77458
+ const firstKeptEntryId = findFirstKeptEntrySummaryId(params.context.sessionManager.getActiveContextSummaries());
77080
77459
  if (!firstKeptEntryId) {
77081
77460
  return { aborted: true };
77082
77461
  }
@@ -77638,11 +78017,11 @@ var HierarchicalSelectorComponent = class extends Container {
77638
78017
  // src/runtime/interactive-ui-helpers.ts
77639
78018
  function showHierarchicalMenu(host, initialPath = []) {
77640
78019
  const basePath = [...initialPath];
77641
- const showAtPath = (path33) => {
78020
+ const showAtPath = (path34) => {
77642
78021
  host.showSelector((done) => {
77643
78022
  const selector = new HierarchicalSelectorComponent({
77644
78023
  tree: commandTree,
77645
- path: path33,
78024
+ path: path34,
77646
78025
  basePath,
77647
78026
  onNavigate: (newPath) => {
77648
78027
  done();
@@ -77650,7 +78029,7 @@ function showHierarchicalMenu(host, initialPath = []) {
77650
78029
  },
77651
78030
  onSelect: async (selectedPath, node, searchArgs) => {
77652
78031
  if (node.handler) {
77653
- const args = searchArgs || (selectedPath.length > path33.length ? selectedPath.slice(path33.length).join(" ") : void 0);
78032
+ const args = searchArgs || (selectedPath.length > path34.length ? selectedPath.slice(path34.length).join(" ") : void 0);
77654
78033
  const commandPath = "/" + selectedPath.join("/");
77655
78034
  if (!args && host.isInteractiveCommand(commandPath)) {
77656
78035
  done();
@@ -77904,6 +78283,18 @@ async function prepareAgentTurn(host, context) {
77904
78283
  };
77905
78284
  }
77906
78285
  function createInteractiveAgentSessionController(host) {
78286
+ try {
78287
+ recoverInterruptedPublishes({
78288
+ sessionsDir: getSessionsDir(),
78289
+ warn: (message) => {
78290
+ console.warn(message);
78291
+ if (typeof host.appendWarningSummary === "function") {
78292
+ host.appendWarningSummary(message);
78293
+ }
78294
+ }
78295
+ });
78296
+ } catch {
78297
+ }
77907
78298
  let retryElapsedTicker;
77908
78299
  let retryElapsedStartedAt = 0;
77909
78300
  const stopRetryElapsedTicker = () => {
@@ -77963,8 +78354,7 @@ function createInteractiveAgentSessionController(host) {
77963
78354
  return { aborted: true };
77964
78355
  }
77965
78356
  if (beforeCompact?.summary) {
77966
- const activeEntryId = context.sessionManager.getActiveEntryId();
77967
- const firstKeptEntryId = activeEntryId ? findFirstKeptEntryId(context.sessionManager.getPathToEntry(activeEntryId)) : void 0;
78357
+ const firstKeptEntryId = findFirstKeptEntrySummaryId(context.sessionManager.getActiveContextSummaries());
77968
78358
  if (!firstKeptEntryId) return { aborted: true };
77969
78359
  return { summary: beforeCompact.summary, firstKeptEntryId };
77970
78360
  }
@@ -78138,6 +78528,14 @@ function createInteractiveAgentSessionController(host) {
78138
78528
  return;
78139
78529
  }
78140
78530
  host.resetFileObservationState();
78531
+ if (!event.result?.aborted) {
78532
+ host.streamingComponent = void 0;
78533
+ host.pendingTools.clear();
78534
+ host.chatContainer.clear();
78535
+ host.lastStatusSpacer = void 0;
78536
+ host.lastStatusText = void 0;
78537
+ host.renderMessageHistory(host.sessionManager.getMessages());
78538
+ }
78141
78539
  const contextUsage = host.calculateContextUsage();
78142
78540
  const contextWindow = host.options.model?.contextWindow ?? 0;
78143
78541
  const contextPercent = contextWindow > 0 && contextUsage.tokens !== null ? contextUsage.tokens / contextWindow * 100 : 0;
@@ -79093,8 +79491,8 @@ async function loadInteractiveExtensions(host) {
79093
79491
  host.extensionRunner.setUIContext(host.extensionUIContext);
79094
79492
  await restoreExtensionProviderCredentials(host.options.modelRegistry);
79095
79493
  if (process.env.PIE_VERBOSE) {
79096
- for (const { path: path33, error } of errors) {
79097
- console.error(`[Extension] Failed to load ${path33}: ${error}`);
79494
+ for (const { path: path34, error } of errors) {
79495
+ console.error(`[Extension] Failed to load ${path34}: ${error}`);
79098
79496
  }
79099
79497
  }
79100
79498
  const extensionTools = filterEnabledTools(convertExtensionTools(extensions), host.options.settingsManager);
@@ -79464,8 +79862,8 @@ var InteractiveMode = class {
79464
79862
  waitForAgentIdle() {
79465
79863
  return this.agentSessionController.waitForIdle();
79466
79864
  }
79467
- replaceAgentMessagesAndMarkSynced(messages, options) {
79468
- this.agentSessionController.replaceMessagesAndMarkSynced(messages, options);
79865
+ replaceAgentMessagesAndMarkSynced(messages) {
79866
+ this.agentSessionController.replaceMessagesAndMarkSynced(messages);
79469
79867
  this.lastSyncedMessageCount = this.agentSessionController.syncedMessageCount;
79470
79868
  }
79471
79869
  syncAgentFromActiveSession(messages) {
@@ -79493,7 +79891,7 @@ var InteractiveMode = class {
79493
79891
  async init() {
79494
79892
  const activeSession = this.sessionManager.getActiveSession();
79495
79893
  this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
79496
- const { Agent } = await import("./chunks/src-QSP2OPHU.js");
79894
+ const { Agent } = await import("./chunks/src-SXUQ7OY6.js");
79497
79895
  this.agent = new Agent({
79498
79896
  initialState: {
79499
79897
  systemPrompt: this.buildSystemPrompt(),
@@ -79603,9 +80001,9 @@ var InteractiveMode = class {
79603
80001
  if (this.isProcessing) {
79604
80002
  throw new Error("Cannot reload while a response is being processed. Wait for the turn to finish or abort it first.");
79605
80003
  }
79606
- const builtinDir = path29.join(getBuiltinDir(), "skills");
79607
- const userDir = path29.join(os8.homedir(), ".pie", "skills");
79608
- const projectDir = path29.join(this.options.cwd, ".pie", "skills");
80004
+ const builtinDir = path30.join(getBuiltinDir(), "skills");
80005
+ const userDir = path30.join(os8.homedir(), ".pie", "skills");
80006
+ const projectDir = path30.join(this.options.cwd, ".pie", "skills");
79609
80007
  const { skills, diagnostics } = loadSkills({
79610
80008
  dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: this.options.cwd })
79611
80009
  });
@@ -79767,7 +80165,7 @@ var InteractiveMode = class {
79767
80165
  return handleResumeCommand(this);
79768
80166
  }
79769
80167
  async loadSession(sessionId) {
79770
- return loadSession2(this, sessionId);
80168
+ return loadSession(this, sessionId);
79771
80169
  }
79772
80170
  updateTerminalTitle() {
79773
80171
  return updateTerminalTitle(this);
@@ -79908,8 +80306,8 @@ var InteractiveMode = class {
79908
80306
  };
79909
80307
 
79910
80308
  // src/app/runtime-composition.ts
79911
- import { existsSync as existsSync18, mkdirSync as mkdirSync13 } from "fs";
79912
- import * as path30 from "path";
80309
+ import { existsSync as existsSync19, mkdirSync as mkdirSync14 } from "fs";
80310
+ import * as path31 from "path";
79913
80311
  var CliMissingApiKeyError = class extends Error {
79914
80312
  constructor(message) {
79915
80313
  super(message);
@@ -79930,13 +80328,13 @@ var CliSessionResumeError = class extends Error {
79930
80328
  function getCliRuntimePaths() {
79931
80329
  const configDir = getConfigDir();
79932
80330
  const sessionsDir = getSessionsDir();
79933
- const skillsDir = path30.join(configDir, "skills");
79934
- const builtinSkillsDir = path30.join(getBuiltinDir(), "skills");
80331
+ const skillsDir = path31.join(configDir, "skills");
80332
+ const builtinSkillsDir = path31.join(getBuiltinDir(), "skills");
79935
80333
  return { configDir, sessionsDir, skillsDir, builtinSkillsDir };
79936
80334
  }
79937
80335
  function ensureCliRuntimePaths(paths = getCliRuntimePaths()) {
79938
- if (!existsSync18(paths.skillsDir)) {
79939
- mkdirSync13(paths.skillsDir, { recursive: true });
80336
+ if (!existsSync19(paths.skillsDir)) {
80337
+ mkdirSync14(paths.skillsDir, { recursive: true });
79940
80338
  }
79941
80339
  return paths;
79942
80340
  }
@@ -80051,7 +80449,7 @@ async function composeCliRuntime(params) {
80051
80449
  fileLogger.log("cli", `Using API key for provider ${provider}`, {
80052
80450
  keyPrefix: apiKey ? maskApiKey2(apiKey) : "none"
80053
80451
  });
80054
- const projectSkillsDir = path30.join(cwd, ".pie", "skills");
80452
+ const projectSkillsDir = path31.join(cwd, ".pie", "skills");
80055
80453
  const { skills: discoveredSkills, diagnostics } = loadSkills({
80056
80454
  dirs: buildSkillDirs({
80057
80455
  builtinDir: paths.builtinSkillsDir,
@@ -80326,7 +80724,7 @@ async function runPrintMode(params) {
80326
80724
  `);
80327
80725
  console.log("Assistant: ");
80328
80726
  }
80329
- const { Agent: AgentClass } = await import("./chunks/src-QSP2OPHU.js");
80727
+ const { Agent: AgentClass } = await import("./chunks/src-SXUQ7OY6.js");
80330
80728
  let agent;
80331
80729
  const printModeExtensions = await loadPrintModeExtensions({
80332
80730
  cwd: runtime.cwd,
@@ -80414,7 +80812,7 @@ async function runPrintMode(params) {
80414
80812
  if (beforeCompact.cancel) return { aborted: true };
80415
80813
  if (beforeCompact.summary) {
80416
80814
  const activeEntryId = context.sessionManager.getActiveEntryId();
80417
- const firstKeptEntryId = activeEntryId ? findFirstKeptEntryId(context.sessionManager.getPathToEntry(activeEntryId)) : void 0;
80815
+ const firstKeptEntryId = activeEntryId ? findFirstKeptEntrySummaryId(context.sessionManager.getActiveContextSummaries()) : void 0;
80418
80816
  if (!firstKeptEntryId) return { aborted: true };
80419
80817
  return { summary: beforeCompact.summary, firstKeptEntryId };
80420
80818
  }
@@ -80804,6 +81202,7 @@ async function runJsonEventsMode(params) {
80804
81202
  let thinkingLevelInitialized = false;
80805
81203
  let defaultRuntime;
80806
81204
  let defaultModelState;
81205
+ let publishRecoveryDone = false;
80807
81206
  const completedSessionControlRequests = /* @__PURE__ */ new Map();
80808
81207
  const completedSidechatRequests = /* @__PURE__ */ new Map();
80809
81208
  const ensureRuntimeInFlight = /* @__PURE__ */ new Map();
@@ -80893,12 +81292,22 @@ async function runJsonEventsMode(params) {
80893
81292
  metadata.rootEntryId = existing?.rootEntryId ?? rootEntryId;
80894
81293
  return metadata;
80895
81294
  }
80896
- async function persistMockTurn(message, assistantText) {
81295
+ function persistMockTurn(message, assistantText) {
80897
81296
  const store = new FileSessionStore(getSessionsDir());
80898
- const existing = await store.load(message.sessionId ?? sessionId);
81297
+ const targetSessionId = message.sessionId ?? sessionId;
81298
+ const status = store.headStatus(targetSessionId);
81299
+ if (status === "legacy") {
81300
+ throw new SessionControlError("session_unsupported_format", `Session uses an unsupported old format: ${targetSessionId}`);
81301
+ }
81302
+ if (status === "corrupt") {
81303
+ throw new SessionControlError("session_unrecoverable", `Session could not be recovered: ${targetSessionId}`);
81304
+ }
81305
+ const existing = store.readHead(targetSessionId);
81306
+ if (existing) store.createHead(targetSessionId, { name: void 0, createdAt: existing.metadata.createdAt });
80899
81307
  const startedAt = activeTurn?.startedAt ?? Date.now();
80900
- const userEntryId = generateEntryId();
80901
- const assistantEntryId = generateEntryId();
81308
+ const baseSeq = existing?.committedSeq ?? store.readHead(targetSessionId)?.committedSeq ?? 0;
81309
+ const userEntryId = generateEntryId(baseSeq + 1);
81310
+ const assistantEntryId = generateEntryId(baseSeq + 2);
80902
81311
  const parentId = existing?.metadata.activeEntryId ?? null;
80903
81312
  const userEntry = {
80904
81313
  id: userEntryId,
@@ -80936,10 +81345,13 @@ async function runJsonEventsMode(params) {
80936
81345
  timestamp: assistantTimestamp,
80937
81346
  message: assistantMessage
80938
81347
  };
80939
- const entries = [...existing?.entries ?? [], userEntry, assistantEntry];
80940
- await store.save(
80941
- message.sessionId ?? sessionId,
80942
- entries,
81348
+ if (!existing) {
81349
+ store.createHead(targetSessionId);
81350
+ }
81351
+ store.appendEntries(
81352
+ targetSessionId,
81353
+ [userEntry, assistantEntry],
81354
+ assistantEntryId,
80943
81355
  persistedMockMetadata(existing?.metadata, assistantEntryId, existing?.metadata.rootEntryId ?? userEntryId, message.cwd)
80944
81356
  );
80945
81357
  return assistantEntryId;
@@ -80962,7 +81374,7 @@ async function runJsonEventsMode(params) {
80962
81374
  };
80963
81375
  }
80964
81376
  function errorToFailureDetail(error) {
80965
- if (error instanceof CliSessionResumeError) {
81377
+ if (error instanceof CliSessionResumeError || error instanceof SessionControlError) {
80966
81378
  return {
80967
81379
  message: error.message,
80968
81380
  code: error.code,
@@ -80972,7 +81384,10 @@ async function runJsonEventsMode(params) {
80972
81384
  return error instanceof Error ? error.message : String(error);
80973
81385
  }
80974
81386
  function sessionControlStore() {
80975
- return new FileSessionStore(runtime?.paths.sessionsDir ?? getSessionsDir());
81387
+ return new FileSessionStore(sessionControlSessionsDir());
81388
+ }
81389
+ function sessionControlSessionsDir() {
81390
+ return runtime?.paths.sessionsDir ?? getSessionsDir();
80976
81391
  }
80977
81392
  function invalidSessionControl(message) {
80978
81393
  return new SessionControlError("invalid_request", message);
@@ -81081,6 +81496,7 @@ async function runJsonEventsMode(params) {
81081
81496
  await saveRuntimeSessionForControl();
81082
81497
  const result = await forkStoredSession({
81083
81498
  store: sessionControlStore(),
81499
+ sessionsDir: sessionControlSessionsDir(),
81084
81500
  sourceSessionId: controlSessionId,
81085
81501
  sourceEntryId,
81086
81502
  targetSessionId,
@@ -81168,7 +81584,7 @@ async function runJsonEventsMode(params) {
81168
81584
  return;
81169
81585
  }
81170
81586
  const parent = agent;
81171
- const { Agent: AgentClass } = await import("./chunks/src-QSP2OPHU.js");
81587
+ const { Agent: AgentClass } = await import("./chunks/src-SXUQ7OY6.js");
81172
81588
  const sideAgent = new AgentClass({
81173
81589
  initialState: {
81174
81590
  systemPrompt: parent.state.systemPrompt,
@@ -81495,6 +81911,16 @@ async function runJsonEventsMode(params) {
81495
81911
  if (!runtime) {
81496
81912
  throw new Error("JSON events mode requires a CLI runtime");
81497
81913
  }
81914
+ if (!publishRecoveryDone) {
81915
+ publishRecoveryDone = true;
81916
+ try {
81917
+ recoverInterruptedPublishes({
81918
+ sessionsDir: runtime.paths.sessionsDir ?? getSessionsDir(),
81919
+ warn: (message) => console.warn(message)
81920
+ });
81921
+ } catch {
81922
+ }
81923
+ }
81498
81924
  if (defaultRuntime !== runtime) {
81499
81925
  defaultRuntime = runtime;
81500
81926
  defaultModelState = configuredDefaultModelState(runtime);
@@ -81502,7 +81928,7 @@ async function runJsonEventsMode(params) {
81502
81928
  if (runtime.initialModel.unconfigured || controller) {
81503
81929
  return;
81504
81930
  }
81505
- const { Agent: AgentClass } = await import("./chunks/src-QSP2OPHU.js");
81931
+ const { Agent: AgentClass } = await import("./chunks/src-SXUQ7OY6.js");
81506
81932
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
81507
81933
  extensionRunner = jsonModeExtensions.runner;
81508
81934
  const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
@@ -81695,9 +82121,9 @@ async function runJsonEventsMode(params) {
81695
82121
  }
81696
82122
  display(params.mockResponse);
81697
82123
  try {
81698
- mockActiveEntryId = await persistMockTurn(message, params.mockResponse);
82124
+ mockActiveEntryId = persistMockTurn(message, params.mockResponse);
81699
82125
  } catch (error) {
81700
- finalize("failed", error instanceof Error ? error.message : String(error));
82126
+ finalize("failed", errorToFailureDetail(error));
81701
82127
  if (activeTurn === turn) emitSettled(turn);
81702
82128
  if (activeTurn === turn) activeTurn = null;
81703
82129
  return;
@@ -81965,19 +82391,19 @@ async function runJsonEventsMode(params) {
81965
82391
  }
81966
82392
 
81967
82393
  // src/developer-instructions.ts
81968
- import * as fs27 from "fs";
81969
- import * as path31 from "path";
82394
+ import * as fs28 from "fs";
82395
+ import * as path32 from "path";
81970
82396
  var MAX_DEVELOPER_INSTRUCTIONS_CHARS = 64e3;
81971
82397
  function readTextFileBounded(filePath) {
81972
- const resolved = path31.resolve(filePath);
81973
- const stat2 = fs27.statSync(resolved);
82398
+ const resolved = path32.resolve(filePath);
82399
+ const stat2 = fs28.statSync(resolved);
81974
82400
  if (!stat2.isFile()) {
81975
82401
  throw new Error(`Developer instructions file is not a regular file: ${filePath}`);
81976
82402
  }
81977
82403
  if (stat2.size > MAX_DEVELOPER_INSTRUCTIONS_CHARS * 4) {
81978
82404
  throw new Error(`Developer instructions file is too large: ${filePath}`);
81979
82405
  }
81980
- return fs27.readFileSync(resolved, "utf8");
82406
+ return fs28.readFileSync(resolved, "utf8");
81981
82407
  }
81982
82408
  function collectFlagValues(args, flag) {
81983
82409
  const values = [];
@@ -82056,8 +82482,8 @@ var logError = (msg, err) => {
82056
82482
  const logPath = getRuntimeLogPath();
82057
82483
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
82058
82484
  const stack = err instanceof Error ? err.stack || "" : "";
82059
- fs28.mkdirSync(path32.dirname(logPath), { recursive: true });
82060
- fs28.appendFileSync(logPath, `[${timestamp}] ${msg}
82485
+ fs29.mkdirSync(path33.dirname(logPath), { recursive: true });
82486
+ fs29.appendFileSync(logPath, `[${timestamp}] ${msg}
82061
82487
  ${stack}
82062
82488
 
82063
82489
  `);
@@ -82091,7 +82517,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
82091
82517
  }
82092
82518
  async function createCliTestStreamFnFromEnv() {
82093
82519
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
82094
- return (await import("./chunks/test-stream-CVGWFLSX.js")).createTestStreamFnFromSequenceEnv();
82520
+ return (await import("./chunks/test-stream-OD3B57AS.js")).createTestStreamFnFromSequenceEnv();
82095
82521
  }
82096
82522
  function resolveJsonEventsDetailFlag() {
82097
82523
  for (let index = 0; index < process.argv.length; index += 1) {