@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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var VERSION = true ? "0.4.13" : "0.0.0-dev";
4
+ var VERSION = true ? "0.4.15" : "0.0.0-dev";
5
5
 
6
6
  export {
7
7
  VERSION
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-F6NNUUF3.js";
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-PXXUITFS.js");
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-6NK2IR6R.js");
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-PXXUITFS.js");
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-IMCUSB6Q.js");
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(
@@ -8,7 +8,7 @@ import "./chunk-7GM6NN5E.js";
8
8
  import "./chunk-PSO7R5AD.js";
9
9
  import {
10
10
  VERSION
11
- } from "./chunk-F6NNUUF3.js";
11
+ } from "./chunk-2PAVSETH.js";
12
12
  import {
13
13
  LOOPBACK_BIND,
14
14
  MAX_FRAME_BYTES,
@@ -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
- /** 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
- /** 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
- /** Ink useInput receives these control reports too; they must not enter the prompt. */
23
- export declare function isMouseControlInput(input: string): boolean;
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<{
@@ -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?.columns ?? 80) - indent - 1);
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 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[<");
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 (isMouseControlInput(input)) return;
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 && !isFocusReport(input)) {
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
- 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;
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 && !isFocusReport(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
- 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;
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 && !isFocusReport(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((input, key) => {
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
- 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;
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 || isFocusReport(input)) return;
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((input, key) => {
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 isRealTty = Boolean(stdout?.isTTY && "fd" in stdout);
1868
- const maxLiveLines = Math.max(8, (stdout?.rows ?? 24) - 10);
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 (stdout?.isTTY && "fd" in stdout) {
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 (isRealTty) {
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 (!stdout?.isTTY || !("fd" in stdout)) return;
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.isTTY || !stdout.isTTY) return;
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 capLiveMarkdown = (raw) => {
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 ? capLiveMarkdown(e.text) : e.text;
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 && isRealTty && allLines.length > maxLiveLines ? `\u2026 (${allLines.length - maxLiveLines} lines above) \u2026
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(
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-F6NNUUF3.js";
4
+ } from "./chunk-2PAVSETH.js";
5
5
  import {
6
6
  t
7
7
  } from "./chunk-R754XIBJ.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.13",
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": "^7.1.1",
30
+ "ink": "^8.0.0",
31
31
  "openai": "^7.27.0",
32
32
  "react": "^19.3.0",
33
33
  "undici": "^8.12.1",
@@ -1 +0,0 @@
1
- export declare const isFocusReport: (input: string) => boolean;