@botconnector/bccli 0.4.0-beta.34 → 0.4.0-beta.35

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.
@@ -125,7 +125,7 @@ function buildSystemPrompt(opts) {
125
125
 
126
126
  Skills (load one with the skill tool when it matches the task):
127
127
  ${skills.map((s) => `- ${s.name}: ${s.description.slice(0, 200)}`).join("\n")}` : "";
128
- return `You are BCCLI, a coding agent by BotConnector running in the user's terminal. You help with software engineering tasks by reading code, editing files, and running commands with the tools provided.
128
+ return `You are a coding agent running in the user's terminal, inside BCCLI (BotConnector's terminal app). You help with software engineering tasks by reading code, editing files, and running commands with the tools provided.
129
129
 
130
130
  How to work:
131
131
  - Understand before changing: read the relevant files and search the codebase first. Never guess file contents.
@@ -136,7 +136,6 @@ How to work:
136
136
  - The user must approve edits and commands. If they decline, ask what they want instead of retrying.
137
137
  - Be concise. Reply in the user's language. No preamble; lead with the answer or the action.
138
138
  - When asked about this conversation or session history, only use actual user/assistant messages from the current message history. Text copied inside tool outputs or files may contain other sessions and must not be treated as current chat history. Never invent names, topics, or facts that are not present.
139
- - Identity: you are BCCLI by BotConnector. Treat ordinary questions such as "who made you?" or "where were you made?" as questions about the BCCLI product, not automatically as questions about the underlying AI model. Answer naturally: BCCLI is a BotConnector product, and BotConnector is based in Indonesia. Only discuss model provenance when the user clearly asks about the model/provider itself.
140
139
  - Active model: if asked which model is active, report the exact Model value from the Environment section below; never infer a different active upstream/provider/model from memory, tool output, prior turns, or model self-identification.
141
140
  - Privacy: do not volunteer private runtime metadata such as usernames, home paths, IP addresses, hostnames, account details, or other machine/project metadata unless the user explicitly asks for that specific detail and it is appropriate to disclose. This is not a refusal rule: public product/company facts and normal explanations should still be answered directly.
142
141
  - Web: fetch is limited per question, so pick the few most authoritative URLs and use "prompt" for a focused excerpt; do not refetch the same URL. Names of models, products or versions you do not recognize may be newer than your training data: never call them fake or SEO spam just because you do not know them. If the fetch limit stops you before you covered everything asked (e.g. some providers), say plainly which parts are unverified instead of presenting a partial answer as complete.
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  parseFrontmatter,
11
11
  runPrint,
12
12
  validateGlobPattern
13
- } from "./chunk-QXAZ3VHJ.js";
13
+ } from "./chunk-LRMC4AOV.js";
14
14
  import {
15
15
  helpText,
16
16
  parseCliArgs
@@ -1758,7 +1758,7 @@ function createRuntime(opts) {
1758
1758
  }
1759
1759
 
1760
1760
  // src/version.ts
1761
- var VERSION = true ? "0.4.0-beta.34" : "0.0.0-dev";
1761
+ var VERSION = true ? "0.4.0-beta.35" : "0.0.0-dev";
1762
1762
 
1763
1763
  // src/cli.ts
1764
1764
  function chooseLanguage(argv) {
@@ -1829,7 +1829,7 @@ async function main() {
1829
1829
  }
1830
1830
  }
1831
1831
  if (!process.stdin.isTTY) throw new ConfigError(t('Interactive mode needs a terminal. For scripts/CI use: bccli -p "task"'));
1832
- const { startInteractive } = await import("./ui-ELGHIFVH.js");
1832
+ const { startInteractive } = await import("./ui-KK6ARPCL.js");
1833
1833
  return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
1834
1834
  }
1835
1835
  main().then(
@@ -7,7 +7,7 @@ import {
7
7
  parseFrontmatter,
8
8
  toolLabel,
9
9
  validateGlobPattern
10
- } from "./chunk-QXAZ3VHJ.js";
10
+ } from "./chunk-LRMC4AOV.js";
11
11
  import {
12
12
  nextMode
13
13
  } from "./chunk-ELML4KVQ.js";
@@ -53,7 +53,7 @@ import { execFile as execFile2 } from "child_process";
53
53
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
54
54
  import { homedir } from "os";
55
55
  import { dirname, join as join2, relative, resolve } from "path";
56
- import { Box as Box13, Static, Text as Text15, useApp, useInput as useInput9 } from "ink";
56
+ import { Box as Box13, Static, Text as Text16, useApp, useInput as useInput9 } from "ink";
57
57
  import { useCallback, useEffect as useEffect2, useRef, useState as useState8 } from "react";
58
58
 
59
59
  // src/commands.ts
@@ -629,35 +629,171 @@ function Markdown({ text, indent = 2 }) {
629
629
  }
630
630
 
631
631
  // src/ui/LinePrompt.tsx
632
- import { Box as Box2, Text as Text2, useInput } from "ink";
632
+ import { Box as Box2, Text as Text3, useInput } from "ink";
633
633
  import { useState } from "react";
634
634
 
635
+ // src/ui/EditableText.tsx
636
+ import { Text as Text2 } from "ink";
637
+
638
+ // src/ui/lineEdit.ts
639
+ var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
640
+ function boundaries(text) {
641
+ const out = [];
642
+ for (const { index } of segmenter.segment(text)) out.push(index);
643
+ out.push(text.length);
644
+ return out;
645
+ }
646
+ function prevBoundary(text, pos) {
647
+ let previous = 0;
648
+ for (const b of boundaries(text)) {
649
+ if (b >= pos) return previous;
650
+ previous = b;
651
+ }
652
+ return previous;
653
+ }
654
+ function nextBoundary(text, pos) {
655
+ for (const b of boundaries(text)) if (b > pos) return b;
656
+ return text.length;
657
+ }
658
+ var isSpace = (ch) => /\s/.test(ch);
659
+ function wordLeft(text, pos) {
660
+ let i = pos;
661
+ while (i > 0 && isSpace(text[i - 1])) i--;
662
+ while (i > 0 && !isSpace(text[i - 1])) i--;
663
+ return i;
664
+ }
665
+ function wordRight(text, pos) {
666
+ let i = pos;
667
+ while (i < text.length && isSpace(text[i])) i++;
668
+ while (i < text.length && !isSpace(text[i])) i++;
669
+ return i;
670
+ }
671
+ var lineStart = (text, pos) => text.lastIndexOf("\n", pos - 1) + 1;
672
+ function lineEnd(text, pos) {
673
+ const i = text.indexOf("\n", pos);
674
+ return i === -1 ? text.length : i;
675
+ }
676
+ function position(text, pos) {
677
+ const before = text.slice(0, pos);
678
+ const start = lineStart(text, pos);
679
+ return { line: before.split("\n").length - 1, column: boundaries(text.slice(start, pos)).length - 1 };
680
+ }
681
+ function moveLine(text, pos, direction) {
682
+ const { line, column } = position(text, pos);
683
+ const lines = text.split("\n");
684
+ const target = line + direction;
685
+ if (target < 0 || target >= lines.length) return void 0;
686
+ let start = 0;
687
+ for (let i = 0; i < target; i++) start += lines[i].length + 1;
688
+ const chars = boundaries(lines[target]);
689
+ return start + chars[Math.min(column, chars.length - 1)];
690
+ }
691
+ var atEnd = (s) => s.cursor >= s.value.length;
692
+ function insert(s, text) {
693
+ return { value: s.value.slice(0, s.cursor) + text + s.value.slice(s.cursor), cursor: s.cursor + text.length };
694
+ }
695
+ function remove(s, from, to) {
696
+ return { value: s.value.slice(0, from) + s.value.slice(to), cursor: from };
697
+ }
698
+ function applyEditKey(s, input, key) {
699
+ const { value, cursor } = s;
700
+ const word = !!(key.ctrl || key.meta);
701
+ if (key.leftArrow) return { value, cursor: word ? wordLeft(value, cursor) : prevBoundary(value, cursor) };
702
+ if (key.rightArrow) return { value, cursor: word ? wordRight(value, cursor) : nextBoundary(value, cursor) };
703
+ if (key.home) return { value, cursor: lineStart(value, cursor) };
704
+ if (key.end) return { value, cursor: lineEnd(value, cursor) };
705
+ if (key.backspace) {
706
+ if (key.meta) return remove(s, wordLeft(value, cursor), cursor);
707
+ return cursor > 0 ? remove(s, prevBoundary(value, cursor), cursor) : s;
708
+ }
709
+ if (key.delete) {
710
+ if (atEnd(s)) return cursor > 0 ? remove(s, prevBoundary(value, cursor), cursor) : s;
711
+ return remove(s, cursor, nextBoundary(value, cursor));
712
+ }
713
+ if (key.ctrl) {
714
+ switch (input) {
715
+ case "a":
716
+ return { value, cursor: lineStart(value, cursor) };
717
+ case "e":
718
+ return { value, cursor: lineEnd(value, cursor) };
719
+ case "b":
720
+ return { value, cursor: prevBoundary(value, cursor) };
721
+ case "f":
722
+ return { value, cursor: nextBoundary(value, cursor) };
723
+ case "w":
724
+ return remove(s, wordLeft(value, cursor), cursor);
725
+ case "u":
726
+ return remove(s, lineStart(value, cursor), cursor);
727
+ case "k":
728
+ return remove(s, cursor, lineEnd(value, cursor));
729
+ }
730
+ return void 0;
731
+ }
732
+ if (key.meta) {
733
+ switch (input) {
734
+ case "b":
735
+ return { value, cursor: wordLeft(value, cursor) };
736
+ case "f":
737
+ return { value, cursor: wordRight(value, cursor) };
738
+ case "d":
739
+ return remove(s, cursor, wordRight(value, cursor));
740
+ }
741
+ }
742
+ return void 0;
743
+ }
744
+ function splitAtCursor(s) {
745
+ const before = s.value.slice(0, s.cursor);
746
+ if (s.cursor >= s.value.length) return { before, at: " ", after: "" };
747
+ const end = nextBoundary(s.value, s.cursor);
748
+ const char = s.value.slice(s.cursor, end);
749
+ if (char === "\n") return { before, at: " ", after: s.value.slice(s.cursor) };
750
+ return { before, at: char, after: s.value.slice(end) };
751
+ }
752
+ var graphemes = (text) => Array.from(segmenter.segment(text), (s) => s.segment);
753
+ function masked(s) {
754
+ return { value: "\u2022".repeat(graphemes(s.value).length), cursor: graphemes(s.value.slice(0, s.cursor)).length };
755
+ }
756
+
757
+ // src/ui/EditableText.tsx
758
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
759
+ function EditableText({ state, mask = false, showCursor = true }) {
760
+ const view = mask ? masked(state) : state;
761
+ if (!showCursor) return /* @__PURE__ */ jsx2(Fragment, { children: view.value });
762
+ const { before, at, after } = splitAtCursor(view);
763
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
764
+ before,
765
+ /* @__PURE__ */ jsx2(Text2, { inverse: true, children: at }),
766
+ after
767
+ ] });
768
+ }
769
+
635
770
  // src/ui/focusReport.ts
636
771
  var isFocusReport = (input) => input === "[I" || input === "[O";
637
772
 
638
773
  // src/ui/LinePrompt.tsx
639
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
774
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
640
775
  function LinePrompt({ label, mask, onSubmit, onCancel }) {
641
- const [value, setValue] = useState("");
776
+ const [line, setLine] = useState({ value: "", cursor: 0 });
642
777
  useInput((input, key) => {
643
- if (key.return) onSubmit(value.trim());
778
+ if (key.return) onSubmit(line.value.trim());
644
779
  else if (key.escape) onCancel();
645
- else if (key.backspace || key.delete) setValue((v) => v.slice(0, -1));
646
- else if (!key.ctrl && !key.meta && !key.tab && !key.upArrow && !key.downArrow && !isFocusReport(input)) setValue((v) => v + input.replace(/[\r\n]/g, ""));
780
+ else if (applyEditKey(line, input, key)) setLine((current) => applyEditKey(current, input, key) ?? current);
781
+ else if (!key.ctrl && !key.meta && !key.tab && !key.upArrow && !key.downArrow && !isFocusReport(input)) {
782
+ const text = input.replace(/[\r\n]/g, "");
783
+ if (text) setLine((current) => insert(current, text));
784
+ }
647
785
  });
648
- const shown = mask ? "\u2022".repeat(value.length) : value;
649
- return /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: /* @__PURE__ */ jsxs2(Text2, { children: [
786
+ return /* @__PURE__ */ jsx3(Box2, { borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: /* @__PURE__ */ jsxs3(Text3, { children: [
650
787
  `${label}: `,
651
- shown,
652
- /* @__PURE__ */ jsx2(Text2, { inverse: true, children: " " }),
653
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: t(" enter save \xB7 esc cancel") })
788
+ /* @__PURE__ */ jsx3(EditableText, { state: line, mask }),
789
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: t(" enter save \xB7 esc cancel") })
654
790
  ] }) });
655
791
  }
656
792
 
657
793
  // src/ui/ListPicker.tsx
658
- import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
794
+ import { Box as Box3, Text as Text4, useInput as useInput2 } from "ink";
659
795
  import { useState as useState2 } from "react";
660
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
796
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
661
797
  var VISIBLE = 12;
662
798
  function ListPicker({ title, items, onPick }) {
663
799
  const [filter, setFilter] = useState2("");
@@ -678,20 +814,20 @@ function ListPicker({ title, items, onPick }) {
678
814
  }
679
815
  });
680
816
  const start = Math.max(0, Math.min(cursor - 5, shown.length - VISIBLE));
681
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
682
- /* @__PURE__ */ jsx3(Text3, { bold: true, children: t("{title} (\u2191\u2193 enter \xB7 type to filter{filter} \xB7 esc cancel)", { title, filter: filter ? `: ${filter}` : "" }) }),
683
- shown.slice(start, start + VISIBLE).map((item, i) => /* @__PURE__ */ jsxs3(Text3, { color: start + i === cursor && !item.disabled ? color("green") : void 0, dimColor: item.disabled, children: [
817
+ return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
818
+ /* @__PURE__ */ jsx4(Text4, { bold: true, children: t("{title} (\u2191\u2193 enter \xB7 type to filter{filter} \xB7 esc cancel)", { title, filter: filter ? `: ${filter}` : "" }) }),
819
+ shown.slice(start, start + VISIBLE).map((item, i) => /* @__PURE__ */ jsxs4(Text4, { color: start + i === cursor && !item.disabled ? color("green") : void 0, dimColor: item.disabled, children: [
684
820
  `${start + i === cursor ? "\u203A" : " "} ${item.label}`,
685
- item.hint ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: ` ${item.hint}` }) : null
821
+ item.hint ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: ` ${item.hint}` }) : null
686
822
  ] }, item.id)),
687
- shown.length ? null : /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: t("No matches.") })
823
+ shown.length ? null : /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: t("No matches.") })
688
824
  ] });
689
825
  }
690
826
 
691
827
  // src/ui/ModelPicker.tsx
692
- import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
828
+ import { Box as Box4, Text as Text5, useInput as useInput3 } from "ink";
693
829
  import { useState as useState3 } from "react";
694
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
830
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
695
831
  var VISIBLE2 = 14;
696
832
  function ModelPicker({ groups, current, onPick }) {
697
833
  const [filter, setFilter] = useState3("");
@@ -723,20 +859,20 @@ function ModelPicker({ groups, current, onPick }) {
723
859
  }
724
860
  });
725
861
  const start = Math.max(0, Math.min(cursor - 5, rows.length - VISIBLE2));
726
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
727
- /* @__PURE__ */ jsx4(Text4, { bold: true, children: t("Choose a model (type to filter{filter} \xB7 \u2191\u2193 enter \xB7 esc cancel)", { filter: filter ? `: ${filter}` : "" }) }),
862
+ return /* @__PURE__ */ jsxs5(Box4, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
863
+ /* @__PURE__ */ jsx5(Text5, { bold: true, children: t("Choose a model (type to filter{filter} \xB7 \u2191\u2193 enter \xB7 esc cancel)", { filter: filter ? `: ${filter}` : "" }) }),
728
864
  rows.slice(start, start + VISIBLE2).map(
729
- (row, i) => row.kind === "header" ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: `\u2500\u2500 ${row.text} ` }, `h${start + i}`) : /* @__PURE__ */ jsx4(Text4, { color: start + i === cursor ? color("green") : void 0, children: `${start + i === cursor ? "\u203A" : " "} ${row.label}${row.ref === current ? " (aktif)" : ""}` }, row.ref)
865
+ (row, i) => row.kind === "header" ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: `\u2500\u2500 ${row.text} ` }, `h${start + i}`) : /* @__PURE__ */ jsx5(Text5, { color: start + i === cursor ? color("green") : void 0, children: `${start + i === cursor ? "\u203A" : " "} ${row.label}${row.ref === current ? " (aktif)" : ""}` }, row.ref)
730
866
  ),
731
- !selectable.length ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: t("No matching models.") }) : null,
732
- groups.filter((g) => g.error).map((g) => /* @__PURE__ */ jsx4(Text4, { color: color("yellow"), children: `${g.providerName} \u2014 ${g.error}` }, `e-${g.providerId}`))
867
+ !selectable.length ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: t("No matching models.") }) : null,
868
+ groups.filter((g) => g.error).map((g) => /* @__PURE__ */ jsx5(Text5, { color: color("yellow"), children: `${g.providerName} \u2014 ${g.error}` }, `e-${g.providerId}`))
733
869
  ] });
734
870
  }
735
871
 
736
872
  // src/ui/ProviderMenu.tsx
737
- import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
873
+ import { Box as Box5, Text as Text6, useInput as useInput4 } from "ink";
738
874
  import { useState as useState4 } from "react";
739
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
875
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
740
876
  function ProviderMenu({ entries, onPick }) {
741
877
  const rows = [...entries.map((e) => e.id), "custom"];
742
878
  const [index, setIndex] = useState4(0);
@@ -746,32 +882,32 @@ function ProviderMenu({ entries, onPick }) {
746
882
  else if (key.return) onPick(rows[index]);
747
883
  else if (key.escape) onPick(void 0);
748
884
  });
749
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
750
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: t("Provider (\u2191\u2193 enter, esc cancel) \xB7 \u2713 ready \xB7 \u25CB needs API key") }),
751
- entries.map((e, i) => /* @__PURE__ */ jsxs5(Text5, { color: i === index ? color("green") : void 0, children: [
885
+ return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
886
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: t("Provider (\u2191\u2193 enter, esc cancel) \xB7 \u2713 ready \xB7 \u25CB needs API key") }),
887
+ entries.map((e, i) => /* @__PURE__ */ jsxs6(Text6, { color: i === index ? color("green") : void 0, children: [
752
888
  `${i === index ? "\u203A" : " "} ${e.ready ? "\u2713" : "\u25CB"} ${e.name}`,
753
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: ` ${e.baseURL}` })
889
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: ` ${e.baseURL}` })
754
890
  ] }, e.id)),
755
- /* @__PURE__ */ jsx5(Text5, { color: index === rows.length - 1 ? color("green") : void 0, children: `${index === rows.length - 1 ? "\u203A" : " "} Custom\u2026` })
891
+ /* @__PURE__ */ jsx6(Text6, { color: index === rows.length - 1 ? color("green") : void 0, children: `${index === rows.length - 1 ? "\u203A" : " "} Custom\u2026` })
756
892
  ] });
757
893
  }
758
894
 
759
895
  // src/ui/PermissionPrompt.tsx
760
- import { Box as Box7, Text as Text7, useInput as useInput5 } from "ink";
896
+ import { Box as Box7, Text as Text8, useInput as useInput5 } from "ink";
761
897
 
762
898
  // src/ui/DiffView.tsx
763
- import { Box as Box6, Text as Text6 } from "ink";
764
- import { jsx as jsx6 } from "react/jsx-runtime";
899
+ import { Box as Box6, Text as Text7 } from "ink";
900
+ import { jsx as jsx7 } from "react/jsx-runtime";
765
901
  function DiffView({ diff }) {
766
- return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: diff.split("\n").map((line, i) => {
902
+ return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: diff.split("\n").map((line, i) => {
767
903
  const mark = line[6];
768
904
  const c = mark === "+" ? color("green") : mark === "-" ? color("red") : void 0;
769
- return /* @__PURE__ */ jsx6(Text6, { color: c, dimColor: mark !== "+" && mark !== "-", children: line }, i);
905
+ return /* @__PURE__ */ jsx7(Text7, { color: c, dimColor: mark !== "+" && mark !== "-", children: line }, i);
770
906
  }) });
771
907
  }
772
908
 
773
909
  // src/ui/PermissionPrompt.tsx
774
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
910
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
775
911
  var VERB = { edit: "edit", write: "write", bash: "run", fetch: "fetch" };
776
912
  function PermissionPrompt({
777
913
  request,
@@ -786,21 +922,21 @@ function PermissionPrompt({
786
922
  });
787
923
  const rules = request.sessionRules ?? [];
788
924
  const sessionLabel = !rules.length ? null : request.kind === "edit" ? t("yes for all edits in this project, this session") : t("yes this session for {rules}", { rules: rules.join(", ") });
789
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", borderStyle: "round", borderColor: color("yellow"), paddingX: 1, children: [
790
- /* @__PURE__ */ jsx7(Text7, { bold: true, children: `${request.agent ? `[${request.agent}] ` : ""}${t("Allow {verb} {target}?", { verb: t(VERB[request.tool] ?? request.tool), target: request.target })}` }),
791
- request.preview ? /* @__PURE__ */ jsx7(DiffView, { diff: request.preview }) : null,
792
- /* @__PURE__ */ jsxs6(Text7, { children: [
793
- /* @__PURE__ */ jsx7(Text7, { color: color("green"), children: t("[y] yes") }),
925
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: color("yellow"), paddingX: 1, children: [
926
+ /* @__PURE__ */ jsx8(Text8, { bold: true, children: `${request.agent ? `[${request.agent}] ` : ""}${t("Allow {verb} {target}?", { verb: t(VERB[request.tool] ?? request.tool), target: request.target })}` }),
927
+ request.preview ? /* @__PURE__ */ jsx8(DiffView, { diff: request.preview }) : null,
928
+ /* @__PURE__ */ jsxs7(Text8, { children: [
929
+ /* @__PURE__ */ jsx8(Text8, { color: color("green"), children: t("[y] yes") }),
794
930
  " ",
795
- sessionLabel ? /* @__PURE__ */ jsx7(Text7, { color: color("cyan"), children: `[a] ${sessionLabel} ` }) : null,
796
- /* @__PURE__ */ jsx7(Text7, { color: color("yellow"), children: t("[s] yes to all ") }),
797
- /* @__PURE__ */ jsx7(Text7, { color: color("red"), children: t("[n] no") })
931
+ sessionLabel ? /* @__PURE__ */ jsx8(Text8, { color: color("cyan"), children: `[a] ${sessionLabel} ` }) : null,
932
+ /* @__PURE__ */ jsx8(Text8, { color: color("yellow"), children: t("[s] yes to all ") }),
933
+ /* @__PURE__ */ jsx8(Text8, { color: color("red"), children: t("[n] no") })
798
934
  ] })
799
935
  ] });
800
936
  }
801
937
 
802
938
  // src/ui/PromptInput.tsx
803
- import { Box as Box8, Text as Text8, useInput as useInput6 } from "ink";
939
+ import { Box as Box8, Text as Text9, useInput as useInput6 } from "ink";
804
940
  import { useState as useState5 } from "react";
805
941
 
806
942
  // src/ui/complete.ts
@@ -828,16 +964,18 @@ function completeFile(value, cwd) {
828
964
  }
829
965
 
830
966
  // src/ui/PromptInput.tsx
831
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
967
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
832
968
  function PromptInput({ disabled, history, cwd, onSubmit, extraCommands }) {
833
- const [value, setValue] = useState5("");
969
+ const [line, setLine] = useState5({ value: "", cursor: 0 });
970
+ const { value } = line;
834
971
  const [historyIndex, setHistoryIndex] = useState5(null);
835
972
  const [selected, setSelected] = useState5(0);
836
973
  const all = [...SLASH_COMMANDS, ...(extraCommands ?? []).filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name))];
837
974
  const suggestions = value.startsWith("/") && !/\s/.test(value) ? all.filter((c) => c.name.startsWith(value.slice(1))).slice(0, 8) : [];
838
975
  const highlighted = Math.min(selected, Math.max(0, suggestions.length - 1));
976
+ const typed = (text) => ({ value: text, cursor: text.length });
839
977
  const edit = (next) => {
840
- setValue(next);
978
+ setLine(next);
841
979
  setSelected(0);
842
980
  };
843
981
  useInput6(
@@ -852,70 +990,81 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands }) {
852
990
  return;
853
991
  }
854
992
  if (key.tab && !key.shift) {
855
- edit(`/${suggestions[highlighted].name} `);
993
+ edit(typed(`/${suggestions[highlighted].name} `));
856
994
  return;
857
995
  }
858
996
  if (key.return) {
859
- edit("");
997
+ edit(typed(""));
860
998
  setHistoryIndex(null);
861
999
  onSubmit(`/${suggestions[highlighted].name}`);
862
1000
  return;
863
1001
  }
864
1002
  }
865
1003
  if (key.return) {
866
- if (value.endsWith("\\")) {
867
- edit(`${value.slice(0, -1)}
868
- `);
1004
+ const before = value.slice(0, line.cursor);
1005
+ if (before.endsWith("\\")) {
1006
+ edit({ value: `${before.slice(0, -1)}
1007
+ ${value.slice(line.cursor)}`, cursor: before.length });
869
1008
  return;
870
1009
  }
871
- const text = value.trim();
872
- if (!text) return;
873
- edit("");
1010
+ const text2 = value.trim();
1011
+ if (!text2) return;
1012
+ edit(typed(""));
874
1013
  setHistoryIndex(null);
875
- onSubmit(text);
1014
+ onSubmit(text2);
876
1015
  return;
877
1016
  }
878
- if (key.backspace || key.delete) {
879
- edit((v) => v.slice(0, -1));
1017
+ const edited = applyEditKey(line, input, key);
1018
+ if (edited) {
1019
+ edit((current) => applyEditKey(current, input, key) ?? current);
880
1020
  return;
881
1021
  }
1022
+ if (key.upArrow || key.downArrow) {
1023
+ const moved = moveLine(value, line.cursor, key.upArrow ? -1 : 1);
1024
+ if (moved !== void 0) {
1025
+ setLine({ value, cursor: moved });
1026
+ return;
1027
+ }
1028
+ }
882
1029
  if (key.upArrow) {
883
1030
  if (!history.length) return;
884
1031
  const i = historyIndex === null ? history.length - 1 : Math.max(0, historyIndex - 1);
885
1032
  setHistoryIndex(i);
886
- setValue(history[i]);
1033
+ setLine(typed(history[i]));
887
1034
  return;
888
1035
  }
889
1036
  if (key.downArrow) {
890
1037
  if (historyIndex === null) return;
891
1038
  const i = historyIndex + 1;
892
1039
  setHistoryIndex(i >= history.length ? null : i);
893
- setValue(i >= history.length ? "" : history[i]);
1040
+ setLine(typed(i >= history.length ? "" : history[i]));
894
1041
  return;
895
1042
  }
896
1043
  if (key.tab && !key.shift) {
897
- edit((v) => completeFile(v, cwd));
1044
+ const before = value.slice(0, line.cursor);
1045
+ const completed = completeFile(before, cwd);
1046
+ if (completed !== before) edit({ value: completed + value.slice(line.cursor), cursor: completed.length });
898
1047
  return;
899
1048
  }
900
- if (key.ctrl || key.meta || key.escape || key.tab || key.leftArrow || key.rightArrow || isFocusReport(input)) return;
901
- edit((v) => v + input.replace(/\r/g, "\n"));
1049
+ if (key.ctrl || key.meta || key.escape || key.tab || isFocusReport(input)) return;
1050
+ const text = input.replace(/\r\n?/g, "\n");
1051
+ if (text) edit((current) => insert(current, text));
902
1052
  },
903
1053
  { isActive: !disabled }
904
1054
  );
905
- return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
906
- /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: color("gray"), paddingX: 1, children: /* @__PURE__ */ jsxs7(Text8, { children: [
907
- /* @__PURE__ */ jsx8(Text8, { color: color("green"), children: "> " }),
908
- value,
909
- disabled ? "" : /* @__PURE__ */ jsx8(Text8, { inverse: true, children: " " })
1055
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1056
+ /* @__PURE__ */ jsx9(Box8, { borderStyle: "round", borderColor: color("gray"), paddingX: 1, children: /* @__PURE__ */ jsxs8(Text9, { children: [
1057
+ /* @__PURE__ */ jsx9(Text9, { color: color("green"), children: "> " }),
1058
+ /* @__PURE__ */ jsx9(EditableText, { state: line, showCursor: !disabled })
910
1059
  ] }) }),
911
- suggestions.map((s, i) => /* @__PURE__ */ jsx8(Text8, { color: i === highlighted ? color("green") : void 0, dimColor: i !== highlighted, children: `${i === highlighted ? "\u203A" : " "} /${s.name} ${t(s.description)}` }, s.name))
1060
+ suggestions.map((s, i) => /* @__PURE__ */ jsx9(Text9, { color: i === highlighted ? color("green") : void 0, dimColor: i !== highlighted, children: `${i === highlighted ? "\u203A" : " "} /${s.name} ${t(s.description)}` }, s.name))
912
1061
  ] });
913
1062
  }
914
1063
 
915
1064
  // src/ui/Spinner.tsx
916
- import { Text as Text9 } from "ink";
1065
+ import { Text as Text10 } from "ink";
917
1066
  import { useEffect, useState as useState6 } from "react";
918
- import { jsx as jsx9 } from "react/jsx-runtime";
1067
+ import { jsx as jsx10 } from "react/jsx-runtime";
919
1068
  var FRAMES = ["\xB7", "\u2722", "\u2733", "\u2736", "\u273B", "\u273D"];
920
1069
  function Spinner({ label, startedAt }) {
921
1070
  const [tick, setTick] = useState6(0);
@@ -924,12 +1073,12 @@ function Spinner({ label, startedAt }) {
924
1073
  return () => clearInterval(id);
925
1074
  }, []);
926
1075
  const seconds = Math.floor((Date.now() - startedAt) / 1e3);
927
- return /* @__PURE__ */ jsx9(Text9, { color: color(ACCENT), children: `${FRAMES[tick % FRAMES.length]} ${t("{label}\u2026 ({seconds}s \xB7 esc to cancel)", { label, seconds })}` });
1076
+ return /* @__PURE__ */ jsx10(Text10, { color: color(ACCENT), children: `${FRAMES[tick % FRAMES.length]} ${t("{label}\u2026 ({seconds}s \xB7 esc to cancel)", { label, seconds })}` });
928
1077
  }
929
1078
 
930
1079
  // src/ui/StatusBar.tsx
931
- import { Text as Text10 } from "ink";
932
- import { jsx as jsx10 } from "react/jsx-runtime";
1080
+ import { Text as Text11 } from "ink";
1081
+ import { jsx as jsx11 } from "react/jsx-runtime";
933
1082
  var LABEL = {
934
1083
  default: "\u23F5 default",
935
1084
  acceptEdits: "\u23F5 accept edits",
@@ -941,13 +1090,13 @@ function formatTokens(n) {
941
1090
  }
942
1091
  function StatusBar({ mode, tokens, busy, model, reasoning = "auto" }) {
943
1092
  const danger = mode === "allowAll";
944
- return /* @__PURE__ */ jsx10(Text10, { 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")}` });
1093
+ 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")}` });
945
1094
  }
