reasonix 0.7.2 → 0.7.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 +1626 -722
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -715,13 +715,13 @@ async function runHooks(opts) {
|
|
|
715
715
|
const matching = opts.hooks.filter((h) => h.event === event && matchesTool(h, toolName));
|
|
716
716
|
const outcomes = [];
|
|
717
717
|
let blocked = false;
|
|
718
|
-
const
|
|
718
|
+
const stdin3 = `${JSON.stringify(opts.payload)}
|
|
719
719
|
`;
|
|
720
720
|
for (const hook of matching) {
|
|
721
721
|
const start = Date.now();
|
|
722
722
|
const timeoutMs = hook.timeout ?? DEFAULT_TIMEOUTS_MS[event];
|
|
723
723
|
const cwd = hook.cwd ?? opts.payload.cwd;
|
|
724
|
-
const raw = await spawner({ command: hook.command, cwd, stdin:
|
|
724
|
+
const raw = await spawner({ command: hook.command, cwd, stdin: stdin3, timeoutMs });
|
|
725
725
|
const decision = decideOutcome(event, raw);
|
|
726
726
|
outcomes.push({
|
|
727
727
|
hook,
|
|
@@ -7113,11 +7113,11 @@ function formatLogSize(path = defaultUsageLogPath()) {
|
|
|
7113
7113
|
// src/cli/commands/chat.tsx
|
|
7114
7114
|
import { existsSync as existsSync12, statSync as statSync7 } from "fs";
|
|
7115
7115
|
import { render } from "ink";
|
|
7116
|
-
import
|
|
7116
|
+
import React26, { useState as useState12 } from "react";
|
|
7117
7117
|
|
|
7118
7118
|
// src/cli/ui/App.tsx
|
|
7119
|
-
import { Box as
|
|
7120
|
-
import
|
|
7119
|
+
import { Box as Box21, Static, useApp, useStdout as useStdout8 } from "ink";
|
|
7120
|
+
import React23, { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo3, useRef as useRef6, useState as useState10 } from "react";
|
|
7121
7121
|
|
|
7122
7122
|
// src/code/pending-edits.ts
|
|
7123
7123
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
@@ -7430,23 +7430,376 @@ function AtMentionSuggestions({
|
|
|
7430
7430
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 1, marginTop: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((path, i) => /* @__PURE__ */ React.createElement(FileRow, { key: path, path, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick \xB7 file content inlined on send"));
|
|
7431
7431
|
}
|
|
7432
7432
|
function FileRow({ path, isSelected }) {
|
|
7433
|
-
const marker = isSelected ? "\u25B8" : " ";
|
|
7434
7433
|
const slash = path.lastIndexOf("/");
|
|
7435
7434
|
const dir = slash >= 0 ? `${path.slice(0, slash)}/` : "";
|
|
7436
7435
|
const base = slash >= 0 ? path.slice(slash + 1) : path;
|
|
7437
7436
|
if (isSelected) {
|
|
7438
|
-
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, {
|
|
7437
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { backgroundColor: "#67e8f9", color: "black", bold: true }, ` \u25B8 ${base}${dir ? ` ${dir}` : ""} `));
|
|
7439
7438
|
}
|
|
7440
|
-
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, {
|
|
7439
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "#94a3b8" }, ` ${base}`), dir ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` ${dir}`) : null);
|
|
7441
7440
|
}
|
|
7442
7441
|
|
|
7443
7442
|
// src/cli/ui/ChoiceConfirm.tsx
|
|
7443
|
+
import { Box as Box4 } from "ink";
|
|
7444
|
+
import React5 from "react";
|
|
7445
|
+
|
|
7446
|
+
// src/cli/ui/ModalCard.tsx
|
|
7447
|
+
import { Box as Box2, Text as Text2, useStdout } from "ink";
|
|
7448
|
+
import React2 from "react";
|
|
7449
|
+
function ModalCard({
|
|
7450
|
+
accent,
|
|
7451
|
+
title,
|
|
7452
|
+
subtitle,
|
|
7453
|
+
icon,
|
|
7454
|
+
children
|
|
7455
|
+
}) {
|
|
7456
|
+
const { stdout: stdout2 } = useStdout();
|
|
7457
|
+
const cols = stdout2?.columns ?? 80;
|
|
7458
|
+
const ruleWidth = Math.min(80, Math.max(28, cols - 4));
|
|
7459
|
+
const titleText = icon ? ` ${icon} ${title} ` : ` ${title} `;
|
|
7460
|
+
return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: accent }, "\u2594".repeat(ruleWidth))), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { backgroundColor: accent, color: "black", bold: true }, titleText), subtitle ? /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, ` ${subtitle}`) : null), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1, flexDirection: "column" }, children), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: accent, dimColor: true }, "\u2581".repeat(ruleWidth))));
|
|
7461
|
+
}
|
|
7462
|
+
|
|
7463
|
+
// src/cli/ui/Select.tsx
|
|
7444
7464
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
7445
|
-
import
|
|
7465
|
+
import React4, { useState } from "react";
|
|
7466
|
+
|
|
7467
|
+
// src/cli/ui/keystroke-context.tsx
|
|
7468
|
+
import React3, { createContext, useContext, useEffect, useRef } from "react";
|
|
7469
|
+
|
|
7470
|
+
// src/cli/ui/stdin-reader.ts
|
|
7471
|
+
import { stdin } from "process";
|
|
7472
|
+
var ESC_TIMEOUT_MS = 250;
|
|
7473
|
+
var PASTE_END = "\x1B[201~";
|
|
7474
|
+
var PASTE_START_BARE = "[200~";
|
|
7475
|
+
var PASTE_END_BARE = "[201~";
|
|
7476
|
+
var CSI_TAIL_MAP = [
|
|
7477
|
+
{ tail: "A", ev: { input: "", upArrow: true } },
|
|
7478
|
+
{ tail: "B", ev: { input: "", downArrow: true } },
|
|
7479
|
+
{ tail: "C", ev: { input: "", rightArrow: true } },
|
|
7480
|
+
{ tail: "D", ev: { input: "", leftArrow: true } },
|
|
7481
|
+
{ tail: "H", ev: { input: "", home: true } },
|
|
7482
|
+
{ tail: "F", ev: { input: "", end: true } },
|
|
7483
|
+
{ tail: "1~", ev: { input: "", home: true } },
|
|
7484
|
+
{ tail: "4~", ev: { input: "", end: true } },
|
|
7485
|
+
{ tail: "5~", ev: { input: "", pageUp: true } },
|
|
7486
|
+
{ tail: "6~", ev: { input: "", pageDown: true } },
|
|
7487
|
+
{ tail: "3~", ev: { input: "", delete: true } },
|
|
7488
|
+
{ tail: "Z", ev: { input: "", shift: true, tab: true } },
|
|
7489
|
+
// modifyOtherKeys (xterm CSI > 4 ; 2 m) sequences for Enter with
|
|
7490
|
+
// modifiers. Only fired when App.tsx has enabled the mode at
|
|
7491
|
+
// startup; otherwise Shift+Enter stays indistinguishable from Enter.
|
|
7492
|
+
// Modifier encoding: 2=shift, 3=alt, 4=alt+shift, 5=ctrl,
|
|
7493
|
+
// 6=ctrl+shift, 7=ctrl+alt, 8=ctrl+alt+shift. Keycode 13 = Enter.
|
|
7494
|
+
{ tail: "27;2;13~", ev: { input: "", return: true, shift: true } },
|
|
7495
|
+
{ tail: "27;5;13~", ev: { input: "", return: true, ctrl: true } },
|
|
7496
|
+
{ tail: "27;6;13~", ev: { input: "", return: true, ctrl: true, shift: true } },
|
|
7497
|
+
// Kitty keyboard protocol — same idea, different envelope:
|
|
7498
|
+
// `\x1b[<keycode>;<mod>u`. Some terminals (kitty, recent Windows
|
|
7499
|
+
// Terminal previews) prefer this shape. Harmless to map here too.
|
|
7500
|
+
{ tail: "13;2u", ev: { input: "", return: true, shift: true } },
|
|
7501
|
+
{ tail: "13;5u", ev: { input: "", return: true, ctrl: true } },
|
|
7502
|
+
{ tail: "13;6u", ev: { input: "", return: true, ctrl: true, shift: true } }
|
|
7503
|
+
];
|
|
7504
|
+
var SS3_MAP = {
|
|
7505
|
+
A: { input: "", upArrow: true },
|
|
7506
|
+
B: { input: "", downArrow: true },
|
|
7507
|
+
C: { input: "", rightArrow: true },
|
|
7508
|
+
D: { input: "", leftArrow: true },
|
|
7509
|
+
H: { input: "", home: true },
|
|
7510
|
+
F: { input: "", end: true }
|
|
7511
|
+
};
|
|
7512
|
+
function tryEscapelessCsi(chunk, i) {
|
|
7513
|
+
if (chunk[i] !== "[") return null;
|
|
7514
|
+
for (const entry of CSI_TAIL_MAP) {
|
|
7515
|
+
const candidate = `[${entry.tail}`;
|
|
7516
|
+
if (chunk.slice(i, i + candidate.length) === candidate) {
|
|
7517
|
+
return { advance: candidate.length, ev: entry.ev };
|
|
7518
|
+
}
|
|
7519
|
+
}
|
|
7520
|
+
return null;
|
|
7521
|
+
}
|
|
7522
|
+
function isCsiFinal(ch) {
|
|
7523
|
+
const code = ch.charCodeAt(0);
|
|
7524
|
+
return code >= 64 && code <= 126;
|
|
7525
|
+
}
|
|
7526
|
+
function lookupCsi(tail) {
|
|
7527
|
+
for (const entry of CSI_TAIL_MAP) {
|
|
7528
|
+
if (entry.tail === tail) return entry.ev;
|
|
7529
|
+
}
|
|
7530
|
+
return null;
|
|
7531
|
+
}
|
|
7532
|
+
var StdinReader = class {
|
|
7533
|
+
subscribers = /* @__PURE__ */ new Set();
|
|
7534
|
+
state = "idle";
|
|
7535
|
+
/** Buffer for partial sequences across chunks. */
|
|
7536
|
+
csiBuf = "";
|
|
7537
|
+
/** Buffer for paste content. */
|
|
7538
|
+
pasteBuf = "";
|
|
7539
|
+
escTimer = null;
|
|
7540
|
+
started = false;
|
|
7541
|
+
/** The actual `data` listener — kept as a field so `stop()` can detach it. */
|
|
7542
|
+
listener = null;
|
|
7543
|
+
start() {
|
|
7544
|
+
if (this.started) return;
|
|
7545
|
+
if (!stdin.isTTY) {
|
|
7546
|
+
return;
|
|
7547
|
+
}
|
|
7548
|
+
stdin.setRawMode(true);
|
|
7549
|
+
stdin.setEncoding("utf8");
|
|
7550
|
+
stdin.resume();
|
|
7551
|
+
this.listener = (chunk) => this.handleChunk(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
|
|
7552
|
+
stdin.on("data", this.listener);
|
|
7553
|
+
this.started = true;
|
|
7554
|
+
}
|
|
7555
|
+
stop() {
|
|
7556
|
+
if (!this.started) return;
|
|
7557
|
+
if (this.listener) {
|
|
7558
|
+
stdin.off("data", this.listener);
|
|
7559
|
+
this.listener = null;
|
|
7560
|
+
}
|
|
7561
|
+
if (stdin.isTTY) {
|
|
7562
|
+
try {
|
|
7563
|
+
stdin.setRawMode(false);
|
|
7564
|
+
} catch {
|
|
7565
|
+
}
|
|
7566
|
+
}
|
|
7567
|
+
stdin.pause();
|
|
7568
|
+
this.cancelEscTimer();
|
|
7569
|
+
this.state = "idle";
|
|
7570
|
+
this.csiBuf = "";
|
|
7571
|
+
this.pasteBuf = "";
|
|
7572
|
+
this.started = false;
|
|
7573
|
+
}
|
|
7574
|
+
/**
|
|
7575
|
+
* Subscribe to parsed key events. Returns an unsubscribe function.
|
|
7576
|
+
* Multiple subscribers are supported — every event fans out to all
|
|
7577
|
+
* of them; the React Context layer above uses one subscriber and
|
|
7578
|
+
* dispatches further to its own consumer list.
|
|
7579
|
+
*/
|
|
7580
|
+
subscribe(fn) {
|
|
7581
|
+
this.subscribers.add(fn);
|
|
7582
|
+
return () => {
|
|
7583
|
+
this.subscribers.delete(fn);
|
|
7584
|
+
};
|
|
7585
|
+
}
|
|
7586
|
+
/**
|
|
7587
|
+
* Inject a chunk of bytes as if it came from stdin. Used by tests
|
|
7588
|
+
* to drive the parser without a real TTY.
|
|
7589
|
+
*/
|
|
7590
|
+
feed(chunk) {
|
|
7591
|
+
this.handleChunk(chunk);
|
|
7592
|
+
}
|
|
7593
|
+
dispatch(ev) {
|
|
7594
|
+
for (const sub of this.subscribers) sub(ev);
|
|
7595
|
+
}
|
|
7596
|
+
cancelEscTimer() {
|
|
7597
|
+
if (this.escTimer) {
|
|
7598
|
+
clearTimeout(this.escTimer);
|
|
7599
|
+
this.escTimer = null;
|
|
7600
|
+
}
|
|
7601
|
+
}
|
|
7602
|
+
scheduleEscTimer() {
|
|
7603
|
+
this.cancelEscTimer();
|
|
7604
|
+
this.escTimer = setTimeout(() => {
|
|
7605
|
+
if (this.state === "esc") {
|
|
7606
|
+
this.state = "idle";
|
|
7607
|
+
this.dispatch({ input: "", escape: true });
|
|
7608
|
+
}
|
|
7609
|
+
}, ESC_TIMEOUT_MS);
|
|
7610
|
+
}
|
|
7611
|
+
handleChunk(chunk) {
|
|
7612
|
+
this.cancelEscTimer();
|
|
7613
|
+
let i = 0;
|
|
7614
|
+
while (i < chunk.length) {
|
|
7615
|
+
if (this.state === "paste") {
|
|
7616
|
+
const endA = chunk.indexOf(PASTE_END, i);
|
|
7617
|
+
const endB = chunk.indexOf(PASTE_END_BARE, i);
|
|
7618
|
+
let endIdx = -1;
|
|
7619
|
+
let endLen = 0;
|
|
7620
|
+
if (endA !== -1 && (endB === -1 || endA <= endB)) {
|
|
7621
|
+
endIdx = endA;
|
|
7622
|
+
endLen = PASTE_END.length;
|
|
7623
|
+
} else if (endB !== -1) {
|
|
7624
|
+
endIdx = endB;
|
|
7625
|
+
endLen = PASTE_END_BARE.length;
|
|
7626
|
+
}
|
|
7627
|
+
if (endIdx === -1) {
|
|
7628
|
+
this.pasteBuf += chunk.slice(i);
|
|
7629
|
+
i = chunk.length;
|
|
7630
|
+
break;
|
|
7631
|
+
}
|
|
7632
|
+
this.pasteBuf += chunk.slice(i, endIdx);
|
|
7633
|
+
this.dispatch({ input: this.pasteBuf, paste: true });
|
|
7634
|
+
this.pasteBuf = "";
|
|
7635
|
+
this.state = "idle";
|
|
7636
|
+
i = endIdx + endLen;
|
|
7637
|
+
continue;
|
|
7638
|
+
}
|
|
7639
|
+
if (this.state === "csi") {
|
|
7640
|
+
const ch2 = chunk[i];
|
|
7641
|
+
this.csiBuf += ch2;
|
|
7642
|
+
if (isCsiFinal(ch2)) {
|
|
7643
|
+
this.dispatchCsi(this.csiBuf);
|
|
7644
|
+
this.csiBuf = "";
|
|
7645
|
+
if (this.state === "csi") this.state = "idle";
|
|
7646
|
+
}
|
|
7647
|
+
i++;
|
|
7648
|
+
continue;
|
|
7649
|
+
}
|
|
7650
|
+
if (this.state === "ss3") {
|
|
7651
|
+
const ev = SS3_MAP[chunk[i]];
|
|
7652
|
+
if (ev) this.dispatch(ev);
|
|
7653
|
+
this.state = "idle";
|
|
7654
|
+
i++;
|
|
7655
|
+
continue;
|
|
7656
|
+
}
|
|
7657
|
+
if (this.state === "esc") {
|
|
7658
|
+
const ch2 = chunk[i];
|
|
7659
|
+
if (ch2 === "[") {
|
|
7660
|
+
this.state = "csi";
|
|
7661
|
+
this.csiBuf = "";
|
|
7662
|
+
i++;
|
|
7663
|
+
continue;
|
|
7664
|
+
}
|
|
7665
|
+
if (ch2 === "O") {
|
|
7666
|
+
this.state = "ss3";
|
|
7667
|
+
i++;
|
|
7668
|
+
continue;
|
|
7669
|
+
}
|
|
7670
|
+
this.dispatch({ input: ch2, meta: true });
|
|
7671
|
+
this.state = "idle";
|
|
7672
|
+
i++;
|
|
7673
|
+
continue;
|
|
7674
|
+
}
|
|
7675
|
+
const ch = chunk[i];
|
|
7676
|
+
if (ch === "\x1B") {
|
|
7677
|
+
this.state = "esc";
|
|
7678
|
+
i++;
|
|
7679
|
+
continue;
|
|
7680
|
+
}
|
|
7681
|
+
if (chunk.slice(i, i + PASTE_START_BARE.length) === PASTE_START_BARE) {
|
|
7682
|
+
this.state = "paste";
|
|
7683
|
+
this.pasteBuf = "";
|
|
7684
|
+
i += PASTE_START_BARE.length;
|
|
7685
|
+
continue;
|
|
7686
|
+
}
|
|
7687
|
+
const escapeless = tryEscapelessCsi(chunk, i);
|
|
7688
|
+
if (escapeless) {
|
|
7689
|
+
this.dispatch(escapeless.ev);
|
|
7690
|
+
i += escapeless.advance;
|
|
7691
|
+
continue;
|
|
7692
|
+
}
|
|
7693
|
+
if (ch === "\r") {
|
|
7694
|
+
this.dispatch({ input: "", return: true });
|
|
7695
|
+
i++;
|
|
7696
|
+
continue;
|
|
7697
|
+
}
|
|
7698
|
+
if (ch === "\n") {
|
|
7699
|
+
this.dispatch({ input: "j", ctrl: true });
|
|
7700
|
+
i++;
|
|
7701
|
+
continue;
|
|
7702
|
+
}
|
|
7703
|
+
if (ch === " ") {
|
|
7704
|
+
this.dispatch({ input: "", tab: true });
|
|
7705
|
+
i++;
|
|
7706
|
+
continue;
|
|
7707
|
+
}
|
|
7708
|
+
if (ch === "\x7F" || ch === "\b") {
|
|
7709
|
+
this.dispatch({ input: "", backspace: true });
|
|
7710
|
+
i++;
|
|
7711
|
+
continue;
|
|
7712
|
+
}
|
|
7713
|
+
if (ch === "") {
|
|
7714
|
+
this.dispatch({ input: "c", ctrl: true });
|
|
7715
|
+
i++;
|
|
7716
|
+
continue;
|
|
7717
|
+
}
|
|
7718
|
+
const code = ch.charCodeAt(0);
|
|
7719
|
+
if (code >= 1 && code <= 26) {
|
|
7720
|
+
const letter = String.fromCharCode(96 + code);
|
|
7721
|
+
this.dispatch({ input: letter, ctrl: true });
|
|
7722
|
+
i++;
|
|
7723
|
+
continue;
|
|
7724
|
+
}
|
|
7725
|
+
let end = i + 1;
|
|
7726
|
+
while (end < chunk.length) {
|
|
7727
|
+
const c = chunk[end];
|
|
7728
|
+
if (c === "\x1B" || c === "\r" || c === "\n" || c === " ") break;
|
|
7729
|
+
if (c === "\x7F" || c === "\b" || c === "") break;
|
|
7730
|
+
const cc = c.charCodeAt(0);
|
|
7731
|
+
if (cc >= 1 && cc <= 26) break;
|
|
7732
|
+
if (c === "[" && tryEscapelessCsi(chunk, end)) break;
|
|
7733
|
+
if (chunk.slice(end, end + PASTE_START_BARE.length) === PASTE_START_BARE) break;
|
|
7734
|
+
end++;
|
|
7735
|
+
}
|
|
7736
|
+
this.dispatch({ input: chunk.slice(i, end) });
|
|
7737
|
+
i = end;
|
|
7738
|
+
}
|
|
7739
|
+
if (this.state === "esc") {
|
|
7740
|
+
this.scheduleEscTimer();
|
|
7741
|
+
}
|
|
7742
|
+
}
|
|
7743
|
+
dispatchCsi(seq) {
|
|
7744
|
+
if (seq === "200~") {
|
|
7745
|
+
this.state = "paste";
|
|
7746
|
+
this.pasteBuf = "";
|
|
7747
|
+
return;
|
|
7748
|
+
}
|
|
7749
|
+
if (seq === "201~") {
|
|
7750
|
+
return;
|
|
7751
|
+
}
|
|
7752
|
+
const ev = lookupCsi(seq);
|
|
7753
|
+
if (ev) this.dispatch(ev);
|
|
7754
|
+
}
|
|
7755
|
+
};
|
|
7756
|
+
var singleton = null;
|
|
7757
|
+
function getStdinReader() {
|
|
7758
|
+
if (!singleton) singleton = new StdinReader();
|
|
7759
|
+
return singleton;
|
|
7760
|
+
}
|
|
7761
|
+
|
|
7762
|
+
// src/cli/ui/keystroke-context.tsx
|
|
7763
|
+
var KeystrokeContext = createContext(null);
|
|
7764
|
+
function KeystrokeProvider({
|
|
7765
|
+
children,
|
|
7766
|
+
reader: providedReader
|
|
7767
|
+
}) {
|
|
7768
|
+
const handlersRef = useRef(/* @__PURE__ */ new Set());
|
|
7769
|
+
const busRef = useRef(null);
|
|
7770
|
+
if (busRef.current === null) {
|
|
7771
|
+
busRef.current = {
|
|
7772
|
+
subscribe(handler) {
|
|
7773
|
+
handlersRef.current.add(handler);
|
|
7774
|
+
return () => {
|
|
7775
|
+
handlersRef.current.delete(handler);
|
|
7776
|
+
};
|
|
7777
|
+
}
|
|
7778
|
+
};
|
|
7779
|
+
}
|
|
7780
|
+
useEffect(() => {
|
|
7781
|
+
const reader = providedReader ?? getStdinReader();
|
|
7782
|
+
reader.start();
|
|
7783
|
+
const unsubscribe = reader.subscribe((ev) => {
|
|
7784
|
+
for (const fn of [...handlersRef.current]) fn(ev);
|
|
7785
|
+
});
|
|
7786
|
+
return () => {
|
|
7787
|
+
unsubscribe();
|
|
7788
|
+
};
|
|
7789
|
+
}, [providedReader]);
|
|
7790
|
+
return /* @__PURE__ */ React3.createElement(KeystrokeContext.Provider, { value: busRef.current }, children);
|
|
7791
|
+
}
|
|
7792
|
+
function useKeystroke(handler, isActive = true) {
|
|
7793
|
+
const bus = useContext(KeystrokeContext);
|
|
7794
|
+
const handlerRef = useRef(handler);
|
|
7795
|
+
handlerRef.current = handler;
|
|
7796
|
+
useEffect(() => {
|
|
7797
|
+
if (!bus || !isActive) return void 0;
|
|
7798
|
+
return bus.subscribe((ev) => handlerRef.current(ev));
|
|
7799
|
+
}, [bus, isActive]);
|
|
7800
|
+
}
|
|
7446
7801
|
|
|
7447
7802
|
// src/cli/ui/Select.tsx
|
|
7448
|
-
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7449
|
-
import React2, { useState } from "react";
|
|
7450
7803
|
function SingleSelect({
|
|
7451
7804
|
items,
|
|
7452
7805
|
initialValue,
|
|
@@ -7459,19 +7812,20 @@ function SingleSelect({
|
|
|
7459
7812
|
items.findIndex((i) => i.value === initialValue && !i.disabled)
|
|
7460
7813
|
);
|
|
7461
7814
|
const [index, setIndex] = useState(initialIndex === -1 ? 0 : initialIndex);
|
|
7462
|
-
|
|
7463
|
-
if (
|
|
7815
|
+
useKeystroke((ev) => {
|
|
7816
|
+
if (ev.paste) return;
|
|
7817
|
+
if (ev.upArrow) {
|
|
7464
7818
|
setIndex((i) => findNextEnabled(items, i, -1));
|
|
7465
|
-
} else if (
|
|
7819
|
+
} else if (ev.downArrow) {
|
|
7466
7820
|
setIndex((i) => findNextEnabled(items, i, 1));
|
|
7467
|
-
} else if (
|
|
7821
|
+
} else if (ev.return) {
|
|
7468
7822
|
const chosen = items[index];
|
|
7469
7823
|
if (chosen && !chosen.disabled) onSubmit(chosen.value);
|
|
7470
|
-
} else if (
|
|
7824
|
+
} else if (ev.escape && onCancel) {
|
|
7471
7825
|
onCancel();
|
|
7472
7826
|
}
|
|
7473
7827
|
});
|
|
7474
|
-
return /* @__PURE__ */
|
|
7828
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React4.createElement(
|
|
7475
7829
|
SelectRow,
|
|
7476
7830
|
{
|
|
7477
7831
|
key: item.value,
|
|
@@ -7479,7 +7833,7 @@ function SingleSelect({
|
|
|
7479
7833
|
active: i === index,
|
|
7480
7834
|
marker: i === index ? "\u25B8" : " "
|
|
7481
7835
|
}
|
|
7482
|
-
)), footer ? /* @__PURE__ */
|
|
7836
|
+
)), footer ? /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, footer)) : null);
|
|
7483
7837
|
}
|
|
7484
7838
|
function MultiSelect({
|
|
7485
7839
|
items,
|
|
@@ -7493,12 +7847,13 @@ function MultiSelect({
|
|
|
7493
7847
|
return first === -1 ? 0 : first;
|
|
7494
7848
|
});
|
|
7495
7849
|
const [selected, setSelected] = useState(new Set(initialSelected));
|
|
7496
|
-
|
|
7497
|
-
if (
|
|
7850
|
+
useKeystroke((ev) => {
|
|
7851
|
+
if (ev.paste) return;
|
|
7852
|
+
if (ev.upArrow) {
|
|
7498
7853
|
setIndex((i) => findNextEnabled(items, i, -1));
|
|
7499
|
-
} else if (
|
|
7854
|
+
} else if (ev.downArrow) {
|
|
7500
7855
|
setIndex((i) => findNextEnabled(items, i, 1));
|
|
7501
|
-
} else if (input === " ") {
|
|
7856
|
+
} else if (ev.input === " ") {
|
|
7502
7857
|
const item = items[index];
|
|
7503
7858
|
if (!item || item.disabled) return;
|
|
7504
7859
|
setSelected((prev) => {
|
|
@@ -7507,17 +7862,17 @@ function MultiSelect({
|
|
|
7507
7862
|
else next.add(item.value);
|
|
7508
7863
|
return next;
|
|
7509
7864
|
});
|
|
7510
|
-
} else if (
|
|
7865
|
+
} else if (ev.return) {
|
|
7511
7866
|
const ordered = items.filter((i) => selected.has(i.value)).map((i) => i.value);
|
|
7512
7867
|
onSubmit(ordered);
|
|
7513
|
-
} else if (
|
|
7868
|
+
} else if (ev.escape && onCancel) {
|
|
7514
7869
|
onCancel();
|
|
7515
7870
|
}
|
|
7516
7871
|
});
|
|
7517
|
-
return /* @__PURE__ */
|
|
7872
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, items.map((item, i) => {
|
|
7518
7873
|
const checked = selected.has(item.value);
|
|
7519
7874
|
const marker = checked ? "[x]" : "[ ]";
|
|
7520
|
-
return /* @__PURE__ */
|
|
7875
|
+
return /* @__PURE__ */ React4.createElement(
|
|
7521
7876
|
SelectRow,
|
|
7522
7877
|
{
|
|
7523
7878
|
key: item.value,
|
|
@@ -7526,7 +7881,7 @@ function MultiSelect({
|
|
|
7526
7881
|
marker: `${i === index ? "\u25B8" : " "} ${marker}`
|
|
7527
7882
|
}
|
|
7528
7883
|
);
|
|
7529
|
-
}), footer ? /* @__PURE__ */
|
|
7884
|
+
}), footer ? /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, footer)) : null);
|
|
7530
7885
|
}
|
|
7531
7886
|
function SelectRow({
|
|
7532
7887
|
item,
|
|
@@ -7534,7 +7889,7 @@ function SelectRow({
|
|
|
7534
7889
|
marker
|
|
7535
7890
|
}) {
|
|
7536
7891
|
const color = item.disabled ? "gray" : active ? "cyan" : void 0;
|
|
7537
|
-
return /* @__PURE__ */
|
|
7892
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React4.createElement(Box3, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, item.hint)) : null);
|
|
7538
7893
|
}
|
|
7539
7894
|
function findNextEnabled(items, from, step) {
|
|
7540
7895
|
if (items.length === 0) return 0;
|
|
@@ -7567,7 +7922,7 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
|
|
|
7567
7922
|
label: "Cancel \u2014 drop the question",
|
|
7568
7923
|
hint: "Model stops and asks what you want instead."
|
|
7569
7924
|
});
|
|
7570
|
-
return /* @__PURE__ */
|
|
7925
|
+
return /* @__PURE__ */ React5.createElement(ModalCard, { accent: "#f0abfc", icon: "\u{1F500}", title: "model wants you to pick", subtitle: question }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(
|
|
7571
7926
|
SingleSelect,
|
|
7572
7927
|
{
|
|
7573
7928
|
initialValue: options[0]?.id,
|
|
@@ -7582,11 +7937,11 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
|
|
|
7582
7937
|
}
|
|
7583
7938
|
)));
|
|
7584
7939
|
}
|
|
7585
|
-
var ChoiceConfirm =
|
|
7940
|
+
var ChoiceConfirm = React5.memo(ChoiceConfirmInner);
|
|
7586
7941
|
|
|
7587
7942
|
// src/cli/ui/EditConfirm.tsx
|
|
7588
|
-
import { Box as
|
|
7589
|
-
import
|
|
7943
|
+
import { Box as Box5, Text as Text4, useStdout as useStdout2 } from "ink";
|
|
7944
|
+
import React6, { useMemo, useState as useState2 } from "react";
|
|
7590
7945
|
|
|
7591
7946
|
// src/code/diff-preview.ts
|
|
7592
7947
|
function formatEditBlockDiff(block, opts = {}) {
|
|
@@ -7661,7 +8016,7 @@ function capLines(lines, maxLines, indent) {
|
|
|
7661
8016
|
var MODAL_OVERHEAD_ROWS = 18;
|
|
7662
8017
|
var MIN_DIFF_ROWS = 8;
|
|
7663
8018
|
function EditConfirm({ block, onChoose }) {
|
|
7664
|
-
const { stdout: stdout2 } =
|
|
8019
|
+
const { stdout: stdout2 } = useStdout2();
|
|
7665
8020
|
const rows = stdout2?.rows ?? 40;
|
|
7666
8021
|
const budget = Math.max(MIN_DIFF_ROWS, rows - MODAL_OVERHEAD_ROWS);
|
|
7667
8022
|
const allLines = useMemo(
|
|
@@ -7671,7 +8026,10 @@ function EditConfirm({ block, onChoose }) {
|
|
|
7671
8026
|
const [scroll, setScroll] = useState2(0);
|
|
7672
8027
|
const maxScroll = Math.max(0, allLines.length - budget);
|
|
7673
8028
|
const effectiveScroll = Math.min(scroll, maxScroll);
|
|
7674
|
-
|
|
8029
|
+
useKeystroke((ev) => {
|
|
8030
|
+
if (ev.paste) return;
|
|
8031
|
+
const input = ev.input;
|
|
8032
|
+
const key = ev;
|
|
7675
8033
|
if (key.return || input === "y") {
|
|
7676
8034
|
onChoose("apply");
|
|
7677
8035
|
return;
|
|
@@ -7722,57 +8080,75 @@ function EditConfirm({ block, onChoose }) {
|
|
|
7722
8080
|
const hiddenBelow = Math.max(0, allLines.length - effectiveScroll - budget);
|
|
7723
8081
|
const totalLines = allLines.length;
|
|
7724
8082
|
const showScrollHud = hiddenAbove + hiddenBelow > 0;
|
|
7725
|
-
|
|
7726
|
-
|
|
8083
|
+
const subtitleParts = [`-${removed} +${added} lines`];
|
|
8084
|
+
if (showScrollHud) {
|
|
8085
|
+
subtitleParts.push(
|
|
8086
|
+
`viewing ${effectiveScroll + 1}-${effectiveScroll + visibleLines.length}/${totalLines}`
|
|
8087
|
+
);
|
|
8088
|
+
}
|
|
8089
|
+
return /* @__PURE__ */ React6.createElement(
|
|
8090
|
+
ModalCard,
|
|
7727
8091
|
{
|
|
7728
|
-
|
|
8092
|
+
accent: isNew ? "#86efac" : "#fcd34d",
|
|
8093
|
+
icon: isNew ? "\u271A" : "\u270E",
|
|
8094
|
+
title: `${tag} ${block.path}`,
|
|
8095
|
+
subtitle: subtitleParts.join(" \xB7 ")
|
|
7729
8096
|
},
|
|
7730
|
-
|
|
7731
|
-
) : null, /* @__PURE__ */ React4.createElement(Box4, { marginTop: hiddenAbove > 0 ? 0 : 1, flexDirection: "column" }, visibleLines.map((line, i) => {
|
|
7732
|
-
const trimmed = line.trimStart();
|
|
7733
|
-
const color = trimmed.startsWith("+") ? "green" : trimmed.startsWith("-") ? "red" : void 0;
|
|
7734
|
-
const dim = !color;
|
|
7735
|
-
return /* @__PURE__ */ React4.createElement(
|
|
8097
|
+
hiddenAbove > 0 ? /* @__PURE__ */ React6.createElement(
|
|
7736
8098
|
Text4,
|
|
7737
8099
|
{
|
|
7738
|
-
|
|
7739
|
-
color,
|
|
7740
|
-
dimColor: dim
|
|
8100
|
+
dimColor: true
|
|
7741
8101
|
},
|
|
7742
|
-
line
|
|
7743
|
-
)
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
8102
|
+
` \u2191 ${hiddenAbove} line${hiddenAbove === 1 ? "" : "s"} above (\u2191/k or PgUp)`
|
|
8103
|
+
) : null,
|
|
8104
|
+
/* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, visibleLines.map((line, i) => {
|
|
8105
|
+
const trimmed = line.trimStart();
|
|
8106
|
+
const color = trimmed.startsWith("+") ? "#4ade80" : trimmed.startsWith("-") ? "#f87171" : void 0;
|
|
8107
|
+
const dim = !color;
|
|
8108
|
+
return /* @__PURE__ */ React6.createElement(
|
|
8109
|
+
Text4,
|
|
8110
|
+
{
|
|
8111
|
+
key: `diff-${effectiveScroll}-${i}`,
|
|
8112
|
+
color,
|
|
8113
|
+
dimColor: dim
|
|
8114
|
+
},
|
|
8115
|
+
line
|
|
8116
|
+
);
|
|
8117
|
+
})),
|
|
8118
|
+
hiddenBelow > 0 ? /* @__PURE__ */ React6.createElement(
|
|
8119
|
+
Text4,
|
|
8120
|
+
{
|
|
8121
|
+
dimColor: true
|
|
8122
|
+
},
|
|
8123
|
+
` \u2193 ${hiddenBelow} line${hiddenBelow === 1 ? "" : "s"} below (\u2193/j or Space/PgDn)`
|
|
8124
|
+
) : null,
|
|
8125
|
+
/* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text4, { dimColor: true }, "[", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "y"), "/Enter] apply \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "n"), "] reject \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "a"), "] apply rest \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "A"), "] flip AUTO \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "\u2191\u2193/Space"), "] scroll \xB7 [Esc] abort"))
|
|
8126
|
+
);
|
|
7751
8127
|
}
|
|
7752
8128
|
|
|
7753
8129
|
// src/cli/ui/EventLog.tsx
|
|
7754
|
-
import { Box as
|
|
7755
|
-
import
|
|
8130
|
+
import { Box as Box9, Text as Text8, useStdout as useStdout3 } from "ink";
|
|
8131
|
+
import React11 from "react";
|
|
7756
8132
|
|
|
7757
8133
|
// src/cli/ui/PlanStateBlock.tsx
|
|
7758
|
-
import { Box as
|
|
7759
|
-
import
|
|
8134
|
+
import { Box as Box6, Text as Text5 } from "ink";
|
|
8135
|
+
import React7 from "react";
|
|
7760
8136
|
function PlanStateBlock({ planState }) {
|
|
7761
8137
|
const fields = [];
|
|
7762
|
-
if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "
|
|
8138
|
+
if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "#67e8f9", false]);
|
|
7763
8139
|
if (planState.hypotheses.length)
|
|
7764
|
-
fields.push(["hypotheses", planState.hypotheses, "
|
|
8140
|
+
fields.push(["hypotheses", planState.hypotheses, "#86efac", false]);
|
|
7765
8141
|
if (planState.uncertainties.length)
|
|
7766
|
-
fields.push(["uncertainties", planState.uncertainties, "
|
|
8142
|
+
fields.push(["uncertainties", planState.uncertainties, "#fcd34d", false]);
|
|
7767
8143
|
if (planState.rejectedPaths.length)
|
|
7768
|
-
fields.push(["rejected", planState.rejectedPaths, "
|
|
8144
|
+
fields.push(["rejected", planState.rejectedPaths, "#94a3b8", true]);
|
|
7769
8145
|
if (fields.length === 0) return null;
|
|
7770
|
-
return /* @__PURE__ */
|
|
8146
|
+
return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React7.createElement(Box6, { key: label }, /* @__PURE__ */ React7.createElement(Text5, { backgroundColor: color, color: "black", bold: true, dimColor: dim }, ` ${label} ${items.length} `), /* @__PURE__ */ React7.createElement(Text5, null, " "), /* @__PURE__ */ React7.createElement(Text5, { dimColor: dim }, items.join(" \xB7 ")))));
|
|
7771
8147
|
}
|
|
7772
8148
|
|
|
7773
8149
|
// src/cli/ui/PlanStepList.tsx
|
|
7774
|
-
import { Box as
|
|
7775
|
-
import
|
|
8150
|
+
import { Box as Box7, Text as Text6 } from "ink";
|
|
8151
|
+
import React8 from "react";
|
|
7776
8152
|
function riskDots(risk) {
|
|
7777
8153
|
switch (risk) {
|
|
7778
8154
|
case "high":
|
|
@@ -7785,18 +8161,6 @@ function riskDots(risk) {
|
|
|
7785
8161
|
return { dots: " ", color: "gray" };
|
|
7786
8162
|
}
|
|
7787
8163
|
}
|
|
7788
|
-
function statusGlyph(status2) {
|
|
7789
|
-
switch (status2) {
|
|
7790
|
-
case "done":
|
|
7791
|
-
return { glyph: "\u2713", color: "green" };
|
|
7792
|
-
case "running":
|
|
7793
|
-
return { glyph: "\u25B6", color: "cyan" };
|
|
7794
|
-
case "skipped":
|
|
7795
|
-
return { glyph: "\u2014", color: "gray" };
|
|
7796
|
-
default:
|
|
7797
|
-
return { glyph: " ", color: "yellow" };
|
|
7798
|
-
}
|
|
7799
|
-
}
|
|
7800
8164
|
function getStatus(stepId, statuses) {
|
|
7801
8165
|
if (!statuses) return "pending";
|
|
7802
8166
|
if (statuses instanceof Map) {
|
|
@@ -7811,25 +8175,37 @@ function PlanStepListInner({ steps, statuses, focusStepId }) {
|
|
|
7811
8175
|
{ length: steps.length },
|
|
7812
8176
|
(_, i) => getStatus(steps[i].id, statuses)
|
|
7813
8177
|
).filter((s) => s === "done").length;
|
|
7814
|
-
|
|
8178
|
+
const pct2 = Math.round(doneCount / steps.length * 100);
|
|
8179
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, `${steps.length} step${steps.length === 1 ? "" : "s"}`, doneCount > 0 ? ` \xB7 ${doneCount}/${steps.length} done (${pct2}%)` : "", hasAnyRisk ? " \xB7 risk: " : ""), hasAnyRisk ? /* @__PURE__ */ React8.createElement(RiskLegend, null) : null), /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", marginTop: 1 }, steps.map((step) => {
|
|
7815
8180
|
const status2 = getStatus(step.id, statuses);
|
|
7816
8181
|
const focus = focusStepId === step.id;
|
|
7817
8182
|
const risk = riskDots(step.risk);
|
|
7818
|
-
const glyph = statusGlyph(status2);
|
|
7819
8183
|
const titleDim = status2 === "done" || status2 === "skipped";
|
|
7820
|
-
return /* @__PURE__ */
|
|
8184
|
+
return /* @__PURE__ */ React8.createElement(Box7, { key: step.id }, /* @__PURE__ */ React8.createElement(Text6, { color: focus ? "#67e8f9" : "gray", bold: focus }, focus ? "\u25B8 " : " "), /* @__PURE__ */ React8.createElement(Text6, { color: risk.color, bold: true }, risk.dots), /* @__PURE__ */ React8.createElement(Text6, null, " "), /* @__PURE__ */ React8.createElement(StatusBadge, { status: status2 }), /* @__PURE__ */ React8.createElement(Text6, null, " "), /* @__PURE__ */ React8.createElement(Text6, { dimColor: titleDim, bold: focus }, `${step.id} \xB7 ${step.title}`));
|
|
7821
8185
|
})));
|
|
7822
8186
|
}
|
|
8187
|
+
function StatusBadge({ status: status2 }) {
|
|
8188
|
+
switch (status2) {
|
|
8189
|
+
case "done":
|
|
8190
|
+
return /* @__PURE__ */ React8.createElement(Text6, { backgroundColor: "#4ade80", color: "black", bold: true }, " \u2713 DONE ");
|
|
8191
|
+
case "running":
|
|
8192
|
+
return /* @__PURE__ */ React8.createElement(Text6, { backgroundColor: "#67e8f9", color: "black", bold: true }, " \u25B6 RUN ");
|
|
8193
|
+
case "skipped":
|
|
8194
|
+
return /* @__PURE__ */ React8.createElement(Text6, { backgroundColor: "#94a3b8", color: "black", bold: true }, " \u2014 SKIP ");
|
|
8195
|
+
default:
|
|
8196
|
+
return /* @__PURE__ */ React8.createElement(Text6, { color: "#94a3b8", dimColor: true }, " \u2610 PEND ");
|
|
8197
|
+
}
|
|
8198
|
+
}
|
|
7823
8199
|
function RiskLegend() {
|
|
7824
|
-
return /* @__PURE__ */
|
|
8200
|
+
return /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text6, { color: "green" }, "\u25CF"), /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, " low "), /* @__PURE__ */ React8.createElement(Text6, { color: "yellow" }, "\u25CF\u25CF"), /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, " med "), /* @__PURE__ */ React8.createElement(Text6, { color: "red" }, "\u25CF\u25CF\u25CF"), /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, " high"));
|
|
7825
8201
|
}
|
|
7826
|
-
var PlanStepList =
|
|
8202
|
+
var PlanStepList = React8.memo(PlanStepListInner);
|
|
7827
8203
|
|
|
7828
8204
|
// src/cli/ui/markdown.tsx
|
|
7829
8205
|
import { readFileSync as readFileSync13, statSync as statSync6 } from "fs";
|
|
7830
8206
|
import { isAbsolute as isAbsolute4, join as join11 } from "path";
|
|
7831
|
-
import { Box as
|
|
7832
|
-
import
|
|
8207
|
+
import { Box as Box8, Text as Text7 } from "ink";
|
|
8208
|
+
import React9 from "react";
|
|
7833
8209
|
var SUPERSCRIPT = {
|
|
7834
8210
|
"0": "\u2070",
|
|
7835
8211
|
"1": "\xB9",
|
|
@@ -8084,67 +8460,67 @@ function InlineMd({
|
|
|
8084
8460
|
for (const m of text.matchAll(INLINE_RE)) {
|
|
8085
8461
|
const start = m.index ?? 0;
|
|
8086
8462
|
if (start > last) {
|
|
8087
|
-
parts.push(/* @__PURE__ */
|
|
8463
|
+
parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `t${idx++}` }, text.slice(last, start)));
|
|
8088
8464
|
}
|
|
8089
8465
|
if (m[2] !== void 0 && m[3] !== void 0) {
|
|
8090
8466
|
const linkText = m[2];
|
|
8091
8467
|
const url = m[3];
|
|
8092
8468
|
if (isExternalUrl(url)) {
|
|
8093
8469
|
parts.push(
|
|
8094
|
-
/* @__PURE__ */
|
|
8470
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
|
|
8095
8471
|
);
|
|
8096
8472
|
} else {
|
|
8097
8473
|
const status2 = citations?.get(url);
|
|
8098
8474
|
if (status2 && !status2.ok) {
|
|
8099
8475
|
parts.push(
|
|
8100
|
-
/* @__PURE__ */
|
|
8476
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
|
|
8101
8477
|
);
|
|
8102
8478
|
} else {
|
|
8103
8479
|
parts.push(
|
|
8104
|
-
/* @__PURE__ */
|
|
8480
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
|
|
8105
8481
|
);
|
|
8106
8482
|
}
|
|
8107
8483
|
}
|
|
8108
8484
|
} else if (m[4] !== void 0) {
|
|
8109
8485
|
parts.push(
|
|
8110
|
-
/* @__PURE__ */
|
|
8486
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
|
|
8111
8487
|
);
|
|
8112
8488
|
} else if (m[5] !== void 0) {
|
|
8113
8489
|
parts.push(
|
|
8114
|
-
/* @__PURE__ */
|
|
8490
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `b${idx++}`, bold: true }, m[5])
|
|
8115
8491
|
);
|
|
8116
8492
|
} else if (m[6] !== void 0) {
|
|
8117
8493
|
const stripped = m[6].replace(/^(\w+)\s+/, "");
|
|
8118
8494
|
parts.push(
|
|
8119
|
-
/* @__PURE__ */
|
|
8495
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, stripped)
|
|
8120
8496
|
);
|
|
8121
8497
|
} else if (m[7] !== void 0) {
|
|
8122
8498
|
parts.push(
|
|
8123
|
-
/* @__PURE__ */
|
|
8499
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, m[7])
|
|
8124
8500
|
);
|
|
8125
8501
|
} else if (m[8] !== void 0) {
|
|
8126
8502
|
parts.push(
|
|
8127
|
-
/* @__PURE__ */
|
|
8503
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
|
|
8128
8504
|
);
|
|
8129
8505
|
} else if (m[9] !== void 0) {
|
|
8130
8506
|
parts.push(
|
|
8131
|
-
/* @__PURE__ */
|
|
8507
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `i${idx++}`, italic: true }, m[9])
|
|
8132
8508
|
);
|
|
8133
8509
|
} else if (m[10] !== void 0) {
|
|
8134
|
-
parts.push(/* @__PURE__ */
|
|
8510
|
+
parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `esc${idx++}` }, m[10]));
|
|
8135
8511
|
}
|
|
8136
8512
|
last = start + m[0].length;
|
|
8137
8513
|
}
|
|
8138
8514
|
if (last < text.length) {
|
|
8139
|
-
parts.push(/* @__PURE__ */
|
|
8515
|
+
parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `t${idx++}` }, text.slice(last)));
|
|
8140
8516
|
}
|
|
8141
8517
|
if (padTo !== void 0) {
|
|
8142
8518
|
const seen = visibleWidth(text);
|
|
8143
8519
|
if (seen < padTo) {
|
|
8144
|
-
parts.push(/* @__PURE__ */
|
|
8520
|
+
parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
|
|
8145
8521
|
}
|
|
8146
8522
|
}
|
|
8147
|
-
return /* @__PURE__ */
|
|
8523
|
+
return /* @__PURE__ */ React9.createElement(Text7, null, parts);
|
|
8148
8524
|
}
|
|
8149
8525
|
function stripInlineMarkup(s) {
|
|
8150
8526
|
return s.replace(
|
|
@@ -8383,34 +8759,34 @@ function parseBulletItem(raw) {
|
|
|
8383
8759
|
function BlockView({ block, citations }) {
|
|
8384
8760
|
switch (block.kind) {
|
|
8385
8761
|
case "heading":
|
|
8386
|
-
return /* @__PURE__ */
|
|
8762
|
+
return /* @__PURE__ */ React9.createElement(HeadingView, { level: block.level, text: block.text, citations });
|
|
8387
8763
|
case "paragraph":
|
|
8388
|
-
return /* @__PURE__ */
|
|
8764
|
+
return /* @__PURE__ */ React9.createElement(ParagraphView, { text: block.text, citations });
|
|
8389
8765
|
case "bullet":
|
|
8390
|
-
return /* @__PURE__ */
|
|
8766
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React9.createElement(Box8, { key: `${i}-${item.text.slice(0, 24)}` }, /* @__PURE__ */ React9.createElement(Text7, { color: item.task === "done" ? "green" : "cyan" }, bulletPrefix(block, i, item)), item.task === "done" ? /* @__PURE__ */ React9.createElement(Text7, { strikethrough: true, dimColor: true }, /* @__PURE__ */ React9.createElement(InlineMd, { text: item.text, citations })) : /* @__PURE__ */ React9.createElement(InlineMd, { text: item.text, citations }))));
|
|
8391
8767
|
case "quote":
|
|
8392
|
-
return /* @__PURE__ */
|
|
8768
|
+
return /* @__PURE__ */ React9.createElement(BlockquoteView, { block, citations });
|
|
8393
8769
|
case "code":
|
|
8394
8770
|
if (DIAGRAM_LANGS.has(block.lang.toLowerCase())) {
|
|
8395
|
-
return /* @__PURE__ */
|
|
8771
|
+
return /* @__PURE__ */ React9.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
|
|
8396
8772
|
}
|
|
8397
|
-
return /* @__PURE__ */
|
|
8773
|
+
return /* @__PURE__ */ React9.createElement(CodeBlockView, { lang: block.lang, text: block.text });
|
|
8398
8774
|
case "edit-block":
|
|
8399
|
-
return /* @__PURE__ */
|
|
8775
|
+
return /* @__PURE__ */ React9.createElement(EditBlockRow, { block });
|
|
8400
8776
|
case "table":
|
|
8401
|
-
return /* @__PURE__ */
|
|
8777
|
+
return /* @__PURE__ */ React9.createElement(TableBlockRow, { block, citations });
|
|
8402
8778
|
case "hr":
|
|
8403
|
-
return /* @__PURE__ */
|
|
8779
|
+
return /* @__PURE__ */ React9.createElement(Text7, { 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");
|
|
8404
8780
|
}
|
|
8405
8781
|
}
|
|
8406
8782
|
function ParagraphView({ text, citations }) {
|
|
8407
8783
|
if (!text.includes("\n")) {
|
|
8408
|
-
return /* @__PURE__ */
|
|
8784
|
+
return /* @__PURE__ */ React9.createElement(InlineMd, { text, citations });
|
|
8409
8785
|
}
|
|
8410
8786
|
const rows = text.split("\n");
|
|
8411
|
-
return /* @__PURE__ */
|
|
8787
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, rows.map((row2, i) => (
|
|
8412
8788
|
// biome-ignore lint/suspicious/noArrayIndexKey: hard-break rows are source-ordered and never reorder
|
|
8413
|
-
/* @__PURE__ */
|
|
8789
|
+
/* @__PURE__ */ React9.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
|
|
8414
8790
|
)));
|
|
8415
8791
|
}
|
|
8416
8792
|
function bulletPrefix(block, i, item) {
|
|
@@ -8423,12 +8799,11 @@ function BlockquoteView({
|
|
|
8423
8799
|
block,
|
|
8424
8800
|
citations
|
|
8425
8801
|
}) {
|
|
8426
|
-
return /* @__PURE__ */
|
|
8427
|
-
|
|
8802
|
+
return /* @__PURE__ */ React9.createElement(
|
|
8803
|
+
Box8,
|
|
8428
8804
|
{
|
|
8429
8805
|
borderStyle: "single",
|
|
8430
|
-
borderColor: "
|
|
8431
|
-
borderDimColor: true,
|
|
8806
|
+
borderColor: "#c4b5fd",
|
|
8432
8807
|
borderTop: false,
|
|
8433
8808
|
borderRight: false,
|
|
8434
8809
|
borderBottom: false,
|
|
@@ -8436,7 +8811,7 @@ function BlockquoteView({
|
|
|
8436
8811
|
flexDirection: "column",
|
|
8437
8812
|
gap: 1
|
|
8438
8813
|
},
|
|
8439
|
-
block.children.map((child, i) => /* @__PURE__ */
|
|
8814
|
+
block.children.map((child, i) => /* @__PURE__ */ React9.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
|
|
8440
8815
|
);
|
|
8441
8816
|
}
|
|
8442
8817
|
function splitTableRow(line) {
|
|
@@ -8454,14 +8829,14 @@ function TableBlockRow({ block, citations }) {
|
|
|
8454
8829
|
widths.push(Math.min(40, Math.max(3, ...cellLengths)));
|
|
8455
8830
|
}
|
|
8456
8831
|
const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
|
|
8457
|
-
return /* @__PURE__ */
|
|
8832
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box8, null, block.header.map((cell, ci) => (
|
|
8458
8833
|
// biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
|
|
8459
|
-
/* @__PURE__ */
|
|
8460
|
-
))), /* @__PURE__ */
|
|
8834
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React9.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
8835
|
+
))), /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, separator), block.rows.map((row2, ri) => (
|
|
8461
8836
|
// biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
|
|
8462
|
-
/* @__PURE__ */
|
|
8837
|
+
/* @__PURE__ */ React9.createElement(Box8, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
|
|
8463
8838
|
// biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
|
|
8464
|
-
/* @__PURE__ */
|
|
8839
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React9.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
8465
8840
|
)))
|
|
8466
8841
|
)));
|
|
8467
8842
|
}
|
|
@@ -8481,7 +8856,7 @@ function EditBlockRow({ block }) {
|
|
|
8481
8856
|
const isNewFile = block.search.length === 0;
|
|
8482
8857
|
const searchLines = block.search.split("\n");
|
|
8483
8858
|
const replaceLines = block.replace.split("\n");
|
|
8484
|
-
return /* @__PURE__ */
|
|
8859
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text7, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React9.createElement(Text7, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React9.createElement(Text7, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React9.createElement(Text7, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
|
|
8485
8860
|
}
|
|
8486
8861
|
var DIAGRAM_LANGS = /* @__PURE__ */ new Set([
|
|
8487
8862
|
"mermaid",
|
|
@@ -8501,43 +8876,137 @@ var DIAGRAM_VIEWER_HINT = {
|
|
|
8501
8876
|
dot: "\u2192 paste at https://dreampuf.github.io/GraphvizOnline to view",
|
|
8502
8877
|
graphviz: "\u2192 paste at https://dreampuf.github.io/GraphvizOnline to view"
|
|
8503
8878
|
};
|
|
8879
|
+
function HeadingView({
|
|
8880
|
+
level,
|
|
8881
|
+
text,
|
|
8882
|
+
citations
|
|
8883
|
+
}) {
|
|
8884
|
+
if (level === 1) {
|
|
8885
|
+
return /* @__PURE__ */ React9.createElement(Box8, { marginY: 1 }, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#67e8f9", color: "black", bold: true }, ` ${text} `));
|
|
8886
|
+
}
|
|
8887
|
+
if (level === 2) {
|
|
8888
|
+
return /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` ${text} `));
|
|
8889
|
+
}
|
|
8890
|
+
if (level === 3) {
|
|
8891
|
+
return /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#f0abfc", color: "black", bold: true }, ` ${text} `));
|
|
8892
|
+
}
|
|
8893
|
+
return /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { bold: true, color: "#f0abfc" }, "\u25B8", " "), /* @__PURE__ */ React9.createElement(Text7, { bold: true }, /* @__PURE__ */ React9.createElement(InlineMd, { text, citations })));
|
|
8894
|
+
}
|
|
8895
|
+
function CodeBlockView({ lang, text }) {
|
|
8896
|
+
const langLabel = lang.trim();
|
|
8897
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "#7dd3fc", paddingX: 1 }, langLabel ? /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#7dd3fc", color: "black", bold: true }, ` ${langLabel} `)) : null, /* @__PURE__ */ React9.createElement(Text7, { color: "#fde68a" }, text));
|
|
8898
|
+
}
|
|
8504
8899
|
function DiagramCodeBlock({ lang, text }) {
|
|
8505
8900
|
const hint = DIAGRAM_VIEWER_HINT[lang.toLowerCase()] ?? "\u2192 render with the matching viewer to view";
|
|
8506
|
-
return /* @__PURE__ */
|
|
8901
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text7, { bold: true, color: "magenta" }, `\u25C7 ${lang} diagram (source \u2014 terminal can't draw the graph)`), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { color: "yellow" }, text)), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, hint)));
|
|
8507
8902
|
}
|
|
8508
8903
|
function Markdown({ text, projectRoot }) {
|
|
8509
8904
|
const cleaned = expandAutolinks(expandEmoji(stripMath(text)));
|
|
8510
8905
|
const root = projectRoot ?? process.cwd();
|
|
8511
|
-
const citations =
|
|
8512
|
-
const blocks =
|
|
8906
|
+
const citations = React9.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
|
|
8907
|
+
const blocks = React9.useMemo(() => parseBlocks(cleaned), [cleaned]);
|
|
8513
8908
|
const broken = [];
|
|
8514
8909
|
for (const [url, status2] of citations) {
|
|
8515
8910
|
if (!status2.ok) broken.push({ url, reason: status2.reason });
|
|
8516
8911
|
}
|
|
8517
|
-
return /* @__PURE__ */
|
|
8912
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React9.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React9.createElement(BrokenCitationsBlock, { items: broken }) : null);
|
|
8518
8913
|
}
|
|
8519
8914
|
function BrokenCitationsBlock({ items }) {
|
|
8520
|
-
return /* @__PURE__ */
|
|
8915
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text7, { 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) => (
|
|
8521
8916
|
// biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
|
|
8522
|
-
/* @__PURE__ */
|
|
8917
|
+
/* @__PURE__ */ React9.createElement(Text7, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
|
|
8523
8918
|
)));
|
|
8524
8919
|
}
|
|
8525
8920
|
|
|
8921
|
+
// src/cli/ui/theme.ts
|
|
8922
|
+
var GRADIENT = [
|
|
8923
|
+
"#5eead4",
|
|
8924
|
+
// teal
|
|
8925
|
+
"#67e8f9",
|
|
8926
|
+
// cyan
|
|
8927
|
+
"#7dd3fc",
|
|
8928
|
+
// sky
|
|
8929
|
+
"#93c5fd",
|
|
8930
|
+
// blue
|
|
8931
|
+
"#a5b4fc",
|
|
8932
|
+
// indigo
|
|
8933
|
+
"#c4b5fd",
|
|
8934
|
+
// violet
|
|
8935
|
+
"#d8b4fe",
|
|
8936
|
+
// purple
|
|
8937
|
+
"#f0abfc"
|
|
8938
|
+
// fuchsia
|
|
8939
|
+
];
|
|
8940
|
+
var COLOR = {
|
|
8941
|
+
primary: "#67e8f9",
|
|
8942
|
+
// cyan-300
|
|
8943
|
+
accent: "#c4b5fd",
|
|
8944
|
+
// violet-300
|
|
8945
|
+
brand: "#5eead4",
|
|
8946
|
+
// teal-300
|
|
8947
|
+
user: "#67e8f9",
|
|
8948
|
+
// user message glyph + bar
|
|
8949
|
+
assistant: "#86efac",
|
|
8950
|
+
// green-300, assistant glyph + bar
|
|
8951
|
+
tool: "#fcd34d",
|
|
8952
|
+
// amber-300, tool ok pill bg
|
|
8953
|
+
toolErr: "#fda4af",
|
|
8954
|
+
// rose-300, tool err pill bg
|
|
8955
|
+
info: "#94a3b8",
|
|
8956
|
+
// slate-400, info / dim
|
|
8957
|
+
warn: "#fbbf24",
|
|
8958
|
+
// amber-400
|
|
8959
|
+
err: "#f87171",
|
|
8960
|
+
// red-400
|
|
8961
|
+
ok: "#4ade80"
|
|
8962
|
+
// green-400
|
|
8963
|
+
};
|
|
8964
|
+
var GLYPH = {
|
|
8965
|
+
brand: "\u25C8",
|
|
8966
|
+
user: "\u25C7",
|
|
8967
|
+
assistant: "\u25C6",
|
|
8968
|
+
toolOk: "\u25A3",
|
|
8969
|
+
toolErr: "\u25A5",
|
|
8970
|
+
warn: "\u25B2",
|
|
8971
|
+
err: "\u2726",
|
|
8972
|
+
arrow: "\u203A",
|
|
8973
|
+
bullet: "\xB7",
|
|
8974
|
+
bar: "\u258E",
|
|
8975
|
+
thinBar: "\u258F",
|
|
8976
|
+
block: "\u2588",
|
|
8977
|
+
shade1: "\u2591",
|
|
8978
|
+
shade2: "\u2592",
|
|
8979
|
+
shade3: "\u2593"
|
|
8980
|
+
};
|
|
8981
|
+
function gradientCells(width, glyph = GLYPH.block) {
|
|
8982
|
+
const cells = [];
|
|
8983
|
+
if (width <= 0) return cells;
|
|
8984
|
+
const last = GRADIENT.length - 1;
|
|
8985
|
+
for (let i = 0; i < width; i++) {
|
|
8986
|
+
const t = width === 1 ? 0 : i * last / (width - 1);
|
|
8987
|
+
const lo = Math.floor(t);
|
|
8988
|
+
const hi = Math.min(last, lo + 1);
|
|
8989
|
+
const color = t - lo < 0.5 ? GRADIENT[lo] : GRADIENT[hi];
|
|
8990
|
+
cells.push({ ch: glyph, color });
|
|
8991
|
+
}
|
|
8992
|
+
return cells;
|
|
8993
|
+
}
|
|
8994
|
+
|
|
8526
8995
|
// src/cli/ui/ticker.tsx
|
|
8527
|
-
import
|
|
8996
|
+
import React10, { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState3 } from "react";
|
|
8528
8997
|
var TICK_MS = 120;
|
|
8529
|
-
var TickContext =
|
|
8998
|
+
var TickContext = createContext2(0);
|
|
8530
8999
|
function TickerProvider({ children, disabled }) {
|
|
8531
9000
|
const [tick, setTick] = useState3(0);
|
|
8532
|
-
|
|
9001
|
+
useEffect2(() => {
|
|
8533
9002
|
if (disabled) return;
|
|
8534
9003
|
const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
|
|
8535
9004
|
return () => clearInterval(id);
|
|
8536
9005
|
}, [disabled]);
|
|
8537
|
-
return /* @__PURE__ */
|
|
9006
|
+
return /* @__PURE__ */ React10.createElement(TickContext.Provider, { value: tick }, children);
|
|
8538
9007
|
}
|
|
8539
9008
|
function useTick() {
|
|
8540
|
-
return
|
|
9009
|
+
return useContext2(TickContext);
|
|
8541
9010
|
}
|
|
8542
9011
|
function useElapsedSeconds() {
|
|
8543
9012
|
const [start] = useState3(() => Date.now());
|
|
@@ -8687,51 +9156,105 @@ function RoleGlyph({
|
|
|
8687
9156
|
glyph,
|
|
8688
9157
|
color
|
|
8689
9158
|
}) {
|
|
8690
|
-
return /* @__PURE__ */
|
|
9159
|
+
return /* @__PURE__ */ React11.createElement(Text8, { color, bold: true }, glyph);
|
|
9160
|
+
}
|
|
9161
|
+
function ToolPill({ label, status: status2 }) {
|
|
9162
|
+
const bg = status2 === "err" ? "red" : "yellow";
|
|
9163
|
+
const symbol = status2 === "err" ? "\u2717" : "\u2713";
|
|
9164
|
+
return /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: bg, color: "black", bold: true }, ` ${symbol} ${label} `);
|
|
8691
9165
|
}
|
|
8692
9166
|
function indentContinuationLines(text) {
|
|
8693
9167
|
if (!text.includes("\n")) return text;
|
|
8694
9168
|
return text.split("\n").join("\n ");
|
|
8695
9169
|
}
|
|
8696
|
-
var EventRow =
|
|
9170
|
+
var EventRow = React11.memo(function EventRow2({
|
|
8697
9171
|
event,
|
|
8698
9172
|
projectRoot
|
|
8699
9173
|
}) {
|
|
8700
9174
|
if (event.role === "user") {
|
|
8701
|
-
return /* @__PURE__ */
|
|
9175
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column" }, event.leadSeparator ? /* @__PURE__ */ React11.createElement(TurnSeparator, null) : null, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(
|
|
9176
|
+
Box9,
|
|
9177
|
+
{
|
|
9178
|
+
flexDirection: "column",
|
|
9179
|
+
borderStyle: "single",
|
|
9180
|
+
borderTop: false,
|
|
9181
|
+
borderRight: false,
|
|
9182
|
+
borderBottom: false,
|
|
9183
|
+
borderColor: COLOR.user,
|
|
9184
|
+
paddingLeft: 1
|
|
9185
|
+
},
|
|
9186
|
+
/* @__PURE__ */ React11.createElement(Text8, null, indentContinuationLines(event.text))
|
|
9187
|
+
)));
|
|
8702
9188
|
}
|
|
8703
9189
|
if (event.role === "assistant") {
|
|
8704
|
-
if (event.streaming) return /* @__PURE__ */
|
|
8705
|
-
return /* @__PURE__ */
|
|
9190
|
+
if (event.streaming) return /* @__PURE__ */ React11.createElement(StreamingAssistant, { event });
|
|
9191
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: COLOR.assistant, color: "black", bold: true }, ` ${event.stats.model.replace(/^deepseek-/, "")} `)) : null), /* @__PURE__ */ React11.createElement(
|
|
9192
|
+
Box9,
|
|
9193
|
+
{
|
|
9194
|
+
flexDirection: "column",
|
|
9195
|
+
marginTop: 1,
|
|
9196
|
+
borderStyle: "single",
|
|
9197
|
+
borderTop: false,
|
|
9198
|
+
borderRight: false,
|
|
9199
|
+
borderBottom: false,
|
|
9200
|
+
borderColor: COLOR.assistant,
|
|
9201
|
+
paddingLeft: 1
|
|
9202
|
+
},
|
|
9203
|
+
event.branch ? /* @__PURE__ */ React11.createElement(BranchBlock, { branch: event.branch }) : null,
|
|
9204
|
+
event.reasoning ? /* @__PURE__ */ React11.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null,
|
|
9205
|
+
!isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React11.createElement(PlanStateBlock, { planState: event.planState }) : null,
|
|
9206
|
+
event.text ? /* @__PURE__ */ React11.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, "(no content)"),
|
|
9207
|
+
event.stats ? /* @__PURE__ */ React11.createElement(StatsLine, { stats: event.stats }) : null,
|
|
9208
|
+
event.repair ? /* @__PURE__ */ React11.createElement(Text8, { color: COLOR.accent }, event.repair) : null
|
|
9209
|
+
));
|
|
8706
9210
|
}
|
|
8707
9211
|
if (event.role === "tool") {
|
|
8708
9212
|
const isExplicitError = event.text.startsWith("ERROR:");
|
|
8709
9213
|
const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isExplicitError;
|
|
8710
9214
|
if (isEditFile) {
|
|
8711
|
-
return /* @__PURE__ */
|
|
9215
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(ToolPill, { label: event.toolName ?? "?", status: "ok" }), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " diff:")), /* @__PURE__ */ React11.createElement(
|
|
9216
|
+
Box9,
|
|
9217
|
+
{
|
|
9218
|
+
flexDirection: "column",
|
|
9219
|
+
marginTop: 1,
|
|
9220
|
+
borderStyle: "single",
|
|
9221
|
+
borderTop: false,
|
|
9222
|
+
borderRight: false,
|
|
9223
|
+
borderBottom: false,
|
|
9224
|
+
borderColor: COLOR.tool,
|
|
9225
|
+
paddingLeft: 1
|
|
9226
|
+
},
|
|
9227
|
+
/* @__PURE__ */ React11.createElement(EditFileDiff, { text: event.text })
|
|
9228
|
+
));
|
|
8712
9229
|
}
|
|
8713
9230
|
const summary = summarizeToolResult(event.toolName ?? "?", event.text);
|
|
8714
|
-
const
|
|
8715
|
-
const
|
|
8716
|
-
const marker = summary.isError ? "\u2717" : "\u2192";
|
|
8717
|
-
const durationLabel = event.durationMs !== void 0 && event.durationMs >= 100 ? ` (${formatDuration(event.durationMs)})` : "";
|
|
9231
|
+
const status2 = summary.isError ? "err" : "ok";
|
|
9232
|
+
const durationLabel = event.durationMs !== void 0 && event.durationMs >= 100 ? formatDuration(event.durationMs) : "";
|
|
8718
9233
|
const indexHint = event.toolIndex !== void 0 ? ` /tool ${event.toolIndex}` : "";
|
|
8719
|
-
return /* @__PURE__ */
|
|
9234
|
+
return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(ToolPill, { label: event.toolName ?? "?", status: status2 }), durationLabel ? /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` ${durationLabel}`) : null, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " "), /* @__PURE__ */ React11.createElement(Text8, { color: status2 === "err" ? "red" : void 0, dimColor: status2 === "ok" }, summary.summary), indexHint ? /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, indexHint) : null);
|
|
8720
9235
|
}
|
|
8721
9236
|
if (event.role === "error") {
|
|
8722
|
-
return /* @__PURE__ */
|
|
9237
|
+
return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#f87171", color: "black", bold: true }, " \u2726 ERROR "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#f87171" }, indentContinuationLines(event.text)));
|
|
8723
9238
|
}
|
|
8724
9239
|
if (event.role === "info") {
|
|
8725
|
-
|
|
9240
|
+
const m = event.text.match(/^([▸▶▲⚠✓✗✖↻ⓘ])\s*(.*)$/s);
|
|
9241
|
+
const lead = m?.[1] ?? "\u25B8";
|
|
9242
|
+
const body = m?.[2] ?? event.text;
|
|
9243
|
+
let leadColor = COLOR.info;
|
|
9244
|
+
if (lead === "\u25B2" || lead === "\u26A0") leadColor = COLOR.warn;
|
|
9245
|
+
else if (lead === "\u2713") leadColor = COLOR.ok;
|
|
9246
|
+
else if (lead === "\u2717" || lead === "\u2716") leadColor = COLOR.err;
|
|
9247
|
+
else if (lead === "\u21BB") leadColor = COLOR.primary;
|
|
9248
|
+
return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { color: leadColor, bold: true }, lead), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, body));
|
|
8726
9249
|
}
|
|
8727
9250
|
if (event.role === "plan") {
|
|
8728
|
-
return /* @__PURE__ */
|
|
9251
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { bold: true, color: "cyan" }, "\u{1F4CB} plan proposed \u2014 pick a choice below")), /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Markdown, { text: event.text, projectRoot })));
|
|
8729
9252
|
}
|
|
8730
9253
|
if (event.role === "step-progress") {
|
|
8731
9254
|
const sp = event.stepProgress;
|
|
8732
|
-
const counter = sp && sp.total > 0 ?
|
|
9255
|
+
const counter = sp && sp.total > 0 ? `${sp.completed}/${sp.total}` : "";
|
|
8733
9256
|
const label = sp?.title ? `${sp.stepId} \xB7 ${sp.title}` : sp?.stepId ?? "";
|
|
8734
|
-
return /* @__PURE__ */
|
|
9257
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#4ade80", color: "black", bold: true }, " \u2713 STEP "), counter ? /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#4ade80", bold: true }, counter)) : null, /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#86efac" }, label)), event.text ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, event.text)) : null, sp?.notes ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24", dimColor: true }, `note: ${sp.notes}`)) : null);
|
|
8735
9258
|
}
|
|
8736
9259
|
if (event.role === "plan-resumed") {
|
|
8737
9260
|
const rp = event.resumedPlan;
|
|
@@ -8746,7 +9269,7 @@ var EventRow = React9.memo(function EventRow2({
|
|
|
8746
9269
|
])
|
|
8747
9270
|
);
|
|
8748
9271
|
const nextStep = rp.steps.find((s) => !completedSet.has(s.id));
|
|
8749
|
-
return /* @__PURE__ */
|
|
9272
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#67e8f9", color: "black", bold: true }, " \u21BB RESUMED PLAN "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#67e8f9", bold: true }, `${done}/${total}`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` done \xB7 last touched ${rp.relativeTime}`)), rp.summary ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#67e8f9" }, rp.summary)) : null, /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(PlanStepList, { steps: rp.steps, statuses, focusStepId: nextStep?.id })));
|
|
8750
9273
|
}
|
|
8751
9274
|
if (event.role === "plan-replay") {
|
|
8752
9275
|
const r = event.replayPlan;
|
|
@@ -8757,67 +9280,79 @@ var EventRow = React9.memo(function EventRow2({
|
|
|
8757
9280
|
const statuses = new Map(
|
|
8758
9281
|
r.steps.map((s) => [s.id, completedSet.has(s.id) ? "done" : "pending"])
|
|
8759
9282
|
);
|
|
8760
|
-
const navHint = r.total > 1 ? `
|
|
8761
|
-
return /* @__PURE__ */
|
|
8762
|
-
Text8,
|
|
8763
|
-
{
|
|
8764
|
-
dimColor: true
|
|
8765
|
-
},
|
|
8766
|
-
` completed ${r.relativeTime} \xB7 ${done}/${total} done${navHint}`
|
|
8767
|
-
)), r.summary ? /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${r.summary}`)) : null, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${r.archiveBasename}`))), r.body ? /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Markdown, { text: r.body, projectRoot })) : null, /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(PlanStepList, { steps: r.steps, statuses })), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { 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)")));
|
|
9283
|
+
const navHint = r.total > 1 ? ` \xB7 ${r.index}/${r.total}` : "";
|
|
9284
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#94a3b8", color: "black", bold: true }, " \u23EA REPLAY "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#94a3b8", bold: true }, `${done}/${total}`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` done \xB7 ${r.relativeTime}${navHint}`)), r.summary ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#94a3b8" }, r.summary)) : null, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, r.archiveBasename)), r.body ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Markdown, { text: r.body, projectRoot })) : null, /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(PlanStepList, { steps: r.steps, statuses })), /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { 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)")));
|
|
8768
9285
|
}
|
|
8769
9286
|
if (event.role === "warning") {
|
|
8770
|
-
return /* @__PURE__ */
|
|
9287
|
+
return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#fbbf24", color: "black", bold: true }, " \u25B2 WARN "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24" }, indentContinuationLines(event.text)));
|
|
8771
9288
|
}
|
|
8772
|
-
return /* @__PURE__ */
|
|
9289
|
+
return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, null, event.text));
|
|
8773
9290
|
});
|
|
9291
|
+
function TurnSeparator() {
|
|
9292
|
+
const { stdout: stdout2 } = useStdout3();
|
|
9293
|
+
const cols = stdout2?.columns ?? 80;
|
|
9294
|
+
const width = Math.max(16, cols - 2);
|
|
9295
|
+
const sideWidth = Math.max(2, Math.floor((width - 5) / 2));
|
|
9296
|
+
const leftCells = gradientCells(sideWidth, "\u2500");
|
|
9297
|
+
const rightCells = gradientCells(sideWidth, "\u2500");
|
|
9298
|
+
return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, marginBottom: 1 }, leftCells.map((c, i) => (
|
|
9299
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row
|
|
9300
|
+
/* @__PURE__ */ React11.createElement(Text8, { key: `tsep-l-${i}`, color: c.color }, c.ch)
|
|
9301
|
+
)), /* @__PURE__ */ React11.createElement(Text8, { color: COLOR.brand, bold: true }, " \u25C6 "), rightCells.map((c, i) => (
|
|
9302
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row
|
|
9303
|
+
/* @__PURE__ */ React11.createElement(Text8, { key: `tsep-r-${i}`, color: c.color }, c.ch)
|
|
9304
|
+
)));
|
|
9305
|
+
}
|
|
8774
9306
|
function EditFileDiff({ text }) {
|
|
8775
9307
|
const lines = text.split(/\r?\n/);
|
|
8776
9308
|
const [statusHeader, hunkHeader, ...body] = lines;
|
|
8777
|
-
return /* @__PURE__ */
|
|
9309
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` ${hunkHeader.trim()} `)) : null, body.map((line, i) => {
|
|
8778
9310
|
const key = `${i}-${line.slice(0, 32)}`;
|
|
8779
|
-
|
|
8780
|
-
|
|
9311
|
+
const stripped = line.replace(/^ {2}/, "");
|
|
9312
|
+
if (stripped.startsWith("- ")) {
|
|
9313
|
+
return /* @__PURE__ */ React11.createElement(Box9, { key }, /* @__PURE__ */ React11.createElement(Text8, { color: "#f87171", bold: true }, "\u2212 "), /* @__PURE__ */ React11.createElement(Text8, { color: "#fca5a5" }, stripped.slice(2)));
|
|
8781
9314
|
}
|
|
8782
|
-
if (
|
|
8783
|
-
return /* @__PURE__ */
|
|
9315
|
+
if (stripped.startsWith("+ ")) {
|
|
9316
|
+
return /* @__PURE__ */ React11.createElement(Box9, { key }, /* @__PURE__ */ React11.createElement(Text8, { color: "#4ade80", bold: true }, "+ "), /* @__PURE__ */ React11.createElement(Text8, { color: "#86efac" }, stripped.slice(2)));
|
|
8784
9317
|
}
|
|
8785
|
-
return /* @__PURE__ */
|
|
9318
|
+
return /* @__PURE__ */ React11.createElement(Box9, { key }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " "), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, stripped));
|
|
8786
9319
|
}));
|
|
8787
9320
|
}
|
|
8788
9321
|
function BranchBlock({ branch: branch2 }) {
|
|
8789
|
-
|
|
8790
|
-
const
|
|
9322
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#93c5fd", color: "black", bold: true }, ` \u2387 BRANCH \xD7${branch2.budget} `), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#93c5fd" }, "picked "), /* @__PURE__ */ React11.createElement(Text8, { color: "#93c5fd", bold: true }, "#", branch2.chosenIndex)), /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2, marginTop: 1 }, branch2.uncertainties.map((u, i) => {
|
|
9323
|
+
const chosen = i === branch2.chosenIndex;
|
|
8791
9324
|
const t = (branch2.temperatures[i] ?? 0).toFixed(1);
|
|
8792
|
-
return
|
|
8793
|
-
|
|
8794
|
-
|
|
9325
|
+
return (
|
|
9326
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: branch index is positional and stable
|
|
9327
|
+
/* @__PURE__ */ React11.createElement(Text8, { key: `b-${i}` }, /* @__PURE__ */ React11.createElement(Text8, { color: chosen ? "#93c5fd" : "#475569", bold: chosen }, chosen ? "\u25B8 " : " "), /* @__PURE__ */ React11.createElement(Text8, { color: chosen ? "#93c5fd" : "#94a3b8", bold: chosen }, `#${i}`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` T=${t} u=${u} `))
|
|
9328
|
+
);
|
|
9329
|
+
})));
|
|
8795
9330
|
}
|
|
8796
9331
|
function ReasoningBlock({ reasoning }) {
|
|
8797
9332
|
const max = 260;
|
|
8798
9333
|
const flat = reasoning.replace(/\s+/g, " ").trim();
|
|
8799
9334
|
const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
|
|
8800
|
-
return /* @__PURE__ */
|
|
9335
|
+
return /* @__PURE__ */ React11.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: COLOR.accent, color: "black", bold: true }, " \u22EF thinking "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: COLOR.accent, italic: true, dimColor: true }, preview));
|
|
8801
9336
|
}
|
|
8802
9337
|
function Elapsed() {
|
|
8803
9338
|
const s = useElapsedSeconds();
|
|
8804
9339
|
const mm = String(Math.floor(s / 60)).padStart(2, "0");
|
|
8805
9340
|
const ss = String(s % 60).padStart(2, "0");
|
|
8806
|
-
return /* @__PURE__ */
|
|
9341
|
+
return /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, `${mm}:${ss}`);
|
|
8807
9342
|
}
|
|
8808
9343
|
function PulsingAssistantGlyph() {
|
|
8809
9344
|
const tick = useTick();
|
|
8810
9345
|
const on = Math.floor(tick / 4) % 2 === 0;
|
|
8811
|
-
return /* @__PURE__ */
|
|
9346
|
+
return /* @__PURE__ */ React11.createElement(Text8, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
|
|
8812
9347
|
}
|
|
8813
9348
|
function StreamingAssistant({ event }) {
|
|
8814
9349
|
if (event.branchProgress) {
|
|
8815
9350
|
const p = event.branchProgress;
|
|
8816
9351
|
if (p.completed === 0) {
|
|
8817
|
-
return /* @__PURE__ */
|
|
9352
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React11.createElement(Text8, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React11.createElement(Elapsed, null)), /* @__PURE__ */ React11.createElement(Text8, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
|
|
8818
9353
|
}
|
|
8819
9354
|
const pct2 = Math.round(p.completed / p.total * 100);
|
|
8820
|
-
return /* @__PURE__ */
|
|
9355
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React11.createElement(Text8, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React11.createElement(Elapsed, null)), /* @__PURE__ */ React11.createElement(Text8, { 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"));
|
|
8821
9356
|
}
|
|
8822
9357
|
const tail = lastLine(event.text, 140);
|
|
8823
9358
|
const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
|
|
@@ -8825,38 +9360,43 @@ function StreamingAssistant({ event }) {
|
|
|
8825
9360
|
const preFirstByte = !event.text && !event.reasoning && !toolCallBuild;
|
|
8826
9361
|
const reasoningOnly = !event.text && !!event.reasoning && !toolCallBuild;
|
|
8827
9362
|
const toolCallOnly = !event.text && !event.reasoning && !!toolCallBuild;
|
|
9363
|
+
let pillBg;
|
|
9364
|
+
let pillText;
|
|
8828
9365
|
let label;
|
|
8829
|
-
let labelColor;
|
|
8830
9366
|
if (preFirstByte) {
|
|
9367
|
+
pillBg = "#fbbf24";
|
|
9368
|
+
pillText = "WAITING";
|
|
8831
9369
|
label = "request sent \xB7 waiting for server";
|
|
8832
|
-
labelColor = "yellow";
|
|
8833
9370
|
} else if (reasoningOnly) {
|
|
8834
|
-
|
|
8835
|
-
|
|
9371
|
+
pillBg = "#c4b5fd";
|
|
9372
|
+
pillText = "THINKING";
|
|
9373
|
+
label = `${event.reasoning?.length ?? 0} chars of thought`;
|
|
8836
9374
|
} else if (toolCallOnly) {
|
|
8837
|
-
|
|
8838
|
-
|
|
9375
|
+
pillBg = "#f0abfc";
|
|
9376
|
+
pillText = "DISPATCH";
|
|
9377
|
+
label = `assembling${formatToolCallIndex(toolCallBuild)} <${toolCallBuild.name}> \xB7 ${toolCallBuild.chars} chars${formatReadyTail(toolCallBuild)}`;
|
|
8839
9378
|
} else {
|
|
8840
|
-
|
|
8841
|
-
|
|
9379
|
+
pillBg = "#86efac";
|
|
9380
|
+
pillText = "WRITING";
|
|
9381
|
+
const parts = [`${event.text.length} chars`];
|
|
9382
|
+
if (event.reasoning) parts.push(`after ${event.reasoning.length} reasoning`);
|
|
8842
9383
|
if (toolCallBuild) {
|
|
8843
9384
|
parts.push(
|
|
8844
|
-
`
|
|
9385
|
+
`tool${formatToolCallIndex(toolCallBuild)} <${toolCallBuild.name}> ${toolCallBuild.chars}c${formatReadyTail(toolCallBuild)}`
|
|
8845
9386
|
);
|
|
8846
9387
|
}
|
|
8847
9388
|
label = parts.join(" \xB7 ");
|
|
8848
|
-
labelColor = "green";
|
|
8849
9389
|
}
|
|
8850
|
-
return /* @__PURE__ */
|
|
8851
|
-
// Non-dim
|
|
9390
|
+
return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Pulse, null), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: pillBg, color: "black", bold: true }, ` ${pillText} `), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` ${label} `), /* @__PURE__ */ React11.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#c4b5fd", italic: true, dimColor: true }, "\u21B3 ", reasoningTail)) : null, tail ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, "\u25B8 ", tail)) : preFirstByte ? (
|
|
9391
|
+
// Non-dim amber: first-time users misread the dim version as
|
|
8852
9392
|
// "app frozen". The reassurance has to be VISIBLE to do its job.
|
|
8853
|
-
/* @__PURE__ */
|
|
8854
|
-
) : reasoningOnly ? /* @__PURE__ */
|
|
9393
|
+
/* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24", italic: true }, "waiting for first byte \u2014 typical 5\u201360s depending on model + load"))
|
|
9394
|
+
) : reasoningOnly ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#c4b5fd", italic: true }, "R1 thinks before it speaks \u2014 body text arrives when reasoning finishes (20\u201390s)")) : toolCallOnly ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#f0abfc", italic: true }, "tool-call arguments streaming \u2014 about to dispatch")) : event.reasoning ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24", italic: true }, "R1 still reasoning \u2014 body text or tool call arrives when thinking finishes")) : null);
|
|
8855
9395
|
}
|
|
8856
9396
|
function Pulse() {
|
|
8857
9397
|
const tick = useTick();
|
|
8858
9398
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8859
|
-
return /* @__PURE__ */
|
|
9399
|
+
return /* @__PURE__ */ React11.createElement(Text8, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
|
|
8860
9400
|
}
|
|
8861
9401
|
function formatToolCallIndex(tb) {
|
|
8862
9402
|
if (!tb || tb.index === void 0) return "";
|
|
@@ -8875,17 +9415,18 @@ function lastLine(s, maxChars) {
|
|
|
8875
9415
|
}
|
|
8876
9416
|
function StatsLine({ stats: stats2 }) {
|
|
8877
9417
|
const hit = (stats2.cacheHitRatio * 100).toFixed(1);
|
|
8878
|
-
|
|
9418
|
+
const hitColor = stats2.cacheHitRatio >= 0.7 ? "#4ade80" : stats2.cacheHitRatio >= 0.4 ? "#fcd34d" : "#f87171";
|
|
9419
|
+
return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { color: hitColor, bold: true }, `\u232C ${hit}%`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React11.createElement(Text8, { color: "#94a3b8" }, "in ", /* @__PURE__ */ React11.createElement(Text8, { color: "#67e8f9", bold: true }, stats2.usage.promptTokens), " \u2192 out ", /* @__PURE__ */ React11.createElement(Text8, { color: "#c4b5fd", bold: true }, stats2.usage.completionTokens)), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React11.createElement(Text8, { color: "#86efac", bold: true }, `$${stats2.cost.toFixed(6)}`));
|
|
8879
9420
|
}
|
|
8880
9421
|
|
|
8881
9422
|
// src/cli/ui/LiveRows.tsx
|
|
8882
|
-
import { Box as
|
|
8883
|
-
import
|
|
9423
|
+
import { Box as Box10, Text as Text9, useStdout as useStdout4 } from "ink";
|
|
9424
|
+
import React12 from "react";
|
|
8884
9425
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8885
9426
|
function StatusRow({ text }) {
|
|
8886
9427
|
const tick = useTick();
|
|
8887
9428
|
const elapsed = useElapsedSeconds();
|
|
8888
|
-
return /* @__PURE__ */
|
|
9429
|
+
return /* @__PURE__ */ React12.createElement(Box10, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text9, null, " "), /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd" }, text), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` \xB7 ${elapsed}s`));
|
|
8889
9430
|
}
|
|
8890
9431
|
function ModeStatusBar({
|
|
8891
9432
|
editMode,
|
|
@@ -8897,15 +9438,28 @@ function ModeStatusBar({
|
|
|
8897
9438
|
}) {
|
|
8898
9439
|
useTick();
|
|
8899
9440
|
const running = jobs2?.runningCount() ?? 0;
|
|
8900
|
-
const jobsTag = running > 0 ? /* @__PURE__ */
|
|
9441
|
+
const jobsTag = running > 0 ? /* @__PURE__ */ React12.createElement(Text9, { color: "yellow", bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
|
|
8901
9442
|
if (planMode) {
|
|
8902
|
-
return /* @__PURE__ */
|
|
9443
|
+
return /* @__PURE__ */ React12.createElement(ModeBarFrame, null, /* @__PURE__ */ React12.createElement(ModePill, { label: "PLAN MODE", bg: "red", flash }), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, " writes gated \xB7 /plan off to leave"), jobsTag);
|
|
8903
9444
|
}
|
|
8904
|
-
const
|
|
8905
|
-
const
|
|
8906
|
-
const
|
|
8907
|
-
const
|
|
8908
|
-
return /* @__PURE__ */
|
|
9445
|
+
const isAuto = editMode === "auto";
|
|
9446
|
+
const label = isAuto ? "AUTO" : "REVIEW";
|
|
9447
|
+
const bg = isAuto ? "magenta" : "cyan";
|
|
9448
|
+
const mid = isAuto ? "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";
|
|
9449
|
+
return /* @__PURE__ */ React12.createElement(ModeBarFrame, null, /* @__PURE__ */ React12.createElement(ModePill, { label, bg, flash }), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` ${mid} \xB7 Shift+Tab to flip`), jobsTag);
|
|
9450
|
+
}
|
|
9451
|
+
function ModeBarFrame({ children }) {
|
|
9452
|
+
const { stdout: stdout2 } = useStdout4();
|
|
9453
|
+
const cols = stdout2?.columns ?? 80;
|
|
9454
|
+
const ruleWidth = Math.max(20, cols - 2);
|
|
9455
|
+
return /* @__PURE__ */ React12.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#475569", dimColor: true }, "\u254C".repeat(ruleWidth))), /* @__PURE__ */ React12.createElement(Box10, { paddingX: 1 }, children));
|
|
9456
|
+
}
|
|
9457
|
+
function ModePill({
|
|
9458
|
+
label,
|
|
9459
|
+
bg,
|
|
9460
|
+
flash
|
|
9461
|
+
}) {
|
|
9462
|
+
return /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: bg, color: "white", bold: true, inverse: flash }, ` ${label} `);
|
|
8909
9463
|
}
|
|
8910
9464
|
function UndoBanner({
|
|
8911
9465
|
banner
|
|
@@ -8915,14 +9469,15 @@ function UndoBanner({
|
|
|
8915
9469
|
const remainingSec = Math.ceil(remainingMs / 1e3);
|
|
8916
9470
|
const ok = banner.results.filter((r) => r.status === "applied" || r.status === "created").length;
|
|
8917
9471
|
const total = banner.results.length;
|
|
8918
|
-
|
|
9472
|
+
const urgent = remainingSec <= 1;
|
|
9473
|
+
return /* @__PURE__ */ React12.createElement(Box10, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` \u2713 AUTO-APPLIED ${ok}/${total} `), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, " press "), /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#67e8f9", color: "black", bold: true }, " u "), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, " to undo "), /* @__PURE__ */ React12.createElement(Text9, { color: urgent ? "#f87171" : "#c4b5fd", bold: urgent }, `${remainingSec}s`));
|
|
8919
9474
|
}
|
|
8920
9475
|
function SubagentRow({
|
|
8921
9476
|
activity
|
|
8922
9477
|
}) {
|
|
8923
9478
|
const tick = useTick();
|
|
8924
9479
|
const seconds = (activity.elapsedMs / 1e3).toFixed(1);
|
|
8925
|
-
return /* @__PURE__ */
|
|
9480
|
+
return /* @__PURE__ */ React12.createElement(Box10, { paddingLeft: 3 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text9, null, " "), /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#c4b5fd", color: "black", bold: true }, " \u232C subagent "), /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd" }, ` ${activity.task}`), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` iter ${activity.iter} \xB7 ${seconds}s`));
|
|
8926
9481
|
}
|
|
8927
9482
|
function OngoingToolRow({
|
|
8928
9483
|
tool: tool2,
|
|
@@ -8931,7 +9486,7 @@ function OngoingToolRow({
|
|
|
8931
9486
|
const tick = useTick();
|
|
8932
9487
|
const elapsed = useElapsedSeconds();
|
|
8933
9488
|
const summary = summarizeToolArgs(tool2.name, tool2.args);
|
|
8934
|
-
return /* @__PURE__ */
|
|
9489
|
+
return /* @__PURE__ */ React12.createElement(Box10, { marginY: 1, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Box10, null, /* @__PURE__ */ React12.createElement(Text9, { color: "#fcd34d", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text9, null, " "), /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#fcd34d", color: "black", bold: true }, ` \u23F5 ${tool2.name} `), /* @__PURE__ */ React12.createElement(Text9, { color: "#fcd34d" }, " running"), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` \xB7 ${elapsed}s`)), progress ? /* @__PURE__ */ React12.createElement(Box10, { paddingLeft: 3 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#67e8f9" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React12.createElement(Box10, { paddingLeft: 3 }, /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, summary)) : null);
|
|
8935
9490
|
}
|
|
8936
9491
|
function renderProgressLine(p) {
|
|
8937
9492
|
const msg = p.message ? ` ${p.message}` : "";
|
|
@@ -8987,8 +9542,8 @@ function summarizeToolArgs(name, args) {
|
|
|
8987
9542
|
}
|
|
8988
9543
|
|
|
8989
9544
|
// src/cli/ui/PlanCheckpointConfirm.tsx
|
|
8990
|
-
import { Box as
|
|
8991
|
-
import
|
|
9545
|
+
import { Box as Box11 } from "ink";
|
|
9546
|
+
import React13 from "react";
|
|
8992
9547
|
function PlanCheckpointConfirmInner({
|
|
8993
9548
|
stepId,
|
|
8994
9549
|
title,
|
|
@@ -8999,10 +9554,11 @@ function PlanCheckpointConfirmInner({
|
|
|
8999
9554
|
onChoose
|
|
9000
9555
|
}) {
|
|
9001
9556
|
const label = title ? `${stepId} \xB7 ${title}` : stepId;
|
|
9002
|
-
const counter = total > 0 ?
|
|
9557
|
+
const counter = total > 0 ? `${completed}/${total}` : "";
|
|
9003
9558
|
const isLast = total > 0 && completed >= total;
|
|
9004
9559
|
const statuses = buildStatusMap(steps, completedStepIds, stepId, isLast);
|
|
9005
|
-
|
|
9560
|
+
const subtitle = counter ? `${counter} \xB7 ${label}` : label;
|
|
9561
|
+
return /* @__PURE__ */ React13.createElement(ModalCard, { accent: "#86efac", icon: "\u2713", title: "checkpoint \u2014 step done", subtitle }, steps && steps.length > 0 ? /* @__PURE__ */ React13.createElement(Box11, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React13.createElement(
|
|
9006
9562
|
SingleSelect,
|
|
9007
9563
|
{
|
|
9008
9564
|
initialValue: isLast ? "stop" : "continue",
|
|
@@ -9027,9 +9583,9 @@ function PlanCheckpointConfirmInner({
|
|
|
9027
9583
|
onCancel: () => onChoose("stop"),
|
|
9028
9584
|
footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] stop"
|
|
9029
9585
|
}
|
|
9030
|
-
))
|
|
9586
|
+
));
|
|
9031
9587
|
}
|
|
9032
|
-
var PlanCheckpointConfirm =
|
|
9588
|
+
var PlanCheckpointConfirm = React13.memo(PlanCheckpointConfirmInner);
|
|
9033
9589
|
function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
|
|
9034
9590
|
const map = /* @__PURE__ */ new Map();
|
|
9035
9591
|
if (!steps) return map;
|
|
@@ -9046,70 +9602,103 @@ function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
|
|
|
9046
9602
|
}
|
|
9047
9603
|
|
|
9048
9604
|
// src/cli/ui/PlanConfirm.tsx
|
|
9049
|
-
import { Box as
|
|
9050
|
-
import
|
|
9605
|
+
import { Box as Box12, Text as Text10 } from "ink";
|
|
9606
|
+
import React14 from "react";
|
|
9051
9607
|
function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
|
|
9052
9608
|
const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan2) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan2);
|
|
9053
|
-
return /* @__PURE__ */
|
|
9054
|
-
|
|
9609
|
+
return /* @__PURE__ */ React14.createElement(
|
|
9610
|
+
ModalCard,
|
|
9055
9611
|
{
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9612
|
+
accent: "#67e8f9",
|
|
9613
|
+
icon: "\u{1F4CB}",
|
|
9614
|
+
title: "plan proposed",
|
|
9615
|
+
subtitle: summary ?? "approve / refine / cancel"
|
|
9616
|
+
},
|
|
9617
|
+
hasOpenQuestions ? /* @__PURE__ */ React14.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text10, { color: "#fbbf24" }, "\u25B2 the plan flags open questions or risks \u2014 pick", " ", /* @__PURE__ */ React14.createElement(Text10, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null,
|
|
9618
|
+
steps && steps.length > 0 ? /* @__PURE__ */ React14.createElement(Box12, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(PlanStepList, { steps })) : null,
|
|
9619
|
+
/* @__PURE__ */ React14.createElement(
|
|
9620
|
+
SingleSelect,
|
|
9621
|
+
{
|
|
9622
|
+
initialValue: hasOpenQuestions ? "refine" : "approve",
|
|
9623
|
+
items: [
|
|
9624
|
+
{
|
|
9625
|
+
value: "approve",
|
|
9626
|
+
label: "Approve and implement",
|
|
9627
|
+
hint: "Exit plan mode. The model starts executing. You'll get a text input to add any last instructions (or just press Enter to skip)."
|
|
9628
|
+
},
|
|
9629
|
+
{
|
|
9630
|
+
value: "refine",
|
|
9631
|
+
label: "Refine / answer questions",
|
|
9632
|
+
hint: "Stay in plan mode. Write answers, modifications, or critiques; the model revises and re-submits."
|
|
9633
|
+
},
|
|
9634
|
+
{
|
|
9635
|
+
value: "cancel",
|
|
9636
|
+
label: "Cancel",
|
|
9637
|
+
hint: "Exit plan mode. Drop the plan; the model won't implement it."
|
|
9638
|
+
}
|
|
9639
|
+
],
|
|
9640
|
+
onSubmit: (v) => onChoose(v),
|
|
9641
|
+
onCancel: () => onChoose("cancel"),
|
|
9642
|
+
footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] cancel"
|
|
9643
|
+
}
|
|
9644
|
+
)
|
|
9645
|
+
);
|
|
9079
9646
|
}
|
|
9080
|
-
var PlanConfirm =
|
|
9647
|
+
var PlanConfirm = React14.memo(PlanConfirmInner);
|
|
9081
9648
|
|
|
9082
9649
|
// src/cli/ui/PlanRefineInput.tsx
|
|
9083
|
-
import { Box as
|
|
9084
|
-
import
|
|
9650
|
+
import { Box as Box13, Text as Text11 } from "ink";
|
|
9651
|
+
import React15, { useState as useState4 } from "react";
|
|
9085
9652
|
function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
|
|
9086
9653
|
const [value, setValue] = useState4("");
|
|
9087
|
-
|
|
9088
|
-
if (
|
|
9654
|
+
useKeystroke((ev) => {
|
|
9655
|
+
if (ev.paste) {
|
|
9656
|
+
setValue((v) => v + ev.input.replace(/\r?\n/g, " "));
|
|
9657
|
+
return;
|
|
9658
|
+
}
|
|
9659
|
+
if (ev.escape) {
|
|
9089
9660
|
onCancel();
|
|
9090
9661
|
return;
|
|
9091
9662
|
}
|
|
9092
|
-
if (
|
|
9663
|
+
if (ev.return) {
|
|
9093
9664
|
onSubmit(value.trim());
|
|
9094
9665
|
return;
|
|
9095
9666
|
}
|
|
9096
|
-
if (
|
|
9667
|
+
if (ev.backspace || ev.delete) {
|
|
9097
9668
|
setValue((v) => v.slice(0, -1));
|
|
9098
9669
|
return;
|
|
9099
9670
|
}
|
|
9100
|
-
if (input && !
|
|
9101
|
-
setValue((v) => v + input);
|
|
9671
|
+
if (ev.input && !ev.ctrl && !ev.meta) {
|
|
9672
|
+
setValue((v) => v + ev.input);
|
|
9102
9673
|
}
|
|
9103
9674
|
});
|
|
9104
|
-
const
|
|
9105
|
-
const
|
|
9675
|
+
const tick = useTick();
|
|
9676
|
+
const cursorOn = Math.floor(tick / 4) % 2 === 0;
|
|
9677
|
+
const meta = mode2 === "approve" ? {
|
|
9678
|
+
title: "approving \u2014 any last instructions?",
|
|
9679
|
+
icon: "\u{1F4CB}",
|
|
9680
|
+
accent: "#67e8f9"
|
|
9681
|
+
} : mode2 === "checkpoint-revise" ? {
|
|
9682
|
+
title: "revising \u2014 what should change before the next step?",
|
|
9683
|
+
icon: "\u270F",
|
|
9684
|
+
accent: "#fbbf24"
|
|
9685
|
+
} : mode2 === "choice-custom" ? {
|
|
9686
|
+
title: "custom answer \u2014 type whatever fits",
|
|
9687
|
+
icon: "\u{1F500}",
|
|
9688
|
+
accent: "#f0abfc"
|
|
9689
|
+
} : {
|
|
9690
|
+
title: "refining \u2014 what should the model change?",
|
|
9691
|
+
icon: "\u270F",
|
|
9692
|
+
accent: "#fbbf24"
|
|
9693
|
+
};
|
|
9694
|
+
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.";
|
|
9106
9695
|
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.)";
|
|
9107
|
-
return /* @__PURE__ */
|
|
9696
|
+
return /* @__PURE__ */ React15.createElement(ModalCard, { accent: meta.accent, icon: meta.icon, title: meta.title }, /* @__PURE__ */ React15.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text11, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React15.createElement(Box13, null, /* @__PURE__ */ React15.createElement(Text11, { color: meta.accent, bold: true }, "\u203A "), /* @__PURE__ */ React15.createElement(Text11, null, value), /* @__PURE__ */ React15.createElement(Text11, { color: meta.accent, bold: true }, cursorOn ? "\u258D" : " ")));
|
|
9108
9697
|
}
|
|
9109
9698
|
|
|
9110
9699
|
// src/cli/ui/PlanReviseConfirm.tsx
|
|
9111
|
-
import { Box as
|
|
9112
|
-
import
|
|
9700
|
+
import { Box as Box14, Text as Text12 } from "ink";
|
|
9701
|
+
import React16 from "react";
|
|
9113
9702
|
function computeDiff(oldSteps, newSteps) {
|
|
9114
9703
|
const oldIds = new Set(oldSteps.map((s) => s.id));
|
|
9115
9704
|
const newIds = new Set(newSteps.map((s) => s.id));
|
|
@@ -9125,13 +9714,13 @@ function computeDiff(oldSteps, newSteps) {
|
|
|
9125
9714
|
function riskDots2(risk) {
|
|
9126
9715
|
switch (risk) {
|
|
9127
9716
|
case "high":
|
|
9128
|
-
return { dots: "\u25CF\u25CF\u25CF", color: "
|
|
9717
|
+
return { dots: "\u25CF\u25CF\u25CF", color: "#f87171" };
|
|
9129
9718
|
case "med":
|
|
9130
|
-
return { dots: "\u25CF\u25CF ", color: "
|
|
9719
|
+
return { dots: "\u25CF\u25CF ", color: "#fbbf24" };
|
|
9131
9720
|
case "low":
|
|
9132
|
-
return { dots: "\u25CF ", color: "
|
|
9721
|
+
return { dots: "\u25CF ", color: "#4ade80" };
|
|
9133
9722
|
default:
|
|
9134
|
-
return { dots: " ", color: "
|
|
9723
|
+
return { dots: " ", color: "#94a3b8" };
|
|
9135
9724
|
}
|
|
9136
9725
|
}
|
|
9137
9726
|
function PlanReviseConfirmInner({
|
|
@@ -9145,54 +9734,103 @@ function PlanReviseConfirmInner({
|
|
|
9145
9734
|
const removedCount = rows.filter((r) => r.kind === "removed").length;
|
|
9146
9735
|
const addedCount = rows.filter((r) => r.kind === "added").length;
|
|
9147
9736
|
const keptCount = rows.filter((r) => r.kind === "kept").length;
|
|
9148
|
-
return /* @__PURE__ */
|
|
9149
|
-
|
|
9150
|
-
const prefix = row2.kind === "removed" ? "\u2212" : row2.kind === "added" ? "+" : " ";
|
|
9151
|
-
const prefixColor = row2.kind === "removed" ? "red" : row2.kind === "added" ? "green" : "gray";
|
|
9152
|
-
const dim = row2.kind === "kept";
|
|
9153
|
-
const strike = row2.kind === "removed";
|
|
9154
|
-
return /* @__PURE__ */ React14.createElement(Box13, { key: `${row2.kind}-${row2.step.id}` }, /* @__PURE__ */ React14.createElement(Text13, { color: prefixColor, bold: true }, `${prefix} `), /* @__PURE__ */ React14.createElement(Text13, { color: risk.color, bold: true, dimColor: dim }, risk.dots), /* @__PURE__ */ React14.createElement(Text13, { dimColor: dim, strikethrough: strike }, ` ${row2.step.id} \xB7 ${row2.step.title}`));
|
|
9155
|
-
})), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
|
|
9156
|
-
SingleSelect,
|
|
9737
|
+
return /* @__PURE__ */ React16.createElement(
|
|
9738
|
+
ModalCard,
|
|
9157
9739
|
{
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9740
|
+
accent: "#fbbf24",
|
|
9741
|
+
icon: "\u270F",
|
|
9742
|
+
title: "plan revision proposed",
|
|
9743
|
+
subtitle: `\u2212${removedCount} +${addedCount} \xB7 ${keptCount} kept`
|
|
9744
|
+
},
|
|
9745
|
+
/* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text12, null, reason)),
|
|
9746
|
+
summary ? /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text12, { dimColor: true }, `updated summary: ${summary}`)) : null,
|
|
9747
|
+
/* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1, flexDirection: "column" }, rows.map((row2) => {
|
|
9748
|
+
const risk = riskDots2(row2.step.risk);
|
|
9749
|
+
const prefix = row2.kind === "removed" ? "\u2212" : row2.kind === "added" ? "+" : " ";
|
|
9750
|
+
const prefixColor = row2.kind === "removed" ? "#f87171" : row2.kind === "added" ? "#4ade80" : "#94a3b8";
|
|
9751
|
+
const dim = row2.kind === "kept";
|
|
9752
|
+
const strike = row2.kind === "removed";
|
|
9753
|
+
return /* @__PURE__ */ React16.createElement(Box14, { key: `${row2.kind}-${row2.step.id}` }, /* @__PURE__ */ React16.createElement(Text12, { color: prefixColor, bold: true }, `${prefix} `), /* @__PURE__ */ React16.createElement(Text12, { color: risk.color, bold: true, dimColor: dim }, risk.dots), /* @__PURE__ */ React16.createElement(Text12, { dimColor: dim, strikethrough: strike }, ` ${row2.step.id} \xB7 ${row2.step.title}`));
|
|
9754
|
+
})),
|
|
9755
|
+
/* @__PURE__ */ React16.createElement(
|
|
9756
|
+
SingleSelect,
|
|
9757
|
+
{
|
|
9758
|
+
initialValue: "accept",
|
|
9759
|
+
items: [
|
|
9760
|
+
{
|
|
9761
|
+
value: "accept",
|
|
9762
|
+
label: "Accept revision \u2014 apply the new step list",
|
|
9763
|
+
hint: "Replaces the remaining plan with the proposed steps. Done steps are untouched."
|
|
9764
|
+
},
|
|
9765
|
+
{
|
|
9766
|
+
value: "reject",
|
|
9767
|
+
label: "Reject \u2014 keep the original plan",
|
|
9768
|
+
hint: "Drops the proposal. Model continues with the original remaining steps."
|
|
9769
|
+
}
|
|
9770
|
+
],
|
|
9771
|
+
onSubmit: (v) => onChoose(v),
|
|
9772
|
+
onCancel: () => onChoose("reject"),
|
|
9773
|
+
footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] reject"
|
|
9774
|
+
}
|
|
9775
|
+
)
|
|
9776
|
+
);
|
|
9176
9777
|
}
|
|
9177
|
-
var PlanReviseConfirm =
|
|
9778
|
+
var PlanReviseConfirm = React16.memo(PlanReviseConfirmInner);
|
|
9178
9779
|
|
|
9179
9780
|
// src/cli/ui/PromptInput.tsx
|
|
9180
|
-
import { Box as
|
|
9181
|
-
import
|
|
9781
|
+
import { Box as Box15, Text as Text13, useStdout as useStdout5 } from "ink";
|
|
9782
|
+
import React17, { useRef as useRef2, useState as useState5 } from "react";
|
|
9783
|
+
|
|
9784
|
+
// src/cli/ui/key-normalize.ts
|
|
9785
|
+
var CSI_TAIL_TO_FLAGS = [
|
|
9786
|
+
// Arrow keys — the most common ConPTY victim.
|
|
9787
|
+
{ tail: "[A", flags: { upArrow: true } },
|
|
9788
|
+
{ tail: "[B", flags: { downArrow: true } },
|
|
9789
|
+
{ tail: "[C", flags: { rightArrow: true } },
|
|
9790
|
+
{ tail: "[D", flags: { leftArrow: true } },
|
|
9791
|
+
// Page navigation.
|
|
9792
|
+
{ tail: "[5~", flags: { pageUp: true } },
|
|
9793
|
+
{ tail: "[6~", flags: { pageDown: true } },
|
|
9794
|
+
// Forward-delete (the key labelled Delete on most keyboards).
|
|
9795
|
+
{ tail: "[3~", flags: { delete: true } },
|
|
9796
|
+
// Shift+Tab — terminal sends `\x1b[Z` rather than tab-with-shift.
|
|
9797
|
+
{ tail: "[Z", flags: { shift: true, tab: true } }
|
|
9798
|
+
];
|
|
9799
|
+
function alreadyStructured(flags) {
|
|
9800
|
+
return Boolean(
|
|
9801
|
+
flags.upArrow || flags.downArrow || flags.leftArrow || flags.rightArrow || flags.pageUp || flags.pageDown || flags.delete || flags.tab && flags.shift
|
|
9802
|
+
);
|
|
9803
|
+
}
|
|
9804
|
+
function recoverCsiTail(input, existing = {}) {
|
|
9805
|
+
if (alreadyStructured(existing)) return null;
|
|
9806
|
+
for (const entry of CSI_TAIL_TO_FLAGS) {
|
|
9807
|
+
if (input === entry.tail || input === `\x1B${entry.tail}`) {
|
|
9808
|
+
return entry.flags;
|
|
9809
|
+
}
|
|
9810
|
+
}
|
|
9811
|
+
return null;
|
|
9812
|
+
}
|
|
9813
|
+
var STRIPPABLE_CSI_FRAGMENTS = [
|
|
9814
|
+
"\x1B[200~",
|
|
9815
|
+
"\x1B[201~",
|
|
9816
|
+
"[200~",
|
|
9817
|
+
"[201~",
|
|
9818
|
+
...CSI_TAIL_TO_FLAGS.flatMap((e) => [`\x1B${e.tail}`, e.tail])
|
|
9819
|
+
];
|
|
9820
|
+
function stripCsiFragments(input) {
|
|
9821
|
+
let out = input;
|
|
9822
|
+
for (const frag of STRIPPABLE_CSI_FRAGMENTS) {
|
|
9823
|
+
if (out.includes(frag)) out = out.replaceAll(frag, "");
|
|
9824
|
+
}
|
|
9825
|
+
return out;
|
|
9826
|
+
}
|
|
9182
9827
|
|
|
9183
9828
|
// src/cli/ui/multiline-keys.ts
|
|
9184
9829
|
var BACKSLASH_SUFFIX = /\\$/;
|
|
9185
9830
|
var NOOP = { next: null, cursor: null, submit: false };
|
|
9186
|
-
function rewriteRawArrowEscape(key) {
|
|
9187
|
-
if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) return key;
|
|
9188
|
-
if (key.input === "\x1B[A") return { ...key, upArrow: true, input: "" };
|
|
9189
|
-
if (key.input === "\x1B[B") return { ...key, downArrow: true, input: "" };
|
|
9190
|
-
if (key.input === "\x1B[C") return { ...key, rightArrow: true, input: "" };
|
|
9191
|
-
if (key.input === "\x1B[D") return { ...key, leftArrow: true, input: "" };
|
|
9192
|
-
return key;
|
|
9193
|
-
}
|
|
9194
9831
|
function processMultilineKey(value, cursor, keyIn) {
|
|
9195
|
-
const
|
|
9832
|
+
const recovered = recoverCsiTail(keyIn.input, keyIn);
|
|
9833
|
+
const key = recovered ? { ...keyIn, ...recovered, input: "" } : keyIn;
|
|
9196
9834
|
if (key.tab || key.escape) {
|
|
9197
9835
|
return NOOP;
|
|
9198
9836
|
}
|
|
@@ -9239,7 +9877,7 @@ function processMultilineKey(value, cursor, keyIn) {
|
|
|
9239
9877
|
submit: false
|
|
9240
9878
|
};
|
|
9241
9879
|
}
|
|
9242
|
-
const stripped = key.input
|
|
9880
|
+
const stripped = stripCsiFragments(key.input);
|
|
9243
9881
|
const looksLikePaste = stripped.length > 1 && (stripped.includes("\n") || stripped.includes("\r"));
|
|
9244
9882
|
if (looksLikePaste) {
|
|
9245
9883
|
const normalized = stripped.replace(/\r\n?/g, "\n");
|
|
@@ -9383,10 +10021,159 @@ function formatBytesShort(n) {
|
|
|
9383
10021
|
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
9384
10022
|
}
|
|
9385
10023
|
|
|
10024
|
+
// src/cli/ui/prompt-viewport.ts
|
|
10025
|
+
function charCells(ch) {
|
|
10026
|
+
if (ch.length === 0) return 0;
|
|
10027
|
+
const code = ch.charCodeAt(0);
|
|
10028
|
+
if (code < 32 || code === 127) return 0;
|
|
10029
|
+
if (code < 4352) return 1;
|
|
10030
|
+
if (code >= 4352 && code <= 4447) return 2;
|
|
10031
|
+
if (code >= 11904 && code <= 12350) return 2;
|
|
10032
|
+
if (code >= 12353 && code <= 13311) return 2;
|
|
10033
|
+
if (code >= 13312 && code <= 19903) return 2;
|
|
10034
|
+
if (code >= 19968 && code <= 40959) return 2;
|
|
10035
|
+
if (code >= 40960 && code <= 42191) return 2;
|
|
10036
|
+
if (code >= 44032 && code <= 55203) return 2;
|
|
10037
|
+
if (code >= 63744 && code <= 64255) return 2;
|
|
10038
|
+
if (code >= 65072 && code <= 65103) return 2;
|
|
10039
|
+
if (code >= 65280 && code <= 65376) return 2;
|
|
10040
|
+
if (code >= 65504 && code <= 65510) return 2;
|
|
10041
|
+
return 1;
|
|
10042
|
+
}
|
|
10043
|
+
function stringCells(s, pastes) {
|
|
10044
|
+
let n = 0;
|
|
10045
|
+
for (let i = 0; i < s.length; i++) {
|
|
10046
|
+
const ch = s[i];
|
|
10047
|
+
const id = decodePasteSentinel(ch);
|
|
10048
|
+
if (id !== null) {
|
|
10049
|
+
n += pasteSentinelCells(id, pastes);
|
|
10050
|
+
} else {
|
|
10051
|
+
n += charCells(ch);
|
|
10052
|
+
}
|
|
10053
|
+
}
|
|
10054
|
+
return n;
|
|
10055
|
+
}
|
|
10056
|
+
function pasteSentinelLabel(id, entry) {
|
|
10057
|
+
if (!entry) return `[paste #${id + 1} \xB7 (missing)]`;
|
|
10058
|
+
return `[paste #${id + 1} \xB7 ${entry.lineCount}l \xB7 ${formatBytesShort(entry.charCount)}]`;
|
|
10059
|
+
}
|
|
10060
|
+
function pasteSentinelCells(id, pastes) {
|
|
10061
|
+
const entry = pastes?.get(id);
|
|
10062
|
+
return pasteSentinelLabel(id, entry).length;
|
|
10063
|
+
}
|
|
10064
|
+
function buildViewport(line, cursorCol, visibleCells, pastes) {
|
|
10065
|
+
if (visibleCells <= 0) {
|
|
10066
|
+
return {
|
|
10067
|
+
segments: [],
|
|
10068
|
+
cursorCell: cursorCol === null ? null : 0,
|
|
10069
|
+
hiddenLeft: false,
|
|
10070
|
+
hiddenRight: line.length > 0
|
|
10071
|
+
};
|
|
10072
|
+
}
|
|
10073
|
+
const totalCells = stringCells(line, pastes);
|
|
10074
|
+
if (totalCells <= visibleCells) {
|
|
10075
|
+
const segments = textToSegments(line, pastes);
|
|
10076
|
+
let cursorCell = null;
|
|
10077
|
+
if (cursorCol !== null) {
|
|
10078
|
+
cursorCell = stringCells(line.slice(0, cursorCol), pastes);
|
|
10079
|
+
}
|
|
10080
|
+
return { segments, cursorCell, hiddenLeft: false, hiddenRight: false };
|
|
10081
|
+
}
|
|
10082
|
+
if (cursorCol === null) {
|
|
10083
|
+
return clipFromLeft(line, visibleCells, pastes);
|
|
10084
|
+
}
|
|
10085
|
+
return clipAroundCursor(line, cursorCol, visibleCells, pastes);
|
|
10086
|
+
}
|
|
10087
|
+
function clipFromLeft(line, visibleCells, pastes) {
|
|
10088
|
+
const budget = Math.max(1, visibleCells - 1);
|
|
10089
|
+
let used = 0;
|
|
10090
|
+
let end = 0;
|
|
10091
|
+
while (end < line.length) {
|
|
10092
|
+
const ch = line[end];
|
|
10093
|
+
const cw = charCellsAt(line, end, pastes);
|
|
10094
|
+
if (used + cw > budget) break;
|
|
10095
|
+
used += cw;
|
|
10096
|
+
end++;
|
|
10097
|
+
}
|
|
10098
|
+
const segments = textToSegments(line.slice(0, end), pastes);
|
|
10099
|
+
return { segments, cursorCell: null, hiddenLeft: false, hiddenRight: end < line.length };
|
|
10100
|
+
}
|
|
10101
|
+
function clipAroundCursor(line, cursorCol, visibleCells, pastes) {
|
|
10102
|
+
let budget = visibleCells;
|
|
10103
|
+
const reservedForMarkers = 2;
|
|
10104
|
+
budget = Math.max(1, budget - reservedForMarkers);
|
|
10105
|
+
const halfBudget = Math.floor(budget / 2);
|
|
10106
|
+
let start = cursorCol;
|
|
10107
|
+
let leftCells = 0;
|
|
10108
|
+
while (start > 0 && leftCells < halfBudget) {
|
|
10109
|
+
const cw = charCellsAt(line, start - 1, pastes);
|
|
10110
|
+
if (leftCells + cw > halfBudget) break;
|
|
10111
|
+
start--;
|
|
10112
|
+
leftCells += cw;
|
|
10113
|
+
}
|
|
10114
|
+
const rightBudget = budget - leftCells;
|
|
10115
|
+
let end = cursorCol;
|
|
10116
|
+
let rightCells = 0;
|
|
10117
|
+
const cursorChar = cursorCol < line.length ? charCellsAt(line, cursorCol, pastes) : 1;
|
|
10118
|
+
if (rightBudget >= cursorChar) {
|
|
10119
|
+
if (cursorCol < line.length) end = cursorCol + 1;
|
|
10120
|
+
rightCells = cursorChar;
|
|
10121
|
+
while (end < line.length && rightCells < rightBudget) {
|
|
10122
|
+
const cw = charCellsAt(line, end, pastes);
|
|
10123
|
+
if (rightCells + cw > rightBudget) break;
|
|
10124
|
+
rightCells += cw;
|
|
10125
|
+
end++;
|
|
10126
|
+
}
|
|
10127
|
+
}
|
|
10128
|
+
let extraLeftBudget = rightBudget - rightCells;
|
|
10129
|
+
while (start > 0 && extraLeftBudget > 0) {
|
|
10130
|
+
const cw = charCellsAt(line, start - 1, pastes);
|
|
10131
|
+
if (cw > extraLeftBudget) break;
|
|
10132
|
+
start--;
|
|
10133
|
+
leftCells += cw;
|
|
10134
|
+
extraLeftBudget -= cw;
|
|
10135
|
+
}
|
|
10136
|
+
const hiddenLeft = start > 0;
|
|
10137
|
+
const hiddenRight = end < line.length;
|
|
10138
|
+
const segments = textToSegments(line.slice(start, end), pastes);
|
|
10139
|
+
const cursorCell = stringCells(line.slice(start, cursorCol), pastes);
|
|
10140
|
+
return { segments, cursorCell, hiddenLeft, hiddenRight };
|
|
10141
|
+
}
|
|
10142
|
+
function charCellsAt(line, idx, pastes) {
|
|
10143
|
+
const ch = line[idx];
|
|
10144
|
+
const id = decodePasteSentinel(ch);
|
|
10145
|
+
if (id !== null) {
|
|
10146
|
+
const entry = pastes?.get(id);
|
|
10147
|
+
return pasteSentinelLabel(id, entry).length;
|
|
10148
|
+
}
|
|
10149
|
+
return charCells(ch);
|
|
10150
|
+
}
|
|
10151
|
+
function textToSegments(line, pastes) {
|
|
10152
|
+
const out = [];
|
|
10153
|
+
let buf = "";
|
|
10154
|
+
const flushBuf = () => {
|
|
10155
|
+
if (buf.length > 0) {
|
|
10156
|
+
out.push({ kind: "text", text: buf });
|
|
10157
|
+
buf = "";
|
|
10158
|
+
}
|
|
10159
|
+
};
|
|
10160
|
+
for (let i = 0; i < line.length; i++) {
|
|
10161
|
+
const ch = line[i];
|
|
10162
|
+
const id = decodePasteSentinel(ch);
|
|
10163
|
+
if (id !== null) {
|
|
10164
|
+
flushBuf();
|
|
10165
|
+
const label = pasteSentinelLabel(id, pastes?.get(id));
|
|
10166
|
+
out.push({ kind: "paste", id, label });
|
|
10167
|
+
} else {
|
|
10168
|
+
buf += ch;
|
|
10169
|
+
}
|
|
10170
|
+
}
|
|
10171
|
+
flushBuf();
|
|
10172
|
+
return out;
|
|
10173
|
+
}
|
|
10174
|
+
|
|
9386
10175
|
// src/cli/ui/PromptInput.tsx
|
|
9387
|
-
var
|
|
9388
|
-
var PASTE_END_MARKER = "\x1B[201~";
|
|
9389
|
-
var PASTE_MERGE_WINDOW_MS = 30;
|
|
10176
|
+
var BAR = "\u258E ";
|
|
9390
10177
|
function PromptInput({
|
|
9391
10178
|
value,
|
|
9392
10179
|
onChange,
|
|
@@ -9397,157 +10184,259 @@ function PromptInput({
|
|
|
9397
10184
|
onHistoryNext
|
|
9398
10185
|
}) {
|
|
9399
10186
|
const [cursor, setCursor] = useState5(value.length);
|
|
9400
|
-
const pastesRef =
|
|
9401
|
-
const nextPasteIdRef =
|
|
9402
|
-
const
|
|
9403
|
-
const lastPasteRef = useRef(null);
|
|
9404
|
-
const lastLocalValueRef = useRef(value);
|
|
10187
|
+
const pastesRef = useRef2(/* @__PURE__ */ new Map());
|
|
10188
|
+
const nextPasteIdRef = useRef2(0);
|
|
10189
|
+
const lastLocalValueRef = useRef2(value);
|
|
9405
10190
|
if (value !== lastLocalValueRef.current) {
|
|
9406
10191
|
lastLocalValueRef.current = value;
|
|
9407
|
-
if (cursor !== value.length)
|
|
9408
|
-
setCursor(value.length);
|
|
9409
|
-
}
|
|
10192
|
+
if (cursor !== value.length) setCursor(value.length);
|
|
9410
10193
|
}
|
|
9411
|
-
const cursorRef = useRef(cursor);
|
|
9412
|
-
cursorRef.current = cursor;
|
|
9413
|
-
const tick = useTick();
|
|
9414
|
-
const showCursor = disabled ? false : Math.floor(tick / 4) % 2 === 0;
|
|
9415
10194
|
const registerPaste = (content) => {
|
|
9416
10195
|
const v = lastLocalValueRef.current;
|
|
9417
|
-
const c =
|
|
9418
|
-
const now = Date.now();
|
|
9419
|
-
const last = lastPasteRef.current;
|
|
9420
|
-
const prevChar = c > 0 ? v[c - 1] : null;
|
|
9421
|
-
const prevId = prevChar ? decodePasteSentinel(prevChar) : null;
|
|
9422
|
-
const canMerge = last !== null && prevId === last.id && now - last.at < PASTE_MERGE_WINDOW_MS && pastesRef.current.has(last.id);
|
|
9423
|
-
if (canMerge && last) {
|
|
9424
|
-
const existing = pastesRef.current.get(last.id);
|
|
9425
|
-
if (existing) {
|
|
9426
|
-
const merged = existing.content + content;
|
|
9427
|
-
pastesRef.current.set(last.id, makePasteEntry(last.id, merged));
|
|
9428
|
-
lastPasteRef.current = { id: last.id, at: now };
|
|
9429
|
-
return;
|
|
9430
|
-
}
|
|
9431
|
-
}
|
|
10196
|
+
const c = cursor;
|
|
9432
10197
|
const id = nextPasteIdRef.current % PASTE_SENTINEL_RANGE;
|
|
9433
10198
|
nextPasteIdRef.current = id + 1;
|
|
9434
10199
|
pastesRef.current.set(id, makePasteEntry(id, content));
|
|
9435
10200
|
const sentinel = encodePasteSentinel(id);
|
|
9436
10201
|
const next = v.slice(0, c) + sentinel + v.slice(c);
|
|
9437
10202
|
lastLocalValueRef.current = next;
|
|
9438
|
-
cursorRef.current = c + 1;
|
|
9439
10203
|
onChange(next);
|
|
9440
10204
|
setCursor(c + 1);
|
|
9441
|
-
lastPasteRef.current = { id, at: now };
|
|
9442
10205
|
};
|
|
9443
|
-
|
|
9444
|
-
(
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
const action = processMultilineKey(value, cursor, ke);
|
|
9485
|
-
if (action.pasteRequest) {
|
|
9486
|
-
registerPaste(action.pasteRequest.content);
|
|
9487
|
-
return;
|
|
9488
|
-
}
|
|
9489
|
-
if (action.next !== null) {
|
|
9490
|
-
lastLocalValueRef.current = action.next;
|
|
9491
|
-
onChange(action.next);
|
|
9492
|
-
}
|
|
9493
|
-
if (action.cursor !== null) {
|
|
9494
|
-
setCursor(action.cursor);
|
|
9495
|
-
}
|
|
9496
|
-
if (action.submit) {
|
|
9497
|
-
const raw = action.submitValue ?? value;
|
|
9498
|
-
const expanded = expandPasteSentinels(raw, pastesRef.current);
|
|
9499
|
-
const reachable = new Set(listPasteIdsInBuffer(raw));
|
|
9500
|
-
for (const id of pastesRef.current.keys()) {
|
|
9501
|
-
if (!reachable.has(id)) pastesRef.current.delete(id);
|
|
9502
|
-
}
|
|
9503
|
-
onSubmit(expanded);
|
|
10206
|
+
useKeystroke((ev) => {
|
|
10207
|
+
if (disabled) return;
|
|
10208
|
+
if (ev.paste) {
|
|
10209
|
+
if (ev.input.length > 0) registerPaste(ev.input);
|
|
10210
|
+
return;
|
|
10211
|
+
}
|
|
10212
|
+
const key = {
|
|
10213
|
+
input: ev.input,
|
|
10214
|
+
return: ev.return,
|
|
10215
|
+
shift: ev.shift,
|
|
10216
|
+
ctrl: ev.ctrl,
|
|
10217
|
+
meta: ev.meta,
|
|
10218
|
+
backspace: ev.backspace,
|
|
10219
|
+
delete: ev.delete,
|
|
10220
|
+
tab: ev.tab,
|
|
10221
|
+
upArrow: ev.upArrow,
|
|
10222
|
+
downArrow: ev.downArrow,
|
|
10223
|
+
leftArrow: ev.leftArrow,
|
|
10224
|
+
rightArrow: ev.rightArrow,
|
|
10225
|
+
escape: ev.escape,
|
|
10226
|
+
pageUp: ev.pageUp,
|
|
10227
|
+
pageDown: ev.pageDown
|
|
10228
|
+
};
|
|
10229
|
+
const action = processMultilineKey(value, cursor, key);
|
|
10230
|
+
if (action.pasteRequest) {
|
|
10231
|
+
registerPaste(action.pasteRequest.content);
|
|
10232
|
+
return;
|
|
10233
|
+
}
|
|
10234
|
+
if (action.next !== null) {
|
|
10235
|
+
lastLocalValueRef.current = action.next;
|
|
10236
|
+
onChange(action.next);
|
|
10237
|
+
}
|
|
10238
|
+
if (action.cursor !== null) {
|
|
10239
|
+
setCursor(action.cursor);
|
|
10240
|
+
}
|
|
10241
|
+
if (action.submit) {
|
|
10242
|
+
const raw = action.submitValue ?? value;
|
|
10243
|
+
const expanded = expandPasteSentinels(raw, pastesRef.current);
|
|
10244
|
+
const reachable = new Set(listPasteIdsInBuffer(raw));
|
|
10245
|
+
for (const id of pastesRef.current.keys()) {
|
|
10246
|
+
if (!reachable.has(id)) pastesRef.current.delete(id);
|
|
9504
10247
|
}
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
);
|
|
9510
|
-
const { stdout: stdout2 } =
|
|
10248
|
+
onSubmit(expanded);
|
|
10249
|
+
}
|
|
10250
|
+
if (action.historyHandoff === "prev") onHistoryPrev?.();
|
|
10251
|
+
if (action.historyHandoff === "next") onHistoryNext?.();
|
|
10252
|
+
}, !disabled);
|
|
10253
|
+
const { stdout: stdout2 } = useStdout5();
|
|
9511
10254
|
const cols = stdout2?.columns ?? 80;
|
|
9512
10255
|
const narrow = cols <= 90;
|
|
9513
|
-
const
|
|
9514
|
-
const
|
|
9515
|
-
const
|
|
10256
|
+
const promptBody = narrow ? "\u203A " : "you \u203A ";
|
|
10257
|
+
const promptPrefix = BAR + promptBody;
|
|
10258
|
+
const continuationIndent = BAR + " ".repeat(promptBody.length);
|
|
10259
|
+
const prefixCells = promptPrefix.length;
|
|
10260
|
+
const visibleCells = Math.max(8, cols - prefixCells - 3);
|
|
10261
|
+
const placeholderActive = narrow ? "type a message, or /command" : "type a message, or /command \xB7 [Ctrl+J] newline (Shift+Enter where supported)";
|
|
9516
10262
|
const effectivePlaceholder = disabled ? placeholder ?? "\u2026waiting for response\u2026" : placeholder ?? placeholderActive;
|
|
9517
10263
|
const lines = value.length > 0 ? value.split("\n") : [""];
|
|
9518
|
-
const
|
|
10264
|
+
const accentColor = disabled ? "gray" : "cyan";
|
|
10265
|
+
const animate = !disabled && cols >= 100;
|
|
10266
|
+
const tick = useTick();
|
|
10267
|
+
const barOffset = animate ? Math.floor(tick / 6) : 0;
|
|
10268
|
+
const barColorAt = (rowIdx) => disabled ? "gray" : GRADIENT[((rowIdx + barOffset) % GRADIENT.length + GRADIENT.length) % GRADIENT.length];
|
|
10269
|
+
const cursorVisible = animate ? Math.floor(tick / 4) % 2 === 0 : true;
|
|
9519
10270
|
const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
|
|
9520
10271
|
const renderItems = collapseLinesForDisplay(lines, cursorLine);
|
|
9521
10272
|
const showHugeBufferHints = lines.length > 20;
|
|
9522
|
-
return /* @__PURE__ */
|
|
10273
|
+
return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", paddingX: 1 }, renderItems.map((item, renderIdx) => {
|
|
9523
10274
|
if (item.kind === "skip") {
|
|
9524
10275
|
return (
|
|
9525
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: stable —
|
|
9526
|
-
/* @__PURE__ */
|
|
9527
|
-
Text14,
|
|
9528
|
-
{
|
|
9529
|
-
dimColor: true
|
|
9530
|
-
},
|
|
9531
|
-
`[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`
|
|
9532
|
-
))
|
|
10276
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stable — collapse markers derive from a fixed sliding window
|
|
10277
|
+
/* @__PURE__ */ React17.createElement(Box15, { key: `skip-${renderIdx}` }, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(renderIdx) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, `[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`))
|
|
9533
10278
|
);
|
|
9534
10279
|
}
|
|
9535
|
-
const line = item.line;
|
|
9536
10280
|
const i = item.originalIndex;
|
|
10281
|
+
const line = item.line;
|
|
9537
10282
|
const isFirst = i === 0;
|
|
9538
|
-
const showPlaceholder = isFirst && value.length === 0;
|
|
9539
10283
|
const isCursorLine = i === cursorLine;
|
|
9540
|
-
|
|
9541
|
-
|
|
10284
|
+
const showPlaceholder = isFirst && value.length === 0;
|
|
10285
|
+
return /* @__PURE__ */ React17.createElement(
|
|
10286
|
+
PromptLine,
|
|
9542
10287
|
{
|
|
10288
|
+
key: `ln-${i}`,
|
|
9543
10289
|
line,
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
10290
|
+
isFirst,
|
|
10291
|
+
isCursorLine: isCursorLine && !disabled,
|
|
10292
|
+
cursorCol: isCursorLine ? cursorCol : null,
|
|
10293
|
+
cursorVisible,
|
|
10294
|
+
showPlaceholder,
|
|
10295
|
+
placeholderText: effectivePlaceholder,
|
|
10296
|
+
promptPrefix,
|
|
10297
|
+
continuationIndent,
|
|
10298
|
+
visibleCells,
|
|
10299
|
+
accentColor,
|
|
10300
|
+
barColor: barColorAt(i),
|
|
10301
|
+
pastes: pastesRef.current,
|
|
10302
|
+
disabled: disabled === true
|
|
9548
10303
|
}
|
|
9549
|
-
)
|
|
9550
|
-
}), showHugeBufferHints && !disabled ? /* @__PURE__ */
|
|
10304
|
+
);
|
|
10305
|
+
}), showHugeBufferHints && !disabled ? /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { 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__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "[Ctrl+J] newline \xB7 [Enter] submit \xB7 ends with \\ for line continuation")) : null, disabled ? /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "[Esc] to stop")) : null);
|
|
10306
|
+
}
|
|
10307
|
+
function PromptLine({
|
|
10308
|
+
line,
|
|
10309
|
+
isFirst,
|
|
10310
|
+
isCursorLine,
|
|
10311
|
+
cursorCol,
|
|
10312
|
+
cursorVisible,
|
|
10313
|
+
showPlaceholder,
|
|
10314
|
+
placeholderText,
|
|
10315
|
+
promptPrefix,
|
|
10316
|
+
continuationIndent,
|
|
10317
|
+
visibleCells,
|
|
10318
|
+
accentColor,
|
|
10319
|
+
barColor,
|
|
10320
|
+
pastes,
|
|
10321
|
+
disabled
|
|
10322
|
+
}) {
|
|
10323
|
+
const barText = promptPrefix.slice(0, BAR.length);
|
|
10324
|
+
const bodyPrefix = promptPrefix.slice(BAR.length);
|
|
10325
|
+
const bodyContinuation = continuationIndent.slice(BAR.length);
|
|
10326
|
+
if (showPlaceholder) {
|
|
10327
|
+
return /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColor }, barText), /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: accentColor }, bodyPrefix), !disabled ? /* @__PURE__ */ React17.createElement(Text13, { color: accentColor }, cursorVisible ? "\u258C" : " ") : null, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, placeholderText));
|
|
10328
|
+
}
|
|
10329
|
+
const viewport = buildViewport(line, isCursorLine ? cursorCol : null, visibleCells, pastes);
|
|
10330
|
+
return /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColor }, barText), isFirst ? /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: accentColor }, bodyPrefix) : /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, bodyContinuation), viewport.hiddenLeft ? /* @__PURE__ */ React17.createElement(Text13, { color: "gray", dimColor: true }, "\u2039") : null, /* @__PURE__ */ React17.createElement(
|
|
10331
|
+
ViewportContent,
|
|
10332
|
+
{
|
|
10333
|
+
segments: viewport.segments,
|
|
10334
|
+
cursorCell: isCursorLine ? viewport.cursorCell : null,
|
|
10335
|
+
accentColor,
|
|
10336
|
+
cursorVisible
|
|
10337
|
+
}
|
|
10338
|
+
), viewport.hiddenRight ? /* @__PURE__ */ React17.createElement(Text13, { color: "gray", dimColor: true }, "\u203A") : null);
|
|
10339
|
+
}
|
|
10340
|
+
function ViewportContent({
|
|
10341
|
+
segments,
|
|
10342
|
+
cursorCell,
|
|
10343
|
+
accentColor,
|
|
10344
|
+
cursorVisible
|
|
10345
|
+
}) {
|
|
10346
|
+
if (cursorCell === null) {
|
|
10347
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, segments.map((seg, i) => renderSegment(seg, i, false)));
|
|
10348
|
+
}
|
|
10349
|
+
const out = [];
|
|
10350
|
+
let cells = 0;
|
|
10351
|
+
let placed = false;
|
|
10352
|
+
for (let i = 0; i < segments.length; i++) {
|
|
10353
|
+
const seg = segments[i];
|
|
10354
|
+
const segCells = segmentCells(seg);
|
|
10355
|
+
if (placed) {
|
|
10356
|
+
out.push(renderSegment(seg, i, false));
|
|
10357
|
+
continue;
|
|
10358
|
+
}
|
|
10359
|
+
if (cursorCell >= cells + segCells) {
|
|
10360
|
+
out.push(renderSegment(seg, i, false));
|
|
10361
|
+
cells += segCells;
|
|
10362
|
+
continue;
|
|
10363
|
+
}
|
|
10364
|
+
if (seg.kind === "paste") {
|
|
10365
|
+
out.push(
|
|
10366
|
+
/* @__PURE__ */ React17.createElement(Text13, { key: `p-${i}-cursor`, color: "magenta", bold: true, inverse: cursorVisible }, seg.label)
|
|
10367
|
+
);
|
|
10368
|
+
placed = true;
|
|
10369
|
+
cells += segCells;
|
|
10370
|
+
continue;
|
|
10371
|
+
}
|
|
10372
|
+
const offsetIntoSeg = cursorCell - cells;
|
|
10373
|
+
const split = splitTextByCells(seg.text, offsetIntoSeg);
|
|
10374
|
+
if (split.before.length > 0) {
|
|
10375
|
+
out.push(/* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-b` }, split.before));
|
|
10376
|
+
}
|
|
10377
|
+
if (split.atCursor.length > 0) {
|
|
10378
|
+
out.push(
|
|
10379
|
+
/* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-c`, inverse: cursorVisible, color: accentColor }, split.atCursor)
|
|
10380
|
+
);
|
|
10381
|
+
} else {
|
|
10382
|
+
out.push(
|
|
10383
|
+
/* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-c-eol`, color: accentColor }, cursorVisible ? "\u258C" : " ")
|
|
10384
|
+
);
|
|
10385
|
+
}
|
|
10386
|
+
if (split.after.length > 0) {
|
|
10387
|
+
out.push(/* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-a` }, split.after));
|
|
10388
|
+
}
|
|
10389
|
+
placed = true;
|
|
10390
|
+
cells += segCells;
|
|
10391
|
+
}
|
|
10392
|
+
if (!placed) {
|
|
10393
|
+
out.push(
|
|
10394
|
+
/* @__PURE__ */ React17.createElement(Text13, { key: "cursor-eol", color: accentColor }, cursorVisible ? "\u258C" : " ")
|
|
10395
|
+
);
|
|
10396
|
+
}
|
|
10397
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, out);
|
|
10398
|
+
}
|
|
10399
|
+
function segmentCells(seg) {
|
|
10400
|
+
if (seg.kind === "paste") return seg.label.length;
|
|
10401
|
+
return stringCells(seg.text);
|
|
10402
|
+
}
|
|
10403
|
+
function splitTextByCells(text, cellOffset) {
|
|
10404
|
+
let cells = 0;
|
|
10405
|
+
for (let i = 0; i < text.length; i++) {
|
|
10406
|
+
const ch = text[i];
|
|
10407
|
+
const cw = charCellsForText(ch);
|
|
10408
|
+
if (cells === cellOffset) {
|
|
10409
|
+
return { before: text.slice(0, i), atCursor: ch, after: text.slice(i + 1) };
|
|
10410
|
+
}
|
|
10411
|
+
if (cells + cw > cellOffset) {
|
|
10412
|
+
return { before: text.slice(0, i), atCursor: ch, after: text.slice(i + 1) };
|
|
10413
|
+
}
|
|
10414
|
+
cells += cw;
|
|
10415
|
+
}
|
|
10416
|
+
return { before: text, atCursor: "", after: "" };
|
|
10417
|
+
}
|
|
10418
|
+
function charCellsForText(ch) {
|
|
10419
|
+
const code = ch.charCodeAt(0);
|
|
10420
|
+
if (code < 32 || code === 127) return 0;
|
|
10421
|
+
if (code < 4352) return 1;
|
|
10422
|
+
if (code >= 4352 && code <= 4447) return 2;
|
|
10423
|
+
if (code >= 11904 && code <= 12350) return 2;
|
|
10424
|
+
if (code >= 12353 && code <= 13311) return 2;
|
|
10425
|
+
if (code >= 13312 && code <= 19903) return 2;
|
|
10426
|
+
if (code >= 19968 && code <= 40959) return 2;
|
|
10427
|
+
if (code >= 40960 && code <= 42191) return 2;
|
|
10428
|
+
if (code >= 44032 && code <= 55203) return 2;
|
|
10429
|
+
if (code >= 63744 && code <= 64255) return 2;
|
|
10430
|
+
if (code >= 65072 && code <= 65103) return 2;
|
|
10431
|
+
if (code >= 65280 && code <= 65376) return 2;
|
|
10432
|
+
if (code >= 65504 && code <= 65510) return 2;
|
|
10433
|
+
return 1;
|
|
10434
|
+
}
|
|
10435
|
+
function renderSegment(seg, key, _inverse) {
|
|
10436
|
+
if (seg.kind === "text") {
|
|
10437
|
+
return /* @__PURE__ */ React17.createElement(Text13, { key: `s-${key}` }, seg.text);
|
|
10438
|
+
}
|
|
10439
|
+
return /* @__PURE__ */ React17.createElement(Text13, { key: `s-${key}`, backgroundColor: "#f0abfc", color: "black", bold: true }, seg.label);
|
|
9551
10440
|
}
|
|
9552
10441
|
var COLLAPSE_THRESHOLD = 20;
|
|
9553
10442
|
var COLLAPSE_HEAD_LINES = 3;
|
|
@@ -9572,88 +10461,49 @@ function collapseLinesForDisplay(lines, cursorLine) {
|
|
|
9572
10461
|
}
|
|
9573
10462
|
return out;
|
|
9574
10463
|
}
|
|
9575
|
-
function RenderLine({
|
|
9576
|
-
line,
|
|
9577
|
-
pastes,
|
|
9578
|
-
inverse
|
|
9579
|
-
}) {
|
|
9580
|
-
const segments = [];
|
|
9581
|
-
let buf = "";
|
|
9582
|
-
let segIdx = 0;
|
|
9583
|
-
const flushBuf = () => {
|
|
9584
|
-
if (buf.length === 0) return;
|
|
9585
|
-
segments.push(
|
|
9586
|
-
/* @__PURE__ */ React15.createElement(Text14, { key: `t-${segIdx++}`, inverse }, buf)
|
|
9587
|
-
);
|
|
9588
|
-
buf = "";
|
|
9589
|
-
};
|
|
9590
|
-
for (let i = 0; i < line.length; i++) {
|
|
9591
|
-
const ch = line[i];
|
|
9592
|
-
const id = decodePasteSentinel(ch);
|
|
9593
|
-
if (id === null) {
|
|
9594
|
-
buf += ch;
|
|
9595
|
-
continue;
|
|
9596
|
-
}
|
|
9597
|
-
flushBuf();
|
|
9598
|
-
const entry = pastes.get(id);
|
|
9599
|
-
const label = entry ? `[paste #${id + 1} \xB7 ${entry.lineCount}l \xB7 ${formatBytesShort(entry.charCount)}]` : `[paste #${id + 1} \xB7 (missing)]`;
|
|
9600
|
-
segments.push(
|
|
9601
|
-
/* @__PURE__ */ React15.createElement(Text14, { key: `p-${segIdx++}`, color: "magenta", bold: true, inverse }, label)
|
|
9602
|
-
);
|
|
9603
|
-
}
|
|
9604
|
-
flushBuf();
|
|
9605
|
-
if (segments.length === 0) {
|
|
9606
|
-
return /* @__PURE__ */ React15.createElement(Text14, null, " ");
|
|
9607
|
-
}
|
|
9608
|
-
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, segments);
|
|
9609
|
-
}
|
|
9610
|
-
function LineWithCursor({
|
|
9611
|
-
line,
|
|
9612
|
-
col,
|
|
9613
|
-
showCursor,
|
|
9614
|
-
borderColor,
|
|
9615
|
-
pastes
|
|
9616
|
-
}) {
|
|
9617
|
-
const before = line.slice(0, col);
|
|
9618
|
-
const atCursor = line.slice(col, col + 1);
|
|
9619
|
-
const after = line.slice(col + 1);
|
|
9620
|
-
if (atCursor.length === 0) {
|
|
9621
|
-
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(RenderLine, { line: before, pastes }), /* @__PURE__ */ React15.createElement(Text14, { color: borderColor }, showCursor ? "\u258C" : " "));
|
|
9622
|
-
}
|
|
9623
|
-
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(RenderLine, { line: before, pastes }), /* @__PURE__ */ React15.createElement(RenderLine, { line: atCursor, pastes, inverse: showCursor }), /* @__PURE__ */ React15.createElement(RenderLine, { line: after, pastes }));
|
|
9624
|
-
}
|
|
9625
10464
|
|
|
9626
10465
|
// src/cli/ui/ShellConfirm.tsx
|
|
9627
|
-
import { Box as
|
|
9628
|
-
import
|
|
10466
|
+
import { Box as Box16, Text as Text14 } from "ink";
|
|
10467
|
+
import React18 from "react";
|
|
9629
10468
|
function ShellConfirm({ command, allowPrefix, kind, onChoose }) {
|
|
9630
10469
|
const isBackground = kind === "run_background";
|
|
9631
|
-
|
|
9632
|
-
|
|
10470
|
+
const subtitle = isBackground ? "long-running process \u2014 keeps running after approval, /kill to stop" : "model wants to run a shell command";
|
|
10471
|
+
return /* @__PURE__ */ React18.createElement(
|
|
10472
|
+
ModalCard,
|
|
9633
10473
|
{
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
10474
|
+
accent: "#f87171",
|
|
10475
|
+
icon: isBackground ? "\u23F1" : "\u26A1",
|
|
10476
|
+
title: isBackground ? "background process" : "shell command",
|
|
10477
|
+
subtitle
|
|
10478
|
+
},
|
|
10479
|
+
/* @__PURE__ */ React18.createElement(Box16, { marginBottom: 1 }, /* @__PURE__ */ React18.createElement(Text14, { dimColor: true }, "$ "), /* @__PURE__ */ React18.createElement(Text14, { color: "#67e8f9", bold: true }, command)),
|
|
10480
|
+
/* @__PURE__ */ React18.createElement(
|
|
10481
|
+
SingleSelect,
|
|
10482
|
+
{
|
|
10483
|
+
initialValue: "run_once",
|
|
10484
|
+
items: [
|
|
10485
|
+
{
|
|
10486
|
+
value: "run_once",
|
|
10487
|
+
label: "Run once",
|
|
10488
|
+
hint: "Execute this command, don't remember it."
|
|
10489
|
+
},
|
|
10490
|
+
{
|
|
10491
|
+
value: "always_allow",
|
|
10492
|
+
label: `Always allow "${allowPrefix}" in this project`,
|
|
10493
|
+
hint: "Save the prefix to ~/.reasonix/config.json; future matches auto-run."
|
|
10494
|
+
},
|
|
10495
|
+
{
|
|
10496
|
+
value: "deny",
|
|
10497
|
+
label: "Deny",
|
|
10498
|
+
hint: "Tell the model the user refused; it will continue without this command."
|
|
10499
|
+
}
|
|
10500
|
+
],
|
|
10501
|
+
onSubmit: (v) => onChoose(v),
|
|
10502
|
+
onCancel: () => onChoose("deny"),
|
|
10503
|
+
footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] deny"
|
|
10504
|
+
}
|
|
10505
|
+
)
|
|
10506
|
+
);
|
|
9657
10507
|
}
|
|
9658
10508
|
function derivePrefix(command) {
|
|
9659
10509
|
const tokens = command.trim().split(/\s+/).filter(Boolean);
|
|
@@ -9685,8 +10535,8 @@ function derivePrefix(command) {
|
|
|
9685
10535
|
}
|
|
9686
10536
|
|
|
9687
10537
|
// src/cli/ui/SlashArgPicker.tsx
|
|
9688
|
-
import { Box as
|
|
9689
|
-
import
|
|
10538
|
+
import { Box as Box17, Text as Text15 } from "ink";
|
|
10539
|
+
import React19 from "react";
|
|
9690
10540
|
function SlashArgPicker({
|
|
9691
10541
|
matches,
|
|
9692
10542
|
selectedIndex,
|
|
@@ -9695,11 +10545,11 @@ function SlashArgPicker({
|
|
|
9695
10545
|
partial
|
|
9696
10546
|
}) {
|
|
9697
10547
|
if (kind === "hint") {
|
|
9698
|
-
return /* @__PURE__ */
|
|
10548
|
+
return /* @__PURE__ */ React19.createElement(Box17, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " ", /* @__PURE__ */ React19.createElement(Text15, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary));
|
|
9699
10549
|
}
|
|
9700
10550
|
if (matches === null) return null;
|
|
9701
10551
|
if (matches.length === 0) {
|
|
9702
|
-
return /* @__PURE__ */
|
|
10552
|
+
return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " ", /* @__PURE__ */ React19.createElement(Text15, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), /* @__PURE__ */ React19.createElement(Text15, { color: "yellow" }, ' no match for "', partial, '" \u2014 keep typing, or Backspace to edit'));
|
|
9703
10553
|
}
|
|
9704
10554
|
const MAX = 8;
|
|
9705
10555
|
const total = matches.length;
|
|
@@ -9707,26 +10557,26 @@ function SlashArgPicker({
|
|
|
9707
10557
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
9708
10558
|
const hiddenAbove = windowStart;
|
|
9709
10559
|
const hiddenBelow = total - windowStart - shown.length;
|
|
9710
|
-
return /* @__PURE__ */
|
|
10560
|
+
return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " ", /* @__PURE__ */ React19.createElement(Text15, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), hiddenAbove > 0 ? /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((value, i) => /* @__PURE__ */ React19.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
|
|
9711
10561
|
}
|
|
9712
10562
|
function ArgRow({ value, isSelected }) {
|
|
9713
10563
|
const marker = isSelected ? "\u25B8" : " ";
|
|
9714
10564
|
if (isSelected) {
|
|
9715
|
-
return /* @__PURE__ */
|
|
10565
|
+
return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text15, { bold: true, color: "cyan" }, marker, " ", value));
|
|
9716
10566
|
}
|
|
9717
|
-
return /* @__PURE__ */
|
|
10567
|
+
return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, marker, " ", value));
|
|
9718
10568
|
}
|
|
9719
10569
|
|
|
9720
10570
|
// src/cli/ui/SlashSuggestions.tsx
|
|
9721
|
-
import { Box as
|
|
9722
|
-
import
|
|
10571
|
+
import { Box as Box18, Text as Text16 } from "ink";
|
|
10572
|
+
import React20 from "react";
|
|
9723
10573
|
function SlashSuggestions({
|
|
9724
10574
|
matches,
|
|
9725
10575
|
selectedIndex
|
|
9726
10576
|
}) {
|
|
9727
10577
|
if (matches === null) return null;
|
|
9728
10578
|
if (matches.length === 0) {
|
|
9729
|
-
return /* @__PURE__ */
|
|
10579
|
+
return /* @__PURE__ */ React20.createElement(Box18, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text16, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
|
|
9730
10580
|
}
|
|
9731
10581
|
const MAX = 8;
|
|
9732
10582
|
const total = matches.length;
|
|
@@ -9734,47 +10584,29 @@ function SlashSuggestions({
|
|
|
9734
10584
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
9735
10585
|
const hiddenAbove = windowStart;
|
|
9736
10586
|
const hiddenBelow = total - windowStart - shown.length;
|
|
9737
|
-
return /* @__PURE__ */
|
|
10587
|
+
return /* @__PURE__ */ React20.createElement(Box18, { flexDirection: "column", paddingX: 1, marginTop: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React20.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
|
|
9738
10588
|
}
|
|
9739
10589
|
function SuggestionRow({ spec, isSelected }) {
|
|
9740
|
-
const marker = isSelected ? "\u25B8" : " ";
|
|
9741
10590
|
const name = `/${spec.cmd}`;
|
|
9742
10591
|
const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
|
|
9743
10592
|
if (isSelected) {
|
|
9744
|
-
return /* @__PURE__ */
|
|
10593
|
+
return /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { backgroundColor: "#67e8f9", color: "black", bold: true }, ` \u25B8 ${name.padEnd(12)}${argsSuffix.padEnd(16)} ${spec.summary} `));
|
|
9745
10594
|
}
|
|
9746
|
-
return /* @__PURE__ */
|
|
10595
|
+
return /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: "#94a3b8" }, ` ${name.padEnd(12)}${argsSuffix.padEnd(16)} ${spec.summary}`));
|
|
9747
10596
|
}
|
|
9748
10597
|
|
|
9749
10598
|
// src/cli/ui/StatsPanel.tsx
|
|
9750
|
-
import { Box as
|
|
9751
|
-
import
|
|
9752
|
-
var
|
|
9753
|
-
|
|
9754
|
-
// teal — brand mark
|
|
9755
|
-
{ ch: " ", color: "#5eead4", isLogo: false },
|
|
9756
|
-
{ ch: "R", color: "#67e8f9", isLogo: false },
|
|
9757
|
-
// cyan
|
|
9758
|
-
{ ch: "E", color: "#7dd3fc", isLogo: false },
|
|
9759
|
-
// sky
|
|
9760
|
-
{ ch: "A", color: "#93c5fd", isLogo: false },
|
|
9761
|
-
// blue
|
|
9762
|
-
{ ch: "S", color: "#a5b4fc", isLogo: false },
|
|
9763
|
-
// indigo
|
|
9764
|
-
{ ch: "O", color: "#c4b5fd", isLogo: false },
|
|
9765
|
-
// violet
|
|
9766
|
-
{ ch: "N", color: "#d8b4fe", isLogo: false },
|
|
9767
|
-
// purple
|
|
9768
|
-
{ ch: "I", color: "#f0abfc", isLogo: false },
|
|
9769
|
-
// fuchsia
|
|
9770
|
-
{ ch: "X", color: "#f0abfc", isLogo: false }
|
|
9771
|
-
// fuchsia
|
|
9772
|
-
];
|
|
9773
|
-
function Wordmark({ busy }) {
|
|
10599
|
+
import { Box as Box19, Text as Text17, useStdout as useStdout6 } from "ink";
|
|
10600
|
+
import React21 from "react";
|
|
10601
|
+
var WORDMARK_LETTERS = ["R", "E", "A", "S", "O", "N", "I", "X"];
|
|
10602
|
+
function Wordmark({ busy, animate }) {
|
|
9774
10603
|
const tick = useTick();
|
|
9775
|
-
const
|
|
9776
|
-
const bright = Math.floor(tick /
|
|
9777
|
-
|
|
10604
|
+
const pulsePeriod = busy ? 5 : 12;
|
|
10605
|
+
const bright = animate ? Math.floor(tick / pulsePeriod) % 2 === 0 : true;
|
|
10606
|
+
const rotateEvery = busy ? 2 : 4;
|
|
10607
|
+
const offset = animate ? Math.floor(tick / rotateEvery) : 0;
|
|
10608
|
+
const colorAt = (i) => GRADIENT[((i + offset) % GRADIENT.length + GRADIENT.length) % GRADIENT.length];
|
|
10609
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: colorAt(0), bold: bright }, "\u25C8"), /* @__PURE__ */ React21.createElement(Text17, null, " "), WORDMARK_LETTERS.map((letter, i) => /* @__PURE__ */ React21.createElement(Text17, { key: letter, color: colorAt(i + 1), bold: true }, letter)));
|
|
9778
10610
|
}
|
|
9779
10611
|
var NARROW_BREAKPOINT = 120;
|
|
9780
10612
|
var COLD_START_TURNS = 3;
|
|
@@ -9796,21 +10628,20 @@ function StatsPanel({
|
|
|
9796
10628
|
const branchOn = (branchBudget ?? 1) > 1;
|
|
9797
10629
|
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model2] ?? DEFAULT_CONTEXT_TOKENS;
|
|
9798
10630
|
const ctxRatio = summary.lastPromptTokens / ctxMax;
|
|
9799
|
-
const { stdout: stdout2 } =
|
|
10631
|
+
const { stdout: stdout2 } = useStdout6();
|
|
9800
10632
|
const columns = stdout2?.columns ?? 80;
|
|
9801
10633
|
const narrow = columns < NARROW_BREAKPOINT;
|
|
9802
10634
|
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
10635
|
+
const ruleWidth = Math.max(20, columns - 2);
|
|
10636
|
+
const animate = columns >= 100;
|
|
9803
10637
|
return (
|
|
9804
|
-
//
|
|
9805
|
-
//
|
|
9806
|
-
//
|
|
9807
|
-
//
|
|
9808
|
-
//
|
|
9809
|
-
//
|
|
9810
|
-
|
|
9811
|
-
// display rows) but makes each frame's dimensions exact so
|
|
9812
|
-
// there's no residual uncertainty in the erase.
|
|
9813
|
-
/* @__PURE__ */ React19.createElement(Box18, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, width: columns }, /* @__PURE__ */ React19.createElement(
|
|
10638
|
+
// Borderless layout: no `borderStyle`, no rounded box. Bordered
|
|
10639
|
+
// Boxes were the most visible amplifier of Ink's eraseLines
|
|
10640
|
+
// miscount on Windows terminals. Visual weight here comes from
|
|
10641
|
+
// truecolor gradient rules at the top and bottom (rendered as
|
|
10642
|
+
// pure Text so they never trigger the eraseLines bug), the
|
|
10643
|
+
// animated wordmark + pill row, and a soft inner padding.
|
|
10644
|
+
/* @__PURE__ */ React21.createElement(Box19, { flexDirection: "column", paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React21.createElement(GradientRule, { width: ruleWidth, animate }), /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(
|
|
9814
10645
|
Header,
|
|
9815
10646
|
{
|
|
9816
10647
|
model: model2,
|
|
@@ -9826,9 +10657,10 @@ function StatsPanel({
|
|
|
9826
10657
|
narrow,
|
|
9827
10658
|
busy: busy ?? false,
|
|
9828
10659
|
proArmed: proArmed ?? false,
|
|
9829
|
-
escalated: escalated ?? false
|
|
10660
|
+
escalated: escalated ?? false,
|
|
10661
|
+
animate
|
|
9830
10662
|
}
|
|
9831
|
-
), narrow ? /* @__PURE__ */
|
|
10663
|
+
)), narrow ? /* @__PURE__ */ React21.createElement(
|
|
9832
10664
|
StackedMetrics,
|
|
9833
10665
|
{
|
|
9834
10666
|
summary,
|
|
@@ -9837,7 +10669,7 @@ function StatsPanel({
|
|
|
9837
10669
|
balance,
|
|
9838
10670
|
coldStart
|
|
9839
10671
|
}
|
|
9840
|
-
) : /* @__PURE__ */
|
|
10672
|
+
) : /* @__PURE__ */ React21.createElement(
|
|
9841
10673
|
InlineMetrics,
|
|
9842
10674
|
{
|
|
9843
10675
|
summary,
|
|
@@ -9846,9 +10678,28 @@ function StatsPanel({
|
|
|
9846
10678
|
balance,
|
|
9847
10679
|
coldStart
|
|
9848
10680
|
}
|
|
9849
|
-
))
|
|
10681
|
+
), /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(GradientRule, { width: ruleWidth, thin: true, animate })))
|
|
9850
10682
|
);
|
|
9851
10683
|
}
|
|
10684
|
+
function GradientRule({
|
|
10685
|
+
width,
|
|
10686
|
+
thin,
|
|
10687
|
+
animate
|
|
10688
|
+
}) {
|
|
10689
|
+
const tick = useTick();
|
|
10690
|
+
const offset = animate ? Math.floor(tick / 6) : 0;
|
|
10691
|
+
const ch = thin ? "\u2581" : "\u2584";
|
|
10692
|
+
const len = GRADIENT.length;
|
|
10693
|
+
return /* @__PURE__ */ React21.createElement(Box19, null, Array.from({ length: width }, (_, i) => {
|
|
10694
|
+
const t = width === 1 ? 0 : i * (len - 1) / (width - 1);
|
|
10695
|
+
const idx = (Math.round(t) + offset) % len;
|
|
10696
|
+
const color = GRADIENT[(idx % len + len) % len];
|
|
10697
|
+
return (
|
|
10698
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient cells never reorder
|
|
10699
|
+
/* @__PURE__ */ React21.createElement(Text17, { key: `grule-${i}`, color }, ch)
|
|
10700
|
+
);
|
|
10701
|
+
}));
|
|
10702
|
+
}
|
|
9852
10703
|
function Header({
|
|
9853
10704
|
model: model2,
|
|
9854
10705
|
prefixHash,
|
|
@@ -9863,9 +10714,16 @@ function Header({
|
|
|
9863
10714
|
narrow,
|
|
9864
10715
|
busy,
|
|
9865
10716
|
proArmed,
|
|
9866
|
-
escalated
|
|
10717
|
+
escalated,
|
|
10718
|
+
animate
|
|
9867
10719
|
}) {
|
|
9868
|
-
|
|
10720
|
+
const modePill = planMode ? { label: "PLAN", bg: "red" } : editMode === "auto" ? { label: "AUTO", bg: "magenta" } : editMode === "review" ? { label: "REVIEW", bg: "cyan" } : null;
|
|
10721
|
+
const proPill = escalated ? { label: "\u21E7 PRO", bg: "red" } : proArmed ? { label: "\u21E7 PRO", bg: "yellow" } : null;
|
|
10722
|
+
const showSecondary = animate && !narrow;
|
|
10723
|
+
return /* @__PURE__ */ React21.createElement(Box19, { justifyContent: "space-between" }, /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Wordmark, { busy, animate }), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, ` ${VERSION}`), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", bold: true }, model2.replace(/^deepseek-/, "")), modePill ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Pill, { label: modePill.label, bg: modePill.bg })) : null, proPill ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Pill, { label: proPill.label, bg: proPill.bg })) : null, showSecondary && harvestOn ? /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "magenta" }, "harvest")) : null, showSecondary && branchOn ? /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "blue" }, `branch\xD7${branchBudget}`)) : null, showSecondary && reasoningEffort === "max" ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "green", dimColor: true }, "max")) : null, showSecondary && reasoningEffort === "high" ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", dimColor: true }, "high")) : null), /* @__PURE__ */ React21.createElement(Text17, null, updateAvailable ? /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", bold: true }, `\u2191 ${updateAvailable} `) : null, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, narrow ? `t${turns}` : `turn ${turns} \xB7 /help`)));
|
|
10724
|
+
}
|
|
10725
|
+
function Pill({ label, bg }) {
|
|
10726
|
+
return /* @__PURE__ */ React21.createElement(Text17, { backgroundColor: bg, color: "white", bold: true }, ` ${label} `);
|
|
9869
10727
|
}
|
|
9870
10728
|
function InlineMetrics({
|
|
9871
10729
|
summary,
|
|
@@ -9874,7 +10732,7 @@ function InlineMetrics({
|
|
|
9874
10732
|
balance,
|
|
9875
10733
|
coldStart
|
|
9876
10734
|
}) {
|
|
9877
|
-
return /* @__PURE__ */
|
|
10735
|
+
return /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React21.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React21.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React21.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React21.createElement(BalanceCell, { balance }) : null);
|
|
9878
10736
|
}
|
|
9879
10737
|
function StackedMetrics({
|
|
9880
10738
|
summary,
|
|
@@ -9883,7 +10741,7 @@ function StackedMetrics({
|
|
|
9883
10741
|
balance,
|
|
9884
10742
|
coldStart
|
|
9885
10743
|
}) {
|
|
9886
|
-
return /* @__PURE__ */
|
|
10744
|
+
return /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React21.createElement(
|
|
9887
10745
|
ContextCell,
|
|
9888
10746
|
{
|
|
9889
10747
|
ratio: ctxRatio,
|
|
@@ -9891,7 +10749,7 @@ function StackedMetrics({
|
|
|
9891
10749
|
ctxMax,
|
|
9892
10750
|
showBar: true
|
|
9893
10751
|
}
|
|
9894
|
-
), balance ? /* @__PURE__ */
|
|
10752
|
+
), balance ? /* @__PURE__ */ React21.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React21.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React21.createElement(CostCell, { summary, coldStart }));
|
|
9895
10753
|
}
|
|
9896
10754
|
function ContextCell({
|
|
9897
10755
|
ratio,
|
|
@@ -9900,11 +10758,11 @@ function ContextCell({
|
|
|
9900
10758
|
showBar
|
|
9901
10759
|
}) {
|
|
9902
10760
|
if (promptTokens === 0) {
|
|
9903
|
-
return /* @__PURE__ */
|
|
10761
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u25A3 ctx "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2014 (no turns yet)"));
|
|
9904
10762
|
}
|
|
9905
|
-
const color = ratio >= 0.8 ?
|
|
10763
|
+
const color = ratio >= 0.8 ? COLOR.err : ratio >= 0.6 ? COLOR.warn : COLOR.ok;
|
|
9906
10764
|
const pct2 = Math.round(ratio * 100);
|
|
9907
|
-
return /* @__PURE__ */
|
|
10765
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u25A3 ctx "), /* @__PURE__ */ React21.createElement(Bar, { ratio, color, cells: showBar ? 14 : 10 }), /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.err, bold: true }, " \xB7 /compact") : null);
|
|
9908
10766
|
}
|
|
9909
10767
|
function CacheCell({
|
|
9910
10768
|
hitRatio,
|
|
@@ -9913,46 +10771,48 @@ function CacheCell({
|
|
|
9913
10771
|
}) {
|
|
9914
10772
|
const pct2 = (hitRatio * 100).toFixed(1);
|
|
9915
10773
|
if (turns === 0) {
|
|
9916
|
-
return /* @__PURE__ */
|
|
10774
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u232C cache "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2014"));
|
|
9917
10775
|
}
|
|
9918
10776
|
if (coldStart) {
|
|
9919
|
-
return /* @__PURE__ */
|
|
10777
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u232C cache "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true, italic: true }, "(cold start)"));
|
|
9920
10778
|
}
|
|
9921
|
-
const color = hitRatio >= 0.7 ?
|
|
9922
|
-
return /* @__PURE__ */
|
|
10779
|
+
const color = hitRatio >= 0.7 ? COLOR.ok : hitRatio >= 0.4 ? COLOR.warn : COLOR.err;
|
|
10780
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u232C cache "), /* @__PURE__ */ React21.createElement(Text17, { color, bold: true }, pct2, "%"));
|
|
9923
10781
|
}
|
|
9924
10782
|
function turnCostColor(cost) {
|
|
9925
10783
|
if (cost <= 0) return void 0;
|
|
9926
|
-
if (cost >= 0.2) return
|
|
9927
|
-
if (cost >= 0.05) return
|
|
9928
|
-
return
|
|
10784
|
+
if (cost >= 0.2) return COLOR.err;
|
|
10785
|
+
if (cost >= 0.05) return COLOR.warn;
|
|
10786
|
+
return COLOR.ok;
|
|
9929
10787
|
}
|
|
9930
10788
|
function sessionCostColor(cost) {
|
|
9931
10789
|
if (cost <= 0) return void 0;
|
|
9932
|
-
if (cost >= 5) return
|
|
9933
|
-
if (cost >= 0.5) return
|
|
9934
|
-
return
|
|
10790
|
+
if (cost >= 5) return COLOR.err;
|
|
10791
|
+
if (cost >= 0.5) return COLOR.warn;
|
|
10792
|
+
return COLOR.ok;
|
|
9935
10793
|
}
|
|
9936
10794
|
function CostCell({
|
|
9937
10795
|
summary,
|
|
9938
10796
|
coldStart
|
|
9939
10797
|
}) {
|
|
9940
10798
|
if (summary.turns === 0) {
|
|
9941
|
-
return /* @__PURE__ */
|
|
10799
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u25F4 cost "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2014"));
|
|
9942
10800
|
}
|
|
9943
10801
|
const turnColor = coldStart ? void 0 : turnCostColor(summary.lastTurnCostUsd);
|
|
9944
10802
|
const sessionColor = coldStart ? void 0 : sessionCostColor(summary.totalCostUsd);
|
|
9945
|
-
return /* @__PURE__ */
|
|
10803
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u25F4 turn "), /* @__PURE__ */ React21.createElement(Text17, { color: turnColor, bold: !coldStart, dimColor: coldStart }, "$", summary.lastTurnCostUsd.toFixed(4)), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " \xB7 session "), /* @__PURE__ */ React21.createElement(Text17, { color: sessionColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(4)));
|
|
9946
10804
|
}
|
|
9947
10805
|
function BalanceCell({ balance }) {
|
|
9948
|
-
const color = balance.total < 1 ?
|
|
9949
|
-
return /* @__PURE__ */
|
|
10806
|
+
const color = balance.total < 1 ? COLOR.err : balance.total < 5 ? COLOR.warn : COLOR.ok;
|
|
10807
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u25D0 balance "), /* @__PURE__ */ React21.createElement(Text17, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
|
|
9950
10808
|
}
|
|
9951
|
-
function Bar({
|
|
9952
|
-
|
|
10809
|
+
function Bar({
|
|
10810
|
+
ratio,
|
|
10811
|
+
color,
|
|
10812
|
+
cells = 14
|
|
10813
|
+
}) {
|
|
9953
10814
|
const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
|
|
9954
|
-
|
|
9955
|
-
return /* @__PURE__ */ React19.createElement(Text18, { color }, bar);
|
|
10815
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color }, "\u25B0".repeat(filled)), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u25B1".repeat(cells - filled)));
|
|
9956
10816
|
}
|
|
9957
10817
|
function formatTokens(n) {
|
|
9958
10818
|
if (n < 1024) return String(n);
|
|
@@ -9960,6 +10820,29 @@ function formatTokens(n) {
|
|
|
9960
10820
|
return k >= 100 ? `${k.toFixed(0)}K` : `${k.toFixed(1)}K`;
|
|
9961
10821
|
}
|
|
9962
10822
|
|
|
10823
|
+
// src/cli/ui/WelcomeBanner.tsx
|
|
10824
|
+
import { Box as Box20, Text as Text18, useStdout as useStdout7 } from "ink";
|
|
10825
|
+
import React22 from "react";
|
|
10826
|
+
function WelcomeBanner({ inCodeMode }) {
|
|
10827
|
+
const { stdout: stdout2 } = useStdout7();
|
|
10828
|
+
const cols = stdout2?.columns ?? 80;
|
|
10829
|
+
const ruleWidth = Math.min(60, Math.max(28, cols - 4));
|
|
10830
|
+
return /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React22.createElement(GradientRule2, { width: ruleWidth }), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.brand }, "\u25C8 welcome"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " \xB7 type a message to start")), /* @__PURE__ */ React22.createElement(BarRow, null), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.primary }, "quick start")), /* @__PURE__ */ React22.createElement(Hint, { cmd: "/help", desc: "every command + keyboard shortcut" }), /* @__PURE__ */ React22.createElement(Hint, { cmd: "/skill", desc: "invoke a stored playbook" }), inCodeMode ? /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(Hint, { cmd: "@path", desc: "inline a file in your message" }), /* @__PURE__ */ React22.createElement(Hint, { cmd: "!cmd", desc: "run a shell command, output goes to context" })) : null, /* @__PURE__ */ React22.createElement(Hint, { cmd: "/exit", desc: "quit (Ctrl+C also works)" }), /* @__PURE__ */ React22.createElement(BarRow, null), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true, italic: true }, "tip:"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " Ctrl+J inserts a newline \xB7 trailing \\ also continues")), /* @__PURE__ */ React22.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(GradientRule2, { width: ruleWidth, thin: true })));
|
|
10831
|
+
}
|
|
10832
|
+
function GradientRule2({ width, thin }) {
|
|
10833
|
+
const cells = gradientCells(width, thin ? "\u2581" : "\u2584");
|
|
10834
|
+
return /* @__PURE__ */ React22.createElement(Box20, null, cells.map((c, i) => (
|
|
10835
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row, never reordered
|
|
10836
|
+
/* @__PURE__ */ React22.createElement(Text18, { key: `wrule-${i}`, color: c.color }, c.ch)
|
|
10837
|
+
)));
|
|
10838
|
+
}
|
|
10839
|
+
function BarRow({ children }) {
|
|
10840
|
+
return /* @__PURE__ */ React22.createElement(Box20, null, /* @__PURE__ */ React22.createElement(Text18, { color: COLOR.brand, bold: true }, "\u258E"), /* @__PURE__ */ React22.createElement(Text18, null, " "), children);
|
|
10841
|
+
}
|
|
10842
|
+
function Hint({ cmd, desc }) {
|
|
10843
|
+
return /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.accent }, cmd.padEnd(8)), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, ` ${desc}`));
|
|
10844
|
+
}
|
|
10845
|
+
|
|
9963
10846
|
// src/cli/ui/bang.ts
|
|
9964
10847
|
function detectBangCommand(text) {
|
|
9965
10848
|
if (!text.startsWith("!")) return null;
|
|
@@ -11800,7 +12683,7 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
11800
12683
|
}
|
|
11801
12684
|
|
|
11802
12685
|
// src/cli/ui/useCompletionPickers.ts
|
|
11803
|
-
import { useCallback, useEffect as
|
|
12686
|
+
import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState6 } from "react";
|
|
11804
12687
|
function useCompletionPickers({
|
|
11805
12688
|
input,
|
|
11806
12689
|
setInput,
|
|
@@ -11813,7 +12696,7 @@ function useCompletionPickers({
|
|
|
11813
12696
|
if (!input.startsWith("/") || input.includes(" ")) return null;
|
|
11814
12697
|
return suggestSlashCommands(input.slice(1), !!codeMode);
|
|
11815
12698
|
}, [input, codeMode]);
|
|
11816
|
-
|
|
12699
|
+
useEffect3(() => {
|
|
11817
12700
|
setSlashSelected((prev) => {
|
|
11818
12701
|
if (!slashMatches || slashMatches.length === 0) return 0;
|
|
11819
12702
|
if (prev >= slashMatches.length) return slashMatches.length - 1;
|
|
@@ -11829,7 +12712,7 @@ function useCompletionPickers({
|
|
|
11829
12712
|
return [];
|
|
11830
12713
|
}
|
|
11831
12714
|
}, [codeMode?.rootDir]);
|
|
11832
|
-
const recentFilesRef =
|
|
12715
|
+
const recentFilesRef = useRef3([]);
|
|
11833
12716
|
const recordRecentFile = useCallback((p) => {
|
|
11834
12717
|
const list = recentFilesRef.current;
|
|
11835
12718
|
const i = list.indexOf(p);
|
|
@@ -11849,7 +12732,7 @@ function useCompletionPickers({
|
|
|
11849
12732
|
recentlyUsed: recentFilesRef.current
|
|
11850
12733
|
});
|
|
11851
12734
|
}, [atPicker, atFiles]);
|
|
11852
|
-
|
|
12735
|
+
useEffect3(() => {
|
|
11853
12736
|
setAtSelected((prev) => {
|
|
11854
12737
|
if (!atMatches || atMatches.length === 0) return 0;
|
|
11855
12738
|
if (prev >= atMatches.length) return atMatches.length - 1;
|
|
@@ -11910,7 +12793,7 @@ function useCompletionPickers({
|
|
|
11910
12793
|
}
|
|
11911
12794
|
return null;
|
|
11912
12795
|
}, [slashArgContext, models2, mcpServers]);
|
|
11913
|
-
|
|
12796
|
+
useEffect3(() => {
|
|
11914
12797
|
setSlashArgSelected((prev) => {
|
|
11915
12798
|
if (!slashArgMatches || slashArgMatches.length === 0) return 0;
|
|
11916
12799
|
if (prev >= slashArgMatches.length) return slashArgMatches.length - 1;
|
|
@@ -11944,13 +12827,13 @@ function useCompletionPickers({
|
|
|
11944
12827
|
}
|
|
11945
12828
|
|
|
11946
12829
|
// src/cli/ui/useEditHistory.ts
|
|
11947
|
-
import { useCallback as useCallback2, useRef as
|
|
12830
|
+
import { useCallback as useCallback2, useRef as useRef4, useState as useState7 } from "react";
|
|
11948
12831
|
function useEditHistory(codeMode) {
|
|
11949
|
-
const editHistory =
|
|
11950
|
-
const nextHistoryId =
|
|
11951
|
-
const currentTurnEntry =
|
|
12832
|
+
const editHistory = useRef4([]);
|
|
12833
|
+
const nextHistoryId = useRef4(1);
|
|
12834
|
+
const currentTurnEntry = useRef4(null);
|
|
11952
12835
|
const [undoBanner, setUndoBanner] = useState7(null);
|
|
11953
|
-
const undoTimeoutRef =
|
|
12836
|
+
const undoTimeoutRef = useRef4(null);
|
|
11954
12837
|
const recordEdit = useCallback2(
|
|
11955
12838
|
(source, blocks, results, snaps) => {
|
|
11956
12839
|
if (snaps.length === 0) return;
|
|
@@ -12146,12 +13029,12 @@ function useEditHistory(codeMode) {
|
|
|
12146
13029
|
}
|
|
12147
13030
|
|
|
12148
13031
|
// src/cli/ui/useSessionInfo.ts
|
|
12149
|
-
import { useCallback as useCallback3, useEffect as
|
|
13032
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useState as useState8 } from "react";
|
|
12150
13033
|
function useSessionInfo(loop) {
|
|
12151
13034
|
const [balance, setBalance] = useState8(null);
|
|
12152
13035
|
const [models2, setModels] = useState8(null);
|
|
12153
13036
|
const [latestVersion, setLatestVersion] = useState8(null);
|
|
12154
|
-
|
|
13037
|
+
useEffect4(() => {
|
|
12155
13038
|
let cancelled = false;
|
|
12156
13039
|
void (async () => {
|
|
12157
13040
|
const bal = await loop.client.getBalance().catch(() => null);
|
|
@@ -12163,7 +13046,7 @@ function useSessionInfo(loop) {
|
|
|
12163
13046
|
cancelled = true;
|
|
12164
13047
|
};
|
|
12165
13048
|
}, [loop]);
|
|
12166
|
-
|
|
13049
|
+
useEffect4(() => {
|
|
12167
13050
|
let cancelled = false;
|
|
12168
13051
|
void (async () => {
|
|
12169
13052
|
const list = await loop.client.listModels().catch(() => null);
|
|
@@ -12174,7 +13057,7 @@ function useSessionInfo(loop) {
|
|
|
12174
13057
|
cancelled = true;
|
|
12175
13058
|
};
|
|
12176
13059
|
}, [loop]);
|
|
12177
|
-
|
|
13060
|
+
useEffect4(() => {
|
|
12178
13061
|
let cancelled = false;
|
|
12179
13062
|
void (async () => {
|
|
12180
13063
|
const latest = await getLatestVersion();
|
|
@@ -12219,11 +13102,11 @@ function useSessionInfo(loop) {
|
|
|
12219
13102
|
}
|
|
12220
13103
|
|
|
12221
13104
|
// src/cli/ui/useSubagent.ts
|
|
12222
|
-
import { useEffect as
|
|
13105
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState9 } from "react";
|
|
12223
13106
|
function useSubagent({ session, setHistorical }) {
|
|
12224
13107
|
const [activity, setActivity] = useState9(null);
|
|
12225
|
-
const sinkRef =
|
|
12226
|
-
|
|
13108
|
+
const sinkRef = useRef5({ current: null });
|
|
13109
|
+
useEffect5(() => {
|
|
12227
13110
|
sinkRef.current.current = (ev) => {
|
|
12228
13111
|
if (ev.kind === "start") {
|
|
12229
13112
|
setActivity({
|
|
@@ -12296,15 +13179,17 @@ function App({
|
|
|
12296
13179
|
const [streaming, setStreaming] = useState10(null);
|
|
12297
13180
|
const [input, setInput] = useState10("");
|
|
12298
13181
|
const [busy, setBusy] = useState10(false);
|
|
12299
|
-
const abortedThisTurn =
|
|
13182
|
+
const abortedThisTurn = useRef6(false);
|
|
12300
13183
|
const [ongoingTool, setOngoingTool] = useState10(null);
|
|
12301
13184
|
const [toolProgress, setToolProgress] = useState10(null);
|
|
12302
|
-
const { stdout: stdout2 } =
|
|
12303
|
-
|
|
13185
|
+
const { stdout: stdout2 } = useStdout8();
|
|
13186
|
+
useEffect6(() => {
|
|
12304
13187
|
if (!stdout2 || !stdout2.isTTY) return;
|
|
12305
13188
|
stdout2.write("\x1B[?2004h");
|
|
13189
|
+
stdout2.write("\x1B[>4;2m");
|
|
12306
13190
|
return () => {
|
|
12307
13191
|
stdout2.write("\x1B[?2004l");
|
|
13192
|
+
stdout2.write("\x1B[>4m");
|
|
12308
13193
|
};
|
|
12309
13194
|
}, [stdout2]);
|
|
12310
13195
|
const { activity: subagentActivity, sinkRef: subagentSinkRef } = useSubagent({
|
|
@@ -12326,24 +13211,24 @@ function App({
|
|
|
12326
13211
|
sealCurrentEntry,
|
|
12327
13212
|
hasUndoable
|
|
12328
13213
|
} = useEditHistory(codeMode);
|
|
12329
|
-
const pendingEdits =
|
|
13214
|
+
const pendingEdits = useRef6([]);
|
|
12330
13215
|
const [pendingCount, setPendingCount] = useState10(0);
|
|
12331
13216
|
const syncPendingCount = useCallback4(() => {
|
|
12332
13217
|
setPendingCount(pendingEdits.current.length);
|
|
12333
13218
|
}, []);
|
|
12334
13219
|
const [editMode, setEditMode] = useState10(() => codeMode ? loadEditMode() : "review");
|
|
12335
|
-
const editModeRef =
|
|
12336
|
-
|
|
13220
|
+
const editModeRef = useRef6(editMode);
|
|
13221
|
+
useEffect6(() => {
|
|
12337
13222
|
editModeRef.current = editMode;
|
|
12338
13223
|
if (codeMode) saveEditMode(editMode);
|
|
12339
13224
|
}, [editMode, codeMode]);
|
|
12340
13225
|
const [pendingEditReview, setPendingEditReview] = useState10(null);
|
|
12341
|
-
const editReviewResolveRef =
|
|
12342
|
-
const turnEditPolicyRef =
|
|
13226
|
+
const editReviewResolveRef = useRef6(null);
|
|
13227
|
+
const turnEditPolicyRef = useRef6("ask");
|
|
12343
13228
|
const [modeFlash, setModeFlash] = useState10(false);
|
|
12344
|
-
const modeFlashTimeoutRef =
|
|
12345
|
-
const prevEditModeRef =
|
|
12346
|
-
|
|
13229
|
+
const modeFlashTimeoutRef = useRef6(null);
|
|
13230
|
+
const prevEditModeRef = useRef6(editMode);
|
|
13231
|
+
useEffect6(() => {
|
|
12347
13232
|
if (prevEditModeRef.current === editMode) return;
|
|
12348
13233
|
prevEditModeRef.current = editMode;
|
|
12349
13234
|
setModeFlash(true);
|
|
@@ -12365,15 +13250,15 @@ function App({
|
|
|
12365
13250
|
const [proArmed, setProArmed] = useState10(false);
|
|
12366
13251
|
const [turnOnPro, setTurnOnPro] = useState10(false);
|
|
12367
13252
|
const [queuedSubmit, setQueuedSubmit] = useState10(null);
|
|
12368
|
-
const promptHistory =
|
|
12369
|
-
const historyCursor =
|
|
12370
|
-
const assistantIterCounter =
|
|
12371
|
-
const toolHistoryRef =
|
|
12372
|
-
const planStepsRef =
|
|
12373
|
-
const completedStepIdsRef =
|
|
12374
|
-
const planBodyRef =
|
|
12375
|
-
const planSummaryRef =
|
|
12376
|
-
const toolStartedAtRef =
|
|
13253
|
+
const promptHistory = useRef6([]);
|
|
13254
|
+
const historyCursor = useRef6(-1);
|
|
13255
|
+
const assistantIterCounter = useRef6(0);
|
|
13256
|
+
const toolHistoryRef = useRef6([]);
|
|
13257
|
+
const planStepsRef = useRef6(null);
|
|
13258
|
+
const completedStepIdsRef = useRef6(/* @__PURE__ */ new Set());
|
|
13259
|
+
const planBodyRef = useRef6(null);
|
|
13260
|
+
const planSummaryRef = useRef6(null);
|
|
13261
|
+
const toolStartedAtRef = useRef6(null);
|
|
12377
13262
|
const persistPlanState = useCallback4(() => {
|
|
12378
13263
|
if (!session) return;
|
|
12379
13264
|
const steps = planStepsRef.current;
|
|
@@ -12397,7 +13282,7 @@ function App({
|
|
|
12397
13282
|
lastPromptTokens: 0,
|
|
12398
13283
|
lastTurnCostUsd: 0
|
|
12399
13284
|
});
|
|
12400
|
-
const transcriptRef =
|
|
13285
|
+
const transcriptRef = useRef6(null);
|
|
12401
13286
|
if (transcript && !transcriptRef.current) {
|
|
12402
13287
|
transcriptRef.current = openTranscriptFile(transcript, {
|
|
12403
13288
|
version: 1,
|
|
@@ -12406,12 +13291,12 @@ function App({
|
|
|
12406
13291
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12407
13292
|
});
|
|
12408
13293
|
}
|
|
12409
|
-
|
|
13294
|
+
useEffect6(() => {
|
|
12410
13295
|
return () => {
|
|
12411
13296
|
transcriptRef.current?.end();
|
|
12412
13297
|
};
|
|
12413
13298
|
}, []);
|
|
12414
|
-
const loopRef =
|
|
13299
|
+
const loopRef = useRef6(null);
|
|
12415
13300
|
const loop = useMemo3(() => {
|
|
12416
13301
|
if (loopRef.current) return loopRef.current;
|
|
12417
13302
|
const client = new DeepSeekClient();
|
|
@@ -12460,7 +13345,7 @@ function App({
|
|
|
12460
13345
|
loopRef.current = l;
|
|
12461
13346
|
return l;
|
|
12462
13347
|
}, [model2, system, harvest3, branch2, session, tools, codeMode]);
|
|
12463
|
-
|
|
13348
|
+
useEffect6(() => {
|
|
12464
13349
|
loop.hooks = hookList;
|
|
12465
13350
|
}, [loop, hookList]);
|
|
12466
13351
|
const {
|
|
@@ -12488,7 +13373,7 @@ function App({
|
|
|
12488
13373
|
setSlashArgSelected,
|
|
12489
13374
|
pickSlashArg
|
|
12490
13375
|
} = useCompletionPickers({ input, setInput, codeMode, models: models2, mcpServers });
|
|
12491
|
-
|
|
13376
|
+
useEffect6(() => {
|
|
12492
13377
|
if (!progressSink) return;
|
|
12493
13378
|
progressSink.current = (info) => {
|
|
12494
13379
|
setToolProgress({
|
|
@@ -12501,8 +13386,8 @@ function App({
|
|
|
12501
13386
|
if (progressSink.current) progressSink.current = null;
|
|
12502
13387
|
};
|
|
12503
13388
|
}, [progressSink]);
|
|
12504
|
-
const sessionBannerShown =
|
|
12505
|
-
|
|
13389
|
+
const sessionBannerShown = useRef6(false);
|
|
13390
|
+
useEffect6(() => {
|
|
12506
13391
|
if (sessionBannerShown.current) return;
|
|
12507
13392
|
sessionBannerShown.current = true;
|
|
12508
13393
|
if (!session) {
|
|
@@ -12584,7 +13469,26 @@ function App({
|
|
|
12584
13469
|
markEditModeHintShown();
|
|
12585
13470
|
}
|
|
12586
13471
|
}, [session, loop, codeMode, syncPendingCount]);
|
|
12587
|
-
|
|
13472
|
+
const quitProcess = useCallback4(() => {
|
|
13473
|
+
transcriptRef.current?.end();
|
|
13474
|
+
process.exit(0);
|
|
13475
|
+
}, []);
|
|
13476
|
+
useEffect6(() => {
|
|
13477
|
+
process.on("SIGINT", quitProcess);
|
|
13478
|
+
return () => {
|
|
13479
|
+
process.off("SIGINT", quitProcess);
|
|
13480
|
+
};
|
|
13481
|
+
}, [quitProcess]);
|
|
13482
|
+
useKeystroke((ev) => {
|
|
13483
|
+
const chKey = ev.input;
|
|
13484
|
+
const key = ev;
|
|
13485
|
+
if (ev.paste) {
|
|
13486
|
+
return;
|
|
13487
|
+
}
|
|
13488
|
+
if (key.ctrl && key.input === "c") {
|
|
13489
|
+
quitProcess();
|
|
13490
|
+
return;
|
|
13491
|
+
}
|
|
12588
13492
|
if (key.escape && busy) {
|
|
12589
13493
|
if (abortedThisTurn.current) return;
|
|
12590
13494
|
abortedThisTurn.current = true;
|
|
@@ -12682,7 +13586,7 @@ function App({
|
|
|
12682
13586
|
historyCursor.current = nextCursor;
|
|
12683
13587
|
setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
|
|
12684
13588
|
}, []);
|
|
12685
|
-
|
|
13589
|
+
useEffect6(() => {
|
|
12686
13590
|
if (!tools || !codeMode) return;
|
|
12687
13591
|
tools.setToolInterceptor(async (name, args) => {
|
|
12688
13592
|
if (name !== "edit_file" && name !== "write_file") return null;
|
|
@@ -13548,7 +14452,7 @@ ${body}`;
|
|
|
13548
14452
|
},
|
|
13549
14453
|
[pendingShell, codeMode, handleSubmit, busy, loop]
|
|
13550
14454
|
);
|
|
13551
|
-
|
|
14455
|
+
useEffect6(() => {
|
|
13552
14456
|
if (!busy && queuedSubmit !== null) {
|
|
13553
14457
|
const text = queuedSubmit;
|
|
13554
14458
|
setQueuedSubmit(null);
|
|
@@ -13592,8 +14496,8 @@ ${body}`;
|
|
|
13592
14496
|
},
|
|
13593
14497
|
[pendingPlan, togglePlanMode, busy, loop, handleSubmit, persistPlanState]
|
|
13594
14498
|
);
|
|
13595
|
-
const handlePlanConfirmRef =
|
|
13596
|
-
|
|
14499
|
+
const handlePlanConfirmRef = useRef6(handlePlanConfirm);
|
|
14500
|
+
useEffect6(() => {
|
|
13597
14501
|
handlePlanConfirmRef.current = handlePlanConfirm;
|
|
13598
14502
|
}, [handlePlanConfirm]);
|
|
13599
14503
|
const stableHandlePlanConfirm = useCallback4(
|
|
@@ -13684,8 +14588,8 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
13684
14588
|
},
|
|
13685
14589
|
[pendingCheckpoint, busy, loop, handleSubmit]
|
|
13686
14590
|
);
|
|
13687
|
-
const handleCheckpointConfirmRef =
|
|
13688
|
-
|
|
14591
|
+
const handleCheckpointConfirmRef = useRef6(handleCheckpointConfirm);
|
|
14592
|
+
useEffect6(() => {
|
|
13689
14593
|
handleCheckpointConfirmRef.current = handleCheckpointConfirm;
|
|
13690
14594
|
}, [handleCheckpointConfirm]);
|
|
13691
14595
|
const stableHandleCheckpointConfirm = useCallback4(
|
|
@@ -13762,8 +14666,8 @@ If the feedback only tweaks how you execute (extra constraints, style preference
|
|
|
13762
14666
|
},
|
|
13763
14667
|
[pendingChoice, busy, loop, handleSubmit]
|
|
13764
14668
|
);
|
|
13765
|
-
const handleChoiceConfirmRef =
|
|
13766
|
-
|
|
14669
|
+
const handleChoiceConfirmRef = useRef6(handleChoiceConfirm);
|
|
14670
|
+
useEffect6(() => {
|
|
13767
14671
|
handleChoiceConfirmRef.current = handleChoiceConfirm;
|
|
13768
14672
|
}, [handleChoiceConfirm]);
|
|
13769
14673
|
const stableHandleChoiceConfirm = useCallback4(
|
|
@@ -13853,20 +14757,20 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13853
14757
|
},
|
|
13854
14758
|
[pendingRevision, busy, loop, handleSubmit, persistPlanState]
|
|
13855
14759
|
);
|
|
13856
|
-
const handleReviseConfirmRef =
|
|
13857
|
-
|
|
14760
|
+
const handleReviseConfirmRef = useRef6(handleReviseConfirm);
|
|
14761
|
+
useEffect6(() => {
|
|
13858
14762
|
handleReviseConfirmRef.current = handleReviseConfirm;
|
|
13859
14763
|
}, [handleReviseConfirm]);
|
|
13860
14764
|
const stableHandleReviseConfirm = useCallback4(
|
|
13861
14765
|
async (choice) => handleReviseConfirmRef.current(choice),
|
|
13862
14766
|
[]
|
|
13863
14767
|
);
|
|
13864
|
-
return /* @__PURE__ */
|
|
14768
|
+
return /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(
|
|
13865
14769
|
TickerProvider,
|
|
13866
14770
|
{
|
|
13867
14771
|
disabled: PLAIN_UI || !!pendingPlan || !!pendingShell || !!pendingEditReview || !!pendingCheckpoint || !!stagedCheckpointRevise || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision
|
|
13868
14772
|
},
|
|
13869
|
-
/* @__PURE__ */
|
|
14773
|
+
/* @__PURE__ */ React23.createElement(Box21, { flexDirection: "column" }, /* @__PURE__ */ React23.createElement(
|
|
13870
14774
|
StatsPanel,
|
|
13871
14775
|
{
|
|
13872
14776
|
summary,
|
|
@@ -13883,28 +14787,28 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13883
14787
|
proArmed,
|
|
13884
14788
|
escalated: turnOnPro
|
|
13885
14789
|
}
|
|
13886
|
-
), /* @__PURE__ */
|
|
14790
|
+
), /* @__PURE__ */ React23.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React23.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React23.createElement(WelcomeBanner, { inCodeMode: !!codeMode }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React23.createElement(Box21, { marginY: 1 }, /* @__PURE__ */ React23.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React23.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React23.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React23.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React23.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React23.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React23.createElement(
|
|
13887
14791
|
PlanRefineInput,
|
|
13888
14792
|
{
|
|
13889
14793
|
mode: stagedInput.mode,
|
|
13890
14794
|
onSubmit: handleStagedInputSubmit,
|
|
13891
14795
|
onCancel: handleStagedInputCancel
|
|
13892
14796
|
}
|
|
13893
|
-
) : stagedCheckpointRevise ? /* @__PURE__ */
|
|
14797
|
+
) : stagedCheckpointRevise ? /* @__PURE__ */ React23.createElement(
|
|
13894
14798
|
PlanRefineInput,
|
|
13895
14799
|
{
|
|
13896
14800
|
mode: "checkpoint-revise",
|
|
13897
14801
|
onSubmit: handleCheckpointReviseSubmit,
|
|
13898
14802
|
onCancel: handleCheckpointReviseCancel
|
|
13899
14803
|
}
|
|
13900
|
-
) : stagedChoiceCustom ? /* @__PURE__ */
|
|
14804
|
+
) : stagedChoiceCustom ? /* @__PURE__ */ React23.createElement(
|
|
13901
14805
|
PlanRefineInput,
|
|
13902
14806
|
{
|
|
13903
14807
|
mode: "choice-custom",
|
|
13904
14808
|
onSubmit: handleChoiceCustomSubmit,
|
|
13905
14809
|
onCancel: handleChoiceCustomCancel
|
|
13906
14810
|
}
|
|
13907
|
-
) : pendingChoice ? /* @__PURE__ */
|
|
14811
|
+
) : pendingChoice ? /* @__PURE__ */ React23.createElement(
|
|
13908
14812
|
ChoiceConfirm,
|
|
13909
14813
|
{
|
|
13910
14814
|
question: pendingChoice.question,
|
|
@@ -13912,7 +14816,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13912
14816
|
allowCustom: pendingChoice.allowCustom,
|
|
13913
14817
|
onChoose: stableHandleChoiceConfirm
|
|
13914
14818
|
}
|
|
13915
|
-
) : pendingRevision ? /* @__PURE__ */
|
|
14819
|
+
) : pendingRevision ? /* @__PURE__ */ React23.createElement(
|
|
13916
14820
|
PlanReviseConfirm,
|
|
13917
14821
|
{
|
|
13918
14822
|
reason: pendingRevision.reason,
|
|
@@ -13923,7 +14827,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13923
14827
|
summary: pendingRevision.summary,
|
|
13924
14828
|
onChoose: stableHandleReviseConfirm
|
|
13925
14829
|
}
|
|
13926
|
-
) : pendingCheckpoint ? /* @__PURE__ */
|
|
14830
|
+
) : pendingCheckpoint ? /* @__PURE__ */ React23.createElement(
|
|
13927
14831
|
PlanCheckpointConfirm,
|
|
13928
14832
|
{
|
|
13929
14833
|
stepId: pendingCheckpoint.stepId,
|
|
@@ -13934,7 +14838,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13934
14838
|
completedStepIds: completedStepIdsRef.current,
|
|
13935
14839
|
onChoose: stableHandleCheckpointConfirm
|
|
13936
14840
|
}
|
|
13937
|
-
) : pendingPlan ? /* @__PURE__ */
|
|
14841
|
+
) : pendingPlan ? /* @__PURE__ */ React23.createElement(
|
|
13938
14842
|
PlanConfirm,
|
|
13939
14843
|
{
|
|
13940
14844
|
plan: pendingPlan,
|
|
@@ -13943,7 +14847,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13943
14847
|
onChoose: stableHandlePlanConfirm,
|
|
13944
14848
|
projectRoot: hookCwd
|
|
13945
14849
|
}
|
|
13946
|
-
) : pendingShell ? /* @__PURE__ */
|
|
14850
|
+
) : pendingShell ? /* @__PURE__ */ React23.createElement(
|
|
13947
14851
|
ShellConfirm,
|
|
13948
14852
|
{
|
|
13949
14853
|
command: pendingShell.command,
|
|
@@ -13951,7 +14855,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13951
14855
|
kind: pendingShell.kind,
|
|
13952
14856
|
onChoose: handleShellConfirm
|
|
13953
14857
|
}
|
|
13954
|
-
) : pendingEditReview ? /* @__PURE__ */
|
|
14858
|
+
) : pendingEditReview ? /* @__PURE__ */ React23.createElement(
|
|
13955
14859
|
EditConfirm,
|
|
13956
14860
|
{
|
|
13957
14861
|
block: pendingEditReview,
|
|
@@ -13963,7 +14867,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13963
14867
|
}
|
|
13964
14868
|
}
|
|
13965
14869
|
}
|
|
13966
|
-
) : /* @__PURE__ */
|
|
14870
|
+
) : /* @__PURE__ */ React23.createElement(React23.Fragment, null, codeMode ? /* @__PURE__ */ React23.createElement(
|
|
13967
14871
|
ModeStatusBar,
|
|
13968
14872
|
{
|
|
13969
14873
|
editMode,
|
|
@@ -13973,7 +14877,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13973
14877
|
undoArmed: !!undoBanner || hasUndoable(),
|
|
13974
14878
|
jobs: codeMode.jobs
|
|
13975
14879
|
}
|
|
13976
|
-
) : null, /* @__PURE__ */
|
|
14880
|
+
) : null, /* @__PURE__ */ React23.createElement(
|
|
13977
14881
|
PromptInput,
|
|
13978
14882
|
{
|
|
13979
14883
|
value: input,
|
|
@@ -13983,14 +14887,14 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13983
14887
|
onHistoryPrev: recallPrev,
|
|
13984
14888
|
onHistoryNext: recallNext
|
|
13985
14889
|
}
|
|
13986
|
-
), /* @__PURE__ */
|
|
14890
|
+
), /* @__PURE__ */ React23.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React23.createElement(
|
|
13987
14891
|
AtMentionSuggestions,
|
|
13988
14892
|
{
|
|
13989
14893
|
matches: atMatches,
|
|
13990
14894
|
selectedIndex: atSelected,
|
|
13991
14895
|
query: atPicker?.query ?? ""
|
|
13992
14896
|
}
|
|
13993
|
-
), slashArgContext ? /* @__PURE__ */
|
|
14897
|
+
), slashArgContext ? /* @__PURE__ */ React23.createElement(
|
|
13994
14898
|
SlashArgPicker,
|
|
13995
14899
|
{
|
|
13996
14900
|
matches: slashArgMatches,
|
|
@@ -14000,19 +14904,19 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
14000
14904
|
partial: slashArgContext.partial
|
|
14001
14905
|
}
|
|
14002
14906
|
) : null))
|
|
14003
|
-
);
|
|
14907
|
+
));
|
|
14004
14908
|
}
|
|
14005
14909
|
|
|
14006
14910
|
// src/cli/ui/SessionPicker.tsx
|
|
14007
|
-
import { Box as
|
|
14008
|
-
import
|
|
14911
|
+
import { Box as Box22, Text as Text19 } from "ink";
|
|
14912
|
+
import React24 from "react";
|
|
14009
14913
|
function SessionPicker({
|
|
14010
14914
|
sessionName,
|
|
14011
14915
|
messageCount,
|
|
14012
14916
|
lastActive,
|
|
14013
14917
|
onChoose
|
|
14014
14918
|
}) {
|
|
14015
|
-
return /* @__PURE__ */
|
|
14919
|
+
return /* @__PURE__ */ React24.createElement(Box22, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React24.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React24.createElement(Text19, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React24.createElement(Text19, { dimColor: true }, ` \xB7 last active ${relativeTime2(lastActive)}`)), /* @__PURE__ */ React24.createElement(
|
|
14016
14920
|
SingleSelect,
|
|
14017
14921
|
{
|
|
14018
14922
|
initialValue: "new",
|
|
@@ -14035,7 +14939,7 @@ function SessionPicker({
|
|
|
14035
14939
|
],
|
|
14036
14940
|
onSubmit: (v) => onChoose(v)
|
|
14037
14941
|
}
|
|
14038
|
-
), /* @__PURE__ */
|
|
14942
|
+
), /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text19, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] select")));
|
|
14039
14943
|
}
|
|
14040
14944
|
function relativeTime2(date) {
|
|
14041
14945
|
const ms = Date.now() - date.getTime();
|
|
@@ -14051,9 +14955,9 @@ function relativeTime2(date) {
|
|
|
14051
14955
|
}
|
|
14052
14956
|
|
|
14053
14957
|
// src/cli/ui/Setup.tsx
|
|
14054
|
-
import { Box as
|
|
14958
|
+
import { Box as Box23, Text as Text20, useApp as useApp2 } from "ink";
|
|
14055
14959
|
import TextInput from "ink-text-input";
|
|
14056
|
-
import
|
|
14960
|
+
import React25, { useState as useState11 } from "react";
|
|
14057
14961
|
function Setup({ onReady }) {
|
|
14058
14962
|
const [value, setValue] = useState11("");
|
|
14059
14963
|
const [error, setError] = useState11(null);
|
|
@@ -14077,7 +14981,7 @@ function Setup({ onReady }) {
|
|
|
14077
14981
|
}
|
|
14078
14982
|
onReady(trimmed);
|
|
14079
14983
|
};
|
|
14080
|
-
return /* @__PURE__ */
|
|
14984
|
+
return /* @__PURE__ */ React25.createElement(Box23, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React25.createElement(
|
|
14081
14985
|
TextInput,
|
|
14082
14986
|
{
|
|
14083
14987
|
value,
|
|
@@ -14086,7 +14990,7 @@ function Setup({ onReady }) {
|
|
|
14086
14990
|
mask: "\u2022",
|
|
14087
14991
|
placeholder: "sk-..."
|
|
14088
14992
|
}
|
|
14089
|
-
)), error ? /* @__PURE__ */
|
|
14993
|
+
)), error ? /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { color: "red" }, error)) : value ? /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "(Type /exit to abort.)")));
|
|
14090
14994
|
}
|
|
14091
14995
|
|
|
14092
14996
|
// src/cli/commands/chat.tsx
|
|
@@ -14102,7 +15006,7 @@ function Root({
|
|
|
14102
15006
|
const [key, setKey] = useState12(initialKey);
|
|
14103
15007
|
const [pending, setPending] = useState12(sessionPreview);
|
|
14104
15008
|
if (!key) {
|
|
14105
|
-
return /* @__PURE__ */
|
|
15009
|
+
return /* @__PURE__ */ React26.createElement(
|
|
14106
15010
|
Setup,
|
|
14107
15011
|
{
|
|
14108
15012
|
onReady: (k) => {
|
|
@@ -14114,7 +15018,7 @@ function Root({
|
|
|
14114
15018
|
}
|
|
14115
15019
|
process.env.DEEPSEEK_API_KEY = key;
|
|
14116
15020
|
if (pending && appProps.session) {
|
|
14117
|
-
return /* @__PURE__ */
|
|
15021
|
+
return /* @__PURE__ */ React26.createElement(KeystrokeProvider, null, /* @__PURE__ */ React26.createElement(
|
|
14118
15022
|
SessionPicker,
|
|
14119
15023
|
{
|
|
14120
15024
|
sessionName: appProps.session,
|
|
@@ -14127,9 +15031,9 @@ function Root({
|
|
|
14127
15031
|
setPending(void 0);
|
|
14128
15032
|
}
|
|
14129
15033
|
}
|
|
14130
|
-
);
|
|
15034
|
+
));
|
|
14131
15035
|
}
|
|
14132
|
-
return /* @__PURE__ */
|
|
15036
|
+
return /* @__PURE__ */ React26.createElement(KeystrokeProvider, null, /* @__PURE__ */ React26.createElement(
|
|
14133
15037
|
App,
|
|
14134
15038
|
{
|
|
14135
15039
|
model: appProps.model,
|
|
@@ -14144,7 +15048,7 @@ function Root({
|
|
|
14144
15048
|
progressSink,
|
|
14145
15049
|
codeMode: appProps.codeMode
|
|
14146
15050
|
}
|
|
14147
|
-
);
|
|
15051
|
+
));
|
|
14148
15052
|
}
|
|
14149
15053
|
async function chatCommand(opts) {
|
|
14150
15054
|
loadDotenv();
|
|
@@ -14233,8 +15137,11 @@ async function chatCommand(opts) {
|
|
|
14233
15137
|
} else if (opts.session && opts.forceNew) {
|
|
14234
15138
|
rewriteSession(opts.session, []);
|
|
14235
15139
|
}
|
|
15140
|
+
if (process.stdout.isTTY) {
|
|
15141
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
15142
|
+
}
|
|
14236
15143
|
const { waitUntilExit } = render(
|
|
14237
|
-
/* @__PURE__ */
|
|
15144
|
+
/* @__PURE__ */ React26.createElement(
|
|
14238
15145
|
Root,
|
|
14239
15146
|
{
|
|
14240
15147
|
initialKey,
|
|
@@ -14283,12 +15190,9 @@ async function codeCommand(opts = {}) {
|
|
|
14283
15190
|
`\u25B8 reasonix code: rooted at ${rootDir}, session "${session ?? "(ephemeral)"}" \xB7 ${tools.size} native tool(s)
|
|
14284
15191
|
`
|
|
14285
15192
|
);
|
|
14286
|
-
|
|
15193
|
+
process.once("exit", () => {
|
|
14287
15194
|
void jobs2.shutdown();
|
|
14288
|
-
};
|
|
14289
|
-
process.once("SIGINT", sigShutdown);
|
|
14290
|
-
process.once("SIGTERM", sigShutdown);
|
|
14291
|
-
process.once("exit", sigShutdown);
|
|
15195
|
+
});
|
|
14292
15196
|
await chatCommand({
|
|
14293
15197
|
model: opts.model ?? "deepseek-v4-flash",
|
|
14294
15198
|
harvest: opts.harvest ?? false,
|
|
@@ -14306,35 +15210,35 @@ async function codeCommand(opts = {}) {
|
|
|
14306
15210
|
import { writeFileSync as writeFileSync7 } from "fs";
|
|
14307
15211
|
import { basename as basename3 } from "path";
|
|
14308
15212
|
import { render as render2 } from "ink";
|
|
14309
|
-
import
|
|
15213
|
+
import React29 from "react";
|
|
14310
15214
|
|
|
14311
15215
|
// src/cli/ui/DiffApp.tsx
|
|
14312
|
-
import { Box as
|
|
14313
|
-
import
|
|
15216
|
+
import { Box as Box25, Static as Static2, Text as Text22, useApp as useApp3, useInput } from "ink";
|
|
15217
|
+
import React28, { useState as useState13 } from "react";
|
|
14314
15218
|
|
|
14315
15219
|
// src/cli/ui/RecordView.tsx
|
|
14316
|
-
import { Box as
|
|
14317
|
-
import
|
|
15220
|
+
import { Box as Box24, Text as Text21 } from "ink";
|
|
15221
|
+
import React27 from "react";
|
|
14318
15222
|
function RecordView({ rec, compact: compact2 = false }) {
|
|
14319
15223
|
const toolArgsMax = compact2 ? 120 : 200;
|
|
14320
15224
|
const toolContentMax = compact2 ? 200 : 400;
|
|
14321
15225
|
if (rec.role === "user") {
|
|
14322
15226
|
const content = rec.content.includes("\n") ? rec.content.split("\n").join("\n ") : rec.content;
|
|
14323
|
-
return /* @__PURE__ */
|
|
15227
|
+
return /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text21, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React27.createElement(Text21, null, content));
|
|
14324
15228
|
}
|
|
14325
15229
|
if (rec.role === "assistant_final") {
|
|
14326
|
-
return /* @__PURE__ */
|
|
15230
|
+
return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React27.createElement(Box24, null, /* @__PURE__ */ React27.createElement(Text21, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React27.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React27.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React27.createElement(Text21, null, rec.content) : /* @__PURE__ */ React27.createElement(Text21, { dimColor: true, italic: true }, "(tool-call response only)"));
|
|
14327
15231
|
}
|
|
14328
15232
|
if (rec.role === "tool") {
|
|
14329
|
-
return /* @__PURE__ */
|
|
15233
|
+
return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text21, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " args: ", truncate2(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " \u2192 ", truncate2(rec.content, toolContentMax)));
|
|
14330
15234
|
}
|
|
14331
15235
|
if (rec.role === "error") {
|
|
14332
|
-
return /* @__PURE__ */
|
|
15236
|
+
return /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text21, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React27.createElement(Text21, { color: "red" }, rec.error ?? rec.content));
|
|
14333
15237
|
}
|
|
14334
15238
|
if (rec.role === "done" || rec.role === "assistant_delta") {
|
|
14335
15239
|
return null;
|
|
14336
15240
|
}
|
|
14337
|
-
return /* @__PURE__ */
|
|
15241
|
+
return /* @__PURE__ */ React27.createElement(Box24, null, /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, "[", rec.role, "] ", rec.content));
|
|
14338
15242
|
}
|
|
14339
15243
|
function CacheBadge({ usage }) {
|
|
14340
15244
|
const hit = usage.prompt_cache_hit_tokens ?? 0;
|
|
@@ -14343,7 +15247,7 @@ function CacheBadge({ usage }) {
|
|
|
14343
15247
|
if (total === 0) return null;
|
|
14344
15248
|
const pct2 = hit / total * 100;
|
|
14345
15249
|
const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
|
|
14346
|
-
return /* @__PURE__ */
|
|
15250
|
+
return /* @__PURE__ */ React27.createElement(Text21, null, /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React27.createElement(Text21, { color }, pct2.toFixed(1), "%"));
|
|
14347
15251
|
}
|
|
14348
15252
|
function truncate2(s, max) {
|
|
14349
15253
|
return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
|
|
@@ -14355,7 +15259,7 @@ function DiffApp({ report }) {
|
|
|
14355
15259
|
const maxIdx = Math.max(0, report.pairs.length - 1);
|
|
14356
15260
|
const initialIdx = report.firstDivergenceTurn ? report.pairs.findIndex((p) => p.turn === report.firstDivergenceTurn) : 0;
|
|
14357
15261
|
const [idx, setIdx] = useState13(Math.max(0, initialIdx));
|
|
14358
|
-
|
|
15262
|
+
useInput((input, key) => {
|
|
14359
15263
|
if (input === "q" || key.ctrl && input === "c") {
|
|
14360
15264
|
exit2();
|
|
14361
15265
|
return;
|
|
@@ -14377,7 +15281,7 @@ function DiffApp({ report }) {
|
|
|
14377
15281
|
}
|
|
14378
15282
|
});
|
|
14379
15283
|
const pair = report.pairs[idx];
|
|
14380
|
-
return /* @__PURE__ */
|
|
15284
|
+
return /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React28.createElement(DiffHeader, { report }), /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React28.createElement(Text22, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React28.createElement(Text22, null, pair ? /* @__PURE__ */ React28.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React28.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React28.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React28.createElement(Text22, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React28.createElement(Text22, null, pair.divergenceNote)) : null, /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "j"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "k"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "N"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "g"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "q"), " ", "quit")));
|
|
14381
15285
|
}
|
|
14382
15286
|
function DiffHeader({ report }) {
|
|
14383
15287
|
const a = report.a;
|
|
@@ -14395,15 +15299,15 @@ function DiffHeader({ report }) {
|
|
|
14395
15299
|
} else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
|
|
14396
15300
|
prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
|
|
14397
15301
|
}
|
|
14398
|
-
return /* @__PURE__ */
|
|
15302
|
+
return /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React28.createElement(Box25, { justifyContent: "space-between" }, /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React28.createElement(Text22, { color: "blue" }, a.label), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " vs B="), /* @__PURE__ */ React28.createElement(Text22, { color: "magenta" }, b.label)), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, "cache "), /* @__PURE__ */ React28.createElement(Text22, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React28.createElement(Text22, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React28.createElement(Text22, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, "cost "), /* @__PURE__ */ React28.createElement(Text22, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React28.createElement(Text22, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React28.createElement(Text22, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, "model calls "), /* @__PURE__ */ React28.createElement(Text22, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true, italic: true }, prefixLine)) : null);
|
|
14399
15303
|
}
|
|
14400
15304
|
function Pane({
|
|
14401
15305
|
label,
|
|
14402
15306
|
headerColor,
|
|
14403
15307
|
records
|
|
14404
15308
|
}) {
|
|
14405
|
-
return /* @__PURE__ */
|
|
14406
|
-
|
|
15309
|
+
return /* @__PURE__ */ React28.createElement(
|
|
15310
|
+
Box25,
|
|
14407
15311
|
{
|
|
14408
15312
|
flexDirection: "column",
|
|
14409
15313
|
flexGrow: 1,
|
|
@@ -14411,21 +15315,21 @@ function Pane({
|
|
|
14411
15315
|
borderStyle: "single",
|
|
14412
15316
|
borderColor: headerColor
|
|
14413
15317
|
},
|
|
14414
|
-
/* @__PURE__ */
|
|
14415
|
-
records.length === 0 ? /* @__PURE__ */
|
|
15318
|
+
/* @__PURE__ */ React28.createElement(Text22, { color: headerColor, bold: true }, label),
|
|
15319
|
+
records.length === 0 ? /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React28.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React28.createElement(RecordView, { key, rec, compact: true }))
|
|
14416
15320
|
);
|
|
14417
15321
|
}
|
|
14418
15322
|
function KindBadge({ kind }) {
|
|
14419
15323
|
if (kind === "match") {
|
|
14420
|
-
return /* @__PURE__ */
|
|
15324
|
+
return /* @__PURE__ */ React28.createElement(Text22, { color: "green" }, "\u2713 match");
|
|
14421
15325
|
}
|
|
14422
15326
|
if (kind === "diverge") {
|
|
14423
|
-
return /* @__PURE__ */
|
|
15327
|
+
return /* @__PURE__ */ React28.createElement(Text22, { color: "yellow" }, "\u2605 diverge");
|
|
14424
15328
|
}
|
|
14425
15329
|
if (kind === "only_in_a") {
|
|
14426
|
-
return /* @__PURE__ */
|
|
15330
|
+
return /* @__PURE__ */ React28.createElement(Text22, { color: "blue" }, "\u2190 only in A");
|
|
14427
15331
|
}
|
|
14428
|
-
return /* @__PURE__ */
|
|
15332
|
+
return /* @__PURE__ */ React28.createElement(Text22, { color: "magenta" }, "\u2192 only in B");
|
|
14429
15333
|
}
|
|
14430
15334
|
function paneRecords(pair, side) {
|
|
14431
15335
|
if (!pair) return [];
|
|
@@ -14456,7 +15360,7 @@ markdown report written to ${opts.mdPath}`);
|
|
|
14456
15360
|
return;
|
|
14457
15361
|
}
|
|
14458
15362
|
if (wantTui) {
|
|
14459
|
-
const { waitUntilExit } = render2(
|
|
15363
|
+
const { waitUntilExit } = render2(React29.createElement(DiffApp, { report }), {
|
|
14460
15364
|
exitOnCtrlC: true,
|
|
14461
15365
|
patchConsole: false
|
|
14462
15366
|
});
|
|
@@ -14597,16 +15501,16 @@ function pad2(s, width) {
|
|
|
14597
15501
|
|
|
14598
15502
|
// src/cli/commands/replay.ts
|
|
14599
15503
|
import { render as render3 } from "ink";
|
|
14600
|
-
import
|
|
15504
|
+
import React31 from "react";
|
|
14601
15505
|
|
|
14602
15506
|
// src/cli/ui/ReplayApp.tsx
|
|
14603
|
-
import { Box as
|
|
14604
|
-
import
|
|
15507
|
+
import { Box as Box26, Static as Static3, Text as Text23, useApp as useApp4, useInput as useInput2 } from "ink";
|
|
15508
|
+
import React30, { useMemo as useMemo4, useState as useState14 } from "react";
|
|
14605
15509
|
function ReplayApp({ meta, pages }) {
|
|
14606
15510
|
const { exit: exit2 } = useApp4();
|
|
14607
15511
|
const maxIdx = Math.max(0, pages.length - 1);
|
|
14608
15512
|
const [idx, setIdx] = useState14(maxIdx);
|
|
14609
|
-
|
|
15513
|
+
useInput2((input, key) => {
|
|
14610
15514
|
if (input === "q" || key.ctrl && input === "c") {
|
|
14611
15515
|
exit2();
|
|
14612
15516
|
return;
|
|
@@ -14641,14 +15545,14 @@ function ReplayApp({ meta, pages }) {
|
|
|
14641
15545
|
const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
|
|
14642
15546
|
const currentPage = pages[idx];
|
|
14643
15547
|
const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
|
|
14644
|
-
return /* @__PURE__ */
|
|
15548
|
+
return /* @__PURE__ */ React30.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React30.createElement(
|
|
14645
15549
|
StatsPanel,
|
|
14646
15550
|
{
|
|
14647
15551
|
summary,
|
|
14648
15552
|
model: cumStats.models[0] ?? meta?.model ?? "?",
|
|
14649
15553
|
prefixHash
|
|
14650
15554
|
}
|
|
14651
|
-
), /* @__PURE__ */
|
|
15555
|
+
), /* @__PURE__ */ React30.createElement(Box26, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React30.createElement(Box26, { justifyContent: "space-between" }, /* @__PURE__ */ React30.createElement(Text23, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React30.createElement(Text23, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React30.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React30.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React30.createElement(Text23, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React30.createElement(Box26, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React30.createElement(Text23, { dimColor: true }, /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "j"), "/", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "k"), "/", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "q"), " quit")));
|
|
14652
15556
|
}
|
|
14653
15557
|
|
|
14654
15558
|
// src/cli/commands/replay.ts
|
|
@@ -14660,7 +15564,7 @@ async function replayCommand(opts) {
|
|
|
14660
15564
|
}
|
|
14661
15565
|
const { parsed } = replayFromFile(opts.path);
|
|
14662
15566
|
const pages = groupRecordsByTurn(parsed.records);
|
|
14663
|
-
const { waitUntilExit } = render3(
|
|
15567
|
+
const { waitUntilExit } = render3(React31.createElement(ReplayApp, { meta: parsed.meta, pages }), {
|
|
14664
15568
|
exitOnCtrlC: true,
|
|
14665
15569
|
patchConsole: false
|
|
14666
15570
|
});
|
|
@@ -14754,12 +15658,12 @@ function oneLine2(s, max = 200) {
|
|
|
14754
15658
|
}
|
|
14755
15659
|
|
|
14756
15660
|
// src/cli/commands/run.ts
|
|
14757
|
-
import { stdin, stdout } from "process";
|
|
15661
|
+
import { stdin as stdin2, stdout } from "process";
|
|
14758
15662
|
import { createInterface } from "readline/promises";
|
|
14759
15663
|
async function ensureApiKey() {
|
|
14760
15664
|
const existing = loadApiKey();
|
|
14761
15665
|
if (existing) return existing;
|
|
14762
|
-
if (!
|
|
15666
|
+
if (!stdin2.isTTY) {
|
|
14763
15667
|
process.stderr.write(
|
|
14764
15668
|
"DEEPSEEK_API_KEY is not set and stdin is not a TTY (cannot prompt).\nSet the env var, or run `reasonix chat` once interactively to save a key.\n"
|
|
14765
15669
|
);
|
|
@@ -14768,7 +15672,7 @@ async function ensureApiKey() {
|
|
|
14768
15672
|
process.stdout.write(
|
|
14769
15673
|
"DeepSeek API key not configured.\nGet one at https://platform.deepseek.com/api_keys\n"
|
|
14770
15674
|
);
|
|
14771
|
-
const rl = createInterface({ input:
|
|
15675
|
+
const rl = createInterface({ input: stdin2, output: stdout });
|
|
14772
15676
|
try {
|
|
14773
15677
|
while (true) {
|
|
14774
15678
|
const answer = (await rl.question("API key \u203A ")).trim();
|
|
@@ -14965,12 +15869,12 @@ function truncate3(s, max) {
|
|
|
14965
15869
|
|
|
14966
15870
|
// src/cli/commands/setup.tsx
|
|
14967
15871
|
import { render as render4 } from "ink";
|
|
14968
|
-
import
|
|
15872
|
+
import React33 from "react";
|
|
14969
15873
|
|
|
14970
15874
|
// src/cli/ui/Wizard.tsx
|
|
14971
|
-
import { Box as
|
|
15875
|
+
import { Box as Box27, Text as Text24, useApp as useApp5, useInput as useInput3 } from "ink";
|
|
14972
15876
|
import TextInput2 from "ink-text-input";
|
|
14973
|
-
import
|
|
15877
|
+
import React32, { useState as useState15 } from "react";
|
|
14974
15878
|
|
|
14975
15879
|
// src/cli/ui/presets.ts
|
|
14976
15880
|
var PRESETS = {
|
|
@@ -15014,11 +15918,11 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15014
15918
|
catalogArgs: {}
|
|
15015
15919
|
});
|
|
15016
15920
|
const [error, setError] = useState15(null);
|
|
15017
|
-
|
|
15921
|
+
useInput3((_input, key) => {
|
|
15018
15922
|
if (key.escape && step !== "saved" && onCancel) onCancel();
|
|
15019
15923
|
});
|
|
15020
15924
|
if (step === "apiKey") {
|
|
15021
|
-
return /* @__PURE__ */
|
|
15925
|
+
return /* @__PURE__ */ React32.createElement(
|
|
15022
15926
|
ApiKeyStep,
|
|
15023
15927
|
{
|
|
15024
15928
|
onSubmit: (key) => {
|
|
@@ -15032,7 +15936,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15032
15936
|
);
|
|
15033
15937
|
}
|
|
15034
15938
|
if (step === "preset") {
|
|
15035
|
-
return /* @__PURE__ */
|
|
15939
|
+
return /* @__PURE__ */ React32.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React32.createElement(
|
|
15036
15940
|
SingleSelect,
|
|
15037
15941
|
{
|
|
15038
15942
|
items: presetItems(),
|
|
@@ -15042,10 +15946,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15042
15946
|
setStep("mcp");
|
|
15043
15947
|
}
|
|
15044
15948
|
}
|
|
15045
|
-
), /* @__PURE__ */
|
|
15949
|
+
), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel")));
|
|
15046
15950
|
}
|
|
15047
15951
|
if (step === "mcp") {
|
|
15048
|
-
return /* @__PURE__ */
|
|
15952
|
+
return /* @__PURE__ */ React32.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React32.createElement(
|
|
15049
15953
|
MultiSelect,
|
|
15050
15954
|
{
|
|
15051
15955
|
items: mcpItems(),
|
|
@@ -15070,7 +15974,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15070
15974
|
}
|
|
15071
15975
|
const currentName = pending[0];
|
|
15072
15976
|
const entry = CATALOG_BY_NAME.get(currentName);
|
|
15073
|
-
return /* @__PURE__ */
|
|
15977
|
+
return /* @__PURE__ */ React32.createElement(
|
|
15074
15978
|
McpArgsStep,
|
|
15075
15979
|
{
|
|
15076
15980
|
entry,
|
|
@@ -15088,7 +15992,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15088
15992
|
}
|
|
15089
15993
|
if (step === "review") {
|
|
15090
15994
|
const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
|
|
15091
|
-
return /* @__PURE__ */
|
|
15995
|
+
return /* @__PURE__ */ React32.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column" }, /* @__PURE__ */ React32.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React32.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React32.createElement(
|
|
15092
15996
|
SummaryLine,
|
|
15093
15997
|
{
|
|
15094
15998
|
label: "MCP",
|
|
@@ -15096,8 +16000,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15096
16000
|
}
|
|
15097
16001
|
), specs.map((spec, i) => (
|
|
15098
16002
|
// biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
|
|
15099
|
-
/* @__PURE__ */
|
|
15100
|
-
)), /* @__PURE__ */
|
|
16003
|
+
/* @__PURE__ */ React32.createElement(Box27, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "\xB7 ", spec))
|
|
16004
|
+
)), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { color: "red" }, error)) : null, /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "[Enter] save \xB7 [Esc] cancel"))), /* @__PURE__ */ React32.createElement(
|
|
15101
16005
|
ReviewConfirm,
|
|
15102
16006
|
{
|
|
15103
16007
|
onConfirm: () => {
|
|
@@ -15123,7 +16027,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15123
16027
|
}
|
|
15124
16028
|
));
|
|
15125
16029
|
}
|
|
15126
|
-
return /* @__PURE__ */
|
|
16030
|
+
return /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "[Enter] to exit")), /* @__PURE__ */ React32.createElement(ExitOnEnter, { onExit: exit2 }));
|
|
15127
16031
|
}
|
|
15128
16032
|
function ApiKeyStep({
|
|
15129
16033
|
onSubmit,
|
|
@@ -15131,7 +16035,7 @@ function ApiKeyStep({
|
|
|
15131
16035
|
onError
|
|
15132
16036
|
}) {
|
|
15133
16037
|
const [value, setValue] = useState15("");
|
|
15134
|
-
return /* @__PURE__ */
|
|
16038
|
+
return /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React32.createElement(
|
|
15135
16039
|
TextInput2,
|
|
15136
16040
|
{
|
|
15137
16041
|
value,
|
|
@@ -15148,7 +16052,7 @@ function ApiKeyStep({
|
|
|
15148
16052
|
mask: "\u2022",
|
|
15149
16053
|
placeholder: "sk-..."
|
|
15150
16054
|
}
|
|
15151
|
-
)), error ? /* @__PURE__ */
|
|
16055
|
+
)), error ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { color: "red" }, error)) : value ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "preview: ", redactKey(value))) : null);
|
|
15152
16056
|
}
|
|
15153
16057
|
function McpArgsStep({
|
|
15154
16058
|
entry,
|
|
@@ -15157,7 +16061,7 @@ function McpArgsStep({
|
|
|
15157
16061
|
onError
|
|
15158
16062
|
}) {
|
|
15159
16063
|
const [value, setValue] = useState15("");
|
|
15160
|
-
return /* @__PURE__ */
|
|
16064
|
+
return /* @__PURE__ */ React32.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column" }, /* @__PURE__ */ React32.createElement(Text24, null, entry.summary), entry.note ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Required parameter: "), /* @__PURE__ */ React32.createElement(Text24, { bold: true }, entry.userArgs)), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React32.createElement(
|
|
15161
16065
|
TextInput2,
|
|
15162
16066
|
{
|
|
15163
16067
|
value,
|
|
@@ -15173,16 +16077,16 @@ function McpArgsStep({
|
|
|
15173
16077
|
},
|
|
15174
16078
|
placeholder: placeholderFor(entry)
|
|
15175
16079
|
}
|
|
15176
|
-
)), error ? /* @__PURE__ */
|
|
16080
|
+
)), error ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { color: "red" }, error)) : null));
|
|
15177
16081
|
}
|
|
15178
16082
|
function ReviewConfirm({ onConfirm }) {
|
|
15179
|
-
|
|
16083
|
+
useInput3((_i, key) => {
|
|
15180
16084
|
if (key.return) onConfirm();
|
|
15181
16085
|
});
|
|
15182
16086
|
return null;
|
|
15183
16087
|
}
|
|
15184
16088
|
function ExitOnEnter({ onExit }) {
|
|
15185
|
-
|
|
16089
|
+
useInput3((_i, key) => {
|
|
15186
16090
|
if (key.return) onExit();
|
|
15187
16091
|
});
|
|
15188
16092
|
return null;
|
|
@@ -15193,10 +16097,10 @@ function StepFrame({
|
|
|
15193
16097
|
total,
|
|
15194
16098
|
children
|
|
15195
16099
|
}) {
|
|
15196
|
-
return /* @__PURE__ */
|
|
16100
|
+
return /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React32.createElement(Box27, null, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1, flexDirection: "column" }, children));
|
|
15197
16101
|
}
|
|
15198
16102
|
function SummaryLine({ label, value }) {
|
|
15199
|
-
return /* @__PURE__ */
|
|
16103
|
+
return /* @__PURE__ */ React32.createElement(Box27, null, /* @__PURE__ */ React32.createElement(Text24, null, label.padEnd(12)), /* @__PURE__ */ React32.createElement(Text24, { bold: true }, value));
|
|
15200
16104
|
}
|
|
15201
16105
|
function presetItems() {
|
|
15202
16106
|
return ["fast", "smart", "max"].map((name) => ({
|
|
@@ -15252,7 +16156,7 @@ async function setupCommand(_opts = {}) {
|
|
|
15252
16156
|
const existingKey = loadApiKey();
|
|
15253
16157
|
const existing = readConfig();
|
|
15254
16158
|
const { waitUntilExit, unmount } = render4(
|
|
15255
|
-
/* @__PURE__ */
|
|
16159
|
+
/* @__PURE__ */ React33.createElement(
|
|
15256
16160
|
Wizard,
|
|
15257
16161
|
{
|
|
15258
16162
|
existingApiKey: existingKey,
|