@botconnector/bccli 0.4.1 → 0.4.3

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 (71) hide show
  1. package/dist/{acp-3PHBAI64.js → acp-NU4HZHQO.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-MFHCQQEN.js → chunk-3I5BW3ZT.js} +3 -2
  8. package/dist/{chunk-UZWJQF67.js → chunk-3WHI4LN3.js} +2 -1
  9. package/dist/{chunk-BGXNR74O.js → chunk-4W5SKQDC.js} +152 -31
  10. package/dist/{chunk-BC7UXFE4.js → chunk-6AUROP2E.js} +64 -3
  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-75BECX4F.js → chunk-7I2ZGPUS.js} +4 -4
  14. package/dist/{chunk-BKGFA2PT.js → chunk-FUJGHCWN.js} +1 -1
  15. package/dist/{chunk-GN4W3T6E.js → chunk-GWVLPN4B.js} +4 -4
  16. package/dist/{chunk-JHPGOAXU.js → chunk-HQW4BROS.js} +4 -5
  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-QNUJHKEL.js} +659 -162
  22. package/dist/{chunk-FLQPE4S5.js → chunk-RX4UQX43.js} +4 -1
  23. package/dist/{chunk-R5RE46CW.js → chunk-WDX62DFH.js} +40 -6
  24. package/dist/{chunk-MHIYLXJC.js → chunk-WFZKJY3R.js} +8 -4
  25. package/dist/{chunk-WNACAUDK.js → chunk-XTOATEI6.js} +66 -9
  26. package/dist/{chunk-BXQQCUAC.js → chunk-Z5NI5FIK.js} +7 -7
  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-GCIUUMKQ.js} +21 -20
  33. package/dist/{integrationCli-Q2YPDTPG.js → integrationCli-HXCSEWH2.js} +2 -2
  34. package/dist/{login-FP3BB44A.js → login-YXSSB2HQ.js} +4 -4
  35. package/dist/lsp.d.ts +26 -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-656AKYZD.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-V2576JXE.js +15 -0
  46. package/dist/sdk.d.ts +5 -1
  47. package/dist/sdk.js +1003 -230
  48. package/dist/{serve-KWOECK5W.js → serve-K5AH4MGO.js} +3 -3
  49. package/dist/{serve-X2ZV4S5U.js → serve-XPAGXIGS.js} +17 -17
  50. package/dist/session-V2VCAF7E.js +12 -0
  51. package/dist/session.d.ts +3 -0
  52. package/dist/setup-HVVHOIL4.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/diagnostics.d.ts +8 -0
  57. package/dist/tools/edit.d.ts +7 -2
  58. package/dist/tools/grep.d.ts +14 -2
  59. package/dist/tools/ignore.d.ts +2 -2
  60. package/dist/tools/paths.d.ts +2 -0
  61. package/dist/tools/sandbox.d.ts +3 -0
  62. package/dist/{transferCli-YUFPI6AH.js → transferCli-C6XS6QYH.js} +8 -6
  63. package/dist/ui/complete.d.ts +5 -0
  64. package/dist/ui/vim.d.ts +1 -1
  65. package/dist/{ui-IVIFNUCC.js → ui-43C6Y57K.js} +199 -54
  66. package/dist/{update-TZ2G6KQ3.js → update-AVZO4XID.js} +2 -2
  67. package/package.json +1 -1
  68. package/dist/args-W6BNKY7K.js +0 -13
  69. package/dist/providerCli-NMUFXAAS.js +0 -15
  70. package/dist/session-GKEXDJKZ.js +0 -12
  71. 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-WDX62DFH.js";
13
13
  import {
14
14
  BUILTIN_AGENTS,
15
15
  appendMemory,
@@ -18,60 +18,64 @@ import {
18
18
  normalizeGlobPath,
19
19
  parseFrontmatter,
20
20
  parseMemoryArgs,
21
+ recordFileMtime,
21
22
  renderBackgroundTasks,
23
+ resolveShell,
24
+ runCommand,
22
25
  runHooks,
23
26
  validateGlobPattern
24
- } from "./chunk-BGXNR74O.js";
27
+ } from "./chunk-4W5SKQDC.js";
25
28
  import "./chunk-PSO7R5AD.js";