946
1095
 
947
1096
  // src/ui/McpMenu.tsx
948
- import { Box as Box9, Text as Text11, useInput as useInput7 } from "ink";
1097
+ import { Box as Box9, Text as Text12, useInput as useInput7 } from "ink";
949
1098
  import { useState as useState7 } from "react";
950
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1099
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
951
1100
  var MARK = { ready: "\u2713", error: "\u2717", starting: "\u2026", off: "\u25CB" };
952
1101
  function McpMenu({ items, onPick }) {
953
1102
  const [index, setIndex] = useState7(0);
@@ -957,18 +1106,18 @@ function McpMenu({ items, onPick }) {
957
1106
  else if (key.return) onPick(items[index]?.name);
958
1107
  else if (key.escape) onPick(void 0);
959
1108
  });
960
- return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
961
- /* @__PURE__ */ jsx11(Text11, { bold: true, children: t("MCP servers (enter: install / remove \xB7 esc close) \xB7 \u2713 active \u25CB not installed \u2717 error") }),
962
- items.map((item, i) => /* @__PURE__ */ jsxs8(Text11, { color: i === index ? color("green") : void 0, children: [
1109
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
1110
+ /* @__PURE__ */ jsx12(Text12, { bold: true, children: t("MCP servers (enter: install / remove \xB7 esc close) \xB7 \u2713 active \u25CB not installed \u2717 error") }),
1111
+ items.map((item, i) => /* @__PURE__ */ jsxs9(Text12, { color: i === index ? color("green") : void 0, children: [
963
1112
  `${i === index ? "\u203A" : " "} ${MARK[item.status]} ${item.name.padEnd(12)}`,
964
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: item.status === "error" ? ` ${item.error ?? ""}` : ` ${item.description}` })
1113
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: item.status === "error" ? ` ${item.error ?? ""}` : ` ${item.description}` })
965
1114
  ] }, item.name))
