@botconnector/bccli 0.4.10 → 0.4.11

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 (53) hide show
  1. package/dist/{acp-L4WGVJTY.js → acp-IPHWC6CO.js} +20 -5
  2. package/dist/acp.d.ts +17 -1
  3. package/dist/args-K5AJFDCZ.js +13 -0
  4. package/dist/budget.d.ts +4 -1
  5. package/dist/{chunk-7HDBPDAD.js → chunk-2DFY43RP.js} +2 -2
  6. package/dist/{chunk-5QCCV2JM.js → chunk-6BXW7DGQ.js} +47 -18
  7. package/dist/{chunk-4WI5ON64.js → chunk-6KZIOICR.js} +1 -1
  8. package/dist/{chunk-3K66L37W.js → chunk-6M5T7N7A.js} +3 -3
  9. package/dist/{chunk-USFXL5BS.js → chunk-C2FUGQJX.js} +6 -6
  10. package/dist/{chunk-24KDXQZT.js → chunk-F54FDJBD.js} +3 -3
  11. package/dist/{chunk-ED5TTYQU.js → chunk-G5TG43R4.js} +3 -0
  12. package/dist/{chunk-67REFMSY.js → chunk-IHQGXDSG.js} +1 -1
  13. package/dist/{chunk-PGDYPOQW.js → chunk-JFYQCPXL.js} +4 -4
  14. package/dist/{chunk-ZWXKBFKW.js → chunk-MBAMDCCV.js} +23 -9
  15. package/dist/{chunk-CBD52BYV.js → chunk-N6APAYSF.js} +1 -1
  16. package/dist/{chunk-6N2BBLIT.js → chunk-NT2G5FSX.js} +2 -2
  17. package/dist/{chunk-3PUWH62K.js → chunk-OAXD3X4R.js} +34 -50
  18. package/dist/{chunk-VXRW5SYP.js → chunk-OOOS5RCT.js} +25 -14
  19. package/dist/{chunk-CIEPLTGS.js → chunk-WSZF2CTU.js} +4 -4
  20. package/dist/{chunk-MPYSYTSO.js → chunk-X24APPXO.js} +1 -1
  21. package/dist/{chunk-6RVAPAE5.js → chunk-XZ2TI5HV.js} +1 -1
  22. package/dist/{chunk-SXRQ2Q7A.js → chunk-Y6AZGGH7.js} +4 -4
  23. package/dist/{chunk-WFZKJY3R.js → chunk-YYTFJUO2.js} +3 -2
  24. package/dist/cli.js +39 -39
  25. package/dist/{completion-GEFRIQWV.js → completion-QVDGAYUY.js} +1 -1
  26. package/dist/{config-JLOH5M6B.js → config-7TQ2KVVX.js} +3 -3
  27. package/dist/{config-JKMYKNAT.js → config-RZY3XQZJ.js} +2 -2
  28. package/dist/{ghBotCli-WEVS6S6O.js → ghBotCli-HHJ4ANTH.js} +18 -16
  29. package/dist/{integrationCli-PKMICTHC.js → integrationCli-LNNZDGZX.js} +40 -5
  30. package/dist/{login-2TZRODUL.js → login-MQEZGF2C.js} +6 -4
  31. package/dist/login.d.ts +2 -0
  32. package/dist/{mcpCli-TAPKYGHO.js → mcpCli-CUIOYJ2A.js} +6 -6
  33. package/dist/{modelsCli-6PK7V2QZ.js → modelsCli-AAFHFI4H.js} +6 -6
  34. package/dist/{oauthLogin-UI34LQZU.js → oauthLogin-YFL2N4QA.js} +1 -1
  35. package/dist/{pluginsCli-RCF33U5J.js → pluginsCli-2QXXFLQA.js} +2 -2
  36. package/dist/{prCli-24PMW7NS.js → prCli-KSA73RCS.js} +1 -1
  37. package/dist/providerCli-TXMVPSW5.js +15 -0
  38. package/dist/sdk.js +103 -72
  39. package/dist/{serve-XNJI67DU.js → serve-EIQHEUYD.js} +3 -3
  40. package/dist/{serve-7BFCIEPJ.js → serve-QYDBFTHC.js} +16 -16
  41. package/dist/session-CQCQ7KAP.js +12 -0
  42. package/dist/setup-DBSGMWHM.js +24 -0
  43. package/dist/setup.d.ts +5 -0
  44. package/dist/{statsCli-QDHE4TKB.js → statsCli-EHNJIQ2Z.js} +2 -2
  45. package/dist/tools/bash.d.ts +2 -0
  46. package/dist/{transferCli-7OKKYGG2.js → transferCli-IXJ2O74Q.js} +4 -4
  47. package/dist/{ui-SZAIIJC5.js → ui-A2LASWDK.js} +14 -14
  48. package/dist/{update-JSNVVXPS.js → update-TR62JV3A.js} +2 -2
  49. package/package.json +1 -1
  50. package/dist/args-EW7XJVQN.js +0 -13
  51. package/dist/providerCli-XA4LTWRD.js +0 -15
  52. package/dist/session-VAPIHHUG.js +0 -12
  53. package/dist/setup-GPIMZOWE.js +0 -24
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ t
4
+ } from "./chunk-G5TG43R4.js";
2
5
 
