reasonix 0.4.13 → 0.4.15

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
@@ -32,6 +32,13 @@ function loadApiKey(path = defaultConfigPath()) {
32
32
  if (process.env.DEEPSEEK_API_KEY) return process.env.DEEPSEEK_API_KEY;
33
33
  return readConfig(path).apiKey;
34
34
  }
35
+ function searchEnabled(path = defaultConfigPath()) {
36
+ const env = process.env.REASONIX_SEARCH;
37
+ if (env === "off" || env === "false" || env === "0") return false;
38
+ const cfg = readConfig(path).search;
39
+ if (cfg === false) return false;
40
+ return true;
41
+ }
35
42
  function saveApiKey(key, path = defaultConfigPath()) {
36
43
  const cfg = readConfig(path);
37
44
  cfg.apiKey = key.trim();
@@ -2232,6 +2239,187 @@ function lineDiff(a, b) {
2232
2239
  return out;
2233
2240
  }
2234
2241
 
2242
+ // src/tools/web.ts
2243
+ var DEFAULT_FETCH_MAX_CHARS = 32e3;
2244
+ var DEFAULT_FETCH_TIMEOUT_MS = 15e3;
2245
+ var DEFAULT_TOPK = 5;
2246
+ var USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
2247
+ var MOJEEK_ENDPOINT = "https://www.mojeek.com/search";
2248
+ async function webSearch(query, opts = {}) {
2249
+ const topK = Math.max(1, Math.min(10, opts.topK ?? DEFAULT_TOPK));
2250
+ const resp = await fetch(`${MOJEEK_ENDPOINT}?q=${encodeURIComponent(query)}`, {
2251
+ headers: {
2252
+ "User-Agent": USER_AGENT,
2253
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9",
2254
+ "Accept-Language": "en-US,en;q=0.9"
2255
+ },
2256
+ signal: opts.signal,
2257
+ redirect: "follow"
2258
+ });
2259
+ if (!resp.ok) throw new Error(`web_search ${resp.status}`);
2260
+ const html = await resp.text();
2261
+ const results = parseMojeekResults(html).slice(0, topK);
2262
+ if (results.length === 0) {
2263
+ if (/no results found|did not match any documents/i.test(html)) return [];
2264
+ if (/captcha|verify you are human|access denied|forbidden/i.test(html)) {
2265
+ throw new Error("web_search: Mojeek anti-bot page \u2014 rate-limited or blocked");
2266
+ }
2267
+ throw new Error(
2268
+ `web_search: 0 results but response doesn't look like a real empty page (${html.length} chars, first 120: ${html.slice(0, 120).replace(/\s+/g, " ")})`
2269
+ );
2270
+ }
2271
+ return results;
2272
+ }
2273
+ function parseMojeekResults(html) {
2274
+ const titles = [];
2275
+ const titleAnchorRe = /<a\b[^>]*\bclass="title"[^>]*>[\s\S]*?<\/a>/g;
2276
+ let m;
2277
+ while (true) {
2278
+ m = titleAnchorRe.exec(html);
2279
+ if (m === null) break;
2280
+ titles.push(m[0]);
2281
+ }
2282
+ const snippets = [];
2283
+ const snippetRe = /<p\b[^>]*\bclass="s"[^>]*>([\s\S]*?)<\/p>/g;
2284
+ while (true) {
2285
+ m = snippetRe.exec(html);
2286
+ if (m === null) break;
2287
+ snippets.push(m[1] ?? "");
2288
+ }
2289
+ const hrefRe = /href="([^"]+)"/;
2290
+ const innerRe = /<a\b[^>]*>([\s\S]*?)<\/a>/;
2291
+ const results = [];
2292
+ for (let i = 0; i < titles.length; i++) {
2293
+ const anchor = titles[i];
2294
+ const hrefMatch = anchor.match(hrefRe);
2295
+ const innerMatch = anchor.match(innerRe);
2296
+ if (!hrefMatch?.[1]) continue;
2297
+ results.push({
2298
+ title: decodeHtmlEntities(stripHtml(innerMatch?.[1] ?? "")).trim(),
2299
+ url: hrefMatch[1],
2300
+ snippet: decodeHtmlEntities(stripHtml(snippets[i] ?? "")).replace(/\s+/g, " ").trim()
2301
+ });
2302
+ }
2303
+ return results;
2304
+ }
2305
+ async function webFetch(url, opts = {}) {
2306
+ const maxChars = opts.maxChars ?? DEFAULT_FETCH_MAX_CHARS;
2307
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
2308
+ const ctl = new AbortController();
2309
+ const timer = setTimeout(() => ctl.abort(), timeoutMs);
2310
+ const cancel = () => ctl.abort();
2311
+ opts.signal?.addEventListener("abort", cancel, { once: true });
2312
+ let resp;
2313
+ try {
2314
+ resp = await fetch(url, {
2315
+ headers: { "User-Agent": USER_AGENT, Accept: "text/html,text/plain,*/*" },
2316
+ signal: ctl.signal,
2317
+ redirect: "follow"
2318
+ });
2319
+ } finally {
2320
+ clearTimeout(timer);
2321
+ opts.signal?.removeEventListener("abort", cancel);
2322
+ }
2323
+ if (!resp.ok) throw new Error(`web_fetch ${resp.status} for ${url}`);
2324
+ const contentType = resp.headers.get("content-type") ?? "";
2325
+ const raw = await resp.text();
2326
+ const title = extractTitle(raw);
2327
+ const text = contentType.includes("text/html") ? htmlToText(raw) : raw;
2328
+ const truncated = text.length > maxChars;
2329
+ const finalText = truncated ? `${text.slice(0, maxChars)}
2330
+
2331
+ [\u2026 truncated ${text.length - maxChars} chars \u2026]` : text;
2332
+ return { url, title, text: finalText, truncated };
2333
+ }
2334
+ function htmlToText(html) {
2335
+ let s = html;
2336
+ s = s.replace(/<script[\s\S]*?<\/script>/gi, "");
2337
+ s = s.replace(/<style[\s\S]*?<\/style>/gi, "");
2338
+ s = s.replace(/<noscript[\s\S]*?<\/noscript>/gi, "");
2339
+ s = s.replace(/<nav[\s\S]*?<\/nav>/gi, "");
2340
+ s = s.replace(/<footer[\s\S]*?<\/footer>/gi, "");
2341
+ s = s.replace(/<aside[\s\S]*?<\/aside>/gi, "");
2342
+ s = s.replace(/<svg[\s\S]*?<\/svg>/gi, "");
2343
+ s = s.replace(/<\/?(p|div|br|h[1-6]|li|tr|section|article)\b[^>]*>/gi, "\n");
2344
+ s = s.replace(/<[^>]+>/g, "");
2345
+ s = decodeHtmlEntities(s);
2346
+ s = s.replace(/[ \t]+/g, " ");
2347
+ s = s.replace(/\n[ \t]+/g, "\n");
2348
+ s = s.replace(/\n{3,}/g, "\n\n");
2349
+ return s.trim();
2350
+ }
2351
+ function stripHtml(s) {
2352
+ return s.replace(/<[^>]+>/g, "");
2353
+ }
2354
+ function decodeHtmlEntities(s) {
2355
+ return s.replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'");
2356
+ }
2357
+ function extractTitle(html) {
2358
+ const m = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
2359
+ if (!m?.[1]) return void 0;
2360
+ return m[1].replace(/\s+/g, " ").trim() || void 0;
2361
+ }
2362
+ function registerWebTools(registry, opts = {}) {
2363
+ const defaultTopK = opts.defaultTopK ?? DEFAULT_TOPK;
2364
+ const maxFetchChars = opts.maxFetchChars ?? DEFAULT_FETCH_MAX_CHARS;
2365
+ registry.register({
2366
+ name: "web_search",
2367
+ description: "Search the public web. Returns ranked results with title, url, and snippet. Use this when the question needs information more current than your training data, when you're unsure of a factual detail, or when the user asks about a specific webpage/library/release you haven't seen.",
2368
+ parameters: {
2369
+ type: "object",
2370
+ properties: {
2371
+ query: { type: "string", description: "Natural-language search query." },
2372
+ topK: {
2373
+ type: "integer",
2374
+ description: `Number of results to return (1..10). Default ${defaultTopK}.`
2375
+ }
2376
+ },
2377
+ required: ["query"]
2378
+ },
2379
+ fn: async (args, ctx) => {
2380
+ const results = await webSearch(args.query, {
2381
+ topK: args.topK ?? defaultTopK,
2382
+ signal: ctx?.signal
2383
+ });
2384
+ return formatSearchResults(args.query, results);
2385
+ }
2386
+ });
2387
+ registry.register({
2388
+ name: "web_fetch",
2389
+ description: "Download a URL and return its visible text content (HTML pages get scripts/styles/nav stripped). Truncated at the tool-result cap. Use after web_search when a snippet isn't enough.",
2390
+ parameters: {
2391
+ type: "object",
2392
+ properties: {
2393
+ url: { type: "string", description: "Absolute http:// or https:// URL." }
2394
+ },
2395
+ required: ["url"]
2396
+ },
2397
+ fn: async (args, ctx) => {
2398
+ if (!/^https?:\/\//i.test(args.url)) {
2399
+ throw new Error("web_fetch: url must start with http:// or https://");
2400
+ }
2401
+ const page = await webFetch(args.url, { maxChars: maxFetchChars, signal: ctx?.signal });
2402
+ const header = page.title ? `${page.title}
2403
+ ${page.url}` : page.url;
2404
+ return `${header}
2405
+
2406
+ ${page.text}`;
2407
+ }
2408
+ });
2409
+ return registry;
2410
+ }
2411
+ function formatSearchResults(query, results) {
2412
+ const lines = [`query: ${query}`, `
2413
+ results (${results.length}):`];
2414
+ results.forEach((r, i) => {
2415
+ lines.push(`
2416
+ ${i + 1}. ${r.title}`);
2417
+ lines.push(` ${r.url}`);
2418
+ if (r.snippet) lines.push(` ${r.snippet}`);
2419
+ });
2420
+ return lines.join("\n");
2421
+ }
2422
+
2235
2423
  // src/env.ts
