@botconnector/bccli 0.4.0-beta.30 → 0.4.0-beta.32

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.
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  helpText,
4
4
  parseCliArgs
5
- } from "./chunk-ON6JYPE7.js";
5
+ } from "./chunk-NM3C75BT.js";
6
6
  import "./chunk-ELML4KVQ.js";
7
- import "./chunk-SN3ODJZN.js";
8
- import "./chunk-EO7IVVX4.js";
7
+ import "./chunk-UJH2JT6H.js";
8
+ import "./chunk-IJGTX7RC.js";
9
9
  export {
10
10
  helpText,
11
11
  parseCliArgs
@@ -5,7 +5,7 @@ import {
5
5
  readCredentials,
6
6
  readJsonConfig,
7
7
  removeCredential
8
- } from "./chunk-EO7IVVX4.js";
8
+ } from "./chunk-IJGTX7RC.js";
9
9
 
10
10
  // src/providers.ts
11
11
  import { mkdirSync, writeFileSync } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ConfigError,
4
4
  t
5
- } from "./chunk-EO7IVVX4.js";
5
+ } from "./chunk-IJGTX7RC.js";
6
6
 
7
7
  // src/mcp/config.ts
8
8
  import { createHash } from "crypto";
@@ -35,8 +35,8 @@ function readSecret(prompt) {
35
35
  });
36
36
  }
37
37
  async function runLogin(providerId, cwd) {
38
- const { runProviderCommand } = await import("./providerCli-II7TQDYQ.js");
39
- const { parseCliArgs } = await import("./args-XQYEBOKB.js");
38
+ const { runProviderCommand } = await import("./providerCli-4JTIW3YA.js");
39
+ const { parseCliArgs } = await import("./args-EFFR44JW.js");
40
40
  return runProviderCommand(parseCliArgs(["provider", "add", providerId]), {
41
41
  env: process.env,
42
42
  cwd,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ConfigError,
4
4
  t
5
- } from "./chunk-EO7IVVX4.js";
5
+ } from "./chunk-IJGTX7RC.js";
6
6
 
7
7
  // src/mcp/catalog.ts
8
8
  var CATALOG = [
@@ -4,17 +4,17 @@ import {
4
4
  providerName,
5
5
  removeGlobalProvider,
6
6
  writeGlobalConfig
7
- } from "./chunk-K5JNR3HL.js";
7
+ } from "./chunk-AOVIQXXO.js";
8
8
  import {
9
9
  reasoningPayload
10
- } from "./chunk-SN3ODJZN.js";
10
+ } from "./chunk-UJH2JT6H.js";
11
11
  import {
12
12
  PRESETS,
13
13
  loadConfig,
14
14
  readCredentials,
15
15
  saveCredential,
16
16
  t
17
- } from "./chunk-EO7IVVX4.js";
17
+ } from "./chunk-IJGTX7RC.js";
18
18
 
19
19
  // src/provider.ts
20
20
  import OpenAI from "openai";
@@ -117,7 +117,12 @@ function errorMessage(body) {
117
117
  return body.slice(0, 300);
118
118
  }
119
119
  }
120
- var toUsage = (u) => u ? { inputTokens: u.prompt_tokens ?? 0, outputTokens: u.completion_tokens ?? 0 } : void 0;
120
+ var toUsage = (u) => u ? {
121
+ inputTokens: u.prompt_tokens ?? 0,
122
+ outputTokens: u.completion_tokens ?? 0,
123
+ ...u.prompt_tokens_details?.cached_tokens != null ? { cachedInputTokens: u.prompt_tokens_details.cached_tokens } : {},
124
+ ...u.prompt_tokens_details?.cache_write_tokens != null ? { cacheWriteTokens: u.prompt_tokens_details.cache_write_tokens } : {}
125
+ } : void 0;
121
126
  async function readStream(res, onText, onThinking) {
122
127
  let text = "";
123
128
  let thinking = "";
@@ -285,6 +285,7 @@ Opsi:
285
285
  "\u273B Thinking (ctrl+t to hide)": "\u273B Berpikir (ctrl+t tutup)",
286
286
  " \u23F3 queued: {q}": " \u23F3 antri: {q}",
287
287
  "Thinking": "Berpikir",
288
+ "Cancelling": "Membatalkan",
288
289
  "Language: {lang}. Change it with /language en or /language id.": "Bahasa: {lang}. Ganti dengan /language en atau /language id.",
289
290
  'Unknown language "{lang}". Use en or id.': 'Bahasa "{lang}" tidak dikenal. Pakai en atau id.',
290
291
  "Could not save the language: {error}": "Gagal menyimpan bahasa: {error}",
@@ -5,12 +5,12 @@ import {
5
5
  import {
6
6
  REASONING_LEVELS,
7
7
  isReasoningLevel
8
- } from "./chunk-SN3ODJZN.js";
8
+ } from "./chunk-UJH2JT6H.js";
9
9
  import {
10
10
  ConfigError,
11
11
  parseLang,
12
12
  t
13
- } from "./chunk-EO7IVVX4.js";
13
+ } from "./chunk-IJGTX7RC.js";
14
14
 