26
29
  import {
27
- nextMode
28
- } from "./chunk-MHIYLXJC.js";
30
+ nextMode,
31
+ requiresSensitiveToolApproval
32
+ } from "./chunk-WFZKJY3R.js";
29
33
  import {
30
34
  hasKey,
31
35
  providerName,
32
36
  writeGlobalConfig
33
- } from "./chunk-JHPGOAXU.js";
37
+ } from "./chunk-HQW4BROS.js";
34
38
  import {
35
39
  Session
36
- } from "./chunk-BC7UXFE4.js";
40
+ } from "./chunk-6AUROP2E.js";
37
41
  import {
38
42
  contentText
39
- } from "./chunk-WNACAUDK.js";
43
+ } from "./chunk-XTOATEI6.js";
40
44
  import {
41
45
  REASONING_LEVELS,
42
46
  assertReasoningSupported,
43
47
  parseReasoningLevel,
44
48
  supportedReasoningLevels
45
- } from "./chunk-BLOYFIAD.js";
49
+ } from "./chunk-KPTML72Q.js";
46
50
  import {
47
51
  addGlobalServer,
48
52
  globalMcpPath,
49
53
  readMcpFile,
50
54
  removeGlobalServer
51
- } from "./chunk-24JN75FZ.js";
55
+ } from "./chunk-6M55UPES.js";
52
56
  import {
53
57
  ACCENT,
54
58
  PRESETS,
55
59
  color,
56
60
  matchKeybind,
57
61
  removeCredential
58
- } from "./chunk-FLQPE4S5.js";
62
+ } from "./chunk-RX4UQX43.js";
59
63
  import {
60
64
  getLanguage,
61
65
  locale,
62
66
  parseLang,
63
67
  setLanguage,
64
68
  t
65
- } from "./chunk-UZWJQF67.js";
69
+ } from "./chunk-3WHI4LN3.js";
66
70
 
67
71
  // src/ui/index.tsx
68
72
  import { render } from "ink";
69
73
 
70
74
  // src/ui/App.tsx
71
75
  import { execFile as execFile3 } from "child_process";
72
- import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
76
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
73
77
  import { homedir, tmpdir } from "os";
74
- import { dirname, join as join3, relative, resolve } from "path";
78
+ import { dirname, join as join3, relative as relative2, resolve as resolve2 } from "path";
75
79
  import { Box as Box13, Static, Text as Text16, measureElement, useApp, useInput as useInput9, useStdin, useStdout as useStdout2 } from "ink";
76
80
  import { useCallback, useEffect as useEffect3, useRef, useState as useState8 } from "react";
77
81
 
@@ -106,6 +110,7 @@ var SLASH_COMMANDS = [
106
110
  { name: "clear", description: "start a new conversation" },
107
111
  { name: "compact", description: "summarize the conversation" },
108
112
  { name: "cost", description: "token usage of this session" },
113
+ { name: "config", description: "view or change configuration settings" },
109
114
  { name: "tasks", description: "list background tasks" },
110
115
  { name: "exit", description: "quit" }
111
116
  ];
