@cydm/pie 1.0.29 → 1.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  cleanupBashOutputArtifacts,
6
6
  createCliHostCapabilities,
7
7
  createCliWebResearchHealthStore,
8
+ formatSize,
8
9
  getAgentDir,
9
10
  getBuiltinDir,
10
11
  getConfigDir,
@@ -16,8 +17,9 @@ import {
16
17
  getSessionsDir,
17
18
  getSettingsPath,
18
19
  getThemesDir,
19
- migrateConfigFromAgentDir
20
- } from "./chunks/chunk-BDDSZSHX.js";
20
+ migrateConfigFromAgentDir,
21
+ truncateHeadTail
22
+ } from "./chunks/chunk-PLJQYVFC.js";
21
23
  import {
22
24
  AGENTS_CONTEXT_FILE_NAME,
23
25
  AgentSessionController,
@@ -67,7 +69,7 @@ import {
67
69
  setExtensionEnabledInSettings,
68
70
  shouldPreserveExecutionStateForUserText,
69
71
  supersedeExecutionState
70
- } from "./chunks/chunk-L63BJMTT.js";
72
+ } from "./chunks/chunk-BOFCKEV5.js";
71
73
  import "./chunks/chunk-4B42ZU4B.js";
72
74
  import {
73
75
  Deref,
@@ -46263,7 +46265,7 @@ Default mode:
46263
46265
  - File tools read and write inside the current workspace.
46264
46266
  - ~/.pie is allowlisted for Pie configuration and session support.
46265
46267
  - Shell commands run from the workspace and return structured output, timeout, and truncation details.
46266
- - web_search is read-only and uses provider-native search; it does not grant bash/curl web scraping permission.
46268
+ - web_research is read-only, uses provider-native web/search/fetch capabilities, and does not grant bash/curl web scraping permission.
46267
46269
  - Protected paths from extensions can block reads/writes even when tools are present.
46268
46270
 
46269
46271
  Plan mode:
@@ -46969,6 +46971,7 @@ var CommandTree = class {
46969
46971
  if (isLast) {
46970
46972
  node.description = info.description;
46971
46973
  node.handler = info.handler;
46974
+ node.hidden = info.hidden === true;
46972
46975
  if (!node.children || node.children.length === 0) {
46973
46976
  node.isCategory = false;
46974
46977
  }
@@ -46993,7 +46996,7 @@ var CommandTree = class {
46993
46996
  */
46994
46997
  getChildren(path30) {
46995
46998
  const node = this.find(path30);
46996
- return node?.children || [];
46999
+ return (node?.children || []).filter((child) => !child.hidden);
46997
47000
  }
46998
47001
  /**
46999
47002
  * Check if a path exists (as category or command)
@@ -47014,6 +47017,7 @@ var CommandTree = class {
47014
47017
  search(prefix) {
47015
47018
  const results = [];
47016
47019
  const traverse = (node, currentPath) => {
47020
+ if (node.hidden) return;
47017
47021
  const newPath = node.name ? [...currentPath, node.name] : currentPath;
47018
47022
  const pathStr = newPath.join("/");
47019
47023
  if (node.name && pathStr.startsWith(prefix)) {
@@ -47038,6 +47042,7 @@ var CommandTree = class {
47038
47042
  searchByName(namePrefix) {
47039
47043
  const results = [];
47040
47044
  const traverse = (node, currentPath) => {
47045
+ if (node.hidden) return;
47041
47046
  const newPath = node.name ? [...currentPath, node.name] : currentPath;
47042
47047
  const pathStr = newPath.join("/");
47043
47048
  if (node.name && node.name.toLowerCase().startsWith(namePrefix.toLowerCase())) {
@@ -47061,6 +47066,7 @@ var CommandTree = class {
47061
47066
  getAllPaths() {
47062
47067
  const paths = [];
47063
47068
  const traverse = (node, currentPath) => {
47069
+ if (node.hidden) return;
47064
47070
  const newPath = node.name ? [...currentPath, node.name] : currentPath;
47065
47071
  if (node.name) {
47066
47072
  paths.push(newPath.join("/"));
@@ -47131,12 +47137,14 @@ function createExtensionContext(extension, cwd, uiContext, abortFn, isIdleFn, ha
47131
47137
  name: finalName,
47132
47138
  description: command.description,
47133
47139
  handler: command.handler,
47134
- path: cmdPath
47140
+ path: cmdPath,
47141
+ hidden: command.hidden === true
47135
47142
  };
47136
- extension.commands.set(finalName, registeredCmd);
47143
+ extension.commands.set(cmdPath.join("/"), registeredCmd);
47137
47144
  commandTree.register(cmdPath, {
47138
47145
  description: command.description,
47139
- handler: command.handler
47146
+ handler: command.handler,
47147
+ hidden: command.hidden === true
47140
47148
  });
47141
47149
  },
47142
47150
  registerShortcut(key, shortcut) {
@@ -50138,6 +50146,18 @@ var SelectList = class {
50138
50146
  this.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));
50139
50147
  this.selectedIndex = 0;
50140
50148
  }
50149
+ getVisibleRange() {
50150
+ const startIndex = Math.max(
50151
+ 0,
50152
+ Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible)
50153
+ );
50154
+ const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);
50155
+ return { startIndex, endIndex };
50156
+ }
50157
+ getVisibleItems() {
50158
+ const { startIndex, endIndex } = this.getVisibleRange();
50159
+ return this.filteredItems.slice(startIndex, endIndex);
50160
+ }
50141
50161
  setSelectedIndex(index) {
50142
50162
  this.selectedIndex = Math.max(0, Math.min(index, this.filteredItems.length - 1));
50143
50163
  }
@@ -50149,11 +50169,7 @@ var SelectList = class {
50149
50169
  lines.push(this.theme.noMatch(" No matching commands"));
50150
50170
  return lines;
50151
50171
  }
50152
- const startIndex = Math.max(
50153
- 0,
50154
- Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible)
50155
- );
50156
- const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);
50172
+ const { startIndex, endIndex } = this.getVisibleRange();
50157
50173
  for (let i = startIndex; i < endIndex; i++) {
50158
50174
  const item = this.filteredItems[i];
50159
50175
  if (!item) continue;
@@ -50166,19 +50182,20 @@ var SelectList = class {
50166
50182
  if (descriptionSingleLine && width > 40) {
50167
50183
  const maxValueWidth = Math.min(30, width - prefixWidth - 4);
50168
50184
  const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
50169
- const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
50170
- const descriptionStart = prefixWidth + truncatedValue.length + spacing.length;
50185
+ const valueWidth = visibleWidth(truncatedValue);
50186
+ const spacing = " ".repeat(Math.max(1, 32 - valueWidth));
50187
+ const descriptionStart = prefixWidth + valueWidth + spacing.length;
50171
50188
  const remainingWidth = width - descriptionStart - 2;
50172
50189
  if (remainingWidth > 10) {
50173
50190
  const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, "");
50174
- line = this.theme.selectedText(`\u2192 ${truncatedValue}${spacing}${truncatedDesc}`);
50191
+ line = truncateToWidth(this.theme.selectedText(`\u2192 ${truncatedValue}${spacing}${truncatedDesc}`), width, "");
50175
50192
  } else {
50176
50193
  const maxWidth = width - prefixWidth - 2;
50177
- line = this.theme.selectedText(`\u2192 ${truncateToWidth(displayValue, maxWidth, "")}`);
50194
+ line = truncateToWidth(this.theme.selectedText(`\u2192 ${truncateToWidth(displayValue, maxWidth, "")}`), width, "");
50178
50195
  }
50179
50196
  } else {
50180
50197
  const maxWidth = width - prefixWidth - 2;
50181
- line = this.theme.selectedText(`\u2192 ${truncateToWidth(displayValue, maxWidth, "")}`);
50198
+ line = truncateToWidth(this.theme.selectedText(`\u2192 ${truncateToWidth(displayValue, maxWidth, "")}`), width, "");
50182
50199
  }
50183
50200
  } else {
50184
50201
  const displayValue = item.label || item.value;
@@ -50186,23 +50203,24 @@ var SelectList = class {
50186
50203
  if (descriptionSingleLine && width > 40) {
50187
50204
  const maxValueWidth = Math.min(30, width - prefix.length - 4);
50188
50205
  const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
50189
- const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
50190
- const descriptionStart = prefix.length + truncatedValue.length + spacing.length;
50206
+ const valueWidth = visibleWidth(truncatedValue);
50207
+ const spacing = " ".repeat(Math.max(1, 32 - valueWidth));
50208
+ const descriptionStart = prefix.length + valueWidth + spacing.length;
50191
50209
  const remainingWidth = width - descriptionStart - 2;
50192
50210
  if (remainingWidth > 10) {
50193
50211
  const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, "");
50194
50212
  const descText = this.theme.description(spacing + truncatedDesc);
50195
- line = prefix + truncatedValue + descText;
50213
+ line = truncateToWidth(prefix + truncatedValue + descText, width, "");
50196
50214
  } else {
50197
50215
  const maxWidth = width - prefix.length - 2;
50198
- line = prefix + truncateToWidth(displayValue, maxWidth, "");
50216
+ line = truncateToWidth(prefix + truncateToWidth(displayValue, maxWidth, ""), width, "");
50199
50217
  }
50200
50218
  } else {
50201
50219
  const maxWidth = width - prefix.length - 2;
50202
- line = prefix + truncateToWidth(displayValue, maxWidth, "");
50220
+ line = truncateToWidth(prefix + truncateToWidth(displayValue, maxWidth, ""), width, "");
50203
50221
  }
50204
50222
  }
50205
- lines.push(line);
50223
+ lines.push(truncateToWidth(line, width, ""));
50206
50224
  }
50207
50225
  if (startIndex > 0 || endIndex < this.filteredItems.length) {
50208
50226
  const scrollText = ` (${this.selectedIndex + 1}/${this.filteredItems.length})`;
@@ -56634,7 +56652,7 @@ var FileManagerError = class extends Error {
56634
56652
  code;
56635
56653
  details;
56636
56654
  locale;
56637
- constructor(code, details, locale = "zh") {
56655
+ constructor(code, details, locale = "en") {
56638
56656
  const messages = FileErrorMessages[code];
56639
56657
  super(messages[locale]);
56640
56658
  this.name = "FileManagerError";
@@ -60724,6 +60742,9 @@ var ExtensionEnablementSelectorComponent = class extends Container {
60724
60742
  getSettingsList() {
60725
60743
  return this.settingsList;
60726
60744
  }
60745
+ handleInput(data) {
60746
+ this.settingsList.handleInput(data);
60747
+ }
60727
60748
  };
60728
60749
 
60729
60750
  // src/commands/interactive-extensions-command.ts
@@ -60841,23 +60862,28 @@ function handleExtensionsCommand(host, args) {
60841
60862
  // src/slash-commands.ts
60842
60863
  var BUILTIN_SLASH_COMMANDS = [
60843
60864
  { name: "sessions/compact", description: "Summarize history and add a compact checkpoint to the session" },
60865
+ { name: "sessions/new", description: "Start a new session" },
60866
+ { name: "sessions/resume", description: "Resume a different session" },
60867
+ { name: "sessions/tree", description: "Navigate session tree" },
60868
+ { name: "sessions/info", description: "Show session info" },
60869
+ { name: "sessions/fork", description: "Fork from a message" },
60844
60870
  { name: "settings", description: "Open settings menu" },
60845
60871
  { name: "settings/extensions", description: "Manage extensions" },
60846
60872
  { name: "settings/help", description: "Show help information (keyboard shortcuts and commands)" },
60847
- { name: "settings/quit", description: "Exit Pie" },
60848
- { name: "model", description: "Select model (e.g., /model kimi-api/kimi-k2.5)" },
60849
- { name: "export", description: "Export session to HTML file" },
60850
- { name: "hotkeys", description: "Show all keyboard shortcuts" },
60851
- { name: "session", description: "Show session info and stats" },
60852
- { name: "resume", description: "Resume a different session" },
60853
- { name: "tree", description: "Navigate session tree" },
60854
- { name: "fork", description: "Create a new fork from a previous message" },
60855
- { name: "skills", description: "List available skills" },
60856
- { name: "skill", description: "Activate a skill (e.g., /skill code-review)" },
60857
- { name: "new", description: "Start a new session" },
60873
+ { name: "settings/hotkeys", description: "Show keyboard shortcuts" },
60874
+ { name: "settings/model", description: "Select AI model" },
60875
+ { name: "settings/theme", description: "Change theme" },
60876
+ { name: "settings/thinking", description: "Set thinking level" },
60877
+ { name: "settings/yolo", description: "Toggle or set YOLO mode" },
60858
60878
  { name: "settings/debugs/cache-test", description: "Run provider cache diagnostics with a dedicated 2-request probe" },
60859
60879
  { name: "settings/debugs/context", description: "Append a context summary to ~/.pie/logs/pie-cli.log" },
60860
- { name: "settings/debugs/package", description: "Append a package summary to ~/.pie/logs/pie-cli.log" }
60880
+ { name: "settings/debugs/package", description: "Append a package summary to ~/.pie/logs/pie-cli.log" },
60881
+ { name: "settings/quit", description: "Exit Pie" },
60882
+ { name: "skills", description: "Open skills menu" },
60883
+ { name: "skills/list", description: "List available skills" },
60884
+ { name: "skills/reload", description: "Reload skills from disk" },
60885
+ { name: "skills/use", description: "Use a skill" },
60886
+ { name: "tools/subagent", description: "Spawn subagents in parallel to handle tasks" }
60861
60887
  ];
60862
60888
 
60863
60889
  // src/commands/interactive-debug-commands.ts
@@ -61199,7 +61225,8 @@ var SessionSelectorComponent = class extends Container {
61199
61225
  items;
61200
61226
  refreshAttempted = /* @__PURE__ */ new Set();
61201
61227
  refreshInFlight = false;
61202
- pendingRefreshId;
61228
+ refreshQueue = [];
61229
+ refreshQueued = /* @__PURE__ */ new Set();
61203
61230
  refreshTimer;
61204
61231
  destroyed = false;
61205
61232
  constructor(sessions, callbacks, options = {}) {
@@ -61233,16 +61260,15 @@ var SessionSelectorComponent = class extends Container {
61233
61260
  this.clearRefreshTimer();
61234
61261
  this.callbacks.onCancel();
61235
61262
  };
61236
- this.selectList.onSelectionChange = (item) => {
61237
- this.scheduleRefresh(item.value);
61263
+ this.selectList.onSelectionChange = () => {
61264
+ this.scheduleVisibleRefreshes();
61238
61265
  };
61239
61266
  this.addChild(this.selectList);
61240
61267
  this.addChild(new Spacer(1));
61241
61268
  this.addChild(
61242
61269
  new Text(theme.fg("dim", " \u2191\u2193 to navigate \xB7 \u2190\u2192 to page \xB7 Enter to select \xB7 Esc to cancel"), 0, 0)
61243
61270
  );
61244
- const selected = this.selectList.getSelectedItem();
61245
- if (selected) this.scheduleRefresh(selected.value);
61271
+ this.scheduleVisibleRefreshes();
61246
61272
  }
61247
61273
  handleInput(data) {
61248
61274
  this.selectList.handleInput(data);
@@ -61264,9 +61290,14 @@ var SessionSelectorComponent = class extends Container {
61264
61290
  this.refreshTimer = void 0;
61265
61291
  }
61266
61292
  }
61267
- scheduleRefresh(sessionId) {
61268
- if (!this.options.refreshMetadata || this.destroyed || this.refreshAttempted.has(sessionId)) return;
61269
- this.pendingRefreshId = sessionId;
61293
+ scheduleVisibleRefreshes() {
61294
+ if (!this.options.refreshMetadata || this.destroyed) return;
61295
+ for (const item of this.selectList.getVisibleItems()) {
61296
+ if (this.refreshAttempted.has(item.value) || this.refreshQueued.has(item.value)) continue;
61297
+ this.refreshQueue.push(item.value);
61298
+ this.refreshQueued.add(item.value);
61299
+ }
61300
+ if (this.refreshQueue.length === 0) return;
61270
61301
  this.clearRefreshTimer();
61271
61302
  this.refreshTimer = setTimeout(() => {
61272
61303
  this.refreshTimer = void 0;
@@ -61276,9 +61307,9 @@ var SessionSelectorComponent = class extends Container {
61276
61307
  async runPendingRefresh() {
61277
61308
  if (this.destroyed || !this.options.refreshMetadata) return;
61278
61309
  if (this.refreshInFlight) return;
61279
- const sessionId = this.pendingRefreshId;
61280
- this.pendingRefreshId = void 0;
61310
+ const sessionId = this.refreshQueue.shift();
61281
61311
  if (!sessionId || this.refreshAttempted.has(sessionId)) return;
61312
+ this.refreshQueued.delete(sessionId);
61282
61313
  this.refreshAttempted.add(sessionId);
61283
61314
  this.refreshInFlight = true;
61284
61315
  try {
@@ -61289,7 +61320,7 @@ var SessionSelectorComponent = class extends Container {
61289
61320
  } catch {
61290
61321
  } finally {
61291
61322
  this.refreshInFlight = false;
61292
- if (this.pendingRefreshId && !this.destroyed) {
61323
+ if (this.refreshQueue.length > 0 && !this.destroyed) {
61293
61324
  void this.runPendingRefresh();
61294
61325
  }
61295
61326
  }
@@ -62383,7 +62414,7 @@ function renderExecutionWidgetLines(steps, activeTheme = theme) {
62383
62414
  }
62384
62415
 
62385
62416
  // src/components/tool-execution.ts
62386
- function formatSize(bytes) {
62417
+ function formatSize2(bytes) {
62387
62418
  if (bytes < 1024) return `${bytes}B`;
62388
62419
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
62389
62420
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
@@ -62513,7 +62544,7 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
62513
62544
  if (truncation.firstLineExceedsLimit) {
62514
62545
  text += "\n" + theme.fg(
62515
62546
  "warning",
62516
- `[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`
62547
+ `[First line exceeds ${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`
62517
62548
  );
62518
62549
  } else if (truncation.truncatedBy === "lines") {
62519
62550
  text += "\n" + theme.fg(
@@ -62523,7 +62554,7 @@ ${renderManageTodoListResult(this.result, { expanded: this.expanded }, theme)}`;
62523
62554
  } else {
62524
62555
  text += "\n" + theme.fg(
62525
62556
  "warning",
62526
- `[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`
62557
+ `[Truncated: ${truncation.outputLines} lines shown (${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`
62527
62558
  );
62528
62559
  }
62529
62560
  }
@@ -62671,7 +62702,7 @@ ${displayLines.map((line) => theme.fg("toolOutput", line)).join("\n")}`;
62671
62702
  warnings.push(`${entryLimit} entries limit`);
62672
62703
  }
62673
62704
  if (truncation?.truncated) {
62674
- warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
62705
+ warnings.push(`${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
62675
62706
  }
62676
62707
  text += `
62677
62708
  ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
@@ -62709,7 +62740,7 @@ ${displayLines.map((line) => theme.fg("toolOutput", line)).join("\n")}`;
62709
62740
  warnings.push(`${resultLimit} results limit`);
62710
62741
  }
62711
62742
  if (truncation?.truncated) {
62712
- warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
62743
+ warnings.push(`${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
62713
62744
  }
62714
62745
  text += `
62715
62746
  ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
@@ -62752,7 +62783,7 @@ ${displayLines.map((line) => theme.fg("toolOutput", line)).join("\n")}`;
62752
62783
  warnings.push(`${matchLimit} matches limit`);
62753
62784
  }
62754
62785
  if (truncation?.truncated) {
62755
- warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
62786
+ warnings.push(`${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
62756
62787
  }
62757
62788
  if (linesTruncated) {
62758
62789
  warnings.push("some lines truncated");
@@ -62792,7 +62823,7 @@ ${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
62792
62823
  warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
62793
62824
  } else {
62794
62825
  warnings.push(
62795
- `Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`
62826
+ `Truncated: ${truncation.outputLines} lines shown (${formatSize2(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`
62796
62827
  );
62797
62828
  }
62798
62829
  }
@@ -63366,7 +63397,7 @@ function handleSkillsCommand(host) {
63366
63397
  }
63367
63398
  function handleSkillCommand(host, name) {
63368
63399
  if (!name) {
63369
- host.showError("Usage: /skill <name>");
63400
+ host.showError("Usage: /skills/skill:<name> <your request>");
63370
63401
  return;
63371
63402
  }
63372
63403
  const skill = host.skills.find((s) => s.name === name);
@@ -63603,13 +63634,15 @@ async function handleSkillsReload(host) {
63603
63634
  function showSettingsSelector(host) {
63604
63635
  host.showSelector((done) => {
63605
63636
  const currentModelId = host.options.model?.id || "unknown";
63637
+ const currentProvider = host.options.model?.provider || "unknown";
63638
+ const currentFullId = `${currentProvider}/${currentModelId}`;
63606
63639
  const availableModels = host.options.modelRegistry.listAvailableModels();
63607
63640
  const selector = new SettingsSelectorComponent(
63608
63641
  {
63609
63642
  thinkingLevel: host.thinkingLevel,
63610
63643
  currentTheme: getCurrentThemeName(),
63611
63644
  availableThemes: getAvailableThemes(),
63612
- currentModel: currentModelId,
63645
+ currentModel: currentFullId,
63613
63646
  availableModels,
63614
63647
  yoloMode: host.yoloMode
63615
63648
  },
@@ -63813,9 +63846,10 @@ function handleHotkeysCommand(host) {
63813
63846
  "",
63814
63847
  ...BUILTIN_SLASH_COMMANDS.map((cmd) => ` /${cmd.name.padEnd(12)} ${theme.fg("muted", cmd.description)}`),
63815
63848
  ...host.extensions.flatMap(
63816
- (ext) => Array.from(ext.commands.entries()).map(
63817
- ([name, cmd]) => ` /${name.padEnd(12)} ${theme.fg("muted", cmd.description)}${theme.fg("dim", " [ext]")}`
63818
- )
63849
+ (ext) => Array.from(ext.commands.values()).filter((cmd) => !cmd.hidden).map((cmd) => {
63850
+ const pathName = cmd.path?.join("/") ?? cmd.name;
63851
+ return ` /${pathName.padEnd(12)} ${theme.fg("muted", cmd.description)}${theme.fg("dim", " [ext]")}`;
63852
+ })
63819
63853
  )
63820
63854
  ];
63821
63855
  host.chatContainer.addChild(new Spacer(1));
@@ -64725,7 +64759,7 @@ function setupInteractiveEditorSubmitHandler(host) {
64725
64759
  const expanded = host.expandSkillCommand(skillText);
64726
64760
  if (expanded !== skillText) {
64727
64761
  if (host.submitLock) {
64728
- host.queueMessage(expanded, "steer");
64762
+ host.queueMessage(expanded, "followUp", { deliverWhileStreaming: false });
64729
64763
  return;
64730
64764
  }
64731
64765
  host.setSubmitLock(true);
@@ -64756,7 +64790,7 @@ function setupInteractiveEditorSubmitHandler(host) {
64756
64790
  if (text.startsWith("/tools/subagent")) {
64757
64791
  const args = text.slice("/tools/subagent".length).trim();
64758
64792
  if (host.submitLock) {
64759
- host.queueMessage(text, "steer");
64793
+ host.queueMessage(text, "followUp", { deliverWhileStreaming: false });
64760
64794
  return;
64761
64795
  }
64762
64796
  host.editor.setText("");
@@ -64775,7 +64809,7 @@ function setupInteractiveEditorSubmitHandler(host) {
64775
64809
  host.showStatus("Wait for the current response to finish before compacting");
64776
64810
  return;
64777
64811
  }
64778
- host.queueMessage(text, "steer");
64812
+ host.queueMessage(text, "followUp", { deliverWhileStreaming: false });
64779
64813
  return;
64780
64814
  }
64781
64815
  host.editor.setText("");
@@ -64805,6 +64839,11 @@ function setupInteractiveEditorSubmitHandler(host) {
64805
64839
  }
64806
64840
  return;
64807
64841
  }
64842
+ if (exactMatch?.isCategory && !exactMatch.handler) {
64843
+ host.showHierarchicalMenu(firstPartSegments);
64844
+ host.editor.setText("");
64845
+ return;
64846
+ }
64808
64847
  const pathStr = text.slice(1);
64809
64848
  const segments = pathStr.split("/").filter(Boolean);
64810
64849
  let node = null;
@@ -64826,7 +64865,7 @@ function setupInteractiveEditorSubmitHandler(host) {
64826
64865
  host.showStatus("Wait for the current response to finish before compacting");
64827
64866
  return;
64828
64867
  }
64829
- host.queueMessage(text, "steer");
64868
+ host.queueMessage(text, "followUp", { deliverWhileStreaming: false });
64830
64869
  return;
64831
64870
  }
64832
64871
  host.editor.setText("");
@@ -64867,7 +64906,7 @@ function setupInteractiveEditorSubmitHandler(host) {
64867
64906
  for (const [name, command] of ext.commands) {
64868
64907
  if (command.path?.join("/") === fullPath) {
64869
64908
  if (host.submitLock) {
64870
- host.queueMessage(text, "steer");
64909
+ host.queueMessage(text, "followUp", { deliverWhileStreaming: false });
64871
64910
  return;
64872
64911
  }
64873
64912
  host.editor.setText("");
@@ -64913,15 +64952,16 @@ function setupInteractiveEditorSubmitHandler(host) {
64913
64952
  }
64914
64953
  }
64915
64954
  if (host.mentionHandler?.hasPendingMentionWork()) {
64916
- host.queueMessage(text, "steer", {
64955
+ host.queueMessage(text, "followUp", {
64917
64956
  clearEditor: false,
64918
- statusMessage: "\u6587\u4EF6\u5904\u7406\u4E2D\uFF0C\u6D88\u606F\u5DF2\u6392\u961F\uFF0C\u6DFB\u52A0\u5B8C\u6210\u540E\u81EA\u52A8\u53D1\u9001"
64957
+ statusMessage: "Files are still processing. Message queued and will send when attachments are ready.",
64958
+ deliverWhileStreaming: false
64919
64959
  });
64920
64960
  host.agentSessionController?.requestQueueDispatch();
64921
64961
  return;
64922
64962
  }
64923
64963
  if (host.submitLock) {
64924
- host.queueMessage(text, "steer");
64964
+ host.queueMessage(text, "followUp", { deliverWhileStreaming: false });
64925
64965
  return;
64926
64966
  }
64927
64967
  host.setSubmitLock(true);
@@ -64951,9 +64991,10 @@ function setupInteractiveEditorSubmitHandler(host) {
64951
64991
  host.setSubmitLock(false);
64952
64992
  host.isProcessing = false;
64953
64993
  host.footer.setState({ status: "ready" });
64954
- host.queueMessage(text, "steer", {
64994
+ host.queueMessage(text, "followUp", {
64955
64995
  clearEditor: false,
64956
- statusMessage: `\u6587\u4EF6\u5904\u7406\u4E2D: ${processingFiles.join(", ")}\uFF0C\u5DF2\u6392\u961F\uFF0C\u5904\u7406\u5B8C\u6210\u540E\u81EA\u52A8\u53D1\u9001`
64996
+ statusMessage: `Files still processing: ${processingFiles.join(", ")}. Message queued and will send when attachments are ready.`,
64997
+ deliverWhileStreaming: false
64957
64998
  });
64958
64999
  host.agentSessionController?.requestQueueDispatch();
64959
65000
  return;
@@ -65193,7 +65234,7 @@ var FilePickerComponent = class extends Container {
65193
65234
  if (this.query) {
65194
65235
  this.addChild(new Text(theme.fg("dim", `@ ${this.query}`), 1, 0));
65195
65236
  } else {
65196
- this.addChild(new Text(theme.fg("dim", "@ \u9009\u62E9\u6587\u4EF6..."), 1, 0));
65237
+ this.addChild(new Text(theme.fg("dim", "@ Select a file..."), 1, 0));
65197
65238
  }
65198
65239
  this.addChild(new Text(theme.fg("border", "\u2500".repeat(40)), 1, 0));
65199
65240
  const maxOptions = 8;
@@ -65218,16 +65259,16 @@ var FilePickerComponent = class extends Container {
65218
65259
  new Text(
65219
65260
  theme.fg(
65220
65261
  "dim",
65221
- ` ${this.selectedIndex + 1}/${this.options.length} \xB7 \u663E\u793A ${this.scrollOffset + 1}-${visibleEnd}`
65262
+ ` ${this.selectedIndex + 1}/${this.options.length} \xB7 showing ${this.scrollOffset + 1}-${visibleEnd}`
65222
65263
  ),
65223
65264
  1,
65224
65265
  0
65225
65266
  )
65226
65267
  );
65227
65268
  }
65228
- this.addChild(new Text(theme.fg("dim", "\u2191\u2193 \u9009\u62E9 \xB7 \u2190 \u8FD4\u56DE / \u2192 \u8FDB\u5165 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88"), 1, 0));
65269
+ this.addChild(new Text(theme.fg("dim", "\u2191\u2193 Select \xB7 \u2190 Back / \u2192 Open \xB7 Enter Confirm \xB7 Esc Cancel"), 1, 0));
65229
65270
  } else {
65230
- this.addChild(new Text(theme.fg("dim", " \u65E0\u5339\u914D\u6587\u4EF6"), 1, 0));
65271
+ this.addChild(new Text(theme.fg("dim", " No matching files"), 1, 0));
65231
65272
  }
65232
65273
  }
65233
65274
  };
@@ -65260,11 +65301,11 @@ var FileCommands = class {
65260
65301
  purpose: parsed.purpose,
65261
65302
  onProgress: (progress, stage) => {
65262
65303
  const stageNames = {
65263
- analyzing: "\u5206\u6790\u4E2D",
65264
- preprocessing: "\u9884\u5904\u7406",
65265
- uploading: "\u4E0A\u4F20\u4E2D",
65266
- processing: "\u5904\u7406\u4E2D",
65267
- complete: "\u5B8C\u6210"
65304
+ analyzing: "Analyzing",
65305
+ preprocessing: "Preprocessing",
65306
+ uploading: "Uploading",
65307
+ processing: "Processing",
65308
+ complete: "Complete"
65268
65309
  };
65269
65310
  this.context.showStatus(`${stageNames[stage] || stage}... ${progress}%`);
65270
65311
  }
@@ -65331,11 +65372,11 @@ var FileCommands = class {
65331
65372
  optimize: parsed.options,
65332
65373
  onProgress: (progress, stage) => {
65333
65374
  const stageNames = {
65334
- analyzing: "\u5206\u6790\u89C6\u9891",
65335
- preprocessing: "\u9884\u5904\u7406",
65336
- uploading: "\u4E0A\u4F20\u4E2D",
65337
- processing: "\u5E73\u53F0\u5904\u7406\u4E2D",
65338
- complete: "\u5B8C\u6210"
65375
+ analyzing: "Analyzing video",
65376
+ preprocessing: "Preprocessing",
65377
+ uploading: "Uploading",
65378
+ processing: "Processing",
65379
+ complete: "Complete"
65339
65380
  };
65340
65381
  this.context.showStatus(`${stageNames[stage] || stage}... ${progress}%`);
65341
65382
  }
@@ -65890,7 +65931,7 @@ var MentionHandler = class {
65890
65931
  this.fileManager.ensureSessionTracking(option.fileId);
65891
65932
  const mention = this.formatMention(option.name, option.fileId);
65892
65933
  this.onInsertMention(mention, queryToken);
65893
- this.onStatus?.(`\u5DF2\u6DFB\u52A0\u6587\u4EF6 ${option.name}\uFF08\u5DF2\u4E0A\u4F20\u5230 ${this.fileManager.getPlatformDisplayName()}\uFF09`);
65934
+ this.onStatus?.(`Added ${option.name} (already uploaded to ${this.fileManager.getPlatformDisplayName()})`);
65894
65935
  } else if (option.type === "upload" && option.path) {
65895
65936
  this.pendingUploadCount += 1;
65896
65937
  const pendingMention = this.formatPendingMention(option.name);
@@ -65900,15 +65941,15 @@ var MentionHandler = class {
65900
65941
  if (option.cacheStatus === "uploaded") {
65901
65942
  this.pushPendingStatus(
65902
65943
  pendingStatusKey,
65903
- `\u51C6\u5907\u6DFB\u52A0 ${option.name}\uFF08\u5C06\u590D\u7528 ${this.fileManager.getPlatformDisplayName()} \u5DF2\u4E0A\u4F20\u6587\u4EF6\uFF09...`
65944
+ `Preparing ${option.name} (reusing upload from ${this.fileManager.getPlatformDisplayName()})...`
65904
65945
  );
65905
65946
  } else if (option.cacheStatus === "cached") {
65906
65947
  this.pushPendingStatus(
65907
65948
  pendingStatusKey,
65908
- `\u51C6\u5907\u6DFB\u52A0 ${option.name}\uFF08\u5C06\u590D\u7528\u672C\u5730\u7F13\u5B58\uFF09...`
65949
+ `Preparing ${option.name} (reusing local cache)...`
65909
65950
  );
65910
65951
  } else {
65911
- this.pushPendingStatus(pendingStatusKey, `\u51C6\u5907\u6DFB\u52A0 ${option.name}...`);
65952
+ this.pushPendingStatus(pendingStatusKey, `Preparing ${option.name}...`);
65912
65953
  }
65913
65954
  const mimeType = FileCache.getMimeType(option.path);
65914
65955
  const shouldStageLocally = !mimeType.startsWith("image/") && !mimeType.startsWith("video/");
@@ -65932,33 +65973,33 @@ var MentionHandler = class {
65932
65973
  const mention = this.formatMention(result.name, result.fileId);
65933
65974
  this.onInsertMention(mention, pendingMention);
65934
65975
  this.clearPendingStatus(pendingStatusKey);
65935
- this.onStatus?.(shouldStageLocally ? `\u5DF2\u6DFB\u52A0\u672C\u5730\u6587\u4EF6 ${result.name}` : `\u5DF2\u6DFB\u52A0\u6587\u4EF6 ${result.name}`);
65976
+ this.onStatus?.(shouldStageLocally ? `Added local file ${result.name}` : `Added ${result.name}`);
65936
65977
  } else {
65937
65978
  this.onInsertMention("", pendingMention);
65938
65979
  this.clearPendingStatus(pendingStatusKey);
65939
- this.onError?.("\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
65980
+ this.onError?.("File upload failed. Please try again.");
65940
65981
  }
65941
65982
  } catch (err) {
65942
65983
  this.onInsertMention("", pendingMention);
65943
65984
  this.clearPendingStatus(pendingStatusKey);
65944
65985
  const errorMessage3 = err instanceof Error ? err.message : String(err);
65945
65986
  if (errorMessage3.includes("PLATFORM_NOT_SUPPORTED")) {
65946
- this.onError?.("\u5F53\u524D AI \u6A21\u578B\u4E0D\u652F\u6301\u6587\u4EF6\u4E0A\u4F20");
65987
+ this.onError?.("The current AI model does not support file uploads.");
65947
65988
  } else if (errorMessage3.includes("ENOENT")) {
65948
- this.onError?.("\u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BBF\u95EE");
65989
+ this.onError?.("File does not exist or cannot be accessed.");
65949
65990
  } else if (errorMessage3.includes("EACCES") || errorMessage3.includes("PERMISSION")) {
65950
- this.onError?.("\u6CA1\u6709\u6743\u9650\u8BBF\u95EE\u8BE5\u6587\u4EF6");
65991
+ this.onError?.("Permission denied while accessing the file.");
65951
65992
  } else if (errorMessage3.includes("network") || errorMessage3.includes("ETIMEDOUT") || errorMessage3.includes("ECONNREFUSED")) {
65952
- this.onError?.("\u7F51\u7EDC\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u8FDE\u63A5\u540E\u91CD\u8BD5");
65993
+ this.onError?.("Network error. Check the connection and try again.");
65953
65994
  } else {
65954
- this.onError?.(`\u4E0A\u4F20\u5931\u8D25: ${errorMessage3}`);
65995
+ this.onError?.(`Upload failed: ${errorMessage3}`);
65955
65996
  }
65956
65997
  } finally {
65957
65998
  this.clearPendingStatus(pendingStatusKey);
65958
65999
  this.pendingUploadCount = Math.max(0, this.pendingUploadCount - 1);
65959
66000
  }
65960
66001
  } else {
65961
- this.onError?.("\u65E0\u6548\u7684\u6587\u4EF6\u9009\u9879");
66002
+ this.onError?.("Invalid file option.");
65962
66003
  }
65963
66004
  this.browsingDirectory = void 0;
65964
66005
  this.onHidePicker();
@@ -66100,10 +66141,10 @@ var MentionHandler = class {
66100
66141
  const seenNames = /* @__PURE__ */ new Set();
66101
66142
  options.push({
66102
66143
  type: "browse",
66103
- name: "\u6D4F\u89C8\u6587\u4EF6\u7CFB\u7EDF...",
66144
+ name: "Browse filesystem...",
66104
66145
  path: process.cwd(),
66105
66146
  icon: "\u{1F4C2}",
66106
- meta: "\u8DF3\u51FA\u5F53\u524D\u76EE\u5F55\u9009\u62E9\u6587\u4EF6"
66147
+ meta: "Choose a file outside the current directory"
66107
66148
  });
66108
66149
  try {
66109
66150
  const sessionFiles = this.fileManager.getSessionFiles();
@@ -66111,7 +66152,7 @@ var MentionHandler = class {
66111
66152
  if (!query || file.name.toLowerCase().includes(query.toLowerCase())) {
66112
66153
  if (seenNames.has(file.name.toLowerCase())) continue;
66113
66154
  seenNames.add(file.name.toLowerCase());
66114
- const statusText = file.status === "ready" ? "\u5DF2\u4E0A\u4F20" : file.status === "uploading" ? "\u4E0A\u4F20\u4E2D" : file.status === "expired" ? "\u5DF2\u8FC7\u671F" : file.status;
66155
+ const statusText = file.status === "ready" ? "uploaded" : file.status === "uploading" ? "uploading" : file.status === "expired" ? "expired" : file.status;
66115
66156
  options.push({
66116
66157
  type: "cached",
66117
66158
  name: file.name,
@@ -66135,7 +66176,7 @@ var MentionHandler = class {
66135
66176
  path: file.path,
66136
66177
  icon: getFileTypeIcon(file.type),
66137
66178
  cacheStatus: file.cacheStatus,
66138
- meta: `${this.formatCacheMeta(file.cacheStatus)}\u5F53\u524D\u76EE\u5F55 \u2022 ${formatBytes(file.size)}`
66179
+ meta: `${this.formatCacheMeta(file.cacheStatus)}current directory \u2022 ${formatBytes(file.size)}`
66139
66180
  });
66140
66181
  }
66141
66182
  } catch (err) {
@@ -66158,7 +66199,7 @@ var MentionHandler = class {
66158
66199
  hash: file.hash,
66159
66200
  fileId,
66160
66201
  icon: getFileTypeIcon(file.type),
66161
- meta: `\u7F13\u5B58 \u2022 ${formatBytes(file.size)}`
66202
+ meta: `cache \u2022 ${formatBytes(file.size)}`
66162
66203
  });
66163
66204
  if (options.length >= 10) break;
66164
66205
  }
@@ -66179,7 +66220,7 @@ var MentionHandler = class {
66179
66220
  name,
66180
66221
  path: resolvedPath,
66181
66222
  icon: "\u2B06\uFE0F",
66182
- meta: `${formatBytes(stats.size)} \u2022 \u70B9\u51FB\u4E0A\u4F20`
66223
+ meta: `${formatBytes(stats.size)} \u2022 click to upload`
66183
66224
  });
66184
66225
  }
66185
66226
  }
@@ -66204,7 +66245,7 @@ var MentionHandler = class {
66204
66245
  name: "..",
66205
66246
  path: path26.dirname(currentDir),
66206
66247
  icon: "\u21A9",
66207
- meta: "\u8FD4\u56DE\u4E0A\u7EA7\u76EE\u5F55"
66248
+ meta: "Parent directory"
66208
66249
  });
66209
66250
  }
66210
66251
  for (const directory of entries.directories) {
@@ -66213,7 +66254,7 @@ var MentionHandler = class {
66213
66254
  name: directory.name,
66214
66255
  path: directory.path,
66215
66256
  icon: "\u{1F4C1}",
66216
- meta: "\u76EE\u5F55"
66257
+ meta: "Directory"
66217
66258
  });
66218
66259
  }
66219
66260
  for (const file of entries.files) {
@@ -66228,7 +66269,7 @@ var MentionHandler = class {
66228
66269
  }
66229
66270
  return {
66230
66271
  options,
66231
- queryLabel: `\u6D4F\u89C8 ${displayDir}${filter ? ` \xB7 ${filter}` : ""}`
66272
+ queryLabel: `Browse ${displayDir}${filter ? ` \xB7 ${filter}` : ""}`
66232
66273
  };
66233
66274
  }
66234
66275
  getBrowserDirectory(query = this.currentQuery) {
@@ -66245,24 +66286,24 @@ var MentionHandler = class {
66245
66286
  const normalizedPlatform = normalizeFileManagerPlatform(platform2);
66246
66287
  const fileInfo = this.findFileByFileId(fileId);
66247
66288
  if (!fileInfo) {
66248
- return { reason: "\u6587\u4EF6\u4E0D\u53EF\u7528" };
66289
+ return { reason: "File unavailable" };
66249
66290
  }
66250
66291
  if (fileInfo.platform === "local") {
66251
- return { fileInfo, reason: "\u4EC5\u672C\u5730\u53EF\u590D\u7528" };
66292
+ return { fileInfo, reason: "Reusable locally only" };
66252
66293
  }
66253
66294
  if (fileInfo.platform !== normalizedPlatform) {
66254
- return { fileInfo, reason: "\u5F53\u524D\u5E73\u53F0\u4E0D\u53EF\u590D\u7528" };
66295
+ return { fileInfo, reason: "Not reusable on the current platform" };
66255
66296
  }
66256
66297
  const fileStatus = await this.fileManager.getFileStatus(fileId);
66257
66298
  if (!fileStatus) {
66258
- return { fileInfo, reason: "\u6587\u4EF6\u4E0D\u53EF\u7528" };
66299
+ return { fileInfo, reason: "File unavailable" };
66259
66300
  }
66260
66301
  if (fileStatus.status === "active" || fileStatus.status === "ready") {
66261
66302
  return { fileInfo, fileId, status: "ready", reason: "ok" };
66262
66303
  }
66263
66304
  if (fileStatus.status === "processing" || fileStatus.status === "uploading") {
66264
66305
  if (fileInfo.mimeType.startsWith("video/")) {
66265
- return { fileInfo, fileId, status: "uploading", reason: "\u89C6\u9891\u5904\u7406\u4E2D" };
66306
+ return { fileInfo, fileId, status: "uploading", reason: "Video is still processing" };
66266
66307
  }
66267
66308
  return { fileInfo, fileId, status: "ready", reason: "ok" };
66268
66309
  }
@@ -66271,12 +66312,12 @@ var MentionHandler = class {
66271
66312
  if (refreshed.success && refreshed.fileId) {
66272
66313
  return { fileInfo, fileId: refreshed.fileId, status: "ready", reason: "ok" };
66273
66314
  }
66274
- return { fileInfo, reason: "\u6587\u4EF6\u5DF2\u8FC7\u671F" };
66315
+ return { fileInfo, reason: "File expired" };
66275
66316
  }
66276
66317
  if (fileStatus.unsupportedPlatform) {
66277
- return { fileInfo, reason: "\u5F53\u524D\u5E73\u53F0\u4E0D\u53EF\u590D\u7528" };
66318
+ return { fileInfo, reason: "Not reusable on the current platform" };
66278
66319
  }
66279
- return { fileInfo, reason: "\u6587\u4EF6\u4E0D\u53EF\u7528" };
66320
+ return { fileInfo, reason: "File unavailable" };
66280
66321
  }
66281
66322
  formatMention(name, fileId) {
66282
66323
  return `@[${name}](file:${fileId}) `;
@@ -66286,20 +66327,20 @@ var MentionHandler = class {
66286
66327
  }
66287
66328
  formatUploadProgress(name, progress, stage) {
66288
66329
  const stageNames = {
66289
- analyzing: "\u5206\u6790\u4E2D",
66290
- preprocessing: "\u9884\u5904\u7406\u4E2D",
66291
- uploading: "\u4E0A\u4F20\u4E2D",
66292
- processing: "\u5E73\u53F0\u5904\u7406\u4E2D",
66293
- complete: "\u5B8C\u6210"
66330
+ analyzing: "Analyzing",
66331
+ preprocessing: "Preprocessing",
66332
+ uploading: "Uploading",
66333
+ processing: "Processing",
66334
+ complete: "Complete"
66294
66335
  };
66295
66336
  return `${stageNames[stage]} ${name}... ${Math.max(0, Math.min(100, Math.round(progress)))}%`;
66296
66337
  }
66297
66338
  formatCacheMeta(cacheStatus) {
66298
66339
  if (cacheStatus === "uploaded") {
66299
- return `\u66FE\u4E0A\u4F20\u5230${this.fileManager.getPlatformDisplayName()} \u2022 `;
66340
+ return `uploaded to ${this.fileManager.getPlatformDisplayName()} \u2022 `;
66300
66341
  }
66301
66342
  if (cacheStatus === "cached") {
66302
- return "\u4EC5\u672C\u5730\u53EF\u590D\u7528 \u2022 ";
66343
+ return "local cache only \u2022 ";
66303
66344
  }
66304
66345
  return "";
66305
66346
  }
@@ -66763,7 +66804,8 @@ function queueMessage(host, text, mode, options = {}) {
66763
66804
  streamingBehavior: mode,
66764
66805
  displayText: text,
66765
66806
  dedupeKey: options.dedupeKey,
66766
- clearEditor
66807
+ clearEditor,
66808
+ deliverWhileStreaming: options.deliverWhileStreaming ?? mode === "steer"
66767
66809
  }
66768
66810
  ).catch((error) => {
66769
66811
  host.showError(`Queue error: ${error instanceof Error ? error.message : String(error)}`);
@@ -67408,7 +67450,7 @@ function recoverFromInvalidFileReferenceError(host, errorMessage3) {
67408
67450
  const fileId = url.slice("ms://".length);
67409
67451
  if (!invalidFileIds.has(fileId)) return [block];
67410
67452
  messageChanged = true;
67411
- return [{ type: "text", text: " [\u6587\u4EF6\u5F15\u7528\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6587\u4EF6] " }];
67453
+ return [{ type: "text", text: " [File reference expired. Please attach the file again.] " }];
67412
67454
  });
67413
67455
  if (!messageChanged) return message;
67414
67456
  changed = true;
@@ -67416,7 +67458,7 @@ function recoverFromInvalidFileReferenceError(host, errorMessage3) {
67416
67458
  });
67417
67459
  if (!changed) return;
67418
67460
  host.replaceAgentMessagesAndMarkSynced(sanitizedMessages, { updateSession: true });
67419
- host.showStatus("\u68C0\u6D4B\u5230\u5931\u6548\u6587\u4EF6\u5F15\u7528\uFF0C\u5DF2\u4ECE\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587\u79FB\u9664\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6587\u4EF6");
67461
+ host.showStatus("Removed expired file references from this session context. Please attach the file again.");
67420
67462
  }
67421
67463
 
67422
67464
  // src/components/hierarchical-selector.ts
@@ -68198,6 +68240,80 @@ function buildDirectShellCommand(command) {
68198
68240
  }
68199
68241
  return { file: "bash", args: ["-lc", command], prompt: "$" };
68200
68242
  }
68243
+ var DIRECT_OUTPUT_MAX_LINES = 400;
68244
+ var DIRECT_OUTPUT_MAX_BYTES = 16 * 1024;
68245
+ var DIRECT_CAPTURE_PREFIX_BYTES = 512 * 1024;
68246
+ var DIRECT_CAPTURE_TAIL_BYTES = 512 * 1024;
68247
+ function takeUtf8Prefix(text, maxBytes) {
68248
+ const bytes = Buffer.from(text, "utf8");
68249
+ if (bytes.length <= maxBytes) return text;
68250
+ return bytes.subarray(0, maxBytes).toString("utf8").replace(/\uFFFD+$/g, "");
68251
+ }
68252
+ function takeUtf8Suffix(text, maxBytes) {
68253
+ const bytes = Buffer.from(text, "utf8");
68254
+ if (bytes.length <= maxBytes) return text;
68255
+ return bytes.subarray(Math.max(0, bytes.length - maxBytes)).toString("utf8").replace(/^\uFFFD+/g, "");
68256
+ }
68257
+ var DirectBashOutputCollector = class {
68258
+ prefix = "";
68259
+ tail = "";
68260
+ totalBytes = 0;
68261
+ overflowed = false;
68262
+ append(text) {
68263
+ if (!text) return;
68264
+ const bytes = Buffer.byteLength(text, "utf8");
68265
+ this.totalBytes += bytes;
68266
+ if (!this.overflowed) {
68267
+ const next = this.prefix + text;
68268
+ if (Buffer.byteLength(next, "utf8") <= DIRECT_CAPTURE_PREFIX_BYTES + DIRECT_CAPTURE_TAIL_BYTES) {
68269
+ this.prefix = next;
68270
+ return;
68271
+ }
68272
+ this.overflowed = true;
68273
+ this.prefix = takeUtf8Prefix(next, DIRECT_CAPTURE_PREFIX_BYTES);
68274
+ this.tail = takeUtf8Suffix(next, DIRECT_CAPTURE_TAIL_BYTES);
68275
+ return;
68276
+ }
68277
+ this.tail = takeUtf8Suffix(this.tail + text, DIRECT_CAPTURE_TAIL_BYTES);
68278
+ }
68279
+ format() {
68280
+ if (this.totalBytes === 0) {
68281
+ return {
68282
+ text: "[command completed with no output]",
68283
+ empty: true,
68284
+ truncated: false,
68285
+ totalBytes: 0,
68286
+ totalLines: 0
68287
+ };
68288
+ }
68289
+ const materialized = this.overflowed ? `${this.prefix}
68290
+ ... [direct bash capture omitted ${formatSize(Math.max(0, this.totalBytes - Buffer.byteLength(this.prefix, "utf8") - Buffer.byteLength(this.tail, "utf8")))} from the middle] ...
68291
+ ${this.tail}` : this.prefix;
68292
+ const truncated = truncateHeadTail(materialized, {
68293
+ maxLines: DIRECT_OUTPUT_MAX_LINES,
68294
+ maxBytes: DIRECT_OUTPUT_MAX_BYTES
68295
+ });
68296
+ const suffix = truncated.truncated ? `
68297
+
68298
+ [direct bash output truncated: showing ${truncated.outputLines}/${truncated.totalLines} lines, ${formatSize(truncated.outputBytes)}/${formatSize(this.totalBytes)}]` : "";
68299
+ return {
68300
+ text: `${truncated.content}${suffix}`,
68301
+ empty: false,
68302
+ truncated: truncated.truncated || this.overflowed,
68303
+ totalBytes: this.totalBytes,
68304
+ totalLines: truncated.totalLines
68305
+ };
68306
+ }
68307
+ };
68308
+ function renderOutputText(outputContainer, text, color = "dim") {
68309
+ const lines = text.split("\n");
68310
+ for (let i = 0; i < lines.length; i += 1) {
68311
+ const line = lines[i];
68312
+ if (line || i < lines.length - 1) {
68313
+ outputContainer.addChild(new Text(theme.fg(color, line), 1, 0));
68314
+ }
68315
+ }
68316
+ }
68201
68317
  async function handleDirectBash(host, command) {
68202
68318
  host.chatContainer.addChild(new Spacer(1));
68203
68319
  const shellCommand = buildDirectShellCommand(command);
@@ -68212,31 +68328,20 @@ async function handleDirectBash(host, command) {
68212
68328
  cwd: process.cwd(),
68213
68329
  env: process.env
68214
68330
  });
68331
+ const output = new DirectBashOutputCollector();
68215
68332
  child.stdout.on("data", (data) => {
68216
- const text = data.toString();
68217
- const lines = text.split("\n");
68218
- for (const line of lines) {
68219
- if (line || lines.indexOf(line) < lines.length - 1) {
68220
- outputContainer.addChild(new Text(theme.fg("dim", line), 1, 0));
68221
- }
68222
- }
68223
- host.ui.requestRender();
68333
+ output.append(data.toString());
68224
68334
  });
68225
68335
  child.stderr.on("data", (data) => {
68226
- const text = data.toString();
68227
- const lines = text.split("\n");
68228
- for (const line of lines) {
68229
- if (line || lines.indexOf(line) < lines.length - 1) {
68230
- outputContainer.addChild(new Text(theme.fg("error", line), 1, 0));
68231
- }
68232
- }
68233
- host.ui.requestRender();
68336
+ output.append(data.toString());
68234
68337
  });
68235
68338
  return new Promise((resolve5) => {
68236
68339
  let settled = false;
68237
68340
  const finish = (code) => {
68238
68341
  if (settled) return;
68239
68342
  settled = true;
68343
+ const formatted = output.format();
68344
+ renderOutputText(outputContainer, formatted.text, code === 0 ? "dim" : "error");
68240
68345
  if (code !== 0) {
68241
68346
  outputContainer.addChild(new Spacer(1));
68242
68347
  outputContainer.addChild(new Text(theme.fg("error", `[exit ${code ?? "spawn error"}]`), 1, 0));
@@ -68246,7 +68351,7 @@ async function handleDirectBash(host, command) {
68246
68351
  resolve5();
68247
68352
  };
68248
68353
  child.on("error", (error) => {
68249
- outputContainer.addChild(new Text(theme.fg("error", error.message), 1, 0));
68354
+ output.append(error.message);
68250
68355
  finish(null);
68251
68356
  });
68252
68357
  child.on("close", (code) => {
@@ -69094,6 +69199,7 @@ var InteractiveMode = class {
69094
69199
  },
69095
69200
  apiKey: this.options.apiKey,
69096
69201
  sessionId: activeSession?.id,
69202
+ streamFn: this.options.streamFn,
69097
69203
  transformContext: createRuntimeModeTransformContext({
69098
69204
  getState: () => this.getRuntimeModeState(),
69099
69205
  consumeTransition: () => this.consumeRuntimeModeTransition(),
@@ -71075,11 +71181,8 @@ async function runWithJsonEventsConsoleIsolation(fn) {
71075
71181
  }
71076
71182
  }
71077
71183
  async function createCliTestStreamFnFromEnv() {
71078
- if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) {
71079
- return void 0;
71080
- }
71081
- const { createTestStreamFnFromSequenceEnv } = await import("./chunks/test-stream-ZNGAUUVH.js");
71082
- return createTestStreamFnFromSequenceEnv();
71184
+ if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
71185
+ return (await import("./chunks/test-stream-A7JSM2UM.js")).createTestStreamFnFromSequenceEnv();
71083
71186
  }
71084
71187
  async function startChat(initialPrompt, testCommand) {
71085
71188
  const rawOutput = process.argv.includes("--raw-output");
@@ -71150,7 +71253,9 @@ async function startChat(initialPrompt, testCommand) {
71150
71253
  process.env.PIE_TUI_ACTIVE = "1";
71151
71254
  const runtimeLogger = initializeCliRuntimeLogger(runtime.sessionId, { mode: "interactive_tui" });
71152
71255
  const restoreConsoleInterception = installInteractiveConsoleInterception(runtimeLogger);
71153
- const interactive = new InteractiveMode(runtime.createInteractiveOptions());
71256
+ const interactiveOptions = runtime.createInteractiveOptions();
71257
+ interactiveOptions.streamFn = await createCliTestStreamFnFromEnv();
71258
+ const interactive = new InteractiveMode(interactiveOptions);
71154
71259
  try {
71155
71260
  await interactive.init();
71156
71261
  if (runtime.initialModel.unconfigured && runtime.initialModel.warning) {