2236
2424
  import { readFileSync as readFileSync3 } from "fs";
2237
2425
  import { resolve as resolve2 } from "path";
@@ -3519,19 +3707,19 @@ function sep() {
3519
3707
  }
3520
3708
 
3521
3709
  // src/index.ts
3522
- var VERSION = "0.4.3";
3710
+ var VERSION = "0.4.15";
3523
3711
 
3524
3712
  // src/cli/commands/chat.tsx
3525
3713
  import { render } from "ink";
3526
- import React9, { useState as useState5 } from "react";
3714
+ import React10, { useState as useState5 } from "react";
3527
3715
 
3528
3716
  // src/cli/ui/App.tsx
3529
3717
  import { Box as Box7, Static, Text as Text7, useApp, useInput as useInput2 } from "ink";
3530
- import React7, { useCallback, useEffect as useEffect3, useMemo, useRef, useState as useState3 } from "react";
3718
+ import React8, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState3 } from "react";
3531
3719
 
3532
3720
  // src/cli/ui/EventLog.tsx
3533
3721
  import { Box as Box3, Text as Text3 } from "ink";
3534
- import React3, { useEffect, useState } from "react";
3722
+ import React4 from "react";
3535
3723
 
3536
3724
  // src/cli/ui/PlanStateBlock.tsx
3537
3725
  import { Box, Text } from "ink";
@@ -3842,45 +4030,67 @@ function Markdown({ text }) {
3842
4030
  return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React2.createElement(BlockView, { key: `${i}-${b.kind}`, block: b })));
3843
4031
  }
3844
4032
 
4033
+ // src/cli/ui/ticker.tsx
4034
+ import React3, { createContext, useContext, useEffect, useState } from "react";
4035
+ var TICK_MS = 120;
4036
+ var TickContext = createContext(0);
4037
+ function TickerProvider({ children, disabled }) {
4038
+ const [tick, setTick] = useState(0);
4039
+ useEffect(() => {
4040
+ if (disabled) return;
4041
+ const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
4042
+ return () => clearInterval(id);
4043
+ }, [disabled]);
4044
+ return /* @__PURE__ */ React3.createElement(TickContext.Provider, { value: tick }, children);
4045
+ }
4046
+ function useTick() {
4047
+ return useContext(TickContext);
4048
+ }
4049
+ function useElapsedSeconds() {
4050
+ const [start] = useState(() => Date.now());
4051
+ useTick();
4052
+ return Math.floor((Date.now() - start) / 1e3);
4053
+ }
4054
+
3845
4055
  // src/cli/ui/EventLog.tsx
3846
- var EventRow = React3.memo(function EventRow2({ event }) {
4056
+ var EventRow = React4.memo(function EventRow2({ event }) {
3847
4057
  if (event.role === "user") {
3848
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React3.createElement(Text3, null, event.text));
4058
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React4.createElement(Text3, null, event.text));
3849
4059
  }
3850
4060
  if (event.role === "assistant") {
3851
- if (event.streaming) return /* @__PURE__ */ React3.createElement(StreamingAssistant, { event });
3852
- 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);
4061
+ if (event.streaming) return /* @__PURE__ */ React4.createElement(StreamingAssistant, { event });
4062
+ 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);
3853
4063
  }
3854
4064
  if (event.role === "tool") {
3855
4065
  const isError = event.text.startsWith("ERROR:");
3856
4066
  const color = isError ? "red" : "yellow";
3857
4067
  const marker = isError ? "\u2717" : "\u2192";
3858
4068
  const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isError;
3859
- 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)));
4069
+ 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)));
3860
4070
  }
3861
4071
  if (event.role === "error") {
3862
- return /* @__PURE__ */ React3.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, event.text));
4072
+ return /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React4.createElement(Text3, { color: "red" }, event.text));
3863
4073
  }
3864
4074
  if (event.role === "info") {
3865
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, event.text));
4075
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, event.text));
3866
4076
  }
3867
4077
  if (event.role === "warning") {
3868
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, "\u25B8 "), /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, event.text));
4078
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { color: "yellow" }, "\u25B8 "), /* @__PURE__ */ React4.createElement(Text3, { color: "yellow" }, event.text));
3869
4079
  }
3870
- return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, null, event.text));
4080
+ return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, null, event.text));
3871
4081
  });
3872
4082
  function EditFileDiff({ text }) {
3873
4083
  const lines = text.split(/\r?\n/);
3874
4084
  const [statusHeader, hunkHeader, ...body] = lines;
3875
- 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) => {
4085
+ 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) => {
3876
4086
  const key = `${i}-${line.slice(0, 32)}`;
3877
4087
  if (line.startsWith("- ")) {
3878
- return /* @__PURE__ */ React3.createElement(Text3, { key, color: "red" }, line);
4088
+ return /* @__PURE__ */ React4.createElement(Text3, { key, color: "red" }, line);
3879
4089
  }
3880
4090
  if (line.startsWith("+ ")) {
3881
- return /* @__PURE__ */ React3.createElement(Text3, { key, color: "green" }, line);
4091
+ return /* @__PURE__ */ React4.createElement(Text3, { key, color: "green" }, line);
3882
4092
  }
3883
- return /* @__PURE__ */ React3.createElement(Text3, { key, dimColor: true }, line);
4093
+ return /* @__PURE__ */ React4.createElement(Text3, { key, dimColor: true }, line);
3884
4094
  }));
