@botconnector/bccli 0.4.1 → 0.4.2

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.
Files changed (69) hide show
  1. package/dist/{acp-3PHBAI64.js → acp-UYC6APR5.js} +30 -6
  2. package/dist/acp.d.ts +1 -0
  3. package/dist/agent.d.ts +5 -1
  4. package/dist/args-NRTZWWEV.js +13 -0
  5. package/dist/args.d.ts +2 -0
  6. package/dist/checkpoints.d.ts +1 -0
  7. package/dist/{chunk-BKGFA2PT.js → chunk-266SY3MC.js} +1 -1
  8. package/dist/{chunk-MFHCQQEN.js → chunk-3I5BW3ZT.js} +3 -2
  9. package/dist/{chunk-UZWJQF67.js → chunk-3WHI4LN3.js} +2 -1
  10. package/dist/{chunk-WNACAUDK.js → chunk-5YJ3ZQVR.js} +66 -9
  11. package/dist/{chunk-24JN75FZ.js → chunk-6M55UPES.js} +2 -2
  12. package/dist/{chunk-XV7ZVL4J.js → chunk-6UO5GX55.js} +26 -12
  13. package/dist/{chunk-R5RE46CW.js → chunk-C64KM37J.js} +36 -6
  14. package/dist/{chunk-GN4W3T6E.js → chunk-H7XJDKJY.js} +4 -4
  15. package/dist/{chunk-JHPGOAXU.js → chunk-HQW4BROS.js} +4 -5
  16. package/dist/{chunk-75BECX4F.js → chunk-IYR5PYA3.js} +4 -4
  17. package/dist/{chunk-45SDLMTV.js → chunk-JXM6REER.js} +1 -1
  18. package/dist/{chunk-BLOYFIAD.js → chunk-KPTML72Q.js} +1 -1
  19. package/dist/{chunk-WI22M2ID.js → chunk-NQOGVP3I.js} +2 -2
  20. package/dist/{chunk-QZKLZELZ.js → chunk-OK2USAXX.js} +28 -4
  21. package/dist/{chunk-PZRKU4UM.js → chunk-R72OV7RF.js} +421 -108
  22. package/dist/{chunk-FLQPE4S5.js → chunk-RX4UQX43.js} +4 -1
  23. package/dist/{chunk-BC7UXFE4.js → chunk-SVD4LHJC.js} +64 -3
  24. package/dist/{chunk-BXQQCUAC.js → chunk-TIMSYZIR.js} +7 -7
  25. package/dist/{chunk-MHIYLXJC.js → chunk-WFZKJY3R.js} +8 -4
  26. package/dist/{chunk-BGXNR74O.js → chunk-ZEPTUKNW.js} +119 -31
  27. package/dist/cli.js +60 -43
  28. package/dist/{completion-HPPFDAPB.js → completion-D2BSBTQO.js} +1 -1
  29. package/dist/{config-DIDLDONU.js → config-ENDRMOTP.js} +3 -3
  30. package/dist/{config-IU76CPK2.js → config-LAINORU5.js} +2 -2
  31. package/dist/config.d.ts +2 -0
  32. package/dist/{ghBotCli-E3VPHNZY.js → ghBotCli-TSLRORJJ.js} +21 -20
  33. package/dist/{integrationCli-Q2YPDTPG.js → integrationCli-HXCSEWH2.js} +2 -2
  34. package/dist/{login-FP3BB44A.js → login-RYESFZG6.js} +4 -4
  35. package/dist/lsp.d.ts +3 -0
  36. package/dist/mcp/manager.d.ts +18 -0
  37. package/dist/{mcpCli-SNBDUWJN.js → mcpCli-SETTCL3K.js} +6 -6
  38. package/dist/{modelsCli-CZ2HNGKR.js → modelsCli-OP7CDZC7.js} +6 -6
  39. package/dist/{oauthLogin-6FWQABJ7.js → oauthLogin-XWY7OHCG.js} +1 -1
  40. package/dist/{pluginsCli-LPIUUDWB.js → pluginsCli-ZQNKWZHJ.js} +2 -2
  41. package/dist/{prCli-5IMV3VNQ.js → prCli-6PUWTMTP.js} +20 -4
  42. package/dist/prCli.d.ts +13 -0
  43. package/dist/print.d.ts +2 -0
  44. package/dist/provider.d.ts +5 -0
  45. package/dist/providerCli-5OZI2GQQ.js +15 -0
  46. package/dist/sdk.d.ts +5 -1
  47. package/dist/sdk.js +733 -176
  48. package/dist/{serve-X2ZV4S5U.js → serve-4J7HA4JO.js} +17 -17
  49. package/dist/{serve-KWOECK5W.js → serve-K5AH4MGO.js} +3 -3
  50. package/dist/session-YQXCCKXI.js +12 -0
  51. package/dist/session.d.ts +3 -0
  52. package/dist/setup-S4AJT6XE.js +24 -0
  53. package/dist/slash/info.d.ts +1 -0
  54. package/dist/{statsCli-CF3R7ATL.js → statsCli-XR6BEZQQ.js} +2 -2
  55. package/dist/tokenBudget.d.ts +1 -1
  56. package/dist/tools/edit.d.ts +7 -2
  57. package/dist/tools/grep.d.ts +14 -2
  58. package/dist/tools/ignore.d.ts +2 -2
  59. package/dist/tools/paths.d.ts +2 -0
  60. package/dist/{transferCli-YUFPI6AH.js → transferCli-R2KEIWQR.js} +8 -6
  61. package/dist/ui/complete.d.ts +5 -0
  62. package/dist/ui/vim.d.ts +1 -1
  63. package/dist/{ui-IVIFNUCC.js → ui-36ZEK65V.js} +177 -54
  64. package/dist/{update-TZ2G6KQ3.js → update-FSS7X5WV.js} +2 -2
  65. package/package.json +1 -1
  66. package/dist/args-W6BNKY7K.js +0 -13
  67. package/dist/providerCli-NMUFXAAS.js +0 -15
  68. package/dist/session-GKEXDJKZ.js +0 -12
  69. package/dist/setup-OV3NWQN5.js +0 -24
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  CATALOG,
4
4
  fillTemplate
