mixdog 0.9.26 → 0.9.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +2 -1
  2. package/scripts/arg-guard-test.mjs +68 -0
  3. package/scripts/compacted-placeholder-scrub-test.mjs +77 -0
  4. package/src/cli.mjs +40 -4
  5. package/src/rules/shared/01-tool.md +3 -0
  6. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  7. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +30 -0
  8. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +5 -0
  9. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +14 -1
  10. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +1 -1
  11. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  12. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +1 -1
  13. package/src/runtime/memory/tool-defs.mjs +2 -2
  14. package/src/runtime/shared/staged-install-worker.mjs +14 -0
  15. package/src/runtime/shared/staged-update.mjs +530 -0
  16. package/src/runtime/shared/update-checker.mjs +1 -1
  17. package/src/session-runtime/lifecycle-api.mjs +9 -11
  18. package/src/session-runtime/runtime-core.mjs +35 -36
  19. package/src/standalone/agent-tool/tool-def.mjs +1 -1
  20. package/src/tui/app/transcript-window.mjs +26 -6
  21. package/src/tui/components/Spinner.jsx +5 -2
  22. package/src/tui/components/StatusLine.jsx +7 -7
  23. package/src/tui/components/ToolExecution.jsx +24 -58
  24. package/src/tui/display-width.mjs +8 -4
  25. package/src/tui/dist/index.mjs +373 -269
  26. package/src/tui/hooks/useSharedTick.mjs +103 -0
  27. package/src/tui/markdown/format-token.mjs +46 -8
  28. package/src/tui/markdown/render-ansi.mjs +24 -1
  29. package/src/tui/markdown/stream-fence.mjs +60 -0
  30. package/src/tui/markdown/streaming-markdown.mjs +22 -1
  31. package/vendor/ink/build/display-width.js +5 -4
@@ -163,7 +163,7 @@ import { performance as performance3 } from "node:perf_hooks";
163
163
  import { format } from "node:util";
164
164
 
165
165
  // src/tui/App.jsx
166
- import React20, { useState as useState8, useCallback as useCallback6, useEffect as useEffect10, useLayoutEffect as useLayoutEffect4, useMemo as useMemo2, useRef as useRef9 } from "react";
166
+ import React20, { useState as useState8, useCallback as useCallback6, useEffect as useEffect10, useLayoutEffect as useLayoutEffect4, useMemo as useMemo2, useRef as useRef10 } from "react";
167
167
  import { Box as Box18, Text as Text20, useApp, useInput as useInput5, useStdin as useStdin3, useStdout as useStdout2 } from "../../../vendor/ink/build/index.js";
168
168
 
169
169
  // src/tui/themes/base.mjs
@@ -3100,8 +3100,67 @@ function formatAggregateDetail(summaries) {
3100
3100
  }
3101
3101
 
3102
3102
  // src/tui/components/Spinner.jsx
3103
- import React, { useRef } from "react";
3104
- import { Box, Text, useAnimation } from "../../../vendor/ink/build/index.js";
3103
+ import React, { useRef as useRef2 } from "react";
3104
+ import { Box, Text } from "../../../vendor/ink/build/index.js";
3105
+
3106
+ // src/tui/hooks/useSharedTick.mjs
3107
+ import { useEffect, useRef, useState } from "react";
3108
+ var TICK_SLOP_MS = 16;
3109
+ var subscribers = /* @__PURE__ */ new Set();
3110
+ var timer = null;
3111
+ function nextDelayMs(now) {
3112
+ let soonest = Infinity;
3113
+ for (const sub of subscribers) {
3114
+ const due = sub.lastFire + sub.interval - now;
3115
+ if (due < soonest) soonest = due;
3116
+ }
3117
+ return Number.isFinite(soonest) ? Math.max(1, soonest) : null;
3118
+ }
3119
+ function reconcileTimer() {
3120
+ if (timer) {
3121
+ clearTimeout(timer);
3122
+ timer = null;
3123
+ }
3124
+ const delay = nextDelayMs(Date.now());
3125
+ if (delay == null) return;
3126
+ timer = setTimeout(onTick, delay);
3127
+ timer.unref?.();
3128
+ }
3129
+ function onTick() {
3130
+ timer = null;
3131
+ const now = Date.now();
3132
+ for (const sub of Array.from(subscribers)) {
3133
+ if (!subscribers.has(sub)) continue;
3134
+ if (now - sub.lastFire >= sub.interval - TICK_SLOP_MS) {
3135
+ sub.lastFire = now;
3136
+ sub.notify(now);
3137
+ }
3138
+ }
3139
+ reconcileTimer();
3140
+ }
3141
+ function useSharedTick(intervalMs, isActive = true, onTick2 = null) {
3142
+ const [, setTick] = useState(0);
3143
+ const cbRef = useRef(onTick2);
3144
+ cbRef.current = onTick2;
3145
+ useEffect(() => {
3146
+ if (!isActive) return void 0;
3147
+ const interval = Math.max(1, Number(intervalMs) || 0);
3148
+ const sub = {
3149
+ interval,
3150
+ lastFire: Date.now(),
3151
+ notify: (now) => {
3152
+ if (cbRef.current) cbRef.current(now);
3153
+ else setTick((t) => (t + 1) % 1e6);
3154
+ }
3155
+ };
3156
+ subscribers.add(sub);
3157
+ reconcileTimer();
3158
+ return () => {
3159
+ subscribers.delete(sub);
3160
+ reconcileTimer();
3161
+ };
3162
+ }, [intervalMs, isActive]);
3163
+ }
3105
3164
 
3106
3165
  // src/tui/spinner-verbs.mjs
3107
3166
  var SPINNER_VERBS = [
@@ -3438,19 +3497,19 @@ function tokenModeGlyph(mode) {
3438
3497
  }
3439
3498
  }