3885
4095
  }
3886
4096
  function BranchBlock({ branch }) {
@@ -3889,33 +4099,28 @@ function BranchBlock({ branch }) {
3889
4099
  const t = (branch.temperatures[i] ?? 0).toFixed(1);
3890
4100
  return `${marker} #${i} T=${t} u=${u}`;
3891
4101
  }).join(" ");
3892
- 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)));
4102
+ 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)));
3893
4103
  }
3894
4104
  function ReasoningBlock({ reasoning }) {
3895
4105
  const max = 260;
3896
4106
  const flat = reasoning.replace(/\s+/g, " ").trim();
3897
4107
  const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
3898
- return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", preview));
4108
+ return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", preview));
3899
4109
  }
3900
4110
  function Elapsed() {
3901
- const [s, setS] = useState(0);
3902
- useEffect(() => {
3903
- const start = Date.now();
3904
- const id = setInterval(() => setS(Math.floor((Date.now() - start) / 1e3)), 1e3);
3905
- return () => clearInterval(id);
3906
- }, []);
4111
+ const s = useElapsedSeconds();
3907
4112
  const mm = String(Math.floor(s / 60)).padStart(2, "0");
3908
4113
  const ss = String(s % 60).padStart(2, "0");
3909
- return /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, `${mm}:${ss}`);
4114
+ return /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, `${mm}:${ss}`);
3910
4115
  }
3911
4116
  function StreamingAssistant({ event }) {
3912
4117
  if (event.branchProgress) {
3913
4118
  const p = event.branchProgress;
3914
4119
  if (p.completed === 0) {
3915
- 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"));
4120
+ 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"));
3916
4121
  }
3917
4122
  const pct2 = Math.round(p.completed / p.total * 100);
3918
- 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"));
4123
+ 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"));
3919
4124
  }
3920
4125
  const tail = lastLine(event.text, 140);
3921
4126
  const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
@@ -3943,16 +4148,12 @@ function StreamingAssistant({ event }) {
3943
4148
  label = parts.join(" \xB7 ");
3944
4149
  labelColor = "green";
3945
4150
  }
3946
- 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"));
4151
+ 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) : preFirstByte ? /* @__PURE__ */ React4.createElement(Text3, { dimColor: true, italic: true }, " connection open, first byte typically in 5-60s depending on model + load") : 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).") : toolCallOnly ? /* @__PURE__ */ React4.createElement(Text3, { color: "magenta", dimColor: true }, " tool-call arguments streaming \u2014 the model is about to dispatch a tool") : event.reasoning ? /* @__PURE__ */ React4.createElement(Text3, { color: "yellow", dimColor: true }, " R1 still reasoning \u2014 body text or tool call arrives when thinking completes") : null);
3947
4152
  }
3948
4153
  function Pulse() {
3949
- const [tick, setTick] = useState(0);
3950
- useEffect(() => {
3951
- const id = setInterval(() => setTick((t) => t + 1), 500);
3952
- return () => clearInterval(id);
3953
- }, []);
4154
+ const tick = useTick();
3954
4155
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
3955
- return /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, frames[tick % frames.length]);
4156
+ return /* @__PURE__ */ React4.createElement(Text3, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
3956
4157
  }
3957
4158
  function lastLine(s, maxChars) {
3958
4159
  const flat = s.replace(/\s+/g, " ").trim();
@@ -3961,7 +4162,7 @@ function lastLine(s, maxChars) {
3961
4162
  }
3962
4163
  function StatsLine({ stats }) {
3963
4164
  const hit = (stats.cacheHitRatio * 100).toFixed(1);
3964
- return /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " \u21B3 cache ", hit, "% \xB7 tokens ", stats.usage.promptTokens, "\u2192", stats.usage.completionTokens, " \xB7 $", stats.cost.toFixed(6));
4165
+ return /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, " \u21B3 cache ", hit, "% \xB7 tokens ", stats.usage.promptTokens, "\u2192", stats.usage.completionTokens, " \xB7 $", stats.cost.toFixed(6));
3965
4166
  }
