@botconnector/bccli 0.4.10 → 0.4.12

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-JZW3XHE5.js} +20 -5
  2. package/dist/acp.d.ts +17 -1
  3. package/dist/args-XVO7TB4C.js +13 -0
  4. package/dist/budget.d.ts +4 -1
  5. package/dist/{chunk-67REFMSY.js → chunk-3CYQYHPK.js} +1 -1
  6. package/dist/{chunk-VXRW5SYP.js → chunk-6JK4IBGK.js} +25 -14
  7. package/dist/{chunk-MPYSYTSO.js → chunk-6SDRWEPN.js} +1 -1
  8. package/dist/{chunk-4WI5ON64.js → chunk-7GM6NN5E.js} +1 -1
  9. package/dist/{chunk-6RVAPAE5.js → chunk-7XD47KN5.js} +1 -1
  10. package/dist/{chunk-SXRQ2Q7A.js → chunk-INMSTUB2.js} +4 -4
  11. package/dist/{chunk-CIEPLTGS.js → chunk-ISOKH5WB.js} +5 -5
  12. package/dist/{chunk-6N2BBLIT.js → chunk-JUC3ZOCV.js} +2 -2
  13. package/dist/{chunk-3PUWH62K.js → chunk-KDVL2NP6.js} +34 -50
  14. package/dist/{chunk-24KDXQZT.js → chunk-KEKDRROL.js} +3 -3
  15. package/dist/{chunk-ZWXKBFKW.js → chunk-KJIXA6MP.js} +23 -9
  16. package/dist/{chunk-CBD52BYV.js → chunk-OFMZ6CE6.js} +1 -1
  17. package/dist/{chunk-7HDBPDAD.js → chunk-Q42ZGVAQ.js} +2 -2
  18. package/dist/{chunk-ED5TTYQU.js → chunk-R754XIBJ.js} +11 -3
  19. package/dist/{chunk-3K66L37W.js → chunk-S3QEZDKB.js} +3 -3
  20. package/dist/{chunk-PGDYPOQW.js → chunk-SWNRA3EW.js} +4 -4
  21. package/dist/{chunk-USFXL5BS.js → chunk-TLCL6DC7.js} +6 -6
  22. package/dist/{chunk-WFZKJY3R.js → chunk-YYTFJUO2.js} +3 -2
  23. package/dist/{chunk-5QCCV2JM.js → chunk-ZJRZTMJF.js} +47 -18
  24. package/dist/cli.js +39 -39
  25. package/dist/{completion-GEFRIQWV.js → completion-Q7VHOPPV.js} +1 -1
  26. package/dist/{config-JKMYKNAT.js → config-T7MKGJVG.js} +2 -2
  27. package/dist/{config-JLOH5M6B.js → config-YYEAEN2C.js} +3 -3
  28. package/dist/{ghBotCli-WEVS6S6O.js → ghBotCli-7VUGI63S.js} +18 -16
  29. package/dist/{integrationCli-PKMICTHC.js → integrationCli-TO42MBZB.js} +192 -12
  30. package/dist/{login-2TZRODUL.js → login-BSMUGW7L.js} +6 -4
  31. package/dist/login.d.ts +2 -0
  32. package/dist/{mcpCli-TAPKYGHO.js → mcpCli-ZT7CRYMP.js} +6 -6
  33. package/dist/{modelsCli-6PK7V2QZ.js → modelsCli-2ZRW4CC4.js} +6 -6
  34. package/dist/{oauthLogin-UI34LQZU.js → oauthLogin-THSM6FE7.js} +1 -1
  35. package/dist/{pluginsCli-RCF33U5J.js → pluginsCli-EKQI4CJW.js} +2 -2
  36. package/dist/{prCli-24PMW7NS.js → prCli-FMQTOBIV.js} +1 -1
  37. package/dist/providerCli-3TFEKV4C.js +15 -0
  38. package/dist/sdk.js +111 -75
  39. package/dist/{serve-7BFCIEPJ.js → serve-DC6YICSK.js} +16 -16
  40. package/dist/{serve-XNJI67DU.js → serve-V6YVZTNR.js} +3 -3
  41. package/dist/session-LX4UNPCD.js +12 -0
  42. package/dist/setup-MFG3BWEU.js +24 -0
  43. package/dist/setup.d.ts +5 -0
  44. package/dist/{statsCli-QDHE4TKB.js → statsCli-7MIQHLVW.js} +2 -2
  45. package/dist/tools/bash.d.ts +2 -0
  46. package/dist/{transferCli-7OKKYGG2.js → transferCli-SRSYQLSJ.js} +4 -4
  47. package/dist/{ui-SZAIIJC5.js → ui-IMCUSB6Q.js} +14 -14
  48. package/dist/{update-JSNVVXPS.js → update-POT5W6MC.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-R754XIBJ.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-XVO7TB4C.js");
194
+ const { createRuntime } = await import("./setup-MFG3BWEU.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-ISOKH5WB.js";
6
+ import "./chunk-YYTFJUO2.js";
7
+ import "./chunk-7XD47KN5.js";
8
+ import "./chunk-TLCL6DC7.js";
9
+ import "./chunk-R754XIBJ.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,7 +2,7 @@
2
2
  import {
3
3
  quarantineCorruptFile,
4
4
  writeFileAtomic
5
- } from "./chunk-USFXL5BS.js";
5
+ } from "./chunk-TLCL6DC7.js";
6
6
 
7
7
  // src/mcp/oauth.ts
8
8
  import { spawn } from "child_process";
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  reasoningPayload
4
- } from "./chunk-6RVAPAE5.js";
4
+ } from "./chunk-7XD47KN5.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-ED5TTYQU.js";
7
+ } from "./chunk-R754XIBJ.js";
8
8
 