@@ -139,12 +144,12 @@ function osc52(text, inTmux) {
139
144
  // src/slash/diff.ts
140
145
  import { execFile } from "child_process";
141
146
  function git(cwd, args, bin = "git") {
142
- return new Promise((resolve2) => {
147
+ return new Promise((resolve3) => {
143
148
  execFile(
144
149
  bin,
145
150
  args,
146
151
  { cwd, maxBuffer: 20 * 1024 * 1024 },
147
- (error, stdout, stderr) => resolve2({ ok: !error, out: error ? stderr : stdout, missing: error?.code === "ENOENT" })
152
+ (error, stdout, stderr) => resolve3({ ok: !error, out: error ? stderr : stdout, missing: error?.code === "ENOENT" })
148
153
  );
149
154
  });
150
155
  }
@@ -203,6 +208,8 @@ var k = (n) => n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
203
208
  function statusText(s) {
204
209
  const ready = s.mcp.filter((m) => m.status === "ready").length;
205
210
  const errors = s.mcp.filter((m) => m.status === "error").length;
211
+ const win = s.contextWindow && s.contextWindow > 0 ? s.contextWindow : 128e3;
212
+ const ctxLine = t("Context: ~{pct}% of 128k", { pct: Math.round(s.lastInputTokens / win * 100) }).replace("128k", k(win));
206
213
  return [
207
214
  `BCCLI ${s.version}`,
208
215
  `Model: ${s.modelRef} (${s.providerLabel})`,
@@ -211,7 +218,7 @@ function statusText(s) {
211
218
  t("MCP: {ready} active, {errors} errors", { ready, errors }),
212
219
  t("Session tokens: {input} in \xB7 {output} out", { input: k(s.usage.inputTokens), output: k(s.usage.outputTokens) }),
213
220
  `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) })
221
+ ctxLine
215
222
  ].join("\n");
216
223
  }
217
224
  function agentsText(defs) {
@@ -868,6 +875,7 @@ function ListPicker({ title, items, onPick }) {
868
875
  const shown = items.filter((i) => i.label.toLowerCase().includes(filter.toLowerCase()));
869
876
  const cursor = Math.min(index, Math.max(0, shown.length - 1));
870
877
  useInput2((input, key) => {
878
+ if (isMouseControlInput(input)) return;
871
879
  if (key.upArrow) setIndex(Math.max(0, cursor - 1));
872
880
  else if (key.downArrow) setIndex(Math.min(shown.length - 1, cursor + 1));
873
881
  else if (key.return && !shown[cursor]?.disabled) onPick(shown[cursor]?.id);
@@ -911,6 +919,7 @@ function ModelPicker({ groups, current, onPick }) {
911
919
  const selectable = rows.flatMap((r, i) => r.kind === "model" ? [i] : []);
912
920
  const cursor = selectable[Math.min(index, selectable.length - 1)] ?? -1;
913
921
  useInput3((input, key) => {
922
+ if (isMouseControlInput(input)) return;
914
923
  if (key.upArrow) setIndex((i) => Math.max(0, i - 1));
915
924
  else if (key.downArrow) setIndex((i) => Math.min(selectable.length - 1, i + 1));
916
925
  else if (key.return) {
@@ -1007,9 +1016,9 @@ import { Box as Box8, Text as Text9, useInput as useInput6 } from "ink";
1007
1016
  import { useEffect, useState as useState5 } from "react";
1008
1017
 
1009
1018
  // src/ui/complete.ts
1010
- import { globSync } from "fs";
1011
- import { statSync } from "fs";
1012
- import { join } from "path";
1019
+ import { existsSync, globSync, readFileSync, statSync } from "fs";
1020
+ import { isAbsolute, join, relative, resolve } from "path";
1021
+ var MAX_ATTACH_BYTES = 32768;
1013
1022
  function completeFile(value, cwd) {
1014
1023
  const match = /(^|\s)@([^\s]*)$/.exec(value);
1015
1024
  if (!match) return value;
@@ -1017,21 +1026,62 @@ function completeFile(value, cwd) {
1017
1026
  const escaped = prefix.replace(/([*?[\]{}()!])/g, "\\$1");
1018
1027
  const pattern = `${escaped}*`;
1019
1028
  if (validateGlobPattern(pattern)) return value;
1020
- const found = globSync(pattern, { cwd, exclude: ignorePatterns(cwd) }).map((entry2) => {
1029
+ const exclude = ignorePatterns(cwd);
1030
+ const formatEntry = (entry2) => {
1021
1031
  const normalized = normalizeGlobPath(entry2);
1022
1032
  try {
1023
1033
  return statSync(join(cwd, entry2)).isDirectory() ? `${normalized}/` : normalized;
1024
1034
  } catch {
1025
1035
  return normalized;
1026
1036
  }
1027
- }).sort();
1037
+ };
1038
+ let found = globSync(pattern, { cwd, exclude }).map(formatEntry).sort();
1039
+ if (!found.length && prefix && !prefix.includes("/")) {
1040
+ const deepPattern = `**/*${escaped}*`;
1041
+ if (!validateGlobPattern(deepPattern)) {
1042
+ found = globSync(deepPattern, { cwd, exclude }).map(formatEntry).sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b));
1043
+ }
1044
+ }
1028
1045
  if (!found.length) return value;
1029
1046
  const pick = found[0];
1030
1047
  return `${value.slice(0, value.length - prefix.length)}${pick}${pick.endsWith("/") ? "" : " "}`;
1031
1048
  }
1049
+ function expandAtFileMentions(prompt, cwd, readFiles) {
1050
+ const matches = [...prompt.matchAll(/(?:^|\s)@([^\s]+)/g)];
1051
+ if (!matches.length) return prompt;
1052
+ const blocks = [];
1053
+ const seen = /* @__PURE__ */ new Set();
1054
+ for (const m of matches) {
1055
+ const rawPath = m[1];
1056
+ if (!rawPath || seen.has(rawPath)) continue;
1057
+ seen.add(rawPath);
1058
+ if (requiresSensitiveToolApproval({ tool: "read", kind: "read", target: rawPath })) continue;
1059
+ const abs = resolve(cwd, rawPath);
1060
+ const rel = relative(cwd, abs);
1061
+ if (!rel || rel.startsWith("..") || isAbsolute(rel)) continue;
1062
+ try {
1063
+ if (!existsSync(abs) || !statSync(abs).isFile() || statSync(abs).size > MAX_ATTACH_BYTES) continue;
1064
+ const buf = readFileSync(abs);
1065
+ if (buf.subarray(0, 4e3).includes(0)) continue;
1066
+ if (readFiles) recordFileMtime(readFiles, abs);
1067
+ blocks.push(`<file path="${rawPath}">
1068
+ ${buf.toString("utf8")}
1069
+ </file>`);
1070
+ } catch {
1071
+ }
1072
+ }
1073
+ return blocks.length ? `${prompt}
1074
+
1075
+ ${blocks.join("\n\n")}` : prompt;
1076
+ }
1032
1077
 
1033
1078
  // src/ui/vim.ts
1034
- var clamp = (s) => ({ value: s.value, cursor: Math.min(s.cursor, Math.max(0, s.value.length - 1)) });
1079
+ var clamp = (s) => {
1080
+ const start = lineStart(s.value, s.cursor);
1081
+ const end = lineEnd(s.value, s.cursor);
1082
+ if (s.cursor < end) return s;
1083
+ return { value: s.value, cursor: Math.max(start, prevBoundary(s.value, end)) };
1084
+ };
1035
1085
  var wordStart = (text, pos) => {
1036
1086
  let i = wordRight(text, pos);
1037
1087
  while (i < text.length && /\s/.test(text[i])) i++;
@@ -1052,19 +1102,20 @@ function applyVim(s, mode, input, key, pending) {
1052
1102
  if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow || key.ctrl || key.meta || key.tab || key.return) {
1053
1103
  return { state: s, mode, pending, handled: false };
1054
1104
  }
1055
- if (pending === "d") {
1056
- if (input === "d") return { state: deleteLine(s), mode, handled: true };
1105
+ if (pending === "d" || pending === "c") {
1106
+ const nextMode2 = pending === "c" ? "insert" : mode;
1107
+ if (input === pending) return { state: deleteLine(s), mode: nextMode2, handled: true };
1057
1108
  if (input === "w") {
1058
1109
  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 };
1110
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(to), cursor: s.cursor }, mode: nextMode2, handled: true };
1060
1111
  }
1061
1112
  return { state: s, mode, handled: true };
1062
1113
  }
1063
1114
  switch (input) {
1064
1115
  case "h":
1065
- return { state: { ...s, cursor: Math.max(lineStart(s.value, s.cursor), s.cursor - 1) }, mode, handled: true };
1116
+ return { state: { ...s, cursor: Math.max(lineStart(s.value, s.cursor), prevBoundary(s.value, s.cursor)) }, mode, handled: true };
1066
1117
  case "l":
1067
- return { state: { ...s, cursor: Math.min(lineEnd(s.value, s.cursor), s.cursor + 1) }, mode, handled: true };
1118
+ return { state: { ...s, cursor: Math.min(lineEnd(s.value, s.cursor), nextBoundary(s.value, s.cursor)) }, mode, handled: true };
1068
1119
  case "j": {
1069
1120
  const moved = moveLine(s.value, s.cursor, 1);
1070
1121
  return { state: moved === void 0 ? s : { ...s, cursor: moved }, mode, handled: true };
@@ -1075,6 +1126,8 @@ function applyVim(s, mode, input, key, pending) {
1075
1126
  }
1076
1127
  case "w":
1077
1128
  return { state: { ...s, cursor: wordStart(s.value, s.cursor) }, mode, handled: true };
1129
+ case "e":
1130
+ return { state: { ...s, cursor: Math.max(s.cursor, prevBoundary(s.value, wordRight(s.value, s.cursor))) }, mode, handled: true };
1078
1131
  case "b":
1079
1132
  return { state: { ...s, cursor: wordLeft(s.value, s.cursor) }, mode, handled: true };
1080
1133
  case "0":
@@ -1083,12 +1136,28 @@ function applyVim(s, mode, input, key, pending) {
1083
1136
  return { state: { ...s, cursor: lineEnd(s.value, s.cursor) }, mode, handled: true };
1084
1137
  case "x": {
1085
1138
  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 };
1139
+ const next = nextBoundary(s.value, s.cursor);
1140
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(next), cursor: s.cursor }, mode, handled: true };
1141
+ }
1142
+ case "D": {
1143
+ const end = lineEnd(s.value, s.cursor);
1144
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(end), cursor: s.cursor }, mode, handled: true };
1145
+ }
1146
+ case "C": {
1147
+ const end = lineEnd(s.value, s.cursor);
1148
+ return { state: { value: s.value.slice(0, s.cursor) + s.value.slice(end), cursor: s.cursor }, mode: "insert", handled: true };
1087
1149
  }
1088
1150
  case "i":
1089
1151
  return { state: s, mode: "insert", handled: true };
1152
+ case "I": {
1153
+ const start = lineStart(s.value, s.cursor);
1154
+ const end = lineEnd(s.value, s.cursor);
1155
+ let pos = start;
1156
+ while (pos < end && (s.value[pos] === " " || s.value[pos] === " ")) pos++;
1157
+ return { state: { ...s, cursor: pos }, mode: "insert", handled: true };
1158
+ }
1090
1159
  case "a":
1091
- return { state: { ...s, cursor: Math.min(s.cursor + 1, s.value.length) }, mode: "insert", handled: true };
1160
+ return { state: { ...s, cursor: Math.min(lineEnd(s.value, s.cursor), nextBoundary(s.value, s.cursor)) }, mode: "insert", handled: true };
1092
1161
  case "A":
1093
1162
  return { state: { ...s, cursor: lineEnd(s.value, s.cursor) }, mode: "insert", handled: true };
1094
1163
  case "o": {
@@ -1102,7 +1171,8 @@ ${s.value.slice(end)}`, cursor: end + 1 }, mode: "insert", handled: true };
1102
1171
  ${s.value.slice(start)}`, cursor: start }, mode: "insert", handled: true };
1103
1172
  }