15
15
  // src/args.ts
16
16
  import { parseArgs } from "util";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  t
4
- } from "./chunk-EO7IVVX4.js";
4
+ } from "./chunk-IJGTX7RC.js";
5
5
 
6
6
  // src/print.ts
7
7
  function toolLabel(tool) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  t
4
- } from "./chunk-EO7IVVX4.js";
4
+ } from "./chunk-IJGTX7RC.js";
5
5
 
6
6
  // src/reasoning.ts
7
7
  var REASONING_LEVELS = ["auto", "off", "low", "medium", "high", "max"];
package/dist/cli.js CHANGED
@@ -10,11 +10,11 @@ import {
10
10
  parseFrontmatter,
11
11
  runPrint,
12
12
  validateGlobPattern
13
- } from "./chunk-22CEHQVR.js";
13
+ } from "./chunk-NWVFCTTO.js";
14
14
  import {
15
15
  helpText,
16
16
  parseCliArgs
17
- } from "./chunk-ON6JYPE7.js";
17
+ } from "./chunk-NM3C75BT.js";
18
18
  import {
19
19
  Permissions
20
20
  } from "./chunk-ELML4KVQ.js";
@@ -24,15 +24,15 @@ import {
24
24
  createProvider,
25
25
  hasPendingProgrammaticReplay,
26
26
  listAllModels
27
- } from "./chunk-WWQVALA5.js";
27
+ } from "./chunk-GJAX4NCM.js";
28
28
  import {
29
29
  providerName,
30
30
  readGlobalConfigFile
31
- } from "./chunk-K5JNR3HL.js";
32
- import "./chunk-SN3ODJZN.js";
31
+ } from "./chunk-AOVIQXXO.js";
32
+ import "./chunk-UJH2JT6H.js";
33
33
  import {
34
34
  runLogin
35
- } from "./chunk-DJR4EAVL.js";
35
+ } from "./chunk-FNBTY56Z.js";
36
36
  import {
37
37
  Session,
38
38
  pruneSessions
@@ -45,7 +45,7 @@ import {
45
45
  resolveModel,
46
46
  setLanguage,
47
47
  t
48
- } from "./chunk-EO7IVVX4.js";
48
+ } from "./chunk-IJGTX7RC.js";
49
49
 
50
50
  // src/textToolCalls.ts