9
9
  // src/provider.ts
10
10
  import OpenAI from "openai";
@@ -440,7 +440,7 @@ function hasPendingProgrammaticReplay(messages) {
440
440
  }
441
441
  return pending;
442
442
  }
443
- async function readResponsesStream(res, onText, onThinking) {
443
+ async function readResponsesStream(res, onText, onThinking, signal) {
444
444
  let text = "";
445
445
  let thinking = "";
446
446
  let usage;
@@ -542,17 +542,28 @@ async function readResponsesStream(res, onText, onThinking) {
542
542
  );
543
543
  }
544
544
  };
545
- for await (const chunk of res.body) {
546
- buffer += decoder.decode(chunk, { stream: true });
547
- let newline = buffer.indexOf("\n");
548
- while (newline >= 0 && loopAt < 0) {
549
- handle(buffer.slice(0, newline).trim());
550
- buffer = buffer.slice(newline + 1);
551
- newline = buffer.indexOf("\n");
552
- }
553
- if (loopAt >= 0) {
554
- return { text: text.slice(0, loopAt), toolCalls: [], usage, finishReason: "repetition" };
545
+ const iterator = res.body[Symbol.asyncIterator]();
546
+ const onAbort = () => void iterator.return?.();
547
+ if (signal?.aborted) onAbort();
548
+ else signal?.addEventListener("abort", onAbort);
549
+ try {
550
+ for (; ; ) {
551
+ const step = await iterator.next();
552
+ if (step.done) break;
553
+ buffer += decoder.decode(step.value, { stream: true });
554
+ let newline = buffer.indexOf("\n");
555
+ while (newline >= 0 && loopAt < 0) {
556
+ handle(buffer.slice(0, newline).trim());
557
+ buffer = buffer.slice(newline + 1);
558
+ newline = buffer.indexOf("\n");
559
+ }
560
+ if (loopAt >= 0) {
561
+ return { text: text.slice(0, loopAt), toolCalls: [], usage, finishReason: "repetition" };
562
+ }
555
563
  }
564
+ } finally {
565
+ signal?.removeEventListener("abort", onAbort);
566
+ void iterator.return?.();
556
567
  }
557
568
  handle(buffer.trim());
558
569
  return {
@@ -996,7 +1007,7 @@ function createProvider(options) {
996
1007
  );
997
1008
  if ((res2.headers.get("content-type") ?? "").includes("application/json")) return readResponsesJson(res2, onThinking);
998
1009
  if (!res2.body) throw new ProviderError(t("Empty response from the provider"));
999
- return readResponsesStream(res2, onText, onThinking);
1010
+ return readResponsesStream(res2, onText, onThinking, signal);
1000
1011
  }
1001
1012
  const res = await post(
1002
1013
  "/chat/completions",
@@ -6,7 +6,7 @@ import {
6
6
  readJsonConfig,
7
7
  removeCredential,
8
8
  writeFileAtomic
9
- } from "./chunk-USFXL5BS.js";
9
+ } from "./chunk-TLCL6DC7.js";
10
10
 
11
11
  // src/providers.ts
12
12
  import { join } from "path";
@@ -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-R754XIBJ.js";
8
8
 
9
9
  // src/tools/websearch.ts
10
10
  import { z } from "zod";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  t
4
- } from "./chunk-ED5TTYQU.js";
4
+ } from "./chunk-R754XIBJ.js";
5
5
 