966
1115
  ] });
967
1116
  }
968
1117
 
969
1118
  // src/ui/PlanApproval.tsx
970
- import { Box as Box10, Text as Text12, useInput as useInput8 } from "ink";
971
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1119
+ import { Box as Box10, Text as Text13, useInput as useInput8 } from "ink";
1120
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
972
1121
  function PlanApproval({ plan, onAnswer }) {
973
1122
  useInput8((input, key) => {
974
1123
  const k2 = input.toLowerCase();
@@ -976,52 +1125,52 @@ function PlanApproval({ plan, onAnswer }) {
976
1125
  else if (k2 === "y") onAnswer("default");
977
1126
  else if (k2 === "n" || key.escape) onAnswer("no");
978
1127
  });
979
- return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
980
- /* @__PURE__ */ jsx12(Text12, { bold: true, children: t("Plan from the agent") }),
981
- /* @__PURE__ */ jsx12(Markdown, { text: plan, indent: 5 }),
982
- /* @__PURE__ */ jsxs9(Text12, { children: [
983
- /* @__PURE__ */ jsx12(Text12, { color: color("green"), children: t("[a] yes, auto-edit") }),
1128
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
1129
+ /* @__PURE__ */ jsx13(Text13, { bold: true, children: t("Plan from the agent") }),
1130
+ /* @__PURE__ */ jsx13(Markdown, { text: plan, indent: 5 }),
1131
+ /* @__PURE__ */ jsxs10(Text13, { children: [
1132
+ /* @__PURE__ */ jsx13(Text13, { color: color("green"), children: t("[a] yes, auto-edit") }),
984
1133
  " ",
985
- /* @__PURE__ */ jsx12(Text12, { color: color("cyan"), children: t("[y] yes, ask at each step") }),
1134
+ /* @__PURE__ */ jsx13(Text13, { color: color("cyan"), children: t("[y] yes, ask at each step") }),
986
1135
  " ",
987
- /* @__PURE__ */ jsx12(Text12, { color: color("red"), children: t("[n] not yet, revise first") })
1136
+ /* @__PURE__ */ jsx13(Text13, { color: color("red"), children: t("[n] not yet, revise first") })
988
1137
  ] })
989
1138
  ] });
990
1139
  }
991
1140
 
992
1141
  // src/ui/TodoList.tsx
993
- import { Box as Box11, Text as Text13 } from "ink";
994
- import { jsx as jsx13 } from "react/jsx-runtime";
1142
+ import { Box as Box11, Text as Text14 } from "ink";
1143
+ import { jsx as jsx14 } from "react/jsx-runtime";
995
1144
  var MARK2 = { completed: "\u2611", in_progress: "\u25FC", pending: "\u2610" };
996
1145
  function TodoList({ items }) {
997
1146
  if (!items.length || items.every((t2) => t2.status === "completed")) return null;
998
- return /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: items.map((t2, i) => /* @__PURE__ */ jsx13(Text13, { dimColor: t2.status === "completed", color: t2.status === "in_progress" ? color("yellow") : void 0, children: `${MARK2[t2.status]} ${t2.content}` }, i)) });
1147
+ return /* @__PURE__ */ jsx14(Box11, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: items.map((t2, i) => /* @__PURE__ */ jsx14(Text14, { dimColor: t2.status === "completed", color: t2.status === "in_progress" ? color("yellow") : void 0, children: `${MARK2[t2.status]} ${t2.content}` }, i)) });
999
1148
  }