51
51
  var PAIR = /(?:<arg_key>\s*|`)?([A-Za-z_]\w*)(?:\s*<\/arg_key>)?`?\s*(?:=\s*`|<arg_value>)([\s\S]*?)<\/arg_value>/g;
@@ -574,6 +574,42 @@ var fetchTool = createFetchTool();
574
574
  // src/tools/glob.ts
575
575
  import { glob as nativeGlob } from "fs/promises";
576
576
  import { z as z4 } from "zod";
577
+
578
+ // src/abort.ts
579
+ var ABORTED = /* @__PURE__ */ Symbol("aborted");
580
+ function raceAbort(promise, signal) {
581
+ if (signal.aborted) return Promise.resolve(ABORTED);
582
+ return new Promise((resolve2, reject) => {
583
+ const onAbort = () => resolve2(ABORTED);
584
+ signal.addEventListener("abort", onAbort, { once: true });
585
+ promise.then(
586
+ (value) => {
587
+ signal.removeEventListener("abort", onAbort);
588
+ resolve2(value);
589
+ },
590
+ (error) => {
591
+ signal.removeEventListener("abort", onAbort);
592
+ reject(error);
593
+ }
594
+ );
595
+ });
596
+ }
597
+ async function collectUntilAbort(iterable, signal, onItem) {
598
+ const iterator = iterable[Symbol.asyncIterator]();
599
+ try {
600
+ for (; ; ) {
601
+ const next = signal ? await raceAbort(iterator.next(), signal) : await iterator.next();
602
+ if (next === ABORTED) return false;
603
+ if (next.done) return true;
604
+ onItem(next.value);
605
+ }
606
+ } finally {
607
+ Promise.resolve(iterator.return?.(void 0)).catch(() => {
608
+ });
609
+ }
610
+ }
611
+
612
+ // src/tools/glob.ts
577
613
  var MAX_OUTPUT_CHARS = 24e3;
578
614
  var globTool = defineTool({
579
615
  name: "glob",
@@ -589,9 +625,12 @@ var globTool = defineTool({
589
625
  if (invalid) return { output: invalid, isError: true };
590
626
  const root = resolvePath(ctx.cwd, input.path ?? ".");
591
627
  const files = [];
592
- for await (const file of nativeGlob(input.pattern, { cwd: root, exclude: ignorePatterns(root) })) {
593
- files.push(normalizeGlobPath(file));
594
- }
628
+ const finished = await collectUntilAbort(
629
+ nativeGlob(input.pattern, { cwd: root, exclude: ignorePatterns(root) }),
630
+ ctx.signal,
631
+ (file) => files.push(normalizeGlobPath(file))
632
+ );
633
+ if (!finished) return { output: "Cancelled by the user.", isError: true };
595
634
  files.sort();
596
635
  if (!files.length) return { output: "No matching files." };
597
636
  const first = files.slice(0, 500);
@@ -621,11 +660,15 @@ var MAX_OUTPUT_CHARS2 = 24e3;
621
660
  async function grepJs(pattern, opts) {
622
661
  const regex = new RegExp(pattern, opts.ignoreCase ? "i" : "");
623
662
  const files = [];
624
- for await (const file of nativeGlob2(opts.glob ?? "**/*", { cwd: opts.root, exclude: ignorePatterns(opts.root) })) {
625
- files.push(normalizeGlobPath(file));
626
- }
663
+ const finished = await collectUntilAbort(
664
+ nativeGlob2(opts.glob ?? "**/*", { cwd: opts.root, exclude: ignorePatterns(opts.root) }),
665
+ opts.signal,
666
+ (file) => files.push(normalizeGlobPath(file))
667
+ );
627
668
  const out = [];
669
+ if (!finished) return out;
628
670
  for (const file of files.sort()) {
671
+ if (opts.signal?.aborted) break;
629
672
  let text;
630
673
  try {
631
674
  const buffer = await readFile2(resolvePath(opts.root, file));
@@ -648,7 +691,8 @@ function grepRg(pattern, opts) {
648
691
  if (opts.glob) args.push("-g", opts.glob);
649
692
  args.push(".");
650
693
  return new Promise((resolve2) => {
651
- execFile("rg", args, { cwd: opts.root, maxBuffer: 10 * 1024 * 1024 }, (error, stdout) => {
694
+ execFile("rg", args, { cwd: opts.root, maxBuffer: 10 * 1024 * 1024, signal: opts.signal }, (error, stdout) => {
695
+ if (opts.signal?.aborted) return resolve2([]);
652
696
  const code = error?.code;
653
697
  if (code === "ENOENT") return resolve2(void 0);
654
698
  if (error && error.code !== 1) return resolve2(void 0);
@@ -672,13 +716,14 @@ var grepTool = defineTool({
672
716
  const invalid = validateGlobPattern(input.glob);
673
717
  if (invalid) return { output: invalid, isError: true };
674
718
  }
675
- const opts = { root: resolvePath(ctx.cwd, input.path ?? "."), glob: input.glob, ignoreCase: input.ignore_case };
719
+ const opts = { root: resolvePath(ctx.cwd, input.path ?? "."), glob: input.glob, ignoreCase: input.ignore_case, signal: ctx.signal };
676
720
  try {
677
721
  new RegExp(input.pattern);
678
722
  } catch (error) {
679
723
  return { output: `Invalid regex: ${error.message}`, isError: true };
680
724
  }
681
725
  const matches = await grepRg(input.pattern, opts) ?? await grepJs(input.pattern, opts);
726
+ if (ctx.signal.aborted) return { output: "Cancelled by the user.", isError: true };
682
727
  if (!matches.length) return { output: "No matches." };
683
728
  const shown = [];
684
729
  let size = 0;
@@ -877,6 +922,7 @@ var WebBudget = class {
877
922
  };
878
923
 
879
924
  // src/agent.ts
925
+ var CANCELLED = "Cancelled by the user.";
880
926
  var estimateTokens = (text) => Math.ceil(text.length / 4);
881
927
  var COMPACT_PROMPT = "Summarize the conversation so far for yourself so you can continue the work with no other context. Include: the user goals, decisions made, files touched and their current state, commands run and results, the task in progress and the next step. Be concise but complete.";
882
928
  var Agent = class {
@@ -964,6 +1010,16 @@ ${completion.text}` });
964
1010
  this.push({ role: "assistant", content: "OK, I will continue from this summary." });
