reasonix 0.13.2 → 0.13.5
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 +1849 -879
- package/dist/cli/index.js.map +1 -1
- package/package.json +10 -2
package/dist/cli/index.js
CHANGED
|
@@ -500,13 +500,13 @@ async function harvest(reasoningContent, client, options = {}, signal) {
|
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
function parsePlanState(raw, maxItems, maxItemLen) {
|
|
503
|
-
const
|
|
504
|
-
if (!
|
|
503
|
+
const text2 = (raw ?? "").trim();
|
|
504
|
+
if (!text2) return emptyPlanState();
|
|
505
505
|
let parsed;
|
|
506
506
|
try {
|
|
507
|
-
parsed = JSON.parse(
|
|
507
|
+
parsed = JSON.parse(text2);
|
|
508
508
|
} catch {
|
|
509
|
-
const match =
|
|
509
|
+
const match = text2.match(/\{[\s\S]*\}/);
|
|
510
510
|
if (!match) return emptyPlanState();
|
|
511
511
|
try {
|
|
512
512
|
parsed = JSON.parse(match[0]);
|
|
@@ -920,8 +920,8 @@ function bpeEncode(piece, mergeRank) {
|
|
|
920
920
|
}
|
|
921
921
|
return word;
|
|
922
922
|
}
|
|
923
|
-
function encode(
|
|
924
|
-
if (!
|
|
923
|
+
function encode(text2) {
|
|
924
|
+
if (!text2) return [];
|
|
925
925
|
const t2 = loadTokenizer();
|
|
926
926
|
const ids = [];
|
|
927
927
|
const process2 = (segment) => {
|
|
@@ -941,21 +941,21 @@ function encode(text) {
|
|
|
941
941
|
if (t2.addedPattern) {
|
|
942
942
|
t2.addedPattern.lastIndex = 0;
|
|
943
943
|
let last = 0;
|
|
944
|
-
for (const m of
|
|
944
|
+
for (const m of text2.matchAll(t2.addedPattern)) {
|
|
945
945
|
const idx = m.index ?? 0;
|
|
946
|
-
if (idx > last) process2(
|
|
946
|
+
if (idx > last) process2(text2.slice(last, idx));
|
|
947
947
|
const id = t2.addedMap.get(m[0]);
|
|
948
948
|
if (id !== void 0) ids.push(id);
|
|
949
949
|
last = idx + m[0].length;
|
|
950
950
|
}
|
|
951
|
-
if (last <
|
|
951
|
+
if (last < text2.length) process2(text2.slice(last));
|
|
952
952
|
} else {
|
|
953
|
-
process2(
|
|
953
|
+
process2(text2);
|
|
954
954
|
}
|
|
955
955
|
return ids;
|
|
956
956
|
}
|
|
957
|
-
function countTokens(
|
|
958
|
-
return encode(
|
|
957
|
+
function countTokens(text2) {
|
|
958
|
+
return encode(text2).length;
|
|
959
959
|
}
|
|
960
960
|
function estimateConversationTokens(messages) {
|
|
961
961
|
let total = 0;
|
|
@@ -1281,9 +1281,9 @@ function sizePrefixToTokens(s, budget2) {
|
|
|
1281
1281
|
let size = Math.min(s.length, budget2 * 4);
|
|
1282
1282
|
for (let iter = 0; iter < 6; iter++) {
|
|
1283
1283
|
if (size <= 0) return "";
|
|
1284
|
-
const
|
|
1285
|
-
const count = countTokens(
|
|
1286
|
-
if (count <= budget2) return
|
|
1284
|
+
const slice2 = s.slice(0, size);
|
|
1285
|
+
const count = countTokens(slice2);
|
|
1286
|
+
if (count <= budget2) return slice2;
|
|
1287
1287
|
const next = Math.floor(size * (budget2 / count) * 0.95);
|
|
1288
1288
|
if (next >= size) return s.slice(0, Math.max(0, size - 1));
|
|
1289
1289
|
size = next;
|
|
@@ -1295,9 +1295,9 @@ function sizeSuffixToTokens(s, budget2) {
|
|
|
1295
1295
|
let size = Math.min(s.length, budget2 * 4);
|
|
1296
1296
|
for (let iter = 0; iter < 6; iter++) {
|
|
1297
1297
|
if (size <= 0) return "";
|
|
1298
|
-
const
|
|
1299
|
-
const count = countTokens(
|
|
1300
|
-
if (count <= budget2) return
|
|
1298
|
+
const slice2 = s.slice(-size);
|
|
1299
|
+
const count = countTokens(slice2);
|
|
1300
|
+
if (count <= budget2) return slice2;
|
|
1301
1301
|
const next = Math.floor(size * (budget2 / count) * 0.95);
|
|
1302
1302
|
if (next >= size) return s.slice(-Math.max(0, size - 1));
|
|
1303
1303
|
size = next;
|
|
@@ -1472,15 +1472,15 @@ function scavengeToolCalls(reasoningContent, opts) {
|
|
|
1472
1472
|
}
|
|
1473
1473
|
return { calls: out, notes };
|
|
1474
1474
|
}
|
|
1475
|
-
function stripDsmlBlocks(
|
|
1476
|
-
let out =
|
|
1475
|
+
function stripDsmlBlocks(text2) {
|
|
1476
|
+
let out = text2;
|
|
1477
1477
|
out = out.replace(/<[||]DSML[||]function_calls>[\s\S]*?<\/?[||]DSML[||]function_calls>/g, "");
|
|
1478
1478
|
out = out.replace(/<[||]DSML[||]invoke\s+[^>]*>[\s\S]*?<\/[||]DSML[||]invoke>/g, "");
|
|
1479
1479
|
return out;
|
|
1480
1480
|
}
|
|
1481
|
-
function* iterateDsmlInvokes(
|
|
1481
|
+
function* iterateDsmlInvokes(text2) {
|
|
1482
1482
|
const INVOKE_RE = /<[||]DSML[||]invoke\s+name="([^"]+)">([\s\S]*?)<\/[||]DSML[||]invoke>/g;
|
|
1483
|
-
for (const match of
|
|
1483
|
+
for (const match of text2.matchAll(INVOKE_RE)) {
|
|
1484
1484
|
const name = match[1];
|
|
1485
1485
|
const body = match[2];
|
|
1486
1486
|
if (!name || body === void 0) continue;
|
|
@@ -1506,14 +1506,14 @@ function parseDsmlParameters(body) {
|
|
|
1506
1506
|
}
|
|
1507
1507
|
return args;
|
|
1508
1508
|
}
|
|
1509
|
-
function* iterateJsonObjects(
|
|
1510
|
-
for (let i = 0; i <
|
|
1511
|
-
if (
|
|
1509
|
+
function* iterateJsonObjects(text2) {
|
|
1510
|
+
for (let i = 0; i < text2.length; i++) {
|
|
1511
|
+
if (text2[i] !== "{") continue;
|
|
1512
1512
|
let depth = 0;
|
|
1513
1513
|
let inString = false;
|
|
1514
1514
|
let escaped = false;
|
|
1515
|
-
for (let j = i; j <
|
|
1516
|
-
const c =
|
|
1515
|
+
for (let j = i; j < text2.length; j++) {
|
|
1516
|
+
const c = text2[j];
|
|
1517
1517
|
if (escaped) {
|
|
1518
1518
|
escaped = false;
|
|
1519
1519
|
continue;
|
|
@@ -1531,7 +1531,7 @@ function* iterateJsonObjects(text) {
|
|
|
1531
1531
|
else if (c === "}") {
|
|
1532
1532
|
depth--;
|
|
1533
1533
|
if (depth === 0) {
|
|
1534
|
-
yield
|
|
1534
|
+
yield text2.slice(i, j + 1);
|
|
1535
1535
|
i = j;
|
|
1536
1536
|
break;
|
|
1537
1537
|
}
|
|
@@ -3532,13 +3532,13 @@ function rankPickerCandidates(files, query, limitOrOpts) {
|
|
|
3532
3532
|
return scored.slice(0, limit).map((s) => s.path);
|
|
3533
3533
|
}
|
|
3534
3534
|
var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
|
|
3535
|
-
function expandAtMentions(
|
|
3535
|
+
function expandAtMentions(text2, rootDir, opts = {}) {
|
|
3536
3536
|
const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
|
|
3537
3537
|
const fs6 = opts.fs ?? defaultFs;
|
|
3538
3538
|
const root = resolve(rootDir);
|
|
3539
3539
|
const seen = /* @__PURE__ */ new Map();
|
|
3540
3540
|
const expansions = [];
|
|
3541
|
-
for (const match of
|
|
3541
|
+
for (const match of text2.matchAll(AT_MENTION_PATTERN)) {
|
|
3542
3542
|
const rawPath = match[1] ?? "";
|
|
3543
3543
|
const cleaned = rawPath.replace(/\.+$/, "");
|
|
3544
3544
|
if (!cleaned) continue;
|
|
@@ -3548,7 +3548,7 @@ function expandAtMentions(text, rootDir, opts = {}) {
|
|
|
3548
3548
|
seen.set(token, expansion);
|
|
3549
3549
|
expansions.push(expansion);
|
|
3550
3550
|
}
|
|
3551
|
-
if (expansions.length === 0) return { text, expansions };
|
|
3551
|
+
if (expansions.length === 0) return { text: text2, expansions };
|
|
3552
3552
|
const blocks = [];
|
|
3553
3553
|
for (const ex of expansions) {
|
|
3554
3554
|
if (ex.ok) {
|
|
@@ -3560,7 +3560,7 @@ ${content}
|
|
|
3560
3560
|
blocks.push(`<file path="${ex.path}" skipped="${ex.skip}" />`);
|
|
3561
3561
|
}
|
|
3562
3562
|
}
|
|
3563
|
-
const augmented = `${
|
|
3563
|
+
const augmented = `${text2}
|
|
3564
3564
|
|
|
3565
3565
|
[Referenced files]
|
|
3566
3566
|
${blocks.join("\n\n")}`;
|
|
@@ -3615,7 +3615,7 @@ var defaultFs = {
|
|
|
3615
3615
|
};
|
|
3616
3616
|
var AT_URL_PATTERN = /(?<=^|\s)@(https?:\/\/\S+)/g;
|
|
3617
3617
|
var DEFAULT_AT_URL_MAX_CHARS = 32e3;
|
|
3618
|
-
async function expandAtUrls(
|
|
3618
|
+
async function expandAtUrls(text2, opts = {}) {
|
|
3619
3619
|
const maxChars = opts.maxChars ?? DEFAULT_AT_URL_MAX_CHARS;
|
|
3620
3620
|
const fetcher = opts.fetcher;
|
|
3621
3621
|
if (!fetcher) {
|
|
@@ -3624,7 +3624,7 @@ async function expandAtUrls(text, opts = {}) {
|
|
|
3624
3624
|
const seen = /* @__PURE__ */ new Map();
|
|
3625
3625
|
const bodies = /* @__PURE__ */ new Map();
|
|
3626
3626
|
const order = [];
|
|
3627
|
-
for (const match of
|
|
3627
|
+
for (const match of text2.matchAll(AT_URL_PATTERN)) {
|
|
3628
3628
|
const rawUrl = match[1] ?? "";
|
|
3629
3629
|
const url = stripUrlTail(rawUrl);
|
|
3630
3630
|
if (!url) continue;
|
|
@@ -3671,7 +3671,7 @@ async function expandAtUrls(text, opts = {}) {
|
|
|
3671
3671
|
if (opts.cache) opts.cache.set(url, { ...expansion, body });
|
|
3672
3672
|
order.push(url);
|
|
3673
3673
|
}
|
|
3674
|
-
if (seen.size === 0) return { text, expansions: [] };
|
|
3674
|
+
if (seen.size === 0) return { text: text2, expansions: [] };
|
|
3675
3675
|
const expansions = order.map((u) => seen.get(u)).filter(Boolean);
|
|
3676
3676
|
const blocks = [];
|
|
3677
3677
|
for (const ex of expansions) {
|
|
@@ -3687,7 +3687,7 @@ ${body}
|
|
|
3687
3687
|
blocks.push(`<url href="${ex.url}" skipped="${reasonAttr}" />`);
|
|
3688
3688
|
}
|
|
3689
3689
|
}
|
|
3690
|
-
const augmented = `${
|
|
3690
|
+
const augmented = `${text2}
|
|
3691
3691
|
|
|
3692
3692
|
[Referenced URLs]
|
|
3693
3693
|
${blocks.join("\n\n")}`;
|
|
@@ -3848,34 +3848,34 @@ When none of these is given AND the file is longer than ${DEFAULT_AUTO_PREVIEW_L
|
|
|
3848
3848
|
|
|
3849
3849
|
[\u2026truncated ${raw.length - maxReadBytes} bytes \u2014 file is ${raw.length} B, cap ${maxReadBytes} B. Retry with head/tail/range for targeted view.]`;
|
|
3850
3850
|
}
|
|
3851
|
-
const
|
|
3852
|
-
let lines =
|
|
3851
|
+
const text2 = raw.toString("utf8");
|
|
3852
|
+
let lines = text2.split(/\r?\n/);
|
|
3853
3853
|
if (lines.length > 0 && lines[lines.length - 1] === "") lines = lines.slice(0, -1);
|
|
3854
3854
|
const totalLines = lines.length;
|
|
3855
3855
|
if (typeof args.range === "string" && /^\d+\s*-\s*\d+$/.test(args.range)) {
|
|
3856
3856
|
const [rawStart, rawEnd] = args.range.split("-").map((s) => Number.parseInt(s, 10));
|
|
3857
3857
|
const start = Math.max(1, rawStart ?? 1);
|
|
3858
3858
|
const end = Math.min(totalLines, Math.max(start, rawEnd ?? totalLines));
|
|
3859
|
-
const
|
|
3859
|
+
const slice2 = lines.slice(start - 1, end);
|
|
3860
3860
|
const label = `[range ${start}-${end} of ${totalLines} lines]`;
|
|
3861
3861
|
return `${label}
|
|
3862
|
-
${
|
|
3862
|
+
${slice2.join("\n")}`;
|
|
3863
3863
|
}
|
|
3864
3864
|
if (typeof args.head === "number" && args.head > 0) {
|
|
3865
3865
|
const count = Math.min(args.head, totalLines);
|
|
3866
|
-
const
|
|
3866
|
+
const slice2 = lines.slice(0, count);
|
|
3867
3867
|
const marker = count < totalLines ? `
|
|
3868
3868
|
|
|
3869
3869
|
[\u2026head ${count} of ${totalLines} lines \u2014 call again with range / tail for more]` : "";
|
|
3870
|
-
return
|
|
3870
|
+
return slice2.join("\n") + marker;
|
|
3871
3871
|
}
|
|
3872
3872
|
if (typeof args.tail === "number" && args.tail > 0) {
|
|
3873
3873
|
const count = Math.min(args.tail, totalLines);
|
|
3874
|
-
const
|
|
3874
|
+
const slice2 = lines.slice(totalLines - count);
|
|
3875
3875
|
const marker = count < totalLines ? `[\u2026tail ${count} of ${totalLines} lines \u2014 call again with range / head for more]
|
|
3876
3876
|
|
|
3877
3877
|
` : "";
|
|
3878
|
-
return marker +
|
|
3878
|
+
return marker + slice2.join("\n");
|
|
3879
3879
|
}
|
|
3880
3880
|
if (totalLines <= DEFAULT_AUTO_PREVIEW_LINES) return lines.join("\n");
|
|
3881
3881
|
const head = lines.slice(0, AUTO_PREVIEW_HEAD_LINES).join("\n");
|
|
@@ -4122,9 +4122,9 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
4122
4122
|
}
|
|
4123
4123
|
const firstNul = raw.indexOf(0);
|
|
4124
4124
|
if (firstNul !== -1 && firstNul < 8 * 1024) continue;
|
|
4125
|
-
const
|
|
4125
|
+
const text2 = raw.toString("utf8");
|
|
4126
4126
|
const rel = pathMod.relative(rootDir, full);
|
|
4127
|
-
const lines =
|
|
4127
|
+
const lines = text2.split(/\r?\n/);
|
|
4128
4128
|
for (let li = 0; li < lines.length; li++) {
|
|
4129
4129
|
const line = lines[li];
|
|
4130
4130
|
const lineForCheck = caseSensitive ? line : line.toLowerCase();
|
|
@@ -5159,17 +5159,17 @@ ${job.output.slice(start)}`;
|
|
|
5159
5159
|
const job = this.jobs.get(id);
|
|
5160
5160
|
if (!job) return null;
|
|
5161
5161
|
const full = job.output;
|
|
5162
|
-
let
|
|
5162
|
+
let slice2 = full;
|
|
5163
5163
|
if (typeof opts.since === "number" && opts.since >= 0 && opts.since < full.length) {
|
|
5164
|
-
|
|
5164
|
+
slice2 = full.slice(opts.since);
|
|
5165
5165
|
}
|
|
5166
5166
|
if (typeof opts.tailLines === "number" && opts.tailLines > 0) {
|
|
5167
|
-
const lines =
|
|
5167
|
+
const lines = slice2.split("\n");
|
|
5168
5168
|
const keep = lines.slice(Math.max(0, lines.length - opts.tailLines));
|
|
5169
|
-
|
|
5169
|
+
slice2 = keep.join("\n");
|
|
5170
5170
|
}
|
|
5171
5171
|
return {
|
|
5172
|
-
output:
|
|
5172
|
+
output: slice2,
|
|
5173
5173
|
byteLength: full.length,
|
|
5174
5174
|
running: job.running,
|
|
5175
5175
|
exitCode: job.exitCode,
|
|
@@ -5882,11 +5882,11 @@ async function webFetch(url, opts = {}) {
|
|
|
5882
5882
|
}
|
|
5883
5883
|
const raw = await readBodyCapped(resp, FETCH_MAX_BYTES);
|
|
5884
5884
|
const title = extractTitle(raw);
|
|
5885
|
-
const
|
|
5886
|
-
const truncated =
|
|
5887
|
-
const finalText = truncated ? `${
|
|
5885
|
+
const text2 = contentType.includes("text/html") ? htmlToText(raw) : raw;
|
|
5886
|
+
const truncated = text2.length > maxChars;
|
|
5887
|
+
const finalText = truncated ? `${text2.slice(0, maxChars)}
|
|
5888
5888
|
|
|
5889
|
-
[\u2026 truncated ${
|
|
5889
|
+
[\u2026 truncated ${text2.length - maxChars} chars \u2026]` : text2;
|
|
5890
5890
|
return { url, title, text: finalText, truncated };
|
|
5891
5891
|
}
|
|
5892
5892
|
async function readBodyCapped(resp, maxBytes) {
|
|
@@ -7436,10 +7436,10 @@ async function trySection(load) {
|
|
|
7436
7436
|
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync9, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
7437
7437
|
import { dirname as dirname6, resolve as resolve6 } from "path";
|
|
7438
7438
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
7439
|
-
function parseEditBlocks(
|
|
7439
|
+
function parseEditBlocks(text2) {
|
|
7440
7440
|
const out = [];
|
|
7441
7441
|
BLOCK_RE.lastIndex = 0;
|
|
7442
|
-
let m = BLOCK_RE.exec(
|
|
7442
|
+
let m = BLOCK_RE.exec(text2);
|
|
7443
7443
|
while (m !== null) {
|
|
7444
7444
|
out.push({
|
|
7445
7445
|
path: m[1].trim(),
|
|
@@ -7447,7 +7447,7 @@ function parseEditBlocks(text) {
|
|
|
7447
7447
|
replace: m[3],
|
|
7448
7448
|
offset: m.index
|
|
7449
7449
|
});
|
|
7450
|
-
m = BLOCK_RE.exec(
|
|
7450
|
+
m = BLOCK_RE.exec(text2);
|
|
7451
7451
|
}
|
|
7452
7452
|
return out;
|
|
7453
7453
|
}
|
|
@@ -7767,12 +7767,12 @@ function formatLogSize(path5 = defaultUsageLogPath()) {
|
|
|
7767
7767
|
// src/cli/commands/chat.tsx
|
|
7768
7768
|
import { existsSync as existsSync23, statSync as statSync13 } from "fs";
|
|
7769
7769
|
import { render } from "ink";
|
|
7770
|
-
import
|
|
7770
|
+
import React31, { useState as useState12 } from "react";
|
|
7771
7771
|
|
|
7772
7772
|
// src/cli/ui/App.tsx
|
|
7773
7773
|
import * as pathMod7 from "path";
|
|
7774
|
-
import { Box as
|
|
7775
|
-
import
|
|
7774
|
+
import { Box as Box26, Text as Text24, useStdout as useStdout9 } from "ink";
|
|
7775
|
+
import React28, { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo3, useRef as useRef6, useState as useState10 } from "react";
|
|
7776
7776
|
|
|
7777
7777
|
// src/code/pending-edits.ts
|
|
7778
7778
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
@@ -8765,7 +8765,7 @@ async function handleModal(method, rest, body, ctx) {
|
|
|
8765
8765
|
};
|
|
8766
8766
|
}
|
|
8767
8767
|
if (method === "POST" && rest[0] === "resolve") {
|
|
8768
|
-
const { kind, choice, text } = parseBody6(body);
|
|
8768
|
+
const { kind, choice, text: text2 } = parseBody6(body);
|
|
8769
8769
|
if (kind === "shell") {
|
|
8770
8770
|
if (!ctx.resolveShellConfirm) {
|
|
8771
8771
|
return { status: 503, body: { error: "shell modal resolution not wired" } };
|
|
@@ -8808,7 +8808,7 @@ async function handleModal(method, rest, body, ctx) {
|
|
|
8808
8808
|
if (choice !== "approve" && choice !== "refine" && choice !== "cancel") {
|
|
8809
8809
|
return { status: 400, body: { error: "plan choice must be approve / refine / cancel" } };
|
|
8810
8810
|
}
|
|
8811
|
-
ctx.resolvePlanConfirm(choice, typeof
|
|
8811
|
+
ctx.resolvePlanConfirm(choice, typeof text2 === "string" && text2.trim() ? text2 : void 0);
|
|
8812
8812
|
return { status: 200, body: { resolved: true } };
|
|
8813
8813
|
}
|
|
8814
8814
|
if (kind === "edit-review") {
|
|
@@ -8843,7 +8843,7 @@ async function handleModal(method, rest, body, ctx) {
|
|
|
8843
8843
|
}
|
|
8844
8844
|
ctx.resolveCheckpointConfirm(
|
|
8845
8845
|
choice,
|
|
8846
|
-
typeof
|
|
8846
|
+
typeof text2 === "string" && text2.trim() ? text2 : void 0
|
|
8847
8847
|
);
|
|
8848
8848
|
return { status: 200, body: { resolved: true } };
|
|
8849
8849
|
}
|
|
@@ -8943,15 +8943,15 @@ var BINARY_EXTS = /* @__PURE__ */ new Set([
|
|
|
8943
8943
|
".sqlite",
|
|
8944
8944
|
".db"
|
|
8945
8945
|
]);
|
|
8946
|
-
function chunkText(
|
|
8947
|
-
const lines =
|
|
8946
|
+
function chunkText(text2, filePath, windowLines, overlap, maxChunkChars = DEFAULT_MAX_CHUNK_CHARS) {
|
|
8947
|
+
const lines = text2.split(/\r?\n/);
|
|
8948
8948
|
if (lines.length === 0 || lines.length === 1 && lines[0] === "") return [];
|
|
8949
8949
|
const stride = Math.max(1, windowLines - overlap);
|
|
8950
8950
|
const chunks = [];
|
|
8951
8951
|
for (let start = 0; start < lines.length; start += stride) {
|
|
8952
8952
|
const end = Math.min(lines.length, start + windowLines);
|
|
8953
|
-
const
|
|
8954
|
-
if (
|
|
8953
|
+
const slice2 = lines.slice(start, end).join("\n").trim();
|
|
8954
|
+
if (slice2.length === 0) {
|
|
8955
8955
|
if (end >= lines.length) break;
|
|
8956
8956
|
continue;
|
|
8957
8957
|
}
|
|
@@ -8959,7 +8959,7 @@ function chunkText(text, filePath, windowLines, overlap, maxChunkChars = DEFAULT
|
|
|
8959
8959
|
path: filePath,
|
|
8960
8960
|
startLine: start + 1,
|
|
8961
8961
|
endLine: end,
|
|
8962
|
-
text:
|
|
8962
|
+
text: slice2
|
|
8963
8963
|
};
|
|
8964
8964
|
for (const sub of safeSplit(window, maxChunkChars)) chunks.push(sub);
|
|
8965
8965
|
if (end >= lines.length) break;
|
|
@@ -9044,15 +9044,15 @@ async function* walkChunks(root, opts = {}) {
|
|
|
9044
9044
|
continue;
|
|
9045
9045
|
}
|
|
9046
9046
|
if (stat2.size > maxFileBytes) continue;
|
|
9047
|
-
let
|
|
9047
|
+
let text2;
|
|
9048
9048
|
try {
|
|
9049
|
-
|
|
9049
|
+
text2 = await fs2.readFile(abs, "utf8");
|
|
9050
9050
|
} catch {
|
|
9051
9051
|
continue;
|
|
9052
9052
|
}
|
|
9053
|
-
if (
|
|
9053
|
+
if (text2.indexOf("\0") !== -1) continue;
|
|
9054
9054
|
const rel = path.relative(root, abs).split(path.sep).join("/");
|
|
9055
|
-
for (const chunk of chunkText(
|
|
9055
|
+
for (const chunk of chunkText(text2, rel, windowLines, overlap, maxChunkChars)) {
|
|
9056
9056
|
yield chunk;
|
|
9057
9057
|
}
|
|
9058
9058
|
}
|
|
@@ -9071,7 +9071,7 @@ var EmbeddingError = class extends Error {
|
|
|
9071
9071
|
}
|
|
9072
9072
|
cause;
|
|
9073
9073
|
};
|
|
9074
|
-
async function embed(
|
|
9074
|
+
async function embed(text2, opts = {}) {
|
|
9075
9075
|
const baseUrl = opts.baseUrl ?? process.env.OLLAMA_URL ?? DEFAULT_OLLAMA_URL;
|
|
9076
9076
|
const model2 = opts.model ?? process.env.REASONIX_EMBED_MODEL ?? DEFAULT_EMBED_MODEL;
|
|
9077
9077
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
@@ -9087,7 +9087,7 @@ async function embed(text, opts = {}) {
|
|
|
9087
9087
|
res = await fetch(`${baseUrl}/api/embeddings`, {
|
|
9088
9088
|
method: "POST",
|
|
9089
9089
|
headers: { "content-type": "application/json" },
|
|
9090
|
-
body: JSON.stringify({ model: model2, prompt:
|
|
9090
|
+
body: JSON.stringify({ model: model2, prompt: text2 }),
|
|
9091
9091
|
signal: controller.signal
|
|
9092
9092
|
});
|
|
9093
9093
|
} catch (err) {
|
|
@@ -9134,10 +9134,10 @@ async function embedAll(texts, opts = {}) {
|
|
|
9134
9134
|
if (opts.signal?.aborted) {
|
|
9135
9135
|
throw new EmbeddingError("embedding aborted");
|
|
9136
9136
|
}
|
|
9137
|
-
const
|
|
9138
|
-
if (
|
|
9137
|
+
const text2 = texts[i];
|
|
9138
|
+
if (text2 === void 0) continue;
|
|
9139
9139
|
try {
|
|
9140
|
-
out[i] = await embed(
|
|
9140
|
+
out[i] = await embed(text2, opts);
|
|
9141
9141
|
} catch (err) {
|
|
9142
9142
|
opts.onError?.(i, err);
|
|
9143
9143
|
}
|
|
@@ -9834,8 +9834,8 @@ ${i + 1}. ${entry.path}:${entry.startLine}-${entry.endLine} (score ${score.toFi
|
|
|
9834
9834
|
});
|
|
9835
9835
|
return lines.join("\n");
|
|
9836
9836
|
}
|
|
9837
|
-
function indentBlock(
|
|
9838
|
-
return
|
|
9837
|
+
function indentBlock(text2, prefix) {
|
|
9838
|
+
return text2.split("\n").map((l) => prefix + l).join("\n");
|
|
9839
9839
|
}
|
|
9840
9840
|
async function bootstrapSemanticSearchInCodeMode(registry, rootDir, opts = {}) {
|
|
9841
9841
|
if (await indexExists(rootDir)) {
|
|
@@ -11503,9 +11503,76 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
|
|
|
11503
11503
|
}
|
|
11504
11504
|
var ChoiceConfirm = React5.memo(ChoiceConfirmInner);
|
|
11505
11505
|
|
|
11506
|
+
// src/cli/ui/ChromeBar.tsx
|
|
11507
|
+
import { Box as Box5, Text as Text4, useStdout as useStdout2 } from "ink";
|
|
11508
|
+
import React6 from "react";
|
|
11509
|
+
var NARROW_BREAKPOINT = 120;
|
|
11510
|
+
var COLD_START_TURNS = 3;
|
|
11511
|
+
var CACHE_BAR_CELLS = 10;
|
|
11512
|
+
function ChromeBar(props) {
|
|
11513
|
+
const { stdout: stdout4 } = useStdout2();
|
|
11514
|
+
const cols = stdout4?.columns ?? 80;
|
|
11515
|
+
const narrow = cols < NARROW_BREAKPOINT;
|
|
11516
|
+
const cold = props.summary.turns <= COLD_START_TURNS;
|
|
11517
|
+
const projectName = props.rootDir ? basename(props.rootDir) : null;
|
|
11518
|
+
const mode2 = pickModePill(props.planMode, props.preset);
|
|
11519
|
+
const proPill = props.escalated ? { label: "\u21E7 pro", color: COLOR.err } : props.proArmed ? { label: "\u21E7 pro", color: COLOR.warn } : null;
|
|
11520
|
+
const showCache = props.summary.turns > COLD_START_TURNS && !narrow;
|
|
11521
|
+
const showBalance = !!props.balance && !narrow;
|
|
11522
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text4, { bold: true, color: GRADIENT[0] }, "\u25C8 "), /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.brand, bold: true }, "reasonix"), projectName ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.info, dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text4, null, projectName), !narrow && props.sessionName ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.info, dimColor: true }, " \u203A "), /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.info }, props.sessionName)) : null) : null, /* @__PURE__ */ React6.createElement(Box5, { flexGrow: 1 }), props.scrollRatio !== void 0 && props.scrollRatio > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.accent, bold: true }, `[\u2191 ${Math.round(props.scrollRatio * 100)}%]`), /* @__PURE__ */ React6.createElement(Text4, null, " ")) : null, props.updateAvailable ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.warn, bold: true }, `\u2191 ${props.updateAvailable}`), /* @__PURE__ */ React6.createElement(Text4, null, " ")) : null, mode2 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: mode2.color, bold: true }, `[${mode2.label}]`), /* @__PURE__ */ React6.createElement(Text4, null, " ")) : null, proPill ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: proPill.color, bold: true }, `[${proPill.label}]`), /* @__PURE__ */ React6.createElement(Text4, null, " ")) : null, /* @__PURE__ */ React6.createElement(CostPill, { summary: props.summary, cold, budgetUsd: props.budgetUsd }), showBalance ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, null, " "), /* @__PURE__ */ React6.createElement(BalancePill, { balance: props.balance })) : null, showCache ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, null, " "), /* @__PURE__ */ React6.createElement(CachePill, { ratio: props.summary.cacheHitRatio })) : null), /* @__PURE__ */ React6.createElement(ChromeRule, null));
|
|
11523
|
+
}
|
|
11524
|
+
function ChromeRule() {
|
|
11525
|
+
const { stdout: stdout4 } = useStdout2();
|
|
11526
|
+
const cols = stdout4?.columns ?? 80;
|
|
11527
|
+
const w = Math.max(20, cols - 2);
|
|
11528
|
+
return /* @__PURE__ */ React6.createElement(Text4, { dimColor: true }, "\u2500".repeat(w));
|
|
11529
|
+
}
|
|
11530
|
+
function CostPill({
|
|
11531
|
+
summary,
|
|
11532
|
+
cold,
|
|
11533
|
+
budgetUsd
|
|
11534
|
+
}) {
|
|
11535
|
+
const cost = summary.totalCostUsd;
|
|
11536
|
+
const color2 = cold ? COLOR.info : sessionCostColor(cost);
|
|
11537
|
+
return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: color2, bold: !cold, dimColor: cold }, `$${cost.toFixed(4)}`), budgetUsd && budgetUsd > 0 ? /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.info, dimColor: true }, ` / $${budgetUsd.toFixed(2)}`) : null);
|
|
11538
|
+
}
|
|
11539
|
+
function BalancePill({
|
|
11540
|
+
balance
|
|
11541
|
+
}) {
|
|
11542
|
+
const { currency, total } = balance;
|
|
11543
|
+
const color2 = total < 1 ? COLOR.err : total < 5 ? COLOR.warn : COLOR.ok;
|
|
11544
|
+
const sym = currency === "USD" ? "$" : currency === "CNY" ? "\xA5" : "";
|
|
11545
|
+
const suf = sym ? "" : ` ${currency}`;
|
|
11546
|
+
return /* @__PURE__ */ React6.createElement(Text4, { color: color2 }, `w ${sym}${total.toFixed(2)}${suf}`);
|
|
11547
|
+
}
|
|
11548
|
+
function CachePill({ ratio }) {
|
|
11549
|
+
const color2 = ratio >= 0.7 ? COLOR.ok : ratio >= 0.4 ? COLOR.warn : COLOR.err;
|
|
11550
|
+
const filled = Math.max(0, Math.min(CACHE_BAR_CELLS, Math.round(ratio * CACHE_BAR_CELLS)));
|
|
11551
|
+
const empty2 = CACHE_BAR_CELLS - filled;
|
|
11552
|
+
return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text4, { color: COLOR.info, dimColor: true }, "cache "), /* @__PURE__ */ React6.createElement(Text4, { color: color2 }, "\u2588".repeat(filled)), /* @__PURE__ */ React6.createElement(Text4, { dimColor: true }, "\u2591".repeat(empty2)), /* @__PURE__ */ React6.createElement(Text4, { color: color2, bold: true }, ` ${Math.round(ratio * 100)}%`));
|
|
11553
|
+
}
|
|
11554
|
+
function pickModePill(planMode, preset2) {
|
|
11555
|
+
if (planMode) return { label: "PLAN", color: COLOR.err };
|
|
11556
|
+
if (!preset2) return null;
|
|
11557
|
+
if (preset2 === "pro") return { label: "pro", color: COLOR.accent };
|
|
11558
|
+
if (preset2 === "flash") return { label: "flash", color: COLOR.info };
|
|
11559
|
+
return { label: "auto", color: COLOR.primary };
|
|
11560
|
+
}
|
|
11561
|
+
function sessionCostColor(cost) {
|
|
11562
|
+
if (cost <= 0) return void 0;
|
|
11563
|
+
if (cost >= 5) return COLOR.err;
|
|
11564
|
+
if (cost >= 0.5) return COLOR.warn;
|
|
11565
|
+
return COLOR.ok;
|
|
11566
|
+
}
|
|
11567
|
+
function basename(path5) {
|
|
11568
|
+
const norm = path5.replace(/\\/g, "/");
|
|
11569
|
+
const i = norm.lastIndexOf("/");
|
|
11570
|
+
return i === -1 ? norm : norm.slice(i + 1);
|
|
11571
|
+
}
|
|
11572
|
+
|
|
11506
11573
|
// src/cli/ui/EditConfirm.tsx
|
|
11507
|
-
import { Box as
|
|
11508
|
-
import
|
|
11574
|
+
import { Box as Box7, Text as Text6, useStdout as useStdout4 } from "ink";
|
|
11575
|
+
import React8, { useMemo, useState as useState2 } from "react";
|
|
11509
11576
|
|
|
11510
11577
|
// src/code/diff-preview.ts
|
|
11511
11578
|
function formatEditBlockDiff(block, opts = {}) {
|
|
@@ -11657,14 +11724,14 @@ function capLines(lines, maxLines, indent) {
|
|
|
11657
11724
|
}
|
|
11658
11725
|
|
|
11659
11726
|
// src/cli/ui/SplitDiff.tsx
|
|
11660
|
-
import { Box as
|
|
11661
|
-
import
|
|
11727
|
+
import { Box as Box6, Text as Text5, useStdout as useStdout3 } from "ink";
|
|
11728
|
+
import React7 from "react";
|
|
11662
11729
|
function SplitDiff({ rows, totalCols }) {
|
|
11663
|
-
const { stdout: stdout4 } =
|
|
11730
|
+
const { stdout: stdout4 } = useStdout3();
|
|
11664
11731
|
const cols = totalCols ?? stdout4?.columns ?? 80;
|
|
11665
11732
|
const innerCols = Math.max(40, cols - 6);
|
|
11666
11733
|
const halfCols = Math.floor((innerCols - 3) / 2);
|
|
11667
|
-
return /* @__PURE__ */
|
|
11734
|
+
return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column" }, rows.map((row2, i) => /* @__PURE__ */ React7.createElement(Box6, { key: `r-${i}-${row2.left.num ?? "p"}-${row2.right.num ?? "p"}` }, /* @__PURE__ */ React7.createElement(Cell, { side: row2.left, width: halfCols, which: "left" }), /* @__PURE__ */ React7.createElement(Text5, { color: COLOR.info, dimColor: true }, " \u2502 "), /* @__PURE__ */ React7.createElement(Cell, { side: row2.right, width: halfCols, which: "right" }))));
|
|
11668
11735
|
}
|
|
11669
11736
|
function Cell({
|
|
11670
11737
|
side,
|
|
@@ -11684,22 +11751,22 @@ function Cell({
|
|
|
11684
11751
|
const truncated = raw.length > inner ? `${raw.slice(0, inner - 1)}\u2026` : raw;
|
|
11685
11752
|
const padded = truncated.padEnd(inner);
|
|
11686
11753
|
if (side.kind === "del") {
|
|
11687
|
-
return /* @__PURE__ */
|
|
11754
|
+
return /* @__PURE__ */ React7.createElement(Text5, { color: "#fbc8c8", backgroundColor: "#2a1212" }, `${numStr} ${sign} ${padded}`);
|
|
11688
11755
|
}
|
|
11689
11756
|
if (side.kind === "add") {
|
|
11690
|
-
return /* @__PURE__ */
|
|
11757
|
+
return /* @__PURE__ */ React7.createElement(Text5, { color: "#bef0c8", backgroundColor: "#0c2718" }, `${numStr} ${sign} ${padded}`);
|
|
11691
11758
|
}
|
|
11692
11759
|
if (side.kind === "pad") {
|
|
11693
|
-
return /* @__PURE__ */
|
|
11760
|
+
return /* @__PURE__ */ React7.createElement(Text5, { color: COLOR.info, dimColor: true, italic: !!raw }, `${numStr} ${sign} ${padded}`);
|
|
11694
11761
|
}
|
|
11695
|
-
return /* @__PURE__ */
|
|
11762
|
+
return /* @__PURE__ */ React7.createElement(Text5, { dimColor: true }, `${numStr} ${sign} ${padded}`);
|
|
11696
11763
|
}
|
|
11697
11764
|
|
|
11698
11765
|
// src/cli/ui/EditConfirm.tsx
|
|
11699
11766
|
var MODAL_OVERHEAD_ROWS = 18;
|
|
11700
11767
|
var MIN_DIFF_ROWS = 8;
|
|
11701
11768
|
function EditConfirm({ block, onChoose }) {
|
|
11702
|
-
const { stdout: stdout4 } =
|
|
11769
|
+
const { stdout: stdout4 } = useStdout4();
|
|
11703
11770
|
const rows = stdout4?.rows ?? 40;
|
|
11704
11771
|
const budget2 = Math.max(MIN_DIFF_ROWS, rows - MODAL_OVERHEAD_ROWS);
|
|
11705
11772
|
const allRows = useMemo(
|
|
@@ -11769,8 +11836,8 @@ function EditConfirm({ block, onChoose }) {
|
|
|
11769
11836
|
`viewing ${effectiveScroll + 1}-${effectiveScroll + visibleRows.length}/${totalLines}`
|
|
11770
11837
|
);
|
|
11771
11838
|
}
|
|
11772
|
-
const footer = /* @__PURE__ */
|
|
11773
|
-
return /* @__PURE__ */
|
|
11839
|
+
const footer = /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, "[", /* @__PURE__ */ React8.createElement(Text6, { color: "#67e8f9", bold: true }, "y"), "/Enter] apply \xB7 [", /* @__PURE__ */ React8.createElement(Text6, { color: "#67e8f9", bold: true }, "n"), "] reject \xB7 [", /* @__PURE__ */ React8.createElement(Text6, { color: "#67e8f9", bold: true }, "a"), "] apply rest \xB7 [", /* @__PURE__ */ React8.createElement(Text6, { color: "#67e8f9", bold: true }, "A"), "] flip AUTO \xB7 [", /* @__PURE__ */ React8.createElement(Text6, { color: "#67e8f9", bold: true }, "\u2191\u2193/Space"), "] scroll \xB7 [Esc] abort");
|
|
11840
|
+
return /* @__PURE__ */ React8.createElement(
|
|
11774
11841
|
ModalCard,
|
|
11775
11842
|
{
|
|
11776
11843
|
accent: isNew ? "#86efac" : "#fcd34d",
|
|
@@ -11779,17 +11846,17 @@ function EditConfirm({ block, onChoose }) {
|
|
|
11779
11846
|
subtitle: subtitleParts.join(" \xB7 "),
|
|
11780
11847
|
footer
|
|
11781
11848
|
},
|
|
11782
|
-
hiddenAbove > 0 ? /* @__PURE__ */
|
|
11783
|
-
|
|
11849
|
+
hiddenAbove > 0 ? /* @__PURE__ */ React8.createElement(
|
|
11850
|
+
Text6,
|
|
11784
11851
|
{
|
|
11785
11852
|
dimColor: true
|
|
11786
11853
|
},
|
|
11787
11854
|
` \u2191 ${hiddenAbove} line${hiddenAbove === 1 ? "" : "s"} above (\u2191/k or PgUp)`
|
|
11788
11855
|
) : null,
|
|
11789
|
-
/* @__PURE__ */
|
|
11790
|
-
/* @__PURE__ */
|
|
11791
|
-
hiddenBelow > 0 ? /* @__PURE__ */
|
|
11792
|
-
|
|
11856
|
+
/* @__PURE__ */ React8.createElement(SplitDiff, { rows: visibleRows }),
|
|
11857
|
+
/* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text6, { color: "#fbc8c8", backgroundColor: "#2a1212" }, " - old "), /* @__PURE__ */ React8.createElement(Text6, null, " "), /* @__PURE__ */ React8.createElement(Text6, { color: "#bef0c8", backgroundColor: "#0c2718" }, " + new "), /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, " side-by-side \xB7 removed lines on the left, added on the right \xB7 paired by offset")),
|
|
11858
|
+
hiddenBelow > 0 ? /* @__PURE__ */ React8.createElement(
|
|
11859
|
+
Text6,
|
|
11793
11860
|
{
|
|
11794
11861
|
dimColor: true
|
|
11795
11862
|
},
|
|
@@ -11799,12 +11866,12 @@ function EditConfirm({ block, onChoose }) {
|
|
|
11799
11866
|
}
|
|
11800
11867
|
|
|
11801
11868
|
// src/cli/ui/EventLog.tsx
|
|
11802
|
-
import { Box as
|
|
11803
|
-
import
|
|
11869
|
+
import { Box as Box12, Text as Text11, useStdout as useStdout5 } from "ink";
|
|
11870
|
+
import React14 from "react";
|
|
11804
11871
|
|
|
11805
11872
|
// src/cli/ui/PlanStateBlock.tsx
|
|
11806
|
-
import { Box as
|
|
11807
|
-
import
|
|
11873
|
+
import { Box as Box8, Text as Text7 } from "ink";
|
|
11874
|
+
import React9 from "react";
|
|
11808
11875
|
function PlanStateBlock({ planState }) {
|
|
11809
11876
|
const fields = [];
|
|
11810
11877
|
if (planState.subgoals.length)
|
|
@@ -11816,16 +11883,16 @@ function PlanStateBlock({ planState }) {
|
|
|
11816
11883
|
if (planState.rejectedPaths.length)
|
|
11817
11884
|
fields.push(["rejected", planState.rejectedPaths, COLOR.info, true]);
|
|
11818
11885
|
if (fields.length === 0) return null;
|
|
11819
|
-
return /* @__PURE__ */
|
|
11886
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color2, dim]) => /* @__PURE__ */ React9.createElement(Box8, { key: label }, /* @__PURE__ */ React9.createElement(Text7, { color: color2, bold: true, dimColor: dim }, label), /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, ` (${items.length})`), /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React9.createElement(Text7, { dimColor: dim, color: dim ? void 0 : COLOR.info }, items.join(" \xB7 ")))));
|
|
11820
11887
|
}
|
|
11821
11888
|
|
|
11822
11889
|
// src/cli/ui/PlanStepList.tsx
|
|
11823
|
-
import { Box as
|
|
11824
|
-
import
|
|
11890
|
+
import { Box as Box10, Text as Text9 } from "ink";
|
|
11891
|
+
import React11 from "react";
|
|
11825
11892
|
|
|
11826
11893
|
// src/cli/ui/char-bar.tsx
|
|
11827
|
-
import { Box as
|
|
11828
|
-
import
|
|
11894
|
+
import { Box as Box9, Text as Text8 } from "ink";
|
|
11895
|
+
import React10 from "react";
|
|
11829
11896
|
function CharBar({
|
|
11830
11897
|
pct: pct2,
|
|
11831
11898
|
width = 24,
|
|
@@ -11837,7 +11904,7 @@ function CharBar({
|
|
|
11837
11904
|
const total = Math.max(4, width);
|
|
11838
11905
|
const clamped = Math.max(0, Math.min(100, Number.isFinite(pct2) ? pct2 : 0));
|
|
11839
11906
|
const filled = Math.round(total * clamped / 100);
|
|
11840
|
-
return /* @__PURE__ */
|
|
11907
|
+
return /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text8, { color: color2 }, GLYPH.block.repeat(filled)), /* @__PURE__ */ React10.createElement(Text8, { color: emptyColor ?? COLOR.info, dimColor: true }, GLYPH.shade1.repeat(total - filled)), showLabel ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${label ?? `${Math.round(clamped)}%`}`) : null);
|
|
11841
11908
|
}
|
|
11842
11909
|
|
|
11843
11910
|
// src/cli/ui/PlanStepList.tsx
|
|
@@ -11867,31 +11934,31 @@ function PlanStepListInner({ steps, statuses, focusStepId }) {
|
|
|
11867
11934
|
const doneCount = statusList.filter((s) => s === "done").length;
|
|
11868
11935
|
const pct2 = Math.round(doneCount / total * 100);
|
|
11869
11936
|
const showProgress = doneCount > 0;
|
|
11870
|
-
return /* @__PURE__ */
|
|
11937
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, showProgress ? `${doneCount}/${total} done (${pct2}%) \xB7 ${total} step${total === 1 ? "" : "s"}` : `${total} step${total === 1 ? "" : "s"}`)), /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column" }, steps.map((step, i) => {
|
|
11871
11938
|
const status2 = statusList[i];
|
|
11872
11939
|
const isLast = i === total - 1;
|
|
11873
11940
|
const isCur = focusStepId === step.id;
|
|
11874
11941
|
const sg = statusGlyph(status2, isCur);
|
|
11875
11942
|
const risk = riskLabel(step.risk);
|
|
11876
11943
|
const titleDim = status2 === "done" || status2 === "skipped";
|
|
11877
|
-
return /* @__PURE__ */
|
|
11878
|
-
|
|
11944
|
+
return /* @__PURE__ */ React11.createElement(Box10, { key: step.id }, /* @__PURE__ */ React11.createElement(Text9, { color: COLOR.info, dimColor: true }, isLast ? GLYPH.branchEnd : GLYPH.branch), /* @__PURE__ */ React11.createElement(Text9, null, " "), /* @__PURE__ */ React11.createElement(Text9, { color: sg.color, bold: status2 === "running" || isCur }, sg.glyph), /* @__PURE__ */ React11.createElement(Text9, null, " "), /* @__PURE__ */ React11.createElement(
|
|
11945
|
+
Text9,
|
|
11879
11946
|
{
|
|
11880
11947
|
dimColor: titleDim,
|
|
11881
11948
|
bold: isCur || status2 === "running",
|
|
11882
11949
|
strikethrough: status2 === "done" || status2 === "skipped"
|
|
11883
11950
|
},
|
|
11884
11951
|
`${step.id} \xB7 ${step.title}`
|
|
11885
|
-
), risk ? /* @__PURE__ */
|
|
11886
|
-
})), showProgress ? /* @__PURE__ */
|
|
11952
|
+
), risk ? /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Text9, null, " "), /* @__PURE__ */ React11.createElement(Text9, { color: risk.color }, risk.text)) : null);
|
|
11953
|
+
})), showProgress ? /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text9, null, " "), /* @__PURE__ */ React11.createElement(CharBar, { pct: pct2, width: 24 })) : null);
|
|
11887
11954
|
}
|
|
11888
|
-
var PlanStepList =
|
|
11955
|
+
var PlanStepList = React11.memo(PlanStepListInner);
|
|
11889
11956
|
|
|
11890
11957
|
// src/cli/ui/markdown.tsx
|
|
11891
11958
|
import { readFileSync as readFileSync19, statSync as statSync11 } from "fs";
|
|
11892
11959
|
import { isAbsolute as isAbsolute5, join as join16 } from "path";
|
|
11893
|
-
import { Box as
|
|
11894
|
-
import
|
|
11960
|
+
import { Box as Box11, Text as Text10 } from "ink";
|
|
11961
|
+
import React12 from "react";
|
|
11895
11962
|
var SUPERSCRIPT = {
|
|
11896
11963
|
"0": "\u2070",
|
|
11897
11964
|
"1": "\xB9",
|
|
@@ -12190,10 +12257,10 @@ function shouldValidateAsCitation(url) {
|
|
|
12190
12257
|
if (!/[/\\.]/.test(url)) return false;
|
|
12191
12258
|
return true;
|
|
12192
12259
|
}
|
|
12193
|
-
function collectCitations(
|
|
12260
|
+
function collectCitations(text2, projectRoot) {
|
|
12194
12261
|
const map = /* @__PURE__ */ new Map();
|
|
12195
12262
|
const re = /\[([^\]\n]+)\]\(([^)\n]+)\)/g;
|
|
12196
|
-
for (const m of
|
|
12263
|
+
for (const m of text2.matchAll(re)) {
|
|
12197
12264
|
const url = m[2] ?? "";
|
|
12198
12265
|
if (!url || isExternalUrl(url)) continue;
|
|
12199
12266
|
if (!shouldValidateAsCitation(url)) continue;
|
|
@@ -12204,77 +12271,77 @@ function collectCitations(text, projectRoot) {
|
|
|
12204
12271
|
}
|
|
12205
12272
|
var INLINE_RE = /(\[([^\]\n]+)\]\(([^)\n]+)\)|\*\*\*([^*\n]+?)\*\*\*|\*\*([^*\n]+?)\*\*|```([^\n]+?)```|`([^`\n]+?)`|~~([^~\n]+?)~~|(?<![*\w])\*([^*\n]+?)\*(?!\w)|\\([*_~`[\](){}#+\-.!\\]))/g;
|
|
12206
12273
|
function InlineMd({
|
|
12207
|
-
text,
|
|
12274
|
+
text: text2,
|
|
12208
12275
|
padTo,
|
|
12209
12276
|
citations
|
|
12210
12277
|
}) {
|
|
12211
12278
|
const parts = [];
|
|
12212
12279
|
let last = 0;
|
|
12213
12280
|
let idx = 0;
|
|
12214
|
-
for (const m of
|
|
12281
|
+
for (const m of text2.matchAll(INLINE_RE)) {
|
|
12215
12282
|
const start = m.index ?? 0;
|
|
12216
12283
|
if (start > last) {
|
|
12217
|
-
parts.push(/* @__PURE__ */
|
|
12284
|
+
parts.push(/* @__PURE__ */ React12.createElement(Text10, { key: `t${idx++}` }, text2.slice(last, start)));
|
|
12218
12285
|
}
|
|
12219
12286
|
if (m[2] !== void 0 && m[3] !== void 0) {
|
|
12220
12287
|
const linkText = m[2];
|
|
12221
12288
|
const url = m[3];
|
|
12222
12289
|
if (isExternalUrl(url)) {
|
|
12223
12290
|
parts.push(
|
|
12224
|
-
/* @__PURE__ */
|
|
12291
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
|
|
12225
12292
|
);
|
|
12226
12293
|
} else {
|
|
12227
12294
|
const status2 = citations?.get(url);
|
|
12228
12295
|
if (status2 && !status2.ok) {
|
|
12229
12296
|
parts.push(
|
|
12230
|
-
/* @__PURE__ */
|
|
12297
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
|
|
12231
12298
|
);
|
|
12232
12299
|
} else {
|
|
12233
12300
|
parts.push(
|
|
12234
|
-
/* @__PURE__ */
|
|
12301
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
|
|
12235
12302
|
);
|
|
12236
12303
|
}
|
|
12237
12304
|
}
|
|
12238
12305
|
} else if (m[4] !== void 0) {
|
|
12239
12306
|
parts.push(
|
|
12240
|
-
/* @__PURE__ */
|
|
12307
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
|
|
12241
12308
|
);
|
|
12242
12309
|
} else if (m[5] !== void 0) {
|
|
12243
12310
|
parts.push(
|
|
12244
|
-
/* @__PURE__ */
|
|
12311
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `b${idx++}`, bold: true }, m[5])
|
|
12245
12312
|
);
|
|
12246
12313
|
} else if (m[6] !== void 0) {
|
|
12247
12314
|
const stripped = m[6].replace(/^(\w+)\s+/, "");
|
|
12248
12315
|
parts.push(
|
|
12249
|
-
/* @__PURE__ */
|
|
12316
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `c${idx++}`, color: "yellow" }, stripped)
|
|
12250
12317
|
);
|
|
12251
12318
|
} else if (m[7] !== void 0) {
|
|
12252
12319
|
parts.push(
|
|
12253
|
-
/* @__PURE__ */
|
|
12320
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `c${idx++}`, color: "yellow" }, m[7])
|
|
12254
12321
|
);
|
|
12255
12322
|
} else if (m[8] !== void 0) {
|
|
12256
12323
|
parts.push(
|
|
12257
|
-
/* @__PURE__ */
|
|
12324
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
|
|
12258
12325
|
);
|
|
12259
12326
|
} else if (m[9] !== void 0) {
|
|
12260
12327
|
parts.push(
|
|
12261
|
-
/* @__PURE__ */
|
|
12328
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `i${idx++}`, italic: true }, m[9])
|
|
12262
12329
|
);
|
|
12263
12330
|
} else if (m[10] !== void 0) {
|
|
12264
|
-
parts.push(/* @__PURE__ */
|
|
12331
|
+
parts.push(/* @__PURE__ */ React12.createElement(Text10, { key: `esc${idx++}` }, m[10]));
|
|
12265
12332
|
}
|
|
12266
12333
|
last = start + m[0].length;
|
|
12267
12334
|
}
|
|
12268
|
-
if (last <
|
|
12269
|
-
parts.push(/* @__PURE__ */
|
|
12335
|
+
if (last < text2.length) {
|
|
12336
|
+
parts.push(/* @__PURE__ */ React12.createElement(Text10, { key: `t${idx++}` }, text2.slice(last)));
|
|
12270
12337
|
}
|
|
12271
12338
|
if (padTo !== void 0) {
|
|
12272
|
-
const seen = visibleWidth(
|
|
12339
|
+
const seen = visibleWidth(text2);
|
|
12273
12340
|
if (seen < padTo) {
|
|
12274
|
-
parts.push(/* @__PURE__ */
|
|
12341
|
+
parts.push(/* @__PURE__ */ React12.createElement(Text10, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
|
|
12275
12342
|
}
|
|
12276
12343
|
}
|
|
12277
|
-
return /* @__PURE__ */
|
|
12344
|
+
return /* @__PURE__ */ React12.createElement(Text10, null, parts);
|
|
12278
12345
|
}
|
|
12279
12346
|
function stripInlineMarkup(s) {
|
|
12280
12347
|
return s.replace(
|
|
@@ -12513,34 +12580,34 @@ function parseBulletItem(raw) {
|
|
|
12513
12580
|
function BlockView({ block, citations }) {
|
|
12514
12581
|
switch (block.kind) {
|
|
12515
12582
|
case "heading":
|
|
12516
|
-
return /* @__PURE__ */
|
|
12583
|
+
return /* @__PURE__ */ React12.createElement(HeadingView, { level: block.level, text: block.text, citations });
|
|
12517
12584
|
case "paragraph":
|
|
12518
|
-
return /* @__PURE__ */
|
|
12585
|
+
return /* @__PURE__ */ React12.createElement(ParagraphView, { text: block.text, citations });
|
|
12519
12586
|
case "bullet":
|
|
12520
|
-
return /* @__PURE__ */
|
|
12587
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React12.createElement(Box11, { key: `${i}-${item.text.slice(0, 24)}` }, /* @__PURE__ */ React12.createElement(Text10, { color: item.task === "done" ? "green" : "cyan" }, bulletPrefix(block, i, item)), item.task === "done" ? /* @__PURE__ */ React12.createElement(Text10, { strikethrough: true, dimColor: true }, /* @__PURE__ */ React12.createElement(InlineMd, { text: item.text, citations })) : /* @__PURE__ */ React12.createElement(InlineMd, { text: item.text, citations }))));
|
|
12521
12588
|
case "quote":
|
|
12522
|
-
return /* @__PURE__ */
|
|
12589
|
+
return /* @__PURE__ */ React12.createElement(BlockquoteView, { block, citations });
|
|
12523
12590
|
case "code":
|
|
12524
12591
|
if (DIAGRAM_LANGS.has(block.lang.toLowerCase())) {
|
|
12525
|
-
return /* @__PURE__ */
|
|
12592
|
+
return /* @__PURE__ */ React12.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
|
|
12526
12593
|
}
|
|
12527
|
-
return /* @__PURE__ */
|
|
12594
|
+
return /* @__PURE__ */ React12.createElement(CodeBlockView, { lang: block.lang, text: block.text });
|
|
12528
12595
|
case "edit-block":
|
|
12529
|
-
return /* @__PURE__ */
|
|
12596
|
+
return /* @__PURE__ */ React12.createElement(EditBlockRow, { block });
|
|
12530
12597
|
case "table":
|
|
12531
|
-
return /* @__PURE__ */
|
|
12598
|
+
return /* @__PURE__ */ React12.createElement(TableBlockRow, { block, citations });
|
|
12532
12599
|
case "hr":
|
|
12533
|
-
return /* @__PURE__ */
|
|
12600
|
+
return /* @__PURE__ */ React12.createElement(Text10, { 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");
|
|
12534
12601
|
}
|
|
12535
12602
|
}
|
|
12536
|
-
function ParagraphView({ text, citations }) {
|
|
12537
|
-
if (!
|
|
12538
|
-
return /* @__PURE__ */
|
|
12603
|
+
function ParagraphView({ text: text2, citations }) {
|
|
12604
|
+
if (!text2.includes("\n")) {
|
|
12605
|
+
return /* @__PURE__ */ React12.createElement(InlineMd, { text: text2, citations });
|
|
12539
12606
|
}
|
|
12540
|
-
const rows =
|
|
12541
|
-
return /* @__PURE__ */
|
|
12607
|
+
const rows = text2.split("\n");
|
|
12608
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, rows.map((row2, i) => (
|
|
12542
12609
|
// biome-ignore lint/suspicious/noArrayIndexKey: hard-break rows are source-ordered and never reorder
|
|
12543
|
-
/* @__PURE__ */
|
|
12610
|
+
/* @__PURE__ */ React12.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
|
|
12544
12611
|
)));
|
|
12545
12612
|
}
|
|
12546
12613
|
function bulletPrefix(block, i, item) {
|
|
@@ -12553,8 +12620,8 @@ function BlockquoteView({
|
|
|
12553
12620
|
block,
|
|
12554
12621
|
citations
|
|
12555
12622
|
}) {
|
|
12556
|
-
return /* @__PURE__ */
|
|
12557
|
-
|
|
12623
|
+
return /* @__PURE__ */ React12.createElement(
|
|
12624
|
+
Box11,
|
|
12558
12625
|
{
|
|
12559
12626
|
borderStyle: "single",
|
|
12560
12627
|
borderColor: "#c4b5fd",
|
|
@@ -12565,7 +12632,7 @@ function BlockquoteView({
|
|
|
12565
12632
|
flexDirection: "column",
|
|
12566
12633
|
gap: 1
|
|
12567
12634
|
},
|
|
12568
|
-
block.children.map((child, i) => /* @__PURE__ */
|
|
12635
|
+
block.children.map((child, i) => /* @__PURE__ */ React12.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
|
|
12569
12636
|
);
|
|
12570
12637
|
}
|
|
12571
12638
|
function splitTableRow(line) {
|
|
@@ -12583,14 +12650,14 @@ function TableBlockRow({ block, citations }) {
|
|
|
12583
12650
|
widths.push(Math.min(40, Math.max(3, ...cellLengths)));
|
|
12584
12651
|
}
|
|
12585
12652
|
const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
|
|
12586
|
-
return /* @__PURE__ */
|
|
12653
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Box11, null, block.header.map((cell, ci) => (
|
|
12587
12654
|
// biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
|
|
12588
|
-
/* @__PURE__ */
|
|
12589
|
-
))), /* @__PURE__ */
|
|
12655
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React12.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
12656
|
+
))), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, separator), block.rows.map((row2, ri) => (
|
|
12590
12657
|
// biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
|
|
12591
|
-
/* @__PURE__ */
|
|
12658
|
+
/* @__PURE__ */ React12.createElement(Box11, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
|
|
12592
12659
|
// biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
|
|
12593
|
-
/* @__PURE__ */
|
|
12660
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React12.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
12594
12661
|
)))
|
|
12595
12662
|
)));
|
|
12596
12663
|
}
|
|
@@ -12610,7 +12677,7 @@ function EditBlockRow({ block }) {
|
|
|
12610
12677
|
const isNewFile = block.search.length === 0;
|
|
12611
12678
|
const searchLines = block.search.split("\n");
|
|
12612
12679
|
const replaceLines = block.replace.split("\n");
|
|
12613
|
-
return /* @__PURE__ */
|
|
12680
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text10, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React12.createElement(Text10, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React12.createElement(Text10, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React12.createElement(Text10, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
|
|
12614
12681
|
}
|
|
12615
12682
|
var DIAGRAM_LANGS = /* @__PURE__ */ new Set([
|
|
12616
12683
|
"mermaid",
|
|
@@ -12632,48 +12699,48 @@ var DIAGRAM_VIEWER_HINT = {
|
|
|
12632
12699
|
};
|
|
12633
12700
|
function HeadingView({
|
|
12634
12701
|
level,
|
|
12635
|
-
text,
|
|
12702
|
+
text: text2,
|
|
12636
12703
|
citations
|
|
12637
12704
|
}) {
|
|
12638
12705
|
if (level === 1) {
|
|
12639
|
-
return /* @__PURE__ */
|
|
12706
|
+
return /* @__PURE__ */ React12.createElement(Box11, { marginY: 1 }, /* @__PURE__ */ React12.createElement(Text10, { backgroundColor: "#67e8f9", color: "black", bold: true }, ` ${text2} `));
|
|
12640
12707
|
}
|
|
12641
12708
|
if (level === 2) {
|
|
12642
|
-
return /* @__PURE__ */
|
|
12709
|
+
return /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text10, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` ${text2} `));
|
|
12643
12710
|
}
|
|
12644
12711
|
if (level === 3) {
|
|
12645
|
-
return /* @__PURE__ */
|
|
12712
|
+
return /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text10, { backgroundColor: "#f0abfc", color: "black", bold: true }, ` ${text2} `));
|
|
12646
12713
|
}
|
|
12647
|
-
return /* @__PURE__ */
|
|
12714
|
+
return /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text10, { bold: true, color: "#f0abfc" }, "\u25B8", " "), /* @__PURE__ */ React12.createElement(Text10, { bold: true }, /* @__PURE__ */ React12.createElement(InlineMd, { text: text2, citations })));
|
|
12648
12715
|
}
|
|
12649
|
-
function CodeBlockView({ lang, text }) {
|
|
12716
|
+
function CodeBlockView({ lang, text: text2 }) {
|
|
12650
12717
|
const langLabel = lang.trim();
|
|
12651
|
-
return /* @__PURE__ */
|
|
12718
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "#7dd3fc", paddingX: 1 }, langLabel ? /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text10, { backgroundColor: "#7dd3fc", color: "black", bold: true }, ` ${langLabel} `)) : null, /* @__PURE__ */ React12.createElement(Text10, { color: "#fde68a" }, text2));
|
|
12652
12719
|
}
|
|
12653
|
-
function DiagramCodeBlock({ lang, text }) {
|
|
12720
|
+
function DiagramCodeBlock({ lang, text: text2 }) {
|
|
12654
12721
|
const hint = DIAGRAM_VIEWER_HINT[lang.toLowerCase()] ?? "\u2192 render with the matching viewer to view";
|
|
12655
|
-
return /* @__PURE__ */
|
|
12722
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text10, { bold: true, color: "magenta" }, `\u25C7 ${lang} diagram (source \u2014 terminal can't draw the graph)`), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text10, { color: "yellow" }, text2)), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, hint)));
|
|
12656
12723
|
}
|
|
12657
|
-
function Markdown({ text, projectRoot }) {
|
|
12658
|
-
const cleaned = expandAutolinks(expandEmoji(stripMath(
|
|
12724
|
+
function Markdown({ text: text2, projectRoot }) {
|
|
12725
|
+
const cleaned = expandAutolinks(expandEmoji(stripMath(text2)));
|
|
12659
12726
|
const root = projectRoot ?? process.cwd();
|
|
12660
|
-
const citations =
|
|
12661
|
-
const blocks =
|
|
12727
|
+
const citations = React12.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
|
|
12728
|
+
const blocks = React12.useMemo(() => parseBlocks(cleaned), [cleaned]);
|
|
12662
12729
|
const broken = [];
|
|
12663
12730
|
for (const [url, status2] of citations) {
|
|
12664
12731
|
if (!status2.ok) broken.push({ url, reason: status2.reason });
|
|
12665
12732
|
}
|
|
12666
|
-
return /* @__PURE__ */
|
|
12733
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React12.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React12.createElement(BrokenCitationsBlock, { items: broken }) : null);
|
|
12667
12734
|
}
|
|
12668
12735
|
function BrokenCitationsBlock({ items }) {
|
|
12669
|
-
return /* @__PURE__ */
|
|
12736
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text10, { 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) => (
|
|
12670
12737
|
// biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
|
|
12671
|
-
/* @__PURE__ */
|
|
12738
|
+
/* @__PURE__ */ React12.createElement(Text10, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
|
|
12672
12739
|
)));
|
|
12673
12740
|
}
|
|
12674
12741
|
|
|
12675
12742
|
// src/cli/ui/ticker.tsx
|
|
12676
|
-
import
|
|
12743
|
+
import React13, { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState3 } from "react";
|
|
12677
12744
|
var FAST_TICK_MS = 120;
|
|
12678
12745
|
var SLOW_TICK_MS = 1e3;
|
|
12679
12746
|
var FastTickContext = createContext2(0);
|
|
@@ -12690,7 +12757,7 @@ function TickerProvider({ children, disabled }) {
|
|
|
12690
12757
|
clearInterval(slowId);
|
|
12691
12758
|
};
|
|
12692
12759
|
}, [disabled]);
|
|
12693
|
-
return /* @__PURE__ */
|
|
12760
|
+
return /* @__PURE__ */ React13.createElement(FastTickContext.Provider, { value: fast }, /* @__PURE__ */ React13.createElement(SlowTickContext.Provider, { value: slow }, children));
|
|
12694
12761
|
}
|
|
12695
12762
|
function useTick() {
|
|
12696
12763
|
return useContext2(FastTickContext);
|
|
@@ -12711,8 +12778,8 @@ function clip(s, max) {
|
|
|
12711
12778
|
if (s.length <= max) return s;
|
|
12712
12779
|
return s.slice(0, Math.max(1, max - TRAILING_ELLIPSIS.length)) + TRAILING_ELLIPSIS;
|
|
12713
12780
|
}
|
|
12714
|
-
function firstNonEmptyLine(
|
|
12715
|
-
for (const line of
|
|
12781
|
+
function firstNonEmptyLine(text2) {
|
|
12782
|
+
for (const line of text2.split(/\r?\n/)) {
|
|
12716
12783
|
const trimmed = line.trim();
|
|
12717
12784
|
if (trimmed) return trimmed;
|
|
12718
12785
|
}
|
|
@@ -12734,8 +12801,8 @@ function formatBytes(n) {
|
|
|
12734
12801
|
if (n < 1e6) return `${(n / 1e3).toFixed(1)}KB`;
|
|
12735
12802
|
return `${(n / 1e6).toFixed(1)}MB`;
|
|
12736
12803
|
}
|
|
12737
|
-
function formatLineCount(
|
|
12738
|
-
const lines =
|
|
12804
|
+
function formatLineCount(text2) {
|
|
12805
|
+
const lines = text2.split(/\r?\n/).length;
|
|
12739
12806
|
return `${lines} line${lines === 1 ? "" : "s"}`;
|
|
12740
12807
|
}
|
|
12741
12808
|
function summarizeStructured(content) {
|
|
@@ -12846,24 +12913,24 @@ function RoleGlyph({
|
|
|
12846
12913
|
glyph,
|
|
12847
12914
|
color: color2
|
|
12848
12915
|
}) {
|
|
12849
|
-
return /* @__PURE__ */
|
|
12916
|
+
return /* @__PURE__ */ React14.createElement(Text11, { color: color2, bold: true }, glyph);
|
|
12850
12917
|
}
|
|
12851
12918
|
function ToolPill({ label, status: status2 }) {
|
|
12852
12919
|
const color2 = status2 === "err" ? COLOR.toolErr : COLOR.tool;
|
|
12853
12920
|
const symbol = status2 === "err" ? GLYPH.toolErr : GLYPH.toolOk;
|
|
12854
|
-
return /* @__PURE__ */
|
|
12921
|
+
return /* @__PURE__ */ React14.createElement(Text11, { color: color2, bold: true }, `${symbol} ${label}`);
|
|
12855
12922
|
}
|
|
12856
|
-
function indentContinuationLines(
|
|
12857
|
-
if (!
|
|
12858
|
-
return
|
|
12923
|
+
function indentContinuationLines(text2) {
|
|
12924
|
+
if (!text2.includes("\n")) return text2;
|
|
12925
|
+
return text2.split("\n").join("\n ");
|
|
12859
12926
|
}
|
|
12860
|
-
var EventRow =
|
|
12927
|
+
var EventRow = React14.memo(function EventRow2({
|
|
12861
12928
|
event,
|
|
12862
12929
|
projectRoot
|
|
12863
12930
|
}) {
|
|
12864
12931
|
if (event.role === "user") {
|
|
12865
|
-
return /* @__PURE__ */
|
|
12866
|
-
|
|
12932
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column" }, event.leadSeparator ? /* @__PURE__ */ React14.createElement(TurnSeparator, null) : null, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(
|
|
12933
|
+
Box12,
|
|
12867
12934
|
{
|
|
12868
12935
|
flexDirection: "column",
|
|
12869
12936
|
borderStyle: "single",
|
|
@@ -12873,13 +12940,13 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
12873
12940
|
borderColor: COLOR.user,
|
|
12874
12941
|
paddingLeft: 1
|
|
12875
12942
|
},
|
|
12876
|
-
/* @__PURE__ */
|
|
12943
|
+
/* @__PURE__ */ React14.createElement(Text11, null, indentContinuationLines(event.text))
|
|
12877
12944
|
)));
|
|
12878
12945
|
}
|
|
12879
12946
|
if (event.role === "assistant") {
|
|
12880
|
-
if (event.streaming) return /* @__PURE__ */
|
|
12881
|
-
return /* @__PURE__ */
|
|
12882
|
-
|
|
12947
|
+
if (event.streaming) return /* @__PURE__ */ React14.createElement(StreamingAssistant, { event });
|
|
12948
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { backgroundColor: COLOR.assistant, color: "black", bold: true }, ` ${event.stats.model.replace(/^deepseek-/, "")} `)) : null), /* @__PURE__ */ React14.createElement(
|
|
12949
|
+
Box12,
|
|
12883
12950
|
{
|
|
12884
12951
|
flexDirection: "column",
|
|
12885
12952
|
marginTop: 1,
|
|
@@ -12890,20 +12957,20 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
12890
12957
|
borderColor: COLOR.assistant,
|
|
12891
12958
|
paddingLeft: 1
|
|
12892
12959
|
},
|
|
12893
|
-
event.branch ? /* @__PURE__ */
|
|
12894
|
-
event.reasoning ? /* @__PURE__ */
|
|
12895
|
-
!isPlanStateEmpty(event.planState) ? /* @__PURE__ */
|
|
12896
|
-
event.text ? /* @__PURE__ */
|
|
12897
|
-
event.stats ? /* @__PURE__ */
|
|
12898
|
-
event.repair ? /* @__PURE__ */
|
|
12960
|
+
event.branch ? /* @__PURE__ */ React14.createElement(BranchBlock, { branch: event.branch }) : null,
|
|
12961
|
+
event.reasoning ? /* @__PURE__ */ React14.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null,
|
|
12962
|
+
!isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React14.createElement(PlanStateBlock, { planState: event.planState }) : null,
|
|
12963
|
+
event.text ? /* @__PURE__ */ React14.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, "(empty body \u2014 likely tool-call only)"),
|
|
12964
|
+
event.stats ? /* @__PURE__ */ React14.createElement(StatsLine, { stats: event.stats }) : null,
|
|
12965
|
+
event.repair ? /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.accent }, event.repair) : null
|
|
12899
12966
|
));
|
|
12900
12967
|
}
|
|
12901
12968
|
if (event.role === "tool") {
|
|
12902
12969
|
const isExplicitError = event.text.startsWith("ERROR:");
|
|
12903
12970
|
const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isExplicitError;
|
|
12904
12971
|
if (isEditFile) {
|
|
12905
|
-
return /* @__PURE__ */
|
|
12906
|
-
|
|
12972
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(ToolPill, { label: event.toolName ?? "?", status: "ok" }), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, " diff:")), /* @__PURE__ */ React14.createElement(
|
|
12973
|
+
Box12,
|
|
12907
12974
|
{
|
|
12908
12975
|
flexDirection: "column",
|
|
12909
12976
|
marginTop: 1,
|
|
@@ -12914,15 +12981,15 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
12914
12981
|
borderColor: COLOR.tool,
|
|
12915
12982
|
paddingLeft: 1
|
|
12916
12983
|
},
|
|
12917
|
-
/* @__PURE__ */
|
|
12984
|
+
/* @__PURE__ */ React14.createElement(EditFileDiff, { text: event.text })
|
|
12918
12985
|
));
|
|
12919
12986
|
}
|
|
12920
12987
|
const summary = summarizeToolResult(event.toolName ?? "?", event.text);
|
|
12921
12988
|
const status2 = summary.isError ? "err" : "ok";
|
|
12922
12989
|
const durationLabel = event.durationMs !== void 0 && event.durationMs >= 100 ? formatDuration(event.durationMs) : "";
|
|
12923
12990
|
const indexHint = event.toolIndex !== void 0 ? ` /tool ${event.toolIndex}` : "";
|
|
12924
|
-
return /* @__PURE__ */
|
|
12925
|
-
|
|
12991
|
+
return /* @__PURE__ */ React14.createElement(
|
|
12992
|
+
Box12,
|
|
12926
12993
|
{
|
|
12927
12994
|
borderStyle: "single",
|
|
12928
12995
|
borderTop: false,
|
|
@@ -12931,16 +12998,16 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
12931
12998
|
borderColor: status2 === "err" ? COLOR.toolErr : COLOR.tool,
|
|
12932
12999
|
paddingLeft: 1
|
|
12933
13000
|
},
|
|
12934
|
-
/* @__PURE__ */
|
|
12935
|
-
durationLabel ? /* @__PURE__ */
|
|
12936
|
-
/* @__PURE__ */
|
|
12937
|
-
/* @__PURE__ */
|
|
12938
|
-
indexHint ? /* @__PURE__ */
|
|
13001
|
+
/* @__PURE__ */ React14.createElement(ToolPill, { label: event.toolName ?? "?", status: status2 }),
|
|
13002
|
+
durationLabel ? /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` ${durationLabel}`) : null,
|
|
13003
|
+
/* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, " "),
|
|
13004
|
+
/* @__PURE__ */ React14.createElement(Text11, { color: status2 === "err" ? "red" : void 0, dimColor: status2 === "ok" }, summary.summary),
|
|
13005
|
+
indexHint ? /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, indexHint) : null
|
|
12939
13006
|
);
|
|
12940
13007
|
}
|
|
12941
13008
|
if (event.role === "error") {
|
|
12942
|
-
return /* @__PURE__ */
|
|
12943
|
-
|
|
13009
|
+
return /* @__PURE__ */ React14.createElement(
|
|
13010
|
+
Box12,
|
|
12944
13011
|
{
|
|
12945
13012
|
marginTop: 1,
|
|
12946
13013
|
borderStyle: "single",
|
|
@@ -12950,9 +13017,9 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
12950
13017
|
borderColor: COLOR.err,
|
|
12951
13018
|
paddingLeft: 1
|
|
12952
13019
|
},
|
|
12953
|
-
/* @__PURE__ */
|
|
12954
|
-
/* @__PURE__ */
|
|
12955
|
-
/* @__PURE__ */
|
|
13020
|
+
/* @__PURE__ */ React14.createElement(Text11, { color: COLOR.err, bold: true }, "\u2726 error"),
|
|
13021
|
+
/* @__PURE__ */ React14.createElement(Text11, null, " "),
|
|
13022
|
+
/* @__PURE__ */ React14.createElement(Text11, { color: COLOR.err }, indentContinuationLines(event.text))
|
|
12956
13023
|
);
|
|
12957
13024
|
}
|
|
12958
13025
|
if (event.role === "info") {
|
|
@@ -12964,8 +13031,8 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
12964
13031
|
else if (lead === "\u2713") leadColor = COLOR.ok;
|
|
12965
13032
|
else if (lead === "\u2717" || lead === "\u2716") leadColor = COLOR.err;
|
|
12966
13033
|
else if (lead === "\u21BB") leadColor = COLOR.primary;
|
|
12967
|
-
return /* @__PURE__ */
|
|
12968
|
-
|
|
13034
|
+
return /* @__PURE__ */ React14.createElement(
|
|
13035
|
+
Box12,
|
|
12969
13036
|
{
|
|
12970
13037
|
borderStyle: "single",
|
|
12971
13038
|
borderTop: false,
|
|
@@ -12974,19 +13041,19 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
12974
13041
|
borderColor: leadColor,
|
|
12975
13042
|
paddingLeft: 1
|
|
12976
13043
|
},
|
|
12977
|
-
/* @__PURE__ */
|
|
12978
|
-
/* @__PURE__ */
|
|
12979
|
-
/* @__PURE__ */
|
|
13044
|
+
/* @__PURE__ */ React14.createElement(Text11, { color: leadColor, bold: true }, lead),
|
|
13045
|
+
/* @__PURE__ */ React14.createElement(Text11, null, " "),
|
|
13046
|
+
/* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, body)
|
|
12980
13047
|
);
|
|
12981
13048
|
}
|
|
12982
13049
|
if (event.role === "plan") {
|
|
12983
|
-
return /* @__PURE__ */
|
|
13050
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { bold: true, color: "cyan" }, "\u{1F4CB} plan proposed \u2014 pick a choice below")), /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Markdown, { text: event.text, projectRoot })));
|
|
12984
13051
|
}
|
|
12985
13052
|
if (event.role === "step-progress") {
|
|
12986
13053
|
const sp = event.stepProgress;
|
|
12987
13054
|
const counter = sp && sp.total > 0 ? `${sp.completed}/${sp.total}` : "";
|
|
12988
13055
|
const label = sp?.title ? `${sp.stepId} \xB7 ${sp.title}` : sp?.stepId ?? "";
|
|
12989
|
-
return /* @__PURE__ */
|
|
13056
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { backgroundColor: "#4ade80", color: "black", bold: true }, " \u2713 STEP "), counter ? /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: "#4ade80", bold: true }, counter)) : null, /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: "#86efac" }, label)), event.text ? /* @__PURE__ */ React14.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, event.text)) : null, sp?.notes ? /* @__PURE__ */ React14.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text11, { color: "#fbbf24", dimColor: true }, `note: ${sp.notes}`)) : null);
|
|
12990
13057
|
}
|
|
12991
13058
|
if (event.role === "plan-resumed") {
|
|
12992
13059
|
const rp = event.resumedPlan;
|
|
@@ -13001,7 +13068,7 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
13001
13068
|
])
|
|
13002
13069
|
);
|
|
13003
13070
|
const nextStep = rp.steps.find((s) => !completedSet.has(s.id));
|
|
13004
|
-
return /* @__PURE__ */
|
|
13071
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { backgroundColor: "#67e8f9", color: "black", bold: true }, " \u21BB RESUMED PLAN "), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: "#67e8f9", bold: true }, `${done}/${total}`), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` done \xB7 last touched ${rp.relativeTime}`)), rp.summary ? /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text11, { color: "#67e8f9" }, rp.summary)) : null, /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(PlanStepList, { steps: rp.steps, statuses, focusStepId: nextStep?.id })));
|
|
13005
13072
|
}
|
|
13006
13073
|
if (event.role === "plan-replay") {
|
|
13007
13074
|
const r = event.replayPlan;
|
|
@@ -13013,11 +13080,11 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
13013
13080
|
r.steps.map((s) => [s.id, completedSet.has(s.id) ? "done" : "pending"])
|
|
13014
13081
|
);
|
|
13015
13082
|
const navHint = r.total > 1 ? ` \xB7 ${r.index}/${r.total}` : "";
|
|
13016
|
-
return /* @__PURE__ */
|
|
13083
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { backgroundColor: "#94a3b8", color: "black", bold: true }, " \u23EA REPLAY "), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: "#94a3b8", bold: true }, `${done}/${total}`), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` done \xB7 ${r.relativeTime}${navHint}`)), r.summary ? /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text11, { color: "#94a3b8" }, r.summary)) : null, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, r.archiveBasename)), r.body ? /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Markdown, { text: r.body, projectRoot })) : null, /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(PlanStepList, { steps: r.steps, statuses })), /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, r.total > 1 ? `(read-only \xB7 /replay ${r.index === 1 ? 2 : 1} for the ${r.index === 1 ? "next" : "newest"} archive)` : "(read-only \xB7 this is an archived plan)")));
|
|
13017
13084
|
}
|
|
13018
13085
|
if (event.role === "warning") {
|
|
13019
|
-
return /* @__PURE__ */
|
|
13020
|
-
|
|
13086
|
+
return /* @__PURE__ */ React14.createElement(
|
|
13087
|
+
Box12,
|
|
13021
13088
|
{
|
|
13022
13089
|
borderStyle: "single",
|
|
13023
13090
|
borderTop: false,
|
|
@@ -13026,53 +13093,53 @@ var EventRow = React13.memo(function EventRow2({
|
|
|
13026
13093
|
borderColor: COLOR.warn,
|
|
13027
13094
|
paddingLeft: 1
|
|
13028
13095
|
},
|
|
13029
|
-
/* @__PURE__ */
|
|
13030
|
-
/* @__PURE__ */
|
|
13031
|
-
/* @__PURE__ */
|
|
13096
|
+
/* @__PURE__ */ React14.createElement(Text11, { color: COLOR.warn, bold: true }, "\u25B2 warn"),
|
|
13097
|
+
/* @__PURE__ */ React14.createElement(Text11, null, " "),
|
|
13098
|
+
/* @__PURE__ */ React14.createElement(Text11, { color: COLOR.warn }, indentContinuationLines(event.text))
|
|
13032
13099
|
);
|
|
13033
13100
|
}
|
|
13034
13101
|
if (event.role === "ctx-breakdown" && event.ctxBreakdown) {
|
|
13035
|
-
return /* @__PURE__ */
|
|
13102
|
+
return /* @__PURE__ */ React14.createElement(CtxBreakdownBlock, { data: event.ctxBreakdown });
|
|
13036
13103
|
}
|
|
13037
|
-
return /* @__PURE__ */
|
|
13104
|
+
return /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, null, event.text));
|
|
13038
13105
|
});
|
|
13039
13106
|
function TurnSeparator() {
|
|
13040
|
-
const { stdout: stdout4 } =
|
|
13107
|
+
const { stdout: stdout4 } = useStdout5();
|
|
13041
13108
|
const cols = stdout4?.columns ?? 80;
|
|
13042
13109
|
const width = Math.max(16, cols - 2);
|
|
13043
13110
|
const sideWidth = Math.max(2, Math.floor((width - 5) / 2));
|
|
13044
13111
|
const leftCells = gradientCells(sideWidth, "\u2500");
|
|
13045
13112
|
const rightCells = gradientCells(sideWidth, "\u2500");
|
|
13046
|
-
return /* @__PURE__ */
|
|
13113
|
+
return /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1, marginBottom: 1 }, leftCells.map((c, i) => (
|
|
13047
13114
|
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row
|
|
13048
|
-
/* @__PURE__ */
|
|
13049
|
-
)), /* @__PURE__ */
|
|
13115
|
+
/* @__PURE__ */ React14.createElement(Text11, { key: `tsep-l-${i}`, color: c.color }, c.ch)
|
|
13116
|
+
)), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.brand, bold: true }, " \u25C6 "), rightCells.map((c, i) => (
|
|
13050
13117
|
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row
|
|
13051
|
-
/* @__PURE__ */
|
|
13118
|
+
/* @__PURE__ */ React14.createElement(Text11, { key: `tsep-r-${i}`, color: c.color }, c.ch)
|
|
13052
13119
|
)));
|
|
13053
13120
|
}
|
|
13054
|
-
function EditFileDiff({ text }) {
|
|
13055
|
-
const lines =
|
|
13121
|
+
function EditFileDiff({ text: text2 }) {
|
|
13122
|
+
const lines = text2.split(/\r?\n/);
|
|
13056
13123
|
const [statusHeader, hunkHeader, ...body] = lines;
|
|
13057
|
-
return /* @__PURE__ */
|
|
13124
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text11, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` ${hunkHeader.trim()} `)) : null, body.map((line, i) => {
|
|
13058
13125
|
const key = `${i}-${line.slice(0, 32)}`;
|
|
13059
13126
|
const stripped = line.replace(/^ {2}/, "");
|
|
13060
13127
|
if (stripped.startsWith("- ")) {
|
|
13061
|
-
return /* @__PURE__ */
|
|
13128
|
+
return /* @__PURE__ */ React14.createElement(Box12, { key }, /* @__PURE__ */ React14.createElement(Text11, { color: "#f87171", bold: true }, "\u2212 "), /* @__PURE__ */ React14.createElement(Text11, { color: "#fca5a5" }, stripped.slice(2)));
|
|
13062
13129
|
}
|
|
13063
13130
|
if (stripped.startsWith("+ ")) {
|
|
13064
|
-
return /* @__PURE__ */
|
|
13131
|
+
return /* @__PURE__ */ React14.createElement(Box12, { key }, /* @__PURE__ */ React14.createElement(Text11, { color: "#4ade80", bold: true }, "+ "), /* @__PURE__ */ React14.createElement(Text11, { color: "#86efac" }, stripped.slice(2)));
|
|
13065
13132
|
}
|
|
13066
|
-
return /* @__PURE__ */
|
|
13133
|
+
return /* @__PURE__ */ React14.createElement(Box12, { key }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, " "), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, stripped));
|
|
13067
13134
|
}));
|
|
13068
13135
|
}
|
|
13069
13136
|
function BranchBlock({ branch: branch2 }) {
|
|
13070
|
-
return /* @__PURE__ */
|
|
13137
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { backgroundColor: "#93c5fd", color: "black", bold: true }, ` \u2387 BRANCH \xD7${branch2.budget} `), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: "#93c5fd" }, "picked "), /* @__PURE__ */ React14.createElement(Text11, { color: "#93c5fd", bold: true }, "#", branch2.chosenIndex)), /* @__PURE__ */ React14.createElement(Box12, { paddingLeft: 2, marginTop: 1 }, branch2.uncertainties.map((u, i) => {
|
|
13071
13138
|
const chosen = i === branch2.chosenIndex;
|
|
13072
13139
|
const t2 = (branch2.temperatures[i] ?? 0).toFixed(1);
|
|
13073
13140
|
return (
|
|
13074
13141
|
// biome-ignore lint/suspicious/noArrayIndexKey: branch index is positional and stable
|
|
13075
|
-
/* @__PURE__ */
|
|
13142
|
+
/* @__PURE__ */ React14.createElement(Text11, { key: `b-${i}` }, /* @__PURE__ */ React14.createElement(Text11, { color: chosen ? "#93c5fd" : "#475569", bold: chosen }, chosen ? "\u25B8 " : " "), /* @__PURE__ */ React14.createElement(Text11, { color: chosen ? "#93c5fd" : "#94a3b8", bold: chosen }, `#${i}`), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` T=${t2} u=${u} `))
|
|
13076
13143
|
);
|
|
13077
13144
|
})));
|
|
13078
13145
|
}
|
|
@@ -13090,8 +13157,8 @@ function CtxBreakdownBlock({
|
|
|
13090
13157
|
const used = sysCells + toolsCells + logCells + inputCells;
|
|
13091
13158
|
const freeCells = Math.max(0, barWidth - used);
|
|
13092
13159
|
const sevColor = winPct >= 80 ? COLOR.err : winPct >= 60 ? COLOR.warn : COLOR.ok;
|
|
13093
|
-
return /* @__PURE__ */
|
|
13094
|
-
|
|
13160
|
+
return /* @__PURE__ */ React14.createElement(
|
|
13161
|
+
Box12,
|
|
13095
13162
|
{
|
|
13096
13163
|
flexDirection: "column",
|
|
13097
13164
|
marginY: 1,
|
|
@@ -13102,11 +13169,11 @@ function CtxBreakdownBlock({
|
|
|
13102
13169
|
borderColor: COLOR.brand,
|
|
13103
13170
|
paddingLeft: 1
|
|
13104
13171
|
},
|
|
13105
|
-
/* @__PURE__ */
|
|
13106
|
-
/* @__PURE__ */
|
|
13107
|
-
/* @__PURE__ */
|
|
13108
|
-
data.topTools.length > 0 ? /* @__PURE__ */
|
|
13109
|
-
/* @__PURE__ */
|
|
13172
|
+
/* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.brand, bold: true }, "\u25A3 context"), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` ${formatTokensCompact(total)} of ${formatTokensCompact(data.ctxMax)}`), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React14.createElement(Text11, { color: sevColor, bold: true }, `${winPct}%`), winPct >= 80 ? /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.err, bold: true }, " \xB7 /compact") : null),
|
|
13173
|
+
/* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.brand }, "\u2588".repeat(sysCells)), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.accent }, "\u2588".repeat(toolsCells)), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.primary }, "\u2588".repeat(logCells)), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.tool }, "\u2588".repeat(inputCells)), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.info, dimColor: true }, "\u2591".repeat(freeCells))),
|
|
13174
|
+
/* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.brand }, "\u25A0"), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` system ${formatTokensCompact(data.systemTokens)}`), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.accent }, "\u25A0"), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` tools ${formatTokensCompact(data.toolsTokens)}`), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` (${data.toolsCount})`), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.primary }, "\u25A0"), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` log ${formatTokensCompact(data.logTokens)}`), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` (${data.logMessages} msg)`), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.tool }, "\u25A0"), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` input ${formatTokensCompact(data.inputTokens)}`)),
|
|
13175
|
+
data.topTools.length > 0 ? /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` top tool results by cost (${data.topTools.length}):`), data.topTools.map((t2) => /* @__PURE__ */ React14.createElement(Box12, { key: `${t2.turn}-${t2.name}` }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` turn ${String(t2.turn).padStart(3)} `), /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.info }, t2.name.padEnd(22)), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` ${formatTokensCompact(t2.tokens).padStart(8)}`)))) : null,
|
|
13176
|
+
/* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, " /compact shrinks oversized tool results \xB7 /new wipes log"))
|
|
13110
13177
|
);
|
|
13111
13178
|
}
|
|
13112
13179
|
function formatTokensCompact(n) {
|
|
@@ -13120,8 +13187,8 @@ function ReasoningBlock({ reasoning }) {
|
|
|
13120
13187
|
const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
|
|
13121
13188
|
const tokensApprox = Math.max(1, Math.round(flat.length / 4.5));
|
|
13122
13189
|
const tokLabel = tokensApprox >= 1e3 ? `${(tokensApprox / 1e3).toFixed(1)}k` : `${tokensApprox}`;
|
|
13123
|
-
return /* @__PURE__ */
|
|
13124
|
-
|
|
13190
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.accent, bold: true }, "R1 \u21AF"), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, ` reasoning \xB7 ~${tokLabel} tok \xB7 /think for full`)), /* @__PURE__ */ React14.createElement(
|
|
13191
|
+
Box12,
|
|
13125
13192
|
{
|
|
13126
13193
|
borderStyle: "single",
|
|
13127
13194
|
borderTop: false,
|
|
@@ -13130,35 +13197,35 @@ function ReasoningBlock({ reasoning }) {
|
|
|
13130
13197
|
borderColor: COLOR.accent,
|
|
13131
13198
|
paddingLeft: 1
|
|
13132
13199
|
},
|
|
13133
|
-
/* @__PURE__ */
|
|
13200
|
+
/* @__PURE__ */ React14.createElement(Text11, { color: COLOR.accent, italic: true, dimColor: true }, preview)
|
|
13134
13201
|
));
|
|
13135
13202
|
}
|
|
13136
13203
|
function Elapsed() {
|
|
13137
13204
|
const s = useElapsedSeconds();
|
|
13138
13205
|
const mm = String(Math.floor(s / 60)).padStart(2, "0");
|
|
13139
13206
|
const ss = String(s % 60).padStart(2, "0");
|
|
13140
|
-
return /* @__PURE__ */
|
|
13207
|
+
return /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, `${mm}:${ss}`);
|
|
13141
13208
|
}
|
|
13142
13209
|
function PulsingAssistantGlyph() {
|
|
13143
|
-
return /* @__PURE__ */
|
|
13210
|
+
return /* @__PURE__ */ React14.createElement(Text11, { color: "green", bold: true }, ROLE_GLYPH.assistant);
|
|
13144
13211
|
}
|
|
13145
13212
|
function StreamingAssistant({ event }) {
|
|
13146
13213
|
if (event.branchProgress) {
|
|
13147
13214
|
const p = event.branchProgress;
|
|
13148
13215
|
if (p.completed === 0) {
|
|
13149
|
-
return /* @__PURE__ */
|
|
13216
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React14.createElement(Text11, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React14.createElement(Elapsed, null)), /* @__PURE__ */ React14.createElement(Text11, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
|
|
13150
13217
|
}
|
|
13151
13218
|
const pct2 = Math.round(p.completed / p.total * 100);
|
|
13152
|
-
return /* @__PURE__ */
|
|
13219
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React14.createElement(Text11, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React14.createElement(Elapsed, null)), /* @__PURE__ */ React14.createElement(Text11, { 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"));
|
|
13153
13220
|
}
|
|
13154
|
-
const tail = lastLine(event.text, 140);
|
|
13155
|
-
const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
|
|
13156
13221
|
const toolCallBuild = event.toolCallBuild;
|
|
13157
|
-
const
|
|
13158
|
-
const
|
|
13159
|
-
const
|
|
13160
|
-
|
|
13161
|
-
|
|
13222
|
+
const text2 = event.text;
|
|
13223
|
+
const reasoning = event.reasoning;
|
|
13224
|
+
const preFirstByte = !text2 && !reasoning && !toolCallBuild;
|
|
13225
|
+
const reasoningOnly = !text2 && !!reasoning && !toolCallBuild;
|
|
13226
|
+
const toolCallOnly = !text2 && !reasoning && !!toolCallBuild;
|
|
13227
|
+
let phaseVerb = null;
|
|
13228
|
+
let phaseColor = COLOR.assistant;
|
|
13162
13229
|
if (preFirstByte) {
|
|
13163
13230
|
phaseVerb = "waiting";
|
|
13164
13231
|
phaseColor = COLOR.warn;
|
|
@@ -13168,13 +13235,11 @@ function StreamingAssistant({ event }) {
|
|
|
13168
13235
|
} else if (toolCallOnly) {
|
|
13169
13236
|
phaseVerb = `dispatching ${toolCallBuild.name}`;
|
|
13170
13237
|
phaseColor = COLOR.accent;
|
|
13171
|
-
} else {
|
|
13172
|
-
phaseVerb = event.reasoning ? "writing (after R1)" : "writing";
|
|
13173
|
-
phaseColor = COLOR.assistant;
|
|
13174
13238
|
}
|
|
13175
|
-
const
|
|
13176
|
-
|
|
13177
|
-
|
|
13239
|
+
const verb = phaseVerb ?? "responding";
|
|
13240
|
+
const verbColor = phaseVerb ? phaseColor : COLOR.info;
|
|
13241
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Text11, { color: verbColor, dimColor: !phaseVerb }, verb), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Marquee, null), /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(Elapsed, null)), /* @__PURE__ */ React14.createElement(
|
|
13242
|
+
Box12,
|
|
13178
13243
|
{
|
|
13179
13244
|
marginTop: 1,
|
|
13180
13245
|
borderStyle: "single",
|
|
@@ -13185,13 +13250,24 @@ function StreamingAssistant({ event }) {
|
|
|
13185
13250
|
paddingLeft: 1,
|
|
13186
13251
|
flexDirection: "column"
|
|
13187
13252
|
},
|
|
13188
|
-
|
|
13253
|
+
reasoning ? /* @__PURE__ */ React14.createElement(ReasoningBlock, { reasoning }) : null,
|
|
13254
|
+
text2 ? /* @__PURE__ */ React14.createElement(Text11, null, text2, /* @__PURE__ */ React14.createElement(BlinkingCursor, null)) : /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, preFirstByte ? "waiting for first byte \u2014 5-60s typical" : reasoningOnly ? `R1 thinking \xB7 ~${Math.round((reasoning?.length ?? 0) / 4)} tok so far` : toolCallOnly ? `assembling ${toolCallBuild.name}${formatToolCallIndex(toolCallBuild)} \xB7 ${toolCallBuild.chars} chars${formatReadyTail(toolCallBuild)}` : "", /* @__PURE__ */ React14.createElement(Text11, null, " "), /* @__PURE__ */ React14.createElement(BlinkingCursor, null))
|
|
13189
13255
|
));
|
|
13190
13256
|
}
|
|
13191
|
-
function
|
|
13257
|
+
function BlinkingCursor() {
|
|
13192
13258
|
const tick = useTick();
|
|
13193
|
-
const
|
|
13194
|
-
return /* @__PURE__ */
|
|
13259
|
+
const visible = Math.floor(tick / 4) % 2 === 0;
|
|
13260
|
+
return /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.primary }, visible ? "\u258C" : " ");
|
|
13261
|
+
}
|
|
13262
|
+
var MARQUEE_W = 12;
|
|
13263
|
+
var MARQUEE_WAVE = ["\u2592", "\u2593", "\u2588", "\u2593", "\u2592"];
|
|
13264
|
+
function Marquee() {
|
|
13265
|
+
const tick = useTick();
|
|
13266
|
+
const cells = new Array(MARQUEE_W).fill("\u2591");
|
|
13267
|
+
for (let i = 0; i < MARQUEE_WAVE.length; i++) {
|
|
13268
|
+
cells[(tick + i) % MARQUEE_W] = MARQUEE_WAVE[i];
|
|
13269
|
+
}
|
|
13270
|
+
return /* @__PURE__ */ React14.createElement(Text11, { color: COLOR.primary }, cells.join(""));
|
|
13195
13271
|
}
|
|
13196
13272
|
function formatToolCallIndex(tb) {
|
|
13197
13273
|
if (!tb || tb.index === void 0) return "";
|
|
@@ -13203,26 +13279,20 @@ function formatReadyTail(tb) {
|
|
|
13203
13279
|
if (n <= 0) return "";
|
|
13204
13280
|
return ` \xB7 ${n} ready`;
|
|
13205
13281
|
}
|
|
13206
|
-
function lastLine(s, maxChars) {
|
|
13207
|
-
const tailSlice = s.length > maxChars * 4 ? s.slice(-maxChars * 4) : s;
|
|
13208
|
-
const flat = tailSlice.replace(/\s+/g, " ").trim();
|
|
13209
|
-
if (!flat) return "";
|
|
13210
|
-
return flat.length <= maxChars ? flat : `\u2026${flat.slice(-maxChars)}`;
|
|
13211
|
-
}
|
|
13212
13282
|
function StatsLine({ stats: stats2 }) {
|
|
13213
13283
|
const hit = (stats2.cacheHitRatio * 100).toFixed(1);
|
|
13214
13284
|
const hitColor = stats2.cacheHitRatio >= 0.7 ? "#4ade80" : stats2.cacheHitRatio >= 0.4 ? "#fcd34d" : "#f87171";
|
|
13215
|
-
return /* @__PURE__ */
|
|
13285
|
+
return /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text11, { color: hitColor, bold: true }, `\u232C ${hit}%`), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React14.createElement(Text11, { color: "#94a3b8" }, "in ", /* @__PURE__ */ React14.createElement(Text11, { color: "#67e8f9", bold: true }, stats2.usage.promptTokens), " \u2192 out ", /* @__PURE__ */ React14.createElement(Text11, { color: "#c4b5fd", bold: true }, stats2.usage.completionTokens)), /* @__PURE__ */ React14.createElement(Text11, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React14.createElement(Text11, { color: "#86efac", bold: true }, `$${stats2.cost.toFixed(6)}`));
|
|
13216
13286
|
}
|
|
13217
13287
|
|
|
13218
13288
|
// src/cli/ui/LiveRows.tsx
|
|
13219
|
-
import { Box as
|
|
13220
|
-
import
|
|
13289
|
+
import { Box as Box13, Text as Text12, useStdout as useStdout6 } from "ink";
|
|
13290
|
+
import React15 from "react";
|
|
13221
13291
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
13222
|
-
function StatusRow({ text }) {
|
|
13292
|
+
function StatusRow({ text: text2 }) {
|
|
13223
13293
|
const tick = useTick();
|
|
13224
13294
|
const elapsed = useElapsedSeconds();
|
|
13225
|
-
return /* @__PURE__ */
|
|
13295
|
+
return /* @__PURE__ */ React15.createElement(Box13, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text12, { color: "#c4b5fd", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React15.createElement(Text12, null, " "), /* @__PURE__ */ React15.createElement(Text12, { color: "#c4b5fd" }, text2), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, ` \xB7 ${elapsed}s`));
|
|
13226
13296
|
}
|
|
13227
13297
|
function ModeStatusBar({
|
|
13228
13298
|
editMode,
|
|
@@ -13234,27 +13304,27 @@ function ModeStatusBar({
|
|
|
13234
13304
|
}) {
|
|
13235
13305
|
useSlowTick();
|
|
13236
13306
|
const running = jobs2?.runningCount() ?? 0;
|
|
13237
|
-
const jobsTag = running > 0 ? /* @__PURE__ */
|
|
13307
|
+
const jobsTag = running > 0 ? /* @__PURE__ */ React15.createElement(Text12, { color: "yellow", bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
|
|
13238
13308
|
if (planMode) {
|
|
13239
|
-
return /* @__PURE__ */
|
|
13309
|
+
return /* @__PURE__ */ React15.createElement(ModeBarFrame, null, /* @__PURE__ */ React15.createElement(ModePill, { label: "PLAN MODE", bg: "red", flash }), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, " writes gated \xB7 /plan off to leave"), jobsTag);
|
|
13240
13310
|
}
|
|
13241
13311
|
const label = editMode === "yolo" ? "YOLO" : editMode === "auto" ? "AUTO" : "REVIEW";
|
|
13242
13312
|
const bg = editMode === "yolo" ? "red" : editMode === "auto" ? "magenta" : "cyan";
|
|
13243
13313
|
const mid = editMode === "yolo" ? "edits + shell auto \xB7 /undo to roll back" : editMode === "auto" ? "edits land now \xB7 u to undo" : pendingCount > 0 ? `${pendingCount} queued \xB7 y apply \xB7 n discard` : "edits queued \xB7 y apply \xB7 n discard";
|
|
13244
|
-
return /* @__PURE__ */
|
|
13314
|
+
return /* @__PURE__ */ React15.createElement(ModeBarFrame, null, /* @__PURE__ */ React15.createElement(ModePill, { label, bg, flash }), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, ` ${mid} \xB7 Shift+Tab to flip`), jobsTag);
|
|
13245
13315
|
}
|
|
13246
13316
|
function ModeBarFrame({ children }) {
|
|
13247
|
-
const { stdout: stdout4 } =
|
|
13317
|
+
const { stdout: stdout4 } = useStdout6();
|
|
13248
13318
|
const cols = stdout4?.columns ?? 80;
|
|
13249
13319
|
const ruleWidth = Math.max(20, cols - 2);
|
|
13250
|
-
return /* @__PURE__ */
|
|
13320
|
+
return /* @__PURE__ */ React15.createElement(Box13, { flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Box13, { paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text12, { color: "#475569", dimColor: true }, "\u254C".repeat(ruleWidth))), /* @__PURE__ */ React15.createElement(Box13, { paddingX: 1 }, children));
|
|
13251
13321
|
}
|
|
13252
13322
|
function ModePill({
|
|
13253
13323
|
label,
|
|
13254
13324
|
bg,
|
|
13255
13325
|
flash
|
|
13256
13326
|
}) {
|
|
13257
|
-
return /* @__PURE__ */
|
|
13327
|
+
return /* @__PURE__ */ React15.createElement(Text12, { color: bg, bold: true, inverse: flash }, `[${label}]`);
|
|
13258
13328
|
}
|
|
13259
13329
|
function UndoBanner({
|
|
13260
13330
|
banner
|
|
@@ -13267,14 +13337,14 @@ function UndoBanner({
|
|
|
13267
13337
|
const total = banner.results.length;
|
|
13268
13338
|
const urgent = remainingSec <= 1;
|
|
13269
13339
|
const pct2 = remainingMs / totalMs * 100;
|
|
13270
|
-
return /* @__PURE__ */
|
|
13340
|
+
return /* @__PURE__ */ React15.createElement(Box13, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text12, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` \u2713 AUTO-APPLIED ${ok}/${total} `), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, " press "), /* @__PURE__ */ React15.createElement(Text12, { backgroundColor: "#67e8f9", color: "black", bold: true }, " u "), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, " to undo "), /* @__PURE__ */ React15.createElement(CharBar, { pct: pct2, width: 20, color: urgent ? "#f87171" : "#c4b5fd", showLabel: false }), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, " "), /* @__PURE__ */ React15.createElement(Text12, { color: urgent ? "#f87171" : "#c4b5fd", bold: urgent }, `${remainingSec}s`));
|
|
13271
13341
|
}
|
|
13272
13342
|
function SubagentRow({
|
|
13273
13343
|
activity
|
|
13274
13344
|
}) {
|
|
13275
13345
|
const tick = useTick();
|
|
13276
13346
|
const seconds = (activity.elapsedMs / 1e3).toFixed(1);
|
|
13277
|
-
return /* @__PURE__ */
|
|
13347
|
+
return /* @__PURE__ */ React15.createElement(Box13, { paddingLeft: 3 }, /* @__PURE__ */ React15.createElement(Text12, { color: "#c4b5fd", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React15.createElement(Text12, null, " "), /* @__PURE__ */ React15.createElement(Text12, { color: "#c4b5fd", bold: true }, "\u232C subagent"), /* @__PURE__ */ React15.createElement(Text12, { color: "#c4b5fd" }, ` ${activity.task}`), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, ` iter ${activity.iter} \xB7 ${seconds}s`));
|
|
13278
13348
|
}
|
|
13279
13349
|
function OngoingToolRow({
|
|
13280
13350
|
tool: tool2,
|
|
@@ -13283,7 +13353,7 @@ function OngoingToolRow({
|
|
|
13283
13353
|
const tick = useTick();
|
|
13284
13354
|
const elapsed = useElapsedSeconds();
|
|
13285
13355
|
const summary = summarizeToolArgs(tool2.name, tool2.args);
|
|
13286
|
-
return /* @__PURE__ */
|
|
13356
|
+
return /* @__PURE__ */ React15.createElement(Box13, { marginY: 1, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React15.createElement(Box13, null, /* @__PURE__ */ React15.createElement(Text12, { color: "#fcd34d", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React15.createElement(Text12, null, " "), /* @__PURE__ */ React15.createElement(Text12, { color: "#fcd34d", bold: true }, `\u25A3 ${tool2.name}`), /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, ` running \xB7 ${elapsed}s`)), progress ? /* @__PURE__ */ React15.createElement(Box13, { paddingLeft: 3 }, /* @__PURE__ */ React15.createElement(Text12, { color: "#67e8f9" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React15.createElement(Box13, { paddingLeft: 3 }, /* @__PURE__ */ React15.createElement(Text12, { dimColor: true }, summary)) : null);
|
|
13287
13357
|
}
|
|
13288
13358
|
function renderProgressLine(p) {
|
|
13289
13359
|
const msg = p.message ? ` ${p.message}` : "";
|
|
@@ -13339,8 +13409,8 @@ function summarizeToolArgs(name, args) {
|
|
|
13339
13409
|
}
|
|
13340
13410
|
|
|
13341
13411
|
// src/cli/ui/PlanCheckpointConfirm.tsx
|
|
13342
|
-
import { Box as
|
|
13343
|
-
import
|
|
13412
|
+
import { Box as Box14 } from "ink";
|
|
13413
|
+
import React16 from "react";
|
|
13344
13414
|
function PlanCheckpointConfirmInner({
|
|
13345
13415
|
stepId,
|
|
13346
13416
|
title,
|
|
@@ -13355,7 +13425,7 @@ function PlanCheckpointConfirmInner({
|
|
|
13355
13425
|
const isLast = total > 0 && completed >= total;
|
|
13356
13426
|
const statuses = buildStatusMap(steps, completedStepIds, stepId, isLast);
|
|
13357
13427
|
const subtitle = counter ? `${counter} \xB7 ${label}` : label;
|
|
13358
|
-
return /* @__PURE__ */
|
|
13428
|
+
return /* @__PURE__ */ React16.createElement(ModalCard, { accent: "#86efac", icon: "\u2713", title: "checkpoint \u2014 step done", subtitle }, steps && steps.length > 0 ? /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React16.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React16.createElement(
|
|
13359
13429
|
SingleSelect,
|
|
13360
13430
|
{
|
|
13361
13431
|
initialValue: isLast ? "stop" : "continue",
|
|
@@ -13382,7 +13452,7 @@ function PlanCheckpointConfirmInner({
|
|
|
13382
13452
|
}
|
|
13383
13453
|
));
|
|
13384
13454
|
}
|
|
13385
|
-
var PlanCheckpointConfirm =
|
|
13455
|
+
var PlanCheckpointConfirm = React16.memo(PlanCheckpointConfirmInner);
|
|
13386
13456
|
function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
|
|
13387
13457
|
const map = /* @__PURE__ */ new Map();
|
|
13388
13458
|
if (!steps) return map;
|
|
@@ -13399,11 +13469,11 @@ function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
|
|
|
13399
13469
|
}
|
|
13400
13470
|
|
|
13401
13471
|
// src/cli/ui/PlanConfirm.tsx
|
|
13402
|
-
import { Box as
|
|
13403
|
-
import
|
|
13472
|
+
import { Box as Box15, Text as Text13 } from "ink";
|
|
13473
|
+
import React17 from "react";
|
|
13404
13474
|
function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
|
|
13405
13475
|
const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan2) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan2);
|
|
13406
|
-
return /* @__PURE__ */
|
|
13476
|
+
return /* @__PURE__ */ React17.createElement(
|
|
13407
13477
|
ModalCard,
|
|
13408
13478
|
{
|
|
13409
13479
|
accent: "#67e8f9",
|
|
@@ -13411,9 +13481,9 @@ function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
|
|
|
13411
13481
|
title: "plan proposed",
|
|
13412
13482
|
subtitle: summary ?? "approve / refine / cancel"
|
|
13413
13483
|
},
|
|
13414
|
-
hasOpenQuestions ? /* @__PURE__ */
|
|
13415
|
-
steps && steps.length > 0 ? /* @__PURE__ */
|
|
13416
|
-
/* @__PURE__ */
|
|
13484
|
+
hasOpenQuestions ? /* @__PURE__ */ React17.createElement(Box15, { marginBottom: 1 }, /* @__PURE__ */ React17.createElement(Text13, { color: "#fbbf24" }, "\u25B2 the plan flags open questions or risks \u2014 pick", " ", /* @__PURE__ */ React17.createElement(Text13, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null,
|
|
13485
|
+
steps && steps.length > 0 ? /* @__PURE__ */ React17.createElement(Box15, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React17.createElement(PlanStepList, { steps })) : null,
|
|
13486
|
+
/* @__PURE__ */ React17.createElement(
|
|
13417
13487
|
SingleSelect,
|
|
13418
13488
|
{
|
|
13419
13489
|
initialValue: hasOpenQuestions ? "refine" : "approve",
|
|
@@ -13441,11 +13511,11 @@ function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
|
|
|
13441
13511
|
)
|
|
13442
13512
|
);
|
|
13443
13513
|
}
|
|
13444
|
-
var PlanConfirm =
|
|
13514
|
+
var PlanConfirm = React17.memo(PlanConfirmInner);
|
|
13445
13515
|
|
|
13446
13516
|
// src/cli/ui/PlanRefineInput.tsx
|
|
13447
|
-
import { Box as
|
|
13448
|
-
import
|
|
13517
|
+
import { Box as Box16, Text as Text14 } from "ink";
|
|
13518
|
+
import React18, { useState as useState4 } from "react";
|
|
13449
13519
|
function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
|
|
13450
13520
|
const [value, setValue] = useState4("");
|
|
13451
13521
|
useKeystroke((ev) => {
|
|
@@ -13490,12 +13560,12 @@ function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
|
|
|
13490
13560
|
};
|
|
13491
13561
|
const hint = mode2 === "approve" ? "Answer questions the plan raised, add constraints, or just press Enter to approve as-is." : mode2 === "checkpoint-revise" ? "Scope change, skip steps, alternative approach \u2014 the model adjusts the remaining plan." : mode2 === "choice-custom" ? "Free-form reply. The model reads it verbatim and proceeds \u2014 no need to match the listed options." : "Describe what's wrong or missing, or answer questions the plan raised.";
|
|
13492
13562
|
const blankHint = mode2 === "approve" ? " (Enter with blank = approve without extra instructions.)" : mode2 === "checkpoint-revise" ? " (Enter with blank = continue with the current plan.)" : mode2 === "choice-custom" ? " (Enter with blank = ask the model what you actually want.)" : " (Enter with blank = ask the model to list concrete questions.)";
|
|
13493
|
-
return /* @__PURE__ */
|
|
13563
|
+
return /* @__PURE__ */ React18.createElement(ModalCard, { accent: meta.accent, icon: meta.icon, title: meta.title }, /* @__PURE__ */ React18.createElement(Box16, { marginBottom: 1 }, /* @__PURE__ */ React18.createElement(Text14, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text14, { color: meta.accent, bold: true }, "\u203A "), /* @__PURE__ */ React18.createElement(Text14, null, value), /* @__PURE__ */ React18.createElement(Text14, { color: meta.accent, bold: true }, cursorOn ? "\u258D" : " ")));
|
|
13494
13564
|
}
|
|
13495
13565
|
|
|
13496
13566
|
// src/cli/ui/PlanReviseConfirm.tsx
|
|
13497
|
-
import { Box as
|
|
13498
|
-
import
|
|
13567
|
+
import { Box as Box17, Text as Text15 } from "ink";
|
|
13568
|
+
import React19 from "react";
|
|
13499
13569
|
function computeDiff(oldSteps, newSteps) {
|
|
13500
13570
|
const oldIds = new Set(oldSteps.map((s) => s.id));
|
|
13501
13571
|
const newIds = new Set(newSteps.map((s) => s.id));
|
|
@@ -13531,7 +13601,7 @@ function PlanReviseConfirmInner({
|
|
|
13531
13601
|
const removedCount = rows.filter((r) => r.kind === "removed").length;
|
|
13532
13602
|
const addedCount = rows.filter((r) => r.kind === "added").length;
|
|
13533
13603
|
const keptCount = rows.filter((r) => r.kind === "kept").length;
|
|
13534
|
-
return /* @__PURE__ */
|
|
13604
|
+
return /* @__PURE__ */ React19.createElement(
|
|
13535
13605
|
ModalCard,
|
|
13536
13606
|
{
|
|
13537
13607
|
accent: "#fbbf24",
|
|
@@ -13539,17 +13609,17 @@ function PlanReviseConfirmInner({
|
|
|
13539
13609
|
title: "plan revision proposed",
|
|
13540
13610
|
subtitle: `\u2212${removedCount} +${addedCount} \xB7 ${keptCount} kept`
|
|
13541
13611
|
},
|
|
13542
|
-
/* @__PURE__ */
|
|
13543
|
-
summary ? /* @__PURE__ */
|
|
13544
|
-
/* @__PURE__ */
|
|
13612
|
+
/* @__PURE__ */ React19.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React19.createElement(Text15, null, reason)),
|
|
13613
|
+
summary ? /* @__PURE__ */ React19.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, `updated summary: ${summary}`)) : null,
|
|
13614
|
+
/* @__PURE__ */ React19.createElement(Box17, { marginBottom: 1, flexDirection: "column" }, rows.map((row2) => {
|
|
13545
13615
|
const risk = riskDots(row2.step.risk);
|
|
13546
13616
|
const prefix = row2.kind === "removed" ? "\u2212" : row2.kind === "added" ? "+" : " ";
|
|
13547
13617
|
const prefixColor = row2.kind === "removed" ? "#f87171" : row2.kind === "added" ? "#4ade80" : "#94a3b8";
|
|
13548
13618
|
const dim = row2.kind === "kept";
|
|
13549
13619
|
const strike = row2.kind === "removed";
|
|
13550
|
-
return /* @__PURE__ */
|
|
13620
|
+
return /* @__PURE__ */ React19.createElement(Box17, { key: `${row2.kind}-${row2.step.id}` }, /* @__PURE__ */ React19.createElement(Text15, { color: prefixColor, bold: true }, `${prefix} `), /* @__PURE__ */ React19.createElement(Text15, { color: risk.color, bold: true, dimColor: dim }, risk.dots), /* @__PURE__ */ React19.createElement(Text15, { dimColor: dim, strikethrough: strike }, ` ${row2.step.id} \xB7 ${row2.step.title}`));
|
|
13551
13621
|
})),
|
|
13552
|
-
/* @__PURE__ */
|
|
13622
|
+
/* @__PURE__ */ React19.createElement(
|
|
13553
13623
|
SingleSelect,
|
|
13554
13624
|
{
|
|
13555
13625
|
initialValue: "accept",
|
|
@@ -13572,11 +13642,11 @@ function PlanReviseConfirmInner({
|
|
|
13572
13642
|
)
|
|
13573
13643
|
);
|
|
13574
13644
|
}
|
|
13575
|
-
var PlanReviseConfirm =
|
|
13645
|
+
var PlanReviseConfirm = React19.memo(PlanReviseConfirmInner);
|
|
13576
13646
|
|
|
13577
13647
|
// src/cli/ui/PromptInput.tsx
|
|
13578
|
-
import { Box as
|
|
13579
|
-
import
|
|
13648
|
+
import { Box as Box18, Text as Text16, useStdout as useStdout7 } from "ink";
|
|
13649
|
+
import React20, { useRef as useRef2, useState as useState5 } from "react";
|
|
13580
13650
|
|
|
13581
13651
|
// src/cli/ui/key-normalize.ts
|
|
13582
13652
|
var CSI_TAIL_TO_FLAGS = [
|
|
@@ -13791,10 +13861,10 @@ function makePasteEntry(id, content) {
|
|
|
13791
13861
|
charCount: content.length
|
|
13792
13862
|
};
|
|
13793
13863
|
}
|
|
13794
|
-
function expandPasteSentinels(
|
|
13864
|
+
function expandPasteSentinels(text2, pastes) {
|
|
13795
13865
|
let out = "";
|
|
13796
|
-
for (let i = 0; i <
|
|
13797
|
-
const ch =
|
|
13866
|
+
for (let i = 0; i < text2.length; i++) {
|
|
13867
|
+
const ch = text2[i];
|
|
13798
13868
|
const id = decodePasteSentinel(ch);
|
|
13799
13869
|
if (id === null) {
|
|
13800
13870
|
out += ch;
|
|
@@ -13805,10 +13875,10 @@ function expandPasteSentinels(text, pastes) {
|
|
|
13805
13875
|
}
|
|
13806
13876
|
return out;
|
|
13807
13877
|
}
|
|
13808
|
-
function listPasteIdsInBuffer(
|
|
13878
|
+
function listPasteIdsInBuffer(text2) {
|
|
13809
13879
|
const ids = [];
|
|
13810
|
-
for (let i = 0; i <
|
|
13811
|
-
const id = decodePasteSentinel(
|
|
13880
|
+
for (let i = 0; i < text2.length; i++) {
|
|
13881
|
+
const id = decodePasteSentinel(text2[i]);
|
|
13812
13882
|
if (id !== null) ids.push(id);
|
|
13813
13883
|
}
|
|
13814
13884
|
return ids;
|
|
@@ -14048,7 +14118,7 @@ function PromptInput({
|
|
|
14048
14118
|
if (action.historyHandoff === "prev") onHistoryPrev?.();
|
|
14049
14119
|
if (action.historyHandoff === "next") onHistoryNext?.();
|
|
14050
14120
|
}, !disabled);
|
|
14051
|
-
const { stdout: stdout4 } =
|
|
14121
|
+
const { stdout: stdout4 } = useStdout7();
|
|
14052
14122
|
const cols = stdout4?.columns ?? 80;
|
|
14053
14123
|
const narrow = cols <= 90;
|
|
14054
14124
|
const promptBody = narrow ? "\u203A " : "you \u203A ";
|
|
@@ -14065,11 +14135,11 @@ function PromptInput({
|
|
|
14065
14135
|
const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
|
|
14066
14136
|
const renderItems = collapseLinesForDisplay(lines, cursorLine);
|
|
14067
14137
|
const showHugeBufferHints = lines.length > 20;
|
|
14068
|
-
return /* @__PURE__ */
|
|
14138
|
+
return /* @__PURE__ */ React20.createElement(Box18, { flexDirection: "column", paddingX: 1 }, renderItems.map((item, renderIdx) => {
|
|
14069
14139
|
if (item.kind === "skip") {
|
|
14070
14140
|
return (
|
|
14071
14141
|
// biome-ignore lint/suspicious/noArrayIndexKey: stable — collapse markers derive from a fixed sliding window
|
|
14072
|
-
/* @__PURE__ */
|
|
14142
|
+
/* @__PURE__ */ React20.createElement(Box18, { key: `skip-${renderIdx}` }, /* @__PURE__ */ React20.createElement(Text16, { color: barColorAt(renderIdx) }, BAR), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, `[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`))
|
|
14073
14143
|
);
|
|
14074
14144
|
}
|
|
14075
14145
|
const i = item.originalIndex;
|
|
@@ -14077,7 +14147,7 @@ function PromptInput({
|
|
|
14077
14147
|
const isFirst = i === 0;
|
|
14078
14148
|
const isCursorLine = i === cursorLine;
|
|
14079
14149
|
const showPlaceholder = isFirst && value.length === 0;
|
|
14080
|
-
return /* @__PURE__ */
|
|
14150
|
+
return /* @__PURE__ */ React20.createElement(
|
|
14081
14151
|
PromptLine,
|
|
14082
14152
|
{
|
|
14083
14153
|
key: `ln-${i}`,
|
|
@@ -14097,7 +14167,7 @@ function PromptInput({
|
|
|
14097
14167
|
disabled: disabled === true
|
|
14098
14168
|
}
|
|
14099
14169
|
);
|
|
14100
|
-
}), showHugeBufferHints && !disabled ? /* @__PURE__ */
|
|
14170
|
+
}), showHugeBufferHints && !disabled ? /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, `[${lines.length} lines \xB7 PageUp/PageDown jump to top/bottom \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null, !disabled && !narrow && value.length > 0 && !value.includes("\n") ? /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, "[Ctrl+J] newline \xB7 [Enter] submit \xB7 ends with \\ for line continuation")) : null, !disabled && !narrow && value.length === 0 ? /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, "[PgUp/PgDn] scroll log \xB7 [End] jump to latest \xB7 drag to select & copy \xB7 /mouse on for wheel")) : null, disabled ? /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, "[Esc] to stop")) : null);
|
|
14101
14171
|
}
|
|
14102
14172
|
function PromptLine({
|
|
14103
14173
|
line,
|
|
@@ -14119,18 +14189,18 @@ function PromptLine({
|
|
|
14119
14189
|
const bodyPrefix = promptPrefix.slice(BAR.length);
|
|
14120
14190
|
const bodyContinuation = continuationIndent.slice(BAR.length);
|
|
14121
14191
|
if (showPlaceholder) {
|
|
14122
|
-
return /* @__PURE__ */
|
|
14192
|
+
return /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: barColor }, barText), /* @__PURE__ */ React20.createElement(Text16, { bold: true, color: accentColor }, bodyPrefix), !disabled ? /* @__PURE__ */ React20.createElement(Text16, { color: accentColor }, cursorVisible ? "\u258C" : " ") : null, /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, placeholderText));
|
|
14123
14193
|
}
|
|
14124
|
-
const
|
|
14125
|
-
return /* @__PURE__ */
|
|
14194
|
+
const viewport2 = buildViewport(line, isCursorLine ? cursorCol : null, visibleCells, pastes);
|
|
14195
|
+
return /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: barColor }, barText), isFirst ? /* @__PURE__ */ React20.createElement(Text16, { bold: true, color: accentColor }, bodyPrefix) : /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, bodyContinuation), viewport2.hiddenLeft ? /* @__PURE__ */ React20.createElement(Text16, { color: "gray", dimColor: true }, "\u2039") : null, /* @__PURE__ */ React20.createElement(
|
|
14126
14196
|
ViewportContent,
|
|
14127
14197
|
{
|
|
14128
|
-
segments:
|
|
14129
|
-
cursorCell: isCursorLine ?
|
|
14198
|
+
segments: viewport2.segments,
|
|
14199
|
+
cursorCell: isCursorLine ? viewport2.cursorCell : null,
|
|
14130
14200
|
accentColor,
|
|
14131
14201
|
cursorVisible
|
|
14132
14202
|
}
|
|
14133
|
-
),
|
|
14203
|
+
), viewport2.hiddenRight ? /* @__PURE__ */ React20.createElement(Text16, { color: "gray", dimColor: true }, "\u203A") : null);
|
|
14134
14204
|
}
|
|
14135
14205
|
function ViewportContent({
|
|
14136
14206
|
segments,
|
|
@@ -14139,7 +14209,7 @@ function ViewportContent({
|
|
|
14139
14209
|
cursorVisible
|
|
14140
14210
|
}) {
|
|
14141
14211
|
if (cursorCell === null) {
|
|
14142
|
-
return /* @__PURE__ */
|
|
14212
|
+
return /* @__PURE__ */ React20.createElement(React20.Fragment, null, segments.map((seg, i) => renderSegment(seg, i, false)));
|
|
14143
14213
|
}
|
|
14144
14214
|
const out = [];
|
|
14145
14215
|
let cells = 0;
|
|
@@ -14158,7 +14228,7 @@ function ViewportContent({
|
|
|
14158
14228
|
}
|
|
14159
14229
|
if (seg.kind === "paste") {
|
|
14160
14230
|
out.push(
|
|
14161
|
-
/* @__PURE__ */
|
|
14231
|
+
/* @__PURE__ */ React20.createElement(Text16, { key: `p-${i}-cursor`, color: "magenta", bold: true, inverse: cursorVisible }, seg.label)
|
|
14162
14232
|
);
|
|
14163
14233
|
placed = true;
|
|
14164
14234
|
cells += segCells;
|
|
@@ -14167,48 +14237,48 @@ function ViewportContent({
|
|
|
14167
14237
|
const offsetIntoSeg = cursorCell - cells;
|
|
14168
14238
|
const split = splitTextByCells(seg.text, offsetIntoSeg);
|
|
14169
14239
|
if (split.before.length > 0) {
|
|
14170
|
-
out.push(/* @__PURE__ */
|
|
14240
|
+
out.push(/* @__PURE__ */ React20.createElement(Text16, { key: `t-${i}-b` }, split.before));
|
|
14171
14241
|
}
|
|
14172
14242
|
if (split.atCursor.length > 0) {
|
|
14173
14243
|
out.push(
|
|
14174
|
-
/* @__PURE__ */
|
|
14244
|
+
/* @__PURE__ */ React20.createElement(Text16, { key: `t-${i}-c`, inverse: cursorVisible, color: accentColor }, split.atCursor)
|
|
14175
14245
|
);
|
|
14176
14246
|
} else {
|
|
14177
14247
|
out.push(
|
|
14178
|
-
/* @__PURE__ */
|
|
14248
|
+
/* @__PURE__ */ React20.createElement(Text16, { key: `t-${i}-c-eol`, color: accentColor }, cursorVisible ? "\u258C" : " ")
|
|
14179
14249
|
);
|
|
14180
14250
|
}
|
|
14181
14251
|
if (split.after.length > 0) {
|
|
14182
|
-
out.push(/* @__PURE__ */
|
|
14252
|
+
out.push(/* @__PURE__ */ React20.createElement(Text16, { key: `t-${i}-a` }, split.after));
|
|
14183
14253
|
}
|
|
14184
14254
|
placed = true;
|
|
14185
14255
|
cells += segCells;
|
|
14186
14256
|
}
|
|
14187
14257
|
if (!placed) {
|
|
14188
14258
|
out.push(
|
|
14189
|
-
/* @__PURE__ */
|
|
14259
|
+
/* @__PURE__ */ React20.createElement(Text16, { key: "cursor-eol", color: accentColor }, cursorVisible ? "\u258C" : " ")
|
|
14190
14260
|
);
|
|
14191
14261
|
}
|
|
14192
|
-
return /* @__PURE__ */
|
|
14262
|
+
return /* @__PURE__ */ React20.createElement(React20.Fragment, null, out);
|
|
14193
14263
|
}
|
|
14194
14264
|
function segmentCells(seg) {
|
|
14195
14265
|
if (seg.kind === "paste") return seg.label.length;
|
|
14196
14266
|
return stringCells(seg.text);
|
|
14197
14267
|
}
|
|
14198
|
-
function splitTextByCells(
|
|
14268
|
+
function splitTextByCells(text2, cellOffset) {
|
|
14199
14269
|
let cells = 0;
|
|
14200
|
-
for (let i = 0; i <
|
|
14201
|
-
const ch =
|
|
14270
|
+
for (let i = 0; i < text2.length; i++) {
|
|
14271
|
+
const ch = text2[i];
|
|
14202
14272
|
const cw = charCellsForText(ch);
|
|
14203
14273
|
if (cells === cellOffset) {
|
|
14204
|
-
return { before:
|
|
14274
|
+
return { before: text2.slice(0, i), atCursor: ch, after: text2.slice(i + 1) };
|
|
14205
14275
|
}
|
|
14206
14276
|
if (cells + cw > cellOffset) {
|
|
14207
|
-
return { before:
|
|
14277
|
+
return { before: text2.slice(0, i), atCursor: ch, after: text2.slice(i + 1) };
|
|
14208
14278
|
}
|
|
14209
14279
|
cells += cw;
|
|
14210
14280
|
}
|
|
14211
|
-
return { before:
|
|
14281
|
+
return { before: text2, atCursor: "", after: "" };
|
|
14212
14282
|
}
|
|
14213
14283
|
function charCellsForText(ch) {
|
|
14214
14284
|
const code = ch.charCodeAt(0);
|
|
@@ -14229,9 +14299,9 @@ function charCellsForText(ch) {
|
|
|
14229
14299
|
}
|
|
14230
14300
|
function renderSegment(seg, key, _inverse) {
|
|
14231
14301
|
if (seg.kind === "text") {
|
|
14232
|
-
return /* @__PURE__ */
|
|
14302
|
+
return /* @__PURE__ */ React20.createElement(Text16, { key: `s-${key}` }, seg.text);
|
|
14233
14303
|
}
|
|
14234
|
-
return /* @__PURE__ */
|
|
14304
|
+
return /* @__PURE__ */ React20.createElement(Text16, { key: `s-${key}`, backgroundColor: "#f0abfc", color: "black", bold: true }, seg.label);
|
|
14235
14305
|
}
|
|
14236
14306
|
var COLLAPSE_THRESHOLD = 20;
|
|
14237
14307
|
var COLLAPSE_HEAD_LINES = 3;
|
|
@@ -14258,12 +14328,12 @@ function collapseLinesForDisplay(lines, cursorLine) {
|
|
|
14258
14328
|
}
|
|
14259
14329
|
|
|
14260
14330
|
// src/cli/ui/ShellConfirm.tsx
|
|
14261
|
-
import { Box as
|
|
14262
|
-
import
|
|
14331
|
+
import { Box as Box19, Text as Text17 } from "ink";
|
|
14332
|
+
import React21 from "react";
|
|
14263
14333
|
function ShellConfirm({ command, allowPrefix, kind, onChoose }) {
|
|
14264
14334
|
const isBackground = kind === "run_background";
|
|
14265
14335
|
const subtitle = isBackground ? "long-running process \u2014 keeps running after approval, /kill to stop" : "model wants to run a shell command";
|
|
14266
|
-
return /* @__PURE__ */
|
|
14336
|
+
return /* @__PURE__ */ React21.createElement(
|
|
14267
14337
|
ModalCard,
|
|
14268
14338
|
{
|
|
14269
14339
|
accent: COLOR.err,
|
|
@@ -14271,8 +14341,8 @@ function ShellConfirm({ command, allowPrefix, kind, onChoose }) {
|
|
|
14271
14341
|
title: isBackground ? "background process" : "shell command",
|
|
14272
14342
|
subtitle
|
|
14273
14343
|
},
|
|
14274
|
-
/* @__PURE__ */
|
|
14275
|
-
/* @__PURE__ */
|
|
14344
|
+
/* @__PURE__ */ React21.createElement(Box19, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.primary, bold: true }, "$ "), /* @__PURE__ */ React21.createElement(Text17, { bold: true }, command)),
|
|
14345
|
+
/* @__PURE__ */ React21.createElement(
|
|
14276
14346
|
SingleSelect,
|
|
14277
14347
|
{
|
|
14278
14348
|
initialValue: "run_once",
|
|
@@ -14330,8 +14400,8 @@ function derivePrefix(command) {
|
|
|
14330
14400
|
}
|
|
14331
14401
|
|
|
14332
14402
|
// src/cli/ui/SlashArgPicker.tsx
|
|
14333
|
-
import { Box as
|
|
14334
|
-
import
|
|
14403
|
+
import { Box as Box20, Text as Text18 } from "ink";
|
|
14404
|
+
import React22 from "react";
|
|
14335
14405
|
function SlashArgPicker({
|
|
14336
14406
|
matches,
|
|
14337
14407
|
selectedIndex,
|
|
@@ -14339,13 +14409,13 @@ function SlashArgPicker({
|
|
|
14339
14409
|
kind,
|
|
14340
14410
|
partial
|
|
14341
14411
|
}) {
|
|
14342
|
-
const headerRow = /* @__PURE__ */
|
|
14412
|
+
const headerRow = /* @__PURE__ */ React22.createElement(Box20, null, /* @__PURE__ */ React22.createElement(Text18, { color: COLOR.accent, bold: true }, "/ "), /* @__PURE__ */ React22.createElement(Text18, { color: COLOR.accent, bold: true }, `/${spec.cmd}`), spec.argsHint ? /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, ` ${spec.argsHint}`) : null, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, ` ${spec.summary}`));
|
|
14343
14413
|
if (kind === "hint") {
|
|
14344
|
-
return /* @__PURE__ */
|
|
14414
|
+
return /* @__PURE__ */ React22.createElement(Box20, { paddingX: 1, marginTop: 1 }, headerRow);
|
|
14345
14415
|
}
|
|
14346
14416
|
if (matches === null) return null;
|
|
14347
14417
|
if (matches.length === 0) {
|
|
14348
|
-
return /* @__PURE__ */
|
|
14418
|
+
return /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column", paddingX: 1, marginTop: 1 }, headerRow, /* @__PURE__ */ React22.createElement(Box20, null, /* @__PURE__ */ React22.createElement(Text18, { color: COLOR.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React22.createElement(Text18, { color: COLOR.warn }, ` no match for "${partial}"`), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " \u2014 keep typing, or Backspace to edit")));
|
|
14349
14419
|
}
|
|
14350
14420
|
const MAX = 8;
|
|
14351
14421
|
const total = matches.length;
|
|
@@ -14353,22 +14423,22 @@ function SlashArgPicker({
|
|
|
14353
14423
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
14354
14424
|
const hiddenAbove = windowStart;
|
|
14355
14425
|
const hiddenBelow = total - windowStart - shown.length;
|
|
14356
|
-
return /* @__PURE__ */
|
|
14426
|
+
return /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column", paddingX: 1, marginTop: 1 }, headerRow, hiddenAbove > 0 ? /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null, shown.map((value, i) => /* @__PURE__ */ React22.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, ` \u2193 ${hiddenBelow} below`) : null, /* @__PURE__ */ React22.createElement(Box20, { marginTop: 0 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " \u2191\u2193 navigate \xB7 Tab / \u23CE pick \xB7 esc cancel")));
|
|
14357
14427
|
}
|
|
14358
14428
|
function ArgRow({ value, isSelected }) {
|
|
14359
|
-
return /* @__PURE__ */
|
|
14429
|
+
return /* @__PURE__ */ React22.createElement(Box20, null, /* @__PURE__ */ React22.createElement(Text18, { color: isSelected ? COLOR.primary : COLOR.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ React22.createElement(Text18, { color: isSelected ? COLOR.user : COLOR.info, bold: isSelected, dimColor: !isSelected }, value));
|
|
14360
14430
|
}
|
|
14361
14431
|
|
|
14362
14432
|
// src/cli/ui/SlashSuggestions.tsx
|
|
14363
|
-
import { Box as
|
|
14364
|
-
import
|
|
14433
|
+
import { Box as Box21, Text as Text19 } from "ink";
|
|
14434
|
+
import React23 from "react";
|
|
14365
14435
|
function SlashSuggestions({
|
|
14366
14436
|
matches,
|
|
14367
14437
|
selectedIndex
|
|
14368
14438
|
}) {
|
|
14369
14439
|
if (matches === null) return null;
|
|
14370
14440
|
if (matches.length === 0) {
|
|
14371
|
-
return /* @__PURE__ */
|
|
14441
|
+
return /* @__PURE__ */ React23.createElement(Box21, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.warn, bold: true }, GLYPH.warn), /* @__PURE__ */ React23.createElement(Text19, null, " "), /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.warn }, "no slash command matches that prefix"), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
|
|
14372
14442
|
}
|
|
14373
14443
|
const MAX = 8;
|
|
14374
14444
|
const total = matches.length;
|
|
@@ -14376,121 +14446,12 @@ function SlashSuggestions({
|
|
|
14376
14446
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
14377
14447
|
const hiddenAbove = windowStart;
|
|
14378
14448
|
const hiddenBelow = total - windowStart - shown.length;
|
|
14379
|
-
return /* @__PURE__ */
|
|
14449
|
+
return /* @__PURE__ */ React23.createElement(Box21, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React23.createElement(Box21, null, /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.accent, bold: true }, "/ "), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, `${total} command${total === 1 ? "" : "s"}`), hiddenAbove > 0 ? /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, ` \u2191 ${hiddenAbove} above`) : null), shown.map((spec, i) => /* @__PURE__ */ React23.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, ` \u2193 ${hiddenBelow} below`) : null, /* @__PURE__ */ React23.createElement(Box21, { marginTop: 0 }, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, " \u2191\u2193 navigate \xB7 Tab / \u23CE pick \xB7 esc cancel")));
|
|
14380
14450
|
}
|
|
14381
14451
|
function SuggestionRow({ spec, isSelected }) {
|
|
14382
14452
|
const name = `/${spec.cmd}`;
|
|
14383
14453
|
const argsSuffix = spec.argsHint ? spec.argsHint : "";
|
|
14384
|
-
return /* @__PURE__ */
|
|
14385
|
-
}
|
|
14386
|
-
|
|
14387
|
-
// src/cli/ui/StatsPanel.tsx
|
|
14388
|
-
import { basename } from "path";
|
|
14389
|
-
import { Box as Box21, Text as Text19, useStdout as useStdout7 } from "ink";
|
|
14390
|
-
import React23 from "react";
|
|
14391
|
-
var NARROW_BREAKPOINT = 120;
|
|
14392
|
-
var COLD_START_TURNS = 3;
|
|
14393
|
-
function StatsPanel({
|
|
14394
|
-
summary,
|
|
14395
|
-
model: model2,
|
|
14396
|
-
prefixHash,
|
|
14397
|
-
harvestOn,
|
|
14398
|
-
branchBudget,
|
|
14399
|
-
reasoningEffort,
|
|
14400
|
-
planMode,
|
|
14401
|
-
editMode,
|
|
14402
|
-
balance,
|
|
14403
|
-
updateAvailable,
|
|
14404
|
-
busy,
|
|
14405
|
-
proArmed,
|
|
14406
|
-
escalated,
|
|
14407
|
-
budgetUsd,
|
|
14408
|
-
rootDir,
|
|
14409
|
-
sessionName
|
|
14410
|
-
}) {
|
|
14411
|
-
const branchOn = (branchBudget ?? 1) > 1;
|
|
14412
|
-
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model2] ?? DEFAULT_CONTEXT_TOKENS;
|
|
14413
|
-
const ctxRatio = summary.lastPromptTokens / ctxMax;
|
|
14414
|
-
const { stdout: stdout4 } = useStdout7();
|
|
14415
|
-
const columns = stdout4?.columns ?? 80;
|
|
14416
|
-
const narrow = columns < NARROW_BREAKPOINT;
|
|
14417
|
-
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
14418
|
-
return /* @__PURE__ */ React23.createElement(Box21, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React23.createElement(
|
|
14419
|
-
ChromeRow,
|
|
14420
|
-
{
|
|
14421
|
-
editMode,
|
|
14422
|
-
planMode,
|
|
14423
|
-
proArmed: proArmed ?? false,
|
|
14424
|
-
escalated: escalated ?? false,
|
|
14425
|
-
summary,
|
|
14426
|
-
coldStart,
|
|
14427
|
-
rootDir,
|
|
14428
|
-
sessionName: sessionName ?? null,
|
|
14429
|
-
updateAvailable,
|
|
14430
|
-
balance: balance ?? null,
|
|
14431
|
-
narrow
|
|
14432
|
-
}
|
|
14433
|
-
), /* @__PURE__ */ React23.createElement(ChromeRule, null), budgetUsd !== null && budgetUsd !== void 0 ? /* @__PURE__ */ React23.createElement(BudgetRow, { spent: summary.totalCostUsd, cap: budgetUsd }) : null);
|
|
14434
|
-
}
|
|
14435
|
-
function ChromeRule() {
|
|
14436
|
-
const { stdout: stdout4 } = useStdout7();
|
|
14437
|
-
const cols = stdout4?.columns ?? 80;
|
|
14438
|
-
const w = Math.max(20, cols - 2);
|
|
14439
|
-
return /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "\u2500".repeat(w));
|
|
14440
|
-
}
|
|
14441
|
-
function ChromeRow({
|
|
14442
|
-
editMode,
|
|
14443
|
-
planMode,
|
|
14444
|
-
proArmed,
|
|
14445
|
-
escalated,
|
|
14446
|
-
summary,
|
|
14447
|
-
coldStart,
|
|
14448
|
-
rootDir,
|
|
14449
|
-
sessionName,
|
|
14450
|
-
updateAvailable,
|
|
14451
|
-
balance,
|
|
14452
|
-
narrow
|
|
14453
|
-
}) {
|
|
14454
|
-
const modePill = pickModePill(planMode, editMode);
|
|
14455
|
-
const proPill = escalated ? { label: "\u21E7 pro", color: COLOR.err } : proArmed ? { label: "\u21E7 pro", color: COLOR.warn } : null;
|
|
14456
|
-
const projectName = rootDir ? basename(rootDir) : null;
|
|
14457
|
-
const cachePct = Math.round(summary.cacheHitRatio * 100);
|
|
14458
|
-
const cacheColor = summary.cacheHitRatio >= 0.7 ? COLOR.ok : summary.cacheHitRatio >= 0.4 ? COLOR.warn : COLOR.err;
|
|
14459
|
-
return /* @__PURE__ */ React23.createElement(Box21, null, /* @__PURE__ */ React23.createElement(Text19, { bold: true, color: GRADIENT[0] }, "\u25C8 "), /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.brand, bold: true }, "reasonix"), projectName ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.info, dimColor: true }, " \xB7 "), /* @__PURE__ */ React23.createElement(Text19, null, projectName), !narrow && sessionName ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.info, dimColor: true }, " \u203A "), /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.info }, sessionName)) : null) : null, /* @__PURE__ */ React23.createElement(Box21, { flexGrow: 1 }), updateAvailable ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.warn, bold: true }, `\u2191 ${updateAvailable}`), /* @__PURE__ */ React23.createElement(Text19, null, " ")) : null, modePill ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Text19, { color: modePill.color, bold: true }, `[${modePill.label}]`), /* @__PURE__ */ React23.createElement(Text19, null, " ")) : null, proPill ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Text19, { color: proPill.color, bold: true }, `[${proPill.label}]`), /* @__PURE__ */ React23.createElement(Text19, null, " ")) : null, /* @__PURE__ */ React23.createElement(
|
|
14460
|
-
Text19,
|
|
14461
|
-
{
|
|
14462
|
-
color: summary.turns === 0 || coldStart ? COLOR.info : sessionCostColor(summary.totalCostUsd),
|
|
14463
|
-
bold: summary.turns > 0 && !coldStart,
|
|
14464
|
-
dimColor: summary.turns === 0 || coldStart
|
|
14465
|
-
},
|
|
14466
|
-
`[$${summary.totalCostUsd.toFixed(4)}]`
|
|
14467
|
-
), balance && !narrow ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Text19, null, " "), /* @__PURE__ */ React23.createElement(Text19, { color: balance.total < 1 ? COLOR.err : balance.total < 5 ? COLOR.warn : COLOR.ok }, `[w ${balance.currency === "USD" ? "$" : ""}${balance.total.toFixed(2)}${balance.currency !== "USD" ? ` ${balance.currency}` : ""}]`)) : null, summary.turns > 3 && !narrow ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Text19, null, " "), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "["), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "c "), /* @__PURE__ */ React23.createElement(Bar, { ratio: summary.cacheHitRatio, color: cacheColor, cells: 6 }), /* @__PURE__ */ React23.createElement(Text19, null, " "), /* @__PURE__ */ React23.createElement(Text19, { color: cacheColor }, `${cachePct}%`), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "]")) : null);
|
|
14468
|
-
}
|
|
14469
|
-
function pickModePill(planMode, editMode) {
|
|
14470
|
-
if (planMode) return { label: "PLAN", color: COLOR.err };
|
|
14471
|
-
if (editMode === "yolo") return { label: "yolo", color: COLOR.err };
|
|
14472
|
-
if (editMode === "auto") return { label: "auto", color: COLOR.primary };
|
|
14473
|
-
if (editMode === "review") return { label: "review", color: COLOR.info };
|
|
14474
|
-
return null;
|
|
14475
|
-
}
|
|
14476
|
-
function BudgetRow({ spent, cap }) {
|
|
14477
|
-
const pct2 = Math.max(0, spent / cap * 100);
|
|
14478
|
-
const color2 = pct2 >= 100 ? "#f87171" : pct2 >= 80 ? "#fbbf24" : "#94a3b8";
|
|
14479
|
-
return /* @__PURE__ */ React23.createElement(Box21, null, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, " budget "), /* @__PURE__ */ React23.createElement(Text19, { color: color2 }, `$${spent.toFixed(4)} / $${cap.toFixed(2)}`, /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, ` (${pct2.toFixed(0)}%)`)));
|
|
14480
|
-
}
|
|
14481
|
-
function sessionCostColor(cost) {
|
|
14482
|
-
if (cost <= 0) return void 0;
|
|
14483
|
-
if (cost >= 5) return COLOR.err;
|
|
14484
|
-
if (cost >= 0.5) return COLOR.warn;
|
|
14485
|
-
return COLOR.ok;
|
|
14486
|
-
}
|
|
14487
|
-
function Bar({
|
|
14488
|
-
ratio,
|
|
14489
|
-
color: color2,
|
|
14490
|
-
cells = 14
|
|
14491
|
-
}) {
|
|
14492
|
-
const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
|
|
14493
|
-
return /* @__PURE__ */ React23.createElement(Text19, null, /* @__PURE__ */ React23.createElement(Text19, { color: color2 }, "\u25B0".repeat(filled)), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, "\u25B1".repeat(cells - filled)));
|
|
14454
|
+
return /* @__PURE__ */ React23.createElement(Box21, null, /* @__PURE__ */ React23.createElement(Text19, { color: isSelected ? COLOR.primary : COLOR.info, bold: isSelected }, isSelected ? `${GLYPH.cur} ` : " "), /* @__PURE__ */ React23.createElement(Text19, { color: COLOR.accent, bold: isSelected }, name.padEnd(14)), /* @__PURE__ */ React23.createElement(Text19, { dimColor: true }, argsSuffix.padEnd(14)), /* @__PURE__ */ React23.createElement(Text19, null, " "), /* @__PURE__ */ React23.createElement(Text19, { color: isSelected ? COLOR.user : COLOR.info, dimColor: !isSelected }, spec.summary));
|
|
14494
14455
|
}
|
|
14495
14456
|
|
|
14496
14457
|
// src/cli/ui/WelcomeBanner.tsx
|
|
@@ -14615,9 +14576,9 @@ function isMouseTrackingOn() {
|
|
|
14615
14576
|
}
|
|
14616
14577
|
|
|
14617
14578
|
// src/cli/ui/bang.ts
|
|
14618
|
-
function detectBangCommand(
|
|
14619
|
-
if (!
|
|
14620
|
-
const body =
|
|
14579
|
+
function detectBangCommand(text2) {
|
|
14580
|
+
if (!text2.startsWith("!")) return null;
|
|
14581
|
+
const body = text2.slice(1).trim();
|
|
14621
14582
|
if (!body) return null;
|
|
14622
14583
|
return body;
|
|
14623
14584
|
}
|
|
@@ -14723,20 +14684,20 @@ into every Reasonix session's prefix regardless of working directory.
|
|
|
14723
14684
|
Private to this machine \u2014 not committed anywhere.
|
|
14724
14685
|
|
|
14725
14686
|
`;
|
|
14726
|
-
function detectHashMemory(
|
|
14727
|
-
if (
|
|
14728
|
-
return { kind: "escape", text:
|
|
14729
|
-
}
|
|
14730
|
-
if (!
|
|
14731
|
-
if (
|
|
14732
|
-
if (/^#g\s*$/.test(
|
|
14733
|
-
const globalMatch = /^#g\s+(.+)$/s.exec(
|
|
14687
|
+
function detectHashMemory(text2) {
|
|
14688
|
+
if (text2.startsWith("\\#")) {
|
|
14689
|
+
return { kind: "escape", text: text2.slice(1) };
|
|
14690
|
+
}
|
|
14691
|
+
if (!text2.startsWith("#")) return null;
|
|
14692
|
+
if (text2.startsWith("##")) return null;
|
|
14693
|
+
if (/^#g\s*$/.test(text2)) return null;
|
|
14694
|
+
const globalMatch = /^#g\s+(.+)$/s.exec(text2);
|
|
14734
14695
|
if (globalMatch) {
|
|
14735
14696
|
const body2 = globalMatch[1].trim();
|
|
14736
14697
|
if (!body2) return null;
|
|
14737
14698
|
return { kind: "memory-global", note: body2 };
|
|
14738
14699
|
}
|
|
14739
|
-
const body =
|
|
14700
|
+
const body = text2.slice(1).trim();
|
|
14740
14701
|
if (!body) return null;
|
|
14741
14702
|
return { kind: "memory", note: body };
|
|
14742
14703
|
}
|
|
@@ -14771,195 +14732,1070 @@ function appendBulletToFile(path5, note, newFileHeader) {
|
|
|
14771
14732
|
return { path: path5, created: false };
|
|
14772
14733
|
}
|
|
14773
14734
|
|
|
14774
|
-
// src/cli/ui/log-
|
|
14735
|
+
// src/cli/ui/log-frame.tsx
|
|
14775
14736
|
import { Box as Box24, Text as Text22 } from "ink";
|
|
14776
14737
|
import React26 from "react";
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
|
|
14780
|
-
|
|
14738
|
+
|
|
14739
|
+
// src/frame/width.ts
|
|
14740
|
+
import stringWidthLib from "string-width";
|
|
14741
|
+
var segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
|
|
14742
|
+
function graphemes(s) {
|
|
14743
|
+
return Array.from(segmenter.segment(s), (seg) => seg.segment);
|
|
14744
|
+
}
|
|
14745
|
+
function graphemeWidth(g) {
|
|
14746
|
+
if (g.length === 0) return 0;
|
|
14747
|
+
const w = stringWidthLib(g);
|
|
14748
|
+
if (w <= 0) return 0;
|
|
14749
|
+
if (w >= 2) return 2;
|
|
14750
|
+
return 1;
|
|
14751
|
+
}
|
|
14752
|
+
|
|
14753
|
+
// src/frame/frame.ts
|
|
14754
|
+
var SPACE = { char: " ", width: 1 };
|
|
14755
|
+
var TAIL = { char: "", width: 1, tail: true };
|
|
14756
|
+
function empty(width = 0) {
|
|
14757
|
+
return { width, rows: [] };
|
|
14758
|
+
}
|
|
14759
|
+
function text(s, opts) {
|
|
14760
|
+
const { width, fg, bg, bold, dim, italic, underline, inverse, href } = opts;
|
|
14761
|
+
if (width <= 0) return empty(0);
|
|
14762
|
+
const styleOf = (g, w) => {
|
|
14763
|
+
const base = { char: g, width: w };
|
|
14764
|
+
if (fg !== void 0) base.fg = fg;
|
|
14765
|
+
if (bg !== void 0) base.bg = bg;
|
|
14766
|
+
if (bold) base.bold = true;
|
|
14767
|
+
if (dim) base.dim = true;
|
|
14768
|
+
if (italic) base.italic = true;
|
|
14769
|
+
if (underline) base.underline = true;
|
|
14770
|
+
if (inverse) base.inverse = true;
|
|
14771
|
+
if (href !== void 0) base.href = href;
|
|
14772
|
+
return base;
|
|
14773
|
+
};
|
|
14774
|
+
const rows = [];
|
|
14775
|
+
const lines = s.split("\n");
|
|
14776
|
+
for (const line of lines) {
|
|
14781
14777
|
if (line.length === 0) {
|
|
14782
|
-
|
|
14778
|
+
rows.push(padRowRight([], width));
|
|
14783
14779
|
continue;
|
|
14784
14780
|
}
|
|
14785
|
-
|
|
14786
|
-
|
|
14781
|
+
let buf = [];
|
|
14782
|
+
let bufWidth = 0;
|
|
14783
|
+
for (const g of graphemes(line)) {
|
|
14784
|
+
const w = graphemeWidth(g);
|
|
14785
|
+
if (w === 0) continue;
|
|
14786
|
+
if (bufWidth + w > width) {
|
|
14787
|
+
rows.push(padRowRight(buf, width - bufWidth));
|
|
14788
|
+
buf = [];
|
|
14789
|
+
bufWidth = 0;
|
|
14790
|
+
}
|
|
14791
|
+
buf.push(styleOf(g, w));
|
|
14792
|
+
if (w === 2) buf.push(TAIL);
|
|
14793
|
+
bufWidth += w;
|
|
14794
|
+
}
|
|
14795
|
+
rows.push(padRowRight(buf, width - bufWidth));
|
|
14796
|
+
}
|
|
14797
|
+
return { width, rows };
|
|
14798
|
+
}
|
|
14799
|
+
function padRowRight(cells, extraSpaces) {
|
|
14800
|
+
if (extraSpaces <= 0) return cells.slice();
|
|
14801
|
+
const out = cells.slice();
|
|
14802
|
+
for (let i = 0; i < extraSpaces; i++) out.push(SPACE);
|
|
14803
|
+
return out;
|
|
14804
|
+
}
|
|
14805
|
+
function spacerRow(width) {
|
|
14806
|
+
if (width <= 0) return [];
|
|
14807
|
+
return Array.from({ length: width }, () => SPACE);
|
|
14808
|
+
}
|
|
14809
|
+
function vstack(...frames) {
|
|
14810
|
+
if (frames.length === 0) return empty(0);
|
|
14811
|
+
const w = Math.max(...frames.map((f) => f.width));
|
|
14812
|
+
const rows = [];
|
|
14813
|
+
for (const f of frames) {
|
|
14814
|
+
if (f.width === w) {
|
|
14815
|
+
rows.push(...f.rows);
|
|
14816
|
+
} else {
|
|
14817
|
+
const extra = w - f.width;
|
|
14818
|
+
for (const r of f.rows) rows.push(padRowRight(r, extra));
|
|
14819
|
+
}
|
|
14820
|
+
}
|
|
14821
|
+
return { width: w, rows };
|
|
14822
|
+
}
|
|
14823
|
+
function hstack(...frames) {
|
|
14824
|
+
if (frames.length === 0) return empty(0);
|
|
14825
|
+
const h = Math.max(...frames.map((f) => f.rows.length));
|
|
14826
|
+
const w = frames.reduce((a, f) => a + f.width, 0);
|
|
14827
|
+
const rows = [];
|
|
14828
|
+
for (let i = 0; i < h; i++) {
|
|
14829
|
+
const cells = [];
|
|
14830
|
+
for (const f of frames) {
|
|
14831
|
+
const r = f.rows[i] ?? spacerRow(f.width);
|
|
14832
|
+
cells.push(...r);
|
|
14833
|
+
}
|
|
14834
|
+
rows.push(cells);
|
|
14835
|
+
}
|
|
14836
|
+
return { width: w, rows };
|
|
14837
|
+
}
|
|
14838
|
+
function pad(f, top, right, bottom2, left) {
|
|
14839
|
+
const newWidth = f.width + Math.max(0, left) + Math.max(0, right);
|
|
14840
|
+
const tPad = Math.max(0, top);
|
|
14841
|
+
const bPad = Math.max(0, bottom2);
|
|
14842
|
+
const blank2 = spacerRow(newWidth);
|
|
14843
|
+
const rows = [];
|
|
14844
|
+
for (let i = 0; i < tPad; i++) rows.push(blank2);
|
|
14845
|
+
if (left <= 0 && right <= 0) {
|
|
14846
|
+
rows.push(...f.rows);
|
|
14847
|
+
} else {
|
|
14848
|
+
const lPad = spacerRow(Math.max(0, left));
|
|
14849
|
+
const rPad = spacerRow(Math.max(0, right));
|
|
14850
|
+
for (const r of f.rows) rows.push([...lPad, ...r, ...rPad]);
|
|
14851
|
+
}
|
|
14852
|
+
for (let i = 0; i < bPad; i++) rows.push(blank2);
|
|
14853
|
+
return { width: newWidth, rows };
|
|
14854
|
+
}
|
|
14855
|
+
function borderLeft(f, color2, char = "\u2502") {
|
|
14856
|
+
const bar = { char, width: 1, fg: color2 };
|
|
14857
|
+
const newWidth = f.width + 1;
|
|
14858
|
+
const rows = [];
|
|
14859
|
+
for (const r of f.rows) rows.push([bar, ...r]);
|
|
14860
|
+
return { width: newWidth, rows };
|
|
14861
|
+
}
|
|
14862
|
+
|
|
14863
|
+
// src/frame/ansi.ts
|
|
14864
|
+
var ESC = "\x1B";
|
|
14865
|
+
var RESET = `${ESC}[0m`;
|
|
14866
|
+
function sameStyle(a, b) {
|
|
14867
|
+
return a.fg === b.fg && a.bg === b.bg && !!a.bold === !!b.bold && !!a.dim === !!b.dim && !!a.italic === !!b.italic && !!a.underline === !!b.underline && !!a.inverse === !!b.inverse && a.href === b.href;
|
|
14868
|
+
}
|
|
14869
|
+
function fgEscape(color2) {
|
|
14870
|
+
if (!color2) return null;
|
|
14871
|
+
const rgb = parseColor(color2);
|
|
14872
|
+
if (rgb) return `38;2;${rgb[0]};${rgb[1]};${rgb[2]}`;
|
|
14873
|
+
const named = NAMED_FG[color2.toLowerCase()];
|
|
14874
|
+
if (named !== void 0) return String(named);
|
|
14875
|
+
return null;
|
|
14876
|
+
}
|
|
14877
|
+
function bgEscape(color2) {
|
|
14878
|
+
if (!color2) return null;
|
|
14879
|
+
const rgb = parseColor(color2);
|
|
14880
|
+
if (rgb) return `48;2;${rgb[0]};${rgb[1]};${rgb[2]}`;
|
|
14881
|
+
const named = NAMED_BG[color2.toLowerCase()];
|
|
14882
|
+
if (named !== void 0) return String(named);
|
|
14883
|
+
return null;
|
|
14884
|
+
}
|
|
14885
|
+
function parseColor(s) {
|
|
14886
|
+
if (!s.startsWith("#")) return null;
|
|
14887
|
+
const hex = s.slice(1);
|
|
14888
|
+
if (hex.length !== 6) return null;
|
|
14889
|
+
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
14890
|
+
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
14891
|
+
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
14892
|
+
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null;
|
|
14893
|
+
return [r, g, b];
|
|
14894
|
+
}
|
|
14895
|
+
var NAMED_FG = {
|
|
14896
|
+
black: 30,
|
|
14897
|
+
red: 31,
|
|
14898
|
+
green: 32,
|
|
14899
|
+
yellow: 33,
|
|
14900
|
+
blue: 34,
|
|
14901
|
+
magenta: 35,
|
|
14902
|
+
cyan: 36,
|
|
14903
|
+
white: 37,
|
|
14904
|
+
gray: 90,
|
|
14905
|
+
grey: 90,
|
|
14906
|
+
brightred: 91,
|
|
14907
|
+
brightgreen: 92,
|
|
14908
|
+
brightyellow: 93,
|
|
14909
|
+
brightblue: 94,
|
|
14910
|
+
brightmagenta: 95,
|
|
14911
|
+
brightcyan: 96,
|
|
14912
|
+
brightwhite: 97
|
|
14913
|
+
};
|
|
14914
|
+
var NAMED_BG = {
|
|
14915
|
+
black: 40,
|
|
14916
|
+
red: 41,
|
|
14917
|
+
green: 42,
|
|
14918
|
+
yellow: 43,
|
|
14919
|
+
blue: 44,
|
|
14920
|
+
magenta: 45,
|
|
14921
|
+
cyan: 46,
|
|
14922
|
+
white: 47,
|
|
14923
|
+
gray: 100,
|
|
14924
|
+
grey: 100
|
|
14925
|
+
};
|
|
14926
|
+
function styleToAnsi(s) {
|
|
14927
|
+
const codes = [];
|
|
14928
|
+
if (s.bold) codes.push("1");
|
|
14929
|
+
if (s.dim) codes.push("2");
|
|
14930
|
+
if (s.italic) codes.push("3");
|
|
14931
|
+
if (s.underline) codes.push("4");
|
|
14932
|
+
if (s.inverse) codes.push("7");
|
|
14933
|
+
const fg = fgEscape(s.fg);
|
|
14934
|
+
if (fg) codes.push(fg);
|
|
14935
|
+
const bg = bgEscape(s.bg);
|
|
14936
|
+
if (bg) codes.push(bg);
|
|
14937
|
+
if (codes.length === 0) return "";
|
|
14938
|
+
return `${ESC}[${codes.join(";")}m`;
|
|
14939
|
+
}
|
|
14940
|
+
var EMPTY_STYLE = {};
|
|
14941
|
+
function frameToAnsi(f, opts = {}) {
|
|
14942
|
+
const out = [];
|
|
14943
|
+
for (let i = 0; i < f.rows.length; i++) {
|
|
14944
|
+
out.push(rowToAnsi(f.rows[i], opts));
|
|
14945
|
+
}
|
|
14946
|
+
return out.join("\n");
|
|
14947
|
+
}
|
|
14948
|
+
function rowToAnsi(row2, opts) {
|
|
14949
|
+
if (opts.plain) {
|
|
14950
|
+
let s = "";
|
|
14951
|
+
for (const c of row2) {
|
|
14952
|
+
if (c.tail) continue;
|
|
14953
|
+
s += c.char;
|
|
14954
|
+
}
|
|
14955
|
+
return s;
|
|
14956
|
+
}
|
|
14957
|
+
let result = "";
|
|
14958
|
+
let curStyle = EMPTY_STYLE;
|
|
14959
|
+
let inHref = false;
|
|
14960
|
+
let curHref;
|
|
14961
|
+
for (const c of row2) {
|
|
14962
|
+
if (c.tail) continue;
|
|
14963
|
+
const cellStyle = {
|
|
14964
|
+
fg: c.fg,
|
|
14965
|
+
bg: c.bg,
|
|
14966
|
+
bold: c.bold,
|
|
14967
|
+
dim: c.dim,
|
|
14968
|
+
italic: c.italic,
|
|
14969
|
+
underline: c.underline,
|
|
14970
|
+
inverse: c.inverse,
|
|
14971
|
+
href: c.href
|
|
14972
|
+
};
|
|
14973
|
+
if (cellStyle.href !== curHref) {
|
|
14974
|
+
if (inHref) {
|
|
14975
|
+
result += `${ESC}]8;;${ESC}\\`;
|
|
14976
|
+
inHref = false;
|
|
14977
|
+
}
|
|
14978
|
+
if (cellStyle.href !== void 0) {
|
|
14979
|
+
result += `${ESC}]8;;${cellStyle.href}${ESC}\\`;
|
|
14980
|
+
inHref = true;
|
|
14981
|
+
}
|
|
14982
|
+
curHref = cellStyle.href;
|
|
14983
|
+
}
|
|
14984
|
+
if (!sameStyle(curStyle, cellStyle)) {
|
|
14985
|
+
result += RESET;
|
|
14986
|
+
result += styleToAnsi(cellStyle);
|
|
14987
|
+
curStyle = cellStyle;
|
|
14988
|
+
}
|
|
14989
|
+
result += c.char;
|
|
14990
|
+
}
|
|
14991
|
+
if (inHref) result += `${ESC}]8;;${ESC}\\`;
|
|
14992
|
+
result += RESET;
|
|
14993
|
+
return result;
|
|
14994
|
+
}
|
|
14995
|
+
|
|
14996
|
+
// src/cli/ui/markdown-frame.ts
|
|
14997
|
+
var INLINE_RE2 = /(\[([^\]\n]+)\]\(([^)\n]+)\)|\*\*\*([^*\n]+?)\*\*\*|\*\*([^*\n]+?)\*\*|```([^\n]+?)```|`([^`\n]+?)`|~~([^~\n]+?)~~|(?<![*\w])\*([^*\n]+?)\*(?!\w)|\\([*_~`[\](){}#+\-.!\\]))/g;
|
|
14998
|
+
function parseInline(input, baseOpts) {
|
|
14999
|
+
const out = [];
|
|
15000
|
+
let lastEnd = 0;
|
|
15001
|
+
INLINE_RE2.lastIndex = 0;
|
|
15002
|
+
for (let m = INLINE_RE2.exec(input); m !== null; m = INLINE_RE2.exec(input)) {
|
|
15003
|
+
if (m.index > lastEnd) {
|
|
15004
|
+
out.push({ text: input.slice(lastEnd, m.index), opts: baseOpts });
|
|
15005
|
+
}
|
|
15006
|
+
const linkText = m[2];
|
|
15007
|
+
const linkUrl = m[3];
|
|
15008
|
+
const boldItalic = m[4];
|
|
15009
|
+
const bold = m[5];
|
|
15010
|
+
const code3 = m[6];
|
|
15011
|
+
const code1 = m[7];
|
|
15012
|
+
const strike = m[8];
|
|
15013
|
+
const italic = m[9];
|
|
15014
|
+
const escapeChar = m[10];
|
|
15015
|
+
if (linkText !== void 0) {
|
|
15016
|
+
out.push({
|
|
15017
|
+
text: linkText,
|
|
15018
|
+
opts: { ...baseOpts, fg: COLOR.accent, underline: true, href: linkUrl }
|
|
15019
|
+
});
|
|
15020
|
+
} else if (boldItalic !== void 0) {
|
|
15021
|
+
out.push({ text: boldItalic, opts: { ...baseOpts, bold: true, italic: true } });
|
|
15022
|
+
} else if (bold !== void 0) {
|
|
15023
|
+
out.push({ text: bold, opts: { ...baseOpts, bold: true } });
|
|
15024
|
+
} else if (code3 !== void 0) {
|
|
15025
|
+
const stripped = code3.replace(/^(\w+)\s+/, "");
|
|
15026
|
+
out.push({ text: stripped, opts: { ...baseOpts, fg: "#67e8f9", bg: "#0f172a" } });
|
|
15027
|
+
} else if (code1 !== void 0) {
|
|
15028
|
+
out.push({ text: code1, opts: { ...baseOpts, fg: "#67e8f9", bg: "#0f172a" } });
|
|
15029
|
+
} else if (strike !== void 0) {
|
|
15030
|
+
out.push({ text: strike, opts: { ...baseOpts, dim: true } });
|
|
15031
|
+
} else if (italic !== void 0) {
|
|
15032
|
+
out.push({ text: italic, opts: { ...baseOpts, italic: true } });
|
|
15033
|
+
} else if (escapeChar !== void 0) {
|
|
15034
|
+
out.push({ text: escapeChar, opts: baseOpts });
|
|
15035
|
+
}
|
|
15036
|
+
lastEnd = m.index + m[0].length;
|
|
15037
|
+
}
|
|
15038
|
+
if (lastEnd < input.length) {
|
|
15039
|
+
out.push({ text: input.slice(lastEnd), opts: baseOpts });
|
|
15040
|
+
}
|
|
15041
|
+
return out;
|
|
15042
|
+
}
|
|
15043
|
+
function segmentsToFrame(segs, width) {
|
|
15044
|
+
if (width <= 0) return empty(0);
|
|
15045
|
+
const atoms = [];
|
|
15046
|
+
for (const seg of segs) {
|
|
15047
|
+
if (!seg.text) continue;
|
|
15048
|
+
const f = text(seg.text, { ...seg.opts, width: Math.max(width, seg.text.length * 2 + 4) });
|
|
15049
|
+
if (f.rows.length > 0) {
|
|
15050
|
+
let stop = f.rows[0].length;
|
|
15051
|
+
while (stop > 0 && f.rows[0][stop - 1].char === " " && f.rows[0][stop - 1].fg === void 0 && f.rows[0][stop - 1].bg === void 0) {
|
|
15052
|
+
stop--;
|
|
15053
|
+
}
|
|
15054
|
+
for (let i = 0; i < stop; i++) atoms.push(f.rows[0][i]);
|
|
15055
|
+
}
|
|
15056
|
+
for (let li = 1; li < f.rows.length; li++) {
|
|
15057
|
+
atoms.push({ char: "\n", width: 1 });
|
|
15058
|
+
let stop = f.rows[li].length;
|
|
15059
|
+
while (stop > 0 && f.rows[li][stop - 1].char === " " && f.rows[li][stop - 1].fg === void 0) {
|
|
15060
|
+
stop--;
|
|
15061
|
+
}
|
|
15062
|
+
for (let i = 0; i < stop; i++) atoms.push(f.rows[li][i]);
|
|
15063
|
+
}
|
|
15064
|
+
}
|
|
15065
|
+
const SPACE2 = { char: " ", width: 1 };
|
|
15066
|
+
const rows = [];
|
|
15067
|
+
let cur = [];
|
|
15068
|
+
let curW = 0;
|
|
15069
|
+
let lastSpaceIdx = -1;
|
|
15070
|
+
const flushRow = (forceNewline = false) => {
|
|
15071
|
+
while (curW < width) {
|
|
15072
|
+
cur.push(SPACE2);
|
|
15073
|
+
curW += 1;
|
|
15074
|
+
}
|
|
15075
|
+
rows.push(cur);
|
|
15076
|
+
cur = [];
|
|
15077
|
+
curW = 0;
|
|
15078
|
+
lastSpaceIdx = -1;
|
|
15079
|
+
if (forceNewline) return;
|
|
15080
|
+
};
|
|
15081
|
+
for (const a of atoms) {
|
|
15082
|
+
if (a.char === "\n") {
|
|
15083
|
+
flushRow(true);
|
|
14787
15084
|
continue;
|
|
14788
15085
|
}
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
15086
|
+
const w = a.tail ? 0 : a.width;
|
|
15087
|
+
if (curW + w > width) {
|
|
15088
|
+
if (lastSpaceIdx >= 0 && lastSpaceIdx > 0) {
|
|
15089
|
+
const overflow = cur.slice(lastSpaceIdx + 1);
|
|
15090
|
+
cur = cur.slice(0, lastSpaceIdx);
|
|
15091
|
+
let newW = 0;
|
|
15092
|
+
for (const c of cur) newW += c.tail ? 0 : c.width;
|
|
15093
|
+
while (newW < width) {
|
|
15094
|
+
cur.push(SPACE2);
|
|
15095
|
+
newW += 1;
|
|
15096
|
+
}
|
|
15097
|
+
rows.push(cur);
|
|
15098
|
+
cur = overflow;
|
|
15099
|
+
curW = 0;
|
|
15100
|
+
for (const c of cur) curW += c.tail ? 0 : c.width;
|
|
15101
|
+
lastSpaceIdx = -1;
|
|
15102
|
+
} else {
|
|
15103
|
+
flushRow();
|
|
15104
|
+
}
|
|
15105
|
+
}
|
|
15106
|
+
if (a.char === " ") lastSpaceIdx = cur.length;
|
|
15107
|
+
cur.push(a);
|
|
15108
|
+
curW += w;
|
|
15109
|
+
}
|
|
15110
|
+
if (cur.length > 0 || rows.length === 0) {
|
|
15111
|
+
flushRow();
|
|
15112
|
+
}
|
|
15113
|
+
return { width, rows };
|
|
15114
|
+
}
|
|
15115
|
+
function paragraphFrame(p, width) {
|
|
15116
|
+
const segs = parseInline(p.text, {});
|
|
15117
|
+
return segmentsToFrame(segs, width);
|
|
15118
|
+
}
|
|
15119
|
+
function headingFrame(h, width) {
|
|
15120
|
+
const isMajor = h.level <= 3;
|
|
15121
|
+
const fg = isMajor ? COLOR.brand : COLOR.accent;
|
|
15122
|
+
const segs = parseInline(h.text, { bold: true, fg, dim: !isMajor });
|
|
15123
|
+
return vstack(segmentsToFrame(segs, width), text("", { width }));
|
|
15124
|
+
}
|
|
15125
|
+
function bulletListFrame(b, width) {
|
|
15126
|
+
const rows = [];
|
|
15127
|
+
for (let i = 0; i < b.items.length; i++) {
|
|
15128
|
+
const item = b.items[i];
|
|
15129
|
+
let prefix;
|
|
15130
|
+
let prefixOpts;
|
|
15131
|
+
if (item.task === "done") {
|
|
15132
|
+
prefix = "[x] ";
|
|
15133
|
+
prefixOpts = { fg: COLOR.ok, bold: true };
|
|
15134
|
+
} else if (item.task === "todo") {
|
|
15135
|
+
prefix = "[ ] ";
|
|
15136
|
+
prefixOpts = { fg: COLOR.warn, bold: true };
|
|
15137
|
+
} else if (b.ordered) {
|
|
15138
|
+
prefix = `${i + 1}. `;
|
|
15139
|
+
prefixOpts = { fg: COLOR.info, bold: true };
|
|
15140
|
+
} else {
|
|
15141
|
+
prefix = "\u2022 ";
|
|
15142
|
+
prefixOpts = { fg: COLOR.info, bold: true };
|
|
15143
|
+
}
|
|
15144
|
+
const prefixWidth = prefix.length;
|
|
15145
|
+
const indentRow = " ".repeat(prefixWidth);
|
|
15146
|
+
const innerSegs = parseInline(item.text, {});
|
|
15147
|
+
const innerFrame = segmentsToFrame(innerSegs, Math.max(8, width - prefixWidth));
|
|
15148
|
+
const decoratedRows = innerFrame.rows.map((r, li) => {
|
|
15149
|
+
const indent = li === 0 ? text(prefix, { width: prefixWidth, ...prefixOpts }) : text(indentRow, { width: prefixWidth });
|
|
15150
|
+
return {
|
|
15151
|
+
width: prefixWidth + innerFrame.width,
|
|
15152
|
+
rows: [[...indent.rows[0], ...r]]
|
|
15153
|
+
};
|
|
15154
|
+
});
|
|
15155
|
+
rows.push(...decoratedRows);
|
|
15156
|
+
}
|
|
15157
|
+
return vstack(...rows);
|
|
15158
|
+
}
|
|
15159
|
+
function codeBlockFrame(c, width) {
|
|
15160
|
+
const lines = c.text.split("\n");
|
|
15161
|
+
const rows = [];
|
|
15162
|
+
if (c.lang) {
|
|
15163
|
+
rows.push(text(c.lang, { width, fg: COLOR.info, dim: true, italic: true }));
|
|
15164
|
+
}
|
|
15165
|
+
for (const line of lines) {
|
|
15166
|
+
rows.push(text(line || " ", { width, fg: "#67e8f9", bg: "#0f172a" }));
|
|
15167
|
+
}
|
|
15168
|
+
return vstack(...rows);
|
|
15169
|
+
}
|
|
15170
|
+
function blockquoteFrame(bq, width) {
|
|
15171
|
+
const inner = bq.children.map((child) => blockToFrame(child, Math.max(8, width - 2)));
|
|
15172
|
+
const stacked = inner.length === 0 ? empty(Math.max(8, width - 2)) : vstack(...inner);
|
|
15173
|
+
return borderLeft(pad(stacked, 0, 0, 0, 1), COLOR.info);
|
|
15174
|
+
}
|
|
15175
|
+
function hrFrame(width) {
|
|
15176
|
+
return text("\u2500".repeat(width), { width, fg: COLOR.info, dim: true });
|
|
15177
|
+
}
|
|
15178
|
+
function blockToFrame(b, width) {
|
|
15179
|
+
switch (b.kind) {
|
|
15180
|
+
case "paragraph":
|
|
15181
|
+
return paragraphFrame(b, width);
|
|
15182
|
+
case "heading":
|
|
15183
|
+
return headingFrame(b, width);
|
|
15184
|
+
case "bullet":
|
|
15185
|
+
return bulletListFrame(b, width);
|
|
15186
|
+
case "code":
|
|
15187
|
+
return codeBlockFrame(b, width);
|
|
15188
|
+
case "quote":
|
|
15189
|
+
return blockquoteFrame(b, width);
|
|
15190
|
+
case "hr":
|
|
15191
|
+
return hrFrame(width);
|
|
15192
|
+
case "table":
|
|
15193
|
+
return vstack(
|
|
15194
|
+
text(b.header.join(" | "), { width, bold: true }),
|
|
15195
|
+
text(b.header.map(() => "\u2500").join("\u2500\u253C\u2500"), { width, dim: true }),
|
|
15196
|
+
text(b.rows.map((r) => r.join(" | ")).join("\n"), { width, dim: true })
|
|
15197
|
+
);
|
|
15198
|
+
case "edit-block":
|
|
15199
|
+
return text(`${b.filename}
|
|
15200
|
+
<<< SEARCH
|
|
15201
|
+
${b.search}
|
|
15202
|
+
=======
|
|
15203
|
+
${b.replace}
|
|
15204
|
+
>>> REPLACE`, {
|
|
15205
|
+
width,
|
|
15206
|
+
dim: true
|
|
15207
|
+
});
|
|
15208
|
+
default:
|
|
15209
|
+
return empty(width);
|
|
15210
|
+
}
|
|
15211
|
+
}
|
|
15212
|
+
function markdownToFrame(markdown, width) {
|
|
15213
|
+
if (!markdown) return empty(width);
|
|
15214
|
+
const blocks = parseBlocks(markdown);
|
|
15215
|
+
if (blocks.length === 0) return empty(width);
|
|
15216
|
+
const frames = [];
|
|
15217
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
15218
|
+
const b = blocks[i];
|
|
15219
|
+
frames.push(blockToFrame(b, width));
|
|
15220
|
+
const isLast = i === blocks.length - 1;
|
|
15221
|
+
const carriesOwnSpacer = b.kind === "heading";
|
|
15222
|
+
if (!isLast && !carriesOwnSpacer) {
|
|
15223
|
+
frames.push(text("", { width }));
|
|
15224
|
+
}
|
|
15225
|
+
}
|
|
15226
|
+
return vstack(...frames);
|
|
15227
|
+
}
|
|
15228
|
+
|
|
15229
|
+
// src/cli/ui/log-frame.tsx
|
|
15230
|
+
function formatTokensCompact2(n) {
|
|
15231
|
+
if (n < 1024) return String(n);
|
|
15232
|
+
const k = n / 1024;
|
|
15233
|
+
return k >= 100 ? `${k.toFixed(0)}K` : `${k.toFixed(1)}K`;
|
|
15234
|
+
}
|
|
15235
|
+
var ROLE_GLYPH2 = {
|
|
15236
|
+
user: "\u25C7",
|
|
15237
|
+
toolOk: GLYPH.toolOk,
|
|
15238
|
+
toolErr: GLYPH.toolErr
|
|
15239
|
+
};
|
|
15240
|
+
var SPACE_CELL = { char: " ", width: 1 };
|
|
15241
|
+
function rowFrame(parts, width) {
|
|
15242
|
+
const cells = [];
|
|
15243
|
+
for (const p of parts) {
|
|
15244
|
+
if (p.rows.length > 0) cells.push(...p.rows[0]);
|
|
15245
|
+
}
|
|
15246
|
+
const w = width ?? cells.reduce((a, c) => a + (c.tail ? 0 : c.width), 0);
|
|
15247
|
+
if (cells.length > w) cells.length = w;
|
|
15248
|
+
while (cells.reduce((a, c) => a + (c.tail ? 0 : c.width), 0) < w) cells.push(SPACE_CELL);
|
|
15249
|
+
return { width: w, rows: [cells] };
|
|
15250
|
+
}
|
|
15251
|
+
function atomRows(a) {
|
|
15252
|
+
return a.kind === "frame" ? a.frame.rows.length : a.rows;
|
|
15253
|
+
}
|
|
15254
|
+
function detectInfoTone(rawText) {
|
|
15255
|
+
const m = rawText.match(/^([▸▶▲⚠✓✗✖↻ⓘ])\s*(.*)$/s);
|
|
15256
|
+
const lead = m?.[1] ?? "\u25B8";
|
|
15257
|
+
const body = m?.[2] ?? rawText;
|
|
15258
|
+
let color2 = COLOR.info;
|
|
15259
|
+
if (lead === "\u25B2" || lead === "\u26A0") color2 = COLOR.warn;
|
|
15260
|
+
else if (lead === "\u2713") color2 = COLOR.ok;
|
|
15261
|
+
else if (lead === "\u2717" || lead === "\u2716") color2 = COLOR.err;
|
|
15262
|
+
else if (lead === "\u21BB") color2 = COLOR.primary;
|
|
15263
|
+
return { lead, color: color2, body };
|
|
15264
|
+
}
|
|
15265
|
+
function accentFrame(glyph, glyphColor, body, bodyColor, bodyDim, width) {
|
|
15266
|
+
const indentCells = 1 + glyph.length + 2;
|
|
15267
|
+
const inner = Math.max(8, width - indentCells);
|
|
15268
|
+
const bodyFrame = text(body, {
|
|
15269
|
+
width: inner,
|
|
15270
|
+
fg: bodyColor,
|
|
15271
|
+
dim: bodyDim
|
|
15272
|
+
});
|
|
15273
|
+
const rows = [];
|
|
15274
|
+
for (let i = 0; i < bodyFrame.rows.length; i++) {
|
|
15275
|
+
const indent = i === 0 ? text(`${glyph} `, { width: indentCells - 1, fg: glyphColor, bold: true }) : text(" ".repeat(indentCells - 1), { width: indentCells - 1 });
|
|
15276
|
+
rows.push({
|
|
15277
|
+
width: bodyFrame.width + indent.width,
|
|
15278
|
+
rows: [[...indent.rows[0], ...bodyFrame.rows[i]]]
|
|
15279
|
+
});
|
|
15280
|
+
}
|
|
15281
|
+
const stacked = vstack(...rows);
|
|
15282
|
+
return borderLeft(stacked, glyphColor);
|
|
15283
|
+
}
|
|
15284
|
+
function infoFrame(event, width) {
|
|
15285
|
+
const { lead, color: color2, body } = detectInfoTone(event.text);
|
|
15286
|
+
return accentFrame(lead, color2, body, void 0, true, width);
|
|
15287
|
+
}
|
|
15288
|
+
function warningFrame(event, width) {
|
|
15289
|
+
return accentFrame("\u25B2 warn", COLOR.warn, event.text, COLOR.warn, false, width);
|
|
15290
|
+
}
|
|
15291
|
+
function errorFrame(event, width) {
|
|
15292
|
+
return accentFrame("\u2726 error", COLOR.err, event.text, COLOR.err, false, width);
|
|
15293
|
+
}
|
|
15294
|
+
function stepProgressFrame(event, width) {
|
|
15295
|
+
const sp = event.stepProgress;
|
|
15296
|
+
const counter = sp && sp.total > 0 ? `${sp.completed}/${sp.total}` : "";
|
|
15297
|
+
const label = sp?.title ? `${sp.stepId} \xB7 ${sp.title}` : sp?.stepId ?? "";
|
|
15298
|
+
const pillFrame = text(" \u2713 STEP ", { width: 8, bg: "#4ade80", fg: "black", bold: true });
|
|
15299
|
+
const counterFrame = counter ? text(` ${counter}`, { width: 2 + counter.length, fg: "#4ade80", bold: true }) : empty(0);
|
|
15300
|
+
const labelFrame = text(` ${label}`, { width: width - 8 - counterFrame.width, fg: "#86efac" });
|
|
15301
|
+
const headerWidth = pillFrame.width + counterFrame.width + labelFrame.width;
|
|
15302
|
+
const headerRow = {
|
|
15303
|
+
width: headerWidth,
|
|
15304
|
+
rows: [[...pillFrame.rows[0], ...counterFrame.rows[0], ...labelFrame.rows[0]]]
|
|
15305
|
+
};
|
|
15306
|
+
const bodyParts = [];
|
|
15307
|
+
if (event.text) {
|
|
15308
|
+
bodyParts.push(pad(text(event.text, { width: width - 2, dim: true }), 0, 0, 0, 2));
|
|
15309
|
+
}
|
|
15310
|
+
if (sp?.notes) {
|
|
15311
|
+
bodyParts.push(
|
|
15312
|
+
pad(text(`note: ${sp.notes}`, { width: width - 2, fg: "#fbbf24", dim: true }), 0, 0, 0, 2)
|
|
15313
|
+
);
|
|
15314
|
+
}
|
|
15315
|
+
const spacer = text("", { width });
|
|
15316
|
+
return vstack(spacer, headerRow, ...bodyParts);
|
|
15317
|
+
}
|
|
15318
|
+
function simpleAssistantFrame(event, width) {
|
|
15319
|
+
const spacer = text("", { width });
|
|
15320
|
+
const glyph = text("\u25C6", { width: 1, fg: COLOR.assistant, bold: true });
|
|
15321
|
+
let header2 = glyph;
|
|
15322
|
+
if (event.stats) {
|
|
15323
|
+
const badge2 = text(` ${event.stats.model.replace(/^deepseek-/, "")} `, {
|
|
15324
|
+
width: 2 + event.stats.model.replace(/^deepseek-/, "").length,
|
|
15325
|
+
bg: COLOR.assistant,
|
|
15326
|
+
fg: "black",
|
|
15327
|
+
bold: true
|
|
15328
|
+
});
|
|
15329
|
+
const gap = text(" ", { width: 2 });
|
|
15330
|
+
header2 = {
|
|
15331
|
+
width: glyph.width + gap.width + badge2.width,
|
|
15332
|
+
rows: [[...glyph.rows[0], ...gap.rows[0], ...badge2.rows[0]]]
|
|
15333
|
+
};
|
|
15334
|
+
}
|
|
15335
|
+
const bodyInnerWidth = width - 1 - 2;
|
|
15336
|
+
const bodyInner = event.text ? markdownToFrame(event.text, bodyInnerWidth) : text("(empty body \u2014 likely tool-call only)", {
|
|
15337
|
+
width: bodyInnerWidth,
|
|
15338
|
+
fg: COLOR.assistant,
|
|
15339
|
+
dim: true
|
|
15340
|
+
});
|
|
15341
|
+
const bodyIndented = pad(bodyInner, 0, 0, 0, 2);
|
|
15342
|
+
const bodyBordered = borderLeft(bodyIndented, COLOR.assistant);
|
|
15343
|
+
const parts = [spacer, header2, bodyBordered];
|
|
15344
|
+
if (event.repair) {
|
|
15345
|
+
parts.push(pad(text(event.repair, { width: width - 2, fg: COLOR.accent }), 0, 0, 0, 2));
|
|
15346
|
+
}
|
|
15347
|
+
if (event.stats) {
|
|
15348
|
+
const hit = (event.stats.cacheHitRatio * 100).toFixed(1);
|
|
15349
|
+
const hitColor = event.stats.cacheHitRatio >= 0.7 ? "#4ade80" : event.stats.cacheHitRatio >= 0.4 ? "#fcd34d" : "#f87171";
|
|
15350
|
+
const statsLine = `\u232C ${hit}% \xB7 in ${event.stats.usage.promptTokens} \u2192 out ${event.stats.usage.completionTokens} \xB7 $${event.stats.cost.toFixed(6)}`;
|
|
15351
|
+
parts.push(pad(text(statsLine, { width: width - 2, fg: hitColor }), 0, 0, 0, 2));
|
|
15352
|
+
}
|
|
15353
|
+
return vstack(...parts);
|
|
15354
|
+
}
|
|
15355
|
+
function turnSeparatorFrame(width) {
|
|
15356
|
+
const w = Math.max(16, width - 2);
|
|
15357
|
+
const sideWidth = Math.max(2, Math.floor((w - 5) / 2));
|
|
15358
|
+
const left = gradientCells(sideWidth, "\u2500");
|
|
15359
|
+
const right = gradientCells(sideWidth, "\u2500");
|
|
15360
|
+
const sideCells = (cells) => cells.map(({ ch, color: color2 }) => ({ char: ch, width: 1, fg: color2 }));
|
|
15361
|
+
const center = [
|
|
15362
|
+
SPACE_CELL,
|
|
15363
|
+
SPACE_CELL,
|
|
15364
|
+
{ char: "\u25C6", width: 1, fg: COLOR.brand, bold: true },
|
|
15365
|
+
SPACE_CELL,
|
|
15366
|
+
SPACE_CELL
|
|
15367
|
+
];
|
|
15368
|
+
const totalUsed = sideWidth * 2 + 5;
|
|
15369
|
+
const padLeft = Math.max(0, Math.floor((width - totalUsed) / 2));
|
|
15370
|
+
const padRight2 = Math.max(0, width - totalUsed - padLeft);
|
|
15371
|
+
const padCells = (n) => Array.from({ length: n }, () => SPACE_CELL);
|
|
15372
|
+
return {
|
|
15373
|
+
width,
|
|
15374
|
+
rows: [
|
|
15375
|
+
[
|
|
15376
|
+
...padCells(padLeft),
|
|
15377
|
+
...sideCells(left),
|
|
15378
|
+
...center,
|
|
15379
|
+
...sideCells(right),
|
|
15380
|
+
...padCells(padRight2)
|
|
15381
|
+
]
|
|
15382
|
+
]
|
|
15383
|
+
};
|
|
15384
|
+
}
|
|
15385
|
+
function userFrame(event, width) {
|
|
15386
|
+
const indentWidth = 3;
|
|
15387
|
+
const bodyInner = text(event.text, { width: Math.max(8, width - indentWidth - 2) });
|
|
15388
|
+
const padded = pad(bodyInner, 0, 0, 0, 1);
|
|
15389
|
+
const bordered = borderLeft(padded, COLOR.user);
|
|
15390
|
+
const indentRows = bordered.rows.map(
|
|
15391
|
+
(_, i) => i === 0 ? text(`${ROLE_GLYPH2.user} `, { width: indentWidth, fg: "cyan", bold: true }) : text(" ".repeat(indentWidth), { width: indentWidth })
|
|
15392
|
+
);
|
|
15393
|
+
const indentCol = vstack(...indentRows);
|
|
15394
|
+
let body = hstack(indentCol, bordered);
|
|
15395
|
+
if (event.leadSeparator) {
|
|
15396
|
+
body = vstack(turnSeparatorFrame(width), body);
|
|
15397
|
+
}
|
|
15398
|
+
return body;
|
|
15399
|
+
}
|
|
15400
|
+
function toolCompactFrame(event, width) {
|
|
15401
|
+
const summary = summarizeToolResult(event.toolName ?? "?", event.text);
|
|
15402
|
+
const status2 = summary.isError ? "err" : "ok";
|
|
15403
|
+
const symbol = status2 === "err" ? ROLE_GLYPH2.toolErr : ROLE_GLYPH2.toolOk;
|
|
15404
|
+
const pillFg = status2 === "err" ? "red" : "cyan";
|
|
15405
|
+
const accent = status2 === "err" ? COLOR.toolErr : COLOR.tool;
|
|
15406
|
+
const innerWidth = width - 2;
|
|
15407
|
+
const segments = [];
|
|
15408
|
+
const pillText = `${symbol} ${event.toolName ?? "?"}`;
|
|
15409
|
+
segments.push(text(pillText, { width: pillText.length, fg: pillFg, bold: true }));
|
|
15410
|
+
if (event.durationMs !== void 0 && event.durationMs >= 100) {
|
|
15411
|
+
const dur = ` ${formatDuration(event.durationMs)}`;
|
|
15412
|
+
segments.push(text(dur, { width: dur.length, dim: true }));
|
|
15413
|
+
}
|
|
15414
|
+
segments.push(text(" ", { width: 2, dim: true }));
|
|
15415
|
+
const used = segments.reduce((a, p) => a + p.width, 0);
|
|
15416
|
+
const indexHint = event.toolIndex !== void 0 ? ` /tool ${event.toolIndex}` : "";
|
|
15417
|
+
const summaryBudget = Math.max(8, innerWidth - used - indexHint.length);
|
|
15418
|
+
segments.push(
|
|
15419
|
+
text(summary.summary, {
|
|
15420
|
+
width: summaryBudget,
|
|
15421
|
+
fg: status2 === "err" ? "red" : void 0,
|
|
15422
|
+
dim: status2 === "ok"
|
|
15423
|
+
})
|
|
15424
|
+
);
|
|
15425
|
+
if (indexHint) {
|
|
15426
|
+
segments.push(text(indexHint, { width: indexHint.length, dim: true }));
|
|
15427
|
+
}
|
|
15428
|
+
const inner = rowFrame(
|
|
15429
|
+
segments.map((s) => ({ width: s.width, rows: [s.rows[0] ?? []] })),
|
|
15430
|
+
innerWidth
|
|
15431
|
+
);
|
|
15432
|
+
return borderLeft(pad(inner, 0, 0, 0, 1), accent);
|
|
15433
|
+
}
|
|
15434
|
+
function editFileDiffFrame(event, width) {
|
|
15435
|
+
const lines = event.text.split(/\r?\n/);
|
|
15436
|
+
const [statusHeader, hunkHeader, ...body] = lines;
|
|
15437
|
+
const innerWidth = width - 2;
|
|
15438
|
+
const parts = [];
|
|
15439
|
+
parts.push(
|
|
15440
|
+
rowFrame(
|
|
15441
|
+
[
|
|
15442
|
+
text(`${ROLE_GLYPH2.toolOk} ${event.toolName ?? "edit_file"}`, {
|
|
15443
|
+
width: 2 + (event.toolName ?? "edit_file").length,
|
|
15444
|
+
fg: "cyan",
|
|
15445
|
+
bold: true
|
|
15446
|
+
}),
|
|
15447
|
+
text(" diff:", { width: 8, dim: true })
|
|
15448
|
+
],
|
|
15449
|
+
innerWidth
|
|
15450
|
+
)
|
|
15451
|
+
);
|
|
15452
|
+
if (statusHeader !== void 0) {
|
|
15453
|
+
parts.push(text(` ${statusHeader}`, { width: innerWidth, dim: true }));
|
|
15454
|
+
}
|
|
15455
|
+
parts.push(text("", { width: innerWidth }));
|
|
15456
|
+
if (hunkHeader !== void 0) {
|
|
15457
|
+
const hunk = hunkHeader.trim();
|
|
15458
|
+
parts.push(
|
|
15459
|
+
rowFrame(
|
|
15460
|
+
[
|
|
15461
|
+
text(` ${hunk} `, {
|
|
15462
|
+
width: hunk.length + 2,
|
|
15463
|
+
bg: "#c4b5fd",
|
|
15464
|
+
fg: "black",
|
|
15465
|
+
bold: true
|
|
15466
|
+
})
|
|
15467
|
+
],
|
|
15468
|
+
innerWidth
|
|
15469
|
+
)
|
|
15470
|
+
);
|
|
15471
|
+
}
|
|
15472
|
+
for (const line of body) {
|
|
15473
|
+
const stripped = line.replace(/^ {2}/, "");
|
|
15474
|
+
if (stripped.startsWith("- ")) {
|
|
15475
|
+
parts.push(
|
|
15476
|
+
rowFrame(
|
|
15477
|
+
[
|
|
15478
|
+
text("\u2212 ", { width: 2, fg: "#f87171", bold: true }),
|
|
15479
|
+
text(stripped.slice(2), { width: innerWidth - 2, fg: "#fca5a5" })
|
|
15480
|
+
],
|
|
15481
|
+
innerWidth
|
|
15482
|
+
)
|
|
15483
|
+
);
|
|
15484
|
+
} else if (stripped.startsWith("+ ")) {
|
|
15485
|
+
parts.push(
|
|
15486
|
+
rowFrame(
|
|
15487
|
+
[
|
|
15488
|
+
text("+ ", { width: 2, fg: "#4ade80", bold: true }),
|
|
15489
|
+
text(stripped.slice(2), { width: innerWidth - 2, fg: "#86efac" })
|
|
15490
|
+
],
|
|
15491
|
+
innerWidth
|
|
15492
|
+
)
|
|
15493
|
+
);
|
|
15494
|
+
} else {
|
|
15495
|
+
parts.push(
|
|
15496
|
+
rowFrame(
|
|
15497
|
+
[
|
|
15498
|
+
text(" ", { width: 2, dim: true }),
|
|
15499
|
+
text(stripped, { width: innerWidth - 2, dim: true })
|
|
15500
|
+
],
|
|
15501
|
+
innerWidth
|
|
15502
|
+
)
|
|
15503
|
+
);
|
|
14793
15504
|
}
|
|
14794
15505
|
}
|
|
14795
|
-
|
|
15506
|
+
const inner = vstack(...parts);
|
|
15507
|
+
return borderLeft(pad(inner, 0, 0, 0, 1), COLOR.tool);
|
|
14796
15508
|
}
|
|
14797
|
-
function
|
|
14798
|
-
|
|
14799
|
-
|
|
14800
|
-
|
|
14801
|
-
const
|
|
14802
|
-
const
|
|
14803
|
-
const
|
|
14804
|
-
|
|
14805
|
-
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
|
|
15509
|
+
function reasoningFrame(reasoning, width) {
|
|
15510
|
+
const max = 260;
|
|
15511
|
+
const flat = reasoning.replace(/\s+/g, " ").trim();
|
|
15512
|
+
const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
|
|
15513
|
+
const tokensApprox = Math.max(1, Math.round(flat.length / 4.5));
|
|
15514
|
+
const tokLabel = tokensApprox >= 1e3 ? `${(tokensApprox / 1e3).toFixed(1)}k` : `${tokensApprox}`;
|
|
15515
|
+
const header2 = rowFrame(
|
|
15516
|
+
[
|
|
15517
|
+
text("R1 \u21AF", { width: 5, fg: COLOR.accent, bold: true }),
|
|
15518
|
+
text(` reasoning \xB7 ~${tokLabel} tok \xB7 /think for full`, {
|
|
15519
|
+
width: 28 + tokLabel.length,
|
|
15520
|
+
dim: true
|
|
15521
|
+
})
|
|
15522
|
+
],
|
|
15523
|
+
width
|
|
15524
|
+
);
|
|
15525
|
+
const previewBody = pad(
|
|
15526
|
+
text(preview, { width: width - 2, fg: COLOR.accent, italic: true, dim: true }),
|
|
15527
|
+
0,
|
|
15528
|
+
0,
|
|
15529
|
+
0,
|
|
15530
|
+
1
|
|
15531
|
+
);
|
|
15532
|
+
const previewBordered = borderLeft(previewBody, COLOR.accent);
|
|
15533
|
+
const trail = text("", { width });
|
|
15534
|
+
return vstack(header2, previewBordered, trail);
|
|
14810
15535
|
}
|
|
14811
|
-
function
|
|
14812
|
-
|
|
14813
|
-
|
|
14814
|
-
|
|
14815
|
-
|
|
14816
|
-
|
|
14817
|
-
|
|
14818
|
-
|
|
14819
|
-
|
|
14820
|
-
|
|
14821
|
-
|
|
14822
|
-
|
|
14823
|
-
|
|
14824
|
-
|
|
14825
|
-
|
|
14826
|
-
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
/* @__PURE__ */ React26.createElement(Text22, { color: bodyColor, dimColor: bodyDim }, body)
|
|
15536
|
+
function branchFrame(branch2, width) {
|
|
15537
|
+
const pill = rowFrame(
|
|
15538
|
+
[
|
|
15539
|
+
text(` \u2387 BRANCH \xD7${branch2.budget} `, {
|
|
15540
|
+
width: 12 + String(branch2.budget).length,
|
|
15541
|
+
bg: "#93c5fd",
|
|
15542
|
+
fg: "black",
|
|
15543
|
+
bold: true
|
|
15544
|
+
}),
|
|
15545
|
+
text(" ", { width: 2 }),
|
|
15546
|
+
text("picked ", { width: 7, fg: "#93c5fd" }),
|
|
15547
|
+
text(`#${branch2.chosenIndex}`, {
|
|
15548
|
+
width: 1 + String(branch2.chosenIndex).length,
|
|
15549
|
+
fg: "#93c5fd",
|
|
15550
|
+
bold: true
|
|
15551
|
+
})
|
|
15552
|
+
],
|
|
15553
|
+
width
|
|
14830
15554
|
);
|
|
15555
|
+
const items = [];
|
|
15556
|
+
for (let i = 0; i < branch2.uncertainties.length; i++) {
|
|
15557
|
+
const u = branch2.uncertainties[i];
|
|
15558
|
+
const chosen = i === branch2.chosenIndex;
|
|
15559
|
+
const t2 = (branch2.temperatures[i] ?? 0).toFixed(1);
|
|
15560
|
+
items.push(
|
|
15561
|
+
pad(
|
|
15562
|
+
rowFrame(
|
|
15563
|
+
[
|
|
15564
|
+
text(chosen ? "\u25B8 " : " ", {
|
|
15565
|
+
width: 2,
|
|
15566
|
+
fg: chosen ? "#93c5fd" : "#475569",
|
|
15567
|
+
bold: chosen
|
|
15568
|
+
}),
|
|
15569
|
+
text(`#${i}`, {
|
|
15570
|
+
width: 1 + String(i).length,
|
|
15571
|
+
fg: chosen ? "#93c5fd" : "#94a3b8",
|
|
15572
|
+
bold: chosen
|
|
15573
|
+
}),
|
|
15574
|
+
text(` T=${t2} u=${u}`, {
|
|
15575
|
+
width: width - 2 - 1 - String(i).length,
|
|
15576
|
+
dim: true
|
|
15577
|
+
})
|
|
15578
|
+
],
|
|
15579
|
+
width - 2
|
|
15580
|
+
),
|
|
15581
|
+
0,
|
|
15582
|
+
0,
|
|
15583
|
+
0,
|
|
15584
|
+
2
|
|
15585
|
+
)
|
|
15586
|
+
);
|
|
15587
|
+
}
|
|
15588
|
+
const trail = text("", { width });
|
|
15589
|
+
return vstack(pill, ...items, trail);
|
|
14831
15590
|
}
|
|
14832
|
-
function
|
|
14833
|
-
const
|
|
14834
|
-
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
14840
|
-
|
|
14841
|
-
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
)
|
|
14858
|
-
})
|
|
15591
|
+
function planStateFrame(planState, width) {
|
|
15592
|
+
const fields = [];
|
|
15593
|
+
if (planState.subgoals.length)
|
|
15594
|
+
fields.push(["subgoals", planState.subgoals, COLOR.primary, false]);
|
|
15595
|
+
if (planState.hypotheses.length)
|
|
15596
|
+
fields.push(["hypotheses", planState.hypotheses, COLOR.assistant, false]);
|
|
15597
|
+
if (planState.uncertainties.length)
|
|
15598
|
+
fields.push(["uncertainties", planState.uncertainties, COLOR.warn, false]);
|
|
15599
|
+
if (planState.rejectedPaths.length)
|
|
15600
|
+
fields.push(["rejected", planState.rejectedPaths, COLOR.info, true]);
|
|
15601
|
+
if (fields.length === 0) return empty(width);
|
|
15602
|
+
const rows = fields.map(([label, items, color2, dim]) => {
|
|
15603
|
+
const header2 = `${label} (${items.length}) \xB7 `;
|
|
15604
|
+
const itemsStr = items.join(" \xB7 ");
|
|
15605
|
+
return rowFrame(
|
|
15606
|
+
[
|
|
15607
|
+
text(label, { width: label.length, fg: color2, bold: true, dim }),
|
|
15608
|
+
text(` (${items.length}) \xB7 `, { width: 7 + String(items.length).length, dim: true }),
|
|
15609
|
+
text(itemsStr, {
|
|
15610
|
+
width: Math.max(8, width - header2.length),
|
|
15611
|
+
fg: dim ? void 0 : COLOR.info,
|
|
15612
|
+
dim
|
|
15613
|
+
})
|
|
15614
|
+
],
|
|
15615
|
+
width
|
|
15616
|
+
);
|
|
15617
|
+
});
|
|
15618
|
+
const trail = text("", { width });
|
|
15619
|
+
return vstack(...rows, trail);
|
|
14859
15620
|
}
|
|
14860
|
-
function
|
|
14861
|
-
const
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14866
|
-
|
|
14867
|
-
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
15621
|
+
function ctxBreakdownFrame(data, width) {
|
|
15622
|
+
const total = data.systemTokens + data.toolsTokens + data.logTokens + data.inputTokens;
|
|
15623
|
+
const winPct = data.ctxMax > 0 ? Math.round(total / data.ctxMax * 100) : 0;
|
|
15624
|
+
const barWidth = 48;
|
|
15625
|
+
const cellOf = (n) => data.ctxMax > 0 ? Math.round(n / data.ctxMax * barWidth) : 0;
|
|
15626
|
+
const sysCells = cellOf(data.systemTokens);
|
|
15627
|
+
const toolsCells = cellOf(data.toolsTokens);
|
|
15628
|
+
const logCells = cellOf(data.logTokens);
|
|
15629
|
+
const inputCells = cellOf(data.inputTokens);
|
|
15630
|
+
const used = sysCells + toolsCells + logCells + inputCells;
|
|
15631
|
+
const freeCells = Math.max(0, barWidth - used);
|
|
15632
|
+
const sevColor = winPct >= 80 ? COLOR.err : winPct >= 60 ? COLOR.warn : COLOR.ok;
|
|
15633
|
+
const innerWidth = width - 2;
|
|
15634
|
+
const headerSegments = [
|
|
15635
|
+
text("\u25A3 context", { width: 9, fg: COLOR.brand, bold: true }),
|
|
15636
|
+
text(` ${formatTokensCompact2(total)} of ${formatTokensCompact2(data.ctxMax)}`, {
|
|
15637
|
+
width: 4 + formatTokensCompact2(total).length + formatTokensCompact2(data.ctxMax).length,
|
|
15638
|
+
dim: true
|
|
15639
|
+
}),
|
|
15640
|
+
text(" \xB7 ", { width: 5, dim: true }),
|
|
15641
|
+
text(`${winPct}%`, { width: 1 + String(winPct).length, fg: sevColor, bold: true })
|
|
15642
|
+
];
|
|
15643
|
+
if (winPct >= 80) {
|
|
15644
|
+
headerSegments.push(text(" \xB7 /compact", { width: 13, fg: COLOR.err, bold: true }));
|
|
14871
15645
|
}
|
|
14872
|
-
const
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
const
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
15646
|
+
const header2 = rowFrame(headerSegments, innerWidth);
|
|
15647
|
+
const bar = rowFrame(
|
|
15648
|
+
[
|
|
15649
|
+
text("\u2588".repeat(sysCells), { width: sysCells, fg: COLOR.brand }),
|
|
15650
|
+
text("\u2588".repeat(toolsCells), { width: toolsCells, fg: COLOR.accent }),
|
|
15651
|
+
text("\u2588".repeat(logCells), { width: logCells, fg: COLOR.primary }),
|
|
15652
|
+
text("\u2588".repeat(inputCells), { width: inputCells, fg: COLOR.tool }),
|
|
15653
|
+
text("\u2591".repeat(freeCells), { width: freeCells, fg: COLOR.info, dim: true })
|
|
15654
|
+
],
|
|
15655
|
+
innerWidth
|
|
15656
|
+
);
|
|
15657
|
+
const legend = rowFrame(
|
|
15658
|
+
[
|
|
15659
|
+
text("\u25A0", { width: 1, fg: COLOR.brand }),
|
|
15660
|
+
text(` system ${formatTokensCompact2(data.systemTokens)}`, {
|
|
15661
|
+
width: 8 + formatTokensCompact2(data.systemTokens).length,
|
|
15662
|
+
dim: true
|
|
15663
|
+
}),
|
|
15664
|
+
text(" ", { width: 3 }),
|
|
15665
|
+
text("\u25A0", { width: 1, fg: COLOR.accent }),
|
|
15666
|
+
text(` tools ${formatTokensCompact2(data.toolsTokens)}`, {
|
|
15667
|
+
width: 7 + formatTokensCompact2(data.toolsTokens).length,
|
|
15668
|
+
dim: true
|
|
15669
|
+
}),
|
|
15670
|
+
text(" ", { width: 3 }),
|
|
15671
|
+
text("\u25A0", { width: 1, fg: COLOR.primary }),
|
|
15672
|
+
text(` log ${formatTokensCompact2(data.logTokens)}`, {
|
|
15673
|
+
width: 5 + formatTokensCompact2(data.logTokens).length,
|
|
15674
|
+
dim: true
|
|
15675
|
+
}),
|
|
15676
|
+
text(" ", { width: 3 }),
|
|
15677
|
+
text("\u25A0", { width: 1, fg: COLOR.tool }),
|
|
15678
|
+
text(` input ${formatTokensCompact2(data.inputTokens)}`, {
|
|
15679
|
+
width: 7 + formatTokensCompact2(data.inputTokens).length,
|
|
15680
|
+
dim: true
|
|
15681
|
+
})
|
|
15682
|
+
],
|
|
15683
|
+
innerWidth
|
|
15684
|
+
);
|
|
15685
|
+
const inner = vstack(header2, bar, legend);
|
|
15686
|
+
const spacer = text("", { width });
|
|
15687
|
+
return vstack(spacer, borderLeft(pad(inner, 0, 0, 0, 1), COLOR.brand), spacer);
|
|
15688
|
+
}
|
|
15689
|
+
function complexAssistantFrame(event, width) {
|
|
15690
|
+
const spacer = text("", { width });
|
|
15691
|
+
const headerSegs = [text("\u25C6", { width: 1, fg: COLOR.assistant, bold: true })];
|
|
15692
|
+
if (event.stats) {
|
|
15693
|
+
const modelName = event.stats.model.replace(/^deepseek-/, "");
|
|
15694
|
+
headerSegs.push(
|
|
15695
|
+
text(" ", { width: 2 }),
|
|
15696
|
+
text(` ${modelName} `, {
|
|
15697
|
+
width: 2 + modelName.length,
|
|
15698
|
+
bg: COLOR.assistant,
|
|
15699
|
+
fg: "black",
|
|
15700
|
+
bold: true
|
|
15701
|
+
})
|
|
15702
|
+
);
|
|
15703
|
+
}
|
|
15704
|
+
const header2 = rowFrame(headerSegs, width);
|
|
15705
|
+
const bodyParts = [];
|
|
15706
|
+
const bodyWidth = width - 2;
|
|
15707
|
+
if (event.branch) {
|
|
15708
|
+
bodyParts.push(branchFrame(event.branch, bodyWidth));
|
|
15709
|
+
}
|
|
15710
|
+
if (event.reasoning) {
|
|
15711
|
+
bodyParts.push(reasoningFrame(event.reasoning, bodyWidth));
|
|
15712
|
+
}
|
|
15713
|
+
if (event.planState && !isPlanStateEmpty(event.planState)) {
|
|
15714
|
+
bodyParts.push(planStateFrame(event.planState, bodyWidth));
|
|
14892
15715
|
}
|
|
15716
|
+
bodyParts.push(
|
|
15717
|
+
event.text ? markdownToFrame(event.text, bodyWidth) : text("(empty body \u2014 likely tool-call only)", {
|
|
15718
|
+
width: bodyWidth,
|
|
15719
|
+
fg: COLOR.assistant,
|
|
15720
|
+
dim: true
|
|
15721
|
+
})
|
|
15722
|
+
);
|
|
14893
15723
|
if (event.stats) {
|
|
14894
15724
|
const hit = (event.stats.cacheHitRatio * 100).toFixed(1);
|
|
14895
15725
|
const hitColor = event.stats.cacheHitRatio >= 0.7 ? "#4ade80" : event.stats.cacheHitRatio >= 0.4 ? "#fcd34d" : "#f87171";
|
|
14896
|
-
|
|
14897
|
-
|
|
14898
|
-
id: `${event.id}/stats`,
|
|
14899
|
-
content: /* @__PURE__ */ React26.createElement(Box24, { paddingLeft: 2 }, /* @__PURE__ */ React26.createElement(Text22, { color: hitColor, bold: true }, `\u232C ${hit}%`), /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React26.createElement(Text22, { color: "#94a3b8" }, "in "), /* @__PURE__ */ React26.createElement(Text22, { color: "#67e8f9", bold: true }, event.stats.usage.promptTokens), /* @__PURE__ */ React26.createElement(Text22, { color: "#94a3b8" }, " \u2192 out "), /* @__PURE__ */ React26.createElement(Text22, { color: "#c4b5fd", bold: true }, event.stats.usage.completionTokens), /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React26.createElement(Text22, { color: "#86efac", bold: true }, `$${event.stats.cost.toFixed(6)}`))
|
|
14900
|
-
});
|
|
15726
|
+
const statsLine = `\u232C ${hit}% \xB7 in ${event.stats.usage.promptTokens} \u2192 out ${event.stats.usage.completionTokens} \xB7 $${event.stats.cost.toFixed(6)}`;
|
|
15727
|
+
bodyParts.push(text(statsLine, { width: bodyWidth, fg: hitColor }));
|
|
14901
15728
|
}
|
|
14902
|
-
|
|
15729
|
+
if (event.repair) {
|
|
15730
|
+
bodyParts.push(text(event.repair, { width: bodyWidth, fg: COLOR.accent }));
|
|
15731
|
+
}
|
|
15732
|
+
const inner = vstack(...bodyParts);
|
|
15733
|
+
const bordered = borderLeft(pad(inner, 0, 0, 0, 1), COLOR.assistant);
|
|
15734
|
+
return vstack(spacer, header2, spacer, bordered);
|
|
15735
|
+
}
|
|
15736
|
+
function planFrame(event, width) {
|
|
15737
|
+
const header2 = text("\u{1F4CB} plan proposed \u2014 pick a choice below", {
|
|
15738
|
+
width: 39,
|
|
15739
|
+
fg: "cyan",
|
|
15740
|
+
bold: true
|
|
15741
|
+
});
|
|
15742
|
+
const headerPadded = rowFrame([header2], width);
|
|
15743
|
+
const body = markdownToFrame(event.text, width - 2);
|
|
15744
|
+
const inner = vstack(headerPadded, text("", { width }), pad(body, 0, 0, 0, 1));
|
|
15745
|
+
const spacer = text("", { width });
|
|
15746
|
+
return vstack(spacer, inner, spacer);
|
|
14903
15747
|
}
|
|
14904
|
-
function
|
|
15748
|
+
function eventToAtom(event, projectRoot, width) {
|
|
14905
15749
|
if (event.role === "info") {
|
|
14906
|
-
|
|
14907
|
-
return accentRows(event.id, lead, color2, body, void 0, true, width);
|
|
15750
|
+
return { kind: "frame", id: event.id, frame: infoFrame(event, width) };
|
|
14908
15751
|
}
|
|
14909
15752
|
if (event.role === "warning") {
|
|
14910
|
-
return
|
|
15753
|
+
return { kind: "frame", id: event.id, frame: warningFrame(event, width) };
|
|
14911
15754
|
}
|
|
14912
15755
|
if (event.role === "error") {
|
|
14913
|
-
return
|
|
14914
|
-
}
|
|
14915
|
-
if (event.role === "assistant" && !event.streaming) {
|
|
14916
|
-
return assistantToRows(event, projectRoot, width);
|
|
15756
|
+
return { kind: "frame", id: event.id, frame: errorFrame(event, width) };
|
|
14917
15757
|
}
|
|
14918
15758
|
if (event.role === "step-progress") {
|
|
14919
|
-
|
|
14920
|
-
|
|
14921
|
-
|
|
14922
|
-
|
|
14923
|
-
|
|
14924
|
-
|
|
14925
|
-
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
|
|
14929
|
-
kind: "row",
|
|
14930
|
-
id: `${event.id}/head`,
|
|
14931
|
-
content: /* @__PURE__ */ React26.createElement(Box24, null, /* @__PURE__ */ React26.createElement(Text22, { backgroundColor: "#4ade80", color: "black", bold: true }, " \u2713 STEP "), counter ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement(Text22, null, " "), /* @__PURE__ */ React26.createElement(Text22, { color: "#4ade80", bold: true }, counter)) : null, /* @__PURE__ */ React26.createElement(Text22, null, " "), /* @__PURE__ */ React26.createElement(Text22, { color: "#86efac" }, label))
|
|
14932
|
-
});
|
|
14933
|
-
if (event.text) {
|
|
14934
|
-
for (const [i, line] of event.text.split("\n").entries()) {
|
|
14935
|
-
rows.push({
|
|
14936
|
-
kind: "row",
|
|
14937
|
-
id: `${event.id}/body/${i}`,
|
|
14938
|
-
content: /* @__PURE__ */ React26.createElement(Box24, { paddingLeft: 2 }, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, line))
|
|
14939
|
-
});
|
|
14940
|
-
}
|
|
15759
|
+
return { kind: "frame", id: event.id, frame: stepProgressFrame(event, width) };
|
|
15760
|
+
}
|
|
15761
|
+
if (event.role === "user") {
|
|
15762
|
+
return { kind: "frame", id: event.id, frame: userFrame(event, width) };
|
|
15763
|
+
}
|
|
15764
|
+
if (event.role === "tool") {
|
|
15765
|
+
const isExplicitError = event.text.startsWith("ERROR:");
|
|
15766
|
+
const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isExplicitError;
|
|
15767
|
+
if (isEditFile) {
|
|
15768
|
+
return { kind: "frame", id: event.id, frame: editFileDiffFrame(event, width) };
|
|
14941
15769
|
}
|
|
14942
|
-
|
|
14943
|
-
|
|
14944
|
-
|
|
14945
|
-
|
|
14946
|
-
|
|
14947
|
-
}
|
|
15770
|
+
return { kind: "frame", id: event.id, frame: toolCompactFrame(event, width) };
|
|
15771
|
+
}
|
|
15772
|
+
if (event.role === "assistant" && !event.streaming) {
|
|
15773
|
+
const hasComplexSub = event.branch || event.reasoning || event.planState && !isPlanStateEmpty(event.planState);
|
|
15774
|
+
if (hasComplexSub) {
|
|
15775
|
+
return { kind: "frame", id: event.id, frame: complexAssistantFrame(event, width) };
|
|
14948
15776
|
}
|
|
14949
|
-
return
|
|
15777
|
+
return { kind: "frame", id: event.id, frame: simpleAssistantFrame(event, width) };
|
|
14950
15778
|
}
|
|
14951
|
-
|
|
14952
|
-
{
|
|
14953
|
-
|
|
15779
|
+
if (event.role === "plan") {
|
|
15780
|
+
return { kind: "frame", id: event.id, frame: planFrame(event, width) };
|
|
15781
|
+
}
|
|
15782
|
+
if (event.role === "ctx-breakdown" && event.ctxBreakdown) {
|
|
15783
|
+
return {
|
|
15784
|
+
kind: "frame",
|
|
14954
15785
|
id: event.id,
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
15786
|
+
frame: ctxBreakdownFrame(event.ctxBreakdown, width)
|
|
15787
|
+
};
|
|
15788
|
+
}
|
|
15789
|
+
return {
|
|
15790
|
+
kind: "ink",
|
|
15791
|
+
id: event.id,
|
|
15792
|
+
rows: estimatedHeight(event),
|
|
15793
|
+
element: /* @__PURE__ */ React26.createElement(EventRow, { event, projectRoot })
|
|
15794
|
+
};
|
|
14959
15795
|
}
|
|
14960
15796
|
function estimatedHeight(e) {
|
|
14961
|
-
const
|
|
14962
|
-
const wrapLines = Math.max(0, Math.floor(
|
|
15797
|
+
const t2 = e.text ?? "";
|
|
15798
|
+
const wrapLines = Math.max(0, Math.floor(t2.length / 80));
|
|
14963
15799
|
if (e.role === "user") return 3 + wrapLines;
|
|
14964
15800
|
if (e.role === "assistant") {
|
|
14965
15801
|
let h = 4 + wrapLines;
|
|
@@ -14970,7 +15806,7 @@ function estimatedHeight(e) {
|
|
|
14970
15806
|
if (e.role === "tool") {
|
|
14971
15807
|
const isEditFile = e.toolName === "edit_file" || e.toolName?.endsWith("_edit_file");
|
|
14972
15808
|
if (isEditFile) {
|
|
14973
|
-
const diffLines = (
|
|
15809
|
+
const diffLines = (t2.match(/\n/g)?.length ?? 0) + 1;
|
|
14974
15810
|
return 6 + Math.min(20, diffLines);
|
|
14975
15811
|
}
|
|
14976
15812
|
return 2;
|
|
@@ -14979,69 +15815,91 @@ function estimatedHeight(e) {
|
|
|
14979
15815
|
if (e.role === "ctx-breakdown") return 7;
|
|
14980
15816
|
return 2;
|
|
14981
15817
|
}
|
|
14982
|
-
function
|
|
14983
|
-
if (
|
|
14984
|
-
return {
|
|
15818
|
+
function viewportLog(atoms, scrollOffset, available) {
|
|
15819
|
+
if (atoms.length === 0 || available <= 0) {
|
|
15820
|
+
return { atoms: [], topSkip: 0, bottomSkip: 0, totalRows: 0, maxScrollRows: 0 };
|
|
14985
15821
|
}
|
|
14986
|
-
const heights =
|
|
15822
|
+
const heights = atoms.map(atomRows);
|
|
14987
15823
|
const totalRows = heights.reduce((a, b) => a + b, 0);
|
|
14988
15824
|
const maxScrollRows = Math.max(0, totalRows - available);
|
|
14989
|
-
const offset = Math.max(0, Math.min(
|
|
15825
|
+
const offset = Math.max(0, Math.min(scrollOffset, maxScrollRows));
|
|
14990
15826
|
const viewportBottom = totalRows - offset;
|
|
14991
15827
|
const viewportTop = Math.max(0, viewportBottom - available);
|
|
14992
15828
|
let cursor = 0;
|
|
14993
15829
|
let firstIdx = -1;
|
|
15830
|
+
let firstStart = 0;
|
|
14994
15831
|
let lastIdx = -1;
|
|
14995
|
-
|
|
14996
|
-
|
|
14997
|
-
const
|
|
14998
|
-
|
|
14999
|
-
|
|
15000
|
-
if (
|
|
15001
|
-
if (
|
|
15832
|
+
let lastEnd = 0;
|
|
15833
|
+
for (let i = 0; i < atoms.length; i++) {
|
|
15834
|
+
const start = cursor;
|
|
15835
|
+
const end = cursor + heights[i];
|
|
15836
|
+
cursor = end;
|
|
15837
|
+
if (end <= viewportTop) continue;
|
|
15838
|
+
if (start >= viewportBottom) break;
|
|
15839
|
+
if (firstIdx === -1) {
|
|
15840
|
+
firstIdx = i;
|
|
15841
|
+
firstStart = start;
|
|
15842
|
+
}
|
|
15002
15843
|
lastIdx = i;
|
|
15844
|
+
lastEnd = end;
|
|
15003
15845
|
}
|
|
15004
15846
|
if (firstIdx === -1) {
|
|
15005
|
-
return {
|
|
15847
|
+
return {
|
|
15848
|
+
atoms: [atoms[atoms.length - 1]],
|
|
15849
|
+
topSkip: 0,
|
|
15850
|
+
bottomSkip: 0,
|
|
15851
|
+
totalRows,
|
|
15852
|
+
maxScrollRows
|
|
15853
|
+
};
|
|
15006
15854
|
}
|
|
15007
|
-
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
if (item.kind === "row") {
|
|
15015
|
-
return /* @__PURE__ */ React26.createElement(Box24, { key: item.id, height: 1, flexShrink: 0 }, item.content);
|
|
15855
|
+
const sliced = atoms.slice(firstIdx, lastIdx + 1);
|
|
15856
|
+
const firstAtom = sliced[0];
|
|
15857
|
+
const lastAtom = sliced[sliced.length - 1];
|
|
15858
|
+
let topSkip = 0;
|
|
15859
|
+
let bottomSkip = 0;
|
|
15860
|
+
if (firstAtom.kind === "frame") {
|
|
15861
|
+
topSkip = Math.max(0, viewportTop - firstStart);
|
|
15016
15862
|
}
|
|
15017
|
-
|
|
15863
|
+
if (lastAtom.kind === "frame") {
|
|
15864
|
+
bottomSkip = Math.max(0, lastEnd - viewportBottom);
|
|
15865
|
+
}
|
|
15866
|
+
return { atoms: sliced, topSkip, bottomSkip, totalRows, maxScrollRows };
|
|
15867
|
+
}
|
|
15868
|
+
function renderViewport(v) {
|
|
15869
|
+
return /* @__PURE__ */ React26.createElement(React26.Fragment, null, v.atoms.map((atom, i) => {
|
|
15870
|
+
if (atom.kind === "ink") {
|
|
15871
|
+
return /* @__PURE__ */ React26.createElement(React26.Fragment, { key: atom.id }, atom.element);
|
|
15872
|
+
}
|
|
15873
|
+
const start = i === 0 ? v.topSkip : 0;
|
|
15874
|
+
const end = i === v.atoms.length - 1 ? atom.frame.rows.length - v.bottomSkip : atom.frame.rows.length;
|
|
15875
|
+
const rows = atom.frame.rows.slice(start, end);
|
|
15876
|
+
return /* @__PURE__ */ React26.createElement(React26.Fragment, { key: atom.id }, rows.map((row2, ri) => /* @__PURE__ */ React26.createElement(Box24, { key: `${atom.id}/${start + ri}`, height: 1, flexShrink: 0 }, /* @__PURE__ */ React26.createElement(Text22, null, frameToAnsi({ width: atom.frame.width, rows: [row2] })))));
|
|
15877
|
+
}));
|
|
15018
15878
|
}
|
|
15019
|
-
function
|
|
15020
|
-
|
|
15879
|
+
function eventsToAtoms(events, projectRoot, width) {
|
|
15880
|
+
const out = [];
|
|
15881
|
+
for (const e of events) out.push(eventToAtom(e, projectRoot, width));
|
|
15882
|
+
return out;
|
|
15883
|
+
}
|
|
15884
|
+
|
|
15885
|
+
// src/cli/ui/log-rows.tsx
|
|
15886
|
+
import { Box as Box25, Text as Text23 } from "ink";
|
|
15887
|
+
import React27 from "react";
|
|
15888
|
+
function BottomHint({
|
|
15889
|
+
rowsBelow,
|
|
15021
15890
|
totalRows,
|
|
15022
|
-
viewportRows
|
|
15023
|
-
scrollOffsetRows
|
|
15891
|
+
viewportRows
|
|
15024
15892
|
}) {
|
|
15025
|
-
if (totalRows <= viewportRows || height <= 0) return null;
|
|
15026
|
-
const maxScroll = Math.max(0, totalRows - viewportRows);
|
|
15027
|
-
const offset = Math.max(0, Math.min(scrollOffsetRows, maxScroll));
|
|
15028
|
-
const viewportBottomFrac = (totalRows - offset) / totalRows;
|
|
15029
|
-
const viewportTopFrac = Math.max(0, viewportBottomFrac - viewportRows / totalRows);
|
|
15030
|
-
const thumbStart = Math.floor(viewportTopFrac * height);
|
|
15031
|
-
const thumbEnd = Math.min(height, Math.ceil(viewportBottomFrac * height));
|
|
15032
|
-
const thumbSize = Math.max(1, thumbEnd - thumbStart);
|
|
15033
|
-
const cells = [];
|
|
15034
|
-
for (let i = 0; i < height; i++) {
|
|
15035
|
-
const inThumb = i >= thumbStart && i < thumbStart + thumbSize;
|
|
15036
|
-
cells.push(
|
|
15037
|
-
/* @__PURE__ */ React26.createElement(Text22, { key: `sb-${i}`, color: inThumb ? COLOR.brand : COLOR.info, dimColor: !inThumb }, inThumb ? "\u2588" : "\u2502")
|
|
15038
|
-
);
|
|
15039
|
-
}
|
|
15040
|
-
return /* @__PURE__ */ React26.createElement(Box24, { flexDirection: "column", width: 1, flexShrink: 0 }, cells);
|
|
15041
|
-
}
|
|
15042
|
-
function BottomHint({ rowsBelow }) {
|
|
15043
15893
|
if (rowsBelow <= 0) return null;
|
|
15044
|
-
|
|
15894
|
+
const maxScroll = Math.max(1, totalRows - viewportRows);
|
|
15895
|
+
const ratioFromTop = Math.max(0, Math.min(1, (totalRows - rowsBelow - viewportRows) / maxScroll));
|
|
15896
|
+
const pct2 = Math.round((1 - ratioFromTop) * 100);
|
|
15897
|
+
const rowsAbove = Math.max(0, totalRows - viewportRows - rowsBelow);
|
|
15898
|
+
const barCells = 16;
|
|
15899
|
+
const markerAt = Math.max(0, Math.min(barCells - 1, Math.round(ratioFromTop * (barCells - 1))));
|
|
15900
|
+
const left = "\u2500".repeat(markerAt);
|
|
15901
|
+
const right = "\u2500".repeat(barCells - 1 - markerAt);
|
|
15902
|
+
return /* @__PURE__ */ React27.createElement(Box25, { height: 1, flexShrink: 0 }, /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.primary, bold: true }, `\u2191 ${rowsAbove}`), /* @__PURE__ */ React27.createElement(Text23, null, " "), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "\u2595"), /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.info, dimColor: true }, left), /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.brand, bold: true }, "\u25CF"), /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.info, dimColor: true }, right), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "\u258F"), /* @__PURE__ */ React27.createElement(Text23, null, " "), /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.primary, bold: true }, `${pct2}%`), /* @__PURE__ */ React27.createElement(Text23, null, " "), /* @__PURE__ */ React27.createElement(Text23, { color: COLOR.primary }, `\u2193 ${rowsBelow}`), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \xB7 End to jump \xB7 wheel to scroll"));
|
|
15045
15903
|
}
|
|
15046
15904
|
|
|
15047
15905
|
// src/cli/ui/loop.ts
|
|
@@ -15219,8 +16077,8 @@ ${formatOneResourceContent(block.resource)}`;
|
|
|
15219
16077
|
}
|
|
15220
16078
|
async function handleMcpBrowseSlash(kind, arg, servers, setHistorical) {
|
|
15221
16079
|
const ts = Date.now();
|
|
15222
|
-
const push = (role,
|
|
15223
|
-
setHistorical((prev) => [...prev, { id: `mcp-${role}-${ts}-${prev.length}`, role, text }]);
|
|
16080
|
+
const push = (role, text2) => {
|
|
16081
|
+
setHistorical((prev) => [...prev, { id: `mcp-${role}-${ts}-${prev.length}`, role, text: text2 }]);
|
|
15224
16082
|
};
|
|
15225
16083
|
if (!arg) {
|
|
15226
16084
|
push("info", kind === "resource" ? formatResourceList(servers) : formatPromptList(servers));
|
|
@@ -15624,9 +16482,9 @@ function detectSlashArgContext(input, codeMode = false) {
|
|
|
15624
16482
|
kind: spec.argCompleter ? "picker" : "hint"
|
|
15625
16483
|
};
|
|
15626
16484
|
}
|
|
15627
|
-
function parseSlash(
|
|
15628
|
-
if (!
|
|
15629
|
-
const parts =
|
|
16485
|
+
function parseSlash(text2) {
|
|
16486
|
+
if (!text2.startsWith("/")) return null;
|
|
16487
|
+
const parts = text2.slice(1).trim().split(/\s+/);
|
|
15630
16488
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
15631
16489
|
if (!cmd) return null;
|
|
15632
16490
|
return { cmd, args: parts.slice(1) };
|
|
@@ -15725,7 +16583,7 @@ function renderSubagentSection(sub) {
|
|
|
15725
16583
|
for (const s of top) {
|
|
15726
16584
|
const sec = (s.durationMs / 1e3).toFixed(1);
|
|
15727
16585
|
lines.push(
|
|
15728
|
-
` ${
|
|
16586
|
+
` ${pad2(s.skillName, 18)} ${pad2(`${s.count}`, 4, "right")} $${s.costUsd.toFixed(6)} ${sec}s`
|
|
15729
16587
|
);
|
|
15730
16588
|
}
|
|
15731
16589
|
if (sub.bySkill.length > top.length) {
|
|
@@ -15735,13 +16593,13 @@ function renderSubagentSection(sub) {
|
|
|
15735
16593
|
}
|
|
15736
16594
|
function header() {
|
|
15737
16595
|
return [
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
16596
|
+
pad2("", 10),
|
|
16597
|
+
pad2("turns", 8, "right"),
|
|
16598
|
+
pad2("cache hit", 10, "right"),
|
|
16599
|
+
pad2("cost (USD)", 14, "right"),
|
|
16600
|
+
pad2("cache saved", 14, "right"),
|
|
16601
|
+
pad2("vs Claude", 14, "right"),
|
|
16602
|
+
pad2("saved", 10, "right")
|
|
15745
16603
|
].join(" ");
|
|
15746
16604
|
}
|
|
15747
16605
|
function divider() {
|
|
@@ -15751,20 +16609,20 @@ function bucketRow(b) {
|
|
|
15751
16609
|
const hit = bucketCacheHitRatio(b);
|
|
15752
16610
|
const savings = bucketSavingsFraction(b);
|
|
15753
16611
|
return [
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
16612
|
+
pad2(b.label, 10),
|
|
16613
|
+
pad2(b.turns.toString(), 8, "right"),
|
|
16614
|
+
pad2(b.turns > 0 ? `${(hit * 100).toFixed(1)}%` : "\u2014", 10, "right"),
|
|
16615
|
+
pad2(b.turns > 0 ? `$${b.costUsd.toFixed(6)}` : "\u2014", 14, "right"),
|
|
16616
|
+
pad2(
|
|
15759
16617
|
b.turns > 0 && b.cacheSavingsUsd > 0 ? `$${b.cacheSavingsUsd.toFixed(4)}` : "\u2014",
|
|
15760
16618
|
14,
|
|
15761
16619
|
"right"
|
|
15762
16620
|
),
|
|
15763
|
-
|
|
15764
|
-
|
|
16621
|
+
pad2(b.turns > 0 ? `$${b.claudeEquivUsd.toFixed(4)}` : "\u2014", 14, "right"),
|
|
16622
|
+
pad2(b.turns > 0 && savings > 0 ? `${(savings * 100).toFixed(1)}%` : "\u2014", 10, "right")
|
|
15765
16623
|
].join(" ");
|
|
15766
16624
|
}
|
|
15767
|
-
function
|
|
16625
|
+
function pad2(s, width, align = "left") {
|
|
15768
16626
|
if (s.length >= width) return s;
|
|
15769
16627
|
const fill = " ".repeat(width - s.length);
|
|
15770
16628
|
return align === "right" ? `${fill}${s}` : `${s}${fill}`;
|
|
@@ -18557,13 +19415,13 @@ var PLAIN_UI = process.env.REASONIX_UI === "plain";
|
|
|
18557
19415
|
function LoopStatusRow({
|
|
18558
19416
|
loop: loop2
|
|
18559
19417
|
}) {
|
|
18560
|
-
const [, setTick] =
|
|
18561
|
-
|
|
19418
|
+
const [, setTick] = React28.useState(0);
|
|
19419
|
+
React28.useEffect(() => {
|
|
18562
19420
|
const id = setInterval(() => setTick((t2) => t2 + 1), 1e3);
|
|
18563
19421
|
return () => clearInterval(id);
|
|
18564
19422
|
}, []);
|
|
18565
19423
|
const nextFireMs = Math.max(0, loop2.nextFireAt - Date.now());
|
|
18566
|
-
return /* @__PURE__ */
|
|
19424
|
+
return /* @__PURE__ */ React28.createElement(Box26, null, /* @__PURE__ */ React28.createElement(Text24, { color: "cyan" }, `\u25B8 ${formatLoopStatus(loop2.prompt, nextFireMs, loop2.iter)} \xB7 /loop stop or type to cancel`));
|
|
18567
19425
|
}
|
|
18568
19426
|
function App({
|
|
18569
19427
|
model: model2,
|
|
@@ -18629,10 +19487,8 @@ function App({
|
|
|
18629
19487
|
if (curLen > prevLen && scrollTargetRef.current > 0) {
|
|
18630
19488
|
const cols = stdout4?.columns ?? 80;
|
|
18631
19489
|
let deltaRows = 0;
|
|
18632
|
-
for (
|
|
18633
|
-
|
|
18634
|
-
deltaRows += it.kind === "row" ? 1 : it.rows;
|
|
18635
|
-
}
|
|
19490
|
+
for (const a of eventsToAtoms(historical.slice(prevLen, curLen), void 0, cols)) {
|
|
19491
|
+
deltaRows += a.kind === "frame" ? a.frame.rows.length : a.rows;
|
|
18636
19492
|
}
|
|
18637
19493
|
if (deltaRows > 0) {
|
|
18638
19494
|
scrollTargetRef.current += deltaRows;
|
|
@@ -18721,6 +19577,10 @@ function App({
|
|
|
18721
19577
|
setPendingTick((t2) => t2 + 1);
|
|
18722
19578
|
}, []);
|
|
18723
19579
|
const [editMode, setEditMode] = useState10(() => codeMode ? loadEditMode() : "review");
|
|
19580
|
+
const [preset2, setPreset] = useState10(() => {
|
|
19581
|
+
if (model2 === "deepseek-v4-pro") return "pro";
|
|
19582
|
+
return "auto";
|
|
19583
|
+
});
|
|
18724
19584
|
const editModeRef = useRef6(editMode);
|
|
18725
19585
|
useEffect7(() => {
|
|
18726
19586
|
editModeRef.current = editMode;
|
|
@@ -19558,6 +20418,8 @@ function App({
|
|
|
19558
20418
|
autoEscalate: settings.autoEscalate,
|
|
19559
20419
|
reasoningEffort: settings.reasoningEffort
|
|
19560
20420
|
});
|
|
20421
|
+
const canonical = settings.model === "deepseek-v4-pro" ? "pro" : settings.autoEscalate ? "auto" : "flash";
|
|
20422
|
+
setPreset(canonical);
|
|
19561
20423
|
},
|
|
19562
20424
|
applyEffortLive: (effort2) => {
|
|
19563
20425
|
loop2.configure({ reasoningEffort: effort2 });
|
|
@@ -19589,13 +20451,13 @@ function App({
|
|
|
19589
20451
|
eventSubscribersRef.current.delete(handler);
|
|
19590
20452
|
};
|
|
19591
20453
|
},
|
|
19592
|
-
submitPrompt: (
|
|
20454
|
+
submitPrompt: (text2) => {
|
|
19593
20455
|
if (busyRef.current) {
|
|
19594
20456
|
return { accepted: false, reason: "loop is busy with a turn" };
|
|
19595
20457
|
}
|
|
19596
20458
|
const fn = handleSubmitRef.current;
|
|
19597
20459
|
if (!fn) return { accepted: false, reason: "TUI not ready" };
|
|
19598
|
-
fn(
|
|
20460
|
+
fn(text2).catch(() => void 0);
|
|
19599
20461
|
return { accepted: true };
|
|
19600
20462
|
},
|
|
19601
20463
|
abortTurn: () => {
|
|
@@ -19696,13 +20558,13 @@ function App({
|
|
|
19696
20558
|
const fn = handleChoiceConfirmRef.current;
|
|
19697
20559
|
if (fn) fn(choice).catch(() => void 0);
|
|
19698
20560
|
},
|
|
19699
|
-
resolvePlanConfirm: (choice,
|
|
20561
|
+
resolvePlanConfirm: (choice, text2) => {
|
|
19700
20562
|
if (choice === "cancel") {
|
|
19701
20563
|
handlePlanConfirmRef.current("cancel").catch(() => void 0);
|
|
19702
20564
|
return;
|
|
19703
20565
|
}
|
|
19704
20566
|
const plan2 = pendingPlanRef.current ?? "";
|
|
19705
|
-
handleStagedInputSubmitRef.current(
|
|
20567
|
+
handleStagedInputSubmitRef.current(text2 ?? "", { plan: plan2, mode: choice }).catch(() => void 0);
|
|
19706
20568
|
},
|
|
19707
20569
|
resolveEditReview: (choice) => {
|
|
19708
20570
|
const resolve15 = editReviewResolveRef.current;
|
|
@@ -19715,12 +20577,12 @@ function App({
|
|
|
19715
20577
|
resolveWorkspaceConfirm: (choice) => {
|
|
19716
20578
|
handleWorkspaceConfirmRef.current(choice).catch(() => void 0);
|
|
19717
20579
|
},
|
|
19718
|
-
resolveCheckpointConfirm: (choice,
|
|
19719
|
-
if (choice === "revise" && typeof
|
|
20580
|
+
resolveCheckpointConfirm: (choice, text2) => {
|
|
20581
|
+
if (choice === "revise" && typeof text2 === "string") {
|
|
19720
20582
|
const snap = pendingCheckpoint;
|
|
19721
20583
|
setPendingCheckpoint(null);
|
|
19722
20584
|
if (!snap) return;
|
|
19723
|
-
handleCheckpointReviseSubmitRef.current(
|
|
20585
|
+
handleCheckpointReviseSubmitRef.current(text2, snap).catch(() => void 0);
|
|
19724
20586
|
return;
|
|
19725
20587
|
}
|
|
19726
20588
|
handleCheckpointConfirmRef.current(choice).catch(() => void 0);
|
|
@@ -19849,8 +20711,8 @@ function App({
|
|
|
19849
20711
|
}, []);
|
|
19850
20712
|
const handleSubmit2 = useCallback4(
|
|
19851
20713
|
async (raw) => {
|
|
19852
|
-
let
|
|
19853
|
-
if (!
|
|
20714
|
+
let text2 = raw.trim();
|
|
20715
|
+
if (!text2) return;
|
|
19854
20716
|
if (activeLoopRef.current && !loopFiringRef.current) {
|
|
19855
20717
|
stopLoop();
|
|
19856
20718
|
}
|
|
@@ -19870,28 +20732,28 @@ function App({
|
|
|
19870
20732
|
return;
|
|
19871
20733
|
}
|
|
19872
20734
|
}
|
|
19873
|
-
if (
|
|
19874
|
-
const typed =
|
|
20735
|
+
if (text2.startsWith("/") && !text2.includes(" ")) {
|
|
20736
|
+
const typed = text2.slice(1).toLowerCase();
|
|
19875
20737
|
const matches = suggestSlashCommands(typed, !!codeMode);
|
|
19876
20738
|
const exact = matches.find((m) => m.cmd === typed);
|
|
19877
20739
|
if (!exact && matches.length > 0) {
|
|
19878
20740
|
const chosen = matches[slashSelected] ?? matches[0];
|
|
19879
|
-
if (chosen)
|
|
20741
|
+
if (chosen) text2 = `/${chosen.cmd}`;
|
|
19880
20742
|
}
|
|
19881
20743
|
}
|
|
19882
20744
|
setInput("");
|
|
19883
20745
|
historyCursor.current = -1;
|
|
19884
|
-
if (codeMode && pendingEdits.current.length > 0 && (
|
|
19885
|
-
const out =
|
|
20746
|
+
if (codeMode && pendingEdits.current.length > 0 && (text2 === "y" || text2 === "n")) {
|
|
20747
|
+
const out = text2 === "y" ? codeApply() : codeDiscard();
|
|
19886
20748
|
setHistorical((prev) => [...prev, { id: `sys-${Date.now()}`, role: "info", text: out }]);
|
|
19887
|
-
promptHistory.current.push(
|
|
20749
|
+
promptHistory.current.push(text2);
|
|
19888
20750
|
return;
|
|
19889
20751
|
}
|
|
19890
|
-
const hashParse = detectHashMemory(
|
|
20752
|
+
const hashParse = detectHashMemory(text2);
|
|
19891
20753
|
if (hashParse?.kind === "memory" || hashParse?.kind === "memory-global") {
|
|
19892
20754
|
const isGlobal = hashParse.kind === "memory-global";
|
|
19893
20755
|
const memRoot = currentRootDir;
|
|
19894
|
-
promptHistory.current.push(
|
|
20756
|
+
promptHistory.current.push(text2);
|
|
19895
20757
|
try {
|
|
19896
20758
|
const result = isGlobal ? appendGlobalMemory(hashParse.note) : appendProjectMemory(memRoot, hashParse.note);
|
|
19897
20759
|
const verb = result.created ? "created" : "appended to";
|
|
@@ -19917,18 +20779,18 @@ function App({
|
|
|
19917
20779
|
return;
|
|
19918
20780
|
}
|
|
19919
20781
|
if (hashParse?.kind === "escape") {
|
|
19920
|
-
|
|
20782
|
+
text2 = hashParse.text;
|
|
19921
20783
|
}
|
|
19922
|
-
const bangCmd = detectBangCommand(
|
|
20784
|
+
const bangCmd = detectBangCommand(text2);
|
|
19923
20785
|
if (bangCmd !== null) {
|
|
19924
20786
|
const bangRoot = currentRootDir;
|
|
19925
|
-
promptHistory.current.push(
|
|
20787
|
+
promptHistory.current.push(text2);
|
|
19926
20788
|
setHistorical((prev) => [
|
|
19927
20789
|
...prev,
|
|
19928
20790
|
{
|
|
19929
20791
|
id: `bang-u-${Date.now()}`,
|
|
19930
20792
|
role: "user",
|
|
19931
|
-
text,
|
|
20793
|
+
text: text2,
|
|
19932
20794
|
leadSeparator: prev.length > 0
|
|
19933
20795
|
}
|
|
19934
20796
|
]);
|
|
@@ -19962,19 +20824,19 @@ function App({
|
|
|
19962
20824
|
}
|
|
19963
20825
|
return;
|
|
19964
20826
|
}
|
|
19965
|
-
const mcpBrowseMatch = /^\/(resource|prompt)(?:\s+([\s\S]*))?$/.exec(
|
|
20827
|
+
const mcpBrowseMatch = /^\/(resource|prompt)(?:\s+([\s\S]*))?$/.exec(text2);
|
|
19966
20828
|
if (mcpBrowseMatch) {
|
|
19967
20829
|
const kind = mcpBrowseMatch[1];
|
|
19968
20830
|
const arg = mcpBrowseMatch[2]?.trim() ?? "";
|
|
19969
|
-
promptHistory.current.push(
|
|
20831
|
+
promptHistory.current.push(text2);
|
|
19970
20832
|
setHistorical((prev) => [
|
|
19971
20833
|
...prev,
|
|
19972
|
-
{ id: `mcp-u-${Date.now()}`, role: "user", text, leadSeparator: prev.length > 0 }
|
|
20834
|
+
{ id: `mcp-u-${Date.now()}`, role: "user", text: text2, leadSeparator: prev.length > 0 }
|
|
19973
20835
|
]);
|
|
19974
20836
|
await handleMcpBrowseSlash(kind, arg, mcpServers ?? [], setHistorical);
|
|
19975
20837
|
return;
|
|
19976
20838
|
}
|
|
19977
|
-
const slash = parseSlash(
|
|
20839
|
+
const slash = parseSlash(text2);
|
|
19978
20840
|
if (slash) {
|
|
19979
20841
|
const result = handleSlash(slash.cmd, slash.args, loop2, {
|
|
19980
20842
|
mcpSpecs,
|
|
@@ -20014,9 +20876,9 @@ function App({
|
|
|
20014
20876
|
stopDashboard,
|
|
20015
20877
|
getDashboardUrl,
|
|
20016
20878
|
jobs: codeMode?.jobs,
|
|
20017
|
-
postInfo: (
|
|
20879
|
+
postInfo: (text3) => setHistorical((prev) => [
|
|
20018
20880
|
...prev,
|
|
20019
|
-
{ id: `sys-late-${Date.now()}-${Math.random()}`, role: "info", text:
|
|
20881
|
+
{ id: `sys-late-${Date.now()}-${Math.random()}`, role: "info", text: text3 }
|
|
20020
20882
|
]),
|
|
20021
20883
|
reloadHooks: () => {
|
|
20022
20884
|
const fresh = loadHooks({ projectRoot: codeMode ? currentRootDir : void 0 });
|
|
@@ -20106,16 +20968,16 @@ function App({
|
|
|
20106
20968
|
]);
|
|
20107
20969
|
}
|
|
20108
20970
|
if (result.resubmit) {
|
|
20109
|
-
|
|
20971
|
+
text2 = result.resubmit;
|
|
20110
20972
|
} else {
|
|
20111
|
-
promptHistory.current.push(
|
|
20973
|
+
promptHistory.current.push(text2);
|
|
20112
20974
|
return;
|
|
20113
20975
|
}
|
|
20114
20976
|
}
|
|
20115
20977
|
if (hookList.some((h) => h.event === "UserPromptSubmit")) {
|
|
20116
20978
|
const promptReport = await runHooks({
|
|
20117
20979
|
hooks: hookList,
|
|
20118
|
-
payload: { event: "UserPromptSubmit", cwd: currentRootDir, prompt:
|
|
20980
|
+
payload: { event: "UserPromptSubmit", cwd: currentRootDir, prompt: text2 }
|
|
20119
20981
|
});
|
|
20120
20982
|
if (promptReport.outcomes.length > 0) {
|
|
20121
20983
|
setHistorical((prev) => [
|
|
@@ -20129,8 +20991,8 @@ function App({
|
|
|
20129
20991
|
}
|
|
20130
20992
|
if (promptReport.blocked) return;
|
|
20131
20993
|
}
|
|
20132
|
-
promptHistory.current.push(
|
|
20133
|
-
const pasteDisplay = formatLongPaste(
|
|
20994
|
+
promptHistory.current.push(text2);
|
|
20995
|
+
const pasteDisplay = formatLongPaste(text2);
|
|
20134
20996
|
setHistorical((prev) => [
|
|
20135
20997
|
...prev,
|
|
20136
20998
|
// `leadSeparator`: thin rule above this user turn when history
|
|
@@ -20145,7 +21007,7 @@ function App({
|
|
|
20145
21007
|
}
|
|
20146
21008
|
]);
|
|
20147
21009
|
const userId = `u-${Date.now()}`;
|
|
20148
|
-
broadcastDashboardEvent({ kind: "user", id: userId, text });
|
|
21010
|
+
broadcastDashboardEvent({ kind: "user", id: userId, text: text2 });
|
|
20149
21011
|
const assistantId = `a-${Date.now()}`;
|
|
20150
21012
|
const streamRef = { id: assistantId, text: "", reasoning: "" };
|
|
20151
21013
|
const contentBuf = { current: "" };
|
|
@@ -20184,9 +21046,9 @@ function App({
|
|
|
20184
21046
|
});
|
|
20185
21047
|
};
|
|
20186
21048
|
const timer = PLAIN_UI ? null : setInterval(flush, FLUSH_INTERVAL_MS);
|
|
20187
|
-
let modelInput =
|
|
21049
|
+
let modelInput = text2;
|
|
20188
21050
|
if (codeMode) {
|
|
20189
|
-
const expanded = expandAtMentions(
|
|
21051
|
+
const expanded = expandAtMentions(text2, currentRootDir);
|
|
20190
21052
|
if (expanded.expansions.length > 0) {
|
|
20191
21053
|
modelInput = expanded.text;
|
|
20192
21054
|
const inlined = expanded.expansions.filter((ex) => ex.ok).map((ex) => `${ex.path} (${(ex.bytes ?? 0).toLocaleString()} bytes)`);
|
|
@@ -20202,7 +21064,7 @@ function App({
|
|
|
20202
21064
|
}
|
|
20203
21065
|
}
|
|
20204
21066
|
}
|
|
20205
|
-
if (/(?:^|\s)@https?:\/\//.test(
|
|
21067
|
+
if (/(?:^|\s)@https?:\/\//.test(text2)) {
|
|
20206
21068
|
try {
|
|
20207
21069
|
const urlExpanded = await expandAtUrls(modelInput, {
|
|
20208
21070
|
fetcher: webFetch,
|
|
@@ -20797,9 +21659,9 @@ ${body}`;
|
|
|
20797
21659
|
);
|
|
20798
21660
|
useEffect7(() => {
|
|
20799
21661
|
if (!busy && queuedSubmit !== null) {
|
|
20800
|
-
const
|
|
21662
|
+
const text2 = queuedSubmit;
|
|
20801
21663
|
setQueuedSubmit(null);
|
|
20802
|
-
void handleSubmit2(
|
|
21664
|
+
void handleSubmit2(text2);
|
|
20803
21665
|
}
|
|
20804
21666
|
}, [busy, queuedSubmit, handleSubmit2]);
|
|
20805
21667
|
const handleWorkspaceConfirm = useCallback4(
|
|
@@ -21166,7 +22028,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21166
22028
|
async (choice) => handleReviseConfirmRef.current(choice),
|
|
21167
22029
|
[]
|
|
21168
22030
|
);
|
|
21169
|
-
return /* @__PURE__ */
|
|
22031
|
+
return /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(
|
|
21170
22032
|
TickerProvider,
|
|
21171
22033
|
{
|
|
21172
22034
|
disabled: PLAIN_UI || isResizing || !!pendingPlan || !!pendingShell || !!pendingWorkspace || !!pendingEditReview || walkthroughActive || !!pendingCheckpoint || !!stagedCheckpointRevise || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision || // Idle gate: when nothing is actively happening, suspend the
|
|
@@ -21179,44 +22041,40 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21179
22041
|
// changes (incoming stream, key press, modal popup).
|
|
21180
22042
|
!busy && !streaming
|
|
21181
22043
|
},
|
|
21182
|
-
/* @__PURE__ */
|
|
21183
|
-
|
|
22044
|
+
/* @__PURE__ */ React28.createElement(
|
|
22045
|
+
Box26,
|
|
21184
22046
|
{
|
|
21185
22047
|
flexDirection: "column",
|
|
21186
22048
|
height: stdout4?.rows ?? 30,
|
|
21187
22049
|
width: stdout4?.columns ?? 80,
|
|
21188
22050
|
overflow: "hidden"
|
|
21189
22051
|
},
|
|
21190
|
-
/* @__PURE__ */
|
|
21191
|
-
|
|
22052
|
+
/* @__PURE__ */ React28.createElement(
|
|
22053
|
+
ChromeBar,
|
|
21192
22054
|
{
|
|
21193
22055
|
summary,
|
|
21194
|
-
model: loop2.model,
|
|
21195
|
-
prefixHash,
|
|
21196
|
-
harvestOn: loop2.harvestEnabled,
|
|
21197
|
-
branchBudget: loop2.branchOptions.budget,
|
|
21198
|
-
reasoningEffort: loop2.reasoningEffort,
|
|
21199
22056
|
planMode,
|
|
21200
|
-
|
|
22057
|
+
preset: preset2,
|
|
21201
22058
|
balance,
|
|
21202
|
-
busy,
|
|
21203
22059
|
updateAvailable,
|
|
21204
22060
|
proArmed,
|
|
21205
22061
|
escalated: turnOnPro,
|
|
21206
22062
|
budgetUsd: loop2.budgetUsd,
|
|
21207
22063
|
rootDir: codeMode ? currentRootDir : void 0,
|
|
21208
|
-
sessionName: session ?? null
|
|
22064
|
+
sessionName: session ?? null,
|
|
22065
|
+
scrollRatio: scrollMaxRowsRef.current > 0 ? logScrollOffset / scrollMaxRowsRef.current : 0
|
|
21209
22066
|
}
|
|
21210
22067
|
),
|
|
21211
|
-
/* @__PURE__ */
|
|
21212
|
-
|
|
22068
|
+
/* @__PURE__ */ React28.createElement(
|
|
22069
|
+
Box26,
|
|
21213
22070
|
{
|
|
21214
|
-
flexDirection: "
|
|
22071
|
+
flexDirection: "column",
|
|
22072
|
+
flexGrow: 1,
|
|
21215
22073
|
height: pendingShell || pendingWorkspace || pendingPlan || pendingEditReview || pendingCheckpoint || stagedCheckpointRevise || stagedInput || stagedChoiceCustom || pendingChoice || pendingRevision || walkthroughActive ? 0 : Math.max(5, (stdout4?.rows ?? 30) - 9),
|
|
21216
22074
|
overflow: "hidden"
|
|
21217
22075
|
},
|
|
21218
|
-
/* @__PURE__ */
|
|
21219
|
-
|
|
22076
|
+
/* @__PURE__ */ React28.createElement(Box26, { flexDirection: "column", flexGrow: 1, overflow: "hidden" }, /* @__PURE__ */ React28.createElement(
|
|
22077
|
+
Box26,
|
|
21220
22078
|
{
|
|
21221
22079
|
flexDirection: "column",
|
|
21222
22080
|
flexGrow: 1,
|
|
@@ -21224,55 +22082,56 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21224
22082
|
overflow: "hidden"
|
|
21225
22083
|
},
|
|
21226
22084
|
(() => {
|
|
21227
|
-
const
|
|
21228
|
-
const available = Math.max(
|
|
22085
|
+
const logHeight = Math.max(5, (stdout4?.rows ?? 30) - 9);
|
|
22086
|
+
const available = Math.max(4, logHeight - (logScrollOffset > 0 ? 1 : 0));
|
|
21229
22087
|
const cols = stdout4?.columns ?? 80;
|
|
21230
|
-
const
|
|
21231
|
-
const
|
|
21232
|
-
scrollMaxRowsRef.current =
|
|
21233
|
-
lastTotalRowsRef.current =
|
|
21234
|
-
return
|
|
22088
|
+
const atoms = eventsToAtoms(historical, currentRootDir, cols);
|
|
22089
|
+
const v = viewportLog(atoms, logScrollOffset, available);
|
|
22090
|
+
scrollMaxRowsRef.current = v.maxScrollRows;
|
|
22091
|
+
lastTotalRowsRef.current = v.totalRows;
|
|
22092
|
+
return renderViewport(v);
|
|
21235
22093
|
})(),
|
|
21236
|
-
!historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */
|
|
21237
|
-
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */
|
|
21238
|
-
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */
|
|
21239
|
-
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */
|
|
21240
|
-
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */
|
|
21241
|
-
!PLAIN_UI && undoBanner && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */
|
|
21242
|
-
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */
|
|
21243
|
-
), /* @__PURE__ */
|
|
21244
|
-
|
|
21245
|
-
ScrollBar,
|
|
22094
|
+
!historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React28.createElement(WelcomeBanner, { inCodeMode: !!codeMode, dashboardUrl }) : null,
|
|
22095
|
+
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React28.createElement(Box26, { marginY: 1 }, /* @__PURE__ */ React28.createElement(EventRow, { event: streaming, projectRoot: currentRootDir })) : null,
|
|
22096
|
+
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React28.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null,
|
|
22097
|
+
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React28.createElement(SubagentRow, { activity: subagentActivity }) : null,
|
|
22098
|
+
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React28.createElement(StatusRow, { text: statusLine }) : null,
|
|
22099
|
+
!PLAIN_UI && undoBanner && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React28.createElement(UndoBanner, { banner: undoBanner }) : null,
|
|
22100
|
+
!PLAIN_UI && !pendingShell && !pendingWorkspace && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React28.createElement(StatusRow, { text: "processing\u2026" }) : null
|
|
22101
|
+
), /* @__PURE__ */ React28.createElement(
|
|
22102
|
+
BottomHint,
|
|
21246
22103
|
{
|
|
21247
|
-
|
|
22104
|
+
rowsBelow: logScrollOffset,
|
|
21248
22105
|
totalRows: lastTotalRowsRef.current,
|
|
21249
|
-
viewportRows: Math.max(
|
|
21250
|
-
|
|
22106
|
+
viewportRows: Math.max(
|
|
22107
|
+
4,
|
|
22108
|
+
Math.max(5, (stdout4?.rows ?? 30) - 9) - (logScrollOffset > 0 ? 1 : 0)
|
|
22109
|
+
)
|
|
21251
22110
|
}
|
|
21252
|
-
)
|
|
22111
|
+
))
|
|
21253
22112
|
),
|
|
21254
|
-
stagedInput ? /* @__PURE__ */
|
|
22113
|
+
stagedInput ? /* @__PURE__ */ React28.createElement(
|
|
21255
22114
|
PlanRefineInput,
|
|
21256
22115
|
{
|
|
21257
22116
|
mode: stagedInput.mode,
|
|
21258
22117
|
onSubmit: handleStagedInputSubmit,
|
|
21259
22118
|
onCancel: handleStagedInputCancel
|
|
21260
22119
|
}
|
|
21261
|
-
) : stagedCheckpointRevise ? /* @__PURE__ */
|
|
22120
|
+
) : stagedCheckpointRevise ? /* @__PURE__ */ React28.createElement(
|
|
21262
22121
|
PlanRefineInput,
|
|
21263
22122
|
{
|
|
21264
22123
|
mode: "checkpoint-revise",
|
|
21265
22124
|
onSubmit: handleCheckpointReviseSubmit,
|
|
21266
22125
|
onCancel: handleCheckpointReviseCancel
|
|
21267
22126
|
}
|
|
21268
|
-
) : stagedChoiceCustom ? /* @__PURE__ */
|
|
22127
|
+
) : stagedChoiceCustom ? /* @__PURE__ */ React28.createElement(
|
|
21269
22128
|
PlanRefineInput,
|
|
21270
22129
|
{
|
|
21271
22130
|
mode: "choice-custom",
|
|
21272
22131
|
onSubmit: handleChoiceCustomSubmit,
|
|
21273
22132
|
onCancel: handleChoiceCustomCancel
|
|
21274
22133
|
}
|
|
21275
|
-
) : pendingChoice ? /* @__PURE__ */
|
|
22134
|
+
) : pendingChoice ? /* @__PURE__ */ React28.createElement(
|
|
21276
22135
|
ChoiceConfirm,
|
|
21277
22136
|
{
|
|
21278
22137
|
question: pendingChoice.question,
|
|
@@ -21280,7 +22139,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21280
22139
|
allowCustom: pendingChoice.allowCustom,
|
|
21281
22140
|
onChoose: stableHandleChoiceConfirm
|
|
21282
22141
|
}
|
|
21283
|
-
) : pendingRevision ? /* @__PURE__ */
|
|
22142
|
+
) : pendingRevision ? /* @__PURE__ */ React28.createElement(
|
|
21284
22143
|
PlanReviseConfirm,
|
|
21285
22144
|
{
|
|
21286
22145
|
reason: pendingRevision.reason,
|
|
@@ -21291,7 +22150,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21291
22150
|
summary: pendingRevision.summary,
|
|
21292
22151
|
onChoose: stableHandleReviseConfirm
|
|
21293
22152
|
}
|
|
21294
|
-
) : pendingCheckpoint ? /* @__PURE__ */
|
|
22153
|
+
) : pendingCheckpoint ? /* @__PURE__ */ React28.createElement(
|
|
21295
22154
|
PlanCheckpointConfirm,
|
|
21296
22155
|
{
|
|
21297
22156
|
stepId: pendingCheckpoint.stepId,
|
|
@@ -21302,7 +22161,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21302
22161
|
completedStepIds: completedStepIdsRef.current,
|
|
21303
22162
|
onChoose: stableHandleCheckpointConfirm
|
|
21304
22163
|
}
|
|
21305
|
-
) : pendingPlan ? /* @__PURE__ */
|
|
22164
|
+
) : pendingPlan ? /* @__PURE__ */ React28.createElement(
|
|
21306
22165
|
PlanConfirm,
|
|
21307
22166
|
{
|
|
21308
22167
|
plan: pendingPlan,
|
|
@@ -21311,7 +22170,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21311
22170
|
onChoose: stableHandlePlanConfirm,
|
|
21312
22171
|
projectRoot: currentRootDir
|
|
21313
22172
|
}
|
|
21314
|
-
) : pendingShell ? /* @__PURE__ */
|
|
22173
|
+
) : pendingShell ? /* @__PURE__ */ React28.createElement(
|
|
21315
22174
|
ShellConfirm,
|
|
21316
22175
|
{
|
|
21317
22176
|
command: pendingShell.command,
|
|
@@ -21319,7 +22178,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21319
22178
|
kind: pendingShell.kind,
|
|
21320
22179
|
onChoose: handleShellConfirm
|
|
21321
22180
|
}
|
|
21322
|
-
) : pendingWorkspace ? /* @__PURE__ */
|
|
22181
|
+
) : pendingWorkspace ? /* @__PURE__ */ React28.createElement(
|
|
21323
22182
|
WorkspaceConfirm,
|
|
21324
22183
|
{
|
|
21325
22184
|
path: pendingWorkspace.path,
|
|
@@ -21327,7 +22186,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21327
22186
|
mcpServerCount: mcpServers?.length ?? 0,
|
|
21328
22187
|
onChoose: handleWorkspaceConfirm
|
|
21329
22188
|
}
|
|
21330
|
-
) : pendingEditReview ? /* @__PURE__ */
|
|
22189
|
+
) : pendingEditReview ? /* @__PURE__ */ React28.createElement(
|
|
21331
22190
|
EditConfirm,
|
|
21332
22191
|
{
|
|
21333
22192
|
block: pendingEditReview,
|
|
@@ -21339,14 +22198,14 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21339
22198
|
}
|
|
21340
22199
|
}
|
|
21341
22200
|
}
|
|
21342
|
-
) : walkthroughActive && pendingEdits.current.length > 0 ? /* @__PURE__ */
|
|
22201
|
+
) : walkthroughActive && pendingEdits.current.length > 0 ? /* @__PURE__ */ React28.createElement(
|
|
21343
22202
|
EditConfirm,
|
|
21344
22203
|
{
|
|
21345
22204
|
key: `walk-${pendingTick}`,
|
|
21346
22205
|
block: pendingEdits.current[0],
|
|
21347
22206
|
onChoose: handleWalkChoice
|
|
21348
22207
|
}
|
|
21349
|
-
) : /* @__PURE__ */
|
|
22208
|
+
) : /* @__PURE__ */ React28.createElement(React28.Fragment, null, codeMode ? /* @__PURE__ */ React28.createElement(
|
|
21350
22209
|
ModeStatusBar,
|
|
21351
22210
|
{
|
|
21352
22211
|
editMode,
|
|
@@ -21356,7 +22215,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21356
22215
|
undoArmed: !!undoBanner || hasUndoable(),
|
|
21357
22216
|
jobs: codeMode.jobs
|
|
21358
22217
|
}
|
|
21359
|
-
) : null, activeLoop ? /* @__PURE__ */
|
|
22218
|
+
) : null, activeLoop ? /* @__PURE__ */ React28.createElement(LoopStatusRow, { loop: activeLoop }) : null, /* @__PURE__ */ React28.createElement(
|
|
21360
22219
|
PromptInput,
|
|
21361
22220
|
{
|
|
21362
22221
|
value: input,
|
|
@@ -21366,14 +22225,14 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21366
22225
|
onHistoryPrev: recallPrev,
|
|
21367
22226
|
onHistoryNext: recallNext
|
|
21368
22227
|
}
|
|
21369
|
-
), /* @__PURE__ */
|
|
22228
|
+
), /* @__PURE__ */ React28.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React28.createElement(
|
|
21370
22229
|
AtMentionSuggestions,
|
|
21371
22230
|
{
|
|
21372
22231
|
matches: atMatches,
|
|
21373
22232
|
selectedIndex: atSelected,
|
|
21374
22233
|
query: atPicker?.query ?? ""
|
|
21375
22234
|
}
|
|
21376
|
-
), slashArgContext ? /* @__PURE__ */
|
|
22235
|
+
), slashArgContext ? /* @__PURE__ */ React28.createElement(
|
|
21377
22236
|
SlashArgPicker,
|
|
21378
22237
|
{
|
|
21379
22238
|
matches: slashArgMatches,
|
|
@@ -21388,15 +22247,15 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
21388
22247
|
}
|
|
21389
22248
|
|
|
21390
22249
|
// src/cli/ui/SessionPicker.tsx
|
|
21391
|
-
import { Box as
|
|
21392
|
-
import
|
|
22250
|
+
import { Box as Box27, Text as Text25 } from "ink";
|
|
22251
|
+
import React29 from "react";
|
|
21393
22252
|
function SessionPicker({
|
|
21394
22253
|
sessionName,
|
|
21395
22254
|
messageCount,
|
|
21396
22255
|
lastActive,
|
|
21397
22256
|
onChoose
|
|
21398
22257
|
}) {
|
|
21399
|
-
return /* @__PURE__ */
|
|
22258
|
+
return /* @__PURE__ */ React29.createElement(Box27, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React29.createElement(Box27, { marginBottom: 1 }, /* @__PURE__ */ React29.createElement(Text25, { color: COLOR.brand, bold: true }, GLYPH.brand), /* @__PURE__ */ React29.createElement(Text25, null, " "), /* @__PURE__ */ React29.createElement(Text25, { color: COLOR.primary, bold: true }, `"${sessionName}"`), /* @__PURE__ */ React29.createElement(Text25, { dimColor: true }, ` has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React29.createElement(Text25, { dimColor: true }, ` \xB7 last active ${relativeTime2(lastActive)}`)), /* @__PURE__ */ React29.createElement(
|
|
21400
22259
|
SingleSelect,
|
|
21401
22260
|
{
|
|
21402
22261
|
initialValue: "new",
|
|
@@ -21419,7 +22278,7 @@ function SessionPicker({
|
|
|
21419
22278
|
],
|
|
21420
22279
|
onSubmit: (v) => onChoose(v)
|
|
21421
22280
|
}
|
|
21422
|
-
), /* @__PURE__ */
|
|
22281
|
+
), /* @__PURE__ */ React29.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text25, { dimColor: true }, " \u2191\u2193 navigate \xB7 \u23CE select")));
|
|
21423
22282
|
}
|
|
21424
22283
|
function relativeTime2(date) {
|
|
21425
22284
|
const ms = Date.now() - date.getTime();
|
|
@@ -21435,9 +22294,9 @@ function relativeTime2(date) {
|
|
|
21435
22294
|
}
|
|
21436
22295
|
|
|
21437
22296
|
// src/cli/ui/Setup.tsx
|
|
21438
|
-
import { Box as
|
|
22297
|
+
import { Box as Box28, Text as Text26, useApp } from "ink";
|
|
21439
22298
|
import TextInput from "ink-text-input";
|
|
21440
|
-
import
|
|
22299
|
+
import React30, { useState as useState11 } from "react";
|
|
21441
22300
|
function Setup({ onReady }) {
|
|
21442
22301
|
const [value, setValue] = useState11("");
|
|
21443
22302
|
const [error, setError] = useState11(null);
|
|
@@ -21461,7 +22320,7 @@ function Setup({ onReady }) {
|
|
|
21461
22320
|
}
|
|
21462
22321
|
onReady(trimmed);
|
|
21463
22322
|
};
|
|
21464
|
-
return /* @__PURE__ */
|
|
22323
|
+
return /* @__PURE__ */ React30.createElement(Box28, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React30.createElement(Box28, null, /* @__PURE__ */ React30.createElement(Text26, { bold: true, color: GRADIENT[0] }, GLYPH.brand), /* @__PURE__ */ React30.createElement(Text26, null, " "), /* @__PURE__ */ React30.createElement(Text26, { bold: true }, "Welcome to "), /* @__PURE__ */ React30.createElement(Text26, { bold: true, color: GRADIENT[2] }, "REASONIX")), /* @__PURE__ */ React30.createElement(Box28, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(Text26, { color: COLOR.info }, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React30.createElement(Box28, null, /* @__PURE__ */ React30.createElement(Text26, { dimColor: true }, " free credit on signup \xB7 "), /* @__PURE__ */ React30.createElement(Text26, { color: COLOR.primary }, "https://platform.deepseek.com/api_keys")), /* @__PURE__ */ React30.createElement(Box28, null, /* @__PURE__ */ React30.createElement(Text26, { dimColor: true }, " saved to "), /* @__PURE__ */ React30.createElement(Text26, { dimColor: true }, defaultConfigPath())), /* @__PURE__ */ React30.createElement(Box28, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(Text26, { bold: true, color: COLOR.brand }, GLYPH.bar), /* @__PURE__ */ React30.createElement(Text26, { bold: true, color: COLOR.primary }, " \u203A "), /* @__PURE__ */ React30.createElement(
|
|
21465
22324
|
TextInput,
|
|
21466
22325
|
{
|
|
21467
22326
|
value,
|
|
@@ -21470,7 +22329,7 @@ function Setup({ onReady }) {
|
|
|
21470
22329
|
mask: "\u2022",
|
|
21471
22330
|
placeholder: "sk-..."
|
|
21472
22331
|
}
|
|
21473
|
-
)), error ? /* @__PURE__ */
|
|
22332
|
+
)), error ? /* @__PURE__ */ React30.createElement(Box28, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(Text26, { color: COLOR.err, bold: true }, GLYPH.err), /* @__PURE__ */ React30.createElement(Text26, { color: COLOR.err }, ` ${error}`)) : value ? /* @__PURE__ */ React30.createElement(Box28, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(Text26, { dimColor: true }, ` preview \xB7 ${redactKey(value)}`)) : null, /* @__PURE__ */ React30.createElement(Box28, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(Text26, { dimColor: true }, " /exit to abort")));
|
|
21474
22333
|
}
|
|
21475
22334
|
|
|
21476
22335
|
// src/cli/commands/chat.tsx
|
|
@@ -21486,7 +22345,7 @@ function Root({
|
|
|
21486
22345
|
const [key, setKey] = useState12(initialKey);
|
|
21487
22346
|
const [pending, setPending] = useState12(sessionPreview);
|
|
21488
22347
|
if (!key) {
|
|
21489
|
-
return /* @__PURE__ */
|
|
22348
|
+
return /* @__PURE__ */ React31.createElement(
|
|
21490
22349
|
Setup,
|
|
21491
22350
|
{
|
|
21492
22351
|
onReady: (k) => {
|
|
@@ -21498,7 +22357,7 @@ function Root({
|
|
|
21498
22357
|
}
|
|
21499
22358
|
process.env.DEEPSEEK_API_KEY = key;
|
|
21500
22359
|
if (pending && appProps.session) {
|
|
21501
|
-
return /* @__PURE__ */
|
|
22360
|
+
return /* @__PURE__ */ React31.createElement(KeystrokeProvider, null, /* @__PURE__ */ React31.createElement(
|
|
21502
22361
|
SessionPicker,
|
|
21503
22362
|
{
|
|
21504
22363
|
sessionName: appProps.session,
|
|
@@ -21513,7 +22372,7 @@ function Root({
|
|
|
21513
22372
|
}
|
|
21514
22373
|
));
|
|
21515
22374
|
}
|
|
21516
|
-
return /* @__PURE__ */
|
|
22375
|
+
return /* @__PURE__ */ React31.createElement(KeystrokeProvider, null, /* @__PURE__ */ React31.createElement(
|
|
21517
22376
|
App,
|
|
21518
22377
|
{
|
|
21519
22378
|
model: appProps.model,
|
|
@@ -21620,7 +22479,7 @@ async function chatCommand(opts) {
|
|
|
21620
22479
|
rewriteSession(opts.session, []);
|
|
21621
22480
|
}
|
|
21622
22481
|
const { waitUntilExit } = render(
|
|
21623
|
-
/* @__PURE__ */
|
|
22482
|
+
/* @__PURE__ */ React31.createElement(
|
|
21624
22483
|
Root,
|
|
21625
22484
|
{
|
|
21626
22485
|
initialKey,
|
|
@@ -21973,35 +22832,35 @@ async function commitCommand(opts = {}) {
|
|
|
21973
22832
|
import { writeFileSync as writeFileSync15 } from "fs";
|
|
21974
22833
|
import { basename as basename4 } from "path";
|
|
21975
22834
|
import { render as render2 } from "ink";
|
|
21976
|
-
import
|
|
22835
|
+
import React34 from "react";
|
|
21977
22836
|
|
|
21978
22837
|
// src/cli/ui/DiffApp.tsx
|
|
21979
|
-
import { Box as
|
|
21980
|
-
import
|
|
22838
|
+
import { Box as Box30, Static, Text as Text28, useApp as useApp2, useInput } from "ink";
|
|
22839
|
+
import React33, { useState as useState13 } from "react";
|
|
21981
22840
|
|
|
21982
22841
|
// src/cli/ui/RecordView.tsx
|
|
21983
|
-
import { Box as
|
|
21984
|
-
import
|
|
22842
|
+
import { Box as Box29, Text as Text27 } from "ink";
|
|
22843
|
+
import React32 from "react";
|
|
21985
22844
|
function RecordView({ rec, compact: compact2 = false }) {
|
|
21986
22845
|
const toolArgsMax = compact2 ? 120 : 200;
|
|
21987
22846
|
const toolContentMax = compact2 ? 200 : 400;
|
|
21988
22847
|
if (rec.role === "user") {
|
|
21989
22848
|
const content = rec.content.includes("\n") ? rec.content.split("\n").join("\n ") : rec.content;
|
|
21990
|
-
return /* @__PURE__ */
|
|
22849
|
+
return /* @__PURE__ */ React32.createElement(Box29, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text27, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React32.createElement(Text27, null, content));
|
|
21991
22850
|
}
|
|
21992
22851
|
if (rec.role === "assistant_final") {
|
|
21993
|
-
return /* @__PURE__ */
|
|
22852
|
+
return /* @__PURE__ */ React32.createElement(Box29, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React32.createElement(Box29, null, /* @__PURE__ */ React32.createElement(Text27, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React32.createElement(Text27, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React32.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React32.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React32.createElement(Text27, null, rec.content) : /* @__PURE__ */ React32.createElement(Text27, { dimColor: true, italic: true }, "(tool-call response only)"));
|
|
21994
22853
|
}
|
|
21995
22854
|
if (rec.role === "tool") {
|
|
21996
|
-
return /* @__PURE__ */
|
|
22855
|
+
return /* @__PURE__ */ React32.createElement(Box29, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text27, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React32.createElement(Text27, { dimColor: true }, " args: ", truncate2(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React32.createElement(Text27, { dimColor: true }, " \u2192 ", truncate2(rec.content, toolContentMax)));
|
|
21997
22856
|
}
|
|
21998
22857
|
if (rec.role === "error") {
|
|
21999
|
-
return /* @__PURE__ */
|
|
22858
|
+
return /* @__PURE__ */ React32.createElement(Box29, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text27, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React32.createElement(Text27, { color: "red" }, rec.error ?? rec.content));
|
|
22000
22859
|
}
|
|
22001
22860
|
if (rec.role === "done" || rec.role === "assistant_delta") {
|
|
22002
22861
|
return null;
|
|
22003
22862
|
}
|
|
22004
|
-
return /* @__PURE__ */
|
|
22863
|
+
return /* @__PURE__ */ React32.createElement(Box29, null, /* @__PURE__ */ React32.createElement(Text27, { dimColor: true }, "[", rec.role, "] ", rec.content));
|
|
22005
22864
|
}
|
|
22006
22865
|
function CacheBadge({ usage }) {
|
|
22007
22866
|
const hit = usage.prompt_cache_hit_tokens ?? 0;
|
|
@@ -22010,7 +22869,7 @@ function CacheBadge({ usage }) {
|
|
|
22010
22869
|
if (total === 0) return null;
|
|
22011
22870
|
const pct2 = hit / total * 100;
|
|
22012
22871
|
const color2 = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
|
|
22013
|
-
return /* @__PURE__ */
|
|
22872
|
+
return /* @__PURE__ */ React32.createElement(Text27, null, /* @__PURE__ */ React32.createElement(Text27, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React32.createElement(Text27, { color: color2 }, pct2.toFixed(1), "%"));
|
|
22014
22873
|
}
|
|
22015
22874
|
function truncate2(s, max) {
|
|
22016
22875
|
return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
|
|
@@ -22044,7 +22903,7 @@ function DiffApp({ report }) {
|
|
|
22044
22903
|
}
|
|
22045
22904
|
});
|
|
22046
22905
|
const pair = report.pairs[idx];
|
|
22047
|
-
return /* @__PURE__ */
|
|
22906
|
+
return /* @__PURE__ */ React33.createElement(Box30, { flexDirection: "column" }, /* @__PURE__ */ React33.createElement(DiffHeader, { report }), /* @__PURE__ */ React33.createElement(Box30, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React33.createElement(Text28, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React33.createElement(Text28, null, pair ? /* @__PURE__ */ React33.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React33.createElement(Box30, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React33.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React33.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React33.createElement(Box30, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React33.createElement(Text28, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React33.createElement(Text28, null, pair.divergenceNote)) : null, /* @__PURE__ */ React33.createElement(Box30, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "j"), "/", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "k"), "/", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "N"), "/", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "g"), "/", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React33.createElement(Text28, { bold: true }, "q"), " ", "quit")));
|
|
22048
22907
|
}
|
|
22049
22908
|
function DiffHeader({ report }) {
|
|
22050
22909
|
const a = report.a;
|
|
@@ -22062,15 +22921,15 @@ function DiffHeader({ report }) {
|
|
|
22062
22921
|
} else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
|
|
22063
22922
|
prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
|
|
22064
22923
|
}
|
|
22065
|
-
return /* @__PURE__ */
|
|
22924
|
+
return /* @__PURE__ */ React33.createElement(Box30, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React33.createElement(Box30, { justifyContent: "space-between" }, /* @__PURE__ */ React33.createElement(Text28, null, /* @__PURE__ */ React33.createElement(Text28, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React33.createElement(Text28, { color: "blue" }, a.label), /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, " vs B="), /* @__PURE__ */ React33.createElement(Text28, { color: "magenta" }, b.label)), /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React33.createElement(Box30, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React33.createElement(Text28, null, /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, "cache "), /* @__PURE__ */ React33.createElement(Text28, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React33.createElement(Text28, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React33.createElement(Text28, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React33.createElement(Text28, null, /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, "cost "), /* @__PURE__ */ React33.createElement(Text28, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React33.createElement(Text28, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React33.createElement(Text28, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React33.createElement(Text28, null, /* @__PURE__ */ React33.createElement(Text28, { dimColor: true }, "model calls "), /* @__PURE__ */ React33.createElement(Text28, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React33.createElement(Box30, { marginTop: 1 }, /* @__PURE__ */ React33.createElement(Text28, { dimColor: true, italic: true }, prefixLine)) : null);
|
|
22066
22925
|
}
|
|
22067
22926
|
function Pane({
|
|
22068
22927
|
label,
|
|
22069
22928
|
headerColor,
|
|
22070
22929
|
records
|
|
22071
22930
|
}) {
|
|
22072
|
-
return /* @__PURE__ */
|
|
22073
|
-
|
|
22931
|
+
return /* @__PURE__ */ React33.createElement(
|
|
22932
|
+
Box30,
|
|
22074
22933
|
{
|
|
22075
22934
|
flexDirection: "column",
|
|
22076
22935
|
flexGrow: 1,
|
|
@@ -22078,21 +22937,21 @@ function Pane({
|
|
|
22078
22937
|
borderStyle: "single",
|
|
22079
22938
|
borderColor: headerColor
|
|
22080
22939
|
},
|
|
22081
|
-
/* @__PURE__ */
|
|
22082
|
-
records.length === 0 ? /* @__PURE__ */
|
|
22940
|
+
/* @__PURE__ */ React33.createElement(Text28, { color: headerColor, bold: true }, label),
|
|
22941
|
+
records.length === 0 ? /* @__PURE__ */ React33.createElement(Box30, { marginTop: 1 }, /* @__PURE__ */ React33.createElement(Text28, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React33.createElement(Static, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React33.createElement(RecordView, { key, rec, compact: true }))
|
|
22083
22942
|
);
|
|
22084
22943
|
}
|
|
22085
22944
|
function KindBadge({ kind }) {
|
|
22086
22945
|
if (kind === "match") {
|
|
22087
|
-
return /* @__PURE__ */
|
|
22946
|
+
return /* @__PURE__ */ React33.createElement(Text28, { color: "green" }, "\u2713 match");
|
|
22088
22947
|
}
|
|
22089
22948
|
if (kind === "diverge") {
|
|
22090
|
-
return /* @__PURE__ */
|
|
22949
|
+
return /* @__PURE__ */ React33.createElement(Text28, { color: "yellow" }, "\u2605 diverge");
|
|
22091
22950
|
}
|
|
22092
22951
|
if (kind === "only_in_a") {
|
|
22093
|
-
return /* @__PURE__ */
|
|
22952
|
+
return /* @__PURE__ */ React33.createElement(Text28, { color: "blue" }, "\u2190 only in A");
|
|
22094
22953
|
}
|
|
22095
|
-
return /* @__PURE__ */
|
|
22954
|
+
return /* @__PURE__ */ React33.createElement(Text28, { color: "magenta" }, "\u2192 only in B");
|
|
22096
22955
|
}
|
|
22097
22956
|
function paneRecords(pair, side) {
|
|
22098
22957
|
if (!pair) return [];
|
|
@@ -22123,7 +22982,7 @@ markdown report written to ${opts.mdPath}`);
|
|
|
22123
22982
|
return;
|
|
22124
22983
|
}
|
|
22125
22984
|
if (wantTui) {
|
|
22126
|
-
const { waitUntilExit } = render2(
|
|
22985
|
+
const { waitUntilExit } = render2(React34.createElement(DiffApp, { report }), {
|
|
22127
22986
|
exitOnCtrlC: true,
|
|
22128
22987
|
patchConsole: false
|
|
22129
22988
|
});
|
|
@@ -22138,9 +22997,9 @@ import { existsSync as existsSync24, statSync as statSync14 } from "fs";
|
|
|
22138
22997
|
import { homedir as homedir11 } from "os";
|
|
22139
22998
|
import { dirname as dirname17, join as join23, resolve as resolve13 } from "path";
|
|
22140
22999
|
var TTY = process.stdout.isTTY && process.env.TERM !== "dumb";
|
|
22141
|
-
function color(
|
|
22142
|
-
if (!TTY) return
|
|
22143
|
-
return `\x1B[${code}m${
|
|
23000
|
+
function color(text2, code) {
|
|
23001
|
+
if (!TTY) return text2;
|
|
23002
|
+
return `\x1B[${code}m${text2}\x1B[0m`;
|
|
22144
23003
|
}
|
|
22145
23004
|
function badge(level) {
|
|
22146
23005
|
if (level === "ok") return color("\u2713", "32");
|
|
@@ -22481,8 +23340,8 @@ async function ollamaPreflight(opts) {
|
|
|
22481
23340
|
return false;
|
|
22482
23341
|
}
|
|
22483
23342
|
log(t("modelPulling", { model: opts.model }));
|
|
22484
|
-
const
|
|
22485
|
-
const ANSI_CSI = new RegExp(`${
|
|
23343
|
+
const ESC2 = String.fromCharCode(27);
|
|
23344
|
+
const ANSI_CSI = new RegExp(`${ESC2}\\[[0-9;]*[A-Za-z]`, "g");
|
|
22486
23345
|
const code = await pullOllamaModel(opts.model, {
|
|
22487
23346
|
onLine: (line) => {
|
|
22488
23347
|
const cleaned = line.replace(ANSI_CSI, "").trim();
|
|
@@ -22744,7 +23603,7 @@ function mcpListCommand(opts) {
|
|
|
22744
23603
|
console.log("Popular MCP servers you can bridge into Reasonix:");
|
|
22745
23604
|
console.log("");
|
|
22746
23605
|
for (const entry of MCP_CATALOG) {
|
|
22747
|
-
console.log(` ${
|
|
23606
|
+
console.log(` ${pad3(entry.name, 12)} ${entry.summary}`);
|
|
22748
23607
|
console.log(` ${mcpCommandFor(entry)}`);
|
|
22749
23608
|
if (entry.note) console.log(` \xB7 ${entry.note}`);
|
|
22750
23609
|
console.log("");
|
|
@@ -22757,17 +23616,128 @@ function mcpListCommand(opts) {
|
|
|
22757
23616
|
" https://mcp.so \u2014 community-maintained catalog"
|
|
22758
23617
|
);
|
|
22759
23618
|
}
|
|
22760
|
-
function
|
|
23619
|
+
function pad3(s, width) {
|
|
22761
23620
|
return s.length >= width ? s : s + " ".repeat(width - s.length);
|
|
22762
23621
|
}
|
|
22763
23622
|
|
|
22764
23623
|
// src/cli/commands/replay.ts
|
|
22765
23624
|
import { render as render3 } from "ink";
|
|
23625
|
+
import React37 from "react";
|
|
23626
|
+
|
|
23627
|
+
// src/cli/ui/ReplayApp.tsx
|
|
23628
|
+
import { Box as Box32, Static as Static2, Text as Text30, useApp as useApp3, useInput as useInput2 } from "ink";
|
|
23629
|
+
import React36, { useMemo as useMemo4, useState as useState14 } from "react";
|
|
23630
|
+
|
|
23631
|
+
// src/cli/ui/StatsPanel.tsx
|
|
23632
|
+
import { basename as basename5 } from "path";
|
|
23633
|
+
import { Box as Box31, Text as Text29, useStdout as useStdout10 } from "ink";
|
|
22766
23634
|
import React35 from "react";
|
|
23635
|
+
var NARROW_BREAKPOINT2 = 120;
|
|
23636
|
+
var COLD_START_TURNS2 = 3;
|
|
23637
|
+
function StatsPanel({
|
|
23638
|
+
summary,
|
|
23639
|
+
model: model2,
|
|
23640
|
+
prefixHash,
|
|
23641
|
+
harvestOn,
|
|
23642
|
+
branchBudget,
|
|
23643
|
+
reasoningEffort,
|
|
23644
|
+
planMode,
|
|
23645
|
+
editMode,
|
|
23646
|
+
balance,
|
|
23647
|
+
updateAvailable,
|
|
23648
|
+
busy,
|
|
23649
|
+
proArmed,
|
|
23650
|
+
escalated,
|
|
23651
|
+
budgetUsd,
|
|
23652
|
+
rootDir,
|
|
23653
|
+
sessionName
|
|
23654
|
+
}) {
|
|
23655
|
+
const branchOn = (branchBudget ?? 1) > 1;
|
|
23656
|
+
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model2] ?? DEFAULT_CONTEXT_TOKENS;
|
|
23657
|
+
const ctxRatio = summary.lastPromptTokens / ctxMax;
|
|
23658
|
+
const { stdout: stdout4 } = useStdout10();
|
|
23659
|
+
const columns = stdout4?.columns ?? 80;
|
|
23660
|
+
const narrow = columns < NARROW_BREAKPOINT2;
|
|
23661
|
+
const coldStart = summary.turns <= COLD_START_TURNS2;
|
|
23662
|
+
return /* @__PURE__ */ React35.createElement(Box31, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React35.createElement(
|
|
23663
|
+
ChromeRow,
|
|
23664
|
+
{
|
|
23665
|
+
editMode,
|
|
23666
|
+
planMode,
|
|
23667
|
+
proArmed: proArmed ?? false,
|
|
23668
|
+
escalated: escalated ?? false,
|
|
23669
|
+
summary,
|
|
23670
|
+
coldStart,
|
|
23671
|
+
rootDir,
|
|
23672
|
+
sessionName: sessionName ?? null,
|
|
23673
|
+
updateAvailable,
|
|
23674
|
+
balance: balance ?? null,
|
|
23675
|
+
narrow
|
|
23676
|
+
}
|
|
23677
|
+
), /* @__PURE__ */ React35.createElement(ChromeRule2, null), budgetUsd !== null && budgetUsd !== void 0 ? /* @__PURE__ */ React35.createElement(BudgetRow, { spent: summary.totalCostUsd, cap: budgetUsd }) : null);
|
|
23678
|
+
}
|
|
23679
|
+
function ChromeRule2() {
|
|
23680
|
+
const { stdout: stdout4 } = useStdout10();
|
|
23681
|
+
const cols = stdout4?.columns ?? 80;
|
|
23682
|
+
const w = Math.max(20, cols - 2);
|
|
23683
|
+
return /* @__PURE__ */ React35.createElement(Text29, { dimColor: true }, "\u2500".repeat(w));
|
|
23684
|
+
}
|
|
23685
|
+
function ChromeRow({
|
|
23686
|
+
editMode,
|
|
23687
|
+
planMode,
|
|
23688
|
+
proArmed,
|
|
23689
|
+
escalated,
|
|
23690
|
+
summary,
|
|
23691
|
+
coldStart,
|
|
23692
|
+
rootDir,
|
|
23693
|
+
sessionName,
|
|
23694
|
+
updateAvailable,
|
|
23695
|
+
balance,
|
|
23696
|
+
narrow
|
|
23697
|
+
}) {
|
|
23698
|
+
const modePill = pickModePill2(planMode, editMode);
|
|
23699
|
+
const proPill = escalated ? { label: "\u21E7 pro", color: COLOR.err } : proArmed ? { label: "\u21E7 pro", color: COLOR.warn } : null;
|
|
23700
|
+
const projectName = rootDir ? basename5(rootDir) : null;
|
|
23701
|
+
const cachePct = Math.round(summary.cacheHitRatio * 100);
|
|
23702
|
+
const cacheColor = summary.cacheHitRatio >= 0.7 ? COLOR.ok : summary.cacheHitRatio >= 0.4 ? COLOR.warn : COLOR.err;
|
|
23703
|
+
return /* @__PURE__ */ React35.createElement(Box31, null, /* @__PURE__ */ React35.createElement(Text29, { bold: true, color: GRADIENT[0] }, "\u25C8 "), /* @__PURE__ */ React35.createElement(Text29, { color: COLOR.brand, bold: true }, "reasonix"), projectName ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement(Text29, { color: COLOR.info, dimColor: true }, " \xB7 "), /* @__PURE__ */ React35.createElement(Text29, null, projectName), !narrow && sessionName ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement(Text29, { color: COLOR.info, dimColor: true }, " \u203A "), /* @__PURE__ */ React35.createElement(Text29, { color: COLOR.info }, sessionName)) : null) : null, /* @__PURE__ */ React35.createElement(Box31, { flexGrow: 1 }), updateAvailable ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement(Text29, { color: COLOR.warn, bold: true }, `\u2191 ${updateAvailable}`), /* @__PURE__ */ React35.createElement(Text29, null, " ")) : null, modePill ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement(Text29, { color: modePill.color, bold: true }, `[${modePill.label}]`), /* @__PURE__ */ React35.createElement(Text29, null, " ")) : null, proPill ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement(Text29, { color: proPill.color, bold: true }, `[${proPill.label}]`), /* @__PURE__ */ React35.createElement(Text29, null, " ")) : null, /* @__PURE__ */ React35.createElement(
|
|
23704
|
+
Text29,
|
|
23705
|
+
{
|
|
23706
|
+
color: summary.turns === 0 || coldStart ? COLOR.info : sessionCostColor2(summary.totalCostUsd),
|
|
23707
|
+
bold: summary.turns > 0 && !coldStart,
|
|
23708
|
+
dimColor: summary.turns === 0 || coldStart
|
|
23709
|
+
},
|
|
23710
|
+
`[$${summary.totalCostUsd.toFixed(4)}]`
|
|
23711
|
+
), balance && !narrow ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement(Text29, null, " "), /* @__PURE__ */ React35.createElement(Text29, { color: balance.total < 1 ? COLOR.err : balance.total < 5 ? COLOR.warn : COLOR.ok }, `[w ${balance.currency === "USD" ? "$" : ""}${balance.total.toFixed(2)}${balance.currency !== "USD" ? ` ${balance.currency}` : ""}]`)) : null, summary.turns > 3 && !narrow ? /* @__PURE__ */ React35.createElement(React35.Fragment, null, /* @__PURE__ */ React35.createElement(Text29, null, " "), /* @__PURE__ */ React35.createElement(Text29, { dimColor: true }, "["), /* @__PURE__ */ React35.createElement(Text29, { dimColor: true }, "c "), /* @__PURE__ */ React35.createElement(Bar, { ratio: summary.cacheHitRatio, color: cacheColor, cells: 6 }), /* @__PURE__ */ React35.createElement(Text29, null, " "), /* @__PURE__ */ React35.createElement(Text29, { color: cacheColor }, `${cachePct}%`), /* @__PURE__ */ React35.createElement(Text29, { dimColor: true }, "]")) : null);
|
|
23712
|
+
}
|
|
23713
|
+
function pickModePill2(planMode, editMode) {
|
|
23714
|
+
if (planMode) return { label: "PLAN", color: COLOR.err };
|
|
23715
|
+
if (editMode === "yolo") return { label: "yolo", color: COLOR.err };
|
|
23716
|
+
if (editMode === "auto") return { label: "auto", color: COLOR.primary };
|
|
23717
|
+
if (editMode === "review") return { label: "review", color: COLOR.info };
|
|
23718
|
+
return null;
|
|
23719
|
+
}
|
|
23720
|
+
function BudgetRow({ spent, cap }) {
|
|
23721
|
+
const pct2 = Math.max(0, spent / cap * 100);
|
|
23722
|
+
const color2 = pct2 >= 100 ? "#f87171" : pct2 >= 80 ? "#fbbf24" : "#94a3b8";
|
|
23723
|
+
return /* @__PURE__ */ React35.createElement(Box31, null, /* @__PURE__ */ React35.createElement(Text29, { dimColor: true }, " budget "), /* @__PURE__ */ React35.createElement(Text29, { color: color2 }, `$${spent.toFixed(4)} / $${cap.toFixed(2)}`, /* @__PURE__ */ React35.createElement(Text29, { dimColor: true }, ` (${pct2.toFixed(0)}%)`)));
|
|
23724
|
+
}
|
|
23725
|
+
function sessionCostColor2(cost) {
|
|
23726
|
+
if (cost <= 0) return void 0;
|
|
23727
|
+
if (cost >= 5) return COLOR.err;
|
|
23728
|
+
if (cost >= 0.5) return COLOR.warn;
|
|
23729
|
+
return COLOR.ok;
|
|
23730
|
+
}
|
|
23731
|
+
function Bar({
|
|
23732
|
+
ratio,
|
|
23733
|
+
color: color2,
|
|
23734
|
+
cells = 14
|
|
23735
|
+
}) {
|
|
23736
|
+
const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
|
|
23737
|
+
return /* @__PURE__ */ React35.createElement(Text29, null, /* @__PURE__ */ React35.createElement(Text29, { color: color2 }, "\u25B0".repeat(filled)), /* @__PURE__ */ React35.createElement(Text29, { dimColor: true }, "\u25B1".repeat(cells - filled)));
|
|
23738
|
+
}
|
|
22767
23739
|
|
|
22768
23740
|
// src/cli/ui/ReplayApp.tsx
|
|
22769
|
-
import { Box as Box30, Static as Static2, Text as Text28, useApp as useApp3, useInput as useInput2 } from "ink";
|
|
22770
|
-
import React34, { useMemo as useMemo4, useState as useState14 } from "react";
|
|
22771
23741
|
function ReplayApp({ meta, pages }) {
|
|
22772
23742
|
const { exit: exit2 } = useApp3();
|
|
22773
23743
|
const maxIdx = Math.max(0, pages.length - 1);
|
|
@@ -22807,14 +23777,14 @@ function ReplayApp({ meta, pages }) {
|
|
|
22807
23777
|
const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
|
|
22808
23778
|
const currentPage = pages[idx];
|
|
22809
23779
|
const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
|
|
22810
|
-
return /* @__PURE__ */
|
|
23780
|
+
return /* @__PURE__ */ React36.createElement(Box32, { flexDirection: "column" }, /* @__PURE__ */ React36.createElement(
|
|
22811
23781
|
StatsPanel,
|
|
22812
23782
|
{
|
|
22813
23783
|
summary,
|
|
22814
23784
|
model: cumStats.models[0] ?? meta?.model ?? "?",
|
|
22815
23785
|
prefixHash
|
|
22816
23786
|
}
|
|
22817
|
-
), /* @__PURE__ */
|
|
23787
|
+
), /* @__PURE__ */ React36.createElement(Box32, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React36.createElement(Box32, { justifyContent: "space-between" }, /* @__PURE__ */ React36.createElement(Text30, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React36.createElement(Text30, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React36.createElement(Static2, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React36.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React36.createElement(Text30, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React36.createElement(Box32, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React36.createElement(Text30, { dimColor: true }, /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "j"), "/", /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "k"), "/", /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React36.createElement(Text30, { bold: true }, "q"), " quit")));
|
|
22818
23788
|
}
|
|
22819
23789
|
|
|
22820
23790
|
// src/cli/commands/replay.ts
|
|
@@ -22826,7 +23796,7 @@ async function replayCommand(opts) {
|
|
|
22826
23796
|
}
|
|
22827
23797
|
const { parsed } = replayFromFile(opts.path);
|
|
22828
23798
|
const pages = groupRecordsByTurn(parsed.records);
|
|
22829
|
-
const { waitUntilExit } = render3(
|
|
23799
|
+
const { waitUntilExit } = render3(React37.createElement(ReplayApp, { meta: parsed.meta, pages }), {
|
|
22830
23800
|
exitOnCtrlC: true,
|
|
22831
23801
|
patchConsole: false
|
|
22832
23802
|
});
|
|
@@ -23132,12 +24102,12 @@ function truncate3(s, max) {
|
|
|
23132
24102
|
|
|
23133
24103
|
// src/cli/commands/setup.tsx
|
|
23134
24104
|
import { render as render4 } from "ink";
|
|
23135
|
-
import
|
|
24105
|
+
import React39 from "react";
|
|
23136
24106
|
|
|
23137
24107
|
// src/cli/ui/Wizard.tsx
|
|
23138
|
-
import { Box as
|
|
24108
|
+
import { Box as Box33, Text as Text31, useApp as useApp4, useInput as useInput3 } from "ink";
|
|
23139
24109
|
import TextInput2 from "ink-text-input";
|
|
23140
|
-
import
|
|
24110
|
+
import React38, { useState as useState15 } from "react";
|
|
23141
24111
|
var CATALOG_BY_NAME = new Map(MCP_CATALOG.map((e) => [e.name, e]));
|
|
23142
24112
|
function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
23143
24113
|
const { exit: exit2 } = useApp4();
|
|
@@ -23153,7 +24123,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
23153
24123
|
if (key.escape && step !== "saved" && onCancel) onCancel();
|
|
23154
24124
|
});
|
|
23155
24125
|
if (step === "apiKey") {
|
|
23156
|
-
return /* @__PURE__ */
|
|
24126
|
+
return /* @__PURE__ */ React38.createElement(
|
|
23157
24127
|
ApiKeyStep,
|
|
23158
24128
|
{
|
|
23159
24129
|
onSubmit: (key) => {
|
|
@@ -23167,7 +24137,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
23167
24137
|
);
|
|
23168
24138
|
}
|
|
23169
24139
|
if (step === "preset") {
|
|
23170
|
-
return /* @__PURE__ */
|
|
24140
|
+
return /* @__PURE__ */ React38.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React38.createElement(
|
|
23171
24141
|
SingleSelect,
|
|
23172
24142
|
{
|
|
23173
24143
|
items: presetItems(),
|
|
@@ -23177,10 +24147,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
23177
24147
|
setStep("mcp");
|
|
23178
24148
|
}
|
|
23179
24149
|
}
|
|
23180
|
-
), /* @__PURE__ */
|
|
24150
|
+
), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel")));
|
|
23181
24151
|
}
|
|
23182
24152
|
if (step === "mcp") {
|
|
23183
|
-
return /* @__PURE__ */
|
|
24153
|
+
return /* @__PURE__ */ React38.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React38.createElement(
|
|
23184
24154
|
MultiSelect,
|
|
23185
24155
|
{
|
|
23186
24156
|
items: mcpItems(),
|
|
@@ -23205,7 +24175,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
23205
24175
|
}
|
|
23206
24176
|
const currentName = pending[0];
|
|
23207
24177
|
const entry = CATALOG_BY_NAME.get(currentName);
|
|
23208
|
-
return /* @__PURE__ */
|
|
24178
|
+
return /* @__PURE__ */ React38.createElement(
|
|
23209
24179
|
McpArgsStep,
|
|
23210
24180
|
{
|
|
23211
24181
|
entry,
|
|
@@ -23223,7 +24193,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
23223
24193
|
}
|
|
23224
24194
|
if (step === "review") {
|
|
23225
24195
|
const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
|
|
23226
|
-
return /* @__PURE__ */
|
|
24196
|
+
return /* @__PURE__ */ React38.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React38.createElement(Box33, { flexDirection: "column" }, /* @__PURE__ */ React38.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React38.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React38.createElement(
|
|
23227
24197
|
SummaryLine,
|
|
23228
24198
|
{
|
|
23229
24199
|
label: "MCP",
|
|
@@ -23231,8 +24201,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
23231
24201
|
}
|
|
23232
24202
|
), specs.map((spec, i) => (
|
|
23233
24203
|
// biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
|
|
23234
|
-
/* @__PURE__ */
|
|
23235
|
-
)), /* @__PURE__ */
|
|
24204
|
+
/* @__PURE__ */ React38.createElement(Box33, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "\xB7 ", spec))
|
|
24205
|
+
)), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { color: "red" }, error)) : null, /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "[Enter] save \xB7 [Esc] cancel"))), /* @__PURE__ */ React38.createElement(
|
|
23236
24206
|
ReviewConfirm,
|
|
23237
24207
|
{
|
|
23238
24208
|
onConfirm: () => {
|
|
@@ -23258,7 +24228,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
23258
24228
|
}
|
|
23259
24229
|
));
|
|
23260
24230
|
}
|
|
23261
|
-
return /* @__PURE__ */
|
|
24231
|
+
return /* @__PURE__ */ React38.createElement(Box33, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React38.createElement(Text31, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "[Enter] to exit")), /* @__PURE__ */ React38.createElement(ExitOnEnter, { onExit: exit2 }));
|
|
23262
24232
|
}
|
|
23263
24233
|
function ApiKeyStep({
|
|
23264
24234
|
onSubmit,
|
|
@@ -23266,7 +24236,7 @@ function ApiKeyStep({
|
|
|
23266
24236
|
onError
|
|
23267
24237
|
}) {
|
|
23268
24238
|
const [value, setValue] = useState15("");
|
|
23269
|
-
return /* @__PURE__ */
|
|
24239
|
+
return /* @__PURE__ */ React38.createElement(Box33, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React38.createElement(Text31, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React38.createElement(
|
|
23270
24240
|
TextInput2,
|
|
23271
24241
|
{
|
|
23272
24242
|
value,
|
|
@@ -23283,7 +24253,7 @@ function ApiKeyStep({
|
|
|
23283
24253
|
mask: "\u2022",
|
|
23284
24254
|
placeholder: "sk-..."
|
|
23285
24255
|
}
|
|
23286
|
-
)), error ? /* @__PURE__ */
|
|
24256
|
+
)), error ? /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { color: "red" }, error)) : value ? /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "preview: ", redactKey(value))) : null);
|
|
23287
24257
|
}
|
|
23288
24258
|
function McpArgsStep({
|
|
23289
24259
|
entry,
|
|
@@ -23292,7 +24262,7 @@ function McpArgsStep({
|
|
|
23292
24262
|
onError
|
|
23293
24263
|
}) {
|
|
23294
24264
|
const [value, setValue] = useState15("");
|
|
23295
|
-
return /* @__PURE__ */
|
|
24265
|
+
return /* @__PURE__ */ React38.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React38.createElement(Box33, { flexDirection: "column" }, /* @__PURE__ */ React38.createElement(Text31, null, entry.summary), entry.note ? /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, null, "Required parameter: "), /* @__PURE__ */ React38.createElement(Text31, { bold: true }, entry.userArgs)), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React38.createElement(
|
|
23296
24266
|
TextInput2,
|
|
23297
24267
|
{
|
|
23298
24268
|
value,
|
|
@@ -23308,7 +24278,7 @@ function McpArgsStep({
|
|
|
23308
24278
|
},
|
|
23309
24279
|
placeholder: placeholderFor(entry)
|
|
23310
24280
|
}
|
|
23311
|
-
)), error ? /* @__PURE__ */
|
|
24281
|
+
)), error ? /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1 }, /* @__PURE__ */ React38.createElement(Text31, { color: "red" }, error)) : null));
|
|
23312
24282
|
}
|
|
23313
24283
|
function ReviewConfirm({ onConfirm }) {
|
|
23314
24284
|
useInput3((_i, key) => {
|
|
@@ -23328,10 +24298,10 @@ function StepFrame({
|
|
|
23328
24298
|
total,
|
|
23329
24299
|
children
|
|
23330
24300
|
}) {
|
|
23331
|
-
return /* @__PURE__ */
|
|
24301
|
+
return /* @__PURE__ */ React38.createElement(Box33, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React38.createElement(Box33, null, /* @__PURE__ */ React38.createElement(Text31, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React38.createElement(Text31, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React38.createElement(Box33, { marginTop: 1, flexDirection: "column" }, children));
|
|
23332
24302
|
}
|
|
23333
24303
|
function SummaryLine({ label, value }) {
|
|
23334
|
-
return /* @__PURE__ */
|
|
24304
|
+
return /* @__PURE__ */ React38.createElement(Box33, null, /* @__PURE__ */ React38.createElement(Text31, null, label.padEnd(12)), /* @__PURE__ */ React38.createElement(Text31, { bold: true }, value));
|
|
23335
24305
|
}
|
|
23336
24306
|
function presetItems() {
|
|
23337
24307
|
return ["auto", "flash", "pro"].map((name) => ({
|
|
@@ -23387,7 +24357,7 @@ async function setupCommand(_opts = {}) {
|
|
|
23387
24357
|
const existingKey = loadApiKey();
|
|
23388
24358
|
const existing = readConfig();
|
|
23389
24359
|
const { waitUntilExit, unmount } = render4(
|
|
23390
|
-
/* @__PURE__ */
|
|
24360
|
+
/* @__PURE__ */ React39.createElement(
|
|
23391
24361
|
Wizard,
|
|
23392
24362
|
{
|
|
23393
24363
|
existingApiKey: existingKey,
|