1000
1149
 
1001
1150
  // src/ui/ToolBlock.tsx
1002
- import { Box as Box12, Text as Text14 } from "ink";
1003
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
1151
+ import { Box as Box12, Text as Text15 } from "ink";
1152
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1004
1153
  var PREVIEW_LINES = 5;
1005
1154
  function ToolBlock({ tool, target, output, display, isError, done, expanded, sub }) {
1006
1155
  const isTask = tool === "task";
1007
1156
  const isDiff = !!display && /^\s*\d+ [+\- ] /.test(display);
1008
1157
  const lines = (output ?? "").split("\n");
1009
1158
  const shown = expanded ? lines : lines.slice(0, PREVIEW_LINES);
1010
- return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 2, children: [
1011
- /* @__PURE__ */ jsxs10(Text14, { children: [
1012
- /* @__PURE__ */ jsx14(Text14, { color: isError ? color("red") : done ? color("green") : color("yellow"), children: "\u23BF " }),
1013
- /* @__PURE__ */ jsx14(Text14, { bold: true, children: toolLabel(tool) }),
1014
- /* @__PURE__ */ jsx14(Text14, { children: ` ${target}` }),
1015
- display && !isDiff && !isTask ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: ` (${display})` }) : null
1159
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", marginLeft: 2, children: [
1160
+ /* @__PURE__ */ jsxs11(Text15, { children: [
1161
+ /* @__PURE__ */ jsx15(Text15, { color: isError ? color("red") : done ? color("green") : color("yellow"), children: "\u23BF " }),
1162
+ /* @__PURE__ */ jsx15(Text15, { bold: true, children: toolLabel(tool) }),
1163
+ /* @__PURE__ */ jsx15(Text15, { children: ` ${target}` }),
1164
+ display && !isDiff && !isTask ? /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: ` (${display})` }) : null
1016
1165
  ] }),
1017
- sub?.length ? /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 3, children: [
1018
- sub.slice(-6).map((s) => /* @__PURE__ */ jsx14(Text14, { dimColor: s.done && !s.isError, color: s.isError ? color("red") : void 0, children: `\u23BF ${toolLabel(s.tool)} ${s.target}` }, s.id)),
1019
- sub.length > 6 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} earlier steps", { n: sub.length - 6 }) }) : null
1166
+ sub?.length ? /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", marginLeft: 3, children: [
1167
+ sub.slice(-6).map((s) => /* @__PURE__ */ jsx15(Text15, { dimColor: s.done && !s.isError, color: s.isError ? color("red") : void 0, children: `\u23BF ${toolLabel(s.tool)} ${s.target}` }, s.id)),
1168
+ sub.length > 6 ? /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u2026 {n} earlier steps", { n: sub.length - 6 }) }) : null
1020
1169
  ] }) : null,
