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