@crazyhappyone/dsh-tui 0.1.0-alpha.50 → 0.1.0-alpha.52

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/index.js CHANGED
@@ -51995,9 +51995,9 @@ function fileUrlFromToolArguments(argumentsJson) {
51995
51995
  try {
51996
51996
  const parsed = JSON.parse(argumentsJson);
51997
51997
  if (parsed === null || typeof parsed !== "object") return void 0;
51998
- const record2 = parsed;
51998
+ const record3 = parsed;
51999
51999
  for (const key of FILE_PATH_KEYS) {
52000
- const value = record2[key];
52000
+ const value = record3[key];
52001
52001
  if (typeof value !== "string" || !isAbsolute2(value)) continue;
52002
52002
  if (/[\u0000-\u001f\u007f]/.test(value)) continue;
52003
52003
  return pathToFileURL2(value).href;
@@ -52378,20 +52378,20 @@ function toolHeadingRow(card, width, expanded, locale) {
52378
52378
  if (subagentInfo?.model !== void 0) {
52379
52379
  parts2.push({ text: ` [${subagentInfo.model}]`, token: "markdownCode" });
52380
52380
  }
52381
- let summary2;
52381
+ let summary3;
52382
52382
  if (status === "error") {
52383
- summary2 = collapsedToolCardSummary(card);
52383
+ summary3 = collapsedToolCardSummary(card);
52384
52384
  } else if (!expanded) {
52385
52385
  if (subagentInfo?.prompt !== void 0 && subagentInfo.prompt !== "") {
52386
- summary2 = escapeContent(subagentInfo.prompt).replace(/\n/g, " ");
52386
+ summary3 = escapeContent(subagentInfo.prompt).replace(/\n/g, " ");
52387
52387
  } else {
52388
- summary2 = collapsedToolCardSummary(card);
52388
+ summary3 = collapsedToolCardSummary(card);
52389
52389
  }
52390
52390
  }
52391
52391
  const available2 = width - parts2.reduce((sum, part) => sum + displayWidth(part.text), 0) - 1;
52392
52392
  const href2 = fileUrlFromToolArguments(card.arguments);
52393
- if (summary2 !== void 0 && available2 >= 2) {
52394
- parts2.push({ text: ` ${truncateDisplay(summary2, available2)}`, token: "fgSoft", ...href2 === void 0 ? {} : { href: href2 } });
52393
+ if (summary3 !== void 0 && available2 >= 2) {
52394
+ parts2.push({ text: ` ${truncateDisplay(summary3, available2)}`, token: "fgSoft", ...href2 === void 0 ? {} : { href: href2 } });
52395
52395
  }
52396
52396
  return toolRow(parts2, 0, width, "toolBg");
52397
52397
  }
@@ -52402,10 +52402,10 @@ function toolHeadingRow(card, width, expanded, locale) {
52402
52402
  const fitted = truncateMiddleDisplay(heading, Math.max(1, width - displayWidth(`${glyph} \xB7 ${label}`)), terminal ? 0.72 : 0.5);
52403
52403
  const parts = expanded && terminal ? [{ text: `${glyph} `, token: "fgDim" }, ...tokenizeCommandHeading(fitted), { text: " \xB7 ", token: "fgDim" }] : [{ text: `${glyph} ${fitted} \xB7 `, token: "fgSoft" }];
52404
52404
  parts.push({ text: label, token: status === "error" ? "error" : status === "running" ? "accentText" : "fgDim" });
52405
- const summary = !expanded || status === "error" ? collapsedToolCardSummary(card) : void 0;
52405
+ const summary2 = !expanded || status === "error" ? collapsedToolCardSummary(card) : void 0;
52406
52406
  const available = width - parts.reduce((sum, part) => sum + displayWidth(part.text), 0) - 1;
52407
52407
  const href = fileUrlFromToolArguments(card.arguments);
52408
- if (summary !== void 0 && available >= 2) parts.push({ text: ` ${truncateDisplay(summary, available)}`, token: "fgDim", ...href === void 0 ? {} : { href } });
52408
+ if (summary2 !== void 0 && available >= 2) parts.push({ text: ` ${truncateDisplay(summary2, available)}`, token: "fgDim", ...href === void 0 ? {} : { href } });
52409
52409
  return toolRow(parts, 0, width, "toolBg");
52410
52410
  }
52411
52411
  var GUTTER_SEPARATOR = " \u2502 ";
@@ -53302,6 +53302,39 @@ function completeDeltaStdoutDrain(metrics, nowMs = performance.now()) {
53302
53302
  PENDING_DELTA_INGRESS.delete(metrics);
53303
53303
  metrics.recordDeltaIngressToStdoutDrain(Math.max(0, nowMs - startedAt));
53304
53304
  }
53305
+ var PENDING_SCROLL_INPUTS = /* @__PURE__ */ new WeakMap();
53306
+ function markScrollInput(metrics, revision, nowMs = performance.now()) {
53307
+ let state = PENDING_SCROLL_INPUTS.get(metrics);
53308
+ if (state === void 0) {
53309
+ state = { pending: void 0, generation: 0 };
53310
+ PENDING_SCROLL_INPUTS.set(metrics, state);
53311
+ }
53312
+ if (state.pending === void 0) state.pending = { revision, startedAt: nowMs };
53313
+ else {
53314
+ metrics.recordCoalescedInput();
53315
+ state.pending.revision = Math.max(state.pending.revision, revision);
53316
+ state.pending.startedAt = Math.min(state.pending.startedAt, nowMs);
53317
+ }
53318
+ }
53319
+ function clearScrollInputs(metrics) {
53320
+ const state = PENDING_SCROLL_INPUTS.get(metrics);
53321
+ if (state === void 0) return;
53322
+ state.pending = void 0;
53323
+ state.generation += 1;
53324
+ }
53325
+ function takeScrollPaintCompletion(metrics, revision) {
53326
+ const state = PENDING_SCROLL_INPUTS.get(metrics);
53327
+ const pending = state?.pending;
53328
+ if (state === void 0 || pending === void 0 || revision < pending.revision) return void 0;
53329
+ state.pending = void 0;
53330
+ const { generation } = state;
53331
+ let completed = false;
53332
+ return () => {
53333
+ if (completed || state.generation !== generation) return;
53334
+ completed = true;
53335
+ metrics.recordScrollInputToPaint(Math.max(0, performance.now() - pending.startedAt));
53336
+ };
53337
+ }
53305
53338
  function emptyCounter() {
53306
53339
  return { total: 0, windowCount: 0, windowSum: 0, windowMax: 0 };
53307
53340
  }
@@ -53537,6 +53570,7 @@ var frameRail;
53537
53570
  var paintedFrameRail;
53538
53571
  var paintedVisibleFrame;
53539
53572
  var paintedTranscriptRepaintKey;
53573
+ var transcriptInvalidated = false;
53540
53574
  function setFrameCaret(caret) {
53541
53575
  frameCaret = caret;
53542
53576
  }
@@ -53638,15 +53672,19 @@ function transcriptOverlay(tier, synchronizedFrameEnded) {
53638
53672
  if (next === void 0) {
53639
53673
  paintedVisibleFrame = void 0;
53640
53674
  paintedTranscriptRepaintKey = void 0;
53675
+ transcriptInvalidated = false;
53641
53676
  return "";
53642
53677
  }
53643
- if (paintedVisibleFrame === next && (next.repaintKey === void 0 || next.repaintKey === paintedTranscriptRepaintKey)) {
53678
+ if (!transcriptInvalidated && paintedVisibleFrame === next && (next.repaintKey === void 0 || next.repaintKey === paintedTranscriptRepaintKey)) {
53644
53679
  return "";
53645
53680
  }
53646
53681
  const diff2 = diffVisibleFrameSnapshots(paintedVisibleFrame, next);
53647
- if (diff2.forced && !synchronizedFrameEnded) return "";
53648
- const repaintAll = synchronizedFrameEnded && (diff2.forced || next.repaintKey !== void 0 && next.repaintKey !== paintedTranscriptRepaintKey);
53649
- if (repaintAll) paintedTranscriptRepaintKey = next.repaintKey;
53682
+ if ((diff2.forced || transcriptInvalidated) && !synchronizedFrameEnded) return "";
53683
+ const repaintAll = synchronizedFrameEnded && (diff2.forced || transcriptInvalidated || next.repaintKey !== void 0 && next.repaintKey !== paintedTranscriptRepaintKey);
53684
+ if (repaintAll) {
53685
+ paintedTranscriptRepaintKey = next.repaintKey;
53686
+ transcriptInvalidated = false;
53687
+ }
53650
53688
  paintedVisibleFrame = next;
53651
53689
  let cells = "";
53652
53690
  if (repaintAll) {
@@ -53675,6 +53713,30 @@ function transcriptOverlay(tier, synchronizedFrameEnded) {
53675
53713
  }
53676
53714
  return cells === "" ? "" : `\x1B7${cells}\x1B8`;
53677
53715
  }
53716
+ function transcriptSlotChanged() {
53717
+ const previous3 = paintedVisibleFrame?.geometry;
53718
+ const next = visibleFrameSnapshot()?.geometry;
53719
+ return previous3 !== void 0 && next !== void 0 && (previous3.columns !== next.columns || previous3.rows !== next.rows || previous3.transcriptTop !== next.transcriptTop || previous3.transcriptLeft !== next.transcriptLeft || previous3.transcriptWidth !== next.transcriptWidth || previous3.transcriptRows !== next.transcriptRows);
53720
+ }
53721
+ function prepareTranscriptOverlay(columns, rows, tier, inkFrameStarting) {
53722
+ const previous3 = paintedVisibleFrame;
53723
+ if (previous3 === void 0) return "";
53724
+ if (visibleFrameSnapshot() === void 0) {
53725
+ paintedVisibleFrame = void 0;
53726
+ paintedTranscriptRepaintKey = void 0;
53727
+ transcriptInvalidated = false;
53728
+ } else {
53729
+ if (!inkFrameStarting || !transcriptSlotChanged()) return "";
53730
+ transcriptInvalidated = true;
53731
+ }
53732
+ const blank = blankPad(Math.min(columns, previous3.geometry.columns), tier);
53733
+ let cells = "";
53734
+ const bottom = Math.min(rows, previous3.geometry.transcriptTop + previous3.geometry.transcriptRows - 1);
53735
+ for (let row = previous3.geometry.transcriptTop; row <= bottom; row += 1) {
53736
+ cells += `\x1B[${String(row)};1H${blank}`;
53737
+ }
53738
+ return cells === "" ? "" : `\x1B7${cells}\x1B8`;
53739
+ }
53678
53740
  function caretSuffix() {
53679
53741
  if (frameCaret === void 0) return "";
53680
53742
  if (frameCaret === "hide") return HIDE_CURSOR;
@@ -53683,7 +53745,13 @@ function caretSuffix() {
53683
53745
  function publishedCaretBytes() {
53684
53746
  return caretSuffix();
53685
53747
  }
53748
+ function snapshotFitsStdout(stdout) {
53749
+ const snapshot2 = visibleFrameSnapshot();
53750
+ if (!stdout.isTTY || snapshot2 === void 0 || !Number.isFinite(stdout.columns) || stdout.columns < 1 || !Number.isFinite(stdout.rows) || stdout.rows < 1) return true;
53751
+ return snapshot2.geometry.columns === stdout.columns && snapshot2.geometry.rows === stdout.rows;
53752
+ }
53686
53753
  function writePublishedFrameSnapshot(stdout, tier = currentTier()) {
53754
+ if (!snapshotFitsStdout(stdout) || transcriptSlotChanged()) return;
53687
53755
  const transcript = transcriptOverlay(tier, true);
53688
53756
  const rail = railOverlay(tier, false);
53689
53757
  const overlay = transcript + rail;
@@ -53694,9 +53762,9 @@ function writePublishedFrameSnapshot(stdout, tier = currentTier()) {
53694
53762
  stdout.write(bytes);
53695
53763
  return;
53696
53764
  }
53697
- writer(bytes);
53765
+ writer(bytes, visibleFrameSnapshot()?.scrollRevision);
53698
53766
  }
53699
- function transformFrameChunk(chunk2, tier = currentTier(), publishFrame = true) {
53767
+ function transformFrameChunk(chunk2, tier = currentTier(), publishFrame = true, onTranscriptPaint) {
53700
53768
  let out = chunk2;
53701
53769
  const on2 = bgSequence(tier);
53702
53770
  if (on2 !== "") {
@@ -53716,7 +53784,9 @@ function transformFrameChunk(chunk2, tier = currentTier(), publishFrame = true)
53716
53784
  }
53717
53785
  const isFrame = out.includes(END_SYNC) || out.includes(SHOW_CURSOR) || out.includes(HIDE_CURSOR);
53718
53786
  if (isFrame && publishFrame) {
53719
- const overlay = transcriptOverlay(tier, out.includes(END_SYNC)) + railOverlay(tier, true) + caretSuffix();
53787
+ const transcript = transcriptOverlay(tier, out.includes(END_SYNC));
53788
+ if (transcript !== "") onTranscriptPaint?.();
53789
+ const overlay = transcript + railOverlay(tier, true) + caretSuffix();
53720
53790
  const syncIndex = out.lastIndexOf(END_SYNC);
53721
53791
  out = syncIndex < 0 ? out + overlay : out.slice(0, syncIndex) + overlay + out.slice(syncIndex);
53722
53792
  }
@@ -53731,28 +53801,46 @@ function wrapStdoutForFrameBg(stdout, getTier = currentTier, frameMetrics) {
53731
53801
  const wrapped = Object.create(stdout);
53732
53802
  let synchronizedFrameOpen = false;
53733
53803
  let inkBottomRow = stdout.rows;
53804
+ let inkCursorRow = 1;
53734
53805
  const transformingWrite = (chunk2, ...args) => {
53735
- if (typeof chunk2 !== "string") return writeMeasured(chunk2, ...args);
53806
+ if (typeof chunk2 !== "string") return writeMeasured(chunk2, args);
53736
53807
  if (chunk2.includes(START_SYNC)) synchronizedFrameOpen = true;
53737
53808
  if (chunk2.includes(END_SYNC)) synchronizedFrameOpen = false;
53738
53809
  const source = stdout.isTTY ? preserveFullWidthRows(chunk2, stdout.columns) : chunk2;
53739
53810
  const inkChunk = stdout.isTTY && frameCaret !== void 0 && /\x1b\[\d*A|\x1b\[2K/u.test(source) ? `\x1B[${Math.min(inkBottomRow, stdout.rows)};1H${source}` : source;
53740
- const transformed = transformFrameChunk(inkChunk, getTier(), !synchronizedFrameOpen);
53741
- if (chunk2.includes("\n")) inkBottomRow = Math.min(stdout.rows, chunk2.split("\n").length);
53742
- return writeMeasured(transformed, ...args);
53811
+ if (stdout.isTTY) {
53812
+ const position2 = trackInkRows(inkChunk, inkCursorRow, stdout.rows);
53813
+ if (position2 !== void 0) {
53814
+ inkCursorRow = position2;
53815
+ inkBottomRow = position2;
53816
+ }
53817
+ }
53818
+ const tier = getTier();
53819
+ const released = stdout.isTTY ? prepareTranscriptOverlay(stdout.columns, stdout.rows, tier, source.includes(START_SYNC)) : "";
53820
+ const frameChunk = released === "" ? inkChunk : inkChunk.includes(START_SYNC) ? inkChunk.replace(START_SYNC, START_SYNC + released) : synchronizedFrameOpen ? released + inkChunk : START_SYNC + released + END_SYNC + inkChunk;
53821
+ let onScrollPaint;
53822
+ const transformed = transformFrameChunk(frameChunk, tier, !synchronizedFrameOpen && snapshotFitsStdout(stdout), () => {
53823
+ const revision = visibleFrameSnapshot()?.scrollRevision;
53824
+ if (frameMetrics !== void 0 && revision !== void 0) {
53825
+ onScrollPaint = takeScrollPaintCompletion(frameMetrics, revision);
53826
+ }
53827
+ });
53828
+ return writeMeasured(transformed, args, onScrollPaint);
53743
53829
  };
53744
- const writeMeasured = (transformed, ...args) => {
53830
+ const writeMeasured = (transformed, args, onScrollPaint) => {
53745
53831
  if (frameMetrics !== void 0 && typeof transformed === "string") {
53746
53832
  frameMetrics.addWrittenCells(countWrittenCells(transformed));
53747
53833
  const last = args.at(-1);
53748
- const onDrain = () => {
53834
+ const onDrain = (error51) => {
53835
+ if (error51 !== void 0 && error51 !== null) return;
53836
+ onScrollPaint?.();
53749
53837
  completeDeltaStdoutDrain(frameMetrics);
53750
53838
  if (transformed.includes(END_SYNC)) frameMetrics.recordFramePresented();
53751
53839
  };
53752
53840
  if (typeof last === "function") {
53753
53841
  const original = last;
53754
53842
  args[args.length - 1] = (...callbackArgs) => {
53755
- onDrain();
53843
+ onDrain(callbackArgs[0]);
53756
53844
  original(...callbackArgs);
53757
53845
  };
53758
53846
  } else {
@@ -53763,14 +53851,71 @@ function wrapStdoutForFrameBg(stdout, getTier = currentTier, frameMetrics) {
53763
53851
  };
53764
53852
  wrapped.write = transformingWrite;
53765
53853
  const overlayStream = wrapped;
53766
- overlayStream[WRITE_FRAME_OVERLAY] = (chunk2) => writeMeasured(chunk2);
53854
+ overlayStream[WRITE_FRAME_OVERLAY] = (chunk2, revision) => writeMeasured(
53855
+ chunk2,
53856
+ [],
53857
+ frameMetrics !== void 0 && revision !== void 0 ? takeScrollPaintCompletion(frameMetrics, revision) : void 0
53858
+ );
53767
53859
  return wrapped;
53768
53860
  }
53769
- var TERMINAL_CONTROL_PATTERN = /\x1b\][^\x07]*(?:\x07|\x1b\\)|\x1b\[[0-?]*[ -/]*[@-~]|\x1b./gu;
53861
+ var TERMINAL_CONTROL_PATTERN = /\x1b\](?:[^\x07\x1b]|\x1b(?!\\))*(?:\x07|\x1b\\)|\x1b\[[0-?]*[ -/]*[@-~]|\x1b./gu;
53770
53862
  function countWrittenCells(chunk2) {
53771
53863
  const printable = chunk2.replace(TERMINAL_CONTROL_PATTERN, (control) => control.startsWith("\x1B]") || control.startsWith("\x1B[") && control.endsWith("m") ? "" : "\n").replace(/[\u0000-\u0009\u000b-\u001f\u007f]/gu, "");
53772
53864
  return printable.split("\n").reduce((cells, line5) => cells + displayWidth(line5), 0);
53773
53865
  }
53866
+ function trackInkRows(chunk2, startRow, rows) {
53867
+ let row = Math.max(1, Math.min(startRow, rows));
53868
+ let active = false;
53869
+ const geometry = visibleFrameSnapshot()?.geometry;
53870
+ const touch = (first, last = first) => {
53871
+ if (geometry !== void 0 && first < geometry.transcriptTop + geometry.transcriptRows && last >= geometry.transcriptTop) transcriptInvalidated = true;
53872
+ };
53873
+ const move = (next) => {
53874
+ row = Math.max(1, Math.min(next, rows));
53875
+ active = true;
53876
+ };
53877
+ const text4 = (value) => {
53878
+ if (value === "") return;
53879
+ for (const [index3, line5] of value.split("\n").entries()) {
53880
+ if (index3 > 0) move(row + 1);
53881
+ if (/[^\u0000-\u001f\u007f]/u.test(line5)) {
53882
+ touch(row);
53883
+ active = true;
53884
+ }
53885
+ }
53886
+ };
53887
+ let index2 = 0;
53888
+ for (const match of chunk2.matchAll(TERMINAL_CONTROL_PATTERN)) {
53889
+ text4(chunk2.slice(index2, match.index));
53890
+ const control = match[0];
53891
+ if (control === ENTER_ALTERNATE_SCREEN) {
53892
+ touch(1, rows);
53893
+ move(1);
53894
+ } else if (control.startsWith("\x1B[")) {
53895
+ const final = control.at(-1);
53896
+ if (final !== void 0 && "ABEFHfdKJ".includes(final)) {
53897
+ const parameter = Number.parseInt(control.slice(2, -1), 10);
53898
+ const count = parameter || 1;
53899
+ if (final === "A" || final === "F") move(row - count);
53900
+ else if (final === "B" || final === "E") move(row + count);
53901
+ else if (final === "H" || final === "f" || final === "d") move(count);
53902
+ else if (final === "K") {
53903
+ touch(row);
53904
+ active = true;
53905
+ } else if (final === "J") {
53906
+ const mode = parameter || 0;
53907
+ if (mode === 0) touch(row, rows);
53908
+ else if (mode === 1) touch(1, row);
53909
+ else if (mode === 2) touch(1, rows);
53910
+ active = true;
53911
+ }
53912
+ }
53913
+ }
53914
+ index2 = match.index + control.length;
53915
+ }
53916
+ text4(chunk2.slice(index2));
53917
+ return active ? row : void 0;
53918
+ }
53774
53919
 
53775
53920
  // packages/tui/tui-render/src/screen-atlas.ts
53776
53921
  var GRAPHEME2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
@@ -55223,9 +55368,9 @@ function projectCompactionEntry(entry, scope) {
55223
55368
  const lines = [
55224
55369
  lineForText(marker, "fgDim", false, 0)
55225
55370
  ];
55226
- const summary = entry.meta?.compactionSummary ?? "";
55227
- if (expanded && summary !== "") {
55228
- const wrapped = wrapDisplayLines(escapeContent(summary), Math.max(1, scope.width - 4));
55371
+ const summary2 = entry.meta?.compactionSummary ?? "";
55372
+ if (expanded && summary2 !== "") {
55373
+ const wrapped = wrapDisplayLines(escapeContent(summary2), Math.max(1, scope.width - 4));
55229
55374
  for (const row of wrapped) {
55230
55375
  lines.push(surfaceLine([
55231
55376
  { text: "\u2502 ", token: "accentText", bold: false },
@@ -55473,14 +55618,14 @@ var MutableRevisionImpl = class {
55473
55618
  this.buffer.push(...lines);
55474
55619
  this.revision += 1;
55475
55620
  this.store.recordTailRerender(lines.length);
55476
- this.store.touchActiveBlock(this.blockId);
55621
+ this.store.recordActiveLines(this, lines, true);
55477
55622
  }
55478
55623
  reset(lines) {
55479
55624
  this.requireAlive();
55480
55625
  this.buffer = [...lines];
55481
55626
  this.revision += 1;
55482
55627
  this.store.recordTailRerender(lines.length);
55483
- this.store.touchActiveBlock(this.blockId);
55628
+ this.store.recordActiveLines(this, lines, false);
55484
55629
  }
55485
55630
  replace(input) {
55486
55631
  this.requireAlive();
@@ -55488,7 +55633,7 @@ var MutableRevisionImpl = class {
55488
55633
  this.buffer = [...input.lines];
55489
55634
  this.revision += 1;
55490
55635
  this.store.recordTailRerender(input.lines.length);
55491
- this.store.touchActiveBlock(this.blockId);
55636
+ this.store.recordActiveLines(this, input.lines, false);
55492
55637
  }
55493
55638
  settle() {
55494
55639
  this.requireAlive();
@@ -55512,8 +55657,12 @@ var MutableRevisionImpl = class {
55512
55657
  var TranscriptRenderStoreImpl = class {
55513
55658
  config;
55514
55659
  entries = /* @__PURE__ */ new Map();
55660
+ /** Insertion order is LRU order; evicted history is never inspected. */
55661
+ settledEntries = /* @__PURE__ */ new Set();
55515
55662
  pins = /* @__PURE__ */ new Set();
55516
- accessCounter = 0;
55663
+ cachedBlocks = 0;
55664
+ cachedRows = 0;
55665
+ cachedBytes = 0;
55517
55666
  counters = {
55518
55667
  hits: 0,
55519
55668
  evictions: 0,
@@ -55543,7 +55692,10 @@ var TranscriptRenderStoreImpl = class {
55543
55692
  settledLines: void 0,
55544
55693
  priorSettled: null,
55545
55694
  activeRevision: null,
55546
- lastAccess: this.nextAccess()
55695
+ cachedRows: 0,
55696
+ cachedBytes: 0,
55697
+ resident: false,
55698
+ settledBytes: 0
55547
55699
  });
55548
55700
  this.enforceBudget();
55549
55701
  return;
@@ -55557,10 +55709,14 @@ var TranscriptRenderStoreImpl = class {
55557
55709
  const sourceChanged = existing.source !== input.source;
55558
55710
  existing.source = input.source;
55559
55711
  existing.scopeKey = input.scopeKey;
55560
- existing.lastAccess = this.nextAccess();
55561
55712
  if (scopeChanged || sourceChanged) {
55562
55713
  existing.revision += 1;
55563
55714
  existing.settledLines = null;
55715
+ existing.settledBytes = 0;
55716
+ this.settledEntries.delete(existing);
55717
+ this.updateResident(existing, 0, 0, false);
55718
+ } else if (this.settledEntries.delete(existing)) {
55719
+ this.settledEntries.add(existing);
55564
55720
  }
55565
55721
  this.enforceBudget();
55566
55722
  }
@@ -55577,7 +55733,10 @@ var TranscriptRenderStoreImpl = class {
55577
55733
  settledLines: void 0,
55578
55734
  priorSettled: null,
55579
55735
  activeRevision: null,
55580
- lastAccess: this.nextAccess()
55736
+ cachedRows: 0,
55737
+ cachedBytes: 0,
55738
+ resident: false,
55739
+ settledBytes: 0
55581
55740
  };
55582
55741
  this.entries.set(input.blockId, entry);
55583
55742
  }
@@ -55589,19 +55748,22 @@ var TranscriptRenderStoreImpl = class {
55589
55748
  const owned = entry;
55590
55749
  const revision = new MutableRevisionImpl(this, owned, input.source, input.scopeKey);
55591
55750
  owned.activeRevision = revision;
55751
+ this.settledEntries.delete(owned);
55752
+ this.updateResident(owned, 0, 0, true);
55592
55753
  return revision;
55593
55754
  }
55594
55755
  readBlock(input) {
55595
55756
  this.assertBlockId(input.blockId);
55596
55757
  const entry = this.entries.get(input.blockId);
55597
55758
  if (entry === void 0) return void 0;
55598
- entry.lastAccess = this.nextAccess();
55599
55759
  const active = entry.activeRevision;
55600
55760
  if (active !== null) {
55601
55761
  this.counters.stableRowsReused += active.lines.length;
55602
55762
  return snapshotFromEntry(entry, active.lines);
55603
55763
  }
55604
55764
  if (entry.settledLines !== void 0 && entry.settledLines !== null) {
55765
+ this.settledEntries.delete(entry);
55766
+ this.settledEntries.add(entry);
55605
55767
  this.counters.hits += 1;
55606
55768
  this.counters.stableRowsReused += entry.settledLines.length;
55607
55769
  return snapshotFromEntry(entry, entry.settledLines);
@@ -55614,6 +55776,9 @@ var TranscriptRenderStoreImpl = class {
55614
55776
  });
55615
55777
  const frozen = Object.freeze([...rebuilt]);
55616
55778
  entry.settledLines = frozen;
55779
+ entry.settledBytes = lineBytes(frozen);
55780
+ this.settledEntries.add(entry);
55781
+ this.updateResident(entry, frozen.length, entry.settledBytes, true);
55617
55782
  this.counters.rebuilds += 1;
55618
55783
  this.counters.stableRowsReused += frozen.length;
55619
55784
  this.enforceBudget();
@@ -55633,8 +55798,11 @@ var TranscriptRenderStoreImpl = class {
55633
55798
  }
55634
55799
  reset() {
55635
55800
  this.entries.clear();
55801
+ this.settledEntries.clear();
55636
55802
  this.pins.clear();
55637
- this.accessCounter = 0;
55803
+ this.cachedBlocks = 0;
55804
+ this.cachedRows = 0;
55805
+ this.cachedBytes = 0;
55638
55806
  this.counters.hits = 0;
55639
55807
  this.counters.evictions = 0;
55640
55808
  this.counters.rebuilds = 0;
@@ -55659,34 +55827,18 @@ var TranscriptRenderStoreImpl = class {
55659
55827
  return { start, end: start + target.rowCount };
55660
55828
  }
55661
55829
  totalRows() {
55662
- let total = 0;
55663
- for (const entry of this.entries.values()) {
55664
- total += this.linesFor(entry.blockId).length;
55665
- }
55666
- return total;
55830
+ return this.cachedRows;
55667
55831
  }
55668
55832
  stats() {
55669
- let cachedBlocks = 0;
55670
- let cachedRows = 0;
55671
- let cachedBytes = 0;
55672
- for (const entry of this.entries.values()) {
55673
- const lines = this.linesFor(entry.blockId);
55674
- if (lines.length === 0 && entry.settledLines === void 0 && entry.activeRevision === null) {
55675
- continue;
55676
- }
55677
- cachedBlocks += 1;
55678
- cachedRows += lines.length;
55679
- for (const line5 of lines) cachedBytes += physicalLineByteSize(line5);
55680
- }
55681
55833
  return {
55682
55834
  hits: this.counters.hits,
55683
55835
  evictions: this.counters.evictions,
55684
55836
  rebuilds: this.counters.rebuilds,
55685
55837
  stableRowsReused: this.counters.stableRowsReused,
55686
55838
  tailRowsRerendered: this.counters.tailRowsRerendered,
55687
- cachedBlocks,
55688
- cachedRows,
55689
- cachedBytes
55839
+ cachedBlocks: this.cachedBlocks,
55840
+ cachedRows: this.cachedRows,
55841
+ cachedBytes: this.cachedBytes
55690
55842
  };
55691
55843
  }
55692
55844
  /** Internal: called by MutableRevisionImpl on settle. */
@@ -55701,8 +55853,9 @@ var TranscriptRenderStoreImpl = class {
55701
55853
  entry.activeRevision = null;
55702
55854
  entry.scopeKey = scopeKey;
55703
55855
  entry.settledLines = frozen;
55856
+ entry.settledBytes = entry.cachedBytes;
55704
55857
  entry.priorSettled = null;
55705
- entry.lastAccess = this.nextAccess();
55858
+ this.settledEntries.add(entry);
55706
55859
  this.enforceBudget();
55707
55860
  return snapshotFromEntry(entry, frozen);
55708
55861
  }
@@ -55715,17 +55868,29 @@ var TranscriptRenderStoreImpl = class {
55715
55868
  entry.activeRevision = null;
55716
55869
  entry.settledLines = entry.priorSettled ?? null;
55717
55870
  entry.priorSettled = null;
55718
- entry.lastAccess = this.nextAccess();
55871
+ if (entry.settledLines !== null) this.settledEntries.add(entry);
55872
+ this.updateResident(
55873
+ entry,
55874
+ entry.settledLines?.length ?? 0,
55875
+ entry.settledBytes,
55876
+ entry.settledLines !== null
55877
+ );
55719
55878
  this.enforceBudget();
55720
55879
  }
55721
55880
  /** Internal: called from the revision to bump tail counters. */
55722
55881
  recordTailRerender(rowCount) {
55723
55882
  this.counters.tailRowsRerendered += rowCount;
55724
55883
  }
55725
- /** Internal: called from the revision to refresh LRU access on the owning block. */
55726
- touchActiveBlock(blockId) {
55727
- const entry = this.entries.get(blockId);
55728
- if (entry !== void 0) entry.lastAccess = this.nextAccess();
55884
+ /** Internal: measure only changed rows of the active block. */
55885
+ recordActiveLines(revision, lines, append) {
55886
+ const entry = this.entries.get(revision.blockId);
55887
+ if (entry === void 0 || entry.activeRevision !== revision) return;
55888
+ this.updateResident(
55889
+ entry,
55890
+ (append ? entry.cachedRows : 0) + lines.length,
55891
+ (append ? entry.cachedBytes : 0) + lineBytes(lines),
55892
+ true
55893
+ );
55729
55894
  }
55730
55895
  /** Internal: keep source authority current while an active handle lives. */
55731
55896
  replaceActiveSource(blockId, source) {
@@ -55736,12 +55901,13 @@ var TranscriptRenderStoreImpl = class {
55736
55901
  entry.source = source;
55737
55902
  entry.revision += 1;
55738
55903
  }
55739
- linesFor(blockId) {
55740
- const entry = this.entries.get(blockId);
55741
- if (entry === void 0) return EMPTY_LINES;
55742
- if (entry.activeRevision !== null) return entry.activeRevision.lines;
55743
- if (entry.settledLines !== void 0 && entry.settledLines !== null) return entry.settledLines;
55744
- return EMPTY_LINES;
55904
+ updateResident(entry, rows, bytes, resident) {
55905
+ this.cachedRows += rows - entry.cachedRows;
55906
+ this.cachedBytes += bytes - entry.cachedBytes;
55907
+ this.cachedBlocks += Number(resident) - Number(entry.resident);
55908
+ entry.cachedRows = rows;
55909
+ entry.cachedBytes = bytes;
55910
+ entry.resident = resident;
55745
55911
  }
55746
55912
  assertBlockId(blockId) {
55747
55913
  if (typeof blockId !== "string" || blockId === "") {
@@ -55753,49 +55919,25 @@ var TranscriptRenderStoreImpl = class {
55753
55919
  throw new Error("TranscriptRenderStore: scopeKey must be a non-empty string");
55754
55920
  }
55755
55921
  }
55756
- nextAccess() {
55757
- this.accessCounter += 1;
55758
- return this.accessCounter;
55759
- }
55760
55922
  /** Evict unpinned settled blocks until both row and byte budgets fit. */
55761
55923
  enforceBudget() {
55762
- const totals = this.computeTotals();
55763
- if (totals.rows <= this.config.maxRows && totals.bytes <= this.config.maxBytes) return;
55764
- const candidates = [];
55765
- for (const entry of this.entries.values()) {
55924
+ if (this.cachedRows <= this.config.maxRows && this.cachedBytes <= this.config.maxBytes) return;
55925
+ for (const entry of this.settledEntries) {
55926
+ if (this.cachedRows <= this.config.maxRows && this.cachedBytes <= this.config.maxBytes) break;
55766
55927
  if (this.pins.has(entry.blockId)) continue;
55767
- if (entry.activeRevision !== null) continue;
55768
- if (entry.settledLines === null || entry.settledLines === void 0) continue;
55769
- candidates.push(entry);
55770
- }
55771
- candidates.sort((a2, b2) => a2.lastAccess - b2.lastAccess);
55772
- for (const entry of candidates) {
55773
- if (totals.rows <= this.config.maxRows && totals.bytes <= this.config.maxBytes) break;
55774
- const settled = entry.settledLines;
55775
- const rowCount = settled.length;
55776
- let byteCount = 0;
55777
- for (const line5 of settled) byteCount += physicalLineByteSize(line5);
55778
55928
  entry.settledLines = null;
55779
- entry.lastAccess = 0;
55929
+ entry.settledBytes = 0;
55930
+ this.settledEntries.delete(entry);
55931
+ this.updateResident(entry, 0, 0, false);
55780
55932
  this.counters.evictions += 1;
55781
- totals.rows -= rowCount;
55782
- totals.bytes -= byteCount;
55783
- }
55784
- }
55785
- computeTotals() {
55786
- let rows = 0;
55787
- let bytes = 0;
55788
- for (const entry of this.entries.values()) {
55789
- const lines = entry.activeRevision === null ? entry.settledLines ?? EMPTY_LINES : entry.activeRevision.lines;
55790
- for (const line5 of lines) {
55791
- rows += 1;
55792
- bytes += physicalLineByteSize(line5);
55793
- }
55794
55933
  }
55795
- return { rows, bytes };
55796
55934
  }
55797
55935
  };
55798
- var EMPTY_LINES = Object.freeze([]);
55936
+ function lineBytes(lines) {
55937
+ let bytes = 0;
55938
+ for (const line5 of lines) bytes += physicalLineByteSize(line5);
55939
+ return bytes;
55940
+ }
55799
55941
  function snapshotFromEntry(entry, lines) {
55800
55942
  return Object.freeze({
55801
55943
  blockId: entry.blockId,
@@ -56128,32 +56270,32 @@ function displayedParts(parts, reasoningExpanded) {
56128
56270
  return parts.filter((part) => isVisiblePart(part) && (part.kind !== "reasoning" || reasoningExpanded));
56129
56271
  }
56130
56272
  var COLLAPSED_TOOL_CARD_LIMIT = 3;
56131
- function toolSummaryStatus(summary) {
56132
- if (summary.errorCount > 0) return "error";
56133
- return summary.runningCount > 0 ? "running" : "ok";
56273
+ function toolSummaryStatus(summary2) {
56274
+ if (summary2.errorCount > 0) return "error";
56275
+ return summary2.runningCount > 0 ? "running" : "ok";
56134
56276
  }
56135
- function toolSummaryText(summary, maxCols) {
56277
+ function toolSummaryText(summary2, maxCols) {
56136
56278
  const status = [
56137
- summary.okCount > 0 && (summary.errorCount > 0 || summary.runningCount > 0) ? `\u5B8C\u6210 ${String(summary.okCount)}` : void 0,
56138
- summary.errorCount > 0 ? `\u5931\u8D25 ${String(summary.errorCount)}` : void 0,
56139
- summary.runningCount > 0 ? `\u8FD0\u884C\u4E2D ${String(summary.runningCount)}` : void 0
56279
+ summary2.okCount > 0 && (summary2.errorCount > 0 || summary2.runningCount > 0) ? `\u5B8C\u6210 ${String(summary2.okCount)}` : void 0,
56280
+ summary2.errorCount > 0 ? `\u5931\u8D25 ${String(summary2.errorCount)}` : void 0,
56281
+ summary2.runningCount > 0 ? `\u8FD0\u884C\u4E2D ${String(summary2.runningCount)}` : void 0
56140
56282
  ].filter((value) => value !== void 0);
56141
56283
  const full = [
56142
- `\u25B8 \u5DE5\u5177\u8BB0\u5F55 \xB7 \u5DF2\u6536\u8D77 ${String(summary.hiddenCount)} \u4E2A`,
56284
+ `\u25B8 \u5DE5\u5177\u8BB0\u5F55 \xB7 \u5DF2\u6536\u8D77 ${String(summary2.hiddenCount)} \u4E2A`,
56143
56285
  ...status,
56144
56286
  "Ctrl+E \u5C55\u5F00"
56145
56287
  ].join(" \xB7 ");
56146
56288
  if (displayWidth(full) <= maxCols) return full;
56147
56289
  const compactStatus = [
56148
- summary.errorCount > 0 ? `\u5931\u8D25${String(summary.errorCount)}` : void 0,
56149
- summary.runningCount > 0 ? `\u8FD0\u884C${String(summary.runningCount)}` : void 0
56290
+ summary2.errorCount > 0 ? `\u5931\u8D25${String(summary2.errorCount)}` : void 0,
56291
+ summary2.runningCount > 0 ? `\u8FD0\u884C${String(summary2.runningCount)}` : void 0
56150
56292
  ].filter((value) => value !== void 0);
56151
- const compact = [`\u25B8 \u5DE5\u5177 ${String(summary.hiddenCount)}`, ...compactStatus, "Ctrl+E"].join(" \xB7 ");
56293
+ const compact = [`\u25B8 \u5DE5\u5177 ${String(summary2.hiddenCount)}`, ...compactStatus, "Ctrl+E"].join(" \xB7 ");
56152
56294
  if (displayWidth(compact) <= maxCols) return compact;
56153
56295
  const suffix = " \xB7 Ctrl+E";
56154
56296
  const prefixBudget = maxCols - displayWidth(suffix);
56155
56297
  if (prefixBudget <= 0) return truncateDisplay("Ctrl+E", maxCols);
56156
- return `${truncateDisplay(`\u25B8 ${String(summary.hiddenCount)} \u5DE5\u5177`, prefixBudget)}${suffix}`;
56298
+ return `${truncateDisplay(`\u25B8 ${String(summary2.hiddenCount)} \u5DE5\u5177`, prefixBudget)}${suffix}`;
56157
56299
  }
56158
56300
  function compactToolParts(parts, toolCardsExpanded, presenters, mode, cache4) {
56159
56301
  if (mode === "focus") {
@@ -56175,7 +56317,7 @@ function compactToolParts(parts, toolCardsExpanded, presenters, mode, cache4) {
56175
56317
  }
56176
56318
  const hidden = cards.filter((card) => !retained.has(card.index));
56177
56319
  const firstHiddenIndex = hidden[0]?.index;
56178
- const summary = {
56320
+ const summary2 = {
56179
56321
  hiddenCount: hidden.length,
56180
56322
  okCount: hidden.filter((card) => card.status === "ok").length,
56181
56323
  errorCount: hidden.filter((card) => card.status === "error").length,
@@ -56183,7 +56325,7 @@ function compactToolParts(parts, toolCardsExpanded, presenters, mode, cache4) {
56183
56325
  };
56184
56326
  return presentedParts.flatMap((part, index2) => {
56185
56327
  if (part.kind !== "card" || retained.has(index2)) return [part];
56186
- return index2 === firstHiddenIndex ? [{ kind: "tool-summary", summary }] : [];
56328
+ return index2 === firstHiddenIndex ? [{ kind: "tool-summary", summary: summary2 }] : [];
56187
56329
  });
56188
56330
  }
56189
56331
  function turnPartGap(parts, index2) {
@@ -56532,9 +56674,20 @@ function framePhysicalLine(blockId, line5, lead, active, prompt) {
56532
56674
  const spans = overlayPromptOnSpans(initialSpans, prompt);
56533
56675
  return clonePhysicalLineWithSpans(base, blockId, spans);
56534
56676
  }
56677
+ var projectorSourceIndexes = /* @__PURE__ */ new WeakMap();
56535
56678
  function projectorStateFor(cache4, blockId, scope, aliases2 = [], source) {
56536
56679
  const projectorScope = scope.scopeKey.replace(/\|(streaming|settled)$/u, "");
56537
56680
  const key = `${blockId}|${projectorScope}`;
56681
+ let index2 = projectorSourceIndexes.get(cache4);
56682
+ if (index2 === void 0) {
56683
+ index2 = { byScope: /* @__PURE__ */ new Map(), previousSource: /* @__PURE__ */ new WeakMap() };
56684
+ projectorSourceIndexes.set(cache4, index2);
56685
+ }
56686
+ let bySource = index2.byScope.get(projectorScope);
56687
+ if (bySource === void 0) {
56688
+ bySource = /* @__PURE__ */ new Map();
56689
+ index2.byScope.set(projectorScope, bySource);
56690
+ }
56538
56691
  let state = cache4.get(key);
56539
56692
  if (state === void 0) {
56540
56693
  for (const alias of aliases2) {
@@ -56542,19 +56695,20 @@ function projectorStateFor(cache4, blockId, scope, aliases2 = [], source) {
56542
56695
  if (state !== void 0) break;
56543
56696
  }
56544
56697
  }
56545
- if (state === void 0 && source !== void 0) {
56546
- for (const candidate of cache4.values()) {
56547
- const candidateScope = candidate.scopeKey.replace(/\|(streaming|settled)$/u, "");
56548
- if (candidateScope === projectorScope && candidate.lastSource === source) {
56549
- state = candidate;
56550
- break;
56551
- }
56552
- }
56698
+ if (state === void 0 && source !== void 0 && scope.renderMode === "settled") {
56699
+ const candidate = bySource.get(source);
56700
+ if (candidate?.lastSource === source) state = candidate;
56553
56701
  }
56554
56702
  if (state === void 0) {
56555
56703
  state = createMarkdownProjectorState(blockId, scope);
56556
56704
  }
56557
56705
  cache4.set(key, state);
56706
+ if (source !== void 0) {
56707
+ const previous3 = index2.previousSource.get(state);
56708
+ if (previous3 !== void 0 && previous3 !== source && bySource.get(previous3) === state) bySource.delete(previous3);
56709
+ bySource.set(source, state);
56710
+ index2.previousSource.set(state, source);
56711
+ }
56558
56712
  return state;
56559
56713
  }
56560
56714
  function stickyToolTitle(card) {
@@ -56577,17 +56731,6 @@ var GAP_LINE = Object.freeze({
56577
56731
  sourceEnd: -1,
56578
56732
  rawTail: false
56579
56733
  });
56580
- function slicedLead(prefix, textRanges, index2) {
56581
- for (const range of textRanges) {
56582
- if (index2 === range.start) {
56583
- return prefix.first;
56584
- }
56585
- if (index2 > range.start && index2 < range.end) {
56586
- return prefix.rest;
56587
- }
56588
- }
56589
- return "";
56590
- }
56591
56734
  function snapshotLead(textRanges, index2) {
56592
56735
  for (const range of textRanges) {
56593
56736
  if (index2 === range.start) return "\u25CF ";
@@ -56619,51 +56762,6 @@ function intersectingLayoutIndexes(layouts, start, end) {
56619
56762
  }
56620
56763
  return indexes;
56621
56764
  }
56622
- var paintedRenderLineCache = /* @__PURE__ */ new WeakMap();
56623
- function cachedPaintedRenderLine(line5, cacheKey, hyperlinks2) {
56624
- let variants = paintedRenderLineCache.get(line5);
56625
- if (variants === void 0) {
56626
- variants = /* @__PURE__ */ new Map();
56627
- paintedRenderLineCache.set(line5, variants);
56628
- }
56629
- const cached2 = variants.get(cacheKey);
56630
- if (cached2 !== void 0) return cached2;
56631
- const painted = paintLineFromRenderLine(line5, hyperlinks2);
56632
- variants.set(cacheKey, painted);
56633
- return painted;
56634
- }
56635
- function areSlicedLinesBlockPropsEqual(prev, next) {
56636
- return prev.lines === next.lines && prev.sliceStart === next.sliceStart && prev.sliceEnd === next.sliceEnd && prev.textRanges === next.textRanges && prev.tailRow === next.tailRow && prev.tail === next.tail && prev.prefix.first === next.prefix.first && prev.prefix.rest === next.prefix.rest;
56637
- }
56638
- var SlicedLinesBlock = (0, import_react37.memo)(function SlicedLinesBlock2(props) {
56639
- const { lines, sliceStart, sliceEnd, prefix, textRanges, tailRow, tail } = props;
56640
- const end = Math.min(lines.length, Math.max(0, sliceEnd));
56641
- const start = Math.max(0, Math.min(end, sliceStart));
56642
- const effectiveTailRow = tailRow ?? lines.length - 1;
56643
- const out = [];
56644
- const hyperlinks2 = hyperlinksEnabled();
56645
- const paintCacheKey = `${currentAppearance()}:${currentTier()}:${hyperlinks2 ? "links" : "plain"}`;
56646
- for (let index2 = start; index2 < end; index2 += 1) {
56647
- const line5 = lines.at(index2);
56648
- if (line5 === void 0) {
56649
- continue;
56650
- }
56651
- const painted = cachedPaintedRenderLine(line5, paintCacheKey, hyperlinks2);
56652
- const lead = slicedLead(prefix, textRanges, index2);
56653
- const trailing = index2 === effectiveTailRow ? tail : void 0;
56654
- out.push(
56655
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { wrap: "truncate", children: [
56656
- lead,
56657
- painted,
56658
- trailing
56659
- ] }, index2)
56660
- );
56661
- }
56662
- if (out.length === 0) {
56663
- return null;
56664
- }
56665
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { flexDirection: "column", width: "100%", children: out });
56666
- }, areSlicedLinesBlockPropsEqual);
56667
56765
  function projectBlockEntry(deps, ownerId, entry, scope, state, active) {
56668
56766
  if (entry.kind === "tool-card" && entry.meta?.toolCard !== void 0) {
56669
56767
  return { lines: deps.toolRows.rows(entry.id, entry.meta.toolCard, scope.width, scope.fold.tools, deps.locale) };
@@ -56707,12 +56805,12 @@ function projectBlockEntry(deps, ownerId, entry, scope, state, active) {
56707
56805
  function makeBlockProjector(deps, storeBlocks) {
56708
56806
  return (ownerId, entry, scope, state, active) => projectBlockEntry({ ...deps, storeBlocks }, ownerId, entry, scope, state, active);
56709
56807
  }
56710
- function makeToolSummaryBlockEntry(id, summary, contentWidth) {
56808
+ function makeToolSummaryBlockEntry(id, summary2, contentWidth) {
56711
56809
  return {
56712
56810
  id: `${id}-tool-summary`,
56713
56811
  kind: "tool-summary",
56714
- source: toolSummaryText(summary, contentWidth),
56715
- meta: { toolSummaryStatus: toolSummaryStatus(summary) }
56812
+ source: toolSummaryText(summary2, contentWidth),
56813
+ meta: { toolSummaryStatus: toolSummaryStatus(summary2) }
56716
56814
  };
56717
56815
  }
56718
56816
  function makeToolCardBlockEntry(id, card) {
@@ -56743,6 +56841,8 @@ function StreamView({
56743
56841
  scrollbar = true,
56744
56842
  brandFrameProbe,
56745
56843
  viewportCommand,
56844
+ viewportCommandRef,
56845
+ onViewportCommandConsumed,
56746
56846
  renderPolicy,
56747
56847
  frameMetrics,
56748
56848
  motionPaused = false,
@@ -56778,7 +56878,6 @@ function StreamView({
56778
56878
  const contentWidth = conversationWidth(columns);
56779
56879
  const contentLeft = conversationLeft(columns, contentWidth);
56780
56880
  const viewportRef = (0, import_react37.useRef)(null);
56781
- const blockRefs = (0, import_react37.useRef)(/* @__PURE__ */ new Map());
56782
56881
  const layoutCache = (0, import_react37.useRef)(new TranscriptLayoutCache());
56783
56882
  const projectorStates = (0, import_react37.useRef)(/* @__PURE__ */ new Map());
56784
56883
  const rebuildBlocks = (0, import_react37.useRef)(/* @__PURE__ */ new Map());
@@ -56808,7 +56907,6 @@ function StreamView({
56808
56907
  const scrollScheduler = (0, import_react37.useRef)(void 0);
56809
56908
  const presentationQueue = (0, import_react37.useRef)(void 0);
56810
56909
  const frameArbiter = (0, import_react37.useRef)(void 0);
56811
- const pendingScrollInputAt = (0, import_react37.useRef)(void 0);
56812
56910
  const lastDispatchedOffset = (0, import_react37.useRef)(viewport.offsetFromBottom);
56813
56911
  (0, import_react37.useLayoutEffect)(() => {
56814
56912
  const scroll = createScrollScheduler({
@@ -56851,12 +56949,6 @@ function StreamView({
56851
56949
  offsetFromBottom: snapshot2.scroll.presented
56852
56950
  });
56853
56951
  }
56854
- if (pendingScrollInputAt.current !== void 0 && frameMetrics !== void 0) {
56855
- frameMetrics.recordScrollInputToPaint(
56856
- Math.max(0, performance.now() - pendingScrollInputAt.current)
56857
- );
56858
- pendingScrollInputAt.current = void 0;
56859
- }
56860
56952
  if (frameMetrics !== void 0) {
56861
56953
  const queue = stream.getStats(snapshot2.nowMs);
56862
56954
  frameMetrics.recordRenderQueue(queue.depth, queue.oldestAgeMs);
@@ -56866,6 +56958,7 @@ function StreamView({
56866
56958
  presentationQueue.current = stream;
56867
56959
  frameArbiter.current = arbiter;
56868
56960
  return () => {
56961
+ if (frameMetrics !== void 0) clearScrollInputs(frameMetrics);
56869
56962
  unsubscribe();
56870
56963
  arbiter.dispose();
56871
56964
  if (scrollScheduler.current === scroll) scrollScheduler.current = void 0;
@@ -57234,7 +57327,9 @@ function StreamView({
57234
57327
  }, assistantBlockRowsScope, projectorStateFor(
57235
57328
  projectorCache,
57236
57329
  partId,
57237
- assistantBlockRowsScope
57330
+ assistantBlockRowsScope,
57331
+ [],
57332
+ part.text
57238
57333
  ), status === "generating").lines);
57239
57334
  ranges.push({ start, end: rows2.length });
57240
57335
  }
@@ -57603,14 +57698,6 @@ function StreamView({
57603
57698
  () => physicalViewport ? intersectingLayoutIndexes(virtualLayouts, overscanTop, overscanBottom) : renderEntries.map((_entry, index2) => index2),
57604
57699
  [overscanBottom, overscanTop, physicalViewport, renderEntries, virtualLayouts]
57605
57700
  );
57606
- const firstVisibleIndex = visibleIndexes[0];
57607
- const lastVisibleIndex = visibleIndexes.at(-1);
57608
- const leadingRows = firstVisibleIndex === void 0 ? 0 : virtualLayouts[firstVisibleIndex]?.top ?? 0;
57609
- const lastVisibleLayout = lastVisibleIndex === void 0 ? void 0 : virtualLayouts[lastVisibleIndex];
57610
- const trailingRows = lastVisibleLayout === void 0 ? 0 : Math.max(
57611
- 0,
57612
- virtualContentRows - lastVisibleLayout.top - lastVisibleLayout.rows
57613
- );
57614
57701
  const visibleEntryPairs = (0, import_react37.useMemo)(
57615
57702
  () => visibleIndexes.flatMap((index2) => {
57616
57703
  const entry = renderEntries[index2];
@@ -57657,13 +57744,17 @@ function StreamView({
57657
57744
  const effectiveViewportRowsRef = (0, import_react37.useRef)(effectiveViewportRows);
57658
57745
  effectiveViewportRowsRef.current = effectiveViewportRows;
57659
57746
  const executeViewportCommand = (0, import_react37.useCallback)((command) => {
57660
- if (command.sequence === lastCommandSequence.current) return;
57747
+ if (command.sequence <= lastCommandSequence.current) {
57748
+ onViewportCommandConsumed?.(command.sequence);
57749
+ return;
57750
+ }
57661
57751
  const vp = viewportStateRef.current;
57662
57752
  if (command.kind !== "reset" && (vp.viewportRows === 0 || vp.contentRows === 0)) return;
57663
- lastCommandSequence.current = command.sequence;
57664
57753
  const scheduler = scrollScheduler.current;
57665
57754
  const arbiter = frameArbiter.current;
57666
57755
  if (scheduler === void 0 || arbiter === void 0) return;
57756
+ lastCommandSequence.current = command.sequence;
57757
+ onViewportCommandConsumed?.(command.sequence);
57667
57758
  const effectiveContentRows = Math.max(vp.contentRows, virtualContentRowsRef.current);
57668
57759
  const maximum = Math.max(0, effectiveContentRows - effectiveViewportRowsRef.current);
57669
57760
  const clamp = (value) => Math.max(0, Math.min(maximum, value));
@@ -57674,11 +57765,14 @@ function StreamView({
57674
57765
  scheduler.setTarget(clamp((reversing ? presented : target) + delta));
57675
57766
  scheduler.tick();
57676
57767
  };
57677
- if (pendingScrollInputAt.current !== void 0) frameMetrics?.recordCoalescedInput();
57678
- pendingScrollInputAt.current ??= performance.now();
57679
57768
  switch (command.kind) {
57680
57769
  case "scroll":
57681
- advance(command.delta);
57770
+ if (command.source === "wheel") {
57771
+ const presented = scheduler.getPresented();
57772
+ const target = scheduler.getTarget();
57773
+ const reversing = command.delta * (target - presented) < 0;
57774
+ scheduler.snapTo(clamp((reversing ? presented : target) + command.delta));
57775
+ } else advance(command.delta);
57682
57776
  break;
57683
57777
  case "page":
57684
57778
  advance(command.delta * Math.max(1, vp.viewportRows - 1));
@@ -57694,21 +57788,29 @@ function StreamView({
57694
57788
  case "reset":
57695
57789
  scheduler.snapTo(0);
57696
57790
  lastDispatchedOffset.current = 0;
57697
- pendingScrollInputAt.current = void 0;
57698
57791
  dispatchViewport({ kind: "reset" });
57699
57792
  return;
57700
57793
  }
57701
57794
  const presentedOffset = scheduler.getPresented();
57795
+ if (frameMetrics !== void 0 && presentedOffset !== lastDispatchedOffset.current) {
57796
+ markScrollInput(frameMetrics, command.sequence, command.inputAt);
57797
+ }
57702
57798
  lastDispatchedOffset.current = presentedOffset;
57703
57799
  dispatchViewport({
57704
57800
  kind: "offset",
57705
57801
  offsetFromBottom: presentedOffset
57706
57802
  });
57707
57803
  arbiter.requestScroll();
57708
- }, [frameMetrics]);
57804
+ }, [frameMetrics, onViewportCommandConsumed]);
57805
+ (0, import_react37.useLayoutEffect)(() => {
57806
+ if (viewportCommandRef === void 0 || viewport.viewportRows === 0 || viewport.contentRows === 0) return;
57807
+ viewportCommandRef.current = executeViewportCommand;
57808
+ return () => {
57809
+ viewportCommandRef.current = void 0;
57810
+ };
57811
+ }, [executeViewportCommand, viewportCommandRef, viewport.viewportRows, viewport.contentRows]);
57709
57812
  (0, import_react37.useLayoutEffect)(() => {
57710
57813
  if (viewportCommand === void 0) return;
57711
- if (viewportCommand.sequence === lastCommandSequence.current) return;
57712
57814
  executeViewportCommand(viewportCommand);
57713
57815
  }, [
57714
57816
  viewportCommand,
@@ -57851,6 +57953,7 @@ function StreamView({
57851
57953
  }
57852
57954
  }
57853
57955
  return Object.freeze({
57956
+ scrollRevision: lastCommandSequence.current,
57854
57957
  revision: [
57855
57958
  contentRevision,
57856
57959
  String(viewport.offsetFromBottom),
@@ -57913,13 +58016,8 @@ function StreamView({
57913
58016
  (0, import_react37.useLayoutEffect)(() => {
57914
58017
  if (publishTranscript) writePublishedFrameSnapshot(stdout);
57915
58018
  }, [
57916
- columns,
57917
- rows,
57918
58019
  publishTranscript,
57919
- viewport.offsetFromBottom,
57920
- rail?.rows,
57921
- rail?.thumbRows,
57922
- rail?.thumbStart,
58020
+ visibleFrame,
57923
58021
  stdout
57924
58022
  ]);
57925
58023
  (0, import_react37.useLayoutEffect)(() => () => {
@@ -58137,148 +58235,47 @@ function StreamView({
58137
58235
  maxRows: viewport.viewportRows > 0 ? viewport.viewportRows : Math.max(0, rows - 7),
58138
58236
  frameProbe: brandFrameProbe
58139
58237
  }
58140
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
58238
+ ) : physicalViewport ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
58141
58239
  Box_default,
58142
58240
  {
58143
58241
  flexDirection: "column",
58144
- position: physicalViewport ? "absolute" : "relative",
58145
- top: physicalViewport && virtualContentRows <= effectiveViewportRows ? 0 : void 0,
58146
- bottom: physicalViewport && virtualContentRows > effectiveViewportRows ? -effectiveOffset : void 0,
58147
- left: physicalViewport ? contentLeft : void 0,
58148
- marginLeft: physicalViewport ? void 0 : contentLeft,
58242
+ marginLeft: contentLeft,
58149
58243
  width: contentWidth,
58150
58244
  flexShrink: 0,
58151
- children: [
58152
- leadingRows > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { height: leadingRows, flexShrink: 0 }) : null,
58153
- visibleEntryPairs.map(({ entry, index: layoutIndex }) => {
58154
- const blockId = entry.id;
58155
- const entryLines = entry.lines;
58156
- const layout = virtualLayouts[layoutIndex];
58157
- let window2;
58158
- if (physicalViewport) {
58159
- window2 = sliceWindow(
58160
- entryLines.length,
58161
- layout?.top ?? 0,
58162
- overscanTop,
58163
- overscanBottom
58164
- );
58165
- }
58166
- if (entry.kind === "active") {
58167
- if (window2 !== void 0) {
58168
- const ranges = activeEntryRows.textRanges.get(blockId) ?? EMPTY_TEXT_RANGES;
58169
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
58170
- Box_default,
58171
- {
58172
- ref: (element) => {
58173
- if (element === null) blockRefs.current.delete(blockId);
58174
- else blockRefs.current.set(blockId, element);
58175
- },
58176
- flexDirection: "column",
58177
- width: "100%",
58178
- flexShrink: 0,
58179
- children: [
58180
- window2.start > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { height: window2.start, flexShrink: 0 }) : null,
58181
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
58182
- SlicedLinesBlock,
58183
- {
58184
- lines: entryLines,
58185
- sliceStart: window2.start,
58186
- sliceEnd: window2.end,
58187
- prefix: { first: activeMarker(), rest: restIndent() },
58188
- textRanges: ranges
58189
- }
58190
- ),
58191
- window2.end < entryLines.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { height: entryLines.length - window2.end, flexShrink: 0 }) : null
58192
- ]
58193
- },
58194
- blockId
58195
- );
58196
- }
58197
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
58198
- Box_default,
58199
- {
58200
- ref: (element) => {
58201
- if (element === null) blockRefs.current.delete(blockId);
58202
- else blockRefs.current.set(blockId, element);
58203
- },
58204
- flexDirection: "column",
58205
- width: "100%",
58206
- flexShrink: 0,
58207
- children: renderActiveTurn(entry.turn)
58208
- },
58209
- blockId
58210
- );
58211
- }
58212
- const row = entry.row;
58213
- if (window2 !== void 0) {
58214
- const assistant = row.kind === "message" && row.message.kind === "assistant";
58215
- const ranges = assistant ? activeEntryRows.textRanges.get(blockId) ?? EMPTY_TEXT_RANGES : EMPTY_TEXT_RANGES;
58216
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
58217
- Box_default,
58218
- {
58219
- ref: (element) => {
58220
- if (element === null) blockRefs.current.delete(blockId);
58221
- else blockRefs.current.set(blockId, element);
58222
- },
58223
- flexDirection: "column",
58224
- width: "100%",
58225
- paddingBottom: entry.gapRows,
58226
- flexShrink: 0,
58227
- children: [
58228
- window2.start > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { height: window2.start, flexShrink: 0 }) : null,
58229
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
58230
- SlicedLinesBlock,
58231
- {
58232
- lines: entryLines,
58233
- sliceStart: window2.start,
58234
- sliceEnd: window2.end,
58235
- prefix: {
58236
- first: kindMarker("\u25CF ", "accentText"),
58237
- rest: restIndent()
58238
- },
58239
- textRanges: ranges
58240
- }
58241
- ),
58242
- window2.end < entryLines.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { height: entryLines.length - window2.end, flexShrink: 0 }) : null
58243
- ]
58244
- },
58245
- blockId
58246
- );
58247
- }
58248
- let rowNode;
58249
- if (row.kind === "compaction") {
58250
- rowNode = renderCompaction(row.divider);
58251
- } else if (row.message.kind === "user") {
58252
- const hasSubsequent = layoutIndex < renderEntries.length - 1 || activeTurn !== void 0;
58253
- rowNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
58254
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { width: "100%", backgroundColor: inkColor("messageBg"), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { wrap: "wrap", children: userRun(row.message.text, contentWidth) }) }),
58255
- hasSubsequent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: styled("\u2500".repeat(contentWidth), "line") }) : null
58256
- ] });
58257
- } else {
58258
- rowNode = renderFrozenMessage(row.message);
58259
- }
58260
- const isUserWithGap = row.kind === "message" && row.message.kind === "user" && (layoutIndex < renderEntries.length - 1 || activeTurn !== void 0);
58261
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
58262
- Box_default,
58263
- {
58264
- ref: (element) => {
58265
- if (element === null) blockRefs.current.delete(blockId);
58266
- else blockRefs.current.set(blockId, element);
58267
- },
58268
- flexDirection: "column",
58269
- width: "100%",
58270
- paddingBottom: isUserWithGap ? 1 : entry.gapRows,
58271
- flexShrink: 0,
58272
- children: rowNode
58273
- },
58274
- blockId
58275
- );
58276
- }),
58277
- trailingRows > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { height: trailingRows, flexShrink: 0 }) : null
58278
- ]
58245
+ children: visibleEntryPairs.map(({ entry, index: layoutIndex }) => {
58246
+ const blockId = entry.id;
58247
+ if (entry.kind === "active") {
58248
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: renderActiveTurn(entry.turn) }, blockId);
58249
+ }
58250
+ const row = entry.row;
58251
+ let rowNode;
58252
+ if (row.kind === "compaction") {
58253
+ rowNode = renderCompaction(row.divider);
58254
+ } else if (row.message.kind === "user") {
58255
+ const hasSubsequent = layoutIndex < renderEntries.length - 1 || activeTurn !== void 0;
58256
+ rowNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
58257
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { width: "100%", backgroundColor: inkColor("messageBg"), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { wrap: "wrap", children: userRun(row.message.text, contentWidth) }) }),
58258
+ hasSubsequent ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: styled("\u2500".repeat(contentWidth), "line") }) : null
58259
+ ] });
58260
+ } else {
58261
+ rowNode = renderFrozenMessage(row.message);
58262
+ }
58263
+ const isUserWithGap = row.kind === "message" && row.message.kind === "user" && (layoutIndex < renderEntries.length - 1 || activeTurn !== void 0);
58264
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
58265
+ Box_default,
58266
+ {
58267
+ flexDirection: "column",
58268
+ width: "100%",
58269
+ paddingBottom: isUserWithGap ? 1 : entry.gapRows,
58270
+ flexShrink: 0,
58271
+ children: rowNode
58272
+ },
58273
+ blockId
58274
+ );
58275
+ })
58279
58276
  }
58280
58277
  ),
58281
- viewport.follow ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { position: "absolute", right: 2, bottom: 0, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: styled(
58278
+ physicalViewport || viewport.follow ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { position: "absolute", right: 2, bottom: 0, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: styled(
58282
58279
  viewport.unseenRows > 0 ? `\u2193 \u6700\u65B0\u6D88\u606F \xB7 ${String(viewport.unseenRows)} \xB7 End/G \u5230\u5E95\u90E8` : "\u2193 \u5E95\u90E8 \xB7 End/G",
58283
58280
  "accentText"
58284
58281
  ) }) })
@@ -58992,19 +58989,117 @@ var SETTINGS_GROUP_LABELS = {
58992
58989
  plugins: "\u63D2\u4EF6",
58993
58990
  other: "\u5176\u4ED6"
58994
58991
  };
58995
- function nextSettingsGroup(rows, selected, direction) {
58996
- const groups = [...new Set(rows.map(settingsGroup))];
58997
- const current = rows[selected];
58998
- if (current === void 0 || groups.length === 0) return 0;
58999
- const next = groups[(groups.indexOf(settingsGroup(current)) + (direction < 0 ? -1 : 1) + groups.length) % groups.length];
59000
- return Math.max(0, rows.findIndex((row) => settingsGroup(row) === next));
58992
+
58993
+ // packages/tui/tui-render/src/settings-browser.tsx
58994
+ var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
58995
+ function fit(text4, width) {
58996
+ const safe = escapeContent(text4).replace(/\n/gu, " \u21B5 ");
58997
+ return displayWidth(safe) <= width ? safe : `${wcwidthSafeSlice(safe, Math.max(0, width - 1))}\u2026`;
58998
+ }
58999
+ function canToggleSetting(row) {
59000
+ return row !== void 0 && row.navigable !== true && row.editable !== false && (row.value === "true" || row.value === "false" || row.namespace === "tui" && ["brandAnimation", "locale", "theme", "colorTier"].includes(row.field));
59001
+ }
59002
+ function tabLine(categories, activeId, width) {
59003
+ const active = Math.max(0, categories.findIndex((category) => category.id === activeId));
59004
+ let start = active;
59005
+ let end = active + 1;
59006
+ const label = (index2) => index2 === active ? `[${categories[index2].label}]` : ` ${categories[index2].label} `;
59007
+ const used = (from2, to2) => categories.slice(from2, to2).reduce((sum, _2, i2) => sum + displayWidth(escapeContent(label(from2 + i2))) + 1, 4);
59008
+ while (start > 0 || end < categories.length) {
59009
+ if (start > 0 && used(start - 1, end) <= width) {
59010
+ start--;
59011
+ continue;
59012
+ }
59013
+ if (end < categories.length && used(start, end + 1) <= width) {
59014
+ end++;
59015
+ continue;
59016
+ }
59017
+ break;
59018
+ }
59019
+ return [
59020
+ styled(start > 0 ? "\u2039 " : " ", "fgDim"),
59021
+ ...categories.slice(start, end).map((_2, index2) => styled(
59022
+ fit(label(start + index2), Math.max(1, width - 5)) + " ",
59023
+ start + index2 === active ? "accentText" : "fgDim",
59024
+ void 0,
59025
+ start + index2 === active
59026
+ )),
59027
+ styled(end < categories.length ? "\u203A" : "", "fgDim")
59028
+ ];
59029
+ }
59030
+ function fieldLabel(row, locale) {
59031
+ const label = row.label ?? row.field;
59032
+ if (row.namespace !== "tui" || label !== row.field) return label;
59033
+ if (row.field === "reasoning" || row.field === "scrollbar" || row.field === "statusDetails" || row.field === "locale") return `${tuiCopy(row.field, locale)} (${row.field})`;
59034
+ const names = { theme: "\u660E\u6697\u4E3B\u9898", brandAnimation: "\u54C1\u724C\u52A8\u753B", submitOnEnter: "\u56DE\u8F66\u53D1\u9001", colorTier: "\u8272\u5F69\u6863\u4F4D" };
59035
+ return locale !== "en-US" && names[row.field] !== void 0 ? `${names[row.field]} (${row.field})` : label;
59036
+ }
59037
+ function SettingsBrowser(props) {
59038
+ const { rows, selectedIndex, editing, updateError, busy, searching, filter = "", breadcrumb = ["\u8BBE\u7F6E"], categories = [], activeCategory, locale } = props;
59039
+ const width = Math.max(1, props.columns);
59040
+ const budget = Math.max(1, props.maxRows ?? 18);
59041
+ const selected = Math.max(0, Math.min(selectedIndex, rows.length - 1));
59042
+ const active = rows[selected];
59043
+ const compact = budget < 8;
59044
+ const filtered = filter !== "" || searching === true;
59045
+ const category = categories.find((entry) => entry.id === activeCategory)?.label ?? breadcrumb[1];
59046
+ const back = breadcrumb.length > 2 ? "\u8FD4\u56DE" : "\u5173\u95ED";
59047
+ const action = active?.navigable === true ? "\u8FDB\u5165" : active?.editable === false ? "\u53EA\u8BFB" : canToggleSetting(active) ? "\u5207\u6362" : "\u7F16\u8F91";
59048
+ const primary = action === "\u53EA\u8BFB" ? action : `Enter ${action}`;
59049
+ let footer = busy === true ? ["\u6B63\u5728\u5904\u7406\uFF0C\u8BF7\u7A0D\u5019\u2026"] : editing ? ["Enter \u4FDD\u5B58 \xB7 Esc \u53D6\u6D88"] : searching === true ? ["\u2191\u2193 \u9009\u62E9 \xB7 Enter \u5B8C\u6210\u641C\u7D22 \xB7 Esc \u6E05\u9664", "Tab/Shift+Tab \u5206\u7C7B"] : compact ? [`${primary} \xB7 Esc ${back}`] : width < 80 ? [`\u2191\u2193 \u9009\u62E9 \xB7 ${primary} \xB7 Esc ${back}`, `Tab \u5206\u7C7B \xB7 / \u641C\u7D22${active?.navigable === true && active.editable !== false ? " \xB7 i JSON" : ""}`] : [`\u2191\u2193 \u9009\u62E9 \xB7 PgUp/PgDn \u7FFB\u9875 \xB7 ${primary} \xB7 \u2190/Esc ${back}`, `Tab/Shift+Tab \u5206\u7C7B \xB7 / \u641C\u7D22${active?.navigable === true && active.editable !== false ? " \xB7 i JSON \u7F16\u8F91" : canToggleSetting(active) ? " \xB7 Space \u5207\u6362" : ""} \xB7 e \u5BFC\u51FA \xB7 r \u91CD\u8F7D`];
59050
+ if (budget <= 2) footer = [];
59051
+ const lines = [];
59052
+ const add = (text4, token = "fg", bold = false, bg = "bg") => lines.push({ parts: [styled(fit(text4, width), token, void 0, bold)], bg });
59053
+ const count = `${rows.length === 0 ? 0 : selected + 1}/${rows.length}`;
59054
+ const title = compact && category !== void 0 ? `[${category}]` : "\u8BBE\u7F6E";
59055
+ add(`${fit(title, Math.max(1, width - displayWidth(count) - 2))} ${count}`, "fg", true);
59056
+ const showTabs = !compact && categories.length > 0;
59057
+ if (showTabs) lines.push({ parts: tabLine(categories, activeCategory, width), bg: "bg" });
59058
+ if (!compact) {
59059
+ const path2 = breadcrumb.slice(showTabs ? 2 : 1).join(" \u203A ") || category || "\u9009\u62E9\u5206\u7C7B";
59060
+ const location = displayWidth(escapeContent(path2)) <= width ? path2 : `\u2026 \u203A ${breadcrumb.slice(-2).join(" \u203A ")}`;
59061
+ add(filtered ? `\u641C\u7D22\u7ED3\u679C /${filter}${searching === true ? "\u258F" : ""}` : location, filtered ? "accentText" : "fgDim");
59062
+ } else if (searching === true) {
59063
+ lines[0] = { parts: [styled(fit(`\u641C\u7D22 /${filter}\u258F`, width), "accentText")], bg: "bg" };
59064
+ }
59065
+ const status = updateError !== void 0 ? `\u2717 \u66F4\u65B0\u5931\u8D25\uFF1A${updateError}` : busy === true ? "\u6B63\u5728\u5904\u7406\u8BBE\u7F6E\u2026" : void 0;
59066
+ const space = Math.max(0, budget - lines.length - footer.length - (status === void 0 ? 0 : 1));
59067
+ const detail = [];
59068
+ const detailBudget = compact || active === void 0 ? 0 : Math.min(6, Math.max(0, space - Math.min(3, Math.max(1, rows.length))));
59069
+ if (active !== void 0 && detailBudget > 0) {
59070
+ const source = filtered ? `${active.namespace} \xB7 ${active.field}` : fieldLabel(active, locale);
59071
+ detail.push(...wrapDisplayLines(escapeContent(`\u5F53\u524D\u9879: ${source}`), width).slice(0, filtered ? 2 : 1));
59072
+ const value = active.value === "" ? "\u2014" : active.value;
59073
+ detail.push(...wrapDisplayLines(escapeContent(`${active.navigable === true ? "\u5305\u542B" : "\u5F53\u524D\u503C"}: ${value}`), width));
59074
+ if (active.description !== void 0) detail.push(...wrapDisplayLines(escapeContent(active.description), width));
59075
+ if (detail.length > detailBudget) {
59076
+ detail.length = detailBudget;
59077
+ detail[detail.length - 1] = `${wcwidthSafeSlice(detail[detail.length - 1], Math.max(0, width - 1))}\u2026`;
59078
+ }
59079
+ }
59080
+ const size = Math.min(rows.length, Math.max(0, space - detail.length));
59081
+ const start = Math.max(0, Math.min(rows.length - size, selected - Math.floor(size / 2)));
59082
+ if (size === 0 && space > detail.length) add(filtered ? "\u6CA1\u6709\u5339\u914D\u7684\u8BBE\u7F6E \xB7 Esc \u6E05\u9664\u641C\u7D22" : "\u65E0\u53EF\u7528\u8BBE\u7F6E", "fgDim");
59083
+ for (const [offset, row] of rows.slice(start, start + size).entries()) {
59084
+ const isSelected = start + offset === selected;
59085
+ const rawValue = row.value === "true" ? "\u2713 \u5F00\u542F" : row.value === "false" ? "\u25CB \u5173\u95ED" : row.value;
59086
+ const value = rawValue || (row.navigable === true ? "\u6253\u5F00 \u203A" : "\u2014");
59087
+ const labelWidth = Math.max(1, Math.min(44, Math.floor((width - 4) * 0.45)));
59088
+ const label = fit(`${fieldLabel(row, locale)}${row.required === true ? " *" : ""}`, labelWidth);
59089
+ const gap = Math.max(2, labelWidth - displayWidth(label) + 2);
59090
+ const text4 = `${isSelected ? "\u203A " : " "}${label}${" ".repeat(gap)}${fit(`${row.navigable === true ? "\u203A " : ""}${value}`, Math.max(1, width - 2 - displayWidth(label) - gap))}`;
59091
+ add(text4, isSelected ? "fg" : "fgSoft", isSelected, isSelected ? "settingsCardBg" : "bg");
59092
+ }
59093
+ for (const text4 of detail) add(text4, "fgDim");
59094
+ if (status !== void 0) add(status, updateError === void 0 ? "fgDim" : "error");
59095
+ for (const text4 of footer) add(text4, "fgDim");
59096
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: lines.slice(0, budget).map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { height: 1, flexShrink: 0, width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { wrap: "truncate-end", children: paintBackgroundRow(line5.parts, line5.bg, width) }) }, index2)) });
59001
59097
  }
59002
59098
 
59003
59099
  // packages/tui/tui-render/src/settings-pane.tsx
59004
- var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
59100
+ var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
59005
59101
  var TITLE2 = "\u8BBE\u7F6E";
59006
59102
  var ONBOARDING_TITLE = "\u9996\u6B21\u8BBE\u7F6E";
59007
- var FOOTNOTE2 = "\u2191\u2193/jk \u9009\u62E9 \xB7 Enter \u7F16\u8F91 \xB7 e \u5BFC\u51FA \xB7 r \u91CD\u8F7D \xB7 Esc \u5173\u95ED";
59008
59103
  var EDIT_FOOTNOTE = "Enter \u5E94\u7528 \xB7 Esc \u53D6\u6D88";
59009
59104
  var ONBOARDING_FOOTNOTE = "Enter \u4FDD\u5B58 \xB7 Esc \u8DF3\u8FC7";
59010
59105
  var DISCOVERY_BUSY = "\u6B63\u5728\u83B7\u53D6\u6A21\u578B\u5217\u8868\u2026";
@@ -59050,7 +59145,9 @@ function fieldRow(label, value, selected, columns, required2 = false) {
59050
59145
  const marker = selected ? styled(escapeContent("\u203A "), "accent", void 0, true) : " ";
59051
59146
  const reqMark = required2 ? styled("* ", "error", void 0, true) : "";
59052
59147
  const reqWidth = required2 ? 2 : 0;
59053
- const escapedLabel = escapeContent(label);
59148
+ const rawLabel = escapeContent(label);
59149
+ const labelBudget = displayWidth(rawLabel) + displayWidth(escapeContent(value)) + MARKER_COLS + reqWidth + VALUE_GAP <= columns ? displayWidth(rawLabel) : Math.max(1, Math.floor((columns - MARKER_COLS - reqWidth - VALUE_GAP) * 0.48));
59150
+ const escapedLabel = fitValue(rawLabel, labelBudget);
59054
59151
  const escapedValue = escapeContent(value);
59055
59152
  const labelToken = selected ? "fg" : "fgSoft";
59056
59153
  const labelCols = MARKER_COLS + reqWidth + displayWidth(escapedLabel);
@@ -59092,72 +59189,59 @@ function SettingsPane({
59092
59189
  updateError,
59093
59190
  busy,
59094
59191
  locale,
59095
- maxRows
59192
+ maxRows,
59193
+ breadcrumb,
59194
+ filter,
59195
+ searching,
59196
+ categories,
59197
+ activeCategory
59096
59198
  }) {
59097
59199
  const { columns } = use_window_size_default();
59098
59200
  const width = columns > 0 ? columns : 80;
59099
- const errorReason2 = updateError ?? (rows.length === 0 ? EMPTY_TABLE_REASON2 : void 0);
59100
- let footnote = `Tab/Shift+Tab \u5206\u7EC4 \xB7 ${FOOTNOTE2}`;
59101
- if (onboarding === true) {
59102
- footnote = editing ? ONBOARDING_FOOTNOTE : "\u2191\u2193/jk \u9009\u62E9\u5BC6\u94A5 \xB7 Enter \u8F93\u5165 \xB7 Esc \u5173\u95ED";
59103
- } else if (editing) {
59104
- footnote = EDIT_FOOTNOTE;
59105
- }
59106
- const windowLimit = computeSettingsWindow(maxRows, rows.length, errorReason2, busy === true);
59107
- const size = Math.min(windowLimit, rows.length);
59108
- const start = rows.length <= size ? 0 : Math.min(
59109
- Math.max(0, selectedIndex - Math.floor(size / 2)),
59110
- rows.length - size
59201
+ if (breadcrumb !== void 0 && onboarding !== true) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
59202
+ SettingsBrowser,
59203
+ {
59204
+ rows,
59205
+ selectedIndex,
59206
+ editing,
59207
+ columns: width,
59208
+ breadcrumb,
59209
+ ...locale === void 0 ? {} : { locale },
59210
+ ...filter === void 0 ? {} : { filter },
59211
+ ...searching === void 0 ? {} : { searching },
59212
+ ...categories === void 0 ? {} : { categories },
59213
+ ...activeCategory === void 0 ? {} : { activeCategory },
59214
+ ...maxRows === void 0 ? {} : { maxRows },
59215
+ ...updateError === void 0 ? {} : { updateError },
59216
+ ...busy === void 0 ? {} : { busy }
59217
+ }
59111
59218
  );
59112
- const visible = rows.slice(start, start + size);
59113
- const renderLine = (text4, token, bold = false) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintBackgroundRow([styled(escapeContent(text4), token, void 0, bold)], "settingsCardBg", width) }) });
59114
- let headingText = rows[selectedIndex] === void 0 ? TITLE2 : `${TITLE2} \xB7 ${SETTINGS_GROUP_LABELS[settingsGroup(rows[selectedIndex])]}`;
59115
- if (onboarding === true) headingText = rows.length > 1 ? "API \u5BC6\u94A5" : ONBOARDING_TITLE;
59116
- const clampedSelected = rows.length === 0 ? 0 : Math.min(Math.max(0, selectedIndex), rows.length - 1);
59117
- const activeNs = rows[clampedSelected]?.namespace;
59118
- let headerRight = "";
59119
- if (rows.length > 0 && (onboarding !== true || rows.length > 1)) {
59120
- headerRight = `${String(clampedSelected + 1)}/${String(rows.length)}`;
59121
- if (activeNs !== void 0 && width >= 40) headerRight = `${activeNs} \xB7 ${headerRight}`;
59122
- }
59123
- const headerGap = headerRight !== "" && displayWidth(headingText) + displayWidth(headerRight) + 2 <= width ? width - displayWidth(headingText) - displayWidth(headerRight) : 0;
59124
- const headerParts = headerGap > 0 ? [
59125
- styled(escapeContent(headingText), "fg", void 0, true),
59126
- styled(" ".repeat(headerGap), "settingsCardBg"),
59127
- styled(escapeContent(headerRight), "fgDim")
59128
- ] : [styled(escapeContent(headingText), "fg", void 0, true)];
59129
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
59130
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintBackgroundRow(headerParts, "settingsCardBg", width) }) }),
59219
+ const selected = Math.min(Math.max(0, selectedIndex), Math.max(0, rows.length - 1));
59220
+ const active = rows[selected];
59221
+ const errorReason2 = updateError ?? (rows.length === 0 ? EMPTY_TABLE_REASON2 : void 0);
59222
+ const footer = onboarding === true ? [editing ? ONBOARDING_FOOTNOTE : "\u2191\u2193 \u9009\u62E9\u5BC6\u94A5 \xB7 Enter \u8F93\u5165 \xB7 Esc \u5173\u95ED"] : [editing ? EDIT_FOOTNOTE : "\u2191\u2193/jk \u9009\u62E9 \xB7 Enter \u7F16\u8F91 \xB7 e \u5BFC\u51FA \xB7 r \u91CD\u8F7D \xB7 Esc \u5173\u95ED"];
59223
+ const size = Math.min(rows.length, computeSettingsWindow(maxRows, rows.length, errorReason2, busy === true));
59224
+ const start = Math.min(Math.max(0, selected - Math.floor(size / 2)), Math.max(0, rows.length - size));
59225
+ const renderLine = (text4, token, bold = false) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { width: "100%", height: 1, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { wrap: "truncate-end", children: paintBackgroundRow([styled(fitValue(escapeContent(text4), width), token, void 0, bold)], "settingsCardBg", width) }) });
59226
+ let heading = active === void 0 ? TITLE2 : `${TITLE2} \xB7 ${SETTINGS_GROUP_LABELS[settingsGroup(active)]}`;
59227
+ if (onboarding === true) heading = rows.length > 1 ? "API \u5BC6\u94A5" : ONBOARDING_TITLE;
59228
+ const counter = rows.length === 0 ? "" : `${active !== void 0 ? `${active.namespace} \xB7 ` : ""}${String(selected + 1)}/${String(rows.length)}`;
59229
+ if (counter !== "") heading = `${fitValue(escapeContent(heading), Math.max(1, width - displayWidth(counter) - 2))} ${counter}`;
59230
+ const localizedLabel = (row) => {
59231
+ if (row.label !== void 0 && !(row.namespace === "tui" && row.label === row.field)) return row.label;
59232
+ const resolved = locale ?? "zh-CN";
59233
+ const label = row.namespace === "tui" && (row.field === "reasoning" || row.field === "scrollbar" || row.field === "statusDetails" || row.field === "locale") ? `${row.field} \xB7 ${tuiCopy(row.field, locale)}` : row.namespace === "tui" && row.field in TUI_EXTRA_LABELS ? `${row.field} \xB7 ${TUI_EXTRA_LABELS[row.field][resolved === "en-US" ? "en-US" : "zh-CN"]}` : row.field === "apiKeyEnv" ? `${row.field} \xB7 \u73AF\u5883\u53D8\u91CF\u540D` : row.field;
59234
+ return `${row.namespace} \xB7 ${label}`;
59235
+ };
59236
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
59237
+ renderLine(heading, "fg", true),
59131
59238
  start > 0 ? renderLine(`\u2191 \u4E0A\u65B9\u8FD8\u6709 ${String(start)} \u9879 (\u2026 \u8FD8\u6709 ${String(start)} \u9879)`, "fgDim") : null,
59132
- visible.map((row, index2) => {
59133
- const absolute = start + index2;
59134
- const selected = absolute === selectedIndex;
59135
- const resolvedLocale = locale ?? "zh-CN";
59136
- let localized;
59137
- if (row.label !== void 0) {
59138
- localized = row.label;
59139
- } else if (row.namespace === "tui" && (row.field === "reasoning" || row.field === "scrollbar" || row.field === "statusDetails" || row.field === "locale")) {
59140
- localized = `${row.field} \xB7 ${tuiCopy(row.field, locale)}`;
59141
- } else if (row.namespace === "tui" && row.field in TUI_EXTRA_LABELS) {
59142
- localized = `${row.field} \xB7 ${TUI_EXTRA_LABELS[row.field][resolvedLocale === "en-US" ? "en-US" : "zh-CN"]}`;
59143
- } else if (row.field === "apiKeyEnv") {
59144
- localized = `${row.field} \xB7 \u73AF\u5883\u53D8\u91CF\u540D`;
59145
- } else {
59146
- localized = row.field;
59147
- }
59148
- const label = row.label === void 0 ? `${row.namespace} \xB7 ${localized}` : localized;
59149
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: paintBackgroundRow(fieldRow(label, row.value, selected, width, row.required === true), "settingsCardBg", width) }) }, `${row.namespace}:${row.field}:${String(absolute)}`);
59150
- }),
59239
+ rows.slice(start, start + size).map((row, index2) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { width: "100%", height: 1, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { wrap: "truncate-end", children: paintBackgroundRow(fieldRow(localizedLabel(row), `${row.navigable === true ? "\u203A " : ""}${row.value}`, start + index2 === selected, width, row.required === true), "settingsCardBg", width) }) }, `${row.namespace}:${JSON.stringify(row.sourcePath ?? row.field)}:${String(start + index2)}`)),
59151
59240
  rows.length > start + size ? renderLine(`\u2026 \u8FD8\u6709 ${String(rows.length - start - size)} \u9879`, "fgDim") : null,
59152
- errorReason2 === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
59153
- renderLine(
59154
- errorReason2 === EMPTY_TABLE_REASON2 ? EMPTY_TABLE_REASON2 : `\u2717 \u66F4\u65B0\u5931\u8D25\uFF1A${errorReason2}`,
59155
- "error"
59156
- ),
59157
- errorReason2 === EMPTY_TABLE_REASON2 ? null : renderLine(FAIL_NEXT2, "fgDim")
59158
- ] }),
59241
+ errorReason2 === void 0 ? null : renderLine(errorReason2 === EMPTY_TABLE_REASON2 ? EMPTY_TABLE_REASON2 : `\u2717 \u66F4\u65B0\u5931\u8D25\uFF1A${errorReason2}`, "error"),
59242
+ errorReason2 === void 0 || errorReason2 === EMPTY_TABLE_REASON2 ? null : renderLine(FAIL_NEXT2, "fgDim"),
59159
59243
  busy === true ? renderLine(DISCOVERY_BUSY, "fgDim") : null,
59160
- renderLine(footnote, "fgDim")
59244
+ footer.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { width: "100%", height: 1, flexShrink: 0, children: renderLine(line5, "fgDim") }, index2))
59161
59245
  ] });
59162
59246
  }
59163
59247
 
@@ -59208,7 +59292,7 @@ function tokenizeComposer(text4) {
59208
59292
  }
59209
59293
 
59210
59294
  // packages/tui/tui-render/src/input-bar.tsx
59211
- var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
59295
+ var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
59212
59296
  var PROMPT_WIDTH = 2;
59213
59297
  var COMPOSER_PLACEHOLDER = tuiCopy("inputHint");
59214
59298
  function InputBar({
@@ -59221,7 +59305,8 @@ function InputBar({
59221
59305
  modelChip,
59222
59306
  modeChip,
59223
59307
  locale,
59224
- secret
59308
+ secret,
59309
+ actionHint
59225
59310
  }) {
59226
59311
  const { text: text4, caretIndex } = maskComposerInput(sourceText, sourceCaretIndex ?? sourceText.length, secret);
59227
59312
  const selectionAnchor = sourceSelectionAnchor === void 0 ? void 0 : maskComposerInput(sourceText, sourceSelectionAnchor, secret).caretIndex;
@@ -59262,7 +59347,7 @@ function InputBar({
59262
59347
  const leftPrefix = "\u2502 ";
59263
59348
  const placeholder = tuiCopy("inputHint", locale);
59264
59349
  const sendHint = tuiCopy("sendHint", locale);
59265
- const modeHint = commandMode ? tuiCopy("commandModeHint", locale) : mentionMode ? tuiCopy("mentionModeHint", locale) : void 0;
59350
+ const modeHint = actionHint ?? (commandMode ? tuiCopy("commandModeHint", locale) : mentionMode ? tuiCopy("mentionModeHint", locale) : void 0);
59266
59351
  const leftHint = modeHint === void 0 ? `\u203A ${placeholder} \xB7 ${sendHint}` : `\u203A ${modeHint}`;
59267
59352
  const leftWidth = displayWidth(leftPrefix + leftHint);
59268
59353
  const chipWidth = chipText !== "" ? displayWidth(chipText) : 0;
@@ -59278,14 +59363,14 @@ function InputBar({
59278
59363
  styled(escapeContent(chipText), "fgDim")
59279
59364
  ] : []
59280
59365
  ];
59281
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
59366
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
59282
59367
  Box_default,
59283
59368
  {
59284
59369
  flexDirection: "column",
59285
59370
  width: "100%",
59286
59371
  backgroundColor: inkColor("inputBg"),
59287
59372
  children: [
59288
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow(headerParts, "inputBg", columns) }),
59373
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow(headerParts, "inputBg", columns) }),
59289
59374
  lines.map((line5, lineIndex) => {
59290
59375
  const window2 = windows[lineIndex];
59291
59376
  let sourceColumn = 0;
@@ -59309,7 +59394,7 @@ function InputBar({
59309
59394
  return selection !== void 0 && start + begin >= selection.start && start + begin < selection.end && visible !== "" && currentTier() !== "none" ? `\x1B[7m${painted}\x1B[27m` : painted;
59310
59395
  });
59311
59396
  });
59312
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow([
59397
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow([
59313
59398
  styled(escapeContent("\u2502 "), "accentText"),
59314
59399
  styled(escapeContent(lineIndex === 0 ? "> " : " "), "accentText"),
59315
59400
  ...window2.hiddenPrefix ? [styled("\u2039", "fgDim")] : [],
@@ -59322,7 +59407,7 @@ function InputBar({
59322
59407
  }
59323
59408
 
59324
59409
  // packages/tui/tui-render/src/agent-hub-pane.tsx
59325
- var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
59410
+ var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
59326
59411
  function formatTokens(value) {
59327
59412
  const scaled = (next) => next >= 100 ? String(Math.round(next)) : String(Math.round(next * 10) / 10);
59328
59413
  if (value < 1e3) return String(value);
@@ -59359,14 +59444,14 @@ function aggregateLine(rows) {
59359
59444
  }
59360
59445
  function hubRow(row, selected) {
59361
59446
  const label = [row.label, row.execution ?? (row.activity === "" ? void 0 : row.activity), ...metricSegments(row)].filter((value) => value !== void 0).join(" \xB7 ");
59362
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Box_default, { width: "100%", flexDirection: "column", children: [
59363
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { wrap: "truncate", children: [
59447
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { width: "100%", flexDirection: "column", children: [
59448
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Text, { wrap: "truncate", children: [
59364
59449
  selected ? styled(escapeContent("\u203A "), "accent", void 0, true) : " ",
59365
59450
  paintRow([styled(escapeContent(label), selected ? "fg" : "fgSoft", void 0, selected)])
59366
59451
  ] }),
59367
- row.task !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintRow([styled(` \u4EFB\u52A1 \xB7 ${escapeContent(row.task)}`, "fgSoft")]) }),
59368
- row.summary !== void 0 && row.summary !== "" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintRow([styled(` \u5F53\u524D \xB7 ${escapeContent(row.summary)}`, "accent")]) }),
59369
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintRow([styled(` ${escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${row.id}`)}`, "fgDim")]) })
59452
+ row.task !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { wrap: "truncate", children: paintRow([styled(` \u4EFB\u52A1 \xB7 ${escapeContent(row.task)}`, "fgSoft")]) }),
59453
+ row.summary !== void 0 && row.summary !== "" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { wrap: "truncate", children: paintRow([styled(` \u5F53\u524D \xB7 ${escapeContent(row.summary)}`, "accent")]) }),
59454
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { wrap: "truncate", children: paintRow([styled(` ${escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${row.id}`)}`, "fgDim")]) })
59370
59455
  ] }, row.id);
59371
59456
  }
59372
59457
  function hubLimitsFootnote(liveContinuable, maxActiveSubagents, maxDepth) {
@@ -59412,7 +59497,7 @@ function AgentHubBody({
59412
59497
  if (view === "transcript") onViewportChange?.({ offset: start, maxOffset: maximum, pageRows: pageSize });
59413
59498
  }, [view, start, maximum, pageSize, onViewportChange]);
59414
59499
  if (missing) {
59415
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
59500
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
59416
59501
  OverlayShell,
59417
59502
  {
59418
59503
  title: "\u5B50\u4EE3\u7406",
@@ -59425,13 +59510,13 @@ function AgentHubBody({
59425
59510
  const selected = rows[clamped];
59426
59511
  const addressable = selected?.parentSessionId !== void 0 && selected.parentSessionId !== selected.id && selected.mode !== void 0;
59427
59512
  const controls = prompt === void 0 ? [addressable && selected.mode === "continuable" ? "c \u7EED\u804A" : "", addressable ? "s \u8BF7\u6C42\u505C\u6B62" : "", "v \u5E76\u6392"].filter(Boolean).join(" \xB7 ") : `Enter \u6392\u961F \xB7 Ctrl+Enter \u5F15\u5BFC \xB7 Esc \u53D6\u6D88${busy ? " \xB7 \u53D1\u9001\u4E2D" : ""}`;
59428
- const editor = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
59429
- notice !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(notice), "fgDim")]) }),
59430
- renderEditor && prompt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(InputBar, { text: prompt, caretIndex, commandMode: false, mentionMode: false })
59513
+ const editor = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
59514
+ notice !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(notice), "fgDim")]) }),
59515
+ renderEditor && prompt !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(InputBar, { text: prompt, caretIndex, commandMode: false, mentionMode: false })
59431
59516
  ] });
59432
59517
  if (view === "transcript") {
59433
59518
  if (error51 !== void 0 && error51 !== "" && prompt === void 0) {
59434
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
59519
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
59435
59520
  OverlayShell,
59436
59521
  {
59437
59522
  title: "\u5B50\u4EE3\u7406",
@@ -59449,7 +59534,7 @@ function AgentHubBody({
59449
59534
  const total = lines.length;
59450
59535
  const slice = lines.slice(start, start + pageSize);
59451
59536
  const scrollInfo = total > pageSize ? ` (${String(start + 1)}-${String(Math.min(start + slice.length, total))}/${String(total)})` : "";
59452
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
59537
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
59453
59538
  OverlayShell,
59454
59539
  {
59455
59540
  title: "\u5B50\u4EE3\u7406",
@@ -59459,10 +59544,10 @@ ${controls}
59459
59544
  Esc \u8FD4\u56DE \xB7 ${scrollOffset === Number.MAX_SAFE_INTEGER ? "\u8DDF\u968F\u6700\u65B0" : "\u9605\u8BFB\u4E2D"}${scrollInfo}
59460
59545
  ${split ? "\u5E76\u6392\u67E5\u770B" : "\u53EA\u8BFB\u67E5\u770B"}\uFF0C\u4E3B\u4F1A\u8BDD\u7EE7\u7EED\u8FD0\u884C`,
59461
59546
  children: [
59462
- headerSegments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Box_default, { width: "100%", flexDirection: "column", marginY: 0, children: [
59463
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(headerSegments.join(" \xB7 ")), "accent", void 0, true)]) }),
59464
- selectedRow?.id && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${selectedRow.id}`), "fgDim")]) }),
59465
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { children: paintRow([styled(escapeContent("\u2500\u2500\u2500 \u6267\u884C\u60C5\u51B5 \u2500\u2500\u2500"), "fgDim")]) })
59547
+ headerSegments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { width: "100%", flexDirection: "column", marginY: 0, children: [
59548
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(headerSegments.join(" \xB7 ")), "accent", void 0, true)]) }),
59549
+ selectedRow?.id && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(`\u5B50\u4F1A\u8BDD ID \xB7 ${selectedRow.id}`), "fgDim")]) }),
59550
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { children: paintRow([styled(escapeContent("\u2500\u2500\u2500 \u6267\u884C\u60C5\u51B5 \u2500\u2500\u2500"), "fgDim")]) })
59466
59551
  ] }),
59467
59552
  slice.map((lineText, index2) => {
59468
59553
  const isUser = lineText.startsWith("> ");
@@ -59473,7 +59558,7 @@ ${split ? "\u5E76\u6392\u67E5\u770B" : "\u53EA\u8BFB\u67E5\u770B"}\uFF0C\u4E3B\u
59473
59558
  if (isUser) token = "accent";
59474
59559
  else if (isTool) token = "codeKeyword";
59475
59560
  else if (isResult || isTurn) token = "fgDim";
59476
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { children: paintRow([styled(escapeContent(lineText), token)]) }, start + index2);
59561
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { children: paintRow([styled(escapeContent(lineText), token)]) }, start + index2);
59477
59562
  }),