3
6
  // src/acp.ts
4
7
  var ACP_PROTOCOL_VERSION = 1;
@@ -175,16 +178,27 @@ function runAcp(input, output, opts) {
175
178
  input.on("end", onEnd);
176
179
  });
177
180
  }
178
- function runtimeAgent(cwd, allowAll = false) {
181
+ function planDecisionFrom(answer) {
182
+ if (answer === "no") return "no";
183
+ if (answer === "session") return "acceptEdits";
184
+ return "default";
185
+ }
186
+ function runtimeAgent(cwd, allowAll = false, deps = {}) {
179
187
  let rt;
180
188
  return {
181
189
  async run(text, onChunk, signal, io) {
182
190
  if (!rt) {
183
- const { parseCliArgs } = await import("./args-EW7XJVQN.js");
184
- const { createRuntime } = await import("./setup-GPIMZOWE.js");
185
- rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll } });
191
+ if (deps.createRuntime) rt = deps.createRuntime({ cwd, allowAll });
192
+ else {
193
+ const { parseCliArgs } = await import("./args-K5AJFDCZ.js");
194
+ const { createRuntime } = await import("./setup-DBSGMWHM.js");
195
+ rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll } });
196
+ }
197
+ }
198
+ if (io && !allowAll) {
199
+ rt.agent.askPermission = (req) => io.askPermission(req);
200
+ rt.interaction.approvePlan = async (plan) => planDecisionFrom(await io.askPermission({ tool: "exit_plan", kind: "edit", target: t("plan"), preview: plan }));
186
201
  }
187
- if (io && !allowAll) rt.agent.askPermission = (req) => io.askPermission(req);
188
202
  let turnError;
