reasonix 0.4.5 → 0.4.6
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 +388 -83
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +48 -1
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2276,6 +2276,9 @@ var McpClient = class {
|
|
|
2276
2276
|
readerStarted = false;
|
|
2277
2277
|
initialized = false;
|
|
2278
2278
|
_serverCapabilities = {};
|
|
2279
|
+
_serverInfo = { name: "", version: "" };
|
|
2280
|
+
_protocolVersion = "";
|
|
2281
|
+
_instructions;
|
|
2279
2282
|
constructor(opts) {
|
|
2280
2283
|
this.transport = opts.transport;
|
|
2281
2284
|
this.clientInfo = opts.clientInfo ?? { name: "reasonix", version: "0.3.0-dev" };
|
|
@@ -2285,6 +2288,18 @@ var McpClient = class {
|
|
|
2285
2288
|
get serverCapabilities() {
|
|
2286
2289
|
return this._serverCapabilities;
|
|
2287
2290
|
}
|
|
2291
|
+
/** Server's self-reported name + version, available after initialize(). */
|
|
2292
|
+
get serverInfo() {
|
|
2293
|
+
return this._serverInfo;
|
|
2294
|
+
}
|
|
2295
|
+
/** Protocol version the server agreed to during the handshake. */
|
|
2296
|
+
get protocolVersion() {
|
|
2297
|
+
return this._protocolVersion;
|
|
2298
|
+
}
|
|
2299
|
+
/** Optional free-form instructions the server provides at handshake. */
|
|
2300
|
+
get serverInstructions() {
|
|
2301
|
+
return this._instructions;
|
|
2302
|
+
}
|
|
2288
2303
|
/**
|
|
2289
2304
|
* Complete the initialize → initialized handshake. Must be called
|
|
2290
2305
|
* before any other method (otherwise compliant servers reject).
|
|
@@ -2303,6 +2318,9 @@ var McpClient = class {
|
|
|
2303
2318
|
clientInfo: this.clientInfo
|
|
2304
2319
|
});
|
|
2305
2320
|
this._serverCapabilities = result.capabilities ?? {};
|
|
2321
|
+
this._serverInfo = result.serverInfo ?? { name: "", version: "" };
|
|
2322
|
+
this._protocolVersion = result.protocolVersion ?? "";
|
|
2323
|
+
this._instructions = result.instructions;
|
|
2306
2324
|
await this.transport.send({
|
|
2307
2325
|
jsonrpc: "2.0",
|
|
2308
2326
|
method: "notifications/initialized"
|
|
@@ -2750,6 +2768,36 @@ function parseMcpSpec(input) {
|
|
|
2750
2768
|
return { transport: "stdio", name, command, args };
|
|
2751
2769
|
}
|
|
2752
2770
|
|
|
2771
|
+
// src/mcp/inspect.ts
|
|
2772
|
+
async function inspectMcpServer(client) {
|
|
2773
|
+
const tools = await trySection(() => client.listTools().then((r) => r.tools));
|
|
2774
|
+
const resources = await trySection(
|
|
2775
|
+
() => client.listResources().then((r) => r.resources)
|
|
2776
|
+
);
|
|
2777
|
+
const prompts = await trySection(() => client.listPrompts().then((r) => r.prompts));
|
|
2778
|
+
return {
|
|
2779
|
+
protocolVersion: client.protocolVersion || "(unknown)",
|
|
2780
|
+
serverInfo: client.serverInfo,
|
|
2781
|
+
capabilities: client.serverCapabilities ?? {},
|
|
2782
|
+
instructions: client.serverInstructions,
|
|
2783
|
+
tools,
|
|
2784
|
+
resources,
|
|
2785
|
+
prompts
|
|
2786
|
+
};
|
|
2787
|
+
}
|
|
2788
|
+
async function trySection(load) {
|
|
2789
|
+
try {
|
|
2790
|
+
const items = await load();
|
|
2791
|
+
return { supported: true, items };
|
|
2792
|
+
} catch (err) {
|
|
2793
|
+
const msg = err.message ?? String(err);
|
|
2794
|
+
if (/-32601/.test(msg) || /method not found/i.test(msg)) {
|
|
2795
|
+
return { supported: false, reason: "method not found (-32601)" };
|
|
2796
|
+
}
|
|
2797
|
+
return { supported: false, reason: msg };
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2753
2801
|
// src/code/edit-blocks.ts
|
|
2754
2802
|
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2755
2803
|
import { dirname as dirname3, resolve as resolve2 } from "path";
|
|
@@ -2880,11 +2928,11 @@ var VERSION = "0.4.3";
|
|
|
2880
2928
|
|
|
2881
2929
|
// src/cli/commands/chat.tsx
|
|
2882
2930
|
import { render } from "ink";
|
|
2883
|
-
import
|
|
2931
|
+
import React9, { useState as useState4 } from "react";
|
|
2884
2932
|
|
|
2885
2933
|
// src/cli/ui/App.tsx
|
|
2886
|
-
import { Box as
|
|
2887
|
-
import
|
|
2934
|
+
import { Box as Box7, Static, Text as Text7, useApp, useInput } from "ink";
|
|
2935
|
+
import React7, { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useState2 } from "react";
|
|
2888
2936
|
|
|
2889
2937
|
// src/cli/ui/EventLog.tsx
|
|
2890
2938
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
@@ -3246,9 +3294,38 @@ function PromptInput({
|
|
|
3246
3294
|
));
|
|
3247
3295
|
}
|
|
3248
3296
|
|
|
3249
|
-
// src/cli/ui/
|
|
3297
|
+
// src/cli/ui/SlashSuggestions.tsx
|
|
3250
3298
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
3251
3299
|
import React5 from "react";
|
|
3300
|
+
function SlashSuggestions({
|
|
3301
|
+
matches,
|
|
3302
|
+
selectedIndex
|
|
3303
|
+
}) {
|
|
3304
|
+
if (matches === null) return null;
|
|
3305
|
+
if (matches.length === 0) {
|
|
3306
|
+
return /* @__PURE__ */ React5.createElement(Box5, { paddingX: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
|
|
3307
|
+
}
|
|
3308
|
+
const MAX = 8;
|
|
3309
|
+
const total = matches.length;
|
|
3310
|
+
const windowStart = total <= MAX ? 0 : Math.max(0, Math.min(selectedIndex - Math.floor(MAX / 2), total - MAX));
|
|
3311
|
+
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
3312
|
+
const hiddenAbove = windowStart;
|
|
3313
|
+
const hiddenBelow = total - windowStart - shown.length;
|
|
3314
|
+
return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React5.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2191/\u2193 navigate \xB7 Tab or Enter to pick"));
|
|
3315
|
+
}
|
|
3316
|
+
function SuggestionRow({ spec, isSelected }) {
|
|
3317
|
+
const marker = isSelected ? "\u25B8" : " ";
|
|
3318
|
+
const name = `/${spec.cmd}`;
|
|
3319
|
+
const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
|
|
3320
|
+
if (isSelected) {
|
|
3321
|
+
return /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, " ", spec.summary));
|
|
3322
|
+
}
|
|
3323
|
+
return /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3326
|
+
// src/cli/ui/StatsPanel.tsx
|
|
3327
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
3328
|
+
import React6 from "react";
|
|
3252
3329
|
function StatsPanel({
|
|
3253
3330
|
summary,
|
|
3254
3331
|
model,
|
|
@@ -3262,7 +3339,7 @@ function StatsPanel({
|
|
|
3262
3339
|
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model] ?? DEFAULT_CONTEXT_TOKENS;
|
|
3263
3340
|
const ctxRatio = summary.lastPromptTokens / ctxMax;
|
|
3264
3341
|
const ctxColor = ctxRatio >= 0.8 ? "red" : ctxRatio >= 0.5 ? "yellow" : void 0;
|
|
3265
|
-
return /* @__PURE__ */
|
|
3342
|
+
return /* @__PURE__ */ React6.createElement(Box6, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React6.createElement(Box6, { justifyContent: "space-between" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "Reasonix"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 model "), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, model), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 prefix "), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, prefixHash), harvestOn ? /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, " \xB7 branch", branchBudget) : null), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "turns ", summary.turns, " \xB7 type /help")), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "cache hit "), /* @__PURE__ */ React6.createElement(Text6, { color: hitColor, bold: true }, hitPct, "%")), /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "cost "), /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, "$", summary.totalCostUsd.toFixed(6))), /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "vs Claude "), /* @__PURE__ */ React6.createElement(Text6, null, "$", summary.claudeEquivalentUsd.toFixed(6))), /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "saving "), /* @__PURE__ */ React6.createElement(Text6, { color: "green", bold: true }, summary.savingsVsClaudePct.toFixed(1), "%")), summary.lastPromptTokens > 0 ? /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "ctx "), /* @__PURE__ */ React6.createElement(Text6, { color: ctxColor, bold: ctxColor !== void 0 }, formatTokens(summary.lastPromptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (", (ctxRatio * 100).toFixed(0), "%)"), ctxRatio >= 0.8 ? /* @__PURE__ */ React6.createElement(Text6, { color: "red", bold: true }, " ", "\xB7 /compact") : null) : null));
|
|
3266
3343
|
}
|
|
3267
3344
|
function formatTokens(n) {
|
|
3268
3345
|
if (n < 1e3) return String(n);
|
|
@@ -3272,6 +3349,45 @@ function formatTokens(n) {
|
|
|
3272
3349
|
|
|
3273
3350
|
// src/cli/ui/slash.ts
|
|
3274
3351
|
import { spawnSync } from "child_process";
|
|
3352
|
+
var SLASH_COMMANDS = [
|
|
3353
|
+
{ cmd: "help", summary: "show the full command reference" },
|
|
3354
|
+
{ cmd: "status", summary: "current model, flags, context, session" },
|
|
3355
|
+
{
|
|
3356
|
+
cmd: "preset",
|
|
3357
|
+
argsHint: "<fast|smart|max>",
|
|
3358
|
+
summary: "one-tap model + harvest + branch bundle"
|
|
3359
|
+
},
|
|
3360
|
+
{ cmd: "model", argsHint: "<id>", summary: "switch DeepSeek model id" },
|
|
3361
|
+
{ cmd: "harvest", argsHint: "[on|off]", summary: "toggle Pillar-2 plan-state extraction" },
|
|
3362
|
+
{ cmd: "branch", argsHint: "<N|off>", summary: "run N parallel samples per turn (N>=2)" },
|
|
3363
|
+
{ cmd: "mcp", summary: "list MCP servers + tools attached to this session" },
|
|
3364
|
+
{ cmd: "tool", argsHint: "[N]", summary: "dump full output of the Nth tool call (1=latest)" },
|
|
3365
|
+
{ cmd: "think", summary: "dump the last turn's full R1 reasoning (reasoner only)" },
|
|
3366
|
+
{ cmd: "retry", summary: "truncate & resend your last message (fresh sample)" },
|
|
3367
|
+
{ cmd: "compact", argsHint: "[cap]", summary: "shrink oversized tool results in the log" },
|
|
3368
|
+
{ cmd: "sessions", summary: "list saved sessions (current marked with \u25B8)" },
|
|
3369
|
+
{ cmd: "forget", summary: "delete the current session from disk" },
|
|
3370
|
+
{ cmd: "setup", summary: "reminds you to exit and run `reasonix setup`" },
|
|
3371
|
+
{ cmd: "clear", summary: "clear the visible scrollback (log + session kept)" },
|
|
3372
|
+
{ cmd: "exit", summary: "quit the TUI" },
|
|
3373
|
+
// Code-mode only
|
|
3374
|
+
{ cmd: "apply", summary: "commit pending edit blocks to disk", contextual: "code" },
|
|
3375
|
+
{ cmd: "discard", summary: "drop pending edit blocks without writing", contextual: "code" },
|
|
3376
|
+
{ cmd: "undo", summary: "roll back the last applied edit batch", contextual: "code" },
|
|
3377
|
+
{
|
|
3378
|
+
cmd: "commit",
|
|
3379
|
+
argsHint: '"msg"',
|
|
3380
|
+
summary: "git add -A && git commit -m ...",
|
|
3381
|
+
contextual: "code"
|
|
3382
|
+
}
|
|
3383
|
+
];
|
|
3384
|
+
function suggestSlashCommands(prefix, codeMode = false) {
|
|
3385
|
+
const p = prefix.toLowerCase();
|
|
3386
|
+
return SLASH_COMMANDS.filter((c) => {
|
|
3387
|
+
if (c.contextual === "code" && !codeMode) return false;
|
|
3388
|
+
return c.cmd.startsWith(p);
|
|
3389
|
+
});
|
|
3390
|
+
}
|
|
3275
3391
|
function parseSlash(text) {
|
|
3276
3392
|
if (!text.startsWith("/")) return null;
|
|
3277
3393
|
const parts = text.slice(1).trim().split(/\s+/);
|
|
@@ -3323,13 +3439,34 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
3323
3439
|
].join("\n")
|
|
3324
3440
|
};
|
|
3325
3441
|
case "mcp": {
|
|
3442
|
+
const servers = ctx.mcpServers ?? [];
|
|
3326
3443
|
const specs = ctx.mcpSpecs ?? [];
|
|
3327
3444
|
const toolSpecs = loop.prefix.toolSpecs ?? [];
|
|
3328
|
-
if (specs.length === 0 && toolSpecs.length === 0) {
|
|
3445
|
+
if (servers.length === 0 && specs.length === 0 && toolSpecs.length === 0) {
|
|
3329
3446
|
return {
|
|
3330
3447
|
info: 'no MCP servers attached. Run `reasonix setup` to pick some, or launch with --mcp "<spec>". `reasonix mcp list` shows the catalog.'
|
|
3331
3448
|
};
|
|
3332
3449
|
}
|
|
3450
|
+
if (servers.length > 0) {
|
|
3451
|
+
const lines2 = [];
|
|
3452
|
+
for (const s of servers) {
|
|
3453
|
+
const { report } = s;
|
|
3454
|
+
const serverName = report.serverInfo.name || "(unknown)";
|
|
3455
|
+
const serverVer = report.serverInfo.version ? ` v${report.serverInfo.version}` : "";
|
|
3456
|
+
lines2.push(`[${s.label}] ${serverName}${serverVer} \u2014 ${s.spec}`);
|
|
3457
|
+
lines2.push(` tools ${s.toolCount}`);
|
|
3458
|
+
appendSection(lines2, "resources", report.resources);
|
|
3459
|
+
appendSection(lines2, "prompts ", report.prompts);
|
|
3460
|
+
lines2.push("");
|
|
3461
|
+
}
|
|
3462
|
+
lines2.push(
|
|
3463
|
+
"Chat mode consumes tools today; resources+prompts are surfaced here for awareness."
|
|
3464
|
+
);
|
|
3465
|
+
lines2.push(
|
|
3466
|
+
"Full catalog: `reasonix mcp list` \xB7 deeper diagnosis: `reasonix mcp inspect <spec>`."
|
|
3467
|
+
);
|
|
3468
|
+
return { info: lines2.join("\n") };
|
|
3469
|
+
}
|
|
3333
3470
|
const lines = [];
|
|
3334
3471
|
if (specs.length > 0) {
|
|
3335
3472
|
lines.push(`MCP servers (${specs.length}):`);
|
|
@@ -3559,6 +3696,22 @@ ${entry.text}`
|
|
|
3559
3696
|
return { unknown: true, info: `unknown command: /${cmd} (try /help)` };
|
|
3560
3697
|
}
|
|
3561
3698
|
}
|
|
3699
|
+
function appendSection(lines, label, section) {
|
|
3700
|
+
if (!section || !section.supported) {
|
|
3701
|
+
lines.push(
|
|
3702
|
+
` ${label.trim()} ${section?.supported === false ? "(not supported)" : "(none)"}`
|
|
3703
|
+
);
|
|
3704
|
+
return;
|
|
3705
|
+
}
|
|
3706
|
+
const names = section.items.map((i) => i.name);
|
|
3707
|
+
if (names.length === 0) {
|
|
3708
|
+
lines.push(` ${label.trim()} (none)`);
|
|
3709
|
+
return;
|
|
3710
|
+
}
|
|
3711
|
+
const head = names.slice(0, 5).join(", ");
|
|
3712
|
+
const more = names.length > 5 ? ` +${names.length - 5} more` : "";
|
|
3713
|
+
lines.push(` ${label.trim()} ${names.length} [${head}${more}]`);
|
|
3714
|
+
}
|
|
3562
3715
|
function formatToolList(history) {
|
|
3563
3716
|
const total = history.length;
|
|
3564
3717
|
const header = `Tool calls in this session (${total}, most recent first):`;
|
|
@@ -3631,6 +3784,7 @@ function App({
|
|
|
3631
3784
|
session,
|
|
3632
3785
|
tools,
|
|
3633
3786
|
mcpSpecs,
|
|
3787
|
+
mcpServers,
|
|
3634
3788
|
codeMode
|
|
3635
3789
|
}) {
|
|
3636
3790
|
const { exit } = useApp();
|
|
@@ -3645,6 +3799,7 @@ function App({
|
|
|
3645
3799
|
const promptHistory = useRef([]);
|
|
3646
3800
|
const historyCursor = useRef(-1);
|
|
3647
3801
|
const toolHistoryRef = useRef([]);
|
|
3802
|
+
const [slashSelected, setSlashSelected] = useState2(0);
|
|
3648
3803
|
const [summary, setSummary] = useState2({
|
|
3649
3804
|
turns: 0,
|
|
3650
3805
|
totalCostUsd: 0,
|
|
@@ -3667,6 +3822,17 @@ function App({
|
|
|
3667
3822
|
transcriptRef.current?.end();
|
|
3668
3823
|
};
|
|
3669
3824
|
}, []);
|
|
3825
|
+
const slashMatches = useMemo(() => {
|
|
3826
|
+
if (!input.startsWith("/") || input.includes(" ")) return null;
|
|
3827
|
+
return suggestSlashCommands(input.slice(1), !!codeMode);
|
|
3828
|
+
}, [input, codeMode]);
|
|
3829
|
+
useEffect2(() => {
|
|
3830
|
+
setSlashSelected((prev) => {
|
|
3831
|
+
if (!slashMatches || slashMatches.length === 0) return 0;
|
|
3832
|
+
if (prev >= slashMatches.length) return slashMatches.length - 1;
|
|
3833
|
+
return prev;
|
|
3834
|
+
});
|
|
3835
|
+
}, [slashMatches]);
|
|
3670
3836
|
const loopRef = useRef(null);
|
|
3671
3837
|
const loop = useMemo(() => {
|
|
3672
3838
|
if (loopRef.current) return loopRef.current;
|
|
@@ -3720,6 +3886,21 @@ function App({
|
|
|
3720
3886
|
return;
|
|
3721
3887
|
}
|
|
3722
3888
|
if (busy) return;
|
|
3889
|
+
if (slashMatches && slashMatches.length > 0) {
|
|
3890
|
+
if (key.upArrow) {
|
|
3891
|
+
setSlashSelected((i) => Math.max(0, i - 1));
|
|
3892
|
+
return;
|
|
3893
|
+
}
|
|
3894
|
+
if (key.downArrow) {
|
|
3895
|
+
setSlashSelected((i) => Math.min(slashMatches.length - 1, i + 1));
|
|
3896
|
+
return;
|
|
3897
|
+
}
|
|
3898
|
+
if (key.tab) {
|
|
3899
|
+
const sel = slashMatches[slashSelected] ?? slashMatches[0];
|
|
3900
|
+
if (sel) setInput(`/${sel.cmd}`);
|
|
3901
|
+
return;
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3723
3904
|
const hist = promptHistory.current;
|
|
3724
3905
|
if (key.upArrow) {
|
|
3725
3906
|
if (hist.length === 0) return;
|
|
@@ -3778,6 +3959,15 @@ function App({
|
|
|
3778
3959
|
async (raw) => {
|
|
3779
3960
|
let text = raw.trim();
|
|
3780
3961
|
if (!text || busy) return;
|
|
3962
|
+
if (text.startsWith("/") && !text.includes(" ")) {
|
|
3963
|
+
const typed = text.slice(1).toLowerCase();
|
|
3964
|
+
const matches = suggestSlashCommands(typed, !!codeMode);
|
|
3965
|
+
const exact = matches.find((m) => m.cmd === typed);
|
|
3966
|
+
if (!exact && matches.length > 0) {
|
|
3967
|
+
const chosen = matches[slashSelected] ?? matches[0];
|
|
3968
|
+
if (chosen) text = `/${chosen.cmd}`;
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3781
3971
|
setInput("");
|
|
3782
3972
|
historyCursor.current = -1;
|
|
3783
3973
|
if (codeMode && pendingEdits.current.length > 0 && (text === "y" || text === "n")) {
|
|
@@ -3790,6 +3980,7 @@ function App({
|
|
|
3790
3980
|
if (slash) {
|
|
3791
3981
|
const result = handleSlash(slash.cmd, slash.args, loop, {
|
|
3792
3982
|
mcpSpecs,
|
|
3983
|
+
mcpServers,
|
|
3793
3984
|
codeUndo: codeMode ? codeUndo : void 0,
|
|
3794
3985
|
codeApply: codeMode ? codeApply : void 0,
|
|
3795
3986
|
codeDiscard: codeMode ? codeDiscard : void 0,
|
|
@@ -3942,9 +4133,21 @@ function App({
|
|
|
3942
4133
|
setBusy(false);
|
|
3943
4134
|
}
|
|
3944
4135
|
},
|
|
3945
|
-
[
|
|
4136
|
+
[
|
|
4137
|
+
busy,
|
|
4138
|
+
codeApply,
|
|
4139
|
+
codeDiscard,
|
|
4140
|
+
codeMode,
|
|
4141
|
+
codeUndo,
|
|
4142
|
+
exit,
|
|
4143
|
+
loop,
|
|
4144
|
+
mcpSpecs,
|
|
4145
|
+
mcpServers,
|
|
4146
|
+
slashSelected,
|
|
4147
|
+
writeTranscript
|
|
4148
|
+
]
|
|
3946
4149
|
);
|
|
3947
|
-
return /* @__PURE__ */
|
|
4150
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(
|
|
3948
4151
|
StatsPanel,
|
|
3949
4152
|
{
|
|
3950
4153
|
summary,
|
|
@@ -3953,7 +4156,7 @@ function App({
|
|
|
3953
4156
|
harvestOn: loop.harvestEnabled,
|
|
3954
4157
|
branchBudget: loop.branchOptions.budget
|
|
3955
4158
|
}
|
|
3956
|
-
), /* @__PURE__ */
|
|
4159
|
+
), /* @__PURE__ */ React7.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React7.createElement(EventRow, { key: item.id, event: item })), streaming ? /* @__PURE__ */ React7.createElement(Box7, { marginY: 1 }, /* @__PURE__ */ React7.createElement(EventRow, { event: streaming })) : null, ongoingTool ? /* @__PURE__ */ React7.createElement(OngoingToolRow, { tool: ongoingTool }) : null, /* @__PURE__ */ React7.createElement(PromptInput, { value: input, onChange: setInput, onSubmit: handleSubmit, disabled: busy }), /* @__PURE__ */ React7.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }));
|
|
3957
4160
|
}
|
|
3958
4161
|
function OngoingToolRow({ tool }) {
|
|
3959
4162
|
const [tick, setTick] = useState2(0);
|
|
@@ -3969,7 +4172,7 @@ function OngoingToolRow({ tool }) {
|
|
|
3969
4172
|
}, []);
|
|
3970
4173
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3971
4174
|
const summary = summarizeToolArgs(tool.name, tool.args);
|
|
3972
|
-
return /* @__PURE__ */
|
|
4175
|
+
return /* @__PURE__ */ React7.createElement(Box7, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, frames[tick % frames.length]), /* @__PURE__ */ React7.createElement(Text7, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, ` ${elapsed}s`)), summary ? /* @__PURE__ */ React7.createElement(Box7, { paddingLeft: 2 }, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, summary)) : null);
|
|
3973
4176
|
}
|
|
3974
4177
|
function summarizeToolArgs(name, args) {
|
|
3975
4178
|
if (!args || args === "{}") return "";
|
|
@@ -4011,9 +4214,6 @@ function summarizeToolArgs(name, args) {
|
|
|
4011
4214
|
}
|
|
4012
4215
|
return args.length > 80 ? `${args.slice(0, 80)}\u2026` : args;
|
|
4013
4216
|
}
|
|
4014
|
-
function CommandStrip({ codeMode }) {
|
|
4015
|
-
return /* @__PURE__ */ React6.createElement(Box6, { paddingX: 2, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "/help \xB7 /preset ", "<fast|smart|max>", " \xB7 /mcp \xB7 /compact \xB7 /sessions \xB7 /setup \xB7 /clear \xB7 /exit"), codeMode ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, 'code mode: /apply (y) \xB7 /discard (n) \xB7 /undo \xB7 /commit "msg" \u2014 edits NEVER write without /apply') : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\u2191/\u2193 recall prompts \xB7 /retry re-send last \xB7 /think see R1 reasoning \xB7 /tool N full tool output"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "Esc (while thinking) \u2014 abort & summarize what was found so far"));
|
|
4016
|
-
}
|
|
4017
4217
|
function formatEditResults(results) {
|
|
4018
4218
|
const lines = results.map((r) => {
|
|
4019
4219
|
const mark = r.status === "applied" || r.status === "created" ? "\u2713" : "\u2717";
|
|
@@ -4056,9 +4256,9 @@ function describeRepair(repair) {
|
|
|
4056
4256
|
}
|
|
4057
4257
|
|
|
4058
4258
|
// src/cli/ui/Setup.tsx
|
|
4059
|
-
import { Box as
|
|
4259
|
+
import { Box as Box8, Text as Text8, useApp as useApp2 } from "ink";
|
|
4060
4260
|
import TextInput2 from "ink-text-input";
|
|
4061
|
-
import
|
|
4261
|
+
import React8, { useState as useState3 } from "react";
|
|
4062
4262
|
function Setup({ onReady }) {
|
|
4063
4263
|
const [value, setValue] = useState3("");
|
|
4064
4264
|
const [error, setError] = useState3(null);
|
|
@@ -4082,7 +4282,7 @@ function Setup({ onReady }) {
|
|
|
4082
4282
|
}
|
|
4083
4283
|
onReady(trimmed);
|
|
4084
4284
|
};
|
|
4085
|
-
return /* @__PURE__ */
|
|
4285
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React8.createElement(
|
|
4086
4286
|
TextInput2,
|
|
4087
4287
|
{
|
|
4088
4288
|
value,
|
|
@@ -4091,14 +4291,14 @@ function Setup({ onReady }) {
|
|
|
4091
4291
|
mask: "\u2022",
|
|
4092
4292
|
placeholder: "sk-..."
|
|
4093
4293
|
}
|
|
4094
|
-
)), error ? /* @__PURE__ */
|
|
4294
|
+
)), error ? /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, error)) : value ? /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React8.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "(Type /exit to abort.)")));
|
|
4095
4295
|
}
|
|
4096
4296
|
|
|
4097
4297
|
// src/cli/commands/chat.tsx
|
|
4098
|
-
function Root({ initialKey, tools, mcpSpecs, ...appProps }) {
|
|
4298
|
+
function Root({ initialKey, tools, mcpSpecs, mcpServers, ...appProps }) {
|
|
4099
4299
|
const [key, setKey] = useState4(initialKey);
|
|
4100
4300
|
if (!key) {
|
|
4101
|
-
return /* @__PURE__ */
|
|
4301
|
+
return /* @__PURE__ */ React9.createElement(
|
|
4102
4302
|
Setup,
|
|
4103
4303
|
{
|
|
4104
4304
|
onReady: (k) => {
|
|
@@ -4109,7 +4309,7 @@ function Root({ initialKey, tools, mcpSpecs, ...appProps }) {
|
|
|
4109
4309
|
);
|
|
4110
4310
|
}
|
|
4111
4311
|
process.env.DEEPSEEK_API_KEY = key;
|
|
4112
|
-
return /* @__PURE__ */
|
|
4312
|
+
return /* @__PURE__ */ React9.createElement(
|
|
4113
4313
|
App,
|
|
4114
4314
|
{
|
|
4115
4315
|
model: appProps.model,
|
|
@@ -4120,6 +4320,7 @@ function Root({ initialKey, tools, mcpSpecs, ...appProps }) {
|
|
|
4120
4320
|
session: appProps.session,
|
|
4121
4321
|
tools,
|
|
4122
4322
|
mcpSpecs,
|
|
4323
|
+
mcpServers,
|
|
4123
4324
|
codeMode: appProps.codeMode
|
|
4124
4325
|
}
|
|
4125
4326
|
);
|
|
@@ -4131,6 +4332,7 @@ async function chatCommand(opts) {
|
|
|
4131
4332
|
const clients = [];
|
|
4132
4333
|
const successfulSpecs = [];
|
|
4133
4334
|
const failedSpecs = [];
|
|
4335
|
+
const mcpServers = [];
|
|
4134
4336
|
let tools;
|
|
4135
4337
|
if (requestedSpecs.length > 0) {
|
|
4136
4338
|
tools = new ToolRegistry();
|
|
@@ -4142,6 +4344,19 @@ async function chatCommand(opts) {
|
|
|
4142
4344
|
const mcp2 = new McpClient({ transport });
|
|
4143
4345
|
await mcp2.initialize();
|
|
4144
4346
|
const bridge = await bridgeMcpTools(mcp2, { registry: tools, namePrefix: prefix });
|
|
4347
|
+
let report;
|
|
4348
|
+
try {
|
|
4349
|
+
report = await inspectMcpServer(mcp2);
|
|
4350
|
+
} catch {
|
|
4351
|
+
report = {
|
|
4352
|
+
protocolVersion: mcp2.protocolVersion,
|
|
4353
|
+
serverInfo: mcp2.serverInfo,
|
|
4354
|
+
capabilities: mcp2.serverCapabilities ?? {},
|
|
4355
|
+
tools: { supported: true, items: [] },
|
|
4356
|
+
resources: { supported: false, reason: "inspect failed" },
|
|
4357
|
+
prompts: { supported: false, reason: "inspect failed" }
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4145
4360
|
const label = spec.name ?? "anon";
|
|
4146
4361
|
const source = spec.transport === "sse" ? spec.url : `${spec.command} ${spec.args.join(" ")}`;
|
|
4147
4362
|
process.stderr.write(
|
|
@@ -4150,6 +4365,12 @@ async function chatCommand(opts) {
|
|
|
4150
4365
|
);
|
|
4151
4366
|
clients.push(mcp2);
|
|
4152
4367
|
successfulSpecs.push(raw);
|
|
4368
|
+
mcpServers.push({
|
|
4369
|
+
label,
|
|
4370
|
+
spec: raw,
|
|
4371
|
+
toolCount: bridge.registeredNames.length,
|
|
4372
|
+
report
|
|
4373
|
+
});
|
|
4153
4374
|
} catch (err) {
|
|
4154
4375
|
const reason = err.message;
|
|
4155
4376
|
failedSpecs.push({ spec: raw, reason });
|
|
@@ -4166,7 +4387,16 @@ async function chatCommand(opts) {
|
|
|
4166
4387
|
}
|
|
4167
4388
|
const mcpSpecs = successfulSpecs;
|
|
4168
4389
|
const { waitUntilExit } = render(
|
|
4169
|
-
/* @__PURE__ */
|
|
4390
|
+
/* @__PURE__ */ React9.createElement(
|
|
4391
|
+
Root,
|
|
4392
|
+
{
|
|
4393
|
+
initialKey,
|
|
4394
|
+
tools,
|
|
4395
|
+
mcpSpecs,
|
|
4396
|
+
mcpServers,
|
|
4397
|
+
...opts
|
|
4398
|
+
}
|
|
4399
|
+
),
|
|
4170
4400
|
{ exitOnCtrlC: true }
|
|
4171
4401
|
);
|
|
4172
4402
|
try {
|
|
@@ -4206,34 +4436,34 @@ function quoteIfNeeded(s) {
|
|
|
4206
4436
|
import { writeFileSync as writeFileSync4 } from "fs";
|
|
4207
4437
|
import { basename as basename2 } from "path";
|
|
4208
4438
|
import { render as render2 } from "ink";
|
|
4209
|
-
import
|
|
4439
|
+
import React12 from "react";
|
|
4210
4440
|
|
|
4211
4441
|
// src/cli/ui/DiffApp.tsx
|
|
4212
|
-
import { Box as
|
|
4213
|
-
import
|
|
4442
|
+
import { Box as Box10, Static as Static2, Text as Text10, useApp as useApp3, useInput as useInput2 } from "ink";
|
|
4443
|
+
import React11, { useState as useState5 } from "react";
|
|
4214
4444
|
|
|
4215
4445
|
// src/cli/ui/RecordView.tsx
|
|
4216
|
-
import { Box as
|
|
4217
|
-
import
|
|
4446
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
4447
|
+
import React10 from "react";
|
|
4218
4448
|
function RecordView({ rec, compact = false }) {
|
|
4219
4449
|
const toolArgsMax = compact ? 120 : 200;
|
|
4220
4450
|
const toolContentMax = compact ? 200 : 400;
|
|
4221
4451
|
if (rec.role === "user") {
|
|
4222
|
-
return /* @__PURE__ */
|
|
4452
|
+
return /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React10.createElement(Text9, null, rec.content));
|
|
4223
4453
|
}
|
|
4224
4454
|
if (rec.role === "assistant_final") {
|
|
4225
|
-
return /* @__PURE__ */
|
|
4455
|
+
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React10.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React10.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React10.createElement(Text9, null, rec.content) : /* @__PURE__ */ React10.createElement(Text9, { dimColor: true, italic: true }, "(tool-call response only)"));
|
|
4226
4456
|
}
|
|
4227
4457
|
if (rec.role === "tool") {
|
|
4228
|
-
return /* @__PURE__ */
|
|
4458
|
+
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " args: ", truncate3(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2192 ", truncate3(rec.content, toolContentMax)));
|
|
4229
4459
|
}
|
|
4230
4460
|
if (rec.role === "error") {
|
|
4231
|
-
return /* @__PURE__ */
|
|
4461
|
+
return /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React10.createElement(Text9, { color: "red" }, rec.error ?? rec.content));
|
|
4232
4462
|
}
|
|
4233
4463
|
if (rec.role === "done" || rec.role === "assistant_delta") {
|
|
4234
4464
|
return null;
|
|
4235
4465
|
}
|
|
4236
|
-
return /* @__PURE__ */
|
|
4466
|
+
return /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "[", rec.role, "] ", rec.content));
|
|
4237
4467
|
}
|
|
4238
4468
|
function CacheBadge({ usage }) {
|
|
4239
4469
|
const hit = usage.prompt_cache_hit_tokens ?? 0;
|
|
@@ -4242,7 +4472,7 @@ function CacheBadge({ usage }) {
|
|
|
4242
4472
|
if (total === 0) return null;
|
|
4243
4473
|
const pct2 = hit / total * 100;
|
|
4244
4474
|
const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
|
|
4245
|
-
return /* @__PURE__ */
|
|
4475
|
+
return /* @__PURE__ */ React10.createElement(Text9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React10.createElement(Text9, { color }, pct2.toFixed(1), "%"));
|
|
4246
4476
|
}
|
|
4247
4477
|
function truncate3(s, max) {
|
|
4248
4478
|
return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
|
|
@@ -4276,7 +4506,7 @@ function DiffApp({ report }) {
|
|
|
4276
4506
|
}
|
|
4277
4507
|
});
|
|
4278
4508
|
const pair = report.pairs[idx];
|
|
4279
|
-
return /* @__PURE__ */
|
|
4509
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React11.createElement(DiffHeader, { report }), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React11.createElement(Text10, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React11.createElement(Text10, null, pair ? /* @__PURE__ */ React11.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React11.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React11.createElement(Text10, null, pair.divergenceNote)) : null, /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "j"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "k"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "N"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "g"), "/", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React11.createElement(Text10, { bold: true }, "q"), " ", "quit")));
|
|
4280
4510
|
}
|
|
4281
4511
|
function DiffHeader({ report }) {
|
|
4282
4512
|
const a = report.a;
|
|
@@ -4294,15 +4524,15 @@ function DiffHeader({ report }) {
|
|
|
4294
4524
|
} else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
|
|
4295
4525
|
prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
|
|
4296
4526
|
}
|
|
4297
|
-
return /* @__PURE__ */
|
|
4527
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Box10, { justifyContent: "space-between" }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, a.label), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " vs B="), /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, b.label)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cache "), /* @__PURE__ */ React11.createElement(Text10, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React11.createElement(Text10, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React11.createElement(Text10, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cost "), /* @__PURE__ */ React11.createElement(Text10, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React11.createElement(Text10, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React11.createElement(Text10, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "model calls "), /* @__PURE__ */ React11.createElement(Text10, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true, italic: true }, prefixLine)) : null);
|
|
4298
4528
|
}
|
|
4299
4529
|
function Pane({
|
|
4300
4530
|
label,
|
|
4301
4531
|
headerColor,
|
|
4302
4532
|
records
|
|
4303
4533
|
}) {
|
|
4304
|
-
return /* @__PURE__ */
|
|
4305
|
-
|
|
4534
|
+
return /* @__PURE__ */ React11.createElement(
|
|
4535
|
+
Box10,
|
|
4306
4536
|
{
|
|
4307
4537
|
flexDirection: "column",
|
|
4308
4538
|
flexGrow: 1,
|
|
@@ -4310,21 +4540,21 @@ function Pane({
|
|
|
4310
4540
|
borderStyle: "single",
|
|
4311
4541
|
borderColor: headerColor
|
|
4312
4542
|
},
|
|
4313
|
-
/* @__PURE__ */
|
|
4314
|
-
records.length === 0 ? /* @__PURE__ */
|
|
4543
|
+
/* @__PURE__ */ React11.createElement(Text10, { color: headerColor, bold: true }, label),
|
|
4544
|
+
records.length === 0 ? /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React11.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React11.createElement(RecordView, { key, rec, compact: true }))
|
|
4315
4545
|
);
|
|
4316
4546
|
}
|
|
4317
4547
|
function KindBadge({ kind }) {
|
|
4318
4548
|
if (kind === "match") {
|
|
4319
|
-
return /* @__PURE__ */
|
|
4549
|
+
return /* @__PURE__ */ React11.createElement(Text10, { color: "green" }, "\u2713 match");
|
|
4320
4550
|
}
|
|
4321
4551
|
if (kind === "diverge") {
|
|
4322
|
-
return /* @__PURE__ */
|
|
4552
|
+
return /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "\u2605 diverge");
|
|
4323
4553
|
}
|
|
4324
4554
|
if (kind === "only_in_a") {
|
|
4325
|
-
return /* @__PURE__ */
|
|
4555
|
+
return /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, "\u2190 only in A");
|
|
4326
4556
|
}
|
|
4327
|
-
return /* @__PURE__ */
|
|
4557
|
+
return /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, "\u2192 only in B");
|
|
4328
4558
|
}
|
|
4329
4559
|
function paneRecords(pair, side) {
|
|
4330
4560
|
if (!pair) return [];
|
|
@@ -4355,7 +4585,7 @@ markdown report written to ${opts.mdPath}`);
|
|
|
4355
4585
|
return;
|
|
4356
4586
|
}
|
|
4357
4587
|
if (wantTui) {
|
|
4358
|
-
const { waitUntilExit } = render2(
|
|
4588
|
+
const { waitUntilExit } = render2(React12.createElement(DiffApp, { report }), {
|
|
4359
4589
|
exitOnCtrlC: true
|
|
4360
4590
|
});
|
|
4361
4591
|
await waitUntilExit();
|
|
@@ -4364,6 +4594,70 @@ markdown report written to ${opts.mdPath}`);
|
|
|
4364
4594
|
console.log(renderSummaryTable(report));
|
|
4365
4595
|
}
|
|
4366
4596
|
|
|
4597
|
+
// src/cli/commands/mcp-inspect.ts
|
|
4598
|
+
async function mcpInspectCommand(opts) {
|
|
4599
|
+
const spec = parseMcpSpec(opts.spec);
|
|
4600
|
+
const transport = spec.transport === "sse" ? new SseTransport({ url: spec.url }) : new StdioTransport({ command: spec.command, args: spec.args });
|
|
4601
|
+
const client = new McpClient({ transport });
|
|
4602
|
+
try {
|
|
4603
|
+
await client.initialize();
|
|
4604
|
+
const report = await inspectMcpServer(client);
|
|
4605
|
+
if (opts.json) {
|
|
4606
|
+
console.log(JSON.stringify(report, null, 2));
|
|
4607
|
+
} else {
|
|
4608
|
+
console.log(formatReport(spec.name ?? "(anon)", report));
|
|
4609
|
+
}
|
|
4610
|
+
} finally {
|
|
4611
|
+
await client.close();
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
function formatReport(nsName, r) {
|
|
4615
|
+
const lines = [];
|
|
4616
|
+
lines.push(`MCP server [${nsName}]`);
|
|
4617
|
+
lines.push(
|
|
4618
|
+
` server ${r.serverInfo.name || "(unknown)"}${r.serverInfo.version ? ` v${r.serverInfo.version}` : ""}`
|
|
4619
|
+
);
|
|
4620
|
+
lines.push(` protocol ${r.protocolVersion}`);
|
|
4621
|
+
const capKeys = Object.keys(r.capabilities);
|
|
4622
|
+
lines.push(` caps ${capKeys.length > 0 ? capKeys.join(", ") : "(none advertised)"}`);
|
|
4623
|
+
if (r.instructions) {
|
|
4624
|
+
lines.push(` notes ${r.instructions.trim().slice(0, 200)}`);
|
|
4625
|
+
}
|
|
4626
|
+
lines.push("");
|
|
4627
|
+
lines.push(formatSection("Tools", r.tools, toolLine));
|
|
4628
|
+
lines.push(formatSection("Resources", r.resources, resourceLine));
|
|
4629
|
+
lines.push(formatSection("Prompts", r.prompts, promptLine));
|
|
4630
|
+
return lines.join("\n");
|
|
4631
|
+
}
|
|
4632
|
+
function formatSection(title, section, render5) {
|
|
4633
|
+
if (!section.supported) {
|
|
4634
|
+
return `${title}: (not supported \u2014 ${section.reason})`;
|
|
4635
|
+
}
|
|
4636
|
+
if (section.items.length === 0) {
|
|
4637
|
+
return `${title}: (none)`;
|
|
4638
|
+
}
|
|
4639
|
+
const lines = [`${title} (${section.items.length}):`];
|
|
4640
|
+
for (const item of section.items) lines.push(` ${render5(item)}`);
|
|
4641
|
+
return lines.join("\n");
|
|
4642
|
+
}
|
|
4643
|
+
function toolLine(t) {
|
|
4644
|
+
const desc = t.description ? ` \u2014 ${oneLine(t.description, 80)}` : "";
|
|
4645
|
+
return `\xB7 ${t.name}${desc}`;
|
|
4646
|
+
}
|
|
4647
|
+
function resourceLine(r) {
|
|
4648
|
+
const mime = r.mimeType ? ` [${r.mimeType}]` : "";
|
|
4649
|
+
return `\xB7 ${r.name}${mime} ${r.uri}`;
|
|
4650
|
+
}
|
|
4651
|
+
function promptLine(p) {
|
|
4652
|
+
const argPart = p.arguments && p.arguments.length > 0 ? ` (${p.arguments.map((a) => a.required ? a.name : `${a.name}?`).join(", ")})` : "";
|
|
4653
|
+
const desc = p.description ? ` \u2014 ${oneLine(p.description, 80)}` : "";
|
|
4654
|
+
return `\xB7 ${p.name}${argPart}${desc}`;
|
|
4655
|
+
}
|
|
4656
|
+
function oneLine(s, max) {
|
|
4657
|
+
const flat = s.replace(/\s+/g, " ").trim();
|
|
4658
|
+
return flat.length <= max ? flat : `${flat.slice(0, max - 1)}\u2026`;
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4367
4661
|
// src/mcp/catalog.ts
|
|
4368
4662
|
var MCP_CATALOG = [
|
|
4369
4663
|
{
|
|
@@ -4431,11 +4725,11 @@ function pad(s, width) {
|
|
|
4431
4725
|
|
|
4432
4726
|
// src/cli/commands/replay.ts
|
|
4433
4727
|
import { render as render3 } from "ink";
|
|
4434
|
-
import
|
|
4728
|
+
import React14 from "react";
|
|
4435
4729
|
|
|
4436
4730
|
// src/cli/ui/ReplayApp.tsx
|
|
4437
|
-
import { Box as
|
|
4438
|
-
import
|
|
4731
|
+
import { Box as Box11, Static as Static3, Text as Text11, useApp as useApp4, useInput as useInput3 } from "ink";
|
|
4732
|
+
import React13, { useMemo as useMemo2, useState as useState6 } from "react";
|
|
4439
4733
|
function ReplayApp({ meta, pages }) {
|
|
4440
4734
|
const { exit } = useApp4();
|
|
4441
4735
|
const maxIdx = Math.max(0, pages.length - 1);
|
|
@@ -4472,14 +4766,14 @@ function ReplayApp({ meta, pages }) {
|
|
|
4472
4766
|
const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
|
|
4473
4767
|
const currentPage = pages[idx];
|
|
4474
4768
|
const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
|
|
4475
|
-
return /* @__PURE__ */
|
|
4769
|
+
return /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
|
|
4476
4770
|
StatsPanel,
|
|
4477
4771
|
{
|
|
4478
4772
|
summary,
|
|
4479
4773
|
model: cumStats.models[0] ?? meta?.model ?? "?",
|
|
4480
4774
|
prefixHash
|
|
4481
4775
|
}
|
|
4482
|
-
), /* @__PURE__ */
|
|
4776
|
+
), /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React13.createElement(Box11, { justifyContent: "space-between" }, /* @__PURE__ */ React13.createElement(Text11, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React13.createElement(Text11, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React13.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React13.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React13.createElement(Text11, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React13.createElement(Text11, { dimColor: true }, /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "j"), "/", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "k"), "/", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "q"), " quit")));
|
|
4483
4777
|
}
|
|
4484
4778
|
|
|
4485
4779
|
// src/cli/commands/replay.ts
|
|
@@ -4491,7 +4785,7 @@ async function replayCommand(opts) {
|
|
|
4491
4785
|
}
|
|
4492
4786
|
const { parsed } = replayFromFile(opts.path);
|
|
4493
4787
|
const pages = groupRecordsByTurn(parsed.records);
|
|
4494
|
-
const { waitUntilExit } = render3(
|
|
4788
|
+
const { waitUntilExit } = render3(React14.createElement(ReplayApp, { meta: parsed.meta, pages }), {
|
|
4495
4789
|
exitOnCtrlC: true
|
|
4496
4790
|
});
|
|
4497
4791
|
await waitUntilExit();
|
|
@@ -4543,7 +4837,7 @@ function sliceRecords(records, opts) {
|
|
|
4543
4837
|
function renderRecord(rec) {
|
|
4544
4838
|
const turn = `[t${rec.turn}]`;
|
|
4545
4839
|
if (rec.role === "user") {
|
|
4546
|
-
console.log(`${turn} USER: ${
|
|
4840
|
+
console.log(`${turn} USER: ${oneLine2(rec.content)}`);
|
|
4547
4841
|
} else if (rec.role === "assistant_final") {
|
|
4548
4842
|
const cost = rec.cost !== void 0 ? ` $${rec.cost.toFixed(6)}` : "";
|
|
4549
4843
|
const cache = rec.usage && (rec.usage.prompt_cache_hit_tokens !== void 0 || rec.usage.prompt_cache_miss_tokens !== void 0) ? (() => {
|
|
@@ -4552,7 +4846,7 @@ function renderRecord(rec) {
|
|
|
4552
4846
|
const total = hit + miss;
|
|
4553
4847
|
return total > 0 ? ` cache=${(hit / total * 100).toFixed(1)}%` : "";
|
|
4554
4848
|
})() : "";
|
|
4555
|
-
console.log(`${turn} AGENT:${cost}${cache} ${
|
|
4849
|
+
console.log(`${turn} AGENT:${cost}${cache} ${oneLine2(rec.content)}`);
|
|
4556
4850
|
if (rec.planState) {
|
|
4557
4851
|
const ps = rec.planState;
|
|
4558
4852
|
if (ps.subgoals.length)
|
|
@@ -4569,16 +4863,16 @@ function renderRecord(rec) {
|
|
|
4569
4863
|
);
|
|
4570
4864
|
}
|
|
4571
4865
|
} else if (rec.role === "tool") {
|
|
4572
|
-
const args = rec.args ? ` args=${
|
|
4573
|
-
console.log(`${turn} TOOL ${rec.tool ?? "?"}:${args} \u2192 ${
|
|
4866
|
+
const args = rec.args ? ` args=${oneLine2(rec.args, 80)}` : "";
|
|
4867
|
+
console.log(`${turn} TOOL ${rec.tool ?? "?"}:${args} \u2192 ${oneLine2(rec.content, 120)}`);
|
|
4574
4868
|
} else if (rec.role === "error") {
|
|
4575
4869
|
console.log(`${turn} ERROR: ${rec.error ?? rec.content}`);
|
|
4576
4870
|
} else if (rec.role === "done") {
|
|
4577
4871
|
} else {
|
|
4578
|
-
console.log(`${turn} ${rec.role}: ${
|
|
4872
|
+
console.log(`${turn} ${rec.role}: ${oneLine2(rec.content)}`);
|
|
4579
4873
|
}
|
|
4580
4874
|
}
|
|
4581
|
-
function
|
|
4875
|
+
function oneLine2(s, max = 200) {
|
|
4582
4876
|
const collapsed = s.replace(/\s+/g, " ").trim();
|
|
4583
4877
|
return collapsed.length > max ? `${collapsed.slice(0, max)}\u2026` : collapsed;
|
|
4584
4878
|
}
|
|
@@ -4764,7 +5058,7 @@ function inspectSession(name, verbose) {
|
|
|
4764
5058
|
function renderMessage(msg, turnIdx, verbose) {
|
|
4765
5059
|
const turn = turnIdx > 0 ? `[t${turnIdx}]` : "[start]";
|
|
4766
5060
|
const content = typeof msg.content === "string" ? msg.content : "";
|
|
4767
|
-
const flat =
|
|
5061
|
+
const flat = oneLine3(content);
|
|
4768
5062
|
if (msg.role === "user") {
|
|
4769
5063
|
console.log(`${turn} USER: ${flat}`);
|
|
4770
5064
|
} else if (msg.role === "assistant") {
|
|
@@ -4782,7 +5076,7 @@ function renderMessage(msg, turnIdx, verbose) {
|
|
|
4782
5076
|
if (verbose) console.log(`${turn} SYSTEM: ${truncate4(flat, 160)}`);
|
|
4783
5077
|
}
|
|
4784
5078
|
}
|
|
4785
|
-
function
|
|
5079
|
+
function oneLine3(s, max = 200) {
|
|
4786
5080
|
const collapsed = s.replace(/\s+/g, " ").trim();
|
|
4787
5081
|
return collapsed.length > max ? `${collapsed.slice(0, max)}\u2026` : collapsed;
|
|
4788
5082
|
}
|
|
@@ -4792,16 +5086,16 @@ function truncate4(s, max) {
|
|
|
4792
5086
|
|
|
4793
5087
|
// src/cli/commands/setup.tsx
|
|
4794
5088
|
import { render as render4 } from "ink";
|
|
4795
|
-
import
|
|
5089
|
+
import React17 from "react";
|
|
4796
5090
|
|
|
4797
5091
|
// src/cli/ui/Wizard.tsx
|
|
4798
|
-
import { Box as
|
|
5092
|
+
import { Box as Box13, Text as Text13, useApp as useApp5, useInput as useInput5 } from "ink";
|
|
4799
5093
|
import TextInput3 from "ink-text-input";
|
|
4800
|
-
import
|
|
5094
|
+
import React16, { useState as useState8 } from "react";
|
|
4801
5095
|
|
|
4802
5096
|
// src/cli/ui/Select.tsx
|
|
4803
|
-
import { Box as
|
|
4804
|
-
import
|
|
5097
|
+
import { Box as Box12, Text as Text12, useInput as useInput4 } from "ink";
|
|
5098
|
+
import React15, { useState as useState7 } from "react";
|
|
4805
5099
|
function SingleSelect({
|
|
4806
5100
|
items,
|
|
4807
5101
|
initialValue,
|
|
@@ -4825,7 +5119,7 @@ function SingleSelect({
|
|
|
4825
5119
|
onCancel();
|
|
4826
5120
|
}
|
|
4827
5121
|
});
|
|
4828
|
-
return /* @__PURE__ */
|
|
5122
|
+
return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React15.createElement(
|
|
4829
5123
|
SelectRow,
|
|
4830
5124
|
{
|
|
4831
5125
|
key: item.value,
|
|
@@ -4868,10 +5162,10 @@ function MultiSelect({
|
|
|
4868
5162
|
onCancel();
|
|
4869
5163
|
}
|
|
4870
5164
|
});
|
|
4871
|
-
return /* @__PURE__ */
|
|
5165
|
+
return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, items.map((item, i) => {
|
|
4872
5166
|
const checked = selected.has(item.value);
|
|
4873
5167
|
const marker = checked ? "[x]" : "[ ]";
|
|
4874
|
-
return /* @__PURE__ */
|
|
5168
|
+
return /* @__PURE__ */ React15.createElement(
|
|
4875
5169
|
SelectRow,
|
|
4876
5170
|
{
|
|
4877
5171
|
key: item.value,
|
|
@@ -4880,7 +5174,7 @@ function MultiSelect({
|
|
|
4880
5174
|
marker: `${i === index ? "\u25B8" : " "} ${marker}`
|
|
4881
5175
|
}
|
|
4882
5176
|
);
|
|
4883
|
-
}), footer ? /* @__PURE__ */
|
|
5177
|
+
}), footer ? /* @__PURE__ */ React15.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, footer)) : null);
|
|
4884
5178
|
}
|
|
4885
5179
|
function SelectRow({
|
|
4886
5180
|
item,
|
|
@@ -4888,7 +5182,7 @@ function SelectRow({
|
|
|
4888
5182
|
marker
|
|
4889
5183
|
}) {
|
|
4890
5184
|
const color = item.disabled ? "gray" : active ? "cyan" : void 0;
|
|
4891
|
-
return /* @__PURE__ */
|
|
5185
|
+
return /* @__PURE__ */ React15.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Box12, null, /* @__PURE__ */ React15.createElement(Text12, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React15.createElement(Box12, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, item.hint)) : null);
|
|
4892
5186
|
}
|
|
4893
5187
|
function findNextEnabled(items, from, step) {
|
|
4894
5188
|
if (items.length === 0) return 0;
|
|
@@ -4937,7 +5231,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
4937
5231
|
if (key.escape && step !== "saved" && onCancel) onCancel();
|
|
4938
5232
|
});
|
|
4939
5233
|
if (step === "apiKey") {
|
|
4940
|
-
return /* @__PURE__ */
|
|
5234
|
+
return /* @__PURE__ */ React16.createElement(
|
|
4941
5235
|
ApiKeyStep,
|
|
4942
5236
|
{
|
|
4943
5237
|
onSubmit: (key) => {
|
|
@@ -4951,7 +5245,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
4951
5245
|
);
|
|
4952
5246
|
}
|
|
4953
5247
|
if (step === "preset") {
|
|
4954
|
-
return /* @__PURE__ */
|
|
5248
|
+
return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React16.createElement(
|
|
4955
5249
|
SingleSelect,
|
|
4956
5250
|
{
|
|
4957
5251
|
items: presetItems(),
|
|
@@ -4961,10 +5255,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
4961
5255
|
setStep("mcp");
|
|
4962
5256
|
}
|
|
4963
5257
|
}
|
|
4964
|
-
), /* @__PURE__ */
|
|
5258
|
+
), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
|
|
4965
5259
|
}
|
|
4966
5260
|
if (step === "mcp") {
|
|
4967
|
-
return /* @__PURE__ */
|
|
5261
|
+
return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React16.createElement(
|
|
4968
5262
|
MultiSelect,
|
|
4969
5263
|
{
|
|
4970
5264
|
items: mcpItems(),
|
|
@@ -4989,7 +5283,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
4989
5283
|
}
|
|
4990
5284
|
const currentName = pending[0];
|
|
4991
5285
|
const entry = CATALOG_BY_NAME.get(currentName);
|
|
4992
|
-
return /* @__PURE__ */
|
|
5286
|
+
return /* @__PURE__ */ React16.createElement(
|
|
4993
5287
|
McpArgsStep,
|
|
4994
5288
|
{
|
|
4995
5289
|
entry,
|
|
@@ -5007,7 +5301,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
5007
5301
|
}
|
|
5008
5302
|
if (step === "review") {
|
|
5009
5303
|
const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
|
|
5010
|
-
return /* @__PURE__ */
|
|
5304
|
+
return /* @__PURE__ */ React16.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React16.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React16.createElement(
|
|
5011
5305
|
SummaryLine,
|
|
5012
5306
|
{
|
|
5013
5307
|
label: "MCP",
|
|
@@ -5015,8 +5309,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
5015
5309
|
}
|
|
5016
5310
|
), specs.map((spec, i) => (
|
|
5017
5311
|
// biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
|
|
5018
|
-
/* @__PURE__ */
|
|
5019
|
-
)), /* @__PURE__ */
|
|
5312
|
+
/* @__PURE__ */ React16.createElement(Box13, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "\xB7 ", spec))
|
|
5313
|
+
)), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { color: "red" }, error)) : null, /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "enter save \xB7 esc cancel"))), /* @__PURE__ */ React16.createElement(
|
|
5020
5314
|
ReviewConfirm,
|
|
5021
5315
|
{
|
|
5022
5316
|
onConfirm: () => {
|
|
@@ -5042,7 +5336,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
5042
5336
|
}
|
|
5043
5337
|
));
|
|
5044
5338
|
}
|
|
5045
|
-
return /* @__PURE__ */
|
|
5339
|
+
return /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Press enter to exit.")), /* @__PURE__ */ React16.createElement(ExitOnEnter, { onExit: exit }));
|
|
5046
5340
|
}
|
|
5047
5341
|
function ApiKeyStep({
|
|
5048
5342
|
onSubmit,
|
|
@@ -5050,7 +5344,7 @@ function ApiKeyStep({
|
|
|
5050
5344
|
onError
|
|
5051
5345
|
}) {
|
|
5052
5346
|
const [value, setValue] = useState8("");
|
|
5053
|
-
return /* @__PURE__ */
|
|
5347
|
+
return /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React16.createElement(
|
|
5054
5348
|
TextInput3,
|
|
5055
5349
|
{
|
|
5056
5350
|
value,
|
|
@@ -5067,7 +5361,7 @@ function ApiKeyStep({
|
|
|
5067
5361
|
mask: "\u2022",
|
|
5068
5362
|
placeholder: "sk-..."
|
|
5069
5363
|
}
|
|
5070
|
-
)), error ? /* @__PURE__ */
|
|
5364
|
+
)), error ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { color: "red" }, error)) : value ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "preview: ", redactKey(value))) : null);
|
|
5071
5365
|
}
|
|
5072
5366
|
function McpArgsStep({
|
|
5073
5367
|
entry,
|
|
@@ -5076,7 +5370,7 @@ function McpArgsStep({
|
|
|
5076
5370
|
onError
|
|
5077
5371
|
}) {
|
|
5078
5372
|
const [value, setValue] = useState8("");
|
|
5079
|
-
return /* @__PURE__ */
|
|
5373
|
+
return /* @__PURE__ */ React16.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Text13, null, entry.summary), entry.note ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, null, "Required parameter: "), /* @__PURE__ */ React16.createElement(Text13, { bold: true }, entry.userArgs)), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React16.createElement(
|
|
5080
5374
|
TextInput3,
|
|
5081
5375
|
{
|
|
5082
5376
|
value,
|
|
@@ -5092,7 +5386,7 @@ function McpArgsStep({
|
|
|
5092
5386
|
},
|
|
5093
5387
|
placeholder: placeholderFor(entry)
|
|
5094
5388
|
}
|
|
5095
|
-
)), error ? /* @__PURE__ */
|
|
5389
|
+
)), error ? /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text13, { color: "red" }, error)) : null));
|
|
5096
5390
|
}
|
|
5097
5391
|
function ReviewConfirm({ onConfirm }) {
|
|
5098
5392
|
useInput5((_i, key) => {
|
|
@@ -5112,10 +5406,10 @@ function StepFrame({
|
|
|
5112
5406
|
total,
|
|
5113
5407
|
children
|
|
5114
5408
|
}) {
|
|
5115
|
-
return /* @__PURE__ */
|
|
5409
|
+
return /* @__PURE__ */ React16.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Box13, null, /* @__PURE__ */ React16.createElement(Text13, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React16.createElement(Text13, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React16.createElement(Box13, { marginTop: 1, flexDirection: "column" }, children));
|
|
5116
5410
|
}
|
|
5117
5411
|
function SummaryLine({ label, value }) {
|
|
5118
|
-
return /* @__PURE__ */
|
|
5412
|
+
return /* @__PURE__ */ React16.createElement(Box13, null, /* @__PURE__ */ React16.createElement(Text13, null, label.padEnd(12)), /* @__PURE__ */ React16.createElement(Text13, { bold: true }, value));
|
|
5119
5413
|
}
|
|
5120
5414
|
function presetItems() {
|
|
5121
5415
|
return ["fast", "smart", "max"].map((name) => ({
|
|
@@ -5171,7 +5465,7 @@ async function setupCommand(_opts = {}) {
|
|
|
5171
5465
|
const existingKey = loadApiKey();
|
|
5172
5466
|
const existing = readConfig();
|
|
5173
5467
|
const { waitUntilExit, unmount } = render4(
|
|
5174
|
-
/* @__PURE__ */
|
|
5468
|
+
/* @__PURE__ */ React17.createElement(
|
|
5175
5469
|
Wizard,
|
|
5176
5470
|
{
|
|
5177
5471
|
existingApiKey: existingKey,
|
|
@@ -5390,6 +5684,17 @@ var mcp = program.command("mcp").description("Model Context Protocol helpers \u2
|
|
|
5390
5684
|
mcp.command("list").description("Show a curated catalog of popular MCP servers with ready-to-use --mcp commands.").option("--json", "Emit the catalog as JSON instead of the human-readable table").action((opts) => {
|
|
5391
5685
|
mcpListCommand({ json: !!opts.json });
|
|
5392
5686
|
});
|
|
5687
|
+
mcp.command("inspect <spec>").description(
|
|
5688
|
+
'Connect to one MCP server and print its server info + tools/resources/prompts. <spec> takes the same forms as --mcp ("name=cmd args", "cmd args", or an SSE URL).'
|
|
5689
|
+
).option("--json", "Emit the full inspection report as JSON instead of the human-readable summary").action(async (spec, opts) => {
|
|
5690
|
+
try {
|
|
5691
|
+
await mcpInspectCommand({ spec, json: !!opts.json });
|
|
5692
|
+
} catch (err) {
|
|
5693
|
+
process.stderr.write(`mcp inspect failed: ${err.message}
|
|
5694
|
+
`);
|
|
5695
|
+
process.exit(1);
|
|
5696
|
+
}
|
|
5697
|
+
});
|
|
5393
5698
|
program.command("version").description("Print Reasonix version.").action(versionCommand);
|
|
5394
5699
|
program.parseAsync(process.argv).catch((err) => {
|
|
5395
5700
|
console.error(err);
|