@botconnector/bccli 0.4.12 → 0.4.14
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-OFMZ6CE6.js → chunk-RRE6WRU5.js} +1 -1
- package/dist/cli.js +6 -6
- package/dist/{integrationCli-TO42MBZB.js → integrationCli-FBRSTF5F.js} +12 -1
- package/dist/{serve-DC6YICSK.js → serve-KBXP23UW.js} +1 -1
- package/dist/ui/thinkingMouse.d.ts +0 -4
- package/dist/ui/tty.d.ts +9 -0
- package/dist/{ui-IMCUSB6Q.js → ui-K5RLE2R6.js} +83 -155
- package/dist/{update-POT5W6MC.js → update-CRFQXBNM.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-RRE6WRU5.js";
|
|
17
17
|
import {
|
|
18
18
|
helpText,
|
|
19
19
|
parseCliArgs
|
|
@@ -95,7 +95,7 @@ async function main() {
|
|
|
95
95
|
return runProviderCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
96
96
|
}
|
|
97
97
|
if (args.command === "connect" || args.command === "disconnect" || args.command === "integrations") {
|
|
98
|
-
const { runIntegrationCommand } = await import("./integrationCli-
|
|
98
|
+
const { runIntegrationCommand } = await import("./integrationCli-FBRSTF5F.js");
|
|
99
99
|
return runIntegrationCommand(args, {
|
|
100
100
|
env: process.env,
|
|
101
101
|
cwd,
|
|
@@ -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-CRFQXBNM.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-KBXP23UW.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-CRFQXBNM.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-K5RLE2R6.js");
|
|
225
225
|
return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION, updateMessage });
|
|
226
226
|
}
|
|
227
227
|
main().then(
|
|
@@ -92,6 +92,17 @@ function readState(target, env) {
|
|
|
92
92
|
return null;
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
+
function capabilityFlags(item) {
|
|
96
|
+
const names = [];
|
|
97
|
+
const isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
98
|
+
const flags = item.botconnector_capabilities;
|
|
99
|
+
if (isRecord(flags)) {
|
|
100
|
+
for (const [name, enabled] of Object.entries(flags)) if (enabled === true) names.push(name);
|
|
101
|
+
}
|
|
102
|
+
const reasoning = item.botconnector_reasoning;
|
|
103
|
+
if (isRecord(reasoning) && reasoning.supported === true && !names.includes("reasoning")) names.push("reasoning");
|
|
104
|
+
return names;
|
|
105
|
+
}
|
|
95
106
|
async function botConnectorCatalog(deps) {
|
|
96
107
|
const config = loadConfig(deps.cwd, deps.env);
|
|
97
108
|
const resolved = resolveModel(config, config.model, deps.env);
|
|
@@ -115,7 +126,7 @@ async function botConnectorCatalog(deps) {
|
|
|
115
126
|
contextWindow: num(item.contextWindow),
|
|
116
127
|
max_tokens: num(item.max_tokens),
|
|
117
128
|
maxTokens: num(item.maxTokens),
|
|
118
|
-
capabilities: strings(item.capabilities),
|
|
129
|
+
capabilities: [...strings(item.capabilities) ?? [], ...capabilityFlags(item)],
|
|
119
130
|
input: strings(item.input)
|
|
120
131
|
}];
|
|
121
132
|
});
|
|
@@ -15,12 +15,8 @@ export declare function clickedThinking(click: MousePress, cursorRow: number, ro
|
|
|
15
15
|
width: number;
|
|
16
16
|
height: number;
|
|
17
17
|
}): boolean;
|
|
18
|
-
/** Parse SGR or Urxvt mouse wheel / 2-finger touchpad vertical scroll events after Ink strips ESC. */
|
|
19
|
-
export declare function parseMouseWheel(input: string): 'up' | 'down' | undefined;
|
|
20
18
|
/** Detect raw SGR/Urxvt wheel packets in a raw stdin data chunk (before ESC is stripped). */
|
|
21
19
|
export declare function hasMouseWheelSequence(chunk: string): boolean;
|
|
22
|
-
/** Ink useInput receives these control reports too; they must not enter the prompt. */
|
|
23
|
-
export declare function isMouseControlInput(input: string): boolean;
|
|
24
20
|
/** Tokenize split/coalesced Windows ConPTY SGR presses and cursor reports. */
|
|
25
21
|
export declare function parseThinkingReports(value: string): {
|
|
26
22
|
events: Array<{
|
package/dist/ui/tty.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
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 one listener per app
|
|
7
|
+
* (App's `useWindowSize`) rather than one per rendered message; App re-renders on resize and passes the new width down.
|
|
8
|
+
*/
|
|
9
|
+
export declare function streamColumns(stream: unknown): number;
|
|
@@ -76,7 +76,7 @@ import { execFile as execFile3 } from "child_process";
|
|
|
76
76
|
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
77
77
|
import { homedir, tmpdir } from "os";
|
|
78
78
|
import { dirname, join as join3, relative as relative2, resolve as resolve2 } from "path";
|
|
79
|
-
import { Box as Box13, Static, Text as Text16, measureElement, useApp, useInput as useInput9, useStdin, useStdout as useStdout2 } from "ink";
|
|
79
|
+
import { Box as Box13, Static, Text as Text16, measureElement, useApp, useInput as useInput9, useStdin, useStdout as useStdout2, useWindowSize } from "ink";
|
|
80
80
|
import { useCallback, useEffect as useEffect3, useRef as useRef2, useState as useState10 } from "react";
|
|
81
81
|
|
|
82
82
|
// src/commands.ts
|
|
@@ -547,6 +547,18 @@ 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
|
+
|
|
550
562
|
// src/ui/Markdown.tsx
|
|
551
563
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
552
564
|
function segment(seg, key) {
|
|
@@ -584,7 +596,7 @@ function hanging(key, marker, body, width, padding = 0) {
|
|
|
584
596
|
}
|
|
585
597
|
function Markdown({ text, indent = 2 }) {
|
|
586
598
|
const { stdout } = useStdout();
|
|
587
|
-
const width = Math.max(20, (stdout
|
|
599
|
+
const width = Math.max(20, streamColumns(stdout) - indent - 1);
|
|
588
600
|
const lines = text.split("\n");
|
|
589
601
|
const rows = [];
|
|
590
602
|
let inCode = false;
|
|
@@ -811,86 +823,15 @@ function EditableText({ state, mask = false, showCursor = true }) {
|
|
|
811
823
|
] });
|
|
812
824
|
}
|
|
813
825
|
|
|
814
|
-
// src/ui/focusReport.ts
|
|
815
|
-
var isFocusReport = (input) => input === "[I" || input === "[O";
|
|
816
|
-
|
|
817
|
-
// src/ui/thinkingMouse.ts
|
|
818
|
-
function parseMousePress(value) {
|
|
819
|
-
const start = value.indexOf("\x1B[<");
|
|
820
|
-
if (start < 0) return void 0;
|
|
821
|
-
const match = /^<(\d+);(\d+);(\d+)M/.exec(value.slice(start + 2));
|
|
822
|
-
if (!match) return void 0;
|
|
823
|
-
const button = Number(match[1]);
|
|
824
|
-
if (button !== 0) return void 0;
|
|
825
|
-
const x = Number(match[2]);
|
|
826
|
-
const y = Number(match[3]);
|
|
827
|
-
if (x < 1 || y < 1) return void 0;
|
|
828
|
-
return { x, y };
|
|
829
|
-
}
|
|
830
|
-
function parseCursorPosition(value) {
|
|
831
|
-
const start = value.indexOf("\x1B[");
|
|
832
|
-
if (start < 0) return void 0;
|
|
833
|
-
const match = /^(\d+);(\d+)R/.exec(value.slice(start + 2));
|
|
834
|
-
if (!match) return void 0;
|
|
835
|
-
const row = Number(match[1]);
|
|
836
|
-
const col = Number(match[2]);
|
|
837
|
-
if (row < 1 || col < 1) return void 0;
|
|
838
|
-
return { row, col };
|
|
839
|
-
}
|
|
840
|
-
function clickedThinking(click, cursorRow, rootHeight, target) {
|
|
841
|
-
if (!rootHeight || !target.width || !target.height) return false;
|
|
842
|
-
const origin = cursorRow - rootHeight + 1;
|
|
843
|
-
const row = origin + target.y;
|
|
844
|
-
const col = target.x + 1;
|
|
845
|
-
return (click.y === row || click.y === row - 1) && click.x >= col && click.x < col + Math.min(target.width, 72);
|
|
846
|
-
}
|
|
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
|
-
function hasMouseWheelSequence(chunk) {
|
|
858
|
-
return chunk.includes("\x1B[") && /\[<?6[4567];\d+;\d+[mM]/.test(chunk);
|
|
859
|
-
}
|
|
860
|
-
function isMouseControlInput(input) {
|
|
861
|
-
return /^\[<[\d;]*[mM]?$/.test(input) || /^\[(?:\d+;){2}\d+[mM]$/.test(input) || /^\[(?:\d+;)+\d*R?$/.test(input) || /^\[M[\s\S]{0,3}$/.test(input) || input.includes("\x1B[<");
|
|
862
|
-
}
|
|
863
|
-
function parseThinkingReports(value) {
|
|
864
|
-
const events = [];
|
|
865
|
-
let offset = 0;
|
|
866
|
-
while (true) {
|
|
867
|
-
const start = value.indexOf("\x1B[", offset);
|
|
868
|
-
if (start < 0) break;
|
|
869
|
-
const finish = /[a-zA-Z~]/.exec(value.slice(start + 2));
|
|
870
|
-
if (!finish) return { events, rest: value.slice(start) };
|
|
871
|
-
const end = start + 2 + finish.index + 1;
|
|
872
|
-
const raw = value.slice(start, end);
|
|
873
|
-
const press = parseMousePress(raw);
|
|
874
|
-
const cursor = parseCursorPosition(raw);
|
|
875
|
-
if (press) events.push({ type: "mouse", press });
|
|
876
|
-
else if (cursor) events.push({ type: "cursor", cursor });
|
|
877
|
-
offset = end;
|
|
878
|
-
}
|
|
879
|
-
const remaining = value.lastIndexOf("\x1B[");
|
|
880
|
-
if (remaining >= offset) return { events, rest: value.slice(remaining) };
|
|
881
|
-
return { events, rest: value.endsWith("\x1B") ? "\x1B" : "" };
|
|
882
|
-
}
|
|
883
|
-
|
|
884
826
|
// src/ui/LinePrompt.tsx
|
|
885
827
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
886
828
|
function LinePrompt({ label, mask, onSubmit, onCancel }) {
|
|
887
829
|
const [line, setLine] = useState({ value: "", cursor: 0 });
|
|
888
830
|
useInput((input, key) => {
|
|
889
|
-
if (isMouseControlInput(input)) return;
|
|
890
831
|
if (key.return) onSubmit(line.value.trim());
|
|
891
832
|
else if (key.escape) onCancel();
|
|
892
833
|
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
|
|
834
|
+
else if (!key.ctrl && !key.meta && !key.tab && !key.upArrow && !key.downArrow) {
|
|
894
835
|
const text = input.replace(/[\r\n]/g, "");
|
|
895
836
|
if (text) setLine((current) => insert(current, text));
|
|
896
837
|
}
|
|
@@ -913,16 +854,6 @@ function ListPicker({ title, items, onPick }) {
|
|
|
913
854
|
const shown = items.filter((i) => i.label.toLowerCase().includes(filter.toLowerCase()));
|
|
914
855
|
const cursor = Math.min(index, Math.max(0, shown.length - 1));
|
|
915
856
|
useInput2((input, key) => {
|
|
916
|
-
const wheel = parseMouseWheel(input);
|
|
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;
|
|
926
857
|
if (key.upArrow) setIndex(Math.max(0, cursor - 1));
|
|
927
858
|
else if (key.downArrow) setIndex(Math.min(Math.max(0, shown.length - 1), cursor + 1));
|
|
928
859
|
else if (key.pageUp) setIndex(Math.max(0, cursor - VISIBLE));
|
|
@@ -932,7 +863,7 @@ function ListPicker({ title, items, onPick }) {
|
|
|
932
863
|
else if (key.backspace || key.delete) {
|
|
933
864
|
setFilter((f) => f.slice(0, -1));
|
|
934
865
|
setIndex(0);
|
|
935
|
-
} else if (!key.ctrl && !key.meta && !key.tab && input
|
|
866
|
+
} else if (!key.ctrl && !key.meta && !key.tab && input) {
|
|
936
867
|
setFilter((f) => f + input);
|
|
937
868
|
setIndex(0);
|
|
938
869
|
}
|
|
@@ -969,16 +900,6 @@ function ModelPicker({ groups, current, onPick }) {
|
|
|
969
900
|
const clampedIndex = Math.min(index, Math.max(0, selectable.length - 1));
|
|
970
901
|
const cursor = selectable[clampedIndex] ?? -1;
|
|
971
902
|
useInput3((input, key) => {
|
|
972
|
-
const wheel = parseMouseWheel(input);
|
|
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;
|
|
982
903
|
if (key.upArrow) setIndex(Math.max(0, clampedIndex - 1));
|
|
983
904
|
else if (key.downArrow) setIndex(Math.min(Math.max(0, selectable.length - 1), clampedIndex + 1));
|
|
984
905
|
else if (key.pageUp) setIndex(Math.max(0, clampedIndex - VISIBLE2));
|
|
@@ -990,7 +911,7 @@ function ModelPicker({ groups, current, onPick }) {
|
|
|
990
911
|
else if (key.backspace || key.delete) {
|
|
991
912
|
setFilter((f) => f.slice(0, -1));
|
|
992
913
|
setIndex(0);
|
|
993
|
-
} else if (!key.ctrl && !key.meta && !key.tab && input
|
|
914
|
+
} else if (!key.ctrl && !key.meta && !key.tab && input) {
|
|
994
915
|
setFilter((f) => f + input);
|
|
995
916
|
setIndex(0);
|
|
996
917
|
}
|
|
@@ -1013,17 +934,7 @@ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
|
1013
934
|
function ProviderMenu({ entries, onPick }) {
|
|
1014
935
|
const rows = [...entries.map((e) => e.id), "custom"];
|
|
1015
936
|
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;
|
|
937
|
+
useInput4((_input, key) => {
|
|
1027
938
|
if (key.upArrow) setIndex((i) => Math.max(0, i - 1));
|
|
1028
939
|
else if (key.downArrow) setIndex((i) => Math.min(rows.length - 1, i + 1));
|
|
1029
940
|
else if (key.pageUp) setIndex((i) => Math.max(0, i - 10));
|
|
@@ -1068,16 +979,6 @@ function PermissionPrompt({
|
|
|
1068
979
|
const maxOffset = Math.max(0, diffLines.length - MAX_DIFF_LINES);
|
|
1069
980
|
const [offset, setOffset] = useState5(0);
|
|
1070
981
|
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
982
|
if (key.upArrow) {
|
|
1082
983
|
setOffset((o) => Math.max(0, o - 1));
|
|
1083
984
|
return;
|
|
@@ -1331,14 +1232,6 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
|
|
|
1331
1232
|
};
|
|
1332
1233
|
useInput6(
|
|
1333
1234
|
(input, key) => {
|
|
1334
|
-
const wheel = parseMouseWheel(input);
|
|
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;
|
|
1342
1235
|
if (suggestions.length) {
|
|
1343
1236
|
if (key.escape) {
|
|
1344
1237
|
setDismissed(true);
|
|
@@ -1451,7 +1344,7 @@ ${value.slice(line.cursor)}`, cursor: before.length });
|
|
|
1451
1344
|
if (completed !== before) edit({ value: completed + value.slice(line.cursor), cursor: completed.length });
|
|
1452
1345
|
return;
|
|
1453
1346
|
}
|
|
1454
|
-
if (key.ctrl || key.meta || key.escape || key.tab
|
|
1347
|
+
if (key.ctrl || key.meta || key.escape || key.tab) return;
|
|
1455
1348
|
const text = input.replace(/\r\n?/g, "\n");
|
|
1456
1349
|
if (text) edit((current) => insert(current, text));
|
|
1457
1350
|
},
|
|
@@ -1486,6 +1379,60 @@ function Spinner({ label, startedAt }) {
|
|
|
1486
1379
|
return /* @__PURE__ */ jsx10(Text10, { color: color(ACCENT), children: `${FRAMES[tick % FRAMES.length]} ${t("{label}\u2026 ({seconds}s \xB7 esc to cancel)", { label, seconds })}` });
|
|
1487
1380
|
}
|
|
1488
1381
|
|
|
1382
|
+
// src/ui/thinkingMouse.ts
|
|
1383
|
+
function parseMousePress(value) {
|
|
1384
|
+
const start = value.indexOf("\x1B[<");
|
|
1385
|
+
if (start < 0) return void 0;
|
|
1386
|
+
const match = /^<(\d+);(\d+);(\d+)M/.exec(value.slice(start + 2));
|
|
1387
|
+
if (!match) return void 0;
|
|
1388
|
+
const button = Number(match[1]);
|
|
1389
|
+
if (button !== 0) return void 0;
|
|
1390
|
+
const x = Number(match[2]);
|
|
1391
|
+
const y = Number(match[3]);
|
|
1392
|
+
if (x < 1 || y < 1) return void 0;
|
|
1393
|
+
return { x, y };
|
|
1394
|
+
}
|
|
1395
|
+
function parseCursorPosition(value) {
|
|
1396
|
+
const start = value.indexOf("\x1B[");
|
|
1397
|
+
if (start < 0) return void 0;
|
|
1398
|
+
const match = /^(\d+);(\d+)R/.exec(value.slice(start + 2));
|
|
1399
|
+
if (!match) return void 0;
|
|
1400
|
+
const row = Number(match[1]);
|
|
1401
|
+
const col = Number(match[2]);
|
|
1402
|
+
if (row < 1 || col < 1) return void 0;
|
|
1403
|
+
return { row, col };
|
|
1404
|
+
}
|
|
1405
|
+
function clickedThinking(click, cursorRow, rootHeight, target) {
|
|
1406
|
+
if (!rootHeight || !target.width || !target.height) return false;
|
|
1407
|
+
const origin = cursorRow - rootHeight + 1;
|
|
1408
|
+
const row = origin + target.y;
|
|
1409
|
+
const col = target.x + 1;
|
|
1410
|
+
return (click.y === row || click.y === row - 1) && click.x >= col && click.x < col + Math.min(target.width, 72);
|
|
1411
|
+
}
|
|
1412
|
+
function hasMouseWheelSequence(chunk) {
|
|
1413
|
+
return chunk.includes("\x1B[") && /\[<?6[4567];\d+;\d+[mM]/.test(chunk);
|
|
1414
|
+
}
|
|
1415
|
+
function parseThinkingReports(value) {
|
|
1416
|
+
const events = [];
|
|
1417
|
+
let offset = 0;
|
|
1418
|
+
while (true) {
|
|
1419
|
+
const start = value.indexOf("\x1B[", offset);
|
|
1420
|
+
if (start < 0) break;
|
|
1421
|
+
const finish = /[a-zA-Z~]/.exec(value.slice(start + 2));
|
|
1422
|
+
if (!finish) return { events, rest: value.slice(start) };
|
|
1423
|
+
const end = start + 2 + finish.index + 1;
|
|
1424
|
+
const raw = value.slice(start, end);
|
|
1425
|
+
const press = parseMousePress(raw);
|
|
1426
|
+
const cursor = parseCursorPosition(raw);
|
|
1427
|
+
if (press) events.push({ type: "mouse", press });
|
|
1428
|
+
else if (cursor) events.push({ type: "cursor", cursor });
|
|
1429
|
+
offset = end;
|
|
1430
|
+
}
|
|
1431
|
+
const remaining = value.lastIndexOf("\x1B[");
|
|
1432
|
+
if (remaining >= offset) return { events, rest: value.slice(remaining) };
|
|
1433
|
+
return { events, rest: value.endsWith("\x1B") ? "\x1B" : "" };
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1489
1436
|
// src/ui/StatusBar.tsx
|
|
1490
1437
|
import { Text as Text11 } from "ink";
|
|
1491
1438
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
@@ -1510,17 +1457,7 @@ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
|
1510
1457
|
var MARK = { ready: "\u2713", error: "\u2717", starting: "\u2026", off: "\u25CB" };
|
|
1511
1458
|
function McpMenu({ items, onPick }) {
|
|
1512
1459
|
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;
|
|
1460
|
+
useInput7((_input, key) => {
|
|
1524
1461
|
if (key.upArrow) setIndex((i) => Math.max(0, i - 1));
|
|
1525
1462
|
else if (key.downArrow) setIndex((i) => Math.min(items.length - 1, i + 1));
|
|
1526
1463
|
else if (key.pageUp) setIndex((i) => Math.max(0, i - 10));
|
|
@@ -1547,16 +1484,6 @@ function PlanApproval({ plan, onAnswer }) {
|
|
|
1547
1484
|
const maxOffset = Math.max(0, planLines.length - MAX_PLAN_LINES);
|
|
1548
1485
|
const [offset, setOffset] = useState9(0);
|
|
1549
1486
|
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
1487
|
if (key.upArrow) {
|
|
1561
1488
|
setOffset((o) => Math.max(0, o - 1));
|
|
1562
1489
|
return;
|
|
@@ -1864,18 +1791,19 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
|
|
|
1864
1791
|
const lastUserIdx = transcript.done.findLastIndex((e) => e.kind === "user");
|
|
1865
1792
|
const { stdin } = useStdin();
|
|
1866
1793
|
const { stdout } = useStdout2();
|
|
1867
|
-
const
|
|
1868
|
-
const
|
|
1794
|
+
const realStdout = isRealTty(stdout);
|
|
1795
|
+
const { rows: windowRows } = useWindowSize();
|
|
1796
|
+
const maxLiveLines = Math.max(8, windowRows - 10);
|
|
1869
1797
|
const maxSplitIdxRef = useRef2(0);
|
|
1870
1798
|
const refreshStatic = useCallback(() => {
|
|
1871
|
-
if (
|
|
1799
|
+
if (realStdout) {
|
|
1872
1800
|
stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
1873
1801
|
}
|
|
1874
1802
|
maxSplitIdxRef.current = 0;
|
|
1875
1803
|
setStaticKey((k2) => k2 + 1);
|
|
1876
|
-
}, [stdout]);
|
|
1804
|
+
}, [stdout, realStdout]);
|
|
1877
1805
|
let splitIdx = Math.max(maxSplitIdxRef.current, lastUserIdx > 0 ? lastUserIdx : 0);
|
|
1878
|
-
if (
|
|
1806
|
+
if (realStdout) {
|
|
1879
1807
|
const entryLines = (e) => {
|
|
1880
1808
|
if (e.kind === "thinking") return showThinking ? Math.min(maxLiveLines, e.text.split("\n").length + 2) : 2;
|
|
1881
1809
|
if (e.kind === "tool") return showToolOutput ? Math.min(maxLiveLines, (e.output ?? e.display ?? "").split("\n").length + 2) : 5;
|
|
@@ -2575,7 +2503,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2575
2503
|
}
|
|
2576
2504
|
}, [initialPrompt, submit]);
|
|
2577
2505
|
useEffect3(() => {
|
|
2578
|
-
if (!
|
|
2506
|
+
if (!isRealTty(stdout)) return;
|
|
2579
2507
|
stdout.write("\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?2004h");
|
|
2580
2508
|
return () => {
|
|
2581
2509
|
stdout.write("\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?2004l");
|
|
@@ -2583,7 +2511,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2583
2511
|
}, [stdout]);
|
|
2584
2512
|
useEffect3(() => {
|
|
2585
2513
|
const modalOpen = !!(pending || planAsk || picker || listPicker || mcpMenu || providerMenu || prompt);
|
|
2586
|
-
if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || modalOpen || !stdin
|
|
2514
|
+
if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || modalOpen || !isTtyStream(stdin) || !isTtyStream(stdout)) return;
|
|
2587
2515
|
let click;
|
|
2588
2516
|
let mouseBuffer = "";
|
|
2589
2517
|
let wheelTimer;
|
|
@@ -2761,7 +2689,7 @@ ARGUMENTS: ${slash.args}`);
|
|
|
2761
2689
|
if (!text) return null;
|
|
2762
2690
|
const allLines = text.split("\n");
|
|
2763
2691
|
const lines = allLines.length;
|
|
2764
|
-
const shownText = isLive &&
|
|
2692
|
+
const shownText = isLive && realStdout && allLines.length > maxLiveLines ? `\u2026 (${allLines.length - maxLiveLines} lines above) \u2026
|
|
2765
2693
|
${allLines.slice(-maxLiveLines).join("\n")}` : text;
|
|
2766
2694
|
const isTarget = e.id === lastThinkingEntryId;
|
|
2767
2695
|
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.14",
|
|
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;
|