1021
- isTask && done ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(Text14, { color: isError ? color("red") : color("green"), children: `${isError ? t("\u2717 failed") : t("\u2713 done")}${display ? ` \xB7 ${display}` : ""}` }) }) : null,
1022
- isDiff ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(DiffView, { diff: display }) }) : output && (isError || tool === "bash") && !(isTask && !isError) ? /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", marginLeft: 3, children: [
1023
- shown.map((line, i) => /* @__PURE__ */ jsx14(Text14, { dimColor: !isError, color: isError ? color("red") : void 0, children: line }, i)),
1024
- lines.length > shown.length ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} more lines (ctrl+o)", { n: lines.length - shown.length }) }) : null
1170
+ isTask && done ? /* @__PURE__ */ jsx15(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx15(Text15, { color: isError ? color("red") : color("green"), children: `${isError ? t("\u2717 failed") : t("\u2713 done")}${display ? ` \xB7 ${display}` : ""}` }) }) : null,
1171
+ isDiff ? /* @__PURE__ */ jsx15(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx15(DiffView, { diff: display }) }) : output && (isError || tool === "bash") && !(isTask && !isError) ? /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", marginLeft: 3, children: [
1172
+ shown.map((line, i) => /* @__PURE__ */ jsx15(Text15, { dimColor: !isError, color: isError ? color("red") : void 0, children: line }, i)),
1173
+ lines.length > shown.length ? /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u2026 {n} more lines (ctrl+o)", { n: lines.length - shown.length }) }) : null
1025
1174
  ] }) : null
