@protolabsai/proto 0.26.12 → 0.26.16

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/README.md CHANGED
@@ -174,11 +174,23 @@ proto auto-discovers Claude Code plugins installed at `~/.claude/plugins/`. Any
174
174
 
175
175
  ### Environment variable overrides
176
176
 
177
- | Variable | Default | Description |
178
- | ------------------------------- | ------- | ----------------------------------------------------------------------------------------------- |
179
- | `PROTO_STREAM_STALL_TIMEOUT_MS` | `90000` | Max ms to wait between streaming chunks before declaring the connection stalled (then retrying) |
180
- | `PROTO_SYSTEM_DEFAULTS_PATH` | — | Override path to the system defaults settings file |
181
- | `PROTO_SYSTEM_SETTINGS_PATH` | — | Override path to the system settings override file |
177
+ | Variable | Default | Description |
178
+ | ----------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
179
+ | `PROTO_STREAM_STALL_TIMEOUT_MS` | `90000` | Max ms to wait between streaming chunks before declaring the connection stalled (then retrying) |
180
+ | `PROTO_SYSTEM_DEFAULTS_PATH` | — | Override path to the system defaults settings file |
181
+ | `PROTO_SYSTEM_SETTINGS_PATH` | — | Override path to the system settings override file |
182
+ | `PROTO_LEGACY_ERASE_LINES` | — | Set to `1` to disable the cursor-collapse optimizer that prevents Ink scrollback bouncing during streaming renders. Only set this if it interferes with your terminal. |
183
+ | `PROTO_FORCE_SYNCHRONIZED_OUTPUT` | — | Set to `1` to force-enable BSU/ESU atomic-frame escape codes regardless of terminal auto-detect (useful if your terminal supports DEC mode 2026 but isn't on the allowlist below). |
184
+ | `PROTO_DISABLE_SYNCHRONIZED_OUTPUT` | — | Set to `1` to opt out of synchronized output even on supported terminals. |
185
+
186
+ ### TUI flicker mitigation
187
+
188
+ proto installs two stdout interventions to reduce flicker during streaming renders:
189
+
190
+ 1. **Cursor-collapse optimizer** — collapses Ink's per-line `{ERASE_LINE, CURSOR_UP_ONE}` sequences into a single bounded erase. Universal; bypass via `PROTO_LEGACY_ERASE_LINES=1`.
191
+ 2. **Synchronized output** — wraps each render frame in BSU/ESU escape codes (DEC mode 2026) on terminals that support it. Auto-detected for: **Alacritty (≥0.14), Ghostty, Kitty, WezTerm, iTerm2**. For other DEC-2026-capable terminals, set `PROTO_FORCE_SYNCHRONIZED_OUTPUT=1`.
192
+
193
+ Both no-op outside a TTY, in screen-reader mode, or under tmux/SSH.
182
194
 
183
195
  ## Observability
184
196
 
package/cli.js CHANGED
@@ -171128,7 +171128,7 @@ __export(geminiContentGenerator_exports, {
171128
171128
  createGeminiContentGenerator: () => createGeminiContentGenerator
171129
171129
  });
171130
171130
  function createGeminiContentGenerator(config2, gcConfig) {
171131
- const version2 = "0.26.12";
171131
+ const version2 = "0.26.16";
171132
171132
  const userAgent2 = config2.userAgent || `QwenCode/${version2} (${process.platform}; ${process.arch})`;
171133
171133
  const baseHeaders = {
171134
171134
  "User-Agent": userAgent2
@@ -183136,7 +183136,21 @@ var require_xterm_headless = __commonJS({
183136
183136
  });
183137
183137
 
183138
183138
  // packages/core/dist/src/utils/terminalSerializer.js
183139
- function serializeTerminalToObject(terminal, scrollOffset = 0) {
183139
+ function serializeTerminalToText(terminal) {
183140
+ const buffer = terminal.buffer.active;
183141
+ const lines = [];
183142
+ for (let i4 = 0; i4 < buffer.length; i4++) {
183143
+ const line = buffer.getLine(i4);
183144
+ const lineContent = line ? line.translateToString(true) : "";
183145
+ if (line?.isWrapped && lines.length > 0) {
183146
+ lines[lines.length - 1] += lineContent;
183147
+ continue;
183148
+ }
183149
+ lines.push(lineContent);
183150
+ }
183151
+ return lines.join("\n").trimEnd();
183152
+ }
183153
+ function serializeTerminalToObject(terminal, scrollOffset = 0, options2 = {}) {
183140
183154
  const buffer = terminal.buffer.active;
183141
183155
  const defaultFg = "";
183142
183156
  const defaultBg = "";
@@ -183189,7 +183203,11 @@ function serializeTerminalToObject(terminal, scrollOffset = 0) {
183189
183203
  };
183190
183204
  currentLine.push(token2);
183191
183205
  }
183192
- result.push(currentLine);
183206
+ if (options2.unwrapWrappedLines && line.isWrapped && result.length > 0) {
183207
+ appendAnsiLineTokens(result[result.length - 1], currentLine);
183208
+ } else {
183209
+ result.push(currentLine);
183210
+ }
183193
183211
  }
183194
183212
  return result;
183195
183213
  }
@@ -183205,11 +183223,23 @@ function convertColorToHex(color, colorMode, defaultColor) {
183205
183223
  }
183206
183224
  return defaultColor;
183207
183225
  }
183208
- var Attribute, ColorMode, Cell, ANSI_COLORS;
183226
+ var canMergeAnsiTokens, appendAnsiLineTokens, Attribute, ColorMode, Cell, ANSI_COLORS;
183209
183227
  var init_terminalSerializer = __esm({
183210
183228
  "packages/core/dist/src/utils/terminalSerializer.js"() {
183211
183229
  "use strict";
183212
183230
  init_esbuild_shims();
183231
+ canMergeAnsiTokens = /* @__PURE__ */ __name((left3, right3) => left3.bold === right3.bold && left3.italic === right3.italic && left3.underline === right3.underline && left3.dim === right3.dim && left3.inverse === right3.inverse && left3.fg === right3.fg && left3.bg === right3.bg, "canMergeAnsiTokens");
183232
+ appendAnsiLineTokens = /* @__PURE__ */ __name((target, source2) => {
183233
+ for (const token2 of source2) {
183234
+ const previous = target[target.length - 1];
183235
+ if (previous && canMergeAnsiTokens(previous, token2)) {
183236
+ previous.text += token2.text;
183237
+ } else {
183238
+ target.push({ ...token2 });
183239
+ }
183240
+ }
183241
+ }, "appendAnsiLineTokens");
183242
+ __name(serializeTerminalToText, "serializeTerminalToText");
183213
183243
  (function(Attribute2) {
183214
183244
  Attribute2[Attribute2["inverse"] = 1] = "inverse";
183215
183245
  Attribute2[Attribute2["bold"] = 2] = "bold";
@@ -183626,7 +183656,7 @@ function applyPowerShellUtf8Prefix(command2, shell2) {
183626
183656
  }
183627
183657
  return command2;
183628
183658
  }
183629
- var import_headless, Terminal, SIGKILL_TIMEOUT_MS, WINDOWS_PATH_DELIMITER, cachedWindowsPathFingerprint, cachedMergedWindowsPath, getErrnoCode, getErrorMessage2, isExpectedPtyReadExitError, isExpectedPtyExitRaceError, getFullBufferText, replayTerminalOutput, windowsStrategy, posixStrategy, getCleanupStrategy, ShellExecutionService;
183659
+ var import_headless, Terminal, SIGKILL_TIMEOUT_MS, WINDOWS_PATH_DELIMITER, cachedWindowsPathFingerprint, cachedMergedWindowsPath, getErrnoCode, getErrorMessage2, isExpectedPtyReadExitError, isExpectedPtyExitRaceError, replayTerminalOutput, getLastNonEmptyAnsiLineIndex, trimTrailingEmptyAnsiLines, areAnsiOutputsEqual, createPlainAnsiLine, serializePlainViewportToAnsiOutput, windowsStrategy, posixStrategy, getCleanupStrategy, ShellExecutionService;
183630
183660
  var init_shellExecutionService = __esm({
183631
183661
  "packages/core/dist/src/services/shellExecutionService.js"() {
183632
183662
  "use strict";
@@ -183669,16 +183699,6 @@ var init_shellExecutionService = __esm({
183669
183699
  const message = getErrorMessage2(error40);
183670
183700
  return message.includes("ioctl(2) failed, EBADF") || message.includes("Cannot resize a pty that has already exited");
183671
183701
  }, "isExpectedPtyExitRaceError");
183672
- getFullBufferText = /* @__PURE__ */ __name((terminal) => {
183673
- const buffer = terminal.buffer.active;
183674
- const lines = [];
183675
- for (let i4 = 0; i4 < buffer.length; i4++) {
183676
- const line = buffer.getLine(i4);
183677
- const lineContent = line ? line.translateToString(true) : "";
183678
- lines.push(lineContent);
183679
- }
183680
- return lines.join("\n").trimEnd();
183681
- }, "getFullBufferText");
183682
183702
  replayTerminalOutput = /* @__PURE__ */ __name(async (output, cols, rows) => {
183683
183703
  const replayTerminal = new Terminal({
183684
183704
  allowProposedApi: true,
@@ -183690,8 +183710,59 @@ var init_shellExecutionService = __esm({
183690
183710
  await new Promise((resolve38) => {
183691
183711
  replayTerminal.write(output, () => resolve38());
183692
183712
  });
183693
- return getFullBufferText(replayTerminal);
183713
+ return serializeTerminalToText(replayTerminal);
183694
183714
  }, "replayTerminalOutput");
183715
+ getLastNonEmptyAnsiLineIndex = /* @__PURE__ */ __name((output) => {
183716
+ for (let i4 = output.length - 1; i4 >= 0; i4--) {
183717
+ const line = output[i4];
183718
+ if (line.map((segment) => segment.text).join("").trim().length > 0) {
183719
+ return i4;
183720
+ }
183721
+ }
183722
+ return -1;
183723
+ }, "getLastNonEmptyAnsiLineIndex");
183724
+ trimTrailingEmptyAnsiLines = /* @__PURE__ */ __name((output) => output.slice(0, getLastNonEmptyAnsiLineIndex(output) + 1), "trimTrailingEmptyAnsiLines");
183725
+ areAnsiOutputsEqual = /* @__PURE__ */ __name((left3, right3) => {
183726
+ if (!left3 || left3.length !== right3.length) {
183727
+ return false;
183728
+ }
183729
+ return left3.every((leftLine, lineIndex) => {
183730
+ const rightLine = right3[lineIndex];
183731
+ if (leftLine.length !== rightLine.length) {
183732
+ return false;
183733
+ }
183734
+ return leftLine.every((leftToken, tokenIndex) => {
183735
+ const rightToken = rightLine[tokenIndex];
183736
+ return leftToken.text === rightToken.text && leftToken.bold === rightToken.bold && leftToken.italic === rightToken.italic && leftToken.underline === rightToken.underline && leftToken.dim === rightToken.dim && leftToken.inverse === rightToken.inverse && leftToken.fg === rightToken.fg && leftToken.bg === rightToken.bg;
183737
+ });
183738
+ });
183739
+ }, "areAnsiOutputsEqual");
183740
+ createPlainAnsiLine = /* @__PURE__ */ __name((text) => [
183741
+ {
183742
+ text,
183743
+ bold: false,
183744
+ italic: false,
183745
+ underline: false,
183746
+ dim: false,
183747
+ inverse: false,
183748
+ fg: "",
183749
+ bg: ""
183750
+ }
183751
+ ], "createPlainAnsiLine");
183752
+ serializePlainViewportToAnsiOutput = /* @__PURE__ */ __name((terminal, unwrapWrappedLines = false) => {
183753
+ const buffer = terminal.buffer.active;
183754
+ const lines = [];
183755
+ for (let y2 = 0; y2 < terminal.rows; y2++) {
183756
+ const line = buffer.getLine(buffer.viewportY + y2);
183757
+ const lineContent = line ? line.translateToString(true) : "";
183758
+ if (unwrapWrappedLines && line?.isWrapped && lines.length > 0) {
183759
+ lines[lines.length - 1][0].text += lineContent;
183760
+ } else {
183761
+ lines.push(createPlainAnsiLine(lineContent));
183762
+ }
183763
+ }
183764
+ return lines;
183765
+ }, "serializePlainViewportToAnsiOutput");
183695
183766
  windowsStrategy = {
183696
183767
  killPty: /* @__PURE__ */ __name((_pid, pty) => {
183697
183768
  pty.ptyProcess.kill();
@@ -183954,7 +184025,7 @@ var init_shellExecutionService = __esm({
183954
184025
  this.activePtys.set(ptyProcess.pid, { ptyProcess, headlessTerminal });
183955
184026
  let processingChain = Promise.resolve();
183956
184027
  let decoder = null;
183957
- let output = null;
184028
+ let outputComparison = null;
183958
184029
  const outputChunks = [];
183959
184030
  const error40 = null;
183960
184031
  let exited = false;
@@ -183972,7 +184043,7 @@ var init_shellExecutionService = __esm({
183972
184043
  }
183973
184044
  if (!shellExecutionConfig.disableDynamicLineTrimming) {
183974
184045
  if (!hasStartedOutput) {
183975
- const bufferText = getFullBufferText(headlessTerminal);
184046
+ const bufferText = serializeTerminalToText(headlessTerminal);
183976
184047
  if (bufferText.trim().length === 0) {
183977
184048
  return;
183978
184049
  }
@@ -183980,41 +184051,20 @@ var init_shellExecutionService = __esm({
183980
184051
  }
183981
184052
  }
183982
184053
  let newOutput;
184054
+ let newOutputComparison;
183983
184055
  if (shellExecutionConfig.showColor) {
183984
184056
  newOutput = serializeTerminalToObject(headlessTerminal);
184057
+ newOutputComparison = serializeTerminalToObject(headlessTerminal, 0, { unwrapWrappedLines: true });
183985
184058
  } else {
183986
- const buffer = headlessTerminal.buffer.active;
183987
- const lines = [];
183988
- for (let y2 = 0; y2 < headlessTerminal.rows; y2++) {
183989
- const line = buffer.getLine(buffer.viewportY + y2);
183990
- const lineContent = line ? line.translateToString(true) : "";
183991
- lines.push([
183992
- {
183993
- text: lineContent,
183994
- bold: false,
183995
- italic: false,
183996
- underline: false,
183997
- dim: false,
183998
- inverse: false,
183999
- fg: "",
184000
- bg: ""
184001
- }
184002
- ]);
184003
- }
184004
- newOutput = lines;
184059
+ newOutput = serializePlainViewportToAnsiOutput(headlessTerminal);
184060
+ newOutputComparison = serializePlainViewportToAnsiOutput(headlessTerminal, true);
184005
184061
  }
184006
- let lastNonEmptyLine = -1;
184007
- for (let i4 = newOutput.length - 1; i4 >= 0; i4--) {
184008
- const line = newOutput[i4];
184009
- if (line.map((segment) => segment.text).join("").trim().length > 0) {
184010
- lastNonEmptyLine = i4;
184011
- break;
184012
- }
184013
- }
184014
- const trimmedOutput = newOutput.slice(0, lastNonEmptyLine + 1);
184062
+ const trimmedOutput = trimTrailingEmptyAnsiLines(newOutput);
184063
+ const trimmedOutputComparison = trimTrailingEmptyAnsiLines(newOutputComparison);
184015
184064
  const finalOutput = shellExecutionConfig.disableDynamicLineTrimming ? newOutput : trimmedOutput;
184016
- if (JSON.stringify(output) !== JSON.stringify(finalOutput)) {
184017
- output = finalOutput;
184065
+ const finalOutputComparison = shellExecutionConfig.disableDynamicLineTrimming ? newOutputComparison : trimmedOutputComparison;
184066
+ if (!areAnsiOutputsEqual(outputComparison, finalOutputComparison)) {
184067
+ outputComparison = finalOutputComparison;
184018
184068
  onOutputEvent({
184019
184069
  type: "data",
184020
184070
  chunk: finalOutput
@@ -184115,11 +184165,11 @@ var init_shellExecutionService = __esm({
184115
184165
  const decodedOutput = new TextDecoder2(finalEncoding).decode(finalBuffer);
184116
184166
  fullOutput = await replayTerminalOutput(decodedOutput, cols, rows);
184117
184167
  } else {
184118
- fullOutput = getFullBufferText(headlessTerminal);
184168
+ fullOutput = serializeTerminalToText(headlessTerminal);
184119
184169
  }
184120
184170
  } catch {
184121
184171
  try {
184122
- fullOutput = getFullBufferText(headlessTerminal);
184172
+ fullOutput = serializeTerminalToText(headlessTerminal);
184123
184173
  } catch {
184124
184174
  }
184125
184175
  }
@@ -189125,7 +189175,7 @@ var init_coreToolScheduler = __esm({
189125
189175
  }
189126
189176
  const isAskUserQuestionTool = reqInfo.name === ToolNames.ASK_USER_QUESTION;
189127
189177
  let confirmationDetails;
189128
- if (approvalMode === ApprovalMode.YOLO && !isAskUserQuestionTool) {
189178
+ if (approvalMode === ApprovalMode.YOLO && !isAskUserQuestionTool && !isExitPlanModeTool) {
189129
189179
  this.setToolCallOutcome(reqInfo.callId, ToolConfirmationOutcome.ProceedAlways);
189130
189180
  this.setStatusInternal(reqInfo.callId, "scheduled");
189131
189181
  } else {
@@ -290139,6 +290189,7 @@ __export(dist_exports, {
290139
290189
  scanMemoryHeaders: () => scanMemoryHeaders,
290140
290190
  serializeMemoryFile: () => serializeMemoryFile,
290141
290191
  serializeTerminalToObject: () => serializeTerminalToObject,
290192
+ serializeTerminalToText: () => serializeTerminalToText,
290142
290193
  sessionScopeLock: () => sessionScopeLock,
290143
290194
  setDebugLogSession: () => setDebugLogSession,
290144
290195
  setGeminiMdFilename: () => setGeminiMdFilename,
@@ -327612,7 +327663,7 @@ var init_de2 = __esm({
327612
327663
  "Custom Witty Phrases": "Benutzerdefinierte Witzige Spr\xFCche",
327613
327664
  "Show Welcome Back Dialog": "Willkommen-zur\xFCck-Dialog anzeigen",
327614
327665
  "Enable User Feedback": "Benutzerfeedback aktivieren",
327615
- "How is Qwen doing this session? (optional)": "Wie macht sich Qwen in dieser Sitzung? (optional)",
327666
+ "How is proto doing this session? (optional)": "Wie macht sich Qwen in dieser Sitzung? (optional)",
327616
327667
  Bad: "Schlecht",
327617
327668
  Fine: "In Ordnung",
327618
327669
  Good: "Gut",
@@ -331857,7 +331908,7 @@ var init_pt2 = __esm({
331857
331908
  "Custom Witty Phrases": "Frases de Efeito Personalizadas",
331858
331909
  "Show Welcome Back Dialog": "Mostrar Di\xE1logo de Bem-vindo de Volta",
331859
331910
  "Enable User Feedback": "Ativar Feedback do Usu\xE1rio",
331860
- "How is Qwen doing this session? (optional)": "Como o Qwen est\xE1 se saindo nesta sess\xE3o? (opcional)",
331911
+ "How is proto doing this session? (optional)": "Como o Qwen est\xE1 se saindo nesta sess\xE3o? (opcional)",
331861
331912
  Bad: "Ruim",
331862
331913
  Fine: "Bom",
331863
331914
  Good: "\xD3timo",
@@ -333303,7 +333354,7 @@ var init_ru2 = __esm({
333303
333354
  "Custom Witty Phrases": "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0435 \u043E\u0441\u0442\u0440\u043E\u0443\u043C\u043D\u044B\u0435 \u0444\u0440\u0430\u0437\u044B",
333304
333355
  "Show Welcome Back Dialog": "\u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0434\u0438\u0430\u043B\u043E\u0433 \u043F\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044F",
333305
333356
  "Enable User Feedback": "\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043E\u0442\u0437\u044B\u0432\u044B \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439",
333306
- "How is Qwen doing this session? (optional)": "\u041A\u0430\u043A \u0434\u0435\u043B\u0430 \u0443 Qwen \u0432 \u044D\u0442\u043E\u0439 \u0441\u0435\u0441\u0441\u0438\u0438? (\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E)",
333357
+ "How is proto doing this session? (optional)": "\u041A\u0430\u043A \u0434\u0435\u043B\u0430 \u0443 Qwen \u0432 \u044D\u0442\u043E\u0439 \u0441\u0435\u0441\u0441\u0438\u0438? (\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E)",
333307
333358
  Bad: "\u041F\u043B\u043E\u0445\u043E",
333308
333359
  Fine: "\u041D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E",
333309
333360
  Good: "\u0425\u043E\u0440\u043E\u0448\u043E",
@@ -334826,7 +334877,7 @@ var init_zh = __esm({
334826
334877
  "Custom Witty Phrases": "\u81EA\u5B9A\u4E49\u8BD9\u8C10\u77ED\u8BED",
334827
334878
  "Show Welcome Back Dialog": "\u663E\u793A\u6B22\u8FCE\u56DE\u6765\u5BF9\u8BDD\u6846",
334828
334879
  "Enable User Feedback": "\u542F\u7528\u7528\u6237\u53CD\u9988",
334829
- "How is Qwen doing this session? (optional)": "Qwen \u8FD9\u6B21\u8868\u73B0\u5982\u4F55\uFF1F\uFF08\u53EF\u9009\uFF09",
334880
+ "How is proto doing this session? (optional)": "Qwen \u8FD9\u6B21\u8868\u73B0\u5982\u4F55\uFF1F\uFF08\u53EF\u9009\uFF09",
334830
334881
  Bad: "\u4E0D\u6EE1\u610F",
334831
334882
  Fine: "\u8FD8\u884C",
334832
334883
  Good: "\u6EE1\u610F",
@@ -416326,7 +416377,7 @@ __name(getPackageJson, "getPackageJson");
416326
416377
  // packages/cli/src/utils/version.ts
416327
416378
  async function getCliVersion() {
416328
416379
  const pkgJson = await getPackageJson();
416329
- return "0.26.12";
416380
+ return "0.26.16";
416330
416381
  }
416331
416382
  __name(getCliVersion, "getCliVersion");
416332
416383
 
@@ -424098,7 +424149,7 @@ var formatDuration = /* @__PURE__ */ __name((milliseconds) => {
424098
424149
 
424099
424150
  // packages/cli/src/generated/git-commit.ts
424100
424151
  init_esbuild_shims();
424101
- var GIT_COMMIT_INFO = "90b666636";
424152
+ var GIT_COMMIT_INFO = "ee5cd29e9";
424102
424153
 
424103
424154
  // packages/cli/src/utils/systemInfo.ts
424104
424155
  async function getNpmVersion() {
@@ -460758,6 +460809,52 @@ var RESERVED_LINE_COUNT = 5;
460758
460809
  var STATUS_INDICATOR_WIDTH = 3;
460759
460810
  var MIN_LINES_SHOWN = 2;
460760
460811
  var MAXIMUM_RESULT_DISPLAY_CHARACTERS = 1e6;
460812
+ function sliceTextForMaxHeight(text, maxHeight, maxWidth) {
460813
+ if (maxHeight === void 0) {
460814
+ return { text, hiddenLinesCount: 0 };
460815
+ }
460816
+ const targetMaxHeight = Math.max(Math.round(maxHeight), MINIMUM_MAX_HEIGHT);
460817
+ const visibleContentHeight = targetMaxHeight - 1;
460818
+ const visualWidth = Math.max(1, Math.floor(maxWidth));
460819
+ const visibleLines = [];
460820
+ let visualLineCount = 0;
460821
+ let currentLine = "";
460822
+ let currentLineWidth = 0;
460823
+ const appendVisibleLine = /* @__PURE__ */ __name((line) => {
460824
+ visualLineCount += 1;
460825
+ visibleLines.push(line);
460826
+ if (visibleLines.length > visibleContentHeight) {
460827
+ visibleLines.shift();
460828
+ }
460829
+ }, "appendVisibleLine");
460830
+ const flushCurrentLine = /* @__PURE__ */ __name(() => {
460831
+ appendVisibleLine(currentLine);
460832
+ currentLine = "";
460833
+ currentLineWidth = 0;
460834
+ }, "flushCurrentLine");
460835
+ for (const char of toCodePoints(text)) {
460836
+ if (char === "\n") {
460837
+ flushCurrentLine();
460838
+ continue;
460839
+ }
460840
+ const charWidth = Math.max(getCachedStringWidth(char), 1);
460841
+ if (currentLineWidth > 0 && currentLineWidth + charWidth > visualWidth) {
460842
+ flushCurrentLine();
460843
+ }
460844
+ currentLine += char;
460845
+ currentLineWidth += charWidth;
460846
+ }
460847
+ flushCurrentLine();
460848
+ if (visualLineCount <= targetMaxHeight) {
460849
+ return { text, hiddenLinesCount: 0 };
460850
+ }
460851
+ const hiddenLinesCount = visualLineCount - visibleContentHeight;
460852
+ return {
460853
+ text: visibleLines.join("\n"),
460854
+ hiddenLinesCount
460855
+ };
460856
+ }
460857
+ __name(sliceTextForMaxHeight, "sliceTextForMaxHeight");
460761
460858
  var useResultDisplayRenderer = /* @__PURE__ */ __name((resultDisplay) => import_react64.default.useMemo(() => {
460762
460859
  if (!resultDisplay) {
460763
460860
  return { type: "none" };
@@ -460845,7 +460942,20 @@ var StringResultRenderer = /* @__PURE__ */ __name(({ data, renderAsMarkdown, ava
460845
460942
  }
460846
460943
  ) });
460847
460944
  }
460848
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MaxSizedBox, { maxHeight: availableHeight, maxWidth: childWidth, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Text3, { wrap: "wrap", color: theme.text.primary, children: displayData }) }) });
460945
+ const sliced = sliceTextForMaxHeight(
460946
+ displayData,
460947
+ availableHeight,
460948
+ childWidth
460949
+ );
460950
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
460951
+ MaxSizedBox,
460952
+ {
460953
+ maxHeight: availableHeight,
460954
+ maxWidth: childWidth,
460955
+ additionalHiddenLinesCount: sliced.hiddenLinesCount,
460956
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Text3, { wrap: "wrap", color: theme.text.primary, children: sliced.text }) })
460957
+ }
460958
+ );
460849
460959
  }, "StringResultRenderer");
460850
460960
  var DiffResultRenderer = /* @__PURE__ */ __name(({ data, availableHeight, childWidth, settings: settings2 }) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
460851
460961
  DiffRenderer,
@@ -474190,7 +474300,7 @@ var FeedbackDialog = /* @__PURE__ */ __name(() => {
474190
474300
  return /* @__PURE__ */ (0, import_jsx_runtime117.jsxs)(Box_default, { flexDirection: "column", marginY: 1, children: [
474191
474301
  /* @__PURE__ */ (0, import_jsx_runtime117.jsxs)(Box_default, { children: [
474192
474302
  /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(Text3, { color: "cyan", children: "\u25CF " }),
474193
- /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(Text3, { bold: true, children: t4("How is Qwen doing this session? (optional)") })
474303
+ /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(Text3, { bold: true, children: t4("How is proto doing this session? (optional)") })
474194
474304
  ] }),
474195
474305
  /* @__PURE__ */ (0, import_jsx_runtime117.jsxs)(Box_default, { marginTop: 1, children: [
474196
474306
  /* @__PURE__ */ (0, import_jsx_runtime117.jsxs)(Text3, { color: "cyan", children: [
@@ -479899,6 +480009,7 @@ function checkImageFormatsSupport(parts2) {
479899
480009
  }
479900
480010
  __name(checkImageFormatsSupport, "checkImageFormatsSupport");
479901
480011
  var EDIT_TOOL_NAMES = /* @__PURE__ */ new Set(["replace", "write_file"]);
480012
+ var STREAM_UPDATE_THROTTLE_MS = 60;
479902
480013
  function showCitations(settings2) {
479903
480014
  const enabled = settings2?.merged?.ui?.showCitations;
479904
480015
  if (enabled !== void 0) {
@@ -479910,6 +480021,7 @@ __name(showCitations, "showCitations");
479910
480021
  var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, config2, settings2, onDebugMessage, handleSlashCommand2, shellModeActive, getPreferredEditor, onAuthError, performMemoryRefresh, modelSwitchedFromQuotaError, setModelSwitchedFromQuotaError, onEditorClose, onCancelSubmit, setShellInputFocused, terminalWidth, terminalHeight, drainQueuedMessages) => {
479911
480022
  const [initError, setInitError] = (0, import_react148.useState)(null);
479912
480023
  const abortControllerRef = (0, import_react148.useRef)(null);
480024
+ const flushBufferedStreamEventsRef = (0, import_react148.useRef)(/* @__PURE__ */ new Set());
479913
480025
  const turnCancelledRef = (0, import_react148.useRef)(false);
479914
480026
  const queryGuardRef = (0, import_react148.useRef)(new QueryGuard());
479915
480027
  const lastPromptRef = (0, import_react148.useRef)(null);
@@ -480107,6 +480219,9 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
480107
480219
  if (turnCancelledRef.current) {
480108
480220
  return;
480109
480221
  }
480222
+ for (const flushBufferedStreamEvents of flushBufferedStreamEventsRef.current) {
480223
+ flushBufferedStreamEvents();
480224
+ }
480110
480225
  turnCancelledRef.current = true;
480111
480226
  queryGuardRef.current.forceEnd();
480112
480227
  abortControllerRef.current?.abort();
@@ -480550,81 +480665,158 @@ var useGeminiStream = /* @__PURE__ */ __name((geminiClient, history, addItem, co
480550
480665
  let geminiMessageBuffer = "";
480551
480666
  let thoughtBuffer = "";
480552
480667
  const toolCallRequests = [];
480553
- for await (const event of stream2) {
480554
- switch (event.type) {
480555
- case GeminiEventType.Thought:
480556
- if (event.value.subject) {
480557
- setThought(event.value);
480558
- } else {
480559
- thoughtBuffer = handleThoughtEvent(
480560
- event.value,
480561
- thoughtBuffer,
480562
- userMessageTimestamp
480563
- );
480668
+ const bufferedEvents = [];
480669
+ let flushTimer = null;
480670
+ const discardBufferedStreamEvents = /* @__PURE__ */ __name(() => {
480671
+ if (flushTimer) {
480672
+ clearTimeout(flushTimer);
480673
+ flushTimer = null;
480674
+ }
480675
+ bufferedEvents.length = 0;
480676
+ }, "discardBufferedStreamEvents");
480677
+ const flushBufferedStreamEvents = /* @__PURE__ */ __name(() => {
480678
+ if (flushTimer) {
480679
+ clearTimeout(flushTimer);
480680
+ flushTimer = null;
480681
+ }
480682
+ if (bufferedEvents.length === 0) {
480683
+ return;
480684
+ }
480685
+ while (bufferedEvents.length > 0) {
480686
+ const nextEvent = bufferedEvents.shift();
480687
+ if (nextEvent.kind === "content") {
480688
+ let mergedContent = nextEvent.value;
480689
+ while (bufferedEvents[0]?.kind === "content") {
480690
+ const queuedContent = bufferedEvents.shift();
480691
+ if (queuedContent?.kind !== "content") {
480692
+ break;
480693
+ }
480694
+ mergedContent += queuedContent.value;
480564
480695
  }
480565
- break;
480566
- case GeminiEventType.Content:
480567
480696
  geminiMessageBuffer = handleContentEvent(
480568
- event.value,
480697
+ mergedContent,
480569
480698
  geminiMessageBuffer,
480570
480699
  userMessageTimestamp
480571
480700
  );
480572
- break;
480573
- case GeminiEventType.ToolCallRequest:
480574
- toolCallRequests.push(event.value);
480575
- break;
480576
- case GeminiEventType.UserCancelled:
480577
- handleUserCancelledEvent(userMessageTimestamp);
480578
- break;
480579
- case GeminiEventType.Error:
480580
- handleErrorEvent(event.value, userMessageTimestamp);
480581
- break;
480582
- case GeminiEventType.ChatCompressed:
480583
- handleChatCompressionEvent(event.value, userMessageTimestamp);
480584
- break;
480585
- case GeminiEventType.ToolCallConfirmation:
480586
- case GeminiEventType.ToolCallResponse:
480587
- break;
480588
- case GeminiEventType.MaxSessionTurns:
480589
- handleMaxSessionTurnsEvent();
480590
- break;
480591
- case GeminiEventType.SessionTokenLimitExceeded:
480592
- handleSessionTokenLimitExceededEvent(event.value);
480593
- break;
480594
- case GeminiEventType.Finished:
480595
- handleFinishedEvent(
480596
- event,
480597
- userMessageTimestamp
480598
- );
480599
- break;
480600
- case GeminiEventType.Citation:
480601
- handleCitationEvent(event.value, userMessageTimestamp);
480602
- break;
480603
- case GeminiEventType.LoopDetected:
480604
- loopDetectedRef.current = true;
480605
- break;
480606
- case GeminiEventType.Retry:
480607
- if (pendingHistoryItemRef.current) {
480608
- setPendingHistoryItem(null);
480701
+ continue;
480702
+ }
480703
+ let mergedThought = nextEvent.value;
480704
+ while (bufferedEvents[0]?.kind === "thought") {
480705
+ const queuedThought = bufferedEvents.shift();
480706
+ if (queuedThought?.kind !== "thought") {
480707
+ break;
480609
480708
  }
480610
- if (event.retryInfo) {
480611
- startRetryCountdown(event.retryInfo);
480612
- } else {
480613
- clearRetryCountdown();
480709
+ mergedThought = {
480710
+ subject: queuedThought.value.subject || mergedThought.subject,
480711
+ description: `${mergedThought.description ?? ""}${queuedThought.value.description ?? ""}`
480712
+ };
480713
+ }
480714
+ thoughtBuffer = handleThoughtEvent(
480715
+ mergedThought,
480716
+ thoughtBuffer,
480717
+ userMessageTimestamp
480718
+ );
480719
+ }
480720
+ }, "flushBufferedStreamEvents");
480721
+ const scheduleBufferedStreamFlush = /* @__PURE__ */ __name(() => {
480722
+ if (flushTimer) {
480723
+ return;
480724
+ }
480725
+ flushTimer = setTimeout(() => {
480726
+ flushBufferedStreamEvents();
480727
+ }, STREAM_UPDATE_THROTTLE_MS);
480728
+ }, "scheduleBufferedStreamFlush");
480729
+ flushBufferedStreamEventsRef.current.add(flushBufferedStreamEvents);
480730
+ try {
480731
+ for await (const event of stream2) {
480732
+ switch (event.type) {
480733
+ case GeminiEventType.Thought:
480734
+ if (event.value.subject) {
480735
+ flushBufferedStreamEvents();
480736
+ setThought(event.value);
480737
+ } else {
480738
+ bufferedEvents.push({ kind: "thought", value: event.value });
480739
+ scheduleBufferedStreamFlush();
480740
+ }
480741
+ break;
480742
+ case GeminiEventType.Content:
480743
+ bufferedEvents.push({ kind: "content", value: event.value });
480744
+ scheduleBufferedStreamFlush();
480745
+ break;
480746
+ case GeminiEventType.ToolCallRequest:
480747
+ flushBufferedStreamEvents();
480748
+ toolCallRequests.push(event.value);
480749
+ break;
480750
+ case GeminiEventType.UserCancelled:
480751
+ flushBufferedStreamEvents();
480752
+ handleUserCancelledEvent(userMessageTimestamp);
480753
+ break;
480754
+ case GeminiEventType.Error:
480755
+ flushBufferedStreamEvents();
480756
+ handleErrorEvent(event.value, userMessageTimestamp);
480757
+ break;
480758
+ case GeminiEventType.ChatCompressed:
480759
+ flushBufferedStreamEvents();
480760
+ handleChatCompressionEvent(event.value, userMessageTimestamp);
480761
+ break;
480762
+ case GeminiEventType.ToolCallConfirmation:
480763
+ case GeminiEventType.ToolCallResponse:
480764
+ flushBufferedStreamEvents();
480765
+ break;
480766
+ case GeminiEventType.MaxSessionTurns:
480767
+ flushBufferedStreamEvents();
480768
+ handleMaxSessionTurnsEvent();
480769
+ break;
480770
+ case GeminiEventType.SessionTokenLimitExceeded:
480771
+ flushBufferedStreamEvents();
480772
+ handleSessionTokenLimitExceededEvent(event.value);
480773
+ break;
480774
+ case GeminiEventType.Finished:
480775
+ flushBufferedStreamEvents();
480776
+ handleFinishedEvent(
480777
+ event,
480778
+ userMessageTimestamp
480779
+ );
480780
+ break;
480781
+ case GeminiEventType.Citation:
480782
+ flushBufferedStreamEvents();
480783
+ handleCitationEvent(event.value, userMessageTimestamp);
480784
+ break;
480785
+ case GeminiEventType.LoopDetected:
480786
+ flushBufferedStreamEvents();
480787
+ loopDetectedRef.current = true;
480788
+ break;
480789
+ case GeminiEventType.Retry:
480790
+ discardBufferedStreamEvents();
480791
+ if (pendingHistoryItemRef.current) {
480792
+ setPendingHistoryItem(null);
480793
+ }
480794
+ geminiMessageBuffer = "";
480795
+ thoughtBuffer = "";
480796
+ if (event.retryInfo) {
480797
+ startRetryCountdown(event.retryInfo);
480798
+ } else {
480799
+ clearRetryCountdown();
480800
+ }
480801
+ break;
480802
+ case GeminiEventType.HookSystemMessage:
480803
+ flushBufferedStreamEvents();
480804
+ geminiMessageBuffer = handleContentEvent(
480805
+ event.value + "\n",
480806
+ geminiMessageBuffer,
480807
+ userMessageTimestamp
480808
+ );
480809
+ break;
480810
+ default: {
480811
+ const unreachable = event;
480812
+ return unreachable;
480614
480813
  }
480615
- break;
480616
- case GeminiEventType.HookSystemMessage:
480617
- geminiMessageBuffer = handleContentEvent(
480618
- event.value + "\n",
480619
- geminiMessageBuffer,
480620
- userMessageTimestamp
480621
- );
480622
- break;
480623
- default: {
480624
- const unreachable = event;
480625
- return unreachable;
480626
480814
  }
480627
480815
  }
480816
+ } finally {
480817
+ flushBufferedStreamEvents();
480818
+ discardBufferedStreamEvents();
480819
+ flushBufferedStreamEventsRef.current.delete(flushBufferedStreamEvents);
480628
480820
  }
480629
480821
  if (toolCallRequests.length > 0) {
480630
480822
  scheduleToolCalls(toolCallRequests, signal);
@@ -491348,7 +491540,7 @@ var Session3 = class {
491348
491540
  );
491349
491541
  }
491350
491542
  const isAskUserQuestionTool = fc.name === ToolNames.ASK_USER_QUESTION;
491351
- const defaultPermission = this.config.getApprovalMode() !== ApprovalMode.YOLO || isAskUserQuestionTool ? await invocation.getDefaultPermission() : "allow";
491543
+ const defaultPermission = this.config.getApprovalMode() !== ApprovalMode.YOLO || isAskUserQuestionTool || isExitPlanModeTool ? await invocation.getDefaultPermission() : "allow";
491352
491544
  const toolParams = invocation.params;
491353
491545
  const pmCtx = buildPermissionCheckContext(
491354
491546
  fc.name,
@@ -491821,7 +492013,7 @@ var QwenAgent = class {
491821
492013
  async initialize(args2) {
491822
492014
  this.clientCapabilities = args2.clientCapabilities;
491823
492015
  const authMethods = buildAuthMethods();
491824
- const version2 = "0.26.12";
492016
+ const version2 = "0.26.16";
491825
492017
  return {
491826
492018
  protocolVersion: PROTOCOL_VERSION,
491827
492019
  agentInfo: {
@@ -492332,11 +492524,23 @@ function terminalSupportsSynchronizedOutput(env5 = process.env) {
492332
492524
  return false;
492333
492525
  }
492334
492526
  const termProgram = env5["TERM_PROGRAM"];
492335
- if (termProgram === "WezTerm" || termProgram === "iTerm.app") {
492527
+ if (termProgram === "WezTerm" || termProgram === "iTerm.app" || termProgram === "ghostty") {
492528
+ return true;
492529
+ }
492530
+ if (env5["ALACRITTY_WINDOW_ID"]) {
492336
492531
  return true;
492337
492532
  }
492338
492533
  const term = env5["TERM"];
492339
- return Boolean(env5["KITTY_WINDOW_ID"] || term?.includes("kitty"));
492534
+ if (env5["KITTY_WINDOW_ID"] || term?.includes("kitty")) {
492535
+ return true;
492536
+ }
492537
+ if (term?.startsWith("alacritty")) {
492538
+ return true;
492539
+ }
492540
+ if (env5["GHOSTTY_RESOURCES_DIR"]) {
492541
+ return true;
492542
+ }
492543
+ return false;
492340
492544
  }
492341
492545
  __name(terminalSupportsSynchronizedOutput, "terminalSupportsSynchronizedOutput");
492342
492546
  function installSynchronizedOutput(stdout3 = process.stdout, env5 = process.env) {
package/locales/de.js CHANGED
@@ -305,7 +305,7 @@ export default {
305
305
  'Custom Witty Phrases': 'Benutzerdefinierte Witzige Sprüche',
306
306
  'Show Welcome Back Dialog': 'Willkommen-zurück-Dialog anzeigen',
307
307
  'Enable User Feedback': 'Benutzerfeedback aktivieren',
308
- 'How is Qwen doing this session? (optional)':
308
+ 'How is proto doing this session? (optional)':
309
309
  'Wie macht sich Qwen in dieser Sitzung? (optional)',
310
310
  Bad: 'Schlecht',
311
311
  Fine: 'In Ordnung',
package/locales/pt.js CHANGED
@@ -330,7 +330,7 @@ export default {
330
330
  'Custom Witty Phrases': 'Frases de Efeito Personalizadas',
331
331
  'Show Welcome Back Dialog': 'Mostrar Diálogo de Bem-vindo de Volta',
332
332
  'Enable User Feedback': 'Ativar Feedback do Usuário',
333
- 'How is Qwen doing this session? (optional)':
333
+ 'How is proto doing this session? (optional)':
334
334
  'Como o Qwen está se saindo nesta sessão? (opcional)',
335
335
  Bad: 'Ruim',
336
336
  Fine: 'Bom',
package/locales/ru.js CHANGED
@@ -328,7 +328,7 @@ export default {
328
328
  'Custom Witty Phrases': 'Пользовательские остроумные фразы',
329
329
  'Show Welcome Back Dialog': 'Показывать диалог приветствия',
330
330
  'Enable User Feedback': 'Включить отзывы пользователей',
331
- 'How is Qwen doing this session? (optional)':
331
+ 'How is proto doing this session? (optional)':
332
332
  'Как дела у Qwen в этой сессии? (необязательно)',
333
333
  Bad: 'Плохо',
334
334
  Fine: 'Нормально',
package/locales/zh.js CHANGED
@@ -374,7 +374,7 @@ export default {
374
374
  'Custom Witty Phrases': '自定义诙谐短语',
375
375
  'Show Welcome Back Dialog': '显示欢迎回来对话框',
376
376
  'Enable User Feedback': '启用用户反馈',
377
- 'How is Qwen doing this session? (optional)': 'Qwen 这次表现如何?(可选)',
377
+ 'How is proto doing this session? (optional)': 'Qwen 这次表现如何?(可选)',
378
378
  Bad: '不满意',
379
379
  Fine: '还行',
380
380
  Good: '满意',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protolabsai/proto",
3
- "version": "0.26.12",
3
+ "version": "0.26.16",
4
4
  "description": "proto - AI-powered coding agent",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,7 +21,7 @@
21
21
  "bundled"
22
22
  ],
23
23
  "config": {
24
- "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.26.12"
24
+ "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.26.16"
25
25
  },
26
26
  "dependencies": {},
27
27
  "optionalDependencies": {