6
6
  // src/reasoning.ts
7
7
  var REASONING_LEVELS = ["auto", "off", "low", "medium", "high", "max"];
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  hasKey,
4
4
  providerName
5
- } from "./chunk-MPYSYTSO.js";
5
+ } from "./chunk-6SDRWEPN.js";
6
6
  import {
7
7
  createProvider
8
- } from "./chunk-VXRW5SYP.js";
8
+ } from "./chunk-6JK4IBGK.js";
9
9
  import {
10
10
  PRESETS,
11
11
  readCredentials
12
- } from "./chunk-USFXL5BS.js";
12
+ } from "./chunk-TLCL6DC7.js";
13
13
  import {
14
14
  t
15
- } from "./chunk-ED5TTYQU.js";
15
+ } from "./chunk-R754XIBJ.js";
16
16
 
17
17
  // src/models.ts
18
18
  function order(ids) {
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MODE_ORDER
4
- } from "./chunk-WFZKJY3R.js";
4
+ } from "./chunk-YYTFJUO2.js";
5
5
  import {
6
6
  REASONING_LEVELS,
7
7
  isReasoningLevel
8
- } from "./chunk-6RVAPAE5.js";
8
+ } from "./chunk-7XD47KN5.js";
9
9
  import {
10
10
  ConfigError
11
- } from "./chunk-USFXL5BS.js";
11
+ } from "./chunk-TLCL6DC7.js";
12
12
  import {
13
13
  parseLang,
14
14
  t
15
- } from "./chunk-ED5TTYQU.js";
15
+ } from "./chunk-R754XIBJ.js";
16
16
 
17
17
  // src/args.ts
18
18
  import { parseArgs } from "util";
@@ -102,7 +102,7 @@ Usage:
102
102
  bccli import <file> import a session JSONL into the current project
103
103
  bccli pr <number> [--repo owner/name] [task] check out a GitHub PR and run a task on it
104
104
  bccli integrations show the status of external agent integrations
105
- bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, cursor, openai-cli, openai-sdk, openai-compatible, openclaw, hermes
105
+ bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, openclaw, hermes, crush, kilo, cursor, openai-cli, openai-sdk, openai-compatible
106
106
  bccli disconnect <agent> remove an integration and restore the previous config
107
107
 
108
108
  Options:
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigError
4
- } from "./chunk-USFXL5BS.js";
4
+ } from "./chunk-TLCL6DC7.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-ED5TTYQU.js";
7
+ } from "./chunk-R754XIBJ.js";
8
8
 
9
9
  // src/mcp/catalog.ts
10
10
  var CATALOG = [
@@ -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-R754XIBJ.js";
8
8
 
9
9
  // src/tools/bash.ts
10
10
  import { spawn } from "child_process";
@@ -34,60 +34,39 @@ function darwinProfile(cwd, network) {
34
34
  network ? "(allow network*)" : "(deny network*)"
35
35
  ].join("\n");
36
36
  }