5
- } from "./chunk-WI22M2ID.js";
5
+ } from "./chunk-NQOGVP3I.js";
6
6
  import {
7
7
  MAX_VERIFY_ROUNDS,
8
8
  runVerify,
9
9
  toolLabel,
10
10
  verifyFollowup,
11
11
  worktreeListText
12
- } from "./chunk-R5RE46CW.js";
12
+ } from "./chunk-C64KM37J.js";
13
13
  import {
14
14
  BUILTIN_AGENTS,
15
15
  appendMemory,
@@ -18,60 +18,62 @@ import {
18
18
  normalizeGlobPath,
19
19
  parseFrontmatter,
20
20
  parseMemoryArgs,
21
+ recordFileMtime,
21
22
  renderBackgroundTasks,
22
23
  runHooks,
23
24
  validateGlobPattern
24
- } from "./chunk-BGXNR74O.js";
25
+ } from "./chunk-ZEPTUKNW.js";
25
26
  import "./chunk-PSO7R5AD.js";
26
27
  import {
27
- nextMode
28
- } from "./chunk-MHIYLXJC.js";
28
+ nextMode,
29
+ requiresSensitiveToolApproval
30
+ } from "./chunk-WFZKJY3R.js";
29
31
  import {
30
32
  hasKey,
31
33
  providerName,
32
34
  writeGlobalConfig
33
- } from "./chunk-JHPGOAXU.js";
35
+ } from "./chunk-HQW4BROS.js";
34
36
  import {
35
37
  Session
36
- } from "./chunk-BC7UXFE4.js";
38
+ } from "./chunk-SVD4LHJC.js";
37
39
  import {
38
40
  contentText
39
- } from "./chunk-WNACAUDK.js";
41
+ } from "./chunk-5YJ3ZQVR.js";
40
42
  import {
41
43
  REASONING_LEVELS,
42
44
  assertReasoningSupported,
43
45
  parseReasoningLevel,
44
46
  supportedReasoningLevels
45
- } from "./chunk-BLOYFIAD.js";
47
+ } from "./chunk-KPTML72Q.js";
46
48
  import {
47
49
  addGlobalServer,
48
50
  globalMcpPath,
49
51
  readMcpFile,
50
52
  removeGlobalServer
51
- } from "./chunk-24JN75FZ.js";
53
+ } from "./chunk-6M55UPES.js";
52
54
  import {
53
55
  ACCENT,
54
56
  PRESETS,
55
57
  color,
56
58
  matchKeybind,
57
59
  removeCredential
58
- } from "./chunk-FLQPE4S5.js";
60
+ } from "./chunk-RX4UQX43.js";
59
61
  import {
60
62
  getLanguage,
61
63
  locale,
62
64
  parseLang,
63
65
  setLanguage,
64
66
  t
65
- } from "./chunk-UZWJQF67.js";
67
+ } from "./chunk-3WHI4LN3.js";
66
68
 
67
69
  // src/ui/index.tsx
68
70
  import { render } from "ink";
69
71
 
70
72
  // src/ui/App.tsx
71
73
  import { execFile as execFile3 } from "child_process";
72
- import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
74
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
73
75
  import { homedir, tmpdir } from "os";
74
- import { dirname, join as join3, relative, resolve } from "path";
76
+ import { dirname, join as join3, relative as relative2, resolve as resolve2 } from "path";
75
77
  import { Box as Box13, Static, Text as Text16, measureElement, useApp, useInput as useInput9, useStdin, useStdout as useStdout2 } from "ink";
76
78
  import { useCallback, useEffect as useEffect3, useRef, useState as useState8 } from "react";
77
79
 
@@ -106,6 +108,7 @@ var SLASH_COMMANDS = [
106
108
  { name: "clear", description: "start a new conversation" },
107
109
  { name: "compact", description: "summarize the conversation" },
108
110
  { name: "cost", description: "token usage of this session" },
111
+ { name: "config", description: "view or change configuration settings" },
109
112
  { name: "tasks", description: "list background tasks" },
110
113
  { name: "exit", description: "quit" }
111
114
  ];