59478
59563
  editor
59479
59564
  ]
@@ -59481,7 +59566,7 @@ ${split ? "\u5E76\u6392\u67E5\u770B" : "\u53EA\u8BFB\u67E5\u770B"}\uFF0C\u4E3B\u
59481
59566
  );
59482
59567
  }
59483
59568
  if (error51 !== void 0 && error51 !== "" && prompt === void 0) {
59484
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
59569
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
59485
59570
  OverlayShell,
59486
59571
  {
59487
59572
  title: "\u5B50\u4EE3\u7406",
@@ -59491,7 +59576,7 @@ ${split ? "\u5E76\u6392\u67E5\u770B" : "\u53EA\u8BFB\u67E5\u770B"}\uFF0C\u4E3B\u
59491
59576
  );
59492
59577
  }
59493
59578
  if (rows.length === 0) {
59494
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
59579
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
59495
59580
  OverlayShell,
59496
59581
  {
59497
59582
  title: "\u5B50\u4EE3\u7406",
@@ -59508,7 +59593,7 @@ ${controls}`;
59508
59593
  const footerRows = wrapDisplayLines(footnote, columns || 80).length;
59509
59594
  const windowSize = Math.max(1, Math.floor((height - 9 - footerRows) / 4));
59510
59595
  const rowStart = Math.max(0, Math.min(rows.length - windowSize, clamped - Math.floor(windowSize / 2)));
59511
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
59596
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
59512
59597
  OverlayShell,
59513
59598
  {
59514
59599
  title: "\u5B50\u4EE3\u7406",
@@ -59516,20 +59601,20 @@ ${controls}`;
59516
59601
  footnote,
59517
59602
  children: [
59518
59603
  rows.slice(rowStart, rowStart + windowSize).map((row) => hubRow(row, row.id === rows[clamped]?.id)),
59519
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(aggregateLine(rows)), "fgDim")]) }),
59604
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(aggregateLine(rows)), "fgDim")]) }),
59520
59605
  editor