189
203
  rt.agent.onEvent = (event) => {
190
204
  if (event.type === "text") onChunk(event.delta);
@@ -201,6 +215,7 @@ function runtimeAgent(cwd, allowAll = false) {
201
215
  }
202
216
  export {
203
217
  ACP_PROTOCOL_VERSION,
218
+ planDecisionFrom,
204
219
  runAcp,
205
220
  runtimeAgent
206
221
  };
package/dist/acp.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import type { PermissionAnswer, PermissionAsk } from './agent';
2
+ import type { Runtime } from './setup';
3
+ import type { PlanDecision } from './tools/plan';
2
4
  export declare const ACP_PROTOCOL_VERSION = 1;
3
5
  /** What the agent reports to the editor besides text: tool calls, and permission questions the editor answers. */
4
6
  export interface AcpIo {
@@ -21,8 +23,22 @@ export declare function runAcp(input: NodeJS.ReadableStream, output: NodeJS.Writ
21
23
  cwd: string;
22
24
  newAgent: (cwd: string) => AcpAgent;
23
25
  }): Promise<void>;
26
+ /**
27
+ * A plan has no ACP primitive of its own, so it is asked through session/request_permission.
28
+ * 'yes' approves and keeps the normal per-tool prompts; 'session' also stops asking for edits
29
+ * for the rest of the session (acceptEdits). A plan answer never turns on allowAll, which stays
30
+ * an explicit user choice.
31
+ */
32
+ export declare function planDecisionFrom(answer: PermissionAnswer): PlanDecision;
33
+ export interface AcpRuntimeDeps {
34
+ /** Test seam: build the runtime without reading config/plugins. */
35
+ createRuntime?: (opts: {
36
+ cwd: string;
37
+ allowAll: boolean;
38
+ }) => Runtime;
39
+ }
24
40
  /**
25
41
  * Production agent: one bccli runtime per ACP session. Permission questions go to the editor
26
42
  * (session/request_permission); `allowAll` skips them and runs everything unasked.
27
43
  */
28
- export declare function runtimeAgent(cwd: string, allowAll?: boolean): AcpAgent;
44
+ export declare function runtimeAgent(cwd: string, allowAll?: boolean, deps?: AcpRuntimeDeps): AcpAgent;
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ helpText,
4
+ parseCliArgs
5
+ } from "./chunk-WSZF2CTU.js";
6
+ import "./chunk-YYTFJUO2.js";
7
+ import "./chunk-XZ2TI5HV.js";
8
+ import "./chunk-C2FUGQJX.js";
9
+ import "./chunk-G5TG43R4.js";
10
+ export {
11
+ helpText,
12
+ parseCliArgs
13
+ };
package/dist/budget.d.ts CHANGED
@@ -3,19 +3,22 @@ export interface UsageCap {
3
3
  tokens?: number;
4
4
  /** Total USD per session; requires `prices`. */
5
5
  usd?: number;
6
- /** USD per 1M tokens, keyed by a substring of the model ref (first match wins). */
6
+ /** USD per 1M tokens. `cachedInput` is optional: without it cache reads cost the input price. */
7
7
  prices?: Record<string, {
8
8
  input: number;
9
9
  output: number;
10
+ cachedInput?: number;
10
11
  }>;
11
12
  }
12
13
  export declare function priceFor(cap: UsageCap, model: string): {
13
14
  input: number;
14
15
  output: number;
16
+ cachedInput?: number;
15
17
  } | undefined;
16
18
  export declare function budgetStatus(usage: {
17
19
  inputTokens: number;
18
20
  outputTokens: number;
21
+ cachedInputTokens?: number;
19
22
  }, cap: UsageCap | undefined, model: string): {
20
23
  kind: 'tokens' | 'usd';
21
24
  used: number;
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  ConfigError,
4
4
  writeFileAtomic
5
- } from "./chunk-USFXL5BS.js";
5
+ } from "./chunk-C2FUGQJX.js";
6
6
  import {
7
7
  t
8
- } from "./chunk-ED5TTYQU.js";
8
+ } from "./chunk-G5TG43R4.js";
9
9
 
10
10
  // src/mcp/config.ts
11
11
  import { createHash } from "crypto";
@@ -24,52 +24,52 @@ import {
24
24
  resolvePath,
25
25
  runHooks,
26
26
  validateGlobPattern
27
- } from "./chunk-3PUWH62K.js";
27
+ } from "./chunk-OAXD3X4R.js";
28
28
  import {
29
29
  createWebSearchTool,
30
30
  fetchTool
31
- } from "./chunk-4WI5ON64.js";
31
+ } from "./chunk-6KZIOICR.js";
32
32
  import {
33
33
  defineTool
34
34
  } from "./chunk-PSO7R5AD.js";