3966
4167
  function truncate2(s, max) {
3967
4168
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -3969,40 +4170,119 @@ function truncate2(s, max) {
3969
4170
 
3970
4171
  // src/cli/ui/PromptInput.tsx
3971
4172
  import { Box as Box4, Text as Text4, useInput } from "ink";
3972
- import React4, { useEffect as useEffect2, useState as useState2 } from "react";
4173
+ import React5, { useRef, useState as useState2 } from "react";
3973
4174
 
3974
4175
  // src/cli/ui/multiline-keys.ts
3975
4176
  var BACKSLASH_SUFFIX = /\\$/;
3976
- function processMultilineKey(value, key) {
3977
- if (key.tab || key.upArrow || key.downArrow || key.leftArrow || key.rightArrow || key.escape || key.pageUp || key.pageDown) {
3978
- return { next: null, submit: false };
4177
+ var NOOP = { next: null, cursor: null, submit: false };
4178
+ function processMultilineKey(value, cursor, key) {
4179
+ if (key.tab || key.escape || key.pageUp || key.pageDown) {
4180
+ return NOOP;
4181
+ }
4182
+ if (value.length === 0 && (key.upArrow || key.downArrow)) {
4183
+ return NOOP;
4184
+ }
4185
+ if (key.leftArrow) {
4186
+ return { next: null, cursor: Math.max(0, cursor - 1), submit: false };
4187
+ }
4188
+ if (key.rightArrow) {
4189
+ return { next: null, cursor: Math.min(value.length, cursor + 1), submit: false };
4190
+ }
4191
+ if (key.upArrow) {
4192
+ const moved = moveCursorUp(value, cursor);
4193
+ return moved === cursor ? NOOP : { next: null, cursor: moved, submit: false };
4194
+ }
4195
+ if (key.downArrow) {
4196
+ const moved = moveCursorDown(value, cursor);
4197
+ return moved === cursor ? NOOP : { next: null, cursor: moved, submit: false };
4198
+ }
4199
+ if (key.ctrl && key.input === "a") {
4200
+ return { next: null, cursor: startOfLine(value, cursor), submit: false };
4201
+ }
4202
+ if (key.ctrl && key.input === "e") {
4203
+ return { next: null, cursor: endOfLine(value, cursor), submit: false };
3979
4204
  }
3980
4205
  if (key.input === "\n" || key.ctrl && key.input === "j") {
3981
- return { next: `${value}
3982
- `, submit: false };
4206
+ return insertAt(value, cursor, "\n");
3983
4207
  }
3984
4208
  if (key.return) {
3985
- if (key.shift) {
3986
- return { next: `${value}
3987
- `, submit: false };
3988
- }
3989
- if (BACKSLASH_SUFFIX.test(value)) {
3990
- return { next: `${value.slice(0, -1)}
3991
- `, submit: false };
4209
+ if (key.shift) return insertAt(value, cursor, "\n");
4210
+ if (cursor === value.length && BACKSLASH_SUFFIX.test(value)) {
4211
+ const replaced = `${value.slice(0, -1)}
4212
+ `;
4213
+ return { next: replaced, cursor: replaced.length, submit: false };
3992
4214
  }
3993
- return { next: null, submit: true, submitValue: value };
4215
+ return { next: null, cursor: null, submit: true, submitValue: value };
3994
4216
  }
3995
- if (key.backspace || key.delete) {
3996
- if (value.length === 0) return { next: null, submit: false };
3997
- return { next: value.slice(0, -1), submit: false };
4217
+ if (key.backspace) {
4218
+ if (cursor === 0) return NOOP;
4219
+ return {
4220
+ next: value.slice(0, cursor - 1) + value.slice(cursor),
4221
+ cursor: cursor - 1,
4222
+ submit: false
4223
+ };
4224
+ }
4225
+ if (key.delete) {
4226
+ if (cursor === value.length) return NOOP;
4227
+ return {
4228
+ next: value.slice(0, cursor) + value.slice(cursor + 1),
4229
+ cursor,
4230
+ submit: false
4231
+ };
3998
4232
  }
3999
- if ((key.ctrl || key.meta) && key.input.length === 0) {
4000
- return { next: null, submit: false };
4233
+ if ((key.ctrl || key.meta) && key.input.length === 0) return NOOP;
4234
+ if (key.ctrl || key.meta) return NOOP;
4235
+ if (key.input.length > 0) {
4236
+ return insertAt(value, cursor, key.input);
4001
4237
  }
4002
- if (key.input.length > 0 && !key.ctrl && !key.meta) {
4003
- return { next: value + key.input, submit: false };
4238
+ return NOOP;
4239
+ }
4240
+ function insertAt(value, cursor, insert) {
4241
+ return {
4242
+ next: value.slice(0, cursor) + insert + value.slice(cursor),
4243
+ cursor: cursor + insert.length,
4244
+ submit: false
4245
+ };
4246
+ }
4247
+ function lineAndColumn(value, cursor) {
4248
+ let line = 0;
4249
+ let col = 0;
4250
+ const n = Math.min(cursor, value.length);
4251
+ for (let i = 0; i < n; i++) {
4252
+ if (value[i] === "\n") {
4253
+ line++;
4254
+ col = 0;
4255
+ } else {
4256
+ col++;
4257
+ }
4004
4258
  }
4005
- return { next: null, submit: false };
4259
+ return { line, col };
4260
+ }
4261
+ function startOfLine(value, cursor) {
4262
+ return value.lastIndexOf("\n", cursor - 1) + 1;
4263
+ }
4264
+ function endOfLine(value, cursor) {
4265
+ const nl = value.indexOf("\n", cursor);
4266
+ return nl === -1 ? value.length : nl;
4267
+ }
4268
+ function moveCursorUp(value, cursor) {
4269
+ const curStart = startOfLine(value, cursor);
4270
+ if (curStart === 0) return cursor;
4271
+ const col = cursor - curStart;
4272
+ const prevEnd = curStart - 1;
4273
+ const prevStart = value.lastIndexOf("\n", prevEnd - 1) + 1;
4274
+ const prevLen = prevEnd - prevStart;
4275
+ return prevStart + Math.min(col, prevLen);
4276
+ }
4277
+ function moveCursorDown(value, cursor) {
4278
+ const nextNl = value.indexOf("\n", cursor);
4279
+ if (nextNl === -1) return cursor;
4280
+ const curStart = startOfLine(value, cursor);
4281
+ const col = cursor - curStart;
4282
+ const nextStart = nextNl + 1;
4283
+ const followingNl = value.indexOf("\n", nextStart);
4284
+ const nextLen = (followingNl === -1 ? value.length : followingNl) - nextStart;
4285
+ return nextStart + Math.min(col, nextLen);
4006
4286
  }
4007
4287
 
4008
4288
  // src/cli/ui/PromptInput.tsx
@@ -4013,19 +4293,19 @@ function PromptInput({
4013
4293
  disabled,
4014
4294
  placeholder
4015
4295
  }) {
4016
- const [showCursor, setShowCursor] = useState2(true);
4017
- useEffect2(() => {
4018
- if (disabled) {
4019
- setShowCursor(false);
4020
- return;
4296
+ const [cursor, setCursor] = useState2(value.length);
4297
+ const lastLocalValueRef = useRef(value);
4298
+ if (value !== lastLocalValueRef.current) {
4299
+ lastLocalValueRef.current = value;
4300
+ if (cursor !== value.length) {
4301
+ setCursor(value.length);
4021
4302
  }
4022
- setShowCursor(true);
4023
- const id = setInterval(() => setShowCursor((s) => !s), 500);
4024
- return () => clearInterval(id);
4025
- }, [disabled]);
4303
+ }
4304
+ const tick = useTick();
4305
+ const showCursor = disabled ? false : Math.floor(tick / 4) % 2 === 0;
4026
4306
  useInput(
4027
4307
  (input, key) => {
4028
- const keyEvent = {
4308
+ const ke = {
4029
4309
  input,
4030
4310
  return: key.return,
4031
4311
  shift: key.shift,
@@ -4042,8 +4322,14 @@ function PromptInput({
4042
4322
  pageUp: key.pageUp,
4043
4323
  pageDown: key.pageDown
4044
4324
  };
4045
- const action = processMultilineKey(value, keyEvent);
4046
- if (action.next !== null) onChange(action.next);
4325
+ const action = processMultilineKey(value, cursor, ke);
4326
+ if (action.next !== null) {
4327
+ lastLocalValueRef.current = action.next;
4328
+ onChange(action.next);
4329
+ }
4330
+ if (action.cursor !== null) {
4331
+ setCursor(action.cursor);
4332
+ }
4047
4333
  if (action.submit) onSubmit(action.submitValue ?? value);
4048
4334
  },
4049
4335
  { isActive: !disabled }
@@ -4051,27 +4337,50 @@ function PromptInput({
4051
4337
  const effectivePlaceholder = disabled ? placeholder ?? "\u2026waiting for response\u2026" : placeholder ?? "type a message, or /command \xB7 Ctrl+J for newline";
4052
4338
  const lines = value.length > 0 ? value.split("\n") : [""];
4053
4339
  const borderColor = disabled ? "gray" : "cyan";
4054
- return /* @__PURE__ */ React4.createElement(Box4, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, lines.map((line, i) => {
4055
- const isLast = i === lines.length - 1;
4340
+ const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
4341
+ return /* @__PURE__ */ React5.createElement(Box4, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, lines.map((line, i) => {
4056
4342
  const isFirst = i === 0;
4057
4343
  const showPlaceholder = isFirst && value.length === 0;
4344
+ const isCursorLine = i === cursorLine;
4058
4345
  return (
4059
4346
  // biome-ignore lint/suspicious/noArrayIndexKey: stable by construction — lines are derived from `value.split("\n")` and never reordered
4060
- /* @__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)
4347
+ /* @__PURE__ */ React5.createElement(Box4, { key: i }, isFirst ? /* @__PURE__ */ React5.createElement(Text4, { bold: true, color: borderColor }, "you \u203A", " ") : /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, " "), showPlaceholder ? /* @__PURE__ */ React5.createElement(React5.Fragment, null, isCursorLine && !disabled ? /* @__PURE__ */ React5.createElement(Text4, { color: borderColor }, showCursor ? "\u258C" : " ") : null, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, effectivePlaceholder)) : isCursorLine && !disabled ? /* @__PURE__ */ React5.createElement(
4348
+ LineWithCursor,
4349
+ {
4350
+ line,
4351
+ col: cursorCol,
4352
+ showCursor,
4353
+ borderColor
4354
+ }
4355
+ ) : /* @__PURE__ */ React5.createElement(Text4, null, line))
4061
4356
  );
4062
4357
  }));
4063
4358
  }
4359
+ function LineWithCursor({
4360
+ line,
4361
+ col,
4362
+ showCursor,
4363
+ borderColor
4364
+ }) {
4365
+ const before = line.slice(0, col);
4366
+ const atCursor = line.slice(col, col + 1);
4367
+ const after = line.slice(col + 1);
4368
+ if (atCursor.length === 0) {
4369
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Text4, null, before), /* @__PURE__ */ React5.createElement(Text4, { color: borderColor }, showCursor ? "\u258C" : " "));
4370
+ }
4371
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Text4, null, before), /* @__PURE__ */ React5.createElement(Text4, { inverse: showCursor }, atCursor), /* @__PURE__ */ React5.createElement(Text4, null, after));
4372
+ }
4064
4373
 
4065
4374
  // src/cli/ui/SlashSuggestions.tsx
4066
4375
  import { Box as Box5, Text as Text5 } from "ink";
4067
- import React5 from "react";
4376
+ import React6 from "react";
4068
4377
  function SlashSuggestions({
4069
4378
  matches,
4070
4379
  selectedIndex
4071
4380
  }) {
4072
4381
  if (matches === null) return null;
4073
4382
  if (matches.length === 0) {
4074
- 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"));
4383
+ 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"));
4075
4384
  }
4076
4385
  const MAX = 8;
4077
4386
  const total = matches.length;
@@ -4079,21 +4388,21 @@ function SlashSuggestions({
4079
4388
  const shown = matches.slice(windowStart, windowStart + MAX);
4080
4389
  const hiddenAbove = windowStart;
4081
4390
  const hiddenBelow = total - windowStart - shown.length;
4082
- 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"));
4391
+ 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"));
4083
4392
  }
4084
4393
  function SuggestionRow({ spec, isSelected }) {
4085
4394
  const marker = isSelected ? "\u25B8" : " ";
4086
4395
  const name = `/${spec.cmd}`;
4087
4396
  const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
4088
4397
  if (isSelected) {
4089
- 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));
4398
+ 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));
4090
4399
  }
4091
- return /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
4400
+ return /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
4092
4401
  }
4093
4402
 
4094
4403
  // src/cli/ui/StatsPanel.tsx
4095
4404
  import { Box as Box6, Text as Text6 } from "ink";
4096
- import React6 from "react";
4405
+ import React7 from "react";
4097
4406
  function StatsPanel({
4098
4407
  summary,
4099
4408
  model,
@@ -4108,7 +4417,7 @@ function StatsPanel({
4108
4417
  const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;
4109
4418
  const ctxRatio = summary.lastPromptTokens / ctxMax;
4110
4419
  const ctxColor = ctxRatio >= 0.8 ? "red" : ctxRatio >= 0.5 ? "yellow" : void 0;
4111
- 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));
4420
+ 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));
4112
4421
  }
4113
4422
  function formatTokens(n) {
4114
4423
  if (n < 1e3) return String(n);
@@ -4556,7 +4865,8 @@ function gitTail(res) {
4556
4865
  }
4557
4866
 
4558
4867
  // src/cli/ui/App.tsx
4559
- var FLUSH_INTERVAL_MS = 60;
4868
+ var FLUSH_INTERVAL_MS = 100;
4869
+ var PLAIN_UI = process.env.REASONIX_UI === "plain";
4560
4870
  function App({
4561
4871
  model,
4562
4872
  system,
@@ -4575,17 +4885,17 @@ function App({
4575
4885
  const [streaming, setStreaming] = useState3(null);
4576
4886
  const [input, setInput] = useState3("");
4577
4887
  const [busy, setBusy] = useState3(false);
4578
- const abortedThisTurn = useRef(false);
4888
+ const abortedThisTurn = useRef2(false);
4579
4889
  const [ongoingTool, setOngoingTool] = useState3(null);
4580
4890
  const [toolProgress, setToolProgress] = useState3(null);
4581
4891
  const [statusLine, setStatusLine] = useState3(null);
4582
4892
  const [balance, setBalance] = useState3(null);
4583
- const lastEditSnapshots = useRef(null);
4584
- const pendingEdits = useRef([]);
4585
- const promptHistory = useRef([]);
4586
- const historyCursor = useRef(-1);
4587
- const assistantIterCounter = useRef(0);
4588
- const toolHistoryRef = useRef([]);
4893
+ const lastEditSnapshots = useRef2(null);
4894
+ const pendingEdits = useRef2([]);
4895
+ const promptHistory = useRef2([]);
4896
+ const historyCursor = useRef2(-1);
4897
+ const assistantIterCounter = useRef2(0);
4898
+ const toolHistoryRef = useRef2([]);
4589
4899
  const [slashSelected, setSlashSelected] = useState3(0);
4590
4900
  const [summary, setSummary] = useState3({
4591
4901
  turns: 0,
@@ -4597,7 +4907,7 @@ function App({
4597
4907
  cacheHitRatio: 0,
4598
4908
  lastPromptTokens: 0
4599
4909
  });
4600
- const transcriptRef = useRef(null);
4910
+ const transcriptRef = useRef2(null);
4601
4911
  if (transcript && !transcriptRef.current) {
4602
4912
  transcriptRef.current = openTranscriptFile(transcript, {
4603
4913
  version: 1,
@@ -4606,7 +4916,7 @@ function App({
4606
4916
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
4607
4917
  });
4608
4918
  }
4609
- useEffect3(() => {
4919
+ useEffect2(() => {
4610
4920
  return () => {
4611
4921
  transcriptRef.current?.end();
4612
4922
  };
@@ -4615,14 +4925,14 @@ function App({
4615
4925
  if (!input.startsWith("/") || input.includes(" ")) return null;
4616
4926
  return suggestSlashCommands(input.slice(1), !!codeMode);
4617
4927
  }, [input, codeMode]);
4618
- useEffect3(() => {
4928
+ useEffect2(() => {
4619
4929
  setSlashSelected((prev) => {
4620
4930
  if (!slashMatches || slashMatches.length === 0) return 0;
4621
4931
  if (prev >= slashMatches.length) return slashMatches.length - 1;
4622
4932
  return prev;
4623
4933
  });
4624
4934
  }, [slashMatches]);
4625
- const loopRef = useRef(null);
4935
+ const loopRef = useRef2(null);
4626
4936
  const loop = useMemo(() => {
4627
4937
  if (loopRef.current) return loopRef.current;
4628
4938
  const client = new DeepSeekClient();
@@ -4634,7 +4944,7 @@ function App({
4634
4944
  loopRef.current = l;
4635
4945
  return l;
4636
4946
  }, [model, system, harvest2, branch, session, tools]);
4637
- useEffect3(() => {
4947
+ useEffect2(() => {
4638
4948
  let cancelled = false;
4639
4949
  void (async () => {
4640
4950
  const bal = await loop.client.getBalance().catch(() => null);
@@ -4646,7 +4956,7 @@ function App({
4646
4956
  cancelled = true;
4647
4957
  };
4648
4958
  }, [loop]);
4649
- useEffect3(() => {
4959
+ useEffect2(() => {
4650
4960
  if (!progressSink) return;
4651
4961
  progressSink.current = (info) => {
4652
4962
  setToolProgress({
@@ -4659,8 +4969,8 @@ function App({
4659
4969
  if (progressSink.current) progressSink.current = null;
4660
4970
  };
4661
4971
  }, [progressSink]);
4662
- const sessionBannerShown = useRef(false);
4663
- useEffect3(() => {
4972
+ const sessionBannerShown = useRef2(false);
4973
+ useEffect2(() => {
4664
4974
  if (sessionBannerShown.current) return;
4665
4975
  sessionBannerShown.current = true;
4666
4976
  if (!session) {
@@ -4715,20 +5025,22 @@ function App({
4715
5025
  return;
4716
5026
  }
4717
5027
  }
4718
- const hist = promptHistory.current;
4719
- if (key.upArrow) {
4720
- if (hist.length === 0) return;
4721
- const nextCursor = Math.min(historyCursor.current + 1, hist.length - 1);
4722
- historyCursor.current = nextCursor;
4723
- setInput(hist[hist.length - 1 - nextCursor] ?? "");
4724
- return;
4725
- }
4726
- if (key.downArrow) {
4727
- if (historyCursor.current < 0) return;
4728
- const nextCursor = historyCursor.current - 1;
4729
- historyCursor.current = nextCursor;
4730
- setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
4731
- return;
5028
+ if (input.length === 0) {
5029
+ const hist = promptHistory.current;
5030
+ if (key.upArrow) {
5031
+ if (hist.length === 0) return;
5032
+ const nextCursor = Math.min(historyCursor.current + 1, hist.length - 1);
5033
+ historyCursor.current = nextCursor;
5034
+ setInput(hist[hist.length - 1 - nextCursor] ?? "");
5035
+ return;
5036
+ }
5037
+ if (key.downArrow) {
5038
+ if (historyCursor.current < 0) return;
5039
+ const nextCursor = historyCursor.current - 1;
5040
+ historyCursor.current = nextCursor;
5041
+ setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
5042
+ return;
5043
+ }
4732
5044
  }
4733
5045
  });
4734
5046
  const codeUndo = useCallback(() => {
@@ -4869,7 +5181,7 @@ function App({
4869
5181
  streaming: true
4870
5182
  });
4871
5183
  };
4872
- const timer = setInterval(flush, FLUSH_INTERVAL_MS);
5184
+ const timer = PLAIN_UI ? null : setInterval(flush, FLUSH_INTERVAL_MS);
4873
5185
  try {
4874
5186
  for await (const ev of loop.step(text)) {
4875
5187
  writeTranscript(ev);
@@ -4981,7 +5293,7 @@ function App({
4981
5293
  }
4982
5294
  flush();
4983
5295
  } finally {
4984
- clearInterval(timer);
5296
+ if (timer) clearInterval(timer);
4985
5297
  setStreaming(null);
4986
5298
  setOngoingTool(null);
4987
5299
  setToolProgress(null);
@@ -5011,7 +5323,7 @@ function App({
5011
5323
  writeTranscript
5012
5324
  ]
5013
5325
  );
5014
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(
5326
+ return /* @__PURE__ */ React8.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(
5015
5327
  StatsPanel,
5016
5328
  {
5017
5329
  summary,
@@ -5021,41 +5333,22 @@ function App({
5021
5333
  branchBudget: loop.branchOptions.budget,
5022
5334
  balance
5023
5335
  }
5024
- ), /* @__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 }));
5336
+ ), /* @__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 })));
5025
5337
  }
5338
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
5026
5339
  function StatusRow({ text }) {
5027
- const [tick, setTick] = useState3(0);
5028
- const [elapsed, setElapsed] = useState3(0);
5029
- useEffect3(() => {
5030
- const start = Date.now();
5031
- const frameId = setInterval(() => setTick((t) => t + 1), 120);
5032
- const secId = setInterval(() => setElapsed(Math.floor((Date.now() - start) / 1e3)), 1e3);
5033
- return () => {
5034
- clearInterval(frameId);
5035
- clearInterval(secId);
5036
- };
5037
- }, []);
5038
- const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
5039
- 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`));
5340
+ const tick = useTick();
5341
+ const elapsed = useElapsedSeconds();
5342
+ 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`));
5040
5343
  }
5041
5344
  function OngoingToolRow({
5042
5345
  tool,
5043
5346
  progress
5044
5347
  }) {
5045
- const [tick, setTick] = useState3(0);
5046
- const [elapsed, setElapsed] = useState3(0);
5047
- useEffect3(() => {
5048
- const start = Date.now();
5049
- const frameId = setInterval(() => setTick((t) => t + 1), 120);
5050
- const secId = setInterval(() => setElapsed(Math.floor((Date.now() - start) / 1e3)), 1e3);
5051
- return () => {
5052
- clearInterval(frameId);
5053
- clearInterval(secId);
5054
- };
5055
- }, []);
5056
- const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
5348
+ const tick = useTick();
5349
+ const elapsed = useElapsedSeconds();
5057
5350
  const summary = summarizeToolArgs(tool.name, tool.args);
5058
- 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);
5351
+ 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);
5059
5352
  }
5060
5353
  function renderProgressLine(p) {
5061
5354
  const msg = p.message ? ` ${p.message}` : "";
@@ -5153,7 +5446,7 @@ function describeRepair(repair) {
5153
5446
  // src/cli/ui/Setup.tsx
5154
5447
  import { Box as Box8, Text as Text8, useApp as useApp2 } from "ink";
5155
5448
  import TextInput from "ink-text-input";
5156
- import React8, { useState as useState4 } from "react";
5449
+ import React9, { useState as useState4 } from "react";
5157
5450
  function Setup({ onReady }) {
5158
5451
  const [value, setValue] = useState4("");
5159
5452
  const [error, setError] = useState4(null);
@@ -5177,7 +5470,7 @@ function Setup({ onReady }) {
5177
5470
  }
5178
5471
  onReady(trimmed);
5179
5472
  };
5180
- 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(
5473
+ 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(
5181
5474
  TextInput,
5182
5475
  {
5183
5476
  value,
@@ -5186,14 +5479,14 @@ function Setup({ onReady }) {
5186
5479
  mask: "\u2022",
5187
5480
  placeholder: "sk-..."
5188
5481
  }
5189
- )), 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.)")));
5482
+ )), 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.)")));
5190
5483
  }
5191
5484
 
5192
5485
  // src/cli/commands/chat.tsx
5193
5486
  function Root({ initialKey, tools, mcpSpecs, mcpServers, progressSink, ...appProps }) {
5194
5487
  const [key, setKey] = useState5(initialKey);
5195
5488
  if (!key) {
5196
- return /* @__PURE__ */ React9.createElement(
5489
+ return /* @__PURE__ */ React10.createElement(
5197
5490
  Setup,
5198
5491
  {
5199
5492
  onReady: (k) => {
@@ -5204,7 +5497,7 @@ function Root({ initialKey, tools, mcpSpecs, mcpServers, progressSink, ...appPro
5204
5497
  );
5205
5498
  }
5206
5499
  process.env.DEEPSEEK_API_KEY = key;
5207
- return /* @__PURE__ */ React9.createElement(
5500
+ return /* @__PURE__ */ React10.createElement(
5208
5501
  App,
5209
5502
  {
5210
5503
  model: appProps.model,
@@ -5287,8 +5580,12 @@ async function chatCommand(opts) {
5287
5580
  }
5288
5581
  }
5289
5582
  const mcpSpecs = successfulSpecs;
5583
+ if (searchEnabled()) {
5584
+ if (!tools) tools = new ToolRegistry();
5585
+ registerWebTools(tools);
5586
+ }
5290
5587
  const { waitUntilExit } = render(
5291
- /* @__PURE__ */ React9.createElement(
5588
+ /* @__PURE__ */ React10.createElement(
5292
5589
  Root,
5293
5590
  {
5294
5591
  initialKey,
@@ -5299,7 +5596,9 @@ async function chatCommand(opts) {
5299
5596
  ...opts
5300
5597
  }
5301
5598
  ),
5302
- { exitOnCtrlC: true }
5599
+ // patchConsole:false we never log to console during the TUI, and the
5600
+ // patch is a known redraw-glitch source on winpty/MINTTY terminals.
5601
+ { exitOnCtrlC: true, patchConsole: false }
5303
5602
  );
5304
5603
  try {
5305
5604
  await waitUntilExit();
@@ -5336,34 +5635,34 @@ async function codeCommand(opts = {}) {
5336
5635
  import { writeFileSync as writeFileSync4 } from "fs";
5337
5636
  import { basename as basename2 } from "path";
5338
5637
  import { render as render2 } from "ink";
5339
- import React12 from "react";
5638
+ import React13 from "react";
5340
5639
 
5341
5640
  // src/cli/ui/DiffApp.tsx
5342
5641
  import { Box as Box10, Static as Static2, Text as Text10, useApp as useApp3, useInput as useInput3 } from "ink";
5343
- import React11, { useState as useState6 } from "react";
5642
+ import React12, { useState as useState6 } from "react";
5344
5643
 
5345
5644
  // src/cli/ui/RecordView.tsx
5346
5645
  import { Box as Box9, Text as Text9 } from "ink";
5347
- import React10 from "react";
5646
+ import React11 from "react";
5348
5647
  function RecordView({ rec, compact = false }) {
5349
5648
  const toolArgsMax = compact ? 120 : 200;
5350
5649
  const toolContentMax = compact ? 200 : 400;
5351
5650
  if (rec.role === "user") {
5352
- return /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React10.createElement(Text9, null, rec.content));
5651
+ return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text9, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React11.createElement(Text9, null, rec.content));
5353
5652
  }
5354
5653
  if (rec.role === "assistant_final") {
5355
- 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)"));
5654
+ 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)"));
5356
5655
  }
5357
5656
  if (rec.role === "tool") {
5358
- 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)));
5657
+ 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)));
5359
5658
  }
5360
5659
  if (rec.role === "error") {
5361
- 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));
5660
+ 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));
5362
5661
  }
5363
5662
  if (rec.role === "done" || rec.role === "assistant_delta") {
5364
5663
  return null;
5365
5664
  }
5366
- return /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "[", rec.role, "] ", rec.content));
5665
+ return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, "[", rec.role, "] ", rec.content));
5367
5666
  }
5368
5667
  function CacheBadge({ usage }) {
5369
5668
  const hit = usage.prompt_cache_hit_tokens ?? 0;
@@ -5372,7 +5671,7 @@ function CacheBadge({ usage }) {
5372
5671
  if (total === 0) return null;
5373
5672
  const pct2 = hit / total * 100;
5374
5673
  const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
5375
- return /* @__PURE__ */ React10.createElement(Text9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React10.createElement(Text9, { color }, pct2.toFixed(1), "%"));
5674
+ return /* @__PURE__ */ React11.createElement(Text9, null, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React11.createElement(Text9, { color }, pct2.toFixed(1), "%"));
5376
5675
  }
5377
5676
  function truncate3(s, max) {
5378
5677
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -5406,7 +5705,7 @@ function DiffApp({ report }) {
5406
5705
  }
5407
5706
  });
5408
5707
  const pair = report.pairs[idx];
5409
- 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")));
5708
+ 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")));
5410
5709
  }
5411
5710
  function DiffHeader({ report }) {
5412
5711
  const a = report.a;
@@ -5424,14 +5723,14 @@ function DiffHeader({ report }) {
5424
5723
  } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
5425
5724
  prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
5426
5725
  }
5427
- 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);
5726
+ 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);
5428
5727
  }
5429
5728
  function Pane({
5430
5729
  label,
5431
5730
  headerColor,
5432
5731
  records
5433
5732
  }) {
5434
- return /* @__PURE__ */ React11.createElement(
5733
+ return /* @__PURE__ */ React12.createElement(
5435
5734
  Box10,
5436
5735
  {
5437
5736
  flexDirection: "column",
@@ -5440,21 +5739,21 @@ function Pane({
5440
5739
  borderStyle: "single",
5441
5740
  borderColor: headerColor
5442
5741
  },
5443
- /* @__PURE__ */ React11.createElement(Text10, { color: headerColor, bold: true }, label),
5444
- 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 }))
5742
+ /* @__PURE__ */ React12.createElement(Text10, { color: headerColor, bold: true }, label),
5743
+ 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 }))
5445
5744
  );
5446
5745
  }
5447
5746
  function KindBadge({ kind }) {
5448
5747
  if (kind === "match") {
5449
- return /* @__PURE__ */ React11.createElement(Text10, { color: "green" }, "\u2713 match");
5748
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "green" }, "\u2713 match");
5450
5749
  }
5451
5750
  if (kind === "diverge") {
5452
- return /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u2605 diverge");
5751
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "yellow" }, "\u2605 diverge");
5453
5752
  }
5454
5753
  if (kind === "only_in_a") {
5455
- return /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, "\u2190 only in A");
5754
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "blue" }, "\u2190 only in A");
5456
5755
  }
5457
- return /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, "\u2192 only in B");
5756
+ return /* @__PURE__ */ React12.createElement(Text10, { color: "magenta" }, "\u2192 only in B");
5458
5757
  }
5459
5758
  function paneRecords(pair, side) {
5460
5759
  if (!pair) return [];
@@ -5485,8 +5784,9 @@ markdown report written to ${opts.mdPath}`);
5485
5784
  return;
5486
5785
  }
5487
5786
  if (wantTui) {
5488
- const { waitUntilExit } = render2(React12.createElement(DiffApp, { report }), {
5489
- exitOnCtrlC: true
5787
+ const { waitUntilExit } = render2(React13.createElement(DiffApp, { report }), {
5788
+ exitOnCtrlC: true,
5789
+ patchConsole: false
5490
5790
  });
5491
5791
  await waitUntilExit();
5492
5792
  return;
@@ -5625,11 +5925,11 @@ function pad(s, width) {
5625
5925
 
5626
5926
  // src/cli/commands/replay.ts
5627
5927
  import { render as render3 } from "ink";
5628
- import React14 from "react";
5928
+ import React15 from "react";
5629
5929
 
5630
5930
  // src/cli/ui/ReplayApp.tsx
5631
5931
  import { Box as Box11, Static as Static3, Text as Text11, useApp as useApp4, useInput as useInput4 } from "ink";
5632
- import React13, { useMemo as useMemo2, useState as useState7 } from "react";
5932
+ import React14, { useMemo as useMemo2, useState as useState7 } from "react";
5633
5933
  function ReplayApp({ meta, pages }) {
5634
5934
  const { exit } = useApp4();
5635
5935
  const maxIdx = Math.max(0, pages.length - 1);
@@ -5668,14 +5968,14 @@ function ReplayApp({ meta, pages }) {
5668
5968
  const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
5669
5969
  const currentPage = pages[idx];
5670
5970
  const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
5671
- return /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
5971
+ return /* @__PURE__ */ React14.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(
5672
5972
  StatsPanel,
5673
5973
  {
5674
5974
  summary,
5675
5975
  model: cumStats.models[0] ?? meta?.model ?? "?",
5676
5976
  prefixHash
5677
5977
  }
5678
- ), /* @__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")));
5978
+ ), /* @__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")));
5679
5979
  }
5680
5980
 
5681
5981
  // src/cli/commands/replay.ts
@@ -5687,8 +5987,9 @@ async function replayCommand(opts) {
5687
5987
  }
5688
5988
  const { parsed } = replayFromFile(opts.path);
5689
5989
  const pages = groupRecordsByTurn(parsed.records);
5690
- const { waitUntilExit } = render3(React14.createElement(ReplayApp, { meta: parsed.meta, pages }), {
5691
- exitOnCtrlC: true
5990
+ const { waitUntilExit } = render3(React15.createElement(ReplayApp, { meta: parsed.meta, pages }), {
5991
+ exitOnCtrlC: true,
5992
+ patchConsole: false
5692
5993
  });
5693
5994
  await waitUntilExit();
5694
5995
  }
@@ -5988,16 +6289,16 @@ function truncate4(s, max) {
5988
6289
 
5989
6290
  // src/cli/commands/setup.tsx
5990
6291
  import { render as render4 } from "ink";
5991
- import React17 from "react";
6292
+ import React18 from "react";
5992
6293
 
5993
6294
  // src/cli/ui/Wizard.tsx
5994
6295
  import { Box as Box13, Text as Text13, useApp as useApp5, useInput as useInput6 } from "ink";
5995
6296
  import TextInput2 from "ink-text-input";
5996
- import React16, { useState as useState9 } from "react";
6297
+ import React17, { useState as useState9 } from "react";
5997
6298
 
5998
6299
  // src/cli/ui/Select.tsx
5999
6300
  import { Box as Box12, Text as Text12, useInput as useInput5 } from "ink";
6000
- import React15, { useState as useState8 } from "react";
6301
+ import React16, { useState as useState8 } from "react";
6001
6302
  function SingleSelect({
6002
6303
  items,
6003
6304
  initialValue,
@@ -6021,7 +6322,7 @@ function SingleSelect({
6021
6322
  onCancel();
6022
6323
  }
6023
6324
  });
6024
- return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React15.createElement(
6325
+ return /* @__PURE__ */ React16.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React16.createElement(
6025
6326
  SelectRow,
6026
6327
  {
6027
6328
  key: item.value,
@@ -6064,10 +6365,10 @@ function MultiSelect({
6064
6365
  onCancel();
6065
6366
  }
6066
6367
  });
6067
- return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => {
6368
+ return /* @__PURE__ */ React16.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => {
6068
6369
  const checked = selected.has(item.value);
6069
6370
  const marker = checked ? "[x]" : "[ ]";
6070
- return /* @__PURE__ */ React15.createElement(
6371
+ return /* @__PURE__ */ React16.createElement(
6071
6372
  SelectRow,
6072
6373
  {
6073
6374
  key: item.value,
@@ -6076,7 +6377,7 @@ function MultiSelect({
6076
6377
  marker: `${i === index ? "\u25B8" : " "} ${marker}`
6077
6378
  }
6078
6379
  );
6079
- }), footer ? /* @__PURE__ */ React15.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, footer)) : null);
6380
+ }), footer ? /* @__PURE__ */ React16.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text12, { dimColor: true }, footer)) : null);
6080
6381
  }
6081
6382
  function SelectRow({
6082
6383
  item,
@@ -6084,7 +6385,7 @@ function SelectRow({
6084
6385
  marker
6085
6386
  }) {
6086
6387
  const color = item.disabled ? "gray" : active ? "cyan" : void 0;
6087
- 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);
6388
+ 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);
6088
6389
  }
6089
6390
  function findNextEnabled(items, from, step) {
6090
6391
  if (items.length === 0) return 0;
@@ -6133,7 +6434,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6133
6434
  if (key.escape && step !== "saved" && onCancel) onCancel();
6134
6435
  });
6135
6436
  if (step === "apiKey") {
6136
- return /* @__PURE__ */ React16.createElement(
6437
+ return /* @__PURE__ */ React17.createElement(
6137
6438
  ApiKeyStep,
6138
6439
  {
6139
6440
  onSubmit: (key) => {
@@ -6147,7 +6448,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6147
6448
  );
6148
6449
  }
6149
6450
  if (step === "preset") {
6150
- return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React16.createElement(
6451
+ return /* @__PURE__ */ React17.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React17.createElement(
6151
6452
  SingleSelect,
6152
6453
  {
6153
6454
  items: presetItems(),
@@ -6157,10 +6458,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6157
6458
  setStep("mcp");
6158
6459
  }
6159
6460
  }
6160
- ), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
6461
+ ), /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
6161
6462
  }
6162
6463
  if (step === "mcp") {
6163
- return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React16.createElement(
6464
+ return /* @__PURE__ */ React17.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React17.createElement(
6164
6465
  MultiSelect,
6165
6466
  {
6166
6467
  items: mcpItems(),
@@ -6185,7 +6486,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6185
6486
  }
6186
6487
  const currentName = pending[0];
6187
6488
  const entry = CATALOG_BY_NAME.get(currentName);
6188
- return /* @__PURE__ */ React16.createElement(
6489
+ return /* @__PURE__ */ React17.createElement(
6189
6490
  McpArgsStep,
6190
6491
  {
6191
6492
  entry,
@@ -6203,7 +6504,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6203
6504
  }
6204
6505
  if (step === "review") {
6205
6506
  const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
6206
- 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(
6507
+ 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(
6207
6508
  SummaryLine,
6208
6509
  {
6209
6510
  label: "MCP",
@@ -6211,8 +6512,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6211
6512
  }
6212
6513
  ), specs.map((spec, i) => (
6213
6514
  // biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
6214
- /* @__PURE__ */ React16.createElement(Box13, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "\xB7 ", spec))
6215
- )), /* @__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(
6515
+ /* @__PURE__ */ React17.createElement(Box13, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "\xB7 ", spec))
6516
+ )), /* @__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(
6216
6517
  ReviewConfirm,
6217
6518
  {
6218
6519
  onConfirm: () => {
@@ -6238,7 +6539,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
6238
6539
  }
6239
6540
  ));
6240
6541
  }
6241
- 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 }));
6542
+ 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 }));
6242
6543
  }
6243
6544
  function ApiKeyStep({
6244
6545
  onSubmit,
@@ -6246,7 +6547,7 @@ function ApiKeyStep({
6246
6547
  onError
6247
6548
  }) {
6248
6549
  const [value, setValue] = useState9("");
6249
- 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(
6550
+ 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(
6250
6551
  TextInput2,
6251
6552
  {
6252
6553
  value,
@@ -6263,7 +6564,7 @@ function ApiKeyStep({
6263
6564
  mask: "\u2022",
6264
6565
  placeholder: "sk-..."
6265
6566
  }
6266
- )), 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);
6567
+ )), 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);
6267
6568
  }
6268
6569
  function McpArgsStep({
6269
6570
  entry,
@@ -6272,7 +6573,7 @@ function McpArgsStep({
6272
6573
  onError
6273
6574
  }) {
6274
6575
  const [value, setValue] = useState9("");
6275
- 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(
6576
+ 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(
6276
6577
  TextInput2,
6277
6578
  {
6278
6579
  value,
@@ -6288,7 +6589,7 @@ function McpArgsStep({
6288
6589
  },
6289
6590
  placeholder: placeholderFor(entry)
6290
6591
  }
6291
- )), error ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { color: "red" }, error)) : null));
6592
+ )), error ? /* @__PURE__ */ React17.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text13, { color: "red" }, error)) : null));
6292
6593
  }
6293
6594
  function ReviewConfirm({ onConfirm }) {
6294
6595
  useInput6((_i, key) => {
@@ -6308,10 +6609,10 @@ function StepFrame({
6308
6609
  total,
6309
6610
  children
6310
6611
  }) {
6311
- 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));
6612
+ 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));
6312
6613
  }
6313
6614
  function SummaryLine({ label, value }) {
6314
- return /* @__PURE__ */ React16.createElement(Box13, null, /* @__PURE__ */ React16.createElement(Text13, null, label.padEnd(12)), /* @__PURE__ */ React16.createElement(Text13, { bold: true }, value));
6615
+ return /* @__PURE__ */ React17.createElement(Box13, null, /* @__PURE__ */ React17.createElement(Text13, null, label.padEnd(12)), /* @__PURE__ */ React17.createElement(Text13, { bold: true }, value));
6315
6616
  }
6316
6617
  function presetItems() {
6317
6618
  return ["fast", "smart", "max"].map((name) => ({
@@ -6367,7 +6668,7 @@ async function setupCommand(_opts = {}) {
6367
6668
  const existingKey = loadApiKey();
6368
6669
  const existing = readConfig();
6369
6670
  const { waitUntilExit, unmount } = render4(
6370
- /* @__PURE__ */ React17.createElement(
6671
+ /* @__PURE__ */ React18.createElement(
6371
6672
  Wizard,
6372
6673
  {
6373
6674
  existingApiKey: existingKey,
@@ -6379,7 +6680,7 @@ async function setupCommand(_opts = {}) {
6379
6680
  }
6380
6681
  }
6381
6682
  ),
6382
- { exitOnCtrlC: true }
6683
+ { exitOnCtrlC: true, patchConsole: false }
6383
6684
  );
6384
6685
  await waitUntilExit();
6385
6686
  }