reasonix 0.4.12 → 0.4.14

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/cli/index.js CHANGED
@@ -1610,6 +1610,15 @@ var CacheFirstLoop = class {
1610
1610
  if (d.argumentsDelta)
1611
1611
  cur.function.arguments = (cur.function.arguments ?? "") + d.argumentsDelta;
1612
1612
  callBuf.set(d.index, cur);
1613
+ if (cur.function.name) {
1614
+ yield {
1615
+ turn: this._turn,
1616
+ role: "tool_call_delta",
1617
+ content: "",
1618
+ toolName: cur.function.name,
1619
+ toolCallArgsChars: (cur.function.arguments ?? "").length
1620
+ };
1621
+ }
1613
1622
  }
1614
1623
  if (chunk.usage) usage = chunk.usage;
1615
1624
  }
@@ -3510,19 +3519,19 @@ function sep() {
3510
3519
  }
3511
3520
 
3512
3521
  // src/index.ts
3513
- var VERSION = "0.4.3";
3522
+ var VERSION = "0.4.14";
3514
3523
 
3515
3524
  // src/cli/commands/chat.tsx
3516
3525
  import { render } from "ink";
3517
- import React9, { useState as useState5 } from "react";
3526
+ import React10, { useState as useState4 } from "react";
3518
3527
 
3519
3528
  // src/cli/ui/App.tsx
3520
3529
  import { Box as Box7, Static, Text as Text7, useApp, useInput as useInput2 } from "ink";
3521
- import React7, { useCallback, useEffect as useEffect3, useMemo, useRef, useState as useState3 } from "react";
3530
+ import React8, { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useState2 } from "react";
3522
3531
 
3523
3532
  // src/cli/ui/EventLog.tsx
3524
3533
  import { Box as Box3, Text as Text3 } from "ink";
3525
- import React3, { useEffect, useState } from "react";
3534
+ import React4 from "react";
3526
3535
 
3527
3536
  // src/cli/ui/PlanStateBlock.tsx
3528
3537
  import { Box, Text } from "ink";
@@ -3833,45 +3842,67 @@ function Markdown({ text }) {
3833
3842
  return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React2.createElement(BlockView, { key: `${i}-${b.kind}`, block: b })));
3834
3843
  }
3835
3844
 
3845
+ // src/cli/ui/ticker.tsx
3846
+ import React3, { createContext, useContext, useEffect, useState } from "react";
3847
+ var TICK_MS = 120;
3848
+ var TickContext = createContext(0);
3849
+ function TickerProvider({ children, disabled }) {
3850
+ const [tick, setTick] = useState(0);
3851
+ useEffect(() => {
3852
+ if (disabled) return;
3853
+ const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
3854
+ return () => clearInterval(id);
3855
+ }, [disabled]);
3856
+ return /* @__PURE__ */ React3.createElement(TickContext.Provider, { value: tick }, children);
3857
+ }
3858
+ function useTick() {
3859
+ return useContext(TickContext);
3860
+ }
3861
+ function useElapsedSeconds() {
3862
+ const [start] = useState(() => Date.now());
3863
+ useTick();
3864
+ return Math.floor((Date.now() - start) / 1e3);
3865
+ }
3866
+
3836
3867
  // src/cli/ui/EventLog.tsx
3837
- var EventRow = React3.memo(function EventRow2({ event }) {
3868
+ var EventRow = React4.memo(function EventRow2({ event }) {
3838
3869
  if (event.role === "user") {
3839
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React3.createElement(Text3, null, event.text));
3870
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React4.createElement(Text3, null, event.text));
3840
3871
  }
3841
3872
  if (event.role === "assistant") {
3842
- if (event.streaming) return /* @__PURE__ */ React3.createElement(StreamingAssistant, { event });
3843
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "assistant")), event.branch ? /* @__PURE__ */ React3.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React3.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React3.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React3.createElement(Markdown, { text: event.text }) : /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React3.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React3.createElement(Text3, { color: "magenta" }, event.repair) : null);
3873
+ if (event.streaming) return /* @__PURE__ */ React4.createElement(StreamingAssistant, { event });
3874
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "green" }, "assistant")), event.branch ? /* @__PURE__ */ React4.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React4.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React4.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React4.createElement(Markdown, { text: event.text }) : /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React4.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React4.createElement(Text3, { color: "magenta" }, event.repair) : null);
3844
3875
  }
3845
3876
  if (event.role === "tool") {
3846
3877
  const isError = event.text.startsWith("ERROR:");
3847
3878
  const color = isError ? "red" : "yellow";
3848
3879
  const marker = isError ? "\u2717" : "\u2192";
3849
3880
  const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isError;
3850
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color }, `tool<${event.toolName ?? "?"}> ${marker}`), isEditFile ? /* @__PURE__ */ React3.createElement(EditFileDiff, { text: event.text }) : /* @__PURE__ */ React3.createElement(Text3, { color: isError ? "red" : void 0, dimColor: !isError }, " ", truncate2(event.text, 400)));
3881
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, { color }, `tool<${event.toolName ?? "?"}> ${marker}`), isEditFile ? /* @__PURE__ */ React4.createElement(EditFileDiff, { text: event.text }) : /* @__PURE__ */ React4.createElement(Text3, { color: isError ? "red" : void 0, dimColor: !isError }, " ", truncate2(event.text, 400)));
3851
3882
  }
3852
3883
  if (event.role === "error") {
3853
- return /* @__PURE__ */ React3.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, event.text));
3884
+ return /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React4.createElement(Text3, { color: "red" }, event.text));
3854
3885
  }
3855
3886
  if (event.role === "info") {
3856
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, event.text));
3887
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, event.text));
3857
3888
  }
3858
3889
  if (event.role === "warning") {
3859
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, "\u25B8 "), /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, event.text));
3890
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { color: "yellow" }, "\u25B8 "), /* @__PURE__ */ React4.createElement(Text3, { color: "yellow" }, event.text));
3860
3891
  }
3861
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, null, event.text));
3892
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, null, event.text));
3862
3893
  });
3863
3894
  function EditFileDiff({ text }) {
3864
3895
  const lines = text.split(/\r?\n/);
3865
3896
  const [statusHeader, hunkHeader, ...body] = lines;
3866
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React3.createElement(Text3, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
3897
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React4.createElement(Text3, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
3867
3898
  const key = `${i}-${line.slice(0, 32)}`;
3868
3899
  if (line.startsWith("- ")) {
3869
- return /* @__PURE__ */ React3.createElement(Text3, { key, color: "red" }, line);
3900
+ return /* @__PURE__ */ React4.createElement(Text3, { key, color: "red" }, line);
3870
3901
  }
3871
3902
  if (line.startsWith("+ ")) {
3872
- return /* @__PURE__ */ React3.createElement(Text3, { key, color: "green" }, line);
3903
+ return /* @__PURE__ */ React4.createElement(Text3, { key, color: "green" }, line);
3873
3904
  }
3874
- return /* @__PURE__ */ React3.createElement(Text3, { key, dimColor: true }, line);
3905
+ return /* @__PURE__ */ React4.createElement(Text3, { key, dimColor: true }, line);
3875
3906
  }));
3876
3907
  }
3877
3908
  function BranchBlock({ branch }) {
@@ -3880,38 +3911,35 @@ function BranchBlock({ branch }) {
3880
3911
  const t = (branch.temperatures[i] ?? 0).toFixed(1);
3881
3912
  return `${marker} #${i} T=${t} u=${u}`;
3882
3913
  }).join(" ");
3883
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, "\u{1F500} branched ", /* @__PURE__ */ React3.createElement(Text3, { bold: true }, branch.budget), ` samples \u2192 picked #${branch.chosenIndex} `, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, per)));
3914
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { color: "blue" }, "\u{1F500} branched ", /* @__PURE__ */ React4.createElement(Text3, { bold: true }, branch.budget), ` samples \u2192 picked #${branch.chosenIndex} `, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, per)));
3884
3915
  }
3885
3916
  function ReasoningBlock({ reasoning }) {
3886
3917
  const max = 260;
3887
3918
  const flat = reasoning.replace(/\s+/g, " ").trim();
3888
3919
  const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
3889
- return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", preview));
3920
+ return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", preview));
3890
3921
  }