35
35
  import {
36
36
  Permissions
37
- } from "./chunk-WFZKJY3R.js";
37
+ } from "./chunk-YYTFJUO2.js";
38
38
  import {
39
39
  addProviderKey
40
- } from "./chunk-PGDYPOQW.js";
40
+ } from "./chunk-JFYQCPXL.js";
41
41
  import {
42
42
  listAllModels
43
- } from "./chunk-SXRQ2Q7A.js";
43
+ } from "./chunk-Y6AZGGH7.js";
44
44
  import {
45
45
  providerName
46
- } from "./chunk-MPYSYTSO.js";
46
+ } from "./chunk-X24APPXO.js";
47
47
  import {
48
48
  FileOAuthProvider,
49
49
  hasStoredTokens
50
- } from "./chunk-67REFMSY.js";
50
+ } from "./chunk-IHQGXDSG.js";
51
51
  import {
52
52
  Session
53
- } from "./chunk-24KDXQZT.js";
53
+ } from "./chunk-F54FDJBD.js";
54
54
  import {
55
55
  completionAssistantMessage,
56
56
  createProvider,
57
57
  hasPendingProgrammaticReplay,
58
58
  imageUserMessage,
59
59
  withFallbackProvider
60
- } from "./chunk-VXRW5SYP.js";
60
+ } from "./chunk-OOOS5RCT.js";
61
61
  import {
62
62
  expandEnvVars
63
- } from "./chunk-7HDBPDAD.js";
63
+ } from "./chunk-2DFY43RP.js";
64
64
  import {
65
65
  ConfigError,
66
66
  bccliHome,
67
67
  loadConfig,
68
68
  resolveModel
69
- } from "./chunk-USFXL5BS.js";
69
+ } from "./chunk-C2FUGQJX.js";
70
70
  import {
71
71
  t
72
- } from "./chunk-ED5TTYQU.js";
72
+ } from "./chunk-G5TG43R4.js";
73
73
 
74
74
  // src/textToolCalls.ts