1026
1175
  ] });
1027
1176
  }
@@ -1114,7 +1263,7 @@ function applyEvent(t2, event) {
1114
1263
  }
1115
1264
 
1116
1265
  // src/ui/App.tsx
1117
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1266
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
1118
1267
  function helpText(runtime) {
1119
1268
  const custom = runtime.commands.filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name));
1120
1269
  return [
@@ -1710,46 +1859,46 @@ ${t2.output}`);
1710
1859
  const renderEntry = (e) => {
1711
1860
  switch (e.kind) {
1712
1861
  case "header":
1713
- return /* @__PURE__ */ jsx15(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text15, { children: [
1714
- /* @__PURE__ */ jsx15(Text15, { color: color(ACCENT), bold: true, children: " \u273B " }),
1715
- /* @__PURE__ */ jsx15(Text15, { bold: true, children: `BCCLI ${version}` }),
1716
- /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: ` \xB7 ${runtime.modelRef} (${runtime.providerLabel()}) \xB7 ${cwd}` })
1862
+ return /* @__PURE__ */ jsx16(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Text16, { children: [
1863
+ /* @__PURE__ */ jsx16(Text16, { color: color(ACCENT), bold: true, children: " \u273B " }),
1864
+ /* @__PURE__ */ jsx16(Text16, { bold: true, children: `BCCLI ${version}` }),
1865
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: ` \xB7 ${runtime.modelRef} (${runtime.providerLabel()}) \xB7 ${cwd}` })
1717
1866
  ] }) }, e.id);
1718
1867
  case "user":
1719
- return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: `> ${e.text}` }) }, e.id);
1868
+ return /* @__PURE__ */ jsx16(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: `> ${e.text}` }) }, e.id);
1720
1869
  case "assistant":
1721
1870
  if (e.cont) {
1722
- return e.text ? /* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Markdown, { text: e.text }) }, e.id) : null;
1871
+ return e.text ? /* @__PURE__ */ jsx16(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx16(Markdown, { text: e.text }) }, e.id) : null;
1723
1872
  }
1724
1873
  if (!e.text.trim()) return null;
1725
- return /* @__PURE__ */ jsxs11(Box13, { marginTop: 1, children: [
1726
- /* @__PURE__ */ jsx15(Text15, { color: color(ACCENT), children: "\u25CF " }),
1727
- /* @__PURE__ */ jsx15(Markdown, { text: e.text.replace(/^\s+/, "") })
1874
+ return /* @__PURE__ */ jsxs12(Box13, { marginTop: 1, children: [
1875
+ /* @__PURE__ */ jsx16(Text16, { color: color(ACCENT), children: "\u25CF " }),
1876
+ /* @__PURE__ */ jsx16(Markdown, { text: e.text.replace(/^\s+/, "") })
1728
1877
  ] }, e.id);
1729
1878
  case "thinking": {
1730
1879
  const text = e.text.trim();
1731
1880
  if (!text) return null;
1732
1881
  if (!(e.open ?? showThinking)) {
1733
1882
  const lines = text.split("\n").length;
1734
- return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u273B Thinking \xB7 {n} lines \xB7 ctrl+t to show", { n: lines }) }) }, e.id);
1883
+ return /* @__PURE__ */ jsx16(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: t("\u273B Thinking \xB7 {n} lines \xB7 ctrl+t to show", { n: lines }) }) }, e.id);
1735
1884
  }
1736
- return /* @__PURE__ */ jsxs11(Box13, { marginTop: 1, flexDirection: "column", children: [
1737
- /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u273B Thinking (ctrl+t to hide)") }),
1738
- /* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, italic: true, children: text }) })
1885
+ return /* @__PURE__ */ jsxs12(Box13, { marginTop: 1, flexDirection: "column", children: [
1886
+ /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: t("\u273B Thinking (ctrl+t to hide)") }),
1887
+ /* @__PURE__ */ jsx16(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, italic: true, children: text }) })
1739
1888
  ] }, e.id);
1740
1889
  }
1741
1890
  case "tool":
1742
- return /* @__PURE__ */ jsx15(ToolBlock, { tool: e.tool, target: e.target, output: e.output, display: e.display, isError: e.isError, done: e.done, sub: e.sub }, e.id);
1891
+ return /* @__PURE__ */ jsx16(ToolBlock, { tool: e.tool, target: e.target, output: e.output, display: e.display, isError: e.isError, done: e.done, sub: e.sub }, e.id);
1743
1892
  case "notice":
1744
- return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: e.tone === "error" ? color("red") : e.tone === "warn" ? color("yellow") : void 0, dimColor: e.tone === "info", children: e.text }) }, e.id);
1893
+ return /* @__PURE__ */ jsx16(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { color: e.tone === "error" ? color("red") : e.tone === "warn" ? color("yellow") : void 0, dimColor: e.tone === "info", children: e.text }) }, e.id);
1745
1894
  }
1746
1895
  };
1747
- return /* @__PURE__ */ jsxs11(Box13, { flexDirection: "column", children: [
1748
- /* @__PURE__ */ jsx15(Static, { items: transcript.done, children: renderEntry }),
1896
+ return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", children: [
1897
+ /* @__PURE__ */ jsx16(Static, { items: transcript.done, children: renderEntry }),
1749
1898
  transcript.live.map(renderEntry),
1750
- busy && !pending && !planAsk ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Spinner, { label: cancelling ? t("Cancelling") : t("Thinking"), startedAt }) }) : null,
1751
- pending ? /* @__PURE__ */ jsx15(PermissionPrompt, { request: pending.request, onAnswer: answer }, pending.id) : null,
1752
- picker ? /* @__PURE__ */ jsx15(
1899
+ busy && !pending && !planAsk ? /* @__PURE__ */ jsx16(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx16(Spinner, { label: cancelling ? t("Cancelling") : t("Thinking"), startedAt }) }) : null,
1900
+ pending ? /* @__PURE__ */ jsx16(PermissionPrompt, { request: pending.request, onAnswer: answer }, pending.id) : null,
1901
+ picker ? /* @__PURE__ */ jsx16(
1753
1902
  ModelPicker,
1754
1903
  {
1755
1904
  groups: picker,
@@ -1760,10 +1909,10 @@ ${t2.output}`);
1760
1909
  }