3891
3922
  function Elapsed() {
3892
- const [s, setS] = useState(0);
3893
- useEffect(() => {
3894
- const start = Date.now();
3895
- const id = setInterval(() => setS(Math.floor((Date.now() - start) / 1e3)), 1e3);
3896
- return () => clearInterval(id);
3897
- }, []);
3923
+ const s = useElapsedSeconds();
3898
3924
  const mm = String(Math.floor(s / 60)).padStart(2, "0");
3899
3925
  const ss = String(s % 60).padStart(2, "0");
3900
- return /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, `${mm}:${ss}`);
3926
+ return /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, `${mm}:${ss}`);
3901
3927
  }
3902
3928
  function StreamingAssistant({ event }) {
3903
3929
  if (event.branchProgress) {
3904
3930
  const p = event.branchProgress;
3905
3931
  if (p.completed === 0) {
3906
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "assistant", " "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, "\u{1F500} launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026", " "), /* @__PURE__ */ React3.createElement(Elapsed, null)), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " ", "spread across T=0.0/0.5/1.0 \xB7 typical wait 30-90s for reasoner"));
3932
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "green" }, "assistant", " "), /* @__PURE__ */ React4.createElement(Text3, { color: "blue" }, "\u{1F500} launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026", " "), /* @__PURE__ */ React4.createElement(Elapsed, null)), /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, " ", "spread across T=0.0/0.5/1.0 \xB7 typical wait 30-90s for reasoner"));
3907
3933
  }
3908
3934
  const pct2 = Math.round(p.completed / p.total * 100);
3909
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "assistant", " "), /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, "\u{1F500} branching ", p.completed, "/", p.total, " (", pct2, "%)", " "), /* @__PURE__ */ React3.createElement(Elapsed, null)), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " latest #", p.latestIndex, " T=", p.latestTemperature.toFixed(1), " u=", p.latestUncertainties, p.completed < p.total ? " \xB7 waiting for other samples\u2026" : " \xB7 selecting winner\u2026"));
3935
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "green" }, "assistant", " "), /* @__PURE__ */ React4.createElement(Text3, { color: "blue" }, "\u{1F500} branching ", p.completed, "/", p.total, " (", pct2, "%)", " "), /* @__PURE__ */ React4.createElement(Elapsed, null)), /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, " latest #", p.latestIndex, " T=", p.latestTemperature.toFixed(1), " u=", p.latestUncertainties, p.completed < p.total ? " \xB7 waiting for other samples\u2026" : " \xB7 selecting winner\u2026"));
3910
3936
  }
3911
3937
  const tail = lastLine(event.text, 140);
3912
3938
  const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
3913
- const preFirstByte = !event.text && !event.reasoning;
3914
- const reasoningOnly = !event.text && !!event.reasoning;
3939
+ const toolCallBuild = event.toolCallBuild;
3940
+ const preFirstByte = !event.text && !event.reasoning && !toolCallBuild;
3941
+ const reasoningOnly = !event.text && !!event.reasoning && !toolCallBuild;
3942
+ const toolCallOnly = !event.text && !event.reasoning && !!toolCallBuild;
3915
3943
  let label;
3916
3944
  let labelColor;
3917
3945
  if (preFirstByte) {
@@ -3920,20 +3948,24 @@ function StreamingAssistant({ event }) {
3920
3948
  } else if (reasoningOnly) {
3921
3949
  label = `R1 reasoning \xB7 ${event.reasoning?.length ?? 0} chars of thought`;
3922
3950
  labelColor = "cyan";
3951
+ } else if (toolCallOnly) {
3952
+ label = `assembling tool call <${toolCallBuild.name}> \xB7 ${toolCallBuild.chars} chars of arguments`;
3953
+ labelColor = "magenta";
3923
3954
  } else {
3924
- label = event.reasoning ? `writing response \xB7 ${event.text.length} chars \xB7 after ${event.reasoning.length} chars of reasoning` : `writing response \xB7 ${event.text.length} chars`;
3955
+ const parts = [`writing response \xB7 ${event.text.length} chars`];
3956
+ if (event.reasoning) parts.push(`after ${event.reasoning.length} chars of reasoning`);
3957
+ if (toolCallBuild) {
3958
+ parts.push(`building tool call <${toolCallBuild.name}> \xB7 ${toolCallBuild.chars} chars`);
3959
+ }
3960
+ label = parts.join(" \xB7 ");
3925
3961
  labelColor = "green";
3926
3962
  }
3927
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "assistant", " "), /* @__PURE__ */ React3.createElement(Pulse, null), /* @__PURE__ */ React3.createElement(Text3, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React3.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React3.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "\u25B8 ", tail) : reasoningOnly ? /* @__PURE__ */ React3.createElement(Text3, { color: "yellow", dimColor: true }, " R1 is thinking before it speaks \u2014 body text starts when reasoning completes (typically 20-90s).") : /* @__PURE__ */ React3.createElement(Text3, { dimColor: true, italic: true }, " connection open, first byte typically in 5-60s depending on model + load"));
3963
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "green" }, "assistant", " "), /* @__PURE__ */ React4.createElement(Pulse, null), /* @__PURE__ */ React4.createElement(Text3, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React4.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React4.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, "\u25B8 ", tail) : reasoningOnly ? /* @__PURE__ */ React4.createElement(Text3, { color: "yellow", dimColor: true }, " R1 is thinking before it speaks \u2014 body text starts when reasoning completes (typically 20-90s).") : /* @__PURE__ */ React4.createElement(Text3, { dimColor: true, italic: true }, " connection open, first byte typically in 5-60s depending on model + load"));
3928
3964
  }
3929
3965
  function Pulse() {
3930
- const [tick, setTick] = useState(0);
3931
- useEffect(() => {
3932
- const id = setInterval(() => setTick((t) => t + 1), 500);
3933
- return () => clearInterval(id);
3934
- }, []);
3966
+ const tick = useTick();
3935
3967
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
3936
- return /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, frames[tick % frames.length]);
3968
+ return /* @__PURE__ */ React4.createElement(Text3, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
3937
3969
  }
3938
3970
  function lastLine(s, maxChars) {
3939
3971
  const flat = s.replace(/\s+/g, " ").trim();
@@ -3942,7 +3974,7 @@ function lastLine(s, maxChars) {
3942
3974
  }
3943
3975
  function StatsLine({ stats }) {
3944
3976
  const hit = (stats.cacheHitRatio * 100).toFixed(1);
3945
- return /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " \u21B3 cache ", hit, "% \xB7 tokens ", stats.usage.promptTokens, "\u2192", stats.usage.completionTokens, " \xB7 $", stats.cost.toFixed(6));
3977
+ return /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, " \u21B3 cache ", hit, "% \xB7 tokens ", stats.usage.promptTokens, "\u2192", stats.usage.completionTokens, " \xB7 $", stats.cost.toFixed(6));
3946
3978
  }
