@cydm/pie 2.3.0 → 2.5.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 +5 -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-JXY3YLDS.js} +8247 -7345
  19. package/dist/chunks/{chunk-P3QPJXS7.js → chunk-PU7IIEKH.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 +1350 -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-PU7IIEKH.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-JXY3YLDS.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"]);
@@ -53356,6 +53356,46 @@ var ModelRegistry = class {
53356
53356
  }
53357
53357
  return { model, apiKey };
53358
53358
  }
53359
+ /** Resolve an explicit model reference for user-requested overrides.
53360
+ * Accepts "provider/model-id" (exact lookup) or a bare model id (only
53361
+ * when it matches exactly one configured model). Never guesses across
53362
+ * providers; ambiguity and missing keys are reported as fallback reasons. */
53363
+ resolveModelRef(ref) {
53364
+ const trimmed = ref.trim();
53365
+ if (!trimmed) {
53366
+ return { fallbackReason: "empty model reference" };
53367
+ }
53368
+ const separator = trimmed.indexOf("/");
53369
+ if (separator >= 0) {
53370
+ if (separator === 0 || separator === trimmed.length - 1) {
53371
+ return { fallbackReason: `invalid model reference "${trimmed}"; expected provider/model-id` };
53372
+ }
53373
+ const provider = trimmed.slice(0, separator);
53374
+ const modelId = trimmed.slice(separator + 1);
53375
+ const model2 = this.find(provider, modelId);
53376
+ if (!model2) {
53377
+ return { fallbackReason: `model "${trimmed}" is not configured` };
53378
+ }
53379
+ const apiKey2 = this.getApiKey(model2);
53380
+ if (!apiKey2) {
53381
+ return { model: model2, fallbackReason: `no API key available for model "${trimmed}"` };
53382
+ }
53383
+ return { model: model2, apiKey: apiKey2 };
53384
+ }
53385
+ const matches = this.getAll().filter((model2) => model2.id === trimmed);
53386
+ if (matches.length === 0) {
53387
+ return { fallbackReason: `model "${trimmed}" is not configured; use provider/model-id` };
53388
+ }
53389
+ if (matches.length > 1) {
53390
+ return { fallbackReason: `model "${trimmed}" is ambiguous across providers (${matches.map((model2) => `${model2.provider}/${model2.id}`).join(", ")}); use provider/model-id` };
53391
+ }
53392
+ const model = matches[0];
53393
+ const apiKey = this.getApiKey(model);
53394
+ if (!apiKey) {
53395
+ return { model, fallbackReason: `no API key available for model "${model.provider}/${model.id}"` };
53396
+ }
53397
+ return { model, apiKey };
53398
+ }
53359
53399
  hasExternalProviderConfig() {
53360
53400
  return this.usingExternalProviders;
53361
53401
  }
@@ -55129,9 +55169,11 @@ function runCapabilitiesCommand(args) {
55129
55169
  }
55130
55170
 
55131
55171
  // src/commands/sessions.ts
55132
- import fs7 from "node:fs";
55172
+ import fs8 from "node:fs";
55133
55173
 
55134
55174
  // src/session-control.ts
55175
+ import * as fs7 from "node:fs";
55176
+ import * as path7 from "node:path";
55135
55177
  var SessionControlError = class extends Error {
55136
55178
  constructor(code, message, recoverable = sessionControlErrorRecoverable(code)) {
55137
55179
  super(message);
@@ -55145,27 +55187,70 @@ var SessionControlError = class extends Error {
55145
55187
  function sessionControlErrorRecoverable(code) {
55146
55188
  return code !== "session_unrecoverable" && code !== "session_mismatch";
55147
55189
  }
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
- );
55190
+ var FORK_BATCH_ENTRIES = 64;
55191
+ var FORK_BATCH_BYTES = 256 * 1024;
55192
+ var STAGING_SESSION_ID_PREFIX = "__pie-staging-";
55193
+ function stagingIdFor(targetSessionId) {
55194
+ return `${STAGING_SESSION_ID_PREFIX}${targetSessionId}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
55156
55195
  }
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}`);
55196
+ var PUBLISH_JOURNAL_DIR = ".pie-publish-journal";
55197
+ function safeSessionDirName(sessionId) {
55198
+ return sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
55199
+ }
55200
+ function canonicalSessionDir(sessionsDir, sessionId) {
55201
+ const dir = path7.join(sessionsDir, safeSessionDirName(sessionId));
55202
+ try {
55203
+ if (!fs7.existsSync(dir)) return null;
55204
+ return fs7.realpathSync(dir);
55205
+ } catch {
55206
+ return null;
55207
+ }
55208
+ }
55209
+ function publishJournalPath(sessionsDir, safeTargetId) {
55210
+ return path7.join(sessionsDir, PUBLISH_JOURNAL_DIR, `${safeTargetId}.json`);
55211
+ }
55212
+ function writePublishJournal(journalPath, record) {
55213
+ fs7.mkdirSync(path7.dirname(journalPath), { recursive: true });
55214
+ const tempPath = `${journalPath}.tmp`;
55215
+ fs7.writeFileSync(tempPath, JSON.stringify(record, void 0, " "));
55216
+ fs7.renameSync(tempPath, journalPath);
55217
+ }
55218
+ function clearPublishJournal(journalPath) {
55219
+ if (!journalPath) return;
55220
+ try {
55221
+ fs7.rmSync(journalPath, { force: true });
55222
+ } catch {
55223
+ }
55224
+ }
55225
+ function toIoError(error) {
55226
+ if (error instanceof SessionControlError) return error;
55227
+ return new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
55228
+ }
55229
+ function loadRequiredSessionHead(store, sessionId) {
55230
+ const status = store.headStatus(sessionId);
55231
+ if (status === "legacy") {
55232
+ throw new SessionControlError(
55233
+ "session_unsupported_format",
55234
+ `Session uses an unsupported old format: ${sessionId}`
55235
+ );
55236
+ }
55237
+ if (status === "corrupt") {
55238
+ throw new SessionControlError("session_unrecoverable", `Session could not be recovered: ${sessionId}`);
55239
+ }
55240
+ const head = store.readHead(sessionId);
55241
+ if (!head) {
55242
+ throw new SessionControlError("session_not_found", `Session not found: ${sessionId}`);
55161
55243
  }
55244
+ return head;
55245
+ }
55246
+ async function rewindStoredSession(params) {
55162
55247
  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);
55248
+ loadRequiredSessionHead(params.store, params.sessionId);
55249
+ if (params.store.getEntrySummary(params.sessionId, params.entryId) === null) {
55250
+ throw new SessionControlError("entry_not_found", `Entry not found: ${params.entryId}`);
55251
+ }
55252
+ params.store.setActiveEntry(params.sessionId, params.entryId);
55253
+ const metadata = params.store.getMetadata(params.sessionId);
55169
55254
  if (!metadata) {
55170
55255
  throw new SessionControlError("session_unrecoverable", `Session could not be recovered after rewind: ${params.sessionId}`, false);
55171
55256
  }
@@ -55176,52 +55261,179 @@ async function rewindStoredSession(params) {
55176
55261
  metadata
55177
55262
  };
55178
55263
  } catch (error) {
55179
- if (error instanceof SessionControlError) throw error;
55180
- throw new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
55264
+ throw toIoError(error);
55181
55265
  }
55182
55266
  }
55183
55267
  async function forkStoredSession(params) {
55268
+ let stagingId;
55184
55269
  try {
55270
+ const sanitizedTargetId = params.targetSessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
55271
+ if (sanitizedTargetId.startsWith(STAGING_SESSION_ID_PREFIX)) {
55272
+ throw new SessionControlError(
55273
+ "invalid_request",
55274
+ `Target session id starts with a reserved internal prefix: ${params.targetSessionId}`
55275
+ );
55276
+ }
55277
+ if (params.sourceSessionId.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase() === sanitizedTargetId.toLowerCase()) {
55278
+ throw new SessionControlError(
55279
+ "invalid_request",
55280
+ "Fork source and target must be different sessions: " + params.sourceSessionId
55281
+ );
55282
+ }
55283
+ if (params.sessionsDir) {
55284
+ const canonicalSourceDir = canonicalSessionDir(params.sessionsDir, params.sourceSessionId);
55285
+ const canonicalTargetDir = canonicalSessionDir(params.sessionsDir, params.targetSessionId);
55286
+ if (canonicalSourceDir !== null && canonicalTargetDir !== null && canonicalSourceDir === canonicalTargetDir) {
55287
+ throw new SessionControlError(
55288
+ "invalid_request",
55289
+ `Fork source and target resolve to the same session directory: ${params.sourceSessionId} -> ${params.targetSessionId}`
55290
+ );
55291
+ }
55292
+ }
55185
55293
  if (!params.force) {
55186
55294
  const existingTarget = await maybeLoadExistingForkTarget(params);
55187
55295
  if (existingTarget) return existingTarget;
55188
55296
  }
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) {
55297
+ const source = loadRequiredSessionHead(params.store, params.sourceSessionId);
55298
+ const pathSummaries = params.store.getPathSummaries(params.sourceSessionId, params.sourceEntryId);
55299
+ if (pathSummaries.length === 0 || pathSummaries[pathSummaries.length - 1]?.id !== params.sourceEntryId) {
55192
55300
  throw new SessionControlError("entry_not_found", `Entry not found: ${params.sourceEntryId}`);
55193
55301
  }
55194
55302
  const now = params.now ?? Date.now();
55303
+ stagingId = stagingIdFor(params.targetSessionId);
55304
+ params.store.createHead(stagingId, {
55305
+ name: params.name,
55306
+ createdAt: now
55307
+ });
55195
55308
  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,
55309
+ let seq = 1;
55310
+ let batch = [];
55311
+ let batchBytes = 0;
55312
+ let lastCopiedId = null;
55313
+ let firstCopiedId = null;
55314
+ const flushBatch = () => {
55315
+ if (batch.length === 0) return;
55316
+ params.store.appendEntries(stagingId, batch, null);
55317
+ batch = [];
55318
+ batchBytes = 0;
55319
+ };
55320
+ for (const summary of pathSummaries) {
55321
+ let entry = null;
55322
+ try {
55323
+ entry = params.store.readEntry(params.sourceSessionId, summary.id);
55324
+ } catch {
55325
+ entry = null;
55326
+ }
55327
+ if (!entry) {
55328
+ throw new SessionControlError(
55329
+ "session_unrecoverable",
55330
+ `Fork source entry is not readable: ${summary.id}`,
55331
+ false
55332
+ );
55333
+ }
55334
+ const copy = {
55335
+ ...entry,
55336
+ id: generateEntryId(seq),
55337
+ parentId: lastCopiedId,
55205
55338
  timestamp: entry.timestamp
55206
55339
  };
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}`);
55340
+ if (copy.compactionData) {
55341
+ const keptId = idMap.get(copy.compactionData.firstKeptEntryId);
55342
+ copy.compactionData = {
55343
+ ...copy.compactionData,
55344
+ firstKeptEntryId: keptId ?? firstCopiedId ?? copy.id
55345
+ };
55346
+ }
55347
+ idMap.set(summary.id, copy.id);
55348
+ if (firstCopiedId === null) {
55349
+ firstCopiedId = copy.id;
55350
+ }
55351
+ const copyBytes = Buffer.byteLength(JSON.stringify(copy), "utf8");
55352
+ if (batch.length > 0 && batchBytes + copyBytes > FORK_BATCH_BYTES) flushBatch();
55353
+ batch.push(copy);
55354
+ batchBytes += copyBytes;
55355
+ lastCopiedId = copy.id;
55356
+ seq += 1;
55357
+ if (batch.length >= FORK_BATCH_ENTRIES || batchBytes >= FORK_BATCH_BYTES) {
55358
+ flushBatch();
55359
+ }
55360
+ }
55361
+ flushBatch();
55362
+ if (!lastCopiedId) {
55363
+ throw new SessionControlError("session_unrecoverable", `Fork source has no readable entries: ${params.sourceSessionId}`, false);
55211
55364
  }
55212
- await params.store.save(params.targetSessionId, forkedEntries, {
55365
+ params.store.setActiveEntry(stagingId, lastCopiedId);
55366
+ params.store.updateMetadata(stagingId, {
55213
55367
  name: params.name,
55214
55368
  createdAt: now,
55215
- updatedAt: now,
55216
- activeEntryId,
55217
55369
  cwd: params.cwd ?? source.metadata.cwd,
55218
55370
  sourceSessionId: params.sourceSessionId,
55219
55371
  sourceEntryId: params.sourceEntryId,
55220
55372
  sourceActiveEntryId: source.metadata.activeEntryId ?? void 0,
55221
- forkBaseEntryId: activeEntryId,
55373
+ forkBaseEntryId: lastCopiedId,
55222
55374
  ...params.requestId ? { sessionControlRequestId: params.requestId } : {}
55223
55375
  });
55224
- const metadata = await params.store.getMetadata(params.targetSessionId);
55376
+ const backupId = `${params.targetSessionId}-previous-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
55377
+ const targetStatus = params.store.headStatus(params.targetSessionId);
55378
+ if (targetStatus === "legacy" || targetStatus === "corrupt") {
55379
+ loadRequiredSessionHead(params.store, params.targetSessionId);
55380
+ }
55381
+ const hadPreviousTarget = targetStatus === "ok";
55382
+ if (hadPreviousTarget && !params.force) {
55383
+ throw new SessionControlError("target_exists", `Target session already exists: ${params.targetSessionId}`);
55384
+ }
55385
+ const safeTargetId = safeSessionDirName(params.targetSessionId);
55386
+ const journalPath = params.sessionsDir ? publishJournalPath(params.sessionsDir, safeTargetId) : null;
55387
+ if (journalPath) {
55388
+ writePublishJournal(journalPath, {
55389
+ v: 1,
55390
+ targetId: safeTargetId,
55391
+ stagingId: safeSessionDirName(stagingId),
55392
+ backupDir: hadPreviousTarget ? safeSessionDirName(backupId) : null,
55393
+ writtenAt: Date.now()
55394
+ });
55395
+ }
55396
+ if (hadPreviousTarget) {
55397
+ try {
55398
+ params.store.moveSession(params.targetSessionId, backupId);
55399
+ } catch (error) {
55400
+ clearPublishJournal(journalPath);
55401
+ throw error;
55402
+ }
55403
+ }
55404
+ try {
55405
+ params.store.moveSession(stagingId, params.targetSessionId);
55406
+ } catch (error) {
55407
+ if (hadPreviousTarget) {
55408
+ try {
55409
+ if (params.store.headStatus(params.targetSessionId) !== "missing") {
55410
+ throw new Error("target path is occupied");
55411
+ }
55412
+ params.store.moveSession(backupId, params.targetSessionId);
55413
+ clearPublishJournal(journalPath);
55414
+ } catch (restoreError) {
55415
+ throw new SessionControlError(
55416
+ "session_io_error",
55417
+ `Fork publication failed; previous session is preserved as ${backupId}. Restore failed: ${String(restoreError)}`,
55418
+ false
55419
+ );
55420
+ }
55421
+ }
55422
+ clearPublishJournal(journalPath);
55423
+ throw error;
55424
+ }
55425
+ let backupDeleted = !hadPreviousTarget;
55426
+ if (hadPreviousTarget) {
55427
+ try {
55428
+ params.store.delete(backupId);
55429
+ backupDeleted = true;
55430
+ } catch {
55431
+ }
55432
+ }
55433
+ if (backupDeleted) {
55434
+ clearPublishJournal(journalPath);
55435
+ }
55436
+ const metadata = params.store.getMetadata(params.targetSessionId);
55225
55437
  if (!metadata) {
55226
55438
  throw new SessionControlError("session_unrecoverable", `Session could not be recovered after fork: ${params.targetSessionId}`, false);
55227
55439
  }
@@ -55232,13 +55444,23 @@ async function forkStoredSession(params) {
55232
55444
  sourceActiveEntryId: source.metadata.activeEntryId ?? null
55233
55445
  });
55234
55446
  } catch (error) {
55235
- if (error instanceof SessionControlError) throw error;
55236
- throw new SessionControlError("session_io_error", error instanceof Error ? error.message : String(error));
55447
+ throw toIoError(error);
55448
+ } finally {
55449
+ if (stagingId) {
55450
+ try {
55451
+ params.store.delete(stagingId);
55452
+ } catch {
55453
+ }
55454
+ }
55237
55455
  }
55238
55456
  }
55239
55457
  async function maybeLoadExistingForkTarget(params) {
55240
- if (!await params.store.exists(params.targetSessionId)) return null;
55241
- const target = await params.store.load(params.targetSessionId);
55458
+ const status = params.store.headStatus(params.targetSessionId);
55459
+ if (status === "missing") return null;
55460
+ if (status === "legacy") {
55461
+ throw new SessionControlError("session_unsupported_format", `Target session uses an unsupported old format: ${params.targetSessionId}`);
55462
+ }
55463
+ const target = params.store.readHead(params.targetSessionId);
55242
55464
  if (!target) {
55243
55465
  throw new SessionControlError("session_unrecoverable", `Session could not be recovered: ${params.targetSessionId}`, false);
55244
55466
  }
@@ -55269,20 +55491,93 @@ function buildForkResult(params) {
55269
55491
  metadata: params.metadata
55270
55492
  };
55271
55493
  }
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;
55494
+ function recoverInterruptedPublishes(params) {
55495
+ const outcomes = [];
55496
+ const journalDir = path7.join(params.sessionsDir, PUBLISH_JOURNAL_DIR);
55497
+ let entries;
55498
+ try {
55499
+ entries = fs7.readdirSync(journalDir);
55500
+ } catch {
55501
+ return outcomes;
55502
+ }
55503
+ for (const entry of entries) {
55504
+ if (!entry.endsWith(".json")) continue;
55505
+ outcomes.push(recoverOnePublishJournal({
55506
+ sessionsDir: params.sessionsDir,
55507
+ journalPath: path7.join(journalDir, entry),
55508
+ warn: params.warn
55509
+ }));
55281
55510
  }
55282
- return path33;
55511
+ return outcomes;
55283
55512
  }
55284
- function cloneJson(value) {
55285
- return JSON.parse(JSON.stringify(value));
55513
+ function recoverOnePublishJournal(params) {
55514
+ const journalName = path7.basename(params.journalPath);
55515
+ const warn = (message) => {
55516
+ (params.warn ?? ((text) => console.warn(text)))(message);
55517
+ };
55518
+ let record;
55519
+ try {
55520
+ const parsed = JSON.parse(fs7.readFileSync(params.journalPath, "utf8"));
55521
+ const safeId = /^[a-zA-Z0-9_-]+$/;
55522
+ if (parsed?.v !== 1 || !safeId.test(parsed.targetId ?? "") || !safeId.test(parsed.stagingId ?? "") || !((parsed.backupDir ?? null) === null || safeId.test(parsed.backupDir))) {
55523
+ throw new Error("journal record has unexpected shape");
55524
+ }
55525
+ record = parsed;
55526
+ } catch (error) {
55527
+ const message = `[session-control] Unreadable publish journal ${journalName}; left in place for manual inspection: ${String(error)}`;
55528
+ warn(message);
55529
+ return { action: "unreadable-journal", journal: journalName, message };
55530
+ }
55531
+ const dirExists = (id) => {
55532
+ try {
55533
+ return fs7.statSync(path7.join(params.sessionsDir, id)).isDirectory();
55534
+ } catch {
55535
+ return false;
55536
+ }
55537
+ };
55538
+ const removeSessionDir = (id) => {
55539
+ fs7.rmSync(path7.join(params.sessionsDir, id), { recursive: true, force: true });
55540
+ };
55541
+ const removeJournal = () => {
55542
+ fs7.rmSync(params.journalPath, { force: true });
55543
+ };
55544
+ const targetExists = dirExists(record.targetId);
55545
+ const backupExists = record.backupDir ? dirExists(record.backupDir) : false;
55546
+ const stagingExists = dirExists(record.stagingId);
55547
+ try {
55548
+ if (targetExists && !stagingExists) {
55549
+ if (backupExists && record.backupDir) removeSessionDir(record.backupDir);
55550
+ removeJournal();
55551
+ return { action: "publish-completed", targetId: record.targetId };
55552
+ }
55553
+ if (!targetExists && backupExists && record.backupDir) {
55554
+ fs7.renameSync(
55555
+ path7.join(params.sessionsDir, record.backupDir),
55556
+ path7.join(params.sessionsDir, record.targetId)
55557
+ );
55558
+ removeJournal();
55559
+ if (stagingExists) {
55560
+ try {
55561
+ removeSessionDir(record.stagingId);
55562
+ } catch (error) {
55563
+ warn(`[session-control] Restored ${record.targetId} but could not remove its abandoned staging copy ${record.stagingId}: ${String(error)}`);
55564
+ }
55565
+ }
55566
+ return { action: "restored-previous-target", targetId: record.targetId };
55567
+ }
55568
+ if (!targetExists && !backupExists) {
55569
+ if (stagingExists) removeSessionDir(record.stagingId);
55570
+ removeJournal();
55571
+ return stagingExists ? { action: "discarded-incomplete-fork", targetId: record.targetId } : { action: "nothing-to-recover", targetId: record.targetId };
55572
+ }
55573
+ 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`;
55574
+ warn(message);
55575
+ return { action: "ambiguous-preserved", targetId: record.targetId, message };
55576
+ } catch (error) {
55577
+ const message = `[session-control] Recovery of publish journal ${journalName} failed; state preserved for manual inspection: ${String(error)}`;
55578
+ warn(message);
55579
+ return { action: "ambiguous-preserved", targetId: record.targetId, message };
55580
+ }
55286
55581
  }
55287
55582
 
55288
55583
  // src/commands/sessions.ts
@@ -55339,6 +55634,7 @@ function toSessionCommandError(error, kind) {
55339
55634
  if (error instanceof SessionControlError) {
55340
55635
  const hints = {
55341
55636
  session_not_found: "list sessions: pie sessions list --json",
55637
+ session_unsupported_format: "old-format sessions cannot be read by this version",
55342
55638
  target_exists: "choose a new --target, or add --force to overwrite"
55343
55639
  };
55344
55640
  return new CommandError(kind, error.code, error.message, { hint: hints[error.code] });
@@ -55427,15 +55723,18 @@ async function readSession(parsed) {
55427
55723
  throw new CommandError("sessions.read", "missing_positional", renderCommandUsage(SESSIONS_READ_SPEC), { usage: true });
55428
55724
  }
55429
55725
  const store = new FileSessionStore(getSessionsDir());
55430
- const data = await loadSession(store, sessionId, "sessions.read");
55431
- const events = activeTranscriptEvents(activePathEntries(data));
55726
+ const data = loadSessionHead(store, sessionId, "sessions.read");
55727
+ const events = await activeTranscriptEvents(store, sessionId, data.metadata.activeEntryId);
55432
55728
  const end = resolveBeforeCursor(events, before);
55433
55729
  const start = Math.max(0, end - limit);
55434
55730
  const page = events.slice(start, end);
55731
+ for (const event of page) {
55732
+ hydrateTranscriptEvent(store, sessionId, event);
55733
+ }
55435
55734
  if (!json) {
55436
55735
  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 ?? ""}`);
55736
+ for (const event of page) {
55737
+ console.log(`${event.logicalSeq} ${event.type}${event.role ? `:${event.role}` : ""} ${event.content ?? ""}`);
55439
55738
  }
55440
55739
  return;
55441
55740
  }
@@ -55481,9 +55780,9 @@ async function renameSession(parsed) {
55481
55780
  throw new CommandError("sessions.rename", "missing_positional", renderCommandUsage(SESSIONS_RENAME_SPEC), { usage: true });
55482
55781
  }
55483
55782
  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);