1104
1173
  case "d":
1105
- return { state: s, mode, pending: "d", handled: true };
1174
+ case "c":
1175
+ return { state: s, mode, pending: input, handled: true };
1106
1176
  default:
1107
1177
  return { state: s, mode, handled: true };
1108
1178
  }
@@ -1115,6 +1185,7 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1115
1185
  const { value } = line;
1116
1186
  const [historyIndex, setHistoryIndex] = useState5(null);
1117
1187
  const [selected, setSelected] = useState5(0);
1188
+ const [dismissed, setDismissed] = useState5(false);
1118
1189
  const [vimMode, setVimMode] = useState5("insert");
1119
1190
  const [vimPending, setVimPending] = useState5(void 0);
1120
1191
  const injectedSeen = useState5(0);
@@ -1126,17 +1197,23 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1126
1197
  }
1127
1198
  }, [injected, injectedSeen]);
1128
1199
  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) : [];
1200
+ const suggestions = historyIndex === null && !dismissed && value.startsWith("/") && !/\s/.test(value) ? all.filter((c) => c.name.startsWith(value.slice(1))).slice(0, 8) : [];
1130
1201
  const highlighted = Math.min(selected, Math.max(0, suggestions.length - 1));
1131
1202
  const typed = (text) => ({ value: text, cursor: text.length });