75
75
  var PAIR = /(?:<arg_key>\s*|`)?([A-Za-z_]\w*)(?:\s*<\/arg_key>)?`?\s*(?:=\s*`|<arg_value>)([\s\S]*?)<\/arg_value>/g;
@@ -622,6 +622,12 @@ async function readTextResult(input, buffer) {
622
622
  const lines = buffer.toString("utf8").split(/\r?\n/);
623
623
  const start = (input.offset ?? 1) - 1;
624
624
  const limit = input.limit ?? 2e3;
625
+ if (start >= lines.length) {
626
+ return {
627
+ output: `offset ${input.offset} is past the end of ${input.path} (${lines.length} line(s)); start at 1.`,
628
+ isError: true
629
+ };
630
+ }
625
631
  const requested = lines.slice(start, start + limit);
626
632
  const shown = [];
627
633
  let size = 0;
@@ -703,7 +709,9 @@ var writeTool = defineTool({
703
709
  target: (input) => input.path,
704
710
  async validate(input, ctx) {
705
711
  const abs = resolvePath(ctx.cwd, input.path);
706
- return existsSync(abs) && !ctx.readFiles.has(abs) ? `${input.path} already exists. Read it with read before overwriting it.` : void 0;
712
+ if (existsSync(abs) && !ctx.readFiles.has(abs)) return `${input.path} already exists. Read it with read before overwriting it.`;
713
+ if (isFileModifiedSinceRead(ctx.readFiles, abs)) return `${input.path} has been modified since it was last read. Read it again before overwriting it.`;
714
+ return void 0;
707
715
  },
708
716
  async preview(input, ctx) {
709
717
  const abs = resolvePath(ctx.cwd, input.path);
@@ -715,6 +723,9 @@ var writeTool = defineTool({
715
723
  if (existsSync(abs) && !ctx.readFiles.has(abs)) {
716
724
  return { output: `${input.path} already exists. Read it with read before overwriting it.`, isError: true };
717
725
  }
726
+ if (isFileModifiedSinceRead(ctx.readFiles, abs)) {
727
+ return { output: `${input.path} has been modified since it was last read. Read it again before overwriting it.`, isError: true };
728
+ }
718
729
  try {
719
730
  await ctx.checkpoint?.(abs);
720
731
  await mkdir(dirname2(abs), { recursive: true });
@@ -824,7 +835,9 @@ function budgetStatus(usage, cap, model) {
824
835
  if (cap.usd !== void 0) {
825
836
  const price = priceFor(cap, model);
826
837
  if (price) {
827
- const usd = (usage.inputTokens * price.input + usage.outputTokens * price.output) / 1e6;
838
+ const cached = Math.max(0, Math.min(usage.cachedInputTokens ?? 0, usage.inputTokens));
839
+ const cachedRate = price.cachedInput ?? price.input;
840
+ const usd = ((usage.inputTokens - cached) * price.input + cached * cachedRate + usage.outputTokens * price.output) / 1e6;
828
841
  if (usd >= cap.usd) return { kind: "usd", used: usd, limit: cap.usd };
829
842
  }
830
843
  }
@@ -2366,6 +2379,15 @@ function loadPlugins(specs, opts) {
2366
2379
 
2367
2380
  // src/setup.ts
2368
2381
  var TOOL_RULES = { bash: "bash", edit: "edit", write: "edit", fetch: "fetch" };
2382
+ var pluginCache = /* @__PURE__ */ new Map();
2383
+ function loadPluginsOnce(specs, opts) {
2384
+ const key = JSON.stringify({ specs, home: opts.home, cwd: opts.cwd });
2385
+ const cached = pluginCache.get(key);
2386
+ if (cached) return cached;
2387
+ const loaded = loadPlugins(specs, opts);
2388
+ pluginCache.set(key, loaded);
2389
+ return loaded;
2390
+ }
2369
2391
  function lunaPtcAutoEnabled(env) {
2370
2392
  const value = String(env.BCCLI_LUNA_PTC ?? "").trim().toLowerCase();
2371
2393
  return !["0", "false", "off", "no"].includes(value);
@@ -2373,6 +2395,7 @@ function lunaPtcAutoEnabled(env) {
2373
2395
  function createRuntime(opts) {
2374
2396
  const env = opts.env ?? process.env;
2375
2397
  const home = bccliHome(env);
2398
+ const persistSession = opts.persistSession !== false;
2376
2399
  let config = loadConfig(opts.cwd, env);
2377
2400
  let modelRef = opts.args.model ?? config.model;
2378
2401
  let reasoning = opts.args.reasoning ?? config.reasoning;
@@ -2461,7 +2484,7 @@ function createRuntime(opts) {
2461
2484
  createRepoMapTool()
2462
2485
  ];
2463
2486
  if (config.lsp?.servers.length) baseTools.push(createDiagnosticsTool(config.lsp.servers));
2464
- const plugins = loadPlugins(config.plugins ?? [], {
2487
+ const plugins = loadPluginsOnce(config.plugins ?? [], {
2465
2488
  home,
2466
2489
  cwd: opts.cwd,
2467
2490
  env,
@@ -2499,9 +2522,15 @@ function createRuntime(opts) {
2499
2522
  usageCap: config.usageCap,
2500
2523
  budgetModel: modelRef,
2501
2524
  contextWindow: contextWindowFor(modelRef, env),
2502
- onMessage: (m) => session.append(m),
2503
- onUsage: (u) => session.appendUsage({ ...u, model: modelRef }),
2504
- onReset: () => session.reset(),
2525
+ onMessage: (m) => {
2526
+ if (persistSession) session.append(m);
2527
+ },
2528
+ onUsage: (u) => {
2529
+ if (persistSession) session.appendUsage({ ...u, model: modelRef });
2530
+ },
2531
+ onReset: () => {
2532
+ if (persistSession) session.reset();
2533
+ },
2505
2534
  onTurnStart: () => {
2506
2535
  for (let i = turnMarks.length - 1; i >= 0 && turnMarks[i] > agent.messages.length; i--) {
2507
2536
  turnMarks.splice(i, 1);
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-PSO7R5AD.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-ED5TTYQU.js";
7
+ } from "./chunk-G5TG43R4.js";
8
8
 
9
9
  // src/tools/websearch.ts
10
10
  import { z } from "zod";
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  runCommand,
4
4
  runHooks
5
- } from "./chunk-3PUWH62K.js";
5
+ } from "./chunk-OAXD3X4R.js";
6
6
  import {
7
7
  ConfigError
8
- } from "./chunk-USFXL5BS.js";
8
+ } from "./chunk-C2FUGQJX.js";
9
9
  import {
10
10
  t
11
- } from "./chunk-ED5TTYQU.js";
11
+ } from "./chunk-G5TG43R4.js";
12
12
 
13
13
  // src/verify.ts
14
14
  var MAX_VERIFY_ROUNDS = 2;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  t
4
- } from "./chunk-ED5TTYQU.js";
4
+ } from "./chunk-G5TG43R4.js";
5
5
 
6
6
  // src/config.ts
7
7
  import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
@@ -149,6 +149,9 @@ function resolvedUsageCap(global) {
149
149
  if (!price || !nonNegative(price.input) || !nonNegative(price.output)) {
150
150
  throw new ConfigError(t('usageCap.prices["{key}"] must have numeric input and output (USD per 1M tokens).', { key }));
151
151
  }
152
+ if (price.cachedInput !== void 0 && !nonNegative(price.cachedInput)) {
153
+ throw new ConfigError(t('usageCap.prices["{key}"].cachedInput must be a number >= 0 (USD per 1M tokens).', { key }));
154
+ }
152
155
  }
153
156
  }
154
157
  if (tokens === void 0 && usd === void 0) throw new ConfigError(t("usageCap needs at least one of: tokens, usd."));
@@ -236,7 +239,7 @@ function loadConfig(cwd, env = process.env) {
236
239
  const project = readJsonConfig(join(cwd, ".bccli", "config.json"));
237
240
  const known = { ...DEFAULT_CONFIG.providers, ...global.providers };
238
241
  const fromProject = untrustedProviders(project, known);
239
- const rawFallbacks = project.fallbackModels ?? global.fallbackModels;
242
+ const rawFallbacks = global.fallbackModels;
240
243
  const fallbackModels = Array.isArray(rawFallbacks) ? rawFallbacks.filter((m) => typeof m === "string" && m.includes("/")) : void 0;
241
244
  return {
242
245
  model: project.model ?? global.model ?? DEFAULT_CONFIG.model,
@@ -305,10 +308,7 @@ function quarantineCorruptFile(path, error) {
305
308
  }
306
309
  function updateGlobalConfig(env, mutate) {
307
310
  const path = globalConfigPath(env);
308
- let cfg = {};
309
- if (existsSync(path)) {
310
- cfg = JSON.parse(readFileSync(path, "utf8"));
311
- }
311
+ const cfg = existsSync(path) ? readJsonConfig(path) : {};
312
312
  mutate(cfg);
313
313
  mkdirSync(dirname(path), { recursive: true });
314
314
  writeFileAtomic(path, `${JSON.stringify(cfg, null, 2)}
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  contentText
4
- } from "./chunk-VXRW5SYP.js";
4
+ } from "./chunk-OOOS5RCT.js";
5
5
 