965
1011
  this.onEvent({ type: "compacted" });
966
1012
  }
1013
+ /**
1014
+ * Events of one tool execution. A cancelled turn gives up on a tool that does not stop, and whatever that tool
1015
+ * reports later must not reach the screen or a newer turn, so this is per execution and not per call id (ids repeat).
1016
+ */
1017
+ report(ticket, event) {
1018
+ if (ticket.abandoned) return;
1019
+ if (event.type === "toolStart") ticket.open = true;
1020
+ if (event.type === "toolEnd") ticket.open = false;
1021
+ this.onEvent(event);
1022
+ }
967
1023
  async run(text, signal) {
968
1024
  this.turnTools = this.tools;
969
1025
  this.turnDefinitions = this.definitions;
@@ -1000,6 +1056,8 @@ ${completion.text}` });
1000
1056
  };
1001
1057
  this.totalUsage.inputTokens += usage.inputTokens;
1002
1058
  this.totalUsage.outputTokens += usage.outputTokens;
1059
+ this.totalUsage.cachedInputTokens = (this.totalUsage.cachedInputTokens ?? 0) + (usage.cachedInputTokens ?? 0);
1060
+ this.totalUsage.cacheWriteTokens = (this.totalUsage.cacheWriteTokens ?? 0) + (usage.cacheWriteTokens ?? 0);
1003
1061
  this.lastInputTokens = usage.inputTokens;
1004
1062
  this.onEvent({ type: "usage", ...this.totalUsage });
1005
1063
  this.push(completionAssistantMessage(completion));
@@ -1020,25 +1078,33 @@ ${completion.text}` });
1020
1078
  let i = 0;