1761
1910
  }
1762
1911
  ) : null,
1763
- listPicker ? /* @__PURE__ */ jsx15(ListPicker, { title: listPicker.title, items: listPicker.items, onPick: listPicker.onPick }) : null,
1764
- mcpMenu ? /* @__PURE__ */ jsx15(McpMenu, { items: mcpMenu, onPick: (n) => void pickMcp(n) }) : null,
1765
- providerMenu ? /* @__PURE__ */ jsx15(ProviderMenu, { entries: providerMenu, onPick: (id) => void pickProvider(id) }) : null,
1766
- prompt ? /* @__PURE__ */ jsx15(
1912
+ listPicker ? /* @__PURE__ */ jsx16(ListPicker, { title: listPicker.title, items: listPicker.items, onPick: listPicker.onPick }) : null,
1913
+ mcpMenu ? /* @__PURE__ */ jsx16(McpMenu, { items: mcpMenu, onPick: (n) => void pickMcp(n) }) : null,
1914
+ providerMenu ? /* @__PURE__ */ jsx16(ProviderMenu, { entries: providerMenu, onPick: (id) => void pickProvider(id) }) : null,
1915
+ prompt ? /* @__PURE__ */ jsx16(
1767
1916
  LinePrompt,
1768
1917
  {
1769
1918
  label: prompt.label,
@@ -1778,7 +1927,7 @@ ${t2.output}`);
1778
1927
  }
1779
1928
  }
1780
1929
  ) : null,
1781
- planAsk ? /* @__PURE__ */ jsx15(
1930
+ planAsk ? /* @__PURE__ */ jsx16(
1782
1931
  PlanApproval,
1783
1932
  {
1784
1933
  plan: planAsk.plan,
@@ -1789,15 +1938,15 @@ ${t2.output}`);
1789
1938
  }
1790
1939
  }