6
6
  // src/session.ts
7
7
  import { randomBytes } from "crypto";
8
8
  import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from "fs";
9
- import { basename, join } from "path";
9
+ import { basename, dirname, join } from "path";
10
10
  function projectDir(home, cwd) {
11
11
  const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(-100) || "root";
12
12
  return join(home, "sessions", slug);
@@ -32,7 +32,6 @@ var Session = class _Session {
32
32
  }
33
33
  static create(home, cwd, now = /* @__PURE__ */ new Date()) {
34
34
  const dir = projectDir(home, cwd);
35
- mkdirSync(dir, { recursive: true });
36
35
  const stamp = now.toISOString().replace(/[:.]/g, "-");
37
36
  return new _Session(join(dir, `${stamp}-${randomBytes(3).toString("hex")}.jsonl`));
38
37
  }
@@ -49,6 +48,7 @@ var Session = class _Session {
49
48
  return _Session.list(home, cwd)[0]?.session;
50
49
  }
51
50
  write(record) {
51
+ mkdirSync(dirname(this.file), { recursive: true });
52
52
  appendFileSync(this.file, `${JSON.stringify(record)}
53
53
  `);
54
54
  }
@@ -185,6 +185,7 @@ Opsi:
185
185
  "usageCap.usd must be a number greater than 0.": "usageCap.usd harus angka lebih dari 0.",
186
186
  "usageCap.usd requires usageCap.prices (USD per 1M tokens).": "usageCap.usd memerlukan usageCap.prices (USD per 1 juta token).",
187
187
  'usageCap.prices["{key}"] must have numeric input and output (USD per 1M tokens).': 'usageCap.prices["{key}"] harus punya input dan output numerik (USD per 1 juta token).',
188
+ 'usageCap.prices["{key}"].cachedInput must be a number >= 0 (USD per 1M tokens).': 'usageCap.prices["{key}"].cachedInput harus angka >= 0 (USD per 1 juta token).',
188
189
  "usageCap needs at least one of: tokens, usd.": "usageCap memerlukan setidaknya salah satu dari: tokens, usd.",
189
190
  'updateCheck must be "on" or "off".': 'updateCheck harus "on" atau "off".',
190
191
  "repoMap must be true or false.": "repoMap harus true atau false.",
@@ -370,6 +371,8 @@ Opsi:
370
371
  "API key: env {env} only (via key_env; a plaintext key in config.yaml is never written).": "API key: hanya env {env} (melalui key_env; key plaintext tidak pernah ditulis ke config.yaml).",
371
372
  "{target}: not managed by BCCLI yet.": "{target}: belum dikelola oleh BCCLI.",
372
373
  "{target}: the BotConnector integration was removed and the config restored.": "{target}: integrasi BotConnector dilepas dan config dipulihkan.",
374
+ '{target}: {path} changed after BCCLI connected it, so the old backup was not copied over it. Remove the BCCLI part (provider "botconnector" or the marked block) from that file by hand.': '{target}: {path} berubah setelah BCCLI menyambungkannya, jadi backup lama tidak ditimpa ke file itu. Hapus bagian BCCLI (provider "botconnector" atau blok bertanda) dari file tersebut secara manual.',
375
+ "{target}: the BotConnector integration was removed. {n} file(s) were left untouched (see above); delete the BCCLI entries in them by hand for a clean removal.": "{target}: integrasi BotConnector dilepas. {n} file tidak disentuh (lihat di atas); hapus entri BCCLI di dalamnya secara manual agar bersih.",
373
376
  "Custom commands:": "Perintah custom:",
374
377
  "Skills:": "Skill:",
375
378
  "shift+tab switch permission mode esc cancel the turn": "shift+tab ganti mode izin esc batalkan giliran",
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  quarantineCorruptFile,
4
4
  writeFileAtomic
5
- } from "./chunk-USFXL5BS.js";
5
+ } from "./chunk-C2FUGQJX.js";
6
6
 