1021
1079
  while (i < calls.length) {
1022
1080
  if (signal.aborted) {
1023
- for (const pending of calls.slice(i))
1024
- this.push({
1025
- role: "tool",
1026
- tool_call_id: pending.id,
1027
- content: "Cancelled by the user.",
1028
- ...pending.caller ? { responses_caller: pending.caller } : {}
1029
- });
1081
+ this.cancelCalls(calls.slice(i));
1030
1082
  this.onEvent({ type: "aborted" });
1031
1083
  return;
1032
1084
  }
1033
1085
  let j = i + 1;
1034
1086
  if (this.isParallelSafe(calls[i])) while (j < calls.length && this.isParallelSafe(calls[j])) j++;
1035
1087
  const batch = calls.slice(i, j);
1036
- const results = await Promise.all(batch.map((c) => this.runTool(c, signal)));
1088
+ const tickets = batch.map(() => ({ abandoned: false, open: false }));
1089
+ const running = Promise.all(batch.map((c, k) => this.runTool(c, signal, tickets[k])));
1090
+ const outcome = await raceAbort(running, signal);
1091
+ if (outcome === ABORTED) {
1092
+ batch.forEach((c, k) => {
1093
+ const ticket = tickets[k];
1094
+ ticket.abandoned = true;
1095
+ if (ticket.open) this.onEvent({ type: "toolEnd", id: c.id, tool: c.name, output: CANCELLED, isError: true });
1096
+ });
1097
+ running.catch(() => {
1098
+ });
1099
+ this.cancelCalls(calls.slice(i));
1100
+ this.onEvent({ type: "aborted" });
1101
+ return;
1102
+ }
1037
1103
  batch.forEach((c, k) => {
1038
1104
  this.push({
1039
1105
  role: "tool",
1040
1106
  tool_call_id: c.id,
1041
- content: results[k],
1107
+ content: outcome[k],
1042
1108
  ...c.caller ? { responses_caller: c.caller } : {}
1043
1109
  });
1044
1110
  });
@@ -1064,10 +1130,21 @@ ${t("This model may not support tool calling. Try another model with /model.")}`
1064
1130
  });
1065
1131
  }
1066
1132
  }
1067
- async runTool(call, signal) {
1133
+ /** Every tool call needs an answer in the history, or the next request to the model is rejected. */
1134
+ cancelCalls(calls) {
1135
+ for (const pending of calls)
1136
+ this.push({
1137
+ role: "tool",
1138
+ tool_call_id: pending.id,
1139
+ content: CANCELLED,
1140
+ ...pending.caller ? { responses_caller: pending.caller } : {}
1141
+ });
1142
+ }
1143
+ async runTool(call, signal, ticket) {
1144
+ const emit = (event) => this.report(ticket, event);
1068
1145
  const fail = (output, target2 = "") => {
1069
- this.onEvent({ type: "toolStart", id: call.id, tool: call.name, target: target2 });
1070
- this.onEvent({ type: "toolEnd", id: call.id, tool: call.name, output, isError: true });
1146
+ emit({ type: "toolStart", id: call.id, tool: call.name, target: target2 });
1147
+ emit({ type: "toolEnd", id: call.id, tool: call.name, output, isError: true });
1071
1148
  return output;
1072
1149
  };
1073
1150
  const tool = this.turnTools.find((t2) => t2.name === call.name);
@@ -1091,20 +1168,22 @@ ${t("This model may not support tool calling. Try another model with /model.")}`
1091
1168
  signal,
1092
1169
  readFiles: this.readFiles,
1093
1170
  callId: call.id,
1094
- emit: (event) => this.onEvent(event),
1171
+ emit,
1095
1172
  ask: (req) => this.askPermission(req),
1096
1173
  checkpoint: this.opts.checkpoint,
1097
1174
  refundFetch: () => this.webBudget.refund(),
1098
1175
  addUsage: (u) => {
1099
1176
  this.totalUsage.inputTokens += u.inputTokens;
1100
1177
  this.totalUsage.outputTokens += u.outputTokens;
1178
+ this.totalUsage.cachedInputTokens = (this.totalUsage.cachedInputTokens ?? 0) + (u.cachedInputTokens ?? 0);
1179
+ this.totalUsage.cacheWriteTokens = (this.totalUsage.cacheWriteTokens ?? 0) + (u.cacheWriteTokens ?? 0);
1101
1180
  this.onEvent({ type: "usage", ...this.totalUsage });
1102
1181
  }
1103
1182
  };
1104
- this.onEvent({ type: "toolStart", id: call.id, tool: tool.name, target });
1183
+ emit({ type: "toolStart", id: call.id, tool: tool.name, target });
1105
1184
  const invalid = await tool.validate?.(input, ctx).catch((error) => error.message);
1106
1185
  if (invalid) {
1107
- this.onEvent({ type: "toolEnd", id: call.id, tool: tool.name, output: invalid, isError: true });
1186
+ emit({ type: "toolEnd", id: call.id, tool: tool.name, output: invalid, isError: true });
1108
1187
  return invalid;
1109
1188
  }
1110
1189
  const request = { tool: tool.name, kind: tool.kind, target };