59521
59606
  ]
59522
59607
  }
59523
59608
  );
59524
59609
  }
59525
59610
  function AgentHubPane(props) {
59526
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Box_default, { width: props.maxCols ?? "100%", flexDirection: "column", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(AgentHubBody, { ...props }) });
59611
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { width: props.maxCols ?? "100%", flexDirection: "column", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AgentHubBody, { ...props }) });
59527
59612
  }
59528
59613
 
59529
59614
  // packages/tui/tui-render/src/plan-directory-pane.tsx
59530
- var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
59615
+ var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
59531
59616
  var TITLE3 = "\u8BA1\u5212";
59532
- var FOOTNOTE3 = "j/k \u9009\u62E9 \xB7 Enter \u5207\u6362 \xB7 Esc \u5173\u95ED";
59617
+ var FOOTNOTE2 = "j/k \u9009\u62E9 \xB7 Enter \u5207\u6362 \xB7 Esc \u5173\u95ED";
59533
59618
  var SWITCH_NEXT = "\u5F53\u524D\u6A21\u5F0F\u4FDD\u6301\u4E0D\u53D8 \xB7 \u53EF\u91CD\u8BD5";
59534
59619
  var STATUS_FOOTNOTE = "Esc \u5173\u95ED \xB7 \u53EF\u91CD\u8BD5";
