reasonix 0.5.4 → 0.5.7
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 +564 -272
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +166 -1
- package/dist/index.js +316 -129
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -126,8 +126,8 @@ function computeWait(attempt, initial, cap, retryAfter) {
|
|
|
126
126
|
}
|
|
127
127
|
function sleep(ms, signal) {
|
|
128
128
|
if (ms <= 0) return Promise.resolve();
|
|
129
|
-
return new Promise((
|
|
130
|
-
const timer = setTimeout(
|
|
129
|
+
return new Promise((resolve7, reject) => {
|
|
130
|
+
const timer = setTimeout(resolve7, ms);
|
|
131
131
|
if (signal) {
|
|
132
132
|
const onAbort = () => {
|
|
133
133
|
clearTimeout(timer);
|
|
@@ -599,7 +599,7 @@ function matchesTool(hook, toolName) {
|
|
|
599
599
|
}
|
|
600
600
|
}
|
|
601
601
|
function defaultSpawner(input) {
|
|
602
|
-
return new Promise((
|
|
602
|
+
return new Promise((resolve7) => {
|
|
603
603
|
const child = spawn(input.command, {
|
|
604
604
|
cwd: input.cwd,
|
|
605
605
|
shell: true,
|
|
@@ -626,7 +626,7 @@ function defaultSpawner(input) {
|
|
|
626
626
|
});
|
|
627
627
|
child.once("error", (err) => {
|
|
628
628
|
clearTimeout(timer);
|
|
629
|
-
|
|
629
|
+
resolve7({
|
|
630
630
|
exitCode: null,
|
|
631
631
|
stdout: stdout2,
|
|
632
632
|
stderr,
|
|
@@ -636,7 +636,7 @@ function defaultSpawner(input) {
|
|
|
636
636
|
});
|
|
637
637
|
child.once("close", (code) => {
|
|
638
638
|
clearTimeout(timer);
|
|
639
|
-
|
|
639
|
+
resolve7({
|
|
640
640
|
exitCode: code,
|
|
641
641
|
stdout: stdout2.trim(),
|
|
642
642
|
stderr: stderr.trim(),
|
|
@@ -697,7 +697,7 @@ async function runHooks(opts) {
|
|
|
697
697
|
}
|
|
698
698
|
|
|
699
699
|
// src/tokenizer.ts
|
|
700
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
700
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
701
701
|
import { createRequire } from "module";
|
|
702
702
|
import { dirname as dirname2, join as join3 } from "path";
|
|
703
703
|
import { fileURLToPath } from "url";
|
|
@@ -725,17 +725,24 @@ function buildByteToChar() {
|
|
|
725
725
|
var cached = null;
|
|
726
726
|
function resolveDataPath() {
|
|
727
727
|
if (process.env.REASONIX_TOKENIZER_PATH) return process.env.REASONIX_TOKENIZER_PATH;
|
|
728
|
+
const candidates = [];
|
|
728
729
|
try {
|
|
729
730
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
730
|
-
|
|
731
|
+
candidates.push(join3(here, "..", "data", "deepseek-tokenizer.json.gz"));
|
|
732
|
+
candidates.push(join3(here, "..", "..", "data", "deepseek-tokenizer.json.gz"));
|
|
731
733
|
} catch {
|
|
734
|
+
}
|
|
735
|
+
try {
|
|
732
736
|
const req = createRequire(import.meta.url);
|
|
733
|
-
|
|
734
|
-
dirname2(req.resolve("reasonix/package.json")),
|
|
735
|
-
"data",
|
|
736
|
-
"deepseek-tokenizer.json.gz"
|
|
737
|
+
candidates.push(
|
|
738
|
+
join3(dirname2(req.resolve("reasonix/package.json")), "data", "deepseek-tokenizer.json.gz")
|
|
737
739
|
);
|
|
740
|
+
} catch {
|
|
741
|
+
}
|
|
742
|
+
for (const p of candidates) {
|
|
743
|
+
if (existsSync2(p)) return p;
|
|
738
744
|
}
|
|
745
|
+
return candidates[0] ?? join3(process.cwd(), "data", "deepseek-tokenizer.json.gz");
|
|
739
746
|
}
|
|
740
747
|
function loadTokenizer() {
|
|
741
748
|
if (cached) return cached;
|
|
@@ -1565,7 +1572,7 @@ function signature2(call) {
|
|
|
1565
1572
|
import {
|
|
1566
1573
|
appendFileSync,
|
|
1567
1574
|
chmodSync as chmodSync2,
|
|
1568
|
-
existsSync as
|
|
1575
|
+
existsSync as existsSync3,
|
|
1569
1576
|
mkdirSync as mkdirSync2,
|
|
1570
1577
|
readFileSync as readFileSync4,
|
|
1571
1578
|
readdirSync,
|
|
@@ -1587,7 +1594,7 @@ function sanitizeName(name) {
|
|
|
1587
1594
|
}
|
|
1588
1595
|
function loadSessionMessages(name) {
|
|
1589
1596
|
const path = sessionPath(name);
|
|
1590
|
-
if (!
|
|
1597
|
+
if (!existsSync3(path)) return [];
|
|
1591
1598
|
try {
|
|
1592
1599
|
const raw = readFileSync4(path, "utf8");
|
|
1593
1600
|
const out = [];
|
|
@@ -1617,7 +1624,7 @@ function appendSessionMessage(name, message) {
|
|
|
1617
1624
|
}
|
|
1618
1625
|
function listSessions() {
|
|
1619
1626
|
const dir = sessionsDir();
|
|
1620
|
-
if (!
|
|
1627
|
+
if (!existsSync3(dir)) return [];
|
|
1621
1628
|
try {
|
|
1622
1629
|
const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
1623
1630
|
return files.map((file) => {
|
|
@@ -1813,9 +1820,9 @@ var CacheFirstLoop = class {
|
|
|
1813
1820
|
this.sessionName = opts.session ?? null;
|
|
1814
1821
|
if (this.sessionName) {
|
|
1815
1822
|
const prior = loadSessionMessages(this.sessionName);
|
|
1816
|
-
const { messages, healedCount,
|
|
1823
|
+
const { messages, healedCount, tokensSaved } = healLoadedMessagesByTokens(
|
|
1817
1824
|
prior,
|
|
1818
|
-
|
|
1825
|
+
DEFAULT_MAX_RESULT_TOKENS
|
|
1819
1826
|
);
|
|
1820
1827
|
for (const msg of messages) this.log.append(msg);
|
|
1821
1828
|
this.resumedMessageCount = messages.length;
|
|
@@ -1825,7 +1832,7 @@ var CacheFirstLoop = class {
|
|
|
1825
1832
|
} catch {
|
|
1826
1833
|
}
|
|
1827
1834
|
process.stderr.write(
|
|
1828
|
-
`\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${
|
|
1835
|
+
`\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${tokensSaved > 0 ? ` (shrunk ${tokensSaved.toLocaleString()} tokens of oversized tool output)` : " (dropped dangling tool_calls tail)"}. Rewrote session file.
|
|
1829
1836
|
`
|
|
1830
1837
|
);
|
|
1831
1838
|
}
|
|
@@ -2094,8 +2101,8 @@ var CacheFirstLoop = class {
|
|
|
2094
2101
|
}
|
|
2095
2102
|
);
|
|
2096
2103
|
for (let k = 0; k < budget; k++) {
|
|
2097
|
-
const sample = queue.shift() ?? await new Promise((
|
|
2098
|
-
waiter =
|
|
2104
|
+
const sample = queue.shift() ?? await new Promise((resolve7) => {
|
|
2105
|
+
waiter = resolve7;
|
|
2099
2106
|
});
|
|
2100
2107
|
yield {
|
|
2101
2108
|
turn: this._turn,
|
|
@@ -2494,15 +2501,12 @@ function shrinkOversizedToolResultsByTokens(messages, maxTokens) {
|
|
|
2494
2501
|
});
|
|
2495
2502
|
return { messages: out, healedCount, tokensSaved, charsSaved };
|
|
2496
2503
|
}
|
|
2497
|
-
function
|
|
2498
|
-
const shrunk = shrinkOversizedToolResults(messages, maxChars);
|
|
2499
|
-
let healedCount = shrunk.healedCount;
|
|
2504
|
+
function fixToolCallPairing(messages) {
|
|
2500
2505
|
const out = [];
|
|
2501
|
-
const openCallIds = /* @__PURE__ */ new Set();
|
|
2502
2506
|
let droppedAssistantCalls = 0;
|
|
2503
2507
|
let droppedStrayTools = 0;
|
|
2504
|
-
for (let i = 0; i <
|
|
2505
|
-
const msg =
|
|
2508
|
+
for (let i = 0; i < messages.length; i++) {
|
|
2509
|
+
const msg = messages[i];
|
|
2506
2510
|
if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
|
|
2507
2511
|
const needed = /* @__PURE__ */ new Set();
|
|
2508
2512
|
for (const call of msg.tool_calls) {
|
|
@@ -2510,8 +2514,8 @@ function healLoadedMessages(messages, maxChars) {
|
|
|
2510
2514
|
}
|
|
2511
2515
|
const candidates = [];
|
|
2512
2516
|
let j = i + 1;
|
|
2513
|
-
while (j <
|
|
2514
|
-
const nxt =
|
|
2517
|
+
while (j < messages.length && needed.size > 0) {
|
|
2518
|
+
const nxt = messages[j];
|
|
2515
2519
|
if (nxt.role !== "tool") break;
|
|
2516
2520
|
const id = nxt.tool_call_id ?? "";
|
|
2517
2521
|
if (!needed.has(id)) break;
|
|
@@ -2536,8 +2540,24 @@ function healLoadedMessages(messages, maxChars) {
|
|
|
2536
2540
|
}
|
|
2537
2541
|
out.push(msg);
|
|
2538
2542
|
}
|
|
2539
|
-
|
|
2540
|
-
|
|
2543
|
+
return { messages: out, droppedAssistantCalls, droppedStrayTools };
|
|
2544
|
+
}
|
|
2545
|
+
function healLoadedMessages(messages, maxChars) {
|
|
2546
|
+
const shrunk = shrinkOversizedToolResults(messages, maxChars);
|
|
2547
|
+
const paired = fixToolCallPairing(shrunk.messages);
|
|
2548
|
+
const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
|
|
2549
|
+
return { messages: paired.messages, healedCount, healedFrom: shrunk.healedFrom };
|
|
2550
|
+
}
|
|
2551
|
+
function healLoadedMessagesByTokens(messages, maxTokens) {
|
|
2552
|
+
const shrunk = shrinkOversizedToolResultsByTokens(messages, maxTokens);
|
|
2553
|
+
const paired = fixToolCallPairing(shrunk.messages);
|
|
2554
|
+
const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
|
|
2555
|
+
return {
|
|
2556
|
+
messages: paired.messages,
|
|
2557
|
+
healedCount,
|
|
2558
|
+
tokensSaved: shrunk.tokensSaved,
|
|
2559
|
+
charsSaved: shrunk.charsSaved
|
|
2560
|
+
};
|
|
2541
2561
|
}
|
|
2542
2562
|
function formatLoopError(err) {
|
|
2543
2563
|
const msg = err.message ?? "";
|
|
@@ -2549,6 +2569,163 @@ function formatLoopError(err) {
|
|
|
2549
2569
|
return msg;
|
|
2550
2570
|
}
|
|
2551
2571
|
|
|
2572
|
+
// src/at-mentions.ts
|
|
2573
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
2574
|
+
import { isAbsolute, join as join5, relative, resolve } from "path";
|
|
2575
|
+
var DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;
|
|
2576
|
+
var DEFAULT_PICKER_IGNORE_DIRS = [
|
|
2577
|
+
"node_modules",
|
|
2578
|
+
".git",
|
|
2579
|
+
"dist",
|
|
2580
|
+
"build",
|
|
2581
|
+
".next",
|
|
2582
|
+
"out",
|
|
2583
|
+
"coverage",
|
|
2584
|
+
".cache",
|
|
2585
|
+
".vscode",
|
|
2586
|
+
".idea",
|
|
2587
|
+
"target",
|
|
2588
|
+
".venv",
|
|
2589
|
+
"venv",
|
|
2590
|
+
"__pycache__"
|
|
2591
|
+
];
|
|
2592
|
+
function listFilesSync(root, opts = {}) {
|
|
2593
|
+
const maxResults = Math.max(1, opts.maxResults ?? 500);
|
|
2594
|
+
const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
|
|
2595
|
+
const rootAbs = resolve(root);
|
|
2596
|
+
const out = [];
|
|
2597
|
+
const walk2 = (dirAbs, dirRel) => {
|
|
2598
|
+
if (out.length >= maxResults) return;
|
|
2599
|
+
let entries;
|
|
2600
|
+
try {
|
|
2601
|
+
entries = readdirSync2(dirAbs, { withFileTypes: true });
|
|
2602
|
+
} catch {
|
|
2603
|
+
return;
|
|
2604
|
+
}
|
|
2605
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
2606
|
+
for (const ent of entries) {
|
|
2607
|
+
if (out.length >= maxResults) return;
|
|
2608
|
+
const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
|
|
2609
|
+
if (ent.isDirectory()) {
|
|
2610
|
+
if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
|
|
2611
|
+
walk2(join5(dirAbs, ent.name), relPath);
|
|
2612
|
+
} else if (ent.isFile()) {
|
|
2613
|
+
out.push(relPath);
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
};
|
|
2617
|
+
walk2(rootAbs, "");
|
|
2618
|
+
return out;
|
|
2619
|
+
}
|
|
2620
|
+
var AT_PICKER_PREFIX = /(?:^|\s)@([a-zA-Z0-9_./\\-]*)$/;
|
|
2621
|
+
function detectAtPicker(input) {
|
|
2622
|
+
const m = AT_PICKER_PREFIX.exec(input);
|
|
2623
|
+
if (!m) return null;
|
|
2624
|
+
const query = m[1] ?? "";
|
|
2625
|
+
const atOffset = input.length - query.length - 1;
|
|
2626
|
+
return { query, atOffset };
|
|
2627
|
+
}
|
|
2628
|
+
function rankPickerCandidates(files, query, limit = 40) {
|
|
2629
|
+
if (!query) return files.slice(0, limit);
|
|
2630
|
+
const needle = query.toLowerCase();
|
|
2631
|
+
const scored = [];
|
|
2632
|
+
for (const f of files) {
|
|
2633
|
+
const lower = f.toLowerCase();
|
|
2634
|
+
const hit = lower.indexOf(needle);
|
|
2635
|
+
if (hit < 0) continue;
|
|
2636
|
+
const slash = lower.lastIndexOf("/");
|
|
2637
|
+
const base = slash >= 0 ? lower.slice(slash + 1) : lower;
|
|
2638
|
+
let score = 2;
|
|
2639
|
+
if (base.startsWith(needle)) score = 0;
|
|
2640
|
+
else if (lower.startsWith(needle)) score = 1;
|
|
2641
|
+
scored.push({ path: f, score: score * 1e4 + hit });
|
|
2642
|
+
}
|
|
2643
|
+
scored.sort((a, b) => a.score - b.score);
|
|
2644
|
+
return scored.slice(0, limit).map((s) => s.path);
|
|
2645
|
+
}
|
|
2646
|
+
var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
|
|
2647
|
+
function expandAtMentions(text, rootDir, opts = {}) {
|
|
2648
|
+
const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
|
|
2649
|
+
const fs2 = opts.fs ?? defaultFs;
|
|
2650
|
+
const root = resolve(rootDir);
|
|
2651
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2652
|
+
const expansions = [];
|
|
2653
|
+
for (const match of text.matchAll(AT_MENTION_PATTERN)) {
|
|
2654
|
+
const rawPath = match[1] ?? "";
|
|
2655
|
+
const cleaned = rawPath.replace(/\.+$/, "");
|
|
2656
|
+
if (!cleaned) continue;
|
|
2657
|
+
const token = `@${cleaned}`;
|
|
2658
|
+
if (seen.has(token)) continue;
|
|
2659
|
+
const expansion = resolveMention(cleaned, root, maxBytes, fs2);
|
|
2660
|
+
seen.set(token, expansion);
|
|
2661
|
+
expansions.push(expansion);
|
|
2662
|
+
}
|
|
2663
|
+
if (expansions.length === 0) return { text, expansions };
|
|
2664
|
+
const blocks = [];
|
|
2665
|
+
for (const ex of expansions) {
|
|
2666
|
+
if (ex.ok) {
|
|
2667
|
+
const content = readSafe(root, ex.path, fs2);
|
|
2668
|
+
blocks.push(`<file path="${ex.path}">
|
|
2669
|
+
${content}
|
|
2670
|
+
</file>`);
|
|
2671
|
+
} else {
|
|
2672
|
+
blocks.push(`<file path="${ex.path}" skipped="${ex.skip}" />`);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
const augmented = `${text}
|
|
2676
|
+
|
|
2677
|
+
[Referenced files]
|
|
2678
|
+
${blocks.join("\n\n")}`;
|
|
2679
|
+
return { text: augmented, expansions };
|
|
2680
|
+
}
|
|
2681
|
+
function resolveMention(rawPath, root, maxBytes, fs2) {
|
|
2682
|
+
if (isAbsolute(rawPath)) {
|
|
2683
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
2684
|
+
}
|
|
2685
|
+
const resolved = resolve(root, rawPath);
|
|
2686
|
+
const rel = relative(root, resolved);
|
|
2687
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
2688
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
2689
|
+
}
|
|
2690
|
+
if (!fs2.exists(resolved)) {
|
|
2691
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "missing" };
|
|
2692
|
+
}
|
|
2693
|
+
if (!fs2.isFile(resolved)) {
|
|
2694
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "not-file" };
|
|
2695
|
+
}
|
|
2696
|
+
const size = fs2.size(resolved);
|
|
2697
|
+
if (size > maxBytes) {
|
|
2698
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "too-large", bytes: size };
|
|
2699
|
+
}
|
|
2700
|
+
return { token: `@${rawPath}`, path: rawPath, ok: true, bytes: size };
|
|
2701
|
+
}
|
|
2702
|
+
function readSafe(root, rawPath, fs2) {
|
|
2703
|
+
const resolved = resolve(root, rawPath);
|
|
2704
|
+
try {
|
|
2705
|
+
return fs2.read(resolved);
|
|
2706
|
+
} catch {
|
|
2707
|
+
return "(read failed)";
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
var defaultFs = {
|
|
2711
|
+
exists: (p) => existsSync4(p),
|
|
2712
|
+
isFile: (p) => {
|
|
2713
|
+
try {
|
|
2714
|
+
return statSync2(p).isFile();
|
|
2715
|
+
} catch {
|
|
2716
|
+
return false;
|
|
2717
|
+
}
|
|
2718
|
+
},
|
|
2719
|
+
size: (p) => {
|
|
2720
|
+
try {
|
|
2721
|
+
return statSync2(p).size;
|
|
2722
|
+
} catch {
|
|
2723
|
+
return 0;
|
|
2724
|
+
}
|
|
2725
|
+
},
|
|
2726
|
+
read: (p) => readFileSync5(p, "utf8")
|
|
2727
|
+
};
|
|
2728
|
+
|
|
2552
2729
|
// src/tools/filesystem.ts
|
|
2553
2730
|
import { promises as fs } from "fs";
|
|
2554
2731
|
import * as pathMod from "path";
|
|
@@ -3359,7 +3536,7 @@ function forkRegistryExcluding(parent, exclude) {
|
|
|
3359
3536
|
|
|
3360
3537
|
// src/tools/shell.ts
|
|
3361
3538
|
import { spawn as spawn2 } from "child_process";
|
|
3362
|
-
import { existsSync as
|
|
3539
|
+
import { existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
3363
3540
|
import * as pathMod2 from "path";
|
|
3364
3541
|
var DEFAULT_TIMEOUT_SEC = 60;
|
|
3365
3542
|
var DEFAULT_MAX_OUTPUT_CHARS = 32e3;
|
|
@@ -3529,7 +3706,7 @@ async function runCommand(cmd, opts) {
|
|
|
3529
3706
|
};
|
|
3530
3707
|
const { bin, args, spawnOverrides } = prepareSpawn(argv);
|
|
3531
3708
|
const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };
|
|
3532
|
-
return await new Promise((
|
|
3709
|
+
return await new Promise((resolve7, reject) => {
|
|
3533
3710
|
let child;
|
|
3534
3711
|
try {
|
|
3535
3712
|
child = spawn2(bin, args, effectiveSpawnOpts);
|
|
@@ -3562,7 +3739,7 @@ async function runCommand(cmd, opts) {
|
|
|
3562
3739
|
const output = buf.length > maxChars ? `${buf.slice(0, maxChars)}
|
|
3563
3740
|
|
|
3564
3741
|
[\u2026 truncated ${buf.length - maxChars} chars \u2026]` : buf;
|
|
3565
|
-
|
|
3742
|
+
resolve7({ exitCode: code, output, timedOut });
|
|
3566
3743
|
});
|
|
3567
3744
|
});
|
|
3568
3745
|
}
|
|
@@ -3587,7 +3764,7 @@ function resolveExecutable(cmd, opts = {}) {
|
|
|
3587
3764
|
}
|
|
3588
3765
|
function defaultIsFile(full) {
|
|
3589
3766
|
try {
|
|
3590
|
-
return
|
|
3767
|
+
return existsSync5(full) && statSync3(full).isFile();
|
|
3591
3768
|
} catch {
|
|
3592
3769
|
return false;
|
|
3593
3770
|
}
|
|
@@ -3914,12 +4091,12 @@ ${i + 1}. ${r.title}`);
|
|
|
3914
4091
|
}
|
|
3915
4092
|
|
|
3916
4093
|
// src/env.ts
|
|
3917
|
-
import { readFileSync as
|
|
3918
|
-
import { resolve as
|
|
4094
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
4095
|
+
import { resolve as resolve4 } from "path";
|
|
3919
4096
|
function loadDotenv(path = ".env") {
|
|
3920
4097
|
let raw;
|
|
3921
4098
|
try {
|
|
3922
|
-
raw =
|
|
4099
|
+
raw = readFileSync6(resolve4(process.cwd(), path), "utf8");
|
|
3923
4100
|
} catch {
|
|
3924
4101
|
return;
|
|
3925
4102
|
}
|
|
@@ -3938,7 +4115,7 @@ function loadDotenv(path = ".env") {
|
|
|
3938
4115
|
}
|
|
3939
4116
|
|
|
3940
4117
|
// src/transcript.ts
|
|
3941
|
-
import { createWriteStream, readFileSync as
|
|
4118
|
+
import { createWriteStream, readFileSync as readFileSync7 } from "fs";
|
|
3942
4119
|
function recordFromLoopEvent(ev, extra) {
|
|
3943
4120
|
const rec = {
|
|
3944
4121
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3989,7 +4166,7 @@ function openTranscriptFile(path, meta) {
|
|
|
3989
4166
|
return stream;
|
|
3990
4167
|
}
|
|
3991
4168
|
function readTranscript(path) {
|
|
3992
|
-
const raw =
|
|
4169
|
+
const raw = readFileSync7(path, "utf8");
|
|
3993
4170
|
return parseTranscript(raw);
|
|
3994
4171
|
}
|
|
3995
4172
|
function isPlanStateEmptyShape(s) {
|
|
@@ -4632,7 +4809,7 @@ var McpClient = class {
|
|
|
4632
4809
|
const id = this.nextId++;
|
|
4633
4810
|
const frame = { jsonrpc: "2.0", id, method, params };
|
|
4634
4811
|
let abortHandler = null;
|
|
4635
|
-
const promise = new Promise((
|
|
4812
|
+
const promise = new Promise((resolve7, reject) => {
|
|
4636
4813
|
const timeout = setTimeout(() => {
|
|
4637
4814
|
this.pending.delete(id);
|
|
4638
4815
|
if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
|
|
@@ -4641,7 +4818,7 @@ var McpClient = class {
|
|
|
4641
4818
|
);
|
|
4642
4819
|
}, this.requestTimeoutMs);
|
|
4643
4820
|
this.pending.set(id, {
|
|
4644
|
-
resolve:
|
|
4821
|
+
resolve: resolve7,
|
|
4645
4822
|
reject,
|
|
4646
4823
|
timeout
|
|
4647
4824
|
});
|
|
@@ -4764,12 +4941,12 @@ var StdioTransport = class {
|
|
|
4764
4941
|
}
|
|
4765
4942
|
async send(message) {
|
|
4766
4943
|
if (this.closed) throw new Error("MCP transport is closed");
|
|
4767
|
-
return new Promise((
|
|
4944
|
+
return new Promise((resolve7, reject) => {
|
|
4768
4945
|
const line = `${JSON.stringify(message)}
|
|
4769
4946
|
`;
|
|
4770
4947
|
this.child.stdin.write(line, "utf8", (err) => {
|
|
4771
4948
|
if (err) reject(err);
|
|
4772
|
-
else
|
|
4949
|
+
else resolve7();
|
|
4773
4950
|
});
|
|
4774
4951
|
});
|
|
4775
4952
|
}
|
|
@@ -4780,8 +4957,8 @@ var StdioTransport = class {
|
|
|
4780
4957
|
continue;
|
|
4781
4958
|
}
|
|
4782
4959
|
if (this.closed) return;
|
|
4783
|
-
const next = await new Promise((
|
|
4784
|
-
this.waiters.push(
|
|
4960
|
+
const next = await new Promise((resolve7) => {
|
|
4961
|
+
this.waiters.push(resolve7);
|
|
4785
4962
|
});
|
|
4786
4963
|
if (next === null) return;
|
|
4787
4964
|
yield next;
|
|
@@ -4847,8 +5024,8 @@ var SseTransport = class {
|
|
|
4847
5024
|
constructor(opts) {
|
|
4848
5025
|
this.url = opts.url;
|
|
4849
5026
|
this.headers = opts.headers ?? {};
|
|
4850
|
-
this.endpointReady = new Promise((
|
|
4851
|
-
this.resolveEndpoint =
|
|
5027
|
+
this.endpointReady = new Promise((resolve7, reject) => {
|
|
5028
|
+
this.resolveEndpoint = resolve7;
|
|
4852
5029
|
this.rejectEndpoint = reject;
|
|
4853
5030
|
});
|
|
4854
5031
|
this.endpointReady.catch(() => void 0);
|
|
@@ -4875,8 +5052,8 @@ var SseTransport = class {
|
|
|
4875
5052
|
continue;
|
|
4876
5053
|
}
|
|
4877
5054
|
if (this.closed) return;
|
|
4878
|
-
const next = await new Promise((
|
|
4879
|
-
this.waiters.push(
|
|
5055
|
+
const next = await new Promise((resolve7) => {
|
|
5056
|
+
this.waiters.push(resolve7);
|
|
4880
5057
|
});
|
|
4881
5058
|
if (next === null) return;
|
|
4882
5059
|
yield next;
|
|
@@ -5075,8 +5252,8 @@ async function trySection(load) {
|
|
|
5075
5252
|
}
|
|
5076
5253
|
|
|
5077
5254
|
// src/code/edit-blocks.ts
|
|
5078
|
-
import { existsSync as
|
|
5079
|
-
import { dirname as dirname5, resolve as
|
|
5255
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
5256
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
5080
5257
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
5081
5258
|
function parseEditBlocks(text) {
|
|
5082
5259
|
const out = [];
|
|
@@ -5094,8 +5271,8 @@ function parseEditBlocks(text) {
|
|
|
5094
5271
|
return out;
|
|
5095
5272
|
}
|
|
5096
5273
|
function applyEditBlock(block, rootDir) {
|
|
5097
|
-
const absRoot =
|
|
5098
|
-
const absTarget =
|
|
5274
|
+
const absRoot = resolve5(rootDir);
|
|
5275
|
+
const absTarget = resolve5(absRoot, block.path);
|
|
5099
5276
|
if (absTarget !== absRoot && !absTarget.startsWith(`${absRoot}${sep()}`)) {
|
|
5100
5277
|
return {
|
|
5101
5278
|
path: block.path,
|
|
@@ -5104,7 +5281,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
5104
5281
|
};
|
|
5105
5282
|
}
|
|
5106
5283
|
const searchEmpty = block.search.length === 0;
|
|
5107
|
-
const exists =
|
|
5284
|
+
const exists = existsSync6(absTarget);
|
|
5108
5285
|
try {
|
|
5109
5286
|
if (!exists) {
|
|
5110
5287
|
if (!searchEmpty) {
|
|
@@ -5118,7 +5295,7 @@ function applyEditBlock(block, rootDir) {
|
|
|
5118
5295
|
writeFileSync3(absTarget, block.replace, "utf8");
|
|
5119
5296
|
return { path: block.path, status: "created" };
|
|
5120
5297
|
}
|
|
5121
|
-
const content =
|
|
5298
|
+
const content = readFileSync8(absTarget, "utf8");
|
|
5122
5299
|
if (searchEmpty) {
|
|
5123
5300
|
return {
|
|
5124
5301
|
path: block.path,
|
|
@@ -5145,19 +5322,19 @@ function applyEditBlocks(blocks, rootDir) {
|
|
|
5145
5322
|
return blocks.map((b) => applyEditBlock(b, rootDir));
|
|
5146
5323
|
}
|
|
5147
5324
|
function snapshotBeforeEdits(blocks, rootDir) {
|
|
5148
|
-
const absRoot =
|
|
5325
|
+
const absRoot = resolve5(rootDir);
|
|
5149
5326
|
const seen = /* @__PURE__ */ new Set();
|
|
5150
5327
|
const snapshots = [];
|
|
5151
5328
|
for (const b of blocks) {
|
|
5152
5329
|
if (seen.has(b.path)) continue;
|
|
5153
5330
|
seen.add(b.path);
|
|
5154
|
-
const abs =
|
|
5155
|
-
if (!
|
|
5331
|
+
const abs = resolve5(absRoot, b.path);
|
|
5332
|
+
if (!existsSync6(abs)) {
|
|
5156
5333
|
snapshots.push({ path: b.path, prevContent: null });
|
|
5157
5334
|
continue;
|
|
5158
5335
|
}
|
|
5159
5336
|
try {
|
|
5160
|
-
snapshots.push({ path: b.path, prevContent:
|
|
5337
|
+
snapshots.push({ path: b.path, prevContent: readFileSync8(abs, "utf8") });
|
|
5161
5338
|
} catch {
|
|
5162
5339
|
snapshots.push({ path: b.path, prevContent: null });
|
|
5163
5340
|
}
|
|
@@ -5165,9 +5342,9 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
5165
5342
|
return snapshots;
|
|
5166
5343
|
}
|
|
5167
5344
|
function restoreSnapshots(snapshots, rootDir) {
|
|
5168
|
-
const absRoot =
|
|
5345
|
+
const absRoot = resolve5(rootDir);
|
|
5169
5346
|
return snapshots.map((snap) => {
|
|
5170
|
-
const abs =
|
|
5347
|
+
const abs = resolve5(absRoot, snap.path);
|
|
5171
5348
|
if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep()}`)) {
|
|
5172
5349
|
return {
|
|
5173
5350
|
path: snap.path,
|
|
@@ -5177,7 +5354,7 @@ function restoreSnapshots(snapshots, rootDir) {
|
|
|
5177
5354
|
}
|
|
5178
5355
|
try {
|
|
5179
5356
|
if (snap.prevContent === null) {
|
|
5180
|
-
if (
|
|
5357
|
+
if (existsSync6(abs)) unlinkSync2(abs);
|
|
5181
5358
|
return {
|
|
5182
5359
|
path: snap.path,
|
|
5183
5360
|
status: "applied",
|
|
@@ -5200,9 +5377,9 @@ function sep() {
|
|
|
5200
5377
|
}
|
|
5201
5378
|
|
|
5202
5379
|
// src/version.ts
|
|
5203
|
-
import { existsSync as
|
|
5380
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
|
|
5204
5381
|
import { homedir as homedir4 } from "os";
|
|
5205
|
-
import { dirname as dirname6, join as
|
|
5382
|
+
import { dirname as dirname6, join as join7 } from "path";
|
|
5206
5383
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5207
5384
|
var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
|
|
5208
5385
|
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -5211,9 +5388,9 @@ function readPackageVersion() {
|
|
|
5211
5388
|
try {
|
|
5212
5389
|
let dir = dirname6(fileURLToPath2(import.meta.url));
|
|
5213
5390
|
for (let i = 0; i < 6; i++) {
|
|
5214
|
-
const p =
|
|
5215
|
-
if (
|
|
5216
|
-
const pkg = JSON.parse(
|
|
5391
|
+
const p = join7(dir, "package.json");
|
|
5392
|
+
if (existsSync7(p)) {
|
|
5393
|
+
const pkg = JSON.parse(readFileSync9(p, "utf8"));
|
|
5217
5394
|
if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
|
|
5218
5395
|
return pkg.version;
|
|
5219
5396
|
}
|
|
@@ -5228,11 +5405,11 @@ function readPackageVersion() {
|
|
|
5228
5405
|
}
|
|
5229
5406
|
var VERSION = readPackageVersion();
|
|
5230
5407
|
function cachePath(homeDirOverride) {
|
|
5231
|
-
return
|
|
5408
|
+
return join7(homeDirOverride ?? homedir4(), ".reasonix", "version-cache.json");
|
|
5232
5409
|
}
|
|
5233
5410
|
function readCache(homeDirOverride) {
|
|
5234
5411
|
try {
|
|
5235
|
-
const raw =
|
|
5412
|
+
const raw = readFileSync9(cachePath(homeDirOverride), "utf8");
|
|
5236
5413
|
const parsed = JSON.parse(raw);
|
|
5237
5414
|
if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
|
|
5238
5415
|
return parsed;
|
|
@@ -5301,11 +5478,11 @@ function isNpxInstall() {
|
|
|
5301
5478
|
}
|
|
5302
5479
|
|
|
5303
5480
|
// src/usage.ts
|
|
5304
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
5481
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
|
|
5305
5482
|
import { homedir as homedir5 } from "os";
|
|
5306
|
-
import { dirname as dirname7, join as
|
|
5483
|
+
import { dirname as dirname7, join as join8 } from "path";
|
|
5307
5484
|
function defaultUsageLogPath(homeDirOverride) {
|
|
5308
|
-
return
|
|
5485
|
+
return join8(homeDirOverride ?? homedir5(), ".reasonix", "usage.jsonl");
|
|
5309
5486
|
}
|
|
5310
5487
|
function appendUsage(input) {
|
|
5311
5488
|
const record = {
|
|
@@ -5329,10 +5506,10 @@ function appendUsage(input) {
|
|
|
5329
5506
|
return record;
|
|
5330
5507
|
}
|
|
5331
5508
|
function readUsageLog(path = defaultUsageLogPath()) {
|
|
5332
|
-
if (!
|
|
5509
|
+
if (!existsSync8(path)) return [];
|
|
5333
5510
|
let raw;
|
|
5334
5511
|
try {
|
|
5335
|
-
raw =
|
|
5512
|
+
raw = readFileSync10(path, "utf8");
|
|
5336
5513
|
} catch {
|
|
5337
5514
|
return [];
|
|
5338
5515
|
}
|
|
@@ -5414,9 +5591,9 @@ function aggregateUsage(records, opts = {}) {
|
|
|
5414
5591
|
};
|
|
5415
5592
|
}
|
|
5416
5593
|
function formatLogSize(path = defaultUsageLogPath()) {
|
|
5417
|
-
if (!
|
|
5594
|
+
if (!existsSync8(path)) return "";
|
|
5418
5595
|
try {
|
|
5419
|
-
const s =
|
|
5596
|
+
const s = statSync4(path);
|
|
5420
5597
|
const bytes = s.size;
|
|
5421
5598
|
if (bytes < 1024) return `${bytes} B`;
|
|
5422
5599
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -5427,13 +5604,13 @@ function formatLogSize(path = defaultUsageLogPath()) {
|
|
|
5427
5604
|
}
|
|
5428
5605
|
|
|
5429
5606
|
// src/cli/commands/chat.tsx
|
|
5430
|
-
import { existsSync as
|
|
5607
|
+
import { existsSync as existsSync10, statSync as statSync6 } from "fs";
|
|
5431
5608
|
import { render } from "ink";
|
|
5432
|
-
import
|
|
5609
|
+
import React16, { useState as useState7 } from "react";
|
|
5433
5610
|
|
|
5434
5611
|
// src/cli/ui/App.tsx
|
|
5435
|
-
import { Box as
|
|
5436
|
-
import
|
|
5612
|
+
import { Box as Box12, Static, Text as Text12, useApp, useInput as useInput4 } from "ink";
|
|
5613
|
+
import React13, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState5 } from "react";
|
|
5437
5614
|
|
|
5438
5615
|
// src/tools/skills.ts
|
|
5439
5616
|
function registerSkillTools(registry, opts = {}) {
|
|
@@ -5504,13 +5681,44 @@ ${skill.body}${argsBlock}`;
|
|
|
5504
5681
|
return registry;
|
|
5505
5682
|
}
|
|
5506
5683
|
|
|
5684
|
+
// src/cli/ui/AtMentionSuggestions.tsx
|
|
5685
|
+
import { Box, Text } from "ink";
|
|
5686
|
+
import React from "react";
|
|
5687
|
+
function AtMentionSuggestions({
|
|
5688
|
+
matches,
|
|
5689
|
+
selectedIndex,
|
|
5690
|
+
query
|
|
5691
|
+
}) {
|
|
5692
|
+
if (matches === null) return null;
|
|
5693
|
+
if (matches.length === 0) {
|
|
5694
|
+
return /* @__PURE__ */ React.createElement(Box, { paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, 'no files match "@', query, '"'), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " ", "\u2014 keep typing, or Backspace to edit. Paths resolve from the code root."));
|
|
5695
|
+
}
|
|
5696
|
+
const MAX = 8;
|
|
5697
|
+
const total = matches.length;
|
|
5698
|
+
const windowStart = total <= MAX ? 0 : Math.max(0, Math.min(selectedIndex - Math.floor(MAX / 2), total - MAX));
|
|
5699
|
+
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
5700
|
+
const hiddenAbove = windowStart;
|
|
5701
|
+
const hiddenBelow = total - windowStart - shown.length;
|
|
5702
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((path, i) => /* @__PURE__ */ React.createElement(FileRow, { key: path, path, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick \xB7 file content inlined on send"));
|
|
5703
|
+
}
|
|
5704
|
+
function FileRow({ path, isSelected }) {
|
|
5705
|
+
const marker = isSelected ? "\u25B8" : " ";
|
|
5706
|
+
const slash = path.lastIndexOf("/");
|
|
5707
|
+
const dir = slash >= 0 ? `${path.slice(0, slash)}/` : "";
|
|
5708
|
+
const base = slash >= 0 ? path.slice(slash + 1) : path;
|
|
5709
|
+
if (isSelected) {
|
|
5710
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "cyan" }, marker, " ", base), /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, dir ? ` ${dir}` : ""));
|
|
5711
|
+
}
|
|
5712
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, marker, " ", base, dir ? ` ${dir}` : ""));
|
|
5713
|
+
}
|
|
5714
|
+
|
|
5507
5715
|
// src/cli/ui/EventLog.tsx
|
|
5508
|
-
import { Box as
|
|
5509
|
-
import
|
|
5716
|
+
import { Box as Box4, Text as Text4, useStdout } from "ink";
|
|
5717
|
+
import React5 from "react";
|
|
5510
5718
|
|
|
5511
5719
|
// src/cli/ui/PlanStateBlock.tsx
|
|
5512
|
-
import { Box, Text } from "ink";
|
|
5513
|
-
import
|
|
5720
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
5721
|
+
import React2 from "react";
|
|
5514
5722
|
function PlanStateBlock({ planState }) {
|
|
5515
5723
|
const fields = [];
|
|
5516
5724
|
if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "cyan", false]);
|
|
@@ -5521,14 +5729,14 @@ function PlanStateBlock({ planState }) {
|
|
|
5521
5729
|
if (planState.rejectedPaths.length)
|
|
5522
5730
|
fields.push(["rejected", planState.rejectedPaths, "red", true]);
|
|
5523
5731
|
if (fields.length === 0) return null;
|
|
5524
|
-
return /* @__PURE__ */
|
|
5732
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React2.createElement(Text2, { key: label }, /* @__PURE__ */ React2.createElement(Text2, { color, bold: true, dimColor: dim }, "\u2039 ", label), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, ` (${items.length})`), /* @__PURE__ */ React2.createElement(Text2, null, `: ${items.join(" \xB7 ")}`))));
|
|
5525
5733
|
}
|
|
5526
5734
|
|
|
5527
5735
|
// src/cli/ui/markdown.tsx
|
|
5528
|
-
import { readFileSync as
|
|
5529
|
-
import { isAbsolute as
|
|
5530
|
-
import { Box as
|
|
5531
|
-
import
|
|
5736
|
+
import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
|
|
5737
|
+
import { isAbsolute as isAbsolute4, join as join9 } from "path";
|
|
5738
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
5739
|
+
import React3 from "react";
|
|
5532
5740
|
var SUPERSCRIPT = {
|
|
5533
5741
|
"0": "\u2070",
|
|
5534
5742
|
"1": "\xB9",
|
|
@@ -5604,10 +5812,10 @@ function parseCitationUrl(url) {
|
|
|
5604
5812
|
function validateCitation(url, projectRoot) {
|
|
5605
5813
|
const parts = parseCitationUrl(url);
|
|
5606
5814
|
if (!parts || !parts.path) return { ok: false, reason: "empty path" };
|
|
5607
|
-
const fullPath =
|
|
5815
|
+
const fullPath = isAbsolute4(parts.path) ? parts.path : join9(projectRoot, parts.path);
|
|
5608
5816
|
let stat;
|
|
5609
5817
|
try {
|
|
5610
|
-
stat =
|
|
5818
|
+
stat = statSync5(fullPath);
|
|
5611
5819
|
} catch {
|
|
5612
5820
|
return { ok: false, reason: "file not found" };
|
|
5613
5821
|
}
|
|
@@ -5615,7 +5823,7 @@ function validateCitation(url, projectRoot) {
|
|
|
5615
5823
|
if (parts.startLine === void 0) return { ok: true };
|
|
5616
5824
|
let lineCount;
|
|
5617
5825
|
try {
|
|
5618
|
-
lineCount =
|
|
5826
|
+
lineCount = readFileSync11(fullPath, "utf8").split("\n").length;
|
|
5619
5827
|
} catch {
|
|
5620
5828
|
return { ok: false, reason: "unreadable" };
|
|
5621
5829
|
}
|
|
@@ -5652,57 +5860,57 @@ function InlineMd({
|
|
|
5652
5860
|
for (const m of text.matchAll(INLINE_RE)) {
|
|
5653
5861
|
const start = m.index ?? 0;
|
|
5654
5862
|
if (start > last) {
|
|
5655
|
-
parts.push(/* @__PURE__ */
|
|
5863
|
+
parts.push(/* @__PURE__ */ React3.createElement(Text3, { key: `t${idx++}` }, text.slice(last, start)));
|
|
5656
5864
|
}
|
|
5657
5865
|
if (m[2] !== void 0 && m[3] !== void 0) {
|
|
5658
5866
|
const linkText = m[2];
|
|
5659
5867
|
const url = m[3];
|
|
5660
5868
|
if (isExternalUrl(url)) {
|
|
5661
5869
|
parts.push(
|
|
5662
|
-
/* @__PURE__ */
|
|
5870
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
|
|
5663
5871
|
);
|
|
5664
5872
|
} else {
|
|
5665
5873
|
const status = citations?.get(url);
|
|
5666
5874
|
if (status && !status.ok) {
|
|
5667
5875
|
parts.push(
|
|
5668
|
-
/* @__PURE__ */
|
|
5876
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
|
|
5669
5877
|
);
|
|
5670
5878
|
} else {
|
|
5671
5879
|
parts.push(
|
|
5672
|
-
/* @__PURE__ */
|
|
5880
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
|
|
5673
5881
|
);
|
|
5674
5882
|
}
|
|
5675
5883
|
}
|
|
5676
5884
|
} else if (m[4] !== void 0) {
|
|
5677
5885
|
parts.push(
|
|
5678
|
-
/* @__PURE__ */
|
|
5886
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `b${idx++}`, bold: true }, m[4])
|
|
5679
5887
|
);
|
|
5680
5888
|
} else if (m[5] !== void 0) {
|
|
5681
5889
|
const stripped = m[5].replace(/^(\w+)\s+/, "");
|
|
5682
5890
|
parts.push(
|
|
5683
|
-
/* @__PURE__ */
|
|
5891
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `c${idx++}`, color: "yellow" }, stripped)
|
|
5684
5892
|
);
|
|
5685
5893
|
} else if (m[6] !== void 0) {
|
|
5686
5894
|
parts.push(
|
|
5687
|
-
/* @__PURE__ */
|
|
5895
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `c${idx++}`, color: "yellow" }, m[6])
|
|
5688
5896
|
);
|
|
5689
5897
|
} else if (m[7] !== void 0) {
|
|
5690
5898
|
parts.push(
|
|
5691
|
-
/* @__PURE__ */
|
|
5899
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `i${idx++}`, italic: true }, m[7])
|
|
5692
5900
|
);
|
|
5693
5901
|
}
|
|
5694
5902
|
last = start + m[0].length;
|
|
5695
5903
|
}
|
|
5696
5904
|
if (last < text.length) {
|
|
5697
|
-
parts.push(/* @__PURE__ */
|
|
5905
|
+
parts.push(/* @__PURE__ */ React3.createElement(Text3, { key: `t${idx++}` }, text.slice(last)));
|
|
5698
5906
|
}
|
|
5699
5907
|
if (padTo !== void 0) {
|
|
5700
5908
|
const seen = visibleWidth(text);
|
|
5701
5909
|
if (seen < padTo) {
|
|
5702
|
-
parts.push(/* @__PURE__ */
|
|
5910
|
+
parts.push(/* @__PURE__ */ React3.createElement(Text3, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
|
|
5703
5911
|
}
|
|
5704
5912
|
}
|
|
5705
|
-
return /* @__PURE__ */
|
|
5913
|
+
return /* @__PURE__ */ React3.createElement(Text3, null, parts);
|
|
5706
5914
|
}
|
|
5707
5915
|
function stripInlineMarkup(s) {
|
|
5708
5916
|
return s.replace(/\[([^\]\n]+)\]\(([^)\n]+)\)/g, "$1").replace(/\*\*([^*\n]+?)\*\*/g, "$1").replace(/```([^\n]+?)```/g, (_m, c) => c.replace(/^(\w+)\s+/, "")).replace(/`([^`\n]+?)`/g, "$1").replace(/(?<![*\w])\*([^*\n]+?)\*(?!\w)/g, "$1");
|
|
@@ -5898,19 +6106,19 @@ function parseBlocks(raw) {
|
|
|
5898
6106
|
function BlockView({ block, citations }) {
|
|
5899
6107
|
switch (block.kind) {
|
|
5900
6108
|
case "heading":
|
|
5901
|
-
return /* @__PURE__ */
|
|
6109
|
+
return /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, /* @__PURE__ */ React3.createElement(InlineMd, { text: block.text, citations }));
|
|
5902
6110
|
case "paragraph":
|
|
5903
|
-
return /* @__PURE__ */
|
|
6111
|
+
return /* @__PURE__ */ React3.createElement(InlineMd, { text: block.text, citations });
|
|
5904
6112
|
case "bullet":
|
|
5905
|
-
return /* @__PURE__ */
|
|
6113
|
+
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React3.createElement(Box3, { key: `${i}-${item.slice(0, 24)}` }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, block.ordered ? ` ${block.start + i}. ` : " \u2022 "), /* @__PURE__ */ React3.createElement(InlineMd, { text: item, citations }))));
|
|
5906
6114
|
case "code":
|
|
5907
|
-
return /* @__PURE__ */
|
|
6115
|
+
return /* @__PURE__ */ React3.createElement(Box3, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, block.text));
|
|
5908
6116
|
case "edit-block":
|
|
5909
|
-
return /* @__PURE__ */
|
|
6117
|
+
return /* @__PURE__ */ React3.createElement(EditBlockRow, { block });
|
|
5910
6118
|
case "table":
|
|
5911
|
-
return /* @__PURE__ */
|
|
6119
|
+
return /* @__PURE__ */ React3.createElement(TableBlockRow, { block, citations });
|
|
5912
6120
|
case "hr":
|
|
5913
|
-
return /* @__PURE__ */
|
|
6121
|
+
return /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
5914
6122
|
}
|
|
5915
6123
|
}
|
|
5916
6124
|
function splitTableRow(line) {
|
|
@@ -5928,14 +6136,14 @@ function TableBlockRow({ block, citations }) {
|
|
|
5928
6136
|
widths.push(Math.min(40, Math.max(3, ...cellLengths)));
|
|
5929
6137
|
}
|
|
5930
6138
|
const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
|
|
5931
|
-
return /* @__PURE__ */
|
|
6139
|
+
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Box3, null, block.header.map((cell, ci) => (
|
|
5932
6140
|
// biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
|
|
5933
|
-
/* @__PURE__ */
|
|
5934
|
-
))), /* @__PURE__ */
|
|
6141
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React3.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
6142
|
+
))), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, separator), block.rows.map((row2, ri) => (
|
|
5935
6143
|
// biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
|
|
5936
|
-
/* @__PURE__ */
|
|
6144
|
+
/* @__PURE__ */ React3.createElement(Box3, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
|
|
5937
6145
|
// biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
|
|
5938
|
-
/* @__PURE__ */
|
|
6146
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React3.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
5939
6147
|
)))
|
|
5940
6148
|
)));
|
|
5941
6149
|
}
|
|
@@ -5955,28 +6163,28 @@ function EditBlockRow({ block }) {
|
|
|
5955
6163
|
const isNewFile = block.search.length === 0;
|
|
5956
6164
|
const searchLines = block.search.split("\n");
|
|
5957
6165
|
const replaceLines = block.replace.split("\n");
|
|
5958
|
-
return /* @__PURE__ */
|
|
6166
|
+
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React3.createElement(Text3, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React3.createElement(Text3, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React3.createElement(Text3, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
|
|
5959
6167
|
}
|
|
5960
6168
|
function Markdown({ text, projectRoot }) {
|
|
5961
6169
|
const cleaned = stripMath(text);
|
|
5962
6170
|
const root = projectRoot ?? process.cwd();
|
|
5963
|
-
const citations =
|
|
5964
|
-
const blocks =
|
|
6171
|
+
const citations = React3.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
|
|
6172
|
+
const blocks = React3.useMemo(() => parseBlocks(cleaned), [cleaned]);
|
|
5965
6173
|
const broken = [];
|
|
5966
6174
|
for (const [url, status] of citations) {
|
|
5967
6175
|
if (!status.ok) broken.push({ url, reason: status.reason });
|
|
5968
6176
|
}
|
|
5969
|
-
return /* @__PURE__ */
|
|
6177
|
+
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React3.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React3.createElement(BrokenCitationsBlock, { items: broken }) : null);
|
|
5970
6178
|
}
|
|
5971
6179
|
function BrokenCitationsBlock({ items }) {
|
|
5972
|
-
return /* @__PURE__ */
|
|
6180
|
+
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "red", bold: true }, `\u26A0 ${items.length} broken citation${items.length > 1 ? "s" : ""} \u2014 the model referenced paths or lines that don't exist`), items.map((b, i) => (
|
|
5973
6181
|
// biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
|
|
5974
|
-
/* @__PURE__ */
|
|
6182
|
+
/* @__PURE__ */ React3.createElement(Text3, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
|
|
5975
6183
|
)));
|
|
5976
6184
|
}
|
|
5977
6185
|
|
|
5978
6186
|
// src/cli/ui/ticker.tsx
|
|
5979
|
-
import
|
|
6187
|
+
import React4, { createContext, useContext, useEffect, useState } from "react";
|
|
5980
6188
|
var TICK_MS = 120;
|
|
5981
6189
|
var TickContext = createContext(0);
|
|
5982
6190
|
function TickerProvider({ children, disabled }) {
|
|
@@ -5986,7 +6194,7 @@ function TickerProvider({ children, disabled }) {
|
|
|
5986
6194
|
const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
|
|
5987
6195
|
return () => clearInterval(id);
|
|
5988
6196
|
}, [disabled]);
|
|
5989
|
-
return /* @__PURE__ */
|
|
6197
|
+
return /* @__PURE__ */ React4.createElement(TickContext.Provider, { value: tick }, children);
|
|
5990
6198
|
}
|
|
5991
6199
|
function useTick() {
|
|
5992
6200
|
return useContext(TickContext);
|
|
@@ -6012,18 +6220,18 @@ function RoleGlyph({
|
|
|
6012
6220
|
glyph,
|
|
6013
6221
|
color
|
|
6014
6222
|
}) {
|
|
6015
|
-
return /* @__PURE__ */
|
|
6223
|
+
return /* @__PURE__ */ React5.createElement(Text4, { color, bold: true }, glyph);
|
|
6016
6224
|
}
|
|
6017
|
-
var EventRow =
|
|
6225
|
+
var EventRow = React5.memo(function EventRow2({
|
|
6018
6226
|
event,
|
|
6019
6227
|
projectRoot
|
|
6020
6228
|
}) {
|
|
6021
6229
|
if (event.role === "user") {
|
|
6022
|
-
return /* @__PURE__ */
|
|
6230
|
+
return /* @__PURE__ */ React5.createElement(Box4, { marginTop: event.leadSeparator ? 1 : 0 }, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React5.createElement(Text4, null, " ", event.text));
|
|
6023
6231
|
}
|
|
6024
6232
|
if (event.role === "assistant") {
|
|
6025
|
-
if (event.streaming) return /* @__PURE__ */
|
|
6026
|
-
return /* @__PURE__ */
|
|
6233
|
+
if (event.streaming) return /* @__PURE__ */ React5.createElement(StreamingAssistant, { event });
|
|
6234
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` ${event.stats.model}`) : null), /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, event.branch ? /* @__PURE__ */ React5.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React5.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React5.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React5.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React5.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React5.createElement(Text4, { color: "magenta" }, event.repair) : null));
|
|
6027
6235
|
}
|
|
6028
6236
|
if (event.role === "tool") {
|
|
6029
6237
|
const isError = event.text.startsWith("ERROR:");
|
|
@@ -6031,31 +6239,31 @@ var EventRow = React4.memo(function EventRow2({
|
|
|
6031
6239
|
const glyph = isError ? ROLE_GLYPH.toolErr : ROLE_GLYPH.toolOk;
|
|
6032
6240
|
const marker = isError ? "\u2717" : "\u2192";
|
|
6033
6241
|
const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isError;
|
|
6034
|
-
return /* @__PURE__ */
|
|
6242
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph, color }), /* @__PURE__ */ React5.createElement(Text4, { color, bold: true }, ` ${event.toolName ?? "?"}`), /* @__PURE__ */ React5.createElement(Text4, { color, dimColor: true }, ` ${marker}`)), /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, isEditFile ? /* @__PURE__ */ React5.createElement(EditFileDiff, { text: event.text }) : /* @__PURE__ */ React5.createElement(Text4, { color: isError ? "red" : void 0, dimColor: !isError }, truncate2(event.text, 400))));
|
|
6035
6243
|
}
|
|
6036
6244
|
if (event.role === "error") {
|
|
6037
|
-
return /* @__PURE__ */
|
|
6245
|
+
return /* @__PURE__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.error, color: "red" }), /* @__PURE__ */ React5.createElement(Text4, { color: "red" }, " ", event.text));
|
|
6038
6246
|
}
|
|
6039
6247
|
if (event.role === "info") {
|
|
6040
|
-
return /* @__PURE__ */
|
|
6248
|
+
return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, event.text));
|
|
6041
6249
|
}
|
|
6042
6250
|
if (event.role === "warning") {
|
|
6043
|
-
return /* @__PURE__ */
|
|
6251
|
+
return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.warning, color: "yellow" }), /* @__PURE__ */ React5.createElement(Text4, { color: "yellow" }, " ", event.text));
|
|
6044
6252
|
}
|
|
6045
|
-
return /* @__PURE__ */
|
|
6253
|
+
return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, null, event.text));
|
|
6046
6254
|
});
|
|
6047
6255
|
function EditFileDiff({ text }) {
|
|
6048
6256
|
const lines = text.split(/\r?\n/);
|
|
6049
6257
|
const [statusHeader, hunkHeader, ...body] = lines;
|
|
6050
|
-
return /* @__PURE__ */
|
|
6258
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
|
|
6051
6259
|
const key = `${i}-${line.slice(0, 32)}`;
|
|
6052
6260
|
if (line.startsWith("- ")) {
|
|
6053
|
-
return /* @__PURE__ */
|
|
6261
|
+
return /* @__PURE__ */ React5.createElement(Text4, { key, color: "red" }, line);
|
|
6054
6262
|
}
|
|
6055
6263
|
if (line.startsWith("+ ")) {
|
|
6056
|
-
return /* @__PURE__ */
|
|
6264
|
+
return /* @__PURE__ */ React5.createElement(Text4, { key, color: "green" }, line);
|
|
6057
6265
|
}
|
|
6058
|
-
return /* @__PURE__ */
|
|
6266
|
+
return /* @__PURE__ */ React5.createElement(Text4, { key, dimColor: true }, line);
|
|
6059
6267
|
}));
|
|
6060
6268
|
}
|
|
6061
6269
|
function BranchBlock({ branch }) {
|
|
@@ -6064,33 +6272,33 @@ function BranchBlock({ branch }) {
|
|
|
6064
6272
|
const t = (branch.temperatures[i] ?? 0).toFixed(1);
|
|
6065
6273
|
return `${marker} #${i} T=${t} u=${u}`;
|
|
6066
6274
|
}).join(" ");
|
|
6067
|
-
return /* @__PURE__ */
|
|
6275
|
+
return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { color: "blue" }, "\u2387 branched ", /* @__PURE__ */ React5.createElement(Text4, { bold: true }, branch.budget), ` samples \u2192 picked #${branch.chosenIndex} `, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, per)));
|
|
6068
6276
|
}
|
|
6069
6277
|
function ReasoningBlock({ reasoning }) {
|
|
6070
6278
|
const max = 260;
|
|
6071
6279
|
const flat = reasoning.replace(/\s+/g, " ").trim();
|
|
6072
6280
|
const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
|
|
6073
|
-
return /* @__PURE__ */
|
|
6281
|
+
return /* @__PURE__ */ React5.createElement(Box4, { marginBottom: 1 }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "\u258F "), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true, italic: true }, "thinking ", preview));
|
|
6074
6282
|
}
|
|
6075
6283
|
function Elapsed() {
|
|
6076
6284
|
const s = useElapsedSeconds();
|
|
6077
6285
|
const mm = String(Math.floor(s / 60)).padStart(2, "0");
|
|
6078
6286
|
const ss = String(s % 60).padStart(2, "0");
|
|
6079
|
-
return /* @__PURE__ */
|
|
6287
|
+
return /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, `${mm}:${ss}`);
|
|
6080
6288
|
}
|
|
6081
6289
|
function PulsingAssistantGlyph() {
|
|
6082
6290
|
const tick = useTick();
|
|
6083
6291
|
const on = Math.floor(tick / 4) % 2 === 0;
|
|
6084
|
-
return /* @__PURE__ */
|
|
6292
|
+
return /* @__PURE__ */ React5.createElement(Text4, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
|
|
6085
6293
|
}
|
|
6086
6294
|
function StreamingAssistant({ event }) {
|
|
6087
6295
|
if (event.branchProgress) {
|
|
6088
6296
|
const p = event.branchProgress;
|
|
6089
6297
|
if (p.completed === 0) {
|
|
6090
|
-
return /* @__PURE__ */
|
|
6298
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React5.createElement(Text4, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React5.createElement(Elapsed, null)), /* @__PURE__ */ React5.createElement(Text4, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
|
|
6091
6299
|
}
|
|
6092
6300
|
const pct2 = Math.round(p.completed / p.total * 100);
|
|
6093
|
-
return /* @__PURE__ */
|
|
6301
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React5.createElement(Text4, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React5.createElement(Elapsed, null)), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, " latest #", p.latestIndex, " T=", p.latestTemperature.toFixed(1), " u=", p.latestUncertainties, p.completed < p.total ? " \xB7 waiting for other samples\u2026" : " \xB7 selecting winner\u2026"));
|
|
6094
6302
|
}
|
|
6095
6303
|
const tail = lastLine(event.text, 140);
|
|
6096
6304
|
const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
|
|
@@ -6118,16 +6326,16 @@ function StreamingAssistant({ event }) {
|
|
|
6118
6326
|
label = parts.join(" \xB7 ");
|
|
6119
6327
|
labelColor = "green";
|
|
6120
6328
|
}
|
|
6121
|
-
return /* @__PURE__ */
|
|
6329
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React5.createElement(Text4, null, " "), /* @__PURE__ */ React5.createElement(Pulse, null), /* @__PURE__ */ React5.createElement(Text4, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React5.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "\u25B8 ", tail) : preFirstByte ? (
|
|
6122
6330
|
// Non-dim yellow: first-time users misread the dim version as
|
|
6123
6331
|
// "app frozen". The reassurance has to be VISIBLE to do its job.
|
|
6124
|
-
/* @__PURE__ */
|
|
6125
|
-
) : reasoningOnly ? /* @__PURE__ */
|
|
6332
|
+
/* @__PURE__ */ React5.createElement(Text4, { color: "yellow", italic: true }, " waiting for first byte \u2014 this is normal, typically 5-60s depending on model + load")
|
|
6333
|
+
) : reasoningOnly ? /* @__PURE__ */ React5.createElement(Text4, { color: "yellow", italic: true }, " R1 is thinking before it speaks \u2014 body text arrives when reasoning finishes (typically 20-90s, this is normal)") : toolCallOnly ? /* @__PURE__ */ React5.createElement(Text4, { color: "magenta", italic: true }, " tool-call arguments streaming \u2014 the model is about to dispatch a tool") : event.reasoning ? /* @__PURE__ */ React5.createElement(Text4, { color: "yellow", italic: true }, " R1 still reasoning \u2014 body text or tool call arrives when thinking finishes") : null);
|
|
6126
6334
|
}
|
|
6127
6335
|
function Pulse() {
|
|
6128
6336
|
const tick = useTick();
|
|
6129
6337
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
6130
|
-
return /* @__PURE__ */
|
|
6338
|
+
return /* @__PURE__ */ React5.createElement(Text4, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
|
|
6131
6339
|
}
|
|
6132
6340
|
function lastLine(s, maxChars) {
|
|
6133
6341
|
const flat = s.replace(/\s+/g, " ").trim();
|
|
@@ -6136,7 +6344,7 @@ function lastLine(s, maxChars) {
|
|
|
6136
6344
|
}
|
|
6137
6345
|
function StatsLine({ stats }) {
|
|
6138
6346
|
const hit = (stats.cacheHitRatio * 100).toFixed(1);
|
|
6139
|
-
return /* @__PURE__ */
|
|
6347
|
+
return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "\u258F "), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "cache ", hit, "% \xB7 tokens ", stats.usage.promptTokens, " \u2192 ", stats.usage.completionTokens, " \xB7 $", stats.cost.toFixed(6)));
|
|
6140
6348
|
}
|
|
6141
6349
|
function truncate2(s, max) {
|
|
6142
6350
|
if (s.length <= max) return s;
|
|
@@ -6159,12 +6367,12 @@ ${s.slice(-max)}`;
|
|
|
6159
6367
|
}
|
|
6160
6368
|
|
|
6161
6369
|
// src/cli/ui/PlanConfirm.tsx
|
|
6162
|
-
import { Box as
|
|
6163
|
-
import
|
|
6370
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
6371
|
+
import React7 from "react";
|
|
6164
6372
|
|
|
6165
6373
|
// src/cli/ui/Select.tsx
|
|
6166
|
-
import { Box as
|
|
6167
|
-
import
|
|
6374
|
+
import { Box as Box5, Text as Text5, useInput } from "ink";
|
|
6375
|
+
import React6, { useState as useState2 } from "react";
|
|
6168
6376
|
function SingleSelect({
|
|
6169
6377
|
items,
|
|
6170
6378
|
initialValue,
|
|
@@ -6189,7 +6397,7 @@ function SingleSelect({
|
|
|
6189
6397
|
onCancel();
|
|
6190
6398
|
}
|
|
6191
6399
|
});
|
|
6192
|
-
return /* @__PURE__ */
|
|
6400
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React6.createElement(
|
|
6193
6401
|
SelectRow,
|
|
6194
6402
|
{
|
|
6195
6403
|
key: item.value,
|
|
@@ -6197,7 +6405,7 @@ function SingleSelect({
|
|
|
6197
6405
|
active: i === index,
|
|
6198
6406
|
marker: i === index ? "\u25B8" : " "
|
|
6199
6407
|
}
|
|
6200
|
-
)), footer ? /* @__PURE__ */
|
|
6408
|
+
)), footer ? /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, footer)) : null);
|
|
6201
6409
|
}
|
|
6202
6410
|
function MultiSelect({
|
|
6203
6411
|
items,
|
|
@@ -6232,10 +6440,10 @@ function MultiSelect({
|
|
|
6232
6440
|
onCancel();
|
|
6233
6441
|
}
|
|
6234
6442
|
});
|
|
6235
|
-
return /* @__PURE__ */
|
|
6443
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, items.map((item, i) => {
|
|
6236
6444
|
const checked = selected.has(item.value);
|
|
6237
6445
|
const marker = checked ? "[x]" : "[ ]";
|
|
6238
|
-
return /* @__PURE__ */
|
|
6446
|
+
return /* @__PURE__ */ React6.createElement(
|
|
6239
6447
|
SelectRow,
|
|
6240
6448
|
{
|
|
6241
6449
|
key: item.value,
|
|
@@ -6244,7 +6452,7 @@ function MultiSelect({
|
|
|
6244
6452
|
marker: `${i === index ? "\u25B8" : " "} ${marker}`
|
|
6245
6453
|
}
|
|
6246
6454
|
);
|
|
6247
|
-
}), footer ? /* @__PURE__ */
|
|
6455
|
+
}), footer ? /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, footer)) : null);
|
|
6248
6456
|
}
|
|
6249
6457
|
function SelectRow({
|
|
6250
6458
|
item,
|
|
@@ -6252,7 +6460,7 @@ function SelectRow({
|
|
|
6252
6460
|
marker
|
|
6253
6461
|
}) {
|
|
6254
6462
|
const color = item.disabled ? "gray" : active ? "cyan" : void 0;
|
|
6255
|
-
return /* @__PURE__ */
|
|
6463
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text5, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, item.hint)) : null);
|
|
6256
6464
|
}
|
|
6257
6465
|
function findNextEnabled(items, from, step) {
|
|
6258
6466
|
if (items.length === 0) return 0;
|
|
@@ -6273,7 +6481,7 @@ function PlanConfirm({ plan, onChoose, maxRenderedChars, projectRoot }) {
|
|
|
6273
6481
|
|
|
6274
6482
|
\u2026 (${plan.length - cap} chars truncated \u2014 use /tool to view the full proposal)` : plan;
|
|
6275
6483
|
const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan);
|
|
6276
|
-
return /* @__PURE__ */
|
|
6484
|
+
return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { bold: true, color: "cyan" }, "\u25B8 plan submitted \u2014 awaiting your review")), /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { color: "cyan", dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")), /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Markdown, { text: visible, projectRoot })), hasOpenQuestions ? /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u25B2 the plan has open questions or flagged risks \u2014 pick", " ", /* @__PURE__ */ React7.createElement(Text6, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null, /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(
|
|
6277
6485
|
SingleSelect,
|
|
6278
6486
|
{
|
|
6279
6487
|
initialValue: hasOpenQuestions ? "refine" : "approve",
|
|
@@ -6302,8 +6510,8 @@ function PlanConfirm({ plan, onChoose, maxRenderedChars, projectRoot }) {
|
|
|
6302
6510
|
}
|
|
6303
6511
|
|
|
6304
6512
|
// src/cli/ui/PlanRefineInput.tsx
|
|
6305
|
-
import { Box as
|
|
6306
|
-
import
|
|
6513
|
+
import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
|
|
6514
|
+
import React8, { useState as useState3 } from "react";
|
|
6307
6515
|
function PlanRefineInput({ mode, onSubmit, onCancel }) {
|
|
6308
6516
|
const [value, setValue] = useState3("");
|
|
6309
6517
|
useInput2((input, key) => {
|
|
@@ -6326,12 +6534,12 @@ function PlanRefineInput({ mode, onSubmit, onCancel }) {
|
|
|
6326
6534
|
const title = mode === "approve" ? "\u25B8 approving \u2014 any last instructions or answers to open questions?" : "\u25B8 refining \u2014 what should the model change?";
|
|
6327
6535
|
const hint = mode === "approve" ? "Answer questions the plan raised, add constraints, or just press Enter to approve as-is." : "Describe what's wrong or missing, or answer questions the plan raised.";
|
|
6328
6536
|
const blankHint = mode === "approve" ? " (Enter with blank = approve without extra instructions.)" : " (Enter with blank = ask the model to list concrete questions.)";
|
|
6329
|
-
return /* @__PURE__ */
|
|
6537
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "yellow" }, title)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, null, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u203A "), /* @__PURE__ */ React8.createElement(Text7, null, value || " "), /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u258D"))));
|
|
6330
6538
|
}
|
|
6331
6539
|
|
|
6332
6540
|
// src/cli/ui/PromptInput.tsx
|
|
6333
|
-
import { Box as
|
|
6334
|
-
import
|
|
6541
|
+
import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
|
|
6542
|
+
import React9, { useRef, useState as useState4 } from "react";
|
|
6335
6543
|
|
|
6336
6544
|
// src/cli/ui/multiline-keys.ts
|
|
6337
6545
|
var BACKSLASH_SUFFIX = /\\$/;
|
|
@@ -6491,13 +6699,13 @@ function PromptInput({
|
|
|
6491
6699
|
const lines = value.length > 0 ? value.split("\n") : [""];
|
|
6492
6700
|
const borderColor = disabled ? "gray" : "cyan";
|
|
6493
6701
|
const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
|
|
6494
|
-
return /* @__PURE__ */
|
|
6702
|
+
return /* @__PURE__ */ React9.createElement(Box8, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, lines.map((line, i) => {
|
|
6495
6703
|
const isFirst = i === 0;
|
|
6496
6704
|
const showPlaceholder = isFirst && value.length === 0;
|
|
6497
6705
|
const isCursorLine = i === cursorLine;
|
|
6498
6706
|
return (
|
|
6499
6707
|
// biome-ignore lint/suspicious/noArrayIndexKey: stable by construction — lines are derived from `value.split("\n")` and never reordered
|
|
6500
|
-
/* @__PURE__ */
|
|
6708
|
+
/* @__PURE__ */ React9.createElement(Box8, { key: i }, isFirst ? /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: borderColor }, "you \u203A", " ") : /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " "), showPlaceholder ? /* @__PURE__ */ React9.createElement(React9.Fragment, null, isCursorLine && !disabled ? /* @__PURE__ */ React9.createElement(Text8, { color: borderColor }, showCursor ? "\u258C" : " ") : null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, effectivePlaceholder)) : isCursorLine && !disabled ? /* @__PURE__ */ React9.createElement(
|
|
6501
6709
|
LineWithCursor,
|
|
6502
6710
|
{
|
|
6503
6711
|
line,
|
|
@@ -6505,7 +6713,7 @@ function PromptInput({
|
|
|
6505
6713
|
showCursor,
|
|
6506
6714
|
borderColor
|
|
6507
6715
|
}
|
|
6508
|
-
) : /* @__PURE__ */
|
|
6716
|
+
) : /* @__PURE__ */ React9.createElement(Text8, null, line))
|
|
6509
6717
|
);
|
|
6510
6718
|
}));
|
|
6511
6719
|
}
|
|
@@ -6519,16 +6727,16 @@ function LineWithCursor({
|
|
|
6519
6727
|
const atCursor = line.slice(col, col + 1);
|
|
6520
6728
|
const after = line.slice(col + 1);
|
|
6521
6729
|
if (atCursor.length === 0) {
|
|
6522
|
-
return /* @__PURE__ */
|
|
6730
|
+
return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Text8, null, before), /* @__PURE__ */ React9.createElement(Text8, { color: borderColor }, showCursor ? "\u258C" : " "));
|
|
6523
6731
|
}
|
|
6524
|
-
return /* @__PURE__ */
|
|
6732
|
+
return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Text8, null, before), /* @__PURE__ */ React9.createElement(Text8, { inverse: showCursor }, atCursor), /* @__PURE__ */ React9.createElement(Text8, null, after));
|
|
6525
6733
|
}
|
|
6526
6734
|
|
|
6527
6735
|
// src/cli/ui/ShellConfirm.tsx
|
|
6528
|
-
import { Box as
|
|
6529
|
-
import
|
|
6736
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
6737
|
+
import React10 from "react";
|
|
6530
6738
|
function ShellConfirm({ command, allowPrefix, onChoose }) {
|
|
6531
|
-
return /* @__PURE__ */
|
|
6739
|
+
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "yellow" }, "\u25B8 model wants to run a shell command")), /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow", dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "$ "), /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, command))), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
|
|
6532
6740
|
SingleSelect,
|
|
6533
6741
|
{
|
|
6534
6742
|
initialValue: "run_once",
|
|
@@ -6585,15 +6793,15 @@ function derivePrefix(command) {
|
|
|
6585
6793
|
}
|
|
6586
6794
|
|
|
6587
6795
|
// src/cli/ui/SlashSuggestions.tsx
|
|
6588
|
-
import { Box as
|
|
6589
|
-
import
|
|
6796
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
6797
|
+
import React11 from "react";
|
|
6590
6798
|
function SlashSuggestions({
|
|
6591
6799
|
matches,
|
|
6592
6800
|
selectedIndex
|
|
6593
6801
|
}) {
|
|
6594
6802
|
if (matches === null) return null;
|
|
6595
6803
|
if (matches.length === 0) {
|
|
6596
|
-
return /* @__PURE__ */
|
|
6804
|
+
return /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
|
|
6597
6805
|
}
|
|
6598
6806
|
const MAX = 8;
|
|
6599
6807
|
const total = matches.length;
|
|
@@ -6601,21 +6809,21 @@ function SlashSuggestions({
|
|
|
6601
6809
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
6602
6810
|
const hiddenAbove = windowStart;
|
|
6603
6811
|
const hiddenBelow = total - windowStart - shown.length;
|
|
6604
|
-
return /* @__PURE__ */
|
|
6812
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React11.createElement(SuggestionRow, { key: spec.cmd, spec, 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"));
|
|
6605
6813
|
}
|
|
6606
6814
|
function SuggestionRow({ spec, isSelected }) {
|
|
6607
6815
|
const marker = isSelected ? "\u25B8" : " ";
|
|
6608
6816
|
const name = `/${spec.cmd}`;
|
|
6609
6817
|
const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
|
|
6610
6818
|
if (isSelected) {
|
|
6611
|
-
return /* @__PURE__ */
|
|
6819
|
+
return /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React11.createElement(Text10, { color: "cyan" }, " ", spec.summary));
|
|
6612
6820
|
}
|
|
6613
|
-
return /* @__PURE__ */
|
|
6821
|
+
return /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
|
|
6614
6822
|
}
|
|
6615
6823
|
|
|
6616
6824
|
// src/cli/ui/StatsPanel.tsx
|
|
6617
|
-
import { Box as
|
|
6618
|
-
import
|
|
6825
|
+
import { Box as Box11, Text as Text11, useStdout as useStdout2 } from "ink";
|
|
6826
|
+
import React12 from "react";
|
|
6619
6827
|
var WORDMARK_STYLES = [
|
|
6620
6828
|
{ ch: "\u25C8", color: "#5eead4", isLogo: true },
|
|
6621
6829
|
// teal — brand mark
|
|
@@ -6641,7 +6849,7 @@ function Wordmark({ busy }) {
|
|
|
6641
6849
|
const tick = useTick();
|
|
6642
6850
|
const period = busy ? 5 : 12;
|
|
6643
6851
|
const bright = Math.floor(tick / period) % 2 === 0;
|
|
6644
|
-
return /* @__PURE__ */
|
|
6852
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, WORDMARK_STYLES.map((c) => /* @__PURE__ */ React12.createElement(Text11, { key: `${c.ch}-${c.color}`, color: c.color, bold: c.isLogo ? bright : true }, c.ch)));
|
|
6645
6853
|
}
|
|
6646
6854
|
var NARROW_BREAKPOINT = 120;
|
|
6647
6855
|
var COLD_START_TURNS = 3;
|
|
@@ -6663,7 +6871,7 @@ function StatsPanel({
|
|
|
6663
6871
|
const columns = stdout2?.columns ?? 80;
|
|
6664
6872
|
const narrow = columns < NARROW_BREAKPOINT;
|
|
6665
6873
|
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
6666
|
-
return /* @__PURE__ */
|
|
6874
|
+
return /* @__PURE__ */ React12.createElement(Box11, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(
|
|
6667
6875
|
Header,
|
|
6668
6876
|
{
|
|
6669
6877
|
model,
|
|
@@ -6677,7 +6885,7 @@ function StatsPanel({
|
|
|
6677
6885
|
narrow,
|
|
6678
6886
|
busy: busy ?? false
|
|
6679
6887
|
}
|
|
6680
|
-
), narrow ? /* @__PURE__ */
|
|
6888
|
+
), narrow ? /* @__PURE__ */ React12.createElement(
|
|
6681
6889
|
StackedMetrics,
|
|
6682
6890
|
{
|
|
6683
6891
|
summary,
|
|
@@ -6686,7 +6894,7 @@ function StatsPanel({
|
|
|
6686
6894
|
balance,
|
|
6687
6895
|
coldStart
|
|
6688
6896
|
}
|
|
6689
|
-
) : /* @__PURE__ */
|
|
6897
|
+
) : /* @__PURE__ */ React12.createElement(
|
|
6690
6898
|
InlineMetrics,
|
|
6691
6899
|
{
|
|
6692
6900
|
summary,
|
|
@@ -6709,7 +6917,7 @@ function Header({
|
|
|
6709
6917
|
narrow,
|
|
6710
6918
|
busy
|
|
6711
6919
|
}) {
|
|
6712
|
-
return /* @__PURE__ */
|
|
6920
|
+
return /* @__PURE__ */ React12.createElement(Box11, { justifyContent: "space-between" }, /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Wordmark, { busy }), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, ` v${VERSION}`), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React12.createElement(Text11, { color: "yellow" }, model), narrow ? null : /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, prefixHash)), harvestOn ? /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React12.createElement(Text11, { color: "blue" }, " \xB7 branch", branchBudget) : null, planMode ? /* @__PURE__ */ React12.createElement(Text11, { color: "red", bold: true }, " \xB7 PLAN") : null), /* @__PURE__ */ React12.createElement(Text11, null, updateAvailable ? /* @__PURE__ */ React12.createElement(Text11, { color: "yellow", bold: true }, `update: ${updateAvailable} \xB7 `) : null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, narrow ? `turn ${turns}` : `turn ${turns} \xB7 /help`)));
|
|
6713
6921
|
}
|
|
6714
6922
|
function InlineMetrics({
|
|
6715
6923
|
summary,
|
|
@@ -6718,7 +6926,7 @@ function InlineMetrics({
|
|
|
6718
6926
|
balance,
|
|
6719
6927
|
coldStart
|
|
6720
6928
|
}) {
|
|
6721
|
-
return /* @__PURE__ */
|
|
6929
|
+
return /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React12.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React12.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React12.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React12.createElement(BalanceCell, { balance }) : null);
|
|
6722
6930
|
}
|
|
6723
6931
|
function StackedMetrics({
|
|
6724
6932
|
summary,
|
|
@@ -6727,7 +6935,7 @@ function StackedMetrics({
|
|
|
6727
6935
|
balance,
|
|
6728
6936
|
coldStart
|
|
6729
6937
|
}) {
|
|
6730
|
-
return /* @__PURE__ */
|
|
6938
|
+
return /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(
|
|
6731
6939
|
ContextCell,
|
|
6732
6940
|
{
|
|
6733
6941
|
ratio: ctxRatio,
|
|
@@ -6735,7 +6943,7 @@ function StackedMetrics({
|
|
|
6735
6943
|
ctxMax,
|
|
6736
6944
|
showBar: true
|
|
6737
6945
|
}
|
|
6738
|
-
), balance ? /* @__PURE__ */
|
|
6946
|
+
), balance ? /* @__PURE__ */ React12.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React12.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React12.createElement(CostCell, { summary, coldStart }));
|
|
6739
6947
|
}
|
|
6740
6948
|
function ContextCell({
|
|
6741
6949
|
ratio,
|
|
@@ -6744,11 +6952,11 @@ function ContextCell({
|
|
|
6744
6952
|
showBar
|
|
6745
6953
|
}) {
|
|
6746
6954
|
if (promptTokens === 0) {
|
|
6747
|
-
return /* @__PURE__ */
|
|
6955
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "ctx "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "\u2014 (no turns yet)"));
|
|
6748
6956
|
}
|
|
6749
6957
|
const color = ratio >= 0.8 ? "red" : ratio >= 0.6 ? "yellow" : "green";
|
|
6750
6958
|
const pct2 = Math.round(ratio * 100);
|
|
6751
|
-
return /* @__PURE__ */
|
|
6959
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "ctx "), showBar ? /* @__PURE__ */ React12.createElement(Bar, { ratio, color }) : null, showBar ? /* @__PURE__ */ React12.createElement(Text11, null, " ") : null, /* @__PURE__ */ React12.createElement(Text11, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React12.createElement(Text11, { color: "red", bold: true }, " \xB7 /compact") : null);
|
|
6752
6960
|
}
|
|
6753
6961
|
function CacheCell({
|
|
6754
6962
|
hitRatio,
|
|
@@ -6757,33 +6965,33 @@ function CacheCell({
|
|
|
6757
6965
|
}) {
|
|
6758
6966
|
const pct2 = (hitRatio * 100).toFixed(1);
|
|
6759
6967
|
if (turns === 0) {
|
|
6760
|
-
return /* @__PURE__ */
|
|
6968
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cache "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "\u2014"));
|
|
6761
6969
|
}
|
|
6762
6970
|
if (coldStart) {
|
|
6763
|
-
return /* @__PURE__ */
|
|
6971
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cache "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true, italic: true }, "(cold start)"));
|
|
6764
6972
|
}
|
|
6765
6973
|
const color = hitRatio >= 0.7 ? "green" : hitRatio >= 0.4 ? "yellow" : "red";
|
|
6766
|
-
return /* @__PURE__ */
|
|
6974
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cache "), /* @__PURE__ */ React12.createElement(Text11, { color, bold: true }, pct2, "%"));
|
|
6767
6975
|
}
|
|
6768
6976
|
function CostCell({
|
|
6769
6977
|
summary,
|
|
6770
6978
|
coldStart
|
|
6771
6979
|
}) {
|
|
6772
6980
|
if (summary.turns === 0) {
|
|
6773
|
-
return /* @__PURE__ */
|
|
6981
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cost "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "\u2014"));
|
|
6774
6982
|
}
|
|
6775
6983
|
const primaryColor = coldStart ? void 0 : "green";
|
|
6776
|
-
return /* @__PURE__ */
|
|
6984
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cost "), /* @__PURE__ */ React12.createElement(Text11, { color: primaryColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")"));
|
|
6777
6985
|
}
|
|
6778
6986
|
function BalanceCell({ balance }) {
|
|
6779
6987
|
const color = balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green";
|
|
6780
|
-
return /* @__PURE__ */
|
|
6988
|
+
return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "balance "), /* @__PURE__ */ React12.createElement(Text11, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
|
|
6781
6989
|
}
|
|
6782
6990
|
function Bar({ ratio, color }) {
|
|
6783
6991
|
const cells = 10;
|
|
6784
6992
|
const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
|
|
6785
6993
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
|
|
6786
|
-
return /* @__PURE__ */
|
|
6994
|
+
return /* @__PURE__ */ React12.createElement(Text11, { color }, bar);
|
|
6787
6995
|
}
|
|
6788
6996
|
function formatTokens(n) {
|
|
6789
6997
|
if (n < 1024) return String(n);
|
|
@@ -6795,7 +7003,7 @@ function formatTokens(n) {
|
|
|
6795
7003
|
import { spawnSync } from "child_process";
|
|
6796
7004
|
|
|
6797
7005
|
// src/cli/commands/stats.ts
|
|
6798
|
-
import { existsSync as
|
|
7006
|
+
import { existsSync as existsSync9, readFileSync as readFileSync12 } from "fs";
|
|
6799
7007
|
function statsCommand(opts) {
|
|
6800
7008
|
if (opts.transcript) {
|
|
6801
7009
|
transcriptSummary(opts.transcript);
|
|
@@ -6804,11 +7012,11 @@ function statsCommand(opts) {
|
|
|
6804
7012
|
dashboard(opts);
|
|
6805
7013
|
}
|
|
6806
7014
|
function transcriptSummary(path) {
|
|
6807
|
-
if (!
|
|
7015
|
+
if (!existsSync9(path)) {
|
|
6808
7016
|
console.error(`no such transcript: ${path}`);
|
|
6809
7017
|
process.exit(1);
|
|
6810
7018
|
}
|
|
6811
|
-
const lines =
|
|
7019
|
+
const lines = readFileSync12(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
6812
7020
|
let assistantTurns = 0;
|
|
6813
7021
|
let toolCalls = 0;
|
|
6814
7022
|
let lastTurn = 0;
|
|
@@ -7944,6 +8152,39 @@ function App({
|
|
|
7944
8152
|
return prev;
|
|
7945
8153
|
});
|
|
7946
8154
|
}, [slashMatches]);
|
|
8155
|
+
const [atSelected, setAtSelected] = useState5(0);
|
|
8156
|
+
const atFiles = useMemo(() => {
|
|
8157
|
+
if (!codeMode?.rootDir) return [];
|
|
8158
|
+
try {
|
|
8159
|
+
return listFilesSync(codeMode.rootDir, { maxResults: 500 });
|
|
8160
|
+
} catch {
|
|
8161
|
+
return [];
|
|
8162
|
+
}
|
|
8163
|
+
}, [codeMode?.rootDir]);
|
|
8164
|
+
const atPicker = useMemo(() => {
|
|
8165
|
+
if (!codeMode?.rootDir) return null;
|
|
8166
|
+
if (slashMatches !== null) return null;
|
|
8167
|
+
return detectAtPicker(input);
|
|
8168
|
+
}, [codeMode?.rootDir, input, slashMatches]);
|
|
8169
|
+
const atMatches = useMemo(() => {
|
|
8170
|
+
if (!atPicker) return null;
|
|
8171
|
+
return rankPickerCandidates(atFiles, atPicker.query, 40);
|
|
8172
|
+
}, [atPicker, atFiles]);
|
|
8173
|
+
useEffect2(() => {
|
|
8174
|
+
setAtSelected((prev) => {
|
|
8175
|
+
if (!atMatches || atMatches.length === 0) return 0;
|
|
8176
|
+
if (prev >= atMatches.length) return atMatches.length - 1;
|
|
8177
|
+
return prev;
|
|
8178
|
+
});
|
|
8179
|
+
}, [atMatches]);
|
|
8180
|
+
const pickAtMention = useCallback(
|
|
8181
|
+
(chosenPath) => {
|
|
8182
|
+
if (!atPicker) return;
|
|
8183
|
+
const before = input.slice(0, atPicker.atOffset);
|
|
8184
|
+
setInput(`${before}@${chosenPath} `);
|
|
8185
|
+
},
|
|
8186
|
+
[atPicker, input]
|
|
8187
|
+
);
|
|
7947
8188
|
const loopRef = useRef2(null);
|
|
7948
8189
|
const subagentSinkRef = useRef2({ current: null });
|
|
7949
8190
|
const loop = useMemo(() => {
|
|
@@ -8113,6 +8354,21 @@ function App({
|
|
|
8113
8354
|
}
|
|
8114
8355
|
if (busy) return;
|
|
8115
8356
|
if (pendingShell) return;
|
|
8357
|
+
if (atMatches && atMatches.length > 0) {
|
|
8358
|
+
if (key.upArrow) {
|
|
8359
|
+
setAtSelected((i) => Math.max(0, i - 1));
|
|
8360
|
+
return;
|
|
8361
|
+
}
|
|
8362
|
+
if (key.downArrow) {
|
|
8363
|
+
setAtSelected((i) => Math.min(atMatches.length - 1, i + 1));
|
|
8364
|
+
return;
|
|
8365
|
+
}
|
|
8366
|
+
if (key.tab) {
|
|
8367
|
+
const sel = atMatches[atSelected] ?? atMatches[0];
|
|
8368
|
+
if (sel) pickAtMention(sel);
|
|
8369
|
+
return;
|
|
8370
|
+
}
|
|
8371
|
+
}
|
|
8116
8372
|
if (slashMatches && slashMatches.length > 0) {
|
|
8117
8373
|
if (key.upArrow) {
|
|
8118
8374
|
setSlashSelected((i) => Math.max(0, i - 1));
|
|
@@ -8198,6 +8454,13 @@ function App({
|
|
|
8198
8454
|
async (raw) => {
|
|
8199
8455
|
let text = raw.trim();
|
|
8200
8456
|
if (!text || busy) return;
|
|
8457
|
+
if (atMatches && atMatches.length > 0 && atPicker) {
|
|
8458
|
+
const sel = atMatches[atSelected] ?? atMatches[0];
|
|
8459
|
+
if (sel) {
|
|
8460
|
+
pickAtMention(sel);
|
|
8461
|
+
return;
|
|
8462
|
+
}
|
|
8463
|
+
}
|
|
8201
8464
|
if (text.startsWith("/") && !text.includes(" ")) {
|
|
8202
8465
|
const typed = text.slice(1).toLowerCase();
|
|
8203
8466
|
const matches = suggestSlashCommands(typed, !!codeMode);
|
|
@@ -8342,8 +8605,26 @@ function App({
|
|
|
8342
8605
|
});
|
|
8343
8606
|
};
|
|
8344
8607
|
const timer = PLAIN_UI ? null : setInterval(flush, FLUSH_INTERVAL_MS);
|
|
8608
|
+
let modelInput = text;
|
|
8609
|
+
if (codeMode?.rootDir) {
|
|
8610
|
+
const expanded = expandAtMentions(text, codeMode.rootDir);
|
|
8611
|
+
if (expanded.expansions.length > 0) {
|
|
8612
|
+
modelInput = expanded.text;
|
|
8613
|
+
const inlined = expanded.expansions.filter((ex) => ex.ok).map((ex) => `${ex.path} (${(ex.bytes ?? 0).toLocaleString()} bytes)`);
|
|
8614
|
+
const skipped = expanded.expansions.filter((ex) => !ex.ok).map((ex) => `${ex.path} (${ex.skip})`);
|
|
8615
|
+
const parts = [];
|
|
8616
|
+
if (inlined.length > 0) parts.push(`inlined ${inlined.join(", ")}`);
|
|
8617
|
+
if (skipped.length > 0) parts.push(`skipped ${skipped.join(", ")}`);
|
|
8618
|
+
if (parts.length > 0) {
|
|
8619
|
+
setHistorical((prev) => [
|
|
8620
|
+
...prev,
|
|
8621
|
+
{ id: `at-${Date.now()}`, role: "info", text: `\u25B8 @mentions: ${parts.join("; ")}` }
|
|
8622
|
+
]);
|
|
8623
|
+
}
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8345
8626
|
try {
|
|
8346
|
-
for await (const ev of loop.step(
|
|
8627
|
+
for await (const ev of loop.step(modelInput)) {
|
|
8347
8628
|
writeTranscript(ev);
|
|
8348
8629
|
if (ev.role !== "status") {
|
|
8349
8630
|
setStatusLine((cur) => cur ? null : cur);
|
|
@@ -8534,6 +8815,10 @@ function App({
|
|
|
8534
8815
|
planMode,
|
|
8535
8816
|
session,
|
|
8536
8817
|
slashSelected,
|
|
8818
|
+
atMatches,
|
|
8819
|
+
atPicker,
|
|
8820
|
+
atSelected,
|
|
8821
|
+
pickAtMention,
|
|
8537
8822
|
togglePlanMode,
|
|
8538
8823
|
writeTranscript
|
|
8539
8824
|
]
|
|
@@ -8684,7 +8969,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
8684
8969
|
if (stagedInput?.plan) setPendingPlan(stagedInput.plan);
|
|
8685
8970
|
setStagedInput(null);
|
|
8686
8971
|
}, [stagedInput]);
|
|
8687
|
-
return /* @__PURE__ */
|
|
8972
|
+
return /* @__PURE__ */ React13.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
|
|
8688
8973
|
StatsPanel,
|
|
8689
8974
|
{
|
|
8690
8975
|
summary,
|
|
@@ -8697,21 +8982,21 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
8697
8982
|
busy,
|
|
8698
8983
|
updateAvailable
|
|
8699
8984
|
}
|
|
8700
|
-
), /* @__PURE__ */
|
|
8985
|
+
), /* @__PURE__ */ React13.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React13.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && streaming ? /* @__PURE__ */ React13.createElement(Box12, { marginY: 1 }, /* @__PURE__ */ React13.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && ongoingTool ? /* @__PURE__ */ React13.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && subagentActivity ? /* @__PURE__ */ React13.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !ongoingTool && statusLine ? /* @__PURE__ */ React13.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React13.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React13.createElement(
|
|
8701
8986
|
PlanRefineInput,
|
|
8702
8987
|
{
|
|
8703
8988
|
mode: stagedInput.mode,
|
|
8704
8989
|
onSubmit: handleStagedInputSubmit,
|
|
8705
8990
|
onCancel: handleStagedInputCancel
|
|
8706
8991
|
}
|
|
8707
|
-
) : pendingPlan ? /* @__PURE__ */
|
|
8992
|
+
) : pendingPlan ? /* @__PURE__ */ React13.createElement(PlanConfirm, { plan: pendingPlan, onChoose: handlePlanConfirm, projectRoot: hookCwd }) : pendingShell ? /* @__PURE__ */ React13.createElement(
|
|
8708
8993
|
ShellConfirm,
|
|
8709
8994
|
{
|
|
8710
8995
|
command: pendingShell,
|
|
8711
8996
|
allowPrefix: derivePrefix(pendingShell),
|
|
8712
8997
|
onChoose: handleShellConfirm
|
|
8713
8998
|
}
|
|
8714
|
-
) : /* @__PURE__ */
|
|
8999
|
+
) : /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
|
|
8715
9000
|
PromptInput,
|
|
8716
9001
|
{
|
|
8717
9002
|
value: input,
|
|
@@ -8719,20 +9004,27 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
8719
9004
|
onSubmit: handleSubmit,
|
|
8720
9005
|
disabled: busy
|
|
8721
9006
|
}
|
|
8722
|
-
), /* @__PURE__ */
|
|
9007
|
+
), /* @__PURE__ */ React13.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React13.createElement(
|
|
9008
|
+
AtMentionSuggestions,
|
|
9009
|
+
{
|
|
9010
|
+
matches: atMatches,
|
|
9011
|
+
selectedIndex: atSelected,
|
|
9012
|
+
query: atPicker?.query ?? ""
|
|
9013
|
+
}
|
|
9014
|
+
))));
|
|
8723
9015
|
}
|
|
8724
9016
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8725
9017
|
function StatusRow({ text }) {
|
|
8726
9018
|
const tick = useTick();
|
|
8727
9019
|
const elapsed = useElapsedSeconds();
|
|
8728
|
-
return /* @__PURE__ */
|
|
9020
|
+
return /* @__PURE__ */ React13.createElement(Box12, { marginY: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` ${elapsed}s`));
|
|
8729
9021
|
}
|
|
8730
9022
|
function SubagentRow({
|
|
8731
9023
|
activity
|
|
8732
9024
|
}) {
|
|
8733
9025
|
const tick = useTick();
|
|
8734
9026
|
const seconds = (activity.elapsedMs / 1e3).toFixed(1);
|
|
8735
|
-
return /* @__PURE__ */
|
|
9027
|
+
return /* @__PURE__ */ React13.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, ` \u232C subagent: ${activity.task}`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
|
|
8736
9028
|
}
|
|
8737
9029
|
function OngoingToolRow({
|
|
8738
9030
|
tool,
|
|
@@ -8741,7 +9033,7 @@ function OngoingToolRow({
|
|
|
8741
9033
|
const tick = useTick();
|
|
8742
9034
|
const elapsed = useElapsedSeconds();
|
|
8743
9035
|
const summary = summarizeToolArgs(tool.name, tool.args);
|
|
8744
|
-
return /* @__PURE__ */
|
|
9036
|
+
return /* @__PURE__ */ React13.createElement(Box12, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React13.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React13.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, summary)) : null);
|
|
8745
9037
|
}
|
|
8746
9038
|
function renderProgressLine(p) {
|
|
8747
9039
|
const msg = p.message ? ` ${p.message}` : "";
|
|
@@ -8837,15 +9129,15 @@ function describeRepair(repair) {
|
|
|
8837
9129
|
}
|
|
8838
9130
|
|
|
8839
9131
|
// src/cli/ui/SessionPicker.tsx
|
|
8840
|
-
import { Box as
|
|
8841
|
-
import
|
|
9132
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
9133
|
+
import React14 from "react";
|
|
8842
9134
|
function SessionPicker({
|
|
8843
9135
|
sessionName,
|
|
8844
9136
|
messageCount,
|
|
8845
9137
|
lastActive,
|
|
8846
9138
|
onChoose
|
|
8847
9139
|
}) {
|
|
8848
|
-
return /* @__PURE__ */
|
|
9140
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` \xB7 last active ${relativeTime(lastActive)}`)), /* @__PURE__ */ React14.createElement(
|
|
8849
9141
|
SingleSelect,
|
|
8850
9142
|
{
|
|
8851
9143
|
initialValue: "new",
|
|
@@ -8868,7 +9160,7 @@ function SessionPicker({
|
|
|
8868
9160
|
],
|
|
8869
9161
|
onSubmit: (v) => onChoose(v)
|
|
8870
9162
|
}
|
|
8871
|
-
), /* @__PURE__ */
|
|
9163
|
+
), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "\u2191\u2193 to move \xB7 Enter to pick")));
|
|
8872
9164
|
}
|
|
8873
9165
|
function relativeTime(date) {
|
|
8874
9166
|
const ms = Date.now() - date.getTime();
|
|
@@ -8884,9 +9176,9 @@ function relativeTime(date) {
|
|
|
8884
9176
|
}
|
|
8885
9177
|
|
|
8886
9178
|
// src/cli/ui/Setup.tsx
|
|
8887
|
-
import { Box as
|
|
9179
|
+
import { Box as Box14, Text as Text14, useApp as useApp2 } from "ink";
|
|
8888
9180
|
import TextInput from "ink-text-input";
|
|
8889
|
-
import
|
|
9181
|
+
import React15, { useState as useState6 } from "react";
|
|
8890
9182
|
function Setup({ onReady }) {
|
|
8891
9183
|
const [value, setValue] = useState6("");
|
|
8892
9184
|
const [error, setError] = useState6(null);
|
|
@@ -8910,7 +9202,7 @@ function Setup({ onReady }) {
|
|
|
8910
9202
|
}
|
|
8911
9203
|
onReady(trimmed);
|
|
8912
9204
|
};
|
|
8913
|
-
return /* @__PURE__ */
|
|
9205
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text14, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React15.createElement(
|
|
8914
9206
|
TextInput,
|
|
8915
9207
|
{
|
|
8916
9208
|
value,
|
|
@@ -8919,7 +9211,7 @@ function Setup({ onReady }) {
|
|
|
8919
9211
|
mask: "\u2022",
|
|
8920
9212
|
placeholder: "sk-..."
|
|
8921
9213
|
}
|
|
8922
|
-
)), error ? /* @__PURE__ */
|
|
9214
|
+
)), error ? /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "red" }, error)) : value ? /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "(Type /exit to abort.)")));
|
|
8923
9215
|
}
|
|
8924
9216
|
|
|
8925
9217
|
// src/cli/commands/chat.tsx
|
|
@@ -8935,7 +9227,7 @@ function Root({
|
|
|
8935
9227
|
const [key, setKey] = useState7(initialKey);
|
|
8936
9228
|
const [pending, setPending] = useState7(sessionPreview);
|
|
8937
9229
|
if (!key) {
|
|
8938
|
-
return /* @__PURE__ */
|
|
9230
|
+
return /* @__PURE__ */ React16.createElement(
|
|
8939
9231
|
Setup,
|
|
8940
9232
|
{
|
|
8941
9233
|
onReady: (k) => {
|
|
@@ -8947,7 +9239,7 @@ function Root({
|
|
|
8947
9239
|
}
|
|
8948
9240
|
process.env.DEEPSEEK_API_KEY = key;
|
|
8949
9241
|
if (pending && appProps.session) {
|
|
8950
|
-
return /* @__PURE__ */
|
|
9242
|
+
return /* @__PURE__ */ React16.createElement(
|
|
8951
9243
|
SessionPicker,
|
|
8952
9244
|
{
|
|
8953
9245
|
sessionName: appProps.session,
|
|
@@ -8962,7 +9254,7 @@ function Root({
|
|
|
8962
9254
|
}
|
|
8963
9255
|
);
|
|
8964
9256
|
}
|
|
8965
|
-
return /* @__PURE__ */
|
|
9257
|
+
return /* @__PURE__ */ React16.createElement(
|
|
8966
9258
|
App,
|
|
8967
9259
|
{
|
|
8968
9260
|
model: appProps.model,
|
|
@@ -9058,14 +9350,14 @@ async function chatCommand(opts) {
|
|
|
9058
9350
|
const prior = loadSessionMessages(opts.session);
|
|
9059
9351
|
if (prior.length > 0) {
|
|
9060
9352
|
const p = sessionPath(opts.session);
|
|
9061
|
-
const mtime =
|
|
9353
|
+
const mtime = existsSync10(p) ? statSync6(p).mtime : /* @__PURE__ */ new Date();
|
|
9062
9354
|
sessionPreview = { messageCount: prior.length, lastActive: mtime };
|
|
9063
9355
|
}
|
|
9064
9356
|
} else if (opts.session && opts.forceNew) {
|
|
9065
9357
|
rewriteSession(opts.session, []);
|
|
9066
9358
|
}
|
|
9067
9359
|
const { waitUntilExit } = render(
|
|
9068
|
-
/* @__PURE__ */
|
|
9360
|
+
/* @__PURE__ */ React16.createElement(
|
|
9069
9361
|
Root,
|
|
9070
9362
|
{
|
|
9071
9363
|
initialKey,
|
|
@@ -9089,10 +9381,10 @@ async function chatCommand(opts) {
|
|
|
9089
9381
|
}
|
|
9090
9382
|
|
|
9091
9383
|
// src/cli/commands/code.tsx
|
|
9092
|
-
import { basename, resolve as
|
|
9384
|
+
import { basename, resolve as resolve6 } from "path";
|
|
9093
9385
|
async function codeCommand(opts = {}) {
|
|
9094
9386
|
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-75XLIUTO.js");
|
|
9095
|
-
const rootDir =
|
|
9387
|
+
const rootDir = resolve6(opts.dir ?? process.cwd());
|
|
9096
9388
|
const session = opts.noSession ? void 0 : `code-${sanitizeName(basename(rootDir))}`;
|
|
9097
9389
|
const tools = new ToolRegistry();
|
|
9098
9390
|
registerFilesystemTools(tools, { rootDir });
|
|
@@ -9128,34 +9420,34 @@ async function codeCommand(opts = {}) {
|
|
|
9128
9420
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
9129
9421
|
import { basename as basename2 } from "path";
|
|
9130
9422
|
import { render as render2 } from "ink";
|
|
9131
|
-
import
|
|
9423
|
+
import React19 from "react";
|
|
9132
9424
|
|
|
9133
9425
|
// src/cli/ui/DiffApp.tsx
|
|
9134
|
-
import { Box as
|
|
9135
|
-
import
|
|
9426
|
+
import { Box as Box16, Static as Static2, Text as Text16, useApp as useApp3, useInput as useInput5 } from "ink";
|
|
9427
|
+
import React18, { useState as useState8 } from "react";
|
|
9136
9428
|
|
|
9137
9429
|
// src/cli/ui/RecordView.tsx
|
|
9138
|
-
import { Box as
|
|
9139
|
-
import
|
|
9430
|
+
import { Box as Box15, Text as Text15 } from "ink";
|
|
9431
|
+
import React17 from "react";
|
|
9140
9432
|
function RecordView({ rec, compact = false }) {
|
|
9141
9433
|
const toolArgsMax = compact ? 120 : 200;
|
|
9142
9434
|
const toolContentMax = compact ? 200 : 400;
|
|
9143
9435
|
if (rec.role === "user") {
|
|
9144
|
-
return /* @__PURE__ */
|
|
9436
|
+
return /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React17.createElement(Text15, null, rec.content));
|
|
9145
9437
|
}
|
|
9146
9438
|
if (rec.role === "assistant_final") {
|
|
9147
|
-
return /* @__PURE__ */
|
|
9439
|
+
return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React17.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React17.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React17.createElement(Text15, null, rec.content) : /* @__PURE__ */ React17.createElement(Text15, { dimColor: true, italic: true }, "(tool-call response only)"));
|
|
9148
9440
|
}
|
|
9149
9441
|
if (rec.role === "tool") {
|
|
9150
|
-
return /* @__PURE__ */
|
|
9442
|
+
return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " args: ", truncate3(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \u2192 ", truncate3(rec.content, toolContentMax)));
|
|
9151
9443
|
}
|
|
9152
9444
|
if (rec.role === "error") {
|
|
9153
|
-
return /* @__PURE__ */
|
|
9445
|
+
return /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React17.createElement(Text15, { color: "red" }, rec.error ?? rec.content));
|
|
9154
9446
|
}
|
|
9155
9447
|
if (rec.role === "done" || rec.role === "assistant_delta") {
|
|
9156
9448
|
return null;
|
|
9157
9449
|
}
|
|
9158
|
-
return /* @__PURE__ */
|
|
9450
|
+
return /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "[", rec.role, "] ", rec.content));
|
|
9159
9451
|
}
|
|
9160
9452
|
function CacheBadge({ usage }) {
|
|
9161
9453
|
const hit = usage.prompt_cache_hit_tokens ?? 0;
|
|
@@ -9164,7 +9456,7 @@ function CacheBadge({ usage }) {
|
|
|
9164
9456
|
if (total === 0) return null;
|
|
9165
9457
|
const pct2 = hit / total * 100;
|
|
9166
9458
|
const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
|
|
9167
|
-
return /* @__PURE__ */
|
|
9459
|
+
return /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React17.createElement(Text15, { color }, pct2.toFixed(1), "%"));
|
|
9168
9460
|
}
|
|
9169
9461
|
function truncate3(s, max) {
|
|
9170
9462
|
return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
|
|
@@ -9198,7 +9490,7 @@ function DiffApp({ report }) {
|
|
|
9198
9490
|
}
|
|
9199
9491
|
});
|
|
9200
9492
|
const pair = report.pairs[idx];
|
|
9201
|
-
return /* @__PURE__ */
|
|
9493
|
+
return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column" }, /* @__PURE__ */ React18.createElement(DiffHeader, { report }), /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React18.createElement(Text16, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React18.createElement(Text16, null, pair ? /* @__PURE__ */ React18.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React18.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React18.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React18.createElement(Text16, null, pair.divergenceNote)) : null, /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "j"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "k"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "N"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "g"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "q"), " ", "quit")));
|
|
9202
9494
|
}
|
|
9203
9495
|
function DiffHeader({ report }) {
|
|
9204
9496
|
const a = report.a;
|
|
@@ -9216,15 +9508,15 @@ function DiffHeader({ report }) {
|
|
|
9216
9508
|
} else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
|
|
9217
9509
|
prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
|
|
9218
9510
|
}
|
|
9219
|
-
return /* @__PURE__ */
|
|
9511
|
+
return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React18.createElement(Box16, { justifyContent: "space-between" }, /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React18.createElement(Text16, { color: "blue" }, a.label), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " vs B="), /* @__PURE__ */ React18.createElement(Text16, { color: "magenta" }, b.label)), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, "cache "), /* @__PURE__ */ React18.createElement(Text16, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React18.createElement(Text16, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React18.createElement(Text16, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, "cost "), /* @__PURE__ */ React18.createElement(Text16, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React18.createElement(Text16, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React18.createElement(Text16, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, "model calls "), /* @__PURE__ */ React18.createElement(Text16, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true, italic: true }, prefixLine)) : null);
|
|
9220
9512
|
}
|
|
9221
9513
|
function Pane({
|
|
9222
9514
|
label,
|
|
9223
9515
|
headerColor,
|
|
9224
9516
|
records
|
|
9225
9517
|
}) {
|
|
9226
|
-
return /* @__PURE__ */
|
|
9227
|
-
|
|
9518
|
+
return /* @__PURE__ */ React18.createElement(
|
|
9519
|
+
Box16,
|
|
9228
9520
|
{
|
|
9229
9521
|
flexDirection: "column",
|
|
9230
9522
|
flexGrow: 1,
|
|
@@ -9232,21 +9524,21 @@ function Pane({
|
|
|
9232
9524
|
borderStyle: "single",
|
|
9233
9525
|
borderColor: headerColor
|
|
9234
9526
|
},
|
|
9235
|
-
/* @__PURE__ */
|
|
9236
|
-
records.length === 0 ? /* @__PURE__ */
|
|
9527
|
+
/* @__PURE__ */ React18.createElement(Text16, { color: headerColor, bold: true }, label),
|
|
9528
|
+
records.length === 0 ? /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React18.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React18.createElement(RecordView, { key, rec, compact: true }))
|
|
9237
9529
|
);
|
|
9238
9530
|
}
|
|
9239
9531
|
function KindBadge({ kind }) {
|
|
9240
9532
|
if (kind === "match") {
|
|
9241
|
-
return /* @__PURE__ */
|
|
9533
|
+
return /* @__PURE__ */ React18.createElement(Text16, { color: "green" }, "\u2713 match");
|
|
9242
9534
|
}
|
|
9243
9535
|
if (kind === "diverge") {
|
|
9244
|
-
return /* @__PURE__ */
|
|
9536
|
+
return /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, "\u2605 diverge");
|
|
9245
9537
|
}
|
|
9246
9538
|
if (kind === "only_in_a") {
|
|
9247
|
-
return /* @__PURE__ */
|
|
9539
|
+
return /* @__PURE__ */ React18.createElement(Text16, { color: "blue" }, "\u2190 only in A");
|
|
9248
9540
|
}
|
|
9249
|
-
return /* @__PURE__ */
|
|
9541
|
+
return /* @__PURE__ */ React18.createElement(Text16, { color: "magenta" }, "\u2192 only in B");
|
|
9250
9542
|
}
|
|
9251
9543
|
function paneRecords(pair, side) {
|
|
9252
9544
|
if (!pair) return [];
|
|
@@ -9277,7 +9569,7 @@ markdown report written to ${opts.mdPath}`);
|
|
|
9277
9569
|
return;
|
|
9278
9570
|
}
|
|
9279
9571
|
if (wantTui) {
|
|
9280
|
-
const { waitUntilExit } = render2(
|
|
9572
|
+
const { waitUntilExit } = render2(React19.createElement(DiffApp, { report }), {
|
|
9281
9573
|
exitOnCtrlC: true,
|
|
9282
9574
|
patchConsole: false
|
|
9283
9575
|
});
|
|
@@ -9418,11 +9710,11 @@ function pad2(s, width) {
|
|
|
9418
9710
|
|
|
9419
9711
|
// src/cli/commands/replay.ts
|
|
9420
9712
|
import { render as render3 } from "ink";
|
|
9421
|
-
import
|
|
9713
|
+
import React21 from "react";
|
|
9422
9714
|
|
|
9423
9715
|
// src/cli/ui/ReplayApp.tsx
|
|
9424
|
-
import { Box as
|
|
9425
|
-
import
|
|
9716
|
+
import { Box as Box17, Static as Static3, Text as Text17, useApp as useApp4, useInput as useInput6 } from "ink";
|
|
9717
|
+
import React20, { useMemo as useMemo2, useState as useState9 } from "react";
|
|
9426
9718
|
function ReplayApp({ meta, pages }) {
|
|
9427
9719
|
const { exit } = useApp4();
|
|
9428
9720
|
const maxIdx = Math.max(0, pages.length - 1);
|
|
@@ -9461,14 +9753,14 @@ function ReplayApp({ meta, pages }) {
|
|
|
9461
9753
|
const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
|
|
9462
9754
|
const currentPage = pages[idx];
|
|
9463
9755
|
const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
|
|
9464
|
-
return /* @__PURE__ */
|
|
9756
|
+
return /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column" }, /* @__PURE__ */ React20.createElement(
|
|
9465
9757
|
StatsPanel,
|
|
9466
9758
|
{
|
|
9467
9759
|
summary,
|
|
9468
9760
|
model: cumStats.models[0] ?? meta?.model ?? "?",
|
|
9469
9761
|
prefixHash
|
|
9470
9762
|
}
|
|
9471
|
-
), /* @__PURE__ */
|
|
9763
|
+
), /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React20.createElement(Box17, { justifyContent: "space-between" }, /* @__PURE__ */ React20.createElement(Text17, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React20.createElement(Text17, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React20.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React20.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React20.createElement(Text17, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React20.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "j"), "/", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "k"), "/", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "q"), " quit")));
|
|
9472
9764
|
}
|
|
9473
9765
|
|
|
9474
9766
|
// src/cli/commands/replay.ts
|
|
@@ -9480,7 +9772,7 @@ async function replayCommand(opts) {
|
|
|
9480
9772
|
}
|
|
9481
9773
|
const { parsed } = replayFromFile(opts.path);
|
|
9482
9774
|
const pages = groupRecordsByTurn(parsed.records);
|
|
9483
|
-
const { waitUntilExit } = render3(
|
|
9775
|
+
const { waitUntilExit } = render3(React21.createElement(ReplayApp, { meta: parsed.meta, pages }), {
|
|
9484
9776
|
exitOnCtrlC: true,
|
|
9485
9777
|
patchConsole: false
|
|
9486
9778
|
});
|
|
@@ -9785,12 +10077,12 @@ function truncate4(s, max) {
|
|
|
9785
10077
|
|
|
9786
10078
|
// src/cli/commands/setup.tsx
|
|
9787
10079
|
import { render as render4 } from "ink";
|
|
9788
|
-
import
|
|
10080
|
+
import React23 from "react";
|
|
9789
10081
|
|
|
9790
10082
|
// src/cli/ui/Wizard.tsx
|
|
9791
|
-
import { Box as
|
|
10083
|
+
import { Box as Box18, Text as Text18, useApp as useApp5, useInput as useInput7 } from "ink";
|
|
9792
10084
|
import TextInput2 from "ink-text-input";
|
|
9793
|
-
import
|
|
10085
|
+
import React22, { useState as useState10 } from "react";
|
|
9794
10086
|
|
|
9795
10087
|
// src/cli/ui/presets.ts
|
|
9796
10088
|
var PRESETS = {
|
|
@@ -9829,7 +10121,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
9829
10121
|
if (key.escape && step !== "saved" && onCancel) onCancel();
|
|
9830
10122
|
});
|
|
9831
10123
|
if (step === "apiKey") {
|
|
9832
|
-
return /* @__PURE__ */
|
|
10124
|
+
return /* @__PURE__ */ React22.createElement(
|
|
9833
10125
|
ApiKeyStep,
|
|
9834
10126
|
{
|
|
9835
10127
|
onSubmit: (key) => {
|
|
@@ -9843,7 +10135,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
9843
10135
|
);
|
|
9844
10136
|
}
|
|
9845
10137
|
if (step === "preset") {
|
|
9846
|
-
return /* @__PURE__ */
|
|
10138
|
+
return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React22.createElement(
|
|
9847
10139
|
SingleSelect,
|
|
9848
10140
|
{
|
|
9849
10141
|
items: presetItems(),
|
|
@@ -9853,10 +10145,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
9853
10145
|
setStep("mcp");
|
|
9854
10146
|
}
|
|
9855
10147
|
}
|
|
9856
|
-
), /* @__PURE__ */
|
|
10148
|
+
), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
|
|
9857
10149
|
}
|
|
9858
10150
|
if (step === "mcp") {
|
|
9859
|
-
return /* @__PURE__ */
|
|
10151
|
+
return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React22.createElement(
|
|
9860
10152
|
MultiSelect,
|
|
9861
10153
|
{
|
|
9862
10154
|
items: mcpItems(),
|
|
@@ -9881,7 +10173,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
9881
10173
|
}
|
|
9882
10174
|
const currentName = pending[0];
|
|
9883
10175
|
const entry = CATALOG_BY_NAME.get(currentName);
|
|
9884
|
-
return /* @__PURE__ */
|
|
10176
|
+
return /* @__PURE__ */ React22.createElement(
|
|
9885
10177
|
McpArgsStep,
|
|
9886
10178
|
{
|
|
9887
10179
|
entry,
|
|
@@ -9899,7 +10191,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
9899
10191
|
}
|
|
9900
10192
|
if (step === "review") {
|
|
9901
10193
|
const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
|
|
9902
|
-
return /* @__PURE__ */
|
|
10194
|
+
return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column" }, /* @__PURE__ */ React22.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React22.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React22.createElement(
|
|
9903
10195
|
SummaryLine,
|
|
9904
10196
|
{
|
|
9905
10197
|
label: "MCP",
|
|
@@ -9907,8 +10199,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
9907
10199
|
}
|
|
9908
10200
|
), specs.map((spec, i) => (
|
|
9909
10201
|
// biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
|
|
9910
|
-
/* @__PURE__ */
|
|
9911
|
-
)), /* @__PURE__ */
|
|
10202
|
+
/* @__PURE__ */ React22.createElement(Box18, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "\xB7 ", spec))
|
|
10203
|
+
)), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { color: "red" }, error)) : null, /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "enter save \xB7 esc cancel"))), /* @__PURE__ */ React22.createElement(
|
|
9912
10204
|
ReviewConfirm,
|
|
9913
10205
|
{
|
|
9914
10206
|
onConfirm: () => {
|
|
@@ -9934,7 +10226,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
9934
10226
|
}
|
|
9935
10227
|
));
|
|
9936
10228
|
}
|
|
9937
|
-
return /* @__PURE__ */
|
|
10229
|
+
return /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Press enter to exit.")), /* @__PURE__ */ React22.createElement(ExitOnEnter, { onExit: exit }));
|
|
9938
10230
|
}
|
|
9939
10231
|
function ApiKeyStep({
|
|
9940
10232
|
onSubmit,
|
|
@@ -9942,7 +10234,7 @@ function ApiKeyStep({
|
|
|
9942
10234
|
onError
|
|
9943
10235
|
}) {
|
|
9944
10236
|
const [value, setValue] = useState10("");
|
|
9945
|
-
return /* @__PURE__ */
|
|
10237
|
+
return /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React22.createElement(
|
|
9946
10238
|
TextInput2,
|
|
9947
10239
|
{
|
|
9948
10240
|
value,
|
|
@@ -9959,7 +10251,7 @@ function ApiKeyStep({
|
|
|
9959
10251
|
mask: "\u2022",
|
|
9960
10252
|
placeholder: "sk-..."
|
|
9961
10253
|
}
|
|
9962
|
-
)), error ? /* @__PURE__ */
|
|
10254
|
+
)), error ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { color: "red" }, error)) : value ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "preview: ", redactKey(value))) : null);
|
|
9963
10255
|
}
|
|
9964
10256
|
function McpArgsStep({
|
|
9965
10257
|
entry,
|
|
@@ -9968,7 +10260,7 @@ function McpArgsStep({
|
|
|
9968
10260
|
onError
|
|
9969
10261
|
}) {
|
|
9970
10262
|
const [value, setValue] = useState10("");
|
|
9971
|
-
return /* @__PURE__ */
|
|
10263
|
+
return /* @__PURE__ */ React22.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column" }, /* @__PURE__ */ React22.createElement(Text18, null, entry.summary), entry.note ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Required parameter: "), /* @__PURE__ */ React22.createElement(Text18, { bold: true }, entry.userArgs)), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React22.createElement(
|
|
9972
10264
|
TextInput2,
|
|
9973
10265
|
{
|
|
9974
10266
|
value,
|
|
@@ -9984,7 +10276,7 @@ function McpArgsStep({
|
|
|
9984
10276
|
},
|
|
9985
10277
|
placeholder: placeholderFor(entry)
|
|
9986
10278
|
}
|
|
9987
|
-
)), error ? /* @__PURE__ */
|
|
10279
|
+
)), error ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { color: "red" }, error)) : null));
|
|
9988
10280
|
}
|
|
9989
10281
|
function ReviewConfirm({ onConfirm }) {
|
|
9990
10282
|
useInput7((_i, key) => {
|
|
@@ -10004,10 +10296,10 @@ function StepFrame({
|
|
|
10004
10296
|
total,
|
|
10005
10297
|
children
|
|
10006
10298
|
}) {
|
|
10007
|
-
return /* @__PURE__ */
|
|
10299
|
+
return /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React22.createElement(Box18, null, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1, flexDirection: "column" }, children));
|
|
10008
10300
|
}
|
|
10009
10301
|
function SummaryLine({ label, value }) {
|
|
10010
|
-
return /* @__PURE__ */
|
|
10302
|
+
return /* @__PURE__ */ React22.createElement(Box18, null, /* @__PURE__ */ React22.createElement(Text18, null, label.padEnd(12)), /* @__PURE__ */ React22.createElement(Text18, { bold: true }, value));
|
|
10011
10303
|
}
|
|
10012
10304
|
function presetItems() {
|
|
10013
10305
|
return ["fast", "smart", "max"].map((name) => ({
|
|
@@ -10063,7 +10355,7 @@ async function setupCommand(_opts = {}) {
|
|
|
10063
10355
|
const existingKey = loadApiKey();
|
|
10064
10356
|
const existing = readConfig();
|
|
10065
10357
|
const { waitUntilExit, unmount } = render4(
|
|
10066
|
-
/* @__PURE__ */
|
|
10358
|
+
/* @__PURE__ */ React23.createElement(
|
|
10067
10359
|
Wizard,
|
|
10068
10360
|
{
|
|
10069
10361
|
existingApiKey: existingKey,
|
|
@@ -10111,13 +10403,13 @@ function planUpdate(input) {
|
|
|
10111
10403
|
};
|
|
10112
10404
|
}
|
|
10113
10405
|
function defaultSpawn(argv) {
|
|
10114
|
-
return new Promise((
|
|
10406
|
+
return new Promise((resolve7, reject) => {
|
|
10115
10407
|
const child = spawn4(argv[0], argv.slice(1), {
|
|
10116
10408
|
stdio: "inherit",
|
|
10117
10409
|
shell: process.platform === "win32"
|
|
10118
10410
|
});
|
|
10119
10411
|
child.once("error", reject);
|
|
10120
|
-
child.once("exit", (code) =>
|
|
10412
|
+
child.once("exit", (code) => resolve7(code ?? 1));
|
|
10121
10413
|
});
|
|
10122
10414
|
}
|
|
10123
10415
|
async function updateCommand(opts = {}) {
|