37
+ function bwrapArgv(cwd, network, command) {
38
+ return [
39
+ "bwrap",
40
+ "--ro-bind",
41
+ "/",
42
+ "/",
43
+ "--dev-bind",
44
+ "/dev",
45
+ "/dev",
46
+ "--proc",
47
+ "/proc",
48
+ "--bind",
49
+ cwd,
50
+ cwd,
51
+ "--tmpfs",
52
+ "/tmp",
53
+ "--die-with-parent",
54
+ ...network ? [] : ["--unshare-net"],
55
+ "--",
56
+ "/bin/bash",
57
+ "-c",
58
+ command
59
+ ];
60
+ }
37
61
  function sandboxArgv(command, opts) {
38
62
  if (opts.platform === "darwin") {
39
63
  return ["sandbox-exec", "-p", darwinProfile(opts.cwd, opts.network), "/bin/bash", "-c", command];
40
64
  }
41
65
  if (opts.platform === "linux") {
42
- return [
43
- "bwrap",
44
- "--ro-bind",
45
- "/",
46
- "/",
47
- "--dev-bind",
48
- "/dev",
49
- "/dev",
50
- "--proc",
51
- "/proc",
52
- "--bind",
53
- opts.cwd,
54
- opts.cwd,
55
- "--tmpfs",
56
- "/tmp",
57
- "--die-with-parent",
58
- ...opts.network ? [] : ["--unshare-net"],
59
- "--",
60
- "/bin/bash",
61
- "-c",
62
- command
63
- ];
66
+ return bwrapArgv(opts.cwd, opts.network, command);
64
67
  }
65
68
  if (opts.platform === "win32" && (opts.wslBwrap || process.env.BCCLI_WIN32_WSL_SANDBOX === "1")) {
66
- const wslCwd = winPathToWsl(opts.cwd);
67
- return [
68
- "wsl.exe",
69
- "--",
70
- "bwrap",
71
- "--ro-bind",
72
- "/",
73
- "/",
74
- "--dev-bind",
75
- "/dev",
76
- "/dev",
77
- "--proc",
78
- "/proc",
79
- "--bind",
80
- wslCwd,
81
- wslCwd,
82
- "--tmpfs",
83
- "/tmp",
84
- "--die-with-parent",
85
- ...opts.network ? [] : ["--unshare-net"],
86
- "--",
87
- "/bin/bash",
88
- "-c",
89
- command
90
- ];
69
+ return ["wsl.exe", "--", ...bwrapArgv(winPathToWsl(opts.cwd), opts.network, command)];
91
70
  }
92
71
  return void 0;
93
72
  }
@@ -156,7 +135,7 @@ function killAllCommands() {
156
135
  }
157
136
  var backgrounds = /* @__PURE__ */ new Map();
158
137
  var nextBackgroundId = 1;