@@ -1123,7 +1202,7 @@ ${t("This model may not support tool calling. Try another model with /model.")}`
1123
1202
  }
1124
1203
  if (decision === "deny") {
1125
1204
  const output = this.permissions.mode === "plan" ? "Denied: plan mode only allows reading and searching. Write the plan for the user without changing anything." : "The user declined to run this tool. Ask the user what they want, or try another approach.";
1126
- this.onEvent({ type: "toolEnd", id: call.id, tool: tool.name, output, isError: true });
1205
+ emit({ type: "toolEnd", id: call.id, tool: tool.name, output, isError: true });
1127
1206
  return output;
1128
1207
  }
1129
1208
  let result;
@@ -1133,7 +1212,7 @@ ${t("This model may not support tool calling. Try another model with /model.")}`
1133
1212
  result = { output: `Error: ${error.message}`, isError: true };
1134
1213
  }
1135
1214
  if (tool.name === "fetch" && !result.isError) this.webBudget.record(result.output.length);
1136
- this.onEvent({ type: "toolEnd", id: call.id, tool: tool.name, output: result.output, display: result.display, isError: !!result.isError });
1215
+ emit({ type: "toolEnd", id: call.id, tool: tool.name, output: result.output, display: result.display, isError: !!result.isError });
1137
1216
  return result.output;
1138
1217
  }
1139
1218
  };
@@ -1677,7 +1756,7 @@ function createRuntime(opts) {
1677
1756
  }
1678
1757
 
1679
1758
  // src/version.ts
1680
- var VERSION = true ? "0.4.0-beta.30" : "0.0.0-dev";
1759
+ var VERSION = true ? "0.4.0-beta.32" : "0.0.0-dev";
1681
1760
 
1682
1761
  // src/cli.ts
1683
1762
  function chooseLanguage(argv) {
@@ -1702,17 +1781,17 @@ async function main() {
1702
1781
  const cwd = process.cwd();
1703
1782
  if (args.command === "login") return runLogin(args.loginProvider ?? "bc-cloud", cwd);
1704
1783
  if (args.command === "mcp") {
1705
- const { runMcpCommand } = await import("./mcpCli-J43FHF2H.js");
1706
- const { readSecret } = await import("./login-HUPT4247.js");
1784
+ const { runMcpCommand } = await import("./mcpCli-UGNEDBMU.js");
1785
+ const { readSecret } = await import("./login-7IARC5WX.js");
1707
1786
  return runMcpCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
1708
1787
  }
1709
1788
  if (args.command === "provider") {
1710
- const { runProviderCommand } = await import("./providerCli-II7TQDYQ.js");
1711
- const { readSecret } = await import("./login-HUPT4247.js");
1789
+ const { runProviderCommand } = await import("./providerCli-4JTIW3YA.js");
1790
+ const { readSecret } = await import("./login-7IARC5WX.js");
1712
1791
  return runProviderCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
1713
1792
  }
1714
1793
  if (args.command === "connect" || args.command === "disconnect" || args.command === "integrations") {
1715
- const { runIntegrationCommand } = await import("./integrationCli-ZTZSZLO7.js");
1794
+ const { runIntegrationCommand } = await import("./integrationCli-G4C6XQUE.js");
1716
1795
  return runIntegrationCommand(args, {
1717
1796
  env: process.env,
1718
1797
  cwd,
@@ -1735,7 +1814,7 @@ async function main() {
1735
1814
  }
1736
1815
  if (args.print) {
1737
1816
  if (!args.prompt) throw new ConfigError(t('-p mode needs a task, e.g. bccli -p "explain this repo"'));
1738
- const { serversToStart } = await import("./config-PBEZ3IGD.js");
1817
+ const { serversToStart } = await import("./config-DMF4AO7E.js");
1739
1818
  const plan = serversToStart(rt.home, cwd);
1740
1819
  for (const s of plan.needTrust) {
1741
1820
  console.error(t('Project MCP server "{name}" skipped (not approved yet; run interactive bccli once to approve it).', { name: s.name }));
@@ -1748,7 +1827,7 @@ async function main() {
1748
1827
  }
1749
1828
  }
1750
1829
  if (!process.stdin.isTTY) throw new ConfigError(t('Interactive mode needs a terminal. For scripts/CI use: bccli -p "task"'));
1751
- const { startInteractive } = await import("./ui-HO3Z5LYD.js");
1830
+ const { startInteractive } = await import("./ui-N7SJ7V7V.js");
1752
1831
  return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
1753
1832
  }
1754
1833
  main().then(
@@ -8,8 +8,8 @@ import {
8
8
  removeGlobalServer,
9
9
  serversToStart,
10
10
  setProjectTrust
11
- } from "./chunk-44MXWCFN.js";
12
- import "./chunk-EO7IVVX4.js";
11
+ } from "./chunk-CDUPYHNL.js";
12
+ import "./chunk-IJGTX7RC.js";
13
13
  export {
14
14
  addGlobalServer,
15
15
  globalMcpPath,
@@ -6,7 +6,7 @@ import {
6
6
  readCredentials,
7
7
  resolveModel,
8
8
  t
9
- } from "./chunk-EO7IVVX4.js";
9
+ } from "./chunk-IJGTX7RC.js";
10
10
 
11
11
  // src/integrationCli.ts
12
12
  import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  readSecret,
4
4
  runLogin
5
- } from "./chunk-DJR4EAVL.js";
5
+ } from "./chunk-FNBTY56Z.js";
6
6
  export {
7
7
  readSecret,
8
8
  runLogin
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  CATALOG,
4
4
  fillTemplate
5
- } from "./chunk-BEXQSEBI.js";
5
+ } from "./chunk-GEG6QT5H.js";
6
6
  import {
7
7
  addGlobalServer,
8
8
  globalMcpPath,
9
9
  readMcpFile,
10
10
  removeGlobalServer
11
- } from "./chunk-44MXWCFN.js";
11
+ } from "./chunk-CDUPYHNL.js";
12
12
  import {
13
13
  bccliHome,
14
14
  t
15
- } from "./chunk-EO7IVVX4.js";
15
+ } from "./chunk-IJGTX7RC.js";
16
16
 
