@botconnector/bccli 0.4.13 → 0.4.15
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/{chunk-F6NNUUF3.js → chunk-2PAVSETH.js} +1 -1
- package/dist/cli.js +5 -5
- package/dist/{serve-6NK2IR6R.js → serve-RKV2JCU7.js} +1 -1
- package/dist/ui/liveCap.d.ts +9 -0
- package/dist/ui/thinkingMouse.d.ts +6 -5
- package/dist/ui/tty.d.ts +11 -0
- package/dist/{ui-IMCUSB6Q.js → ui-ICUWKBUG.js} +53 -112
- package/dist/{update-PXXUITFS.js → update-U4FXFWNV.js} +1 -1
- package/package.json +2 -2
- package/dist/ui/focusReport.d.ts +0 -1
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import "./chunk-7GM6NN5E.js";
|
|
|
13
13
|
import "./chunk-PSO7R5AD.js";
|
|
14
14
|
import {
|
|
15
15
|
VERSION
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-2PAVSETH.js";
|
|
17
17
|
import {
|
|
18
18
|
helpText,
|
|
19
19
|
parseCliArgs
|
|
@@ -109,7 +109,7 @@ async function main() {
|
|
|
109
109
|
return runModelsCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), fetch: globalThis.fetch });
|
|
110
110
|
}
|
|
111
111
|
if (args.command === "update") {
|
|
112
|
-
const { runUpdateCommand } = await import("./update-
|
|
112
|
+
const { runUpdateCommand } = await import("./update-U4FXFWNV.js");
|
|
113
113
|
return runUpdateCommand({ env: process.env });
|
|
114
114
|
}
|
|
115
115
|
if (args.command === "acp") {
|
|
@@ -118,7 +118,7 @@ async function main() {
|
|
|
118
118
|
return 0;
|
|
119
119
|
}
|
|
120
120
|
if (args.command === "serve") {
|
|
121
|
-
const { serveBanner, startServe } = await import("./serve-
|
|
121
|
+
const { serveBanner, startServe } = await import("./serve-RKV2JCU7.js");
|
|
122
122
|
const handle = await startServe({ port: args.port, host: args.host, token: args.token, cwd, env: process.env });
|
|
123
123
|
process.stderr.write(serveBanner(handle, { token: args.token }));
|
|
124
124
|
await new Promise((resolve) => {
|
|
@@ -215,13 +215,13 @@ async function main() {
|
|
|
215
215
|
let updateMessage;
|
|
216
216
|
if (rt.config.updateCheck !== "off" && !process.env.BCCLI_NO_UPDATE_CHECK) {
|
|
217
217
|
try {
|
|
218
|
-
const { checkForUpdate } = await import("./update-
|
|
218
|
+
const { checkForUpdate } = await import("./update-U4FXFWNV.js");
|
|
219
219
|
const update = await checkForUpdate({ home: rt.home, fetch: globalThis.fetch, now: /* @__PURE__ */ new Date() });
|
|
220
220
|
updateMessage = update;
|
|
221
221
|
} catch {
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
-
const { startInteractive } = await import("./ui-
|
|
224
|
+
const { startInteractive } = await import("./ui-ICUWKBUG.js");
|
|
225
225
|
return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION, updateMessage });
|
|
226
226
|
}
|
|
227
227
|
main().then(
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live assistant text is drawn inside the Ink frame, so on a real terminal it is capped to the rows left after the
|
|
3
|
+
* prompt and status bar; the hidden part is announced instead of silently dropped. Piped stdout has no rows to
|
|
4
|
+
* respect (`bccli | tee log`, CI harnesses), so the text is kept whole there.
|
|
5
|
+
*/
|
|
6
|
+
export declare function capLiveMarkdown(raw: string, options: {
|
|
7
|
+
isRealTty: boolean;
|
|
8
|
+
maxLines: number;
|
|
9
|
+
}): string;
|
|
@@ -15,12 +15,13 @@ export declare function clickedThinking(click: MousePress, cursorRow: number, ro
|
|
|
15
15
|
width: number;
|
|
16
16
|
height: number;
|
|
17
17
|
}): boolean;
|
|
18
|
-
/**
|
|
19
|
-
export declare function parseMouseWheel(input: string): 'up' | 'down' | undefined;
|
|
20
|
-
/** Detect raw SGR/Urxvt wheel packets in a raw stdin data chunk (before ESC is stripped). */
|
|
18
|
+
/** Detect raw SGR wheel packets in a raw stdin data chunk (before ESC is stripped), used to suspend mouse capture. */
|
|
21
19
|
export declare function hasMouseWheelSequence(chunk: string): boolean;
|
|
22
|
-
/**
|
|
23
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Sequence fragments Ink 8 does not recognise (mouse, cursor reports) are dropped when complete, but an incomplete
|
|
22
|
+
* escape is flushed as literal input after ~20 ms. That fragment must never be typed into a prompt or filter.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isControlReportFragment(input: string): boolean;
|
|
24
25
|
/** Tokenize split/coalesced Windows ConPTY SGR presses and cursor reports. */
|
|
25
26
|
export declare function parseThinkingReports(value: string): {
|
|
26
27
|
events: Array<{
|
package/dist/ui/tty.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** True when the stream reports itself as a TTY (fake test streams may still report `true`). */
|
|
2
|
+
export declare function isTtyStream(stream: unknown): boolean;
|
|
3
|
+
/** True only for a real terminal: a TTY that also exposes a file descriptor. */
|
|
4
|
+
export declare function isRealTty(stream: unknown): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Terminal width at render time. Reading it instead of listening to `resize` keeps the app to the single resize
|
|
7
|
+
* listener Ink already owns (it re-renders the tree on resize), instead of one listener per rendered message.
|
|
8
|
+
*/
|
|
9
|
+
export declare function streamColumns(stream: unknown): number;
|
|
10
|
+
/** Terminal height at render time; same reasoning as `streamColumns`. */
|
|
11
|
+
export declare function streamRows(stream: unknown): number;
|
|
@@ -547,6 +547,22 @@ function layoutTable(table, width) {
|
|
|
547
547
|
return out;
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
+
// src/ui/tty.ts
|
|
551
|
+
function isTtyStream(stream) {
|
|
552
|
+
return typeof stream === "object" && stream !== null && stream.isTTY === true;
|
|
553
|
+
}
|
|
554
|
+
function isRealTty(stream) {
|
|
555
|
+
return isTtyStream(stream) && typeof stream.fd === "number";
|
|
556
|
+
}
|
|
557
|
+
function streamColumns(stream) {
|
|
558
|
+
const columns = typeof stream === "object" && stream !== null ? stream.columns : void 0;
|
|
559
|
+
return typeof columns === "number" && columns > 0 ? columns : 80;
|
|
560
|
+
}
|
|
561
|
+
function streamRows(stream) {
|
|
562
|
+
const rows = typeof stream === "object" && stream !== null ? stream.rows : void 0;
|
|
563
|
+
return typeof rows === "number" && rows > 0 ? rows : 24;
|
|
564
|
+
}
|
|
565
|
+
|
|
550
566
|
// src/ui/Markdown.tsx
|
|
551
567
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
552
568
|
function segment(seg, key) {
|
|
@@ -584,7 +600,7 @@ function hanging(key, marker, body, width, padding = 0) {
|
|
|
584
600
|
}
|
|
585
601
|
function Markdown({ text, indent = 2 }) {
|
|
586
602
|
const { stdout } = useStdout();
|
|
587
|
-
const width = Math.max(20, (stdout
|
|
603
|
+
const width = Math.max(20, streamColumns(stdout) - indent - 1);
|
|
588
604
|
const lines = text.split("\n");
|
|
589
605
|
const rows = [];
|
|
590
606
|
let inCode = false;
|
|
@@ -811,9 +827,6 @@ function EditableText({ state, mask = false, showCursor = true }) {
|
|
|
811
827
|
] });
|
|
812
828
|
}
|
|
813
829
|
|
|
814
|
-
// src/ui/focusReport.ts
|
|
815
|
-
var isFocusReport = (input) => input === "[I" || input === "[O";
|
|
816
|
-
|
|
817
830
|
// src/ui/thinkingMouse.ts
|
|
818
831
|
function parseMousePress(value) {
|
|
819
832
|
const start = value.indexOf("\x1B[<");
|
|
@@ -844,21 +857,11 @@ function clickedThinking(click, cursorRow, rootHeight, target) {
|
|
|
844
857
|
const col = target.x + 1;
|
|
845
858
|
return (click.y === row || click.y === row - 1) && click.x >= col && click.x < col + Math.min(target.width, 72);
|
|
846
859
|
}
|
|
847
|
-
function parseMouseWheel(input) {
|
|
848
|
-
const match = /^\[<?(\d+);\d+;\d+[mM]$/.exec(input);
|
|
849
|
-
if (!match) return void 0;
|
|
850
|
-
const button = Number(match[1]);
|
|
851
|
-
if ((button & 64) === 0) return void 0;
|
|
852
|
-
const dir = button & 3;
|
|
853
|
-
if (dir === 0) return "up";
|
|
854
|
-
if (dir === 1) return "down";
|
|
855
|
-
return void 0;
|
|
856
|
-
}
|
|
857
860
|
function hasMouseWheelSequence(chunk) {
|
|
858
861
|
return chunk.includes("\x1B[") && /\[<?6[4567];\d+;\d+[mM]/.test(chunk);
|
|
859
862
|
}
|
|
860
|
-
function
|
|
861
|
-
return /^\[<[\d;]*[mM]?$/.test(input) || /^\[(?:\d+;){2}\d+[mM]$/.test(input) || /^\[(?:\d+;)+\d*R?$/.test(input) || /^\[M[\s\S]{0,3}$/.test(input)
|
|
863
|
+
function isControlReportFragment(input) {
|
|
864
|
+
return /^\[<[\d;]*[mM]?$/.test(input) || /^\[(?:\d+;){2}\d+[mM]$/.test(input) || /^\[(?:\d+;)+\d*R?$/.test(input) || /^\[M[\s\S]{0,3}$/.test(input);
|
|
862
865
|
}
|
|
863
866
|
function parseThinkingReports(value) {
|
|
864
867
|
const events = [];
|
|
@@ -886,11 +889,11 @@ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
|
886
889
|
function LinePrompt({ label, mask, onSubmit, onCancel }) {
|
|
887
890
|
const [line, setLine] = useState({ value: "", cursor: 0 });
|
|
888
891
|
useInput((input, key) => {
|
|
889
|
-
if (
|
|
892
|
+
if (isControlReportFragment(input)) return;
|
|
890
893
|
if (key.return) onSubmit(line.value.trim());
|
|
891
894
|
else if (key.escape) onCancel();
|
|
892
895
|
else if (applyEditKey(line, input, key)) setLine((current) => applyEditKey(current, input, key) ?? current);
|
|
893
|
-
else if (!key.ctrl && !key.meta && !key.tab && !key.upArrow && !key.downArrow
|
|
896
|
+
else if (!key.ctrl && !key.meta && !key.tab && !key.upArrow && !key.downArrow) {
|
|
894
897
|
const text = input.replace(/[\r\n]/g, "");
|
|
895
898
|
if (text) setLine((current) => insert(current, text));
|
|
896
899
|
}
|
|
@@ -913,16 +916,7 @@ function ListPicker({ title, items, onPick }) {
|
|
|
913
916
|
const shown = items.filter((i) => i.label.toLowerCase().includes(filter.toLowerCase()));
|
|
914
917
|
const cursor = Math.min(index, Math.max(0, shown.length - 1));
|
|
915
918
|
useInput2((input, key) => {
|
|
916
|
-
|
|
917
|
-
if (wheel === "up") {
|
|
918
|
-
setIndex(Math.max(0, cursor - 1));
|
|
919
|
-
return;
|
|
920
|
-
}
|
|
921
|
-
if (wheel === "down") {
|
|
922
|
-
setIndex(Math.min(Math.max(0, shown.length - 1), cursor + 1));
|
|
923
|
-
return;
|
|
924
|
-
}
|
|
925
|
-
if (isMouseControlInput(input)) return;
|
|
919
|
+
if (isControlReportFragment(input)) return;
|
|
926
920
|
if (key.upArrow) setIndex(Math.max(0, cursor - 1));
|
|
927
921
|
else if (key.downArrow) setIndex(Math.min(Math.max(0, shown.length - 1), cursor + 1));
|
|
928
922
|
else if (key.pageUp) setIndex(Math.max(0, cursor - VISIBLE));
|
|
@@ -932,7 +926,7 @@ function ListPicker({ title, items, onPick }) {
|
|
|
932
926
|
else if (key.backspace || key.delete) {
|
|
933
927
|
setFilter((f) => f.slice(0, -1));
|
|
934
928
|
setIndex(0);
|
|
935
|
-
} else if (!key.ctrl && !key.meta && !key.tab && input
|
|
929
|
+
} else if (!key.ctrl && !key.meta && !key.tab && input) {
|
|
936
930
|
setFilter((f) => f + input);
|
|
937
931
|
setIndex(0);
|
|
938
932
|
}
|
|
@@ -969,16 +963,7 @@ function ModelPicker({ groups, current, onPick }) {
|
|
|
969
963
|
const clampedIndex = Math.min(index, Math.max(0, selectable.length - 1));
|
|
970
964
|
const cursor = selectable[clampedIndex] ?? -1;
|
|
971
965
|
useInput3((input, key) => {
|
|
972
|
-
|
|
973
|
-
if (wheel === "up") {
|
|
974
|
-
setIndex(Math.max(0, clampedIndex - 1));
|
|
975
|
-
return;
|
|
976
|
-
}
|
|
977
|
-
if (wheel === "down") {
|
|
978
|
-
setIndex(Math.min(Math.max(0, selectable.length - 1), clampedIndex + 1));
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
if (isMouseControlInput(input)) return;
|
|
966
|
+
if (isControlReportFragment(input)) return;
|
|
982
967
|
if (key.upArrow) setIndex(Math.max(0, clampedIndex - 1));
|
|
983
968
|
else if (key.downArrow) setIndex(Math.min(Math.max(0, selectable.length - 1), clampedIndex + 1));
|
|
984
969
|
else if (key.pageUp) setIndex(Math.max(0, clampedIndex - VISIBLE2));
|
|
@@ -990,7 +975,7 @@ function ModelPicker({ groups, current, onPick }) {
|
|
|
990
975
|
else if (key.backspace || key.delete) {
|
|
991
976
|
setFilter((f) => f.slice(0, -1));
|
|
992
977
|
setIndex(0);
|
|
993
|
-
} else if (!key.ctrl && !key.meta && !key.tab && input
|
|
978
|
+
} else if (!key.ctrl && !key.meta && !key.tab && input) {
|
|
994
979
|
setFilter((f) => f + input);
|
|
995
980
|
setIndex(0);
|
|
996
981
|
}
|
|
@@ -1013,17 +998,7 @@ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
|
1013
998
|
function ProviderMenu({ entries, onPick }) {
|
|
1014
999
|
const rows = [...entries.map((e) => e.id), "custom"];
|
|
1015
1000
|
const [index, setIndex] = useState4(0);
|
|
1016
|
-
useInput4((
|
|
1017
|
-
const wheel = parseMouseWheel(input);
|
|
1018
|
-
if (wheel === "up") {
|
|
1019
|
-
setIndex((i) => Math.max(0, i - 1));
|
|
1020
|
-
return;
|
|
1021
|
-
}
|
|
1022
|
-
if (wheel === "down") {
|
|
1023
|
-
setIndex((i) => Math.min(rows.length - 1, i + 1));
|
|
1024
|
-
return;
|
|
1025
|
-
}
|
|
1026
|
-
if (isMouseControlInput(input) || isFocusReport(input)) return;
|
|
1001
|
+
useInput4((_input, key) => {
|
|
1027
1002
|
if (key.upArrow) setIndex((i) => Math.max(0, i - 1));
|
|
1028
1003
|
else if (key.downArrow) setIndex((i) => Math.min(rows.length - 1, i + 1));
|
|
1029
1004
|
else if (key.pageUp) setIndex((i) => Math.max(0, i - 10));
|
|
@@ -1068,16 +1043,6 @@ function PermissionPrompt({
|
|
|
1068
1043
|
const maxOffset = Math.max(0, diffLines.length - MAX_DIFF_LINES);
|
|
1069
1044
|
const [offset, setOffset] = useState5(0);
|
|
1070
1045
|
useInput5((input, key) => {
|
|
1071
|
-
const wheel = parseMouseWheel(input);
|
|
1072
|
-
if (wheel === "up") {
|
|
1073
|
-
setOffset((o) => Math.max(0, o - 2));
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
if (wheel === "down") {
|
|
1077
|
-
setOffset((o) => Math.min(maxOffset, o + 2));
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
|
-
if (isMouseControlInput(input) || isFocusReport(input)) return;
|
|
1081
1046
|
if (key.upArrow) {
|
|
1082
1047
|
setOffset((o) => Math.max(0, o - 1));
|
|
1083
1048
|
return;
|
|
@@ -1331,14 +1296,7 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
|
|
|
1331
1296
|
};
|
|
1332
1297
|
useInput6(
|
|
1333
1298
|
(input, key) => {
|
|
1334
|
-
|
|
1335
|
-
if (wheel) {
|
|
1336
|
-
if (activeCount > 0) {
|
|
1337
|
-
setSelected((current) => wheel === "up" ? Math.max(0, Math.min(current, activeCount - 1) - 1) : Math.min(activeCount - 1, Math.min(current, activeCount - 1) + 1));
|
|
1338
|
-
}
|
|
1339
|
-
return;
|
|
1340
|
-
}
|
|
1341
|
-
if (isMouseControlInput(input)) return;
|
|
1299
|
+
if (isControlReportFragment(input)) return;
|
|
1342
1300
|
if (suggestions.length) {
|
|
1343
1301
|
if (key.escape) {
|
|
1344
1302
|
setDismissed(true);
|
|
@@ -1451,7 +1409,7 @@ ${value.slice(line.cursor)}`, cursor: before.length });
|
|
|
1451
1409
|
if (completed !== before) edit({ value: completed + value.slice(line.cursor), cursor: completed.length });
|
|
1452
1410
|
return;
|
|
1453
1411
|
}
|
|
1454
|
-
if (key.ctrl || key.meta || key.escape || key.tab
|
|
1412
|
+
if (key.ctrl || key.meta || key.escape || key.tab) return;
|
|
1455
1413
|
const text = input.replace(/\r\n?/g, "\n");
|
|
1456
1414
|
if (text) edit((current) => insert(current, text));
|
|
1457
1415
|
},
|
|
@@ -1503,6 +1461,20 @@ function StatusBar({ mode, tokens, busy, model, reasoning = "auto" }) {
|
|
|
1503
1461
|
return /* @__PURE__ */ jsx11(Text11, { color: danger ? color("red") : void 0, dimColor: !danger, children: ` ${LABEL[mode]}${model ? ` \xB7 ${model}` : ""} \xB7 reasoning: ${reasoning} \xB7 ${t("shift+tab switch mode")} \xB7 ${t("{n} tokens", { n: formatTokens(tokens) })} \xB7 ${busy ? t("esc to cancel") : t("/ for commands")}` });
|
|
1504
1462
|
}
|
|
1505
1463
|
|
|
1464
|
+
// src/ui/liveCap.ts
|
|
1465
|
+
function capLiveMarkdown(raw, options) {
|
|
1466
|
+
if (!options.isRealTty) return raw;
|
|
1467
|
+
const lines = raw.split("\n");
|
|
1468
|
+
if (lines.length <= options.maxLines) return raw;
|
|
1469
|
+
const hidden = lines.length - options.maxLines;
|
|
1470
|
+
const headFence = lines.slice(0, hidden).find((line) => line.trimStart().startsWith("```"));
|
|
1471
|
+
const prefix = headFence ? `${headFence}
|
|
1472
|
+
\u2026 (${hidden} lines above) \u2026
|
|
1473
|
+
` : `\u2026 (${hidden} lines above) \u2026
|
|
1474
|
+
`;
|
|
1475
|
+
return `${prefix}${lines.slice(-options.maxLines).join("\n")}`;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1506
1478
|
// src/ui/McpMenu.tsx
|
|
1507
1479
|
import { Box as Box9, Text as Text12, useInput as useInput7 } from "ink";
|
|
1508
1480
|
import { useState as useState8 } from "react";
|
|
@@ -1510,17 +1482,7 @@ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
|
1510
1482
|
var MARK = { ready: "\u2713", error: "\u2717", starting: "\u2026", off: "\u25CB" };
|
|
1511
1483
|
function McpMenu({ items, onPick }) {
|
|
1512
1484
|
const [index, setIndex] = useState8(0);
|
|
1513
|
-
useInput7((
|
|
1514
|
-
const wheel = parseMouseWheel(input);
|
|
1515
|
-
if (wheel === "up") {
|
|
1516
|
-
setIndex((i) => Math.max(0, i - 1));
|
|
1517
|
-
return;
|
|
1518
|
-
}
|
|
1519
|
-
if (wheel === "down") {
|
|
1520
|
-
setIndex((i) => Math.min(items.length - 1, i + 1));
|
|
1521
|
-
return;
|
|
1522
|
-
}
|
|
1523
|
-
if (isMouseControlInput(input) || isFocusReport(input)) return;
|
|
1485
|
+
useInput7((_input, key) => {
|
|
1524
1486
|
if (key.upArrow) setIndex((i) => Math.max(0, i - 1));
|
|
1525
1487
|
else if (key.downArrow) setIndex((i) => Math.min(items.length - 1, i + 1));
|
|
1526
1488
|
else if (key.pageUp) setIndex((i) => Math.max(0, i - 10));
|
|
@@ -1547,16 +1509,6 @@ function PlanApproval({ plan, onAnswer }) {
|
|
|
1547
1509
|
const maxOffset = Math.max(0, planLines.length - MAX_PLAN_LINES);
|
|
1548
1510
|
const [offset, setOffset] = useState9(0);
|
|
1549
1511
|
useInput8((input, key) => {
|
|
1550
|
-
const wheel = parseMouseWheel(input);
|
|
1551
|
-
if (wheel === "up") {
|
|
1552
|
-
setOffset((o) => Math.max(0, o - 2));
|
|
1553
|
-
return;
|
|
1554
|
-
}
|
|
1555
|
-
if (wheel === "down") {
|
|
1556
|
-
setOffset((o) => Math.min(maxOffset, o + 2));
|
|
1557
|
-
return;
|
|
1558
|
-
}
|
|
1559
|
-
if (isMouseControlInput(input) || isFocusReport(input)) return;
|
|
1560
1512
|
if (key.upArrow) {
|
|
1561
1513
|
setOffset((o) => Math.max(0, o - 1));
|
|
1562
1514
|
return;
|
|
@@ -1864,18 +1816,18 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
|
|
|
1864
1816
|
const lastUserIdx = transcript.done.findLastIndex((e) => e.kind === "user");
|
|
1865
1817
|
const { stdin } = useStdin();
|
|
1866
1818
|
const { stdout } = useStdout2();
|
|
1867
|
-
const
|
|
1868
|
-
const maxLiveLines = Math.max(8, (stdout
|
|
1819
|
+
const realStdout = isRealTty(stdout);
|
|
1820
|
+
const maxLiveLines = Math.max(8, streamRows(stdout) - 10);
|
|
1869
1821
|
const maxSplitIdxRef = useRef2(0);
|
|
1870
1822
|
const refreshStatic = useCallback(() => {
|
|
1871
|
-
if (
|
|
1823
|
+
if (realStdout) {
|
|
1872
1824
|
stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
1873
1825
|
}
|
|
1874
1826
|
maxSplitIdxRef.current = 0;
|
|
1875
1827
|
setStaticKey((k2) => k2 + 1);
|
|
1876
|
-
}, [stdout]);
|
|
1828
|
+
}, [stdout, realStdout]);
|
|
1877
1829
|
let splitIdx = Math.max(maxSplitIdxRef.current, lastUserIdx > 0 ? lastUserIdx : 0);
|
|
1878
|
-
if (
|
|
1830
|
+
if (realStdout) {
|
|
1879
1831
|
const entryLines = (e) => {
|
|
1880
1832
|
if (e.kind === "thinking") return showThinking ? Math.min(maxLiveLines, e.text.split("\n").length + 2) : 2;
|
|
1881
1833
|
if (e.kind === "tool") return showToolOutput ? Math.min(maxLiveLines, (e.output ?? e.display ?? "").split("\n").length + 2) : 5;
|
|
@@ -2575,7 +2527,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2575
2527
|
}
|
|
2576
2528
|
}, [initialPrompt, submit]);
|
|
2577
2529
|
useEffect3(() => {
|
|
2578
|
-
if (!
|
|
2530
|
+
if (!isRealTty(stdout)) return;
|
|
2579
2531
|
stdout.write("\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?2004h");
|
|
2580
2532
|
return () => {
|
|
2581
2533
|
stdout.write("\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?2004l");
|
|
@@ -2583,7 +2535,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2583
2535
|
}, [stdout]);
|
|
2584
2536
|
useEffect3(() => {
|
|
2585
2537
|
const modalOpen = !!(pending || planAsk || picker || listPicker || mcpMenu || providerMenu || prompt);
|
|
2586
|
-
if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || modalOpen || !stdin
|
|
2538
|
+
if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || modalOpen || !isTtyStream(stdin) || !isTtyStream(stdout)) return;
|
|
2587
2539
|
let click;
|
|
2588
2540
|
let mouseBuffer = "";
|
|
2589
2541
|
let wheelTimer;
|
|
@@ -2721,18 +2673,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2721
2673
|
pending?.resolve(a);
|
|
2722
2674
|
setAsks((q) => q.slice(1));
|
|
2723
2675
|
};
|
|
2724
|
-
const
|
|
2725
|
-
if (!isRealTty) return raw;
|
|
2726
|
-
const lines = raw.split("\n");
|
|
2727
|
-
if (lines.length <= maxLiveLines) return raw;
|
|
2728
|
-
const hidden = lines.length - maxLiveLines;
|
|
2729
|
-
const headFence = lines.slice(0, hidden).find((l) => l.trimStart().startsWith("```"));
|
|
2730
|
-
const prefix = headFence ? `${headFence}
|
|
2731
|
-
\u2026 (${hidden} lines above) \u2026
|
|
2732
|
-
` : `\u2026 (${hidden} lines above) \u2026
|
|
2733
|
-
`;
|
|
2734
|
-
return `${prefix}${lines.slice(-maxLiveLines).join("\n")}`;
|
|
2735
|
-
};
|
|
2676
|
+
const capLive = (raw) => capLiveMarkdown(raw, { isRealTty: realStdout, maxLines: maxLiveLines });
|
|
2736
2677
|
const cwd = runtime.cwd.startsWith(homedir()) ? `~${runtime.cwd.slice(homedir().length)}` : runtime.cwd;
|
|
2737
2678
|
const renderEntry = (e) => {
|
|
2738
2679
|
const isLive = transcript.live.some((le) => le.id === e.id);
|
|
@@ -2746,7 +2687,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2746
2687
|
case "user":
|
|
2747
2688
|
return /* @__PURE__ */ jsx16(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: `> ${e.text}` }) }, e.id);
|
|
2748
2689
|
case "assistant": {
|
|
2749
|
-
const displayText = isLive ?
|
|
2690
|
+
const displayText = isLive ? capLive(e.text) : e.text;
|
|
2750
2691
|
if (e.cont) {
|
|
2751
2692
|
return displayText ? /* @__PURE__ */ jsx16(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx16(Markdown, { text: displayText }) }, e.id) : null;
|
|
2752
2693
|
}
|
|
@@ -2761,7 +2702,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2761
2702
|
if (!text) return null;
|
|
2762
2703
|
const allLines = text.split("\n");
|
|
2763
2704
|
const lines = allLines.length;
|
|
2764
|
-
const shownText = isLive &&
|
|
2705
|
+
const shownText = isLive && realStdout && allLines.length > maxLiveLines ? `\u2026 (${allLines.length - maxLiveLines} lines above) \u2026
|
|
2765
2706
|
${allLines.slice(-maxLiveLines).join("\n")}` : text;
|
|
2766
2707
|
const isTarget = e.id === lastThinkingEntryId;
|
|
2767
2708
|
return /* @__PURE__ */ jsxs12(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botconnector/bccli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.15",
|
|
4
4
|
"description": "BCCLI — BotConnector AI coding agent for the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
29
29
|
"diff": "^9.0.0",
|
|
30
|
-
"ink": "^
|
|
30
|
+
"ink": "^8.0.0",
|
|
31
31
|
"openai": "^7.27.0",
|
|
32
32
|
"react": "^19.3.0",
|
|
33
33
|
"undici": "^8.12.1",
|
package/dist/ui/focusReport.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const isFocusReport: (input: string) => boolean;
|