3440
3499
  function Spinner({ verb = "Working", startedAt, outputTokens = 0, tokens = 0, thinking = false, thinkingActiveSince = 0, mode = "responding", columns = 80, marginTop = 1 }) {
3441
- useAnimation({ interval: FRAME_MS });
3500
+ useSharedTick(FRAME_MS);
3442
3501
  const { TEXT_RGB, SHIMMER_RGB, SPINNER_GLYPH_RGB, THINKING_INACTIVE, THINKING_SHIMMER, STALL_RGB } = spinnerRgb();
3443
3502
  const now = Date.now();
3444
3503
  const elapsedMs = startedAt ? Math.max(0, now - startedAt) : 0;
3445
3504
  const frame = Math.floor(elapsedMs / FRAME_MS);
3446
- const lastGrowRef = useRef(now);
3447
- const lastTokensRef = useRef(0);
3448
- const displayedOutputRef = useRef(0);
3449
- const displayVerbRef = useRef("");
3450
- const displayVerbModeRef = useRef("");
3451
- const nextVerbCheckRef = useRef(0);
3452
- const stallSmoothRef = useRef(0);
3453
- const lastStallTickRef = useRef(0);
3505
+ const lastGrowRef = useRef2(now);
3506
+ const lastTokensRef = useRef2(0);
3507
+ const displayedOutputRef = useRef2(0);
3508
+ const displayVerbRef = useRef2("");
3509
+ const displayVerbModeRef = useRef2("");
3510
+ const nextVerbCheckRef = useRef2(0);
3511
+ const stallSmoothRef = useRef2(0);
3512
+ const lastStallTickRef = useRef2(0);
3454
3513
  const targetOutputTokens = Math.max(0, Number(outputTokens || tokens || 0));
3455
3514
  if (targetOutputTokens > lastTokensRef.current) {
3456
3515
  lastTokensRef.current = targetOutputTokens;
@@ -3559,7 +3618,7 @@ function Spinner({ verb = "Working", startedAt, outputTokens = 0, tokens = 0, th
3559
3618
  }
3560
3619
 
3561
3620
  // src/tui/components/StatusLine.jsx
3562
- import React2, { useEffect, useRef as useRef2, useState } from "react";
3621
+ import React2, { useEffect as useEffect2, useRef as useRef3, useState as useState2 } from "react";
3563
3622
  import { Box as Box2, Text as Text2 } from "../../../vendor/ink/build/index.js";
3564
3623
 
3565
3624
  // src/tui/statusline-ansi-bridge.mjs
@@ -3693,11 +3752,11 @@ var statuslineModulePrewarmScheduled = false;
3693
3752
  function scheduleStatuslineModulePrewarm() {
3694
3753
  if (statuslineModulePrewarmScheduled) return;
3695
3754
  statuslineModulePrewarmScheduled = true;
3696
- const timer = setTimeout(() => {
3755
+ const timer2 = setTimeout(() => {
3697
3756
  loadStatuslineModule().catch(() => {
3698
3757
  });
3699
3758
  }, STATUSLINE_MODULE_PREWARM_DELAY_MS);
3700
- timer.unref?.();
3759
+ timer2.unref?.();
3701
3760
  }
3702
3761
  var STATUSLINE_BOOT_FULL_DELAY_MS = 1e3;
3703
3762
  var STATUSLINE_BOOT_FULL_DELAY_ACTIVE_MS = 2200;
@@ -4006,7 +4065,7 @@ function workflowModeLabel(workflow = {}, remoteEnabled = false) {
4006
4065
  return remoteEnabled === true ? `Remote / ${base}` : base;
4007
4066
  }
4008
4067
  function StatusLineView({ sessionId, clientHostPid, provider, model, effort, fast, cwd, stats, contextWindow, displayContextWindow = 0, compactBoundaryTokens = 0, autoCompactTokenLimit = 0, rawContextWindow, resizeEpoch, agentRevision = "", agentWorkers = [], agentJobs = [], activeTools = null, initialLine = "", workflow = null, remoteEnabled = false, themeEpoch = 0 }) {
4009
- const [line, setLine] = useState(() => normalizeStatusLine(initialLine || localBootStatusLine({
4068
+ const [line, setLine] = useState2(() => normalizeStatusLine(initialLine || localBootStatusLine({
4010
4069
  provider,
4011
4070
  model,
4012
4071
  effort,
@@ -4021,19 +4080,19 @@ function StatusLineView({ sessionId, clientHostPid, provider, model, effort, fas
4021
4080
  agentJobs,
4022
4081
  activeTools
4023
4082
  })));
4024
- const [refreshTick, setRefreshTick] = useState(0);
4025
- const statuslineArgsRef = useRef2(null);
4026
- const bootFullDoneRef = useRef2(false);
4027
- const mountAtRef = useRef2(Date.now());
4028
- const lineRef = useRef2("");
4029
- const bootFullNextAttemptAtRef = useRef2(0);
4030
- const bootFullRetryBackoffMsRef = useRef2(STATUSLINE_BOOT_FULL_RETRY_MS);
4031
- const renderEffectIdRef = useRef2(0);
4032
- const lastImmediateArgsRef = useRef2(null);
4033
- const themeEpochRef = useRef2(themeEpoch);
4034
- const lastRawFullLineRef = useRef2("");
4035
- const lastRawFullLineCacheKeyRef = useRef2("");
4036
- const lastRawFullLineAtRef = useRef2(0);
4083
+ const [refreshTick, setRefreshTick] = useState2(0);
4084
+ const statuslineArgsRef = useRef3(null);
4085
+ const bootFullDoneRef = useRef3(false);
4086
+ const mountAtRef = useRef3(Date.now());
4087
+ const lineRef = useRef3("");
4088
+ const bootFullNextAttemptAtRef = useRef3(0);
4089
+ const bootFullRetryBackoffMsRef = useRef3(STATUSLINE_BOOT_FULL_RETRY_MS);
4090
+ const renderEffectIdRef = useRef3(0);
4091
+ const lastImmediateArgsRef = useRef3(null);
4092
+ const themeEpochRef = useRef3(themeEpoch);
4093
+ const lastRawFullLineRef = useRef3("");
4094
+ const lastRawFullLineCacheKeyRef = useRef3("");
4095
+ const lastRawFullLineAtRef = useRef3(0);
4037
4096
  const statuslineArgs = {
4038
4097
  sessionId,
4039
4098
  clientHostPid,
@@ -4074,17 +4133,13 @@ function StatusLineView({ sessionId, clientHostPid, provider, model, effort, fas
4074
4133
  String(statsForSignature.currentContextSource || "")
4075
4134
  ].join("|");
4076
4135
  const refreshMs = hasActiveStatuslineWork(line, agentWorkers, agentJobs, activeTools) ? STATUSLINE_ACTIVE_REFRESH_MS : STATUSLINE_REFRESH_MS;
4077
- useEffect(() => {
4136
+ useEffect2(() => {
4078
4137
  scheduleStatuslineModulePrewarm();
4079
4138
  }, []);
4080
- useEffect(() => {
4081
- const timer = setInterval(() => {
4082
- setRefreshTick((tick) => (tick + 1) % 1e6);
4083
- }, refreshMs);
4084
- timer.unref?.();
4085
- return () => clearInterval(timer);
4086
- }, [refreshMs]);
4087
- useEffect(() => {
4139
+ useSharedTick(refreshMs, true, () => {
4140
+ setRefreshTick((tick) => (tick + 1) % 1e6);
4141
+ });
4142
+ useEffect2(() => {
4088
4143
  let alive = true;
4089
4144
  let bootRetryTimer = null;
4090
4145
  const effectId = renderEffectIdRef.current + 1;
@@ -4146,7 +4201,7 @@ ${grafted}` : cachedL1;
4146
4201
  autoCompactTokenLimit: args.autoCompactTokenLimit,
4147
4202
  stats: args.stats
4148
4203
  };
4149
- const timer = setTimeout(() => {
4204
+ const timer2 = setTimeout(() => {
4150
4205
  if (bootFullDoneRef.current !== true) {
4151
4206
  if (!bootFullRenderEligible(mountAtRef.current, lineRef.current, args.agentWorkers, args.agentJobs, args.activeTools)) {
4152
4207
  const active = hasActiveStatuslineWork(lineRef.current, args.agentWorkers, args.agentJobs, args.activeTools);
@@ -4192,10 +4247,10 @@ ${grafted}` : cachedL1;
4192
4247
  resetStatuslineModuleLoad();
4193
4248
  });
4194
4249
  }, STATUSLINE_RENDER_DEBOUNCE_MS);
4195
- timer.unref?.();
4250
+ timer2.unref?.();
4196
4251
  return () => {
4197
4252
  alive = false;
4198
- clearTimeout(timer);
4253
+ clearTimeout(timer2);
4199
4254
  clearTimeout(bootRetryTimer);
4200
4255
  };
4201
4256
  }, [sessionId, clientHostPid, provider, model, effort, fast, cwd, statsSignature, contextWindow, displayContextWindow, compactBoundaryTokens, autoCompactTokenLimit, rawContextWindow, resizeEpoch, agentRevision, agentWorkersSignature, agentJobsSignature, activeToolsSignature, refreshTick, themeEpoch]);
@@ -4212,16 +4267,16 @@ ${grafted}` : cachedL1;
4212
4267
  var StatusLine = React2.memo(StatusLineView);
4213
4268
 
4214
4269
  // src/tui/components/PromptInput.jsx
4215
- import React3, { useEffect as useEffect2, useLayoutEffect, useState as useState2, useRef as useRef3 } from "react";
4270
+ import React3, { useEffect as useEffect3, useLayoutEffect, useState as useState3, useRef as useRef4 } from "react";
4216
4271
  import { Box as Box3, Text as Text3, useInput, usePaste, useStdin } from "../../../vendor/ink/build/index.js";
4217
4272
 
4218
4273
  // src/tui/display-width.mjs
4219
4274
  import stringWidth from "string-width";
4220
4275
  var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
4221
4276
  function isProblemCodePoint(cp) {
4222
- return cp >= 9312 && cp <= 9471 || cp >= 8592 && cp <= 8703;
4277
+ return cp >= 9312 && cp <= 9471 || cp >= 8596 && cp <= 8703;
4223
4278
  }
4224
- var PROBLEM_RE = /[\u2190-\u21ff\u2460-\u24ff]/;
4279
+ var PROBLEM_RE = /[\u2194-\u21ff\u2460-\u24ff]/;
4225
4280
  function resolveAmbiguousWidePolicy(env = process.env, platform = process.platform) {
4226
4281
  const override = env?.MIXDOG_TUI_AMBIGUOUS_WIDE;
4227
4282
  if (override === "1") return true;
@@ -4577,29 +4632,29 @@ function PromptInput({
4577
4632
  mouseSelectionRef,
4578
4633
  suppressShiftNavRef
4579
4634
  }) {
4580
- const [draft, setDraft] = useState2(() => {
4635
+ const [draft, setDraft] = useState3(() => {
4581
4636
  const value2 = String(initialValue || "");
4582
4637
  return { value: value2, cursor: value2.length, selectionAnchor: null };
4583
4638
  });
4584
- const [, bumpCursorAnchorEpoch] = useState2(0);
4585
- const draftRef = useRef3(draft);
4586
- const lastReportedValueRef = useRef3(draft.value);
4587
- const pasteGenerationRef = useRef3(0);
4639
+ const [, bumpCursorAnchorEpoch] = useState3(0);
4640
+ const draftRef = useRef4(draft);
4641
+ const lastReportedValueRef = useRef4(draft.value);
4642
+ const pasteGenerationRef = useRef4(0);
4588
4643
  if (valueRef) valueRef.current = draftRef.current.value;
4589
4644
  const { isRawModeSupported } = useStdin();
4590
- const boxRef = useRef3(null);
4591
- const cursorEnabledRef = useRef3(false);
4592
- const contentWidthRef = useRef3(80);
4593
- const preferredColumnRef = useRef3(null);
4594
- const mouseExtendCoalesceRef = useRef3({ pendingNext: null, timer: null, t: 0 });
4595
- const undoRef = useRef3({ past: [], future: [], lastPushAt: 0, lastValue: null });
4645
+ const boxRef = useRef4(null);
4646
+ const cursorEnabledRef = useRef4(false);
4647
+ const contentWidthRef = useRef4(80);
4648
+ const preferredColumnRef = useRef4(null);
4649
+ const mouseExtendCoalesceRef = useRef4({ pendingNext: null, timer: null, t: 0 });
4650
+ const undoRef = useRef4({ past: [], future: [], lastPushAt: 0, lastValue: null });
4596
4651
  const { value, cursor } = draft;
4597
4652
  draftRef.current = draft;
4598
4653
  if (selectionRef) {
4599
4654
  const range = selectionRange(draft);
4600
4655
  selectionRef.current = range ? { range, text: mask ? "" : draft.value.slice(range.start, range.end) } : null;
4601
4656
  }
4602
- const flushThrottleRef = useRef3({ lastAt: 0, timer: null });
4657
+ const flushThrottleRef = useRef4({ lastAt: 0, timer: null });
4603
4658
  const flushImmediate = () => {
4604
4659
  let node = boxRef.current;
4605
4660
  for (let i = 0; node && i < 64; i++) {
@@ -4816,7 +4871,7 @@ function PromptInput({
4816
4871
  }
4817
4872
  };
4818
4873
  }
4819
- useEffect2(() => () => {
4874
+ useEffect3(() => () => {
4820
4875
  const state = mouseExtendCoalesceRef.current;
4821
4876
  if (state.timer) clearTimeout(state.timer);
4822
4877
  state.timer = null;
@@ -4879,13 +4934,13 @@ function PromptInput({
4879
4934
  apply(handled);
4880
4935
  }
4881
4936
  };
4882
- useEffect2(() => {
4937
+ useEffect3(() => {
4883
4938
  if (!draftOverride || typeof draftOverride.value !== "string") return;
4884
4939
  pasteGenerationRef.current += 1;
4885
4940
  commitDraft({ value: draftOverride.value, cursor: draftOverride.value.length, selectionAnchor: null }, { skipHistory: true });
4886
4941
  resetUndo();
4887
4942
  }, [draftOverride?.id]);
4888
- useEffect2(() => () => {
4943
+ useEffect3(() => () => {
4889
4944
  pasteGenerationRef.current += 1;
4890
4945
  if (selectionRef) selectionRef.current = null;
4891
4946
  }, [selectionRef]);
@@ -5270,7 +5325,7 @@ function QueuedCommands({ queued, columns, compact = false }) {
5270
5325
  }
5271
5326
 
5272
5327
  // src/tui/components/Picker.jsx
5273
- import React6, { useState as useState3, useCallback, useEffect as useEffect3, useRef as useRef4 } from "react";
5328
+ import React6, { useState as useState4, useCallback, useEffect as useEffect4, useRef as useRef5 } from "react";
5274
5329
  import { Box as Box6, Text as Text6, useInput as useInput2 } from "../../../vendor/ink/build/index.js";
5275
5330
  import stringWidth2 from "string-width";
5276
5331
 
@@ -5388,20 +5443,20 @@ function Picker({
5388
5443
  themeEpoch = 0
5389
5444
  }) {
5390
5445
  const visibleLimit = Math.max(1, Math.floor(Number(visibleCount) || MAX_VISIBLE));
5391
- const [selectedIndex, setSelectedIndex] = useState3(() => Math.max(0, Math.min(Number(initialIndex) || 0, Math.max(0, items.length - 1))));
5446
+ const [selectedIndex, setSelectedIndex] = useState4(() => Math.max(0, Math.min(Number(initialIndex) || 0, Math.max(0, items.length - 1))));
5392
5447
  const confirmButtons = Array.isArray(confirmBar?.buttons) ? confirmBar.buttons.filter(Boolean) : [];
5393
5448
  const hasConfirm = confirmButtons.length > 0;
5394
- const [confirmFocus, setConfirmFocus] = useState3(-1);
5395
- const lastTabAtRef = useRef4(0);
5396
- useEffect3(() => {
5449
+ const [confirmFocus, setConfirmFocus] = useState4(-1);
5450
+ const lastTabAtRef = useRef5(0);
5451
+ useEffect4(() => {
5397
5452
  setConfirmFocus(-1);
5398
5453
  }, [confirmButtons.length, confirmBar]);
5399
- const [selectionMemo] = useState3(() => ({ value: null, initialIndex }));
5400
- useEffect3(() => {
5454
+ const [selectionMemo] = useState4(() => ({ value: null, initialIndex }));
5455
+ useEffect4(() => {
5401
5456
  const item = items[selectedIndex];
5402
5457
  if (item && item.value != null) selectionMemo.value = item.value;
5403
5458
  }, [items, selectedIndex, selectionMemo]);
5404
- useEffect3(() => {
5459
+ useEffect4(() => {
5405
5460
  setSelectedIndex((i) => {
5406
5461
  if (selectionMemo.value != null) {
5407
5462
  const found = items.findIndex((entry) => entry && entry.value === selectionMemo.value);
@@ -5412,7 +5467,7 @@ function Picker({
5412
5467
  return Math.min(Math.max(0, i), Math.max(0, items.length - 1));
5413
5468
  });
5414
5469
  }, [items, selectionMemo, initialIndex]);
5415
- useEffect3(() => {
5470
+ useEffect4(() => {
5416
5471
  if (initialIndex == null) {
5417
5472
  selectionMemo.initialIndex = null;
5418
5473
  return;
@@ -5421,7 +5476,7 @@ function Picker({
5421
5476
  selectionMemo.initialIndex = initialIndex;
5422
5477
  setSelectedIndex(Math.max(0, Math.min(Number(initialIndex) || 0, Math.max(0, items.length - 1))));
5423
5478
  }, [initialIndex, items.length, selectionMemo]);
5424
- useEffect3(() => {
5479
+ useEffect4(() => {
5425
5480
  if (typeof onHighlight !== "function") return;
5426
5481
  const item = items[selectedIndex];
5427
5482
  if (item) onHighlight(item.value, item, selectedIndex);
@@ -6048,7 +6103,7 @@ function ContextPanel({ rows, title = "Context Usage", columns = 80, fillHeight
6048
6103
  }
6049
6104
 
6050
6105
  // src/tui/components/UsagePanel.jsx
6051
- import React9, { useEffect as useEffect4, useState as useState4 } from "react";
6106
+ import React9, { useEffect as useEffect5, useState as useState5 } from "react";
6052
6107
  import { Box as Box9, Text as Text9, useInput as useInput3 } from "../../../vendor/ink/build/index.js";
6053
6108
  import stringWidth5 from "string-width";
6054
6109
  import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
@@ -6265,11 +6320,11 @@ function UsagePanel({ dashboard, loading = false, columns = 80, fillHeight = fal
6265
6320
  const hasMeasuredRows = Number(panelRows) > 0;
6266
6321
  const maxProviderRows = hasMeasuredRows ? Math.max(1, Math.floor(panelRows) - 6) : rows.length;
6267
6322
  const maxScrollOffset = Math.max(0, rows.length - maxProviderRows);
6268
- const [scrollOffset, setScrollOffset] = useState4(0);
6323
+ const [scrollOffset, setScrollOffset] = useState5(0);
6269
6324
  const visibleRows = hasMeasuredRows ? rows.slice(scrollOffset, scrollOffset + maxProviderRows) : rows;
6270
6325
  const scrollable = rows.length > maxProviderRows;
6271
6326
  const helpText = `${scrollable || isLoading || isChecking ? "\u2191/\u2193 Scroll \xB7 PgUp/PgDn Page \xB7 " : ""}Esc Back \xB7 /usage refresh`;
6272
- useEffect4(() => {
6327
+ useEffect5(() => {
6273
6328
  setScrollOffset((offset) => Math.min(Math.max(0, offset), maxScrollOffset));
6274
6329
  }, [maxScrollOffset]);
6275
6330
  useInput3((input, key) => {
@@ -6342,7 +6397,7 @@ function UsagePanel({ dashboard, loading = false, columns = 80, fillHeight = fal
6342
6397
  }
6343
6398
 
6344
6399
  // src/tui/components/TextEntryPanel.jsx
6345
- import React10, { useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState5 } from "react";
6400
+ import React10, { useEffect as useEffect6, useLayoutEffect as useLayoutEffect2, useRef as useRef6, useState as useState6 } from "react";
6346
6401
  import { Box as Box10, Text as Text10, useInput as useInput4, usePaste as usePaste2, useStdin as useStdin2 } from "../../../vendor/ink/build/index.js";
6347
6402
  import stringWidth6 from "string-width";
6348
6403
 
@@ -6555,13 +6610,13 @@ function TextEntryPanel({
6555
6610
  onSubmit,
6556
6611
  onCancel
6557
6612
  }) {
6558
- const [draft, setDraft] = useState5(() => ({ value: String(initialValue || ""), cursor: String(initialValue || "").length, selectionAnchor: null }));
6559
- const [, bumpCursorAnchorEpoch] = useState5(0);
6560
- const draftRef = useRef5(draft);
6561
- const boxRef = useRef5(null);
6562
- const cursorEnabledRef = useRef5(false);
6563
- const contentWidthRef = useRef5(80);
6564
- const preferredColumnRef = useRef5(null);
6613
+ const [draft, setDraft] = useState6(() => ({ value: String(initialValue || ""), cursor: String(initialValue || "").length, selectionAnchor: null }));
6614
+ const [, bumpCursorAnchorEpoch] = useState6(0);
6615
+ const draftRef = useRef6(draft);
6616
+ const boxRef = useRef6(null);
6617
+ const cursorEnabledRef = useRef6(false);
6618
+ const contentWidthRef = useRef6(80);
6619
+ const preferredColumnRef = useRef6(null);
6565
6620
  const { isRawModeSupported } = useStdin2();
6566
6621
  draftRef.current = draft;
6567
6622
  const flushImmediate = () => {
@@ -6597,13 +6652,13 @@ function TextEntryPanel({
6597
6652
  commitDraft(moveCursor(current, moved.cursor, { extend }), { keepPreferredColumn: true });
6598
6653
  return true;
6599
6654
  };
6600
- useEffect5(() => {
6655
+ useEffect6(() => {
6601
6656
  const value = String(initialValue || "");
6602
6657
  commitDraft({ value, cursor: value.length, selectionAnchor: null });
6603
6658
  }, [title, initialValue]);
6604
6659
  const labelCells = stringWidth6(String(promptLabel || ""));
6605
6660
  const contentCells = Math.max(1, columns - 4 - labelCells);
6606
- useEffect5(() => {
6661
+ useEffect6(() => {
6607
6662
  if (!multiline) {
6608
6663
  onContentRowsChange?.(1);
6609
6664
  return;
@@ -7381,7 +7436,7 @@ function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
7381
7436
  }
7382
7437
  let stdout = "";
7383
7438
  let settled = false;
7384
- const timer = setTimeout(() => {
7439
+ const timer2 = setTimeout(() => {
7385
7440
  if (settled) return;
7386
7441
  settled = true;
7387
7442
  try {
@@ -7390,20 +7445,20 @@ function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
7390
7445
  }
7391
7446
  resolve5({ ok: false, code: -1, stdout: "", error: new Error("dialog timed out") });
7392
7447
  }, timeoutMs);
7393
- timer.unref?.();
7448
+ timer2.unref?.();
7394
7449
  child.stdout.on("data", (chunk) => {
7395
7450
  stdout += chunk.toString("utf8");
7396
7451
  });
7397
7452
  child.on("error", (error) => {
7398
7453
  if (settled) return;
7399
7454
  settled = true;
7400
- clearTimeout(timer);
7455
+ clearTimeout(timer2);
7401
7456
  resolve5({ ok: false, code: -1, stdout: "", error });
7402
7457
  });
7403
7458
  child.on("close", (code) => {
7404
7459
  if (settled) return;
7405
7460
  settled = true;
7406
- clearTimeout(timer);
7461
+ clearTimeout(timer2);
7407
7462
  resolve5({ ok: code === 0, code, stdout });
7408
7463
  });
7409
7464
  });
@@ -7989,7 +8044,7 @@ function copyToClipboard(text) {
7989
8044
  import stringWidth11 from "string-width";
7990
8045
 
7991
8046
  // src/tui/app/use-mouse-input.mjs
7992
- import { useCallback as useCallback2, useEffect as useEffect6, useRef as useRef6 } from "react";
8047
+ import { useCallback as useCallback2, useEffect as useEffect7, useRef as useRef7 } from "react";
7993
8048
 
7994
8049
  // src/tui/markdown/measure-rendered-rows.mjs
7995
8050
  import stripAnsi4 from "strip-ansi";
@@ -8454,6 +8509,25 @@ function collectFlatBodyLines(text, codeBlock, bandWidth) {
8454
8509
  }
8455
8510
  return lines;
8456
8511
  }
8512
+ function normalizeCodePlain(text) {
8513
+ return String(text ?? "").replace(/\r\n?/g, "\n").replace(/\t/g, " ").replace(/[\u0000-\u0009\u000b-\u001f\u007f]/g, " ");
8514
+ }
8515
+ function collectPlainBodyLines(text, codeBlock, bandWidth) {
8516
+ const max = Math.max(1, bandWidth);
8517
+ const lines = [];
8518
+ for (const line of String(text ?? "").split(EOL)) {
8519
+ if (!line) {
8520
+ lines.push("");
8521
+ continue;
8522
+ }
8523
+ if (line.length <= max && displayWidth(line) <= max) {
8524
+ lines.push(codeBlock(line));
8525
+ } else {
8526
+ for (const seg of wrapCodeLine(codeBlock(line), max)) lines.push(seg);
8527
+ }
8528
+ }
8529
+ return lines;
8530
+ }
8457
8531
  function collectHighlightedBodyLines(text, hljsLang, bandWidth) {
8458
8532
  const highlighted = highlightCodeText(text, hljsLang);
8459
8533
  const { codeBlock } = colorizers();
@@ -8469,19 +8543,24 @@ function renderCodeBlock(token, width = 0) {
8469
8543
  const { codeBlock } = colorizers();
8470
8544
  const c = extraColorizers();
8471
8545
  const lang = normalizeLang(token.lang);
8472
- const text = normalizeCodeText(decodeEntities(token.text ?? ""));
8473
8546
  const renderWidth = Math.max(8, Number(width) || 80);
8474
8547
  const contentWidth = Math.max(1, renderWidth - CODE_GUTTER.length);
8475
8548
  let bodyLines;
8476
- if (DIFF_LANGS.has(lang) || !lang && looksLikeUnifiedDiff(text)) {
8477
- bodyLines = collectDiffBodyLines(text, c, contentWidth);
8549
+ if (token.plain) {
8550
+ const text = normalizeCodePlain(decodeEntities(token.text ?? ""));
8551
+ bodyLines = collectPlainBodyLines(text, codeBlock, contentWidth);
8478
8552
  } else {
8479
- const hljsLang = resolveHljsLanguage(lang);
8480
- const family = LANG_FAMILY[lang];
8481
- if (hljsLang && family !== "md") {
8482
- bodyLines = collectHighlightedBodyLines(text, hljsLang, contentWidth);
8553
+ const text = normalizeCodeText(decodeEntities(token.text ?? ""));
8554
+ if (DIFF_LANGS.has(lang) || !lang && looksLikeUnifiedDiff(text)) {
8555
+ bodyLines = collectDiffBodyLines(text, c, contentWidth);
8483
8556
  } else {
8484
- bodyLines = collectFlatBodyLines(text, codeBlock, contentWidth);
8557
+ const hljsLang = resolveHljsLanguage(lang);
8558
+ const family = LANG_FAMILY[lang];
8559
+ if (hljsLang && family !== "md") {
8560
+ bodyLines = collectHighlightedBodyLines(text, hljsLang, contentWidth);
8561
+ } else {
8562
+ bodyLines = collectFlatBodyLines(text, codeBlock, contentWidth);
8563
+ }
8485
8564
  }
8486
8565
  }
8487
8566
  const indentedBody = bodyLines.map((line) => `${CODE_GUTTER}${line ?? ""}`);
@@ -8903,6 +8982,38 @@ function trimPartialClosingFences(tokens) {
8903
8982
  if (lastLine.length >= marker.length || lastLine !== marker[0].repeat(lastLine.length)) return;
8904
8983
  token.text = String(token.text ?? "").slice(0, -lastLine.length).replace(/\n$/, "");
8905
8984
  }
8985
+ var OPEN_FENCE_RE = /^( {0,3})(`{3,}|~{3,})(.*)$/;
8986
+ var CLOSE_FENCE_RE = /^ {0,3}([`~]+)[ \t]*$/;
8987
+ function isClosingFence(line, char, openLen) {
8988
+ const m = CLOSE_FENCE_RE.exec(line);
8989
+ if (!m) return false;
8990
+ const run = m[1];
8991
+ return run.startsWith(char.repeat(openLen));
8992
+ }
8993
+ function findOpenFenceStart(text) {
8994
+ const value = String(text ?? "");
8995
+ let open = null;
8996
+ let start = 0;
8997
+ for (let i = 0; i <= value.length; i++) {
8998
+ if (i !== value.length && value[i] !== "\n") continue;
8999
+ const line = value.slice(start, i);
9000
+ if (!open) {
9001
+ const m = OPEN_FENCE_RE.exec(line);
9002
+ if (m) {
9003
+ const char = m[2][0];
9004
+ const info = m[3];
9005
+ if (!(char === "`" && info.indexOf("`") !== -1)) {
9006
+ open = { index: start, indent: m[1].length, char, len: m[2].length, lang: info.trim() };
9007
+ }
9008
+ }
9009
+ } else if (isClosingFence(line, open.char, open.len)) {
9010
+ open = null;
9011
+ }
9012
+ start = i + 1;
9013
+ }
9014
+ if (!open || open.indent !== 0) return null;
9015
+ return { index: open.index, lang: open.lang };
9016
+ }
8906
9017
 
8907
9018
  // src/tui/markdown/render-ansi.mjs
8908
9019
  var TOKEN_CACHE_MAX = 500;
@@ -8932,6 +9043,23 @@ function lexMarkdown(content, { trimPartialFences = false } = {}) {
8932
9043
  }];
8933
9044
  }
8934
9045
  if (trimPartialFences) {
9046
+ const open = findOpenFenceStart(text);
9047
+ if (open) {
9048
+ const post = text.slice(open.index);
9049
+ const nl = post.indexOf("\n");
9050
+ const codeToken = {
9051
+ type: "code",
9052
+ raw: post,
9053
+ lang: open.lang,
9054
+ text: nl === -1 ? "" : post.slice(nl + 1),
9055
+ plain: true
9056
+ };
9057
+ const pre = text.slice(0, open.index);
9058
+ const tokens3 = pre ? marked.lexer(pre) : [];
9059
+ tokens3.push(codeToken);
9060
+ trimPartialClosingFences(tokens3);
9061
+ return tokens3;
9062
+ }
8935
9063
  const tokens2 = marked.lexer(text);
8936
9064
  trimPartialClosingFences(tokens2);
8937
9065
  return tokens2;
@@ -9077,6 +9205,21 @@ function resolveStreamingMarkdownParts(text, streamKey) {
9077
9205
  if (!t.startsWith(stablePrefix)) {
9078
9206
  stablePrefix = "";
9079
9207
  }
9208
+ const open = findOpenFenceStart(t);
9209
+ if (open) {
9210
+ let openPrefix = t.substring(0, open.index);
9211
+ if (isWhitespaceOnlyText(openPrefix)) openPrefix = "";
9212
+ if (key && openPrefix) touchStablePrefixKey(key, openPrefix);
9213
+ else if (key) stablePrefixByStreamKey.delete(key);
9214
+ const unstableSuffix2 = t.substring(openPrefix.length);
9215
+ return {
9216
+ plain: false,
9217
+ openFence: true,
9218
+ stablePrefix: openPrefix,
9219
+ unstableSuffix: unstableSuffix2,
9220
+ unstableForRender: unstableSuffix2
9221
+ };
9222
+ }
9080
9223
  try {
9081
9224
  configureMarked();
9082
9225
  const boundary = stablePrefix.length;
@@ -9831,6 +9974,8 @@ function positiveIntEnv(name, fallback) {
9831
9974
  var TRANSCRIPT_WINDOW_MIN_ITEMS = positiveIntEnv("MIXDOG_TUI_TRANSCRIPT_WINDOW_MIN_ITEMS", 12);
9832
9975
  var TRANSCRIPT_WINDOW_OVERSCAN_ROWS = positiveIntEnv("MIXDOG_TUI_TRANSCRIPT_OVERSCAN_ROWS", 16);
9833
9976
  var TRANSCRIPT_WINDOW_MAX_ITEMS = positiveIntEnv("MIXDOG_TUI_TRANSCRIPT_WINDOW_ITEMS", 80);
9977
+ var TRANSCRIPT_WINDOW_TAIL_OVERSCAN_ROWS = positiveIntEnv("MIXDOG_TUI_TRANSCRIPT_TAIL_OVERSCAN_ROWS", 4);
9978
+ var TRANSCRIPT_WINDOW_TAIL_MAX_ITEMS = positiveIntEnv("MIXDOG_TUI_TRANSCRIPT_WINDOW_TAIL_ITEMS", 20);
9834
9979
  var SELECTION_PAINT_INTERVAL_MS = positiveIntEnv("MIXDOG_TUI_SELECTION_PAINT_MS", 24);
9835
9980
  var SCROLL_COALESCE_MS = positiveIntEnv("MIXDOG_TUI_SCROLL_COALESCE_MS", 16);
9836
9981
  var PROMPT_HISTORY_LIMIT = 50;
@@ -10449,12 +10594,14 @@ function transcriptRenderWindow(items, { scrollOffset = 0, viewportHeight = 24,
10449
10594
  return { startIndex: 0, endIndex: itemCount, items: allItems, bottomSpacerRows: 0, totalRows, maxScrollRows, effectiveScrollOffset };
10450
10595
  }
10451
10596
  const minItems = Math.min(TRANSCRIPT_WINDOW_MIN_ITEMS, itemCount);
10452
- const maxItems = Math.max(minItems, TRANSCRIPT_WINDOW_MAX_ITEMS);
10597
+ const atTail = effectiveScrollOffset === 0;
10598
+ const overscanRows = atTail ? TRANSCRIPT_WINDOW_TAIL_OVERSCAN_ROWS : TRANSCRIPT_WINDOW_OVERSCAN_ROWS;
10599
+ const maxItems = Math.max(minItems, atTail ? TRANSCRIPT_WINDOW_TAIL_MAX_ITEMS : TRANSCRIPT_WINDOW_MAX_ITEMS);
10453
10600
  const prefixRows = fallbackIndex.prefixRows;
10454
10601
  const visibleTop = Math.max(0, totalRows - effectiveScrollOffset - viewRows);
10455
10602
  const visibleBottom = Math.min(totalRows, totalRows - effectiveScrollOffset);
10456
- const desiredTop = Math.max(0, visibleTop - TRANSCRIPT_WINDOW_OVERSCAN_ROWS);
10457
- const desiredBottom = Math.min(totalRows, visibleBottom + TRANSCRIPT_WINDOW_OVERSCAN_ROWS);
10603
+ const desiredTop = Math.max(0, visibleTop - overscanRows);
10604
+ const desiredBottom = Math.min(totalRows, visibleBottom + overscanRows);
10458
10605
  let startIndex = Math.max(0, upperBound(prefixRows, desiredTop) - 1);
10459
10606
  let endIndex = Math.min(itemCount, Math.max(startIndex + 1, lowerBound(prefixRows, Math.max(desiredBottom, desiredTop + 1))));
10460
10607
  while (endIndex - startIndex < minItems && startIndex > 0) startIndex--;
@@ -10462,9 +10609,10 @@ function transcriptRenderWindow(items, { scrollOffset = 0, viewportHeight = 24,
10462
10609
  if (endIndex - startIndex > maxItems) {
10463
10610
  const visibleStartIndex = Math.max(0, upperBound(prefixRows, visibleTop) - 1);
10464
10611
  const visibleEndIndex = Math.min(itemCount, Math.max(visibleStartIndex + 1, lowerBound(prefixRows, Math.max(visibleBottom, visibleTop + 1))));
10465
- startIndex = Math.max(0, Math.min(visibleStartIndex, itemCount - maxItems));
10466
- endIndex = Math.min(itemCount, Math.max(visibleEndIndex, startIndex + maxItems));
10467
- if (endIndex - startIndex > maxItems) startIndex = Math.max(0, endIndex - maxItems);
10612
+ const effectiveMaxItems = Math.max(maxItems, visibleEndIndex - visibleStartIndex);
10613
+ startIndex = Math.max(0, Math.min(visibleStartIndex, itemCount - effectiveMaxItems));
10614
+ endIndex = Math.min(itemCount, Math.max(visibleEndIndex, startIndex + effectiveMaxItems));
10615
+ if (endIndex - startIndex > effectiveMaxItems) startIndex = Math.max(0, endIndex - effectiveMaxItems);
10468
10616
  }
10469
10617
  const bottomSpacerRows = Math.max(0, totalRows - (prefixRows[endIndex] || totalRows));
10470
10618
  return {
@@ -10513,8 +10661,8 @@ function useMouseInput({
10513
10661
  setMeasuredRowsVersion,
10514
10662
  clearStitchBuffer
10515
10663
  }) {
10516
- const zoomTimerRef = useRef6(null);
10517
- const edgeAutoscrollRef = useRef6({ dir: 0, timer: null, noMove: 0 });
10664
+ const zoomTimerRef = useRef7(null);
10665
+ const edgeAutoscrollRef = useRef7({ dir: 0, timer: null, noMove: 0 });
10518
10666
  const passthroughCtrlWheelZoom = useCallback2(() => {
10519
10667
  if (!stdout?.write) return;
10520
10668
  try {
@@ -10537,10 +10685,10 @@ function useMouseInput({
10537
10685
  zoomTimerRef.current = setTimeout(() => restore(0), 700);
10538
10686
  zoomTimerRef.current.unref?.();
10539
10687
  }, [stdout, zoomTimerRef]);
10540
- useEffect6(() => () => {
10688
+ useEffect7(() => () => {
10541
10689
  if (zoomTimerRef.current) clearTimeout(zoomTimerRef.current);
10542
10690
  }, [zoomTimerRef]);
10543
- useEffect6(() => {
10691
+ useEffect7(() => {
10544
10692
  if (!inkInput || !isRawModeSupported) return void 0;
10545
10693
  const WHEEL_SGR = /\x1b\[<(\d+);/;
10546
10694
  const linearSelection = (a, b) => {
@@ -10917,7 +11065,7 @@ function useMouseInput({
10917
11065
  }
10918
11066
 
10919
11067
  // src/tui/app/use-transcript-scroll.mjs
10920
- import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef7 } from "react";
11068
+ import { useCallback as useCallback3, useEffect as useEffect8, useRef as useRef8 } from "react";
10921
11069
  function useTranscriptScroll({
10922
11070
  store,
10923
11071
  frameColumns,
@@ -10937,13 +11085,13 @@ function useTranscriptScroll({
10937
11085
  selectionLayoutRef,
10938
11086
  selectionTextRef
10939
11087
  }) {
10940
- const scrollAnimationRef = useRef7(null);
10941
- const selectionPaintRef = useRef7({ t: 0, rect: null, pending: null, timer: null });
10942
- const scrollCoalesceRef = useRef7({ pendingRows: 0, timer: null });
10943
- const selectionTextTimerRef = useRef7(null);
10944
- const stitchBufferRef = useRef7(/* @__PURE__ */ new Map());
10945
- const stitchHarvestTimerRef = useRef7(null);
10946
- const stitchHarvestScrollRef = useRef7(0);
11088
+ const scrollAnimationRef = useRef8(null);
11089
+ const selectionPaintRef = useRef8({ t: 0, rect: null, pending: null, timer: null });
11090
+ const scrollCoalesceRef = useRef8({ pendingRows: 0, timer: null });
11091
+ const selectionTextTimerRef = useRef8(null);
11092
+ const stitchBufferRef = useRef8(/* @__PURE__ */ new Map());
11093
+ const stitchHarvestTimerRef = useRef8(null);
11094
+ const stitchHarvestScrollRef = useRef8(0);
10947
11095
  const clearStitchBuffer = useCallback3(() => {
10948
11096
  stitchBufferRef.current.clear();
10949
11097
  if (stitchHarvestTimerRef.current) {
@@ -11210,14 +11358,14 @@ function useTranscriptScroll({
11210
11358
  if (lr != null && Number.isFinite(lr.x2)) return Math.max(0, lr.x2);
11211
11359
  return Math.max(0, frameColumns - 1);
11212
11360
  }, [store, frameColumns]);
11213
- const gridSelectionActiveRef = useRef7(() => {
11361
+ const gridSelectionActiveRef = useRef8(() => {
11214
11362
  const drag = dragRef.current;
11215
11363
  if (!drag || drag.active) return false;
11216
11364
  if (drag.region !== "transcript" && drag.region !== "status") return false;
11217
11365
  const rect = drag.rect;
11218
11366
  return Boolean(rect) && !(rect.x1 === rect.x2 && rect.y1 === rect.y2);
11219
11367
  });
11220
- useEffect7(() => () => {
11368
+ useEffect8(() => () => {
11221
11369
  const paintState = selectionPaintRef.current;
11222
11370
  if (paintState.timer) clearTimeout(paintState.timer);
11223
11371
  paintState.timer = null;
@@ -11421,7 +11569,7 @@ function useTranscriptScroll({
11421
11569
  }
11422
11570
 
11423
11571
  // src/tui/app/use-transcript-window.mjs
11424
- import { useCallback as useCallback4, useEffect as useEffect8, useLayoutEffect as useLayoutEffect3, useMemo, useRef as useRef8, useState as useState6 } from "react";
11572
+ import { useCallback as useCallback4, useEffect as useEffect9, useLayoutEffect as useLayoutEffect3, useMemo, useRef as useRef9, useState as useState7 } from "react";
11425
11573
  function useTranscriptWindow({
11426
11574
  items,
11427
11575
  themeEpoch,
@@ -11450,14 +11598,14 @@ function useTranscriptWindow({
11450
11598
  measuredRowsVersion,
11451
11599
  setMeasuredRowsVersion
11452
11600
  }) {
11453
- const transcriptTotalRowsRef = useRef8(0);
11454
- const preservedScrollDeltaRef = useRef8(0);
11455
- const committedMaxScrollRowsRef = useRef8(0);
11456
- const incrementalRowIndexCacheRef = useRef8(null);
11457
- const prevViewportGeomRef = useRef8({ contentHeight: 0, floatingPanelRows: 0 });
11458
- const transcriptItemElsRef = useRef8(/* @__PURE__ */ new Map());
11459
- const transcriptMeasureRefCache = useRef8(/* @__PURE__ */ new Map());
11460
- const transcriptMeasureItemsRef = useRef8(/* @__PURE__ */ new Map());
11601
+ const transcriptTotalRowsRef = useRef9(0);
11602
+ const preservedScrollDeltaRef = useRef9(0);
11603
+ const committedMaxScrollRowsRef = useRef9(0);
11604
+ const incrementalRowIndexCacheRef = useRef9(null);
11605
+ const prevViewportGeomRef = useRef9({ contentHeight: 0, floatingPanelRows: 0 });
11606
+ const transcriptItemElsRef = useRef9(/* @__PURE__ */ new Map());
11607
+ const transcriptMeasureRefCache = useRef9(/* @__PURE__ */ new Map());
11608
+ const transcriptMeasureItemsRef = useRef9(/* @__PURE__ */ new Map());
11461
11609
  const transcriptMeasureRef = useCallback4((item) => {
11462
11610
  if (!TRANSCRIPT_MEASURED_ROWS || !item || item.id == null) return void 0;
11463
11611
  if (shouldSuppressFullyFailedToolItem(item)) {
@@ -11855,13 +12003,13 @@ function useTranscriptWindow({
11855
12003
  dragRef.current = { ...dragRef.current, rect: clippedRect };
11856
12004
  paintSelectionRect(clippedRect, { rememberText: false, immediate: true });
11857
12005
  }, [transcriptContentHeight, transcriptWindow.totalRows, transcriptWindow.effectiveScrollOffset, withSelectionClip, paintSelectionRect]);
11858
- useEffect8(() => {
12006
+ useEffect9(() => {
11859
12007
  if (!dragRef.current.rect) return;
11860
12008
  const clippedRect = withSelectionClip(dragRef.current.rect);
11861
12009
  dragRef.current = { ...dragRef.current, rect: clippedRect };
11862
12010
  paintSelectionRect(clippedRect, { rememberText: false, immediate: true });
11863
12011
  }, [themeEpoch, withSelectionClip, paintSelectionRect]);
11864
- useEffect8(() => {
12012
+ useEffect9(() => {
11865
12013
  const maxRows = Math.max(0, Number(transcriptWindow.maxScrollRows) || 0);
11866
12014
  if (scrollTargetRef.current <= maxRows && scrollPositionRef.current <= maxRows && scrollOffset <= maxRows) return;
11867
12015
  stopSmoothScroll();
@@ -17635,16 +17783,16 @@ function reconcileWithDisk(filePath, pend) {
17635
17783
  function scheduleWriteBehind(filePath) {
17636
17784
  if (!filePath) return;
17637
17785
  if (pendingTimers.has(filePath)) clearTimeout(pendingTimers.get(filePath));
17638
- const timer = setTimeout(() => {
17786
+ const timer2 = setTimeout(() => {
17639
17787
  void writeBehindFlush(filePath);
17640
17788
  }, WRITE_BEHIND_MS);
17641
- if (typeof timer.unref === "function") timer.unref();
17642
- pendingTimers.set(filePath, timer);
17789
+ if (typeof timer2.unref === "function") timer2.unref();
17790
+ pendingTimers.set(filePath, timer2);
17643
17791
  }
17644
17792
  async function writeBehindFlush(filePath) {
17645
- const timer = pendingTimers.get(filePath);
17646
- if (timer) {
17647
- clearTimeout(timer);
17793
+ const timer2 = pendingTimers.get(filePath);
17794
+ if (timer2) {
17795
+ clearTimeout(timer2);
17648
17796
  pendingTimers.delete(filePath);
17649
17797
  }
17650
17798
  const pend = pendingAppends.get(filePath);
@@ -17660,7 +17808,7 @@ async function writeBehindFlush(filePath) {
17660
17808
  }
17661
17809
  }
17662
17810
  function flushPromptHistory() {
17663
- for (const timer of pendingTimers.values()) clearTimeout(timer);
17811
+ for (const timer2 of pendingTimers.values()) clearTimeout(timer2);
17664
17812
  pendingTimers.clear();
17665
17813
  for (const [filePath, pend] of pendingAppends) {
17666
17814
  if (!pend.length) continue;
@@ -18170,7 +18318,7 @@ function NoticeMessage({ text, tone, columns = 80 }) {
18170
18318
  }
18171
18319
 
18172
18320
  // src/tui/components/ToolExecution.jsx
18173
- import React16, { useEffect as useEffect9, useState as useState7 } from "react";
18321
+ import React16 from "react";
18174
18322
  import { Box as Box14, Text as Text16 } from "../../../vendor/ink/build/index.js";
18175
18323
  import stringWidth9 from "string-width";
18176
18324
 
@@ -18641,15 +18789,12 @@ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
18641
18789
  var TOOL_BLINK_MS = 500;
18642
18790
  var TOOL_BLINK_LIMIT_MS = 3e3;
18643
18791
  var TOOL_PENDING_SHOW_DELAY_MS = 1e3;
18792
+ var TOOL_ANIM_TICK_MS = TOOL_BLINK_MS;
18644
18793
  function statusCopy(name, label, count, doneCount, pending, isError, args = {}) {
18645
18794
  return formatToolActionHeader(name, args, { pending, count });
18646
18795
  }
18647
18796
  function ToolExecution({ name, args, result, rawResult, isError, errorCount, expanded, columns = 80, attached = false, count = 1, completedCount = 0, startedAt = 0, completedAt = 0, aggregate = false, categories = {}, doneCategories = null, headerFinalized = true, deferredDisplayReady = false }) {
18648
18797
  const rowWidth = Math.max(1, Number(columns || 80));
18649
- const [blinkOn, setBlinkOn] = useState7(true);
18650
- const [blinkExpired, setBlinkExpired] = useState7(false);
18651
- const [pendingDelayElapsed, setPendingDelayElapsed] = useState7(false);
18652
- const [, setElapsedTick] = useState7(0);
18653
18798
  const groupCount = Math.max(1, Number(count || 1));
18654
18799
  const doneCount = Math.max(0, Math.min(groupCount, Number(completedCount || (result == null ? 0 : groupCount))));
18655
18800
  const rt = result == null ? null : String(result).replace(/\s+$/, "");
@@ -18657,13 +18802,19 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, exp
18657
18802
  const pending = doneCount < groupCount;
18658
18803
  const startedAtMs = Number(startedAt || 0);
18659
18804
  const completedAtMs = Number(completedAt || 0);
18660
- const pendingAgeMs = pending && startedAtMs ? Math.max(0, Date.now() - startedAtMs) : 0;
18805
+ const nowMs = Date.now();
18806
+ useSharedTick(TOOL_ANIM_TICK_MS, pending);
18807
+ const pendingAgeMs = pending && startedAtMs ? Math.max(0, nowMs - startedAtMs) : 0;
18808
+ const pendingDelayElapsed = pending ? !startedAtMs || pendingAgeMs >= TOOL_PENDING_SHOW_DELAY_MS : false;
18661
18809
  const hasVisibleProgress = doneCount > 0 || Boolean(String(rt || "").trim());
18662
18810
  const pendingDisplayReady = !pending || !startedAtMs || pendingDelayElapsed || pendingAgeMs >= TOOL_PENDING_SHOW_DELAY_MS || hasVisibleProgress || deferredDisplayReady;
18811
+ const blinkActive = pending && pendingDisplayReady;
18812
+ const blinkExpired = blinkActive && startedAtMs > 0 && nowMs - startedAtMs >= TOOL_BLINK_LIMIT_MS;
18813
+ const blinkOn = !blinkActive || blinkExpired ? true : Math.floor(nowMs / TOOL_BLINK_MS) % 2 === 0;
18663
18814
  const headerPending = pending || headerFinalized === false;
18664
18815
  const hasResult = result != null && Boolean(String(rt || "").trim());
18665
18816
  const hasRawResult = rawResult != null && Boolean(String(rawRt || "").trim());
18666
- const elapsedMs = startedAtMs ? Math.max(0, (pending ? Date.now() : completedAtMs || Date.now()) - startedAtMs) : 0;
18817
+ const elapsedMs = startedAtMs ? Math.max(0, (pending ? nowMs : completedAtMs || nowMs) - startedAtMs) : 0;
18667
18818
  const elapsed = elapsedMs >= 1e3 ? formatElapsed(elapsedMs) : "";
18668
18819
  const failedCount = clampFailureCount(errorCount, groupCount, isError);
18669
18820
  const displayGroupCount = groupCount;
@@ -18673,53 +18824,6 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, exp
18673
18824
  (v) => (v && typeof v === "object" ? Number(v.count || 0) : Number(v || 0)) > 0
18674
18825
  );
18675
18826
  const displayDoneCategories = hasDoneCounts ? normalizedDoneCategories : displayCategories;
18676
- useEffect9(() => {
18677
- if (!pending) {
18678
- setPendingDelayElapsed(false);
18679
- return void 0;
18680
- }
18681
- const started = Number(startedAt || 0);
18682
- if (!started) {
18683
- setPendingDelayElapsed(true);
18684
- return void 0;
18685
- }
18686
- const remaining = TOOL_PENDING_SHOW_DELAY_MS - Math.max(0, Date.now() - started);
18687
- if (remaining <= 0) {
18688
- setPendingDelayElapsed(true);
18689
- return void 0;
18690
- }
18691
- setPendingDelayElapsed(false);
18692
- const timer = setTimeout(() => setPendingDelayElapsed(true), remaining);
18693
- return () => clearTimeout(timer);
18694
- }, [pending, startedAt]);
18695
- useEffect9(() => {
18696
- if (!pending || !pendingDisplayReady || blinkExpired) {
18697
- setBlinkOn(true);
18698
- return void 0;
18699
- }
18700
- const timer = setInterval(() => setBlinkOn((on) => !on), TOOL_BLINK_MS);
18701
- return () => clearInterval(timer);
18702
- }, [pending, pendingDisplayReady, blinkExpired]);
18703
- useEffect9(() => {
18704
- if (!pending || !pendingDisplayReady) {
18705
- setBlinkExpired(false);
18706
- return void 0;
18707
- }
18708
- const started = Number(startedAt || 0);
18709
- const remaining = TOOL_BLINK_LIMIT_MS - (started ? Math.max(0, Date.now() - started) : 0);
18710
- if (remaining <= 0) {
18711
- setBlinkExpired(true);
18712
- return void 0;
18713
- }
18714
- setBlinkExpired(false);
18715
- const timer = setTimeout(() => setBlinkExpired(true), remaining);
18716
- return () => clearTimeout(timer);
18717
- }, [pending, pendingDisplayReady, startedAt]);
18718
- useEffect9(() => {
18719
- if (!pending || !pendingDisplayReady || !startedAtMs) return void 0;
18720
- const timer = setInterval(() => setElapsedTick((tick) => (tick + 1) % 1e6), 1e3);
18721
- return () => clearInterval(timer);
18722
- }, [pending, pendingDisplayReady, startedAtMs]);
18723
18827
  if (pending && !pendingDisplayReady) {
18724
18828
  const placeholderNormalizedName = String(formatToolSurface(name, args)?.normalizedName || "").toLowerCase();
18725
18829
  const placeholderSingleRow = !aggregate && (SKILL_SURFACE_NAMES2.has(placeholderNormalizedName) || isAgentTool(placeholderNormalizedName));
@@ -19128,7 +19232,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19128
19232
  const { stdout } = useStdout2();
19129
19233
  const [exiting, setExiting] = useState8(false);
19130
19234
  const [tuiReady, setTuiReady] = useState8(false);
19131
- const exitRequestedRef = useRef9(false);
19235
+ const exitRequestedRef = useRef10(false);
19132
19236
  const [resizeState, setResizeState] = useState8(() => ({ ...terminalSize(stdout), epoch: 0 }));
19133
19237
  const [panelTransitionEpoch, setPanelTransitionEpoch] = useState8(0);
19134
19238
  const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState8(0);
@@ -19136,22 +19240,22 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19136
19240
  const rightSafetyColumns = windowsLikeTerminal ? 1 : 0;
19137
19241
  const frameColumns = Math.max(1, resizeState.columns - rightSafetyColumns);
19138
19242
  const [scrollOffset, setScrollOffset] = useState8(0);
19139
- const scrollPositionRef = useRef9(0);
19140
- const scrollTargetRef = useRef9(0);
19141
- const maxScrollRowsRef = useRef9(0);
19142
- const transcriptBottomSlackRowsRef = useRef9(0);
19143
- const transcriptAnchorRef = useRef9(null);
19144
- const transcriptAnchorDirtyRef = useRef9(false);
19145
- const transcriptGeomRef = useRef9({ prefixRows: null, totalRows: 0, viewRows: 1 });
19243
+ const scrollPositionRef = useRef10(0);
19244
+ const scrollTargetRef = useRef10(0);
19245
+ const maxScrollRowsRef = useRef10(0);
19246
+ const transcriptBottomSlackRowsRef = useRef10(0);
19247
+ const transcriptAnchorRef = useRef10(null);
19248
+ const transcriptAnchorDirtyRef = useRef10(false);
19249
+ const transcriptGeomRef = useRef10({ prefixRows: null, totalRows: 0, viewRows: 1 });
19146
19250
  const [measuredRowsVersion, setMeasuredRowsVersion] = useState8(0);
19147
- const followingRef = useRef9(false);
19148
- const lastItemsCountRef = useRef9(0);
19149
- const pickerOpenedFromEnterRef = useRef9(false);
19150
- const pickerOpenedFromEnterTimerRef = useRef9(null);
19151
- const projectPickerRef = useRef9(null);
19251
+ const followingRef = useRef10(false);
19252
+ const lastItemsCountRef = useRef10(0);
19253
+ const pickerOpenedFromEnterRef = useRef10(false);
19254
+ const pickerOpenedFromEnterTimerRef = useRef10(null);
19255
+ const projectPickerRef = useRef10(null);
19152
19256
  const buildProjectPickerState = (opts) => projectPickerRef.current.buildProjectPickerState(opts);
19153
19257
  const [picker, setPickerState] = useState8(null);
19154
- const livePickerRef = useRef9(null);
19258
+ const livePickerRef = useRef10(null);
19155
19259
  const setPicker = useCallback6((next) => {
19156
19260
  livePickerRef.current = typeof next === "function" ? next(livePickerRef.current) : next;
19157
19261
  setPickerState((prev) => {
@@ -19173,14 +19277,14 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19173
19277
  livePickerRef.current = picker;
19174
19278
  const [contextPanel, setContextPanel] = useState8(null);
19175
19279
  const [usagePanel, setUsagePanel] = useState8(null);
19176
- const usageRequestRef = useRef9(0);
19177
- const settingsHeavyCacheRef = useRef9(null);
19280
+ const usageRequestRef = useRef10(0);
19281
+ const settingsHeavyCacheRef = useRef10(null);
19178
19282
  const closeUsagePanel = useCallback6(() => {
19179
19283
  usageRequestRef.current += 1;
19180
19284
  setUsagePanel(null);
19181
19285
  }, []);
19182
19286
  const [providerPrompt, setProviderPrompt] = useState8(null);
19183
- const oauthSubmitRef = useRef9(false);
19287
+ const oauthSubmitRef = useRef10(false);
19184
19288
  const [channelPrompt, setChannelPrompt] = useState8(null);
19185
19289
  const [hookPrompt, setHookPrompt] = useState8(null);
19186
19290
  const [settingsPrompt, setSettingsPrompt] = useState8(null);
@@ -19202,7 +19306,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19202
19306
  pickFolder
19203
19307
  });
19204
19308
  projectPickerRef.current = projectPicker;
19205
- const initialPickerBuiltRef = useRef9(false);
19309
+ const initialPickerBuiltRef = useRef10(false);
19206
19310
  if (!initialPickerBuiltRef.current) {
19207
19311
  initialPickerBuiltRef.current = true;
19208
19312
  let onboardingOwnsScreen = false;
@@ -19310,30 +19414,30 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19310
19414
  const toolApproval = state.toolApproval || null;
19311
19415
  const [promptDraft, setPromptDraft] = useState8("");
19312
19416
  const [promptDraftOverride, setPromptDraftOverride] = useState8(null);
19313
- const promptLayoutValueRef = useRef9("");
19417
+ const promptLayoutValueRef = useRef10("");
19314
19418
  const [, setPromptLayoutRows] = useState8(1);
19315
19419
  const [textEntryLayoutRows, setTextEntryLayoutRows] = useState8(1);
19316
19420
  const [, setPastedImages] = useState8({});
19317
- const pastedImagesRef = useRef9({});
19318
- const nextPastedImageIdRef = useRef9(1);
19421
+ const pastedImagesRef = useRef10({});
19422
+ const nextPastedImageIdRef = useRef10(1);
19319
19423
  const [, setPastedTexts] = useState8({});
19320
- const pastedTextsRef = useRef9({});
19321
- const nextPastedTextIdRef = useRef9(1);
19322
- const promptValueRef = useRef9("");
19323
- const promptSelectionRef = useRef9(null);
19324
- const promptBoxRectRef = useRef9(null);
19325
- const promptMouseSelectionRef = useRef9(null);
19326
- const promptHistoryNavRef = useRef9({ active: false, index: -1, seed: "", lastValue: "" });
19327
- const promptHistoryDraftChangeRef = useRef9(false);
19424
+ const pastedTextsRef = useRef10({});
19425
+ const nextPastedTextIdRef = useRef10(1);
19426
+ const promptValueRef = useRef10("");
19427
+ const promptSelectionRef = useRef10(null);
19428
+ const promptBoxRectRef = useRef10(null);
19429
+ const promptMouseSelectionRef = useRef10(null);
19430
+ const promptHistoryNavRef = useRef10({ active: false, index: -1, seed: "", lastValue: "" });
19431
+ const promptHistoryDraftChangeRef = useRef10(false);
19328
19432
  const [promptHint, setPromptHint] = useState8("");
19329
19433
  const [promptHintTone, setPromptHintTone] = useState8("info");
19330
19434
  const [welcomePromptHintDismissed, setWelcomePromptHintDismissed] = useState8(false);
19331
19435
  const [conditionalWelcomePromptHint, setConditionalWelcomePromptHint] = useState8("");
19332
- const welcomePromptHintRef = useRef9(null);
19436
+ const welcomePromptHintRef = useRef10(null);
19333
19437
  if (welcomePromptHintRef.current === null) {
19334
19438
  welcomePromptHintRef.current = randomWelcomePromptHint();
19335
19439
  }
19336
- const welcomePromptHintVisibleRef = useRef9(false);
19440
+ const welcomePromptHintVisibleRef = useRef10(false);
19337
19441
  const dismissWelcomePromptHint = useCallback6(() => {
19338
19442
  if (!welcomePromptHintVisibleRef.current) return;
19339
19443
  setWelcomePromptHintDismissed((dismissed) => dismissed || true);
@@ -19341,15 +19445,15 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19341
19445
  const toastErrorSignature = useMemo2(() => (state.toasts || []).filter((toast) => toast?.tone === "error").map((toast) => `${toast.id || ""}:${toast.text || ""}`).join("|"), [state.toasts]);
19342
19446
  const [slashIndex, setSlashIndex] = useState8(0);
19343
19447
  const [slashDismissedFor, setSlashDismissedFor] = useState8("");
19344
- const slashPaletteRef = useRef9({ open: false, count: 0 });
19345
- const workflowTabCycleRef = useRef9({ pending: false, lastAt: 0 });
19346
- const scrollFocusRef = useRef9({});
19347
- const onboardingStartedRef = useRef9(false);
19348
- const onboardingRef = useRef9({ defaultRoute: null, searchRoute: null, agentRoutes: {}, agents: [], providerModels: [] });
19349
- const providerModelsCacheRef = useRef9({ models: null, at: 0 });
19350
- const searchModelsCacheRef = useRef9({ models: null, at: 0 });
19351
- const modelPickerRequestRef = useRef9(0);
19352
- const onboardingPrefetchSeqRef = useRef9(0);
19448
+ const slashPaletteRef = useRef10({ open: false, count: 0 });
19449
+ const workflowTabCycleRef = useRef10({ pending: false, lastAt: 0 });
19450
+ const scrollFocusRef = useRef10({});
19451
+ const onboardingStartedRef = useRef10(false);
19452
+ const onboardingRef = useRef10({ defaultRoute: null, searchRoute: null, agentRoutes: {}, agents: [], providerModels: [] });
19453
+ const providerModelsCacheRef = useRef10({ models: null, at: 0 });
19454
+ const searchModelsCacheRef = useRef10({ models: null, at: 0 });
19455
+ const modelPickerRequestRef = useRef10(0);
19456
+ const onboardingPrefetchSeqRef = useRef10(0);
19353
19457
  const clearModelCaches = useCallback6((scope = "all") => {
19354
19458
  if (scope === "all" || scope === "provider") {
19355
19459
  providerModelsCacheRef.current = { models: null, at: 0 };
@@ -19514,14 +19618,14 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19514
19618
  runDoctor: (...a) => store.runDoctor?.(...a),
19515
19619
  requestExit: (...a) => requestExit(...a)
19516
19620
  });
19517
- const promptHintTimerRef = useRef9(null);
19518
- const promptHintActiveRef = useRef9(false);
19519
- const dragRef = useRef9({ anchor: null, anchorScroll: 0, last: null, active: false, rect: null, region: null, anchorSpan: null });
19520
- const transcriptViewportRef = useRef9({ top: 0, bottom: 0 });
19521
- const panelTransitionRef = useRef9({ signature: "", reserve: 0, clearRows: 0, guardRows: 0, epoch: 0 });
19522
- const panelCloseInkMaskRowsRef = useRef9(0);
19523
- const projectBootInputLatchRef = useRef9(false);
19524
- const frameRowsRef = useRef9(24);
19621
+ const promptHintTimerRef = useRef10(null);
19622
+ const promptHintActiveRef = useRef10(false);
19623
+ const dragRef = useRef10({ anchor: null, anchorScroll: 0, last: null, active: false, rect: null, region: null, anchorSpan: null });
19624
+ const transcriptViewportRef = useRef10({ top: 0, bottom: 0 });
19625
+ const panelTransitionRef = useRef10({ signature: "", reserve: 0, clearRows: 0, guardRows: 0, epoch: 0 });
19626
+ const panelCloseInkMaskRowsRef = useRef10(0);
19627
+ const projectBootInputLatchRef = useRef10(false);
19628
+ const frameRowsRef = useRef10(24);
19525
19629
  const STATUSLINE_BAND_ROWS = 3;
19526
19630
  const promptContentColumns = Math.max(1, frameColumns - 4);
19527
19631
  const syncPromptLayoutRows = useCallback6((value) => {
@@ -19598,9 +19702,9 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19598
19702
  alive = false;
19599
19703
  };
19600
19704
  }, [store, state.provider, state.model, state.workflow?.id, toastErrorSignature]);
19601
- const selectionLayoutRef = useRef9(null);
19602
- const selectionTextRef = useRef9("");
19603
- const lastClickRef = useRef9({ x: -1, y: -1, t: 0, count: 0 });
19705
+ const selectionLayoutRef = useRef10(null);
19706
+ const selectionTextRef = useRef10("");
19707
+ const lastClickRef = useRef10({ x: -1, y: -1, t: 0, count: 0 });
19604
19708
  const showSelectionCopyHint = useCallback6((text, tone = "plain") => {
19605
19709
  if (promptHintTimerRef.current) clearTimeout(promptHintTimerRef.current);
19606
19710
  promptHintActiveRef.current = true;
@@ -19614,8 +19718,8 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19614
19718
  }, 2200);
19615
19719
  }, []);
19616
19720
  useEffect10(() => {
19617
- const timer = setTimeout(() => setTuiReady(true), 0);
19618
- return () => clearTimeout(timer);
19721
+ const timer2 = setTimeout(() => setTuiReady(true), 0);
19722
+ return () => clearTimeout(timer2);
19619
19723
  }, []);
19620
19724
  useEffect10(() => {
19621
19725
  if (!stdout) return void 0;
@@ -19868,14 +19972,14 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19868
19972
  }, 2e3);
19869
19973
  hardExitTimer.unref?.();
19870
19974
  setTimeout(() => {
19871
- let timer = null;
19975
+ let timer2 = null;
19872
19976
  Promise.race([
19873
19977
  Promise.resolve(store.dispose?.("cli-react-exit", { detach: true })),
19874
19978
  new Promise((resolve5) => {
19875
- timer = setTimeout(resolve5, 350);
19979
+ timer2 = setTimeout(resolve5, 350);
19876
19980
  })
19877
19981
  ]).finally(() => {
19878
- if (timer) clearTimeout(timer);
19982
+ if (timer2) clearTimeout(timer2);
19879
19983
  exit();
19880
19984
  });
19881
19985
  }, 60);
@@ -21106,8 +21210,8 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
21106
21210
  return void 0;
21107
21211
  }
21108
21212
  if (!hadTransitionClearance) return void 0;
21109
- const timer = setTimeout(() => setPanelTransitionEpoch((epoch) => epoch + 1), 0);
21110
- return () => clearTimeout(timer);
21213
+ const timer2 = setTimeout(() => setPanelTransitionEpoch((epoch) => epoch + 1), 0);
21214
+ return () => clearTimeout(timer2);
21111
21215
  }, [panelLayoutSignature, bottomClusterRows, panelTransitionClearRows, panelTransitionGuardRows]);
21112
21216
  useEffect10(() => {
21113
21217
  panelTransitionRef.current.tailId = latestTranscriptItem?.id ?? null;
@@ -23581,9 +23685,9 @@ function createSessionFlow(bag) {
23581
23685
  }
23582
23686
  if (compactType) {
23583
23687
  const clearPromise = runtime.clear({ compactType, requireCompactSuccess: true });
23584
- let timer = null;
23688
+ let timer2 = null;
23585
23689
  const timeout = new Promise((_, reject) => {
23586
- timer = setTimeout(
23690
+ timer2 = setTimeout(
23587
23691
  () => reject(new Error(`compaction timed out after ${AUTO_CLEAR_COMPACT_TIMEOUT_MS}ms; auto-clear deferred to next idle`)),
23588
23692
  AUTO_CLEAR_COMPACT_TIMEOUT_MS
23589
23693
  );
@@ -23608,7 +23712,7 @@ function createSessionFlow(bag) {
23608
23712
  });
23609
23713
  throw raceError;
23610
23714
  } finally {
23611
- if (timer) clearTimeout(timer);
23715
+ if (timer2) clearTimeout(timer2);
23612
23716
  }
23613
23717
  } else {
23614
23718
  await runtime.clear({});
@@ -26062,13 +26166,13 @@ async function createEngineSession({
26062
26166
  const value = String(text ?? "").trim();
26063
26167
  if (!value) return null;
26064
26168
  set({ toasts: [...state.toasts.filter((toast) => toast.id !== id), { id, text: value, tone }] });
26065
- const timer = setTimeout(() => {
26066
- toastTimers.delete(timer);
26169
+ const timer2 = setTimeout(() => {
26170
+ toastTimers.delete(timer2);
26067
26171
  if (flags.disposed) return;
26068
26172
  set({ toasts: state.toasts.filter((toast) => toast.id !== id) });
26069
26173
  }, ttlMs);
26070
- toastTimers.add(timer);
26071
- timer.unref?.();
26174
+ toastTimers.add(timer2);
26175
+ timer2.unref?.();
26072
26176
  return id;
26073
26177
  };
26074
26178
  const pushNotice = (text, tone = "info", options = {}) => {
@@ -26137,8 +26241,8 @@ async function createEngineSession({
26137
26241
  }, 2e3);
26138
26242
  lifecycle.runtimePulseTimer.unref?.();
26139
26243
  function clearToastTimers() {
26140
- for (const timer of toastTimers) {
26141
- clearTimeout(timer);
26244
+ for (const timer2 of toastTimers) {
26245
+ clearTimeout(timer2);
26142
26246
  }
26143
26247
  toastTimers.clear();
26144
26248
  }
@@ -26255,21 +26359,21 @@ function waitWithTimeout(promise, timeoutMs, label = "cleanup") {
26255
26359
  const ms = Math.max(1, Math.floor(Number(timeoutMs) || 1));
26256
26360
  return new Promise((resolve5, reject) => {
26257
26361
  let settled = false;
26258
- const timer = setTimeout(() => {
26362
+ const timer2 = setTimeout(() => {
26259
26363
  if (settled) return;
26260
26364
  settled = true;
26261
26365
  reject(new Error(`${label} timed out after ${ms}ms`));
26262
26366
  }, ms);
26263
- if (typeof timer.unref === "function") timer.unref();
26367
+ if (typeof timer2.unref === "function") timer2.unref();
26264
26368
  Promise.resolve(promise).then((value) => {
26265
26369
  if (settled) return;
26266
26370
  settled = true;
26267
- clearTimeout(timer);
26371
+ clearTimeout(timer2);
26268
26372
  resolve5(value);
26269
26373
  }).catch((error) => {
26270
26374
  if (settled) return;
26271
26375
  settled = true;
26272
- clearTimeout(timer);
26376
+ clearTimeout(timer2);
26273
26377
  reject(error);
26274
26378
  });
26275
26379
  });
@@ -26406,7 +26510,7 @@ function installTuiLoopProbe() {
26406
26510
  if (!LOOP_PROBE_ENABLED) return () => {
26407
26511
  };
26408
26512
  let last = performance3.now();
26409
- const timer = setInterval(() => {
26513
+ const timer2 = setInterval(() => {
26410
26514
  const now = performance3.now();
26411
26515
  const drift = now - last - LOOP_PROBE_INTERVAL_MS;
26412
26516
  last = now;
@@ -26418,10 +26522,10 @@ function installTuiLoopProbe() {
26418
26522
  }
26419
26523
  }
26420
26524
  }, LOOP_PROBE_INTERVAL_MS);
26421
- timer.unref?.();
26525
+ timer2.unref?.();
26422
26526
  return () => {
26423
26527
  try {
26424
- clearInterval(timer);
26528
+ clearInterval(timer2);
26425
26529
  } catch {
26426
26530
  }
26427
26531
  };
@@ -26454,7 +26558,7 @@ function installTuiPerfProbe() {
26454
26558
  stallMs: PERF_STALL_THRESHOLD_MS,
26455
26559
  renderGapMs: PERF_RENDER_GAP_MS
26456
26560
  });
26457
- const timer = setInterval(() => {
26561
+ const timer2 = setInterval(() => {
26458
26562
  const now = performance3.now();
26459
26563
  const elapsed = now - last;
26460
26564
  const lagMs = elapsed - PERF_STALL_INTERVAL_MS;
@@ -26472,10 +26576,10 @@ function installTuiPerfProbe() {
26472
26576
  heapMb: (mem.heapUsed / 1048576).toFixed(1)
26473
26577
  });
26474
26578
  }, PERF_STALL_INTERVAL_MS);
26475
- timer.unref?.();
26579
+ timer2.unref?.();
26476
26580
  return () => {
26477
26581
  try {
26478
- clearInterval(timer);
26582
+ clearInterval(timer2);
26479
26583
  } catch {
26480
26584
  }
26481
26585
  };
@@ -26573,19 +26677,19 @@ function dumpActiveHandles(label) {
26573
26677
  }
26574
26678
  }
26575
26679
  function waitWithTimeout2(promise, ms) {
26576
- let timer = null;
26680
+ let timer2 = null;
26577
26681
  return Promise.race([
26578
26682
  Promise.resolve(promise).then(() => true),
26579
26683
  new Promise((resolve5) => {
26580
- timer = setTimeout(() => resolve5(false), ms);
26684
+ timer2 = setTimeout(() => resolve5(false), ms);
26581
26685
  })
26582
26686
  ]).finally(() => {
26583
- if (timer) clearTimeout(timer);
26687
+ if (timer2) clearTimeout(timer2);
26584
26688
  });
26585
26689
  }
26586
26690
  function scheduleHardExit(code = 0) {
26587
26691
  if (!EXIT_HARD_ENABLED) return;
26588
- const timer = setTimeout(() => {
26692
+ const timer2 = setTimeout(() => {
26589
26693
  dumpActiveHandles("hard-exit");
26590
26694
  try {
26591
26695
  process.stdout.write(`${TERMINAL_MODE_RESET}${TERMINAL_OSC_RESET_BG}`);
@@ -26593,7 +26697,7 @@ function scheduleHardExit(code = 0) {
26593
26697
  }
26594
26698
  process.exit(code);
26595
26699
  }, EXIT_HARD_DELAY_MS);
26596
- timer.unref?.();
26700
+ timer2.unref?.();
26597
26701
  }
26598
26702
  function resolveTuiStderrLogPath() {
26599
26703
  return process.env.MIXDOG_TUI_STDERR_LOG || join10(process.env.MIXDOG_RUNTIME_ROOT || join10(tmpdir2(), "mixdog"), "mixdog-tui.stderr.log");