17
17
  // src/mcpCli.ts
18
18
  async function runMcpCommand(args, deps) {
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ addProviderKey,
4
+ runProviderCommand
5
+ } from "./chunk-GJAX4NCM.js";
6
+ import "./chunk-AOVIQXXO.js";
7
+ import "./chunk-UJH2JT6H.js";
8
+ import "./chunk-IJGTX7RC.js";
9
+ export {
10
+ addProviderKey,
11
+ runProviderCommand
12
+ };
@@ -7,7 +7,7 @@ import {
7
7
  parseFrontmatter,
8
8
  toolLabel,
9
9
  validateGlobPattern
10
- } from "./chunk-22CEHQVR.js";
10
+ } from "./chunk-NWVFCTTO.js";
11
11
  import {
12
12
  nextMode
13
13
  } from "./chunk-ELML4KVQ.js";
@@ -15,26 +15,26 @@ import {
15
15
  hasKey,
16
16
  providerName,
17
17
  writeGlobalConfig
18
- } from "./chunk-K5JNR3HL.js";
18
+ } from "./chunk-AOVIQXXO.js";
19
19
  import {
20
20
  REASONING_LEVELS,
21
21
  assertReasoningSupported,
22
22
  parseReasoningLevel,
23
23
  supportedReasoningLevels
24
- } from "./chunk-SN3ODJZN.js";
24
+ } from "./chunk-UJH2JT6H.js";
25
25
  import {
26
26
  Session
27
27
  } from "./chunk-SJH3YLW4.js";
28
28
  import {
29
29
  CATALOG,
30
30
  fillTemplate
31
- } from "./chunk-BEXQSEBI.js";
31
+ } from "./chunk-GEG6QT5H.js";
32
32
  import {
33
33
  addGlobalServer,
34
34
  globalMcpPath,
35
35
  readMcpFile,
36
36
  removeGlobalServer
37
- } from "./chunk-44MXWCFN.js";
37
+ } from "./chunk-CDUPYHNL.js";
38
38
  import {
39
39
  PRESETS,
40
40
  getLanguage,
@@ -43,7 +43,7 @@ import {
43
43
  removeCredential,
44
44
  setLanguage,
45
45
  t
46
- } from "./chunk-EO7IVVX4.js";
46
+ } from "./chunk-IJGTX7RC.js";
47
47
 
48
48
  // src/ui/index.tsx
49
49
  import { render } from "ink";