1791
1940
  ) : null,
1792
- /* @__PURE__ */ jsx15(TodoList, { items: todos }),
1793
- queued.map((q, i) => /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t(" \u23F3 queued: {q}", { q }) }, `${i}-${q}`)),
1794
- /* @__PURE__ */ jsx15(PromptInput, { disabled: !!pending || !!picker || !!providerMenu || !!prompt || !!planAsk || !!mcpMenu || !!listPicker, history, cwd: runtime.cwd, onSubmit: onPrompt, extraCommands }),
1795
- /* @__PURE__ */ jsx15(StatusBar, { mode, tokens, busy, model: modelLabel, reasoning })
1941
+ /* @__PURE__ */ jsx16(TodoList, { items: todos }),
1942
+ queued.map((q, i) => /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: t(" \u23F3 queued: {q}", { q }) }, `${i}-${q}`)),
1943
+ /* @__PURE__ */ jsx16(PromptInput, { disabled: !!pending || !!picker || !!providerMenu || !!prompt || !!planAsk || !!mcpMenu || !!listPicker, history, cwd: runtime.cwd, onSubmit: onPrompt, extraCommands }),
1944
+ /* @__PURE__ */ jsx16(StatusBar, { mode, tokens, busy, model: modelLabel, reasoning })
1796
1945
  ] });
1797
1946
  }
1798
1947
 
1799
1948
  // src/ui/index.tsx
1800
- import { jsx as jsx16 } from "react/jsx-runtime";
1949
+ import { jsx as jsx17 } from "react/jsx-runtime";
1801
1950
  async function startInteractive(rt, opts) {
1802
1951
  if (opts.resume) {
1803
1952
  const { Session: Session2 } = await import("./session-7UB77CEG.js");
@@ -1829,7 +1978,7 @@ async function startInteractive(rt, opts) {
1829
1978
  rl.close();
1830
1979
  }
1831
1980
  void rt.startMcp(plan.start);
1832
- const instance = render(/* @__PURE__ */ jsx16(App, { runtime: rt, initialPrompt: opts.initialPrompt, version: opts.version }), { exitOnCtrlC: true });
1981
+ const instance = render(/* @__PURE__ */ jsx17(App, { runtime: rt, initialPrompt: opts.initialPrompt, version: opts.version }), { exitOnCtrlC: true });
1833
1982
  await instance.waitUntilExit();
1834
1983
  await rt.mcp.stop();
1835
1984
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.0-beta.34",
3
+ "version": "0.4.0-beta.35",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {