@wrongstack/tui 0.68.0 → 0.73.1

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
@@ -1,8 +1,7 @@
1
- import { Readable } from 'stream';
2
1
  import { writeErr, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, buildChildEnv } from '@wrongstack/core';
3
2
  export { buildGoalPreamble } from '@wrongstack/core';
4
3
  import { Box, Text, render, useApp, useStdout, measureElement, Static, useInput, useStdin } from 'ink';
5
- import React6, { useState, useEffect, useReducer, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
4
+ import React5, { useState, useEffect, useReducer, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
6
5
  import * as fs2 from 'fs/promises';
7
6
  import * as path2 from 'path';
8
7
  import { routeImagesForModel } from '@wrongstack/runtime/vision';
@@ -450,28 +449,6 @@ function ContextChip({ ctx }) {
450
449
  ] })
451
450
  ] });
452
451
  }
453
- var SB_GAP = 2;
454
- var SB_PADX = 1;
455
- function statusBarModelSpan(opts) {
456
- let col = SB_PADX;
457
- if (opts.version) {
458
- col += `WS v${opts.version}`.length + SB_GAP;
459
- col += 1 + SB_GAP;
460
- }
461
- const { label } = stateChip(opts.state, opts.fleetRunning ?? 0);
462
- col += 2 + label.length + SB_GAP;
463
- col += 1 + SB_GAP;
464
- return { start: col, len: opts.model.length };
465
- }
466
- function statusBarAutonomySpan(opts) {
467
- if (!opts.autonomy || opts.autonomy === "off") return null;
468
- let col = SB_PADX;
469
- if (opts.yolo) {
470
- col += "\u26A0 YOLO".length + SB_GAP;
471
- col += 1 + SB_GAP;
472
- }
473
- return { start: col, len: 2 + opts.autonomy.toUpperCase().length };
474
- }
475
452
  function stateChip(state, fleetRunning) {
476
453
  if (state === "idle" && fleetRunning > 0) {
477
454
  return { label: `agents \u25B6${fleetRunning}`, color: "magenta" };
@@ -1140,16 +1117,6 @@ function buttonLabels(suggestedPattern) {
1140
1117
  { decision: "deny", bracket: "[d]", rest: "eny" }
1141
1118
  ];
1142
1119
  }
1143
- function confirmButtonSegments(suggestedPattern) {
1144
- const out = [];
1145
- let col = 0;
1146
- for (const l of buttonLabels(suggestedPattern)) {
1147
- const len = l.bracket.length + l.rest.length;
1148
- out.push({ decision: l.decision, start: col, len });
1149
- col += len;
1150
- }
1151
- return out;
1152
- }
1153
1120
  function stringifyInput(input) {
1154
1121
  if (!input || typeof input !== "object") return "";
1155
1122
  const obj = input;
@@ -1180,7 +1147,7 @@ function ConfirmPrompt({
1180
1147
  suggestedPattern,
1181
1148
  onDecision
1182
1149
  }) {
1183
- React6.useEffect(() => {
1150
+ React5.useEffect(() => {
1184
1151
  writeOut("\x07");
1185
1152
  }, []);
1186
1153
  useInput((input2, _key) => {
@@ -1209,7 +1176,7 @@ function ConfirmPrompt({
1209
1176
  inputSummary ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: inputSummary }) : null,
1210
1177
  showDiff && diff ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff) }) : null,
1211
1178
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
1212
- /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(React6.Fragment, { children: [
1179
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs(React5.Fragment, { children: [
1213
1180
  /* @__PURE__ */ jsx(Text, { bold: true, color: BUTTON_COLOR[l.decision], children: l.bracket }),
1214
1181
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: l.rest })
1215
1182
  ] }, l.decision)) }) })