59535
59620
  var ROWS = ["\u5F00\u542F", "\u5173\u95ED"];
@@ -59540,13 +59625,13 @@ var EMPTY_PLAN_DIRECTORY_PANE = {
59540
59625
  };
59541
59626
  function directoryRow(label, selected, current) {
59542
59627
  const text4 = current ? `${label} \xB7 \u5F53\u524D` : label;
59543
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { width: "100%", children: [
59544
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { children: selected ? styled(escapeContent("\u203A "), "accent", void 0, true) : " " }),
59545
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { children: paintRow([styled(escapeContent(text4), selected ? "fg" : "fgDim")]) })
59628
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Box_default, { width: "100%", children: [
59629
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { children: selected ? styled(escapeContent("\u203A "), "accent", void 0, true) : " " }),
59630
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { children: paintRow([styled(escapeContent(text4), selected ? "fg" : "fgDim")]) })
59546
59631
  ] }, label);
59547
59632
  }
59548
59633
  function line3(text4, token) {
59549
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { children: paintRow([styled(escapeContent(text4), token)]) });
59634
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { children: paintRow([styled(escapeContent(text4), token)]) });
59550
59635
  }
59551
59636
  function PlanDirectoryPane({
59552
59637
  selectedIndex = 0,
@@ -59555,7 +59640,7 @@ function PlanDirectoryPane({
59555
59640
  statusError
59556
59641
  }) {
59557
59642
  if (statusError !== void 0 && statusError !== "") {
59558
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
59643
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
59559
59644
  OverlayShell,
59560
59645
  {
59561
59646
  title: TITLE3,
@@ -59564,7 +59649,7 @@ function PlanDirectoryPane({
59564
59649
  }
59565
59650
  );
59566
59651
  }
59567
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(OverlayShell, { title: TITLE3, footnote: FOOTNOTE3, children: [
59652
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(OverlayShell, { title: TITLE3, footnote: FOOTNOTE2, children: [
59568
59653
  ROWS.map(
59569
59654
  (label, index2) => directoryRow(
59570
59655
  label,
@@ -59572,7 +59657,7 @@ function PlanDirectoryPane({
59572
59657
  label === "\u5F00\u542F" ? currentActive : !currentActive
59573
59658
  )
59574
59659
  ),
59575
- switchError !== void 0 && switchError !== "" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
59660
+ switchError !== void 0 && switchError !== "" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
59576
59661
  line3(`\u2717 \u5207\u6362\u8BA1\u5212\u5931\u8D25\uFF1A${switchError}`, "error"),
59577
59662
  line3(SWITCH_NEXT, "fgDim")
59578
59663
  ] }) : null
@@ -59581,9 +59666,9 @@ function PlanDirectoryPane({
59581
59666
 
59582
59667
  // packages/tui/tui-render/src/plan-review-pane.tsx
59583
59668
  var import_react43 = __toESM(require_react(), 1);
59584
- var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
59669
+ var import_jsx_runtime20 = __toESM(require_jsx_runtime(), 1);
59585
59670
  var TITLE4 = "\u8BA1\u5212\u8BC4\u5BA1";
59586
- var FOOTNOTE4 = "y \u6279\u51C6 \xB7 n \u7EE7\u7EED\u89C4\u5212 \xB7 Esc \u53D6\u6D88";
59671
+ var FOOTNOTE3 = "y \u6279\u51C6 \xB7 n \u7EE7\u7EED\u89C4\u5212 \xB7 Esc \u53D6\u6D88";
59587
59672
  var EMPTY_BODY = "\u8BA1\u5212\u6B63\u6587\u4E3A\u7A7A";
59588
59673
  var DELIVERY_NEXT2 = "\u5F53\u524D\u8BA1\u5212\u672A\u6279\u51C6 \xB7 \u53EF\u91CD\u8BD5\u8BE5\u8F6E";
59589
59674
  var PLAN_REVIEW_WINDOW = 12;
@@ -59591,7 +59676,7 @@ var EMPTY_PLAN_REVIEW_PANE = {
59591
59676
  open: false
59592
59677
  };
59593
59678
  function line4(text4, token, bold = false) {
59594
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(text4), token, void 0, bold)]) });
59679
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(escapeContent(text4), token, void 0, bold)]) });
59595
59680
  }
59596
59681
  function PlanReviewPane({
59597
59682
  plan = "",
@@ -59625,21 +59710,21 @@ ${DELIVERY_NEXT2}` : "", width);
59625
59710
  const view = failed ? errorView : planView;
59626
59711
  const position2 = view.total > 0 ? ` ${view.start + 1}\u2013${view.start + view.visible.length}/${view.total}` : "";
59627
59712
  let body;
59628
- if (failed) body = errorView.visible.map((text4, index2) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { wrap: "truncate", children: paintRow([styled(text4 || " ", "error")]) }, errorView.start + index2));
59713
+ if (failed) body = errorView.visible.map((text4, index2) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(text4 || " ", "error")]) }, errorView.start + index2));
59629
59714
  else if (plan.trim() === "") body = line4(EMPTY_BODY, "fg");
59630
- else body = planView.visible.map((row, index2) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { wrap: "truncate", children: row.spans.length === 0 ? " " : paintLineFromRenderLine(row, links) }, planView.start + index2));
59631
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59632
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { wrap: "truncate", children: paintRow([styled(TITLE4, "fg", void 0, true), styled(position2, "fgDim")]) }),
59715
+ else body = planView.visible.map((row, index2) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: row.spans.length === 0 ? " " : paintLineFromRenderLine(row, links) }, planView.start + index2));
59716
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59717
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(TITLE4, "fg", void 0, true), styled(position2, "fgDim")]) }),
59633
59718
  body,
59634
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { wrap: "truncate", children: paintRow([styled(" [y] ", "success", void 0, true), styled("\u6279\u51C6", "fg", void 0, true), styled(" (\u5F00\u59CB\u6267\u884C\u8BA1\u5212)", "fgDim")]) }),
59635
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { wrap: "truncate", children: paintRow([styled(" [n] ", "warning", void 0, true), styled("\u7EE7\u7EED\u89C4\u5212", "fg", void 0, true), styled(" (\u8FD4\u56DE\u8C03\u6574\u65B9\u6848)", "fgDim")]) }),
59636
- line4(width < 70 ? "\u2191\u2193/PgUp/PgDn \xB7 Home/End \xB7 Esc \u53D6\u6D88" : `${FOOTNOTE4} \xB7 \u2191\u2193/PgUp/PgDn \u6D4F\u89C8`, "fgDim")
59719
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(" [y] ", "success", void 0, true), styled("\u6279\u51C6", "fg", void 0, true), styled(" (\u5F00\u59CB\u6267\u884C\u8BA1\u5212)", "fgDim")]) }),
59720
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(" [n] ", "warning", void 0, true), styled("\u7EE7\u7EED\u89C4\u5212", "fg", void 0, true), styled(" (\u8FD4\u56DE\u8C03\u6574\u65B9\u6848)", "fgDim")]) }),
59721
+ line4(width < 70 ? "\u2191\u2193/PgUp/PgDn \xB7 Home/End \xB7 Esc \u53D6\u6D88" : `${FOOTNOTE3} \xB7 \u2191\u2193/PgUp/PgDn \u6D4F\u89C8`, "fgDim")
59637
59722
  ] });
59638
59723
  }
59639
59724
 
59640
59725
  // packages/tui/tui-render/src/ask-user-pane.tsx
59641
- var import_jsx_runtime20 = __toESM(require_jsx_runtime(), 1);
59642
- var FOOTNOTE5 = "Enter \u4F5C\u7B54 \xB7 Esc \u53D6\u6D88\u63D0\u95EE";
59726
+ var import_jsx_runtime21 = __toESM(require_jsx_runtime(), 1);
59727
+ var FOOTNOTE4 = "Enter \u4F5C\u7B54 \xB7 Esc \u53D6\u6D88\u63D0\u95EE";
59643
59728
  var INVALID_TITLE = "\u2717 \u63D0\u95EE\u65E0\u6548";
59644
59729
  var INVALID_NEXT = "Esc \u53D6\u6D88";
59645
59730
  var EMPTY_ASK_USER_PANE = {
@@ -59683,9 +59768,9 @@ function AskUserPane({
59683
59768
  const detailRows = useDialogTextRows(source, width);
59684
59769
  const view = useDialogWindow(detailRows, offset, limit, detailsOpen ? onOffsetChange : void 0);
59685
59770
  const progress = questionCount === void 0 ? "" : ` (${questionNumber}/${questionCount})`;
59686
- if (editingCustom && !detailsOpen) return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59687
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(`${escapeContent(header)}${progress}`, "fg", void 0, true)]) }),
59688
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
59771
+ if (editingCustom && !detailsOpen) return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59772
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([styled(`${escapeContent(header)}${progress}`, "fg", void 0, true)]) }),
59773
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
59689
59774
  InputBar,
59690
59775
  {
59691
59776
  text: (customText ?? "").replace(/[\r\n]/gu, "\u21B5"),
@@ -59695,10 +59780,10 @@ function AskUserPane({
59695
59780
  rowsBelow: customRowsBelow ?? 2
59696
59781
  }
59697
59782
  ),
59698
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled("Enter \u786E\u8BA4 \xB7 Tab \u5168\u6587 \xB7 Esc \u53D6\u6D88", "fgDim")]) })
59783
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([styled("Enter \u786E\u8BA4 \xB7 Tab \u5168\u6587 \xB7 Esc \u53D6\u6D88", "fgDim")]) })
59699
59784
  ] });
59700
59785
  if (options.length === 0 && !editingCustom) {
59701
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59786
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59702
59787
  renderPaneLine(INVALID_TITLE, "error", true),
59703
59788
  renderPaneLine(INVALID_NEXT, "fgDim")
59704
59789
  ] });
@@ -59706,28 +59791,28 @@ function AskUserPane({
59706
59791
  const start = Math.max(0, Math.min(options.length - limit, selected - Math.floor(limit / 2)));
59707
59792
  const position2 = detailsOpen ? ` ${view.start + 1}\u2013${view.start + view.visible.length}/${view.total}` : "";
59708
59793
  const heading = detailsOpen ? `\u63D0\u95EE\u5168\u6587${options.length === 0 ? progress : ` \xB7 \u9009\u9879 ${selected + 1}/${options.length}`}${position2}` : `${escapeContent(header || "\u8BF7\u9009\u62E9").replace(/\n/g, " \u21B5 ")}${progress}`;
59709
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59710
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(heading, "fg", void 0, true)]) }),
59711
- detailsOpen ? view.visible.map((text4, index2) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(text4 || " ", "fg")]) }, view.start + index2)) : options.slice(start, start + limit).map((label, index2) => {
59794
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59795
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([styled(heading, "fg", void 0, true)]) }),
59796
+ detailsOpen ? view.visible.map((text4, index2) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([styled(text4 || " ", "fg")]) }, view.start + index2)) : options.slice(start, start + limit).map((label, index2) => {
59712
59797
  const actualIndex = start + index2;
59713
59798
  const active = actualIndex === selected;
59714
59799
  const marker = multiSelect ? selectedIndices?.includes(actualIndex) ? "[x] " : "[ ] " : "";
59715
59800
  const numbered = escapeContent(`${actualIndex + 1} ${marker}${label}`).replace(/\n/g, " \u21B5 ");
59716
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([
59801
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([
59717
59802
  styled(active ? "\u203A " : " ", "accent", void 0, active),
59718
59803
  styled(numbered, active ? "fg" : "fgDim", void 0, active)
59719
59804
  ]) }, actualIndex);
59720
59805
  }),
59721
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59722
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(editingCustom ? "Tab/Esc \u8FD4\u56DE\u8F93\u5165" : FOOTNOTE5, "fgDim")]) }),
59723
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(editingCustom ? "\u2191\u2193/jk \u6EDA\u52A8 \xB7 Home/End \u9996\u5C3E" : multiSelect ? "\u2191\u2193 \u79FB\u52A8 \xB7 Space \u591A\u9009 \xB7 c \u81EA\u5B9A\u4E49" : "\u2191\u2193/jk \u79FB\u52A8 \xB7 1-9 \u9009\u62E9 \xB7 c \u81EA\u5B9A\u4E49", "fgDim")]) }),
59724
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Text, { wrap: "truncate", children: paintRow([styled(editingCustom ? "PgUp/PgDn \u7FFB\u9875" : customText === void 0 ? "[i] \u5168\u6587 \xB7 PgUp/PgDn \u7FFB\u9875" : "\u5DF2\u6709\u81EA\u5B9A\u4E49\u56DE\u7B54 \xB7 [i] \u5168\u6587", "fgDim")]) })
59806
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Box_default, { flexDirection: "column", width: "100%", flexShrink: 0, children: [
59807
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([styled(editingCustom ? "Tab/Esc \u8FD4\u56DE\u8F93\u5165" : FOOTNOTE4, "fgDim")]) }),
59808
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([styled(editingCustom ? "\u2191\u2193/jk \u6EDA\u52A8 \xB7 Home/End \u9996\u5C3E" : multiSelect ? "\u2191\u2193 \u79FB\u52A8 \xB7 Space \u591A\u9009 \xB7 c \u81EA\u5B9A\u4E49" : "\u2191\u2193/jk \u79FB\u52A8 \xB7 1-9 \u9009\u62E9 \xB7 c \u81EA\u5B9A\u4E49", "fgDim")]) }),
59809
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { wrap: "truncate", children: paintRow([styled(editingCustom ? "PgUp/PgDn \u7FFB\u9875" : customText === void 0 ? "[i] \u5168\u6587 \xB7 PgUp/PgDn \u7FFB\u9875" : "\u5DF2\u6709\u81EA\u5B9A\u4E49\u56DE\u7B54 \xB7 [i] \u5168\u6587", "fgDim")]) })
59725
59810
  ] })
59726
59811
  ] });
59727
59812
  }
59728
59813
 
59729
59814
  // packages/tui/tui-render/src/timeline-view.tsx
59730
- var import_jsx_runtime21 = __toESM(require_jsx_runtime(), 1);
59815
+ var import_jsx_runtime22 = __toESM(require_jsx_runtime(), 1);
59731
59816
  var FIRST_LINE_MAX = 120;
59732
59817
  var TIMELINE_WINDOW = 60;
59733
59818
  function TimelineView({
@@ -59742,19 +59827,19 @@ function TimelineView({
59742
59827
  const start = Math.max(0, end - TIMELINE_WINDOW);
59743
59828
  const visible = history.slice(start, end);
59744
59829
  const current = end >= history.length ? visible.length - 1 : -1;
59745
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
59746
- history.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { dimColor: true, children: "\uFF08\u65E0\u5386\u53F2\u6D88\u606F\uFF09" }) : null,
59747
- start > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Text, { dimColor: true, children: [
59830
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
59831
+ history.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Text, { dimColor: true, children: "\uFF08\u65E0\u5386\u53F2\u6D88\u606F\uFF09" }) : null,
59832
+ start > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Text, { dimColor: true, children: [
59748
59833
  "\u2026 \u8FD8\u6709 ",
59749
59834
  start,
59750
59835
  " \u6761"
59751
59836
  ] }) : null,
59752
- visible.map((message, index2) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Text, { children: [
59837
+ visible.map((message, index2) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Text, { children: [
59753
59838
  styled(relativeTime(message.timestamp, clock), "fgDim"),
59754
59839
  ` ${message.kind === "user" ? "> " : "\u25CF "}`,
59755
59840
  index2 === current ? styled(escapeContent(firstLine(message.text)), "accent") : escapeContent(firstLine(message.text))
59756
59841
  ] }, start + index2)),
59757
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Text, { children: styled(escapeContent("\u2191\u2193/jk \u6EDA\u52A8 \xB7 Esc \u5173\u95ED"), "fgDim") })
59842
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Text, { children: styled(escapeContent("\u2191\u2193/jk \u6EDA\u52A8 \xB7 Esc \u5173\u95ED"), "fgDim") })
59758
59843
  ] });
59759
59844
  }
59760
59845
  function firstLine(text4) {
@@ -59763,7 +59848,7 @@ function firstLine(text4) {
59763
59848
  }
59764
59849
 
59765
59850
  // packages/tui/tui-render/src/command-menu.tsx
59766
- var import_jsx_runtime22 = __toESM(require_jsx_runtime(), 1);
59851
+ var import_jsx_runtime23 = __toESM(require_jsx_runtime(), 1);
59767
59852
  var COMMAND_MENU_WINDOW = 8;
59768
59853
  var MARKER_COLS2 = 2;
59769
59854
  var NAME_GAP = 2;
@@ -59830,11 +59915,11 @@ function CommandMenu({
59830
59915
  const widthName = displayWidth(`/${item.name}`);
59831
59916
  if (widthName > nameCols) nameCols = widthName;
59832
59917
  }
59833
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Box_default, { flexDirection: "column", alignItems: "center", width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Box_default, { flexDirection: "column", width, children: matches.map((item, index2) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Box_default, { width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Text, { children: paintRow(paletteRow(item, offset + index2 === clampedIndex, nameCols, width)) }) }, item.name)) }) });
59918
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { flexDirection: "column", alignItems: "center", width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { flexDirection: "column", width, children: matches.map((item, index2) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text, { children: paintRow(paletteRow(item, offset + index2 === clampedIndex, nameCols, width)) }) }, item.name)) }) });
59834
59919
  }
59835
59920
 
59836
59921
  // packages/tui/tui-render/src/mention.tsx
59837
- var import_jsx_runtime23 = __toESM(require_jsx_runtime(), 1);
59922
+ var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1);
59838
59923
  var KIND_LABELS = {
59839
59924
  file: "\u6587\u4EF6",
59840
59925
  directory: "\u76EE\u5F55",
@@ -59852,10 +59937,10 @@ function Mention({
59852
59937
  const { columns } = use_window_size_default();
59853
59938
  const width = conversationWidth(columns > 0 ? columns : 80);
59854
59939
  if (phase === "loading") {
59855
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { width: "100%", alignItems: "center", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { width, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text, { dimColor: true, children: "\u52A0\u8F7D\u4E2D\u2026" }) }) });
59940
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Box_default, { width: "100%", alignItems: "center", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Box_default, { width, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { dimColor: true, children: "\u52A0\u8F7D\u4E2D\u2026" }) }) });
59856
59941
  }
59857
59942
  if (candidates.length === 0) {
59858
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { width: "100%", alignItems: "center", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { width, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text, { dimColor: true, children: "\u65E0\u5339\u914D" }) }) });
59943
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Box_default, { width: "100%", alignItems: "center", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Box_default, { width, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { dimColor: true, children: "\u65E0\u5339\u914D" }) }) });
59859
59944
  }
59860
59945
  const clampedIndex = Math.max(0, Math.min(selectedIndex, candidates.length - 1));
59861
59946
  const sections = /* @__PURE__ */ new Map();
@@ -59871,12 +59956,12 @@ function Mention({
59871
59956
  let rowIndex = 0;
59872
59957
  for (const [kind, group] of sections) {
59873
59958
  rows.push(
59874
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Text, { wrap: "truncate", children: styled(KIND_LABELS[kind], "accentText", void 0, true) }, kind)
59959
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { wrap: "truncate", children: styled(KIND_LABELS[kind], "accentText", void 0, true) }, kind)
59875
59960
  );
59876
59961
  for (const candidate of group) {
59877
59962
  const selected = rowIndex === clampedIndex;
59878
59963
  rows.push(
59879
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Text, { wrap: "truncate", children: [
59964
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(Text, { wrap: "truncate", children: [
59880
59965
  selected ? styled(escapeContent("\u203A "), "accent", void 0, true) : " ",
59881
59966
  styled(`@ ${escapeContent(candidate.name)}`, selected ? "fg" : "fgSoft", void 0, selected),
59882
59967
  candidate.description !== void 0 ? styled(` \u2014 ${escapeContent(candidate.description)}`, "fgDim") : ""
@@ -59885,7 +59970,7 @@ function Mention({
59885
59970
  rowIndex += 1;
59886
59971
  }
59887
59972
  }
59888
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { flexDirection: "column", alignItems: "center", width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Box_default, { flexDirection: "column", width, children: rows }) });
59973
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Box_default, { flexDirection: "column", alignItems: "center", width: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Box_default, { flexDirection: "column", width, children: rows }) });
59889
59974
  }
59890
59975
 
59891
59976
  // packages/tui/tui-render/src/goal-footer.ts
@@ -60269,7 +60354,7 @@ function layoutHud(input) {
60269
60354
  }
60270
60355
 
60271
60356
  // packages/tui/tui-render/src/workflow-overlay.tsx
60272
- var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1);
60357
+ var import_jsx_runtime25 = __toESM(require_jsx_runtime(), 1);
60273
60358
  var WORKFLOW_OVERLAY_WINDOW = 8;
60274
60359
  var EMPTY_WORKFLOW_OVERLAY = { open: false, offset: 0 };
60275
60360
  function WorkflowOverlay({
@@ -60277,15 +60362,15 @@ function WorkflowOverlay({
60277
60362
  }) {
60278
60363
  if (!state.open) return null;
60279
60364
  if (state.error !== void 0) {
60280
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u6D41", error: state.error, footnote: "Esc \u5173\u95ED" });
60365
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u6D41", error: state.error, footnote: "Esc \u5173\u95ED" });
60281
60366
  }
60282
60367
  if (state.run === void 0) {
60283
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u6D41", body: "\u5F53\u524D\u65E0\u5DE5\u4F5C\u6D41\u8FD0\u884C", footnote: "Esc \u5173\u95ED" });
60368
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u6D41", body: "\u5F53\u524D\u65E0\u5DE5\u4F5C\u6D41\u8FD0\u884C", footnote: "Esc \u5173\u95ED" });
60284
60369
  }
60285
60370
  const rows = [];
60286
60371
  if (state.run.phase !== void 0 && state.run.phase !== "") {
60287
60372
  rows.push(
60288
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { children: paintRow([styled(escapeContent(`\u9636\u6BB5 ${state.run.phase}`), "fg")]) }, "phase")
60373
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text, { children: paintRow([styled(escapeContent(`\u9636\u6BB5 ${state.run.phase}`), "fg")]) }, "phase")
60289
60374
  );
60290
60375
  }
60291
60376
  const windowed = state.run.members.slice(
@@ -60295,17 +60380,17 @@ function WorkflowOverlay({
60295
60380
  for (const member of windowed) {
60296
60381
  const outcomeSuffix = member.outcome === void 0 ? "" : ` \xB7 ${member.outcome}`;
60297
60382
  rows.push(
60298
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Text, { children: paintRow([
60383
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text, { children: paintRow([
60299
60384
  styled(escapeContent(`${member.seq} \xB7 ${member.label}${outcomeSuffix}`), "fgDim")
60300
60385
  ]) }, member.seq)
60301
60386
  );
60302
60387
  }
60303
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u6D41", footnote: "j/k \u6EDA\u52A8 \xB7 Esc \u5173\u95ED", children: rows });
60388
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u6D41", footnote: "j/k \u6EDA\u52A8 \xB7 Esc \u5173\u95ED", children: rows });
60304
60389
  }
60305
60390
 
60306
60391
  // packages/tui/tui-render/src/workspace-pane.tsx
60307
60392
  var import_react44 = __toESM(require_react(), 1);
60308
- var import_jsx_runtime25 = __toESM(require_jsx_runtime(), 1);
60393
+ var import_jsx_runtime26 = __toESM(require_jsx_runtime(), 1);
60309
60394
  var EMPTY_WORKSPACE_PANE = {
60310
60395
  open: false,
60311
60396
  root: "",
@@ -60398,12 +60483,12 @@ function WorkspacePreview({ preview, columns, maxRows, onLayout, systemOpen }) {
60398
60483
  if (start >= fragment.end) break;
60399
60484
  }
60400
60485
  }
60401
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow(parts, "codeBg", columns) }, `${fragment.line}:${fragment.start}`);
60486
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Text, { wrap: "truncate", children: paintBackgroundRow(parts, "codeBg", columns) }, `${fragment.line}:${fragment.start}`);
60402
60487
  });
60403
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Box_default, { flexDirection: "column", width: columns, children: [
60404
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text, { wrap: "truncate", children: paintRow([styled(title, "fg", void 0, true)]) }),
60488
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Box_default, { flexDirection: "column", width: columns, children: [
60489
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Text, { wrap: "truncate", children: paintRow([styled(title, "fg", void 0, true)]) }),
60405
60490
  rows,
60406
- maxRows > 1 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text, { wrap: "truncate", children: paintRow([styled(footnote, "fgDim")]) }) : null
60491
+ maxRows > 1 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Text, { wrap: "truncate", children: paintRow([styled(footnote, "fgDim")]) }) : null
60407
60492
  ] });
60408
60493
  }
60409
60494
  function WorkspacePane({
@@ -60415,10 +60500,10 @@ function WorkspacePane({
60415
60500
  const { rows: windowRows, columns: windowColumns } = use_window_size_default();
60416
60501
  if (!state.open) return null;
60417
60502
  if (state.error !== void 0) {
60418
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u533A", error: state.error, footnote: "Esc \u5173\u95ED" });
60503
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OverlayShell, { title: "\u5DE5\u4F5C\u533A", error: state.error, footnote: "Esc \u5173\u95ED" });
60419
60504
  }
60420
60505
  if (state.preview !== void 0) {
60421
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
60506
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
60422
60507
  WorkspacePreview,
60423
60508
  {
60424
60509
  preview: state.preview,
@@ -60439,7 +60524,7 @@ function WorkspacePane({
60439
60524
  const selected = index2 === state.selectedIndex && !state.editing;
60440
60525
  const head = `${selected ? "\u203A " : " "}${" ".repeat(node2.depth)}${glyph} `;
60441
60526
  rows.push(
60442
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Text, { wrap: "truncate", children: paintRow([
60527
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Text, { wrap: "truncate", children: paintRow([
60443
60528
  styled(escapeContent(head), selected ? "accent" : "fgDim"),
60444
60529
  styled(
60445
60530
  truncateDisplay(
@@ -60451,7 +60536,7 @@ function WorkspacePane({
60451
60536
  ]) }, node2.path)
60452
60537
  );
60453
60538
  });
60454
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
60539
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
60455
60540
  OverlayShell,
60456
60541
  {
60457
60542
  title: state.mode === "deliveries" ? "\u4EA4\u4ED8\u6587\u4EF6" : "\u5DE5\u4F5C\u533A",
@@ -60465,7 +60550,7 @@ function WorkspacePane({
60465
60550
  }
60466
60551
 
60467
60552
  // packages/tui/tui-render/src/plugins-pane.tsx
60468
- var import_jsx_runtime26 = __toESM(require_jsx_runtime(), 1);
60553
+ var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
60469
60554
  var EMPTY_PLUGINS_PANE = {
60470
60555
  open: false,
60471
60556
  available: false,
@@ -60570,11 +60655,11 @@ function PluginsPane({ state, locale = "zh-CN", maxCols, maxRows }) {
60570
60655
  return { text: text4, token };
60571
60656
  });
60572
60657
  const visible = [...lines.slice(start, start + bodyBudget), ...statusEntries];
60573
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OverlayShell, { title: clean(copy("pluginsTitle")), body: clean(copy("pluginsScope")), footnote: clean(hint), children: visible.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Text, { wrap: "truncate", children: paintRow([styled(clean(line5.text), line5.token ?? (line5.selected ? "accent" : "fg"), void 0, line5.bold === true)]) }, index2)) });
60658
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(OverlayShell, { title: clean(copy("pluginsTitle")), body: clean(copy("pluginsScope")), footnote: clean(hint), children: visible.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { wrap: "truncate", children: paintRow([styled(clean(line5.text), line5.token ?? (line5.selected ? "accent" : "fg"), void 0, line5.bold === true)]) }, index2)) });
60574
60659
  }
60575
60660
 
60576
60661
  // packages/tui/tui-render/src/account-pane.tsx
60577
- var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
60662
+ var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
60578
60663
  var EMPTY_ACCOUNT_PANE = {
60579
60664
  open: false,
60580
60665
  available: false,
@@ -60669,11 +60754,11 @@ function AccountPane({ state, locale = "zh-CN", maxCols }) {
60669
60754
  }
60670
60755
  if (state.busy) hint = copy("accountBusyHint");
60671
60756
  }
60672
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(OverlayShell, { title: copy("accountTitle"), footnote: truncateDisplay(escapeContent(hint), width), error: state.error, children: lines.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Text, { wrap: "truncate", children: paintRow([styled(line5.wrap === true ? escapeContent(line5.text) : truncateDisplay(escapeContent(line5.text), width), line5.token, void 0, line5.bold === true)]) }, index2)) });
60757
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(OverlayShell, { title: copy("accountTitle"), footnote: truncateDisplay(escapeContent(hint), width), error: state.error, children: lines.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Text, { wrap: "truncate", children: paintRow([styled(line5.wrap === true ? escapeContent(line5.text) : truncateDisplay(escapeContent(line5.text), width), line5.token, void 0, line5.bold === true)]) }, index2)) });
60673
60758
  }
60674
60759
 
60675
60760
  // packages/tui/tui-render/src/feedback-pane.tsx
60676
- var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
60761
+ var import_jsx_runtime29 = __toESM(require_jsx_runtime(), 1);
60677
60762
  var EMPTY_FEEDBACK_PANE = {
60678
60763
  open: false,
60679
60764
  hasTarget: false,
@@ -60689,10 +60774,10 @@ function FeedbackPane({
60689
60774
  }) {
60690
60775
  if (!state.open) return null;
60691
60776
  if (state.error !== void 0) {
60692
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(OverlayShell, { title: "\u53CD\u9988", error: state.error, footnote: "Esc \u5173\u95ED" });
60777
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(OverlayShell, { title: "\u53CD\u9988", error: state.error, footnote: "Esc \u5173\u95ED" });
60693
60778
  }
60694
60779
  if (!state.hasTarget) {
60695
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
60780
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
60696
60781
  OverlayShell,
60697
60782
  {
60698
60783
  title: "\u53CD\u9988",
@@ -60708,7 +60793,7 @@ function FeedbackPane({
60708
60793
  { key: "negative", shortcut: "[d] ", label: "\u8E29", token: "warning" }
60709
60794
  ].map((row) => {
60710
60795
  const isCurrent = state.rating === row.key;
60711
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Text, { wrap: "truncate", children: paintRow([
60796
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { wrap: "truncate", children: paintRow([
60712
60797
  styled(escapeContent(` ${row.shortcut}`), isCurrent ? row.token : "fgDim", void 0, isCurrent),
60713
60798
  styled(
60714
60799
  escapeContent(`${row.label}${isCurrent ? " \xB7 \u5F53\u524D" : ""}`),
@@ -60720,13 +60805,13 @@ function FeedbackPane({
60720
60805
  });
60721
60806
  if (state.note !== void 0 && state.note.trim() !== "") {
60722
60807
  rows.push(
60723
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Text, { wrap: "truncate", children: paintRow([
60808
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { wrap: "truncate", children: paintRow([
60724
60809
  styled(" \u5907\u6CE8: ", "fgDim"),
60725
60810
  styled(escapeContent(state.note), "fgSoft")
60726
60811
  ]) }, "note")
60727
60812
  );
60728
60813
  }
60729
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
60814
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
60730
60815
  OverlayShell,
60731
60816
  {
60732
60817
  title: "\u53CD\u9988",
@@ -60778,7 +60863,7 @@ function toolDetailsKeyAction(key, info) {
60778
60863
 
60779
60864
  // packages/tui/tui-render/src/todo-pane.tsx
60780
60865
  var import_react45 = __toESM(require_react(), 1);
60781
- var import_jsx_runtime29 = __toESM(require_jsx_runtime(), 1);
60866
+ var import_jsx_runtime30 = __toESM(require_jsx_runtime(), 1);
60782
60867
  function TodoPane({ todos, offset, onOffsetChange, locale }) {
60783
60868
  const { columns, rows } = use_window_size_default();
60784
60869
  const width = Math.max(1, (columns || 80) - 4);
@@ -60809,17 +60894,17 @@ function TodoPane({ todos, offset, onOffsetChange, locale }) {
60809
60894
  (0, import_react45.useEffect)(() => {
60810
60895
  if (start !== offset) onOffsetChange?.(start);
60811
60896
  }, [start, offset, onOffsetChange]);
60812
- const summary = english ? `${todos.length} tasks \xB7 ${counts.in_progress} active \xB7 ${counts.pending} pending \xB7 ${counts.completed} done` : `\u5171 ${todos.length} \u9879 \xB7 \u8FDB\u884C\u4E2D ${counts.in_progress} \xB7 \u5F85\u529E ${counts.pending} \xB7 \u5DF2\u5B8C\u6210 ${counts.completed}`;
60897
+ const summary2 = english ? `${todos.length} tasks \xB7 ${counts.in_progress} active \xB7 ${counts.pending} pending \xB7 ${counts.completed} done` : `\u5171 ${todos.length} \u9879 \xB7 \u8FDB\u884C\u4E2D ${counts.in_progress} \xB7 \u5F85\u529E ${counts.pending} \xB7 \u5DF2\u5B8C\u6210 ${counts.completed}`;
60813
60898
  const position2 = lines.length === 0 ? "" : ` ${start + 1}\u2013${Math.min(start + height, lines.length)}/${lines.length}`;
60814
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
60899
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
60815
60900
  OverlayShell,
60816
60901
  {
60817
60902
  title: english ? "TODO list" : "\u5F85\u529E\u6E05\u5355",
60818
60903
  footnote: `${english ? "\u2191\u2193/jk Scroll \xB7 PgUp/PgDn Page \xB7 Esc Back" : "\u2191\u2193/jk \u6EDA\u52A8 \xB7 PgUp/PgDn \u7FFB\u9875 \xB7 Esc \u8FD4\u56DE"}${position2}`,
60819
60904
  children: [
60820
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { wrap: "truncate", children: paintRow([styled(summary, "fgDim")]) }),
60821
- todos.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { children: english ? "No TODO list in this turn." : "\u5F53\u524D\u56DE\u5408\u6682\u65E0\u5F85\u529E\u6E05\u5355\u3002" }),
60822
- lines.slice(start, start + height).map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Text, { wrap: "truncate", children: paintRow([styled(line5.text || " ", line5.token)]) }, start + index2))
60905
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Text, { wrap: "truncate", children: paintRow([styled(summary2, "fgDim")]) }),
60906
+ todos.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Text, { children: english ? "No TODO list in this turn." : "\u5F53\u524D\u56DE\u5408\u6682\u65E0\u5F85\u529E\u6E05\u5355\u3002" }),
60907
+ lines.slice(start, start + height).map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Text, { wrap: "truncate", children: paintRow([styled(line5.text || " ", line5.token)]) }, start + index2))
60823
60908
  ]
60824
60909
  }
60825
60910
  );
@@ -60827,7 +60912,7 @@ function TodoPane({ todos, offset, onOffsetChange, locale }) {
60827
60912
 
60828
60913
  // packages/tui/tui-render/src/schedule-pane.tsx
60829
60914
  var import_react46 = __toESM(require_react(), 1);
60830
- var import_jsx_runtime30 = __toESM(require_jsx_runtime(), 1);
60915
+ var import_jsx_runtime31 = __toESM(require_jsx_runtime(), 1);
60831
60916
  var EMPTY_SCHEDULE_PANE = {
60832
60917
  open: false,
60833
60918
  rows: [],
@@ -60874,14 +60959,14 @@ ${escapeContent(selected.id)}
60874
60959
  if (lines.length === 0) lines = [state.loading ? "\u6B63\u5728\u8BFB\u53D6\u4EFB\u52A1\u2026" : "\u6682\u65E0\u4EFB\u52A1\uFF1B\u53EF\u8BA9\u6A21\u578B\u521B\u5EFA\u5B9A\u65F6\u63D0\u9192\u3002"];
60875
60960
  }
60876
60961
  const footnote = state.busy ? "\u6B63\u5728\u53D6\u6D88\u4EFB\u52A1\u2026" : state.confirmDelete ? "y \u786E\u8BA4\u53D6\u6D88 \xB7 n/Esc \u4FDD\u7559" : state.details ? "\u2191\u2193/PgUp/PgDn \u9605\u8BFB \xB7 Enter \u539F\u4F1A\u8BDD \xB7 d \u53D6\u6D88\u4EFB\u52A1 \xB7 Esc \u5217\u8868" : "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u8BE6\u60C5 \xB7 d \u53D6\u6D88\u4EFB\u52A1 \xB7 r \u5237\u65B0 \xB7 Esc \u8FD4\u56DE";
60877
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(OverlayShell, { title: `\u5B9A\u65F6\u4EFB\u52A1 \xB7 ${state.rows.length}`, footnote, children: [
60878
- state.error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Text, { wrap: "truncate", children: paintRow([styled(truncateDisplay(escapeContent(state.error), width), "fg")]) }),
60879
- lines.slice(0, Math.max(0, capacity - (state.error === void 0 ? 0 : 1))).map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Text, { wrap: "truncate", children: paintRow([styled(line5 || " ", "fg")]) }, index2))
60962
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(OverlayShell, { title: `\u5B9A\u65F6\u4EFB\u52A1 \xB7 ${state.rows.length}`, footnote, children: [
60963
+ state.error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Text, { wrap: "truncate", children: paintRow([styled(truncateDisplay(escapeContent(state.error), width), "fg")]) }),
60964
+ lines.slice(0, Math.max(0, capacity - (state.error === void 0 ? 0 : 1))).map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Text, { wrap: "truncate", children: paintRow([styled(line5 || " ", "fg")]) }, index2))
60880
60965
  ] });
60881
60966
  }
60882
60967
 
60883
60968
  // packages/tui/tui-render/src/tool-details-pane.tsx
60884
- var import_jsx_runtime31 = __toESM(require_jsx_runtime(), 1);
60969
+ var import_jsx_runtime32 = __toESM(require_jsx_runtime(), 1);
60885
60970
  var EMPTY_TOOL_DETAILS_PANE = Object.freeze({
60886
60971
  open: false,
60887
60972
  cards: [],
@@ -60918,21 +61003,21 @@ function ToolDetailsPane({ state, columns, maxRows, pageRows, locale }) {
60918
61003
  }
60919
61004
  lines.push(truncateDisplay(`${state.page + 1} \xB7 ${page.remainingLines} ${tuiCopy("remaining", locale)} \xB7 d ${tuiCopy("diagnostics", locale)} ${tuiCopy(state.diagnostics ? "on" : "off", locale)}`, columns));
60920
61005
  }
60921
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
60922
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Text, { wrap: "truncate", children: heading }),
60923
- lines.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Text, { wrap: "truncate", children: line5 }, index2)),
60924
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Text, { dimColor: true, wrap: "truncate", children: escapeContent(tuiCopy(state.detail ? "toolPageHint" : "toolListHint", locale)) })
61006
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Box_default, { flexDirection: "column", width: "100%", children: [
61007
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Text, { wrap: "truncate", children: heading }),
61008
+ lines.map((line5, index2) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Text, { wrap: "truncate", children: line5 }, index2)),
61009
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Text, { dimColor: true, wrap: "truncate", children: escapeContent(tuiCopy(state.detail ? "toolPageHint" : "toolListHint", locale)) })
60925
61010
  ] });
60926
61011
  }
60927
61012
 
60928
61013
  // packages/tui/tui-render/src/queue-chip.tsx
60929
- var import_jsx_runtime32 = __toESM(require_jsx_runtime(), 1);
61014
+ var import_jsx_runtime33 = __toESM(require_jsx_runtime(), 1);
60930
61015
  function queueChipText(count) {
60931
61016
  return count <= 0 ? void 0 : `\u5F85\u53D1 ${String(count)} \xB7 \u2191 \u53D6\u51FA`;
60932
61017
  }
60933
61018
  function QueueChip({ count }) {
60934
61019
  const text4 = queueChipText(count);
60935
- return text4 === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Text, { children: paintRow([styled(escapeContent(text4), "fg")]) });
61020
+ return text4 === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Text, { children: paintRow([styled(escapeContent(text4), "fg")]) });
60936
61021
  }
60937
61022
 
60938
61023
  // packages/tui/tui-render/src/loop.tsx
@@ -61386,14 +61471,33 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
61386
61471
  });
61387
61472
  }
61388
61473
  if (settings.open) {
61474
+ if (settings.busy === true) return { kind: "none" };
61475
+ if (settings.searching === true) {
61476
+ const query = settings.filter ?? "";
61477
+ if (keyInfo.escape) return holdComposer(state, { kind: "settings-search", query: "", active: false });
61478
+ if (keyInfo.return) return holdComposer(state, { kind: "settings-search", query, active: false });
61479
+ if (keyInfo.tab) return holdComposer(state, { kind: "settings-group", delta: keyInfo.shift ? -1 : 1 });
61480
+ if (keyInfo.downArrow || keyInfo.upArrow) return holdComposer(state, { kind: "settings-move", delta: keyInfo.downArrow ? 1 : -1 });
61481
+ if (keyInfo.pageDown || keyInfo.pageUp) return holdComposer(state, { kind: "settings-move", delta: keyInfo.pageDown ? 5 : -5 });
61482
+ if (keyInfo.home || keyInfo.end) return holdComposer(state, { kind: "settings-move", delta: keyInfo.end ? 1e4 : -1e4 });
61483
+ if (keyInfo.backspace || keyInfo.delete) return holdComposer(state, { kind: "settings-search", query: Array.from(query).slice(0, -1).join(""), active: true });
61484
+ if (!keyInfo.ctrl && !keyInfo.meta && !keyInfo.upArrow && !keyInfo.downArrow && key !== "") return holdComposer(state, { kind: "settings-search", query: query + key, active: true });
61485
+ return { kind: "none" };
61486
+ }
61487
+ if (key === "/" && settings.onboarding !== true) return holdComposer(state, { kind: "settings-search", query: "", active: true });
61488
+ if (keyInfo.leftArrow || keyInfo.backspace) return holdComposer(state, { kind: "settings-escape" });
61389
61489
  if (keyInfo.tab) return holdComposer(state, { kind: "settings-group", delta: keyInfo.shift ? -1 : 1 });
61390
61490
  if (keyInfo.escape) {
61391
61491
  return holdComposer(state, { kind: "settings-escape" });
61392
61492
  }
61393
- if (keyInfo.return) {
61493
+ if (keyInfo.return || keyInfo.rightArrow || key === "i") {
61494
+ if (key !== "i" && settings.navigable === true) return holdComposer(state, { kind: "settings-edit" });
61495
+ if (keyInfo.rightArrow) return { kind: "none" };
61496
+ if (settings.editable === false) return { kind: "none" };
61497
+ if (keyInfo.return && settings.toggleable === true) return holdComposer(state, { kind: "settings-toggle" });
61394
61498
  return {
61395
61499
  kind: "dispatch",
61396
- action: { kind: "settings-edit" },
61500
+ action: { kind: key === "i" ? "settings-edit-json" : "settings-edit" },
61397
61501
  text: settings.editValue ?? "",
61398
61502
  commandQuery: void 0,
61399
61503
  prefixG: false,
@@ -62212,11 +62316,17 @@ function TuiLoop({
62212
62316
  askUserDetailsRef.current = askUserDetails;
62213
62317
  const viewportSequenceRef = (0, import_react47.useRef)(0);
62214
62318
  const [viewportCommand, setViewportCommand] = (0, import_react47.useState)();
62319
+ const viewportCommandRef = (0, import_react47.useRef)(void 0);
62320
+ const onViewportCommandConsumed = (0, import_react47.useCallback)((sequence) => {
62321
+ setViewportCommand((current) => current?.sequence === sequence ? void 0 : current);
62322
+ }, []);
62215
62323
  const [topDividerLabel, setTopDividerLabel] = (0, import_react47.useState)();
62216
- const issueViewportCommand = (0, import_react47.useCallback)((command) => {
62324
+ const issueViewportCommand = (0, import_react47.useCallback)((command, inputAt = performance.now()) => {
62217
62325
  frameProbe?.beginMeasurement();
62218
62326
  viewportSequenceRef.current += 1;
62219
- setViewportCommand({ ...command, sequence: viewportSequenceRef.current });
62327
+ const next = { ...command, sequence: viewportSequenceRef.current, inputAt };
62328
+ if (viewportCommandRef.current === void 0) setViewportCommand(next);
62329
+ else viewportCommandRef.current(next);
62220
62330
  }, [frameProbe]);
62221
62331
  const brandRevealStartedRef = (0, import_react47.useRef)(false);
62222
62332
  const brandRevealStoppedRef = (0, import_react47.useRef)(false);
@@ -62505,6 +62615,7 @@ function TuiLoop({
62505
62615
  (0, import_react47.useEffect)(() => clearChord, []);
62506
62616
  (0, import_react47.useEffect)(() => {
62507
62617
  const listener = (delta) => {
62618
+ const inputAt = performance.now();
62508
62619
  frameMetrics?.recordInputEvent();
62509
62620
  syncPaneRef(approvalPaneRef, controller.getApprovalPane?.bind(controller));
62510
62621
  syncPaneRef(askUserPaneRef, controller.getAskUserPane?.bind(controller));
@@ -62571,7 +62682,7 @@ function TuiLoop({
62571
62682
  );
62572
62683
  return;
62573
62684
  }
62574
- issueViewportCommand({ kind: "scroll", delta });
62685
+ issueViewportCommand({ kind: "scroll", delta, source: "wheel" }, inputAt);
62575
62686
  };
62576
62687
  setMouseScrollListener(listener);
62577
62688
  setMouseRailListener((fraction) => {
@@ -62856,6 +62967,12 @@ function TuiLoop({
62856
62967
  open: settingsPaneRef.current.open,
62857
62968
  editing: settingsPaneRef.current.editing,
62858
62969
  onboarding: settingsPaneRef.current.onboarding,
62970
+ navigable: settingsPaneRef.current.rows[settingsPaneRef.current.selectedIndex]?.navigable,
62971
+ toggleable: canToggleSetting(settingsPaneRef.current.rows[settingsPaneRef.current.selectedIndex]),
62972
+ busy: settingsPaneRef.current.busy,
62973
+ editable: settingsPaneRef.current.rows[settingsPaneRef.current.selectedIndex]?.editable,
62974
+ searching: settingsPaneRef.current.searching,
62975
+ filter: settingsPaneRef.current.filter,
62859
62976
  editValue: settingsPaneRef.current.rows[settingsPaneRef.current.selectedIndex]?.editValue ?? settingsPaneRef.current.rows[settingsPaneRef.current.selectedIndex]?.value
62860
62977
  },
62861
62978
  controller.getSubmitOnEnter(),
@@ -62897,7 +63014,7 @@ function TuiLoop({
62897
63014
  }
62898
63015
  if (effect.kind === "dispatch") {
62899
63016
  const action = effect.action;
62900
- if (action.kind === "settings-edit" && settingsComposerRef.current === void 0) settingsComposerRef.current = current;
63017
+ if ((action.kind === "settings-edit" || action.kind === "settings-edit-json") && settingsComposerRef.current === void 0) settingsComposerRef.current = current;
62901
63018
  if (isSessionTransitionAction(action) && isSessionTransitionStatus(feedbackRef.current)) {
62902
63019
  } else if (action.kind === "timeline-scroll") {
62903
63020
  const maxOffset2 = Math.max(
@@ -63309,6 +63426,8 @@ function TuiLoop({
63309
63426
  scrollbar,
63310
63427
  brandFrameProbe,
63311
63428
  viewportCommand,
63429
+ viewportCommandRef,
63430
+ onViewportCommandConsumed,
63312
63431
  renderPolicy,
63313
63432
  frameMetrics,
63314
63433
  motionPaused: viewportMotionPaused,
@@ -63381,6 +63500,11 @@ function TuiLoop({
63381
63500
  content3 = (0, import_react47.createElement)(SettingsPane, {
63382
63501
  locale,
63383
63502
  rows: settingsPane.rows,
63503
+ ...settingsPane.breadcrumb === void 0 ? {} : { breadcrumb: settingsPane.breadcrumb },
63504
+ ...settingsPane.categories === void 0 ? {} : { categories: settingsPane.categories },
63505
+ ...settingsPane.activeCategory === void 0 ? {} : { activeCategory: settingsPane.activeCategory },
63506
+ ...settingsPane.filter === void 0 ? {} : { filter: settingsPane.filter },
63507
+ ...settingsPane.searching === void 0 ? {} : { searching: settingsPane.searching },
63384
63508
  selectedIndex: settingsPane.selectedIndex,
63385
63509
  editing: settingsPane.editing,
63386
63510
  maxRows: settingsMaxRows,
@@ -63530,7 +63654,12 @@ function TuiLoop({
63530
63654
  mentionMode: false,
63531
63655
  caretIndex: state.caretIndex,
63532
63656
  selectionAnchor: state.selectionAnchor,
63533
- secret: settingsPane.editing && (settingsPane.onboarding === true || settingsPane.rows[settingsPane.selectedIndex]?.namespace === "credentials")
63657
+ secret: settingsPane.editing && (settingsPane.onboarding === true || settingsPane.rows[settingsPane.selectedIndex]?.namespace === "credentials"),
63658
+ ...settingsPane.editing ? {
63659
+ actionHint: locale === "en-US" ? "Setting value \xB7 Enter save \xB7 Esc cancel" : "\u8BBE\u7F6E\u503C \xB7 Enter \u4FDD\u5B58 \xB7 Esc \u53D6\u6D88",
63660
+ modelChip: "",
63661
+ modeChip: ""
63662
+ } : {}
63534
63663
  });
63535
63664
  } else if (toolDetailsPane.open) {
63536
63665
  inputSlot = void 0;
@@ -66755,8 +66884,8 @@ function brandNumber(value) {
66755
66884
 
66756
66885
  // packages/llm/llm/src/message.ts
66757
66886
  var CONTEXT_SUMMARY_MAX_CHARS = 120;
66758
- function boundContextSummary(summary) {
66759
- return summary.length <= CONTEXT_SUMMARY_MAX_CHARS ? summary : `${summary.slice(0, CONTEXT_SUMMARY_MAX_CHARS - 1)}\u2026`;
66887
+ function boundContextSummary(summary2) {
66888
+ return summary2.length <= CONTEXT_SUMMARY_MAX_CHARS ? summary2 : `${summary2.slice(0, CONTEXT_SUMMARY_MAX_CHARS - 1)}\u2026`;
66760
66889
  }
66761
66890
  function freezeMessage(message) {
66762
66891
  return deepFreeze(structuredClone(message));
@@ -68025,16 +68154,16 @@ var BlockAssembler = class {
68025
68154
  // packages/llm/llm/src/assistant-stream.ts
68026
68155
  function lastAssistantStreamChunk(stream, type) {
68027
68156
  for (let index2 = stream.length - 1; index2 >= 0; index2 -= 1) {
68028
- const record2 = stream[index2];
68029
- if (record2.type === "chunk" && record2.chunk.type === type) return record2.chunk;
68157
+ const record3 = stream[index2];
68158
+ if (record3.type === "chunk" && record3.chunk.type === type) return record3.chunk;
68030
68159
  }
68031
68160
  return void 0;
68032
68161
  }
68033
68162
  function joinAssistantStreamText(stream) {
68034
68163
  const parts = [];
68035
- for (const record2 of stream) {
68036
- if (record2.type === "text-chunks") parts.push(record2.texts.join(""));
68037
- else if (record2.type === "chunk" && record2.chunk.type === "text-delta") parts.push(record2.chunk.text);
68164
+ for (const record3 of stream) {
68165
+ if (record3.type === "text-chunks") parts.push(record3.texts.join(""));
68166
+ else if (record3.type === "chunk" && record3.chunk.type === "text-delta") parts.push(record3.chunk.text);
68038
68167
  }
68039
68168
  return parts.join("");
68040
68169
  }
@@ -68956,7 +69085,7 @@ function latestAssistantCopyTarget(history) {
68956
69085
  function reasoningDurationsFromStream(stream) {
68957
69086
  if (!Array.isArray(stream)) return [];
68958
69087
  const records = stream;
68959
- const startOf = (record2) => record2.time0 ?? record2.time;
69088
+ const startOf = (record3) => record3.time0 ?? record3.time;
68960
69089
  const durations = [];
68961
69090
  let blockIndex;
68962
69091
  let blockStart = 0;
@@ -68966,20 +69095,20 @@ function reasoningDurationsFromStream(stream) {
68966
69095
  durations.push(Math.max(0, end - blockStart));
68967
69096
  blockIndex = void 0;
68968
69097
  };
68969
- for (const record2 of records) {
68970
- const start = startOf(record2);
69098
+ for (const record3 of records) {
69099
+ const start = startOf(record3);
68971
69100
  if (typeof start !== "number") continue;
68972
- if (record2.type === "reasoning-chunks") {
68973
- const end = start + (record2.dt ?? []).reduce((sum, gap) => sum + gap, 0);
68974
- if (blockIndex !== void 0 && record2.index === blockIndex) {
69101
+ if (record3.type === "reasoning-chunks") {
69102
+ const end = start + (record3.dt ?? []).reduce((sum, gap) => sum + gap, 0);
69103
+ if (blockIndex !== void 0 && record3.index === blockIndex) {
68975
69104
  blockEnd = end;
68976
69105
  continue;
68977
69106
  }
68978
69107
  close(start);
68979
- blockIndex = record2.index ?? -1;
69108
+ blockIndex = record3.index ?? -1;
68980
69109
  blockStart = start;
68981
69110
  blockEnd = end;
68982
- } else if (record2.type !== "chunk") {
69111
+ } else if (record3.type !== "chunk") {
68983
69112
  close(start);
68984
69113
  }
68985
69114
  }
@@ -69350,7 +69479,7 @@ ${formattedError}` });
69350
69479
  replaceStep(assembler.blocks());
69351
69480
  return;
69352
69481
  case "end":
69353
- if (frame.outcome.kind !== "committed" && !stepCommitted) replaceStep([]);
69482
+ if (!stepCommitted) replaceStep([]);
69354
69483
  assembler = void 0;
69355
69484
  return;
69356
69485
  }
@@ -69378,13 +69507,13 @@ ${formattedError}` });
69378
69507
  }
69379
69508
 
69380
69509
  // packages/tui/tui-render/src/todo-hud.tsx
69381
- var import_jsx_runtime33 = __toESM(require_jsx_runtime(), 1);
69510
+ var import_jsx_runtime34 = __toESM(require_jsx_runtime(), 1);
69382
69511
 
69383
69512
  // packages/tui/tui-render/src/jobs-hud.tsx
69384
- var import_jsx_runtime34 = __toESM(require_jsx_runtime(), 1);
69513
+ var import_jsx_runtime35 = __toESM(require_jsx_runtime(), 1);
69385
69514
 
69386
69515
  // packages/tui/tui-render/src/workflow-hud.tsx
69387
- var import_jsx_runtime35 = __toESM(require_jsx_runtime(), 1);
69516
+ var import_jsx_runtime36 = __toESM(require_jsx_runtime(), 1);
69388
69517
 
69389
69518
  // packages/tui/tui-render/src/interaction-state.ts
69390
69519
  function reduceInteraction(state, event) {
@@ -69782,15 +69911,15 @@ function userErrorReason(error51) {
69782
69911
  }
69783
69912
 
69784
69913
  // packages/tui/tui/src/workspace-changes.ts
69785
- function workspaceChangesCardFromSummary(seq, summary) {
69786
- if (summary === void 0 || summary.files.length === 0) return void 0;
69914
+ function workspaceChangesCardFromSummary(seq, summary2) {
69915
+ if (summary2 === void 0 || summary2.files.length === 0) return void 0;
69787
69916
  return {
69788
69917
  seq,
69789
- turn: summary.turn,
69790
- files: summary.files.map(toFileView),
69791
- total: summary.total,
69792
- added: summary.added,
69793
- deleted: summary.deleted
69918
+ turn: summary2.turn,
69919
+ files: summary2.files.map(toFileView),
69920
+ total: summary2.total,
69921
+ added: summary2.added,
69922
+ deleted: summary2.deleted
69794
69923
  };
69795
69924
  }
69796
69925
  function toFileView(file2) {
@@ -88784,41 +88913,41 @@ function validateSessionHeader(id, input) {
88784
88913
  if (input === null || typeof input !== "object" || Array.isArray(input)) {
88785
88914
  throw new Error("session header is not a plain JSON record");
88786
88915
  }
88787
- const record2 = input;
88788
- if (Object.hasOwn(record2, "seedLength")) {
88916
+ const record3 = input;
88917
+ if (Object.hasOwn(record3, "seedLength")) {
88789
88918
  throw new Error('session header has invalid field "seedLength"');
88790
88919
  }
88791
- if (record2.version !== SESSION_FORMAT_VERSION) {
88792
- throw new Error(`session header version must be ${SESSION_FORMAT_VERSION}, got ${String(record2.version)}`);
88920
+ if (record3.version !== SESSION_FORMAT_VERSION) {
88921
+ throw new Error(`session header version must be ${SESSION_FORMAT_VERSION}, got ${String(record3.version)}`);
88793
88922
  }
88794
- if (record2.id !== id) {
88795
- throw new Error(`session header id "${String(record2.id)}" does not match session id "${id}"`);
88923
+ if (record3.id !== id) {
88924
+ throw new Error(`session header id "${String(record3.id)}" does not match session id "${id}"`);
88796
88925
  }
88797
- if (typeof record2.createdAt !== "number" || !Number.isSafeInteger(record2.createdAt) || record2.createdAt < 0) {
88926
+ if (typeof record3.createdAt !== "number" || !Number.isSafeInteger(record3.createdAt) || record3.createdAt < 0) {
88798
88927
  throw new Error("session header createdAt must be a non-negative safe integer");
88799
88928
  }
88800
- if (record2.cwd !== void 0) {
88801
- if (typeof record2.cwd !== "string") throw new Error("session header cwd must be a string");
88802
- if (!isAbsolute4(record2.cwd)) {
88803
- throw new Error(`session header cwd must be an absolute path, got "${record2.cwd}"`);
88929
+ if (record3.cwd !== void 0) {
88930
+ if (typeof record3.cwd !== "string") throw new Error("session header cwd must be a string");
88931
+ if (!isAbsolute4(record3.cwd)) {
88932
+ throw new Error(`session header cwd must be an absolute path, got "${record3.cwd}"`);
88804
88933
  }
88805
88934
  }
88806
- if (record2.parentSession !== void 0 && typeof record2.parentSession !== "string") {
88935
+ if (record3.parentSession !== void 0 && typeof record3.parentSession !== "string") {
88807
88936
  throw new Error("session header parentSession must be a string");
88808
88937
  }
88809
- if (typeof record2.isSeeded !== "boolean") {
88938
+ if (typeof record3.isSeeded !== "boolean") {
88810
88939
  throw new Error("session header isSeeded must be a boolean");
88811
88940
  }
88812
- if (record2.origin !== void 0 && record2.origin !== "subagent") {
88941
+ if (record3.origin !== void 0 && record3.origin !== "subagent") {
88813
88942
  throw new Error('session header origin must be "subagent"');
88814
88943
  }
88815
- if (record2.delegationDepth !== void 0 && (typeof record2.delegationDepth !== "number" || !Number.isSafeInteger(record2.delegationDepth) || record2.delegationDepth < 0)) {
88944
+ if (record3.delegationDepth !== void 0 && (typeof record3.delegationDepth !== "number" || !Number.isSafeInteger(record3.delegationDepth) || record3.delegationDepth < 0)) {
88816
88945
  throw new Error("session header delegationDepth must be a non-negative safe integer");
88817
88946
  }
88818
- if (record2.agentPreset !== void 0 && typeof record2.agentPreset !== "string") {
88947
+ if (record3.agentPreset !== void 0 && typeof record3.agentPreset !== "string") {
88819
88948
  throw new Error("session header agentPreset must be a string");
88820
88949
  }
88821
- return deepFreeze(record2);
88950
+ return deepFreeze(record3);
88822
88951
  }
88823
88952
  function validateRestoredSessionHeader(id, input) {
88824
88953
  if (input !== null && typeof input === "object" && !Array.isArray(input)) {
@@ -88875,9 +89004,9 @@ function assertSessionEventEnvelope(value, index2) {
88875
89004
  }
88876
89005
  function assertCurrentLlmShape(event, index2) {
88877
89006
  const data = event["data"];
88878
- const record2 = typeof data === "object" && data !== null ? data : void 0;
89007
+ const record3 = typeof data === "object" && data !== null ? data : void 0;
88879
89008
  if (event["type"] === "request/header") {
88880
- const headerRecord = record2?.["header"];
89009
+ const headerRecord = record3?.["header"];
88881
89010
  const config2 = headerRecord["config"];
88882
89011
  if (!hasProviderModel(config2)) throw new Error(`seed request/header at index ${index2} lacks provider/model`);
88883
89012
  const configRecord = config2;
@@ -88886,23 +89015,23 @@ function assertCurrentLlmShape(event, index2) {
88886
89015
  throw new Error(`seed request/header at index ${index2} has an invalid reasoningEffort`);
88887
89016
  }
88888
89017
  assertAdapterDefaults(headerRecord["adapterDefaults"], configRecord, index2);
88889
- const reason = record2?.["reason"];
89018
+ const reason = record3?.["reason"];
88890
89019
  if (reason !== "initial" && reason !== "resume" && reason !== "change" && reason !== "series") {
88891
89020
  throw new Error(`seed request/header at index ${index2} has an invalid reason`);
88892
89021
  }
88893
- if (record2?.["startsSeries"] !== void 0 && record2["startsSeries"] !== true) {
89022
+ if (record3?.["startsSeries"] !== void 0 && record3["startsSeries"] !== true) {
88894
89023
  throw new Error(`seed request/header at index ${index2} has an invalid startsSeries marker`);
88895
89024
  }
88896
89025
  }
88897
89026
  const type = event["type"];
88898
89027
  if (type === "assistant/attempt") {
88899
- assertAssistantSettlementShape(record2, type, index2);
89028
+ assertAssistantSettlementShape(record3, type, index2);
88900
89029
  return;
88901
89030
  }
88902
89031
  if (!isMessageEventType(type)) return;
88903
89032
  assertMessageEventShape(event, `seed ${type} at index ${index2}`);
88904
89033
  if (type === "assistant/message") {
88905
- assertAssistantSettlementShape(record2, type, index2);
89034
+ assertAssistantSettlementShape(record3, type, index2);
88906
89035
  }
88907
89036
  }
88908
89037
  function assertAssistantSettlementShape(data, type, index2) {
@@ -88937,8 +89066,8 @@ function assertMessageEventShape(event, subject) {
88937
89066
  const type = event["type"];
88938
89067
  if (!isMessageEventType(type)) return;
88939
89068
  const data = event["data"];
88940
- const record2 = typeof data === "object" && data !== null ? data : void 0;
88941
- const message = type === "user/message" ? record2 : record2?.["message"];
89069
+ const record3 = typeof data === "object" && data !== null ? data : void 0;
89070
+ const message = type === "user/message" ? record3 : record3?.["message"];
88942
89071
  if (typeof message !== "object" || message === null || typeof message["id"] !== "string" || message["id"] === "") {
88943
89072
  throw new Error(`${subject} lacks an identified message`);
88944
89073
  }
@@ -89269,16 +89398,16 @@ var Session = class _Session {
89269
89398
  throw new Error(`plugin record "${type}" carries non-JSON-serializable data`);
89270
89399
  }
89271
89400
  const entry = this.publicationEntry();
89272
- const record2 = deepFreeze({
89401
+ const record3 = deepFreeze({
89273
89402
  type,
89274
89403
  seq: SessionSeq(this.log.length),
89275
89404
  time: Date.now(),
89276
89405
  data: dataSnapshot,
89277
89406
  ignorable: true
89278
89407
  });
89279
- assertPluginRecordEvent(record2);
89280
- this.commit(record2, entry);
89281
- return record2.seq;
89408
+ assertPluginRecordEvent(record3);
89409
+ this.commit(record3, entry);
89410
+ return record3.seq;
89282
89411
  }
89283
89412
  /**
89284
89413
  * Read the store attachment for one append, refusing an append that
@@ -89589,13 +89718,13 @@ function settlementSummary(childId, stopReason, continuable) {
89589
89718
  }
89590
89719
  }
89591
89720
  function createSettlementMessage(childId, terminal, continuable = true) {
89592
- const summary = settlementSummary(childId, terminal.stopReason, continuable);
89721
+ const summary2 = settlementSummary(childId, terminal.stopReason, continuable);
89593
89722
  const closingText = terminal.output.flatMap(
89594
89723
  (block) => block.type === "text" && block.text.length > 0 ? [block] : []
89595
89724
  );
89596
89725
  return createUserMessage({
89597
89726
  content: [
89598
- { type: "text", text: summary },
89727
+ { type: "text", text: summary2 },
89599
89728
  ...closingText.length === 0 ? [{ type: "text", text: "It left no closing message." }] : [{ type: "text", text: "Its closing message:" }, ...closingText],
89600
89729
  ...terminal.structured !== void 0 ? [{ type: "text", text: `Structured result: ${JSON.stringify(terminal.structured)}` }] : [],
89601
89730
  ...terminal.diagnostic !== void 0 ? [{ type: "text", text: terminal.diagnostic }] : []
@@ -89603,7 +89732,7 @@ function createSettlementMessage(childId, terminal, continuable = true) {
89603
89732
  source: {
89604
89733
  kind: "subagent-settled",
89605
89734
  form: "notice",
89606
- summary: boundContextSummary(summary),
89735
+ summary: boundContextSummary(summary2),
89607
89736
  senderSessionId: childId
89608
89737
  }
89609
89738
  });
@@ -96365,9 +96494,9 @@ function decodeScheduleRecord(value) {
96365
96494
  if (isRecord4(value) && value["kind"] === "daily") return decodeDailyRecord(value);
96366
96495
  if (isRecord4(value) && value["kind"] === "weekly") return decodeWeeklyRecord(value);
96367
96496
  if (isRecord4(value) && value["kind"] === "cron") return decodeCronRecord(value);
96368
- const record2 = decodeLegacyScheduleRecord(value);
96369
- if (record2.title === void 0) throw new ScheduleLogError(REQUIRED_TITLE_MESSAGE);
96370
- return record2;
96497
+ const record3 = decodeLegacyScheduleRecord(value);
96498
+ if (record3.title === void 0) throw new ScheduleLogError(REQUIRED_TITLE_MESSAGE);
96499
+ return record3;
96371
96500
  }
96372
96501
  function decodeLegacyScheduleRecord(value) {
96373
96502
  if (!isRecord4(value)) throw new ScheduleLogError("schedule record must be an object");
@@ -96429,9 +96558,9 @@ function decodeScheduleChange(value) {
96429
96558
  throw new ScheduleLogError("schedule/change operation must be create, delete, or dispatch");
96430
96559
  }
96431
96560
  }
96432
- function resolveEveryOccurrence(record2, acceptedAt) {
96433
- const target = Date.parse(record2.scheduledAt);
96434
- const interval = record2.everySeconds * 1e3;
96561
+ function resolveEveryOccurrence(record3, acceptedAt) {
96562
+ const target = Date.parse(record3.scheduledAt);
96563
+ const interval = record3.everySeconds * 1e3;
96435
96564
  if (!Number.isSafeInteger(acceptedAt) || acceptedAt < MIN_FOUR_DIGIT_YEAR_MS || acceptedAt > MAX_FOUR_DIGIT_YEAR_MS) {
96436
96565
  throw new ScheduleLogError("every acceptedAt must be a representable four-digit-year instant");
96437
96566
  }
@@ -96497,28 +96626,28 @@ function acceptedDecision(selector, acceptedAt) {
96497
96626
  function nextDailyTarget(time3, timeZone, now, afterDate) {
96498
96627
  return nextMatchingTarget(time3, timeZone, now, EVERY_DATE, afterDate);
96499
96628
  }
96500
- function resolveDailyOccurrence(record2, acceptedAt) {
96629
+ function resolveDailyOccurrence(record3, acceptedAt) {
96501
96630
  const decision = acceptedDecision("daily", acceptedAt);
96502
- const savedTarget = Date.parse(record2.scheduledAt);
96631
+ const savedTarget = Date.parse(record3.scheduledAt);
96503
96632
  if (decision < savedTarget) throw new ScheduleLogError("daily dispatch cannot precede the active scheduledAt");
96504
- const time3 = dailyTime(record2.time);
96505
- const occurrence = latestDueOccurrence(record2.timeZone, EVERY_DATE, time3, decision, savedTarget);
96633
+ const time3 = dailyTime(record3.time);
96634
+ const occurrence = latestDueOccurrence(record3.timeZone, EVERY_DATE, time3, decision, savedTarget);
96506
96635
  const occurrenceAt = new Date(occurrence).toISOString();
96507
- const nextScheduledAt = nextDailyTarget(time3, record2.timeZone, decision, localDate(occurrence, record2.timeZone));
96636
+ const nextScheduledAt = nextDailyTarget(time3, record3.timeZone, decision, localDate(occurrence, record3.timeZone));
96508
96637
  return Object.freeze(nextScheduledAt === void 0 ? { occurrenceAt } : { occurrenceAt, nextScheduledAt });
96509
96638
  }
96510
96639
  function nextWeeklyTarget(time3, timeZone, weekdays, now, afterDate) {
96511
96640
  return nextMatchingTarget(time3, timeZone, now, weekdaySet(weekdays), afterDate);
96512
96641
  }
96513
- function resolveWeeklyOccurrence(record2, acceptedAt) {
96642
+ function resolveWeeklyOccurrence(record3, acceptedAt) {
96514
96643
  const decision = acceptedDecision("weekly", acceptedAt);
96515
- const savedTarget = Date.parse(record2.scheduledAt);
96644
+ const savedTarget = Date.parse(record3.scheduledAt);
96516
96645
  if (decision < savedTarget) throw new ScheduleLogError("weekly dispatch cannot precede the active scheduledAt");
96517
- const time3 = weeklyTime(record2.time);
96518
- const weekdays = normalizeWeekdays(record2.weekdays);
96519
- const occurrence = latestDueOccurrence(record2.timeZone, weekdaySet(weekdays), time3, decision, savedTarget);
96646
+ const time3 = weeklyTime(record3.time);
96647
+ const weekdays = normalizeWeekdays(record3.weekdays);
96648
+ const occurrence = latestDueOccurrence(record3.timeZone, weekdaySet(weekdays), time3, decision, savedTarget);
96520
96649
  const occurrenceAt = new Date(occurrence).toISOString();
96521
- const nextScheduledAt = nextWeeklyTarget(time3, record2.timeZone, weekdays, decision, localDate(occurrence, record2.timeZone));
96650
+ const nextScheduledAt = nextWeeklyTarget(time3, record3.timeZone, weekdays, decision, localDate(occurrence, record3.timeZone));
96522
96651
  return Object.freeze(nextScheduledAt === void 0 ? { occurrenceAt } : { occurrenceAt, nextScheduledAt });
96523
96652
  }
96524
96653
  function cronDateMatch(parsed) {
@@ -96602,43 +96731,43 @@ function latestCronOccurrence(parsed, timeZone, decision, savedTarget) {
96602
96731
  }
96603
96732
  return savedTarget;
96604
96733
  }
96605
- function resolveCronOccurrence(record2, acceptedAt) {
96734
+ function resolveCronOccurrence(record3, acceptedAt) {
96606
96735
  const decision = acceptedDecision("cron", acceptedAt);
96607
- const savedTarget = Date.parse(record2.scheduledAt);
96736
+ const savedTarget = Date.parse(record3.scheduledAt);
96608
96737
  if (decision < savedTarget) throw new ScheduleLogError("cron dispatch cannot precede the active scheduledAt");
96609
- const parsed = parseCronExpression(record2.expression);
96610
- const occurrence = latestCronOccurrence(parsed, record2.timeZone, decision, savedTarget);
96738
+ const parsed = parseCronExpression(record3.expression);
96739
+ const occurrence = latestCronOccurrence(parsed, record3.timeZone, decision, savedTarget);
96611
96740
  const occurrenceAt = new Date(occurrence).toISOString();
96612
- const nextScheduledAt = nextCronTarget(parsed, record2.timeZone, decision);
96741
+ const nextScheduledAt = nextCronTarget(parsed, record3.timeZone, decision);
96613
96742
  return Object.freeze(nextScheduledAt === void 0 ? { occurrenceAt } : { occurrenceAt, nextScheduledAt });
96614
96743
  }
96615
- function isRecurringScheduleRecord(record2) {
96616
- return record2.kind === "every" || record2.kind === "daily" || record2.kind === "weekly" || record2.kind === "cron";
96744
+ function isRecurringScheduleRecord(record3) {
96745
+ return record3.kind === "every" || record3.kind === "daily" || record3.kind === "weekly" || record3.kind === "cron";
96617
96746
  }
96618
- function resolveRecurringOccurrence(record2, acceptedAt) {
96619
- switch (record2.kind) {
96747
+ function resolveRecurringOccurrence(record3, acceptedAt) {
96748
+ switch (record3.kind) {
96620
96749
  case "every":
96621
- return resolveEveryOccurrence(record2, acceptedAt);
96750
+ return resolveEveryOccurrence(record3, acceptedAt);
96622
96751
  case "daily":
96623
- return resolveDailyOccurrence(record2, acceptedAt);
96752
+ return resolveDailyOccurrence(record3, acceptedAt);
96624
96753
  case "weekly":
96625
- return resolveWeeklyOccurrence(record2, acceptedAt);
96754
+ return resolveWeeklyOccurrence(record3, acceptedAt);
96626
96755
  case "cron":
96627
- return resolveCronOccurrence(record2, acceptedAt);
96756
+ return resolveCronOccurrence(record3, acceptedAt);
96628
96757
  }
96629
96758
  }
96630
- function dispatchedRecord(record2, change) {
96759
+ function dispatchedRecord(record3, change) {
96631
96760
  const hasAcceptedAt = "acceptedAt" in change;
96632
- if (record2.kind !== "every") {
96761
+ if (record3.kind !== "every") {
96633
96762
  if (hasAcceptedAt) throw new ScheduleLogError("one-shot dispatch must not contain acceptedAt");
96634
96763
  return void 0;
96635
96764
  }
96636
96765
  if (!hasAcceptedAt) throw new ScheduleLogError("every dispatch must contain acceptedAt");
96637
- const occurrence = resolveEveryOccurrence(record2, Date.parse(change.acceptedAt));
96638
- return occurrence.nextScheduledAt === void 0 ? void 0 : Object.freeze({ ...record2, scheduledAt: occurrence.nextScheduledAt });
96766
+ const occurrence = resolveEveryOccurrence(record3, Date.parse(change.acceptedAt));
96767
+ return occurrence.nextScheduledAt === void 0 ? void 0 : Object.freeze({ ...record3, scheduledAt: occurrence.nextScheduledAt });
96639
96768
  }
96640
96769
  function applyScheduleChanges(folded, changes) {
96641
- const active = new Map(folded.active.map((record2) => [record2.id, record2]));
96770
+ const active = new Map(folded.active.map((record3) => [record3.id, record3]));
96642
96771
  const seen = new Set(folded.seenIds);
96643
96772
  for (const change of changes) {
96644
96773
  switch (change.operation) {
@@ -96655,11 +96784,11 @@ function applyScheduleChanges(folded, changes) {
96655
96784
  }
96656
96785
  break;
96657
96786
  case "dispatch": {
96658
- const record2 = active.get(change.id);
96659
- if (record2 === void 0) {
96787
+ const record3 = active.get(change.id);
96788
+ if (record3 === void 0) {
96660
96789
  throw new ScheduleLogError(`schedule dispatch targets inactive id ${JSON.stringify(change.id)}`);
96661
96790
  }
96662
- const next = dispatchedRecord(record2, change);
96791
+ const next = dispatchedRecord(record3, change);
96663
96792
  if (next === void 0) active.delete(change.id);
96664
96793
  else active.set(change.id, next);
96665
96794
  break;
@@ -97073,20 +97202,20 @@ function parseCronInput(cron) {
97073
97202
  };
97074
97203
  }
97075
97204
  var SCHEDULED_MESSAGE_FRAMING = "This is a scheduled message from the user";
97076
- function renderReminderFraming(record2) {
97205
+ function renderReminderFraming(record3) {
97077
97206
  return [
97078
97207
  "[SCHEDULE REMINDER]",
97079
97208
  SCHEDULED_MESSAGE_FRAMING,
97080
- `schedule_id_json: ${JSON.stringify(record2.id)}`,
97081
- `occurrence_at: ${record2.scheduledAt}`,
97082
- `reminder_prompt_json: ${JSON.stringify(record2.prompt)}`
97209
+ `schedule_id_json: ${JSON.stringify(record3.id)}`,
97210
+ `occurrence_at: ${record3.scheduledAt}`,
97211
+ `reminder_prompt_json: ${JSON.stringify(record3.prompt)}`
97083
97212
  ].join("\n");
97084
97213
  }
97085
97214
  function renderRecurringReminderBatchFraming(reminders) {
97086
- const payload = reminders.map(({ record: record2, occurrenceAt }) => ({
97087
- schedule_id: record2.id,
97215
+ const payload = reminders.map(({ record: record3, occurrenceAt }) => ({
97216
+ schedule_id: record3.id,
97088
97217
  occurrence_at: occurrenceAt,
97089
- reminder_prompt: record2.prompt
97218
+ reminder_prompt: record3.prompt
97090
97219
  }));
97091
97220
  return [
97092
97221
  "[SCHEDULE REMINDER BATCH]",
@@ -97107,7 +97236,7 @@ function appendDelivery(task, receipt, bounds) {
97107
97236
  const history = deliveryHistoryOf(task);
97108
97237
  const appended = [...history.records, { ...receipt, prompt: task.record.prompt }];
97109
97238
  const floor = Date.parse(receipt.deliveredAt) - bounds.days * DAY_MS;
97110
- const retained = appended.filter((record2) => Date.parse(record2.deliveredAt) >= floor).slice(-bounds.records);
97239
+ const retained = appended.filter((record3) => Date.parse(record3.deliveredAt) >= floor).slice(-bounds.records);
97111
97240
  return {
97112
97241
  lastDelivery: receipt,
97113
97242
  deliveryHistory: {
@@ -97119,7 +97248,7 @@ function appendDelivery(task, receipt, bounds) {
97119
97248
  }
97120
97249
  function deliveryHistoryPage(task, request, retention) {
97121
97250
  const history = deliveryHistoryOf(task);
97122
- const end = request.before === void 0 ? history.records.length : history.records.findIndex((record2) => record2.messageId === request.before);
97251
+ const end = request.before === void 0 ? history.records.length : history.records.findIndex((record3) => record3.messageId === request.before);
97123
97252
  if (end === -1) return { id: request.id, code: "delivery_cursor_not_found" };
97124
97253
  const start = Math.max(0, end - request.limit);
97125
97254
  const records = history.records.slice(start, end).reverse().map(({ prompt, ...receipt }) => ({
@@ -97359,7 +97488,7 @@ var deliveryHistorySchema = external_exports.object({
97359
97488
  records: external_exports.array(deliveryReceiptSchema.extend({ prompt: external_exports.string().optional() }).strict()),
97360
97489
  earlierRecordsUnavailable: external_exports.boolean(),
97361
97490
  earlierRecordsPruned: external_exports.boolean().optional()
97362
- }).strict().refine((history) => new Set(history.records.map((record2) => record2.messageId)).size === history.records.length, {
97491
+ }).strict().refine((history) => new Set(history.records.map((record3) => record3.messageId)).size === history.records.length, {
97363
97492
  message: "Delivery history message identities must be unique within a task"
97364
97493
  });
97365
97494
  var scheduleTaskSchema = external_exports.object({
@@ -97416,8 +97545,8 @@ function schedulePrompt(prompt) {
97416
97545
  }
97417
97546
  return prompt.trim();
97418
97547
  }
97419
- function retainedTitle(record2) {
97420
- return decodeStoredTitle(record2.title);
97548
+ function retainedTitle(record3) {
97549
+ return decodeStoredTitle(record3.title);
97421
97550
  }
97422
97551
  function withContent(current, title, prompt) {
97423
97552
  return title === current.title && prompt === current.prompt ? current : Object.freeze({ ...current, title, prompt });
@@ -97477,8 +97606,8 @@ function resolveScheduleUpdate(current, expected, change, now, content3 = {}) {
97477
97606
  const retained = retainedTitle(current);
97478
97607
  const title = content3.title === void 0 ? retained : scheduleTitle(content3.title);
97479
97608
  const prompt = content3.prompt === void 0 ? current.prompt : schedulePrompt(content3.prompt);
97480
- const record2 = changedRecord(current, title, prompt, change, now);
97481
- return { id: current.id, updated: record2 !== current, record: record2 };
97609
+ const record3 = changedRecord(current, title, prompt, change, now);
97610
+ return { id: current.id, updated: record3 !== current, record: record3 };
97482
97611
  } catch (error51) {
97483
97612
  if (!(error51 instanceof ScheduleInputError)) throw error51;
97484
97613
  return { code: error51.code, message: error51.message };
@@ -97570,7 +97699,7 @@ var ScheduleService = class extends (_b2 = TypertRemoteService) {
97570
97699
  if (active.length === 0) return rest;
97571
97700
  const own3 = {
97572
97701
  kind: "schedule",
97573
- items: active.map((record2) => ({ id: record2.id, label: record2.title }))
97702
+ items: active.map((record3) => ({ id: record3.id, label: record3.title }))
97574
97703
  };
97575
97704
  return [own3, ...rest];
97576
97705
  });
@@ -97608,16 +97737,16 @@ var ScheduleService = class extends (_b2 = TypertRemoteService) {
97608
97737
  const title = scheduleTitle(request.title);
97609
97738
  const id = ScheduleId(`schedule-${randomUUID5()}`);
97610
97739
  const now = Date.now();
97611
- let record2;
97740
+ let record3;
97612
97741
  if (request.at !== void 0) {
97613
- record2 = createAtScheduleRecord(id, request.prompt, request.at, now, title);
97742
+ record3 = createAtScheduleRecord(id, request.prompt, request.at, now, title);
97614
97743
  } else if (request.after_seconds !== void 0) {
97615
- record2 = createAfterScheduleRecord(id, request.prompt, request.after_seconds, now, title);
97744
+ record3 = createAfterScheduleRecord(id, request.prompt, request.after_seconds, now, title);
97616
97745
  } else if (request.every_seconds !== void 0) {
97617
- record2 = createEveryScheduleRecord(id, request.prompt, request.every_seconds, now, title);
97618
- } else if (request.daily !== void 0) record2 = createDailyScheduleRecord(id, request.prompt, request.daily, now, title);
97619
- else if (request.weekly !== void 0) record2 = createWeeklyScheduleRecord(id, request.prompt, request.weekly, now, title);
97620
- else if (request.cron !== void 0) record2 = createCronScheduleRecord(id, request.prompt, request.cron, now, title);
97746
+ record3 = createEveryScheduleRecord(id, request.prompt, request.every_seconds, now, title);
97747
+ } else if (request.daily !== void 0) record3 = createDailyScheduleRecord(id, request.prompt, request.daily, now, title);
97748
+ else if (request.weekly !== void 0) record3 = createWeeklyScheduleRecord(id, request.prompt, request.weekly, now, title);
97749
+ else if (request.cron !== void 0) record3 = createCronScheduleRecord(id, request.prompt, request.cron, now, title);
97621
97750
  else throw new ScheduleInputError("invalid_selector", "Exactly one reminder selector is required.");
97622
97751
  return this.serialize(async () => {
97623
97752
  const refusal = this.reminderTargetRefusal(sessionId);
@@ -97626,13 +97755,13 @@ var ScheduleService = class extends (_b2 = TypertRemoteService) {
97626
97755
  signal?.throwIfAborted();
97627
97756
  await domain3.table("tasks").put(id, {
97628
97757
  sessionId,
97629
- record: record2,
97758
+ record: record3,
97630
97759
  status: "active",
97631
97760
  deliveryHistory: { records: [], earlierRecordsUnavailable: false }
97632
97761
  });
97633
97762
  this.emitChanged();
97634
97763
  this.runtime?.requestDrive();
97635
- return record2;
97764
+ return record3;
97636
97765
  });
97637
97766
  }
97638
97767
  async list(request) {
@@ -98791,11 +98920,11 @@ var SessionTitleService = class extends Service {
98791
98920
  if (modelCandidate === null || typeof modelCandidate !== "object") {
98792
98921
  throw new Error("session-title provider result model must contain non-empty provider and model strings");
98793
98922
  }
98794
- const record2 = modelCandidate;
98795
- if (typeof record2.provider !== "string" || record2.provider.length === 0 || typeof record2.model !== "string" || record2.model.length === 0) {
98923
+ const record3 = modelCandidate;
98924
+ if (typeof record3.provider !== "string" || record3.provider.length === 0 || typeof record3.model !== "string" || record3.model.length === 0) {
98796
98925
  throw new Error("session-title provider result model must contain non-empty provider and model strings");
98797
98926
  }
98798
- model = { provider: record2.provider, model: record2.model };
98927
+ model = { provider: record3.provider, model: record3.model };
98799
98928
  }
98800
98929
  return {
98801
98930
  title,
@@ -98995,8 +99124,8 @@ function timeHeaderOf(time3) {
98995
99124
  function proseBlock(text4) {
98996
99125
  return escapeContent(text4).split("\n").map((line5) => line5 === "" ? ">" : `> ${line5}`).join("\n");
98997
99126
  }
98998
- function structuredBlock(record2) {
98999
- const json2 = JSON.stringify(record2, void 0, 2);
99127
+ function structuredBlock(record3) {
99128
+ const json2 = JSON.stringify(record3, void 0, 2);
99000
99129
  const longestRun = Math.max(
99001
99130
  0,
99002
99131
  ...(json2.match(/`+/gu) ?? []).map((run2) => run2.length)