55783
+ loadSessionHead(store, sessionId, "sessions.rename");
55784
+ store.updateMetadata(sessionId, { name, nameSource: "manual", ...cwd ? { cwd } : {}, updatedAt: Date.now() });
55785
+ const updated = store.getMetadata(sessionId);
55487
55786
  if (!updated) throw new CommandError("sessions.rename", "session_not_found", `Session not found after rename: ${sessionId}`);
55488
55787
  if (json) {
55489
55788
  printSuccessEnvelope("sessions.rename", { session: fullSessionRow(updated) });
@@ -55523,6 +55822,7 @@ async function forkSession(parsed) {
55523
55822
  const store = new FileSessionStore(getSessionsDir());
55524
55823
  const result = await forkStoredSession({
55525
55824
  store,
55825
+ sessionsDir: getSessionsDir(),
55526
55826
  sourceSessionId: sessionId,
55527
55827
  sourceEntryId,
55528
55828
  targetSessionId,
@@ -55542,10 +55842,19 @@ async function forkSession(parsed) {
55542
55842
  }
55543
55843
  console.log(`Forked ${sessionId} at ${sourceEntryId} into ${targetSessionId}.`);
55544
55844
  }
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;
55845
+ function loadSessionHead(store, sessionId, kind) {
55846
+ const status = store.headStatus(sessionId);
55847
+ if (status === "legacy") {
55848
+ throw new CommandError(kind, "session_unsupported_format", `Session uses an unsupported old format: ${sessionId}`, {
55849
+ hint: "old-format sessions cannot be read by this version"
55850
+ });
55851
+ }
55852
+ if (status === "corrupt") {
55853
+ throw new CommandError(kind, "session_unrecoverable", `Session could not be recovered: ${sessionId}`);
55854
+ }
55855
+ const head = store.readHead(sessionId);
55856
+ if (!head) throw new CommandError(kind, "session_not_found", `Session not found: ${sessionId}`, { hint: "list sessions: pie sessions list --json" });
55857
+ return { metadata: head.metadata };
55549
55858
  }
55550
55859
  function fullSessionRow(metadata) {
55551
55860
  return {
@@ -55599,31 +55908,30 @@ function cwdMatches(sessionCwd, requestedCwd) {
55599
55908
  }
55600
55909
  function realpathOrInput(value) {
55601
55910
  try {
55602
- return fs7.realpathSync.native(value);
55911
+ return fs8.realpathSync.native(value);
55603
55912
  } catch {
55604
55913
  return value;
55605
55914
  }
55606
55915
  }
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;
55916
+ async function activeTranscriptEvents(store, sessionId, activeEntryId) {
55625
55917
  if (!activeEntryId) return [];
55626
- return pathToEntry(data, activeEntryId);
55918
+ const summaries = store.getPathSummaries(sessionId, activeEntryId);
55919
+ return summaries.map((summary, index) => ({
55920
+ logicalSeq: index + 1,
55921
+ seq: summary.seq,
55922
+ entryId: summary.id,
55923
+ type: summary.type,
55924
+ timestamp: summary.timestamp,
55925
+ role: summary.role,
55926
+ content: summary.preview || void 0
55927
+ }));
55928
+ }
55929
+ function hydrateTranscriptEvent(store, sessionId, event) {
55930
+ const entry = store.readEntry(sessionId, event.entryId);
55931
+ if (!entry) return;
55932
+ event.turnId = isRecord2(entry.message) && typeof entry.message.turnId === "string" ? entry.message.turnId : void 0;
55933
+ event.content = textFromMessage(entry.message);
55934
+ event.message = entry.message ? cloneJson(entry.message) : void 0;
55627
55935
  }
55628
55936
  function resolveBeforeCursor(events, cursor) {
55629
55937
  if (!cursor) return events.length;
@@ -55634,7 +55942,7 @@ function resolveBeforeCursor(events, cursor) {
55634
55942
  const index = events.findIndex((event) => event.entryId === cursor);
55635
55943
  return index >= 0 ? index : events.length;
55636
55944
  }
55637
- function cloneJson2(value) {
55945
+ function cloneJson(value) {
55638
55946
  return JSON.parse(JSON.stringify(value));
55639
55947
  }
55640
55948
  function listCursorQueryKey(input) {
@@ -55671,9 +55979,9 @@ function isRecord2(value) {
55671
55979
  }
55672
55980
 
55673
55981
  // src/extensions/loader.ts
55674
- import * as fs8 from "node:fs";
55982
+ import * as fs9 from "node:fs";
55675
55983
  import * as os2 from "os";
55676
- import * as path7 from "path";
55984
+ import * as path8 from "path";
55677
55985
  import { pathToFileURL } from "node:url";
55678
55986
 
55679
55987
  // src/command-tree.ts
@@ -55686,19 +55994,19 @@ var CommandTree = class {
55686
55994
  * register(["session", "new"], { description, handler })
55687
55995
  * register(["tools", "subagent", "spawn", "local"], { description, handler })
55688
55996
  */
55689
- register(path33, info) {
55690
- if (path33.length === 0) {
55997
+ register(path34, info) {
55998
+ if (path34.length === 0) {
55691
55999
  throw new Error("Command path cannot be empty");
55692
56000
  }
55693
56001
  let current = this.root;
55694
56002
  const fullPath = [];
55695
- for (let i = 0; i < path33.length; i++) {
55696
- const segment = path33[i];
56003
+ for (let i = 0; i < path34.length; i++) {
56004
+ const segment = path34[i];
55697
56005
  fullPath.push(segment);
55698
56006
  if (!current.children) {
55699
56007
  current.children = [];
55700
56008
  }
55701
- const isLast = i === path33.length - 1;
56009
+ const isLast = i === path34.length - 1;
55702
56010
  let node = current.children.find((n) => n.name === segment);
55703
56011
  if (!node) {
55704
56012
  node = {
@@ -55728,31 +56036,31 @@ var CommandTree = class {
55728
56036
  /**
55729
56037
  * Find a node by path
55730
56038
  */
55731
- find(path33) {
55732
- if (path33.length === 0) {
56039
+ find(path34) {
56040
+ if (path34.length === 0) {
55733
56041
  return this.root;
55734
56042
  }
55735
- const key = path33.join("/");
56043
+ const key = path34.join("/");
55736
56044
  return this.pathCache.get(key) || null;
55737
56045
  }
55738
56046
  /**
55739
56047
  * Get children of a path
55740
56048
  */
55741
- getChildren(path33) {
55742
- const node = this.find(path33);
56049
+ getChildren(path34) {
56050
+ const node = this.find(path34);
55743
56051
  return (node?.children || []).filter((child) => !child.hidden);
55744
56052
  }
55745
56053
  /**
55746
56054
  * Check if a path exists (as category or command)
55747
56055
  */
55748
- exists(path33) {
55749
- return this.find(path33) !== null;
56056
+ exists(path34) {
56057
+ return this.find(path34) !== null;
55750
56058
  }
55751
56059
  /**
55752
56060
  * Check if path is a category (has children)
55753
56061
  */
55754
- isCategory(path33) {
55755
- const node = this.find(path33);
56062
+ isCategory(path34) {
56063
+ const node = this.find(path34);
55756
56064
  return node?.isCategory || false;
55757
56065
  }
55758
56066
  /**
@@ -55831,8 +56139,8 @@ var CommandTree = class {
55831
56139
  * Supports dot notation: "tools.subagent.spawn.local"
55832
56140
  */
55833
56141
  registerFromPath(pathStr, info) {
55834
- const path33 = pathStr.split(/[./]/).filter(Boolean);
55835
- this.register(path33, info);
56142
+ const path34 = pathStr.split(/[./]/).filter(Boolean);
56143
+ this.register(path34, info);
55836
56144
  }
55837
56145
  };
55838
56146
  var commandTree = new CommandTree();
@@ -55938,6 +56246,9 @@ function createExtensionContext(extension, cwd, uiContext, abortFn, isIdleFn, ha
55938
56246
  resolveModelClass(modelClass) {
55939
56247
  return actions?.resolveModelClass?.(modelClass) ?? {};
55940
56248
  },
56249
+ resolveModelRef(modelRef) {
56250
+ return actions?.resolveModelRef?.(modelRef) ?? {};
56251
+ },
55941
56252
  getMessages() {
55942
56253
  return actions?.getMessages?.() ?? [];
55943
56254
  },
@@ -55995,19 +56306,19 @@ function createExtension(extensionPath, resolvedPath, identity, source) {
55995
56306
  }
55996
56307
  function expandPath(p) {
55997
56308
  if (p.startsWith("~/")) {
55998
- return path7.join(os2.homedir(), p.slice(2));
56309
+ return path8.join(os2.homedir(), p.slice(2));
55999
56310
  }
56000
56311
  if (p.startsWith("~")) {
56001
- return path7.join(os2.homedir(), p.slice(1));
56312
+ return path8.join(os2.homedir(), p.slice(1));
56002
56313
  }
56003
56314
  return p;
56004
56315
  }
56005
56316
  function resolvePath(extPath, cwd) {
56006
56317
  const expanded = expandPath(extPath);
56007
- if (path7.isAbsolute(expanded)) {
56318
+ if (path8.isAbsolute(expanded)) {
56008
56319
  return expanded;
56009
56320
  }
56010
- return path7.resolve(cwd, expanded);
56321
+ return path8.resolve(cwd, expanded);
56011
56322
  }
56012
56323
  async function loadExtensionModule(extensionPath) {
56013
56324
  try {
@@ -56027,14 +56338,14 @@ function normalizeExtensionImportPath(extensionPath) {
56027
56338
  if (/^[a-zA-Z]:[\\/]/.test(extensionPath)) {
56028
56339
  return `file:///${extensionPath.replace(/\\/g, "/")}`;
56029
56340
  }
56030
- if (path7.isAbsolute(extensionPath)) {
56341
+ if (path8.isAbsolute(extensionPath)) {
56031
56342
  return pathToFileURL(extensionPath).href;
56032
56343
  }
56033
56344
  return extensionPath;
56034
56345
  }
56035
56346
  async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, hasUI, actions, discovered) {
56036
56347
  const resolvedPath = resolvePath(extensionPath, cwd);
56037
- if (!fs8.existsSync(resolvedPath)) {
56348
+ if (!fs9.existsSync(resolvedPath)) {
56038
56349
  return { extension: null, error: `Extension not found: ${extensionPath}` };
56039
56350
  }
56040
56351
  try {
@@ -56060,17 +56371,17 @@ async function loadExtension(extensionPath, cwd, uiContext, abortFn, isIdleFn, h
56060
56371
  }
56061
56372
  }
56062
56373
  function discoverExtensionsInDir(dir, source) {
56063
- if (!fs8.existsSync(dir)) {
56374
+ if (!fs9.existsSync(dir)) {
56064
56375
  return [];
56065
56376
  }
56066
56377
  const discovered = [];
56067
56378
  try {
56068
- const entries = fs8.readdirSync(dir, { withFileTypes: true });
56379
+ const entries = fs9.readdirSync(dir, { withFileTypes: true });
56069
56380
  for (const entry of entries) {
56070
56381
  if (entry.name.endsWith(".disabled")) {
56071
56382
  continue;
56072
56383
  }
56073
- const entryPath = path7.join(dir, entry.name);
56384
+ const entryPath = path8.join(dir, entry.name);
56074
56385
  if (entry.isFile() && (entry.name.endsWith(".cjs") || entry.name.endsWith(".js") || entry.name.endsWith(".ts"))) {
56075
56386
  discovered.push({
56076
56387
  entryPath,
@@ -56080,13 +56391,13 @@ function discoverExtensionsInDir(dir, source) {
56080
56391
  continue;
56081
56392
  }
56082
56393
  if (entry.isDirectory()) {
56083
- const packageJsonPath = path7.join(entryPath, "package.json");
56394
+ const packageJsonPath = path8.join(entryPath, "package.json");
56084
56395
  let packageIdentity;
56085
56396
  let packageDescription;
56086
56397
  let packageMainPath;
56087
- if (fs8.existsSync(packageJsonPath)) {
56398
+ if (fs9.existsSync(packageJsonPath)) {
56088
56399
  try {
56089
- const pkg = JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8"));
56400
+ const pkg = JSON.parse(fs9.readFileSync(packageJsonPath, "utf-8"));
56090
56401
  const manifest = pkg.pie && typeof pkg.pie === "object" && !Array.isArray(pkg.pie) ? pkg.pie : void 0;
56091
56402
  packageIdentity = resolveExtensionIdentity({
56092
56403
  pieName: typeof manifest?.name === "string" ? manifest.name : void 0,
@@ -56095,8 +56406,8 @@ function discoverExtensionsInDir(dir, source) {
56095
56406
  });
56096
56407
  packageDescription = typeof pkg.description === "string" ? pkg.description : void 0;
56097
56408
  if (typeof manifest?.main === "string" && manifest.main.trim().length > 0) {
56098
- const candidate = path7.resolve(entryPath, manifest.main);
56099
- if (fs8.existsSync(candidate)) {
56409
+ const candidate = path8.resolve(entryPath, manifest.main);
56410
+ if (fs9.existsSync(candidate)) {
56100
56411
  packageMainPath = candidate;
56101
56412
  }
56102
56413
  }
@@ -56112,8 +56423,8 @@ function discoverExtensionsInDir(dir, source) {
56112
56423
  });
56113
56424
  continue;
56114
56425
  }
56115
- const indexCjs = path7.join(entryPath, "index.cjs");
56116
- if (fs8.existsSync(indexCjs)) {
56426
+ const indexCjs = path8.join(entryPath, "index.cjs");
56427
+ if (fs9.existsSync(indexCjs)) {
56117
56428
  discovered.push({
56118
56429
  entryPath: indexCjs,
56119
56430
  source,
@@ -56122,8 +56433,8 @@ function discoverExtensionsInDir(dir, source) {
56122
56433
  });
56123
56434
  continue;
56124
56435
  }
56125
- const indexJs = path7.join(entryPath, "index.js");
56126
- if (fs8.existsSync(indexJs)) {
56436
+ const indexJs = path8.join(entryPath, "index.js");
56437
+ if (fs9.existsSync(indexJs)) {
56127
56438
  discovered.push({
56128
56439
  entryPath: indexJs,
56129
56440
  source,
@@ -56132,8 +56443,8 @@ function discoverExtensionsInDir(dir, source) {
56132
56443
  });
56133
56444
  continue;
56134
56445
  }
56135
- const indexTs = path7.join(entryPath, "index.ts");
56136
- if (fs8.existsSync(indexTs)) {
56446
+ const indexTs = path8.join(entryPath, "index.ts");
56447
+ if (fs9.existsSync(indexTs)) {
56137
56448
  discovered.push({
56138
56449
  entryPath: indexTs,
56139
56450
  source,
@@ -56154,21 +56465,21 @@ function collectDiscoveredExtensions(configuredPaths, cwd, options) {
56154
56465
  const errors = [];
56155
56466
  if (!options?.noExtensions) {
56156
56467
  if (!options?.noBuiltinExtensions) {
56157
- const builtinExtDir = path7.join(getBuiltinDir(), "extensions");
56468
+ const builtinExtDir = path8.join(getBuiltinDir(), "extensions");
56158
56469
  discovered.push(...discoverExtensionsInDir(builtinExtDir, "builtin"));
56159
56470
  }
56160
- const globalExtDir = path7.join(os2.homedir(), ".pie", "extensions");
56471
+ const globalExtDir = path8.join(os2.homedir(), ".pie", "extensions");
56161
56472
  discovered.push(...discoverExtensionsInDir(globalExtDir, "global"));
56162
- const localExtDir = path7.join(cwd, ".pie", "extensions");
56473
+ const localExtDir = path8.join(cwd, ".pie", "extensions");
56163
56474
  discovered.push(...discoverExtensionsInDir(localExtDir, "project"));
56164
56475
  }
56165
56476
  for (const p of configuredPaths) {
56166
56477
  const resolved = resolvePath(p, cwd);
56167
- if (!fs8.existsSync(resolved)) {
56478
+ if (!fs9.existsSync(resolved)) {
56168
56479
  errors.push({ path: p, error: `Extension path not found: ${p}` });
56169
56480
  continue;
56170
56481
  }
56171
- if (!fs8.statSync(resolved).isDirectory()) {
56482
+ if (!fs9.statSync(resolved).isDirectory()) {
56172
56483
  errors.push({ path: p, error: `Extension path must be a directory: ${p}` });
56173
56484
  continue;
56174
56485
  }
@@ -57023,8 +57334,8 @@ function wrapSingleLine(line, width) {
57023
57334
  if (!line) {
57024
57335
  return [""];
57025
57336
  }
57026
- const visibleLength2 = visibleWidth(line);
57027
- if (visibleLength2 <= width) {
57337
+ const visibleLength = visibleWidth(line);
57338
+ if (visibleLength <= width) {
57028
57339
  return [line];
57029
57340
  }
57030
57341
  const wrapped = [];
@@ -58056,9 +58367,9 @@ var KillRing = class {
58056
58367
  };
58057
58368
 
58058
58369
  // ../../packages/tui/src/tui.ts
58059
- import * as fs9 from "node:fs";
58370
+ import * as fs10 from "node:fs";
58060
58371
  import * as os3 from "node:os";
58061
- import * as path8 from "node:path";
58372
+ import * as path9 from "node:path";
58062
58373
 
58063
58374
  // ../../packages/tui/src/terminal-image.ts
58064
58375
  var cachedCapabilities = null;
@@ -58738,11 +59049,11 @@ var TUI = class extends Container {
58738
59049
  const debugRedraw = process.env.PIE_DEBUG_REDRAW === "1";
58739
59050
  const logRedraw = (reason) => {
58740
59051
  if (!debugRedraw) return;
58741
- const logPath = path8.join(os3.homedir(), ".pie", "logs", "pie-cli.log");
58742
- fs9.mkdirSync(path8.dirname(logPath), { recursive: true });
59052
+ const logPath = path9.join(os3.homedir(), ".pie", "logs", "pie-cli.log");
59053
+ fs10.mkdirSync(path9.dirname(logPath), { recursive: true });
58743
59054
  const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] [DEBUG] [ui] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})
58744
59055
  `;
58745
- fs9.appendFileSync(logPath, msg);
59056
+ fs10.appendFileSync(logPath, msg);
58746
59057
  };
58747
59058
  if (this.previousLines.length === 0 && !widthChanged) {
58748
59059
  logRedraw("first render");
@@ -58835,7 +59146,7 @@ var TUI = class extends Container {
58835
59146
  const line = newLines[i];
58836
59147
  const isImage = isImageLine(line);
58837
59148
  if (!isImage && visibleWidth(line) > width) {
58838
- const crashLogPath = path8.join(os3.homedir(), ".pie", "pie-crash.log");
59149
+ const crashLogPath = path9.join(os3.homedir(), ".pie", "pie-crash.log");
58839
59150
  const crashData = [
58840
59151
  `Crash at ${(/* @__PURE__ */ new Date()).toISOString()}`,
58841
59152
  `Terminal width: ${width}`,
@@ -58845,8 +59156,8 @@ var TUI = class extends Container {
58845
59156
  ...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),
58846
59157
  ""
58847
59158
  ].join("\n");
58848
- fs9.mkdirSync(path8.dirname(crashLogPath), { recursive: true });
58849
- fs9.writeFileSync(crashLogPath, crashData);
59159
+ fs10.mkdirSync(path9.dirname(crashLogPath), { recursive: true });
59160
+ fs10.writeFileSync(crashLogPath, crashData);
58850
59161
  this.stop();
58851
59162
  const errorMsg = [
58852
59163
  `Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,
@@ -58876,8 +59187,8 @@ var TUI = class extends Container {
58876
59187
  buffer += "\x1B[?2026l";
58877
59188
  if (process.env.PIE_TUI_DEBUG === "1") {
58878
59189
  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`);
59190
+ fs10.mkdirSync(debugDir, { recursive: true });
59191
+ const debugPath = path9.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
58881
59192
  const debugData = [
58882
59193
  `firstChanged: ${firstChanged}`,
58883
59194
  `viewportTop: ${viewportTop}`,
@@ -58900,7 +59211,7 @@ var TUI = class extends Container {
58900
59211
  "=== buffer ===",
58901
59212
  JSON.stringify(buffer)
58902
59213
  ].join("\n");
58903
- fs9.writeFileSync(debugPath, debugData);
59214
+ fs10.writeFileSync(debugPath, debugData);
58904
59215
  }
58905
59216
  this.terminal.write(buffer);
58906
59217
  this.cursorRow = Math.max(0, newLines.length - 1);
@@ -63189,7 +63500,7 @@ var StdinBuffer = class extends EventEmitter {
63189
63500
  };
63190
63501
 
63191
63502
  // ../../packages/tui/src/terminal.ts
63192
- import * as fs10 from "node:fs";
63503
+ import * as fs11 from "node:fs";
63193
63504
  import koffi from "koffi";
63194
63505
  var ProcessTerminal = class {
63195
63506
  wasRaw = false;
@@ -63352,7 +63663,7 @@ var ProcessTerminal = class {
63352
63663
  process.stdout.write(data);
63353
63664
  if (this.writeLogPath) {
63354
63665
  try {
63355
- fs10.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
63666
+ fs11.appendFileSync(this.writeLogPath, data, { encoding: "utf8" });
63356
63667
  } catch {
63357
63668
  }
63358
63669
  }
@@ -63617,6 +63928,7 @@ var ExtensionRunner = class {
63617
63928
  getAllTools: () => runner.actions.getAllTools(),
63618
63929
  getRuntimeTools: () => runner.actions.getRuntimeTools(),
63619
63930
  resolveModelClass: (modelClass) => runner.actions.resolveModelClass?.(modelClass) ?? {},
63931
+ resolveModelRef: (modelRef) => runner.actions.resolveModelRef?.(modelRef) ?? {},
63620
63932
  getMessages: () => runner.actions.getMessages(),
63621
63933
  getSessionMetadata: () => runner.actions.getSessionMetadata(),
63622
63934
  setSessionMetadata: (key, value) => runner.actions.setSessionMetadata(key, value),
@@ -64197,8 +64509,8 @@ function restoreInteractiveSessionState(options) {
64197
64509
  }
64198
64510
 
64199
64511
  // src/keybindings.ts
64200
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
64201
- import { join as join7 } from "path";
64512
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
64513
+ import { join as join8 } from "path";
64202
64514
  var DEFAULT_APP_KEYBINDINGS = {
64203
64515
  interrupt: "escape",
64204
64516
  clear: "ctrl+c",
@@ -64262,7 +64574,7 @@ var KeybindingsManager = class _KeybindingsManager {
64262
64574
  * Create from config file and set up editor keybindings.
64263
64575
  */
64264
64576
  static create(agentDir = getAgentDir()) {
64265
- const configPath = join7(agentDir, "keybindings.json");
64577
+ const configPath = join8(agentDir, "keybindings.json");
64266
64578
  const config = _KeybindingsManager.loadFromFile(configPath);
64267
64579
  const manager = new _KeybindingsManager(config);
64268
64580
  const editorConfig = {};
@@ -64280,10 +64592,10 @@ var KeybindingsManager = class _KeybindingsManager {
64280
64592
  static inMemory(config = {}) {
64281
64593
  return new _KeybindingsManager(config);
64282
64594
  }
64283
- static loadFromFile(path33) {
64284
- if (!existsSync8(path33)) return {};
64595
+ static loadFromFile(path34) {
64596
+ if (!existsSync9(path34)) return {};
64285
64597
  try {
64286
- return JSON.parse(readFileSync7(path33, "utf-8"));
64598
+ return JSON.parse(readFileSync8(path34, "utf-8"));
64287
64599
  } catch {
64288
64600
  return {};
64289
64601
  }
@@ -64332,19 +64644,19 @@ var KeybindingsManager = class _KeybindingsManager {
64332
64644
  };
64333
64645
 
64334
64646
  // src/project-knowledge.ts
64335
- import fs11 from "node:fs";
64336
- import path9 from "node:path";
64647
+ import fs12 from "node:fs";
64648
+ import path10 from "node:path";
64337
64649
  function collectAncestorAgentsFiles(cwd) {
64338
- const resolvedCwd = path9.resolve(cwd || process.cwd());
64650
+ const resolvedCwd = path10.resolve(cwd || process.cwd());
64339
64651
  const projectRoot = resolveCliProjectRoot(resolvedCwd);
64340
64652
  const candidates = [];
64341
64653
  let current = resolvedCwd;
64342
64654
  while (true) {
64343
- candidates.unshift(path9.join(current, AGENTS_CONTEXT_FILE_NAME));
64655
+ candidates.unshift(path10.join(current, AGENTS_CONTEXT_FILE_NAME));
64344
64656
  if (current === projectRoot) {
64345
64657
  break;
64346
64658
  }
64347
- const parent = path9.dirname(current);
64659
+ const parent = path10.dirname(current);
64348
64660
  if (parent === current) {
64349
64661
  break;
64350
64662
  }
@@ -64352,13 +64664,13 @@ function collectAncestorAgentsFiles(cwd) {
64352
64664
  }
64353
64665
  const files = [];
64354
64666
  for (const candidate of candidates) {
64355
- if (!fs11.existsSync(candidate)) {
64667
+ if (!fs12.existsSync(candidate)) {
64356
64668
  continue;
64357
64669
  }
64358
64670
  try {
64359
64671
  files.push({
64360
- path: path9.relative(resolvedCwd, candidate) || AGENTS_CONTEXT_FILE_NAME,
64361
- content: fs11.readFileSync(candidate, "utf-8")
64672
+ path: path10.relative(resolvedCwd, candidate) || AGENTS_CONTEXT_FILE_NAME,
64673
+ content: fs12.readFileSync(candidate, "utf-8")
64362
64674
  });
64363
64675
  } catch {
64364
64676
  }
@@ -64370,14 +64682,14 @@ function buildCliProjectContextSection(cwd) {
64370
64682
  }
64371
64683
 
64372
64684
  // src/file-access-context.ts
64373
- import * as path10 from "node:path";
64685
+ import * as path11 from "node:path";
64374
64686
  function uniqueNormalizedPaths(paths) {
64375
64687
  const seen = /* @__PURE__ */ new Set();
64376
64688
  const result = [];
64377
64689
  for (const entry of paths) {
64378
64690
  const trimmed = String(entry || "").trim();
64379
64691
  if (!trimmed) continue;
64380
- const normalized = path10.normalize(trimmed);
64692
+ const normalized = path11.normalize(trimmed);
64381
64693
  if (seen.has(normalized)) continue;
64382
64694
  seen.add(normalized);
64383
64695
  result.push(normalized);
@@ -64396,8 +64708,8 @@ function buildCliFileAccessOptions(params) {
64396
64708
  }
64397
64709
 
64398
64710
  // src/theme/theme.ts
64399
- import * as fs12 from "node:fs";
64400
- import * as path11 from "node:path";
64711
+ import * as fs13 from "node:fs";
64712
+ import * as path12 from "node:path";
64401
64713
 
64402
64714
  // ../../node_modules/@sinclair/typebox/build/esm/compiler/compiler.mjs
64403
64715
  var TypeCheck = class {
@@ -65284,11 +65596,11 @@ var BUILTIN_THEMES;
65284
65596
  function getBuiltinThemes() {
65285
65597
  if (!BUILTIN_THEMES) {
65286
65598
  const themesDir = getThemesDir();
65287
- const darkPath = path11.join(themesDir, "dark.json");
65288
- const lightPath = path11.join(themesDir, "light.json");
65599
+ const darkPath = path12.join(themesDir, "dark.json");
65600
+ const lightPath = path12.join(themesDir, "light.json");
65289
65601
  BUILTIN_THEMES = {
65290
- dark: JSON.parse(fs12.readFileSync(darkPath, "utf-8")),
65291
- light: JSON.parse(fs12.readFileSync(lightPath, "utf-8"))
65602
+ dark: JSON.parse(fs13.readFileSync(darkPath, "utf-8")),
65603
+ light: JSON.parse(fs13.readFileSync(lightPath, "utf-8"))
65292
65604
  };
65293
65605
  }
65294
65606
  return BUILTIN_THEMES;
@@ -65296,8 +65608,8 @@ function getBuiltinThemes() {
65296
65608
  function getAvailableThemes() {
65297
65609
  const themes = new Set(Object.keys(getBuiltinThemes()));
65298
65610
  const customThemesDir = getCustomThemesDir();
65299
- if (fs12.existsSync(customThemesDir)) {
65300
- const files = fs12.readdirSync(customThemesDir);
65611
+ if (fs13.existsSync(customThemesDir)) {
65612
+ const files = fs13.readdirSync(customThemesDir);
65301
65613
  for (const file of files) {
65302
65614
  if (file.endsWith(".json")) {
65303
65615
  themes.add(file.slice(0, -5));
@@ -65358,18 +65670,18 @@ function loadThemeJson(name) {
65358
65670
  }
65359
65671
  const registeredTheme = registeredThemes.get(name);
65360
65672
  if (registeredTheme?.sourcePath) {
65361
- const content2 = fs12.readFileSync(registeredTheme.sourcePath, "utf-8");
65673
+ const content2 = fs13.readFileSync(registeredTheme.sourcePath, "utf-8");
65362
65674
  return parseThemeJsonContent(registeredTheme.sourcePath, content2);
65363
65675
  }
65364
65676
  if (registeredTheme) {
65365
65677
  throw new Error(`Theme "${name}" does not have a source path for export`);
65366
65678
  }
65367
65679
  const customThemesDir = getCustomThemesDir();
65368
- const themePath = path11.join(customThemesDir, `${name}.json`);
65369
- if (!fs12.existsSync(themePath)) {
65680
+ const themePath = path12.join(customThemesDir, `${name}.json`);
65681
+ if (!fs13.existsSync(themePath)) {
65370
65682
  throw new Error(`Theme not found: ${name}`);
65371
65683
  }
65372
- const content = fs12.readFileSync(themePath, "utf-8");
65684
+ const content = fs13.readFileSync(themePath, "utf-8");
65373
65685
  return parseThemeJsonContent(name, content);
65374
65686
  }
65375
65687
  function createTheme(themeJson, mode, sourcePath) {
@@ -65482,12 +65794,12 @@ function startThemeWatcher() {
65482
65794
  return;
65483
65795
  }
65484
65796
  const customThemesDir = getCustomThemesDir();
65485
- const themeFile = path11.join(customThemesDir, `${currentThemeName}.json`);
65486
- if (!fs12.existsSync(themeFile)) {
65797
+ const themeFile = path12.join(customThemesDir, `${currentThemeName}.json`);
65798
+ if (!fs13.existsSync(themeFile)) {
65487
65799
  return;
65488
65800
  }
65489
65801
  try {
65490
- themeWatcher = fs12.watch(themeFile, (eventType) => {
65802
+ themeWatcher = fs13.watch(themeFile, (eventType) => {
65491
65803
  if (eventType === "change") {
65492
65804
  setTimeout(() => {
65493
65805
  try {
@@ -65500,7 +65812,7 @@ function startThemeWatcher() {
65500
65812
  }, 100);
65501
65813
  } else if (eventType === "rename") {
65502
65814
  setTimeout(() => {
65503
- if (!fs12.existsSync(themeFile)) {
65815
+ if (!fs13.existsSync(themeFile)) {
65504
65816
  currentThemeName = "dark";
65505
65817
  setGlobalTheme(loadTheme("dark"));
65506
65818
  if (themeWatcher) {
@@ -65681,9 +65993,9 @@ function getSettingsListTheme() {
65681
65993
 
65682
65994
  // src/skills/loader.ts
65683
65995
  var import_yaml = __toESM(require_dist2(), 1);
65684
- import * as fs13 from "fs";
65996
+ import * as fs14 from "fs";
65685
65997
  import * as os4 from "os";
65686
- import * as path12 from "path";
65998
+ import * as path13 from "path";
65687
65999
  function parseSkillDescription(content) {
65688
66000
  content = content.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n");
65689
66001
  const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---(?:\n|$)/);
@@ -65707,19 +66019,19 @@ function parseSkillDescription(content) {
65707
66019
  }
65708
66020
  var USER_CONTROLLED_SOURCES = /* @__PURE__ */ new Set(["user-agents", "user"]);
65709
66021
  function pathIsInside(child, parent) {
65710
- const relative3 = path12.relative(parent, child);
65711
- return relative3 !== "" && !relative3.startsWith(`..${path12.sep}`) && relative3 !== ".." && !path12.isAbsolute(relative3);
66022
+ const relative3 = path13.relative(parent, child);
66023
+ return relative3 !== "" && !relative3.startsWith(`..${path13.sep}`) && relative3 !== ".." && !path13.isAbsolute(relative3);
65712
66024
  }
65713
66025
  function resolveSkillSymlink(fullPath, dir, source) {
65714
66026
  let target;
65715
66027
  let stats;
65716
66028
  try {
65717
- target = fs13.realpathSync(fullPath);
65718
- stats = fs13.statSync(target);
66029
+ target = fs14.realpathSync(fullPath);
66030
+ stats = fs14.statSync(target);
65719
66031
  } catch {
65720
66032
  return { error: `broken skill symlink: ${fullPath}` };
65721
66033
  }
65722
- if (!USER_CONTROLLED_SOURCES.has(source) && !pathIsInside(target, fs13.realpathSync(dir))) {
66034
+ if (!USER_CONTROLLED_SOURCES.has(source) && !pathIsInside(target, fs14.realpathSync(dir))) {
65723
66035
  return { error: `skill symlink escapes the "${source}" layer (not loaded): ${fullPath} -> ${target}` };
65724
66036
  }
65725
66037
  return { target, isDirectory: stats.isDirectory(), isFile: stats.isFile() };
@@ -65727,13 +66039,13 @@ function resolveSkillSymlink(fullPath, dir, source) {
65727
66039
  function loadSkillsFromDir(dir, source) {
65728
66040
  const skills = [];
65729
66041
  const diagnostics = [];
65730
- if (!fs13.existsSync(dir)) {
66042
+ if (!fs14.existsSync(dir)) {
65731
66043
  return { skills, diagnostics };
65732
66044
  }
65733
- const entries = fs13.readdirSync(dir, { withFileTypes: true });
66045
+ const entries = fs14.readdirSync(dir, { withFileTypes: true });
65734
66046
  for (const entry of entries) {
65735
66047
  if (entry.name.startsWith(".")) continue;
65736
- const fullPath = path12.join(dir, entry.name);
66048
+ const fullPath = path13.join(dir, entry.name);
65737
66049
  let entryPath = fullPath;
65738
66050
  let entryIsDirectory = entry.isDirectory();
65739
66051
  let entryIsFile = entry.isFile();
@@ -65748,10 +66060,10 @@ function loadSkillsFromDir(dir, source) {
65748
66060
  entryIsFile = resolved.isFile;
65749
66061
  }
65750
66062
  if (entryIsDirectory) {
65751
- const skillMdPath = path12.join(entryPath, "SKILL.md");
65752
- if (fs13.existsSync(skillMdPath)) {
66063
+ const skillMdPath = path13.join(entryPath, "SKILL.md");
66064
+ if (fs14.existsSync(skillMdPath)) {
65753
66065
  try {
65754
- const content = fs13.readFileSync(skillMdPath, "utf-8");
66066
+ const content = fs14.readFileSync(skillMdPath, "utf-8");
65755
66067
  const description = parseSkillDescription(content);
65756
66068
  skills.push({
65757
66069
  name: entry.name,
@@ -65772,7 +66084,7 @@ function loadSkillsFromDir(dir, source) {
65772
66084
  } else if (entryIsFile && entry.name.endsWith(".md")) {
65773
66085
  const name = entry.name.slice(0, -3);
65774
66086
  try {
65775
- const content = fs13.readFileSync(entryPath, "utf-8");
66087
+ const content = fs14.readFileSync(entryPath, "utf-8");
65776
66088
  const description = parseSkillDescription(content);
65777
66089
  skills.push({
65778
66090
  name,
@@ -65780,7 +66092,7 @@ function loadSkillsFromDir(dir, source) {
65780
66092
  content,
65781
66093
  filePath: entryPath,
65782
66094
  source,
65783
- baseDir: path12.dirname(entryPath)
66095
+ baseDir: path13.dirname(entryPath)
65784
66096
  });
65785
66097
  } catch (e) {
65786
66098
  diagnostics.push({
@@ -65794,18 +66106,18 @@ function loadSkillsFromDir(dir, source) {
65794
66106
  return { skills, diagnostics };
65795
66107
  }
65796
66108
  function discoverAgentsSkillsDirs(cwd) {
65797
- const resolvedCwd = path12.resolve(cwd || process.cwd());
66109
+ const resolvedCwd = path13.resolve(cwd || process.cwd());
65798
66110
  const projectRoot = resolveCliProjectRoot(resolvedCwd);
65799
66111
  const projectAgentsDirs = [];
65800
66112
  let current = projectRoot;
65801
66113
  while (true) {
65802
- projectAgentsDirs.push(path12.join(current, ".agents", "skills"));
66114
+ projectAgentsDirs.push(path13.join(current, ".agents", "skills"));
65803
66115
  if (current === resolvedCwd) break;
65804
- const child = path12.relative(current, resolvedCwd).split(path12.sep)[0];
66116
+ const child = path13.relative(current, resolvedCwd).split(path13.sep)[0];
65805
66117
  if (!child) break;
65806
- current = path12.join(current, child);
66118
+ current = path13.join(current, child);
65807
66119
  }
65808
- return { userAgentsDir: path12.join(os4.homedir(), ".agents", "skills"), projectAgentsDirs };
66120
+ return { userAgentsDir: path13.join(os4.homedir(), ".agents", "skills"), projectAgentsDirs };
65809
66121
  }
65810
66122
  function buildSkillDirs(options) {
65811
66123
  const { userAgentsDir, projectAgentsDirs } = discoverAgentsSkillsDirs(options.cwd);
@@ -65976,11 +66288,11 @@ function validateSkillName(name) {
65976
66288
  }
65977
66289
 
65978
66290
  // src/interactive-mode.ts
65979
- import * as path29 from "path";
66291
+ import * as path30 from "path";
65980
66292
 
65981
66293
  // src/capabilities/read-file-understanding.ts
65982
- import * as path21 from "node:path";
65983
- import * as fs21 from "node:fs/promises";
66294
+ import * as path22 from "node:path";
66295
+ import * as fs22 from "node:fs/promises";
65984
66296
 
65985
66297
  // src/core/provider-capabilities.ts
65986
66298
  var PLATFORM_DISPLAY_NAMES = {
@@ -66006,8 +66318,8 @@ function getProviderDisplayName(platform2) {
66006
66318
  }
66007
66319
 
66008
66320
  // src/files/adapters/kimi-adapter.ts
66009
- import * as fs14 from "node:fs";
66010
- import * as path13 from "node:path";
66321
+ import * as fs15 from "node:fs";
66322
+ import * as path14 from "node:path";
66011
66323
 
66012
66324
  // src/files/errors.ts
66013
66325
  var FileErrorMessages = {
@@ -66144,17 +66456,17 @@ var KimiFileAdapter = class {
66144
66456
  // Upload
66145
66457
  // ============================================================================
66146
66458
  async upload(filePath, options = {}) {
66147
- const fileName = options.sourceName || path13.basename(filePath);
66459
+ const fileName = options.sourceName || path14.basename(filePath);
66148
66460
  const mimeType = options.mimeType || this.guessMimeType(fileName);
66149
66461
  const purpose = this.detectPurpose(filePath, options.purpose, mimeType);
66150
- const stats = fs14.statSync(filePath);
66462
+ const stats = fs15.statSync(filePath);
66151
66463
  if (stats.size > this.capabilities.maxFileSize) {
66152
66464
  throw new FileManagerError(
66153
66465
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
66154
66466
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds Kimi limit of 100MB`
66155
66467
  );
66156
66468
  }
66157
- const fileBuffer = fs14.readFileSync(filePath);
66469
+ const fileBuffer = fs15.readFileSync(filePath);
66158
66470
  const file = new File([fileBuffer], fileName, { type: mimeType });
66159
66471
  const formData = new FormData();
66160
66472
  formData.append("file", file);
@@ -66206,7 +66518,7 @@ var KimiFileAdapter = class {
66206
66518
  return "file-extract";
66207
66519
  }
66208
66520
  guessMimeType(filename) {
66209
- const ext = path13.extname(filename).toLowerCase();
66521
+ const ext = path14.extname(filename).toLowerCase();
66210
66522
  switch (ext) {
66211
66523
  case ".jpg":
66212
66524
  case ".jpeg":
@@ -66368,8 +66680,8 @@ var KimiFileAdapter = class {
66368
66680
  };
66369
66681
 
66370
66682
  // src/files/adapters/gemini-adapter.ts
66371
- import * as fs15 from "node:fs";
66372
- import * as path14 from "node:path";
66683
+ import * as fs16 from "node:fs";
66684
+ import * as path15 from "node:path";
66373
66685
  import { Readable } from "node:stream";
66374
66686
  var GeminiFileAdapter = class {
66375
66687
  platform = "gemini";
@@ -66426,7 +66738,7 @@ var GeminiFileAdapter = class {
66426
66738
  // Upload
66427
66739
  // ============================================================================
66428
66740
  async upload(filePath, options = {}) {
66429
- const stats = fs15.statSync(filePath);
66741
+ const stats = fs16.statSync(filePath);
66430
66742
  if (stats.size > this.capabilities.maxFileSize) {
66431
66743
  throw new FileManagerError(
66432
66744
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
@@ -66434,7 +66746,7 @@ var GeminiFileAdapter = class {
66434
66746
  );
66435
66747
  }
66436
66748
  const mimeType = options.mimeType || this.guessMimeType(filePath);
66437
- const displayName = options.sourceName || path14.basename(filePath);
66749
+ const displayName = options.sourceName || path15.basename(filePath);
66438
66750
  const startResponse = await fetch(
66439
66751
  `${this.baseUrl}/upload/v1beta/files?key=${this.apiKey}`,
66440
66752
  {
@@ -66465,7 +66777,7 @@ var GeminiFileAdapter = class {
66465
66777
  "No upload URL received"
66466
66778
  );
66467
66779
  }
66468
- const fileStream = Readable.toWeb(fs15.createReadStream(filePath));
66780
+ const fileStream = Readable.toWeb(fs16.createReadStream(filePath));
66469
66781
  const uploadResponse = await fetch(uploadUrl, {
66470
66782
  method: "POST",
66471
66783
  headers: {
@@ -66669,8 +66981,8 @@ var GeminiFileAdapter = class {
66669
66981
  };
66670
66982
 
66671
66983
  // src/files/adapters/openai-compatible-files-adapter.ts
66672
- import * as fs16 from "node:fs";
66673
- import * as path15 from "node:path";
66984
+ import * as fs17 from "node:fs";
66985
+ import * as path16 from "node:path";
66674
66986
  var OpenAICompatibleFilesAdapter = class {
66675
66987
  constructor(apiKey, baseUrl, extraHeaders = {}) {
66676
66988
  this.apiKey = apiKey;
@@ -66696,16 +67008,16 @@ var OpenAICompatibleFilesAdapter = class {
66696
67008
  ]
66697
67009
  };
66698
67010
  async upload(filePath, options = {}) {
66699
- const fileName = options.sourceName || path15.basename(filePath);
67011
+ const fileName = options.sourceName || path16.basename(filePath);
66700
67012
  const mimeType = options.mimeType || guessMimeType(fileName);
66701
- const stats = fs16.statSync(filePath);
67013
+ const stats = fs17.statSync(filePath);
66702
67014
  if (stats.size > this.capabilities.maxFileSize) {
66703
67015
  throw new FileManagerError(
66704
67016
  "FILE_TOO_LARGE" /* FILE_TOO_LARGE */,
66705
67017
  `File size ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds OpenAI-compatible Files limit of ${this.capabilities.maxFileSize / 1024 / 1024}MB`
66706
67018
  );
66707
67019
  }
66708
- const file = new File([fs16.readFileSync(filePath)], fileName, { type: mimeType });
67020
+ const file = new File([fs17.readFileSync(filePath)], fileName, { type: mimeType });
66709
67021
  const formData = new FormData();
66710
67022
  formData.append("file", file);
66711
67023
  formData.append("purpose", options.purpose && options.purpose !== "auto" ? options.purpose : "file-extract");
@@ -66822,7 +67134,7 @@ function extractContentText(raw) {
66822
67134
  return raw;
66823
67135
  }
66824
67136
  function guessMimeType(filename) {
66825
- const ext = path15.extname(filename).toLowerCase();
67137
+ const ext = path16.extname(filename).toLowerCase();
66826
67138
  switch (ext) {
66827
67139
  case ".pdf":
66828
67140
  return "application/pdf";
@@ -66838,13 +67150,13 @@ function guessMimeType(filename) {
66838
67150
  }
66839
67151
 
66840
67152
  // src/files/file-manager.ts
66841
- import * as fs20 from "node:fs";
66842
- import * as path20 from "node:path";
67153
+ import * as fs21 from "node:fs";
67154
+ import * as path21 from "node:path";
66843
67155
  import * as crypto2 from "node:crypto";
66844
67156
 
66845
67157
  // src/files/file-cache.ts
66846
- import * as fs17 from "node:fs";
66847
- import * as path17 from "node:path";
67158
+ import * as fs18 from "node:fs";
67159
+ import * as path18 from "node:path";
66848
67160
  import * as crypto from "node:crypto";
66849
67161
 
66850
67162
  // src/files/logger.ts
@@ -66939,7 +67251,7 @@ var DEFAULT_PIC_OPTIONS = {
66939
67251
  };
66940
67252
 
66941
67253
  // src/files/utils.ts
66942
- import * as path16 from "node:path";
67254
+ import * as path17 from "node:path";
66943
67255
  import { homedir as homedir5 } from "node:os";
66944
67256
  var WINDOWS_ABSOLUTE_PATH_RE = /^(?:[a-zA-Z]:[\\/]|[\\/]{2}[^\\/]+[\\/][^\\/]+)/;
66945
67257
  function isWindowsAbsolutePath(filePath) {
@@ -66960,13 +67272,13 @@ function formatBytes(bytes) {
66960
67272
  }
66961
67273
  function resolvePath2(inputPath) {
66962
67274
  if (inputPath.startsWith("~")) {
66963
- return path16.join(getHomeDirectory(), inputPath.slice(1));
67275
+ return path17.join(getHomeDirectory(), inputPath.slice(1));
66964
67276
  }
66965
67277
  if (isWindowsAbsolutePath(inputPath)) {
66966
67278
  return inputPath;
66967
67279
  }
66968
- if (!path16.isAbsolute(inputPath)) {
66969
- return path16.resolve(process.cwd(), inputPath);
67280
+ if (!path17.isAbsolute(inputPath)) {
67281
+ return path17.resolve(process.cwd(), inputPath);
66970
67282
  }
66971
67283
  return inputPath;
66972
67284
  }
@@ -66994,8 +67306,8 @@ var FileCache = class _FileCache {
66994
67306
  maxEntries;
66995
67307
  constructor(baseDir, maxEntries = DEFAULT_MAX_CACHE_ENTRIES) {
66996
67308
  this.baseDir = baseDir;
66997
- this.dataDir = path17.join(baseDir, "data");
66998
- this.indexPath = path17.join(baseDir, "index.json");
67309
+ this.dataDir = path18.join(baseDir, "data");
67310
+ this.indexPath = path18.join(baseDir, "index.json");
66999
67311
  this.maxEntries = maxEntries;
67000
67312
  this.index = this.loadIndex();
67001
67313
  this.ensureDirectories();
@@ -67004,22 +67316,22 @@ var FileCache = class _FileCache {
67004
67316
  // Directory Management
67005
67317
  // ============================================================================
67006
67318
  ensureDirectories() {
67007
- if (!fs17.existsSync(this.baseDir)) {
67008
- fs17.mkdirSync(this.baseDir, { recursive: true });
67319
+ if (!fs18.existsSync(this.baseDir)) {
67320
+ fs18.mkdirSync(this.baseDir, { recursive: true });
67009
67321
  }
67010
- if (!fs17.existsSync(this.dataDir)) {
67011
- fs17.mkdirSync(this.dataDir, { recursive: true });
67322
+ if (!fs18.existsSync(this.dataDir)) {
67323
+ fs18.mkdirSync(this.dataDir, { recursive: true });
67012
67324
  }
67013
67325
  }
67014
67326
  // ============================================================================
67015
67327
  // Index Management
67016
67328
  // ============================================================================
67017
67329
  loadIndex() {
67018
- if (!fs17.existsSync(this.indexPath)) {
67330
+ if (!fs18.existsSync(this.indexPath)) {
67019
67331
  return { version: CACHE_VERSION, files: {}, pathHints: {} };
67020
67332
  }
67021
67333
  try {
67022
- const data = JSON.parse(fs17.readFileSync(this.indexPath, "utf-8"));
67334
+ const data = JSON.parse(fs18.readFileSync(this.indexPath, "utf-8"));
67023
67335
  if (data.version !== CACHE_VERSION) {
67024
67336
  cacheLogger.warn(`Index version mismatch: ${data.version} vs ${CACHE_VERSION}`);
67025
67337
  }
@@ -67035,7 +67347,7 @@ var FileCache = class _FileCache {
67035
67347
  }
67036
67348
  saveIndex() {
67037
67349
  try {
67038
- fs17.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
67350
+ fs18.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
67039
67351
  } catch (err) {
67040
67352
  cacheLogger.error(" Failed to save index:", err);
67041
67353
  throw err;
@@ -67047,7 +67359,7 @@ var FileCache = class _FileCache {
67047
67359
  async computeHash(filePath) {
67048
67360
  return new Promise((resolve7, reject) => {
67049
67361
  const hash = crypto.createHash("sha256");
67050
- const stream = fs17.createReadStream(filePath);
67362
+ const stream = fs18.createReadStream(filePath);
67051
67363
  stream.on("data", (chunk) => hash.update(chunk));
67052
67364
  stream.on("end", () => resolve7(hash.digest("hex")));
67053
67365
  stream.on("error", reject);
@@ -67061,25 +67373,25 @@ var FileCache = class _FileCache {
67061
67373
  // ============================================================================
67062
67374
  getStoragePath(hash) {
67063
67375
  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 });
67376
+ const fullDir = path18.join(this.dataDir, subdir);
67377
+ if (!fs18.existsSync(fullDir)) {
67378
+ fs18.mkdirSync(fullDir, { recursive: true });
67067
67379
  }
67068
- return path17.join(fullDir, hash);
67380
+ return path18.join(fullDir, hash);
67069
67381
  }
67070
67382
  getStorageRelativePath(hash) {
67071
67383
  const subdir = hash.slice(0, 2);
67072
- return path17.join(subdir, hash);
67384
+ return path18.join(subdir, hash);
67073
67385
  }
67074
67386
  async storeFile(sourcePath, name, mimeType) {
67075
67387
  const hash = await this.computeHash(sourcePath);
67076
67388
  const storagePath = this.getStoragePath(hash);
67077
67389
  this.rememberPathHint(sourcePath, hash, name);
67078
- if (fs17.existsSync(storagePath)) {
67390
+ if (fs18.existsSync(storagePath)) {
67079
67391
  return { hash, localPath: storagePath };
67080
67392
  }
67081
- fs17.copyFileSync(sourcePath, storagePath);
67082
- const stat2 = fs17.statSync(storagePath);
67393
+ fs18.copyFileSync(sourcePath, storagePath);
67394
+ const stat2 = fs18.statSync(storagePath);
67083
67395
  this.index.files[hash] = {
67084
67396
  hash,
67085
67397
  name,
@@ -67096,10 +67408,10 @@ var FileCache = class _FileCache {
67096
67408
  async storeBuffer(data, name, mimeType) {
67097
67409
  const hash = this.computeHashSync(data);
67098
67410
  const storagePath = this.getStoragePath(hash);
67099
- if (fs17.existsSync(storagePath)) {
67411
+ if (fs18.existsSync(storagePath)) {
67100
67412
  return { hash, localPath: storagePath };
67101
67413
  }
67102
- fs17.writeFileSync(storagePath, data);
67414
+ fs18.writeFileSync(storagePath, data);
67103
67415
  this.index.files[hash] = {
67104
67416
  hash,
67105
67417
  name,
@@ -67131,7 +67443,7 @@ var FileCache = class _FileCache {
67131
67443
  getLocalPath(hash) {
67132
67444
  const entry = this.index.files[hash];
67133
67445
  if (!entry) return void 0;
67134
- return path17.join(this.dataDir, entry.localPath);
67446
+ return path18.join(this.dataDir, entry.localPath);
67135
67447
  }
67136
67448
  exists(hash) {
67137
67449
  return hash in this.index.files;
@@ -67171,7 +67483,7 @@ var FileCache = class _FileCache {
67171
67483
  getPathHint(filePath) {
67172
67484
  try {
67173
67485
  const resolvedPath = this.getResolvedHintPath(filePath);
67174
- const stat2 = fs17.statSync(resolvedPath);
67486
+ const stat2 = fs18.statSync(resolvedPath);
67175
67487
  if (!stat2.isFile()) return void 0;
67176
67488
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
67177
67489
  const key = this.getPathHintKey(resolvedPath);
@@ -67201,7 +67513,7 @@ var FileCache = class _FileCache {
67201
67513
  rememberPathHint(filePath, hash, name) {
67202
67514
  try {
67203
67515
  const resolvedPath = this.getResolvedHintPath(filePath);
67204
- const stat2 = fs17.statSync(resolvedPath);
67516
+ const stat2 = fs18.statSync(resolvedPath);
67205
67517
  if (!stat2.isFile()) return;
67206
67518
  const entry = this.index.files[hash];
67207
67519
  const normalizedMtimeMs = this.normalizeHintMtimeMs(stat2.mtimeMs);
@@ -67211,7 +67523,7 @@ var FileCache = class _FileCache {
67211
67523
  this.index.pathHints[this.getPathHintKey(resolvedPath)] = {
67212
67524
  path: resolvedPath,
67213
67525
  hash,
67214
- name: name || entry?.name || path17.basename(resolvedPath),
67526
+ name: name || entry?.name || path18.basename(resolvedPath),
67215
67527
  size: stat2.size,
67216
67528
  mtimeMs: normalizedMtimeMs,
67217
67529
  lastSeenAt: Date.now(),
@@ -67259,9 +67571,9 @@ var FileCache = class _FileCache {
67259
67571
  deleteEntry(hash, entry) {
67260
67572
  entry = entry || this.index.files[hash];
67261
67573
  if (!entry) return;
67262
- const localPath = path17.join(this.dataDir, entry.localPath);
67263
- if (fs17.existsSync(localPath)) {
67264
- fs17.unlinkSync(localPath);
67574
+ const localPath = path18.join(this.dataDir, entry.localPath);
67575
+ if (fs18.existsSync(localPath)) {
67576
+ fs18.unlinkSync(localPath);
67265
67577
  }
67266
67578
  delete this.index.files[hash];
67267
67579
  if (this.index.pathHints) {
@@ -67275,9 +67587,9 @@ var FileCache = class _FileCache {
67275
67587
  }
67276
67588
  clear() {
67277
67589
  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);
67590
+ const localPath = path18.join(this.dataDir, entry.localPath);
67591
+ if (fs18.existsSync(localPath)) {
67592
+ fs18.unlinkSync(localPath);
67281
67593
  }
67282
67594
  }
67283
67595
  this.index = { version: CACHE_VERSION, files: {}, pathHints: {} };
@@ -67330,11 +67642,11 @@ var FileCache = class _FileCache {
67330
67642
  };
67331
67643
  }
67332
67644
  static getMimeType(fileName) {
67333
- const ext = path17.extname(fileName).toLowerCase();
67645
+ const ext = path18.extname(fileName).toLowerCase();
67334
67646
  return MIME_TYPES[ext] || "application/octet-stream";
67335
67647
  }
67336
67648
  static getFileTypeFromName(fileName) {
67337
- const baseName = path17.basename(fileName);
67649
+ const baseName = path18.basename(fileName);
67338
67650
  if (!baseName || baseName.startsWith(".")) {
67339
67651
  return void 0;
67340
67652
  }
@@ -67365,7 +67677,7 @@ var FileCache = class _FileCache {
67365
67677
  getResolvedHintPath(filePath) {
67366
67678
  const resolvedPath = resolvePath2(filePath);
67367
67679
  try {
67368
- return fs17.realpathSync.native ? fs17.realpathSync.native(resolvedPath) : fs17.realpathSync(resolvedPath);
67680
+ return fs18.realpathSync.native ? fs18.realpathSync.native(resolvedPath) : fs18.realpathSync(resolvedPath);
67369
67681
  } catch {
67370
67682
  return resolvedPath;
67371
67683
  }
@@ -67373,8 +67685,8 @@ var FileCache = class _FileCache {
67373
67685
  };
67374
67686
 
67375
67687
  // src/files/session-file-manager.ts
67376
- import * as fs18 from "node:fs";
67377
- import * as path18 from "node:path";
67688
+ import * as fs19 from "node:fs";
67689
+ import * as path19 from "node:path";
67378
67690
  var INITIAL_REFRESH_BACKOFF_MS = 6e4;
67379
67691
  var MAX_REFRESH_BACKOFF_MS = 60 * 60 * 1e3;
67380
67692
  var SessionFileManager = class {
@@ -67388,7 +67700,7 @@ var SessionFileManager = class {
67388
67700
  constructor(sessionId, sessionsDir, fileCache, authFingerprint) {
67389
67701
  this.sessionId = sessionId;
67390
67702
  this.sessionsDir = sessionsDir;
67391
- this.statePath = path18.join(this.sessionsDir, `${sessionId}-files.json`);
67703
+ this.statePath = path19.join(this.sessionsDir, `${sessionId}-files.json`);
67392
67704
  this.fileCache = fileCache;
67393
67705
  this.authFingerprint = authFingerprint;
67394
67706
  this.state = this.loadState();
@@ -67398,15 +67710,15 @@ var SessionFileManager = class {
67398
67710
  // Directory Management
67399
67711
  // ============================================================================
67400
67712
  ensureDirectories() {
67401
- if (!fs18.existsSync(this.sessionsDir)) {
67402
- fs18.mkdirSync(this.sessionsDir, { recursive: true });
67713
+ if (!fs19.existsSync(this.sessionsDir)) {
67714
+ fs19.mkdirSync(this.sessionsDir, { recursive: true });
67403
67715
  }
67404
67716
  }
67405
67717
  // ============================================================================
67406
67718
  // State Management
67407
67719
  // ============================================================================
67408
67720
  loadState() {
67409
- if (!fs18.existsSync(this.statePath)) {
67721
+ if (!fs19.existsSync(this.statePath)) {
67410
67722
  return {
67411
67723
  sessionId: this.sessionId,
67412
67724
  lastSyncedAt: 0,
@@ -67414,7 +67726,7 @@ var SessionFileManager = class {
67414
67726
  };
67415
67727
  }
67416
67728
  try {
67417
- return JSON.parse(fs18.readFileSync(this.statePath, "utf-8"));
67729
+ return JSON.parse(fs19.readFileSync(this.statePath, "utf-8"));
67418
67730
  } catch (err) {
67419
67731
  sessionLogger.error(" Failed to load state:", err);
67420
67732
  return {
@@ -67427,12 +67739,12 @@ var SessionFileManager = class {
67427
67739
  saveState() {
67428
67740
  try {
67429
67741
  if (Object.keys(this.state.files).length === 0) {
67430
- if (fs18.existsSync(this.statePath)) {
67431
- fs18.unlinkSync(this.statePath);
67742
+ if (fs19.existsSync(this.statePath)) {
67743
+ fs19.unlinkSync(this.statePath);
67432
67744
  }
67433
67745
  return;
67434
67746
  }
67435
- fs18.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
67747
+ fs19.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
67436
67748
  } catch (err) {
67437
67749
  sessionLogger.error(" Failed to save state:", err);
67438
67750
  }
@@ -67578,7 +67890,7 @@ var SessionFileManager = class {
67578
67890
  return { success: false, coolingDown: true };
67579
67891
  }
67580
67892
  const localPath = this.fileCache.getLocalPath(entry.hash);
67581
- if (!localPath || !fs18.existsSync(localPath)) {
67893
+ if (!localPath || !fs19.existsSync(localPath)) {
67582
67894
  sessionLogger.warn(`Local file not found for ${fileId}`);
67583
67895
  entry.status = "expired";
67584
67896
  entry.error = "Local file missing";
@@ -67729,15 +68041,15 @@ var SessionFileManager = class {
67729
68041
  // Static Utilities
67730
68042
  // ============================================================================
67731
68043
  static cleanupOldSessions(sessionsDir, maxAge = 30 * 24 * 60 * 60 * 1e3) {
67732
- if (!fs18.existsSync(sessionsDir)) return;
68044
+ if (!fs19.existsSync(sessionsDir)) return;
67733
68045
  const now = Date.now();
67734
- const files = fs18.readdirSync(sessionsDir);
68046
+ const files = fs19.readdirSync(sessionsDir);
67735
68047
  for (const file of files) {
67736
68048
  if (!file.endsWith(".json")) continue;
67737
- const filePath = path18.join(sessionsDir, file);
67738
- const stat2 = fs18.statSync(filePath);
68049
+ const filePath = path19.join(sessionsDir, file);
68050
+ const stat2 = fs19.statSync(filePath);
67739
68051
  if (now - stat2.mtime.getTime() > maxAge) {
67740
- fs18.unlinkSync(filePath);
68052
+ fs19.unlinkSync(filePath);
67741
68053
  sessionLogger.debug(`Cleaned up old session: ${file}`);
67742
68054
  }
67743
68055
  }
@@ -67745,8 +68057,8 @@ var SessionFileManager = class {
67745
68057
  };
67746
68058
 
67747
68059
  // src/files/ffmpeg-processor.ts
67748
- import * as fs19 from "node:fs";
67749
- import * as path19 from "node:path";
68060
+ import * as fs20 from "node:fs";
68061
+ import * as path20 from "node:path";
67750
68062
  import { spawn } from "node:child_process";
67751
68063
  var FFmpegProcessor = class {
67752
68064
  ffmpegPath = "ffmpeg";
@@ -67850,7 +68162,7 @@ var FFmpegProcessor = class {
67850
68162
  }
67851
68163
  async compressVideo(inputPath, outputDir, info, opts, onProgress) {
67852
68164
  const outputName = `compressed_${Date.now()}.mp4`;
67853
- const outputPath = path19.join(outputDir, outputName);
68165
+ const outputPath = path20.join(outputDir, outputName);
67854
68166
  const adaptiveParams = this.calculateAdaptiveParams(info.duration, opts);
67855
68167
  const args = [
67856
68168
  "-i",
@@ -67881,7 +68193,7 @@ var FFmpegProcessor = class {
67881
68193
  onProgress?.(percent);
67882
68194
  }
67883
68195
  });
67884
- const outputStat = fs19.statSync(outputPath);
68196
+ const outputStat = fs20.statSync(outputPath);
67885
68197
  return {
67886
68198
  type: "video",
67887
68199
  output: outputPath,
@@ -67912,9 +68224,9 @@ var FFmpegProcessor = class {
67912
68224
  }
67913
68225
  async extractKeyframes(inputPath, outputDir, info, opts, onProgress) {
67914
68226
  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");
68227
+ const framesDir = path20.join(outputDir, `keyframes_${Date.now()}`);
68228
+ fs20.mkdirSync(framesDir, { recursive: true });
68229
+ const outputPattern = path20.join(framesDir, "frame_%03d.jpg");
67918
68230
  const args = [
67919
68231
  "-i",
67920
68232
  inputPath,
@@ -67932,10 +68244,10 @@ var FFmpegProcessor = class {
67932
68244
  onProgress?.(percent);
67933
68245
  }
67934
68246
  });
67935
- let frames = fs19.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
68247
+ let frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path20.join(framesDir, f));
67936
68248
  if (frames.length < opts.keyframeCount / 2) {
67937
- fs19.rmSync(framesDir, { recursive: true, force: true });
67938
- fs19.mkdirSync(framesDir, { recursive: true });
68249
+ fs20.rmSync(framesDir, { recursive: true, force: true });
68250
+ fs20.mkdirSync(framesDir, { recursive: true });
67939
68251
  const uniformArgs = [
67940
68252
  "-i",
67941
68253
  inputPath,
@@ -67951,10 +68263,10 @@ var FFmpegProcessor = class {
67951
68263
  onProgress?.(percent);
67952
68264
  }
67953
68265
  });
67954
- frames = fs19.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
68266
+ frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path20.join(framesDir, f));
67955
68267
  }
67956
68268
  const totalOutputSize = frames.reduce(
67957
- (sum, f) => sum + fs19.statSync(f).size,
68269
+ (sum, f) => sum + fs20.statSync(f).size,
67958
68270
  0
67959
68271
  );
67960
68272
  return {
@@ -67975,7 +68287,7 @@ var FFmpegProcessor = class {
67975
68287
  const opts = { ...DEFAULT_PIC_OPTIONS, ...options };
67976
68288
  const ext = opts.format === "webp" ? ".webp" : ".jpg";
67977
68289
  const outputName = `optimized_${Date.now()}${ext}`;
67978
- const outputPath = path19.join(outputDir, outputName);
68290
+ const outputPath = path20.join(outputDir, outputName);
67979
68291
  const args = [
67980
68292
  "-i",
67981
68293
  inputPath,
@@ -68150,8 +68462,8 @@ var DIRECTORY_LISTING_TTL_MS = 1500;
68150
68462
  var FileManager = class {
68151
68463
  constructor(options) {
68152
68464
  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");
68465
+ const baseDir = options.baseDir || path21.join(process.env.HOME || ".", ".pie", "files");
68466
+ const sessionsDir = options.sessionsDir || path21.join(process.env.HOME || ".", ".pie", "sessions");
68155
68467
  this.fileCache = new FileCache(baseDir);
68156
68468
  this.authFingerprint = options.apiKey ? this.buildAuthFingerprint(options.apiKey) : void 0;
68157
68469
  this.sessionManager = new SessionFileManager(
@@ -68162,7 +68474,7 @@ var FileManager = class {
68162
68474
  );
68163
68475
  this.ffmpeg = new FFmpegProcessor(options.ffmpegPath);
68164
68476
  this.platform = normalizeFileManagerPlatform(options.platform);
68165
- this.tempDir = path20.join(baseDir, "temp");
68477
+ this.tempDir = path21.join(baseDir, "temp");
68166
68478
  this.ensureDirectories();
68167
68479
  }
68168
68480
  options;
@@ -68174,8 +68486,8 @@ var FileManager = class {
68174
68486
  directoryListingCache = /* @__PURE__ */ new Map();
68175
68487
  authFingerprint;
68176
68488
  ensureDirectories() {
68177
- if (!fs20.existsSync(this.tempDir)) {
68178
- fs20.mkdirSync(this.tempDir, { recursive: true });
68489
+ if (!fs21.existsSync(this.tempDir)) {
68490
+ fs21.mkdirSync(this.tempDir, { recursive: true });
68179
68491
  }
68180
68492
  }
68181
68493
  // ============================================================================
@@ -68209,8 +68521,8 @@ var FileManager = class {
68209
68521
  // ============================================================================
68210
68522
  async stageLocal(filePath, options = {}) {
68211
68523
  const resolvedPath = resolvePath2(filePath);
68212
- const sourceName = options.sourceName || path20.basename(resolvedPath);
68213
- if (!fs20.existsSync(resolvedPath)) {
68524
+ const sourceName = options.sourceName || path21.basename(resolvedPath);
68525
+ if (!fs21.existsSync(resolvedPath)) {
68214
68526
  throw new FileManagerError(
68215
68527
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68216
68528
  `File not found: ${filePath}`
@@ -68225,7 +68537,7 @@ var FileManager = class {
68225
68537
  this.fileCache.rememberPathHint(resolvedPath, hash, sourceName);
68226
68538
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
68227
68539
  const entry = this.fileCache.getByHash(hash);
68228
- const size = entry?.size ?? fs20.statSync(resolvedPath).size;
68540
+ const size = entry?.size ?? fs21.statSync(resolvedPath).size;
68229
68541
  return {
68230
68542
  success: true,
68231
68543
  hash,
@@ -68239,8 +68551,8 @@ var FileManager = class {
68239
68551
  }
68240
68552
  async upload(filePath, options = {}) {
68241
68553
  const resolvedPath = resolvePath2(filePath);
68242
- const sourceName = options.sourceName || path20.basename(resolvedPath);
68243
- if (!fs20.existsSync(resolvedPath)) {
68554
+ const sourceName = options.sourceName || path21.basename(resolvedPath);
68555
+ if (!fs21.existsSync(resolvedPath)) {
68244
68556
  throw new FileManagerError(
68245
68557
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68246
68558
  `File not found: ${filePath}`
@@ -68321,7 +68633,7 @@ var FileManager = class {
68321
68633
  // ============================================================================
68322
68634
  async uploadPic(filePath, options = {}) {
68323
68635
  const resolvedPath = resolvePath2(filePath);
68324
- if (!fs20.existsSync(resolvedPath)) {
68636
+ if (!fs21.existsSync(resolvedPath)) {
68325
68637
  throw new FileManagerError(
68326
68638
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68327
68639
  `File not found: ${filePath}`
@@ -68329,7 +68641,7 @@ var FileManager = class {
68329
68641
  }
68330
68642
  const cachedResult = await this.tryReuseCachedSourceUpload(
68331
68643
  resolvedPath,
68332
- options.sourceName || path20.basename(resolvedPath),
68644
+ options.sourceName || path21.basename(resolvedPath),
68333
68645
  options.platform || this.platform
68334
68646
  );
68335
68647
  if (cachedResult) {
@@ -68346,12 +68658,12 @@ var FileManager = class {
68346
68658
  const result = await this.upload(optimizedPath, {
68347
68659
  ...options,
68348
68660
  purpose: "image",
68349
- sourceName: path20.basename(resolvedPath)
68661
+ sourceName: path21.basename(resolvedPath)
68350
68662
  });
68351
- this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
68663
+ this.fileCache.rememberPathHint(resolvedPath, result.hash, path21.basename(resolvedPath));
68352
68664
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
68353
68665
  try {
68354
- fs20.unlinkSync(optimizedPath);
68666
+ fs21.unlinkSync(optimizedPath);
68355
68667
  } catch {
68356
68668
  }
68357
68669
  return result;
@@ -68361,7 +68673,7 @@ var FileManager = class {
68361
68673
  // ============================================================================
68362
68674
  async uploadVideo(filePath, options = {}) {
68363
68675
  const resolvedPath = resolvePath2(filePath);
68364
- if (!fs20.existsSync(resolvedPath)) {
68676
+ if (!fs21.existsSync(resolvedPath)) {
68365
68677
  throw new FileManagerError(
68366
68678
  "LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
68367
68679
  `File not found: ${filePath}`
@@ -68369,7 +68681,7 @@ var FileManager = class {
68369
68681
  }
68370
68682
  const cachedResult = await this.tryReuseCachedSourceUpload(
68371
68683
  resolvedPath,
68372
- options.sourceName || path20.basename(resolvedPath),
68684
+ options.sourceName || path21.basename(resolvedPath),
68373
68685
  options.platform || this.platform
68374
68686
  );
68375
68687
  if (cachedResult) {
@@ -68419,9 +68731,9 @@ var FileManager = class {
68419
68731
  result = await this.upload(preprocessResult.output, {
68420
68732
  ...options,
68421
68733
  purpose: "video",
68422
- sourceName: path20.basename(resolvedPath)
68734
+ sourceName: path21.basename(resolvedPath)
68423
68735
  });
68424
- this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
68736
+ this.fileCache.rememberPathHint(resolvedPath, result.hash, path21.basename(resolvedPath));
68425
68737
  this.invalidateDirectoryListingCacheForPath(resolvedPath);
68426
68738
  } else {
68427
68739
  throw new FileManagerError(
@@ -68713,7 +69025,7 @@ var FileManager = class {
68713
69025
  * Detect purpose from file path based on extension
68714
69026
  */
68715
69027
  detectPurpose(filePath) {
68716
- const ext = path20.extname(filePath).toLowerCase();
69028
+ const ext = path21.extname(filePath).toLowerCase();
68717
69029
  switch (ext) {
68718
69030
  case ".mp4":
68719
69031
  case ".mov":
@@ -68755,13 +69067,13 @@ var FileManager = class {
68755
69067
  cleanupTempFiles(output) {
68756
69068
  try {
68757
69069
  if (typeof output === "string") {
68758
- if (fs20.existsSync(output)) {
68759
- fs20.unlinkSync(output);
69070
+ if (fs21.existsSync(output)) {
69071
+ fs21.unlinkSync(output);
68760
69072
  }
68761
69073
  } else {
68762
69074
  for (const file of output) {
68763
- if (fs20.existsSync(file)) {
68764
- fs20.unlinkSync(file);
69075
+ if (fs21.existsSync(file)) {
69076
+ fs21.unlinkSync(file);
68765
69077
  }
68766
69078
  }
68767
69079
  }
@@ -68793,7 +69105,7 @@ var FileManager = class {
68793
69105
  }];
68794
69106
  }
68795
69107
  const localPath = this.fileCache.getLocalPath(entry.hash);
68796
- if (localPath && fs20.existsSync(localPath)) {
69108
+ if (localPath && fs21.existsSync(localPath)) {
68797
69109
  return [{
68798
69110
  fileId,
68799
69111
  name: cacheEntry.name,
@@ -68890,12 +69202,12 @@ var FileManager = class {
68890
69202
  directories: []
68891
69203
  };
68892
69204
  try {
68893
- const entries = fs20.readdirSync(resolvedDir, { withFileTypes: true });
69205
+ const entries = fs21.readdirSync(resolvedDir, { withFileTypes: true });
68894
69206
  for (const entry of entries) {
68895
69207
  if (!entry.name || entry.name.startsWith(".")) {
68896
69208
  continue;
68897
69209
  }
68898
- const fullPath = path20.join(resolvedDir, entry.name);
69210
+ const fullPath = path21.join(resolvedDir, entry.name);
68899
69211
  if (entry.isDirectory()) {
68900
69212
  listing.directories.push({ name: entry.name, path: fullPath });
68901
69213
  continue;
@@ -68904,7 +69216,7 @@ var FileManager = class {
68904
69216
  let isFile = entry.isFile();
68905
69217
  if (entry.isSymbolicLink()) {
68906
69218
  try {
68907
- const targetStat = fs20.statSync(fullPath);
69219
+ const targetStat = fs21.statSync(fullPath);
68908
69220
  isDirectory = targetStat.isDirectory();
68909
69221
  isFile = targetStat.isFile();
68910
69222
  } catch {
@@ -68922,7 +69234,7 @@ var FileManager = class {
68922
69234
  if (!type) {
68923
69235
  continue;
68924
69236
  }
68925
- const stat2 = fs20.statSync(fullPath);
69237
+ const stat2 = fs21.statSync(fullPath);
68926
69238
  listing.files.push({
68927
69239
  name: entry.name,
68928
69240
  path: fullPath,
@@ -68936,7 +69248,7 @@ var FileManager = class {
68936
69248
  return listing;
68937
69249
  }
68938
69250
  invalidateDirectoryListingCacheForPath(filePath) {
68939
- this.directoryListingCache.delete(path20.dirname(resolvePath2(filePath)));
69251
+ this.directoryListingCache.delete(path21.dirname(resolvePath2(filePath)));
68940
69252
  }
68941
69253
  buildAuthFingerprint(apiKey) {
68942
69254
  return crypto2.createHash("sha256").update(apiKey).digest("hex").slice(0, 16);
@@ -68985,8 +69297,8 @@ function createFileManagerForModel(params) {
68985
69297
  sessionId: params.sessionId,
68986
69298
  platform: platform2,
68987
69299
  apiKey: params.apiKey,
68988
- baseDir: path21.join(params.configDir, "files"),
68989
- sessionsDir: path21.join(params.configDir, "sessions")
69300
+ baseDir: path22.join(params.configDir, "files"),
69301
+ sessionsDir: path22.join(params.configDir, "sessions")
68990
69302
  });
68991
69303
  switch (getFileManagerAdapterKind(platform2)) {
68992
69304
  case "kimi":
@@ -69021,15 +69333,15 @@ function isInlineMediaRequest(request) {
69021
69333
  return request.kind === "image" || request.kind === "video";
69022
69334
  }
69023
69335
  async function prepareInlineMediaContent(params) {
69024
- const stat2 = await fs21.stat(params.request.absolutePath);
69336
+ const stat2 = await fs22.stat(params.request.absolutePath);
69025
69337
  const limitMb = getCapabilityLimitMb(params.model, params.request.kind);
69026
69338
  const limitBytes = limitMb * 1024 * 1024;
69027
69339
  if (stat2.size > limitBytes) {
69028
69340
  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.`
69341
+ `${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
69342
  );
69031
69343
  }
69032
- const data = await fs21.readFile(params.request.absolutePath, "base64");
69344
+ const data = await fs22.readFile(params.request.absolutePath, "base64");
69033
69345
  const content = params.request.kind === "video" ? [{ type: "video", data, mimeType: params.request.mimeType }] : [{ type: "image", data, mimeType: params.request.mimeType }];
69034
69346
  return {
69035
69347
  content,
@@ -69065,7 +69377,7 @@ async function prepareFileContent(configDir, params) {
69065
69377
  });
69066
69378
  if (params.request.kind === "document") {
69067
69379
  const upload2 = await manager.upload(params.request.absolutePath, {
69068
- sourceName: path21.basename(params.request.displayPath),
69380
+ sourceName: path22.basename(params.request.displayPath),
69069
69381
  purpose: "file-extract"
69070
69382
  });
69071
69383
  await waitForReady({ manager, fileId: upload2.fileId, timeoutMs: 12e4, signal: params.request.signal });
@@ -69088,8 +69400,8 @@ async function prepareFileContent(configDir, params) {
69088
69400
  }
69089
69401
  };
69090
69402
  }
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),
69403
+ 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, {
69404
+ sourceName: path22.basename(params.request.displayPath),
69093
69405
  purpose: params.request.kind === "image" ? "image" : "file-extract"
69094
69406
  });
69095
69407
  if (params.request.kind !== "video") {
@@ -69510,22 +69822,22 @@ var ExecutionStateManager = class {
69510
69822
  };
69511
69823
 
69512
69824
  // src/session-trace.ts
69513
- import * as fs22 from "node:fs";
69514
- import * as path22 from "node:path";
69825
+ import * as fs23 from "node:fs";
69826
+ import * as path23 from "node:path";
69515
69827
  function saveTraceFileBestEffort(tracePath, content) {
69516
69828
  const tempPath = `${tracePath}.${process.pid}.${Date.now()}.tmp`;
69517
69829
  try {
69518
- fs22.writeFileSync(tempPath, content, "utf8");
69830
+ fs23.writeFileSync(tempPath, content, "utf8");
69519
69831
  try {
69520
- fs22.renameSync(tempPath, tracePath);
69832
+ fs23.renameSync(tempPath, tracePath);
69521
69833
  return;
69522
69834
  } catch {
69523
69835
  try {
69524
- fs22.copyFileSync(tempPath, tracePath);
69836
+ fs23.copyFileSync(tempPath, tracePath);
69525
69837
  } catch {
69526
69838
  } finally {
69527
69839
  try {
69528
- fs22.unlinkSync(tempPath);
69840
+ fs23.unlinkSync(tempPath);
69529
69841
  } catch {
69530
69842
  }
69531
69843
  }
@@ -69538,16 +69850,16 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
69538
69850
  super({
69539
69851
  getSessionId: () => sessionManager.getActiveSessionId(),
69540
69852
  loadTrace: (sessionId) => {
69541
- const tracePath = path22.join(sessionsDir, `${sessionId}.trace.json`);
69542
- if (!fs22.existsSync(tracePath)) return null;
69853
+ const tracePath = path23.join(sessionsDir, `${sessionId}.trace.json`);
69854
+ if (!fs23.existsSync(tracePath)) return null;
69543
69855
  try {
69544
- return JSON.parse(fs22.readFileSync(tracePath, "utf8"));
69856
+ return JSON.parse(fs23.readFileSync(tracePath, "utf8"));
69545
69857
  } catch {
69546
69858
  return null;
69547
69859
  }
69548
69860
  },
69549
69861
  saveTrace: (trace) => {
69550
- const tracePath = path22.join(sessionsDir, `${trace.sessionId}.trace.json`);
69862
+ const tracePath = path23.join(sessionsDir, `${trace.sessionId}.trace.json`);
69551
69863
  saveTraceFileBestEffort(tracePath, JSON.stringify(trace, null, 2));
69552
69864
  }
69553
69865
  });
@@ -69837,7 +70149,7 @@ function normalizeSessionTitle(raw) {
69837
70149
  }
69838
70150
 
69839
70151
  // src/components/extension-selector.ts
69840
- import * as path23 from "node:path";
70152
+ import * as path24 from "node:path";
69841
70153
  var ExtensionSelectorComponent = class extends Container {
69842
70154
  selectList;
69843
70155
  shortcuts;
@@ -69893,8 +70205,8 @@ function selectRuntimeExtensionWinners(infos) {
69893
70205
  return reversed.reverse();
69894
70206
  }
69895
70207
  function unidentifiedLabel(info) {
69896
- const parentName = path23.basename(path23.dirname(info.entryPath));
69897
- const fileName = path23.basename(info.entryPath);
70208
+ const parentName = path24.basename(path24.dirname(info.entryPath));
70209
+ const fileName = path24.basename(info.entryPath);
69898
70210
  return `(unidentified) ${parentName || fileName}`;
69899
70211
  }
69900
70212
  var ExtensionEnablementSelectorComponent = class extends Container {
@@ -70442,7 +70754,7 @@ async function handleDebugPackageCommand(host) {
70442
70754
  import * as os6 from "os";
70443
70755
 
70444
70756
  // src/components/session-selector.ts
70445
- import * as path24 from "node:path";
70757
+ import * as path25 from "node:path";
70446
70758
  function formatDate(timestamp) {
70447
70759
  const date = new Date(timestamp);
70448
70760
  const now = /* @__PURE__ */ new Date();
@@ -70473,7 +70785,7 @@ function getPathFlavor(value, peer) {
70473
70785
  return "posix";
70474
70786
  }
70475
70787
  function getPathApi(flavor) {
70476
- return flavor === "windows" ? path24.win32 : path24.posix;
70788
+ return flavor === "windows" ? path25.win32 : path25.posix;
70477
70789
  }
70478
70790
  function normalizeForComparison(value, flavor) {
70479
70791
  const pathApi = getPathApi(flavor);
@@ -70630,102 +70942,37 @@ var SessionSelectorComponent = class extends Container {
70630
70942
  var RESET = "\x1B[0m";
70631
70943
  var INVERSE = "\x1B[7m";
70632
70944
  var DIM = "\x1B[2m";
70633
- function visibleLength(str2) {
70634
- return visibleWidth(str2);
70635
- }
70945
+ var searchSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
70636
70946
  var TREE_CHARS = {
70637
70947
  branch: "\u251C\u2500\u2500 ",
70638
70948
  corner: "\u2514\u2500\u2500 ",
70639
70949
  pipe: "\u2502 ",
70640
70950
  space: " ",
70641
70951
  active: "\u25CF ",
70642
- inactive: "\u25CB "
70952
+ inactive: "\u25CB ",
70953
+ /** Marks rows whose full ancestry is not visible in the window. */
70954
+ hiddenAncestry: "\u2026"
70643
70955
  };
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) {
70956
+ var MIN_PAGE_SIZE = 48;
70957
+ var MAX_PAGE_SIZE = 256;
70958
+ var SEGMENT_WIDTH = 4;
70959
+ var MIN_BODY_WIDTH = 12;
70960
+ var PREFIX_DEPTH_ABS_CAP = 24;
70961
+ var SEARCH_SCAN_PAGE_LIMIT = 16;
70962
+ var COLLAPSED_CAP = 256;
70963
+ function roleName(summary) {
70964
+ if (summary.type === "fork") return "fork";
70965
+ if (summary.type === "compaction") return "compact";
70966
+ if (summary.type === "custom") return "custom";
70967
+ return summary.role ?? "entry";
70968
+ }
70969
+ function roleColor(role) {
70724
70970
  switch (role) {
70725
70971
  case "user":
70726
70972
  return theme.fg("accent", role);
70727
70973
  case "assistant":
70728
70974
  return theme.fg("text", role);
70975
+ case "toolResult":
70729
70976
  case "tool":
70730
70977
  return theme.fg("dim", role);
70731
70978
  case "fork":
@@ -70736,57 +70983,47 @@ function getRoleColor(role) {
70736
70983
  return theme.fg("muted", role);
70737
70984
  }
70738
70985
  }
70986
+ function seqFromEntryId(entryId) {
70987
+ if (!entryId) return null;
70988
+ const match = /^e(\d+)-/.exec(entryId);
70989
+ if (!match) return null;
70990
+ const seq = Number(match[1]);
70991
+ return Number.isInteger(seq) && seq > 0 ? seq : null;
70992
+ }
70739
70993
  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);
70994
+ const normalized = content.replace(/[\r\n]+/g, " ");
70995
+ const body = isSelected ? INVERSE + normalized : normalized;
70996
+ return truncateToWidth(body + RESET, width, "...", true);
70753
70997
  }
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;
70998
+ function clampPrefixForDisplay(prefix, budget) {
70999
+ if (budget <= 0) return "";
71000
+ if (prefix.length <= budget) return prefix;
71001
+ const keep = Math.floor((budget - 1) / SEGMENT_WIDTH) * SEGMENT_WIDTH;
71002
+ return TREE_CHARS.hiddenAncestry + (keep > 0 ? prefix.slice(-keep) : "");
70779
71003
  }
70780
71004
  var TreeSelectorComponent = class {
70781
- tree;
70782
- flatItems = [];
70783
- filteredItems = [];
71005
+ options;
71006
+ /** The single resident window of headers (bounded by pageSize). */
71007
+ pageSummaries = [];
71008
+ totalEntries;
71009
+ hasPrev = false;
71010
+ hasNext = false;
71011
+ rows = [];
71012
+ filteredRows = [];
70784
71013
  selectedIndex = 0;
70785
71014
  maxVisibleLines;
71015
+ pageSizeValue;
71016
+ prefixDepthCap;
70786
71017
  filterMode = "all";
70787
71018
  searchQuery = "";
70788
- expandedNodes = /* @__PURE__ */ new Set();
70789
- // Node IDs that are expanded
71019
+ statusMessage = null;
71020
+ collapsed = /* @__PURE__ */ new Map();
71021
+ // Bounded-memory instrumentation (tests/telemetry).
71022
+ maxResidentHeadersSeen = 0;
71023
+ maxPrefixCharsSeen = 0;
71024
+ currentTotalPrefixChars = 0;
71025
+ fetchCallCount = 0;
71026
+ headersFetchedTotal = 0;
70790
71027
  onSelect;
70791
71028
  onCancel;
70792
71029
  _focused = false;
@@ -70796,189 +71033,387 @@ var TreeSelectorComponent = class {
70796
71033
  set focused(value) {
70797
71034
  this._focused = value;
70798
71035
  }
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;
71036
+ constructor(options) {
71037
+ this.options = options;
71038
+ this.totalEntries = options.totalEntries;
71039
+ this.maxVisibleLines = Math.max(15, Math.floor(options.terminalHeight * 0.6));
71040
+ this.pageSizeValue = Math.max(MIN_PAGE_SIZE, Math.min(MAX_PAGE_SIZE, this.maxVisibleLines * 3));
71041
+ this.prefixDepthCap = Math.max(3, Math.min(PREFIX_DEPTH_ABS_CAP, this.maxVisibleLines));
71042
+ this.onSelect = options.onSelect;
71043
+ this.onCancel = options.onCancel;
71044
+ if (options.totalEntries === 0) {
71045
+ setTimeout(() => options.onCancel(), 100);
71046
+ return;
71047
+ }
71048
+ const activeSeq = this.resolveActiveSeq() ?? options.totalEntries;
71049
+ const afterSeq = Math.max(0, activeSeq - Math.floor(this.pageSizeValue / 2));
71050
+ this.loadWindow(afterSeq);
71051
+ this.selectNearestSeq(activeSeq);
71052
+ }
71053
+ /**
71054
+ * Locate the active entry without loading bodies: prefer the commit
71055
+ * sequence encoded in the entry id, then the deepest active-path seq
71056
+ * (children always commit after parents, so the max is the active leaf).
71057
+ */
71058
+ resolveActiveSeq() {
71059
+ const fromId = seqFromEntryId(this.options.activeEntryId);
71060
+ if (fromId !== null) return fromId;
71061
+ let deepest = 0;
71062
+ for (const seq of this.options.activePathSeqs) {
71063
+ if (seq > deepest) deepest = seq;
71064
+ }
71065
+ return deepest > 0 ? deepest : null;
71066
+ }
71067
+ /** Select the row whose seq equals `target`, else the nearest earlier row. */
71068
+ selectNearestSeq(target) {
71069
+ let chosen = -1;
71070
+ for (let i = 0; i < this.filteredRows.length; i++) {
71071
+ const seq = this.filteredRows[i].summary.seq;
71072
+ if (seq === target) {
71073
+ chosen = i;
71074
+ break;
70812
71075
  }
70813
- } else if (this.flatItems.length > 0) {
70814
- this.selectedIndex = this.flatItems.length - 1;
71076
+ if (seq < target) chosen = i;
70815
71077
  }
70816
- if (tree.length === 0) {
70817
- setTimeout(() => onCancel(), 100);
71078
+ this.selectedIndex = chosen === -1 ? 0 : chosen;
71079
+ }
71080
+ /** Current resident header count (tests/telemetry; one window only). */
71081
+ get loadedCount() {
71082
+ return this.pageSummaries.length;
71083
+ }
71084
+ /** High-water mark of resident headers across the component lifetime. */
71085
+ get maxResidentHeaders() {
71086
+ return this.maxResidentHeadersSeen;
71087
+ }
71088
+ /** High-water mark of per-row prefix characters. */
71089
+ get maxPrefixChars() {
71090
+ return this.maxPrefixCharsSeen;
71091
+ }
71092
+ /** Sum of prefix characters across the current rows. */
71093
+ get totalPrefixChars() {
71094
+ return this.currentTotalPrefixChars;
71095
+ }
71096
+ /** Configured header window size. */
71097
+ get pageSize() {
71098
+ return this.pageSizeValue;
71099
+ }
71100
+ /** Number of fetchSummaries calls issued. */
71101
+ get fetchCount() {
71102
+ return this.fetchCallCount;
71103
+ }
71104
+ /** Cumulative headers returned by fetchSummaries (all pages ever fetched). */
71105
+ get headersFetched() {
71106
+ return this.headersFetchedTotal;
71107
+ }
71108
+ /** Current collapsed-id count (bounded by COLLAPSED_CAP). */
71109
+ get collapsedCount() {
71110
+ return this.collapsed.size;
71111
+ }
71112
+ /** Seq of the selected row, or null when nothing is selected. */
71113
+ get selectedSeq() {
71114
+ return this.filteredRows[this.selectedIndex]?.summary.seq ?? null;
71115
+ }
71116
+ /** First and last seq of the resident window, or null when empty. */
71117
+ get windowSeqRange() {
71118
+ if (this.pageSummaries.length === 0) return null;
71119
+ return [this.pageSummaries[0].seq, this.pageSummaries[this.pageSummaries.length - 1].seq];
71120
+ }
71121
+ /**
71122
+ * Fetch one window of headers and adopt it as the single resident page.
71123
+ * The previous window is replaced (not merged), keeping residency at
71124
+ * O(pageSize). `upperExclusiveSeq` trims overlap when paging backward;
71125
+ * entries trimmed away still count toward hasNext so the forward
71126
+ * direction never strands a short history behind a backward page.
71127
+ * Returns false when the fetch adopted nothing (boundary/gap).
71128
+ */
71129
+ fetchWindow(afterSeq, upperExclusiveSeq) {
71130
+ const page = this.options.fetchSummaries(afterSeq > 0 ? afterSeq : void 0, this.pageSizeValue);
71131
+ this.fetchCallCount++;
71132
+ this.headersFetchedTotal += page.summaries.length;
71133
+ let summaries = page.summaries.length > this.pageSizeValue ? page.summaries.slice(0, this.pageSizeValue) : page.summaries;
71134
+ let trimmedAway = 0;
71135
+ if (upperExclusiveSeq !== null) {
71136
+ const kept = summaries.filter((summary) => summary.seq < upperExclusiveSeq);
71137
+ trimmedAway = summaries.length - kept.length;
71138
+ summaries = kept;
71139
+ }
71140
+ this.hasNext = page.hasMore || trimmedAway > 0;
71141
+ this.totalEntries = page.total;
71142
+ if (summaries.length === 0) {
71143
+ return false;
70818
71144
  }
71145
+ this.pageSummaries = summaries;
71146
+ this.maxResidentHeadersSeen = Math.max(this.maxResidentHeadersSeen, this.pageSummaries.length);
71147
+ this.hasPrev = summaries[0].seq > 1;
71148
+ this.rebuildRows();
71149
+ return true;
70819
71150
  }
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
- }
71151
+ loadWindow(afterSeq) {
71152
+ this.fetchWindow(afterSeq, null);
71153
+ }
71154
+ /**
71155
+ * Load the window immediately before the current one. Backs off (up to a
71156
+ * few attempts) around seq gaps, then reports the oldest boundary.
71157
+ */
71158
+ goToPreviousPage() {
71159
+ if (this.pageSummaries.length === 0 || !this.hasPrev) return false;
71160
+ const firstSeq = this.pageSummaries[0].seq;
71161
+ let back = Math.max(0, firstSeq - 1 - this.pageSizeValue);
71162
+ for (let attempt = 0; attempt < 4; attempt++) {
71163
+ if (this.fetchWindow(back, firstSeq)) {
71164
+ this.selectedIndex = Math.max(0, this.filteredRows.length - 1);
71165
+ return true;
70827
71166
  }
70828
- };
70829
- expand(this.tree);
71167
+ if (back === 0) break;
71168
+ back = Math.max(0, back - this.pageSizeValue);
71169
+ }
71170
+ this.hasPrev = false;
71171
+ return false;
70830
71172
  }
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
- }
71173
+ /** Load the window immediately after the current one. */
71174
+ goToNextPage() {
71175
+ if (this.pageSummaries.length === 0 || !this.hasNext) return false;
71176
+ const lastSeq = this.pageSummaries[this.pageSummaries.length - 1].seq;
71177
+ let anchor = lastSeq;
71178
+ for (let attempt = 0; attempt < 4; attempt++) {
71179
+ if (this.fetchWindow(anchor, null)) {
71180
+ this.selectedIndex = 0;
71181
+ return true;
70838
71182
  }
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);
71183
+ if (!this.hasNext) break;
71184
+ anchor += this.pageSizeValue;
71185
+ }
71186
+ return false;
71187
+ }
71188
+ /**
71189
+ * Iteratively flatten the resident window. Parents always commit before
71190
+ * children, so one forward pass resolves in-window ancestry; an explicit
71191
+ * stack (no recursion) emits DFS rows whose prefixes are capped to
71192
+ * prefixDepthCap segments, so prefix memory stays O(rows).
71193
+ */
71194
+ rebuildRows() {
71195
+ const count = this.pageSummaries.length;
71196
+ const seqToIndex = /* @__PURE__ */ new Map();
71197
+ const depth = new Int32Array(count);
71198
+ const parentIndex = new Int32Array(count).fill(-1);
71199
+ const childLists = new Array(count);
71200
+ for (let i = 0; i < count; i++) {
71201
+ const summary = this.pageSummaries[i];
71202
+ seqToIndex.set(summary.seq, i);
71203
+ const parent = summary.parentSeq === null ? -1 : seqToIndex.get(summary.parentSeq) ?? -1;
71204
+ if (parent >= 0) {
71205
+ depth[i] = depth[parent] + 1;
71206
+ parentIndex[i] = parent;
71207
+ const bucket = childLists[parent];
71208
+ if (bucket) bucket.push(i);
71209
+ else childLists[parent] = [i];
71210
+ }
71211
+ }
71212
+ const capChars = this.prefixDepthCap * SEGMENT_WIDTH;
71213
+ const capSegments = (segments) => segments.length > capChars ? segments.slice(segments.length - capChars) : segments;
71214
+ const roots = [];
71215
+ for (let i = 0; i < count; i++) {
71216
+ if (parentIndex[i] === -1) roots.push(i);
71217
+ }
71218
+ const rows = [];
71219
+ const stack = [];
71220
+ for (let i = roots.length - 1; i >= 0; i--) {
71221
+ stack.push({ index: roots[i], base: "", isLast: i === roots.length - 1 });
71222
+ }
71223
+ while (stack.length > 0) {
71224
+ const item = stack.pop();
71225
+ const summary = this.pageSummaries[item.index];
71226
+ const rowDepth = depth[item.index];
71227
+ const connector = rowDepth === 0 ? "" : item.isLast ? TREE_CHARS.corner : TREE_CHARS.branch;
71228
+ const segments = capSegments(item.base + connector);
71229
+ const ancestryHidden = rowDepth > this.prefixDepthCap || summary.parentSeq !== null && parentIndex[item.index] === -1;
71230
+ const prefix = ancestryHidden ? TREE_CHARS.hiddenAncestry + segments : segments;
71231
+ rows.push({
71232
+ summary,
71233
+ prefix,
71234
+ hasChildren: summary.childCount > 0,
71235
+ inWindowChildren: childLists[item.index] !== void 0
71236
+ });
71237
+ if (prefix.length > this.maxPrefixCharsSeen) this.maxPrefixCharsSeen = prefix.length;
71238
+ if (this.collapsed.has(summary.id)) continue;
71239
+ const children = childLists[item.index];
71240
+ if (children === void 0) continue;
71241
+ const childBase = capSegments(item.base + (item.isLast ? TREE_CHARS.space : TREE_CHARS.pipe));
71242
+ for (let i = children.length - 1; i >= 0; i--) {
71243
+ stack.push({ index: children[i], base: childBase, isLast: i === children.length - 1 });
71244
+ }
71245
+ }
71246
+ this.rows = rows;
71247
+ let totalPrefix = 0;
71248
+ for (const row of rows) totalPrefix += row.prefix.length;
71249
+ this.currentTotalPrefixChars = totalPrefix;
70854
71250
  this.applyFilter();
70855
71251
  }
70856
71252
  applyFilter() {
70857
71253
  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") {
71254
+ this.filteredRows = this.rows;
71255
+ } else {
71256
+ const tokens = this.searchQuery.toLowerCase().split(/\s+/).filter(Boolean);
71257
+ this.filteredRows = this.rows.filter((row) => {
71258
+ if (this.filterMode === "user-only" && (row.summary.type !== "message" || row.summary.role !== "user")) {
70866
71259
  return false;
70867
71260
  }
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
- );
71261
+ if (tokens.length === 0) return true;
71262
+ const text = `${row.summary.preview ?? ""} ${roleName(row.summary)} ${row.summary.customType ?? ""} ${row.summary.label ?? ""} ${row.summary.seq}`.toLowerCase();
71263
+ return tokens.every((token) => text.includes(token));
71264
+ });
71265
+ }
71266
+ this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, this.filteredRows.length - 1));
70882
71267
  }
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));
71268
+ moveUp() {
71269
+ if (this.selectedIndex > 0) {
71270
+ this.selectedIndex--;
71271
+ this.statusMessage = null;
71272
+ return;
71273
+ }
71274
+ if (this.goToPreviousPage()) {
71275
+ this.statusMessage = null;
71276
+ return;
71277
+ }
71278
+ this.selectedIndex = 0;
71279
+ this.statusMessage = "at oldest entry";
71280
+ }
71281
+ moveDown() {
71282
+ if (this.selectedIndex < this.filteredRows.length - 1) {
71283
+ this.selectedIndex++;
71284
+ this.statusMessage = null;
71285
+ return;
71286
+ }
71287
+ if (this.goToNextPage()) {
71288
+ this.statusMessage = null;
71289
+ return;
71290
+ }
71291
+ this.statusMessage = this.filteredRows.length === 0 && this.searchQuery ? "no matches on this page - tab scans ahead" : "at latest entry";
71292
+ }
71293
+ pageNext() {
71294
+ if (this.goToNextPage()) {
71295
+ this.statusMessage = null;
70890
71296
  } else {
70891
- parts.push(...prefixes);
71297
+ this.statusMessage = this.pageSummaries.length === 0 ? "no entries" : "latest page";
70892
71298
  }
70893
- if (item.depth > 0) {
70894
- parts.push(item.isLast ? TREE_CHARS.corner : TREE_CHARS.branch);
71299
+ }
71300
+ pagePrev() {
71301
+ if (this.goToPreviousPage()) {
71302
+ this.statusMessage = null;
71303
+ } else {
71304
+ this.statusMessage = this.pageSummaries.length === 0 ? "no entries" : "oldest page";
70895
71305
  }
70896
- return parts.join("");
71306
+ }
71307
+ /**
71308
+ * Bounded "next match": step to the next in-page match, otherwise scan
71309
+ * forward at most SEARCH_SCAN_PAGE_LIMIT pages per press. Never scans
71310
+ * the whole history eagerly and never accumulates fetched pages.
71311
+ */
71312
+ findNextMatch() {
71313
+ if (!this.searchQuery && this.filterMode === "all") {
71314
+ this.pageNext();
71315
+ return;
71316
+ }
71317
+ if (this.filteredRows.length > 1 && this.selectedIndex < this.filteredRows.length - 1) {
71318
+ this.selectedIndex++;
71319
+ this.statusMessage = null;
71320
+ return;
71321
+ }
71322
+ let scanned = 0;
71323
+ while (this.hasNext && scanned < SEARCH_SCAN_PAGE_LIMIT) {
71324
+ if (!this.goToNextPage()) break;
71325
+ scanned++;
71326
+ if (this.filteredRows.length > 0) {
71327
+ this.selectedIndex = 0;
71328
+ this.statusMessage = scanned === 1 ? "match on next page" : `match ${scanned} pages ahead`;
71329
+ return;
71330
+ }
71331
+ }
71332
+ if (!this.hasNext) {
71333
+ this.statusMessage = "no more matches - end of history";
71334
+ } else {
71335
+ this.statusMessage = `no matches in next ${scanned} pages - tab to continue`;
71336
+ }
71337
+ }
71338
+ toggleCollapse() {
71339
+ const selected = this.filteredRows[this.selectedIndex];
71340
+ if (!selected) return;
71341
+ if (this.collapsed.has(selected.summary.id)) {
71342
+ this.collapsed.delete(selected.summary.id);
71343
+ } else {
71344
+ if (this.collapsed.size >= COLLAPSED_CAP) {
71345
+ const oldest = this.collapsed.keys().next().value;
71346
+ if (oldest !== void 0) this.collapsed.delete(oldest);
71347
+ }
71348
+ this.collapsed.set(selected.summary.id, true);
71349
+ }
71350
+ this.rebuildRows();
70897
71351
  }
70898
71352
  render(width) {
70899
71353
  const lines = [];
70900
71354
  const totalLines = this.maxVisibleLines + 5;
71355
+ const range = this.windowSeqRange;
71356
+ const rangeLabel = range === null ? "empty" : `seqs ${range[0]}-${range[1]} of ${this.totalEntries}`;
70901
71357
  lines.push(createLine(" Conversation Tree", width, false));
70902
71358
  lines.push(
70903
71359
  createLine(
70904
- " \u2191\u2193:move \u2190\u2192:page e:expand/collapse F:fork Enter:navigate Esc:cancel",
71360
+ " \u2191\u2193:move \u2190\u2192:page e:collapse tab:next match F:fork Enter:navigate Esc:cancel",
70905
71361
  width,
70906
71362
  false
70907
71363
  )
70908
71364
  );
70909
71365
  lines.push(
70910
71366
  createLine(
70911
- this.searchQuery ? ` Search: ${this.searchQuery}` : " Type to search",
71367
+ this.searchQuery ? ` Search: ${this.searchQuery} (${this.filteredRows.length} on this page, tab:next match)` : ` Type to search (${rangeLabel})`,
70912
71368
  width,
70913
71369
  false
70914
71370
  )
70915
71371
  );
70916
- lines.push(createLine("", width, false));
70917
- if (this.filteredItems.length === 0) {
70918
- for (let i = 0; i < this.maxVisibleLines; i++) {
71372
+ lines.push(createLine(this.statusMessage ? ` ${this.statusMessage}` : "", width, false));
71373
+ if (this.filteredRows.length === 0) {
71374
+ const notice = this.searchQuery || this.filterMode === "user-only" ? " (no matching entries on this page)" : " (no entries)";
71375
+ lines.push(createLine(notice, width, false));
71376
+ for (let i = 1; i < this.maxVisibleLines; i++) {
70919
71377
  lines.push(createLine("", width, false));
70920
71378
  }
70921
71379
  } else {
70922
- this.selectedIndex = Math.max(
70923
- 0,
70924
- Math.min(this.selectedIndex, this.filteredItems.length - 1)
70925
- );
71380
+ this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, this.filteredRows.length - 1));
70926
71381
  let startIndex = Math.max(
70927
71382
  0,
70928
71383
  Math.min(
70929
71384
  this.selectedIndex - Math.floor(this.maxVisibleLines / 2),
70930
- this.filteredItems.length - this.maxVisibleLines
71385
+ this.filteredRows.length - this.maxVisibleLines
70931
71386
  )
70932
71387
  );
70933
- let endIndex = Math.min(
70934
- startIndex + this.maxVisibleLines,
70935
- this.filteredItems.length
70936
- );
71388
+ const endIndex = Math.min(startIndex + this.maxVisibleLines, this.filteredRows.length);
70937
71389
  if (endIndex - startIndex < this.maxVisibleLines && startIndex > 0) {
70938
71390
  startIndex = Math.max(0, endIndex - this.maxVisibleLines);
70939
71391
  }
70940
71392
  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++) {
71393
+ const row = this.filteredRows[i];
71394
+ const activeIndicator = this.options.activePathSeqs.has(row.summary.seq) ? theme.fg("success", TREE_CHARS.active) : DIM + TREE_CHARS.inactive + RESET;
71395
+ const expandIndicator = row.inWindowChildren ? theme.fg("dim", this.collapsed.has(row.summary.id) ? "\u25B6 " : "\u25BC ") : row.hasChildren ? theme.fg("dim", "\xB7\xB7") : " ";
71396
+ const role = roleColor(roleName(row.summary));
71397
+ const indicatorWidth = visibleWidth(activeIndicator) + visibleWidth(expandIndicator) + visibleWidth(role) + 2;
71398
+ const prefixBudget = Math.max(0, Math.min(Math.floor(width * 0.35), width - indicatorWidth - MIN_BODY_WIDTH));
71399
+ const displayPrefix = clampPrefixForDisplay(row.prefix, prefixBudget);
71400
+ const availableWidth = Math.max(0, width - visibleWidth(displayPrefix) - indicatorWidth);
71401
+ const content = truncateToWidth(row.summary.preview ?? "", availableWidth);
71402
+ lines.push(createLine(`${displayPrefix}${activeIndicator}${expandIndicator}${role}: ${content}`, width, i === this.selectedIndex));
71403
+ }
71404
+ for (let i = endIndex - startIndex; i < this.maxVisibleLines; i++) {
70970
71405
  lines.push(createLine("", width, false));
70971
71406
  }
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
71407
  }
71408
+ const selectedRow = this.filteredRows[this.selectedIndex];
71409
+ const activePath = selectedRow && this.options.activePathSeqs.has(selectedRow.summary.seq) ? " [active]" : "";
71410
+ lines.push(
71411
+ createLine(
71412
+ ` (${selectedRow ? this.selectedIndex + 1 : 0}/${this.filteredRows.length})${this.filterMode === "user-only" ? " [user]" : ""}${activePath} \xB7 ${rangeLabel}`,
71413
+ width,
71414
+ false
71415
+ )
71416
+ );
70982
71417
  while (lines.length < totalLines) {
70983
71418
  lines.push(createLine("", width, false));
70984
71419
  }
@@ -70987,51 +71422,24 @@ var TreeSelectorComponent = class {
70987
71422
  handleInput(keyData) {
70988
71423
  const kb = getEditorKeybindings();
70989
71424
  if (kb.matches(keyData, "selectUp")) {
70990
- this.selectedIndex = Math.max(0, this.selectedIndex - 1);
71425
+ this.moveUp();
70991
71426
  } 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);
71427
+ this.moveDown();
71428
+ } else if (kb.matches(keyData, "cursorRight") || kb.matches(keyData, "selectPageDown")) {
71429
+ this.pageNext();
71430
+ } else if (kb.matches(keyData, "cursorLeft") || kb.matches(keyData, "selectPageUp")) {
71431
+ this.pagePrev();
71003
71432
  } 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
- }
71433
+ this.toggleCollapse();
71026
71434
  } else if (kb.matches(keyData, "selectConfirm")) {
71027
- const selected = this.filteredItems[this.selectedIndex];
71435
+ const selected = this.filteredRows[this.selectedIndex];
71028
71436
  if (selected && this.onSelect) {
71029
- this.onSelect(selected.node.id, "navigate");
71437
+ this.onSelect(selected.summary.id, "navigate");
71030
71438
  }
71031
71439
  } else if (keyData === "f" || keyData === "F") {
71032
- const selected = this.filteredItems[this.selectedIndex];
71440
+ const selected = this.filteredRows[this.selectedIndex];
71033
71441
  if (selected && this.onSelect) {
71034
- this.onSelect(selected.node.id, "fork");
71442
+ this.onSelect(selected.summary.id, "fork");
71035
71443
  }
71036
71444
  } else if (kb.matches(keyData, "selectCancel")) {
71037
71445
  if (this.searchQuery) {
@@ -71040,12 +71448,15 @@ var TreeSelectorComponent = class {
71040
71448
  } else {
71041
71449
  this.onCancel?.();
71042
71450
  }
71451
+ } else if (matchesKey(keyData, "tab")) {
71452
+ this.findNextMatch();
71043
71453
  } else if (matchesKey(keyData, "ctrl+u")) {
71044
71454
  this.filterMode = this.filterMode === "user-only" ? "all" : "user-only";
71045
71455
  this.applyFilter();
71046
71456
  } else if (kb.matches(keyData, "deleteCharBackward")) {
71047
71457
  if (this.searchQuery.length > 0) {
71048
- this.searchQuery = this.searchQuery.slice(0, -1);
71458
+ const last = searchSegmenter.segment(this.searchQuery).containing(this.searchQuery.length - 1);
71459
+ this.searchQuery = this.searchQuery.slice(0, last?.index ?? 0);
71049
71460
  this.applyFilter();
71050
71461
  }
71051
71462
  } else {
@@ -71060,10 +71471,10 @@ var TreeSelectorComponent = class {
71060
71471
  }
71061
71472
  }
71062
71473
  invalidate() {
71063
- this.refreshFlatItems();
71474
+ this.rebuildRows();
71064
71475
  }
71065
71476
  getSelectedEntryId() {
71066
- return this.filteredItems[this.selectedIndex]?.node.id ?? null;
71477
+ return this.filteredRows[this.selectedIndex]?.summary.id ?? null;
71067
71478
  }
71068
71479
  };
71069
71480
 
@@ -71265,16 +71676,16 @@ var Diff = class {
71265
71676
  }
71266
71677
  }
71267
71678
  }
71268
- addToPath(path33, added, removed, oldPosInc, options) {
71269
- const last = path33.lastComponent;
71679
+ addToPath(path34, added, removed, oldPosInc, options) {
71680
+ const last = path34.lastComponent;
71270
71681
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
71271
71682
  return {
71272
- oldPos: path33.oldPos + oldPosInc,
71683
+ oldPos: path34.oldPos + oldPosInc,
71273
71684
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
71274
71685
  };
71275
71686
  } else {
71276
71687
  return {
71277
- oldPos: path33.oldPos + oldPosInc,
71688
+ oldPos: path34.oldPos + oldPosInc,
71278
71689
  lastComponent: { count: 1, added, removed, previousComponent: last }
71279
71690
  };
71280
71691
  }
@@ -71722,13 +72133,13 @@ function formatSize2(bytes) {
71722
72133
  }
71723
72134
  var DEFAULT_MAX_BYTES = 102400;
71724
72135
  var DEFAULT_MAX_LINES = 100;
71725
- function shortenPath(path33) {
71726
- if (typeof path33 !== "string") return "";
72136
+ function shortenPath(path34) {
72137
+ if (typeof path34 !== "string") return "";
71727
72138
  const home = os5.homedir();
71728
- if (path33.startsWith(home)) {
71729
- return `~${path33.slice(home.length)}`;
72139
+ if (path34.startsWith(home)) {
72140
+ return `~${path34.slice(home.length)}`;
71730
72141
  }
71731
- return path33;
72142
+ return path34;
71732
72143
  }
71733
72144
  function replaceTabs(text) {
71734
72145
  return text.replace(/\t/g, " ");
@@ -71738,6 +72149,18 @@ function str(value) {
71738
72149
  if (value == null) return "";
71739
72150
  return null;
71740
72151
  }
72152
+ function projectResultForDisplay(result) {
72153
+ const content = result.content;
72154
+ if (!Array.isArray(content) || !content.some((block) => typeof block?.data === "string" && block.data.length > 0)) {
72155
+ return result;
72156
+ }
72157
+ return {
72158
+ ...result,
72159
+ content: content.map(
72160
+ (block) => typeof block?.data === "string" && block.data.length > 0 ? { ...block, data: "" } : block
72161
+ )
72162
+ };
72163
+ }
71741
72164
  function partialStr(value, maxLen = 30) {
71742
72165
  if (typeof value === "string") {
71743
72166
  if (value.length === 0) return "...";
@@ -71772,7 +72195,7 @@ var ToolExecutionComponent = class extends Container {
71772
72195
  this.updateDisplay();
71773
72196
  }
71774
72197
  updateResult(result, isPartial = false) {
71775
- this.result = result;
72198
+ this.result = projectResultForDisplay(result);
71776
72199
  this.isPartial = isPartial;
71777
72200
  this.updateDisplay();
71778
72201
  }
@@ -71811,14 +72234,14 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
71811
72234
  }
71812
72235
  } else if (this.toolName === "read_file") {
71813
72236
  const rawPath = str(this.args?.file_path ?? this.args?.path);
71814
- const path33 = rawPath !== null ? shortenPath(rawPath) : null;
72237
+ const path34 = rawPath !== null ? shortenPath(rawPath) : null;
71815
72238
  const offset = typeof this.args?.offset === "number" ? this.args.offset : void 0;
71816
72239
  const limit = typeof this.args?.limit === "number" ? this.args.limit : void 0;
71817
72240
  let pathDisplay;
71818
- if (path33 === null) {
72241
+ if (path34 === null) {
71819
72242
  pathDisplay = invalidArg;
71820
- } else if (path33) {
71821
- pathDisplay = theme.fg("accent", path33);
72243
+ } else if (path34) {
72244
+ pathDisplay = theme.fg("accent", path34);
71822
72245
  } else {
71823
72246
  const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
71824
72247
  pathDisplay = theme.fg("toolOutput", partialPath);
@@ -71865,12 +72288,12 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
71865
72288
  } else if (this.toolName === "write_file") {
71866
72289
  const rawPath = str(this.args?.file_path ?? this.args?.path);
71867
72290
  const fileContent = str(this.args?.content);
71868
- const path33 = rawPath !== null ? shortenPath(rawPath) : null;
72291
+ const path34 = rawPath !== null ? shortenPath(rawPath) : null;
71869
72292
  let pathDisplay;
71870
- if (path33 === null) {
72293
+ if (path34 === null) {
71871
72294
  pathDisplay = invalidArg;
71872
- } else if (path33) {
71873
- pathDisplay = theme.fg("accent", path33);
72295
+ } else if (path34) {
72296
+ pathDisplay = theme.fg("accent", path34);
71874
72297
  } else {
71875
72298
  const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
71876
72299
  pathDisplay = theme.fg("toolOutput", partialPath);
@@ -71907,12 +72330,12 @@ ${theme.fg("error", errorText)}`;
71907
72330
  }
71908
72331
  } else if (this.toolName === "edit_file") {
71909
72332
  const rawPath = str(this.args?.file_path ?? this.args?.path);
71910
- const path33 = rawPath !== null ? shortenPath(rawPath) : null;
72333
+ const path34 = rawPath !== null ? shortenPath(rawPath) : null;
71911
72334
  let pathDisplay;
71912
- if (path33 === null) {
72335
+ if (path34 === null) {
71913
72336
  pathDisplay = invalidArg;
71914
- } else if (path33) {
71915
- pathDisplay = theme.fg("accent", path33);
72337
+ } else if (path34) {
72338
+ pathDisplay = theme.fg("accent", path34);
71916
72339
  } else {
71917
72340
  const partialPath = partialStr(this.args?.file_path ?? this.args?.path);
71918
72341
  pathDisplay = theme.fg("toolOutput", partialPath);
@@ -71937,7 +72360,7 @@ ${theme.fg("error", errorText)}`;
71937
72360
  const diff = this.result.details.diff;
71938
72361
  const firstChangedLine = this.result.details.firstChangedLine;
71939
72362
  if (firstChangedLine) {
71940
- text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path33 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
72363
+ text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path34 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
71941
72364
  }
71942
72365
  const lines = diff.split("\n");
71943
72366
  const maxLines = this.expanded ? lines.length : 15;
@@ -71957,7 +72380,7 @@ ${theme.fg("error", errorText)}`;
71957
72380
  const diff = generateEditDiff(oldText, newText, rawPath);
71958
72381
  const firstChangedLine = findFirstChangedLine(oldText, newText);
71959
72382
  if (firstChangedLine) {
71960
- text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path33 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
72383
+ text = `${theme.fg("toolTitle", theme.bold("edit_file"))} ${theme.fg("accent", path34 || rawPath)}${theme.fg("warning", `:${firstChangedLine}`)}`;
71961
72384
  }
71962
72385
  const lines = diff.split("\n");
71963
72386
  const maxLines = this.expanded ? lines.length : 15;
@@ -71976,9 +72399,9 @@ ${theme.fg("error", errorText)}`;
71976
72399
  }
71977
72400
  } else if (this.toolName === "list_dir") {
71978
72401
  const rawPath = str(this.args?.path);
71979
- const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72402
+ const path34 = rawPath !== null ? shortenPath(rawPath || ".") : null;
71980
72403
  const limit = this.args?.limit;
71981
- text = `${theme.fg("toolTitle", theme.bold("list_dir"))} ${path33 === null ? invalidArg : theme.fg("accent", path33)}`;
72404
+ text = `${theme.fg("toolTitle", theme.bold("list_dir"))} ${path34 === null ? invalidArg : theme.fg("accent", path34)}`;
71982
72405
  if (limit !== void 0) {
71983
72406
  text += theme.fg("toolOutput", ` (limit ${limit})`);
71984
72407
  }
@@ -72014,9 +72437,9 @@ ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
72014
72437
  } else if (this.toolName === "find_files") {
72015
72438
  const pattern = str(this.args?.pattern);
72016
72439
  const rawPath = str(this.args?.path);
72017
- const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72440
+ const path34 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72018
72441
  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}`);
72442
+ text = theme.fg("toolTitle", theme.bold("find_files")) + " " + (pattern === null ? invalidArg : theme.fg("accent", pattern || "")) + theme.fg("toolOutput", ` in ${path34 === null ? invalidArg : path34}`);
72020
72443
  if (limit !== void 0) {
72021
72444
  text += theme.fg("toolOutput", ` (limit ${limit})`);
72022
72445
  }
@@ -72052,10 +72475,10 @@ ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
72052
72475
  } else if (this.toolName === "grep_text") {
72053
72476
  const pattern = str(this.args?.pattern);
72054
72477
  const rawPath = str(this.args?.path);
72055
- const path33 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72478
+ const path34 = rawPath !== null ? shortenPath(rawPath || ".") : null;
72056
72479
  const glob = str(this.args?.glob);
72057
72480
  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}`);
72481
+ text = theme.fg("toolTitle", theme.bold("grep_text")) + " " + (pattern === null ? invalidArg : theme.fg("accent", `/${pattern || ""}/`)) + theme.fg("toolOutput", ` in ${path34 === null ? invalidArg : path34}`);
72059
72482
  if (glob) {
72060
72483
  text += theme.fg("toolOutput", ` (${glob})`);
72061
72484
  }
@@ -72278,7 +72701,7 @@ async function handleResumeCommand(host) {
72278
72701
  return { component: selector, focus: selector.getSelectList() };
72279
72702
  });
72280
72703
  }
72281
- async function loadSession2(host, sessionId) {
72704
+ async function loadSession(host, sessionId) {
72282
72705
  const beforeSwitch = await host.extensionRunner?.emitSessionBeforeSwitch({
72283
72706
  type: "session:before_switch",
72284
72707
  reason: "resume",
@@ -72475,29 +72898,31 @@ function setWaitingForUser(host, waiting) {
72475
72898
  syncTitleActivity(host);
72476
72899
  }
72477
72900
  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})`);
72901
+ const head = host.sessionManager.getEntrySummariesPage({ limit: 1 });
72902
+ if (head.total === 0) {
72903
+ host.showStatus(`No entries in current session (entries: 0)`);
72482
72904
  return;
72483
72905
  }
72484
72906
  host.showSelector((done) => {
72485
72907
  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);
72908
+ {
72909
+ terminalHeight: host.ui.terminal.rows,
72910
+ activeEntryId: host.sessionManager.getActiveEntryId(),
72911
+ activePathSeqs: host.sessionManager.getActivePathSeqs(),
72912
+ totalEntries: head.total,
72913
+ fetchSummaries: (afterSeq, limit) => host.sessionManager.getEntrySummariesPage({ limit, afterSeq }),
72914
+ onSelect: async (entryId, action) => {
72915
+ done();
72916
+ if (action === "fork") {
72917
+ await host.forkAtEntry(entryId);
72918
+ } else {
72919
+ await host.navigateToEntry(entryId);
72920
+ }
72921
+ },
72922
+ onCancel: () => {
72923
+ done();
72494
72924
  }
72495
- },
72496
- () => {
72497
- done();
72498
- },
72499
- host.sessionManager.getActiveEntryId()
72500
- // Start at active entry
72925
+ }
72501
72926
  );
72502
72927
  return { component: selector, focus: selector };
72503
72928
  });
@@ -72514,8 +72939,8 @@ async function forkAtEntry(host, entryId) {
72514
72939
  host.showError("Failed to branch at entry");
72515
72940
  return;
72516
72941
  }
72517
- const path33 = host.sessionManager.getPathToEntry(entryId);
72518
- const pathNames = path33.map((e) => e.message?.role || "entry").join(" \u2192 ");
72942
+ const path34 = host.sessionManager.getPathSummaries(entryId);
72943
+ const pathNames = path34.map((summary) => summary.role || summary.type).join(" \u2192 ");
72519
72944
  const messages = host.sessionManager.getMessages();
72520
72945
  host.syncAgentFromActiveSession(messages);
72521
72946
  await host.syncSessionScopedState(messages);
@@ -72528,7 +72953,7 @@ async function forkAtEntry(host, entryId) {
72528
72953
  host.updatePendingMessagesDisplay();
72529
72954
  host.renderMessageHistory(messages);
72530
72955
  await host.sessionManager.save();
72531
- host.showStatus(`Branched at: ${pathNames} (${path33.length} messages). Continue to add to this branch.`);
72956
+ host.showStatus(`Branched at: ${pathNames} (${path34.length} messages). Continue to add to this branch.`);
72532
72957
  } catch (error) {
72533
72958
  host.showError(
72534
72959
  `Failed to branch: ${error instanceof Error ? error.message : String(error)}`
@@ -72556,10 +72981,10 @@ async function navigateToEntry(host, entryId) {
72556
72981
  host.sessionManager.save().catch((err) => {
72557
72982
  console.error("[Session] Save after navigation failed:", err);
72558
72983
  });
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)`);
72984
+ const path34 = host.sessionManager.getPathSummaries(entryId);
72985
+ const summary = host.sessionManager.getEntrySummary(entryId);
72986
+ const role = summary?.role || summary?.type || "entry";
72987
+ host.showStatus(`Switched to branch: ${role} (${path34.length} entries in path)`);
72563
72988
  } catch (error) {
72564
72989
  host.showError(
72565
72990
  `Failed to navigate: ${error instanceof Error ? error.message : String(error)}`
@@ -72654,9 +73079,9 @@ async function handleForkCommand(host) {
72654
73079
  }
72655
73080
 
72656
73081
  // src/commands/interactive-skill-commands.ts
72657
- import * as fs23 from "fs";
73082
+ import * as fs24 from "fs";
72658
73083
  import * as os7 from "os";
72659
- import * as path25 from "path";
73084
+ import * as path26 from "path";
72660
73085
 
72661
73086
  // src/commands/subagent-command.ts
72662
73087
  async function handleSubagentCommand(host, args) {
@@ -72793,9 +73218,9 @@ function handleSkillsCommand(host) {
72793
73218
  });
72794
73219
  }
72795
73220
  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");
73221
+ const builtinDir = path26.join(getBuiltinDir(), "skills");
73222
+ const userDir = path26.join(os7.homedir(), ".pie", "skills");
73223
+ const projectDir = path26.join(process.cwd(), ".pie", "skills");
72799
73224
  return loadSkills({ dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: process.cwd() }) });
72800
73225
  }
72801
73226
  function listDiscoveredSkills(host) {
@@ -72927,7 +73352,7 @@ function expandSkillCommand(host, text) {
72927
73352
  const skill = host.skills.find((s) => s.name === skillName);
72928
73353
  if (!skill) return text;
72929
73354
  try {
72930
- const content = fs23.readFileSync(skill.filePath, "utf-8");
73355
+ const content = fs24.readFileSync(skill.filePath, "utf-8");
72931
73356
  const body = host.stripFrontmatter(content).trim();
72932
73357
  const skillBlock = `<skill name="${skill.name}" location="${skill.filePath}">
72933
73358
  References are relative to ${skill.baseDir}.
@@ -72954,9 +73379,9 @@ async function handleSkillToggleCommand(host, args, enabled) {
72954
73379
  host.showError(`Usage: /skills/${enabled ? "enable" : "disable"} <name>`);
72955
73380
  return;
72956
73381
  }
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");
73382
+ const builtinDir = path26.join(getBuiltinDir(), "skills");
73383
+ const userDir = path26.join(os7.homedir(), ".pie", "skills");
73384
+ const projectDir = path26.join(process.cwd(), ".pie", "skills");
72960
73385
  const discovered = loadSkills({ dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: process.cwd() }) }).skills;
72961
73386
  if (!discovered.some((skill) => skill.name === name)) {
72962
73387
  host.showError(`Skill not found: ${name}`);
@@ -73022,17 +73447,17 @@ async function handleSkillsCreate(host, args) {
73022
73447
  if (!description) {
73023
73448
  description = `Skill for ${name}`;
73024
73449
  }
73025
- const skillsDir = path25.join(os7.homedir(), ".pie", "skills");
73026
- const skillDir = path25.join(skillsDir, name);
73027
- const skillFile = path25.join(skillDir, "SKILL.md");
73450
+ const skillsDir = path26.join(os7.homedir(), ".pie", "skills");
73451
+ const skillDir = path26.join(skillsDir, name);
73452
+ const skillFile = path26.join(skillDir, "SKILL.md");
73028
73453
  debugLog2(`Creating at: ${skillFile}`);
73029
- if (fs23.existsSync(skillDir)) {
73454
+ if (fs24.existsSync(skillDir)) {
73030
73455
  host.showError(`Skill "${name}" already exists at ${skillDir}`);
73031
73456
  return;
73032
73457
  }
73033
- fs23.mkdirSync(skillDir, { recursive: true });
73458
+ fs24.mkdirSync(skillDir, { recursive: true });
73034
73459
  const template = createSkillTemplate(name, description);
73035
- fs23.writeFileSync(skillFile, template, "utf-8");
73460
+ fs24.writeFileSync(skillFile, template, "utf-8");
73036
73461
  debugLog2("Successfully created skill");
73037
73462
  host.chatContainer.addChild(new Spacer(1));
73038
73463
  host.chatContainer.addChild(new Text(theme.fg("accent", `\u2713 Created skill: ${name}`), 1, 0));
@@ -73778,6 +74203,7 @@ function createExtensionContextForCommands(host) {
73778
74203
  },
73779
74204
  getRuntimeTools: () => host.agent.state.tools,
73780
74205
  resolveModelClass: (modelClass) => host.options.modelRegistry.resolveModelClass(modelClass),
74206
+ resolveModelRef: (modelRef) => host.options.modelRegistry.resolveModelRef(modelRef),
73781
74207
  getMessages: () => host.agent.state.messages,
73782
74208
  getSessionMetadata: () => ({ ...host.sessionManager.getActiveSession()?.metadata ?? {} }),
73783
74209
  setSessionMetadata: (key, value) => {
@@ -73968,8 +74394,7 @@ async function handleCompactCommand(host) {
73968
74394
  host.showStatus("Nothing to compact yet");
73969
74395
  return;
73970
74396
  }
73971
- const pathEntries = host.sessionManager.getPathToEntry(activeEntryId);
73972
- const firstKeptEntryId = findFirstKeptEntryId(pathEntries);
74397
+ const firstKeptEntryId = findFirstKeptEntrySummaryId(host.sessionManager.getActiveContextSummaries());
73973
74398
  if (!firstKeptEntryId) {
73974
74399
  host.showStatus("Need at least one real user message before compacting");
73975
74400
  return;
@@ -74885,8 +75310,8 @@ function setupInteractiveEditorSubmitHandler(host) {
74885
75310
  }
74886
75311
 
74887
75312
  // src/input/interactive-file-pipeline.ts
74888
- import * as fs26 from "fs";
74889
- import * as path28 from "path";
75313
+ import * as fs27 from "fs";
75314
+ import * as path29 from "path";
74890
75315
 
74891
75316
  // src/components/file-picker.ts
74892
75317
  var FilePickerComponent = class extends Container {
@@ -75107,8 +75532,8 @@ var FilePickerComponent = class extends Container {
75107
75532
  };
75108
75533
 
75109
75534
  // src/files/commands/file-commands.ts
75110
- import * as fs24 from "node:fs";
75111
- import * as path26 from "node:path";
75535
+ import * as fs25 from "node:fs";
75536
+ import * as path27 from "node:path";
75112
75537
  var FileCommands = class {
75113
75538
  context;
75114
75539
  constructor(context) {
@@ -75124,11 +75549,11 @@ var FileCommands = class {
75124
75549
  return;
75125
75550
  }
75126
75551
  const filePath = resolvePath2(parsed.path);
75127
- if (!fs24.existsSync(filePath)) {
75552
+ if (!fs25.existsSync(filePath)) {
75128
75553
  this.context.showError(`File not found: ${parsed.path}`);
75129
75554
  return;
75130
75555
  }
75131
- this.context.showStatus(`Uploading ${path26.basename(filePath)}...`);
75556
+ this.context.showStatus(`Uploading ${path27.basename(filePath)}...`);
75132
75557
  try {
75133
75558
  const result = await this.context.fileManager.upload(filePath, {
75134
75559
  purpose: parsed.purpose,
@@ -75163,7 +75588,7 @@ var FileCommands = class {
75163
75588
  return;
75164
75589
  }
75165
75590
  const resolvedPath = resolvePath2(filePath);
75166
- if (!fs24.existsSync(resolvedPath)) {
75591
+ if (!fs25.existsSync(resolvedPath)) {
75167
75592
  this.context.showError(`File not found: ${filePath}`);
75168
75593
  return;
75169
75594
  }
@@ -75194,7 +75619,7 @@ var FileCommands = class {
75194
75619
  return;
75195
75620
  }
75196
75621
  const resolvedPath = resolvePath2(parsed.path);
75197
- if (!fs24.existsSync(resolvedPath)) {
75622
+ if (!fs25.existsSync(resolvedPath)) {
75198
75623
  this.context.showError(`File not found: ${parsed.path}`);
75199
75624
  return;
75200
75625
  }
@@ -75672,8 +76097,8 @@ var FileStatusMonitor = class {
75672
76097
  };
75673
76098
 
75674
76099
  // src/files/mention/mention-handler.ts
75675
- import * as fs25 from "node:fs";
75676
- import * as path27 from "node:path";
76100
+ import * as fs26 from "node:fs";
76101
+ import * as path28 from "node:path";
75677
76102
  var MentionHandler = class {
75678
76103
  fileManager;
75679
76104
  onShowPicker;
@@ -75728,7 +76153,7 @@ var MentionHandler = class {
75728
76153
  navigateBrowseParent() {
75729
76154
  const currentDir = this.getBrowserDirectory();
75730
76155
  if (!currentDir) return;
75731
- const parentDir = path27.dirname(currentDir);
76156
+ const parentDir = path28.dirname(currentDir);
75732
76157
  if (parentDir === currentDir) return;
75733
76158
  this.browsingDirectory = parentDir;
75734
76159
  this.showMentionPicker("");
@@ -75748,7 +76173,7 @@ var MentionHandler = class {
75748
76173
  if (option.type === "parent") {
75749
76174
  const currentDir = this.getBrowserDirectory();
75750
76175
  if (currentDir) {
75751
- this.browsingDirectory = path27.dirname(currentDir);
76176
+ this.browsingDirectory = path28.dirname(currentDir);
75752
76177
  this.showMentionPicker("");
75753
76178
  this.isPickerVisible = true;
75754
76179
  }
@@ -75888,7 +76313,7 @@ var MentionHandler = class {
75888
76313
  id: part.content,
75889
76314
  name: part.name || fileInfo.name,
75890
76315
  mimeType: fileInfo.mimeType,
75891
- ext: path27.extname(part.name || fileInfo.name).toLowerCase(),
76316
+ ext: path28.extname(part.name || fileInfo.name).toLowerCase(),
75892
76317
  size: fileInfo.size,
75893
76318
  source: fileInfo.platforms.length > 0 ? "session" : "local",
75894
76319
  fileId: part.content,
@@ -76046,11 +76471,11 @@ var MentionHandler = class {
76046
76471
  }
76047
76472
  if (this.isPath(query)) {
76048
76473
  const resolvedPath = resolvePath2(query);
76049
- if (fs25.existsSync(resolvedPath)) {
76050
- const stats = fs25.statSync(resolvedPath);
76474
+ if (fs26.existsSync(resolvedPath)) {
76475
+ const stats = fs26.statSync(resolvedPath);
76051
76476
  if (stats.isFile()) {
76052
76477
  const type = FileCache.getFileTypeFromName(resolvedPath);
76053
- const name = path27.basename(resolvedPath);
76478
+ const name = path28.basename(resolvedPath);
76054
76479
  if (!seenNames.has(name.toLowerCase())) {
76055
76480
  options.push({
76056
76481
  type: "upload",
@@ -76071,16 +76496,16 @@ var MentionHandler = class {
76071
76496
  return void 0;
76072
76497
  }
76073
76498
  const queryPath = this.isPath(query) ? resolvePath2(query) : void 0;
76074
- const filter = queryPath ? fs25.existsSync(queryPath) && fs25.statSync(queryPath).isDirectory() ? "" : path27.basename(queryPath) : query;
76499
+ const filter = queryPath ? fs26.existsSync(queryPath) && fs26.statSync(queryPath).isDirectory() ? "" : path28.basename(queryPath) : query;
76075
76500
  const entries = this.fileManager.listPathEntries(currentDir, filter);
76076
76501
  const options = [];
76077
76502
  const homeDir = process.env.HOME || "";
76078
76503
  const displayDir = currentDir.startsWith(homeDir) ? `~${currentDir.slice(homeDir.length)}` : currentDir;
76079
- if (path27.dirname(currentDir) !== currentDir) {
76504
+ if (path28.dirname(currentDir) !== currentDir) {
76080
76505
  options.push({
76081
76506
  type: "parent",
76082
76507
  name: "..",
76083
- path: path27.dirname(currentDir),
76508
+ path: path28.dirname(currentDir),
76084
76509
  icon: "\u21A9",
76085
76510
  meta: "Parent directory"
76086
76511
  });
@@ -76112,10 +76537,10 @@ var MentionHandler = class {
76112
76537
  getBrowserDirectory(query = this.currentQuery) {
76113
76538
  if (this.isPath(query)) {
76114
76539
  const resolvedPath = resolvePath2(query);
76115
- if (fs25.existsSync(resolvedPath) && fs25.statSync(resolvedPath).isDirectory()) {
76540
+ if (fs26.existsSync(resolvedPath) && fs26.statSync(resolvedPath).isDirectory()) {
76116
76541
  return resolvedPath;
76117
76542
  }
76118
- return path27.dirname(resolvedPath);
76543
+ return path28.dirname(resolvedPath);
76119
76544
  }
76120
76545
  return this.browsingDirectory;
76121
76546
  }
@@ -76202,8 +76627,8 @@ async function initializeFileManager(host) {
76202
76627
  sessionId,
76203
76628
  platform: platform2,
76204
76629
  apiKey: host.options.apiKey,
76205
- baseDir: path28.join(host.options.configDir, "files"),
76206
- sessionsDir: path28.join(host.options.configDir, "sessions")
76630
+ baseDir: path29.join(host.options.configDir, "files"),
76631
+ sessionsDir: path29.join(host.options.configDir, "sessions")
76207
76632
  });
76208
76633
  switch (getFileManagerAdapterKind(platform2)) {
76209
76634
  case "kimi":
@@ -76483,13 +76908,13 @@ function convertPreparedAttachmentItems(items) {
76483
76908
  break;
76484
76909
  case "image": {
76485
76910
  if (!item.data && !item.path) return void 0;
76486
- const data = item.data ?? fs26.readFileSync(item.path, "base64");
76911
+ const data = item.data ?? fs27.readFileSync(item.path, "base64");
76487
76912
  converted.push({ type: "image", data, mimeType: item.mimeType });
76488
76913
  break;
76489
76914
  }
76490
76915
  case "video": {
76491
76916
  if (!item.data && !item.path) return void 0;
76492
- const data = item.data ?? fs26.readFileSync(item.path, "base64");
76917
+ const data = item.data ?? fs27.readFileSync(item.path, "base64");
76493
76918
  converted.push({ type: "video", data, mimeType: item.mimeType });
76494
76919
  break;
76495
76920
  }
@@ -77075,8 +77500,7 @@ async function createCliAutoCompactionResult(params) {
77075
77500
  if (!activeEntryId) {
77076
77501
  return { aborted: true };
77077
77502
  }
77078
- const pathEntries = params.context.sessionManager.getPathToEntry(activeEntryId);
77079
- const firstKeptEntryId = findFirstKeptEntryId(pathEntries);
77503
+ const firstKeptEntryId = findFirstKeptEntrySummaryId(params.context.sessionManager.getActiveContextSummaries());
77080
77504
  if (!firstKeptEntryId) {
77081
77505
  return { aborted: true };
77082
77506
  }
@@ -77638,11 +78062,11 @@ var HierarchicalSelectorComponent = class extends Container {
77638
78062
  // src/runtime/interactive-ui-helpers.ts
77639
78063
  function showHierarchicalMenu(host, initialPath = []) {
77640
78064
  const basePath = [...initialPath];
77641
- const showAtPath = (path33) => {
78065
+ const showAtPath = (path34) => {
77642
78066
  host.showSelector((done) => {
77643
78067
  const selector = new HierarchicalSelectorComponent({
77644
78068
  tree: commandTree,
77645
- path: path33,
78069
+ path: path34,
77646
78070
  basePath,
77647
78071
  onNavigate: (newPath) => {
77648
78072
  done();
@@ -77650,7 +78074,7 @@ function showHierarchicalMenu(host, initialPath = []) {
77650
78074
  },
77651
78075
  onSelect: async (selectedPath, node, searchArgs) => {
77652
78076
  if (node.handler) {
77653
- const args = searchArgs || (selectedPath.length > path33.length ? selectedPath.slice(path33.length).join(" ") : void 0);
78077
+ const args = searchArgs || (selectedPath.length > path34.length ? selectedPath.slice(path34.length).join(" ") : void 0);
77654
78078
  const commandPath = "/" + selectedPath.join("/");
77655
78079
  if (!args && host.isInteractiveCommand(commandPath)) {
77656
78080
  done();
@@ -77904,6 +78328,18 @@ async function prepareAgentTurn(host, context) {
77904
78328
  };
77905
78329
  }
77906
78330
  function createInteractiveAgentSessionController(host) {
78331
+ try {
78332
+ recoverInterruptedPublishes({
78333
+ sessionsDir: getSessionsDir(),
78334
+ warn: (message) => {
78335
+ console.warn(message);
78336
+ if (typeof host.appendWarningSummary === "function") {
78337
+ host.appendWarningSummary(message);
78338
+ }
78339
+ }
78340
+ });
78341
+ } catch {
78342
+ }
77907
78343
  let retryElapsedTicker;
77908
78344
  let retryElapsedStartedAt = 0;
77909
78345
  const stopRetryElapsedTicker = () => {
@@ -77963,8 +78399,7 @@ function createInteractiveAgentSessionController(host) {
77963
78399
  return { aborted: true };
77964
78400
  }
77965
78401
  if (beforeCompact?.summary) {
77966
- const activeEntryId = context.sessionManager.getActiveEntryId();
77967
- const firstKeptEntryId = activeEntryId ? findFirstKeptEntryId(context.sessionManager.getPathToEntry(activeEntryId)) : void 0;
78402
+ const firstKeptEntryId = findFirstKeptEntrySummaryId(context.sessionManager.getActiveContextSummaries());
77968
78403
  if (!firstKeptEntryId) return { aborted: true };
77969
78404
  return { summary: beforeCompact.summary, firstKeptEntryId };
77970
78405
  }
@@ -78138,6 +78573,14 @@ function createInteractiveAgentSessionController(host) {
78138
78573
  return;
78139
78574
  }
78140
78575
  host.resetFileObservationState();
78576
+ if (!event.result?.aborted) {
78577
+ host.streamingComponent = void 0;
78578
+ host.pendingTools.clear();
78579
+ host.chatContainer.clear();
78580
+ host.lastStatusSpacer = void 0;
78581
+ host.lastStatusText = void 0;
78582
+ host.renderMessageHistory(host.sessionManager.getMessages());
78583
+ }
78141
78584
  const contextUsage = host.calculateContextUsage();
78142
78585
  const contextWindow = host.options.model?.contextWindow ?? 0;
78143
78586
  const contextPercent = contextWindow > 0 && contextUsage.tokens !== null ? contextUsage.tokens / contextWindow * 100 : 0;
@@ -79036,6 +79479,7 @@ async function loadInteractiveExtensions(host) {
79036
79479
  fallbackReason: resolved.fallbackReason
79037
79480
  };
79038
79481
  },
79482
+ resolveModelRef: (modelRef) => host.options.modelRegistry.resolveModelRef(modelRef),
79039
79483
  getMessages: () => host.agent.state.messages,
79040
79484
  getSessionMetadata: () => ({ ...host.sessionManager.getActiveSession()?.metadata ?? {} }),
79041
79485
  setSessionMetadata: (key, value) => {
@@ -79093,8 +79537,8 @@ async function loadInteractiveExtensions(host) {
79093
79537
  host.extensionRunner.setUIContext(host.extensionUIContext);
79094
79538
  await restoreExtensionProviderCredentials(host.options.modelRegistry);
79095
79539
  if (process.env.PIE_VERBOSE) {
79096
- for (const { path: path33, error } of errors) {
79097
- console.error(`[Extension] Failed to load ${path33}: ${error}`);
79540
+ for (const { path: path34, error } of errors) {
79541
+ console.error(`[Extension] Failed to load ${path34}: ${error}`);
79098
79542
  }
79099
79543
  }
79100
79544
  const extensionTools = filterEnabledTools(convertExtensionTools(extensions), host.options.settingsManager);
@@ -79464,8 +79908,8 @@ var InteractiveMode = class {
79464
79908
  waitForAgentIdle() {
79465
79909
  return this.agentSessionController.waitForIdle();
79466
79910
  }
79467
- replaceAgentMessagesAndMarkSynced(messages, options) {
79468
- this.agentSessionController.replaceMessagesAndMarkSynced(messages, options);
79911
+ replaceAgentMessagesAndMarkSynced(messages) {
79912
+ this.agentSessionController.replaceMessagesAndMarkSynced(messages);
79469
79913
  this.lastSyncedMessageCount = this.agentSessionController.syncedMessageCount;
79470
79914
  }
79471
79915
  syncAgentFromActiveSession(messages) {
@@ -79493,7 +79937,7 @@ var InteractiveMode = class {
79493
79937
  async init() {
79494
79938
  const activeSession = this.sessionManager.getActiveSession();
79495
79939
  this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
79496
- const { Agent } = await import("./chunks/src-QSP2OPHU.js");
79940
+ const { Agent } = await import("./chunks/src-SXUQ7OY6.js");
79497
79941
  this.agent = new Agent({
79498
79942
  initialState: {
79499
79943
  systemPrompt: this.buildSystemPrompt(),
@@ -79603,9 +80047,9 @@ var InteractiveMode = class {
79603
80047
  if (this.isProcessing) {
79604
80048
  throw new Error("Cannot reload while a response is being processed. Wait for the turn to finish or abort it first.");
79605
80049
  }
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");
80050
+ const builtinDir = path30.join(getBuiltinDir(), "skills");
80051
+ const userDir = path30.join(os8.homedir(), ".pie", "skills");
80052
+ const projectDir = path30.join(this.options.cwd, ".pie", "skills");
79609
80053
  const { skills, diagnostics } = loadSkills({
79610
80054
  dirs: buildSkillDirs({ builtinDir, userDir, projectDir, cwd: this.options.cwd })
79611
80055
  });
@@ -79767,7 +80211,7 @@ var InteractiveMode = class {
79767
80211
  return handleResumeCommand(this);
79768
80212
  }
79769
80213
  async loadSession(sessionId) {
79770
- return loadSession2(this, sessionId);
80214
+ return loadSession(this, sessionId);
79771
80215
  }
79772
80216
  updateTerminalTitle() {
79773
80217
  return updateTerminalTitle(this);
@@ -79908,8 +80352,8 @@ var InteractiveMode = class {
79908
80352
  };
79909
80353
 
79910
80354
  // src/app/runtime-composition.ts
79911
- import { existsSync as existsSync18, mkdirSync as mkdirSync13 } from "fs";
79912
- import * as path30 from "path";
80355
+ import { existsSync as existsSync19, mkdirSync as mkdirSync14 } from "fs";
80356
+ import * as path31 from "path";
79913
80357
  var CliMissingApiKeyError = class extends Error {
79914
80358
  constructor(message) {
79915
80359
  super(message);
@@ -79930,13 +80374,13 @@ var CliSessionResumeError = class extends Error {
79930
80374
  function getCliRuntimePaths() {
79931
80375
  const configDir = getConfigDir();
79932
80376
  const sessionsDir = getSessionsDir();
79933
- const skillsDir = path30.join(configDir, "skills");
79934
- const builtinSkillsDir = path30.join(getBuiltinDir(), "skills");
80377
+ const skillsDir = path31.join(configDir, "skills");
80378
+ const builtinSkillsDir = path31.join(getBuiltinDir(), "skills");
79935
80379
  return { configDir, sessionsDir, skillsDir, builtinSkillsDir };
79936
80380
  }
79937
80381
  function ensureCliRuntimePaths(paths = getCliRuntimePaths()) {
79938
- if (!existsSync18(paths.skillsDir)) {
79939
- mkdirSync13(paths.skillsDir, { recursive: true });
80382
+ if (!existsSync19(paths.skillsDir)) {
80383
+ mkdirSync14(paths.skillsDir, { recursive: true });
79940
80384
  }
79941
80385
  return paths;
79942
80386
  }
@@ -80051,7 +80495,7 @@ async function composeCliRuntime(params) {
80051
80495
  fileLogger.log("cli", `Using API key for provider ${provider}`, {
80052
80496
  keyPrefix: apiKey ? maskApiKey2(apiKey) : "none"
80053
80497
  });
80054
- const projectSkillsDir = path30.join(cwd, ".pie", "skills");
80498
+ const projectSkillsDir = path31.join(cwd, ".pie", "skills");
80055
80499
  const { skills: discoveredSkills, diagnostics } = loadSkills({
80056
80500
  dirs: buildSkillDirs({
80057
80501
  builtinDir: paths.builtinSkillsDir,
@@ -80259,6 +80703,7 @@ async function loadPrintModeExtensions(params) {
80259
80703
  })),
80260
80704
  getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
80261
80705
  resolveModelClass: (modelClass) => params.modelRegistry.resolveModelClass(modelClass),
80706
+ resolveModelRef: (modelRef) => params.modelRegistry.resolveModelRef(modelRef),
80262
80707
  getMessages: () => params.getAgent()?.state.messages ?? [],
80263
80708
  getSessionMetadata: () => ({ ...params.sessionManager.getActiveSession()?.metadata ?? {} }),
80264
80709
  setSessionMetadata: (key, value) => {
@@ -80326,7 +80771,7 @@ async function runPrintMode(params) {
80326
80771
  `);
80327
80772
  console.log("Assistant: ");
80328
80773
  }
80329
- const { Agent: AgentClass } = await import("./chunks/src-QSP2OPHU.js");
80774
+ const { Agent: AgentClass } = await import("./chunks/src-SXUQ7OY6.js");
80330
80775
  let agent;
80331
80776
  const printModeExtensions = await loadPrintModeExtensions({
80332
80777
  cwd: runtime.cwd,
@@ -80414,7 +80859,7 @@ async function runPrintMode(params) {
80414
80859
  if (beforeCompact.cancel) return { aborted: true };
80415
80860
  if (beforeCompact.summary) {
80416
80861
  const activeEntryId = context.sessionManager.getActiveEntryId();
80417
- const firstKeptEntryId = activeEntryId ? findFirstKeptEntryId(context.sessionManager.getPathToEntry(activeEntryId)) : void 0;
80862
+ const firstKeptEntryId = activeEntryId ? findFirstKeptEntrySummaryId(context.sessionManager.getActiveContextSummaries()) : void 0;
80418
80863
  if (!firstKeptEntryId) return { aborted: true };
80419
80864
  return { summary: beforeCompact.summary, firstKeptEntryId };
80420
80865
  }
@@ -80747,6 +81192,7 @@ async function loadJsonModeExtensions(params) {
80747
81192
  })),
80748
81193
  getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
80749
81194
  resolveModelClass: (modelClass) => params.runtime.modelRegistry.resolveModelClass(modelClass),
81195
+ resolveModelRef: (modelRef) => params.runtime.modelRegistry.resolveModelRef(modelRef),
80750
81196
  getMessages: () => params.getAgent()?.state.messages ?? [],
80751
81197
  getSessionMetadata: () => ({ ...params.runtime.sessionManager.getActiveSession()?.metadata ?? {} }),
80752
81198
  setSessionMetadata: (key, value) => {
@@ -80804,6 +81250,7 @@ async function runJsonEventsMode(params) {
80804
81250
  let thinkingLevelInitialized = false;
80805
81251
  let defaultRuntime;
80806
81252
  let defaultModelState;
81253
+ let publishRecoveryDone = false;
80807
81254
  const completedSessionControlRequests = /* @__PURE__ */ new Map();
80808
81255
  const completedSidechatRequests = /* @__PURE__ */ new Map();
80809
81256
  const ensureRuntimeInFlight = /* @__PURE__ */ new Map();
@@ -80893,12 +81340,22 @@ async function runJsonEventsMode(params) {
80893
81340
  metadata.rootEntryId = existing?.rootEntryId ?? rootEntryId;
80894
81341
  return metadata;
80895
81342
  }
80896
- async function persistMockTurn(message, assistantText) {
81343
+ function persistMockTurn(message, assistantText) {
80897
81344
  const store = new FileSessionStore(getSessionsDir());
80898
- const existing = await store.load(message.sessionId ?? sessionId);
81345
+ const targetSessionId = message.sessionId ?? sessionId;
81346
+ const status = store.headStatus(targetSessionId);
81347
+ if (status === "legacy") {
81348
+ throw new SessionControlError("session_unsupported_format", `Session uses an unsupported old format: ${targetSessionId}`);
81349
+ }
81350
+ if (status === "corrupt") {
81351
+ throw new SessionControlError("session_unrecoverable", `Session could not be recovered: ${targetSessionId}`);
81352
+ }
81353
+ const existing = store.readHead(targetSessionId);
81354
+ if (existing) store.createHead(targetSessionId, { name: void 0, createdAt: existing.metadata.createdAt });
80899
81355
  const startedAt = activeTurn?.startedAt ?? Date.now();
80900
- const userEntryId = generateEntryId();
80901
- const assistantEntryId = generateEntryId();
81356
+ const baseSeq = existing?.committedSeq ?? store.readHead(targetSessionId)?.committedSeq ?? 0;
81357
+ const userEntryId = generateEntryId(baseSeq + 1);
81358
+ const assistantEntryId = generateEntryId(baseSeq + 2);
80902
81359
  const parentId = existing?.metadata.activeEntryId ?? null;
80903
81360
  const userEntry = {
80904
81361
  id: userEntryId,
@@ -80936,10 +81393,13 @@ async function runJsonEventsMode(params) {
80936
81393
  timestamp: assistantTimestamp,
80937
81394
  message: assistantMessage
80938
81395
  };
80939
- const entries = [...existing?.entries ?? [], userEntry, assistantEntry];
80940
- await store.save(
80941
- message.sessionId ?? sessionId,
80942
- entries,
81396
+ if (!existing) {
81397
+ store.createHead(targetSessionId);
81398
+ }
81399
+ store.appendEntries(
81400
+ targetSessionId,
81401
+ [userEntry, assistantEntry],
81402
+ assistantEntryId,
80943
81403
  persistedMockMetadata(existing?.metadata, assistantEntryId, existing?.metadata.rootEntryId ?? userEntryId, message.cwd)
80944
81404
  );
80945
81405
  return assistantEntryId;
@@ -80962,7 +81422,7 @@ async function runJsonEventsMode(params) {
80962
81422
  };
80963
81423
  }
80964
81424
  function errorToFailureDetail(error) {
80965
- if (error instanceof CliSessionResumeError) {
81425
+ if (error instanceof CliSessionResumeError || error instanceof SessionControlError) {
80966
81426
  return {
80967
81427
  message: error.message,
80968
81428
  code: error.code,
@@ -80972,7 +81432,10 @@ async function runJsonEventsMode(params) {
80972
81432
  return error instanceof Error ? error.message : String(error);
80973
81433
  }
80974
81434
  function sessionControlStore() {
80975
- return new FileSessionStore(runtime?.paths.sessionsDir ?? getSessionsDir());
81435
+ return new FileSessionStore(sessionControlSessionsDir());
81436
+ }
81437
+ function sessionControlSessionsDir() {
81438
+ return runtime?.paths.sessionsDir ?? getSessionsDir();
80976
81439
  }
80977
81440
  function invalidSessionControl(message) {
80978
81441
  return new SessionControlError("invalid_request", message);
@@ -81081,6 +81544,7 @@ async function runJsonEventsMode(params) {
81081
81544
  await saveRuntimeSessionForControl();
81082
81545
  const result = await forkStoredSession({
81083
81546
  store: sessionControlStore(),
81547
+ sessionsDir: sessionControlSessionsDir(),
81084
81548
  sourceSessionId: controlSessionId,
81085
81549
  sourceEntryId,
81086
81550
  targetSessionId,
@@ -81168,7 +81632,7 @@ async function runJsonEventsMode(params) {
81168
81632
  return;
81169
81633
  }
81170
81634
  const parent = agent;
81171
- const { Agent: AgentClass } = await import("./chunks/src-QSP2OPHU.js");
81635
+ const { Agent: AgentClass } = await import("./chunks/src-SXUQ7OY6.js");
81172
81636
  const sideAgent = new AgentClass({
81173
81637
  initialState: {
81174
81638
  systemPrompt: parent.state.systemPrompt,
@@ -81495,6 +81959,16 @@ async function runJsonEventsMode(params) {
81495
81959
  if (!runtime) {
81496
81960
  throw new Error("JSON events mode requires a CLI runtime");
81497
81961
  }
81962
+ if (!publishRecoveryDone) {
81963
+ publishRecoveryDone = true;
81964
+ try {
81965
+ recoverInterruptedPublishes({
81966
+ sessionsDir: runtime.paths.sessionsDir ?? getSessionsDir(),
81967
+ warn: (message) => console.warn(message)
81968
+ });
81969
+ } catch {
81970
+ }
81971
+ }
81498
81972
  if (defaultRuntime !== runtime) {
81499
81973
  defaultRuntime = runtime;
81500
81974
  defaultModelState = configuredDefaultModelState(runtime);
@@ -81502,7 +81976,7 @@ async function runJsonEventsMode(params) {
81502
81976
  if (runtime.initialModel.unconfigured || controller) {
81503
81977
  return;
81504
81978
  }
81505
- const { Agent: AgentClass } = await import("./chunks/src-QSP2OPHU.js");
81979
+ const { Agent: AgentClass } = await import("./chunks/src-SXUQ7OY6.js");
81506
81980
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
81507
81981
  extensionRunner = jsonModeExtensions.runner;
81508
81982
  const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
@@ -81695,9 +82169,9 @@ async function runJsonEventsMode(params) {
81695
82169
  }
81696
82170
  display(params.mockResponse);
81697
82171
  try {
81698
- mockActiveEntryId = await persistMockTurn(message, params.mockResponse);
82172
+ mockActiveEntryId = persistMockTurn(message, params.mockResponse);
81699
82173
  } catch (error) {
81700
- finalize("failed", error instanceof Error ? error.message : String(error));
82174
+ finalize("failed", errorToFailureDetail(error));
81701
82175
  if (activeTurn === turn) emitSettled(turn);
81702
82176
  if (activeTurn === turn) activeTurn = null;
81703
82177
  return;
@@ -81965,19 +82439,19 @@ async function runJsonEventsMode(params) {
81965
82439
  }
81966
82440
 
81967
82441
  // src/developer-instructions.ts
81968
- import * as fs27 from "fs";
81969
- import * as path31 from "path";
82442
+ import * as fs28 from "fs";
82443
+ import * as path32 from "path";
81970
82444
  var MAX_DEVELOPER_INSTRUCTIONS_CHARS = 64e3;
81971
82445
  function readTextFileBounded(filePath) {
81972
- const resolved = path31.resolve(filePath);
81973
- const stat2 = fs27.statSync(resolved);
82446
+ const resolved = path32.resolve(filePath);
82447
+ const stat2 = fs28.statSync(resolved);
81974
82448
  if (!stat2.isFile()) {
81975
82449
  throw new Error(`Developer instructions file is not a regular file: ${filePath}`);
81976
82450
  }
81977
82451
  if (stat2.size > MAX_DEVELOPER_INSTRUCTIONS_CHARS * 4) {
81978
82452
  throw new Error(`Developer instructions file is too large: ${filePath}`);
81979
82453
  }
81980
- return fs27.readFileSync(resolved, "utf8");
82454
+ return fs28.readFileSync(resolved, "utf8");
81981
82455
  }
81982
82456
  function collectFlagValues(args, flag) {
81983
82457
  const values = [];
@@ -82056,8 +82530,8 @@ var logError = (msg, err) => {
82056
82530
  const logPath = getRuntimeLogPath();
82057
82531
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
82058
82532
  const stack = err instanceof Error ? err.stack || "" : "";
82059
- fs28.mkdirSync(path32.dirname(logPath), { recursive: true });
82060
- fs28.appendFileSync(logPath, `[${timestamp}] ${msg}
82533
+ fs29.mkdirSync(path33.dirname(logPath), { recursive: true });
82534
+ fs29.appendFileSync(logPath, `[${timestamp}] ${msg}
82061
82535
  ${stack}
82062
82536
 
82063
82537
  `);
@@ -82091,7 +82565,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
82091
82565
  }
82092
82566
  async function createCliTestStreamFnFromEnv() {
82093
82567
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
82094
- return (await import("./chunks/test-stream-CVGWFLSX.js")).createTestStreamFnFromSequenceEnv();
82568
+ return (await import("./chunks/test-stream-OD3B57AS.js")).createTestStreamFnFromSequenceEnv();
82095
82569
  }
82096
82570
  function resolveJsonEventsDetailFlag() {
82097
82571
  for (let index = 0; index < process.argv.length; index += 1) {