1132
1203
  const edit = (next) => {
1133
1204
  setLine(next);
1134
1205
  setSelected(0);
1206
+ setDismissed(false);
1207
+ setHistoryIndex(null);
1135
1208
  };
1136
1209
  useInput6(
1137
1210
  (input, key) => {
1138
1211
  if (isMouseControlInput(input)) return;
1139
1212
  if (suggestions.length) {
1213
+ if (key.escape) {
1214
+ setDismissed(true);
1215
+ return;
1216
+ }
1140
1217
  if (key.upArrow) {
1141
1218
  setSelected(Math.max(0, highlighted - 1));
1142
1219
  return;
@@ -1149,7 +1226,7 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1149
1226
  edit(typed(`/${suggestions[highlighted].name} `));
1150
1227
  return;
1151
1228
  }
1152
- if (key.return) {
1229
+ if (key.return && !key.meta) {
1153
1230
  edit(typed(""));
1154
1231
  setHistoryIndex(null);
1155
1232
  onSubmit(`/${suggestions[highlighted].name}`);
@@ -1166,6 +1243,10 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands, injected
1166
1243
  return;
1167
1244
  }
1168
1245
  }
1246
+ if (key.return && key.meta || key.ctrl && input.toLowerCase() === "j") {
1247
+ edit((current) => insert(current, "\n"));
1248
+ return;
1249
+ }
1169
1250
  if (key.return) {
1170
1251
  const before = value.slice(0, line.cursor);
1171
1252
  if (before.endsWith("\\")) {
@@ -1450,7 +1531,7 @@ function replayEntries(history) {
1450
1531
 
1451
1532
  // src/clipboardImage.ts
1452
1533
  import { execFile as execFile2 } from "child_process";
1453
- import { existsSync, statSync as statSync2 } from "fs";
1534
+ import { existsSync as existsSync2, statSync as statSync2 } from "fs";
1454
1535
  import { join as join2 } from "path";
1455
1536
  function clipboardTarget(tmpdir2, now) {
1456
1537
  const stamp = now.toISOString().replace(/[-:]/g, "").replace("T", "-").slice(0, 15);
@@ -1501,10 +1582,10 @@ function clipboardCommand(platform, target) {
1501
1582
  }
1502
1583
  return void 0;
1503
1584
  }
1504
- var defaultRun = (cmd, args) => new Promise((resolve2) => {
1585
+ var defaultRun = (cmd, args) => new Promise((resolve3) => {
1505
1586
  execFile2(cmd, args, { timeout: 15e3, windowsHide: true }, (error, stdout) => {
1506
1587
  const code = error ? error.code ?? 1 : 0;
1507
- resolve2({ code: typeof code === "number" ? code : 1, output: String(stdout ?? "") });
1588
+ resolve3({ code: typeof code === "number" ? code : 1, output: String(stdout ?? "") });
1508
1589
  });
1509
1590
  });
1510
1591
  async function grabClipboardImage(deps) {
@@ -1513,7 +1594,7 @@ async function grabClipboardImage(deps) {
1513
1594
  if (!command) return void 0;
1514
1595
  const run = deps.run ?? defaultRun;
1515
1596
  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;
1597
+ if (r.code === 0 && r.output.includes("OK") && existsSync2(target) && statSync2(target).size > 0) return target;
1517
1598
  return void 0;
1518
1599
  }
1519
1600
 
@@ -1553,7 +1634,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1553
1634
  const [picker, setPicker] = useState8(null);
1554
1635
  const [providerMenu, setProviderMenu] = useState8(null);
1555
1636
  const [prompt, setPrompt] = useState8(null);
1556
- const ask = useCallback((label, mask = false) => new Promise((resolve2) => setPrompt({ label, mask, resolve: resolve2 })), []);
1637
+ const ask = useCallback((label, mask = false) => new Promise((resolve3) => setPrompt({ label, mask, resolve: resolve3 })), []);
1557
1638
  const [modelLabel, setModelLabel] = useState8(() => labelFor(runtime, runtime.modelRef));
1558
1639
  const [history, setHistory] = useState8([]);
1559
1640
  const controller = useRef(null);
@@ -1604,8 +1685,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1604
1685
  }, [notice]);
1605
1686
  useEffect3(() => {
1606
1687
  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 }));
1688
+ runtime.agent.askPermission = (request) => new Promise((resolve3) => setAsks((q) => [...q, { id: askId.current++, request, resolve: resolve3 }]));
1689
+ runtime.interaction.approvePlan = (plan) => new Promise((resolve3) => setPlanAsk({ plan, resolve: resolve3 }));
1609
1690
  runHooks(runtime.config.hooks, "SessionStart", {}, { env: runtime.env, cwd: runtime.cwd }).then((outcome) => {
1610
1691
  for (const w of outcome.warnings) notice(w, "warn");
1611
1692
  }).catch(() => {
@@ -1622,7 +1703,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1622
1703
  editedInTurn.current = false;
1623
1704
  controller.current = new AbortController();
1624
1705
  const signal = controller.current.signal;
1625
- await runtime.agent.run(text, signal);
1706
+ const expandedText = expandAtFileMentions(text, runtime.cwd, runtime.agent.readFiles);
1707
+ await runtime.agent.run(expandedText, signal);
1626
1708
  const commands = runtime.config.verifyCommands;
1627
1709
  if (editedInTurn.current && commands.length && !signal.aborted) {
1628
1710
  for (let round = 0; round < MAX_VERIFY_ROUNDS; round++) {
@@ -1808,7 +1890,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1808
1890
  cwd: runtime.cwd,
1809
1891
  mcp: runtime.mcp.states(),
1810
1892
  usage: runtime.agent.totalUsage,
1811
- lastInputTokens: runtime.agent.lastInputTokens
1893
+ lastInputTokens: runtime.agent.lastInputTokens,
1894
+ contextWindow: runtime.agent.getContextWindow()
1812
1895
  })
1813
1896
  );
1814
1897
  return;
@@ -1958,7 +2041,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1958
2041
  notice(t("No file edits to undo."));
1959
2042
  return;
1960
2043
  }
1961
- const rel = (p) => relative(runtime.cwd, p) || p;
2044
+ const rel = (p) => relative2(runtime.cwd, p) || p;
1962
2045
  notice(
1963
2046
  [
1964
2047
  result.failed.length ? t("Could not restore: {files}", { files: result.failed.map(rel).join(", ") }) : "",
@@ -1976,7 +2059,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1976
2059
  notice(t("No file edits to redo."));
1977
2060
  return;
1978
2061
  }
1979
- const rel = (p) => relative(runtime.cwd, p) || p;
2062
+ const rel = (p) => relative2(runtime.cwd, p) || p;
1980
2063
  notice(
1981
2064
  [
1982
2065
  result.failed.length ? t("Could not restore: {files}", { files: result.failed.map(rel).join(", ") }) : "",
@@ -1994,7 +2077,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
1994
2077
  notice(t("Nothing to rewind."));
1995
2078
  return;
1996
2079
  }
1997
- const rel = (p) => relative(runtime.cwd, p) || p;
2080
+ const rel = (p) => relative2(runtime.cwd, p) || p;
1998
2081
  notice(
1999
2082
  [
2000
2083
  result.failed.length ? t("Could not restore: {files}", { files: result.failed.map(rel).join(", ") }) : "",
@@ -2021,8 +2104,8 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
2021
2104
  }
2022
2105
  case "export": {
2023
2106
  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)) {
2107
+ const file = resolve2(runtime.cwd, name2);
2108
+ if (existsSync3(file)) {
2026
2109
  const answer2 = await ask(t("{file} already exists. Overwrite? (y/N)", { file }));
2027
2110
  if (!answer2 || !/^y(a|es)?$/i.test(answer2.trim())) {
2028
2111
  notice(t("Export cancelled."));
@@ -2045,6 +2128,42 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
2045
2128
  );
2046
2129
  return;
2047
2130
  }
2131
+ case "config": {
2132
+ const c = runtime.config;
2133
+ const applySetting = (key, val) => {
2134
+ if (key === "theme") writeGlobalConfig({ theme: val }, runtime.env);
2135
+ else if (key === "editor" && (val === "emacs" || val === "vim")) writeGlobalConfig({ editor: val }, runtime.env);
2136
+ else if (key === "repoMap") writeGlobalConfig({ repoMap: val === "true" || val === "on" }, runtime.env);
2137
+ else if (key === "thinkingVisible") writeGlobalConfig({ thinkingVisible: val === "true" || val === "on" }, runtime.env);
2138
+ else if (key === "sandbox" && (val === "on" || val === "off")) writeGlobalConfig({ sandbox: val }, runtime.env);
2139
+ else if (key === "networkPolicy" && (val === "allow" || val === "offline")) writeGlobalConfig({ networkPolicy: val }, runtime.env);
2140
+ else return false;
2141
+ runtime.reloadConfig();
2142
+ notice(`${key} = ${val}`);
2143
+ return true;
2144
+ };
2145
+ if (args.trim()) {
2146
+ const [k2, v] = args.trim().split(/\s+/);
2147
+ if (k2 && v && applySetting(k2, v)) return;
2148
+ }
2149
+ setListPicker({
2150
+ title: "Config",
2151
+ items: [
2152
+ { id: `editor:${c.editor === "vim" ? "emacs" : "vim"}`, label: `editor: ${c.editor}`, hint: "toggle emacs/vim" },
2153
+ { id: `repoMap:${!c.repoMap}`, label: `repoMap: ${c.repoMap}`, hint: "toggle true/false" },
2154
+ { id: `thinkingVisible:${!c.thinkingVisible}`, label: `thinkingVisible: ${!!c.thinkingVisible}`, hint: "toggle true/false" },
2155
+ { id: `sandbox:${c.sandbox === "on" ? "off" : "on"}`, label: `sandbox: ${c.sandbox}`, hint: "toggle on/off" },
2156
+ { id: `networkPolicy:${c.networkPolicy === "offline" ? "allow" : "offline"}`, label: `networkPolicy: ${c.networkPolicy ?? "allow"}`, hint: "toggle allow/offline" }
2157
+ ],
2158
+ onPick: (picked) => {
2159
+ setListPicker(null);
2160
+ if (!picked) return;
2161
+ const [k2, v] = picked.split(":");
2162
+ if (k2 && v) applySetting(k2, v);
2163
+ }
2164
+ });
2165
+ return;
2166
+ }
2048
2167
  default:
2049
2168
  notice(t("Unknown command: /{name}. Type /help.", { name }), "warn");
2050
2169
  }
@@ -2058,6 +2177,26 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
2058
2177
  const submit = useCallback(
2059
2178
  (text) => {
2060
2179
  setHistory((h) => [...h, text]);
2180
+ if (text.startsWith("#") && text.slice(1).trim()) {
2181
+ void runSlash("memory", text.slice(1).trim());
2182
+ return;
2183
+ }
2184
+ if (text.startsWith("!") && text.slice(1).trim()) {
2185
+ const cmd = text.slice(1).trim();
2186
+ setTranscript((tr) => ({ ...tr, done: [...tr.done, entry({ kind: "user", text })] }));
2187
+ const shell = resolveShell({ platform: process.platform, env: runtime.env, exists: existsSync3 });
2188
+ void runCommand(cmd, { cwd: runtime.cwd, timeoutMs: 6e4, signal: new AbortController().signal, shell }).then((r) => {
2189
+ const out = r.output.trim() || "(no output)";
2190
+ notice(`$ ${cmd}
2191
+ ${out}`, r.exitCode ? "error" : "info");
2192
+ const ctxMsg = { role: "user", content: `Local shell command executed:
2193
+ $ ${cmd}
2194
+ ${out}` };
2195
+ runtime.agent.messages.push(ctxMsg);
2196
+ runtime.session.append(ctxMsg);
2197
+ });
2198
+ return;
2199
+ }
2061
2200
  const slash = parseSlash(text);
2062
2201
  if (!slash) {
2063
2202
  void runTurn(text);
@@ -2070,7 +2209,7 @@ function App({ runtime, initialPrompt, version, updateMessage }) {
2070
2209
  else if (skill) {
2071
2210
  let body;
2072
2211
  try {
2073
- body = parseFrontmatter(readFileSync(skill.file, "utf8")).body;
2212
+ body = parseFrontmatter(readFileSync2(skill.file, "utf8")).body;
2074
2213
  } catch (error) {
2075
2214
  notice(t("Skill {name} cannot be read: {error}", { name: skill.name, error: error.code ?? error.message }), "error");
2076
2215
  return;
@@ -2113,7 +2252,8 @@ ARGUMENTS: ${slash.args}`);
2113
2252
  }
2114
2253
  }, [runtime, notice]);
2115
2254
  useEffect3(() => {
2116
- if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || pending || !stdin.isTTY || !stdout.isTTY || !thinkingTargetRef.current) return;
2255
+ const modalOpen = !!(pending || planAsk || picker || listPicker || mcpMenu || providerMenu || prompt);
2256
+ if (!runtime.config.thinkingClickCollapse || !busy && !hasThinking || modalOpen || !stdin.isTTY || !stdout.isTTY || !thinkingTargetRef.current) return;
2117
2257
  let click;
2118
2258
  let mouseBuffer = "";
2119
2259
  const onData = (data) => {
@@ -2139,13 +2279,13 @@ ARGUMENTS: ${slash.args}`);
2139
2279
  stdin.off("data", onData);
2140
2280
  stdout.write("\x1B[?1000l\x1B[?1006l");
2141
2281
  };
2142
- }, [busy, pending, stdin, stdout, toggleThinking, hasThinking, runtime.config.thinkingClickCollapse]);
2282
+ }, [busy, pending, planAsk, picker, listPicker, mcpMenu, providerMenu, prompt, stdin, stdout, toggleThinking, hasThinking, runtime.config.thinkingClickCollapse]);
2143
2283
  useInput9((input, key) => {
2144
2284
  if (key.tab && key.shift) {
2145
2285
  const next = nextMode(runtime.agent.permissions.mode);
2146
2286
  runtime.agent.permissions.mode = next;
2147
2287
  setMode(next);
2148
- } else if (key.escape && busy && !pending) {
2288
+ } else if (key.escape && busy && !pending && !planAsk) {
2149
2289
  controller.current?.abort();
2150
2290
  setCancelling(true);
2151
2291
  if (queued.length) {
@@ -2223,9 +2363,14 @@ ${t2.output}`);
2223
2363
  setPicker(await runtime.listModels(target));
2224
2364
  };
2225
2365
  const answer = (a) => {
2366
+ if (a === "all") {
2367
+ for (const item of asks) item.resolve("all");
2368
+ setAsks([]);
2369
+ setMode("allowAll");
2370
+ return;
2371
+ }
2226
2372
  pending?.resolve(a);
2227
2373
  setAsks((q) => q.slice(1));
2228
- if (a === "all") setMode("allowAll");
2229
2374
  };
2230
2375
  const cwd = runtime.cwd.startsWith(homedir()) ? `~${runtime.cwd.slice(homedir().length)}` : runtime.cwd;
2231
2376
  const renderEntry = (e) => {
@@ -2324,7 +2469,7 @@ ${t2.output}`);
2324
2469
  import { jsx as jsx17 } from "react/jsx-runtime";
2325
2470
  async function startInteractive(rt, opts) {
2326
2471
  if (opts.resume) {
2327
- const { Session: Session2 } = await import("./session-GKEXDJKZ.js");
2472
+ const { Session: Session2 } = await import("./session-V2VCAF7E.js");
2328
2473
  const list = Session2.list(rt.home, rt.cwd).slice(0, 20);
2329
2474
  if (!list.length) console.log(t("No sessions in this folder yet; starting a new one."));
2330
2475
  else {
@@ -2340,7 +2485,7 @@ async function startInteractive(rt, opts) {
2340
2485
  if (chosen) rt.resume(chosen.session);
2341
2486
  }
2342
2487
  }
2343
- const { serversToStart, setProjectTrust } = await import("./config-DIDLDONU.js");
2488
+ const { serversToStart, setProjectTrust } = await import("./config-ENDRMOTP.js");
2344
2489
  const plan = serversToStart(rt.home, rt.cwd);
2345
2490
  if (plan.needTrust.length) {
2346
2491
  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-FUJGHCWN.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.3",
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
- };