@@ -139,12 +142,12 @@ function osc52(text, inTmux) {
139
142
  // src/slash/diff.ts
140
143
  import { execFile } from "child_process";
141
144
  function git(cwd, args, bin = "git") {
142
- return new Promise((resolve2) => {
145
+ return new Promise((resolve3) => {
143
146
  execFile(
144
147
  bin,
145
148
  args,
146
149
  { cwd, maxBuffer: 20 * 1024 * 1024 },
147
- (error, stdout, stderr) => resolve2({ ok: !error, out: error ? stderr : stdout, missing: error?.code === "ENOENT" })
150
+ (error, stdout, stderr) => resolve3({ ok: !error, out: error ? stderr : stdout, missing: error?.code === "ENOENT" })
148
151
  );
149
152
  });
150
153
  }
@@ -203,6 +206,8 @@ var k = (n) => n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
203
206
  function statusText(s) {
204
207
  const ready = s.mcp.filter((m) => m.status === "ready").length;
205
208
  const errors = s.mcp.filter((m) => m.status === "error").length;
209
+ const win = s.contextWindow && s.contextWindow > 0 ? s.contextWindow : 128e3;
210
+ const ctxLine = t("Context: ~{pct}% of 128k", { pct: Math.round(s.lastInputTokens / win * 100) }).replace("128k", k(win));
206
211
  return [
207
212
  `BCCLI ${s.version}`,
208
213
  `Model: ${s.modelRef} (${s.providerLabel})`,
@@ -211,7 +216,7 @@ function statusText(s) {
211
216
  t("MCP: {ready} active, {errors} errors", { ready, errors }),
212
217
  t("Session tokens: {input} in \xB7 {output} out", { input: k(s.usage.inputTokens), output: k(s.usage.outputTokens) }),
213
218
  `Cache: ${k(s.usage.cachedInputTokens ?? 0)} read \xB7 ${k(s.usage.cacheWriteTokens ?? 0)} write`,
214
- t("Context: ~{pct}% of 128k", { pct: Math.round(s.lastInputTokens / 128e3 * 100) })
219
+ ctxLine
215
220
  ].join("\n");
216
221
  }
217
222
  function agentsText(defs) {
@@ -868,6 +873,7 @@ function ListPicker({ title, items, onPick }) {
868
873
  const shown = items.filter((i) => i.label.toLowerCase().includes(filter.toLowerCase()));
869
874
  const cursor = Math.min(index, Math.max(0, shown.length - 1));
870
875
  useInput2((input, key) => {
876
+ if (isMouseControlInput(input)) return;
871
877
  if (key.upArrow) setIndex(Math.max(0, cursor - 1));
872
878
  else if (key.downArrow) setIndex(Math.min(shown.length - 1, cursor + 1));
873
879
  else if (key.return && !shown[cursor]?.disabled) onPick(shown[cursor]?.id);
@@ -911,6 +917,7 @@ function ModelPicker({ groups, current, onPick }) {
911
917
  const selectable = rows.flatMap((r, i) => r.kind === "model" ? [i] : []);
912
918
  const cursor = selectable[Math.min(index, selectable.length - 1)] ?? -1;
913
919
  useInput3((input, key) => {
920
+ if (isMouseControlInput(input)) return;
914
921
  if (key.upArrow) setIndex((i) => Math.max(0, i - 1));
915
922
  else if (key.downArrow) setIndex((i) => Math.min(selectable.length - 1, i + 1));
916
923
  else if (key.return) {
@@ -1007,9 +1014,9 @@ import { Box as Box8, Text as Text9, useInput as useInput6 } from "ink";
1007
1014
  import { useEffect, useState as useState5 } from "react";
1008
1015
 
1009
1016
  // src/ui/complete.ts
1010
- import { globSync } from "fs";
1011
- import { statSync } from "fs";
1012
- import { join } from "path";
1017
+ import { existsSync, globSync, readFileSync, statSync } from "fs";
1018
+ import { isAbsolute, join, relative, resolve } from "path";
1019
+ var MAX_ATTACH_BYTES = 32768;
1013
1020
  function completeFile(value, cwd) {
1014
1021
  const match = /(^|\s)@([^\s]*)$/.exec(value);
1015
1022
  if (!match) return value;
@@ -1017,21 +1024,62 @@ function completeFile(value, cwd) {
1017
1024
  const escaped = prefix.replace(/([*?[\]{}()!])/g, "\\$1");
1018
1025
  const pattern = `${escaped}*`;
1019
1026
  if (validateGlobPattern(pattern)) return value;
1020
- const found = globSync(pattern, { cwd, exclude: ignorePatterns(cwd) }).map((entry2) => {
1027
+ const exclude = ignorePatterns(cwd);
1028
+ const formatEntry = (entry2) => {
1021
1029
  const normalized = normalizeGlobPath(entry2);
1022
1030
  try {
1023
1031
  return statSync(join(cwd, entry2)).isDirectory() ? `${normalized}/` : normalized;
1024
1032
  } catch {
1025
1033
  return normalized;
1026
1034
  }
1027
- }).sort();
1035
+ };
1036
+ let found = globSync(pattern, { cwd, exclude }).map(formatEntry).sort();
1037
+ if (!found.length && prefix && !prefix.includes("/")) {
1038
+ const deepPattern = `**/*${escaped}*`;
1039
+ if (!validateGlobPattern(deepPattern)) {
1040
+ found = globSync(deepPattern, { cwd, exclude }).map(formatEntry).sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b));
1041
+ }
1042
+ }
1028
1043
  if (!found.length) return value;
1029
1044
  const pick = found[0];
1030
1045
  return `${value.slice(0, value.length - prefix.length)}${pick}${pick.endsWith("/") ? "" : " "}`;
1031
1046
  }
1047
+ function expandAtFileMentions(prompt, cwd, readFiles) {
1048
+ const matches = [...prompt.matchAll(/(?:^|\s)@([^\s]+)/g)];
1049
+ if (!matches.length) return prompt;
1050
+ const blocks = [];
1051
+ const seen = /* @__PURE__ */ new Set();
1052
+ for (const m of matches) {
1053
+ const rawPath = m[1];
1054
+ if (!rawPath || seen.has(rawPath)) continue;
1055
+ seen.add(rawPath);
1056
+ if (requiresSensitiveToolApproval({ tool: "read", kind: "read", target: rawPath })) continue;
1057
+ const abs = resolve(cwd, rawPath);
1058
+ const rel = relative(cwd, abs);
1059
+ if (!rel || rel.startsWith("..") || isAbsolute(rel)) continue;
1060
+ try {
1061
+ if (!existsSync(abs) || !statSync(abs).isFile() || statSync(abs).size > MAX_ATTACH_BYTES) continue;
1062
+ const buf = readFileSync(abs);
1063
+ if (buf.subarray(0, 4e3).includes(0)) continue;
1064
+ if (readFiles) recordFileMtime(readFiles, abs);
1065
+ blocks.push(`<file path="${rawPath}">
1066
+ ${buf.toString("utf8")}
1067
+ </file>`);
1068
+ } catch {
1069
+ }
1070
+ }
1071
+ return blocks.length ? `${prompt}
1072
+
1073
+ ${blocks.join("\n\n")}` : prompt;
1074
+ }
1032
1075
 
1033
1076
  // src/ui/vim.ts
1034
- var clamp = (s) => ({ value: s.value, cursor: Math.min(s.cursor, Math.max(0, s.value.length - 1)) });
1077
+ var clamp = (s) => {
1078
+ const start = lineStart(s.value, s.cursor);
1079
+ const end = lineEnd(s.value, s.cursor);
1080
+ if (s.cursor < end) return s;
1081
+ return { value: s.value, cursor: Math.max(start, prevBoundary(s.value, end)) };
1082
+ };
1035
1083
  var wordStart = (text, pos) => {
1036
1084
  let i = wordRight(text, pos);
1037
1085
  while (i < text.length && /\s/.test(text[i])) i++;
@@ -1052,19 +1100,20 @@ function applyVim(s, mode, input, key, pending) {
1052
1100
  if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow || key.ctrl || key.meta || key.tab || key.return) {
1053
1101
  return { state: s, mode, pending, handled: false };
1054
1102
  }
1055
- if (pending === "d") {
1056
- if (input === "d") return { state: deleteLine(s), mode, handled: true };
1103
+ if (pending === "d" || pending === "c") {
1104
+ const nextMode2 = pending === "c" ? "insert" : mode;
1105
+ if (input === pending) return { state: deleteLine(s), mode: nextMode2, handled: true };
1057
1106
  if (input === "w") {
1058
1107
  const to = wordStart(s.value, s.cursor);
1059
- return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(to), cursor: s.cursor }, mode, handled: true };
1108
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(to), cursor: s.cursor }, mode: nextMode2, handled: true };
1060
1109
  }
1061
1110
  return { state: s, mode, handled: true };
1062
1111
  }
1063
1112
  switch (input) {
1064
1113
  case "h":
1065
- return { state: { ...s, cursor: Math.max(lineStart(s.value, s.cursor), s.cursor - 1) }, mode, handled: true };
1114
+ return { state: { ...s, cursor: Math.max(lineStart(s.value, s.cursor), prevBoundary(s.value, s.cursor)) }, mode, handled: true };
1066
1115
  case "l":
1067
- return { state: { ...s, cursor: Math.min(lineEnd(s.value, s.cursor), s.cursor + 1) }, mode, handled: true };
1116
+ return { state: { ...s, cursor: Math.min(lineEnd(s.value, s.cursor), nextBoundary(s.value, s.cursor)) }, mode, handled: true };
1068
1117
  case "j": {
1069
1118
  const moved = moveLine(s.value, s.cursor, 1);
1070
1119
  return { state: moved === void 0 ? s : { ...s, cursor: moved }, mode, handled: true };
@@ -1075,6 +1124,8 @@ function applyVim(s, mode, input, key, pending) {
1075
1124
  }
1076
1125
  case "w":
1077
1126
  return { state: { ...s, cursor: wordStart(s.value, s.cursor) }, mode, handled: true };
1127
+ case "e":
1128
+ return { state: { ...s, cursor: Math.max(s.cursor, prevBoundary(s.value, wordRight(s.value, s.cursor))) }, mode, handled: true };
1078
1129
  case "b":
1079
1130
  return { state: { ...s, cursor: wordLeft(s.value, s.cursor) }, mode, handled: true };
1080
1131
  case "0":
@@ -1083,12 +1134,28 @@ function applyVim(s, mode, input, key, pending) {
1083
1134
  return { state: { ...s, cursor: lineEnd(s.value, s.cursor) }, mode, handled: true };
1084
1135
  case "x": {
1085
1136
  if (s.cursor >= s.value.length || s.value[s.cursor] === "\n") return { state: s, mode, handled: true };
1086
- return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(s.cursor + 1), cursor: s.cursor }, mode, handled: true };
1137
+ const next = nextBoundary(s.value, s.cursor);
1138
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(next), cursor: s.cursor }, mode, handled: true };
1139
+ }
1140
+ case "D": {
1141
+ const end = lineEnd(s.value, s.cursor);
1142
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(end), cursor: s.cursor }, mode, handled: true };
1143
+ }
1144
+ case "C": {
1145
+ const end = lineEnd(s.value, s.cursor);
1146
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(end), cursor: s.cursor }, mode: "insert", handled: true };
1087
1147
  }
1088
1148
  case "i":
1089
1149
  return { state: s, mode: "insert", handled: true };
1150
+ case "I": {
1151
+ const start = lineStart(s.value, s.cursor);
1152
+ const end = lineEnd(s.value, s.cursor);
1153
+ let pos = start;
1154
+ while (pos < end && (s.value[pos] === " " || s.value[pos] === " ")) pos++;
1155
+ return { state: { ...s, cursor: pos }, mode: "insert", handled: true };
1156
+ }
1090
1157
  case "a":
1091
- return { state: { ...s, cursor: Math.min(s.cursor + 1, s.value.length) }, mode: "insert", handled: true };
1158
+ return { state: { ...s, cursor: Math.min(lineEnd(s.value, s.cursor), nextBoundary(s.value, s.cursor)) }, mode: "insert", handled: true };
1092
1159
  case "A":
1093
1160
  return { state: { ...s, cursor: lineEnd(s.value, s.cursor) }, mode: "insert", handled: true };
1094
1161
  case "o": {
@@ -1102,7 +1169,8 @@ ${s.value.slice(end)}`, cursor: end + 1 }, mode: "insert", handled: true };
1102
1169
  ${s.value.slice(start)}`, cursor: start }, mode: "insert", handled: true };
1103
1170
  }
1104
1171
  case "d":
1105
- return { state: s, mode, pending: "d", handled: true };
1172
+ case "c":
1173
+ return { state: s, mode, pending: input, handled: true };
1106
1174
  default:
1107
1175
  return { state: s, mode, handled: true };
1108
1176
  }
@@ -1115,6 +1183,7 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1115
1183
  const { value } = line;
1116
1184
  const [historyIndex, setHistoryIndex] = useState5(null);
1117
1185
  const [selected, setSelected] = useState5(0);
1186
+ const [dismissed, setDismissed] = useState5(false);
1118
1187
  const [vimMode, setVimMode] = useState5("insert");
1119
1188
  const [vimPending, setVimPending] = useState5(void 0);
1120
1189
  const injectedSeen = useState5(0);
@@ -1126,17 +1195,23 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1126
1195
  }