@@ -177,6 +177,7 @@ function statusText(s) {
177
177
  t("Folder: {cwd}", { cwd: s.cwd }),
178
178
  t("MCP: {ready} active, {errors} errors", { ready, errors }),
179
179
  t("Session tokens: {input} in \xB7 {output} out", { input: k(s.usage.inputTokens), output: k(s.usage.outputTokens) }),
180
+ `Cache: ${k(s.usage.cachedInputTokens ?? 0)} read \xB7 ${k(s.usage.cacheWriteTokens ?? 0)} write`,
180
181
  t("Context: ~{pct}% of 128k", { pct: Math.round(s.lastInputTokens / 128e3 * 100) })
181
182
  ].join("\n");
182
183
  }
@@ -1133,6 +1134,7 @@ function App({ runtime, initialPrompt, version }) {
1133
1134
  const { exit } = useApp();
1134
1135
  const [transcript, setTranscript] = useState8(() => ({ done: [entry({ kind: "header" })], live: [] }));
1135
1136
  const [busy, setBusy] = useState8(false);
1137
+ const [cancelling, setCancelling] = useState8(false);
1136
1138
  const [startedAt, setStartedAt] = useState8(0);
1137
1139
  const [mode, setMode] = useState8(runtime.agent.permissions.mode);
1138
1140
  const [reasoning, setReasoning] = useState8(runtime.reasoning);
@@ -1186,6 +1188,7 @@ function App({ runtime, initialPrompt, version }) {
1186
1188
  controller.current = null;
1187
1189
  setTranscript(endTurn);
1188
1190
  setBusy(false);
1191
+ setCancelling(false);
1189
1192
  },
1190
1193
  [runtime]
1191
1194
  );
@@ -1219,6 +1222,7 @@ function App({ runtime, initialPrompt, version }) {
1219
1222
  }
1220
1223
  controller.current = null;
1221
1224
  setBusy(false);
1225
+ setCancelling(false);
1222
1226
  return;
1223
1227
  }
1224
1228
  case "reasoning": {
@@ -1618,6 +1622,7 @@ ARGUMENTS: ${slash.args}`);
1618
1622
  setMode(next);
1619
1623
  } else if (key.escape && busy && !pending) {
1620
1624
  controller.current?.abort();
1625
+ setCancelling(true);
1621
1626
  if (queued.length) {
1622
1627
  setQueued([]);
1623
1628
  notice(t("{n} queued messages cancelled.", { n: queued.length }), "warn");
@@ -1742,7 +1747,7 @@ ${t2.output}`);
1742
1747
  return /* @__PURE__ */ jsxs11(Box13, { flexDirection: "column", children: [
1743
1748
  /* @__PURE__ */ jsx15(Static, { items: transcript.done, children: renderEntry }),
1744
1749
  transcript.live.map(renderEntry),
1745
- busy && !pending && !planAsk ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Spinner, { label: t("Thinking"), startedAt }) }) : null,
1750
+ busy && !pending && !planAsk ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Spinner, { label: cancelling ? t("Cancelling") : t("Thinking"), startedAt }) }) : null,
1746
1751
  pending ? /* @__PURE__ */ jsx15(PermissionPrompt, { request: pending.request, onAnswer: answer }, pending.id) : null,
1747
1752
  picker ? /* @__PURE__ */ jsx15(
1748
1753
  ModelPicker,
@@ -1810,7 +1815,7 @@ async function startInteractive(rt, opts) {
1810
1815
  if (chosen) rt.resume(chosen.session);
1811
1816
  }
1812
1817
  }
1813
- const { serversToStart, setProjectTrust } = await import("./config-PBEZ3IGD.js");
1818
+ const { serversToStart, setProjectTrust } = await import("./config-DMF4AO7E.js");
1814
1819
  const plan = serversToStart(rt.home, rt.cwd);
1815
1820
  if (plan.needTrust.length) {
1816
1821
  const { createInterface } = await import("readline/promises");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.0-beta.30",
3
+ "version": "0.4.0-beta.32",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- addProviderKey,
4
- runProviderCommand
5
- } from "./chunk-WWQVALA5.js";
6
- import "./chunk-K5JNR3HL.js";
7
- import "./chunk-SN3ODJZN.js";
8
- import "./chunk-EO7IVVX4.js";
9
- export {
10
- addProviderKey,
11
- runProviderCommand
12
- };