reasonix 0.7.2 → 0.7.4
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 +1133 -520
- 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 React25, { useState as useState12 } from "react";
|
|
7117
7117
|
|
|
7118
7118
|
// src/cli/ui/App.tsx
|
|
7119
|
-
import { Box as
|
|
7120
|
-
import
|
|
7119
|
+
import { Box as Box20, Static, useApp, useStdout as useStdout5 } from "ink";
|
|
7120
|
+
import React22, { 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";
|
|
@@ -7442,11 +7442,348 @@ function FileRow({ path, isSelected }) {
|
|
|
7442
7442
|
|
|
7443
7443
|
// src/cli/ui/ChoiceConfirm.tsx
|
|
7444
7444
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
7445
|
-
import
|
|
7445
|
+
import React4 from "react";
|
|
7446
|
+
|
|
7447
|
+
// src/cli/ui/Select.tsx
|
|
7448
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
7449
|
+
import React3, { useState } from "react";
|
|
7450
|
+
|
|
7451
|
+
// src/cli/ui/keystroke-context.tsx
|
|
7452
|
+
import React2, { createContext, useContext, useEffect, useRef } from "react";
|
|
7453
|
+
|
|
7454
|
+
// src/cli/ui/stdin-reader.ts
|
|
7455
|
+
import { stdin } from "process";
|
|
7456
|
+
var ESC_TIMEOUT_MS = 250;
|
|
7457
|
+
var PASTE_END = "\x1B[201~";
|
|
7458
|
+
var PASTE_START_BARE = "[200~";
|
|
7459
|
+
var PASTE_END_BARE = "[201~";
|
|
7460
|
+
var CSI_TAIL_MAP = [
|
|
7461
|
+
{ tail: "A", ev: { input: "", upArrow: true } },
|
|
7462
|
+
{ tail: "B", ev: { input: "", downArrow: true } },
|
|
7463
|
+
{ tail: "C", ev: { input: "", rightArrow: true } },
|
|
7464
|
+
{ tail: "D", ev: { input: "", leftArrow: true } },
|
|
7465
|
+
{ tail: "H", ev: { input: "", home: true } },
|
|
7466
|
+
{ tail: "F", ev: { input: "", end: true } },
|
|
7467
|
+
{ tail: "1~", ev: { input: "", home: true } },
|
|
7468
|
+
{ tail: "4~", ev: { input: "", end: true } },
|
|
7469
|
+
{ tail: "5~", ev: { input: "", pageUp: true } },
|
|
7470
|
+
{ tail: "6~", ev: { input: "", pageDown: true } },
|
|
7471
|
+
{ tail: "3~", ev: { input: "", delete: true } },
|
|
7472
|
+
{ tail: "Z", ev: { input: "", shift: true, tab: true } },
|
|
7473
|
+
// modifyOtherKeys (xterm CSI > 4 ; 2 m) sequences for Enter with
|
|
7474
|
+
// modifiers. Only fired when App.tsx has enabled the mode at
|
|
7475
|
+
// startup; otherwise Shift+Enter stays indistinguishable from Enter.
|
|
7476
|
+
// Modifier encoding: 2=shift, 3=alt, 4=alt+shift, 5=ctrl,
|
|
7477
|
+
// 6=ctrl+shift, 7=ctrl+alt, 8=ctrl+alt+shift. Keycode 13 = Enter.
|
|
7478
|
+
{ tail: "27;2;13~", ev: { input: "", return: true, shift: true } },
|
|
7479
|
+
{ tail: "27;5;13~", ev: { input: "", return: true, ctrl: true } },
|
|
7480
|
+
{ tail: "27;6;13~", ev: { input: "", return: true, ctrl: true, shift: true } },
|
|
7481
|
+
// Kitty keyboard protocol — same idea, different envelope:
|
|
7482
|
+
// `\x1b[<keycode>;<mod>u`. Some terminals (kitty, recent Windows
|
|
7483
|
+
// Terminal previews) prefer this shape. Harmless to map here too.
|
|
7484
|
+
{ tail: "13;2u", ev: { input: "", return: true, shift: true } },
|
|
7485
|
+
{ tail: "13;5u", ev: { input: "", return: true, ctrl: true } },
|
|
7486
|
+
{ tail: "13;6u", ev: { input: "", return: true, ctrl: true, shift: true } }
|
|
7487
|
+
];
|
|
7488
|
+
var SS3_MAP = {
|
|
7489
|
+
A: { input: "", upArrow: true },
|
|
7490
|
+
B: { input: "", downArrow: true },
|
|
7491
|
+
C: { input: "", rightArrow: true },
|
|
7492
|
+
D: { input: "", leftArrow: true },
|
|
7493
|
+
H: { input: "", home: true },
|
|
7494
|
+
F: { input: "", end: true }
|
|
7495
|
+
};
|
|
7496
|
+
function tryEscapelessCsi(chunk, i) {
|
|
7497
|
+
if (chunk[i] !== "[") return null;
|
|
7498
|
+
for (const entry of CSI_TAIL_MAP) {
|
|
7499
|
+
const candidate = `[${entry.tail}`;
|
|
7500
|
+
if (chunk.slice(i, i + candidate.length) === candidate) {
|
|
7501
|
+
return { advance: candidate.length, ev: entry.ev };
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
return null;
|
|
7505
|
+
}
|
|
7506
|
+
function isCsiFinal(ch) {
|
|
7507
|
+
const code = ch.charCodeAt(0);
|
|
7508
|
+
return code >= 64 && code <= 126;
|
|
7509
|
+
}
|
|
7510
|
+
function lookupCsi(tail) {
|
|
7511
|
+
for (const entry of CSI_TAIL_MAP) {
|
|
7512
|
+
if (entry.tail === tail) return entry.ev;
|
|
7513
|
+
}
|
|
7514
|
+
return null;
|
|
7515
|
+
}
|
|
7516
|
+
var StdinReader = class {
|
|
7517
|
+
subscribers = /* @__PURE__ */ new Set();
|
|
7518
|
+
state = "idle";
|
|
7519
|
+
/** Buffer for partial sequences across chunks. */
|
|
7520
|
+
csiBuf = "";
|
|
7521
|
+
/** Buffer for paste content. */
|
|
7522
|
+
pasteBuf = "";
|
|
7523
|
+
escTimer = null;
|
|
7524
|
+
started = false;
|
|
7525
|
+
/** The actual `data` listener — kept as a field so `stop()` can detach it. */
|
|
7526
|
+
listener = null;
|
|
7527
|
+
start() {
|
|
7528
|
+
if (this.started) return;
|
|
7529
|
+
if (!stdin.isTTY) {
|
|
7530
|
+
return;
|
|
7531
|
+
}
|
|
7532
|
+
stdin.setRawMode(true);
|
|
7533
|
+
stdin.setEncoding("utf8");
|
|
7534
|
+
stdin.resume();
|
|
7535
|
+
this.listener = (chunk) => this.handleChunk(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
|
|
7536
|
+
stdin.on("data", this.listener);
|
|
7537
|
+
this.started = true;
|
|
7538
|
+
}
|
|
7539
|
+
stop() {
|
|
7540
|
+
if (!this.started) return;
|
|
7541
|
+
if (this.listener) {
|
|
7542
|
+
stdin.off("data", this.listener);
|
|
7543
|
+
this.listener = null;
|
|
7544
|
+
}
|
|
7545
|
+
if (stdin.isTTY) {
|
|
7546
|
+
try {
|
|
7547
|
+
stdin.setRawMode(false);
|
|
7548
|
+
} catch {
|
|
7549
|
+
}
|
|
7550
|
+
}
|
|
7551
|
+
stdin.pause();
|
|
7552
|
+
this.cancelEscTimer();
|
|
7553
|
+
this.state = "idle";
|
|
7554
|
+
this.csiBuf = "";
|
|
7555
|
+
this.pasteBuf = "";
|
|
7556
|
+
this.started = false;
|
|
7557
|
+
}
|
|
7558
|
+
/**
|
|
7559
|
+
* Subscribe to parsed key events. Returns an unsubscribe function.
|
|
7560
|
+
* Multiple subscribers are supported — every event fans out to all
|
|
7561
|
+
* of them; the React Context layer above uses one subscriber and
|
|
7562
|
+
* dispatches further to its own consumer list.
|
|
7563
|
+
*/
|
|
7564
|
+
subscribe(fn) {
|
|
7565
|
+
this.subscribers.add(fn);
|
|
7566
|
+
return () => {
|
|
7567
|
+
this.subscribers.delete(fn);
|
|
7568
|
+
};
|
|
7569
|
+
}
|
|
7570
|
+
/**
|
|
7571
|
+
* Inject a chunk of bytes as if it came from stdin. Used by tests
|
|
7572
|
+
* to drive the parser without a real TTY.
|
|
7573
|
+
*/
|
|
7574
|
+
feed(chunk) {
|
|
7575
|
+
this.handleChunk(chunk);
|
|
7576
|
+
}
|
|
7577
|
+
dispatch(ev) {
|
|
7578
|
+
for (const sub of this.subscribers) sub(ev);
|
|
7579
|
+
}
|
|
7580
|
+
cancelEscTimer() {
|
|
7581
|
+
if (this.escTimer) {
|
|
7582
|
+
clearTimeout(this.escTimer);
|
|
7583
|
+
this.escTimer = null;
|
|
7584
|
+
}
|
|
7585
|
+
}
|
|
7586
|
+
scheduleEscTimer() {
|
|
7587
|
+
this.cancelEscTimer();
|
|
7588
|
+
this.escTimer = setTimeout(() => {
|
|
7589
|
+
if (this.state === "esc") {
|
|
7590
|
+
this.state = "idle";
|
|
7591
|
+
this.dispatch({ input: "", escape: true });
|
|
7592
|
+
}
|
|
7593
|
+
}, ESC_TIMEOUT_MS);
|
|
7594
|
+
}
|
|
7595
|
+
handleChunk(chunk) {
|
|
7596
|
+
this.cancelEscTimer();
|
|
7597
|
+
let i = 0;
|
|
7598
|
+
while (i < chunk.length) {
|
|
7599
|
+
if (this.state === "paste") {
|
|
7600
|
+
const endA = chunk.indexOf(PASTE_END, i);
|
|
7601
|
+
const endB = chunk.indexOf(PASTE_END_BARE, i);
|
|
7602
|
+
let endIdx = -1;
|
|
7603
|
+
let endLen = 0;
|
|
7604
|
+
if (endA !== -1 && (endB === -1 || endA <= endB)) {
|
|
7605
|
+
endIdx = endA;
|
|
7606
|
+
endLen = PASTE_END.length;
|
|
7607
|
+
} else if (endB !== -1) {
|
|
7608
|
+
endIdx = endB;
|
|
7609
|
+
endLen = PASTE_END_BARE.length;
|
|
7610
|
+
}
|
|
7611
|
+
if (endIdx === -1) {
|
|
7612
|
+
this.pasteBuf += chunk.slice(i);
|
|
7613
|
+
i = chunk.length;
|
|
7614
|
+
break;
|
|
7615
|
+
}
|
|
7616
|
+
this.pasteBuf += chunk.slice(i, endIdx);
|
|
7617
|
+
this.dispatch({ input: this.pasteBuf, paste: true });
|
|
7618
|
+
this.pasteBuf = "";
|
|
7619
|
+
this.state = "idle";
|
|
7620
|
+
i = endIdx + endLen;
|
|
7621
|
+
continue;
|
|
7622
|
+
}
|
|
7623
|
+
if (this.state === "csi") {
|
|
7624
|
+
const ch2 = chunk[i];
|
|
7625
|
+
this.csiBuf += ch2;
|
|
7626
|
+
if (isCsiFinal(ch2)) {
|
|
7627
|
+
this.dispatchCsi(this.csiBuf);
|
|
7628
|
+
this.csiBuf = "";
|
|
7629
|
+
if (this.state === "csi") this.state = "idle";
|
|
7630
|
+
}
|
|
7631
|
+
i++;
|
|
7632
|
+
continue;
|
|
7633
|
+
}
|
|
7634
|
+
if (this.state === "ss3") {
|
|
7635
|
+
const ev = SS3_MAP[chunk[i]];
|
|
7636
|
+
if (ev) this.dispatch(ev);
|
|
7637
|
+
this.state = "idle";
|
|
7638
|
+
i++;
|
|
7639
|
+
continue;
|
|
7640
|
+
}
|
|
7641
|
+
if (this.state === "esc") {
|
|
7642
|
+
const ch2 = chunk[i];
|
|
7643
|
+
if (ch2 === "[") {
|
|
7644
|
+
this.state = "csi";
|
|
7645
|
+
this.csiBuf = "";
|
|
7646
|
+
i++;
|
|
7647
|
+
continue;
|
|
7648
|
+
}
|
|
7649
|
+
if (ch2 === "O") {
|
|
7650
|
+
this.state = "ss3";
|
|
7651
|
+
i++;
|
|
7652
|
+
continue;
|
|
7653
|
+
}
|
|
7654
|
+
this.dispatch({ input: ch2, meta: true });
|
|
7655
|
+
this.state = "idle";
|
|
7656
|
+
i++;
|
|
7657
|
+
continue;
|
|
7658
|
+
}
|
|
7659
|
+
const ch = chunk[i];
|
|
7660
|
+
if (ch === "\x1B") {
|
|
7661
|
+
this.state = "esc";
|
|
7662
|
+
i++;
|
|
7663
|
+
continue;
|
|
7664
|
+
}
|
|
7665
|
+
if (chunk.slice(i, i + PASTE_START_BARE.length) === PASTE_START_BARE) {
|
|
7666
|
+
this.state = "paste";
|
|
7667
|
+
this.pasteBuf = "";
|
|
7668
|
+
i += PASTE_START_BARE.length;
|
|
7669
|
+
continue;
|
|
7670
|
+
}
|
|
7671
|
+
const escapeless = tryEscapelessCsi(chunk, i);
|
|
7672
|
+
if (escapeless) {
|
|
7673
|
+
this.dispatch(escapeless.ev);
|
|
7674
|
+
i += escapeless.advance;
|
|
7675
|
+
continue;
|
|
7676
|
+
}
|
|
7677
|
+
if (ch === "\r") {
|
|
7678
|
+
this.dispatch({ input: "", return: true });
|
|
7679
|
+
i++;
|
|
7680
|
+
continue;
|
|
7681
|
+
}
|
|
7682
|
+
if (ch === "\n") {
|
|
7683
|
+
this.dispatch({ input: "j", ctrl: true });
|
|
7684
|
+
i++;
|
|
7685
|
+
continue;
|
|
7686
|
+
}
|
|
7687
|
+
if (ch === " ") {
|
|
7688
|
+
this.dispatch({ input: "", tab: true });
|
|
7689
|
+
i++;
|
|
7690
|
+
continue;
|
|
7691
|
+
}
|
|
7692
|
+
if (ch === "\x7F" || ch === "\b") {
|
|
7693
|
+
this.dispatch({ input: "", backspace: true });
|
|
7694
|
+
i++;
|
|
7695
|
+
continue;
|
|
7696
|
+
}
|
|
7697
|
+
if (ch === "") {
|
|
7698
|
+
this.dispatch({ input: "c", ctrl: true });
|
|
7699
|
+
i++;
|
|
7700
|
+
continue;
|
|
7701
|
+
}
|
|
7702
|
+
const code = ch.charCodeAt(0);
|
|
7703
|
+
if (code >= 1 && code <= 26) {
|
|
7704
|
+
const letter = String.fromCharCode(96 + code);
|
|
7705
|
+
this.dispatch({ input: letter, ctrl: true });
|
|
7706
|
+
i++;
|
|
7707
|
+
continue;
|
|
7708
|
+
}
|
|
7709
|
+
let end = i + 1;
|
|
7710
|
+
while (end < chunk.length) {
|
|
7711
|
+
const c = chunk[end];
|
|
7712
|
+
if (c === "\x1B" || c === "\r" || c === "\n" || c === " ") break;
|
|
7713
|
+
if (c === "\x7F" || c === "\b" || c === "") break;
|
|
7714
|
+
const cc = c.charCodeAt(0);
|
|
7715
|
+
if (cc >= 1 && cc <= 26) break;
|
|
7716
|
+
if (c === "[" && tryEscapelessCsi(chunk, end)) break;
|
|
7717
|
+
if (chunk.slice(end, end + PASTE_START_BARE.length) === PASTE_START_BARE) break;
|
|
7718
|
+
end++;
|
|
7719
|
+
}
|
|
7720
|
+
this.dispatch({ input: chunk.slice(i, end) });
|
|
7721
|
+
i = end;
|
|
7722
|
+
}
|
|
7723
|
+
if (this.state === "esc") {
|
|
7724
|
+
this.scheduleEscTimer();
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
dispatchCsi(seq) {
|
|
7728
|
+
if (seq === "200~") {
|
|
7729
|
+
this.state = "paste";
|
|
7730
|
+
this.pasteBuf = "";
|
|
7731
|
+
return;
|
|
7732
|
+
}
|
|
7733
|
+
if (seq === "201~") {
|
|
7734
|
+
return;
|
|
7735
|
+
}
|
|
7736
|
+
const ev = lookupCsi(seq);
|
|
7737
|
+
if (ev) this.dispatch(ev);
|
|
7738
|
+
}
|
|
7739
|
+
};
|
|
7740
|
+
var singleton = null;
|
|
7741
|
+
function getStdinReader() {
|
|
7742
|
+
if (!singleton) singleton = new StdinReader();
|
|
7743
|
+
return singleton;
|
|
7744
|
+
}
|
|
7745
|
+
|
|
7746
|
+
// src/cli/ui/keystroke-context.tsx
|
|
7747
|
+
var KeystrokeContext = createContext(null);
|
|
7748
|
+
function KeystrokeProvider({
|
|
7749
|
+
children,
|
|
7750
|
+
reader: providedReader
|
|
7751
|
+
}) {
|
|
7752
|
+
const handlersRef = useRef(/* @__PURE__ */ new Set());
|
|
7753
|
+
const busRef = useRef(null);
|
|
7754
|
+
if (busRef.current === null) {
|
|
7755
|
+
busRef.current = {
|
|
7756
|
+
subscribe(handler) {
|
|
7757
|
+
handlersRef.current.add(handler);
|
|
7758
|
+
return () => {
|
|
7759
|
+
handlersRef.current.delete(handler);
|
|
7760
|
+
};
|
|
7761
|
+
}
|
|
7762
|
+
};
|
|
7763
|
+
}
|
|
7764
|
+
useEffect(() => {
|
|
7765
|
+
const reader = providedReader ?? getStdinReader();
|
|
7766
|
+
reader.start();
|
|
7767
|
+
const unsubscribe = reader.subscribe((ev) => {
|
|
7768
|
+
for (const fn of [...handlersRef.current]) fn(ev);
|
|
7769
|
+
});
|
|
7770
|
+
return () => {
|
|
7771
|
+
unsubscribe();
|
|
7772
|
+
};
|
|
7773
|
+
}, [providedReader]);
|
|
7774
|
+
return /* @__PURE__ */ React2.createElement(KeystrokeContext.Provider, { value: busRef.current }, children);
|
|
7775
|
+
}
|
|
7776
|
+
function useKeystroke(handler, isActive = true) {
|
|
7777
|
+
const bus = useContext(KeystrokeContext);
|
|
7778
|
+
const handlerRef = useRef(handler);
|
|
7779
|
+
handlerRef.current = handler;
|
|
7780
|
+
useEffect(() => {
|
|
7781
|
+
if (!bus || !isActive) return void 0;
|
|
7782
|
+
return bus.subscribe((ev) => handlerRef.current(ev));
|
|
7783
|
+
}, [bus, isActive]);
|
|
7784
|
+
}
|
|
7446
7785
|
|
|
7447
7786
|
// src/cli/ui/Select.tsx
|
|
7448
|
-
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7449
|
-
import React2, { useState } from "react";
|
|
7450
7787
|
function SingleSelect({
|
|
7451
7788
|
items,
|
|
7452
7789
|
initialValue,
|
|
@@ -7459,19 +7796,20 @@ function SingleSelect({
|
|
|
7459
7796
|
items.findIndex((i) => i.value === initialValue && !i.disabled)
|
|
7460
7797
|
);
|
|
7461
7798
|
const [index, setIndex] = useState(initialIndex === -1 ? 0 : initialIndex);
|
|
7462
|
-
|
|
7463
|
-
if (
|
|
7799
|
+
useKeystroke((ev) => {
|
|
7800
|
+
if (ev.paste) return;
|
|
7801
|
+
if (ev.upArrow) {
|
|
7464
7802
|
setIndex((i) => findNextEnabled(items, i, -1));
|
|
7465
|
-
} else if (
|
|
7803
|
+
} else if (ev.downArrow) {
|
|
7466
7804
|
setIndex((i) => findNextEnabled(items, i, 1));
|
|
7467
|
-
} else if (
|
|
7805
|
+
} else if (ev.return) {
|
|
7468
7806
|
const chosen = items[index];
|
|
7469
7807
|
if (chosen && !chosen.disabled) onSubmit(chosen.value);
|
|
7470
|
-
} else if (
|
|
7808
|
+
} else if (ev.escape && onCancel) {
|
|
7471
7809
|
onCancel();
|
|
7472
7810
|
}
|
|
7473
7811
|
});
|
|
7474
|
-
return /* @__PURE__ */
|
|
7812
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React3.createElement(
|
|
7475
7813
|
SelectRow,
|
|
7476
7814
|
{
|
|
7477
7815
|
key: item.value,
|
|
@@ -7479,7 +7817,7 @@ function SingleSelect({
|
|
|
7479
7817
|
active: i === index,
|
|
7480
7818
|
marker: i === index ? "\u25B8" : " "
|
|
7481
7819
|
}
|
|
7482
|
-
)), footer ? /* @__PURE__ */
|
|
7820
|
+
)), footer ? /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, footer)) : null);
|
|
7483
7821
|
}
|
|
7484
7822
|
function MultiSelect({
|
|
7485
7823
|
items,
|
|
@@ -7493,12 +7831,13 @@ function MultiSelect({
|
|
|
7493
7831
|
return first === -1 ? 0 : first;
|
|
7494
7832
|
});
|
|
7495
7833
|
const [selected, setSelected] = useState(new Set(initialSelected));
|
|
7496
|
-
|
|
7497
|
-
if (
|
|
7834
|
+
useKeystroke((ev) => {
|
|
7835
|
+
if (ev.paste) return;
|
|
7836
|
+
if (ev.upArrow) {
|
|
7498
7837
|
setIndex((i) => findNextEnabled(items, i, -1));
|
|
7499
|
-
} else if (
|
|
7838
|
+
} else if (ev.downArrow) {
|
|
7500
7839
|
setIndex((i) => findNextEnabled(items, i, 1));
|
|
7501
|
-
} else if (input === " ") {
|
|
7840
|
+
} else if (ev.input === " ") {
|
|
7502
7841
|
const item = items[index];
|
|
7503
7842
|
if (!item || item.disabled) return;
|
|
7504
7843
|
setSelected((prev) => {
|
|
@@ -7507,17 +7846,17 @@ function MultiSelect({
|
|
|
7507
7846
|
else next.add(item.value);
|
|
7508
7847
|
return next;
|
|
7509
7848
|
});
|
|
7510
|
-
} else if (
|
|
7849
|
+
} else if (ev.return) {
|
|
7511
7850
|
const ordered = items.filter((i) => selected.has(i.value)).map((i) => i.value);
|
|
7512
7851
|
onSubmit(ordered);
|
|
7513
|
-
} else if (
|
|
7852
|
+
} else if (ev.escape && onCancel) {
|
|
7514
7853
|
onCancel();
|
|
7515
7854
|
}
|
|
7516
7855
|
});
|
|
7517
|
-
return /* @__PURE__ */
|
|
7856
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => {
|
|
7518
7857
|
const checked = selected.has(item.value);
|
|
7519
7858
|
const marker = checked ? "[x]" : "[ ]";
|
|
7520
|
-
return /* @__PURE__ */
|
|
7859
|
+
return /* @__PURE__ */ React3.createElement(
|
|
7521
7860
|
SelectRow,
|
|
7522
7861
|
{
|
|
7523
7862
|
key: item.value,
|
|
@@ -7526,7 +7865,7 @@ function MultiSelect({
|
|
|
7526
7865
|
marker: `${i === index ? "\u25B8" : " "} ${marker}`
|
|
7527
7866
|
}
|
|
7528
7867
|
);
|
|
7529
|
-
}), footer ? /* @__PURE__ */
|
|
7868
|
+
}), footer ? /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, footer)) : null);
|
|
7530
7869
|
}
|
|
7531
7870
|
function SelectRow({
|
|
7532
7871
|
item,
|
|
@@ -7534,7 +7873,7 @@ function SelectRow({
|
|
|
7534
7873
|
marker
|
|
7535
7874
|
}) {
|
|
7536
7875
|
const color = item.disabled ? "gray" : active ? "cyan" : void 0;
|
|
7537
|
-
return /* @__PURE__ */
|
|
7876
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Box2, null, /* @__PURE__ */ React3.createElement(Text2, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React3.createElement(Box2, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, item.hint)) : null);
|
|
7538
7877
|
}
|
|
7539
7878
|
function findNextEnabled(items, from, step) {
|
|
7540
7879
|
if (items.length === 0) return 0;
|
|
@@ -7567,7 +7906,7 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
|
|
|
7567
7906
|
label: "Cancel \u2014 drop the question",
|
|
7568
7907
|
hint: "Model stops and asks what you want instead."
|
|
7569
7908
|
});
|
|
7570
|
-
return /* @__PURE__ */
|
|
7909
|
+
return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "magenta" }, "\u{1F500} the model is asking you to pick")), /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, null, question)), /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(
|
|
7571
7910
|
SingleSelect,
|
|
7572
7911
|
{
|
|
7573
7912
|
initialValue: options[0]?.id,
|
|
@@ -7582,11 +7921,11 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
|
|
|
7582
7921
|
}
|
|
7583
7922
|
)));
|
|
7584
7923
|
}
|
|
7585
|
-
var ChoiceConfirm =
|
|
7924
|
+
var ChoiceConfirm = React4.memo(ChoiceConfirmInner);
|
|
7586
7925
|
|
|
7587
7926
|
// src/cli/ui/EditConfirm.tsx
|
|
7588
|
-
import { Box as Box4, Text as Text4,
|
|
7589
|
-
import
|
|
7927
|
+
import { Box as Box4, Text as Text4, useStdout } from "ink";
|
|
7928
|
+
import React5, { useMemo, useState as useState2 } from "react";
|
|
7590
7929
|
|
|
7591
7930
|
// src/code/diff-preview.ts
|
|
7592
7931
|
function formatEditBlockDiff(block, opts = {}) {
|
|
@@ -7671,7 +8010,10 @@ function EditConfirm({ block, onChoose }) {
|
|
|
7671
8010
|
const [scroll, setScroll] = useState2(0);
|
|
7672
8011
|
const maxScroll = Math.max(0, allLines.length - budget);
|
|
7673
8012
|
const effectiveScroll = Math.min(scroll, maxScroll);
|
|
7674
|
-
|
|
8013
|
+
useKeystroke((ev) => {
|
|
8014
|
+
if (ev.paste) return;
|
|
8015
|
+
const input = ev.input;
|
|
8016
|
+
const key = ev;
|
|
7675
8017
|
if (key.return || input === "y") {
|
|
7676
8018
|
onChoose("apply");
|
|
7677
8019
|
return;
|
|
@@ -7722,17 +8064,17 @@ function EditConfirm({ block, onChoose }) {
|
|
|
7722
8064
|
const hiddenBelow = Math.max(0, allLines.length - effectiveScroll - budget);
|
|
7723
8065
|
const totalLines = allLines.length;
|
|
7724
8066
|
const showScrollHud = hiddenAbove + hiddenBelow > 0;
|
|
7725
|
-
return /* @__PURE__ */
|
|
8067
|
+
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { bold: true, color: "yellow" }, "\u25B8 model wants to edit a file")), /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { color: "yellow", dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")), /* @__PURE__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text4, null, /* @__PURE__ */ React5.createElement(Text4, { color: isNew ? "green" : "yellow", bold: true }, `[${tag}] `), /* @__PURE__ */ React5.createElement(Text4, { color: "cyan" }, block.path), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` (-${removed} +${added} lines)`), showScrollHud ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` \xB7 viewing ${effectiveScroll + 1}-${effectiveScroll + visibleLines.length}/${totalLines}`) : null)), hiddenAbove > 0 ? /* @__PURE__ */ React5.createElement(
|
|
7726
8068
|
Text4,
|
|
7727
8069
|
{
|
|
7728
8070
|
dimColor: true
|
|
7729
8071
|
},
|
|
7730
8072
|
` \u2191 ${hiddenAbove} line${hiddenAbove === 1 ? "" : "s"} above (\u2191/k or PgUp)`
|
|
7731
|
-
) : null, /* @__PURE__ */
|
|
8073
|
+
) : null, /* @__PURE__ */ React5.createElement(Box4, { marginTop: hiddenAbove > 0 ? 0 : 1, flexDirection: "column" }, visibleLines.map((line, i) => {
|
|
7732
8074
|
const trimmed = line.trimStart();
|
|
7733
8075
|
const color = trimmed.startsWith("+") ? "green" : trimmed.startsWith("-") ? "red" : void 0;
|
|
7734
8076
|
const dim = !color;
|
|
7735
|
-
return /* @__PURE__ */
|
|
8077
|
+
return /* @__PURE__ */ React5.createElement(
|
|
7736
8078
|
Text4,
|
|
7737
8079
|
{
|
|
7738
8080
|
key: `diff-${effectiveScroll}-${i}`,
|
|
@@ -7741,22 +8083,22 @@ function EditConfirm({ block, onChoose }) {
|
|
|
7741
8083
|
},
|
|
7742
8084
|
line
|
|
7743
8085
|
);
|
|
7744
|
-
})), hiddenBelow > 0 ? /* @__PURE__ */
|
|
8086
|
+
})), hiddenBelow > 0 ? /* @__PURE__ */ React5.createElement(
|
|
7745
8087
|
Text4,
|
|
7746
8088
|
{
|
|
7747
8089
|
dimColor: true
|
|
7748
8090
|
},
|
|
7749
8091
|
` \u2193 ${hiddenBelow} line${hiddenBelow === 1 ? "" : "s"} below (\u2193/j or Space/PgDn)`
|
|
7750
|
-
) : null, /* @__PURE__ */
|
|
8092
|
+
) : null, /* @__PURE__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "[", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "y"), "/Enter] apply \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "n"), "] reject \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "a"), "] apply rest \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "A"), "] flip AUTO \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "\u2191\u2193/Space"), "] scroll \xB7 [Esc] abort")));
|
|
7751
8093
|
}
|
|
7752
8094
|
|
|
7753
8095
|
// src/cli/ui/EventLog.tsx
|
|
7754
8096
|
import { Box as Box8, Text as Text8, useStdout as useStdout2 } from "ink";
|
|
7755
|
-
import
|
|
8097
|
+
import React10 from "react";
|
|
7756
8098
|
|
|
7757
8099
|
// src/cli/ui/PlanStateBlock.tsx
|
|
7758
8100
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
7759
|
-
import
|
|
8101
|
+
import React6 from "react";
|
|
7760
8102
|
function PlanStateBlock({ planState }) {
|
|
7761
8103
|
const fields = [];
|
|
7762
8104
|
if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "cyan", false]);
|
|
@@ -7767,12 +8109,12 @@ function PlanStateBlock({ planState }) {
|
|
|
7767
8109
|
if (planState.rejectedPaths.length)
|
|
7768
8110
|
fields.push(["rejected", planState.rejectedPaths, "red", true]);
|
|
7769
8111
|
if (fields.length === 0) return null;
|
|
7770
|
-
return /* @__PURE__ */
|
|
8112
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React6.createElement(Text5, { key: label }, /* @__PURE__ */ React6.createElement(Text5, { color, bold: true, dimColor: dim }, "\u2039 ", label), /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, ` (${items.length})`), /* @__PURE__ */ React6.createElement(Text5, null, `: ${items.join(" \xB7 ")}`))));
|
|
7771
8113
|
}
|
|
7772
8114
|
|
|
7773
8115
|
// src/cli/ui/PlanStepList.tsx
|
|
7774
8116
|
import { Box as Box6, Text as Text6 } from "ink";
|
|
7775
|
-
import
|
|
8117
|
+
import React7 from "react";
|
|
7776
8118
|
function riskDots(risk) {
|
|
7777
8119
|
switch (risk) {
|
|
7778
8120
|
case "high":
|
|
@@ -7811,25 +8153,25 @@ function PlanStepListInner({ steps, statuses, focusStepId }) {
|
|
|
7811
8153
|
{ length: steps.length },
|
|
7812
8154
|
(_, i) => getStatus(steps[i].id, statuses)
|
|
7813
8155
|
).filter((s) => s === "done").length;
|
|
7814
|
-
return /* @__PURE__ */
|
|
8156
|
+
return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, `${steps.length} step${steps.length === 1 ? "" : "s"}`, doneCount > 0 ? ` \xB7 ${doneCount} done` : "", hasAnyRisk ? " \xB7 risk: " : ""), hasAnyRisk ? /* @__PURE__ */ React7.createElement(RiskLegend, null) : null), /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", marginTop: 1 }, steps.map((step) => {
|
|
7815
8157
|
const status2 = getStatus(step.id, statuses);
|
|
7816
8158
|
const focus = focusStepId === step.id;
|
|
7817
8159
|
const risk = riskDots(step.risk);
|
|
7818
8160
|
const glyph = statusGlyph(status2);
|
|
7819
8161
|
const titleDim = status2 === "done" || status2 === "skipped";
|
|
7820
|
-
return /* @__PURE__ */
|
|
8162
|
+
return /* @__PURE__ */ React7.createElement(Box6, { key: step.id }, /* @__PURE__ */ React7.createElement(Text6, { color: focus ? "cyan" : "gray", bold: focus }, focus ? "\u203A " : " "), /* @__PURE__ */ React7.createElement(Text6, { color: risk.color, bold: true }, risk.dots), /* @__PURE__ */ React7.createElement(Text6, { color: glyph.color, bold: true }, ` ${glyph.glyph} `), /* @__PURE__ */ React7.createElement(Text6, { dimColor: titleDim }, `${step.id} \xB7 ${step.title}`));
|
|
7821
8163
|
})));
|
|
7822
8164
|
}
|
|
7823
8165
|
function RiskLegend() {
|
|
7824
|
-
return /* @__PURE__ */
|
|
8166
|
+
return /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { color: "green" }, "\u25CF"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " low "), /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u25CF\u25CF"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " med "), /* @__PURE__ */ React7.createElement(Text6, { color: "red" }, "\u25CF\u25CF\u25CF"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " high"));
|
|
7825
8167
|
}
|
|
7826
|
-
var PlanStepList =
|
|
8168
|
+
var PlanStepList = React7.memo(PlanStepListInner);
|
|
7827
8169
|
|
|
7828
8170
|
// src/cli/ui/markdown.tsx
|
|
7829
8171
|
import { readFileSync as readFileSync13, statSync as statSync6 } from "fs";
|
|
7830
8172
|
import { isAbsolute as isAbsolute4, join as join11 } from "path";
|
|
7831
8173
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
7832
|
-
import
|
|
8174
|
+
import React8 from "react";
|
|
7833
8175
|
var SUPERSCRIPT = {
|
|
7834
8176
|
"0": "\u2070",
|
|
7835
8177
|
"1": "\xB9",
|
|
@@ -8084,67 +8426,67 @@ function InlineMd({
|
|
|
8084
8426
|
for (const m of text.matchAll(INLINE_RE)) {
|
|
8085
8427
|
const start = m.index ?? 0;
|
|
8086
8428
|
if (start > last) {
|
|
8087
|
-
parts.push(/* @__PURE__ */
|
|
8429
|
+
parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `t${idx++}` }, text.slice(last, start)));
|
|
8088
8430
|
}
|
|
8089
8431
|
if (m[2] !== void 0 && m[3] !== void 0) {
|
|
8090
8432
|
const linkText = m[2];
|
|
8091
8433
|
const url = m[3];
|
|
8092
8434
|
if (isExternalUrl(url)) {
|
|
8093
8435
|
parts.push(
|
|
8094
|
-
/* @__PURE__ */
|
|
8436
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
|
|
8095
8437
|
);
|
|
8096
8438
|
} else {
|
|
8097
8439
|
const status2 = citations?.get(url);
|
|
8098
8440
|
if (status2 && !status2.ok) {
|
|
8099
8441
|
parts.push(
|
|
8100
|
-
/* @__PURE__ */
|
|
8442
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
|
|
8101
8443
|
);
|
|
8102
8444
|
} else {
|
|
8103
8445
|
parts.push(
|
|
8104
|
-
/* @__PURE__ */
|
|
8446
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
|
|
8105
8447
|
);
|
|
8106
8448
|
}
|
|
8107
8449
|
}
|
|
8108
8450
|
} else if (m[4] !== void 0) {
|
|
8109
8451
|
parts.push(
|
|
8110
|
-
/* @__PURE__ */
|
|
8452
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
|
|
8111
8453
|
);
|
|
8112
8454
|
} else if (m[5] !== void 0) {
|
|
8113
8455
|
parts.push(
|
|
8114
|
-
/* @__PURE__ */
|
|
8456
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `b${idx++}`, bold: true }, m[5])
|
|
8115
8457
|
);
|
|
8116
8458
|
} else if (m[6] !== void 0) {
|
|
8117
8459
|
const stripped = m[6].replace(/^(\w+)\s+/, "");
|
|
8118
8460
|
parts.push(
|
|
8119
|
-
/* @__PURE__ */
|
|
8461
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, stripped)
|
|
8120
8462
|
);
|
|
8121
8463
|
} else if (m[7] !== void 0) {
|
|
8122
8464
|
parts.push(
|
|
8123
|
-
/* @__PURE__ */
|
|
8465
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, m[7])
|
|
8124
8466
|
);
|
|
8125
8467
|
} else if (m[8] !== void 0) {
|
|
8126
8468
|
parts.push(
|
|
8127
|
-
/* @__PURE__ */
|
|
8469
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
|
|
8128
8470
|
);
|
|
8129
8471
|
} else if (m[9] !== void 0) {
|
|
8130
8472
|
parts.push(
|
|
8131
|
-
/* @__PURE__ */
|
|
8473
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `i${idx++}`, italic: true }, m[9])
|
|
8132
8474
|
);
|
|
8133
8475
|
} else if (m[10] !== void 0) {
|
|
8134
|
-
parts.push(/* @__PURE__ */
|
|
8476
|
+
parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `esc${idx++}` }, m[10]));
|
|
8135
8477
|
}
|
|
8136
8478
|
last = start + m[0].length;
|
|
8137
8479
|
}
|
|
8138
8480
|
if (last < text.length) {
|
|
8139
|
-
parts.push(/* @__PURE__ */
|
|
8481
|
+
parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `t${idx++}` }, text.slice(last)));
|
|
8140
8482
|
}
|
|
8141
8483
|
if (padTo !== void 0) {
|
|
8142
8484
|
const seen = visibleWidth(text);
|
|
8143
8485
|
if (seen < padTo) {
|
|
8144
|
-
parts.push(/* @__PURE__ */
|
|
8486
|
+
parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
|
|
8145
8487
|
}
|
|
8146
8488
|
}
|
|
8147
|
-
return /* @__PURE__ */
|
|
8489
|
+
return /* @__PURE__ */ React8.createElement(Text7, null, parts);
|
|
8148
8490
|
}
|
|
8149
8491
|
function stripInlineMarkup(s) {
|
|
8150
8492
|
return s.replace(
|
|
@@ -8383,34 +8725,34 @@ function parseBulletItem(raw) {
|
|
|
8383
8725
|
function BlockView({ block, citations }) {
|
|
8384
8726
|
switch (block.kind) {
|
|
8385
8727
|
case "heading":
|
|
8386
|
-
return /* @__PURE__ */
|
|
8728
|
+
return /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, /* @__PURE__ */ React8.createElement(InlineMd, { text: block.text, citations }));
|
|
8387
8729
|
case "paragraph":
|
|
8388
|
-
return /* @__PURE__ */
|
|
8730
|
+
return /* @__PURE__ */ React8.createElement(ParagraphView, { text: block.text, citations });
|
|
8389
8731
|
case "bullet":
|
|
8390
|
-
return /* @__PURE__ */
|
|
8732
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React8.createElement(Box7, { key: `${i}-${item.text.slice(0, 24)}` }, /* @__PURE__ */ React8.createElement(Text7, { color: item.task === "done" ? "green" : "cyan" }, bulletPrefix(block, i, item)), item.task === "done" ? /* @__PURE__ */ React8.createElement(Text7, { strikethrough: true, dimColor: true }, /* @__PURE__ */ React8.createElement(InlineMd, { text: item.text, citations })) : /* @__PURE__ */ React8.createElement(InlineMd, { text: item.text, citations }))));
|
|
8391
8733
|
case "quote":
|
|
8392
|
-
return /* @__PURE__ */
|
|
8734
|
+
return /* @__PURE__ */ React8.createElement(BlockquoteView, { block, citations });
|
|
8393
8735
|
case "code":
|
|
8394
8736
|
if (DIAGRAM_LANGS.has(block.lang.toLowerCase())) {
|
|
8395
|
-
return /* @__PURE__ */
|
|
8737
|
+
return /* @__PURE__ */ React8.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
|
|
8396
8738
|
}
|
|
8397
|
-
return /* @__PURE__ */
|
|
8739
|
+
return /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, block.text));
|
|
8398
8740
|
case "edit-block":
|
|
8399
|
-
return /* @__PURE__ */
|
|
8741
|
+
return /* @__PURE__ */ React8.createElement(EditBlockRow, { block });
|
|
8400
8742
|
case "table":
|
|
8401
|
-
return /* @__PURE__ */
|
|
8743
|
+
return /* @__PURE__ */ React8.createElement(TableBlockRow, { block, citations });
|
|
8402
8744
|
case "hr":
|
|
8403
|
-
return /* @__PURE__ */
|
|
8745
|
+
return /* @__PURE__ */ React8.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
8746
|
}
|
|
8405
8747
|
}
|
|
8406
8748
|
function ParagraphView({ text, citations }) {
|
|
8407
8749
|
if (!text.includes("\n")) {
|
|
8408
|
-
return /* @__PURE__ */
|
|
8750
|
+
return /* @__PURE__ */ React8.createElement(InlineMd, { text, citations });
|
|
8409
8751
|
}
|
|
8410
8752
|
const rows = text.split("\n");
|
|
8411
|
-
return /* @__PURE__ */
|
|
8753
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, rows.map((row2, i) => (
|
|
8412
8754
|
// biome-ignore lint/suspicious/noArrayIndexKey: hard-break rows are source-ordered and never reorder
|
|
8413
|
-
/* @__PURE__ */
|
|
8755
|
+
/* @__PURE__ */ React8.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
|
|
8414
8756
|
)));
|
|
8415
8757
|
}
|
|
8416
8758
|
function bulletPrefix(block, i, item) {
|
|
@@ -8423,7 +8765,7 @@ function BlockquoteView({
|
|
|
8423
8765
|
block,
|
|
8424
8766
|
citations
|
|
8425
8767
|
}) {
|
|
8426
|
-
return /* @__PURE__ */
|
|
8768
|
+
return /* @__PURE__ */ React8.createElement(
|
|
8427
8769
|
Box7,
|
|
8428
8770
|
{
|
|
8429
8771
|
borderStyle: "single",
|
|
@@ -8436,7 +8778,7 @@ function BlockquoteView({
|
|
|
8436
8778
|
flexDirection: "column",
|
|
8437
8779
|
gap: 1
|
|
8438
8780
|
},
|
|
8439
|
-
block.children.map((child, i) => /* @__PURE__ */
|
|
8781
|
+
block.children.map((child, i) => /* @__PURE__ */ React8.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
|
|
8440
8782
|
);
|
|
8441
8783
|
}
|
|
8442
8784
|
function splitTableRow(line) {
|
|
@@ -8454,14 +8796,14 @@ function TableBlockRow({ block, citations }) {
|
|
|
8454
8796
|
widths.push(Math.min(40, Math.max(3, ...cellLengths)));
|
|
8455
8797
|
}
|
|
8456
8798
|
const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
|
|
8457
|
-
return /* @__PURE__ */
|
|
8799
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Box7, null, block.header.map((cell, ci) => (
|
|
8458
8800
|
// biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
|
|
8459
|
-
/* @__PURE__ */
|
|
8460
|
-
))), /* @__PURE__ */
|
|
8801
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React8.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
8802
|
+
))), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, separator), block.rows.map((row2, ri) => (
|
|
8461
8803
|
// biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
|
|
8462
|
-
/* @__PURE__ */
|
|
8804
|
+
/* @__PURE__ */ React8.createElement(Box7, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
|
|
8463
8805
|
// biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
|
|
8464
|
-
/* @__PURE__ */
|
|
8806
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React8.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
|
|
8465
8807
|
)))
|
|
8466
8808
|
)));
|
|
8467
8809
|
}
|
|
@@ -8481,7 +8823,7 @@ function EditBlockRow({ block }) {
|
|
|
8481
8823
|
const isNewFile = block.search.length === 0;
|
|
8482
8824
|
const searchLines = block.search.split("\n");
|
|
8483
8825
|
const replaceLines = block.replace.split("\n");
|
|
8484
|
-
return /* @__PURE__ */
|
|
8826
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React8.createElement(Text7, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React8.createElement(Text7, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React8.createElement(Text7, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
|
|
8485
8827
|
}
|
|
8486
8828
|
var DIAGRAM_LANGS = /* @__PURE__ */ new Set([
|
|
8487
8829
|
"mermaid",
|
|
@@ -8503,41 +8845,41 @@ var DIAGRAM_VIEWER_HINT = {
|
|
|
8503
8845
|
};
|
|
8504
8846
|
function DiagramCodeBlock({ lang, text }) {
|
|
8505
8847
|
const hint = DIAGRAM_VIEWER_HINT[lang.toLowerCase()] ?? "\u2192 render with the matching viewer to view";
|
|
8506
|
-
return /* @__PURE__ */
|
|
8848
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "magenta" }, `\u25C7 ${lang} diagram (source \u2014 terminal can't draw the graph)`), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, text)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, hint)));
|
|
8507
8849
|
}
|
|
8508
8850
|
function Markdown({ text, projectRoot }) {
|
|
8509
8851
|
const cleaned = expandAutolinks(expandEmoji(stripMath(text)));
|
|
8510
8852
|
const root = projectRoot ?? process.cwd();
|
|
8511
|
-
const citations =
|
|
8512
|
-
const blocks =
|
|
8853
|
+
const citations = React8.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
|
|
8854
|
+
const blocks = React8.useMemo(() => parseBlocks(cleaned), [cleaned]);
|
|
8513
8855
|
const broken = [];
|
|
8514
8856
|
for (const [url, status2] of citations) {
|
|
8515
8857
|
if (!status2.ok) broken.push({ url, reason: status2.reason });
|
|
8516
8858
|
}
|
|
8517
|
-
return /* @__PURE__ */
|
|
8859
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React8.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React8.createElement(BrokenCitationsBlock, { items: broken }) : null);
|
|
8518
8860
|
}
|
|
8519
8861
|
function BrokenCitationsBlock({ items }) {
|
|
8520
|
-
return /* @__PURE__ */
|
|
8862
|
+
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React8.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
8863
|
// biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
|
|
8522
|
-
/* @__PURE__ */
|
|
8864
|
+
/* @__PURE__ */ React8.createElement(Text7, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
|
|
8523
8865
|
)));
|
|
8524
8866
|
}
|
|
8525
8867
|
|
|
8526
8868
|
// src/cli/ui/ticker.tsx
|
|
8527
|
-
import
|
|
8869
|
+
import React9, { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState3 } from "react";
|
|
8528
8870
|
var TICK_MS = 120;
|
|
8529
|
-
var TickContext =
|
|
8871
|
+
var TickContext = createContext2(0);
|
|
8530
8872
|
function TickerProvider({ children, disabled }) {
|
|
8531
8873
|
const [tick, setTick] = useState3(0);
|
|
8532
|
-
|
|
8874
|
+
useEffect2(() => {
|
|
8533
8875
|
if (disabled) return;
|
|
8534
8876
|
const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
|
|
8535
8877
|
return () => clearInterval(id);
|
|
8536
8878
|
}, [disabled]);
|
|
8537
|
-
return /* @__PURE__ */
|
|
8879
|
+
return /* @__PURE__ */ React9.createElement(TickContext.Provider, { value: tick }, children);
|
|
8538
8880
|
}
|
|
8539
8881
|
function useTick() {
|
|
8540
|
-
return
|
|
8882
|
+
return useContext2(TickContext);
|
|
8541
8883
|
}
|
|
8542
8884
|
function useElapsedSeconds() {
|
|
8543
8885
|
const [start] = useState3(() => Date.now());
|
|
@@ -8687,28 +9029,28 @@ function RoleGlyph({
|
|
|
8687
9029
|
glyph,
|
|
8688
9030
|
color
|
|
8689
9031
|
}) {
|
|
8690
|
-
return /* @__PURE__ */
|
|
9032
|
+
return /* @__PURE__ */ React10.createElement(Text8, { color, bold: true }, glyph);
|
|
8691
9033
|
}
|
|
8692
9034
|
function indentContinuationLines(text) {
|
|
8693
9035
|
if (!text.includes("\n")) return text;
|
|
8694
9036
|
return text.split("\n").join("\n ");
|
|
8695
9037
|
}
|
|
8696
|
-
var EventRow =
|
|
9038
|
+
var EventRow = React10.memo(function EventRow2({
|
|
8697
9039
|
event,
|
|
8698
9040
|
projectRoot
|
|
8699
9041
|
}) {
|
|
8700
9042
|
if (event.role === "user") {
|
|
8701
|
-
return /* @__PURE__ */
|
|
9043
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, event.leadSeparator ? /* @__PURE__ */ React10.createElement(TurnSeparator, null) : null, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React10.createElement(Text8, null, " ", indentContinuationLines(event.text))));
|
|
8702
9044
|
}
|
|
8703
9045
|
if (event.role === "assistant") {
|
|
8704
|
-
if (event.streaming) return /* @__PURE__ */
|
|
8705
|
-
return /* @__PURE__ */
|
|
9046
|
+
if (event.streaming) return /* @__PURE__ */ React10.createElement(StreamingAssistant, { event });
|
|
9047
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${event.stats.model}`) : null), /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, event.branch ? /* @__PURE__ */ React10.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React10.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React10.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React10.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React10.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React10.createElement(Text8, { color: "magenta" }, event.repair) : null));
|
|
8706
9048
|
}
|
|
8707
9049
|
if (event.role === "tool") {
|
|
8708
9050
|
const isExplicitError = event.text.startsWith("ERROR:");
|
|
8709
9051
|
const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isExplicitError;
|
|
8710
9052
|
if (isEditFile) {
|
|
8711
|
-
return /* @__PURE__ */
|
|
9053
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.toolOk, color: "yellow" }), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", bold: true }, ` ${event.toolName ?? "?"}`), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", dimColor: true }, " \u2192")), /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, /* @__PURE__ */ React10.createElement(EditFileDiff, { text: event.text })));
|
|
8712
9054
|
}
|
|
8713
9055
|
const summary = summarizeToolResult(event.toolName ?? "?", event.text);
|
|
8714
9056
|
const color = summary.isError ? "red" : "yellow";
|
|
@@ -8716,22 +9058,22 @@ var EventRow = React9.memo(function EventRow2({
|
|
|
8716
9058
|
const marker = summary.isError ? "\u2717" : "\u2192";
|
|
8717
9059
|
const durationLabel = event.durationMs !== void 0 && event.durationMs >= 100 ? ` (${formatDuration(event.durationMs)})` : "";
|
|
8718
9060
|
const indexHint = event.toolIndex !== void 0 ? ` /tool ${event.toolIndex}` : "";
|
|
8719
|
-
return /* @__PURE__ */
|
|
9061
|
+
return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph, color }), /* @__PURE__ */ React10.createElement(Text8, { color, bold: true }, ` ${event.toolName ?? "?"}`), durationLabel ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, durationLabel) : null, /* @__PURE__ */ React10.createElement(Text8, { color, dimColor: true }, ` ${marker} `), /* @__PURE__ */ React10.createElement(Text8, { color: summary.isError ? "red" : void 0, dimColor: !summary.isError }, summary.summary), indexHint ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, indexHint) : null);
|
|
8720
9062
|
}
|
|
8721
9063
|
if (event.role === "error") {
|
|
8722
|
-
return /* @__PURE__ */
|
|
9064
|
+
return /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.error, color: "red" }), /* @__PURE__ */ React10.createElement(Text8, { color: "red" }, " ", indentContinuationLines(event.text)));
|
|
8723
9065
|
}
|
|
8724
9066
|
if (event.role === "info") {
|
|
8725
|
-
return /* @__PURE__ */
|
|
9067
|
+
return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, event.text));
|
|
8726
9068
|
}
|
|
8727
9069
|
if (event.role === "plan") {
|
|
8728
|
-
return /* @__PURE__ */
|
|
9070
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { bold: true, color: "cyan" }, "\u{1F4CB} plan proposed \u2014 pick a choice below")), /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Markdown, { text: event.text, projectRoot })));
|
|
8729
9071
|
}
|
|
8730
9072
|
if (event.role === "step-progress") {
|
|
8731
9073
|
const sp = event.stepProgress;
|
|
8732
9074
|
const counter = sp && sp.total > 0 ? ` (${sp.completed}/${sp.total})` : "";
|
|
8733
9075
|
const label = sp?.title ? `${sp.stepId} \xB7 ${sp.title}` : sp?.stepId ?? "";
|
|
8734
|
-
return /* @__PURE__ */
|
|
9076
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { color: "green", bold: true }, "\u2713"), /* @__PURE__ */ React10.createElement(Text8, { color: "green" }, ` ${label}`), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, counter)), event.text ? /* @__PURE__ */ React10.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, event.text)) : null, sp?.notes ? /* @__PURE__ */ React10.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", dimColor: true }, `note: ${sp.notes}`)) : null);
|
|
8735
9077
|
}
|
|
8736
9078
|
if (event.role === "plan-resumed") {
|
|
8737
9079
|
const rp = event.resumedPlan;
|
|
@@ -8746,7 +9088,7 @@ var EventRow = React9.memo(function EventRow2({
|
|
|
8746
9088
|
])
|
|
8747
9089
|
);
|
|
8748
9090
|
const nextStep = rp.steps.find((s) => !completedSet.has(s.id));
|
|
8749
|
-
return /* @__PURE__ */
|
|
9091
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { bold: true, color: "cyan" }, "\u25B8 resumed plan"), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${done}/${total} done \xB7 last touched ${rp.relativeTime}`)), rp.summary ? /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { color: "cyan" }, ` ${rp.summary}`)) : null), /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(PlanStepList, { steps: rp.steps, statuses, focusStepId: nextStep?.id })));
|
|
8750
9092
|
}
|
|
8751
9093
|
if (event.role === "plan-replay") {
|
|
8752
9094
|
const r = event.replayPlan;
|
|
@@ -8758,31 +9100,40 @@ var EventRow = React9.memo(function EventRow2({
|
|
|
8758
9100
|
r.steps.map((s) => [s.id, completedSet.has(s.id) ? "done" : "pending"])
|
|
8759
9101
|
);
|
|
8760
9102
|
const navHint = r.total > 1 ? ` \xB7 ${r.index}/${r.total}` : "";
|
|
8761
|
-
return /* @__PURE__ */
|
|
9103
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { bold: true, dimColor: true }, "\u23EA replay"), /* @__PURE__ */ React10.createElement(
|
|
8762
9104
|
Text8,
|
|
8763
9105
|
{
|
|
8764
9106
|
dimColor: true
|
|
8765
9107
|
},
|
|
8766
9108
|
` completed ${r.relativeTime} \xB7 ${done}/${total} done${navHint}`
|
|
8767
|
-
)), r.summary ? /* @__PURE__ */
|
|
9109
|
+
)), r.summary ? /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${r.summary}`)) : null, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${r.archiveBasename}`))), r.body ? /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Markdown, { text: r.body, projectRoot })) : null, /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(PlanStepList, { steps: r.steps, statuses })), /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React10.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
9110
|
}
|
|
8769
9111
|
if (event.role === "warning") {
|
|
8770
|
-
return /* @__PURE__ */
|
|
9112
|
+
return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.warning, color: "yellow" }), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow" }, " ", indentContinuationLines(event.text)));
|
|
8771
9113
|
}
|
|
8772
|
-
return /* @__PURE__ */
|
|
9114
|
+
return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, null, event.text));
|
|
8773
9115
|
});
|
|
9116
|
+
function TurnSeparator() {
|
|
9117
|
+
const { stdout: stdout2 } = useStdout2();
|
|
9118
|
+
const cols = stdout2?.columns ?? 80;
|
|
9119
|
+
const width = Math.max(16, cols - 2);
|
|
9120
|
+
const half = Math.floor((width - 3) / 2);
|
|
9121
|
+
const left = "\u2500".repeat(half);
|
|
9122
|
+
const right = "\u2500".repeat(width - half - 3);
|
|
9123
|
+
return /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, left), /* @__PURE__ */ React10.createElement(Text8, { color: "cyan", bold: true }, " \u25C6 "), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, right));
|
|
9124
|
+
}
|
|
8774
9125
|
function EditFileDiff({ text }) {
|
|
8775
9126
|
const lines = text.split(/\r?\n/);
|
|
8776
9127
|
const [statusHeader, hunkHeader, ...body] = lines;
|
|
8777
|
-
return /* @__PURE__ */
|
|
9128
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React10.createElement(Text8, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
|
|
8778
9129
|
const key = `${i}-${line.slice(0, 32)}`;
|
|
8779
9130
|
if (line.startsWith("- ")) {
|
|
8780
|
-
return /* @__PURE__ */
|
|
9131
|
+
return /* @__PURE__ */ React10.createElement(Text8, { key, color: "red" }, line);
|
|
8781
9132
|
}
|
|
8782
9133
|
if (line.startsWith("+ ")) {
|
|
8783
|
-
return /* @__PURE__ */
|
|
9134
|
+
return /* @__PURE__ */ React10.createElement(Text8, { key, color: "green" }, line);
|
|
8784
9135
|
}
|
|
8785
|
-
return /* @__PURE__ */
|
|
9136
|
+
return /* @__PURE__ */ React10.createElement(Text8, { key, dimColor: true }, line);
|
|
8786
9137
|
}));
|
|
8787
9138
|
}
|
|
8788
9139
|
function BranchBlock({ branch: branch2 }) {
|
|
@@ -8791,33 +9142,33 @@ function BranchBlock({ branch: branch2 }) {
|
|
|
8791
9142
|
const t = (branch2.temperatures[i] ?? 0).toFixed(1);
|
|
8792
9143
|
return `${marker} #${i} T=${t} u=${u}`;
|
|
8793
9144
|
}).join(" ");
|
|
8794
|
-
return /* @__PURE__ */
|
|
9145
|
+
return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { color: "blue" }, "\u2387 branched ", /* @__PURE__ */ React10.createElement(Text8, { bold: true }, branch2.budget), ` samples \u2192 picked #${branch2.chosenIndex} `, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, per)));
|
|
8795
9146
|
}
|
|
8796
9147
|
function ReasoningBlock({ reasoning }) {
|
|
8797
9148
|
const max = 260;
|
|
8798
9149
|
const flat = reasoning.replace(/\s+/g, " ").trim();
|
|
8799
9150
|
const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
|
|
8800
|
-
return /* @__PURE__ */
|
|
9151
|
+
return /* @__PURE__ */ React10.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "\u258F "), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true, italic: true }, "thinking ", preview));
|
|
8801
9152
|
}
|
|
8802
9153
|
function Elapsed() {
|
|
8803
9154
|
const s = useElapsedSeconds();
|
|
8804
9155
|
const mm = String(Math.floor(s / 60)).padStart(2, "0");
|
|
8805
9156
|
const ss = String(s % 60).padStart(2, "0");
|
|
8806
|
-
return /* @__PURE__ */
|
|
9157
|
+
return /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, `${mm}:${ss}`);
|
|
8807
9158
|
}
|
|
8808
9159
|
function PulsingAssistantGlyph() {
|
|
8809
9160
|
const tick = useTick();
|
|
8810
9161
|
const on = Math.floor(tick / 4) % 2 === 0;
|
|
8811
|
-
return /* @__PURE__ */
|
|
9162
|
+
return /* @__PURE__ */ React10.createElement(Text8, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
|
|
8812
9163
|
}
|
|
8813
9164
|
function StreamingAssistant({ event }) {
|
|
8814
9165
|
if (event.branchProgress) {
|
|
8815
9166
|
const p = event.branchProgress;
|
|
8816
9167
|
if (p.completed === 0) {
|
|
8817
|
-
return /* @__PURE__ */
|
|
9168
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React10.createElement(Text8, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React10.createElement(Elapsed, null)), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
|
|
8818
9169
|
}
|
|
8819
9170
|
const pct2 = Math.round(p.completed / p.total * 100);
|
|
8820
|
-
return /* @__PURE__ */
|
|
9171
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React10.createElement(Text8, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React10.createElement(Elapsed, null)), /* @__PURE__ */ React10.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
9172
|
}
|
|
8822
9173
|
const tail = lastLine(event.text, 140);
|
|
8823
9174
|
const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
|
|
@@ -8847,16 +9198,16 @@ function StreamingAssistant({ event }) {
|
|
|
8847
9198
|
label = parts.join(" \xB7 ");
|
|
8848
9199
|
labelColor = "green";
|
|
8849
9200
|
}
|
|
8850
|
-
return /* @__PURE__ */
|
|
9201
|
+
return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React10.createElement(Text8, null, " "), /* @__PURE__ */ React10.createElement(Pulse, null), /* @__PURE__ */ React10.createElement(Text8, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React10.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "\u25B8 ", tail) : preFirstByte ? (
|
|
8851
9202
|
// Non-dim yellow: first-time users misread the dim version as
|
|
8852
9203
|
// "app frozen". The reassurance has to be VISIBLE to do its job.
|
|
8853
|
-
/* @__PURE__ */
|
|
8854
|
-
) : reasoningOnly ? /* @__PURE__ */
|
|
9204
|
+
/* @__PURE__ */ React10.createElement(Text8, { color: "yellow", italic: true }, " waiting for first byte \u2014 this is normal, typically 5-60s depending on model + load")
|
|
9205
|
+
) : reasoningOnly ? /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", italic: true }, " R1 is thinking before it speaks \u2014 body text arrives when reasoning finishes (typically 20-90s, this is normal)") : toolCallOnly ? /* @__PURE__ */ React10.createElement(Text8, { color: "magenta", italic: true }, " tool-call arguments streaming \u2014 the model is about to dispatch a tool") : event.reasoning ? /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", italic: true }, " R1 still reasoning \u2014 body text or tool call arrives when thinking finishes") : null);
|
|
8855
9206
|
}
|
|
8856
9207
|
function Pulse() {
|
|
8857
9208
|
const tick = useTick();
|
|
8858
9209
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8859
|
-
return /* @__PURE__ */
|
|
9210
|
+
return /* @__PURE__ */ React10.createElement(Text8, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
|
|
8860
9211
|
}
|
|
8861
9212
|
function formatToolCallIndex(tb) {
|
|
8862
9213
|
if (!tb || tb.index === void 0) return "";
|
|
@@ -8875,17 +9226,17 @@ function lastLine(s, maxChars) {
|
|
|
8875
9226
|
}
|
|
8876
9227
|
function StatsLine({ stats: stats2 }) {
|
|
8877
9228
|
const hit = (stats2.cacheHitRatio * 100).toFixed(1);
|
|
8878
|
-
return /* @__PURE__ */
|
|
9229
|
+
return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "\u258F "), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "cache ", hit, "% \xB7 tokens ", stats2.usage.promptTokens, " \u2192 ", stats2.usage.completionTokens, " \xB7 $", stats2.cost.toFixed(6)));
|
|
8879
9230
|
}
|
|
8880
9231
|
|
|
8881
9232
|
// src/cli/ui/LiveRows.tsx
|
|
8882
9233
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
8883
|
-
import
|
|
9234
|
+
import React11 from "react";
|
|
8884
9235
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8885
9236
|
function StatusRow({ text }) {
|
|
8886
9237
|
const tick = useTick();
|
|
8887
9238
|
const elapsed = useElapsedSeconds();
|
|
8888
|
-
return /* @__PURE__ */
|
|
9239
|
+
return /* @__PURE__ */ React11.createElement(Box9, { marginY: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` ${elapsed}s`));
|
|
8889
9240
|
}
|
|
8890
9241
|
function ModeStatusBar({
|
|
8891
9242
|
editMode,
|
|
@@ -8897,15 +9248,14 @@ function ModeStatusBar({
|
|
|
8897
9248
|
}) {
|
|
8898
9249
|
useTick();
|
|
8899
9250
|
const running = jobs2?.runningCount() ?? 0;
|
|
8900
|
-
const jobsTag = running > 0 ? /* @__PURE__ */
|
|
9251
|
+
const jobsTag = running > 0 ? /* @__PURE__ */ React11.createElement(Text9, { color: "yellow", bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
|
|
8901
9252
|
if (planMode) {
|
|
8902
|
-
return /* @__PURE__ */
|
|
9253
|
+
return /* @__PURE__ */ React11.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "red", bold: true, inverse: flash }, "plan mode"), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " writes gated \xB7 /plan off to leave"), jobsTag);
|
|
8903
9254
|
}
|
|
8904
|
-
const label = editMode === "auto" ? "
|
|
8905
|
-
const
|
|
8906
|
-
const mid = editMode === "auto" ?
|
|
8907
|
-
|
|
8908
|
-
return /* @__PURE__ */ React10.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color, bold: true, inverse: flash }, `\u25B8 ${label}`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${mid} \xB7 ${flip}`), jobsTag);
|
|
9255
|
+
const label = editMode === "auto" ? "auto" : "review";
|
|
9256
|
+
const labelColor = editMode === "auto" ? "magenta" : "cyan";
|
|
9257
|
+
const mid = editMode === "auto" ? "edits land now \xB7 u to undo" : pendingCount > 0 ? `${pendingCount} queued \xB7 y apply \xB7 n discard` : "edits queued \xB7 y apply \xB7 n discard";
|
|
9258
|
+
return /* @__PURE__ */ React11.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: labelColor, bold: true, inverse: flash }, label), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` ${mid} \xB7 Shift+Tab to flip`), jobsTag);
|
|
8909
9259
|
}
|
|
8910
9260
|
function UndoBanner({
|
|
8911
9261
|
banner
|
|
@@ -8915,14 +9265,14 @@ function UndoBanner({
|
|
|
8915
9265
|
const remainingSec = Math.ceil(remainingMs / 1e3);
|
|
8916
9266
|
const ok = banner.results.filter((r) => r.status === "applied" || r.status === "created").length;
|
|
8917
9267
|
const total = banner.results.length;
|
|
8918
|
-
return /* @__PURE__ */
|
|
9268
|
+
return /* @__PURE__ */ React11.createElement(Box9, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "magenta", bold: true }, "\u2713 auto-applied "), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, `${ok}/${total} edit${total === 1 ? "" : "s"}`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " \xB7 press "), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta", bold: true }, "u"), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " to undo ("), /* @__PURE__ */ React11.createElement(Text9, { color: remainingSec <= 1 ? "red" : "magenta" }, `${remainingSec}s`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ")"));
|
|
8919
9269
|
}
|
|
8920
9270
|
function SubagentRow({
|
|
8921
9271
|
activity
|
|
8922
9272
|
}) {
|
|
8923
9273
|
const tick = useTick();
|
|
8924
9274
|
const seconds = (activity.elapsedMs / 1e3).toFixed(1);
|
|
8925
|
-
return /* @__PURE__ */
|
|
9275
|
+
return /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, ` \u232C subagent: ${activity.task}`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
|
|
8926
9276
|
}
|
|
8927
9277
|
function OngoingToolRow({
|
|
8928
9278
|
tool: tool2,
|
|
@@ -8931,7 +9281,7 @@ function OngoingToolRow({
|
|
|
8931
9281
|
const tick = useTick();
|
|
8932
9282
|
const elapsed = useElapsedSeconds();
|
|
8933
9283
|
const summary = summarizeToolArgs(tool2.name, tool2.args);
|
|
8934
|
-
return /* @__PURE__ */
|
|
9284
|
+
return /* @__PURE__ */ React11.createElement(Box9, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text9, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React11.createElement(Text9, { color: "yellow" }, ` tool<${tool2.name}> running\u2026`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text9, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, summary)) : null);
|
|
8935
9285
|
}
|
|
8936
9286
|
function renderProgressLine(p) {
|
|
8937
9287
|
const msg = p.message ? ` ${p.message}` : "";
|
|
@@ -8988,7 +9338,7 @@ function summarizeToolArgs(name, args) {
|
|
|
8988
9338
|
|
|
8989
9339
|
// src/cli/ui/PlanCheckpointConfirm.tsx
|
|
8990
9340
|
import { Box as Box10, Text as Text10 } from "ink";
|
|
8991
|
-
import
|
|
9341
|
+
import React12 from "react";
|
|
8992
9342
|
function PlanCheckpointConfirmInner({
|
|
8993
9343
|
stepId,
|
|
8994
9344
|
title,
|
|
@@ -9002,7 +9352,7 @@ function PlanCheckpointConfirmInner({
|
|
|
9002
9352
|
const counter = total > 0 ? ` (${completed}/${total})` : "";
|
|
9003
9353
|
const isLast = total > 0 && completed >= total;
|
|
9004
9354
|
const statuses = buildStatusMap(steps, completedStepIds, stepId, isLast);
|
|
9005
|
-
return /* @__PURE__ */
|
|
9355
|
+
return /* @__PURE__ */ React12.createElement(Box10, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React12.createElement(Box10, null, /* @__PURE__ */ React12.createElement(Text10, { bold: true, color: "green" }, "\u25B8 checkpoint \u2014 step done"), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, ` ${label}${counter}`)), steps && steps.length > 0 ? /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(
|
|
9006
9356
|
SingleSelect,
|
|
9007
9357
|
{
|
|
9008
9358
|
initialValue: isLast ? "stop" : "continue",
|
|
@@ -9029,7 +9379,7 @@ function PlanCheckpointConfirmInner({
|
|
|
9029
9379
|
}
|
|
9030
9380
|
)));
|
|
9031
9381
|
}
|
|
9032
|
-
var PlanCheckpointConfirm =
|
|
9382
|
+
var PlanCheckpointConfirm = React12.memo(PlanCheckpointConfirmInner);
|
|
9033
9383
|
function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
|
|
9034
9384
|
const map = /* @__PURE__ */ new Map();
|
|
9035
9385
|
if (!steps) return map;
|
|
@@ -9047,10 +9397,10 @@ function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
|
|
|
9047
9397
|
|
|
9048
9398
|
// src/cli/ui/PlanConfirm.tsx
|
|
9049
9399
|
import { Box as Box11, Text as Text11 } from "ink";
|
|
9050
|
-
import
|
|
9400
|
+
import React13 from "react";
|
|
9051
9401
|
function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
|
|
9052
9402
|
const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan2) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan2);
|
|
9053
|
-
return /* @__PURE__ */
|
|
9403
|
+
return /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Box11, null, /* @__PURE__ */ React13.createElement(Text11, { bold: true, color: "cyan" }, "\u25B8 plan proposed (full text above) \u2014 approve / refine / cancel")), summary ? /* @__PURE__ */ React13.createElement(Box11, null, /* @__PURE__ */ React13.createElement(Text11, { color: "cyan" }, ` ${summary}`)) : null), hasOpenQuestions ? /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text11, { color: "yellow" }, "\u25B2 the plan flags open questions or risks \u2014 pick", " ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null, steps && steps.length > 0 ? /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(PlanStepList, { steps })) : null, /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(
|
|
9054
9404
|
SingleSelect,
|
|
9055
9405
|
{
|
|
9056
9406
|
initialValue: hasOpenQuestions ? "refine" : "approve",
|
|
@@ -9077,39 +9427,43 @@ function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
|
|
|
9077
9427
|
}
|
|
9078
9428
|
)));
|
|
9079
9429
|
}
|
|
9080
|
-
var PlanConfirm =
|
|
9430
|
+
var PlanConfirm = React13.memo(PlanConfirmInner);
|
|
9081
9431
|
|
|
9082
9432
|
// src/cli/ui/PlanRefineInput.tsx
|
|
9083
|
-
import { Box as Box12, Text as Text12
|
|
9084
|
-
import
|
|
9433
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
9434
|
+
import React14, { useState as useState4 } from "react";
|
|
9085
9435
|
function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
|
|
9086
9436
|
const [value, setValue] = useState4("");
|
|
9087
|
-
|
|
9088
|
-
if (
|
|
9437
|
+
useKeystroke((ev) => {
|
|
9438
|
+
if (ev.paste) {
|
|
9439
|
+
setValue((v) => v + ev.input.replace(/\r?\n/g, " "));
|
|
9440
|
+
return;
|
|
9441
|
+
}
|
|
9442
|
+
if (ev.escape) {
|
|
9089
9443
|
onCancel();
|
|
9090
9444
|
return;
|
|
9091
9445
|
}
|
|
9092
|
-
if (
|
|
9446
|
+
if (ev.return) {
|
|
9093
9447
|
onSubmit(value.trim());
|
|
9094
9448
|
return;
|
|
9095
9449
|
}
|
|
9096
|
-
if (
|
|
9450
|
+
if (ev.backspace || ev.delete) {
|
|
9097
9451
|
setValue((v) => v.slice(0, -1));
|
|
9098
9452
|
return;
|
|
9099
9453
|
}
|
|
9100
|
-
if (input && !
|
|
9101
|
-
setValue((v) => v + input);
|
|
9454
|
+
if (ev.input && !ev.ctrl && !ev.meta) {
|
|
9455
|
+
setValue((v) => v + ev.input);
|
|
9102
9456
|
}
|
|
9103
9457
|
});
|
|
9104
9458
|
const title = mode2 === "approve" ? "\u25B8 approving \u2014 any last instructions or answers to open questions?" : mode2 === "checkpoint-revise" ? "\u25B8 revising \u2014 what should change before the next step?" : mode2 === "choice-custom" ? "\u25B8 custom answer \u2014 type whatever fits" : "\u25B8 refining \u2014 what should the model change?";
|
|
9105
9459
|
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 will adjust the remaining plan based on this." : 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
9460
|
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__ */
|
|
9461
|
+
return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text12, { bold: true, color: "yellow" }, title)), /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text12, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text12, null, /* @__PURE__ */ React14.createElement(Text12, { color: "yellow" }, "\u203A "), /* @__PURE__ */ React14.createElement(Text12, null, value || " "), /* @__PURE__ */ React14.createElement(Text12, { color: "yellow" }, "\u258D"))));
|
|
9108
9462
|
}
|
|
9109
9463
|
|
|
9110
9464
|
// src/cli/ui/PlanReviseConfirm.tsx
|
|
9111
9465
|
import { Box as Box13, Text as Text13 } from "ink";
|
|
9112
|
-
import
|
|
9466
|
+
import React15 from "react";
|
|
9113
9467
|
function computeDiff(oldSteps, newSteps) {
|
|
9114
9468
|
const oldIds = new Set(oldSteps.map((s) => s.id));
|
|
9115
9469
|
const newIds = new Set(newSteps.map((s) => s.id));
|
|
@@ -9145,14 +9499,14 @@ function PlanReviseConfirmInner({
|
|
|
9145
9499
|
const removedCount = rows.filter((r) => r.kind === "removed").length;
|
|
9146
9500
|
const addedCount = rows.filter((r) => r.kind === "added").length;
|
|
9147
9501
|
const keptCount = rows.filter((r) => r.kind === "kept").length;
|
|
9148
|
-
return /* @__PURE__ */
|
|
9502
|
+
return /* @__PURE__ */ React15.createElement(Box13, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React15.createElement(Box13, null, /* @__PURE__ */ React15.createElement(Text13, { bold: true, color: "yellow" }, "\u270F plan revision proposed"), /* @__PURE__ */ React15.createElement(Text13, { dimColor: true }, ` \u2212${removedCount} +${addedCount} (${keptCount} kept)`)), /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text13, null, reason)), summary ? /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text13, { dimColor: true }, `updated summary: ${summary}`)) : null, /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1, flexDirection: "column" }, rows.map((row2) => {
|
|
9149
9503
|
const risk = riskDots2(row2.step.risk);
|
|
9150
9504
|
const prefix = row2.kind === "removed" ? "\u2212" : row2.kind === "added" ? "+" : " ";
|
|
9151
9505
|
const prefixColor = row2.kind === "removed" ? "red" : row2.kind === "added" ? "green" : "gray";
|
|
9152
9506
|
const dim = row2.kind === "kept";
|
|
9153
9507
|
const strike = row2.kind === "removed";
|
|
9154
|
-
return /* @__PURE__ */
|
|
9155
|
-
})), /* @__PURE__ */
|
|
9508
|
+
return /* @__PURE__ */ React15.createElement(Box13, { key: `${row2.kind}-${row2.step.id}` }, /* @__PURE__ */ React15.createElement(Text13, { color: prefixColor, bold: true }, `${prefix} `), /* @__PURE__ */ React15.createElement(Text13, { color: risk.color, bold: true, dimColor: dim }, risk.dots), /* @__PURE__ */ React15.createElement(Text13, { dimColor: dim, strikethrough: strike }, ` ${row2.step.id} \xB7 ${row2.step.title}`));
|
|
9509
|
+
})), /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(
|
|
9156
9510
|
SingleSelect,
|
|
9157
9511
|
{
|
|
9158
9512
|
initialValue: "accept",
|
|
@@ -9174,25 +9528,62 @@ function PlanReviseConfirmInner({
|
|
|
9174
9528
|
}
|
|
9175
9529
|
)));
|
|
9176
9530
|
}
|
|
9177
|
-
var PlanReviseConfirm =
|
|
9531
|
+
var PlanReviseConfirm = React15.memo(PlanReviseConfirmInner);
|
|
9178
9532
|
|
|
9179
9533
|
// src/cli/ui/PromptInput.tsx
|
|
9180
|
-
import { Box as Box14, Text as Text14,
|
|
9181
|
-
import
|
|
9534
|
+
import { Box as Box14, Text as Text14, useStdout as useStdout3 } from "ink";
|
|
9535
|
+
import React16, { useRef as useRef2, useState as useState5 } from "react";
|
|
9536
|
+
|
|
9537
|
+
// src/cli/ui/key-normalize.ts
|
|
9538
|
+
var CSI_TAIL_TO_FLAGS = [
|
|
9539
|
+
// Arrow keys — the most common ConPTY victim.
|
|
9540
|
+
{ tail: "[A", flags: { upArrow: true } },
|
|
9541
|
+
{ tail: "[B", flags: { downArrow: true } },
|
|
9542
|
+
{ tail: "[C", flags: { rightArrow: true } },
|
|
9543
|
+
{ tail: "[D", flags: { leftArrow: true } },
|
|
9544
|
+
// Page navigation.
|
|
9545
|
+
{ tail: "[5~", flags: { pageUp: true } },
|
|
9546
|
+
{ tail: "[6~", flags: { pageDown: true } },
|
|
9547
|
+
// Forward-delete (the key labelled Delete on most keyboards).
|
|
9548
|
+
{ tail: "[3~", flags: { delete: true } },
|
|
9549
|
+
// Shift+Tab — terminal sends `\x1b[Z` rather than tab-with-shift.
|
|
9550
|
+
{ tail: "[Z", flags: { shift: true, tab: true } }
|
|
9551
|
+
];
|
|
9552
|
+
function alreadyStructured(flags) {
|
|
9553
|
+
return Boolean(
|
|
9554
|
+
flags.upArrow || flags.downArrow || flags.leftArrow || flags.rightArrow || flags.pageUp || flags.pageDown || flags.delete || flags.tab && flags.shift
|
|
9555
|
+
);
|
|
9556
|
+
}
|
|
9557
|
+
function recoverCsiTail(input, existing = {}) {
|
|
9558
|
+
if (alreadyStructured(existing)) return null;
|
|
9559
|
+
for (const entry of CSI_TAIL_TO_FLAGS) {
|
|
9560
|
+
if (input === entry.tail || input === `\x1B${entry.tail}`) {
|
|
9561
|
+
return entry.flags;
|
|
9562
|
+
}
|
|
9563
|
+
}
|
|
9564
|
+
return null;
|
|
9565
|
+
}
|
|
9566
|
+
var STRIPPABLE_CSI_FRAGMENTS = [
|
|
9567
|
+
"\x1B[200~",
|
|
9568
|
+
"\x1B[201~",
|
|
9569
|
+
"[200~",
|
|
9570
|
+
"[201~",
|
|
9571
|
+
...CSI_TAIL_TO_FLAGS.flatMap((e) => [`\x1B${e.tail}`, e.tail])
|
|
9572
|
+
];
|
|
9573
|
+
function stripCsiFragments(input) {
|
|
9574
|
+
let out = input;
|
|
9575
|
+
for (const frag of STRIPPABLE_CSI_FRAGMENTS) {
|
|
9576
|
+
if (out.includes(frag)) out = out.replaceAll(frag, "");
|
|
9577
|
+
}
|
|
9578
|
+
return out;
|
|
9579
|
+
}
|
|
9182
9580
|
|
|
9183
9581
|
// src/cli/ui/multiline-keys.ts
|
|
9184
9582
|
var BACKSLASH_SUFFIX = /\\$/;
|
|
9185
9583
|
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
9584
|
function processMultilineKey(value, cursor, keyIn) {
|
|
9195
|
-
const
|
|
9585
|
+
const recovered = recoverCsiTail(keyIn.input, keyIn);
|
|
9586
|
+
const key = recovered ? { ...keyIn, ...recovered, input: "" } : keyIn;
|
|
9196
9587
|
if (key.tab || key.escape) {
|
|
9197
9588
|
return NOOP;
|
|
9198
9589
|
}
|
|
@@ -9239,7 +9630,7 @@ function processMultilineKey(value, cursor, keyIn) {
|
|
|
9239
9630
|
submit: false
|
|
9240
9631
|
};
|
|
9241
9632
|
}
|
|
9242
|
-
const stripped = key.input
|
|
9633
|
+
const stripped = stripCsiFragments(key.input);
|
|
9243
9634
|
const looksLikePaste = stripped.length > 1 && (stripped.includes("\n") || stripped.includes("\r"));
|
|
9244
9635
|
if (looksLikePaste) {
|
|
9245
9636
|
const normalized = stripped.replace(/\r\n?/g, "\n");
|
|
@@ -9383,10 +9774,159 @@ function formatBytesShort(n) {
|
|
|
9383
9774
|
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
9384
9775
|
}
|
|
9385
9776
|
|
|
9777
|
+
// src/cli/ui/prompt-viewport.ts
|
|
9778
|
+
function charCells(ch) {
|
|
9779
|
+
if (ch.length === 0) return 0;
|
|
9780
|
+
const code = ch.charCodeAt(0);
|
|
9781
|
+
if (code < 32 || code === 127) return 0;
|
|
9782
|
+
if (code < 4352) return 1;
|
|
9783
|
+
if (code >= 4352 && code <= 4447) return 2;
|
|
9784
|
+
if (code >= 11904 && code <= 12350) return 2;
|
|
9785
|
+
if (code >= 12353 && code <= 13311) return 2;
|
|
9786
|
+
if (code >= 13312 && code <= 19903) return 2;
|
|
9787
|
+
if (code >= 19968 && code <= 40959) return 2;
|
|
9788
|
+
if (code >= 40960 && code <= 42191) return 2;
|
|
9789
|
+
if (code >= 44032 && code <= 55203) return 2;
|
|
9790
|
+
if (code >= 63744 && code <= 64255) return 2;
|
|
9791
|
+
if (code >= 65072 && code <= 65103) return 2;
|
|
9792
|
+
if (code >= 65280 && code <= 65376) return 2;
|
|
9793
|
+
if (code >= 65504 && code <= 65510) return 2;
|
|
9794
|
+
return 1;
|
|
9795
|
+
}
|
|
9796
|
+
function stringCells(s, pastes) {
|
|
9797
|
+
let n = 0;
|
|
9798
|
+
for (let i = 0; i < s.length; i++) {
|
|
9799
|
+
const ch = s[i];
|
|
9800
|
+
const id = decodePasteSentinel(ch);
|
|
9801
|
+
if (id !== null) {
|
|
9802
|
+
n += pasteSentinelCells(id, pastes);
|
|
9803
|
+
} else {
|
|
9804
|
+
n += charCells(ch);
|
|
9805
|
+
}
|
|
9806
|
+
}
|
|
9807
|
+
return n;
|
|
9808
|
+
}
|
|
9809
|
+
function pasteSentinelLabel(id, entry) {
|
|
9810
|
+
if (!entry) return `[paste #${id + 1} \xB7 (missing)]`;
|
|
9811
|
+
return `[paste #${id + 1} \xB7 ${entry.lineCount}l \xB7 ${formatBytesShort(entry.charCount)}]`;
|
|
9812
|
+
}
|
|
9813
|
+
function pasteSentinelCells(id, pastes) {
|
|
9814
|
+
const entry = pastes?.get(id);
|
|
9815
|
+
return pasteSentinelLabel(id, entry).length;
|
|
9816
|
+
}
|
|
9817
|
+
function buildViewport(line, cursorCol, visibleCells, pastes) {
|
|
9818
|
+
if (visibleCells <= 0) {
|
|
9819
|
+
return {
|
|
9820
|
+
segments: [],
|
|
9821
|
+
cursorCell: cursorCol === null ? null : 0,
|
|
9822
|
+
hiddenLeft: false,
|
|
9823
|
+
hiddenRight: line.length > 0
|
|
9824
|
+
};
|
|
9825
|
+
}
|
|
9826
|
+
const totalCells = stringCells(line, pastes);
|
|
9827
|
+
if (totalCells <= visibleCells) {
|
|
9828
|
+
const segments = textToSegments(line, pastes);
|
|
9829
|
+
let cursorCell = null;
|
|
9830
|
+
if (cursorCol !== null) {
|
|
9831
|
+
cursorCell = stringCells(line.slice(0, cursorCol), pastes);
|
|
9832
|
+
}
|
|
9833
|
+
return { segments, cursorCell, hiddenLeft: false, hiddenRight: false };
|
|
9834
|
+
}
|
|
9835
|
+
if (cursorCol === null) {
|
|
9836
|
+
return clipFromLeft(line, visibleCells, pastes);
|
|
9837
|
+
}
|
|
9838
|
+
return clipAroundCursor(line, cursorCol, visibleCells, pastes);
|
|
9839
|
+
}
|
|
9840
|
+
function clipFromLeft(line, visibleCells, pastes) {
|
|
9841
|
+
const budget = Math.max(1, visibleCells - 1);
|
|
9842
|
+
let used = 0;
|
|
9843
|
+
let end = 0;
|
|
9844
|
+
while (end < line.length) {
|
|
9845
|
+
const ch = line[end];
|
|
9846
|
+
const cw = charCellsAt(line, end, pastes);
|
|
9847
|
+
if (used + cw > budget) break;
|
|
9848
|
+
used += cw;
|
|
9849
|
+
end++;
|
|
9850
|
+
}
|
|
9851
|
+
const segments = textToSegments(line.slice(0, end), pastes);
|
|
9852
|
+
return { segments, cursorCell: null, hiddenLeft: false, hiddenRight: end < line.length };
|
|
9853
|
+
}
|
|
9854
|
+
function clipAroundCursor(line, cursorCol, visibleCells, pastes) {
|
|
9855
|
+
let budget = visibleCells;
|
|
9856
|
+
const reservedForMarkers = 2;
|
|
9857
|
+
budget = Math.max(1, budget - reservedForMarkers);
|
|
9858
|
+
const halfBudget = Math.floor(budget / 2);
|
|
9859
|
+
let start = cursorCol;
|
|
9860
|
+
let leftCells = 0;
|
|
9861
|
+
while (start > 0 && leftCells < halfBudget) {
|
|
9862
|
+
const cw = charCellsAt(line, start - 1, pastes);
|
|
9863
|
+
if (leftCells + cw > halfBudget) break;
|
|
9864
|
+
start--;
|
|
9865
|
+
leftCells += cw;
|
|
9866
|
+
}
|
|
9867
|
+
const rightBudget = budget - leftCells;
|
|
9868
|
+
let end = cursorCol;
|
|
9869
|
+
let rightCells = 0;
|
|
9870
|
+
const cursorChar = cursorCol < line.length ? charCellsAt(line, cursorCol, pastes) : 1;
|
|
9871
|
+
if (rightBudget >= cursorChar) {
|
|
9872
|
+
if (cursorCol < line.length) end = cursorCol + 1;
|
|
9873
|
+
rightCells = cursorChar;
|
|
9874
|
+
while (end < line.length && rightCells < rightBudget) {
|
|
9875
|
+
const cw = charCellsAt(line, end, pastes);
|
|
9876
|
+
if (rightCells + cw > rightBudget) break;
|
|
9877
|
+
rightCells += cw;
|
|
9878
|
+
end++;
|
|
9879
|
+
}
|
|
9880
|
+
}
|
|
9881
|
+
let extraLeftBudget = rightBudget - rightCells;
|
|
9882
|
+
while (start > 0 && extraLeftBudget > 0) {
|
|
9883
|
+
const cw = charCellsAt(line, start - 1, pastes);
|
|
9884
|
+
if (cw > extraLeftBudget) break;
|
|
9885
|
+
start--;
|
|
9886
|
+
leftCells += cw;
|
|
9887
|
+
extraLeftBudget -= cw;
|
|
9888
|
+
}
|
|
9889
|
+
const hiddenLeft = start > 0;
|
|
9890
|
+
const hiddenRight = end < line.length;
|
|
9891
|
+
const segments = textToSegments(line.slice(start, end), pastes);
|
|
9892
|
+
const cursorCell = stringCells(line.slice(start, cursorCol), pastes);
|
|
9893
|
+
return { segments, cursorCell, hiddenLeft, hiddenRight };
|
|
9894
|
+
}
|
|
9895
|
+
function charCellsAt(line, idx, pastes) {
|
|
9896
|
+
const ch = line[idx];
|
|
9897
|
+
const id = decodePasteSentinel(ch);
|
|
9898
|
+
if (id !== null) {
|
|
9899
|
+
const entry = pastes?.get(id);
|
|
9900
|
+
return pasteSentinelLabel(id, entry).length;
|
|
9901
|
+
}
|
|
9902
|
+
return charCells(ch);
|
|
9903
|
+
}
|
|
9904
|
+
function textToSegments(line, pastes) {
|
|
9905
|
+
const out = [];
|
|
9906
|
+
let buf = "";
|
|
9907
|
+
const flushBuf = () => {
|
|
9908
|
+
if (buf.length > 0) {
|
|
9909
|
+
out.push({ kind: "text", text: buf });
|
|
9910
|
+
buf = "";
|
|
9911
|
+
}
|
|
9912
|
+
};
|
|
9913
|
+
for (let i = 0; i < line.length; i++) {
|
|
9914
|
+
const ch = line[i];
|
|
9915
|
+
const id = decodePasteSentinel(ch);
|
|
9916
|
+
if (id !== null) {
|
|
9917
|
+
flushBuf();
|
|
9918
|
+
const label = pasteSentinelLabel(id, pastes?.get(id));
|
|
9919
|
+
out.push({ kind: "paste", id, label });
|
|
9920
|
+
} else {
|
|
9921
|
+
buf += ch;
|
|
9922
|
+
}
|
|
9923
|
+
}
|
|
9924
|
+
flushBuf();
|
|
9925
|
+
return out;
|
|
9926
|
+
}
|
|
9927
|
+
|
|
9386
9928
|
// src/cli/ui/PromptInput.tsx
|
|
9387
|
-
var
|
|
9388
|
-
var PASTE_END_MARKER = "\x1B[201~";
|
|
9389
|
-
var PASTE_MERGE_WINDOW_MS = 30;
|
|
9929
|
+
var BAR = "\u258E ";
|
|
9390
9930
|
function PromptInput({
|
|
9391
9931
|
value,
|
|
9392
9932
|
onChange,
|
|
@@ -9397,157 +9937,248 @@ function PromptInput({
|
|
|
9397
9937
|
onHistoryNext
|
|
9398
9938
|
}) {
|
|
9399
9939
|
const [cursor, setCursor] = useState5(value.length);
|
|
9400
|
-
const pastesRef =
|
|
9401
|
-
const nextPasteIdRef =
|
|
9402
|
-
const
|
|
9403
|
-
const lastPasteRef = useRef(null);
|
|
9404
|
-
const lastLocalValueRef = useRef(value);
|
|
9940
|
+
const pastesRef = useRef2(/* @__PURE__ */ new Map());
|
|
9941
|
+
const nextPasteIdRef = useRef2(0);
|
|
9942
|
+
const lastLocalValueRef = useRef2(value);
|
|
9405
9943
|
if (value !== lastLocalValueRef.current) {
|
|
9406
9944
|
lastLocalValueRef.current = value;
|
|
9407
|
-
if (cursor !== value.length)
|
|
9408
|
-
setCursor(value.length);
|
|
9409
|
-
}
|
|
9945
|
+
if (cursor !== value.length) setCursor(value.length);
|
|
9410
9946
|
}
|
|
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
9947
|
const registerPaste = (content) => {
|
|
9416
9948
|
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
|
-
}
|
|
9949
|
+
const c = cursor;
|
|
9432
9950
|
const id = nextPasteIdRef.current % PASTE_SENTINEL_RANGE;
|
|
9433
9951
|
nextPasteIdRef.current = id + 1;
|
|
9434
9952
|
pastesRef.current.set(id, makePasteEntry(id, content));
|
|
9435
9953
|
const sentinel = encodePasteSentinel(id);
|
|
9436
9954
|
const next = v.slice(0, c) + sentinel + v.slice(c);
|
|
9437
9955
|
lastLocalValueRef.current = next;
|
|
9438
|
-
cursorRef.current = c + 1;
|
|
9439
9956
|
onChange(next);
|
|
9440
9957
|
setCursor(c + 1);
|
|
9441
|
-
lastPasteRef.current = { id, at: now };
|
|
9442
9958
|
};
|
|
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);
|
|
9959
|
+
useKeystroke((ev) => {
|
|
9960
|
+
if (disabled) return;
|
|
9961
|
+
if (ev.paste) {
|
|
9962
|
+
if (ev.input.length > 0) registerPaste(ev.input);
|
|
9963
|
+
return;
|
|
9964
|
+
}
|
|
9965
|
+
const key = {
|
|
9966
|
+
input: ev.input,
|
|
9967
|
+
return: ev.return,
|
|
9968
|
+
shift: ev.shift,
|
|
9969
|
+
ctrl: ev.ctrl,
|
|
9970
|
+
meta: ev.meta,
|
|
9971
|
+
backspace: ev.backspace,
|
|
9972
|
+
delete: ev.delete,
|
|
9973
|
+
tab: ev.tab,
|
|
9974
|
+
upArrow: ev.upArrow,
|
|
9975
|
+
downArrow: ev.downArrow,
|
|
9976
|
+
leftArrow: ev.leftArrow,
|
|
9977
|
+
rightArrow: ev.rightArrow,
|
|
9978
|
+
escape: ev.escape,
|
|
9979
|
+
pageUp: ev.pageUp,
|
|
9980
|
+
pageDown: ev.pageDown
|
|
9981
|
+
};
|
|
9982
|
+
const action = processMultilineKey(value, cursor, key);
|
|
9983
|
+
if (action.pasteRequest) {
|
|
9984
|
+
registerPaste(action.pasteRequest.content);
|
|
9985
|
+
return;
|
|
9986
|
+
}
|
|
9987
|
+
if (action.next !== null) {
|
|
9988
|
+
lastLocalValueRef.current = action.next;
|
|
9989
|
+
onChange(action.next);
|
|
9990
|
+
}
|
|
9991
|
+
if (action.cursor !== null) {
|
|
9992
|
+
setCursor(action.cursor);
|
|
9993
|
+
}
|
|
9994
|
+
if (action.submit) {
|
|
9995
|
+
const raw = action.submitValue ?? value;
|
|
9996
|
+
const expanded = expandPasteSentinels(raw, pastesRef.current);
|
|
9997
|
+
const reachable = new Set(listPasteIdsInBuffer(raw));
|
|
9998
|
+
for (const id of pastesRef.current.keys()) {
|
|
9999
|
+
if (!reachable.has(id)) pastesRef.current.delete(id);
|
|
9504
10000
|
}
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
);
|
|
10001
|
+
onSubmit(expanded);
|
|
10002
|
+
}
|
|
10003
|
+
if (action.historyHandoff === "prev") onHistoryPrev?.();
|
|
10004
|
+
if (action.historyHandoff === "next") onHistoryNext?.();
|
|
10005
|
+
}, !disabled);
|
|
9510
10006
|
const { stdout: stdout2 } = useStdout3();
|
|
9511
10007
|
const cols = stdout2?.columns ?? 80;
|
|
9512
10008
|
const narrow = cols <= 90;
|
|
9513
|
-
const
|
|
9514
|
-
const
|
|
9515
|
-
const
|
|
10009
|
+
const promptBody = narrow ? "\u203A " : "you \u203A ";
|
|
10010
|
+
const promptPrefix = BAR + promptBody;
|
|
10011
|
+
const continuationIndent = BAR + " ".repeat(promptBody.length);
|
|
10012
|
+
const prefixCells = promptPrefix.length;
|
|
10013
|
+
const visibleCells = Math.max(8, cols - prefixCells - 3);
|
|
10014
|
+
const placeholderActive = narrow ? "type a message, or /command" : "type a message, or /command \xB7 [Ctrl+J] newline (Shift+Enter where supported)";
|
|
9516
10015
|
const effectivePlaceholder = disabled ? placeholder ?? "\u2026waiting for response\u2026" : placeholder ?? placeholderActive;
|
|
9517
10016
|
const lines = value.length > 0 ? value.split("\n") : [""];
|
|
9518
|
-
const
|
|
10017
|
+
const accentColor = disabled ? "gray" : "cyan";
|
|
9519
10018
|
const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
|
|
9520
10019
|
const renderItems = collapseLinesForDisplay(lines, cursorLine);
|
|
9521
10020
|
const showHugeBufferHints = lines.length > 20;
|
|
9522
|
-
return /* @__PURE__ */
|
|
10021
|
+
return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", paddingX: 1 }, renderItems.map((item, renderIdx) => {
|
|
9523
10022
|
if (item.kind === "skip") {
|
|
9524
10023
|
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
|
-
))
|
|
10024
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stable — collapse markers derive from a fixed sliding window
|
|
10025
|
+
/* @__PURE__ */ React16.createElement(Box14, { key: `skip-${renderIdx}` }, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, `[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`))
|
|
9533
10026
|
);
|
|
9534
10027
|
}
|
|
9535
|
-
const line = item.line;
|
|
9536
10028
|
const i = item.originalIndex;
|
|
10029
|
+
const line = item.line;
|
|
9537
10030
|
const isFirst = i === 0;
|
|
9538
|
-
const showPlaceholder = isFirst && value.length === 0;
|
|
9539
10031
|
const isCursorLine = i === cursorLine;
|
|
9540
|
-
|
|
9541
|
-
|
|
10032
|
+
const showPlaceholder = isFirst && value.length === 0;
|
|
10033
|
+
return /* @__PURE__ */ React16.createElement(
|
|
10034
|
+
PromptLine,
|
|
9542
10035
|
{
|
|
10036
|
+
key: `ln-${i}`,
|
|
9543
10037
|
line,
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
10038
|
+
isFirst,
|
|
10039
|
+
isCursorLine: isCursorLine && !disabled,
|
|
10040
|
+
cursorCol: isCursorLine ? cursorCol : null,
|
|
10041
|
+
showPlaceholder,
|
|
10042
|
+
placeholderText: effectivePlaceholder,
|
|
10043
|
+
promptPrefix,
|
|
10044
|
+
continuationIndent,
|
|
10045
|
+
visibleCells,
|
|
10046
|
+
accentColor,
|
|
10047
|
+
pastes: pastesRef.current,
|
|
10048
|
+
disabled: disabled === true
|
|
9548
10049
|
}
|
|
9549
|
-
)
|
|
9550
|
-
}), showHugeBufferHints && !disabled ? /* @__PURE__ */
|
|
10050
|
+
);
|
|
10051
|
+
}), showHugeBufferHints && !disabled ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { 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__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, "[Ctrl+J] newline \xB7 [Enter] submit \xB7 ends with \\ for line continuation")) : null, disabled ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, "[Esc] to stop")) : null);
|
|
10052
|
+
}
|
|
10053
|
+
function PromptLine({
|
|
10054
|
+
line,
|
|
10055
|
+
isFirst,
|
|
10056
|
+
isCursorLine,
|
|
10057
|
+
cursorCol,
|
|
10058
|
+
showPlaceholder,
|
|
10059
|
+
placeholderText,
|
|
10060
|
+
promptPrefix,
|
|
10061
|
+
continuationIndent,
|
|
10062
|
+
visibleCells,
|
|
10063
|
+
accentColor,
|
|
10064
|
+
pastes,
|
|
10065
|
+
disabled
|
|
10066
|
+
}) {
|
|
10067
|
+
const barText = promptPrefix.slice(0, BAR.length);
|
|
10068
|
+
const bodyPrefix = promptPrefix.slice(BAR.length);
|
|
10069
|
+
const bodyContinuation = continuationIndent.slice(BAR.length);
|
|
10070
|
+
if (showPlaceholder) {
|
|
10071
|
+
return /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, barText), /* @__PURE__ */ React16.createElement(Text14, { bold: true, color: accentColor }, bodyPrefix), !disabled ? /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, "\u258C") : null, /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, placeholderText));
|
|
10072
|
+
}
|
|
10073
|
+
const viewport = buildViewport(line, isCursorLine ? cursorCol : null, visibleCells, pastes);
|
|
10074
|
+
return /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, barText), isFirst ? /* @__PURE__ */ React16.createElement(Text14, { bold: true, color: accentColor }, bodyPrefix) : /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, bodyContinuation), viewport.hiddenLeft ? /* @__PURE__ */ React16.createElement(Text14, { color: "gray", dimColor: true }, "\u2039") : null, /* @__PURE__ */ React16.createElement(
|
|
10075
|
+
ViewportContent,
|
|
10076
|
+
{
|
|
10077
|
+
segments: viewport.segments,
|
|
10078
|
+
cursorCell: isCursorLine ? viewport.cursorCell : null,
|
|
10079
|
+
accentColor
|
|
10080
|
+
}
|
|
10081
|
+
), viewport.hiddenRight ? /* @__PURE__ */ React16.createElement(Text14, { color: "gray", dimColor: true }, "\u203A") : null);
|
|
10082
|
+
}
|
|
10083
|
+
function ViewportContent({
|
|
10084
|
+
segments,
|
|
10085
|
+
cursorCell,
|
|
10086
|
+
accentColor
|
|
10087
|
+
}) {
|
|
10088
|
+
if (cursorCell === null) {
|
|
10089
|
+
return /* @__PURE__ */ React16.createElement(React16.Fragment, null, segments.map((seg, i) => renderSegment(seg, i, false)));
|
|
10090
|
+
}
|
|
10091
|
+
const out = [];
|
|
10092
|
+
let cells = 0;
|
|
10093
|
+
let placed = false;
|
|
10094
|
+
for (let i = 0; i < segments.length; i++) {
|
|
10095
|
+
const seg = segments[i];
|
|
10096
|
+
const segCells = segmentCells(seg);
|
|
10097
|
+
if (placed) {
|
|
10098
|
+
out.push(renderSegment(seg, i, false));
|
|
10099
|
+
continue;
|
|
10100
|
+
}
|
|
10101
|
+
if (cursorCell >= cells + segCells) {
|
|
10102
|
+
out.push(renderSegment(seg, i, false));
|
|
10103
|
+
cells += segCells;
|
|
10104
|
+
continue;
|
|
10105
|
+
}
|
|
10106
|
+
if (seg.kind === "paste") {
|
|
10107
|
+
out.push(
|
|
10108
|
+
/* @__PURE__ */ React16.createElement(Text14, { key: `p-${i}-cursor`, color: "magenta", bold: true, inverse: true }, seg.label)
|
|
10109
|
+
);
|
|
10110
|
+
placed = true;
|
|
10111
|
+
cells += segCells;
|
|
10112
|
+
continue;
|
|
10113
|
+
}
|
|
10114
|
+
const offsetIntoSeg = cursorCell - cells;
|
|
10115
|
+
const split = splitTextByCells(seg.text, offsetIntoSeg);
|
|
10116
|
+
if (split.before.length > 0) {
|
|
10117
|
+
out.push(/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-b` }, split.before));
|
|
10118
|
+
}
|
|
10119
|
+
if (split.atCursor.length > 0) {
|
|
10120
|
+
out.push(
|
|
10121
|
+
/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-c`, inverse: true, color: accentColor }, split.atCursor)
|
|
10122
|
+
);
|
|
10123
|
+
} else {
|
|
10124
|
+
out.push(
|
|
10125
|
+
/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-c-eol`, color: accentColor }, "\u258C")
|
|
10126
|
+
);
|
|
10127
|
+
}
|
|
10128
|
+
if (split.after.length > 0) {
|
|
10129
|
+
out.push(/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-a` }, split.after));
|
|
10130
|
+
}
|
|
10131
|
+
placed = true;
|
|
10132
|
+
cells += segCells;
|
|
10133
|
+
}
|
|
10134
|
+
if (!placed) {
|
|
10135
|
+
out.push(
|
|
10136
|
+
/* @__PURE__ */ React16.createElement(Text14, { key: "cursor-eol", color: accentColor }, "\u258C")
|
|
10137
|
+
);
|
|
10138
|
+
}
|
|
10139
|
+
return /* @__PURE__ */ React16.createElement(React16.Fragment, null, out);
|
|
10140
|
+
}
|
|
10141
|
+
function segmentCells(seg) {
|
|
10142
|
+
if (seg.kind === "paste") return seg.label.length;
|
|
10143
|
+
return stringCells(seg.text);
|
|
10144
|
+
}
|
|
10145
|
+
function splitTextByCells(text, cellOffset) {
|
|
10146
|
+
let cells = 0;
|
|
10147
|
+
for (let i = 0; i < text.length; i++) {
|
|
10148
|
+
const ch = text[i];
|
|
10149
|
+
const cw = charCellsForText(ch);
|
|
10150
|
+
if (cells === cellOffset) {
|
|
10151
|
+
return { before: text.slice(0, i), atCursor: ch, after: text.slice(i + 1) };
|
|
10152
|
+
}
|
|
10153
|
+
if (cells + cw > cellOffset) {
|
|
10154
|
+
return { before: text.slice(0, i), atCursor: ch, after: text.slice(i + 1) };
|
|
10155
|
+
}
|
|
10156
|
+
cells += cw;
|
|
10157
|
+
}
|
|
10158
|
+
return { before: text, atCursor: "", after: "" };
|
|
10159
|
+
}
|
|
10160
|
+
function charCellsForText(ch) {
|
|
10161
|
+
const code = ch.charCodeAt(0);
|
|
10162
|
+
if (code < 32 || code === 127) return 0;
|
|
10163
|
+
if (code < 4352) return 1;
|
|
10164
|
+
if (code >= 4352 && code <= 4447) return 2;
|
|
10165
|
+
if (code >= 11904 && code <= 12350) return 2;
|
|
10166
|
+
if (code >= 12353 && code <= 13311) return 2;
|
|
10167
|
+
if (code >= 13312 && code <= 19903) return 2;
|
|
10168
|
+
if (code >= 19968 && code <= 40959) return 2;
|
|
10169
|
+
if (code >= 40960 && code <= 42191) return 2;
|
|
10170
|
+
if (code >= 44032 && code <= 55203) return 2;
|
|
10171
|
+
if (code >= 63744 && code <= 64255) return 2;
|
|
10172
|
+
if (code >= 65072 && code <= 65103) return 2;
|
|
10173
|
+
if (code >= 65280 && code <= 65376) return 2;
|
|
10174
|
+
if (code >= 65504 && code <= 65510) return 2;
|
|
10175
|
+
return 1;
|
|
10176
|
+
}
|
|
10177
|
+
function renderSegment(seg, key, _inverse) {
|
|
10178
|
+
if (seg.kind === "text") {
|
|
10179
|
+
return /* @__PURE__ */ React16.createElement(Text14, { key: `s-${key}` }, seg.text);
|
|
10180
|
+
}
|
|
10181
|
+
return /* @__PURE__ */ React16.createElement(Text14, { key: `s-${key}`, color: "magenta", bold: true }, seg.label);
|
|
9551
10182
|
}
|
|
9552
10183
|
var COLLAPSE_THRESHOLD = 20;
|
|
9553
10184
|
var COLLAPSE_HEAD_LINES = 3;
|
|
@@ -9572,63 +10203,13 @@ function collapseLinesForDisplay(lines, cursorLine) {
|
|
|
9572
10203
|
}
|
|
9573
10204
|
return out;
|
|
9574
10205
|
}
|
|
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
10206
|
|
|
9626
10207
|
// src/cli/ui/ShellConfirm.tsx
|
|
9627
10208
|
import { Box as Box15, Text as Text15 } from "ink";
|
|
9628
|
-
import
|
|
10209
|
+
import React17 from "react";
|
|
9629
10210
|
function ShellConfirm({ command, allowPrefix, kind, onChoose }) {
|
|
9630
10211
|
const isBackground = kind === "run_background";
|
|
9631
|
-
return /* @__PURE__ */
|
|
10212
|
+
return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { bold: true, color: "red" }, isBackground ? "\u25B8 model wants to start a BACKGROUND process" : "\u25B8 model wants to run a shell command")), isBackground ? /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " (long-running: dev server / watcher; keeps running after approval, /kill to stop)")) : null, /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { color: "red", dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")), /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "$ "), /* @__PURE__ */ React17.createElement(Text15, { color: "cyan" }, command))), /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(
|
|
9632
10213
|
SingleSelect,
|
|
9633
10214
|
{
|
|
9634
10215
|
initialValue: "run_once",
|
|
@@ -9686,7 +10267,7 @@ function derivePrefix(command) {
|
|
|
9686
10267
|
|
|
9687
10268
|
// src/cli/ui/SlashArgPicker.tsx
|
|
9688
10269
|
import { Box as Box16, Text as Text16 } from "ink";
|
|
9689
|
-
import
|
|
10270
|
+
import React18 from "react";
|
|
9690
10271
|
function SlashArgPicker({
|
|
9691
10272
|
matches,
|
|
9692
10273
|
selectedIndex,
|
|
@@ -9695,11 +10276,11 @@ function SlashArgPicker({
|
|
|
9695
10276
|
partial
|
|
9696
10277
|
}) {
|
|
9697
10278
|
if (kind === "hint") {
|
|
9698
|
-
return /* @__PURE__ */
|
|
10279
|
+
return /* @__PURE__ */ React18.createElement(Box16, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary));
|
|
9699
10280
|
}
|
|
9700
10281
|
if (matches === null) return null;
|
|
9701
10282
|
if (matches.length === 0) {
|
|
9702
|
-
return /* @__PURE__ */
|
|
10283
|
+
return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, ' no match for "', partial, '" \u2014 keep typing, or Backspace to edit'));
|
|
9703
10284
|
}
|
|
9704
10285
|
const MAX = 8;
|
|
9705
10286
|
const total = matches.length;
|
|
@@ -9707,26 +10288,26 @@ function SlashArgPicker({
|
|
|
9707
10288
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
9708
10289
|
const hiddenAbove = windowStart;
|
|
9709
10290
|
const hiddenBelow = total - windowStart - shown.length;
|
|
9710
|
-
return /* @__PURE__ */
|
|
10291
|
+
return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), hiddenAbove > 0 ? /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((value, i) => /* @__PURE__ */ React18.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
|
|
9711
10292
|
}
|
|
9712
10293
|
function ArgRow({ value, isSelected }) {
|
|
9713
10294
|
const marker = isSelected ? "\u25B8" : " ";
|
|
9714
10295
|
if (isSelected) {
|
|
9715
|
-
return /* @__PURE__ */
|
|
10296
|
+
return /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { bold: true, color: "cyan" }, marker, " ", value));
|
|
9716
10297
|
}
|
|
9717
|
-
return /* @__PURE__ */
|
|
10298
|
+
return /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, marker, " ", value));
|
|
9718
10299
|
}
|
|
9719
10300
|
|
|
9720
10301
|
// src/cli/ui/SlashSuggestions.tsx
|
|
9721
10302
|
import { Box as Box17, Text as Text17 } from "ink";
|
|
9722
|
-
import
|
|
10303
|
+
import React19 from "react";
|
|
9723
10304
|
function SlashSuggestions({
|
|
9724
10305
|
matches,
|
|
9725
10306
|
selectedIndex
|
|
9726
10307
|
}) {
|
|
9727
10308
|
if (matches === null) return null;
|
|
9728
10309
|
if (matches.length === 0) {
|
|
9729
|
-
return /* @__PURE__ */
|
|
10310
|
+
return /* @__PURE__ */ React19.createElement(Box17, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text17, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
|
|
9730
10311
|
}
|
|
9731
10312
|
const MAX = 8;
|
|
9732
10313
|
const total = matches.length;
|
|
@@ -9734,21 +10315,21 @@ function SlashSuggestions({
|
|
|
9734
10315
|
const shown = matches.slice(windowStart, windowStart + MAX);
|
|
9735
10316
|
const hiddenAbove = windowStart;
|
|
9736
10317
|
const hiddenBelow = total - windowStart - shown.length;
|
|
9737
|
-
return /* @__PURE__ */
|
|
10318
|
+
return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column", paddingX: 1, marginTop: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React19.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
|
|
9738
10319
|
}
|
|
9739
10320
|
function SuggestionRow({ spec, isSelected }) {
|
|
9740
10321
|
const marker = isSelected ? "\u25B8" : " ";
|
|
9741
10322
|
const name = `/${spec.cmd}`;
|
|
9742
10323
|
const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
|
|
9743
10324
|
if (isSelected) {
|
|
9744
|
-
return /* @__PURE__ */
|
|
10325
|
+
return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text17, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React19.createElement(Text17, { color: "cyan" }, " ", spec.summary));
|
|
9745
10326
|
}
|
|
9746
|
-
return /* @__PURE__ */
|
|
10327
|
+
return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
|
|
9747
10328
|
}
|
|
9748
10329
|
|
|
9749
10330
|
// src/cli/ui/StatsPanel.tsx
|
|
9750
10331
|
import { Box as Box18, Text as Text18, useStdout as useStdout4 } from "ink";
|
|
9751
|
-
import
|
|
10332
|
+
import React20 from "react";
|
|
9752
10333
|
var WORDMARK_STYLES = [
|
|
9753
10334
|
{ ch: "\u25C8", color: "#5eead4", isLogo: true },
|
|
9754
10335
|
// teal — brand mark
|
|
@@ -9774,7 +10355,7 @@ function Wordmark({ busy }) {
|
|
|
9774
10355
|
const tick = useTick();
|
|
9775
10356
|
const period = busy ? 5 : 12;
|
|
9776
10357
|
const bright = Math.floor(tick / period) % 2 === 0;
|
|
9777
|
-
return /* @__PURE__ */
|
|
10358
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, WORDMARK_STYLES.map((c) => /* @__PURE__ */ React20.createElement(Text18, { key: `${c.ch}-${c.color}`, color: c.color, bold: c.isLogo ? bright : true }, c.ch)));
|
|
9778
10359
|
}
|
|
9779
10360
|
var NARROW_BREAKPOINT = 120;
|
|
9780
10361
|
var COLD_START_TURNS = 3;
|
|
@@ -9800,17 +10381,16 @@ function StatsPanel({
|
|
|
9800
10381
|
const columns = stdout2?.columns ?? 80;
|
|
9801
10382
|
const narrow = columns < NARROW_BREAKPOINT;
|
|
9802
10383
|
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
10384
|
+
const ruleWidth = Math.max(20, columns - 2);
|
|
9803
10385
|
return (
|
|
9804
|
-
//
|
|
9805
|
-
//
|
|
9806
|
-
//
|
|
9807
|
-
//
|
|
9808
|
-
//
|
|
9809
|
-
//
|
|
9810
|
-
//
|
|
9811
|
-
|
|
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(
|
|
10386
|
+
// Borderless layout: no `borderStyle`, no rounded box, no `width={cols}`
|
|
10387
|
+
// pinning. Bordered Boxes were the most visible amplifier of Ink's
|
|
10388
|
+
// eraseLines miscount on Windows terminals — every miscounted render
|
|
10389
|
+
// pushed a top-border frame into scrollback. Without a border there
|
|
10390
|
+
// is nothing visually obvious to duplicate; visual structure comes
|
|
10391
|
+
// from the gradient wordmark + colored pills + a top/bottom margin
|
|
10392
|
+
// + a thin dim rule that closes the panel cleanly under the metrics.
|
|
10393
|
+
/* @__PURE__ */ React20.createElement(Box18, { flexDirection: "column", paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React20.createElement(
|
|
9814
10394
|
Header,
|
|
9815
10395
|
{
|
|
9816
10396
|
model: model2,
|
|
@@ -9828,7 +10408,7 @@ function StatsPanel({
|
|
|
9828
10408
|
proArmed: proArmed ?? false,
|
|
9829
10409
|
escalated: escalated ?? false
|
|
9830
10410
|
}
|
|
9831
|
-
), narrow ? /* @__PURE__ */
|
|
10411
|
+
), narrow ? /* @__PURE__ */ React20.createElement(
|
|
9832
10412
|
StackedMetrics,
|
|
9833
10413
|
{
|
|
9834
10414
|
summary,
|
|
@@ -9837,7 +10417,7 @@ function StatsPanel({
|
|
|
9837
10417
|
balance,
|
|
9838
10418
|
coldStart
|
|
9839
10419
|
}
|
|
9840
|
-
) : /* @__PURE__ */
|
|
10420
|
+
) : /* @__PURE__ */ React20.createElement(
|
|
9841
10421
|
InlineMetrics,
|
|
9842
10422
|
{
|
|
9843
10423
|
summary,
|
|
@@ -9846,7 +10426,7 @@ function StatsPanel({
|
|
|
9846
10426
|
balance,
|
|
9847
10427
|
coldStart
|
|
9848
10428
|
}
|
|
9849
|
-
))
|
|
10429
|
+
), /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2500".repeat(ruleWidth))))
|
|
9850
10430
|
);
|
|
9851
10431
|
}
|
|
9852
10432
|
function Header({
|
|
@@ -9865,7 +10445,12 @@ function Header({
|
|
|
9865
10445
|
proArmed,
|
|
9866
10446
|
escalated
|
|
9867
10447
|
}) {
|
|
9868
|
-
|
|
10448
|
+
const modePill = planMode ? { label: "PLAN", bg: "red" } : editMode === "auto" ? { label: "AUTO", bg: "magenta" } : editMode === "review" ? { label: "REVIEW", bg: "cyan" } : null;
|
|
10449
|
+
const proPill = escalated ? { label: "\u21E7 PRO", bg: "red" } : proArmed ? { label: "\u21E7 PRO", bg: "yellow" } : null;
|
|
10450
|
+
return /* @__PURE__ */ React20.createElement(Box18, { justifyContent: "space-between" }, /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Wordmark, { busy }), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, ` ${VERSION}`), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "yellow", bold: true }, model2.replace(/^deepseek-/, "")), modePill ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Pill, { label: modePill.label, bg: modePill.bg })) : null, proPill ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Pill, { label: proPill.label, bg: proPill.bg })) : null, harvestOn ? /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "magenta" }, "harvest")) : null, branchOn ? /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "blue" }, `branch\xD7${branchBudget}`)) : null, reasoningEffort === "max" ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "green", dimColor: true }, "max")) : null, reasoningEffort === "high" ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "yellow", dimColor: true }, "high")) : null), /* @__PURE__ */ React20.createElement(Text18, null, updateAvailable ? /* @__PURE__ */ React20.createElement(Text18, { color: "yellow", bold: true }, `\u2191 ${updateAvailable} `) : null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, narrow ? `t${turns}` : `turn ${turns} \xB7 /help`)));
|
|
10451
|
+
}
|
|
10452
|
+
function Pill({ label, bg }) {
|
|
10453
|
+
return /* @__PURE__ */ React20.createElement(Text18, { backgroundColor: bg, color: "white", bold: true }, ` ${label} `);
|
|
9869
10454
|
}
|
|
9870
10455
|
function InlineMetrics({
|
|
9871
10456
|
summary,
|
|
@@ -9874,7 +10459,7 @@ function InlineMetrics({
|
|
|
9874
10459
|
balance,
|
|
9875
10460
|
coldStart
|
|
9876
10461
|
}) {
|
|
9877
|
-
return /* @__PURE__ */
|
|
10462
|
+
return /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React20.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React20.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React20.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React20.createElement(BalanceCell, { balance }) : null);
|
|
9878
10463
|
}
|
|
9879
10464
|
function StackedMetrics({
|
|
9880
10465
|
summary,
|
|
@@ -9883,7 +10468,7 @@ function StackedMetrics({
|
|
|
9883
10468
|
balance,
|
|
9884
10469
|
coldStart
|
|
9885
10470
|
}) {
|
|
9886
|
-
return /* @__PURE__ */
|
|
10471
|
+
return /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(
|
|
9887
10472
|
ContextCell,
|
|
9888
10473
|
{
|
|
9889
10474
|
ratio: ctxRatio,
|
|
@@ -9891,7 +10476,7 @@ function StackedMetrics({
|
|
|
9891
10476
|
ctxMax,
|
|
9892
10477
|
showBar: true
|
|
9893
10478
|
}
|
|
9894
|
-
), balance ? /* @__PURE__ */
|
|
10479
|
+
), balance ? /* @__PURE__ */ React20.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React20.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React20.createElement(CostCell, { summary, coldStart }));
|
|
9895
10480
|
}
|
|
9896
10481
|
function ContextCell({
|
|
9897
10482
|
ratio,
|
|
@@ -9900,11 +10485,11 @@ function ContextCell({
|
|
|
9900
10485
|
showBar
|
|
9901
10486
|
}) {
|
|
9902
10487
|
if (promptTokens === 0) {
|
|
9903
|
-
return /* @__PURE__ */
|
|
10488
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "ctx "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014 (no turns yet)"));
|
|
9904
10489
|
}
|
|
9905
10490
|
const color = ratio >= 0.8 ? "red" : ratio >= 0.6 ? "yellow" : "green";
|
|
9906
10491
|
const pct2 = Math.round(ratio * 100);
|
|
9907
|
-
return /* @__PURE__ */
|
|
10492
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "ctx "), showBar ? /* @__PURE__ */ React20.createElement(Bar, { ratio, color }) : null, showBar ? /* @__PURE__ */ React20.createElement(Text18, null, " ") : null, /* @__PURE__ */ React20.createElement(Text18, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React20.createElement(Text18, { color: "red", bold: true }, " \xB7 /compact") : null);
|
|
9908
10493
|
}
|
|
9909
10494
|
function CacheCell({
|
|
9910
10495
|
hitRatio,
|
|
@@ -9913,13 +10498,13 @@ function CacheCell({
|
|
|
9913
10498
|
}) {
|
|
9914
10499
|
const pct2 = (hitRatio * 100).toFixed(1);
|
|
9915
10500
|
if (turns === 0) {
|
|
9916
|
-
return /* @__PURE__ */
|
|
10501
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014"));
|
|
9917
10502
|
}
|
|
9918
10503
|
if (coldStart) {
|
|
9919
|
-
return /* @__PURE__ */
|
|
10504
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true, italic: true }, "(cold start)"));
|
|
9920
10505
|
}
|
|
9921
10506
|
const color = hitRatio >= 0.7 ? "green" : hitRatio >= 0.4 ? "yellow" : "red";
|
|
9922
|
-
return /* @__PURE__ */
|
|
10507
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { color, bold: true }, pct2, "%"));
|
|
9923
10508
|
}
|
|
9924
10509
|
function turnCostColor(cost) {
|
|
9925
10510
|
if (cost <= 0) return void 0;
|
|
@@ -9938,21 +10523,21 @@ function CostCell({
|
|
|
9938
10523
|
coldStart
|
|
9939
10524
|
}) {
|
|
9940
10525
|
if (summary.turns === 0) {
|
|
9941
|
-
return /* @__PURE__ */
|
|
10526
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cost "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014"));
|
|
9942
10527
|
}
|
|
9943
10528
|
const turnColor = coldStart ? void 0 : turnCostColor(summary.lastTurnCostUsd);
|
|
9944
10529
|
const sessionColor = coldStart ? void 0 : sessionCostColor(summary.totalCostUsd);
|
|
9945
|
-
return /* @__PURE__ */
|
|
10530
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "turn "), /* @__PURE__ */ React20.createElement(Text18, { color: turnColor, bold: !coldStart, dimColor: coldStart }, "$", summary.lastTurnCostUsd.toFixed(4)), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, " \xB7 session "), /* @__PURE__ */ React20.createElement(Text18, { color: sessionColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(4)));
|
|
9946
10531
|
}
|
|
9947
10532
|
function BalanceCell({ balance }) {
|
|
9948
10533
|
const color = balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green";
|
|
9949
|
-
return /* @__PURE__ */
|
|
10534
|
+
return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "balance "), /* @__PURE__ */ React20.createElement(Text18, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
|
|
9950
10535
|
}
|
|
9951
10536
|
function Bar({ ratio, color }) {
|
|
9952
10537
|
const cells = 10;
|
|
9953
10538
|
const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
|
|
9954
10539
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
|
|
9955
|
-
return /* @__PURE__ */
|
|
10540
|
+
return /* @__PURE__ */ React20.createElement(Text18, { color }, bar);
|
|
9956
10541
|
}
|
|
9957
10542
|
function formatTokens(n) {
|
|
9958
10543
|
if (n < 1024) return String(n);
|
|
@@ -9960,6 +10545,16 @@ function formatTokens(n) {
|
|
|
9960
10545
|
return k >= 100 ? `${k.toFixed(0)}K` : `${k.toFixed(1)}K`;
|
|
9961
10546
|
}
|
|
9962
10547
|
|
|
10548
|
+
// src/cli/ui/WelcomeBanner.tsx
|
|
10549
|
+
import { Box as Box19, Text as Text19 } from "ink";
|
|
10550
|
+
import React21 from "react";
|
|
10551
|
+
function WelcomeBanner({ inCodeMode }) {
|
|
10552
|
+
return /* @__PURE__ */ React21.createElement(Box19, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Text19, { bold: true, color: "cyan" }, "Hi"), /* @__PURE__ */ React21.createElement(Text19, null, " \u2014 type a message to start, or try:")), /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React21.createElement(Hint, { cmd: "/help", desc: "every command + keyboard shortcut" }), /* @__PURE__ */ React21.createElement(Hint, { cmd: "/skill", desc: "invoke a stored playbook" }), inCodeMode ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Hint, { cmd: "@path", desc: "inline a file in your message" }), /* @__PURE__ */ React21.createElement(Hint, { cmd: "!cmd", desc: "run a shell command, output goes to context" })) : null, /* @__PURE__ */ React21.createElement(Hint, { cmd: "/exit", desc: "quit" })));
|
|
10553
|
+
}
|
|
10554
|
+
function Hint({ cmd, desc }) {
|
|
10555
|
+
return /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Text19, { dimColor: true }, " "), /* @__PURE__ */ React21.createElement(Text19, { bold: true, color: "magenta" }, cmd.padEnd(8)), /* @__PURE__ */ React21.createElement(Text19, { dimColor: true }, ` ${desc}`));
|
|
10556
|
+
}
|
|
10557
|
+
|
|
9963
10558
|
// src/cli/ui/bang.ts
|
|
9964
10559
|
function detectBangCommand(text) {
|
|
9965
10560
|
if (!text.startsWith("!")) return null;
|
|
@@ -11800,7 +12395,7 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
11800
12395
|
}
|
|
11801
12396
|
|
|
11802
12397
|
// src/cli/ui/useCompletionPickers.ts
|
|
11803
|
-
import { useCallback, useEffect as
|
|
12398
|
+
import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState6 } from "react";
|
|
11804
12399
|
function useCompletionPickers({
|
|
11805
12400
|
input,
|
|
11806
12401
|
setInput,
|
|
@@ -11813,7 +12408,7 @@ function useCompletionPickers({
|
|
|
11813
12408
|
if (!input.startsWith("/") || input.includes(" ")) return null;
|
|
11814
12409
|
return suggestSlashCommands(input.slice(1), !!codeMode);
|
|
11815
12410
|
}, [input, codeMode]);
|
|
11816
|
-
|
|
12411
|
+
useEffect3(() => {
|
|
11817
12412
|
setSlashSelected((prev) => {
|
|
11818
12413
|
if (!slashMatches || slashMatches.length === 0) return 0;
|
|
11819
12414
|
if (prev >= slashMatches.length) return slashMatches.length - 1;
|
|
@@ -11829,7 +12424,7 @@ function useCompletionPickers({
|
|
|
11829
12424
|
return [];
|
|
11830
12425
|
}
|
|
11831
12426
|
}, [codeMode?.rootDir]);
|
|
11832
|
-
const recentFilesRef =
|
|
12427
|
+
const recentFilesRef = useRef3([]);
|
|
11833
12428
|
const recordRecentFile = useCallback((p) => {
|
|
11834
12429
|
const list = recentFilesRef.current;
|
|
11835
12430
|
const i = list.indexOf(p);
|
|
@@ -11849,7 +12444,7 @@ function useCompletionPickers({
|
|
|
11849
12444
|
recentlyUsed: recentFilesRef.current
|
|
11850
12445
|
});
|
|
11851
12446
|
}, [atPicker, atFiles]);
|
|
11852
|
-
|
|
12447
|
+
useEffect3(() => {
|
|
11853
12448
|
setAtSelected((prev) => {
|
|
11854
12449
|
if (!atMatches || atMatches.length === 0) return 0;
|
|
11855
12450
|
if (prev >= atMatches.length) return atMatches.length - 1;
|
|
@@ -11910,7 +12505,7 @@ function useCompletionPickers({
|
|
|
11910
12505
|
}
|
|
11911
12506
|
return null;
|
|
11912
12507
|
}, [slashArgContext, models2, mcpServers]);
|
|
11913
|
-
|
|
12508
|
+
useEffect3(() => {
|
|
11914
12509
|
setSlashArgSelected((prev) => {
|
|
11915
12510
|
if (!slashArgMatches || slashArgMatches.length === 0) return 0;
|
|
11916
12511
|
if (prev >= slashArgMatches.length) return slashArgMatches.length - 1;
|
|
@@ -11944,13 +12539,13 @@ function useCompletionPickers({
|
|
|
11944
12539
|
}
|
|
11945
12540
|
|
|
11946
12541
|
// src/cli/ui/useEditHistory.ts
|
|
11947
|
-
import { useCallback as useCallback2, useRef as
|
|
12542
|
+
import { useCallback as useCallback2, useRef as useRef4, useState as useState7 } from "react";
|
|
11948
12543
|
function useEditHistory(codeMode) {
|
|
11949
|
-
const editHistory =
|
|
11950
|
-
const nextHistoryId =
|
|
11951
|
-
const currentTurnEntry =
|
|
12544
|
+
const editHistory = useRef4([]);
|
|
12545
|
+
const nextHistoryId = useRef4(1);
|
|
12546
|
+
const currentTurnEntry = useRef4(null);
|
|
11952
12547
|
const [undoBanner, setUndoBanner] = useState7(null);
|
|
11953
|
-
const undoTimeoutRef =
|
|
12548
|
+
const undoTimeoutRef = useRef4(null);
|
|
11954
12549
|
const recordEdit = useCallback2(
|
|
11955
12550
|
(source, blocks, results, snaps) => {
|
|
11956
12551
|
if (snaps.length === 0) return;
|
|
@@ -12146,12 +12741,12 @@ function useEditHistory(codeMode) {
|
|
|
12146
12741
|
}
|
|
12147
12742
|
|
|
12148
12743
|
// src/cli/ui/useSessionInfo.ts
|
|
12149
|
-
import { useCallback as useCallback3, useEffect as
|
|
12744
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useState as useState8 } from "react";
|
|
12150
12745
|
function useSessionInfo(loop) {
|
|
12151
12746
|
const [balance, setBalance] = useState8(null);
|
|
12152
12747
|
const [models2, setModels] = useState8(null);
|
|
12153
12748
|
const [latestVersion, setLatestVersion] = useState8(null);
|
|
12154
|
-
|
|
12749
|
+
useEffect4(() => {
|
|
12155
12750
|
let cancelled = false;
|
|
12156
12751
|
void (async () => {
|
|
12157
12752
|
const bal = await loop.client.getBalance().catch(() => null);
|
|
@@ -12163,7 +12758,7 @@ function useSessionInfo(loop) {
|
|
|
12163
12758
|
cancelled = true;
|
|
12164
12759
|
};
|
|
12165
12760
|
}, [loop]);
|
|
12166
|
-
|
|
12761
|
+
useEffect4(() => {
|
|
12167
12762
|
let cancelled = false;
|
|
12168
12763
|
void (async () => {
|
|
12169
12764
|
const list = await loop.client.listModels().catch(() => null);
|
|
@@ -12174,7 +12769,7 @@ function useSessionInfo(loop) {
|
|
|
12174
12769
|
cancelled = true;
|
|
12175
12770
|
};
|
|
12176
12771
|
}, [loop]);
|
|
12177
|
-
|
|
12772
|
+
useEffect4(() => {
|
|
12178
12773
|
let cancelled = false;
|
|
12179
12774
|
void (async () => {
|
|
12180
12775
|
const latest = await getLatestVersion();
|
|
@@ -12219,11 +12814,11 @@ function useSessionInfo(loop) {
|
|
|
12219
12814
|
}
|
|
12220
12815
|
|
|
12221
12816
|
// src/cli/ui/useSubagent.ts
|
|
12222
|
-
import { useEffect as
|
|
12817
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState9 } from "react";
|
|
12223
12818
|
function useSubagent({ session, setHistorical }) {
|
|
12224
12819
|
const [activity, setActivity] = useState9(null);
|
|
12225
|
-
const sinkRef =
|
|
12226
|
-
|
|
12820
|
+
const sinkRef = useRef5({ current: null });
|
|
12821
|
+
useEffect5(() => {
|
|
12227
12822
|
sinkRef.current.current = (ev) => {
|
|
12228
12823
|
if (ev.kind === "start") {
|
|
12229
12824
|
setActivity({
|
|
@@ -12296,15 +12891,17 @@ function App({
|
|
|
12296
12891
|
const [streaming, setStreaming] = useState10(null);
|
|
12297
12892
|
const [input, setInput] = useState10("");
|
|
12298
12893
|
const [busy, setBusy] = useState10(false);
|
|
12299
|
-
const abortedThisTurn =
|
|
12894
|
+
const abortedThisTurn = useRef6(false);
|
|
12300
12895
|
const [ongoingTool, setOngoingTool] = useState10(null);
|
|
12301
12896
|
const [toolProgress, setToolProgress] = useState10(null);
|
|
12302
12897
|
const { stdout: stdout2 } = useStdout5();
|
|
12303
|
-
|
|
12898
|
+
useEffect6(() => {
|
|
12304
12899
|
if (!stdout2 || !stdout2.isTTY) return;
|
|
12305
12900
|
stdout2.write("\x1B[?2004h");
|
|
12901
|
+
stdout2.write("\x1B[>4;2m");
|
|
12306
12902
|
return () => {
|
|
12307
12903
|
stdout2.write("\x1B[?2004l");
|
|
12904
|
+
stdout2.write("\x1B[>4m");
|
|
12308
12905
|
};
|
|
12309
12906
|
}, [stdout2]);
|
|
12310
12907
|
const { activity: subagentActivity, sinkRef: subagentSinkRef } = useSubagent({
|
|
@@ -12326,24 +12923,24 @@ function App({
|
|
|
12326
12923
|
sealCurrentEntry,
|
|
12327
12924
|
hasUndoable
|
|
12328
12925
|
} = useEditHistory(codeMode);
|
|
12329
|
-
const pendingEdits =
|
|
12926
|
+
const pendingEdits = useRef6([]);
|
|
12330
12927
|
const [pendingCount, setPendingCount] = useState10(0);
|
|
12331
12928
|
const syncPendingCount = useCallback4(() => {
|
|
12332
12929
|
setPendingCount(pendingEdits.current.length);
|
|
12333
12930
|
}, []);
|
|
12334
12931
|
const [editMode, setEditMode] = useState10(() => codeMode ? loadEditMode() : "review");
|
|
12335
|
-
const editModeRef =
|
|
12336
|
-
|
|
12932
|
+
const editModeRef = useRef6(editMode);
|
|
12933
|
+
useEffect6(() => {
|
|
12337
12934
|
editModeRef.current = editMode;
|
|
12338
12935
|
if (codeMode) saveEditMode(editMode);
|
|
12339
12936
|
}, [editMode, codeMode]);
|
|
12340
12937
|
const [pendingEditReview, setPendingEditReview] = useState10(null);
|
|
12341
|
-
const editReviewResolveRef =
|
|
12342
|
-
const turnEditPolicyRef =
|
|
12938
|
+
const editReviewResolveRef = useRef6(null);
|
|
12939
|
+
const turnEditPolicyRef = useRef6("ask");
|
|
12343
12940
|
const [modeFlash, setModeFlash] = useState10(false);
|
|
12344
|
-
const modeFlashTimeoutRef =
|
|
12345
|
-
const prevEditModeRef =
|
|
12346
|
-
|
|
12941
|
+
const modeFlashTimeoutRef = useRef6(null);
|
|
12942
|
+
const prevEditModeRef = useRef6(editMode);
|
|
12943
|
+
useEffect6(() => {
|
|
12347
12944
|
if (prevEditModeRef.current === editMode) return;
|
|
12348
12945
|
prevEditModeRef.current = editMode;
|
|
12349
12946
|
setModeFlash(true);
|
|
@@ -12365,15 +12962,15 @@ function App({
|
|
|
12365
12962
|
const [proArmed, setProArmed] = useState10(false);
|
|
12366
12963
|
const [turnOnPro, setTurnOnPro] = useState10(false);
|
|
12367
12964
|
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 =
|
|
12965
|
+
const promptHistory = useRef6([]);
|
|
12966
|
+
const historyCursor = useRef6(-1);
|
|
12967
|
+
const assistantIterCounter = useRef6(0);
|
|
12968
|
+
const toolHistoryRef = useRef6([]);
|
|
12969
|
+
const planStepsRef = useRef6(null);
|
|
12970
|
+
const completedStepIdsRef = useRef6(/* @__PURE__ */ new Set());
|
|
12971
|
+
const planBodyRef = useRef6(null);
|
|
12972
|
+
const planSummaryRef = useRef6(null);
|
|
12973
|
+
const toolStartedAtRef = useRef6(null);
|
|
12377
12974
|
const persistPlanState = useCallback4(() => {
|
|
12378
12975
|
if (!session) return;
|
|
12379
12976
|
const steps = planStepsRef.current;
|
|
@@ -12397,7 +12994,7 @@ function App({
|
|
|
12397
12994
|
lastPromptTokens: 0,
|
|
12398
12995
|
lastTurnCostUsd: 0
|
|
12399
12996
|
});
|
|
12400
|
-
const transcriptRef =
|
|
12997
|
+
const transcriptRef = useRef6(null);
|
|
12401
12998
|
if (transcript && !transcriptRef.current) {
|
|
12402
12999
|
transcriptRef.current = openTranscriptFile(transcript, {
|
|
12403
13000
|
version: 1,
|
|
@@ -12406,12 +13003,12 @@ function App({
|
|
|
12406
13003
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12407
13004
|
});
|
|
12408
13005
|
}
|
|
12409
|
-
|
|
13006
|
+
useEffect6(() => {
|
|
12410
13007
|
return () => {
|
|
12411
13008
|
transcriptRef.current?.end();
|
|
12412
13009
|
};
|
|
12413
13010
|
}, []);
|
|
12414
|
-
const loopRef =
|
|
13011
|
+
const loopRef = useRef6(null);
|
|
12415
13012
|
const loop = useMemo3(() => {
|
|
12416
13013
|
if (loopRef.current) return loopRef.current;
|
|
12417
13014
|
const client = new DeepSeekClient();
|
|
@@ -12460,7 +13057,7 @@ function App({
|
|
|
12460
13057
|
loopRef.current = l;
|
|
12461
13058
|
return l;
|
|
12462
13059
|
}, [model2, system, harvest3, branch2, session, tools, codeMode]);
|
|
12463
|
-
|
|
13060
|
+
useEffect6(() => {
|
|
12464
13061
|
loop.hooks = hookList;
|
|
12465
13062
|
}, [loop, hookList]);
|
|
12466
13063
|
const {
|
|
@@ -12488,7 +13085,7 @@ function App({
|
|
|
12488
13085
|
setSlashArgSelected,
|
|
12489
13086
|
pickSlashArg
|
|
12490
13087
|
} = useCompletionPickers({ input, setInput, codeMode, models: models2, mcpServers });
|
|
12491
|
-
|
|
13088
|
+
useEffect6(() => {
|
|
12492
13089
|
if (!progressSink) return;
|
|
12493
13090
|
progressSink.current = (info) => {
|
|
12494
13091
|
setToolProgress({
|
|
@@ -12501,8 +13098,8 @@ function App({
|
|
|
12501
13098
|
if (progressSink.current) progressSink.current = null;
|
|
12502
13099
|
};
|
|
12503
13100
|
}, [progressSink]);
|
|
12504
|
-
const sessionBannerShown =
|
|
12505
|
-
|
|
13101
|
+
const sessionBannerShown = useRef6(false);
|
|
13102
|
+
useEffect6(() => {
|
|
12506
13103
|
if (sessionBannerShown.current) return;
|
|
12507
13104
|
sessionBannerShown.current = true;
|
|
12508
13105
|
if (!session) {
|
|
@@ -12584,7 +13181,26 @@ function App({
|
|
|
12584
13181
|
markEditModeHintShown();
|
|
12585
13182
|
}
|
|
12586
13183
|
}, [session, loop, codeMode, syncPendingCount]);
|
|
12587
|
-
|
|
13184
|
+
const quitProcess = useCallback4(() => {
|
|
13185
|
+
transcriptRef.current?.end();
|
|
13186
|
+
process.exit(0);
|
|
13187
|
+
}, []);
|
|
13188
|
+
useEffect6(() => {
|
|
13189
|
+
process.on("SIGINT", quitProcess);
|
|
13190
|
+
return () => {
|
|
13191
|
+
process.off("SIGINT", quitProcess);
|
|
13192
|
+
};
|
|
13193
|
+
}, [quitProcess]);
|
|
13194
|
+
useKeystroke((ev) => {
|
|
13195
|
+
const chKey = ev.input;
|
|
13196
|
+
const key = ev;
|
|
13197
|
+
if (ev.paste) {
|
|
13198
|
+
return;
|
|
13199
|
+
}
|
|
13200
|
+
if (key.ctrl && key.input === "c") {
|
|
13201
|
+
quitProcess();
|
|
13202
|
+
return;
|
|
13203
|
+
}
|
|
12588
13204
|
if (key.escape && busy) {
|
|
12589
13205
|
if (abortedThisTurn.current) return;
|
|
12590
13206
|
abortedThisTurn.current = true;
|
|
@@ -12682,7 +13298,7 @@ function App({
|
|
|
12682
13298
|
historyCursor.current = nextCursor;
|
|
12683
13299
|
setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
|
|
12684
13300
|
}, []);
|
|
12685
|
-
|
|
13301
|
+
useEffect6(() => {
|
|
12686
13302
|
if (!tools || !codeMode) return;
|
|
12687
13303
|
tools.setToolInterceptor(async (name, args) => {
|
|
12688
13304
|
if (name !== "edit_file" && name !== "write_file") return null;
|
|
@@ -13548,7 +14164,7 @@ ${body}`;
|
|
|
13548
14164
|
},
|
|
13549
14165
|
[pendingShell, codeMode, handleSubmit, busy, loop]
|
|
13550
14166
|
);
|
|
13551
|
-
|
|
14167
|
+
useEffect6(() => {
|
|
13552
14168
|
if (!busy && queuedSubmit !== null) {
|
|
13553
14169
|
const text = queuedSubmit;
|
|
13554
14170
|
setQueuedSubmit(null);
|
|
@@ -13592,8 +14208,8 @@ ${body}`;
|
|
|
13592
14208
|
},
|
|
13593
14209
|
[pendingPlan, togglePlanMode, busy, loop, handleSubmit, persistPlanState]
|
|
13594
14210
|
);
|
|
13595
|
-
const handlePlanConfirmRef =
|
|
13596
|
-
|
|
14211
|
+
const handlePlanConfirmRef = useRef6(handlePlanConfirm);
|
|
14212
|
+
useEffect6(() => {
|
|
13597
14213
|
handlePlanConfirmRef.current = handlePlanConfirm;
|
|
13598
14214
|
}, [handlePlanConfirm]);
|
|
13599
14215
|
const stableHandlePlanConfirm = useCallback4(
|
|
@@ -13684,8 +14300,8 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
|
|
|
13684
14300
|
},
|
|
13685
14301
|
[pendingCheckpoint, busy, loop, handleSubmit]
|
|
13686
14302
|
);
|
|
13687
|
-
const handleCheckpointConfirmRef =
|
|
13688
|
-
|
|
14303
|
+
const handleCheckpointConfirmRef = useRef6(handleCheckpointConfirm);
|
|
14304
|
+
useEffect6(() => {
|
|
13689
14305
|
handleCheckpointConfirmRef.current = handleCheckpointConfirm;
|
|
13690
14306
|
}, [handleCheckpointConfirm]);
|
|
13691
14307
|
const stableHandleCheckpointConfirm = useCallback4(
|
|
@@ -13762,8 +14378,8 @@ If the feedback only tweaks how you execute (extra constraints, style preference
|
|
|
13762
14378
|
},
|
|
13763
14379
|
[pendingChoice, busy, loop, handleSubmit]
|
|
13764
14380
|
);
|
|
13765
|
-
const handleChoiceConfirmRef =
|
|
13766
|
-
|
|
14381
|
+
const handleChoiceConfirmRef = useRef6(handleChoiceConfirm);
|
|
14382
|
+
useEffect6(() => {
|
|
13767
14383
|
handleChoiceConfirmRef.current = handleChoiceConfirm;
|
|
13768
14384
|
}, [handleChoiceConfirm]);
|
|
13769
14385
|
const stableHandleChoiceConfirm = useCallback4(
|
|
@@ -13853,20 +14469,20 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13853
14469
|
},
|
|
13854
14470
|
[pendingRevision, busy, loop, handleSubmit, persistPlanState]
|
|
13855
14471
|
);
|
|
13856
|
-
const handleReviseConfirmRef =
|
|
13857
|
-
|
|
14472
|
+
const handleReviseConfirmRef = useRef6(handleReviseConfirm);
|
|
14473
|
+
useEffect6(() => {
|
|
13858
14474
|
handleReviseConfirmRef.current = handleReviseConfirm;
|
|
13859
14475
|
}, [handleReviseConfirm]);
|
|
13860
14476
|
const stableHandleReviseConfirm = useCallback4(
|
|
13861
14477
|
async (choice) => handleReviseConfirmRef.current(choice),
|
|
13862
14478
|
[]
|
|
13863
14479
|
);
|
|
13864
|
-
return /* @__PURE__ */
|
|
14480
|
+
return /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(
|
|
13865
14481
|
TickerProvider,
|
|
13866
14482
|
{
|
|
13867
14483
|
disabled: PLAIN_UI || !!pendingPlan || !!pendingShell || !!pendingEditReview || !!pendingCheckpoint || !!stagedCheckpointRevise || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision
|
|
13868
14484
|
},
|
|
13869
|
-
/* @__PURE__ */
|
|
14485
|
+
/* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React22.createElement(
|
|
13870
14486
|
StatsPanel,
|
|
13871
14487
|
{
|
|
13872
14488
|
summary,
|
|
@@ -13883,28 +14499,28 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13883
14499
|
proArmed,
|
|
13884
14500
|
escalated: turnOnPro
|
|
13885
14501
|
}
|
|
13886
|
-
), /* @__PURE__ */
|
|
14502
|
+
), /* @__PURE__ */ React22.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React22.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React22.createElement(WelcomeBanner, { inCodeMode: !!codeMode }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React22.createElement(Box20, { marginY: 1 }, /* @__PURE__ */ React22.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React22.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React22.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React22.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React22.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React22.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React22.createElement(
|
|
13887
14503
|
PlanRefineInput,
|
|
13888
14504
|
{
|
|
13889
14505
|
mode: stagedInput.mode,
|
|
13890
14506
|
onSubmit: handleStagedInputSubmit,
|
|
13891
14507
|
onCancel: handleStagedInputCancel
|
|
13892
14508
|
}
|
|
13893
|
-
) : stagedCheckpointRevise ? /* @__PURE__ */
|
|
14509
|
+
) : stagedCheckpointRevise ? /* @__PURE__ */ React22.createElement(
|
|
13894
14510
|
PlanRefineInput,
|
|
13895
14511
|
{
|
|
13896
14512
|
mode: "checkpoint-revise",
|
|
13897
14513
|
onSubmit: handleCheckpointReviseSubmit,
|
|
13898
14514
|
onCancel: handleCheckpointReviseCancel
|
|
13899
14515
|
}
|
|
13900
|
-
) : stagedChoiceCustom ? /* @__PURE__ */
|
|
14516
|
+
) : stagedChoiceCustom ? /* @__PURE__ */ React22.createElement(
|
|
13901
14517
|
PlanRefineInput,
|
|
13902
14518
|
{
|
|
13903
14519
|
mode: "choice-custom",
|
|
13904
14520
|
onSubmit: handleChoiceCustomSubmit,
|
|
13905
14521
|
onCancel: handleChoiceCustomCancel
|
|
13906
14522
|
}
|
|
13907
|
-
) : pendingChoice ? /* @__PURE__ */
|
|
14523
|
+
) : pendingChoice ? /* @__PURE__ */ React22.createElement(
|
|
13908
14524
|
ChoiceConfirm,
|
|
13909
14525
|
{
|
|
13910
14526
|
question: pendingChoice.question,
|
|
@@ -13912,7 +14528,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13912
14528
|
allowCustom: pendingChoice.allowCustom,
|
|
13913
14529
|
onChoose: stableHandleChoiceConfirm
|
|
13914
14530
|
}
|
|
13915
|
-
) : pendingRevision ? /* @__PURE__ */
|
|
14531
|
+
) : pendingRevision ? /* @__PURE__ */ React22.createElement(
|
|
13916
14532
|
PlanReviseConfirm,
|
|
13917
14533
|
{
|
|
13918
14534
|
reason: pendingRevision.reason,
|
|
@@ -13923,7 +14539,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13923
14539
|
summary: pendingRevision.summary,
|
|
13924
14540
|
onChoose: stableHandleReviseConfirm
|
|
13925
14541
|
}
|
|
13926
|
-
) : pendingCheckpoint ? /* @__PURE__ */
|
|
14542
|
+
) : pendingCheckpoint ? /* @__PURE__ */ React22.createElement(
|
|
13927
14543
|
PlanCheckpointConfirm,
|
|
13928
14544
|
{
|
|
13929
14545
|
stepId: pendingCheckpoint.stepId,
|
|
@@ -13934,7 +14550,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13934
14550
|
completedStepIds: completedStepIdsRef.current,
|
|
13935
14551
|
onChoose: stableHandleCheckpointConfirm
|
|
13936
14552
|
}
|
|
13937
|
-
) : pendingPlan ? /* @__PURE__ */
|
|
14553
|
+
) : pendingPlan ? /* @__PURE__ */ React22.createElement(
|
|
13938
14554
|
PlanConfirm,
|
|
13939
14555
|
{
|
|
13940
14556
|
plan: pendingPlan,
|
|
@@ -13943,7 +14559,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13943
14559
|
onChoose: stableHandlePlanConfirm,
|
|
13944
14560
|
projectRoot: hookCwd
|
|
13945
14561
|
}
|
|
13946
|
-
) : pendingShell ? /* @__PURE__ */
|
|
14562
|
+
) : pendingShell ? /* @__PURE__ */ React22.createElement(
|
|
13947
14563
|
ShellConfirm,
|
|
13948
14564
|
{
|
|
13949
14565
|
command: pendingShell.command,
|
|
@@ -13951,7 +14567,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13951
14567
|
kind: pendingShell.kind,
|
|
13952
14568
|
onChoose: handleShellConfirm
|
|
13953
14569
|
}
|
|
13954
|
-
) : pendingEditReview ? /* @__PURE__ */
|
|
14570
|
+
) : pendingEditReview ? /* @__PURE__ */ React22.createElement(
|
|
13955
14571
|
EditConfirm,
|
|
13956
14572
|
{
|
|
13957
14573
|
block: pendingEditReview,
|
|
@@ -13963,7 +14579,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13963
14579
|
}
|
|
13964
14580
|
}
|
|
13965
14581
|
}
|
|
13966
|
-
) : /* @__PURE__ */
|
|
14582
|
+
) : /* @__PURE__ */ React22.createElement(React22.Fragment, null, codeMode ? /* @__PURE__ */ React22.createElement(
|
|
13967
14583
|
ModeStatusBar,
|
|
13968
14584
|
{
|
|
13969
14585
|
editMode,
|
|
@@ -13973,7 +14589,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13973
14589
|
undoArmed: !!undoBanner || hasUndoable(),
|
|
13974
14590
|
jobs: codeMode.jobs
|
|
13975
14591
|
}
|
|
13976
|
-
) : null, /* @__PURE__ */
|
|
14592
|
+
) : null, /* @__PURE__ */ React22.createElement(
|
|
13977
14593
|
PromptInput,
|
|
13978
14594
|
{
|
|
13979
14595
|
value: input,
|
|
@@ -13983,14 +14599,14 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13983
14599
|
onHistoryPrev: recallPrev,
|
|
13984
14600
|
onHistoryNext: recallNext
|
|
13985
14601
|
}
|
|
13986
|
-
), /* @__PURE__ */
|
|
14602
|
+
), /* @__PURE__ */ React22.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React22.createElement(
|
|
13987
14603
|
AtMentionSuggestions,
|
|
13988
14604
|
{
|
|
13989
14605
|
matches: atMatches,
|
|
13990
14606
|
selectedIndex: atSelected,
|
|
13991
14607
|
query: atPicker?.query ?? ""
|
|
13992
14608
|
}
|
|
13993
|
-
), slashArgContext ? /* @__PURE__ */
|
|
14609
|
+
), slashArgContext ? /* @__PURE__ */ React22.createElement(
|
|
13994
14610
|
SlashArgPicker,
|
|
13995
14611
|
{
|
|
13996
14612
|
matches: slashArgMatches,
|
|
@@ -14000,19 +14616,19 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
14000
14616
|
partial: slashArgContext.partial
|
|
14001
14617
|
}
|
|
14002
14618
|
) : null))
|
|
14003
|
-
);
|
|
14619
|
+
));
|
|
14004
14620
|
}
|
|
14005
14621
|
|
|
14006
14622
|
// src/cli/ui/SessionPicker.tsx
|
|
14007
|
-
import { Box as
|
|
14008
|
-
import
|
|
14623
|
+
import { Box as Box21, Text as Text20 } from "ink";
|
|
14624
|
+
import React23 from "react";
|
|
14009
14625
|
function SessionPicker({
|
|
14010
14626
|
sessionName,
|
|
14011
14627
|
messageCount,
|
|
14012
14628
|
lastActive,
|
|
14013
14629
|
onChoose
|
|
14014
14630
|
}) {
|
|
14015
|
-
return /* @__PURE__ */
|
|
14631
|
+
return /* @__PURE__ */ React23.createElement(Box21, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React23.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React23.createElement(Text20, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React23.createElement(Text20, { dimColor: true }, ` \xB7 last active ${relativeTime2(lastActive)}`)), /* @__PURE__ */ React23.createElement(
|
|
14016
14632
|
SingleSelect,
|
|
14017
14633
|
{
|
|
14018
14634
|
initialValue: "new",
|
|
@@ -14035,7 +14651,7 @@ function SessionPicker({
|
|
|
14035
14651
|
],
|
|
14036
14652
|
onSubmit: (v) => onChoose(v)
|
|
14037
14653
|
}
|
|
14038
|
-
), /* @__PURE__ */
|
|
14654
|
+
), /* @__PURE__ */ React23.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text20, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] select")));
|
|
14039
14655
|
}
|
|
14040
14656
|
function relativeTime2(date) {
|
|
14041
14657
|
const ms = Date.now() - date.getTime();
|
|
@@ -14051,9 +14667,9 @@ function relativeTime2(date) {
|
|
|
14051
14667
|
}
|
|
14052
14668
|
|
|
14053
14669
|
// src/cli/ui/Setup.tsx
|
|
14054
|
-
import { Box as
|
|
14670
|
+
import { Box as Box22, Text as Text21, useApp as useApp2 } from "ink";
|
|
14055
14671
|
import TextInput from "ink-text-input";
|
|
14056
|
-
import
|
|
14672
|
+
import React24, { useState as useState11 } from "react";
|
|
14057
14673
|
function Setup({ onReady }) {
|
|
14058
14674
|
const [value, setValue] = useState11("");
|
|
14059
14675
|
const [error, setError] = useState11(null);
|
|
@@ -14077,7 +14693,7 @@ function Setup({ onReady }) {
|
|
|
14077
14693
|
}
|
|
14078
14694
|
onReady(trimmed);
|
|
14079
14695
|
};
|
|
14080
|
-
return /* @__PURE__ */
|
|
14696
|
+
return /* @__PURE__ */ React24.createElement(Box22, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React24.createElement(Text21, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React24.createElement(
|
|
14081
14697
|
TextInput,
|
|
14082
14698
|
{
|
|
14083
14699
|
value,
|
|
@@ -14086,7 +14702,7 @@ function Setup({ onReady }) {
|
|
|
14086
14702
|
mask: "\u2022",
|
|
14087
14703
|
placeholder: "sk-..."
|
|
14088
14704
|
}
|
|
14089
|
-
)), error ? /* @__PURE__ */
|
|
14705
|
+
)), error ? /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { color: "red" }, error)) : value ? /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "(Type /exit to abort.)")));
|
|
14090
14706
|
}
|
|
14091
14707
|
|
|
14092
14708
|
// src/cli/commands/chat.tsx
|
|
@@ -14102,7 +14718,7 @@ function Root({
|
|
|
14102
14718
|
const [key, setKey] = useState12(initialKey);
|
|
14103
14719
|
const [pending, setPending] = useState12(sessionPreview);
|
|
14104
14720
|
if (!key) {
|
|
14105
|
-
return /* @__PURE__ */
|
|
14721
|
+
return /* @__PURE__ */ React25.createElement(
|
|
14106
14722
|
Setup,
|
|
14107
14723
|
{
|
|
14108
14724
|
onReady: (k) => {
|
|
@@ -14114,7 +14730,7 @@ function Root({
|
|
|
14114
14730
|
}
|
|
14115
14731
|
process.env.DEEPSEEK_API_KEY = key;
|
|
14116
14732
|
if (pending && appProps.session) {
|
|
14117
|
-
return /* @__PURE__ */
|
|
14733
|
+
return /* @__PURE__ */ React25.createElement(KeystrokeProvider, null, /* @__PURE__ */ React25.createElement(
|
|
14118
14734
|
SessionPicker,
|
|
14119
14735
|
{
|
|
14120
14736
|
sessionName: appProps.session,
|
|
@@ -14127,9 +14743,9 @@ function Root({
|
|
|
14127
14743
|
setPending(void 0);
|
|
14128
14744
|
}
|
|
14129
14745
|
}
|
|
14130
|
-
);
|
|
14746
|
+
));
|
|
14131
14747
|
}
|
|
14132
|
-
return /* @__PURE__ */
|
|
14748
|
+
return /* @__PURE__ */ React25.createElement(KeystrokeProvider, null, /* @__PURE__ */ React25.createElement(
|
|
14133
14749
|
App,
|
|
14134
14750
|
{
|
|
14135
14751
|
model: appProps.model,
|
|
@@ -14144,7 +14760,7 @@ function Root({
|
|
|
14144
14760
|
progressSink,
|
|
14145
14761
|
codeMode: appProps.codeMode
|
|
14146
14762
|
}
|
|
14147
|
-
);
|
|
14763
|
+
));
|
|
14148
14764
|
}
|
|
14149
14765
|
async function chatCommand(opts) {
|
|
14150
14766
|
loadDotenv();
|
|
@@ -14234,7 +14850,7 @@ async function chatCommand(opts) {
|
|
|
14234
14850
|
rewriteSession(opts.session, []);
|
|
14235
14851
|
}
|
|
14236
14852
|
const { waitUntilExit } = render(
|
|
14237
|
-
/* @__PURE__ */
|
|
14853
|
+
/* @__PURE__ */ React25.createElement(
|
|
14238
14854
|
Root,
|
|
14239
14855
|
{
|
|
14240
14856
|
initialKey,
|
|
@@ -14283,12 +14899,9 @@ async function codeCommand(opts = {}) {
|
|
|
14283
14899
|
`\u25B8 reasonix code: rooted at ${rootDir}, session "${session ?? "(ephemeral)"}" \xB7 ${tools.size} native tool(s)
|
|
14284
14900
|
`
|
|
14285
14901
|
);
|
|
14286
|
-
|
|
14902
|
+
process.once("exit", () => {
|
|
14287
14903
|
void jobs2.shutdown();
|
|
14288
|
-
};
|
|
14289
|
-
process.once("SIGINT", sigShutdown);
|
|
14290
|
-
process.once("SIGTERM", sigShutdown);
|
|
14291
|
-
process.once("exit", sigShutdown);
|
|
14904
|
+
});
|
|
14292
14905
|
await chatCommand({
|
|
14293
14906
|
model: opts.model ?? "deepseek-v4-flash",
|
|
14294
14907
|
harvest: opts.harvest ?? false,
|
|
@@ -14306,35 +14919,35 @@ async function codeCommand(opts = {}) {
|
|
|
14306
14919
|
import { writeFileSync as writeFileSync7 } from "fs";
|
|
14307
14920
|
import { basename as basename3 } from "path";
|
|
14308
14921
|
import { render as render2 } from "ink";
|
|
14309
|
-
import
|
|
14922
|
+
import React28 from "react";
|
|
14310
14923
|
|
|
14311
14924
|
// src/cli/ui/DiffApp.tsx
|
|
14312
|
-
import { Box as
|
|
14313
|
-
import
|
|
14925
|
+
import { Box as Box24, Static as Static2, Text as Text23, useApp as useApp3, useInput } from "ink";
|
|
14926
|
+
import React27, { useState as useState13 } from "react";
|
|
14314
14927
|
|
|
14315
14928
|
// src/cli/ui/RecordView.tsx
|
|
14316
|
-
import { Box as
|
|
14317
|
-
import
|
|
14929
|
+
import { Box as Box23, Text as Text22 } from "ink";
|
|
14930
|
+
import React26 from "react";
|
|
14318
14931
|
function RecordView({ rec, compact: compact2 = false }) {
|
|
14319
14932
|
const toolArgsMax = compact2 ? 120 : 200;
|
|
14320
14933
|
const toolContentMax = compact2 ? 200 : 400;
|
|
14321
14934
|
if (rec.role === "user") {
|
|
14322
14935
|
const content = rec.content.includes("\n") ? rec.content.split("\n").join("\n ") : rec.content;
|
|
14323
|
-
return /* @__PURE__ */
|
|
14936
|
+
return /* @__PURE__ */ React26.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React26.createElement(Text22, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React26.createElement(Text22, null, content));
|
|
14324
14937
|
}
|
|
14325
14938
|
if (rec.role === "assistant_final") {
|
|
14326
|
-
return /* @__PURE__ */
|
|
14939
|
+
return /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React26.createElement(Box23, null, /* @__PURE__ */ React26.createElement(Text22, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React26.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React26.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React26.createElement(Text22, null, rec.content) : /* @__PURE__ */ React26.createElement(Text22, { dimColor: true, italic: true }, "(tool-call response only)"));
|
|
14327
14940
|
}
|
|
14328
14941
|
if (rec.role === "tool") {
|
|
14329
|
-
return /* @__PURE__ */
|
|
14942
|
+
return /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React26.createElement(Text22, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " args: ", truncate2(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \u2192 ", truncate2(rec.content, toolContentMax)));
|
|
14330
14943
|
}
|
|
14331
14944
|
if (rec.role === "error") {
|
|
14332
|
-
return /* @__PURE__ */
|
|
14945
|
+
return /* @__PURE__ */ React26.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React26.createElement(Text22, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React26.createElement(Text22, { color: "red" }, rec.error ?? rec.content));
|
|
14333
14946
|
}
|
|
14334
14947
|
if (rec.role === "done" || rec.role === "assistant_delta") {
|
|
14335
14948
|
return null;
|
|
14336
14949
|
}
|
|
14337
|
-
return /* @__PURE__ */
|
|
14950
|
+
return /* @__PURE__ */ React26.createElement(Box23, null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, "[", rec.role, "] ", rec.content));
|
|
14338
14951
|
}
|
|
14339
14952
|
function CacheBadge({ usage }) {
|
|
14340
14953
|
const hit = usage.prompt_cache_hit_tokens ?? 0;
|
|
@@ -14343,7 +14956,7 @@ function CacheBadge({ usage }) {
|
|
|
14343
14956
|
if (total === 0) return null;
|
|
14344
14957
|
const pct2 = hit / total * 100;
|
|
14345
14958
|
const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
|
|
14346
|
-
return /* @__PURE__ */
|
|
14959
|
+
return /* @__PURE__ */ React26.createElement(Text22, null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React26.createElement(Text22, { color }, pct2.toFixed(1), "%"));
|
|
14347
14960
|
}
|
|
14348
14961
|
function truncate2(s, max) {
|
|
14349
14962
|
return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
|
|
@@ -14355,7 +14968,7 @@ function DiffApp({ report }) {
|
|
|
14355
14968
|
const maxIdx = Math.max(0, report.pairs.length - 1);
|
|
14356
14969
|
const initialIdx = report.firstDivergenceTurn ? report.pairs.findIndex((p) => p.turn === report.firstDivergenceTurn) : 0;
|
|
14357
14970
|
const [idx, setIdx] = useState13(Math.max(0, initialIdx));
|
|
14358
|
-
|
|
14971
|
+
useInput((input, key) => {
|
|
14359
14972
|
if (input === "q" || key.ctrl && input === "c") {
|
|
14360
14973
|
exit2();
|
|
14361
14974
|
return;
|
|
@@ -14377,7 +14990,7 @@ function DiffApp({ report }) {
|
|
|
14377
14990
|
}
|
|
14378
14991
|
});
|
|
14379
14992
|
const pair = report.pairs[idx];
|
|
14380
|
-
return /* @__PURE__ */
|
|
14993
|
+
return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column" }, /* @__PURE__ */ React27.createElement(DiffHeader, { report }), /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React27.createElement(Text23, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React27.createElement(Text23, null, pair ? /* @__PURE__ */ React27.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React27.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React27.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React27.createElement(Text23, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React27.createElement(Text23, null, pair.divergenceNote)) : null, /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "j"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "k"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "N"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "g"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "q"), " ", "quit")));
|
|
14381
14994
|
}
|
|
14382
14995
|
function DiffHeader({ report }) {
|
|
14383
14996
|
const a = report.a;
|
|
@@ -14395,15 +15008,15 @@ function DiffHeader({ report }) {
|
|
|
14395
15008
|
} else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
|
|
14396
15009
|
prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
|
|
14397
15010
|
}
|
|
14398
|
-
return /* @__PURE__ */
|
|
15011
|
+
return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React27.createElement(Box24, { justifyContent: "space-between" }, /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React27.createElement(Text23, { color: "blue" }, a.label), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " vs B="), /* @__PURE__ */ React27.createElement(Text23, { color: "magenta" }, b.label)), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "cache "), /* @__PURE__ */ React27.createElement(Text23, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React27.createElement(Text23, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React27.createElement(Text23, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "cost "), /* @__PURE__ */ React27.createElement(Text23, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React27.createElement(Text23, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React27.createElement(Text23, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "model calls "), /* @__PURE__ */ React27.createElement(Text23, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true, italic: true }, prefixLine)) : null);
|
|
14399
15012
|
}
|
|
14400
15013
|
function Pane({
|
|
14401
15014
|
label,
|
|
14402
15015
|
headerColor,
|
|
14403
15016
|
records
|
|
14404
15017
|
}) {
|
|
14405
|
-
return /* @__PURE__ */
|
|
14406
|
-
|
|
15018
|
+
return /* @__PURE__ */ React27.createElement(
|
|
15019
|
+
Box24,
|
|
14407
15020
|
{
|
|
14408
15021
|
flexDirection: "column",
|
|
14409
15022
|
flexGrow: 1,
|
|
@@ -14411,21 +15024,21 @@ function Pane({
|
|
|
14411
15024
|
borderStyle: "single",
|
|
14412
15025
|
borderColor: headerColor
|
|
14413
15026
|
},
|
|
14414
|
-
/* @__PURE__ */
|
|
14415
|
-
records.length === 0 ? /* @__PURE__ */
|
|
15027
|
+
/* @__PURE__ */ React27.createElement(Text23, { color: headerColor, bold: true }, label),
|
|
15028
|
+
records.length === 0 ? /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React27.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React27.createElement(RecordView, { key, rec, compact: true }))
|
|
14416
15029
|
);
|
|
14417
15030
|
}
|
|
14418
15031
|
function KindBadge({ kind }) {
|
|
14419
15032
|
if (kind === "match") {
|
|
14420
|
-
return /* @__PURE__ */
|
|
15033
|
+
return /* @__PURE__ */ React27.createElement(Text23, { color: "green" }, "\u2713 match");
|
|
14421
15034
|
}
|
|
14422
15035
|
if (kind === "diverge") {
|
|
14423
|
-
return /* @__PURE__ */
|
|
15036
|
+
return /* @__PURE__ */ React27.createElement(Text23, { color: "yellow" }, "\u2605 diverge");
|
|
14424
15037
|
}
|
|
14425
15038
|
if (kind === "only_in_a") {
|
|
14426
|
-
return /* @__PURE__ */
|
|
15039
|
+
return /* @__PURE__ */ React27.createElement(Text23, { color: "blue" }, "\u2190 only in A");
|
|
14427
15040
|
}
|
|
14428
|
-
return /* @__PURE__ */
|
|
15041
|
+
return /* @__PURE__ */ React27.createElement(Text23, { color: "magenta" }, "\u2192 only in B");
|
|
14429
15042
|
}
|
|
14430
15043
|
function paneRecords(pair, side) {
|
|
14431
15044
|
if (!pair) return [];
|
|
@@ -14456,7 +15069,7 @@ markdown report written to ${opts.mdPath}`);
|
|
|
14456
15069
|
return;
|
|
14457
15070
|
}
|
|
14458
15071
|
if (wantTui) {
|
|
14459
|
-
const { waitUntilExit } = render2(
|
|
15072
|
+
const { waitUntilExit } = render2(React28.createElement(DiffApp, { report }), {
|
|
14460
15073
|
exitOnCtrlC: true,
|
|
14461
15074
|
patchConsole: false
|
|
14462
15075
|
});
|
|
@@ -14597,16 +15210,16 @@ function pad2(s, width) {
|
|
|
14597
15210
|
|
|
14598
15211
|
// src/cli/commands/replay.ts
|
|
14599
15212
|
import { render as render3 } from "ink";
|
|
14600
|
-
import
|
|
15213
|
+
import React30 from "react";
|
|
14601
15214
|
|
|
14602
15215
|
// src/cli/ui/ReplayApp.tsx
|
|
14603
|
-
import { Box as
|
|
14604
|
-
import
|
|
15216
|
+
import { Box as Box25, Static as Static3, Text as Text24, useApp as useApp4, useInput as useInput2 } from "ink";
|
|
15217
|
+
import React29, { useMemo as useMemo4, useState as useState14 } from "react";
|
|
14605
15218
|
function ReplayApp({ meta, pages }) {
|
|
14606
15219
|
const { exit: exit2 } = useApp4();
|
|
14607
15220
|
const maxIdx = Math.max(0, pages.length - 1);
|
|
14608
15221
|
const [idx, setIdx] = useState14(maxIdx);
|
|
14609
|
-
|
|
15222
|
+
useInput2((input, key) => {
|
|
14610
15223
|
if (input === "q" || key.ctrl && input === "c") {
|
|
14611
15224
|
exit2();
|
|
14612
15225
|
return;
|
|
@@ -14641,14 +15254,14 @@ function ReplayApp({ meta, pages }) {
|
|
|
14641
15254
|
const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
|
|
14642
15255
|
const currentPage = pages[idx];
|
|
14643
15256
|
const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
|
|
14644
|
-
return /* @__PURE__ */
|
|
15257
|
+
return /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React29.createElement(
|
|
14645
15258
|
StatsPanel,
|
|
14646
15259
|
{
|
|
14647
15260
|
summary,
|
|
14648
15261
|
model: cumStats.models[0] ?? meta?.model ?? "?",
|
|
14649
15262
|
prefixHash
|
|
14650
15263
|
}
|
|
14651
|
-
), /* @__PURE__ */
|
|
15264
|
+
), /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React29.createElement(Box25, { justifyContent: "space-between" }, /* @__PURE__ */ React29.createElement(Text24, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React29.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React29.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React29.createElement(Text24, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "j"), "/", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "k"), "/", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "q"), " quit")));
|
|
14652
15265
|
}
|
|
14653
15266
|
|
|
14654
15267
|
// src/cli/commands/replay.ts
|
|
@@ -14660,7 +15273,7 @@ async function replayCommand(opts) {
|
|
|
14660
15273
|
}
|
|
14661
15274
|
const { parsed } = replayFromFile(opts.path);
|
|
14662
15275
|
const pages = groupRecordsByTurn(parsed.records);
|
|
14663
|
-
const { waitUntilExit } = render3(
|
|
15276
|
+
const { waitUntilExit } = render3(React30.createElement(ReplayApp, { meta: parsed.meta, pages }), {
|
|
14664
15277
|
exitOnCtrlC: true,
|
|
14665
15278
|
patchConsole: false
|
|
14666
15279
|
});
|
|
@@ -14754,12 +15367,12 @@ function oneLine2(s, max = 200) {
|
|
|
14754
15367
|
}
|
|
14755
15368
|
|
|
14756
15369
|
// src/cli/commands/run.ts
|
|
14757
|
-
import { stdin, stdout } from "process";
|
|
15370
|
+
import { stdin as stdin2, stdout } from "process";
|
|
14758
15371
|
import { createInterface } from "readline/promises";
|
|
14759
15372
|
async function ensureApiKey() {
|
|
14760
15373
|
const existing = loadApiKey();
|
|
14761
15374
|
if (existing) return existing;
|
|
14762
|
-
if (!
|
|
15375
|
+
if (!stdin2.isTTY) {
|
|
14763
15376
|
process.stderr.write(
|
|
14764
15377
|
"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
15378
|
);
|
|
@@ -14768,7 +15381,7 @@ async function ensureApiKey() {
|
|
|
14768
15381
|
process.stdout.write(
|
|
14769
15382
|
"DeepSeek API key not configured.\nGet one at https://platform.deepseek.com/api_keys\n"
|
|
14770
15383
|
);
|
|
14771
|
-
const rl = createInterface({ input:
|
|
15384
|
+
const rl = createInterface({ input: stdin2, output: stdout });
|
|
14772
15385
|
try {
|
|
14773
15386
|
while (true) {
|
|
14774
15387
|
const answer = (await rl.question("API key \u203A ")).trim();
|
|
@@ -14965,12 +15578,12 @@ function truncate3(s, max) {
|
|
|
14965
15578
|
|
|
14966
15579
|
// src/cli/commands/setup.tsx
|
|
14967
15580
|
import { render as render4 } from "ink";
|
|
14968
|
-
import
|
|
15581
|
+
import React32 from "react";
|
|
14969
15582
|
|
|
14970
15583
|
// src/cli/ui/Wizard.tsx
|
|
14971
|
-
import { Box as
|
|
15584
|
+
import { Box as Box26, Text as Text25, useApp as useApp5, useInput as useInput3 } from "ink";
|
|
14972
15585
|
import TextInput2 from "ink-text-input";
|
|
14973
|
-
import
|
|
15586
|
+
import React31, { useState as useState15 } from "react";
|
|
14974
15587
|
|
|
14975
15588
|
// src/cli/ui/presets.ts
|
|
14976
15589
|
var PRESETS = {
|
|
@@ -15014,11 +15627,11 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15014
15627
|
catalogArgs: {}
|
|
15015
15628
|
});
|
|
15016
15629
|
const [error, setError] = useState15(null);
|
|
15017
|
-
|
|
15630
|
+
useInput3((_input, key) => {
|
|
15018
15631
|
if (key.escape && step !== "saved" && onCancel) onCancel();
|
|
15019
15632
|
});
|
|
15020
15633
|
if (step === "apiKey") {
|
|
15021
|
-
return /* @__PURE__ */
|
|
15634
|
+
return /* @__PURE__ */ React31.createElement(
|
|
15022
15635
|
ApiKeyStep,
|
|
15023
15636
|
{
|
|
15024
15637
|
onSubmit: (key) => {
|
|
@@ -15032,7 +15645,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15032
15645
|
);
|
|
15033
15646
|
}
|
|
15034
15647
|
if (step === "preset") {
|
|
15035
|
-
return /* @__PURE__ */
|
|
15648
|
+
return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React31.createElement(
|
|
15036
15649
|
SingleSelect,
|
|
15037
15650
|
{
|
|
15038
15651
|
items: presetItems(),
|
|
@@ -15042,10 +15655,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15042
15655
|
setStep("mcp");
|
|
15043
15656
|
}
|
|
15044
15657
|
}
|
|
15045
|
-
), /* @__PURE__ */
|
|
15658
|
+
), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel")));
|
|
15046
15659
|
}
|
|
15047
15660
|
if (step === "mcp") {
|
|
15048
|
-
return /* @__PURE__ */
|
|
15661
|
+
return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React31.createElement(
|
|
15049
15662
|
MultiSelect,
|
|
15050
15663
|
{
|
|
15051
15664
|
items: mcpItems(),
|
|
@@ -15070,7 +15683,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15070
15683
|
}
|
|
15071
15684
|
const currentName = pending[0];
|
|
15072
15685
|
const entry = CATALOG_BY_NAME.get(currentName);
|
|
15073
|
-
return /* @__PURE__ */
|
|
15686
|
+
return /* @__PURE__ */ React31.createElement(
|
|
15074
15687
|
McpArgsStep,
|
|
15075
15688
|
{
|
|
15076
15689
|
entry,
|
|
@@ -15088,7 +15701,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15088
15701
|
}
|
|
15089
15702
|
if (step === "review") {
|
|
15090
15703
|
const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
|
|
15091
|
-
return /* @__PURE__ */
|
|
15704
|
+
return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React31.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React31.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React31.createElement(
|
|
15092
15705
|
SummaryLine,
|
|
15093
15706
|
{
|
|
15094
15707
|
label: "MCP",
|
|
@@ -15096,8 +15709,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15096
15709
|
}
|
|
15097
15710
|
), specs.map((spec, i) => (
|
|
15098
15711
|
// biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
|
|
15099
|
-
/* @__PURE__ */
|
|
15100
|
-
)), /* @__PURE__ */
|
|
15712
|
+
/* @__PURE__ */ React31.createElement(Box26, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "\xB7 ", spec))
|
|
15713
|
+
)), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { color: "red" }, error)) : null, /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "[Enter] save \xB7 [Esc] cancel"))), /* @__PURE__ */ React31.createElement(
|
|
15101
15714
|
ReviewConfirm,
|
|
15102
15715
|
{
|
|
15103
15716
|
onConfirm: () => {
|
|
@@ -15123,7 +15736,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
|
|
|
15123
15736
|
}
|
|
15124
15737
|
));
|
|
15125
15738
|
}
|
|
15126
|
-
return /* @__PURE__ */
|
|
15739
|
+
return /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "[Enter] to exit")), /* @__PURE__ */ React31.createElement(ExitOnEnter, { onExit: exit2 }));
|
|
15127
15740
|
}
|
|
15128
15741
|
function ApiKeyStep({
|
|
15129
15742
|
onSubmit,
|
|
@@ -15131,7 +15744,7 @@ function ApiKeyStep({
|
|
|
15131
15744
|
onError
|
|
15132
15745
|
}) {
|
|
15133
15746
|
const [value, setValue] = useState15("");
|
|
15134
|
-
return /* @__PURE__ */
|
|
15747
|
+
return /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React31.createElement(
|
|
15135
15748
|
TextInput2,
|
|
15136
15749
|
{
|
|
15137
15750
|
value,
|
|
@@ -15148,7 +15761,7 @@ function ApiKeyStep({
|
|
|
15148
15761
|
mask: "\u2022",
|
|
15149
15762
|
placeholder: "sk-..."
|
|
15150
15763
|
}
|
|
15151
|
-
)), error ? /* @__PURE__ */
|
|
15764
|
+
)), error ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { color: "red" }, error)) : value ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "preview: ", redactKey(value))) : null);
|
|
15152
15765
|
}
|
|
15153
15766
|
function McpArgsStep({
|
|
15154
15767
|
entry,
|
|
@@ -15157,7 +15770,7 @@ function McpArgsStep({
|
|
|
15157
15770
|
onError
|
|
15158
15771
|
}) {
|
|
15159
15772
|
const [value, setValue] = useState15("");
|
|
15160
|
-
return /* @__PURE__ */
|
|
15773
|
+
return /* @__PURE__ */ React31.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Text25, null, entry.summary), entry.note ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Required parameter: "), /* @__PURE__ */ React31.createElement(Text25, { bold: true }, entry.userArgs)), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React31.createElement(
|
|
15161
15774
|
TextInput2,
|
|
15162
15775
|
{
|
|
15163
15776
|
value,
|
|
@@ -15173,16 +15786,16 @@ function McpArgsStep({
|
|
|
15173
15786
|
},
|
|
15174
15787
|
placeholder: placeholderFor(entry)
|
|
15175
15788
|
}
|
|
15176
|
-
)), error ? /* @__PURE__ */
|
|
15789
|
+
)), error ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { color: "red" }, error)) : null));
|
|
15177
15790
|
}
|
|
15178
15791
|
function ReviewConfirm({ onConfirm }) {
|
|
15179
|
-
|
|
15792
|
+
useInput3((_i, key) => {
|
|
15180
15793
|
if (key.return) onConfirm();
|
|
15181
15794
|
});
|
|
15182
15795
|
return null;
|
|
15183
15796
|
}
|
|
15184
15797
|
function ExitOnEnter({ onExit }) {
|
|
15185
|
-
|
|
15798
|
+
useInput3((_i, key) => {
|
|
15186
15799
|
if (key.return) onExit();
|
|
15187
15800
|
});
|
|
15188
15801
|
return null;
|
|
@@ -15193,10 +15806,10 @@ function StepFrame({
|
|
|
15193
15806
|
total,
|
|
15194
15807
|
children
|
|
15195
15808
|
}) {
|
|
15196
|
-
return /* @__PURE__ */
|
|
15809
|
+
return /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React31.createElement(Box26, null, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1, flexDirection: "column" }, children));
|
|
15197
15810
|
}
|
|
15198
15811
|
function SummaryLine({ label, value }) {
|
|
15199
|
-
return /* @__PURE__ */
|
|
15812
|
+
return /* @__PURE__ */ React31.createElement(Box26, null, /* @__PURE__ */ React31.createElement(Text25, null, label.padEnd(12)), /* @__PURE__ */ React31.createElement(Text25, { bold: true }, value));
|
|
15200
15813
|
}
|
|
15201
15814
|
function presetItems() {
|
|
15202
15815
|
return ["fast", "smart", "max"].map((name) => ({
|
|
@@ -15252,7 +15865,7 @@ async function setupCommand(_opts = {}) {
|
|
|
15252
15865
|
const existingKey = loadApiKey();
|
|
15253
15866
|
const existing = readConfig();
|
|
15254
15867
|
const { waitUntilExit, unmount } = render4(
|
|
15255
|
-
/* @__PURE__ */
|
|
15868
|
+
/* @__PURE__ */ React32.createElement(
|
|
15256
15869
|
Wizard,
|
|
15257
15870
|
{
|
|
15258
15871
|
existingApiKey: existingKey,
|