3947
3979
  function truncate2(s, max) {
3948
3980
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -3950,7 +3982,7 @@ function truncate2(s, max) {
3950
3982
 
3951
3983
  // src/cli/ui/PromptInput.tsx
3952
3984
  import { Box as Box4, Text as Text4, useInput } from "ink";
3953
- import React4, { useEffect as useEffect2, useState as useState2 } from "react";
3985
+ import React5 from "react";
3954
3986
 
3955
3987
  // src/cli/ui/multiline-keys.ts
3956
3988
  var BACKSLASH_SUFFIX = /\\$/;
@@ -3994,16 +4026,8 @@ function PromptInput({
3994
4026
  disabled,
3995
4027
  placeholder
3996
4028
  }) {
3997
- const [showCursor, setShowCursor] = useState2(true);
3998
- useEffect2(() => {
3999
- if (disabled) {
4000
- setShowCursor(false);
4001
- return;
4002
- }
4003
- setShowCursor(true);
4004
- const id = setInterval(() => setShowCursor((s) => !s), 500);
4005
- return () => clearInterval(id);
4006
- }, [disabled]);
4029
+ const tick = useTick();
4030
+ const showCursor = disabled ? false : Math.floor(tick / 4) % 2 === 0;
4007
4031
  useInput(
4008
4032
  (input, key) => {
4009
4033
  const keyEvent = {
@@ -4032,27 +4056,27 @@ function PromptInput({
4032
4056
  const effectivePlaceholder = disabled ? placeholder ?? "\u2026waiting for response\u2026" : placeholder ?? "type a message, or /command \xB7 Ctrl+J for newline";
4033
4057
  const lines = value.length > 0 ? value.split("\n") : [""];
4034
4058
  const borderColor = disabled ? "gray" : "cyan";
4035
- return /* @__PURE__ */ React4.createElement(Box4, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, lines.map((line, i) => {
4059
+ return /* @__PURE__ */ React5.createElement(Box4, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, lines.map((line, i) => {
4036
4060
  const isLast = i === lines.length - 1;
4037
4061
  const isFirst = i === 0;
4038
4062
  const showPlaceholder = isFirst && value.length === 0;
4039
4063
  return (
4040
4064
  // biome-ignore lint/suspicious/noArrayIndexKey: stable by construction — lines are derived from `value.split("\n")` and never reordered
4041
- /* @__PURE__ */ React4.createElement(Box4, { key: i }, isFirst ? /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: borderColor }, "you \u203A", " ") : /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, " "), showPlaceholder && isLast && !disabled ? /* @__PURE__ */ React4.createElement(Text4, { color: borderColor }, showCursor ? "\u258C" : " ") : null, showPlaceholder ? /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, effectivePlaceholder) : /* @__PURE__ */ React4.createElement(Text4, null, line), !showPlaceholder && isLast && !disabled ? /* @__PURE__ */ React4.createElement(Text4, { color: borderColor }, showCursor ? "\u258C" : " ") : null)
4065
+ /* @__PURE__ */ React5.createElement(Box4, { key: i }, isFirst ? /* @__PURE__ */ React5.createElement(Text4, { bold: true, color: borderColor }, "you \u203A", " ") : /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, " "), showPlaceholder && isLast && !disabled ? /* @__PURE__ */ React5.createElement(Text4, { color: borderColor }, showCursor ? "\u258C" : " ") : null, showPlaceholder ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, effectivePlaceholder) : /* @__PURE__ */ React5.createElement(Text4, null, line), !showPlaceholder && isLast && !disabled ? /* @__PURE__ */ React5.createElement(Text4, { color: borderColor }, showCursor ? "\u258C" : " ") : null)
4042
4066
  );
4043
4067
  }));
4044
4068
  }
4045
4069
 
4046
4070
  // src/cli/ui/SlashSuggestions.tsx
4047
4071
  import { Box as Box5, Text as Text5 } from "ink";
4048
- import React5 from "react";
4072
+ import React6 from "react";
4049
4073
  function SlashSuggestions({
4050
4074
  matches,
4051
4075
  selectedIndex
4052
4076
  }) {
4053
4077
  if (matches === null) return null;
4054
4078
  if (matches.length === 0) {
4055
- return /* @__PURE__ */ React5.createElement(Box5, { paddingX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
4079
+ return /* @__PURE__ */ React6.createElement(Box5, { paddingX: 1 }, /* @__PURE__ */ React6.createElement(Text5, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
4056
4080
  }
4057
4081
  const MAX = 8;
4058
4082
  const total = matches.length;
@@ -4060,21 +4084,21 @@ function SlashSuggestions({
4060
4084
  const shown = matches.slice(windowStart, windowStart + MAX);
4061
4085
  const hiddenAbove = windowStart;
4062
4086
  const hiddenBelow = total - windowStart - shown.length;
4063
- return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React5.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2191/\u2193 navigate \xB7 Tab or Enter to pick"));
4087
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React6.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, " \u2191/\u2193 navigate \xB7 Tab or Enter to pick"));
4064
4088
  }
4065
4089
  function SuggestionRow({ spec, isSelected }) {
4066
4090
  const marker = isSelected ? "\u25B8" : " ";
4067
4091
  const name = `/${spec.cmd}`;
4068
4092
  const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
4069
4093
  if (isSelected) {
4070
- return /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, " ", spec.summary));
4094
+ return /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text5, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React6.createElement(Text5, { color: "cyan" }, " ", spec.summary));
4071
4095
  }
4072
- return /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
4096
+ return /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
4073
4097
  }
4074
4098
 
4075
4099
  // src/cli/ui/StatsPanel.tsx
4076
4100
  import { Box as Box6, Text as Text6 } from "ink";
4077
- import React6 from "react";
4101
+ import React7 from "react";
4078
4102
  function StatsPanel({
4079
4103
  summary,
4080
4104
  model,
@@ -4089,7 +4113,7 @@ function StatsPanel({
4089
4113
  const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;
4090
4114
  const ctxRatio = summary.lastPromptTokens / ctxMax;
4091
4115
  const ctxColor = ctxRatio >= 0.8 ? "red" : ctxRatio >= 0.5 ? "yellow" : void 0;
4092
- return /* @__PURE__ */ React6.createElement(Box6, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React6.createElement(Box6, { justifyContent: "space-between" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "Reasonix"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 model "), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, model), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 prefix "), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, prefixHash), harvestOn ? /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, " \xB7 branch", branchBudget) : null), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "turns ", summary.turns, " \xB7 type /help")), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "cache hit "), /* @__PURE__ */ React6.createElement(Text6, { color: hitColor, bold: true }, hitPct, "%")), /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "cost "), /* @__PURE__ */ React6.createElement(Text6, { color: "green", bold: true }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")")), summary.lastPromptTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "ctx "), /* @__PURE__ */ React6.createElement(Text6, { color: ctxColor, bold: ctxColor !== void 0 }, formatTokens(summary.lastPromptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", (ctxRatio * 100).toFixed(0), "%)"), ctxRatio >= 0.8 ? /* @__PURE__ */ React6.createElement(Text6, { color: "red", bold: true }, " ", "\xB7 /compact") : null) : null, balance ? /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "balance "), /* @__PURE__ */ React6.createElement(Text6, { color: balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green", bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : "")) : null));
4116
+ return /* @__PURE__ */ React7.createElement(Box6, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Box6, { justifyContent: "space-between" }, /* @__PURE__ */ React7.createElement(Text6, null, /* @__PURE__ */ React7.createElement(Text6, { color: "cyan", bold: true }, "Reasonix"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " \xB7 model "), /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, model), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " \xB7 prefix "), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, prefixHash), harvestOn ? /* @__PURE__ */ React7.createElement(Text6, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React7.createElement(Text6, { color: "blue" }, " \xB7 branch", branchBudget) : null), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, "turns ", summary.turns, " \xB7 type /help")), /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React7.createElement(Text6, null, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, "cache hit "), /* @__PURE__ */ React7.createElement(Text6, { color: hitColor, bold: true }, hitPct, "%")), /* @__PURE__ */ React7.createElement(Text6, null, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, "cost "), /* @__PURE__ */ React7.createElement(Text6, { color: "green", bold: true }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")")), summary.lastPromptTokens > 0 ? /* @__PURE__ */ React7.createElement(Text6, null, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, "ctx "), /* @__PURE__ */ React7.createElement(Text6, { color: ctxColor, bold: ctxColor !== void 0 }, formatTokens(summary.lastPromptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " (", (ctxRatio * 100).toFixed(0), "%)"), ctxRatio >= 0.8 ? /* @__PURE__ */ React7.createElement(Text6, { color: "red", bold: true }, " ", "\xB7 /compact") : null) : null, balance ? /* @__PURE__ */ React7.createElement(Text6, null, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, "balance "), /* @__PURE__ */ React7.createElement(Text6, { color: balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green", bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : "")) : null));
4093
4117
  }
4094
4118
  function formatTokens(n) {
4095
4119
  if (n < 1e3) return String(n);
@@ -4537,7 +4561,8 @@ function gitTail(res) {
4537
4561
  }
4538
4562
 
4539
4563
  // src/cli/ui/App.tsx
4540
- var FLUSH_INTERVAL_MS = 60;
4564
+ var FLUSH_INTERVAL_MS = 100;
4565
+ var PLAIN_UI = process.env.REASONIX_UI === "plain";
4541
4566
  function App({
4542
4567
  model,
4543
4568
  system,
@@ -4552,22 +4577,23 @@ function App({
4552
4577
  codeMode
4553
4578
  }) {
4554
4579
  const { exit } = useApp();
4555
- const [historical, setHistorical] = useState3([]);
4556
- const [streaming, setStreaming] = useState3(null);
4557
- const [input, setInput] = useState3("");
4558
- const [busy, setBusy] = useState3(false);
4580
+ const [historical, setHistorical] = useState2([]);
4581
+ const [streaming, setStreaming] = useState2(null);
4582
+ const [input, setInput] = useState2("");
4583
+ const [busy, setBusy] = useState2(false);
4559
4584
  const abortedThisTurn = useRef(false);
4560
- const [ongoingTool, setOngoingTool] = useState3(null);
4561
- const [toolProgress, setToolProgress] = useState3(null);
4562
- const [statusLine, setStatusLine] = useState3(null);
4563
- const [balance, setBalance] = useState3(null);
4585
+ const [ongoingTool, setOngoingTool] = useState2(null);
4586
+ const [toolProgress, setToolProgress] = useState2(null);
4587
+ const [statusLine, setStatusLine] = useState2(null);
4588
+ const [balance, setBalance] = useState2(null);
4564
4589
  const lastEditSnapshots = useRef(null);
4565
4590
  const pendingEdits = useRef([]);
4566
4591
  const promptHistory = useRef([]);
4567
4592
  const historyCursor = useRef(-1);
4593
+ const assistantIterCounter = useRef(0);
4568
4594
  const toolHistoryRef = useRef([]);
4569
- const [slashSelected, setSlashSelected] = useState3(0);
4570
- const [summary, setSummary] = useState3({
4595
+ const [slashSelected, setSlashSelected] = useState2(0);
4596
+ const [summary, setSummary] = useState2({
4571
4597
  turns: 0,
4572
4598
  totalCostUsd: 0,
4573
4599
  totalInputCostUsd: 0,
@@ -4586,7 +4612,7 @@ function App({
4586
4612
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
4587
4613
  });
4588
4614
  }
4589
- useEffect3(() => {
4615
+ useEffect2(() => {
4590
4616
  return () => {
4591
4617
  transcriptRef.current?.end();
4592
4618
  };
@@ -4595,7 +4621,7 @@ function App({
4595
4621
  if (!input.startsWith("/") || input.includes(" ")) return null;
4596
4622
  return suggestSlashCommands(input.slice(1), !!codeMode);
4597
4623
  }, [input, codeMode]);
4598
- useEffect3(() => {
4624
+ useEffect2(() => {
4599
4625
  setSlashSelected((prev) => {
4600
4626
  if (!slashMatches || slashMatches.length === 0) return 0;
4601
4627
  if (prev >= slashMatches.length) return slashMatches.length - 1;
@@ -4614,7 +4640,7 @@ function App({
4614
4640
  loopRef.current = l;
4615
4641
  return l;
4616
4642
  }, [model, system, harvest2, branch, session, tools]);
4617
- useEffect3(() => {
4643
+ useEffect2(() => {
4618
4644
  let cancelled = false;
4619
4645
  void (async () => {
4620
4646
  const bal = await loop.client.getBalance().catch(() => null);
@@ -4626,7 +4652,7 @@ function App({
4626
4652
  cancelled = true;
4627
4653
  };
4628
4654
  }, [loop]);
4629
- useEffect3(() => {
4655
+ useEffect2(() => {
4630
4656
  if (!progressSink) return;
4631
4657
  progressSink.current = (info) => {
4632
4658
  setToolProgress({
@@ -4640,7 +4666,7 @@ function App({
4640
4666
  };
4641
4667
  }, [progressSink]);
4642
4668
  const sessionBannerShown = useRef(false);
4643
- useEffect3(() => {
4669
+ useEffect2(() => {
4644
4670
  if (sessionBannerShown.current) return;
4645
4671
  sessionBannerShown.current = true;
4646
4672
  if (!session) {
@@ -4824,24 +4850,32 @@ function App({
4824
4850
  const streamRef = { id: assistantId, text: "", reasoning: "" };
4825
4851
  const contentBuf = { current: "" };
4826
4852
  const reasoningBuf = { current: "" };
4853
+ const toolCallBuildBuf = {
4854
+ current: null
4855
+ };
4827
4856
  setStreaming({ id: assistantId, role: "assistant", text: "", streaming: true });
4828
4857
  setBusy(true);
4829
4858
  abortedThisTurn.current = false;
4830
4859
  const flush = () => {
4831
- if (!contentBuf.current && !reasoningBuf.current) return;
4860
+ if (!contentBuf.current && !reasoningBuf.current && !toolCallBuildBuf.current) return;
4832
4861
  streamRef.text += contentBuf.current;
4833
4862
  streamRef.reasoning += reasoningBuf.current;
4863
+ if (toolCallBuildBuf.current) {
4864
+ streamRef.toolCallBuild = toolCallBuildBuf.current;
4865
+ }
4834
4866
  contentBuf.current = "";
4835
4867
  reasoningBuf.current = "";
4868
+ toolCallBuildBuf.current = null;
4836
4869
  setStreaming({
4837
4870
  id: assistantId,
4838
4871
  role: "assistant",
4839
4872
  text: streamRef.text,
4840
4873
  reasoning: streamRef.reasoning || void 0,
4874
+ toolCallBuild: streamRef.toolCallBuild,
4841
4875
  streaming: true
4842
4876
  });
4843
4877
  };
4844
- const timer = setInterval(flush, FLUSH_INTERVAL_MS);
4878
+ const timer = PLAIN_UI ? null : setInterval(flush, FLUSH_INTERVAL_MS);
4845
4879
  try {
4846
4880
  for await (const ev of loop.step(text)) {
4847
4881
  writeTranscript(ev);
@@ -4853,6 +4887,13 @@ function App({
4853
4887
  } else if (ev.role === "assistant_delta") {
4854
4888
  if (ev.content) contentBuf.current += ev.content;
4855
4889
  if (ev.reasoningDelta) reasoningBuf.current += ev.reasoningDelta;
4890
+ } else if (ev.role === "tool_call_delta") {
4891
+ if (ev.toolName) {
4892
+ toolCallBuildBuf.current = {
4893
+ name: ev.toolName,
4894
+ chars: ev.toolCallArgsChars ?? 0
4895
+ };
4896
+ }
4856
4897
  } else if (ev.role === "branch_start") {
4857
4898
  setStreaming({
4858
4899
  id: assistantId,
@@ -4876,13 +4917,15 @@ function App({
4876
4917
  setStreaming(null);
4877
4918
  setSummary(loop.stats.summary());
4878
4919
  const finalText = ev.content || streamRef.text;
4920
+ const iterReasoning = streamRef.reasoning || void 0;
4921
+ const iterId = `${assistantId}-i${assistantIterCounter.current++}`;
4879
4922
  setHistorical((prev) => [
4880
4923
  ...prev,
4881
4924
  {
4882
- id: assistantId,
4925
+ id: iterId,
4883
4926
  role: "assistant",
4884
4927
  text: finalText,
4885
- reasoning: streamRef.reasoning || void 0,
4928
+ reasoning: iterReasoning,
4886
4929
  planState: ev.planState,
4887
4930
  branch: ev.branch,
4888
4931
  stats: ev.stats,
@@ -4890,6 +4933,12 @@ function App({
4890
4933
  streaming: false
4891
4934
  }
4892
4935
  ]);
4936
+ streamRef.text = "";
4937
+ streamRef.reasoning = "";
4938
+ streamRef.toolCallBuild = void 0;
4939
+ contentBuf.current = "";
4940
+ reasoningBuf.current = "";
4941
+ toolCallBuildBuf.current = null;
4893
4942
  if (codeMode && finalText && !ev.forcedSummary) {
4894
4943
  const blocks = parseEditBlocks(finalText);
4895
4944
  if (blocks.length > 0) {
@@ -4938,7 +4987,7 @@ function App({
4938
4987
  }
4939
4988
  flush();
4940
4989
  } finally {
4941
- clearInterval(timer);
4990
+ if (timer) clearInterval(timer);
4942
4991
  setStreaming(null);
4943
4992
  setOngoingTool(null);
4944
4993
  setToolProgress(null);
@@ -4968,7 +5017,7 @@ function App({
4968
5017
  writeTranscript
4969
5018
  ]
4970
5019
  );
4971
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(
5020
+ return /* @__PURE__ */ React8.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(
4972
5021
  StatsPanel,
4973
5022
  {
4974
5023
  summary,
@@ -4978,41 +5027,22 @@ function App({
4978
5027
  branchBudget: loop.branchOptions.budget,
4979
5028
  balance
4980
5029
  }
4981
- ), /* @__PURE__ */ React7.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React7.createElement(EventRow, { key: item.id, event: item })), streaming ? /* @__PURE__ */ React7.createElement(Box7, { marginY: 1 }, /* @__PURE__ */ React7.createElement(EventRow, { event: streaming })) : null, ongoingTool ? /* @__PURE__ */ React7.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !ongoingTool && statusLine ? /* @__PURE__ */ React7.createElement(StatusRow, { text: statusLine }) : null, busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React7.createElement(StatusRow, { text: "processing\u2026" }) : null, /* @__PURE__ */ React7.createElement(PromptInput, { value: input, onChange: setInput, onSubmit: handleSubmit, disabled: busy }), /* @__PURE__ */ React7.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }));
5030
+ ), /* @__PURE__ */ React8.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React8.createElement(EventRow, { key: item.id, event: item })), !PLAIN_UI && streaming ? /* @__PURE__ */ React8.createElement(Box7, { marginY: 1 }, /* @__PURE__ */ React8.createElement(EventRow, { event: streaming })) : null, !PLAIN_UI && ongoingTool ? /* @__PURE__ */ React8.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !ongoingTool && statusLine ? /* @__PURE__ */ React8.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React8.createElement(StatusRow, { text: "processing\u2026" }) : null, /* @__PURE__ */ React8.createElement(PromptInput, { value: input, onChange: setInput, onSubmit: handleSubmit, disabled: busy }), /* @__PURE__ */ React8.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected })));
4982
5031
  }
5032
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4983
5033
  function StatusRow({ text }) {
4984
- const [tick, setTick] = useState3(0);
4985
- const [elapsed, setElapsed] = useState3(0);
4986
- useEffect3(() => {
4987
- const start = Date.now();
4988
- const frameId = setInterval(() => setTick((t) => t + 1), 120);
4989
- const secId = setInterval(() => setElapsed(Math.floor((Date.now() - start) / 1e3)), 1e3);
4990
- return () => {
4991
- clearInterval(frameId);
4992
- clearInterval(secId);
4993
- };
4994
- }, []);
4995
- const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4996
- return /* @__PURE__ */ React7.createElement(Box7, { marginY: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "magenta" }, frames[tick % frames.length]), /* @__PURE__ */ React7.createElement(Text7, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, ` ${elapsed}s`));
5034
+ const tick = useTick();
5035
+ const elapsed = useElapsedSeconds();
5036
+ return /* @__PURE__ */ React8.createElement(Box7, { marginY: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React8.createElement(Text7, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, ` ${elapsed}s`));
4997
5037
  }
4998
5038
  function OngoingToolRow({
4999
5039
  tool,
5000
5040
  progress
5001
5041
  }) {
5002
- const [tick, setTick] = useState3(0);
5003
- const [elapsed, setElapsed] = useState3(0);
5004
- useEffect3(() => {
5005
- const start = Date.now();
5006
- const frameId = setInterval(() => setTick((t) => t + 1), 120);
5007
- const secId = setInterval(() => setElapsed(Math.floor((Date.now() - start) / 1e3)), 1e3);
5008
- return () => {
5009
- clearInterval(frameId);
5010
- clearInterval(secId);
5011
- };
5012
- }, []);
5013
- const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
5042
+ const tick = useTick();
5043
+ const elapsed = useElapsedSeconds();
5014
5044
  const summary = summarizeToolArgs(tool.name, tool.args);
5015
- return /* @__PURE__ */ React7.createElement(Box7, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, frames[tick % frames.length]), /* @__PURE__ */ React7.createElement(Text7, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React7.createElement(Box7, { paddingLeft: 2 }, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React7.createElement(Box7, { paddingLeft: 2 }, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, summary)) : null);
5045
+ return /* @__PURE__ */ React8.createElement(Box7, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React8.createElement(Box7, { paddingLeft: 2 }, /* @__PURE__ */ React8.createElement(Text7, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React8.createElement(Box7, { paddingLeft: 2 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, summary)) : null);
5016
5046
  }
5017
5047
  function renderProgressLine(p) {
5018
5048
  const msg = p.message ? ` ${p.message}` : "";
@@ -5110,10 +5140,10 @@ function describeRepair(repair) {
5110
5140
  // src/cli/ui/Setup.tsx
5111
5141
  import { Box as Box8, Text as Text8, useApp as useApp2 } from "ink";
5112
5142
  import TextInput from "ink-text-input";
5113
- import React8, { useState as useState4 } from "react";
5143
+ import React9, { useState as useState3 } from "react";
5114
5144
  function Setup({ onReady }) {
5115
- const [value, setValue] = useState4("");
5116
- const [error, setError] = useState4(null);
5145
+ const [value, setValue] = useState3("");
5146
+ const [error, setError] = useState3(null);
5117
5147
  const { exit } = useApp2();
5118
5148
  const handleSubmit = (raw) => {
5119
5149
  const trimmed = raw.trim();
@@ -5134,7 +5164,7 @@ function Setup({ onReady }) {
5134
5164
  }
5135
5165
  onReady(trimmed);
5136
5166
  };
5137
- return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React8.createElement(
5167
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React9.createElement(
5138
5168
  TextInput,
5139
5169
  {
5140
5170
  value,
@@ -5143,14 +5173,14 @@ function Setup({ onReady }) {
5143
5173
  mask: "\u2022",
5144
5174
  placeholder: "sk-..."
5145
5175
  }
5146
- )), error ? /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, error)) : value ? /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "(Type /exit to abort.)")));
5176
+ )), error ? /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { color: "red" }, error)) : value ? /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "(Type /exit to abort.)")));
5147
5177
  }
5148
5178
 
5149
5179
  // src/cli/commands/chat.tsx
5150
5180
  function Root({ initialKey, tools, mcpSpecs, mcpServers, progressSink, ...appProps }) {
5151
- const [key, setKey] = useState5(initialKey);
5181
+ const [key, setKey] = useState4(initialKey);
5152
5182
  if (!key) {
5153
- return /* @__PURE__ */ React9.createElement(
5183
+ return /* @__PURE__ */ React10.createElement(
5154
5184
  Setup,
5155
5185
  {
5156
5186
  onReady: (k) => {
@@ -5161,7 +5191,7 @@ function Root({ initialKey, tools, mcpSpecs, mcpServers, progressSink, ...appPro
5161
5191
  );
5162
5192
  }
5163
5193
  process.env.DEEPSEEK_API_KEY = key;
5164
- return /* @__PURE__ */ React9.createElement(
5194
+ return /* @__PURE__ */ React10.createElement(
5165
5195
  App,
5166
5196
  {
5167
5197
  model: appProps.model,
@@ -5245,7 +5275,7 @@ async function chatCommand(opts) {
5245
5275
  }
5246
5276
  const mcpSpecs = successfulSpecs;
5247
5277
  const { waitUntilExit } = render(
5248
- /* @__PURE__ */ React9.createElement(
5278
+ /* @__PURE__ */ React10.createElement(
5249
5279
  Root,
5250
5280
  {
5251
5281
  initialKey,
@@ -5256,7 +5286,9 @@ async function chatCommand(opts) {
5256
5286
  ...opts
5257
5287
  }
5258
5288
  ),
5259
- { exitOnCtrlC: true }
5289
+ // patchConsole:false we never log to console during the TUI, and the
5290
+ // patch is a known redraw-glitch source on winpty/MINTTY terminals.
5291
+ { exitOnCtrlC: true, patchConsole: false }
5260
5292
  );
5261
5293
  try {
5262
5294
  await waitUntilExit();
@@ -5293,34 +5325,34 @@ async function codeCommand(opts = {}) {
5293
5325
  import { writeFileSync as writeFileSync4 } from "fs";
5294
5326
  import { basename as basename2 } from "path";
5295
5327
  import { render as render2 } from "ink";
5296
- import React12 from "react";
5328
+ import React13 from "react";
5297
5329
 
5298
5330
  // src/cli/ui/DiffApp.tsx
5299
5331
  import { Box as Box10, Static as Static2, Text as Text10, useApp as useApp3, useInput as useInput3 } from "ink";
5300
- import React11, { useState as useState6 } from "react";
5332
+ import React12, { useState as useState5 } from "react";
5301
5333
 
5302
5334
  // src/cli/ui/RecordView.tsx
5303
5335
  import { Box as Box9, Text as Text9 } from "ink";
5304
- import React10 from "react";
5336
+ import React11 from "react";
5305
5337
  function RecordView({ rec, compact = false }) {
5306
5338
  const toolArgsMax = compact ? 120 : 200;
5307
5339
  const toolContentMax = compact ? 200 : 400;
5308
5340
  if (rec.role === "user") {
5309
- return /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React10.createElement(Text9, null, rec.content));
5341
+ return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text9, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React11.createElement(Text9, null, rec.content));
5310
5342
  }
5311
5343
  if (rec.role === "assistant_final") {
5312
- return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React10.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React10.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React10.createElement(Text9, null, rec.content) : /* @__PURE__ */ React10.createElement(Text9, { dimColor: true, italic: true }, "(tool-call response only)"));
5344
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text9, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React11.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React11.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React11.createElement(Text9, null, rec.content) : /* @__PURE__ */ React11.createElement(Text9, { dimColor: true, italic: true }, "(tool-call response only)"));
5313
5345
  }
5314
5346
  if (rec.role === "tool") {
5315
- return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " args: ", truncate3(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2192 ", truncate3(rec.content, toolContentMax)));
5347
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " args: ", truncate3(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " \u2192 ", truncate3(rec.content, toolContentMax)));
5316
5348
  }
5317
5349
  if (rec.role === "error") {
5318
- return /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React10.createElement(Text9, { color: "red" }, rec.error ?? rec.content));
5350
+ return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React11.createElement(Text9, { color: "red" }, rec.error ?? rec.content));
5319
5351
  }
5320
5352
  if (rec.role === "done" || rec.role === "assistant_delta") {
5321
5353
  return null;
5322
5354
  }
5323
- return /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "[", rec.role, "] ", rec.content));
5355
+ return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, "[", rec.role, "] ", rec.content));
5324
5356
  }
5325
5357
  function CacheBadge({ usage }) {
5326
5358
  const hit = usage.prompt_cache_hit_tokens ?? 0;
@@ -5329,7 +5361,7 @@ function CacheBadge({ usage }) {
5329
5361
  if (total === 0) return null;
5330
5362
  const pct2 = hit / total * 100;
5331
5363
  const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
5332
- return /* @__PURE__ */ React10.createElement(Text9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React10.createElement(Text9, { color }, pct2.toFixed(1), "%"));
5364
+ return /* @__PURE__ */ React11.createElement(Text9, null, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React11.createElement(Text9, { color }, pct2.toFixed(1), "%"));
5333
5365
  }
5334
5366
  function truncate3(s, max) {
5335
5367
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -5340,7 +5372,7 @@ function DiffApp({ report }) {
5340
5372
  const { exit } = useApp3();
5341
5373
  const maxIdx = Math.max(0, report.pairs.length - 1);
5342
5374
  const initialIdx = report.firstDivergenceTurn ? report.pairs.findIndex((p) => p.turn === report.firstDivergenceTurn) : 0;
5343
- const [idx, setIdx] = useState6(Math.max(0, initialIdx));
5375
+ const [idx, setIdx] = useState5(Math.max(0, initialIdx));
5344
5376
  useInput3((input, key) => {
5345
5377
  if (input === "q" || key.ctrl && input === "c") {
5346
5378
  exit();
@@ -5363,7 +5395,7 @@ function DiffApp({ report }) {
5363
5395
  }
5364
5396
  });
5365
5397
  const pair = report.pairs[idx];
5366
- return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React11.createElement(DiffHeader, { report }), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React11.createElement(Text10, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React11.createElement(Text10, null, pair ? /* @__PURE__ */ React11.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React11.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React11.createElement(Text10, null, pair.divergenceNote)) : null, /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "j"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "k"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "N"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "g"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "q"), " ", "quit")));
5398
+ return /* @__PURE__ */ React12.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(DiffHeader, { report }), /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React12.createElement(Text10, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React12.createElement(Text10, null, pair ? /* @__PURE__ */ React12.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React12.createElement(Box10, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React12.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React12.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text10, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React12.createElement(Text10, null, pair.divergenceNote)) : null, /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "j"), "/", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "k"), "/", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "N"), "/", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "g"), "/", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React12.createElement(Text10, { bold: true }, "q"), " ", "quit")));
5367
5399
  }
5368
5400
  function DiffHeader({ report }) {
5369
5401
  const a = report.a;
@@ -5381,14 +5413,14 @@ function DiffHeader({ report }) {
5381
5413
  } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
5382
5414
  prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
5383
5415
  }
5384
- return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Box10, { justifyContent: "space-between" }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, a.label), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " vs B="), /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, b.label)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cache "), /* @__PURE__ */ React11.createElement(Text10, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React11.createElement(Text10, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React11.createElement(Text10, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cost "), /* @__PURE__ */ React11.createElement(Text10, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React11.createElement(Text10, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React11.createElement(Text10, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "model calls "), /* @__PURE__ */ React11.createElement(Text10, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true, italic: true }, prefixLine)) : null);
5416
+ return /* @__PURE__ */ React12.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Box10, { justifyContent: "space-between" }, /* @__PURE__ */ React12.createElement(Text10, null, /* @__PURE__ */ React12.createElement(Text10, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React12.createElement(Text10, { color: "blue" }, a.label), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, " vs B="), /* @__PURE__ */ React12.createElement(Text10, { color: "magenta" }, b.label)), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React12.createElement(Text10, null, /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, "cache "), /* @__PURE__ */ React12.createElement(Text10, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React12.createElement(Text10, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React12.createElement(Text10, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React12.createElement(Text10, null, /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, "cost "), /* @__PURE__ */ React12.createElement(Text10, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React12.createElement(Text10, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React12.createElement(Text10, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React12.createElement(Text10, null, /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, "model calls "), /* @__PURE__ */ React12.createElement(Text10, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text10, { dimColor: true, italic: true }, prefixLine)) : null);
5385
5417
  }
5386
5418
  function Pane({
5387
5419
  label,
5388
5420
  headerColor,
5389
5421
  records
5390
5422
  }) {
5391
- return /* @__PURE__ */ React11.createElement(
5423
+ return /* @__PURE__ */ React12.createElement(
5392
5424
  Box10,
5393
5425
  {
5394
5426
  flexDirection: "column",
@@ -5397,21 +5429,21 @@ function Pane({
5397
5429
  borderStyle: "single",
5398
5430
  borderColor: headerColor
5399
5431
  },
5400
- /* @__PURE__ */ React11.createElement(Text10, { color: headerColor, bold: true }, label),
5401
- records.length === 0 ? /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React11.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React11.createElement(RecordView, { key, rec, compact: true }))
5432
+ /* @__PURE__ */ React12.createElement(Text10, { color: headerColor, bold: true }, label),
5433
+ records.length === 0 ? /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text10, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React12.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React12.createElement(RecordView, { key, rec, compact: true }))
5402
5434
  );
5403
5435
  }
5404
5436
  function KindBadge({ kind }) {
5405
5437
  if (kind === "match") {
5406
- return /* @__PURE__ */ React11.createElement(Text10, { color: "green" }, "\u2713 match");
5438
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "green" }, "\u2713 match");
5407
5439
  }
5408
5440
  if (kind === "diverge") {
5409
- return /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u2605 diverge");
5441
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "yellow" }, "\u2605 diverge");
5410
5442
  }
5411
5443
  if (kind === "only_in_a") {
5412
- return /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, "\u2190 only in A");
5444
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "blue" }, "\u2190 only in A");
5413
5445
  }
5414
- return /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, "\u2192 only in B");
5446
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "magenta" }, "\u2192 only in B");
5415
5447
  }
5416
5448
  function paneRecords(pair, side) {
5417
5449
  if (!pair) return [];
@@ -5442,8 +5474,9 @@ markdown report written to ${opts.mdPath}`);
5442
5474
  return;
5443
5475
  }
5444
5476
  if (wantTui) {
5445
- const { waitUntilExit } = render2(React12.createElement(DiffApp, { report }), {
5446
- exitOnCtrlC: true
5477
+ const { waitUntilExit } = render2(React13.createElement(DiffApp, { report }), {
5478
+ exitOnCtrlC: true,
5479
+ patchConsole: false
5447
5480
  });
5448
5481
  await waitUntilExit();
5449
5482
  return;
@@ -5582,15 +5615,15 @@ function pad(s, width) {
5582
5615
 
5583
5616
  // src/cli/commands/replay.ts
5584
5617
  import { render as render3 } from "ink";
5585
- import React14 from "react";
5618
+ import React15 from "react";
5586
5619
 
5587
5620
  // src/cli/ui/ReplayApp.tsx
5588
5621
  import { Box as Box11, Static as Static3, Text as Text11, useApp as useApp4, useInput as useInput4 } from "ink";
5589
- import React13, { useMemo as useMemo2, useState as useState7 } from "react";
5622
+ import React14, { useMemo as useMemo2, useState as useState6 } from "react";
5590
5623
  function ReplayApp({ meta, pages }) {
5591
5624
  const { exit } = useApp4();
5592
5625
  const maxIdx = Math.max(0, pages.length - 1);
5593
- const [idx, setIdx] = useState7(maxIdx);
5626
+ const [idx, setIdx] = useState6(maxIdx);
5594
5627
  useInput4((input, key) => {
5595
5628
  if (input === "q" || key.ctrl && input === "c") {
5596
5629
  exit();
@@ -5625,14 +5658,14 @@ function ReplayApp({ meta, pages }) {
5625
5658
  const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
5626
5659
  const currentPage = pages[idx];
5627
5660
  const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
5628
- return /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
5661
+ return /* @__PURE__ */ React14.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(
5629
5662
  StatsPanel,
5630
5663
  {
5631
5664
  summary,
5632
5665
  model: cumStats.models[0] ?? meta?.model ?? "?",
5633
5666
  prefixHash
5634
5667
  }
5635
- ), /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React13.createElement(Box11, { justifyContent: "space-between" }, /* @__PURE__ */ React13.createElement(Text11, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React13.createElement(Text11, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React13.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React13.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React13.createElement(Text11, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React13.createElement(Text11, { dimColor: true }, /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "j"), "/", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "k"), "/", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "q"), " quit")));
5668
+ ), /* @__PURE__ */ React14.createElement(Box11, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React14.createElement(Box11, { justifyContent: "space-between" }, /* @__PURE__ */ React14.createElement(Text11, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React14.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React14.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React14.createElement(Text11, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React14.createElement(Box11, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "j"), "/", /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "k"), "/", /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React14.createElement(Text11, { bold: true }, "q"), " quit")));
5636
5669
  }
5637
5670
 
5638
5671
  // src/cli/commands/replay.ts
@@ -5644,8 +5677,9 @@ async function replayCommand(opts) {
5644
5677
  }
5645
5678
  const { parsed } = replayFromFile(opts.path);
5646
5679
  const pages = groupRecordsByTurn(parsed.records);
5647
- const { waitUntilExit } = render3(React14.createElement(ReplayApp, { meta: parsed.meta, pages }), {
5648
- exitOnCtrlC: true
5680
+ const { waitUntilExit } = render3(React15.createElement(ReplayApp, { meta: parsed.meta, pages }), {
5681
+ exitOnCtrlC: true,
5682
+ patchConsole: false
5649
5683
  });
5650
5684
  await waitUntilExit();
5651
5685
  }
@@ -5945,16 +5979,16 @@ function truncate4(s, max) {
5945
5979
 
5946
5980
  // src/cli/commands/setup.tsx
5947
5981
  import { render as render4 } from "ink";
5948
- import React17 from "react";
5982
+ import React18 from "react";
5949
5983
 
5950
5984
  // src/cli/ui/Wizard.tsx
5951
5985
  import { Box as Box13, Text as Text13, useApp as useApp5, useInput as useInput6 } from "ink";
5952
5986
  import TextInput2 from "ink-text-input";
5953
- import React16, { useState as useState9 } from "react";
5987
+ import React17, { useState as useState8 } from "react";
5954
5988
 
5955
5989
  // src/cli/ui/Select.tsx
5956
5990
  import { Box as Box12, Text as Text12, useInput as useInput5 } from "ink";
5957
- import React15, { useState as useState8 } from "react";
5991
+ import React16, { useState as useState7 } from "react";
5958
5992
  function SingleSelect({
5959
5993
  items,
5960
5994
  initialValue,
@@ -5965,7 +5999,7 @@ function SingleSelect({
5965
5999
  0,
5966
6000
  items.findIndex((i) => i.value === initialValue && !i.disabled)
5967
6001
  );
5968
- const [index, setIndex] = useState8(initialIndex === -1 ? 0 : initialIndex);
6002
+ const [index, setIndex] = useState7(initialIndex === -1 ? 0 : initialIndex);
5969
6003
  useInput5((_input, key) => {
5970
6004
  if (key.upArrow) {
5971
6005
  setIndex((i) => findNextEnabled(items, i, -1));
@@ -5978,7 +6012,7 @@ function SingleSelect({
5978
6012
  onCancel();
5979
6013
  }
5980
6014
  });
5981
- return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React15.createElement(
6015
+ return /* @__PURE__ */ React16.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React16.createElement(
5982
6016
  SelectRow,
5983
6017
  {
5984
6018
  key: item.value,
@@ -5995,11 +6029,11 @@ function MultiSelect({
5995
6029
  onCancel,
5996
6030
  footer
5997
6031
  }) {
5998
- const [index, setIndex] = useState8(() => {
6032
+ const [index, setIndex] = useState7(() => {
5999
6033
  const first = items.findIndex((i) => !i.disabled);
6000
6034
  return first === -1 ? 0 : first;
6001
6035
  });
6002
- const [selected, setSelected] = useState8(new Set(initialSelected));
6036
+ const [selected, setSelected] = useState7(new Set(initialSelected));
6003
6037
  useInput5((input, key) => {
6004
6038
  if (key.upArrow) {
6005
6039
  setIndex((i) => findNextEnabled(items, i, -1));
@@ -6021,10 +6055,10 @@ function MultiSelect({
6021
6055
  onCancel();
6022
6056
  }
6023
6057
  });
6024
- return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => {
6058
+ return /* @__PURE__ */ React16.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => {
6025
6059
  const checked = selected.has(item.value);
6026
6060
  const marker = checked ? "[x]" : "[ ]";
6027
- return /* @__PURE__ */ React15.createElement(
6061
+ return /* @__PURE__ */ React16.createElement(
6028
6062
  SelectRow,
6029
6063
  {
6030
6064
  key: item.value,
@@ -6033,7 +6067,7 @@ function MultiSelect({
6033
6067
  marker: `${i === index ? "\u25B8" : " "} ${marker}`
6034
6068
  }
6035
6069
  );
6036
- }), footer ? /* @__PURE__ */ React15.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, footer)) : null);
6070
+ }), footer ? /* @__PURE__ */ React16.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text12, { dimColor: true }, footer)) : null);
6037
6071
  }
6038
6072
  function SelectRow({
6039
6073
  item,
@@ -6041,7 +6075,7 @@ function SelectRow({
6041
6075
  marker
6042
6076
  }) {
6043
6077
  const color = item.disabled ? "gray" : active ? "cyan" : void 0;
6044
- return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Box12, null, /* @__PURE__ */ React15.createElement(Text12, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React15.createElement(Box12, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, item.hint)) : null);
6078
+ return /* @__PURE__ */ React16.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Box12, null, /* @__PURE__ */ React16.createElement(Text12, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React16.createElement(Box12, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React16.createElement(Text12, { dimColor: true }, item.hint)) : null);
6045
6079
  }
6046
6080
  function findNextEnabled(items, from, step) {
6047
6081
  if (items.length === 0) return 0;
@@ -6078,19 +6112,19 @@ var PRESET_DESCRIPTIONS = {
6078
6112
  var CATALOG_BY_NAME = new Map(MCP_CATALOG.map((e) => [e.name, e]));
6079
6113
  function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6080
6114
  const { exit } = useApp5();
6081
- const [step, setStep] = useState9(existingApiKey ? "preset" : "apiKey");
6082
- const [data, setData] = useState9({
6115
+ const [step, setStep] = useState8(existingApiKey ? "preset" : "apiKey");
6116
+ const [data, setData] = useState8({
6083
6117
  apiKey: existingApiKey ?? "",
6084
6118
  preset: initial?.preset ?? "fast",
6085
6119
  selectedCatalog: deriveInitialCatalog(initial?.mcp ?? []),
6086
6120
  catalogArgs: {}
6087
6121
  });
6088
- const [error, setError] = useState9(null);
6122
+ const [error, setError] = useState8(null);
6089
6123
  useInput6((_input, key) => {
6090
6124
  if (key.escape && step !== "saved" && onCancel) onCancel();
6091
6125
  });
6092
6126
  if (step === "apiKey") {
6093
- return /* @__PURE__ */ React16.createElement(
6127
+ return /* @__PURE__ */ React17.createElement(
6094
6128
  ApiKeyStep,
6095
6129
  {
6096
6130
  onSubmit: (key) => {
@@ -6104,7 +6138,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6104
6138
  );
6105
6139
  }
6106
6140
  if (step === "preset") {
6107
- return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React16.createElement(
6141
+ return /* @__PURE__ */ React17.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React17.createElement(
6108
6142
  SingleSelect,
6109
6143
  {
6110
6144
  items: presetItems(),
@@ -6114,10 +6148,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6114
6148
  setStep("mcp");
6115
6149
  }
6116
6150
  }
6117
- ), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
6151
+ ), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
6118
6152
  }
6119
6153
  if (step === "mcp") {
6120
- return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React16.createElement(
6154
+ return /* @__PURE__ */ React17.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React17.createElement(
6121
6155
  MultiSelect,
6122
6156
  {
6123
6157
  items: mcpItems(),
@@ -6142,7 +6176,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6142
6176
  }
6143
6177
  const currentName = pending[0];
6144
6178
  const entry = CATALOG_BY_NAME.get(currentName);
6145
- return /* @__PURE__ */ React16.createElement(
6179
+ return /* @__PURE__ */ React17.createElement(
6146
6180
  McpArgsStep,
6147
6181
  {
6148
6182
  entry,
@@ -6160,7 +6194,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6160
6194
  }
6161
6195
  if (step === "review") {
6162
6196
  const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
6163
- return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React16.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React16.createElement(
6197
+ return /* @__PURE__ */ React17.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React17.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React17.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React17.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React17.createElement(
6164
6198
  SummaryLine,
6165
6199
  {
6166
6200
  label: "MCP",
@@ -6168,8 +6202,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6168
6202
  }
6169
6203
  ), specs.map((spec, i) => (
6170
6204
  // biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
6171
- /* @__PURE__ */ React16.createElement(Box13, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "\xB7 ", spec))
6172
- )), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { color: "red" }, error)) : null, /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "enter save \xB7 esc cancel"))), /* @__PURE__ */ React16.createElement(
6205
+ /* @__PURE__ */ React17.createElement(Box13, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "\xB7 ", spec))
6206
+ )), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { color: "red" }, error)) : null, /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "enter save \xB7 esc cancel"))), /* @__PURE__ */ React17.createElement(
6173
6207
  ReviewConfirm,
6174
6208
  {
6175
6209
  onConfirm: () => {
@@ -6195,15 +6229,15 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6195
6229
  }
6196
6230
  ));
6197
6231
  }
6198
- return /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Press enter to exit.")), /* @__PURE__ */ React16.createElement(ExitOnEnter, { onExit: exit }));
6232
+ return /* @__PURE__ */ React17.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "Press enter to exit.")), /* @__PURE__ */ React17.createElement(ExitOnEnter, { onExit: exit }));
6199
6233
  }
6200
6234
  function ApiKeyStep({
6201
6235
  onSubmit,
6202
6236
  error,
6203
6237
  onError
6204
6238
  }) {
6205
- const [value, setValue] = useState9("");
6206
- return /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React16.createElement(
6239
+ const [value, setValue] = useState8("");
6240
+ return /* @__PURE__ */ React17.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React17.createElement(
6207
6241
  TextInput2,
6208
6242
  {
6209
6243
  value,
@@ -6220,7 +6254,7 @@ function ApiKeyStep({
6220
6254
  mask: "\u2022",
6221
6255
  placeholder: "sk-..."
6222
6256
  }
6223
- )), error ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { color: "red" }, error)) : value ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "preview: ", redactKey(value))) : null);
6257
+ )), error ? /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { color: "red" }, error)) : value ? /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "preview: ", redactKey(value))) : null);
6224
6258
  }
6225
6259
  function McpArgsStep({
6226
6260
  entry,
@@ -6228,8 +6262,8 @@ function McpArgsStep({
6228
6262
  onSubmit,
6229
6263
  onError
6230
6264
  }) {
6231
- const [value, setValue] = useState9("");
6232
- return /* @__PURE__ */ React16.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Text13, null, entry.summary), entry.note ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Required parameter: "), /* @__PURE__ */ React16.createElement(Text13, { bold: true }, entry.userArgs)), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React16.createElement(
6265
+ const [value, setValue] = useState8("");
6266
+ return /* @__PURE__ */ React17.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React17.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React17.createElement(Text13, null, entry.summary), entry.note ? /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, null, "Required parameter: "), /* @__PURE__ */ React17.createElement(Text13, { bold: true }, entry.userArgs)), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React17.createElement(
6233
6267
  TextInput2,
6234
6268
  {
6235
6269
  value,
@@ -6245,7 +6279,7 @@ function McpArgsStep({
6245
6279
  },
6246
6280
  placeholder: placeholderFor(entry)
6247
6281
  }
6248
- )), error ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { color: "red" }, error)) : null));
6282
+ )), error ? /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { color: "red" }, error)) : null));
6249
6283
  }
6250
6284
  function ReviewConfirm({ onConfirm }) {
6251
6285
  useInput6((_i, key) => {
@@ -6265,10 +6299,10 @@ function StepFrame({
6265
6299
  total,
6266
6300
  children
6267
6301
  }) {
6268
- return /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Box13, null, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1, flexDirection: "column" }, children));
6302
+ return /* @__PURE__ */ React17.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React17.createElement(Box13, null, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1, flexDirection: "column" }, children));
6269
6303
  }
6270
6304
  function SummaryLine({ label, value }) {
6271
- return /* @__PURE__ */ React16.createElement(Box13, null, /* @__PURE__ */ React16.createElement(Text13, null, label.padEnd(12)), /* @__PURE__ */ React16.createElement(Text13, { bold: true }, value));
6305
+ return /* @__PURE__ */ React17.createElement(Box13, null, /* @__PURE__ */ React17.createElement(Text13, null, label.padEnd(12)), /* @__PURE__ */ React17.createElement(Text13, { bold: true }, value));
6272
6306
  }
6273
6307
  function presetItems() {
6274
6308
  return ["fast", "smart", "max"].map((name) => ({
@@ -6324,7 +6358,7 @@ async function setupCommand(_opts = {}) {
6324
6358
  const existingKey = loadApiKey();
6325
6359
  const existing = readConfig();
6326
6360
  const { waitUntilExit, unmount } = render4(
6327
- /* @__PURE__ */ React17.createElement(
6361
+ /* @__PURE__ */ React18.createElement(
6328
6362
  Wizard,
6329
6363
  {
6330
6364
  existingApiKey: existingKey,
@@ -6336,7 +6370,7 @@ async function setupCommand(_opts = {}) {
6336
6370
  }
6337
6371
  }
6338
6372
  ),
6339
- { exitOnCtrlC: true }
6373
+ { exitOnCtrlC: true, patchConsole: false }
6340
6374
  );
6341
6375
  await waitUntilExit();
6342
6376
  }