@@ -1306,13 +1273,6 @@ function FleetPanel({
1306
1273
  function helpSections(opts) {
1307
1274
  const nav = [];
1308
1275
  if (opts.managed) nav.push({ keys: "PgUp/PgDn", desc: "scroll chat history" });
1309
- if (opts.mouse)
1310
- nav.push(
1311
- { keys: "wheel", desc: "scroll chat history" },
1312
- { keys: "drag scrollbar", desc: "scrub to any position" },
1313
- { keys: "click input", desc: "move the caret" },
1314
- { keys: "click", desc: "select / confirm" }
1315
- );
1316
1276
  nav.push(
1317
1277
  { keys: "\u2191/\u2193", desc: "previous / next input (empty prompt)" },
1318
1278
  { keys: "?", desc: "open this help (empty prompt)" }
@@ -1353,10 +1313,9 @@ function helpSections(opts) {
1353
1313
  ];
1354
1314
  }
1355
1315
  function HelpOverlay({
1356
- managed,
1357
- mouse
1316
+ managed
1358
1317
  }) {
1359
- const sections = helpSections({ managed, mouse });
1318
+ const sections = helpSections({ managed });
1360
1319
  const keyWidth = Math.max(...sections.flatMap((s2) => s2.entries.map((e) => e.keys.length)), 0);
1361
1320
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
1362
1321
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
@@ -2771,7 +2730,7 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
2771
2730
  }
2772
2731
  var MAX_STREAM_DISPLAY_CHARS = 480;
2773
2732
  var MAX_STREAM_LINES = 8;
2774
- var ToolStreamBox = React6.memo(function ToolStreamBox2({
2733
+ var ToolStreamBox = React5.memo(function ToolStreamBox2({
2775
2734
  name,
2776
2735
  text,
2777
2736
  startedAt,
@@ -3091,7 +3050,7 @@ function brainRiskColor(risk) {
3091
3050
  function assistantContentWidth(termWidth) {
3092
3051
  return Math.max(20, termWidth - MESSAGE_PANEL_CHROME_WIDTH);
3093
3052
  }
3094
- var Entry = React6.memo(function Entry2({
3053
+ var Entry = React5.memo(function Entry2({
3095
3054
  entry,
3096
3055
  termWidth
3097
3056
  }) {
@@ -3435,52 +3394,6 @@ function layoutInputRows(prompt, value, cursor, width) {
3435
3394
  if (row.length > 0 || rows.length === 0) rows.push(row);
3436
3395
  return rows;
3437
3396
  }
3438
- function inputIndexAtRowCol(prompt, value, width, row, col) {
3439
- const w = Math.max(1, Math.floor(width));
3440
- const flat = [];
3441
- for (let i = 0; i < prompt.length; i++) flat.push({ ch: prompt[i], buf: -1 });
3442
- for (let i = 0; i < value.length; i++) flat.push({ ch: value[i], buf: i });
3443
- const rows = [];
3444
- const starts = [];
3445
- let cur = [];
3446
- let curStart = 0;
3447
- for (const cell of flat) {
3448
- if (cell.ch === "\n") {
3449
- rows.push(cur);
3450
- starts.push(curStart);
3451
- cur = [];
3452
- curStart = cell.buf + 1;
3453
- continue;
3454
- }
3455
- if (cur.length === 0 && cell.buf >= 0) curStart = cell.buf;
3456
- cur.push({ buf: cell.buf });
3457
- if (cur.length >= w) {
3458
- rows.push(cur);
3459
- starts.push(curStart);
3460
- cur = [];
3461
- curStart = -1;
3462
- }
3463
- }
3464
- if (cur.length > 0 || rows.length === 0) {
3465
- rows.push(cur);
3466
- starts.push(curStart);
3467
- }
3468
- const clamp = (n) => Math.max(0, Math.min(value.length, n));
3469
- if (row < 0) return 0;
3470
- if (row >= rows.length) return value.length;
3471
- const r = rows[row];
3472
- const c = Math.max(0, col);
3473
- if (c < r.length) {
3474
- const b = r[c].buf;
3475
- return b < 0 ? 0 : clamp(b);
3476
- }
3477
- for (let k = r.length - 1; k >= 0; k--) {
3478
- const b = r[k].buf;
3479
- if (b >= 0) return clamp(b + 1);
3480
- }
3481
- const start = starts[row];
3482
- return clamp(start !== void 0 && start >= 0 ? start : value.length);
3483
- }
3484
3397
  function renderRow2(cells, rowKey, promptColor) {
3485
3398
  const out = [];
3486
3399
  let run = "";
@@ -3620,8 +3533,7 @@ function hintsFor(ctx) {
3620
3533
  return [
3621
3534
  { key: "\u2191\u2193", label: "move" },
3622
3535
  { key: "\u21B5", label: "select" },
3623
- { key: "Esc", label: "cancel" },
3624
- ...ctx.mouse ? [{ key: "click", label: "pick" }] : []
3536
+ { key: "Esc", label: "cancel" }
3625
3537
  ];
3626
3538
  }
3627
3539
  if (ctx.monitor) {
@@ -3634,7 +3546,6 @@ function hintsFor(ctx) {
3634
3546
  }
3635
3547
  const base = [{ key: "?", label: "help" }];
3636
3548
  if (ctx.managed) base.push({ key: "PgUp/PgDn", label: "scroll" });
3637
- if (ctx.mouse) base.push({ key: "wheel", label: "scroll" }, { key: "click", label: "select" });
3638
3549
  base.push({ key: "^G", label: "agents" }, { key: "^C", label: "stop" });
3639
3550
  return base;
3640
3551
  }
@@ -3674,7 +3585,7 @@ function fmtRecentMessage(message) {
3674
3585
  const text = message.text.replace(/\s+/g, " ");
3675
3586
  return text.length > 48 ? `${text.slice(0, 47)}...` : text;
3676
3587
  }
3677
- var LiveActivityStrip = React6.memo(function LiveActivityStrip2({
3588
+ var LiveActivityStrip = React5.memo(function LiveActivityStrip2({
3678
3589
  entries,
3679
3590
  nowTick,
3680
3591
  maxRows = 4
@@ -4000,13 +3911,6 @@ function scrollbarThumb(rows, offset, total) {
4000
3911
  const top = Math.max(0, Math.min(rawTop, rows - size));
4001
3912
  return { top, size, scrollable: true };
4002
3913
  }
4003
- function scrollOffsetForTrackRow(rows, total, cell) {
4004
- if (total <= rows) return 0;
4005
- const maxOffset = total - rows;
4006
- const clampedCell = Math.max(0, Math.min(rows - 1, cell));
4007
- const windowTop = Math.round(clampedCell / Math.max(1, rows - 1) * maxOffset);
4008
- return Math.max(0, Math.min(maxOffset, maxOffset - windowTop));
4009
- }
4010
3914
  function Scrollbar({
4011
3915
  rows,
4012
3916
  offset,
@@ -4506,7 +4410,11 @@ function labelFor(labelsRef, id, name) {
4506
4410
  }
4507
4411
  function useSubagentEvents(events, dispatch, setActiveMaxContext) {
4508
4412
  const labelsRef = useRef(/* @__PURE__ */ new Map());
4509
- const lbl = (id, name) => labelFor(labelsRef, id, name);
4413
+ const lbl = useCallback(
4414
+ (id, name) => labelFor(labelsRef, id, name),
4415
+ []
4416
+ // labelsRef is a stable ref
4417
+ );
4510
4418
  useEffect(() => {
4511
4419
  const offSpawned = events.on("subagent.spawned", (e) => {
4512
4420
  const l = lbl(e.subagentId, e.name);
@@ -4553,6 +4461,12 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext) {
4553
4461
  const offCtxPct = events.on("subagent.ctx_pct", (e) => {
4554
4462
  dispatch({ type: "fleetCtxPct", id: e.subagentId, load: e.load, tokens: e.tokens, maxContext: e.maxContext });
4555
4463
  });
4464
+ const offConcurrencyChanged = events.on("concurrency.changed", (e) => {
4465
+ const { n } = e;
4466
+ if (typeof n === "number" && n > 0) {
4467
+ dispatch({ type: "fleetConcurrency", n });
4468
+ }
4469
+ });
4556
4470
  const offLeaderCtxPct = events.on("ctx.pct", (e) => {
4557
4471
  setActiveMaxContext(e.maxContext);
4558
4472
  dispatch({ type: "leaderCtxPct", load: e.load, tokens: e.tokens, maxContext: e.maxContext });
@@ -4572,11 +4486,12 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext) {
4572
4486
  offBudgetExtended();
4573
4487
  offIterationSummary();
4574
4488
  offCtxPct();
4489
+ offConcurrencyChanged();
4575
4490
  offLeaderCtxPct();
4576
4491
  offLeaderMaxContext();
4577
4492
  offTool();
4578
4493
  };
4579
- }, [events, dispatch, setActiveMaxContext]);
4494
+ }, [events, dispatch, setActiveMaxContext, lbl]);
4580
4495
  }
4581
4496
  function useBrainEvents(events, dispatch) {
4582
4497
  useEffect(() => {
@@ -4826,6 +4741,42 @@ function oneLine(s2, max) {
4826
4741
  return collapsed.length <= max ? collapsed : `${collapsed.slice(0, max - 1)}\u2026`;
4827
4742
  }
4828
4743
 
4744
+ // src/steering-preamble.ts
4745
+ function buildSteeringPreamble(snapshot, newDirection) {
4746
+ const lines = ["[STEERING \u2014 I pressed Esc to interrupt you mid-task on purpose.", ""];
4747
+ const ctx = [];
4748
+ if (snapshot?.runningTools && snapshot.runningTools.length > 0) {
4749
+ ctx.push(`- in-flight tools (now cancelled): ${snapshot.runningTools.join(", ")}`);
4750
+ }
4751
+ if (snapshot?.subagentsTerminated && snapshot.subagentsTerminated > 0) {
4752
+ const subDetails = snapshot.subagents.map((s2) => `${s2.label}${s2.tool ? ` (was running: ${s2.tool})` : ""}`).join(", ");
4753
+ ctx.push(
4754
+ `- subagents (${snapshot.subagentsTerminated} terminated by me, do NOT await them): ${subDetails}`
4755
+ );
4756
+ }
4757
+ if (snapshot?.partialAssistantText && snapshot.partialAssistantText.trim().length > 0) {
4758
+ const tail = snapshot.partialAssistantText.trim().slice(-300);
4759
+ ctx.push(`- your last partial output (truncated, for context only): "${tail}"`);
4760
+ }
4761
+ if (ctx.length > 0) {
4762
+ lines.push("What was happening when I cut you off:");
4763
+ lines.push(...ctx);
4764
+ lines.push("");
4765
+ }
4766
+ lines.push("You have authority to:");
4767
+ lines.push("- Abandon the prior plan entirely if the new direction makes it stale.");
4768
+ lines.push("- Re-spawn fresh subagents (with different roles or tasks) if needed.");
4769
+ lines.push('- Skip a polite "should I continue?" \u2014 just pivot.');
4770
+ lines.push("- Ask me to clarify if the new direction is genuinely ambiguous.");
4771
+ lines.push("");
4772
+ lines.push("New direction:");
4773
+ lines.push("---");
4774
+ lines.push(newDirection);
4775
+ lines.push("---");
4776
+ lines.push("]");
4777
+ return lines.join("\n");
4778
+ }
4779
+
4829
4780
  // src/app-reducer.ts
4830
4781
  function reducer(state, action) {
4831
4782
  switch (action.type) {
@@ -5420,6 +5371,9 @@ function reducer(state, action) {
5420
5371
  } : state.fleetTokens
5421
5372
  };
5422
5373
  }
5374
+ case "fleetConcurrency": {
5375
+ return { ...state, fleetConcurrency: action.n };
5376
+ }
5423
5377
  case "leaderIterStart": {
5424
5378
  return {
5425
5379
  ...state,
@@ -5608,7 +5562,7 @@ function reducer(state, action) {
5608
5562
  case "worktreeMonitorToggle": {
5609
5563
  return { ...state, worktreeMonitorOpen: !state.worktreeMonitorOpen };
5610
5564
  }
5611
- // --- In-app chat scroll (mouse mode) ---
5565
+ // --- In-app chat scroll ---
5612
5566
  case "scrollBy": {
5613
5567
  const maxOffset = Math.max(0, state.totalLines - state.viewportRows);
5614
5568
  const next = Math.max(0, Math.min(maxOffset, state.scrollOffset + action.delta));
@@ -5786,7 +5740,6 @@ function reducer(state, action) {
5786
5740
  }
5787
5741
  }
5788
5742
  }
5789
- var WHEEL_STEP = 3;
5790
5743
  var MIN_VIEWPORT = 3;
5791
5744
  var INPUT_PROMPT = "\u203A ";
5792
5745
  function selectedSlashCommandLine(picker) {
@@ -5795,40 +5748,6 @@ function selectedSlashCommandLine(picker) {
5795
5748
  return picked ? `/${picked.name}` : null;
5796
5749
  }
5797
5750
  var PASTE_THRESHOLD_CHARS = 200;
5798
- function buildSteeringPreamble(snapshot, newDirection) {
5799
- const lines = ["[STEERING \u2014 I pressed Esc to interrupt you mid-task on purpose.", ""];
5800
- const ctx = [];
5801
- if (snapshot?.runningTools && snapshot.runningTools.length > 0) {
5802
- ctx.push(`- in-flight tools (now cancelled): ${snapshot.runningTools.join(", ")}`);
5803
- }
5804
- if (snapshot?.subagentsTerminated && snapshot.subagentsTerminated > 0) {
5805
- const subDetails = snapshot.subagents.map((s2) => `${s2.label}${s2.tool ? ` (was running: ${s2.tool})` : ""}`).join(", ");
5806
- ctx.push(
5807
- `- subagents (${snapshot.subagentsTerminated} terminated by me, do NOT await them): ${subDetails}`
5808
- );
5809
- }
5810
- if (snapshot?.partialAssistantText && snapshot.partialAssistantText.trim().length > 0) {
5811
- const tail = snapshot.partialAssistantText.trim().slice(-300);
5812
- ctx.push(`- your last partial output (truncated, for context only): "${tail}"`);
5813
- }
5814
- if (ctx.length > 0) {
5815
- lines.push("What was happening when I cut you off:");
5816
- lines.push(...ctx);
5817
- lines.push("");
5818
- }
5819
- lines.push("You have authority to:");
5820
- lines.push("- Abandon the prior plan entirely if the new direction makes it stale.");
5821
- lines.push("- Re-spawn fresh subagents (with different roles or tasks) if needed.");
5822
- lines.push('- Skip a polite "should I continue?" \u2014 just pivot.');
5823
- lines.push("- Ask me to clarify if the new direction is genuinely ambiguous.");
5824
- lines.push("");
5825
- lines.push("New direction:");
5826
- lines.push("---");
5827
- lines.push(newDirection);
5828
- lines.push("---");
5829
- lines.push("]");
5830
- return lines.join("\n");
5831
- }
5832
5751
  function App({
5833
5752
  agent,
5834
5753
  slashRegistry,
@@ -5872,8 +5791,6 @@ function App({
5872
5791
  initialGoal,
5873
5792
  initialAsk,
5874
5793
  sessionsDir,
5875
- mouse = false,
5876
- subscribeMouse,
5877
5794
  managed = false
5878
5795
  }) {
5879
5796
  const { exit } = useApp();
@@ -5885,18 +5802,15 @@ function App({
5885
5802
  const [hiddenItems, setHiddenItems] = useState(statuslineHiddenItems);
5886
5803
  const { stdout } = useStdout();
5887
5804
  const [termRows, setTermRows] = useState(stdout?.rows ?? 24);
5888
- const [termCols, setTermCols] = useState(stdout?.columns ?? 80);
5889
5805
  useEffect(() => {
5890
5806
  const onResize = () => {
5891
5807
  setTermRows(process.stdout.rows ?? 24);
5892
- setTermCols(process.stdout.columns ?? 80);
5893
5808
  };
5894
5809
  process.stdout.on("resize", onResize);
5895
5810
  return () => {
5896
5811
  process.stdout.off("resize", onResize);
5897
5812
  };
5898
5813
  }, []);
5899
- const [mouseLive, setMouseLive] = useState(mouse);
5900
5814
  const [managedLive, setManagedLive] = useState(managed);
5901
5815
  useEffect(() => {
5902
5816
  setHiddenItems(statuslineHiddenItems);
@@ -5983,6 +5897,7 @@ function App({
5983
5897
  },
5984
5898
  fleetCost: 0,
5985
5899
  fleetTokens: { input: 0, output: 0 },
5900
+ fleetConcurrency: 4,
5986
5901
  streamFleet: true,
5987
5902
  monitorOpen: false,
5988
5903
  agentsMonitorOpen: false,
@@ -6011,7 +5926,7 @@ function App({
6011
5926
  const inputGateRef = useRef(false);
6012
5927
  const lastEnterAtRef = useRef(0);
6013
5928
  const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
6014
- const projectName = React6.useMemo(() => {
5929
+ const projectName = React5.useMemo(() => {
6015
5930
  const base = path2.basename(projectRoot);
6016
5931
  return base && base !== path2.sep ? base : void 0;
6017
5932
  }, [projectRoot]);
@@ -6023,21 +5938,11 @@ function App({
6023
5938
  const draftRef = useRef({ buffer: state.buffer, cursor: state.cursor });
6024
5939
  draftRef.current = { buffer: state.buffer, cursor: state.cursor };
6025
5940
  const bottomRef = useRef(null);
6026
- const prePickerRef = useRef(null);
6027
- const preRowsRef = useRef(0);
6028
- const liveStripRef = useRef(null);
6029
- const liveStripRowsRef = useRef(0);
6030
- React6.useLayoutEffect(() => {
5941
+ React5.useLayoutEffect(() => {
6031
5942
  if (!managedLive) return;
6032
5943
  const node = bottomRef.current;
6033
5944
  if (!node) return;
6034
5945
  const { height } = measureElement(node);
6035
- if (prePickerRef.current) {
6036
- preRowsRef.current = measureElement(prePickerRef.current).height;
6037
- }
6038
- if (liveStripRef.current) {
6039
- liveStripRowsRef.current = measureElement(liveStripRef.current).height;
6040
- }
6041
5946
  const s2 = stateRef.current;
6042
5947
  const affordance = s2.scrollOffset > 0 && s2.pendingNewLines > 0 ? 1 : 0;
6043
5948
  const vp = Math.max(MIN_VIEWPORT, termRows - height - affordance - 1);
@@ -6046,214 +5951,7 @@ function App({
6046
5951
  }
6047
5952
  }, [managedLive, termRows]);
6048
5953
  const handleKeyRef = useRef(null);
6049
- const pendingClickConfirmRef = useRef(null);
6050
- const openModelPickerRef = useRef(null);
6051
- const openAutonomyPickerRef = useRef(null);
6052
- const handleRewindToRef = useRef(null);
6053
- const confirmRef = useRef(null);
6054
- const confirmDecisionRef = useRef(null);
6055
- const scrollbarDragRef = useRef(false);
6056
- const lastLeftClickRef = useRef(null);
6057
- const DOUBLE_CLICK_MS = 500;
6058
- const DOUBLE_CLICK_DIST = 5;
6059
- const statusChipRef = useRef({ version: appVersion, model, fleetRunning: 0, yolo, autonomy: "off" });
6060
- const handleMouse = React6.useCallback(
6061
- (ev) => {
6062
- const s2 = stateRef.current;
6063
- if (ev.type === "wheel") {
6064
- const up = ev.button === "wheelUp";
6065
- const step = up ? -1 : 1;
6066
- if (s2.slashPicker.open) return dispatch({ type: "slashPickerMove", delta: step });
6067
- if (s2.modelPicker.open) return dispatch({ type: "modelPickerMove", delta: step });
6068
- if (s2.autonomyPicker.open) return dispatch({ type: "autonomyPickerMove", delta: step });
6069
- if (s2.settingsPicker.open) return dispatch({ type: "settingsFieldMove", delta: step });
6070
- if (s2.picker.open) return dispatch({ type: "pickerMove", delta: step });
6071
- if (s2.rewindOverlay) return dispatch({ type: "rewindOverlayMove", delta: step });
6072
- return dispatch({ type: "scrollBy", delta: up ? WHEEL_STEP : -WHEEL_STEP });
6073
- }
6074
- if (ev.type === "release") {
6075
- scrollbarDragRef.current = false;
6076
- return;
6077
- }
6078
- if (ev.button !== "left") return;
6079
- const now = Date.now();
6080
- const lastClick = lastLeftClickRef.current;
6081
- const isMultiClick = lastClick !== null && now - lastClick.ts < DOUBLE_CLICK_MS && Math.abs(ev.x - lastClick.x) <= DOUBLE_CLICK_DIST && Math.abs(ev.y - lastClick.y) <= DOUBLE_CLICK_DIST;
6082
- const clickCount = isMultiClick ? lastClick.count + 1 : 1;
6083
- lastLeftClickRef.current = { x: ev.x, y: ev.y, ts: now, count: clickCount };
6084
- {
6085
- const rows = s2.viewportRows;
6086
- if (ev.drag) {
6087
- if (scrollbarDragRef.current && s2.totalLines > rows) {
6088
- dispatch({
6089
- type: "scrollTo",
6090
- offset: scrollOffsetForTrackRow(rows, s2.totalLines, ev.y - 1)
6091
- });
6092
- }
6093
- return;
6094
- }
6095
- const cols = termCols || 80;
6096
- const onScrollbar = cols > 0 && ev.x >= cols - 2 && ev.y >= 1 && ev.y <= rows;
6097
- if (onScrollbar && s2.totalLines > rows) {
6098
- scrollbarDragRef.current = true;
6099
- dispatch({
6100
- type: "scrollTo",
6101
- offset: scrollOffsetForTrackRow(rows, s2.totalLines, ev.y - 1)
6102
- });
6103
- return;
6104
- }
6105
- }
6106
- if (ev.y > s2.viewportRows) {
6107
- if (s2.helpOpen) return dispatch({ type: "toggleHelp" });
6108
- if (s2.agentsMonitorOpen) return dispatch({ type: "toggleAgentsMonitor" });
6109
- if (s2.monitorOpen) return dispatch({ type: "toggleMonitor" });
6110
- if (s2.worktreeMonitorOpen) return dispatch({ type: "worktreeMonitorToggle" });
6111
- if (s2.autoPhase?.monitorOpen) return dispatch({ type: "autoPhaseMonitorToggle" });
6112
- }
6113
- const affordance = s2.scrollOffset > 0 && s2.pendingNewLines > 0 ? 1 : 0;
6114
- if (affordance && ev.y === s2.viewportRows + 1) {
6115
- return dispatch({ type: "scrollToBottom" });
6116
- }
6117
- if (s2.confirmQueue.length > 0) {
6118
- const node = confirmRef.current;
6119
- const head = s2.confirmQueue[0];
6120
- if (node && head) {
6121
- const { height } = measureElement(node);
6122
- const top = s2.viewportRows + affordance + preRowsRef.current + 1;
6123
- const buttonsRow = top + height - 2;
6124
- if (ev.y === buttonsRow) {
6125
- const contentX = ev.x - 1 - 2;
6126
- for (const seg of confirmButtonSegments(head.suggestedPattern)) {
6127
- if (contentX >= seg.start && contentX < seg.start + seg.len) {
6128
- confirmDecisionRef.current?.(seg.decision);
6129
- return;
6130
- }
6131
- }
6132
- }
6133
- }
6134
- return;
6135
- }
6136
- if (s2.rewindOverlay) {
6137
- const cps = s2.rewindOverlay.checkpoints;
6138
- const firstItemRow2 = s2.viewportRows + affordance + preRowsRef.current + 3 + 1;
6139
- const index2 = ev.y - firstItemRow2;
6140
- if (index2 < 0 || index2 >= cps.length) return;
6141
- if (index2 === s2.rewindOverlay.selected) {
6142
- handleRewindToRef.current?.(cps[index2].promptIndex);
6143
- } else {
6144
- dispatch({ type: "rewindOverlayMove", delta: index2 - s2.rewindOverlay.selected });
6145
- }
6146
- return;
6147
- }
6148
- if (s2.settingsPicker.open) {
6149
- const firstRow = s2.viewportRows + affordance + preRowsRef.current + 2 + 1;
6150
- const field = ev.y - firstRow;
6151
- if (field < 0 || field > 1) return;
6152
- if (field === s2.settingsPicker.field) {
6153
- dispatch({ type: "settingsValueChange", delta: 1 });
6154
- } else {
6155
- dispatch({ type: "settingsFieldSet", field });
6156
- }
6157
- return;
6158
- }
6159
- const picker = s2.modelPicker.open ? {
6160
- header: 2,
6161
- count: s2.modelPicker.step === "provider" ? s2.modelPicker.providerOptions.length : s2.modelPicker.modelOptions.length,
6162
- selected: s2.modelPicker.selected,
6163
- move: (delta) => dispatch({ type: "modelPickerMove", delta })
6164
- } : s2.autonomyPicker.open ? {
6165
- header: 2,
6166
- count: s2.autonomyPicker.options.length,
6167
- selected: s2.autonomyPicker.selected,
6168
- move: (delta) => dispatch({ type: "autonomyPickerMove", delta })
6169
- } : s2.slashPicker.open ? {
6170
- header: 1,
6171
- count: s2.slashPicker.matches.length,
6172
- selected: s2.slashPicker.selected,
6173
- move: (delta) => dispatch({ type: "slashPickerMove", delta })
6174
- } : s2.picker.open ? {
6175
- header: 1,
6176
- count: s2.picker.matches.length,
6177
- selected: s2.picker.selected,
6178
- move: (delta) => dispatch({ type: "pickerMove", delta })
6179
- } : null;
6180
- if (!picker || picker.count === 0) {
6181
- const inputDisabled = s2.status === "aborting" && !s2.steeringPending;
6182
- if (!inputDisabled) {
6183
- const cols = termCols || 80;
6184
- const inputTop = s2.viewportRows + affordance + liveStripRowsRef.current + 1;
6185
- const inputRows = layoutInputRows(INPUT_PROMPT, s2.buffer, s2.cursor, cols).length;
6186
- const rowIdx = ev.y - inputTop;
6187
- if (rowIdx >= 0 && rowIdx < inputRows) {
6188
- const next = inputIndexAtRowCol(INPUT_PROMPT, s2.buffer, cols, rowIdx, ev.x - 1);
6189
- return dispatch({ type: "setBuffer", buffer: s2.buffer, cursor: next });
6190
- }
6191
- }
6192
- if (!s2.helpOpen && !s2.agentsMonitorOpen && !s2.monitorOpen && !s2.worktreeMonitorOpen && !s2.autoPhase?.monitorOpen) {
6193
- const chip = statusChipRef.current;
6194
- const statusTop = s2.viewportRows + affordance + preRowsRef.current + 1;
6195
- const contentX = ev.x - 1;
6196
- if (ev.y === statusTop + 1) {
6197
- const span = statusBarModelSpan({
6198
- version: chip.version,
6199
- state: s2.status,
6200
- fleetRunning: chip.fleetRunning,
6201
- model: chip.model
6202
- });
6203
- if (contentX >= span.start && contentX < span.start + span.len) {
6204
- openModelPickerRef.current?.();
6205
- }
6206
- } else if (ev.y === statusTop + 2) {
6207
- const span = statusBarAutonomySpan({ yolo: chip.yolo, autonomy: chip.autonomy });
6208
- if (span && contentX >= span.start && contentX < span.start + span.len) {
6209
- openAutonomyPickerRef.current?.();
6210
- }
6211
- }
6212
- }
6213
- return;
6214
- }
6215
- const firstItemRow = s2.viewportRows + affordance + preRowsRef.current + picker.header + 1;
6216
- const index = ev.y - firstItemRow;
6217
- if (index < 0 || index >= picker.count) return;
6218
- if (index === picker.selected) {
6219
- handleKeyRef.current?.("", { ...EMPTY_KEY, return: true });
6220
- } else {
6221
- pendingClickConfirmRef.current = index;
6222
- picker.move(index - picker.selected);
6223
- }
6224
- },
6225
- // dispatch is stable (useReducer); refs are mutable — no reactive deps.
6226
- // termCols is stable (useState + resize effect).
6227
- [termCols]
6228
- );
6229
- useEffect(() => {
6230
- if (!subscribeMouse) return;
6231
- return subscribeMouse(handleMouse);
6232
- }, [subscribeMouse, handleMouse]);
6233
- useEffect(() => {
6234
- const target = pendingClickConfirmRef.current;
6235
- if (target === null) return;
6236
- const open = state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.picker.open;
6237
- if (!open) {
6238
- pendingClickConfirmRef.current = null;
6239
- return;
6240
- }
6241
- const sel = state.slashPicker.open ? state.slashPicker.selected : state.modelPicker.open ? state.modelPicker.selected : state.autonomyPicker.open ? state.autonomyPicker.selected : state.picker.selected;
6242
- if (sel === target) {
6243
- pendingClickConfirmRef.current = null;
6244
- handleKeyRef.current?.("", { ...EMPTY_KEY, return: true });
6245
- }
6246
- }, [
6247
- state.slashPicker.open,
6248
- state.slashPicker.selected,
6249
- state.modelPicker.open,
6250
- state.modelPicker.selected,
6251
- state.autonomyPicker.open,
6252
- state.autonomyPicker.selected,
6253
- state.picker.open,
6254
- state.picker.selected
6255
- ]);
6256
- const handleRewindTo = React6.useCallback(
5954
+ const handleRewindTo = React5.useCallback(
6257
5955
  async (checkpointIndex) => {
6258
5956
  const sessionId = agent.ctx.session.id;
6259
5957
  if (!sessionId) return;
@@ -6272,13 +5970,13 @@ function App({
6272
5970
  dispatch({ type: "clearInput" });
6273
5971
  };
6274
5972
  const startedAtRef = useRef(Date.now());
6275
- const [nowTick, setNowTick] = React6.useState(Date.now());
5973
+ const [nowTick, setNowTick] = React5.useState(Date.now());
6276
5974
  useEffect(() => {
6277
5975
  const t = setInterval(() => setNowTick(Date.now()), 1e3);
6278
5976
  return () => clearInterval(t);
6279
5977
  }, []);
6280
5978
  const elapsedMs = nowTick - startedAtRef.current;
6281
- const [gitInfo, setGitInfo] = React6.useState(null);
5979
+ const [gitInfo, setGitInfo] = React5.useState(null);
6282
5980
  useEffect(() => {
6283
5981
  let cancelled = false;
6284
5982
  const refresh = () => {
@@ -6635,60 +6333,6 @@ function App({
6635
6333
  slashRegistry.unregister("altscreen");
6636
6334
  };
6637
6335
  }, [slashRegistry]);
6638
- const mouseLiveRef = useRef(mouseLive);
6639
- mouseLiveRef.current = mouseLive;
6640
- useEffect(() => {
6641
- const MOUSE_ON_SEQ = "\x1B[?1000h\x1B[?1006h";
6642
- const MOUSE_OFF_SEQ = "\x1B[?1006l\x1B[?1000l";
6643
- const ALT_ON = "\x1B[?1049h";
6644
- const ALT_OFF = "\x1B[?1049l";
6645
- const cmd = {
6646
- name: "mouse",
6647
- description: "Toggle mouse mode (clickable menus + wheel-scroll chat). Needs launch with --mouse to enable.",
6648
- async run(args) {
6649
- const arg = args.trim().toLowerCase();
6650
- if (arg !== "on" && arg !== "off") {
6651
- return {
6652
- message: `Mouse mode is ${mouseLiveRef.current ? "ON" : "OFF"}. Usage: /mouse on|off`
6653
- };
6654
- }
6655
- if (arg === "on") {
6656
- if (!mouse) {
6657
- return {
6658
- message: "Mouse mode needs the --mouse launch flag (it rewires stdin so mouse bytes never reach the input). Restart with `wstack --tui --mouse`."
6659
- };
6660
- }
6661
- try {
6662
- writeOut(ALT_ON);
6663
- writeOut("\x1B[H");
6664
- writeOut(MOUSE_ON_SEQ);
6665
- } catch {
6666
- return { message: "Failed to enable mouse mode." };
6667
- }
6668
- setMouseLive(true);
6669
- setManagedLive(true);
6670
- return {
6671
- message: "Mouse mode ON. Click menu items, wheel-scroll the chat (PgUp/PgDn too). Native terminal copy/scroll are suspended until `/mouse off`."
6672
- };
6673
- }
6674
- try {
6675
- writeOut(MOUSE_OFF_SEQ);
6676
- writeOut(ALT_OFF);
6677
- } catch {
6678
- return { message: "Failed to disable mouse mode." };
6679
- }
6680
- setMouseLive(false);
6681
- setManagedLive(false);
6682
- return {
6683
- message: "Mouse mode OFF. Native terminal scroll/copy restored; chat history flows into native scrollback again."
6684
- };
6685
- }
6686
- };
6687
- slashRegistry.register(cmd);
6688
- return () => {
6689
- slashRegistry.unregister("mouse");
6690
- };
6691
- }, [slashRegistry, mouse]);
6692
6336
  useEffect(() => {
6693
6337
  const cmd = {
6694
6338
  name: "steer",
@@ -6795,16 +6439,12 @@ function App({
6795
6439
  slashRegistry.unregister("agents");
6796
6440
  };
6797
6441
  }, [slashRegistry]);
6798
- const openModelPicker = React6.useCallback(async () => {
6442
+ const openModelPicker = React5.useCallback(async () => {
6799
6443
  if (!getPickableProviders) return;
6800
6444
  const providers = await getPickableProviders();
6801
6445
  dispatch({ type: "modelPickerOpen", providers });
6802
6446
  }, [getPickableProviders]);
6803
- const openAutonomyPicker = React6.useCallback(() => {
6804
- if (!switchAutonomy) return;
6805
- dispatch({ type: "autonomyPickerOpen", options: AUTONOMY_OPTIONS });
6806
- }, [switchAutonomy]);
6807
- const openSettings = React6.useCallback(() => {
6447
+ const openSettings = React5.useCallback(() => {
6808
6448
  if (!getSettings) return;
6809
6449
  const s2 = getSettings();
6810
6450
  dispatch({ type: "settingsOpen", mode: s2.mode, delayMs: s2.delayMs });
@@ -8547,20 +8187,6 @@ User message:
8547
8187
  })();
8548
8188
  }, [initialAsk, initialGoal]);
8549
8189
  handleKeyRef.current = handleKey;
8550
- openModelPickerRef.current = () => {
8551
- void openModelPicker();
8552
- };
8553
- openAutonomyPickerRef.current = openAutonomyPicker;
8554
- handleRewindToRef.current = (promptIndex) => {
8555
- void handleRewindTo(promptIndex);
8556
- };
8557
- statusChipRef.current = {
8558
- version: appVersion,
8559
- model: `${liveProvider}/${liveModel}`,
8560
- fleetRunning: fleetCounts?.running ?? 0,
8561
- yolo: yoloLive,
8562
- autonomy: autonomyLive
8563
- };
8564
8190
  const inputHint = useMemo(() => {
8565
8191
  if (state.status !== "idle") return "";
8566
8192
  if (state.buffer.startsWith("/")) return "slash command \u2014 Enter to dispatch";
@@ -8590,20 +8216,18 @@ User message:
8590
8216
  ),
8591
8217
  affordanceShown ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2193 ${state.pendingNewLines} new line${state.pendingNewLines === 1 ? "" : "s"} \u2014 PgDn or click to jump to bottom` }) : null,
8592
8218
  /* @__PURE__ */ jsxs(Box, { ref: managedLive ? bottomRef : void 0, flexDirection: "column", flexShrink: 0, children: [
8593
- /* @__PURE__ */ jsxs(Box, { ref: managedLive ? prePickerRef : void 0, flexDirection: "column", flexShrink: 0, children: [
8594
- /* @__PURE__ */ jsx(Box, { ref: managedLive ? liveStripRef : void 0, flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsx(LiveActivityStrip, { entries: state.fleet, nowTick }) }),
8595
- /* @__PURE__ */ jsx(
8596
- Input,
8597
- {
8598
- prompt: INPUT_PROMPT,
8599
- value: state.buffer,
8600
- cursor: state.cursor,
8601
- disabled: state.status === "aborting" && !state.steeringPending || state.confirmQueue.length > 0,
8602
- hint: inputHint,
8603
- onKey: handleKey
8604
- }
8605
- )
8606
- ] }),
8219
+ /* @__PURE__ */ jsx(LiveActivityStrip, { entries: state.fleet, nowTick }),
8220
+ /* @__PURE__ */ jsx(
8221
+ Input,
8222
+ {
8223
+ prompt: INPUT_PROMPT,
8224
+ value: state.buffer,
8225
+ cursor: state.cursor,
8226
+ disabled: state.status === "aborting" && !state.steeringPending || state.confirmQueue.length > 0,
8227
+ hint: inputHint,
8228
+ onKey: handleKey
8229
+ }
8230
+ ),
8607
8231
  state.picker.open ? /* @__PURE__ */ jsx(
8608
8232
  FilePicker,
8609
8233
  {
@@ -8679,8 +8303,7 @@ User message:
8679
8303
  head.resolve(decision);
8680
8304
  dispatch({ type: "confirmClose" });
8681
8305
  };
8682
- confirmDecisionRef.current = onDecision;
8683
- return /* @__PURE__ */ jsx(Box, { ref: confirmRef, flexDirection: "column", marginY: 1, flexShrink: 0, children: /* @__PURE__ */ jsx(
8306
+ return /* @__PURE__ */ jsx(
8684
8307
  ConfirmPrompt,
8685
8308
  {
8686
8309
  toolName: head.toolName,
@@ -8688,7 +8311,7 @@ User message:
8688
8311
  suggestedPattern: head.suggestedPattern,
8689
8312
  onDecision
8690
8313
  }
8691
- ) });
8314
+ );
8692
8315
  })(),
8693
8316
  /* @__PURE__ */ jsx(
8694
8317
  StatusBar,
@@ -8723,12 +8346,11 @@ User message:
8723
8346
  confirm: state.confirmQueue.length > 0,
8724
8347
  picker: state.picker.open || state.slashPicker.open || state.modelPicker.open || state.autonomyPicker.open || state.settingsPicker.open || !!state.rewindOverlay,
8725
8348
  monitor: state.agentsMonitorOpen || state.monitorOpen || state.worktreeMonitorOpen || !!state.autoPhase?.monitorOpen,
8726
- managed: managedLive,
8727
- mouse: mouseLive
8349
+ managed: managedLive
8728
8350
  }
8729
8351
  }
8730
8352
  ) : null,
8731
- state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, { managed: managedLive, mouse: mouseLive }) : null,
8353
+ state.helpOpen ? /* @__PURE__ */ jsx(HelpOverlay, { managed: managedLive }) : null,
8732
8354
  state.agentsMonitorOpen ? /* @__PURE__ */ jsx(
8733
8355
  AgentsMonitor,
8734
8356
  {
@@ -8760,6 +8382,7 @@ User message:
8760
8382
  entries: state.fleet,
8761
8383
  totalCost: state.fleetCost,
8762
8384
  totalTokens: state.fleetTokens,
8385
+ maxConcurrent: state.fleetConcurrency,
8763
8386
  nowTick,
8764
8387
  collabSession: state.collabSession
8765
8388
  }
@@ -8816,48 +8439,6 @@ function fmtTok3(n) {
8816
8439
  return `${(n / 1e6).toFixed(1)}M`;
8817
8440
  }
8818
8441
 
8819
- // src/mouse.ts
8820
- var SGR_MOUSE_RE = /\x1b?\[<(\d+);(\d+);(\d+)([Mm])/g;
8821
- function stripSgrMouse(s2) {
8822
- return s2.replace(SGR_MOUSE_RE, "");
8823
- }
8824
- function parseSgrMouse(s2) {
8825
- const events = [];
8826
- for (const m of s2.matchAll(SGR_MOUSE_RE)) {
8827
- const cb = Number.parseInt(m[1] ?? "", 10);
8828
- const x = Number.parseInt(m[2] ?? "", 10);
8829
- const y = Number.parseInt(m[3] ?? "", 10);
8830
- const final = m[4];
8831
- if (!Number.isFinite(cb) || !Number.isFinite(x) || !Number.isFinite(y)) continue;
8832
- const isWheel = (cb & 64) !== 0;
8833
- const drag = (cb & 32) !== 0;
8834
- const low = cb & 3;
8835
- let button;
8836
- let type;
8837
- if (isWheel) {
8838
- type = "wheel";
8839
- button = low === 0 ? "wheelUp" : low === 1 ? "wheelDown" : "other";
8840
- } else if (final === "m") {
8841
- type = "release";
8842
- button = low === 0 ? "left" : low === 1 ? "middle" : low === 2 ? "right" : "other";
8843
- } else {
8844
- type = "press";
8845
- button = low === 0 ? "left" : low === 1 ? "middle" : low === 2 ? "right" : "other";
8846
- }
8847
- events.push({
8848
- type,
8849
- button,
8850
- x,
8851
- y,
8852
- shift: (cb & 4) !== 0,
8853
- alt: (cb & 8) !== 0,
8854
- ctrl: (cb & 16) !== 0,
8855
- drag
8856
- });
8857
- }
8858
- return events;
8859
- }
8860
-
8861
8442
  // src/terminal-title.ts
8862
8443
  var SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8863
8444
  var setTitle = (s2) => `\x1B]0;${s2}\x07`;
@@ -8927,8 +8508,6 @@ var BRACKETED_PASTE_OFF = "\x1B[?2004l";
8927
8508
  var ALT_SCREEN_ON = "\x1B[?1049h";
8928
8509
  var ALT_SCREEN_OFF = "\x1B[?1049l";
8929
8510
  var CURSOR_HOME = "\x1B[H";
8930
- var MOUSE_ON = "\x1B[?1000h\x1B[?1002h\x1B[?1006h";
8931
- var MOUSE_OFF = "\x1B[?1006l\x1B[?1002l\x1B[?1000l";
8932
8511
  async function runTui(opts) {
8933
8512
  const stdout = process.stdout;
8934
8513
  const stdin = process.stdin;
@@ -8938,107 +8517,13 @@ async function runTui(opts) {
8938
8517
  );
8939
8518
  return 2;
8940
8519
  }
8941
- const useMouse = opts.mouse === true;
8942
- const useAltScreen = opts.altScreen === true || useMouse;
8520
+ const useAltScreen = opts.altScreen === true;
8943
8521
  if (useAltScreen) {
8944
8522
  stdout.write(ALT_SCREEN_ON);
8945
8523
  stdout.write(CURSOR_HOME);
8946
8524
  }
8947
8525
  stdout.write(BRACKETED_PASTE_ON);
8948
- if (useMouse) {
8949
- stdout.write(MOUSE_ON);
8950
- }
8951
- const mouseListeners = /* @__PURE__ */ new Set();
8952
- let inkStdin = stdin;
8953
- let detachMouse = null;
8954
- if (useMouse) {
8955
- class KeyboardReadable extends Readable {
8956
- pendingChunks = [];
8957
- // eslint-disable-next-line no-useless-constructor
8958
- constructor() {
8959
- super({ encoding: "utf8", highWaterMark: 64 * 1024 });
8960
- }
8961
- _read(_size) {
8962
- this.flushPending();
8963
- }
8964
- flushPending() {
8965
- while (this.pendingChunks.length > 0) {
8966
- const chunk = this.pendingChunks[0];
8967
- const ok = this.push(chunk);
8968
- this.pendingChunks.shift();
8969
- if (!ok) {
8970
- break;
8971
- }
8972
- }
8973
- }
8974
- /** Called by the stdin data handler when keyboard bytes are available. */
8975
- doPush(chunk) {
8976
- if (chunk.length === 0) return;
8977
- const ok = this.push(chunk);
8978
- if (ok) {
8979
- if (this.pendingChunks.length > 0) {
8980
- this.flushPending();
8981
- }
8982
- } else {
8983
- if (this.pendingChunks.length >= 100) {
8984
- this.pendingChunks.shift();
8985
- }
8986
- this.pendingChunks.push(chunk);
8987
- }
8988
- }
8989
- /** Called on shutdown so the stream closes cleanly. */
8990
- doEnd() {
8991
- this.pendingChunks = [];
8992
- this.push(null);
8993
- }
8994
- }
8995
- const keyboardStream = new KeyboardReadable();
8996
- const p = keyboardStream;
8997
- p.isTTY = true;
8998
- p.setRawMode = (mode) => {
8999
- try {
9000
- stdin.setRawMode?.(mode);
9001
- } catch {
9002
- }
9003
- return p;
9004
- };
9005
- const realRef = stdin.ref?.bind(stdin);
9006
- const realUnref = stdin.unref?.bind(stdin);
9007
- p.ref = () => {
9008
- realRef?.();
9009
- return p;
9010
- };
9011
- p.unref = () => {
9012
- realUnref?.();
9013
- return p;
9014
- };
9015
- stdin.setEncoding("utf8");
9016
- const onData = (chunk) => {
9017
- const evs = parseSgrMouse(chunk);
9018
- for (const ev of evs) {
9019
- for (const fn of mouseListeners) {
9020
- try {
9021
- fn(ev);
9022
- } catch {
9023
- }
9024
- }
9025
- }
9026
- const rest = stripSgrMouse(chunk);
9027
- keyboardStream.doPush(rest);
9028
- };
9029
- stdin.on("data", onData);
9030
- detachMouse = () => {
9031
- stdin.off("data", onData);
9032
- keyboardStream.doEnd();
9033
- };
9034
- inkStdin = p;
9035
- }
9036
- const subscribeMouse = useMouse ? (fn) => {
9037
- mouseListeners.add(fn);
9038
- return () => {
9039
- mouseListeners.delete(fn);
9040
- };
9041
- } : void 0;
8526
+ const inkStdin = stdin;
9042
8527
  const stopTitle = startTerminalTitle({ stdout, events: opts.events, model: opts.model });
9043
8528
  const swallowSignals = ["SIGTSTP", "SIGQUIT", "SIGTTIN", "SIGTTOU"];
9044
8529
  const swallow = () => {
@@ -9057,15 +8542,8 @@ async function runTui(opts) {
9057
8542
  stopTitle();
9058
8543
  } catch {
9059
8544
  }
9060
- try {
9061
- detachMouse?.();
9062
- } catch {
9063
- }
9064
8545
  try {
9065
8546
  stdout.write(BRACKETED_PASTE_OFF);
9066
- if (useMouse) {
9067
- stdout.write(MOUSE_OFF);
9068
- }
9069
8547
  if (useAltScreen) {
9070
8548
  stdout.write(ALT_SCREEN_OFF);
9071
8549
  }
@@ -9106,7 +8584,7 @@ async function runTui(opts) {
9106
8584
  let instance;
9107
8585
  try {
9108
8586
  instance = render(
9109
- React6.createElement(App, {
8587
+ React5.createElement(App, {
9110
8588
  agent: opts.agent,
9111
8589
  slashRegistry: opts.slashRegistry,
9112
8590
  attachments: opts.attachments,
@@ -9150,11 +8628,8 @@ async function runTui(opts) {
9150
8628
  getSettings: opts.getSettings,
9151
8629
  saveSettings: opts.saveSettings,
9152
8630
  predictNext: opts.predictNext,
9153
- mouse: useMouse,
9154
- subscribeMouse,
9155
8631
  // Managed viewport (in-app scroll + collapsibility) follows
9156
- // alt-screen: it owns the screen, so there's no native-scrollback
9157
- // leak. Decoupled from mouse so --alt-screen alone gets it.
8632
+ // alt-screen: it owns the screen, so there's no native-scrollback leak.
9158
8633
  managed: useAltScreen
9159
8634
  }),
9160
8635
  { exitOnCtrlC: false, stdin: inkStdin }