7
7
  // src/mcp/oauth.ts
8
8
  import { spawn } from "child_process";
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  listAllModels
4
- } from "./chunk-SXRQ2Q7A.js";
4
+ } from "./chunk-Y6AZGGH7.js";
5
5
  import {
6
6
  hasKey,
7
7
  providerName,
8
8
  removeGlobalProvider,
9
9
  writeGlobalConfig
10
- } from "./chunk-MPYSYTSO.js";
10
+ } from "./chunk-X24APPXO.js";
11
11
  import {
12
12
  PRESETS,
13
13
  loadConfig,
14
14
  saveCredential
15
- } from "./chunk-USFXL5BS.js";
15
+ } from "./chunk-C2FUGQJX.js";
16
16
  import {
17
17
  t
18
- } from "./chunk-ED5TTYQU.js";
18
+ } from "./chunk-G5TG43R4.js";
19
19
 
20
20
  // src/providerCli.ts
21
21
  async function addProviderKey(providerId, key, deps) {
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  defaultOpen
4
- } from "./chunk-67REFMSY.js";
4
+ } from "./chunk-IHQGXDSG.js";
5
5
  import {
6
6
  removeCredential,
7
7
  saveCredential
8
- } from "./chunk-USFXL5BS.js";
8
+ } from "./chunk-C2FUGQJX.js";
9
9
  import {
10
10
  t
11
- } from "./chunk-ED5TTYQU.js";
11
+ } from "./chunk-G5TG43R4.js";
12
12
 
