@protolabsai/proto 0.26.12 → 0.26.13

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 (3) hide show
  1. package/README.md +17 -5
  2. package/cli.js +326 -122
  3. package/package.json +2 -2
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.13";
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
  }
@@ -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,
@@ -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.13";
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 = "1cbd798c9";
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,
@@ -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);
@@ -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.13";
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protolabsai/proto",
3
- "version": "0.26.12",
3
+ "version": "0.26.13",
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.13"
25
25
  },
26
26
  "dependencies": {},
27
27
  "optionalDependencies": {