1127
1196
  }, [injected, injectedSeen]);
1128
1197
  const all = [...SLASH_COMMANDS, ...(extraCommands ?? []).filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name))];
1129
- const suggestions = value.startsWith("/") && !/\s/.test(value) ? all.filter((c) => c.name.startsWith(value.slice(1))).slice(0, 8) : [];
1198
+ const suggestions = historyIndex === null && !dismissed && value.startsWith("/") && !/\s/.test(value) ? all.filter((c) => c.name.startsWith(value.slice(1))).slice(0, 8) : [];
1130
1199
  const highlighted = Math.min(selected, Math.max(0, suggestions.length - 1));
1131
1200
  const typed = (text) => ({ value: text, cursor: text.length });
1132
1201
  const edit = (next) => {
1133
1202
  setLine(next);
1134
1203
  setSelected(0);
1204
+ setDismissed(false);
1205
+ setHistoryIndex(null);
1135
1206
  };
1136
1207
  useInput6(
1137
1208
  (input, key) => {
1138
1209
  if (isMouseControlInput(input)) return;
1139
1210
  if (suggestions.length) {
1211
+ if (key.escape) {
1212
+ setDismissed(true);
1213
+ return;
1214
+ }
1140
1215
  if (key.upArrow) {
1141
1216
  setSelected(Math.max(0, highlighted - 1));
1142
1217
  return;
@@ -1149,7 +1224,7 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1149
1224
  edit(typed(`/${suggestions[highlighted].name} `));
1150
1225
  return;
1151
1226
  }
1152
- if (key.return) {
1227
+ if (key.return && !key.meta) {
1153
1228
  edit(typed(""));
1154
1229
  setHistoryIndex(null);
1155
1230
  onSubmit(`/${suggestions[highlighted].name}`);
@@ -1166,6 +1241,10 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1166
1241
  return;
1167
1242
  }
1168
1243
  }
1244
+ if (key.return && key.meta || key.ctrl && input.toLowerCase() === "j") {
1245
+ edit((current) => insert(current, "\n"));
1246
+ return;
1247
+ }
1169
1248
  if (key.return) {
1170
1249
  const before = value.slice(0, line.cursor);
1171
1250
  if (before.endsWith("\\")) {
@@ -1450,7 +1529,7 @@ function replayEntries(history) {
1450
1529
 
1451
1530
  // src/clipboardImage.ts
1452
1531
  import { execFile as execFile2 } from "child_process";
1453
- import { existsSync, statSync as statSync2 } from "fs";
1532
+ import { existsSync as existsSync2, statSync as statSync2 } from "fs";
1454
1533
  import { join as join2 } from "path";
1455
1534
  function clipboardTarget(tmpdir2, now) {
1456
1535
  const stamp = now.toISOString().replace(/[-:]/g, "").replace("T", "-").slice(0, 15);
@@ -1501,10 +1580,10 @@ function clipboardCommand(platform, target) {
1501
1580
  }
1502
1581
  return void 0;
1503
1582
  }
1504
- var defaultRun = (cmd, args) => new Promise((resolve2) => {
1583
+ var defaultRun = (cmd, args) => new Promise((resolve3) => {
1505
1584
  execFile2(cmd, args, { timeout: 15e3, windowsHide: true }, (error, stdout) => {
1506
1585
  const code = error ? error.code ?? 1 : 0;
1507
- resolve2({ code: typeof code === "number" ? code : 1, output: String(stdout ?? "") });
1586
+ resolve3({ code: typeof code === "number" ? code : 1, output: String(stdout ?? "") });
1508
1587
  });
1509
1588
  });
1510
1589
  async function grabClipboardImage(deps) {
@@ -1513,7 +1592,7 @@ async function grabClipboardImage(deps) {
1513
1592
  if (!command) return void 0;
1514
1593
  const run = deps.run ?? defaultRun;
1515
1594
  const r = await run(command.cmd, command.args);
1516
- if (r.code === 0 && r.output.includes("OK") && existsSync(target) && statSync2(target).size > 0) return target;
1595
+ if (r.code === 0 && r.output.includes("OK") && existsSync2(target) && statSync2(target).size > 0) return target;
1517
1596
  return void 0;
1518
1597
  }
1519
1598
 
@@ -1553,7 +1632,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1553
1632
  const [picker, setPicker] = useState8(null);
1554
1633
  const [providerMenu, setProviderMenu] = useState8(null);
1555
1634
  const [prompt, setPrompt] = useState8(null);
1556
- const ask = useCallback((label, mask = false) => new Promise((resolve2) => setPrompt({ label, mask, resolve: resolve2 })), []);
1635
+ const ask = useCallback((label, mask = false) => new Promise((resolve3) => setPrompt({ label, mask, resolve: resolve3 })), []);
1557
1636
  const [modelLabel, setModelLabel] = useState8(() => labelFor(runtime, runtime.modelRef));
1558
1637
  const [history, setHistory] = useState8([]);
1559
1638
  const controller = useRef(null);
@@ -1604,8 +1683,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1604
1683
  }, [notice]);
1605
1684
  useEffect3(() => {
1606
1685
  runtime.agent.onEvent = onEvent;
1607
- runtime.agent.askPermission = (request) => new Promise((resolve2) => setAsks((q) => [...q, { id: askId.current++, request, resolve: resolve2 }]));
1608
- runtime.interaction.approvePlan = (plan) => new Promise((resolve2) => setPlanAsk({ plan, resolve: resolve2 }));
1686
+ runtime.agent.askPermission = (request) => new Promise((resolve3) => setAsks((q) => [...q, { id: askId.current++, request, resolve: resolve3 }]));
1687
+ runtime.interaction.approvePlan = (plan) => new Promise((resolve3) => setPlanAsk({ plan, resolve: resolve3 }));
1609
1688
  runHooks(runtime.config.hooks, "SessionStart", {}, { env: runtime.env, cwd: runtime.cwd }).then((outcome) => {
1610
1689
  for (const w of outcome.warnings) notice(w, "warn");
1611
1690
  }).catch(() => {
@@ -1622,7 +1701,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1622
1701
  editedInTurn.current = false;
1623
1702
  controller.current = new AbortController();
1624
1703
  const signal = controller.current.signal;
1625
- await runtime.agent.run(text, signal);
1704
+ const expandedText = expandAtFileMentions(text, runtime.cwd, runtime.agent.readFiles);
1705
+ await runtime.agent.run(expandedText, signal);
1626
1706
  const commands = runtime.config.verifyCommands;
1627
1707
  if (editedInTurn.current && commands.length && !signal.aborted) {
1628
1708
  for (let round = 0; round < MAX_VERIFY_ROUNDS; round++) {
@@ -1808,7 +1888,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1808
1888
  cwd: runtime.cwd,
1809
1889
  mcp: runtime.mcp.states(),
1810
1890
  usage: runtime.agent.totalUsage,
1811
- lastInputTokens: runtime.agent.lastInputTokens
1891
+ lastInputTokens: runtime.agent.lastInputTokens,
1892
+ contextWindow: runtime.agent.getContextWindow()
1812
1893
  })
1813
1894
  );
1814
1895
  return;
@@ -1958,7 +2039,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1958
2039
  notice(t("No file edits to undo."));
1959
2040
  return;
1960
2041
  }
1961
- const rel = (p) => relative(runtime.cwd, p) || p;
2042
+ const rel = (p) => relative2(runtime.cwd, p) || p;
1962
2043
  notice(
1963
2044
  [
1964
2045
  result.failed.length ? t("Could not restore: {files}", { files: result.failed.map(rel).join(", ") }) : "",
@@ -1976,7 +2057,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1976
2057
  notice(t("No file edits to redo."));
1977
2058
  return;
1978
2059
  }
1979
- const rel = (p) => relative(runtime.cwd, p) || p;
2060
+ const rel = (p) => relative2(runtime.cwd, p) || p;
1980
2061
  notice(
1981
2062
  [
1982
2063
  result.failed.length ? t("Could not restore: {files}", { files: result.failed.map(rel).join(", ") }) : "",
@@ -1994,7 +2075,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1994
2075
  notice(t("Nothing to rewind."));
1995
2076
  return;
1996
2077
  }
1997
- const rel = (p) => relative(runtime.cwd, p) || p;
2078
+ const rel = (p) => relative2(runtime.cwd, p) || p;
1998
2079
  notice(
1999
2080
  [
2000
2081
  result.failed.length ? t("Could not restore: {files}", { files: result.failed.map(rel).join(", ") }) : "",
@@ -2021,8 +2102,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
2021
2102
  }
2022
2103
  case "export": {
2023
2104
  const name2 = args || `bccli-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16).replace(/[:T]/g, "-")}.md`;
2024
- const file = resolve(runtime.cwd, name2);
2025
- if (existsSync2(file)) {
2105
+ const file = resolve2(runtime.cwd, name2);
2106
+ if (existsSync3(file)) {
2026
2107
  const answer2 = await ask(t("{file} already exists. Overwrite? (y/N)", { file }));
2027
2108
  if (!answer2 || !/^y(a|es)?$/i.test(answer2.trim())) {
2028
2109
  notice(t("Export cancelled."));
@@ -2045,6 +2126,42 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
2045
2126
  );
2046
2127
  return;
2047
2128
  }
2129
+ case "config": {
2130
+ const c = runtime.config;
2131
+ const applySetting = (key, val) => {
2132
+ if (key === "theme") writeGlobalConfig({ theme: val }, runtime.env);
2133
+ else if (key === "editor" && (val === "emacs" || val === "vim")) writeGlobalConfig({ editor: val }, runtime.env);
2134
+ else if (key === "repoMap") writeGlobalConfig({ repoMap: val === "true" || val === "on" }, runtime.env);
2135
+ else if (key === "thinkingVisible") writeGlobalConfig({ thinkingVisible: val === "true" || val === "on" }, runtime.env);
2136
+ else if (key === "sandbox" && (val === "on" || val === "off")) writeGlobalConfig({ sandbox: val }, runtime.env);
2137
+ else if (key === "networkPolicy" && (val === "allow" || val === "offline")) writeGlobalConfig({ networkPolicy: val }, runtime.env);
2138
+ else return false;
2139
+ runtime.reloadConfig();
2140
+ notice(`${key} = ${val}`);
2141
+ return true;
2142
+ };
2143
+ if (args.trim()) {
2144
+ const [k2, v] = args.trim().split(/\s+/);
2145
+ if (k2 && v && applySetting(k2, v)) return;
2146
+ }
2147
+ setListPicker({
2148
+ title: "Config",
2149
+ items: [
2150
+ { id: `editor:${c.editor === "vim" ? "emacs" : "vim"}`, label: `editor: ${c.editor}`, hint: "toggle emacs/vim" },
2151
+ { id: `repoMap:${!c.repoMap}`, label: `repoMap: ${c.repoMap}`, hint: "toggle true/false" },
2152
+ { id: `thinkingVisible:${!c.thinkingVisible}`, label: `thinkingVisible: ${!!c.thinkingVisible}`, hint: "toggle true/false" },
2153
+ { id: `sandbox:${c.sandbox === "on" ? "off" : "on"}`, label: `sandbox: ${c.sandbox}`, hint: "toggle on/off" },
2154
+ { id: `networkPolicy:${c.networkPolicy === "offline" ? "allow" : "offline"}`, label: `networkPolicy: ${c.networkPolicy ?? "allow"}`, hint: "toggle allow/offline" }
2155
+ ],
2156
+ onPick: (picked) => {
2157
+ setListPicker(null);
2158
+ if (!picked) return;
2159
+ const [k2, v] = picked.split(":");
2160
+ if (k2 && v) applySetting(k2, v);
2161
+ }
2162
+ });
2163
+ return;
2164
+ }
2048
2165
  default:
2049
2166
  notice(t("Unknown command: /{name}. Type /help.", { name }), "warn");
2050
2167
  }
@@ -2070,7 +2187,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
2070
2187
  else if (skill) {
2071
2188
  let body;
2072
2189
  try {
2073
- body = parseFrontmatter(readFileSync(skill.file, "utf8")).body;
2190
+ body = parseFrontmatter(readFileSync2(skill.file, "utf8")).body;
2074
2191
  } catch (error) {
2075
2192
  notice(t("Skill {name} cannot be read: {error}", { name: skill.name, error: error.code ?? error.message }), "error");
2076
2193
  return;
@@ -2113,7 +2230,8 @@ ARGUMENTS: ${slash.args}`);
2113
2230
  }
2114
2231
  }, [runtime, notice]);
2115
2232
  useEffect3(() => {
2116
- if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || pending || !stdin.isTTY || !stdout.isTTY || !thinkingTargetRef.current) return;
2233
+ const modalOpen = !!(pending || planAsk || picker || listPicker || mcpMenu || providerMenu || prompt);
2234
+ if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || modalOpen || !stdin.isTTY || !stdout.isTTY || !thinkingTargetRef.current) return;
2117
2235
  let click;
2118
2236
  let mouseBuffer = "";
2119
2237
  const onData = (data) => {
@@ -2139,13 +2257,13 @@ ARGUMENTS: ${slash.args}`);
2139
2257
  stdin.off("data", onData);
2140
2258
  stdout.write("\x1B[?1000l\x1B[?1006l");
2141
2259
  };
2142
- }, [busy, pending, stdin, stdout, toggleThinking, hasThinking, runtime.config.thinkingClickCollapse]);
2260
+ }, [busy, pending, planAsk, picker, listPicker, mcpMenu, providerMenu, prompt, stdin, stdout, toggleThinking, hasThinking, runtime.config.thinkingClickCollapse]);
2143
2261
  useInput9((input, key) => {
2144
2262
  if (key.tab && key.shift) {
2145
2263
  const next = nextMode(runtime.agent.permissions.mode);
2146
2264
  runtime.agent.permissions.mode = next;
2147
2265
  setMode(next);
2148
- } else if (key.escape && busy && !pending) {
2266
+ } else if (key.escape && busy && !pending && !planAsk) {
2149
2267
  controller.current?.abort();
2150
2268
  setCancelling(true);
2151
2269
  if (queued.length) {
@@ -2223,9 +2341,14 @@ ${t2.output}`);
2223
2341
  setPicker(await runtime.listModels(target));
2224
2342
  };
2225
2343
  const answer = (a) => {
2344
+ if (a === "all") {
2345
+ for (const item of asks) item.resolve("all");
2346
+ setAsks([]);
2347
+ setMode("allowAll");
2348
+ return;
2349
+ }
2226
2350
  pending?.resolve(a);
2227
2351
  setAsks((q) => q.slice(1));
2228
- if (a === "all") setMode("allowAll");
2229
2352
  };
2230
2353
  const cwd = runtime.cwd.startsWith(homedir()) ? `~${runtime.cwd.slice(homedir().length)}` : runtime.cwd;
2231
2354
  const renderEntry = (e) => {
@@ -2324,7 +2447,7 @@ ${t2.output}`);
2324
2447
  import { jsx as jsx17 } from "react/jsx-runtime";
2325
2448
  async function startInteractive(rt, opts) {
2326
2449
  if (opts.resume) {
2327
- const { Session: Session2 } = await import("./session-GKEXDJKZ.js");
2450
+ const { Session: Session2 } = await import("./session-YQXCCKXI.js");
2328
2451
  const list = Session2.list(rt.home, rt.cwd).slice(0, 20);
2329
2452
  if (!list.length) console.log(t("No sessions in this folder yet; starting a new one."));
2330
2453
  else {
@@ -2340,7 +2463,7 @@ async function startInteractive(rt, opts) {
2340
2463
  if (chosen) rt.resume(chosen.session);
2341
2464
  }
2342
2465
  }
2343
- const { serversToStart, setProjectTrust } = await import("./config-DIDLDONU.js");
2466
+ const { serversToStart, setProjectTrust } = await import("./config-ENDRMOTP.js");
2344
2467
  const plan = serversToStart(rt.home, rt.cwd);
2345
2468
  if (plan.needTrust.length) {
2346
2469
  const { createInterface } = await import("readline/promises");
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-BKGFA2PT.js";
4
+ } from "./chunk-266SY3MC.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-UZWJQF67.js";
7
+ } from "./chunk-3WHI4LN3.js";
8
8
 
9
9
  // src/update.ts
10
10
  import { spawnSync } from "child_process";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- helpText,
4
- parseCliArgs
5
- } from "./chunk-XV7ZVL4J.js";
6
- import "./chunk-MHIYLXJC.js";
7
- import "./chunk-BLOYFIAD.js";
8
- import "./chunk-FLQPE4S5.js";
9
- import "./chunk-UZWJQF67.js";
10
- export {
11
- helpText,
12
- parseCliArgs
13
- };
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- addProviderKey,
4
- runProviderCommand
5
- } from "./chunk-GN4W3T6E.js";
6
- import "./chunk-75BECX4F.js";
7
- import "./chunk-JHPGOAXU.js";
8
- import "./chunk-WNACAUDK.js";
9
- import "./chunk-BLOYFIAD.js";
10
- import "./chunk-FLQPE4S5.js";
11
- import "./chunk-UZWJQF67.js";
12
- export {
13
- addProviderKey,
14
- runProviderCommand
15
- };
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- Session,
4
- pruneSessions
5
- } from "./chunk-BC7UXFE4.js";
6
- import "./chunk-WNACAUDK.js";
7
- import "./chunk-BLOYFIAD.js";
8
- import "./chunk-UZWJQF67.js";
9
- export {
10
- Session,
11
- pruneSessions
12
- };
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- createRuntime,
4
- lunaPtcAutoEnabled
5
- } from "./chunk-PZRKU4UM.js";
6
- import "./chunk-QZKLZELZ.js";
7
- import "./chunk-BGXNR74O.js";
8
- import "./chunk-45SDLMTV.js";
9
- import "./chunk-PSO7R5AD.js";
10
- import "./chunk-MHIYLXJC.js";
11
- import "./chunk-GN4W3T6E.js";
12
- import "./chunk-75BECX4F.js";
13
- import "./chunk-JHPGOAXU.js";
14
- import "./chunk-MFHCQQEN.js";
15
- import "./chunk-BC7UXFE4.js";
16
- import "./chunk-WNACAUDK.js";
17
- import "./chunk-BLOYFIAD.js";
18
- import "./chunk-24JN75FZ.js";
19
- import "./chunk-FLQPE4S5.js";
20
- import "./chunk-UZWJQF67.js";
21
- export {
22
- createRuntime,
23
- lunaPtcAutoEnabled
24
- };