reasonix 0.5.7 → 0.5.13
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 +519 -122
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +44 -6
- package/dist/index.js +44 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2589,7 +2589,7 @@ var DEFAULT_PICKER_IGNORE_DIRS = [
|
|
|
2589
2589
|
"venv",
|
|
2590
2590
|
"__pycache__"
|
|
2591
2591
|
];
|
|
2592
|
-
function
|
|
2592
|
+
function listFilesWithStatsSync(root, opts = {}) {
|
|
2593
2593
|
const maxResults = Math.max(1, opts.maxResults ?? 500);
|
|
2594
2594
|
const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
|
|
2595
2595
|
const rootAbs = resolve(root);
|
|
@@ -2610,7 +2610,12 @@ function listFilesSync(root, opts = {}) {
|
|
|
2610
2610
|
if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
|
|
2611
2611
|
walk2(join5(dirAbs, ent.name), relPath);
|
|
2612
2612
|
} else if (ent.isFile()) {
|
|
2613
|
-
|
|
2613
|
+
let mtimeMs = 0;
|
|
2614
|
+
try {
|
|
2615
|
+
mtimeMs = statSync2(join5(dirAbs, ent.name)).mtimeMs;
|
|
2616
|
+
} catch {
|
|
2617
|
+
}
|
|
2618
|
+
out.push({ path: relPath, mtimeMs });
|
|
2614
2619
|
}
|
|
2615
2620
|
}
|
|
2616
2621
|
};
|
|
@@ -2625,12 +2630,31 @@ function detectAtPicker(input) {
|
|
|
2625
2630
|
const atOffset = input.length - query.length - 1;
|
|
2626
2631
|
return { query, atOffset };
|
|
2627
2632
|
}
|
|
2628
|
-
function rankPickerCandidates(files, query,
|
|
2629
|
-
|
|
2633
|
+
function rankPickerCandidates(files, query, limitOrOpts) {
|
|
2634
|
+
const opts = typeof limitOrOpts === "number" ? { limit: limitOrOpts } : limitOrOpts ?? {};
|
|
2635
|
+
const limit = opts.limit ?? 40;
|
|
2636
|
+
const recent = new Set(opts.recentlyUsed ?? []);
|
|
2637
|
+
const entries = files.map(
|
|
2638
|
+
(f) => typeof f === "string" ? { path: f, mtimeMs: 0 } : f
|
|
2639
|
+
);
|
|
2640
|
+
if (!query) {
|
|
2641
|
+
const anyMtime = entries.some((e) => e.mtimeMs > 0);
|
|
2642
|
+
if (!anyMtime && recent.size === 0) {
|
|
2643
|
+
return entries.slice(0, limit).map((e) => e.path);
|
|
2644
|
+
}
|
|
2645
|
+
const sorted = [...entries].sort((a, b) => {
|
|
2646
|
+
const aRecent = recent.has(a.path) ? 1 : 0;
|
|
2647
|
+
const bRecent = recent.has(b.path) ? 1 : 0;
|
|
2648
|
+
if (aRecent !== bRecent) return bRecent - aRecent;
|
|
2649
|
+
if (a.mtimeMs !== b.mtimeMs) return b.mtimeMs - a.mtimeMs;
|
|
2650
|
+
return a.path.localeCompare(b.path);
|
|
2651
|
+
});
|
|
2652
|
+
return sorted.slice(0, limit).map((e) => e.path);
|
|
2653
|
+
}
|
|
2630
2654
|
const needle = query.toLowerCase();
|
|
2631
2655
|
const scored = [];
|
|
2632
|
-
for (const
|
|
2633
|
-
const lower =
|
|
2656
|
+
for (const e of entries) {
|
|
2657
|
+
const lower = e.path.toLowerCase();
|
|
2634
2658
|
const hit = lower.indexOf(needle);
|
|
2635
2659
|
if (hit < 0) continue;
|
|
2636
2660
|
const slash = lower.lastIndexOf("/");
|
|
@@ -2638,9 +2662,18 @@ function rankPickerCandidates(files, query, limit = 40) {
|
|
|
2638
2662
|
let score = 2;
|
|
2639
2663
|
if (base.startsWith(needle)) score = 0;
|
|
2640
2664
|
else if (lower.startsWith(needle)) score = 1;
|
|
2641
|
-
scored.push({
|
|
2665
|
+
scored.push({
|
|
2666
|
+
path: e.path,
|
|
2667
|
+
score: score * 1e4 + hit,
|
|
2668
|
+
mtimeMs: e.mtimeMs,
|
|
2669
|
+
recent: recent.has(e.path)
|
|
2670
|
+
});
|
|
2642
2671
|
}
|
|
2643
|
-
scored.sort((a, b) =>
|
|
2672
|
+
scored.sort((a, b) => {
|
|
2673
|
+
if (a.score !== b.score) return a.score - b.score;
|
|
2674
|
+
if (a.recent !== b.recent) return a.recent ? -1 : 1;
|
|
2675
|
+
return b.mtimeMs - a.mtimeMs;
|
|
2676
|
+
});
|
|
2644
2677
|
return scored.slice(0, limit).map((s) => s.path);
|
|
2645
2678
|
}
|
|
2646
2679
|
var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
|
|
@@ -5606,11 +5639,80 @@ function formatLogSize(path = defaultUsageLogPath()) {
|
|
|
5606
5639
|
// src/cli/commands/chat.tsx
|
|
5607
5640
|
import { existsSync as existsSync10, statSync as statSync6 } from "fs";
|
|
5608
5641
|
import { render } from "ink";
|
|
5609
|
-
import
|
|
5642
|
+
import React17, { useState as useState7 } from "react";
|
|
5610
5643
|
|
|
5611
5644
|
// src/cli/ui/App.tsx
|
|
5612
|
-
import { Box as
|
|
5613
|
-
import
|
|
5645
|
+
import { Box as Box13, Static, Text as Text13, useApp, useInput as useInput4 } from "ink";
|
|
5646
|
+
import React14, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState5 } from "react";
|
|
5647
|
+
|
|
5648
|
+
// src/code/diff-preview.ts
|
|
5649
|
+
function formatEditBlockDiff(block, opts = {}) {
|
|
5650
|
+
const contextLines = Math.max(0, opts.contextLines ?? 2);
|
|
5651
|
+
const maxLines = Math.max(4, opts.maxLines ?? 20);
|
|
5652
|
+
const indent = opts.indent ?? " ";
|
|
5653
|
+
const search = block.search === "" ? [] : block.search.split("\n");
|
|
5654
|
+
const replace = block.replace.split("\n");
|
|
5655
|
+
if (search.length === 0) {
|
|
5656
|
+
return renderAllPlus(replace, indent, maxLines);
|
|
5657
|
+
}
|
|
5658
|
+
let leading = 0;
|
|
5659
|
+
while (leading < search.length && leading < replace.length && search[leading] === replace[leading]) {
|
|
5660
|
+
leading++;
|
|
5661
|
+
}
|
|
5662
|
+
let trailing = 0;
|
|
5663
|
+
while (trailing < search.length - leading && trailing < replace.length - leading && search[search.length - 1 - trailing] === replace[replace.length - 1 - trailing]) {
|
|
5664
|
+
trailing++;
|
|
5665
|
+
}
|
|
5666
|
+
const searchMiddle = search.slice(leading, search.length - trailing);
|
|
5667
|
+
const replaceMiddle = replace.slice(leading, replace.length - trailing);
|
|
5668
|
+
const leadShown = search.slice(Math.max(0, leading - contextLines), leading);
|
|
5669
|
+
const leadHidden = leading - leadShown.length;
|
|
5670
|
+
const trailShown = search.slice(
|
|
5671
|
+
search.length - trailing,
|
|
5672
|
+
search.length - trailing + contextLines
|
|
5673
|
+
);
|
|
5674
|
+
const trailHidden = trailing - trailShown.length;
|
|
5675
|
+
const out = [];
|
|
5676
|
+
if (leadHidden > 0) {
|
|
5677
|
+
out.push(`${indent} \u2026 ${leadHidden} unchanged line${leadHidden === 1 ? "" : "s"} above`);
|
|
5678
|
+
}
|
|
5679
|
+
for (const l of leadShown) out.push(`${indent} ${l}`);
|
|
5680
|
+
for (const l of searchMiddle) out.push(`${indent}- ${l}`);
|
|
5681
|
+
for (const l of replaceMiddle) out.push(`${indent}+ ${l}`);
|
|
5682
|
+
for (const l of trailShown) out.push(`${indent} ${l}`);
|
|
5683
|
+
if (trailHidden > 0) {
|
|
5684
|
+
out.push(`${indent} \u2026 ${trailHidden} unchanged line${trailHidden === 1 ? "" : "s"} below`);
|
|
5685
|
+
}
|
|
5686
|
+
return capLines(out, maxLines, indent);
|
|
5687
|
+
}
|
|
5688
|
+
function formatAllBlockDiffs(blocks, opts = {}) {
|
|
5689
|
+
const out = [];
|
|
5690
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
5691
|
+
const b = blocks[i];
|
|
5692
|
+
const removed = b.search === "" ? 0 : countLines2(b.search);
|
|
5693
|
+
const added = countLines2(b.replace);
|
|
5694
|
+
const tag = b.search === "" ? "NEW " : " ";
|
|
5695
|
+
if (i > 0) out.push("");
|
|
5696
|
+
out.push(` ${tag}${b.path} (-${removed} +${added} lines)`);
|
|
5697
|
+
out.push(...formatEditBlockDiff(b, opts));
|
|
5698
|
+
}
|
|
5699
|
+
return out;
|
|
5700
|
+
}
|
|
5701
|
+
function countLines2(s) {
|
|
5702
|
+
if (s.length === 0) return 0;
|
|
5703
|
+
return (s.match(/\n/g)?.length ?? 0) + 1;
|
|
5704
|
+
}
|
|
5705
|
+
function renderAllPlus(lines, indent, maxLines) {
|
|
5706
|
+
const out = lines.map((l) => `${indent}+ ${l}`);
|
|
5707
|
+
return capLines(out, maxLines, indent);
|
|
5708
|
+
}
|
|
5709
|
+
function capLines(lines, maxLines, indent) {
|
|
5710
|
+
if (lines.length <= maxLines) return lines;
|
|
5711
|
+
const head = lines.slice(0, maxLines - 1);
|
|
5712
|
+
const hidden = lines.length - head.length;
|
|
5713
|
+
head.push(`${indent}\u2026 (${hidden} more diff lines \u2014 full content applies on /apply)`);
|
|
5714
|
+
return head;
|
|
5715
|
+
}
|
|
5614
5716
|
|
|
5615
5717
|
// src/tools/skills.ts
|
|
5616
5718
|
function registerSkillTools(registry, opts = {}) {
|
|
@@ -6792,16 +6894,49 @@ function derivePrefix(command) {
|
|
|
6792
6894
|
return TWO_TOKEN_WRAPPERS.has(first) ? `${first} ${tokens[1]}` : first;
|
|
6793
6895
|
}
|
|
6794
6896
|
|
|
6795
|
-
// src/cli/ui/
|
|
6897
|
+
// src/cli/ui/SlashArgPicker.tsx
|
|
6796
6898
|
import { Box as Box10, Text as Text10 } from "ink";
|
|
6797
6899
|
import React11 from "react";
|
|
6900
|
+
function SlashArgPicker({
|
|
6901
|
+
matches,
|
|
6902
|
+
selectedIndex,
|
|
6903
|
+
spec,
|
|
6904
|
+
kind,
|
|
6905
|
+
partial
|
|
6906
|
+
}) {
|
|
6907
|
+
if (kind === "hint") {
|
|
6908
|
+
return /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary));
|
|
6909
|
+
}
|
|
6910
|
+
if (matches === null) return null;
|
|
6911
|
+
if (matches.length === 0) {
|
|
6912
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, ' no match for "', partial, '" \u2014 keep typing, or Backspace to edit'));
|
|
6913
|
+
}
|
|
6914
|
+
const MAX = 8;
|
|
6915
|
+
const total = matches.length;
|
|
6916
|
+
const windowStart = total <= MAX ? 0 : Math.max(0, Math.min(selectedIndex - Math.floor(MAX / 2), total - MAX));
|
|
6917
|
+
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
6918
|
+
const hiddenAbove = windowStart;
|
|
6919
|
+
const hiddenBelow = total - windowStart - shown.length;
|
|
6920
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), hiddenAbove > 0 ? /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((value, i) => /* @__PURE__ */ React11.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
|
|
6921
|
+
}
|
|
6922
|
+
function ArgRow({ value, isSelected }) {
|
|
6923
|
+
const marker = isSelected ? "\u25B8" : " ";
|
|
6924
|
+
if (isSelected) {
|
|
6925
|
+
return /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: "cyan" }, marker, " ", value));
|
|
6926
|
+
}
|
|
6927
|
+
return /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, marker, " ", value));
|
|
6928
|
+
}
|
|
6929
|
+
|
|
6930
|
+
// src/cli/ui/SlashSuggestions.tsx
|
|
6931
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
6932
|
+
import React12 from "react";
|
|
6798
6933
|
function SlashSuggestions({
|
|
6799
6934
|
matches,
|
|
6800
6935
|
selectedIndex
|
|
6801
6936
|
}) {
|
|
6802
6937
|
if (matches === null) return null;
|
|
6803
6938
|
if (matches.length === 0) {
|
|
6804
|
-
return /* @__PURE__ */
|
|
6939
|
+
return /* @__PURE__ */ React12.createElement(Box11, { paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
|
|
6805
6940
|
}
|
|
6806
6941
|
const MAX = 8;
|
|
6807
6942
|
const total = matches.length;
|
|
@@ -6809,21 +6944,21 @@ function SlashSuggestions({
|
|
|
6809
6944
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
6810
6945
|
const hiddenAbove = windowStart;
|
|
6811
6946
|
const hiddenBelow = total - windowStart - shown.length;
|
|
6812
|
-
return /* @__PURE__ */
|
|
6947
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React12.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
|
|
6813
6948
|
}
|
|
6814
6949
|
function SuggestionRow({ spec, isSelected }) {
|
|
6815
6950
|
const marker = isSelected ? "\u25B8" : " ";
|
|
6816
6951
|
const name = `/${spec.cmd}`;
|
|
6817
6952
|
const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
|
|
6818
6953
|
if (isSelected) {
|
|
6819
|
-
return /* @__PURE__ */
|
|
6954
|
+
return /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, " ", spec.summary));
|
|
6820
6955
|
}
|
|
6821
|
-
return /* @__PURE__ */
|
|
6956
|
+
return /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
|
|
6822
6957
|
}
|
|
6823
6958
|
|
|
6824
6959
|
// src/cli/ui/StatsPanel.tsx
|
|
6825
|
-
import { Box as
|
|
6826
|
-
import
|
|
6960
|
+
import { Box as Box12, Text as Text12, useStdout as useStdout2 } from "ink";
|
|
6961
|
+
import React13 from "react";
|
|
6827
6962
|
var WORDMARK_STYLES = [
|
|
6828
6963
|
{ ch: "\u25C8", color: "#5eead4", isLogo: true },
|
|
6829
6964
|
// teal — brand mark
|
|
@@ -6849,7 +6984,7 @@ function Wordmark({ busy }) {
|
|
|
6849
6984
|
const tick = useTick();
|
|
6850
6985
|
const period = busy ? 5 : 12;
|
|
6851
6986
|
const bright = Math.floor(tick / period) % 2 === 0;
|
|
6852
|
-
return /* @__PURE__ */
|
|
6987
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, WORDMARK_STYLES.map((c) => /* @__PURE__ */ React13.createElement(Text12, { key: `${c.ch}-${c.color}`, color: c.color, bold: c.isLogo ? bright : true }, c.ch)));
|
|
6853
6988
|
}
|
|
6854
6989
|
var NARROW_BREAKPOINT = 120;
|
|
6855
6990
|
var COLD_START_TURNS = 3;
|
|
@@ -6871,7 +7006,7 @@ function StatsPanel({
|
|
|
6871
7006
|
const columns = stdout2?.columns ?? 80;
|
|
6872
7007
|
const narrow = columns < NARROW_BREAKPOINT;
|
|
6873
7008
|
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
6874
|
-
return /* @__PURE__ */
|
|
7009
|
+
return /* @__PURE__ */ React13.createElement(Box12, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React13.createElement(
|
|
6875
7010
|
Header,
|
|
6876
7011
|
{
|
|
6877
7012
|
model,
|
|
@@ -6885,7 +7020,7 @@ function StatsPanel({
|
|
|
6885
7020
|
narrow,
|
|
6886
7021
|
busy: busy ?? false
|
|
6887
7022
|
}
|
|
6888
|
-
), narrow ? /* @__PURE__ */
|
|
7023
|
+
), narrow ? /* @__PURE__ */ React13.createElement(
|
|
6889
7024
|
StackedMetrics,
|
|
6890
7025
|
{
|
|
6891
7026
|
summary,
|
|
@@ -6894,7 +7029,7 @@ function StatsPanel({
|
|
|
6894
7029
|
balance,
|
|
6895
7030
|
coldStart
|
|
6896
7031
|
}
|
|
6897
|
-
) : /* @__PURE__ */
|
|
7032
|
+
) : /* @__PURE__ */ React13.createElement(
|
|
6898
7033
|
InlineMetrics,
|
|
6899
7034
|
{
|
|
6900
7035
|
summary,
|
|
@@ -6917,7 +7052,7 @@ function Header({
|
|
|
6917
7052
|
narrow,
|
|
6918
7053
|
busy
|
|
6919
7054
|
}) {
|
|
6920
|
-
return /* @__PURE__ */
|
|
7055
|
+
return /* @__PURE__ */ React13.createElement(Box12, { justifyContent: "space-between" }, /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Wordmark, { busy }), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` v${VERSION}`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, model), narrow ? null : /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, prefixHash)), harvestOn ? /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React13.createElement(Text12, { color: "blue" }, " \xB7 branch", branchBudget) : null, planMode ? /* @__PURE__ */ React13.createElement(Text12, { color: "red", bold: true }, " \xB7 PLAN") : null), /* @__PURE__ */ React13.createElement(Text12, null, updateAvailable ? /* @__PURE__ */ React13.createElement(Text12, { color: "yellow", bold: true }, `update: ${updateAvailable} \xB7 `) : null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, narrow ? `turn ${turns}` : `turn ${turns} \xB7 /help`)));
|
|
6921
7056
|
}
|
|
6922
7057
|
function InlineMetrics({
|
|
6923
7058
|
summary,
|
|
@@ -6926,7 +7061,7 @@ function InlineMetrics({
|
|
|
6926
7061
|
balance,
|
|
6927
7062
|
coldStart
|
|
6928
7063
|
}) {
|
|
6929
|
-
return /* @__PURE__ */
|
|
7064
|
+
return /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React13.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React13.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React13.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React13.createElement(BalanceCell, { balance }) : null);
|
|
6930
7065
|
}
|
|
6931
7066
|
function StackedMetrics({
|
|
6932
7067
|
summary,
|
|
@@ -6935,7 +7070,7 @@ function StackedMetrics({
|
|
|
6935
7070
|
balance,
|
|
6936
7071
|
coldStart
|
|
6937
7072
|
}) {
|
|
6938
|
-
return /* @__PURE__ */
|
|
7073
|
+
return /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
|
|
6939
7074
|
ContextCell,
|
|
6940
7075
|
{
|
|
6941
7076
|
ratio: ctxRatio,
|
|
@@ -6943,7 +7078,7 @@ function StackedMetrics({
|
|
|
6943
7078
|
ctxMax,
|
|
6944
7079
|
showBar: true
|
|
6945
7080
|
}
|
|
6946
|
-
), balance ? /* @__PURE__ */
|
|
7081
|
+
), balance ? /* @__PURE__ */ React13.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React13.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React13.createElement(CostCell, { summary, coldStart }));
|
|
6947
7082
|
}
|
|
6948
7083
|
function ContextCell({
|
|
6949
7084
|
ratio,
|
|
@@ -6952,11 +7087,11 @@ function ContextCell({
|
|
|
6952
7087
|
showBar
|
|
6953
7088
|
}) {
|
|
6954
7089
|
if (promptTokens === 0) {
|
|
6955
|
-
return /* @__PURE__ */
|
|
7090
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "ctx "), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "\u2014 (no turns yet)"));
|
|
6956
7091
|
}
|
|
6957
7092
|
const color = ratio >= 0.8 ? "red" : ratio >= 0.6 ? "yellow" : "green";
|
|
6958
7093
|
const pct2 = Math.round(ratio * 100);
|
|
6959
|
-
return /* @__PURE__ */
|
|
7094
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "ctx "), showBar ? /* @__PURE__ */ React13.createElement(Bar, { ratio, color }) : null, showBar ? /* @__PURE__ */ React13.createElement(Text12, null, " ") : null, /* @__PURE__ */ React13.createElement(Text12, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React13.createElement(Text12, { color: "red", bold: true }, " \xB7 /compact") : null);
|
|
6960
7095
|
}
|
|
6961
7096
|
function CacheCell({
|
|
6962
7097
|
hitRatio,
|
|
@@ -6965,33 +7100,33 @@ function CacheCell({
|
|
|
6965
7100
|
}) {
|
|
6966
7101
|
const pct2 = (hitRatio * 100).toFixed(1);
|
|
6967
7102
|
if (turns === 0) {
|
|
6968
|
-
return /* @__PURE__ */
|
|
7103
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "cache "), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "\u2014"));
|
|
6969
7104
|
}
|
|
6970
7105
|
if (coldStart) {
|
|
6971
|
-
return /* @__PURE__ */
|
|
7106
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "cache "), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true, italic: true }, "(cold start)"));
|
|
6972
7107
|
}
|
|
6973
7108
|
const color = hitRatio >= 0.7 ? "green" : hitRatio >= 0.4 ? "yellow" : "red";
|
|
6974
|
-
return /* @__PURE__ */
|
|
7109
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "cache "), /* @__PURE__ */ React13.createElement(Text12, { color, bold: true }, pct2, "%"));
|
|
6975
7110
|
}
|
|
6976
7111
|
function CostCell({
|
|
6977
7112
|
summary,
|
|
6978
7113
|
coldStart
|
|
6979
7114
|
}) {
|
|
6980
7115
|
if (summary.turns === 0) {
|
|
6981
|
-
return /* @__PURE__ */
|
|
7116
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "cost "), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "\u2014"));
|
|
6982
7117
|
}
|
|
6983
7118
|
const primaryColor = coldStart ? void 0 : "green";
|
|
6984
|
-
return /* @__PURE__ */
|
|
7119
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "cost "), /* @__PURE__ */ React13.createElement(Text12, { color: primaryColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")"));
|
|
6985
7120
|
}
|
|
6986
7121
|
function BalanceCell({ balance }) {
|
|
6987
7122
|
const color = balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green";
|
|
6988
|
-
return /* @__PURE__ */
|
|
7123
|
+
return /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "balance "), /* @__PURE__ */ React13.createElement(Text12, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
|
|
6989
7124
|
}
|
|
6990
7125
|
function Bar({ ratio, color }) {
|
|
6991
7126
|
const cells = 10;
|
|
6992
7127
|
const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
|
|
6993
7128
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
|
|
6994
|
-
return /* @__PURE__ */
|
|
7129
|
+
return /* @__PURE__ */ React13.createElement(Text12, { color }, bar);
|
|
6995
7130
|
}
|
|
6996
7131
|
function formatTokens(n) {
|
|
6997
7132
|
if (n < 1024) return String(n);
|
|
@@ -6999,6 +7134,50 @@ function formatTokens(n) {
|
|
|
6999
7134
|
return k >= 100 ? `${k.toFixed(0)}K` : `${k.toFixed(1)}K`;
|
|
7000
7135
|
}
|
|
7001
7136
|
|
|
7137
|
+
// src/cli/ui/bang.ts
|
|
7138
|
+
function detectBangCommand(text) {
|
|
7139
|
+
if (!text.startsWith("!")) return null;
|
|
7140
|
+
const body = text.slice(1).trim();
|
|
7141
|
+
if (!body) return null;
|
|
7142
|
+
return body;
|
|
7143
|
+
}
|
|
7144
|
+
function formatBangUserMessage(cmd, output) {
|
|
7145
|
+
return `[!${cmd}]
|
|
7146
|
+
${output}`;
|
|
7147
|
+
}
|
|
7148
|
+
|
|
7149
|
+
// src/cli/ui/paste-collapse.ts
|
|
7150
|
+
var DEFAULT_PASTE_LINE_THRESHOLD = 40;
|
|
7151
|
+
var DEFAULT_PASTE_CHAR_THRESHOLD = 2e3;
|
|
7152
|
+
var DEFAULT_PASTE_HEAD_LINES = 10;
|
|
7153
|
+
function formatLongPaste(input, opts = {}) {
|
|
7154
|
+
const lineCap = opts.lineThreshold ?? DEFAULT_PASTE_LINE_THRESHOLD;
|
|
7155
|
+
const charCap = opts.charThreshold ?? DEFAULT_PASTE_CHAR_THRESHOLD;
|
|
7156
|
+
const headN = Math.max(1, opts.headLines ?? DEFAULT_PASTE_HEAD_LINES);
|
|
7157
|
+
const originalChars = input.length;
|
|
7158
|
+
const lines = input.split("\n");
|
|
7159
|
+
const originalLines = lines.length;
|
|
7160
|
+
if (originalChars <= charCap && originalLines <= lineCap) {
|
|
7161
|
+
return { displayText: input, collapsed: false, originalChars, originalLines };
|
|
7162
|
+
}
|
|
7163
|
+
const header2 = `\u25B8 pasted ${formatBytes(originalChars)} (${originalLines} lines) \u2014 first ${Math.min(headN, originalLines)} shown, full text sent to model`;
|
|
7164
|
+
const head = lines.slice(0, headN).join("\n");
|
|
7165
|
+
const remaining = originalLines - headN;
|
|
7166
|
+
const footer = remaining > 0 ? `\u2026 (${remaining} more line${remaining === 1 ? "" : "s"})` : "";
|
|
7167
|
+
const displayText = footer ? `${header2}
|
|
7168
|
+
${head}
|
|
7169
|
+
${footer}` : `${header2}
|
|
7170
|
+
${head}`;
|
|
7171
|
+
return { displayText, collapsed: true, originalChars, originalLines };
|
|
7172
|
+
}
|
|
7173
|
+
function formatBytes(n) {
|
|
7174
|
+
if (n < 1024) return `${n} B`;
|
|
7175
|
+
const kb = n / 1024;
|
|
7176
|
+
if (kb < 1024) return `${kb.toFixed(kb >= 10 ? 0 : 1)} KB`;
|
|
7177
|
+
const mb = kb / 1024;
|
|
7178
|
+
return `${mb.toFixed(mb >= 10 ? 0 : 1)} MB`;
|
|
7179
|
+
}
|
|
7180
|
+
|
|
7002
7181
|
// src/cli/ui/slash.ts
|
|
7003
7182
|
import { spawnSync } from "child_process";
|
|
7004
7183
|
|
|
@@ -7115,12 +7294,28 @@ var SLASH_COMMANDS = [
|
|
|
7115
7294
|
{
|
|
7116
7295
|
cmd: "preset",
|
|
7117
7296
|
argsHint: "<fast|smart|max>",
|
|
7118
|
-
summary: "one-tap model + harvest + branch bundle"
|
|
7297
|
+
summary: "one-tap model + harvest + branch bundle",
|
|
7298
|
+
argCompleter: ["fast", "smart", "max"]
|
|
7299
|
+
},
|
|
7300
|
+
{
|
|
7301
|
+
cmd: "model",
|
|
7302
|
+
argsHint: "<id>",
|
|
7303
|
+
summary: "switch DeepSeek model id",
|
|
7304
|
+
argCompleter: "models"
|
|
7119
7305
|
},
|
|
7120
|
-
{ cmd: "model", argsHint: "<id>", summary: "switch DeepSeek model id" },
|
|
7121
7306
|
{ cmd: "models", summary: "list available models fetched from DeepSeek /models" },
|
|
7122
|
-
{
|
|
7123
|
-
|
|
7307
|
+
{
|
|
7308
|
+
cmd: "harvest",
|
|
7309
|
+
argsHint: "[on|off]",
|
|
7310
|
+
summary: "toggle Pillar-2 plan-state extraction",
|
|
7311
|
+
argCompleter: ["on", "off"]
|
|
7312
|
+
},
|
|
7313
|
+
{
|
|
7314
|
+
cmd: "branch",
|
|
7315
|
+
argsHint: "<N|off>",
|
|
7316
|
+
summary: "run N parallel samples per turn (N>=2)",
|
|
7317
|
+
argCompleter: ["off", "2", "3", "4", "5"]
|
|
7318
|
+
},
|
|
7124
7319
|
{ cmd: "mcp", summary: "list MCP servers + tools attached to this session" },
|
|
7125
7320
|
{ cmd: "tool", argsHint: "[N]", summary: "dump full output of the Nth tool call (1=latest)" },
|
|
7126
7321
|
{
|
|
@@ -7157,6 +7352,7 @@ var SLASH_COMMANDS = [
|
|
|
7157
7352
|
argsHint: "[tokens]",
|
|
7158
7353
|
summary: "shrink oversized tool results in the log (cap in tokens, default 4000)"
|
|
7159
7354
|
},
|
|
7355
|
+
{ cmd: "keys", summary: "show all keyboard shortcuts and prompt prefixes" },
|
|
7160
7356
|
{ cmd: "sessions", summary: "list saved sessions (current marked with \u25B8)" },
|
|
7161
7357
|
{ cmd: "forget", summary: "delete the current session from disk" },
|
|
7162
7358
|
{ cmd: "setup", summary: "reminds you to exit and run `reasonix setup`" },
|
|
@@ -7177,7 +7373,8 @@ var SLASH_COMMANDS = [
|
|
|
7177
7373
|
cmd: "plan",
|
|
7178
7374
|
argsHint: "[on|off]",
|
|
7179
7375
|
summary: "toggle read-only plan mode (writes bounced until submit_plan + approval)",
|
|
7180
|
-
contextual: "code"
|
|
7376
|
+
contextual: "code",
|
|
7377
|
+
argCompleter: ["on", "off"]
|
|
7181
7378
|
},
|
|
7182
7379
|
{
|
|
7183
7380
|
cmd: "apply-plan",
|
|
@@ -7192,6 +7389,27 @@ function suggestSlashCommands(prefix, codeMode = false) {
|
|
|
7192
7389
|
return c.cmd.startsWith(p);
|
|
7193
7390
|
});
|
|
7194
7391
|
}
|
|
7392
|
+
function detectSlashArgContext(input, codeMode = false) {
|
|
7393
|
+
const m = /^\/(\S+) ([\s\S]*)$/.exec(input);
|
|
7394
|
+
if (!m) return null;
|
|
7395
|
+
const cmdName = m[1].toLowerCase();
|
|
7396
|
+
const tail = m[2] ?? "";
|
|
7397
|
+
const spec = SLASH_COMMANDS.find(
|
|
7398
|
+
(s) => s.cmd === cmdName && (s.contextual !== "code" || codeMode)
|
|
7399
|
+
);
|
|
7400
|
+
if (!spec) return null;
|
|
7401
|
+
const hasInternalSpace = /\s/.test(tail);
|
|
7402
|
+
const partialOffset = input.length - tail.length;
|
|
7403
|
+
if (hasInternalSpace) {
|
|
7404
|
+
return { spec, partial: tail, partialOffset, kind: "hint" };
|
|
7405
|
+
}
|
|
7406
|
+
return {
|
|
7407
|
+
spec,
|
|
7408
|
+
partial: tail,
|
|
7409
|
+
partialOffset,
|
|
7410
|
+
kind: spec.argCompleter ? "picker" : "hint"
|
|
7411
|
+
};
|
|
7412
|
+
}
|
|
7195
7413
|
function parseSlash(text) {
|
|
7196
7414
|
if (!text.startsWith("/")) return null;
|
|
7197
7415
|
const parts = text.slice(1).trim().split(/\s+/);
|
|
@@ -7217,12 +7435,42 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
7217
7435
|
info: `\u25B8 new conversation \u2014 dropped ${dropped} message(s) from context. Same session, fresh slate.`
|
|
7218
7436
|
};
|
|
7219
7437
|
}
|
|
7438
|
+
case "keys":
|
|
7439
|
+
return {
|
|
7440
|
+
info: [
|
|
7441
|
+
"Keyboard & prompt shortcuts:",
|
|
7442
|
+
"",
|
|
7443
|
+
" Enter submit the current prompt",
|
|
7444
|
+
" Shift+Enter / Ctrl+J insert a newline (multi-line prompt)",
|
|
7445
|
+
" \\<Enter> bash-style line continuation",
|
|
7446
|
+
" \u2190 \u2192 \u2191 \u2193 move cursor / recall history when buffer empty",
|
|
7447
|
+
" Ctrl+A / Ctrl+E jump to start / end of the current line",
|
|
7448
|
+
" Backspace delete left; Delete delete under cursor",
|
|
7449
|
+
" Esc abort the in-flight turn",
|
|
7450
|
+
" y / n accept / reject pending edits (code mode)",
|
|
7451
|
+
"",
|
|
7452
|
+
"Prompt prefixes:",
|
|
7453
|
+
" /<name> slash command; Tab/Enter picks from the suggestion list",
|
|
7454
|
+
" @<path> inline a file under [Referenced files] (code mode).",
|
|
7455
|
+
" Trailing `@\u2026` opens a file picker; \u2191/\u2193 navigate, Tab/Enter pick.",
|
|
7456
|
+
" !<cmd> run <cmd> as shell in the sandbox root; output goes into context",
|
|
7457
|
+
" so the model sees it next turn. No allowlist gate.",
|
|
7458
|
+
"",
|
|
7459
|
+
"Pickers (slash + @-mention):",
|
|
7460
|
+
" \u2191 / \u2193 navigate the suggestion list",
|
|
7461
|
+
" Tab insert the highlighted item without submitting",
|
|
7462
|
+
" Enter insert and (slash) run it, (@) keep editing",
|
|
7463
|
+
"",
|
|
7464
|
+
"Useful slashes: /help \xB7 /context \xB7 /stats \xB7 /compact \xB7 /new \xB7 /exit"
|
|
7465
|
+
].join("\n")
|
|
7466
|
+
};
|
|
7220
7467
|
case "help":
|
|
7221
7468
|
case "?":
|
|
7222
7469
|
return {
|
|
7223
7470
|
info: [
|
|
7224
7471
|
"Commands:",
|
|
7225
7472
|
" /help this message",
|
|
7473
|
+
" /keys keyboard shortcuts + prompt prefixes (!, @, /)",
|
|
7226
7474
|
" /status show current settings",
|
|
7227
7475
|
" /preset <fast|smart|max> one-tap presets \u2014 see below",
|
|
7228
7476
|
" /model <id> deepseek-chat or deepseek-reasoner",
|
|
@@ -7250,6 +7498,16 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
7250
7498
|
" /clear clear displayed scrollback only (context kept \u2014 model still sees it)",
|
|
7251
7499
|
" /exit quit",
|
|
7252
7500
|
"",
|
|
7501
|
+
"Shell shortcut:",
|
|
7502
|
+
" !<cmd> run <cmd> in the sandbox root; output goes into",
|
|
7503
|
+
" the conversation so the model sees it next turn.",
|
|
7504
|
+
" No allowlist gate \u2014 user-typed = explicit consent.",
|
|
7505
|
+
" Example: !git status !ls src/ !npm test",
|
|
7506
|
+
"",
|
|
7507
|
+
"File references (code mode):",
|
|
7508
|
+
" @path/to/file inline file content under [Referenced files] on send.",
|
|
7509
|
+
" Type `@` to open the picker (\u2191\u2193 navigate, Tab/Enter pick).",
|
|
7510
|
+
"",
|
|
7253
7511
|
"Presets:",
|
|
7254
7512
|
" fast deepseek-chat no harvest no branch ~1\xA2/100turns \u2190 default",
|
|
7255
7513
|
" smart reasoner harvest ~10x cost, slower",
|
|
@@ -8156,11 +8414,19 @@ function App({
|
|
|
8156
8414
|
const atFiles = useMemo(() => {
|
|
8157
8415
|
if (!codeMode?.rootDir) return [];
|
|
8158
8416
|
try {
|
|
8159
|
-
return
|
|
8417
|
+
return listFilesWithStatsSync(codeMode.rootDir, { maxResults: 500 });
|
|
8160
8418
|
} catch {
|
|
8161
8419
|
return [];
|
|
8162
8420
|
}
|
|
8163
8421
|
}, [codeMode?.rootDir]);
|
|
8422
|
+
const recentFilesRef = useRef2([]);
|
|
8423
|
+
const recordRecentFile = useCallback((p) => {
|
|
8424
|
+
const list = recentFilesRef.current;
|
|
8425
|
+
const i = list.indexOf(p);
|
|
8426
|
+
if (i >= 0) list.splice(i, 1);
|
|
8427
|
+
list.unshift(p);
|
|
8428
|
+
if (list.length > 20) list.length = 20;
|
|
8429
|
+
}, []);
|
|
8164
8430
|
const atPicker = useMemo(() => {
|
|
8165
8431
|
if (!codeMode?.rootDir) return null;
|
|
8166
8432
|
if (slashMatches !== null) return null;
|
|
@@ -8168,7 +8434,10 @@ function App({
|
|
|
8168
8434
|
}, [codeMode?.rootDir, input, slashMatches]);
|
|
8169
8435
|
const atMatches = useMemo(() => {
|
|
8170
8436
|
if (!atPicker) return null;
|
|
8171
|
-
return rankPickerCandidates(atFiles, atPicker.query,
|
|
8437
|
+
return rankPickerCandidates(atFiles, atPicker.query, {
|
|
8438
|
+
limit: 40,
|
|
8439
|
+
recentlyUsed: recentFilesRef.current
|
|
8440
|
+
});
|
|
8172
8441
|
}, [atPicker, atFiles]);
|
|
8173
8442
|
useEffect2(() => {
|
|
8174
8443
|
setAtSelected((prev) => {
|
|
@@ -8185,6 +8454,45 @@ function App({
|
|
|
8185
8454
|
},
|
|
8186
8455
|
[atPicker, input]
|
|
8187
8456
|
);
|
|
8457
|
+
const [slashArgSelected, setSlashArgSelected] = useState5(0);
|
|
8458
|
+
const slashArgContext = useMemo(() => {
|
|
8459
|
+
if (!input.startsWith("/")) return null;
|
|
8460
|
+
if (slashMatches !== null) return null;
|
|
8461
|
+
return detectSlashArgContext(input, !!codeMode);
|
|
8462
|
+
}, [input, slashMatches, codeMode]);
|
|
8463
|
+
const slashArgMatches = useMemo(() => {
|
|
8464
|
+
if (!slashArgContext || slashArgContext.kind !== "picker") return null;
|
|
8465
|
+
const completer = slashArgContext.spec.argCompleter;
|
|
8466
|
+
const partial = slashArgContext.partial;
|
|
8467
|
+
const needle = partial.toLowerCase();
|
|
8468
|
+
if (Array.isArray(completer)) {
|
|
8469
|
+
if (partial && completer.some((v) => v.toLowerCase() === needle)) return null;
|
|
8470
|
+
if (!partial) return completer.slice();
|
|
8471
|
+
return completer.filter((v) => v.toLowerCase().startsWith(needle));
|
|
8472
|
+
}
|
|
8473
|
+
if (completer === "models") {
|
|
8474
|
+
const all = models ?? [];
|
|
8475
|
+
if (partial && all.some((m) => m.toLowerCase() === needle)) return null;
|
|
8476
|
+
if (!partial) return all.slice(0, 40);
|
|
8477
|
+
return all.filter((m) => m.toLowerCase().includes(needle)).slice(0, 40);
|
|
8478
|
+
}
|
|
8479
|
+
return null;
|
|
8480
|
+
}, [slashArgContext, models]);
|
|
8481
|
+
useEffect2(() => {
|
|
8482
|
+
setSlashArgSelected((prev) => {
|
|
8483
|
+
if (!slashArgMatches || slashArgMatches.length === 0) return 0;
|
|
8484
|
+
if (prev >= slashArgMatches.length) return slashArgMatches.length - 1;
|
|
8485
|
+
return prev;
|
|
8486
|
+
});
|
|
8487
|
+
}, [slashArgMatches]);
|
|
8488
|
+
const pickSlashArg = useCallback(
|
|
8489
|
+
(chosen) => {
|
|
8490
|
+
if (!slashArgContext) return;
|
|
8491
|
+
const before = input.slice(0, slashArgContext.partialOffset);
|
|
8492
|
+
setInput(`${before}${chosen}`);
|
|
8493
|
+
},
|
|
8494
|
+
[slashArgContext, input]
|
|
8495
|
+
);
|
|
8188
8496
|
const loopRef = useRef2(null);
|
|
8189
8497
|
const subagentSinkRef = useRef2({ current: null });
|
|
8190
8498
|
const loop = useMemo(() => {
|
|
@@ -8369,6 +8677,21 @@ function App({
|
|
|
8369
8677
|
return;
|
|
8370
8678
|
}
|
|
8371
8679
|
}
|
|
8680
|
+
if (slashArgMatches && slashArgMatches.length > 0) {
|
|
8681
|
+
if (key.upArrow) {
|
|
8682
|
+
setSlashArgSelected((i) => Math.max(0, i - 1));
|
|
8683
|
+
return;
|
|
8684
|
+
}
|
|
8685
|
+
if (key.downArrow) {
|
|
8686
|
+
setSlashArgSelected((i) => Math.min(slashArgMatches.length - 1, i + 1));
|
|
8687
|
+
return;
|
|
8688
|
+
}
|
|
8689
|
+
if (key.tab) {
|
|
8690
|
+
const sel = slashArgMatches[slashArgSelected] ?? slashArgMatches[0];
|
|
8691
|
+
if (sel) pickSlashArg(sel);
|
|
8692
|
+
return;
|
|
8693
|
+
}
|
|
8694
|
+
}
|
|
8372
8695
|
if (slashMatches && slashMatches.length > 0) {
|
|
8373
8696
|
if (key.upArrow) {
|
|
8374
8697
|
setSlashSelected((i) => Math.max(0, i - 1));
|
|
@@ -8461,6 +8784,13 @@ function App({
|
|
|
8461
8784
|
return;
|
|
8462
8785
|
}
|
|
8463
8786
|
}
|
|
8787
|
+
if (slashArgMatches && slashArgMatches.length > 0 && slashArgContext) {
|
|
8788
|
+
const sel = slashArgMatches[slashArgSelected] ?? slashArgMatches[0];
|
|
8789
|
+
if (sel) {
|
|
8790
|
+
pickSlashArg(sel);
|
|
8791
|
+
return;
|
|
8792
|
+
}
|
|
8793
|
+
}
|
|
8464
8794
|
if (text.startsWith("/") && !text.includes(" ")) {
|
|
8465
8795
|
const typed = text.slice(1).toLowerCase();
|
|
8466
8796
|
const matches = suggestSlashCommands(typed, !!codeMode);
|
|
@@ -8478,6 +8808,49 @@ function App({
|
|
|
8478
8808
|
promptHistory.current.push(text);
|
|
8479
8809
|
return;
|
|
8480
8810
|
}
|
|
8811
|
+
const bangCmd = detectBangCommand(text);
|
|
8812
|
+
if (bangCmd !== null) {
|
|
8813
|
+
const bangRoot = codeMode?.rootDir ?? process.cwd();
|
|
8814
|
+
promptHistory.current.push(text);
|
|
8815
|
+
setHistorical((prev) => [
|
|
8816
|
+
...prev,
|
|
8817
|
+
{
|
|
8818
|
+
id: `bang-u-${Date.now()}`,
|
|
8819
|
+
role: "user",
|
|
8820
|
+
text,
|
|
8821
|
+
leadSeparator: prev.length > 0
|
|
8822
|
+
}
|
|
8823
|
+
]);
|
|
8824
|
+
setBusy(true);
|
|
8825
|
+
try {
|
|
8826
|
+
const result = await runCommand(bangCmd, {
|
|
8827
|
+
cwd: bangRoot,
|
|
8828
|
+
timeoutSec: 60,
|
|
8829
|
+
maxOutputChars: 32e3
|
|
8830
|
+
});
|
|
8831
|
+
const formatted = formatCommandResult(bangCmd, result);
|
|
8832
|
+
setHistorical((prev) => [
|
|
8833
|
+
...prev,
|
|
8834
|
+
{ id: `bang-o-${Date.now()}`, role: "info", text: formatted }
|
|
8835
|
+
]);
|
|
8836
|
+
loop.log.append({
|
|
8837
|
+
role: "user",
|
|
8838
|
+
content: formatBangUserMessage(bangCmd, formatted)
|
|
8839
|
+
});
|
|
8840
|
+
} catch (err) {
|
|
8841
|
+
setHistorical((prev) => [
|
|
8842
|
+
...prev,
|
|
8843
|
+
{
|
|
8844
|
+
id: `bang-e-${Date.now()}`,
|
|
8845
|
+
role: "warning",
|
|
8846
|
+
text: `! command failed: ${err.message}`
|
|
8847
|
+
}
|
|
8848
|
+
]);
|
|
8849
|
+
} finally {
|
|
8850
|
+
setBusy(false);
|
|
8851
|
+
}
|
|
8852
|
+
return;
|
|
8853
|
+
}
|
|
8481
8854
|
const slash = parseSlash(text);
|
|
8482
8855
|
if (slash) {
|
|
8483
8856
|
const result = handleSlash(slash.cmd, slash.args, loop, {
|
|
@@ -8567,13 +8940,19 @@ function App({
|
|
|
8567
8940
|
if (promptReport.blocked) return;
|
|
8568
8941
|
}
|
|
8569
8942
|
promptHistory.current.push(text);
|
|
8943
|
+
const pasteDisplay = formatLongPaste(text);
|
|
8570
8944
|
setHistorical((prev) => [
|
|
8571
8945
|
...prev,
|
|
8572
8946
|
// `leadSeparator`: thin rule above this user turn when history
|
|
8573
8947
|
// isn't empty — visual pacing for multi-turn sessions. First
|
|
8574
8948
|
// user message leaves it off so the UI doesn't open with a
|
|
8575
8949
|
// dangling divider.
|
|
8576
|
-
{
|
|
8950
|
+
{
|
|
8951
|
+
id: `u-${Date.now()}`,
|
|
8952
|
+
role: "user",
|
|
8953
|
+
text: pasteDisplay.displayText,
|
|
8954
|
+
leadSeparator: prev.length > 0
|
|
8955
|
+
}
|
|
8577
8956
|
]);
|
|
8578
8957
|
const assistantId = `a-${Date.now()}`;
|
|
8579
8958
|
const streamRef = { id: assistantId, text: "", reasoning: "" };
|
|
@@ -8710,6 +9089,19 @@ function App({
|
|
|
8710
9089
|
} else if (ev.role === "tool_start") {
|
|
8711
9090
|
setOngoingTool({ name: ev.toolName ?? "?", args: ev.toolArgs });
|
|
8712
9091
|
setToolProgress(null);
|
|
9092
|
+
if (codeMode && ev.toolArgs) {
|
|
9093
|
+
try {
|
|
9094
|
+
const parsed = JSON.parse(ev.toolArgs);
|
|
9095
|
+
for (const k of ["path", "file_path", "file"]) {
|
|
9096
|
+
const v = parsed[k];
|
|
9097
|
+
if (typeof v === "string" && v.trim()) {
|
|
9098
|
+
recordRecentFile(v.trim());
|
|
9099
|
+
break;
|
|
9100
|
+
}
|
|
9101
|
+
}
|
|
9102
|
+
} catch {
|
|
9103
|
+
}
|
|
9104
|
+
}
|
|
8713
9105
|
} else if (ev.role === "tool") {
|
|
8714
9106
|
flush();
|
|
8715
9107
|
setOngoingTool(null);
|
|
@@ -8819,6 +9211,11 @@ function App({
|
|
|
8819
9211
|
atPicker,
|
|
8820
9212
|
atSelected,
|
|
8821
9213
|
pickAtMention,
|
|
9214
|
+
recordRecentFile,
|
|
9215
|
+
slashArgMatches,
|
|
9216
|
+
slashArgContext,
|
|
9217
|
+
slashArgSelected,
|
|
9218
|
+
pickSlashArg,
|
|
8822
9219
|
togglePlanMode,
|
|
8823
9220
|
writeTranscript
|
|
8824
9221
|
]
|
|
@@ -8969,7 +9366,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
8969
9366
|
if (stagedInput?.plan) setPendingPlan(stagedInput.plan);
|
|
8970
9367
|
setStagedInput(null);
|
|
8971
9368
|
}, [stagedInput]);
|
|
8972
|
-
return /* @__PURE__ */
|
|
9369
|
+
return /* @__PURE__ */ React14.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(
|
|
8973
9370
|
StatsPanel,
|
|
8974
9371
|
{
|
|
8975
9372
|
summary,
|
|
@@ -8982,21 +9379,21 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
8982
9379
|
busy,
|
|
8983
9380
|
updateAvailable
|
|
8984
9381
|
}
|
|
8985
|
-
), /* @__PURE__ */
|
|
9382
|
+
), /* @__PURE__ */ React14.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React14.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && streaming ? /* @__PURE__ */ React14.createElement(Box13, { marginY: 1 }, /* @__PURE__ */ React14.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && ongoingTool ? /* @__PURE__ */ React14.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && subagentActivity ? /* @__PURE__ */ React14.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !ongoingTool && statusLine ? /* @__PURE__ */ React14.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React14.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React14.createElement(
|
|
8986
9383
|
PlanRefineInput,
|
|
8987
9384
|
{
|
|
8988
9385
|
mode: stagedInput.mode,
|
|
8989
9386
|
onSubmit: handleStagedInputSubmit,
|
|
8990
9387
|
onCancel: handleStagedInputCancel
|
|
8991
9388
|
}
|
|
8992
|
-
) : pendingPlan ? /* @__PURE__ */
|
|
9389
|
+
) : pendingPlan ? /* @__PURE__ */ React14.createElement(PlanConfirm, { plan: pendingPlan, onChoose: handlePlanConfirm, projectRoot: hookCwd }) : pendingShell ? /* @__PURE__ */ React14.createElement(
|
|
8993
9390
|
ShellConfirm,
|
|
8994
9391
|
{
|
|
8995
9392
|
command: pendingShell,
|
|
8996
9393
|
allowPrefix: derivePrefix(pendingShell),
|
|
8997
9394
|
onChoose: handleShellConfirm
|
|
8998
9395
|
}
|
|
8999
|
-
) : /* @__PURE__ */
|
|
9396
|
+
) : /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(
|
|
9000
9397
|
PromptInput,
|
|
9001
9398
|
{
|
|
9002
9399
|
value: input,
|
|
@@ -9004,27 +9401,36 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
9004
9401
|
onSubmit: handleSubmit,
|
|
9005
9402
|
disabled: busy
|
|
9006
9403
|
}
|
|
9007
|
-
), /* @__PURE__ */
|
|
9404
|
+
), /* @__PURE__ */ React14.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React14.createElement(
|
|
9008
9405
|
AtMentionSuggestions,
|
|
9009
9406
|
{
|
|
9010
9407
|
matches: atMatches,
|
|
9011
9408
|
selectedIndex: atSelected,
|
|
9012
9409
|
query: atPicker?.query ?? ""
|
|
9013
9410
|
}
|
|
9014
|
-
)
|
|
9411
|
+
), slashArgContext ? /* @__PURE__ */ React14.createElement(
|
|
9412
|
+
SlashArgPicker,
|
|
9413
|
+
{
|
|
9414
|
+
matches: slashArgMatches,
|
|
9415
|
+
selectedIndex: slashArgSelected,
|
|
9416
|
+
spec: slashArgContext.spec,
|
|
9417
|
+
kind: slashArgContext.kind,
|
|
9418
|
+
partial: slashArgContext.partial
|
|
9419
|
+
}
|
|
9420
|
+
) : null)));
|
|
9015
9421
|
}
|
|
9016
9422
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
9017
9423
|
function StatusRow({ text }) {
|
|
9018
9424
|
const tick = useTick();
|
|
9019
9425
|
const elapsed = useElapsedSeconds();
|
|
9020
|
-
return /* @__PURE__ */
|
|
9426
|
+
return /* @__PURE__ */ React14.createElement(Box13, { marginY: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React14.createElement(Text13, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` ${elapsed}s`));
|
|
9021
9427
|
}
|
|
9022
9428
|
function SubagentRow({
|
|
9023
9429
|
activity
|
|
9024
9430
|
}) {
|
|
9025
9431
|
const tick = useTick();
|
|
9026
9432
|
const seconds = (activity.elapsedMs / 1e3).toFixed(1);
|
|
9027
|
-
return /* @__PURE__ */
|
|
9433
|
+
return /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React14.createElement(Text13, { color: "magenta" }, ` \u232C subagent: ${activity.task}`), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
|
|
9028
9434
|
}
|
|
9029
9435
|
function OngoingToolRow({
|
|
9030
9436
|
tool,
|
|
@@ -9033,7 +9439,7 @@ function OngoingToolRow({
|
|
|
9033
9439
|
const tick = useTick();
|
|
9034
9440
|
const elapsed = useElapsedSeconds();
|
|
9035
9441
|
const summary = summarizeToolArgs(tool.name, tool.args);
|
|
9036
|
-
return /* @__PURE__ */
|
|
9442
|
+
return /* @__PURE__ */ React14.createElement(Box13, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React14.createElement(Text13, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React14.createElement(Box13, { paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, summary)) : null);
|
|
9037
9443
|
}
|
|
9038
9444
|
function renderProgressLine(p) {
|
|
9039
9445
|
const msg = p.message ? ` ${p.message}` : "";
|
|
@@ -9099,18 +9505,9 @@ function formatEditResults(results) {
|
|
|
9099
9505
|
return [header2, ...lines].join("\n");
|
|
9100
9506
|
}
|
|
9101
9507
|
function formatPendingPreview(blocks) {
|
|
9102
|
-
const lines = blocks.map((b) => {
|
|
9103
|
-
const removed = b.search === "" ? 0 : countLines2(b.search);
|
|
9104
|
-
const added = countLines2(b.replace);
|
|
9105
|
-
const tag = b.search === "" ? "NEW " : " ";
|
|
9106
|
-
return ` ${tag}${b.path} (-${removed} +${added} lines)`;
|
|
9107
|
-
});
|
|
9108
9508
|
const header2 = `\u25B8 ${blocks.length} pending edit block(s) \u2014 /apply (or y) to commit \xB7 /discard (or n) to drop`;
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
function countLines2(s) {
|
|
9112
|
-
if (s.length === 0) return 0;
|
|
9113
|
-
return (s.match(/\n/g)?.length ?? 0) + 1;
|
|
9509
|
+
const diffLines = formatAllBlockDiffs(blocks);
|
|
9510
|
+
return [header2, ...diffLines].join("\n");
|
|
9114
9511
|
}
|
|
9115
9512
|
function formatUndoResults(results) {
|
|
9116
9513
|
const lines = results.map((r) => {
|
|
@@ -9129,15 +9526,15 @@ function describeRepair(repair) {
|
|
|
9129
9526
|
}
|
|
9130
9527
|
|
|
9131
9528
|
// src/cli/ui/SessionPicker.tsx
|
|
9132
|
-
import { Box as
|
|
9133
|
-
import
|
|
9529
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
9530
|
+
import React15 from "react";
|
|
9134
9531
|
function SessionPicker({
|
|
9135
9532
|
sessionName,
|
|
9136
9533
|
messageCount,
|
|
9137
9534
|
lastActive,
|
|
9138
9535
|
onChoose
|
|
9139
9536
|
}) {
|
|
9140
|
-
return /* @__PURE__ */
|
|
9537
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text14, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, ` \xB7 last active ${relativeTime(lastActive)}`)), /* @__PURE__ */ React15.createElement(
|
|
9141
9538
|
SingleSelect,
|
|
9142
9539
|
{
|
|
9143
9540
|
initialValue: "new",
|
|
@@ -9160,7 +9557,7 @@ function SessionPicker({
|
|
|
9160
9557
|
],
|
|
9161
9558
|
onSubmit: (v) => onChoose(v)
|
|
9162
9559
|
}
|
|
9163
|
-
), /* @__PURE__ */
|
|
9560
|
+
), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "\u2191\u2193 to move \xB7 Enter to pick")));
|
|
9164
9561
|
}
|
|
9165
9562
|
function relativeTime(date) {
|
|
9166
9563
|
const ms = Date.now() - date.getTime();
|
|
@@ -9176,9 +9573,9 @@ function relativeTime(date) {
|
|
|
9176
9573
|
}
|
|
9177
9574
|
|
|
9178
9575
|
// src/cli/ui/Setup.tsx
|
|
9179
|
-
import { Box as
|
|
9576
|
+
import { Box as Box15, Text as Text15, useApp as useApp2 } from "ink";
|
|
9180
9577
|
import TextInput from "ink-text-input";
|
|
9181
|
-
import
|
|
9578
|
+
import React16, { useState as useState6 } from "react";
|
|
9182
9579
|
function Setup({ onReady }) {
|
|
9183
9580
|
const [value, setValue] = useState6("");
|
|
9184
9581
|
const [error, setError] = useState6(null);
|
|
@@ -9202,7 +9599,7 @@ function Setup({ onReady }) {
|
|
|
9202
9599
|
}
|
|
9203
9600
|
onReady(trimmed);
|
|
9204
9601
|
};
|
|
9205
|
-
return /* @__PURE__ */
|
|
9602
|
+
return /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text15, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text15, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React16.createElement(Text15, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React16.createElement(Text15, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text15, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React16.createElement(
|
|
9206
9603
|
TextInput,
|
|
9207
9604
|
{
|
|
9208
9605
|
value,
|
|
@@ -9211,7 +9608,7 @@ function Setup({ onReady }) {
|
|
|
9211
9608
|
mask: "\u2022",
|
|
9212
9609
|
placeholder: "sk-..."
|
|
9213
9610
|
}
|
|
9214
|
-
)), error ? /* @__PURE__ */
|
|
9611
|
+
)), error ? /* @__PURE__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text15, { color: "red" }, error)) : value ? /* @__PURE__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text15, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text15, { dimColor: true }, "(Type /exit to abort.)")));
|
|
9215
9612
|
}
|
|
9216
9613
|
|
|
9217
9614
|
// src/cli/commands/chat.tsx
|
|
@@ -9227,7 +9624,7 @@ function Root({
|
|
|
9227
9624
|
const [key, setKey] = useState7(initialKey);
|
|
9228
9625
|
const [pending, setPending] = useState7(sessionPreview);
|
|
9229
9626
|
if (!key) {
|
|
9230
|
-
return /* @__PURE__ */
|
|
9627
|
+
return /* @__PURE__ */ React17.createElement(
|
|
9231
9628
|
Setup,
|
|
9232
9629
|
{
|
|
9233
9630
|
onReady: (k) => {
|
|
@@ -9239,7 +9636,7 @@ function Root({
|
|
|
9239
9636
|
}
|
|
9240
9637
|
process.env.DEEPSEEK_API_KEY = key;
|
|
9241
9638
|
if (pending && appProps.session) {
|
|
9242
|
-
return /* @__PURE__ */
|
|
9639
|
+
return /* @__PURE__ */ React17.createElement(
|
|
9243
9640
|
SessionPicker,
|
|
9244
9641
|
{
|
|
9245
9642
|
sessionName: appProps.session,
|
|
@@ -9254,7 +9651,7 @@ function Root({
|
|
|
9254
9651
|
}
|
|
9255
9652
|
);
|
|
9256
9653
|
}
|
|
9257
|
-
return /* @__PURE__ */
|
|
9654
|
+
return /* @__PURE__ */ React17.createElement(
|
|
9258
9655
|
App,
|
|
9259
9656
|
{
|
|
9260
9657
|
model: appProps.model,
|
|
@@ -9357,7 +9754,7 @@ async function chatCommand(opts) {
|
|
|
9357
9754
|
rewriteSession(opts.session, []);
|
|
9358
9755
|
}
|
|
9359
9756
|
const { waitUntilExit } = render(
|
|
9360
|
-
/* @__PURE__ */
|
|
9757
|
+
/* @__PURE__ */ React17.createElement(
|
|
9361
9758
|
Root,
|
|
9362
9759
|
{
|
|
9363
9760
|
initialKey,
|
|
@@ -9420,34 +9817,34 @@ async function codeCommand(opts = {}) {
|
|
|
9420
9817
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
9421
9818
|
import { basename as basename2 } from "path";
|
|
9422
9819
|
import { render as render2 } from "ink";
|
|
9423
|
-
import
|
|
9820
|
+
import React20 from "react";
|
|
9424
9821
|
|
|
9425
9822
|
// src/cli/ui/DiffApp.tsx
|
|
9426
|
-
import { Box as
|
|
9427
|
-
import
|
|
9823
|
+
import { Box as Box17, Static as Static2, Text as Text17, useApp as useApp3, useInput as useInput5 } from "ink";
|
|
9824
|
+
import React19, { useState as useState8 } from "react";
|
|
9428
9825
|
|
|
9429
9826
|
// src/cli/ui/RecordView.tsx
|
|
9430
|
-
import { Box as
|
|
9431
|
-
import
|
|
9827
|
+
import { Box as Box16, Text as Text16 } from "ink";
|
|
9828
|
+
import React18 from "react";
|
|
9432
9829
|
function RecordView({ rec, compact = false }) {
|
|
9433
9830
|
const toolArgsMax = compact ? 120 : 200;
|
|
9434
9831
|
const toolContentMax = compact ? 200 : 400;
|
|
9435
9832
|
if (rec.role === "user") {
|
|
9436
|
-
return /* @__PURE__ */
|
|
9833
|
+
return /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React18.createElement(Text16, null, rec.content));
|
|
9437
9834
|
}
|
|
9438
9835
|
if (rec.role === "assistant_final") {
|
|
9439
|
-
return /* @__PURE__ */
|
|
9836
|
+
return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React18.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React18.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React18.createElement(Text16, null, rec.content) : /* @__PURE__ */ React18.createElement(Text16, { dimColor: true, italic: true }, "(tool-call response only)"));
|
|
9440
9837
|
}
|
|
9441
9838
|
if (rec.role === "tool") {
|
|
9442
|
-
return /* @__PURE__ */
|
|
9839
|
+
return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " args: ", truncate3(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2192 ", truncate3(rec.content, toolContentMax)));
|
|
9443
9840
|
}
|
|
9444
9841
|
if (rec.role === "error") {
|
|
9445
|
-
return /* @__PURE__ */
|
|
9842
|
+
return /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React18.createElement(Text16, { color: "red" }, rec.error ?? rec.content));
|
|
9446
9843
|
}
|
|
9447
9844
|
if (rec.role === "done" || rec.role === "assistant_delta") {
|
|
9448
9845
|
return null;
|
|
9449
9846
|
}
|
|
9450
|
-
return /* @__PURE__ */
|
|
9847
|
+
return /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, "[", rec.role, "] ", rec.content));
|
|
9451
9848
|
}
|
|
9452
9849
|
function CacheBadge({ usage }) {
|
|
9453
9850
|
const hit = usage.prompt_cache_hit_tokens ?? 0;
|
|
@@ -9456,7 +9853,7 @@ function CacheBadge({ usage }) {
|
|
|
9456
9853
|
if (total === 0) return null;
|
|
9457
9854
|
const pct2 = hit / total * 100;
|
|
9458
9855
|
const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
|
|
9459
|
-
return /* @__PURE__ */
|
|
9856
|
+
return /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React18.createElement(Text16, { color }, pct2.toFixed(1), "%"));
|
|
9460
9857
|
}
|
|
9461
9858
|
function truncate3(s, max) {
|
|
9462
9859
|
return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
|
|
@@ -9490,7 +9887,7 @@ function DiffApp({ report }) {
|
|
|
9490
9887
|
}
|
|
9491
9888
|
});
|
|
9492
9889
|
const pair = report.pairs[idx];
|
|
9493
|
-
return /* @__PURE__ */
|
|
9890
|
+
return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column" }, /* @__PURE__ */ React19.createElement(DiffHeader, { report }), /* @__PURE__ */ React19.createElement(Box17, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React19.createElement(Text17, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React19.createElement(Text17, null, pair ? /* @__PURE__ */ React19.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React19.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React19.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React19.createElement(Box17, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React19.createElement(Text17, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React19.createElement(Text17, null, pair.divergenceNote)) : null, /* @__PURE__ */ React19.createElement(Box17, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "j"), "/", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "k"), "/", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "N"), "/", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "g"), "/", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React19.createElement(Text17, { bold: true }, "q"), " ", "quit")));
|
|
9494
9891
|
}
|
|
9495
9892
|
function DiffHeader({ report }) {
|
|
9496
9893
|
const a = report.a;
|
|
@@ -9508,15 +9905,15 @@ function DiffHeader({ report }) {
|
|
|
9508
9905
|
} else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
|
|
9509
9906
|
prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
|
|
9510
9907
|
}
|
|
9511
|
-
return /* @__PURE__ */
|
|
9908
|
+
return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React19.createElement(Box17, { justifyContent: "space-between" }, /* @__PURE__ */ React19.createElement(Text17, null, /* @__PURE__ */ React19.createElement(Text17, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React19.createElement(Text17, { color: "blue" }, a.label), /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " vs B="), /* @__PURE__ */ React19.createElement(Text17, { color: "magenta" }, b.label)), /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React19.createElement(Box17, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React19.createElement(Text17, null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, "cache "), /* @__PURE__ */ React19.createElement(Text17, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React19.createElement(Text17, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React19.createElement(Text17, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React19.createElement(Text17, null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, "cost "), /* @__PURE__ */ React19.createElement(Text17, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React19.createElement(Text17, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React19.createElement(Text17, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React19.createElement(Text17, null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, "model calls "), /* @__PURE__ */ React19.createElement(Text17, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React19.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true, italic: true }, prefixLine)) : null);
|
|
9512
9909
|
}
|
|
9513
9910
|
function Pane({
|
|
9514
9911
|
label,
|
|
9515
9912
|
headerColor,
|
|
9516
9913
|
records
|
|
9517
9914
|
}) {
|
|
9518
|
-
return /* @__PURE__ */
|
|
9519
|
-
|
|
9915
|
+
return /* @__PURE__ */ React19.createElement(
|
|
9916
|
+
Box17,
|
|
9520
9917
|
{
|
|
9521
9918
|
flexDirection: "column",
|
|
9522
9919
|
flexGrow: 1,
|
|
@@ -9524,21 +9921,21 @@ function Pane({
|
|
|
9524
9921
|
borderStyle: "single",
|
|
9525
9922
|
borderColor: headerColor
|
|
9526
9923
|
},
|
|
9527
|
-
/* @__PURE__ */
|
|
9528
|
-
records.length === 0 ? /* @__PURE__ */
|
|
9924
|
+
/* @__PURE__ */ React19.createElement(Text17, { color: headerColor, bold: true }, label),
|
|
9925
|
+
records.length === 0 ? /* @__PURE__ */ React19.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React19.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React19.createElement(RecordView, { key, rec, compact: true }))
|
|
9529
9926
|
);
|
|
9530
9927
|
}
|
|
9531
9928
|
function KindBadge({ kind }) {
|
|
9532
9929
|
if (kind === "match") {
|
|
9533
|
-
return /* @__PURE__ */
|
|
9930
|
+
return /* @__PURE__ */ React19.createElement(Text17, { color: "green" }, "\u2713 match");
|
|
9534
9931
|
}
|
|
9535
9932
|
if (kind === "diverge") {
|
|
9536
|
-
return /* @__PURE__ */
|
|
9933
|
+
return /* @__PURE__ */ React19.createElement(Text17, { color: "yellow" }, "\u2605 diverge");
|
|
9537
9934
|
}
|
|
9538
9935
|
if (kind === "only_in_a") {
|
|
9539
|
-
return /* @__PURE__ */
|
|
9936
|
+
return /* @__PURE__ */ React19.createElement(Text17, { color: "blue" }, "\u2190 only in A");
|
|
9540
9937
|
}
|
|
9541
|
-
return /* @__PURE__ */
|
|
9938
|
+
return /* @__PURE__ */ React19.createElement(Text17, { color: "magenta" }, "\u2192 only in B");
|
|
9542
9939
|
}
|
|
9543
9940
|
function paneRecords(pair, side) {
|
|
9544
9941
|
if (!pair) return [];
|
|
@@ -9569,7 +9966,7 @@ markdown report written to ${opts.mdPath}`);
|
|
|
9569
9966
|
return;
|
|
9570
9967
|
}
|
|
9571
9968
|
if (wantTui) {
|
|
9572
|
-
const { waitUntilExit } = render2(
|
|
9969
|
+
const { waitUntilExit } = render2(React20.createElement(DiffApp, { report }), {
|
|
9573
9970
|
exitOnCtrlC: true,
|
|
9574
9971
|
patchConsole: false
|
|
9575
9972
|
});
|
|
@@ -9710,11 +10107,11 @@ function pad2(s, width) {
|
|
|
9710
10107
|
|
|
9711
10108
|
// src/cli/commands/replay.ts
|
|
9712
10109
|
import { render as render3 } from "ink";
|
|
9713
|
-
import
|
|
10110
|
+
import React22 from "react";
|
|
9714
10111
|
|
|
9715
10112
|
// src/cli/ui/ReplayApp.tsx
|
|
9716
|
-
import { Box as
|
|
9717
|
-
import
|
|
10113
|
+
import { Box as Box18, Static as Static3, Text as Text18, useApp as useApp4, useInput as useInput6 } from "ink";
|
|
10114
|
+
import React21, { useMemo as useMemo2, useState as useState9 } from "react";
|
|
9718
10115
|
function ReplayApp({ meta, pages }) {
|
|
9719
10116
|
const { exit } = useApp4();
|
|
9720
10117
|
const maxIdx = Math.max(0, pages.length - 1);
|
|
@@ -9753,14 +10150,14 @@ function ReplayApp({ meta, pages }) {
|
|
|
9753
10150
|
const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
|
|
9754
10151
|
const currentPage = pages[idx];
|
|
9755
10152
|
const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
|
|
9756
|
-
return /* @__PURE__ */
|
|
10153
|
+
return /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column" }, /* @__PURE__ */ React21.createElement(
|
|
9757
10154
|
StatsPanel,
|
|
9758
10155
|
{
|
|
9759
10156
|
summary,
|
|
9760
10157
|
model: cumStats.models[0] ?? meta?.model ?? "?",
|
|
9761
10158
|
prefixHash
|
|
9762
10159
|
}
|
|
9763
|
-
), /* @__PURE__ */
|
|
10160
|
+
), /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React21.createElement(Box18, { justifyContent: "space-between" }, /* @__PURE__ */ React21.createElement(Text18, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React21.createElement(Text18, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React21.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React21.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React21.createElement(Text18, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React21.createElement(Text18, { dimColor: true }, /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "j"), "/", /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "k"), "/", /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React21.createElement(Text18, { bold: true }, "q"), " quit")));
|
|
9764
10161
|
}
|
|
9765
10162
|
|
|
9766
10163
|
// src/cli/commands/replay.ts
|
|
@@ -9772,7 +10169,7 @@ async function replayCommand(opts) {
|
|
|
9772
10169
|
}
|
|
9773
10170
|
const { parsed } = replayFromFile(opts.path);
|
|
9774
10171
|
const pages = groupRecordsByTurn(parsed.records);
|
|
9775
|
-
const { waitUntilExit } = render3(
|
|
10172
|
+
const { waitUntilExit } = render3(React22.createElement(ReplayApp, { meta: parsed.meta, pages }), {
|
|
9776
10173
|
exitOnCtrlC: true,
|
|
9777
10174
|
patchConsole: false
|
|
9778
10175
|
});
|
|
@@ -10077,12 +10474,12 @@ function truncate4(s, max) {
|
|
|
10077
10474
|
|
|
10078
10475
|
// src/cli/commands/setup.tsx
|
|
10079
10476
|
import { render as render4 } from "ink";
|
|
10080
|
-
import
|
|
10477
|
+
import React24 from "react";
|
|
10081
10478
|
|
|
10082
10479
|
// src/cli/ui/Wizard.tsx
|
|
10083
|
-
import { Box as
|
|
10480
|
+
import { Box as Box19, Text as Text19, useApp as useApp5, useInput as useInput7 } from "ink";
|
|
10084
10481
|
import TextInput2 from "ink-text-input";
|
|
10085
|
-
import
|
|
10482
|
+
import React23, { useState as useState10 } from "react";
|
|
10086
10483
|
|
|
10087
10484
|
// src/cli/ui/presets.ts
|
|
10088
10485
|
var PRESETS = {
|
|
@@ -10121,7 +10518,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
10121
10518
|
if (key.escape && step !== "saved" && onCancel) onCancel();
|
|
10122
10519
|
});
|
|
10123
10520
|
if (step === "apiKey") {
|
|
10124
|
-
return /* @__PURE__ */
|
|
10521
|
+
return /* @__PURE__ */ React23.createElement(
|
|
10125
10522
|
ApiKeyStep,
|
|
10126
10523
|
{
|
|
10127
10524
|
onSubmit: (key) => {
|
|
@@ -10135,7 +10532,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
10135
10532
|
);
|
|
10136
10533
|
}
|
|
10137
10534
|
if (step === "preset") {
|
|
10138
|
-
return /* @__PURE__ */
|
|
10535
|
+
return /* @__PURE__ */ React23.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React23.createElement(
|
|
10139
10536
|
SingleSelect,
|
|
10140
10537
|
{
|
|
10141
10538
|
items: presetItems(),
|
|
@@ -10145,10 +10542,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
10145
10542
|
setStep("mcp");
|
|
10146
10543
|
}
|
|
10147
10544
|
}
|
|
10148
|
-
), /* @__PURE__ */
|
|
10545
|
+
), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
|
|
10149
10546
|
}
|
|
10150
10547
|
if (step === "mcp") {
|
|
10151
|
-
return /* @__PURE__ */
|
|
10548
|
+
return /* @__PURE__ */ React23.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React23.createElement(
|
|
10152
10549
|
MultiSelect,
|
|
10153
10550
|
{
|
|
10154
10551
|
items: mcpItems(),
|
|
@@ -10173,7 +10570,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
10173
10570
|
}
|
|
10174
10571
|
const currentName = pending[0];
|
|
10175
10572
|
const entry = CATALOG_BY_NAME.get(currentName);
|
|
10176
|
-
return /* @__PURE__ */
|
|
10573
|
+
return /* @__PURE__ */ React23.createElement(
|
|
10177
10574
|
McpArgsStep,
|
|
10178
10575
|
{
|
|
10179
10576
|
entry,
|
|
@@ -10191,7 +10588,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
10191
10588
|
}
|
|
10192
10589
|
if (step === "review") {
|
|
10193
10590
|
const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
|
|
10194
|
-
return /* @__PURE__ */
|
|
10591
|
+
return /* @__PURE__ */ React23.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React23.createElement(Box19, { flexDirection: "column" }, /* @__PURE__ */ React23.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React23.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React23.createElement(
|
|
10195
10592
|
SummaryLine,
|
|
10196
10593
|
{
|
|
10197
10594
|
label: "MCP",
|
|
@@ -10199,8 +10596,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
10199
10596
|
}
|
|
10200
10597
|
), specs.map((spec, i) => (
|
|
10201
10598
|
// biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
|
|
10202
|
-
/* @__PURE__ */
|
|
10203
|
-
)), /* @__PURE__ */
|
|
10599
|
+
/* @__PURE__ */ React23.createElement(Box19, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "\xB7 ", spec))
|
|
10600
|
+
)), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { color: "red" }, error)) : null, /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "enter save \xB7 esc cancel"))), /* @__PURE__ */ React23.createElement(
|
|
10204
10601
|
ReviewConfirm,
|
|
10205
10602
|
{
|
|
10206
10603
|
onConfirm: () => {
|
|
@@ -10226,7 +10623,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
10226
10623
|
}
|
|
10227
10624
|
));
|
|
10228
10625
|
}
|
|
10229
|
-
return /* @__PURE__ */
|
|
10626
|
+
return /* @__PURE__ */ React23.createElement(Box19, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React23.createElement(Text19, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "Press enter to exit.")), /* @__PURE__ */ React23.createElement(ExitOnEnter, { onExit: exit }));
|
|
10230
10627
|
}
|
|
10231
10628
|
function ApiKeyStep({
|
|
10232
10629
|
onSubmit,
|
|
@@ -10234,7 +10631,7 @@ function ApiKeyStep({
|
|
|
10234
10631
|
onError
|
|
10235
10632
|
}) {
|
|
10236
10633
|
const [value, setValue] = useState10("");
|
|
10237
|
-
return /* @__PURE__ */
|
|
10634
|
+
return /* @__PURE__ */ React23.createElement(Box19, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React23.createElement(Text19, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React23.createElement(
|
|
10238
10635
|
TextInput2,
|
|
10239
10636
|
{
|
|
10240
10637
|
value,
|
|
@@ -10251,7 +10648,7 @@ function ApiKeyStep({
|
|
|
10251
10648
|
mask: "\u2022",
|
|
10252
10649
|
placeholder: "sk-..."
|
|
10253
10650
|
}
|
|
10254
|
-
)), error ? /* @__PURE__ */
|
|
10651
|
+
)), error ? /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { color: "red" }, error)) : value ? /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "preview: ", redactKey(value))) : null);
|
|
10255
10652
|
}
|
|
10256
10653
|
function McpArgsStep({
|
|
10257
10654
|
entry,
|
|
@@ -10260,7 +10657,7 @@ function McpArgsStep({
|
|
|
10260
10657
|
onError
|
|
10261
10658
|
}) {
|
|
10262
10659
|
const [value, setValue] = useState10("");
|
|
10263
|
-
return /* @__PURE__ */
|
|
10660
|
+
return /* @__PURE__ */ React23.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React23.createElement(Box19, { flexDirection: "column" }, /* @__PURE__ */ React23.createElement(Text19, null, entry.summary), entry.note ? /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, null, "Required parameter: "), /* @__PURE__ */ React23.createElement(Text19, { bold: true }, entry.userArgs)), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React23.createElement(
|
|
10264
10661
|
TextInput2,
|
|
10265
10662
|
{
|
|
10266
10663
|
value,
|
|
@@ -10276,7 +10673,7 @@ function McpArgsStep({
|
|
|
10276
10673
|
},
|
|
10277
10674
|
placeholder: placeholderFor(entry)
|
|
10278
10675
|
}
|
|
10279
|
-
)), error ? /* @__PURE__ */
|
|
10676
|
+
)), error ? /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { color: "red" }, error)) : null));
|
|
10280
10677
|
}
|
|
10281
10678
|
function ReviewConfirm({ onConfirm }) {
|
|
10282
10679
|
useInput7((_i, key) => {
|
|
@@ -10296,10 +10693,10 @@ function StepFrame({
|
|
|
10296
10693
|
total,
|
|
10297
10694
|
children
|
|
10298
10695
|
}) {
|
|
10299
|
-
return /* @__PURE__ */
|
|
10696
|
+
return /* @__PURE__ */ React23.createElement(Box19, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React23.createElement(Box19, null, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React23.createElement(Text19, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React23.createElement(Box19, { marginTop: 1, flexDirection: "column" }, children));
|
|
10300
10697
|
}
|
|
10301
10698
|
function SummaryLine({ label, value }) {
|
|
10302
|
-
return /* @__PURE__ */
|
|
10699
|
+
return /* @__PURE__ */ React23.createElement(Box19, null, /* @__PURE__ */ React23.createElement(Text19, null, label.padEnd(12)), /* @__PURE__ */ React23.createElement(Text19, { bold: true }, value));
|
|
10303
10700
|
}
|
|
10304
10701
|
function presetItems() {
|
|
10305
10702
|
return ["fast", "smart", "max"].map((name) => ({
|
|
@@ -10355,7 +10752,7 @@ async function setupCommand(_opts = {}) {
|
|
|
10355
10752
|
const existingKey = loadApiKey();
|
|
10356
10753
|
const existing = readConfig();
|
|
10357
10754
|
const { waitUntilExit, unmount } = render4(
|
|
10358
|
-
/* @__PURE__ */
|
|
10755
|
+
/* @__PURE__ */ React24.createElement(
|
|
10359
10756
|
Wizard,
|
|
10360
10757
|
{
|
|
10361
10758
|
existingApiKey: existingKey,
|