159
- function startBackground(command, cwd, env, shell) {
138
+ function startBackground(command, cwd, env, shell, maxRetained) {
160
139
  const child = spawnChild(command, cwd, env, shell);
161
140
  const task = {
162
141
  id: nextBackgroundId++,
@@ -177,6 +156,10 @@ function startBackground(command, cwd, env, shell) {
177
156
  if (child.pid !== void 0) killProcessTree(child.pid);
178
157
  };
179
158
  backgrounds.set(task.id, task);
159
+ for (const [id, other] of backgrounds) {
160
+ if (backgrounds.size <= maxRetained) break;
161
+ if (id !== task.id && other.status === "exited") backgrounds.delete(id);
162
+ }
180
163
  const onData = (data) => {
181
164
  let s = data;
182
165
  if (task.head.length < HALF) {
@@ -385,6 +368,7 @@ var SHELL_NOTE = {
385
368
  function createBashTool(options = {}) {
386
369
  const offline = options.networkPolicy === "offline";
387
370
  const sandbox = options.sandbox === true;
371
+ const maxRetained = options.maxRetainedTasks ?? 50;
388
372
  const platform = options.platform ?? process.platform;
389
373
  const shell = resolveShell({ platform, env: process.env, exists: existsSync2, ...options.shellDeps });
390
374
  const childEnv = offline ? offlineEnv() : void 0;
@@ -431,7 +415,7 @@ Network access is off (networkPolicy "offline"): internet commands such as curl,
431
415
  }
432
416
  if (input.background) {
433
417
  if (!input.command) return { output: 'The "command" argument is required to start a background task.', isError: true };
434
- const task = startBackground(exec, ctx.cwd, childEnv, shell);
418
+ const task = startBackground(exec, ctx.cwd, childEnv, shell, maxRetained);
435
419
  return {
436
420
  output: `Background task #${task.id} started: ${input.command}
437
421
  Poll it with {task_id: ${task.id}}; stop it with {task_id: ${task.id}, kill: true}.`
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  contentText
4
- } from "./chunk-VXRW5SYP.js";
4
+ } from "./chunk-6JK4IBGK.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
  }
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  defaultOpen
4
- } from "./chunk-67REFMSY.js";
4
+ } from "./chunk-3CYQYHPK.js";
5
5
  import {
6
6
  removeCredential,
7
7
  saveCredential
8
- } from "./chunk-USFXL5BS.js";
8
+ } from "./chunk-TLCL6DC7.js";
9
9
  import {
10
10
  t
11
- } from "./chunk-ED5TTYQU.js";
11
+ } from "./chunk-R754XIBJ.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-3TFEKV4C.js");
108
+ const { parseCliArgs: parse } = await import("./args-XVO7TB4C.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-THSM6FE7.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-THSM6FE7.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.12" : "0.0.0-dev";
5
5
 
6
6
  export {
7
7
  VERSION
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  ConfigError,
4
4
  writeFileAtomic
5
- } from "./chunk-USFXL5BS.js";
5
+ } from "./chunk-TLCL6DC7.js";
6
6
  import {
7
7
  t
8
- } from "./chunk-ED5TTYQU.js";
8
+ } from "./chunk-R754XIBJ.js";
9
9
 
10
10
  // src/mcp/config.ts
11
11
  import { createHash } from "crypto";
@@ -126,7 +126,7 @@ Usage:
126
126
  bccli import <file> import a session JSONL into the current project
127
127
  bccli pr <number> [--repo owner/name] [task] check out a GitHub PR and run a task on it
128
128
  bccli integrations show the status of external agent integrations
129
- bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, cursor, openai-cli, openai-sdk, openai-compatible, openclaw, hermes
129
+ bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, openclaw, hermes, crush, kilo, cursor, openai-cli, openai-sdk, openai-compatible
130
130
  bccli disconnect <agent> remove an integration and restore the previous config
131
131
 
132
132
  Options:
@@ -157,7 +157,7 @@ Pemakaian:
157
157
  bccli provider list|add <id>|remove <id> kelola provider (custom: --url <url> [--name N] [--key-env ENV])
158
158
  bccli mcp list|add <nama>|remove <nama>|auth <nama>|logout <nama>|serve [--base-url <url>] kelola server MCP, atau layani tools akun ini lewat stdio
159
159
  bccli integrations lihat status integrasi agent eksternal
160
- bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, cursor, openai-cli, openai-sdk, openai-compatible, openclaw, hermes
160
+ bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, openclaw, hermes, crush, kilo, cursor, openai-cli, openai-sdk, openai-compatible
161
161
  bccli disconnect <agent> lepas integrasi dan pulihkan config sebelumnya
162
162
 
163
163
  Opsi:
@@ -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.",
@@ -334,7 +335,12 @@ Opsi:
334
335
  '-p mode needs a task, e.g. bccli -p "explain this repo"': 'Mode -p butuh tugas, contoh: bccli -p "jelaskan repo ini"',
335
336
  'Project MCP server "{name}" skipped (not approved yet; run interactive bccli once to approve it).': 'Server MCP project "{name}" dilewati (belum diizinkan; jalankan bccli interaktif sekali untuk menyetujuinya).',
336
337
  'Interactive mode needs a terminal. For scripts/CI use: bccli -p "task"': 'Mode interaktif butuh terminal. Untuk skrip/CI pakai: bccli -p "tugas"',