@@ -99015,7 +99144,7 @@ function toolCallBlock(event) {
99015
99144
  }
99016
99145
  function toolResultBlock(event) {
99017
99146
  const result = event.data.message;
99018
- const record2 = {
99147
+ const record3 = {
99019
99148
  callId: escapeContent(result.toolCallId),
99020
99149
  result: escapeContent(result.content.map((block) => block.type === "text" ? block.text : "").join("")),
99021
99150
  isError: result.isError ?? false,
@@ -99026,7 +99155,7 @@ function toolResultBlock(event) {
99026
99155
  }
99027
99156
  }
99028
99157
  };
99029
- return structuredBlock(record2);
99158
+ return structuredBlock(record3);
99030
99159
  }
99031
99160
  function renderSessionMarkdown(events) {
99032
99161
  const blocks = [];
@@ -99085,14 +99214,6 @@ async function exportSessionMarkdown(session, dir) {
99085
99214
  }
99086
99215
 
99087
99216
  // packages/tui/tui/src/settings-rows.ts
99088
- var LEADING_NAMESPACES = [
99089
- "tui",
99090
- "llm-deepseek",
99091
- "llm-openai",
99092
- "llm-anthropic",
99093
- "llm-pi-ai",
99094
- "subagent"
99095
- ];
99096
99217
  var BRAND_ANIMATION_LABELS = {
99097
99218
  auto: "\u81EA\u52A8",
99098
99219
  on: "\u5F00\u542F",
@@ -99483,121 +99604,6 @@ function parseSettingsFieldValue(namespace, field, current, draft, knownProvider
99483
99604
  }
99484
99605
  return parseSettingValue(current, draft);
99485
99606
  }
99486
- function settingsRowsFromDescribe(descriptors, read, options) {
99487
- const leadingNames = new Set(LEADING_NAMESPACES);
99488
- const leading = /* @__PURE__ */ new Map();
99489
- const rest = [];
99490
- for (const entry of descriptors) {
99491
- const value = read(entry.ns);
99492
- if (!isPlainObject3(value)) continue;
99493
- const secretHeads = new Set(
99494
- (entry.secrets ?? []).map((secret) => secret.path[0]).filter((head) => head !== void 0)
99495
- );
99496
- const rows = [];
99497
- for (const [field, fieldValue] of Object.entries(value)) {
99498
- if (secretHeads.has(field)) continue;
99499
- if (options?.expandProviders === true && String(entry.ns) === "llm-pi-ai" && field === "providers" && isPlainObject3(fieldValue)) {
99500
- const providersObj = fieldValue;
99501
- const providerIds = Object.keys(providersObj);
99502
- if (providerIds.length === 0) {
99503
- rows.push({
99504
- namespace: "llm-pi-ai",
99505
- field: "providers",
99506
- value: "Enter\uFF1A\u76EE\u5F55\u540D / \u6A21\u677F\u5E8F\u53F7 1-4 / \u6216\u6309\u8868\u5355\u586B\u5199",
99507
- label: "providers \xB7 [+ \u6DFB\u52A0 Provider]",
99508
- editValue: PROVIDER_FORM_TEMPLATE
99509
- });
99510
- } else {
99511
- rows.push({
99512
- namespace: "llm-pi-ai",
99513
- field: "providers",
99514
- value: stringifySettingsFieldValue("llm-pi-ai", "providers", providersObj),
99515
- label: "providers \xB7 \u63D0\u4F9B\u5546\u5217\u8868 (Enter \u8FFD\u52A0)",
99516
- editValue: PROVIDER_FORM_TEMPLATE
99517
- });
99518
- for (const pId of providerIds) {
99519
- const profile = isPlainObject3(providersObj[pId]) ? providersObj[pId] : {};
99520
- rows.push({
99521
- namespace: "llm-pi-ai",
99522
- field: `providers.${pId}.api`,
99523
- value: stringifySettingValue(profile.api ?? "openai-completions"),
99524
- required: true,
99525
- label: `providers \xB7 ${pId} \xB7 \u534F\u8BAE (api)`
99526
- });
99527
- rows.push({
99528
- namespace: "llm-pi-ai",
99529
- field: `providers.${pId}.baseURL`,
99530
- value: stringifySettingValue(profile.baseURL ?? ""),
99531
- required: true,
99532
- label: `providers \xB7 ${pId} \xB7 \u7AEF\u70B9 (baseURL)`
99533
- });
99534
- rows.push({
99535
- namespace: "llm-pi-ai",
99536
- field: `providers.${pId}.apiKeyEnv`,
99537
- value: stringifySettingValue(profile.apiKeyEnv ?? ""),
99538
- required: true,
99539
- label: `providers \xB7 ${pId} \xB7 \u51ED\u636E\u53D8\u91CF (apiKeyEnv)`
99540
- });
99541
- rows.push({
99542
- namespace: "llm-pi-ai",
99543
- field: `providers.${pId}.defaultInput`,
99544
- value: stringifySettingsFieldValue("llm-pi-ai", `providers.${pId}.defaultInput`, profile.defaultInput),
99545
- required: false,
99546
- label: `providers \xB7 ${pId} \xB7 \u8F93\u5165\u6A21\u6001 (defaultInput: text/image)`,
99547
- editValue: Array.isArray(profile.defaultInput) ? profile.defaultInput.join(", ") : "text, image"
99548
- });
99549
- rows.push({
99550
- namespace: "llm-pi-ai",
99551
- field: `providers.${pId}.displayName`,
99552
- value: stringifySettingValue(profile.displayName ?? pId),
99553
- required: false,
99554
- label: `providers \xB7 ${pId} \xB7 \u522B\u540D (displayName)`
99555
- });
99556
- rows.push({
99557
- namespace: "llm-pi-ai",
99558
- field: `providers.${pId}.models`,
99559
- value: formatModelsList(profile.models),
99560
- required: false,
99561
- label: `providers \xB7 ${pId} \xB7 \u6A21\u578B (models, \u9017\u53F7\u5206\u9694)`
99562
- });
99563
- }
99564
- rows.push({
99565
- namespace: "llm-pi-ai",
99566
- field: "providers",
99567
- value: "Enter\uFF1A\u76EE\u5F55\u540D / \u6A21\u677F\u5E8F\u53F7 1-4 / \u6216\u6309\u8868\u5355\u586B\u5199",
99568
- label: "providers \xB7 [+ \u6DFB\u52A0 Provider]",
99569
- editValue: PROVIDER_FORM_TEMPLATE
99570
- });
99571
- }
99572
- continue;
99573
- }
99574
- rows.push({
99575
- namespace: String(entry.ns),
99576
- field,
99577
- value: stringifySettingsFieldValue(String(entry.ns), field, fieldValue),
99578
- ...(field === "models" || field.endsWith(".models")) && Array.isArray(fieldValue) ? { editValue: stringifySettingValue(fieldValue) } : {}
99579
- });
99580
- }
99581
- const key = String(entry.ns);
99582
- if (leadingNames.has(key)) {
99583
- const bucket = leading.get(key) ?? [];
99584
- bucket.push(...rows);
99585
- leading.set(key, bucket);
99586
- } else {
99587
- rest.push(...rows);
99588
- }
99589
- }
99590
- const ordered = [];
99591
- for (const name2 of LEADING_NAMESPACES) {
99592
- const bucket = leading.get(name2);
99593
- if (bucket !== void 0) ordered.push(...bucket);
99594
- }
99595
- rest.sort((left, right) => {
99596
- const ns = left.namespace.localeCompare(right.namespace);
99597
- return ns === 0 ? left.field.localeCompare(right.field) : ns;
99598
- });
99599
- return [...ordered, ...rest];
99600
- }
99601
99607
  function credentialRowValue(configured) {
99602
99608
  if (configured === void 0) return "Enter \u8BBE\u7F6E\u5BC6\u94A5";
99603
99609
  return configured ? "\u5DF2\u914D\u7F6E" : "\u672A\u914D\u7F6E";
@@ -99619,6 +99625,227 @@ function credentialSettingRows(names, configured) {
99619
99625
  return rows;
99620
99626
  }
99621
99627
 
99628
+ // packages/tui/tui/src/settings-navigation.ts
99629
+ function record2(value) {
99630
+ return typeof value === "object" && value !== null ? value : {};
99631
+ }
99632
+ function childSchema(schema, key) {
99633
+ const node2 = record2(schema);
99634
+ return record2(node2.dict)[key] ?? record2(node2.properties)[key] ?? node2.inner ?? node2.items;
99635
+ }
99636
+ function summary(value) {
99637
+ return Array.isArray(value) ? `${String(value.length)} \u9879` : value !== null && typeof value === "object" ? `${String(Object.keys(value).length)} \u4E2A\u5B57\u6BB5` : stringifySettingValue(value);
99638
+ }
99639
+ function withUserFields(resolved, user) {
99640
+ if (Array.isArray(user)) return user.map((value, index2) => withUserFields(Array.isArray(resolved) ? resolved[index2] : void 0, value));
99641
+ if (user !== null && typeof user === "object") return Object.fromEntries(
99642
+ [.../* @__PURE__ */ new Set([...Object.keys(record2(resolved)), ...Object.keys(user)])].map((key) => [key, Object.hasOwn(user, key) ? withUserFields(record2(resolved)[key], record2(user)[key]) : record2(resolved)[key]])
99643
+ );
99644
+ return user === void 0 ? resolved : user;
99645
+ }
99646
+ function settingsTreeFromDescribe(descriptors, credentials) {
99647
+ const nodes = [];
99648
+ const groups = /* @__PURE__ */ new Set();
99649
+ const addGroup = (namespace) => {
99650
+ const group = settingsGroup({ namespace, field: "" });
99651
+ const id = `group:${group}`;
99652
+ if (!groups.has(id)) {
99653
+ groups.add(id);
99654
+ nodes.push({ id, parentId: "", namespace, field: "", label: SETTINGS_GROUP_LABELS[group], value: "", navigable: true, editable: false });
99655
+ }
99656
+ return id;
99657
+ };
99658
+ for (const descriptor of descriptors) {
99659
+ if (descriptor.value === null || typeof descriptor.value !== "object" || Array.isArray(descriptor.value)) continue;
99660
+ const namespace = String(descriptor.ns);
99661
+ const nsId = `ns:${namespace}`;
99662
+ const group = addGroup(namespace);
99663
+ nodes.push({ id: nsId, parentId: group, namespace, field: "", label: namespace, value: summary(descriptor.value), navigable: true, editable: false });
99664
+ const formValue = withUserFields(descriptor.value, descriptor.user);
99665
+ const secrets = (descriptor.secrets ?? []).map((secret) => secret.path.map(String));
99666
+ const walk = (value, path2, parentId, schema) => {
99667
+ if (secrets.some((secret) => secret.every((key2, index2) => path2[index2] === key2))) return;
99668
+ const field = path2.join(".");
99669
+ const key = path2[path2.length - 1] ?? "";
99670
+ const parentValue = atPath(formValue, path2.slice(0, -1));
99671
+ const modelId = record2(value).id;
99672
+ const identity = Array.isArray(parentValue) && typeof modelId === "string" && parentValue.filter((entry) => record2(entry).id === modelId).length === 1 ? `id:${modelId}` : key;
99673
+ const id = `${parentId}:${JSON.stringify(identity)}`;
99674
+ const nested = value !== null && typeof value === "object";
99675
+ const meta3 = record2(record2(schema).meta);
99676
+ const label = Array.isArray(parentValue) ? String(record2(value).id ?? record2(value).name ?? key) : key;
99677
+ nodes.push({
99678
+ id,
99679
+ parentId,
99680
+ namespace,
99681
+ field,
99682
+ sourcePath: path2,
99683
+ label,
99684
+ value: path2.length === 2 && path2[0] === "providers" ? `${String(Array.isArray(record2(value).models) ? record2(value).models.length : 0)} \u6A21\u578B \xB7 ${String(record2(value).api ?? "\u9ED8\u8BA4\u534F\u8BAE")}` : nested ? summary(value) : stringifySettingsFieldValue(namespace, field, value),
99685
+ editValue: stringifySettingValue(value),
99686
+ ...nested && secrets.some((secret) => path2.every((key2, index2) => secret[index2] === key2)) ? { editable: false } : {},
99687
+ ...nested ? { navigable: true } : {},
99688
+ ...typeof meta3.description === "string" ? { description: meta3.description } : {},
99689
+ ...meta3.required === true ? { required: true } : {}
99690
+ });
99691
+ if (nested) {
99692
+ for (const [child, next] of Object.entries(value)) walk(next, [...path2, child], id, childSchema(schema, child));
99693
+ if (namespace === "llm-pi-ai" && field === "providers") {
99694
+ nodes.push({ id: `${id}:add`, parentId: id, namespace, field, sourcePath: path2, label: "+ \u6DFB\u52A0 Provider", value: "\u76EE\u5F55\u540D / \u8868\u5355", editValue: PROVIDER_FORM_TEMPLATE });
99695
+ }
99696
+ }
99697
+ };
99698
+ for (const [key, value] of Object.entries(record2(formValue))) walk(value, [key], nsId, childSchema(descriptor.schema, key));
99699
+ }
99700
+ if (credentials.length > 0) {
99701
+ const group = addGroup("credentials");
99702
+ const parentId = "ns:credentials";
99703
+ nodes.push({ id: parentId, parentId: group, namespace: "credentials", field: "", label: "\u51ED\u636E\u7BA1\u7406", value: `${String(credentials.length)} \u9879`, navigable: true, editable: false });
99704
+ for (const row of credentials) nodes.push({ ...row, editValue: "", id: `${parentId}:${row.field}`, parentId, label: row.field });
99705
+ }
99706
+ return nodes;
99707
+ }
99708
+ function atPath(value, path2) {
99709
+ let current = value;
99710
+ for (const key of path2) current = record2(current)[key];
99711
+ return current;
99712
+ }
99713
+ function settingsPathPatch(section, path2, value, user) {
99714
+ const replace2 = (current, remaining, stored, preserve = false) => {
99715
+ const [key, ...rest] = remaining;
99716
+ if (key === void 0) return value;
99717
+ const source = stored !== void 0 ? stored : current;
99718
+ const complete = preserve || Array.isArray(source);
99719
+ const copy = Array.isArray(source) ? [...source] : complete ? { ...record2(source) } : {};
99720
+ Object.defineProperty(copy, key, { value: replace2(record2(current)[key], rest, record2(stored)[key], complete), writable: true, enumerable: true, configurable: true });
99721
+ return copy;
99722
+ };
99723
+ return replace2(section, path2, user);
99724
+ }
99725
+ var SettingsNavigation = class {
99726
+ constructor(nodes) {
99727
+ this.nodes = nodes;
99728
+ }
99729
+ nodes;
99730
+ selectedIndex = 0;
99731
+ parentId = "";
99732
+ query = "";
99733
+ selections = /* @__PURE__ */ new Map();
99734
+ categoryPositions = /* @__PURE__ */ new Map();
99735
+ beforeSearchIndex = 0;
99736
+ get rows() {
99737
+ const query = this.query.toLocaleLowerCase();
99738
+ return query === "" ? this.nodes.filter((node2) => node2.parentId === this.parentId) : this.nodes.filter((node2) => node2.field !== "" && `${node2.namespace} ${node2.field} ${node2.label ?? ""} ${node2.value} ${node2.description ?? ""}`.toLocaleLowerCase().includes(query));
99739
+ }
99740
+ get breadcrumb() {
99741
+ const labels = ["\u8BBE\u7F6E"];
99742
+ let node2 = this.nodes.find((entry) => entry.id === this.parentId);
99743
+ const tail = [];
99744
+ while (node2 !== void 0) {
99745
+ tail.unshift(node2.label ?? node2.field);
99746
+ node2 = this.nodes.find((entry) => entry.id === node2?.parentId);
99747
+ }
99748
+ return [...labels, ...tail];
99749
+ }
99750
+ get categories() {
99751
+ return this.nodes.filter((node2) => node2.parentId === "").map((node2) => ({
99752
+ id: node2.id,
99753
+ label: node2.label ?? node2.field,
99754
+ count: this.nodes.filter((child) => child.parentId === node2.id).length
99755
+ }));
99756
+ }
99757
+ get activeCategory() {
99758
+ let node2 = this.nodes.find((entry) => entry.id === this.parentId);
99759
+ while (node2 !== void 0 && node2.parentId !== "") node2 = this.nodes.find((entry) => entry.id === node2?.parentId);
99760
+ return node2?.id;
99761
+ }
99762
+ open() {
99763
+ if (this.parentId === "") this.group(1);
99764
+ }
99765
+ get filter() {
99766
+ return this.query;
99767
+ }
99768
+ remember() {
99769
+ if (this.query !== "") return;
99770
+ const category = this.activeCategory;
99771
+ if (category !== void 0) this.categoryPositions.set(category, this.parentId);
99772
+ const id = this.rows[this.selectedIndex]?.id;
99773
+ if (id !== void 0) this.selections.set(this.parentId, id);
99774
+ }
99775
+ restore() {
99776
+ const index2 = this.rows.findIndex((node2) => node2.id === this.selections.get(this.parentId));
99777
+ this.selectedIndex = index2 < 0 ? Math.min(this.selectedIndex, Math.max(0, this.rows.length - 1)) : index2;
99778
+ }
99779
+ replace(nodes) {
99780
+ const selected = this.rows[this.selectedIndex]?.id;
99781
+ this.remember();
99782
+ const previous3 = this.nodes;
99783
+ this.nodes = nodes;
99784
+ const survivingParent = (parent) => {
99785
+ while (parent !== "" && !nodes.some((node2) => node2.id === parent)) {
99786
+ parent = previous3.find((node2) => node2.id === parent)?.parentId ?? "";
99787
+ }
99788
+ return parent;
99789
+ };
99790
+ this.parentId = survivingParent(this.parentId);
99791
+ for (const [parent, id] of this.selections) {
99792
+ if (!nodes.some((node2) => node2.id === id && node2.parentId === parent)) this.selections.delete(parent);
99793
+ }
99794
+ for (const [category, parent] of this.categoryPositions) {
99795
+ if (!nodes.some((node2) => node2.id === category && node2.parentId === "")) this.categoryPositions.delete(category);
99796
+ else this.categoryPositions.set(category, survivingParent(parent));
99797
+ }
99798
+ const index2 = this.rows.findIndex((node2) => node2.id === selected);
99799
+ if (index2 >= 0) this.selectedIndex = index2;
99800
+ else this.restore();
99801
+ }
99802
+ enter() {
99803
+ const node2 = this.rows[this.selectedIndex];
99804
+ if (node2?.navigable !== true) return false;
99805
+ this.remember();
99806
+ this.parentId = node2.id;
99807
+ this.query = "";
99808
+ this.selectedIndex = 0;
99809
+ this.restore();
99810
+ return true;
99811
+ }
99812
+ back() {
99813
+ if (this.query !== "") {
99814
+ this.search("");
99815
+ return true;
99816
+ }
99817
+ const node2 = this.nodes.find((entry) => entry.id === this.parentId);
99818
+ if (node2 === void 0 || node2.parentId === "") return false;
99819
+ this.remember();
99820
+ this.parentId = node2.parentId;
99821
+ this.selectedIndex = 0;
99822
+ this.restore();
99823
+ return true;
99824
+ }
99825
+ search(query) {
99826
+ if (query === this.query) return;
99827
+ if (this.query === "") {
99828
+ this.remember();
99829
+ this.beforeSearchIndex = this.selectedIndex;
99830
+ }
99831
+ this.query = query;
99832
+ this.selectedIndex = query === "" ? this.beforeSearchIndex : 0;
99833
+ if (query === "") this.restore();
99834
+ }
99835
+ group(delta) {
99836
+ if (this.query !== "") this.search("");
99837
+ this.remember();
99838
+ const groups = this.categories;
99839
+ const index2 = groups.findIndex((node2) => node2.id === this.activeCategory);
99840
+ const nextIndex = index2 < 0 ? delta < 0 ? groups.length - 1 : 0 : (index2 + (delta < 0 ? -1 : 1) + groups.length) % groups.length;
99841
+ const next = groups[nextIndex];
99842
+ if (next === void 0) return;
99843
+ this.parentId = this.categoryPositions.get(next.id) ?? next.id;
99844
+ this.selectedIndex = 0;
99845
+ this.restore();
99846
+ }
99847
+ };
99848
+
99622
99849
  // packages/tui/tui/src/index.ts
99623
99850
  try {
99624
99851
  if (typeof Session === "function" && !("events" in Session.prototype)) {
@@ -99876,18 +100103,6 @@ function fieldOf(section, field) {
99876
100103
  }
99877
100104
  return current;
99878
100105
  }
99879
- function createSettingsPatch(field, value) {
99880
- const parts = field.split(".");
99881
- const root = {};
99882
- let current = root;
99883
- for (let i2 = 0; i2 < parts.length - 1; i2++) {
99884
- const next = {};
99885
- current[parts[i2]] = next;
99886
- current = next;
99887
- }
99888
- current[parts[parts.length - 1]] = value;
99889
- return root;
99890
- }
99891
100106
  function persistenceHasOpen(persistence) {
99892
100107
  return typeof persistence?.open === "function";
99893
100108
  }
@@ -100384,6 +100599,8 @@ var RuntimeController = class _RuntimeController {
100384
100599
  settingsOpen = false;
100385
100600
  settingsRows = [];
100386
100601
  settingsSelectedIndex = 0;
100602
+ settingsNavigation = new SettingsNavigation([]);
100603
+ settingsSearching = false;
100387
100604
  settingsEditing = false;
100388
100605
  settingsOnboarding = false;
100389
100606
  settingsUpdateError;
@@ -100685,8 +100902,8 @@ var RuntimeController = class _RuntimeController {
100685
100902
  cacheWorkspaceChange(seq) {
100686
100903
  const sessionId = this.session?.id;
100687
100904
  const service = this.ctx.get("workspaceChanges");
100688
- const summary = sessionId === void 0 || service === void 0 ? void 0 : service.summary(sessionId, seq);
100689
- const card = workspaceChangesCardFromSummary(seq, summary);
100905
+ const summary2 = sessionId === void 0 || service === void 0 ? void 0 : service.summary(sessionId, seq);
100906
+ const card = workspaceChangesCardFromSummary(seq, summary2);
100690
100907
  if (card === void 0) this.workspaceChangeCards.delete(seq);
100691
100908
  else this.workspaceChangeCards.set(seq, card);
100692
100909
  }
@@ -100855,15 +101072,15 @@ var RuntimeController = class _RuntimeController {
100855
101072
  if (service === void 0) throw new Error("\u53D8\u66F4\u8BB0\u5F55\u670D\u52A1\u672A\u7EC4\u5408");
100856
101073
  for (const event of getSessionEvents(session)) {
100857
101074
  if (event.type !== "workspace/changes") continue;
100858
- const summary = service.summary(session.id, event.seq);
100859
- if (summary === void 0) {
101075
+ const summary2 = service.summary(session.id, event.seq);
101076
+ if (summary2 === void 0) {
100860
101077
  rows.push({ id: `${event.seq}:missing`, title: `\u56DE\u5408 ${event.data.turn} \xB7 \u53D8\u66F4\u5FEB\u7167\u5DF2\u4E0D\u53EF\u7528` });
100861
101078
  continue;
100862
101079
  }
100863
- for (const [index2, file2] of summary.files.entries()) {
101080
+ for (const [index2, file2] of summary2.files.entries()) {
100864
101081
  const id = `${event.seq}:${index2}`;
100865
101082
  coordinates.set(id, { seq: event.seq, index: index2 });
100866
- rows.push({ id, title: `\u56DE\u5408 ${summary.turn} \xB7 ${file2.display}`, hint: file2.binary ? "binary" : file2.oversized ? "oversized" : `+${file2.added} -${file2.deleted}` });
101083
+ rows.push({ id, title: `\u56DE\u5408 ${summary2.turn} \xB7 ${file2.display}`, hint: file2.binary ? "binary" : file2.oversized ? "oversized" : `+${file2.added} -${file2.deleted}` });
100867
101084
  }
100868
101085
  }
100869
101086
  return rows;
@@ -101030,6 +101247,7 @@ var RuntimeController = class _RuntimeController {
101030
101247
  rows: this.settingsRows,
101031
101248
  selectedIndex: this.settingsSelectedIndex,
101032
101249
  editing: this.settingsEditing,
101250
+ ...!this.settingsOnboarding ? { breadcrumb: this.settingsNavigation.breadcrumb, filter: this.settingsNavigation.filter, searching: this.settingsSearching, categories: this.settingsNavigation.categories, ...this.settingsNavigation.activeCategory === void 0 ? {} : { activeCategory: this.settingsNavigation.activeCategory } } : {},
101033
101251
  ...this.settingsOnboarding ? { onboarding: true } : {},
101034
101252
  ...this.settingsBusy ? { busy: true } : {},
101035
101253
  ...this.settingsUpdateError === void 0 ? {} : { updateError: this.settingsUpdateError }
@@ -101246,7 +101464,8 @@ var RuntimeController = class _RuntimeController {
101246
101464
  const fs3 = this.ctx.get("fs");
101247
101465
  if (fs3 === void 0) return;
101248
101466
  try {
101249
- const root = await fs3.resolve(value);
101467
+ const cwd2 = this.sessionDirectory();
101468
+ const root = await fs3.resolve(value, cwd2 === void 0 ? void 0 : { cwd: cwd2 });
101250
101469
  const children = await fs3.listDir(root);
101251
101470
  if (seq !== this.workspaceSeq || !this.workspaceOpen) return;
101252
101471
  this.commitResolvedWorkspaceRoot(root, children);
@@ -101583,15 +101802,15 @@ var RuntimeController = class _RuntimeController {
101583
101802
  if (service === void 0) throw new Error("\u5B9A\u65F6\u4EFB\u52A1\u670D\u52A1\u672A\u7EC4\u5408");
101584
101803
  const catalog = await service.catalog();
101585
101804
  if (this.closed || !this.schedulePane.open || seq !== this.scheduleSeq) return;
101586
- const rows = catalog.map((record2) => ({
101587
- id: record2.id,
101588
- sessionId: record2.sessionId,
101589
- title: record2.title,
101590
- prompt: record2.prompt,
101591
- scheduledAt: record2.scheduledAt,
101592
- active: record2.status === "active",
101593
- timing: record2.kind === "after" ? "\u5EF6\u65F6\u4E00\u6B21" : record2.kind === "at" ? "\u6307\u5B9A\u65F6\u95F4\u4E00\u6B21" : record2.kind === "every" ? `\u6BCF ${record2.everySeconds} \u79D2` : record2.kind === "daily" ? `\u6BCF\u5929 ${record2.time} \xB7 ${record2.timeZone}` : record2.kind === "weekly" ? `\u6BCF\u5468 ${record2.weekdays.join(",")} ${record2.time} \xB7 ${record2.timeZone}` : `cron ${record2.expression} \xB7 ${record2.timeZone}`,
101594
- ...record2.lastDelivery === void 0 ? {} : { lastDelivery: record2.lastDelivery.deliveredAt }
101805
+ const rows = catalog.map((record3) => ({
101806
+ id: record3.id,
101807
+ sessionId: record3.sessionId,
101808
+ title: record3.title,
101809
+ prompt: record3.prompt,
101810
+ scheduledAt: record3.scheduledAt,
101811
+ active: record3.status === "active",
101812
+ timing: record3.kind === "after" ? "\u5EF6\u65F6\u4E00\u6B21" : record3.kind === "at" ? "\u6307\u5B9A\u65F6\u95F4\u4E00\u6B21" : record3.kind === "every" ? `\u6BCF ${record3.everySeconds} \u79D2` : record3.kind === "daily" ? `\u6BCF\u5929 ${record3.time} \xB7 ${record3.timeZone}` : record3.kind === "weekly" ? `\u6BCF\u5468 ${record3.weekdays.join(",")} ${record3.time} \xB7 ${record3.timeZone}` : `cron ${record3.expression} \xB7 ${record3.timeZone}`,
101813
+ ...record3.lastDelivery === void 0 ? {} : { lastDelivery: record3.lastDelivery.deliveredAt }
101595
101814
  }));
101596
101815
  const selectedIndex = Math.max(0, rows.findIndex((row) => row.id === selectedId));
101597
101816
  this.schedulePane = {
@@ -102010,14 +102229,24 @@ var RuntimeController = class _RuntimeController {
102010
102229
  phase: attempt?.phase,
102011
102230
  authorizeUrl: attempt?.authorizeUrl,
102012
102231
  errorCode: attempt?.errorCode,
102232
+ forward: attempt === null ? void 0 : this.accountForward(),
102013
102233
  ...identityChanged || view.status === "signed-out" ? { profile: void 0, balance: void 0 } : {}
102014
102234
  });
102015
102235
  if (attempt?.phase === "waiting-browser" && attempt.authorizeUrl !== void 0 && this.accountUrlOpened !== attempt.authorizeUrl) {
102016
102236
  this.accountUrlOpened = attempt.authorizeUrl;
102017
- if (this.accountPane.forward === void 0) internals.openUrl(attempt.authorizeUrl);
102237
+ if (!this.accountIsRemote()) internals.openUrl(attempt.authorizeUrl);
102018
102238
  }
102019
102239
  if (view.status === "credential-stored" && !wasSignedIn) this.ownWork(this.loadAccountDetails(), "account details");
102020
102240
  }
102241
+ accountIsRemote() {
102242
+ const environment2 = internals.accountEnvironment;
102243
+ return environment2.SSH_CONNECTION !== void 0 || environment2.SSH_TTY !== void 0;
102244
+ }
102245
+ accountForward() {
102246
+ const webServer = this.ctx.get("webServer");
102247
+ if (!this.accountIsRemote() || webServer?.protocol !== "http:" || webServer.port === void 0) return void 0;
102248
+ return `ssh -L ${String(webServer.port)}:${webServer.host}:${String(webServer.port)} <host>`;
102249
+ }
102021
102250
  /** Read profile and balance; only the originating page and credential revision may publish. */
102022
102251
  async loadAccountDetails() {
102023
102252
  const account = this.ctx.get("deepseekAccount");
@@ -102050,13 +102279,11 @@ var RuntimeController = class _RuntimeController {
102050
102279
  return;
102051
102280
  }
102052
102281
  const host = webServer.host.includes(":") ? `[${webServer.host}]` : webServer.host;
102053
- const environment2 = internals.accountEnvironment;
102054
- const remote = environment2.SSH_CONNECTION !== void 0 || environment2.SSH_TTY !== void 0;
102055
102282
  this.accountUrlOpened = void 0;
102056
102283
  this.updateAccount({
102057
102284
  busy: true,
102058
102285
  error: void 0,
102059
- forward: remote ? `ssh -L ${String(webServer.port)}:${webServer.host}:${String(webServer.port)} <host>` : void 0
102286
+ forward: this.accountForward()
102060
102287
  });
102061
102288
  try {
102062
102289
  const view = await account.startSignIn(this.accountClient(), `http://${host}:${String(webServer.port)}/`, "web");
@@ -103252,7 +103479,7 @@ ${line5}`.slice(-64e3);
103252
103479
  return;
103253
103480
  }
103254
103481
  case "settings-escape":
103255
- if (!this.settingsOpen) return;
103482
+ if (!this.settingsOpen || this.settingsBusy) return;
103256
103483
  if (this.settingsOnboarding) {
103257
103484
  this.settingsOnboarding = false;
103258
103485
  this.settingsOpen = false;
@@ -103262,34 +103489,65 @@ ${line5}`.slice(-64e3);
103262
103489
  this.setFeedback("\u2713 \u5DF2\u8DF3\u8FC7\u5F15\u5BFC");
103263
103490
  return;
103264
103491
  }
103492
+ this.settingsNavigation.selectedIndex = this.settingsSelectedIndex;
103493
+ if (this.settingsNavigation.back()) {
103494
+ this.settingsSearching = false;
103495
+ this.syncSettingsNavigation();
103496
+ return;
103497
+ }
103265
103498
  this.settingsOpen = false;
103266
103499
  this.settingsEditing = false;
103267
103500
  this.settingsBusy = false;
103268
103501
  this.settingsUpdateError = void 0;
103269
103502
  this.emit();
103270
103503
  return;
103504
+ case "settings-search":
103505
+ if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding || this.settingsBusy) return;
103506
+ this.settingsSearching = action.active;
103507
+ this.settingsNavigation.selectedIndex = this.settingsSelectedIndex;
103508
+ this.settingsNavigation.search(action.query);
103509
+ this.syncSettingsNavigation();
103510
+ return;
103271
103511
  case "settings-group":
103272
- if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding) return;
103273
- this.settingsSelectedIndex = nextSettingsGroup(this.settingsRows, this.settingsSelectedIndex, action.delta);
103274
- this.emit();
103512
+ if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding || this.settingsBusy) return;
103513
+ this.settingsNavigation.selectedIndex = this.settingsSelectedIndex;
103514
+ this.settingsNavigation.group(action.delta);
103515
+ this.settingsSearching = false;
103516
+ this.syncSettingsNavigation();
103275
103517
  return;
103276
103518
  case "settings-move":
103277
- if (!this.settingsOpen || this.settingsEditing) return;
103519
+ if (!this.settingsOpen || this.settingsEditing || this.settingsBusy) return;
103278
103520
  if (this.settingsRows.length === 0) return;
103279
103521
  this.settingsSelectedIndex = Math.min(
103280
103522
  this.settingsRows.length - 1,
103281
103523
  Math.max(0, this.settingsSelectedIndex + action.delta)
103282
103524
  );
103525
+ this.settingsNavigation.selectedIndex = this.settingsSelectedIndex;
103283
103526
  this.emit();
103284
103527
  return;
103285
103528
  case "settings-edit":
103286
- if (!this.settingsOpen) return;
103529
+ case "settings-edit-json":
103530
+ if (!this.settingsOpen || this.settingsBusy) return;
103531
+ if (!this.settingsOnboarding) {
103532
+ this.settingsNavigation.selectedIndex = this.settingsSelectedIndex;
103533
+ if (action.kind === "settings-edit" && this.settingsNavigation.enter()) {
103534
+ this.settingsSearching = false;
103535
+ this.syncSettingsNavigation();
103536
+ return;
103537
+ }
103538
+ if (this.settingsRows[this.settingsSelectedIndex]?.editable === false) return;
103539
+ }
103540
+ if (this.settingsRows[this.settingsSelectedIndex] === void 0) {
103541
+ this.settingsUpdateError = "\u65E0\u53EF\u7528\u8BBE\u7F6E";
103542
+ this.emit();
103543
+ return;
103544
+ }
103287
103545
  this.settingsEditing = true;
103288
103546
  this.settingsUpdateError = void 0;
103289
103547
  this.emit();
103290
103548
  return;
103291
103549
  case "settings-cancel-edit":
103292
- if (!this.settingsOpen) return;
103550
+ if (!this.settingsOpen || this.settingsBusy) return;
103293
103551
  if (this.settingsOnboarding) {
103294
103552
  this.settingsOnboarding = false;
103295
103553
  this.settingsOpen = false;
@@ -105066,8 +105324,13 @@ ${row.hint ?? ""}` });
105066
105324
  this.settingsEditing = false;
105067
105325
  this.settingsBusy = false;
105068
105326
  this.settingsUpdateError = void 0;
105069
- this.settingsRows = this.readSettingsRows();
105327
+ this.settingsNavigation = new SettingsNavigation([]);
105070
105328
  this.settingsSelectedIndex = 0;
105329
+ this.settingsSearching = false;
105330
+ this.readSettingsRows();
105331
+ this.settingsNavigation.open();
105332
+ this.settingsRows = this.settingsNavigation.rows;
105333
+ this.settingsSelectedIndex = this.settingsNavigation.selectedIndex;
105071
105334
  this.settingsOnboarding = false;
105072
105335
  this.settingsOpen = true;
105073
105336
  this.emit();
@@ -105082,15 +105345,20 @@ ${row.hint ?? ""}` });
105082
105345
  const settings = this.ctx.get("settings");
105083
105346
  if (settings === void 0) return [];
105084
105347
  const descriptors = settings.describe({ redactSecrets: true });
105085
- const rows = settingsRowsFromDescribe(
105086
- descriptors,
105087
- (ns) => descriptors.find((form) => form.ns === ns)?.value,
105088
- { expandProviders: true }
105089
- );
105090
- return [...rows, ...credentialSettingRows(
105348
+ const credentials = credentialSettingRows(
105091
105349
  this.referencedCredentialNames(),
105092
105350
  (name2) => this.configuredCredentials.get(name2)
105093
- )];
105351
+ );
105352
+ this.settingsNavigation.selectedIndex = this.settingsSelectedIndex;
105353
+ this.settingsNavigation.replace(settingsTreeFromDescribe(descriptors, credentials));
105354
+ this.settingsSelectedIndex = this.settingsNavigation.selectedIndex;
105355
+ return this.settingsNavigation.rows;
105356
+ }
105357
+ syncSettingsNavigation() {
105358
+ this.settingsRows = this.settingsNavigation.rows;
105359
+ this.settingsSelectedIndex = this.settingsNavigation.selectedIndex;
105360
+ this.settingsUpdateError = void 0;
105361
+ this.emit();
105094
105362
  }
105095
105363
  /**
105096
105364
  * Credential reference names this configuration asks for: the DeepSeek key
@@ -105177,8 +105445,8 @@ ${row.hint ?? ""}` });
105177
105445
  }
105178
105446
  /**
105179
105447
  * Persist the composer draft as the selected row's field. Onboarding writes
105180
- * `ctx.credentials.set` and never logs the value. Success closes the overlay
105181
- * and writes the status-row confirmation; failure stays on the overlay with
105448
+ * `ctx.credentials.set` and never logs the value. Success retains the selected
105449
+ * field and writes the status-row confirmation; failure stays on the overlay with
105182
105450
  * the ✗ pair. Does not write environment variables.
105183
105451
  *
105184
105452
  * A draft the parser marked with {@link AUTO_DISCOVER} defers profile
@@ -105189,7 +105457,7 @@ ${row.hint ?? ""}` });
105189
105457
  * @param value - composer draft captured by the key reducer.
105190
105458
  */
105191
105459
  applySettingsValue(value) {
105192
- if (!this.settingsOpen || !this.settingsEditing) return;
105460
+ if (!this.settingsOpen || !this.settingsEditing || this.settingsBusy) return;
105193
105461
  this.settingsEditing = false;
105194
105462
  const row = this.settingsRows[this.settingsSelectedIndex];
105195
105463
  if (row === void 0) {
@@ -105209,10 +105477,13 @@ ${row.hint ?? ""}` });
105209
105477
  }
105210
105478
  let parsed;
105211
105479
  try {
105480
+ const descriptor = settings.describe().find((form) => String(form.ns) === row.namespace);
105481
+ const path2 = row.sourcePath ?? row.field.split(".");
105482
+ const stored = atPath(descriptor?.user, path2);
105212
105483
  parsed = parseSettingsFieldValue(
105213
105484
  row.namespace,
105214
105485
  row.field,
105215
- row.field === "providers" ? this.rawUserProviders(row.namespace) ?? {} : fieldOf(settings.describe().find((form) => String(form.ns) === row.namespace)?.value, row.field),
105486
+ row.field === "providers" ? this.rawUserProviders(row.namespace) ?? {} : stored === void 0 ? atPath(descriptor?.value, path2) : stored,
105216
105487
  value,
105217
105488
  this.catalogProviderIds(row.namespace)
105218
105489
  );
@@ -105234,19 +105505,23 @@ ${row.hint ?? ""}` });
105234
105505
  this.applyAutoDiscoverProvider(row.namespace, row.field, parsed);
105235
105506
  return;
105236
105507
  }
105508
+ this.settingsBusy = true;
105509
+ this.settingsUpdateError = void 0;
105510
+ this.emit();
105237
105511
  this.ownWork((async () => {
105238
105512
  try {
105239
- await settings.update(row.namespace, createSettingsPatch(row.field, parsed));
105513
+ const descriptor = settings.describe().find((form) => String(form.ns) === row.namespace);
105514
+ await settings.update(row.namespace, settingsPathPatch(descriptor?.value, row.sourcePath ?? row.field.split("."), parsed, descriptor?.user));
105240
105515
  if (this.closed) return;
105241
105516
  if (row.namespace === TUI_SETTINGS_NS) this.applyColorTierSetting();
105242
- this.settingsOpen = false;
105243
105517
  this.settingsEditing = false;
105244
- this.settingsOnboarding = false;
105245
105518
  this.settingsBusy = false;
105246
105519
  this.settingsUpdateError = void 0;
105520
+ this.settingsRows = this.readSettingsRows();
105247
105521
  this.setFeedback(`\u2713 \u5DF2\u66F4\u65B0 ${row.field}`);
105248
105522
  } catch (error51) {
105249
105523
  if (this.closed) return;
105524
+ this.settingsBusy = false;
105250
105525
  this.settingsUpdateError = errorReason(error51);
105251
105526
  this.settingsRows = this.readSettingsRows();
105252
105527
  this.emit();
@@ -105258,9 +105533,9 @@ ${row.hint ?? ""}` });
105258
105533
  * closing the settings overlay. Non-toggleable rows open the inline editor.
105259
105534
  */
105260
105535
  toggleSelectedSettingValue() {
105261
- if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding) return;
105536
+ if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding || this.settingsBusy) return;
105262
105537
  const row = this.settingsRows[this.settingsSelectedIndex];
105263
- if (row === void 0) return;
105538
+ if (row === void 0 || row.editable === false) return;
105264
105539
  let nextValue;
105265
105540
  if (row.value === "true") {
105266
105541
  nextValue = false;
@@ -105284,16 +105559,22 @@ ${row.hint ?? ""}` });
105284
105559
  }
105285
105560
  const settings = this.ctx.get("settings");
105286
105561
  if (settings === void 0) return;
105562
+ this.settingsBusy = true;
105563
+ this.settingsUpdateError = void 0;
105564
+ this.emit();
105287
105565
  this.ownWork((async () => {
105288
105566
  try {
105289
- await settings.update(row.namespace, createSettingsPatch(row.field, nextValue));
105567
+ const descriptor = settings.describe().find((form) => String(form.ns) === row.namespace);
105568
+ await settings.update(row.namespace, settingsPathPatch(descriptor?.value, row.sourcePath ?? row.field.split("."), nextValue, descriptor?.user));
105290
105569
  if (this.closed) return;
105291
105570
  if (row.namespace === TUI_SETTINGS_NS) this.applyColorTierSetting();
105571
+ this.settingsBusy = false;
105292
105572
  this.settingsUpdateError = void 0;
105293
105573
  this.settingsRows = this.readSettingsRows();
105294
105574
  this.setFeedback(`\u2713 \u5DF2\u66F4\u65B0 ${row.field}`);
105295
105575
  } catch (error51) {
105296
105576
  if (this.closed) return;
105577
+ this.settingsBusy = false;
105297
105578
  this.settingsUpdateError = errorReason(error51);
105298
105579
  this.settingsRows = this.readSettingsRows();
105299
105580
  this.emit();
@@ -105391,10 +105672,9 @@ ${row.hint ?? ""}` });
105391
105672
  }
105392
105673
  if (this.isDisposed()) return;
105393
105674
  this.settingsBusy = false;
105394
- this.settingsOpen = false;
105395
105675
  this.settingsEditing = false;
105396
- this.settingsOnboarding = false;
105397
105676
  this.settingsUpdateError = void 0;
105677
+ this.settingsRows = this.readSettingsRows();
105398
105678
  this.setFeedback(`\u2713 \u5DF2\u5199\u5165 ${String(discovered.length)} \u4E2A\u6A21\u578B`);
105399
105679
  }
105400
105680
  /** Surface a discovery refusal on the overlay; nothing was written. */
@@ -105559,7 +105839,7 @@ ${row.hint ?? ""}` });
105559
105839
  * Leaves the overlay open.
105560
105840
  */
105561
105841
  exportSettingsDocument() {
105562
- if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding) return;
105842
+ if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding || this.settingsBusy) return;
105563
105843
  const settings = this.ctx.get("settings");
105564
105844
  if (settings === void 0 || typeof settings.prepareDocument !== "function") {
105565
105845
  this.setFeedback("\u65E0\u53EF\u7528\u8BBE\u7F6E\u6587\u4EF6");
@@ -105582,7 +105862,7 @@ ${row.hint ?? ""}` });
105582
105862
  * Reread overlay rows from the live host without closing the overlay.
105583
105863
  */
105584
105864
  reloadSettingsRows() {
105585
- if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding) return;
105865
+ if (!this.settingsOpen || this.settingsEditing || this.settingsOnboarding || this.settingsBusy) return;
105586
105866
  this.settingsRows = this.readSettingsRows();
105587
105867
  if (this.settingsSelectedIndex >= this.settingsRows.length) {
105588
105868
  this.settingsSelectedIndex = Math.max(0, this.settingsRows.length - 1);