13
13
  // src/login.ts
14
14
  function readSecret(prompt) {
@@ -44,6 +44,11 @@ function readSecret(prompt) {
44
44
  stdin.on("data", onData);
45
45
  });
46
46
  }
47
+ function echoFor(ch) {
48
+ const code = ch.codePointAt(0) ?? 0;
49
+ if (code < 32 || code === 127) return void 0;
50
+ return ch;
51
+ }
47
52
  function readLine(prompt) {
48
53
  return new Promise((resolve) => {
49
54
  process.stdout.write(prompt);
@@ -71,8 +76,16 @@ function readLine(prompt) {
71
76
  return;
72
77
  }
73
78
  if (code === 3) process.exit(130);
74
- if (code === 127 || code === 8) value = value.slice(0, -1);
75
- else value += ch;
79
+ if (code === 127 || code === 8) {
80
+ if (value) {
81
+ value = value.slice(0, -1);
82
+ process.stdout.write("\b \b");
83
+ }
84
+ continue;
85
+ }
86
+ const echo = echoFor(ch);
87
+ if (echo) process.stdout.write(echo);
88
+ value += ch;
76
89
  }
77
90
  };
78
91
  stdin.on("data", onData);
@@ -91,8 +104,8 @@ function defaultLoginDeps() {
91
104
  fetch: globalThis.fetch,
92
105
  // Wiring NYATA jalur lama: persis runLogin lama (provider add + prompt key).
93
106
  legacyAdd: async (providerId, targetCwd) => {
94
- const { runProviderCommand } = await import("./providerCli-XA4LTWRD.js");
95
- const { parseCliArgs: parse } = await import("./args-EW7XJVQN.js");
107
+ const { runProviderCommand } = await import("./providerCli-TXMVPSW5.js");
108
+ const { parseCliArgs: parse } = await import("./args-K5AJFDCZ.js");
96
109
  return runProviderCommand(parse(["provider", "add", providerId]), {
97
110
  env: process.env,
98
111
  cwd: targetCwd,
@@ -117,12 +130,12 @@ async function runLogin(providerId, cwd, args, deps) {
117
130
  );
118
131
  return 1;
119
132
  }
120
- const { runOauthLogout } = await import("./oauthLogin-UI34LQZU.js");
133
+ const { runOauthLogout } = await import("./oauthLogin-YFL2N4QA.js");
121
134
  return runOauthLogout({ out: deps.out, err: deps.err, env: deps.env, removeCredential: deps.removeCredential });
122
135
  }
123
136
  if (args.key) return deps.legacyAdd(providerId, cwd);
124
137
  if (providerId === "openrouter") {
125
- const { runOauthLogin } = await import("./oauthLogin-UI34LQZU.js");
138
+ const { runOauthLogin } = await import("./oauthLogin-YFL2N4QA.js");
126
139
  return runOauthLogin({
127
140
  out: deps.out,
128
141
  err: deps.err,
@@ -139,6 +152,7 @@ async function runLogin(providerId, cwd, args, deps) {
139
152
 
140
153
  export {
141
154
  readSecret,
155
+ echoFor,
142
156
  readLine,
143
157
  defaultLoginDeps,
144
158
  runLogin
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var VERSION = true ? "0.4.10" : "0.0.0-dev";
4
+ var VERSION = true ? "0.4.11" : "0.0.0-dev";
5
5
 
6
6
  export {
7
7
  VERSION
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigError
4
- } from "./chunk-USFXL5BS.js";
4
+ } from "./chunk-C2FUGQJX.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-ED5TTYQU.js";
7
+ } from "./chunk-G5TG43R4.js";
8
8
 
9
9
  // src/mcp/catalog.ts
10
10
  var CATALOG = [