337
- "Agent must be one of: opencode, aider, cline, deepseek-harness (dsh), cursor, openai-cli, openai-sdk, openai-compatible, codex, claude-code, openclaw, hermes": "Agent harus salah satu dari: opencode, aider, cline, deepseek-harness (dsh), cursor, openai-cli, openai-sdk, openai-compatible, codex, claude-code, openclaw, hermes",
338
+ "Agent must be one of: opencode, aider, cline, deepseek-harness (dsh), cursor, openai-cli, openai-sdk, openai-compatible, codex, claude-code, openclaw, hermes, crush, kilo": "Agent harus salah satu dari: opencode, aider, cline, deepseek-harness (dsh), cursor, openai-cli, openai-sdk, openai-compatible, codex, claude-code, openclaw, hermes, crush, kilo",
339
+ "Crush already has a botconnector provider outside the BCCLI block: {path}": "Crush sudah memiliki provider botconnector di luar blok BCCLI: {path}",
340
+ "Crush is connected to BotConnector ({n} models available; large model {model}).": "Crush terhubung ke BotConnector ({n} model tersedia; model large {model}).",
341
+ "The Kilo global kilo.json is not valid JSON: {path}": "kilo.json global Kilo tidak valid JSON: {path}",
342
+ 'Kilo already has a provider "{id}" with a different endpoint.': 'Kilo sudah memiliki provider "{id}" dengan endpoint lain.',
343
+ "Kilo Code is connected to BotConnector ({n} models available; suggested model {model}).": "Kilo Code terhubung ke BotConnector ({n} model tersedia; model yang disarankan {model}).",
338
344
  "Cannot determine the home directory.": "Home directory tidak dapat ditentukan.",
339
345
  "No BotConnector API key yet. Run bccli login bc-cloud first.": "API key BotConnector belum tersedia. Jalankan bccli login bc-cloud terlebih dahulu.",
340
346
  "Could not load the BotConnector model catalog (HTTP {status}).": "Katalog model BotConnector gagal dimuat (HTTP {status}).",
@@ -370,6 +376,8 @@ Opsi:
370
376
  "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
377
  "{target}: not managed by BCCLI yet.": "{target}: belum dikelola oleh BCCLI.",
372
378
  "{target}: the BotConnector integration was removed and the config restored.": "{target}: integrasi BotConnector dilepas dan config dipulihkan.",
379
+ '{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.',
380
+ "{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
381
  "Custom commands:": "Perintah custom:",
374
382
  "Skills:": "Skill:",
375
383
  "shift+tab switch permission mode esc cancel the turn": "shift+tab ganti mode izin esc batalkan giliran",
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  runCommand,
4
4
  runHooks
5
- } from "./chunk-3PUWH62K.js";
5
+ } from "./chunk-KDVL2NP6.js";
6
6
  import {
7
7
  ConfigError
8
- } from "./chunk-USFXL5BS.js";
8
+ } from "./chunk-TLCL6DC7.js";
9
9
  import {
10
10
  t
11
- } from "./chunk-ED5TTYQU.js";
11
+ } from "./chunk-R754XIBJ.js";
12
12
 
13
13
  // src/verify.ts
14
14
  var MAX_VERIFY_ROUNDS = 2;
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  listAllModels
4
- } from "./chunk-SXRQ2Q7A.js";
4
+ } from "./chunk-INMSTUB2.js";
5
5
  import {
6
6
  hasKey,
7
7
  providerName,
8
8
  removeGlobalProvider,
9
9
  writeGlobalConfig
10
- } from "./chunk-MPYSYTSO.js";
10
+ } from "./chunk-6SDRWEPN.js";
11
11
  import {
12
12
  PRESETS,
13
13
  loadConfig,
14
14
  saveCredential
15
- } from "./chunk-USFXL5BS.js";
15
+ } from "./chunk-TLCL6DC7.js";
16
16
  import {
17
17
  t
18
- } from "./chunk-ED5TTYQU.js";
18
+ } from "./chunk-R754XIBJ.js";
19
19
 
20
20
  // src/providerCli.ts
21
21
  async function addProviderKey(providerId, key, deps) {