@botconnector/bccli 0.4.0-beta.41 → 0.4.0-beta.43

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 (50) hide show
  1. package/dist/{acp-SZWZ5EE4.js → acp-U25MNDND.js} +2 -2
  2. package/dist/{args-4SMOHFN5.js → args-MFTMBNRN.js} +4 -4
  3. package/dist/{chunk-LN32JIZR.js → chunk-25DSN3Y3.js} +4 -4
  4. package/dist/{chunk-JROUQ5YS.js → chunk-2ON3WIDP.js} +4 -4
  5. package/dist/{chunk-3HCOAJEQ.js → chunk-7F3IWBPQ.js} +1 -0
  6. package/dist/{chunk-VM7HYAJS.js → chunk-BQHKN7JI.js} +1 -1
  7. package/dist/{chunk-AS7VV7D3.js → chunk-CYTRCZXI.js} +27 -8
  8. package/dist/{chunk-EQQTTE2K.js → chunk-DUSVS3XK.js} +1 -1
  9. package/dist/{chunk-M7LLJQ7M.js → chunk-GIGWZFCY.js} +64 -24
  10. package/dist/{chunk-ISCT3PN3.js → chunk-I7GXIJCY.js} +2 -2
  11. package/dist/{chunk-HE33XAPZ.js → chunk-NVRNFR4S.js} +1 -1
  12. package/dist/{chunk-DBHDZ5EP.js → chunk-PSRNKKGA.js} +13 -3
  13. package/dist/{chunk-AVB6M4JE.js → chunk-PZC2Q6MJ.js} +2 -2
  14. package/dist/{chunk-M23QBX3V.js → chunk-QHNWI3OT.js} +80 -3
  15. package/dist/{chunk-GGNXHJL6.js → chunk-RMDW3OQ6.js} +2 -2
  16. package/dist/{chunk-BUHWQU3V.js → chunk-TW5HZOTB.js} +3 -3
  17. package/dist/chunk-U6PCNS4B.js +20 -0
  18. package/dist/{chunk-SESBH44L.js → chunk-VO6MF6JJ.js} +1 -1
  19. package/dist/chunk-Y3QKYORR.js +145 -0
  20. package/dist/{chunk-M4IYXI3V.js → chunk-ZGH4B7OU.js} +27 -33
  21. package/dist/{chunk-NI5JZUZ3.js → chunk-ZKMSTD6G.js} +1 -1
  22. package/dist/cli.js +78 -37
  23. package/dist/completion-6K4AXKK2.js +125 -0
  24. package/dist/config-LCY27K3L.js +30 -0
  25. package/dist/{config-C4KLLDC6.js → config-Z4HSA435.js} +3 -3
  26. package/dist/ghBotCli-TJMKJU3E.js +677 -0
  27. package/dist/{integrationCli-HR7CDUSI.js → integrationCli-33KU6GIK.js} +2 -2
  28. package/dist/login-LNF7ZV2S.js +16 -0
  29. package/dist/{mcpCli-5QTXH7XJ.js → mcpCli-TXFS3AOJ.js} +6 -6
  30. package/dist/{modelsCli-DKTT3UZD.js → modelsCli-IZSMIYVB.js} +6 -6
  31. package/dist/npmRunner-LU43GM3W.js +46 -0
  32. package/dist/oauthLogin-QGDYTOW7.js +210 -0
  33. package/dist/pluginsCli-RD4QW3DX.js +284 -0
  34. package/dist/prCli-NR3ZQMST.js +73 -0
  35. package/dist/providerCli-AA3CHCGV.js +15 -0
  36. package/dist/sdk.js +160 -57
  37. package/dist/{serve-KQ35P4W3.js → serve-F7BYQ7X6.js} +19 -18
  38. package/dist/{serve-I2VQUTHR.js → serve-YNKE332Z.js} +3 -3
  39. package/dist/session-KRV2UP5C.js +12 -0
  40. package/dist/setup-L4OPF3XW.js +24 -0
  41. package/dist/statsCli-RPCIMT5R.js +109 -0
  42. package/dist/transferCli-RQBB6RVY.js +71 -0
  43. package/dist/{ui-S4QFJJIB.js → ui-4ZTUMTYM.js} +13 -13
  44. package/dist/{update-VBDEHHMR.js → update-7SSREI2O.js} +2 -2
  45. package/package.json +1 -1
  46. package/dist/chunk-DSFHN5CH.js +0 -52
  47. package/dist/login-T5S6SPZA.js +0 -9
  48. package/dist/providerCli-DDH4ZZUY.js +0 -15
  49. package/dist/session-H2YL5RSB.js +0 -12
  50. package/dist/setup-45WQXUBK.js +0 -23
@@ -97,8 +97,8 @@ function runAcp(input, output, opts) {
97
97
  function runtimeAgent(cwd) {
98
98
  return {
99
99
  async run(text, onChunk, signal) {
100
- const { parseCliArgs } = await import("./args-4SMOHFN5.js");
101
- const { createRuntime } = await import("./setup-45WQXUBK.js");
100
+ const { parseCliArgs } = await import("./args-MFTMBNRN.js");
101
+ const { createRuntime } = await import("./setup-L4OPF3XW.js");
102
102
  const rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll: true } });
103
103
  rt.agent.onEvent = (event) => {
104
104
  if (event.type === "text") onChunk(event.delta);
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  helpText,
4
4
  parseCliArgs
5
- } from "./chunk-AS7VV7D3.js";
5
+ } from "./chunk-CYTRCZXI.js";
6
6
  import "./chunk-GAFJEQTJ.js";
7
- import "./chunk-NI5JZUZ3.js";
8
- import "./chunk-M7LLJQ7M.js";
9
- import "./chunk-M23QBX3V.js";
7
+ import "./chunk-ZKMSTD6G.js";
8
+ import "./chunk-GIGWZFCY.js";
9
+ import "./chunk-QHNWI3OT.js";
10
10
  export {
11
11
  helpText,
12
12
  parseCliArgs
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  hasKey,
4
4
  providerName
5
- } from "./chunk-SESBH44L.js";
5
+ } from "./chunk-VO6MF6JJ.js";
6
6
  import {
7
7
  createProvider
8
- } from "./chunk-GGNXHJL6.js";
8
+ } from "./chunk-RMDW3OQ6.js";
9
9
  import {
10
10
  PRESETS,
11
11
  readCredentials
12
- } from "./chunk-M7LLJQ7M.js";
12
+ } from "./chunk-GIGWZFCY.js";
13
13
  import {
14
14
  t
15
- } from "./chunk-M23QBX3V.js";
15
+ } from "./chunk-QHNWI3OT.js";
16
16
 
17
17
  // src/models.ts
18
18
  function order(ids) {
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  listAllModels
4
- } from "./chunk-LN32JIZR.js";
4
+ } from "./chunk-25DSN3Y3.js";
5
5
  import {
6
6
  hasKey,
7
7
  providerName,
8
8
  removeGlobalProvider,
9
9
  writeGlobalConfig
10
- } from "./chunk-SESBH44L.js";
10
+ } from "./chunk-VO6MF6JJ.js";
11
11
  import {
12
12
  PRESETS,
13
13
  loadConfig,
14
14
  saveCredential
15
- } from "./chunk-M7LLJQ7M.js";
15
+ } from "./chunk-GIGWZFCY.js";
16
16
  import {
17
17
  t
18
- } from "./chunk-M23QBX3V.js";
18
+ } from "./chunk-QHNWI3OT.js";
19
19
 
20
20
  // src/providerCli.ts
21
21
  async function addProviderKey(providerId, key, deps) {
@@ -185,6 +185,7 @@ async function authorizeMcpServer(spec, deps) {
185
185
  export {
186
186
  hasStoredTokens,
187
187
  clearTokens,
188
+ defaultOpen,
188
189
  FileOAuthProvider,
189
190
  authorizeMcpServer
190
191
  };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  contentText
4
- } from "./chunk-GGNXHJL6.js";
4
+ } from "./chunk-RMDW3OQ6.js";
5
5
 
6
6
  // src/session.ts
7
7
  import { randomBytes } from "crypto";
@@ -5,14 +5,14 @@ import {
5
5
  import {
6
6
  REASONING_LEVELS,
7
7
  isReasoningLevel
8
- } from "./chunk-NI5JZUZ3.js";
8
+ } from "./chunk-ZKMSTD6G.js";
9
9
  import {
10
10
  ConfigError
11
- } from "./chunk-M7LLJQ7M.js";
11
+ } from "./chunk-GIGWZFCY.js";
12
12
  import {
13
13
  parseLang,
14
14
  t
15
- } from "./chunk-M23QBX3V.js";
15
+ } from "./chunk-QHNWI3OT.js";
16
16
 
17
17
  // src/args.ts
18
18
  import { parseArgs } from "util";
@@ -77,13 +77,20 @@ var HELP = `BCCLI \u2014 BotConnector's AI coding agent for the terminal
77
77
  Usage:
78
78
  bccli [task] interactive mode (optionally start with a task)
79
79
  bccli -p "task" run one task without interaction (scripts/CI)
80
- bccli login [provider] save an API key (default: bc-cloud)
80
+ bccli login [provider] OAuth login (or --key paste API key, --logout remove)
81
81
  bccli models [provider] list models (default: the active provider)
82
82
  bccli update install the newest bccli from npm
83
83
  bccli acp run as an ACP agent for editors (Zed, ...)
84
84
  bccli serve [--port N] serve sessions over HTTP+WS for IDEs/bots
85
+ bccli plugins list, install, remove, or update plugins
86
+ bccli gh-bot [serve] GitHub comment bot (off-by-default; needs config)
85
87
  bccli provider list|add <id>|remove <id> manage providers (custom: --url <url> [--name N] [--key-env ENV])
86
88
  bccli mcp list|add <name>|remove <name>|auth <name>|logout <name>|serve [--base-url <url>] manage MCP servers, or serve this account's tools over stdio
89
+ bccli completion <shell> print a shell completion script (bash, zsh, fish, powershell)
90
+ bccli stats [--days N] show token usage from local sessions (default: last 7 days)
91
+ bccli export [session] [file] copy a session JSONL to a file (default: last session here)
92
+ bccli import <file> import a session JSONL into the current project
93
+ bccli pr <number> [--repo owner/name] [task] check out a GitHub PR and run a task on it
87
94
  bccli integrations show the status of external agent integrations
88
95
  bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, cursor, openai-cli, openai-sdk, openai-compatible, openclaw, hermes
89
96
  bccli disconnect <agent> remove an integration and restore the previous config
@@ -124,10 +131,14 @@ function parseCliArgs(argv) {
124
131
  name: { type: "string" },
125
132
  "key-env": { type: "string" },
126
133
  value: { type: "string", multiple: true },
134
+ key: { type: "boolean" },
135
+ logout: { type: "boolean" },
127
136
  port: { type: "string" },
128
137
  host: { type: "string" },
129
138
  token: { type: "string" },
130
- "base-url": { type: "string" }
139
+ "base-url": { type: "string" },
140
+ days: { type: "string" },
141
+ repo: { type: "string" }
131
142
  }
132
143
  });
133
144
  const reasoning = values.reasoning;
@@ -144,13 +155,17 @@ function parseCliArgs(argv) {
144
155
  throw new ConfigError(t("--output-format must be one of: {formats}", { formats: "text, json, stream-json" }));
145
156
  }
146
157
  const [first, ...rest] = positionals;
147
- const SUBCOMMANDS = ["login", "models", "update", "acp", "serve", "provider", "mcp", "connect", "disconnect", "integrations"];
158
+ const SUBCOMMANDS = ["login", "models", "update", "acp", "serve", "plugins", "gh-bot", "provider", "mcp", "connect", "disconnect", "integrations", "completion", "stats", "export", "import", "pr"];
148
159
  const command = SUBCOMMANDS.includes(first) ? first : "run";
149
160
  const words = command === "run" ? positionals : rest;
150
161
  const port = values.port !== void 0 ? Number(values.port) : void 0;
151
162
  if (port !== void 0 && (!Number.isInteger(port) || port < 0 || port > 65535)) {
152
163
  throw new ConfigError(t("--port must be a number between 0 and 65535"));
153
164
  }
165
+ const days = values.days !== void 0 ? Number(values.days) : void 0;
166
+ if (days !== void 0 && (!Number.isInteger(days) || days < 1)) {
167
+ throw new ConfigError(t("--days must be a positive integer"));
168
+ }
154
169
  if (values.host !== void 0 && !LOOPBACK_BIND.has(values.host)) {
155
170
  throw new ConfigError(t("serve only accepts loopback --host (127.0.0.1, localhost, ::1)"));
156
171
  }
@@ -171,7 +186,9 @@ function parseCliArgs(argv) {
171
186
  help: !!values.help,
172
187
  version: !!values.version,
173
188
  loginProvider: command === "login" ? rest[0] ?? "bc-cloud" : void 0,
174
- subArgs: ["models", "provider", "mcp", "connect", "disconnect", "integrations"].includes(command) ? rest : [],
189
+ key: !!values.key,
190
+ logout: !!values.logout,
191
+ subArgs: ["models", "plugins", "gh-bot", "provider", "mcp", "connect", "disconnect", "integrations", "completion", "stats", "export", "import", "pr"].includes(command) ? rest : [],
175
192
  url: values.url,
176
193
  name: values.name,
177
194
  keyEnv: values["key-env"],
@@ -179,7 +196,9 @@ function parseCliArgs(argv) {
179
196
  port,
180
197
  host: values.host,
181
198
  token: values.token,
182
- baseUrl: values["base-url"]
199
+ baseUrl: values["base-url"],
200
+ days,
201
+ repo: values.repo
183
202
  };
184
203
  }
185
204
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var VERSION = true ? "0.4.0-beta.41" : "0.0.0-dev";
4
+ var VERSION = true ? "0.4.0-beta.43" : "0.0.0-dev";
5
5
 
6
6
  export {
7
7
  VERSION
@@ -1,7 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  t
4
- } from "./chunk-M23QBX3V.js";
4
+ } from "./chunk-QHNWI3OT.js";
5
+
6
+ // src/config.ts
7
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
8
+ import { homedir } from "os";
9
+ import { dirname, join } from "path";
5
10
 
6
11
  // src/presets.ts
7
12
  var PRESETS = [
@@ -16,29 +21,6 @@ var PRESETS = [
16
21
  { id: "lmstudio", name: "LM Studio lokal", baseURL: "http://127.0.0.1:1234/v1", local: true }
17
22
  ];
18
23
 
19
- // src/ui/theme.ts
20
- var THEMES = ["default", "blue", "amber", "magenta", "mono"];
21
- var REMAP = {
22
- blue: { green: "blue" },
23
- amber: { green: "yellow" },
24
- magenta: { green: "magenta" }
25
- };
26
- var theme = "default";
27
- function setTheme(name) {
28
- theme = name;
29
- }
30
- function color(name) {
31
- if (process.env.NO_COLOR) return void 0;
32
- if (theme === "mono") return void 0;
33
- return REMAP[theme]?.[name] ?? name;
34
- }
35
- var ACCENT = "green";
36
-
37
- // src/config.ts
38
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
39
- import { homedir } from "os";
40
- import { join } from "path";
41
-
42
24
  // src/keybinds.ts
43
25
  var KEYBIND_ACTIONS = ["thinking", "toolOutput", "pasteImage"];
44
26
  var DEFAULT_KEYBINDS = {
@@ -62,6 +44,24 @@ function matchKeybind(kb, input, key) {
62
44
  return kb.ctrl === !!key.ctrl && kb.meta === !!key.meta && input.toLowerCase() === kb.key;
63
45
  }
64
46
 
47
+ // src/ui/theme.ts
48
+ var THEMES = ["default", "blue", "amber", "magenta", "mono"];
49
+ var REMAP = {
50
+ blue: { green: "blue" },
51
+ amber: { green: "yellow" },
52
+ magenta: { green: "magenta" }
53
+ };
54
+ var theme = "default";
55
+ function setTheme(name) {
56
+ theme = name;
57
+ }
58
+ function color(name) {
59
+ if (process.env.NO_COLOR) return void 0;
60
+ if (theme === "mono") return void 0;
61
+ return REMAP[theme]?.[name] ?? name;
62
+ }
63
+ var ACCENT = "green";
64
+
65
65
  // src/config.ts
66
66
  var ConfigError = class extends Error {
67
67
  };
@@ -251,6 +251,42 @@ function loadConfig(cwd, env = process.env) {
251
251
  allow: [...global.allow ?? []]
252
252
  };
253
253
  }
254
+ function globalConfigPath(env = process.env) {
255
+ return join(bccliHome(env), "config.json");
256
+ }
257
+ function readGlobalPlugins(env = process.env) {
258
+ const raw = readJsonConfig(globalConfigPath(env));
259
+ const value = raw.plugins;
260
+ if (value === void 0) return [];
261
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
262
+ throw new ConfigError(t("plugins must be an array of strings."));
263
+ }
264
+ return value;
265
+ }
266
+ function writeFileAtomic(path, data) {
267
+ const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
268
+ try {
269
+ writeFileSync(tmp, data);
270
+ renameSync(tmp, path);
271
+ } catch (error) {
272
+ try {
273
+ rmSync(tmp, { force: true });
274
+ } catch {
275
+ }
276
+ throw error;
277
+ }
278
+ }
279
+ function updateGlobalConfig(env, mutate) {
280
+ const path = globalConfigPath(env);
281
+ let cfg = {};
282
+ if (existsSync(path)) {
283
+ cfg = JSON.parse(readFileSync(path, "utf8"));
284
+ }
285
+ mutate(cfg);
286
+ mkdirSync(dirname(path), { recursive: true });
287
+ writeFileAtomic(path, `${JSON.stringify(cfg, null, 2)}
288
+ `);
289
+ }
254
290
  function readCredentials(env = process.env) {
255
291
  const path = join(bccliHome(env), "credentials");
256
292
  if (!existsSync(path)) return {};
@@ -300,9 +336,13 @@ export {
300
336
  color,
301
337
  ACCENT,
302
338
  ConfigError,
339
+ DEFAULT_MAX_STEPS,
303
340
  bccliHome,
304
341
  readJsonConfig,
305
342
  loadConfig,
343
+ globalConfigPath,
344
+ readGlobalPlugins,
345
+ updateGlobalConfig,
306
346
  readCredentials,
307
347
  saveCredential,
308
348
  resolveModel,
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigError
4
- } from "./chunk-M7LLJQ7M.js";
4
+ } from "./chunk-GIGWZFCY.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-M23QBX3V.js";
7
+ } from "./chunk-QHNWI3OT.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-M23QBX3V.js";
7
+ } from "./chunk-QHNWI3OT.js";
8
8
 
9
9
  // src/tools/websearch.ts
10
10
  import { z } from "zod";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-PSO7R5AD.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-M23QBX3V.js";
7
+ } from "./chunk-QHNWI3OT.js";
8
8
 
9
9
  // src/tools/bash.ts
10
10
  import { spawn } from "child_process";
@@ -173,8 +173,8 @@ function startBackground(command, cwd, env, shell) {
173
173
  return task;
174
174
  }
175
175
  function backgroundStatus(task) {
176
- if (task.status === "running") return `[running ${Math.round((Date.now() - task.startedAt) / 1e3)}s]`;
177
176
  if (task.killed) return "[killed]";
177
+ if (task.status === "running") return `[running ${Math.round((Date.now() - task.startedAt) / 1e3)}s]`;
178
178
  return `[exit code ${task.exitCode}]`;
179
179
  }
180
180
  function backgroundOutput(task) {
@@ -585,8 +585,18 @@ function runOne(command, event, payload, opts) {
585
585
  resolve(result);
586
586
  };
587
587
  let child;
588
+ const shell = defaultShell();
588
589
  try {
589
- child = spawn2(command, { shell: true, env, cwd: opts.cwd ?? process.cwd(), stdio: ["ignore", "pipe", "pipe"] });
590
+ if (shell) {
591
+ child = spawn2(shell.file, shell.args(command), {
592
+ shell: false,
593
+ env,
594
+ cwd: opts.cwd ?? process.cwd(),
595
+ stdio: ["ignore", "pipe", "pipe"]
596
+ });
597
+ } else {
598
+ child = spawn2(command, { shell: true, env, cwd: opts.cwd ?? process.cwd(), stdio: ["ignore", "pipe", "pipe"] });
599
+ }
590
600
  } catch (error) {
591
601
  resolve({ failure: error.message });
592
602
  return;
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigError
4
- } from "./chunk-M7LLJQ7M.js";
4
+ } from "./chunk-GIGWZFCY.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-M23QBX3V.js";
7
+ } from "./chunk-QHNWI3OT.js";
8
8
 
9
9
  // src/mcp/config.ts
10
10
  import { createHash } from "crypto";
@@ -103,13 +103,20 @@ var ID = {
103
103
  Usage:
104
104
  bccli [task] interactive mode (optionally start with a task)
105
105
  bccli -p "task" run one task without interaction (scripts/CI)
106
- bccli login [provider] save an API key (default: bc-cloud)
106
+ bccli login [provider] OAuth login (or --key paste API key, --logout remove)
107
107
  bccli models [provider] list models (default: the active provider)
108
108
  bccli update install the newest bccli from npm
109
109
  bccli acp run as an ACP agent for editors (Zed, ...)
110
110
  bccli serve [--port N] serve sessions over HTTP+WS for IDEs/bots
111
+ bccli plugins list, install, remove, or update plugins
112
+ bccli gh-bot [serve] GitHub comment bot (off-by-default; needs config)
111
113
  bccli provider list|add <id>|remove <id> manage providers (custom: --url <url> [--name N] [--key-env ENV])
112
114
  bccli mcp list|add <name>|remove <name>|auth <name>|logout <name>|serve [--base-url <url>] manage MCP servers, or serve this account's tools over stdio
115
+ bccli completion <shell> print a shell completion script (bash, zsh, fish, powershell)
116
+ bccli stats [--days N] show token usage from local sessions (default: last 7 days)
117
+ bccli export [session] [file] copy a session JSONL to a file (default: last session here)
118
+ bccli import <file> import a session JSONL into the current project
119
+ bccli pr <number> [--repo owner/name] [task] check out a GitHub PR and run a task on it
113
120
  bccli integrations show the status of external agent integrations
114
121
  bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, cursor, openai-cli, openai-sdk, openai-compatible, openclaw, hermes
115
122
  bccli disconnect <agent> remove an integration and restore the previous config
@@ -131,11 +138,13 @@ Options:
131
138
  Pemakaian:
132
139
  bccli [tugas] mode interaktif (opsional langsung dengan tugas)
133
140
  bccli -p "tugas" jalankan satu tugas tanpa interaksi (skrip/CI)
134
- bccli login [provider] simpan API key (default: bc-cloud)
141
+ bccli login [provider] login OAuth (atau --key tempel API key, --logout hapus)
135
142
  bccli models [provider] daftar model (default: provider aktif)
136
143
  bccli update pasang bccli terbaru dari npm
137
144
  bccli acp jalankan sebagai agen ACP untuk editor (Zed, ...)
138
145
  bccli serve [--port N] sajikan sesi lewat HTTP+WS untuk IDE/bot
146
+ bccli plugins daftar, install, remove, atau perbarui plugin
147
+ bccli gh-bot [serve] bot komentar GitHub (nonaktif default; butuh config)
139
148
  bccli provider list|add <id>|remove <id> kelola provider (custom: --url <url> [--name N] [--key-env ENV])
140
149
  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
141
150
  bccli integrations lihat status integrasi agent eksternal
@@ -179,6 +188,58 @@ Opsi:
179
188
  "A new bccli is available: {latest} (you have {current}). Run: bccli update": "bccli versi baru tersedia: {latest} (kamu punya {current}). Jalankan: bccli update",
180
189
  "Clipboard image saved to {path} \u2014 the path is inserted in the input; the model sees it when you send.": "Gambar clipboard disimpan ke {path} \u2014 path disisipkan ke input; model melihatnya saat kamu kirim.",
181
190
  "No image on the clipboard.": "Tidak ada gambar di clipboard.",
191
+ "githubBot secret env {env} is empty \u2014 set it before enabling the bot.": "secret env githubBot {env} kosong \u2014 setel sebelum mengaktifkan bot.",
192
+ "githubBot.{name} must be an array of strings.": "githubBot.{name} harus berupa array of string.",
193
+ "githubBot.{name} must be a positive integer.": "githubBot.{name} harus bilangan bulat positif.",
194
+ "githubBot.enabled must be a boolean.": "githubBot.enabled harus boolean.",
195
+ "githubBot.path must be an absolute path like /github.": "githubBot.path harus path absolut seperti /github.",
196
+ "githubBot.secretEnv must be a non-empty string.": "githubBot.secretEnv harus string tidak kosong.",
197
+ "Ignored empty command in delivery {id}.": "Mengabaikan perintah kosong di delivery {id}.",
198
+ "Unknown action: {action}. Use serve.": "Aksi tidak dikenal: {action}. Gunakan serve.",
199
+ "gh CLI not found (exit {code}) \u2014 install GitHub CLI before enabling gh-bot.": "gh CLI tidak ditemukan (exit {code}) \u2014 pasang GitHub CLI sebelum mengaktifkan gh-bot.",
200
+ "Unknown action: {action}. Use list, install <spec>, remove <name>, or update [name].": "Aksi tidak dikenal: {action}. Gunakan list, install <spec>, remove <nama>, atau update [nama].",
201
+ "Cannot read the plugin config while running {action}: {reason} at {path} \u2014 no changes were made; fix the config, then retry.": "Tidak bisa membaca config plugin saat menjalankan {action}: {reason} di {path} \u2014 tidak ada perubahan; perbaiki config, lalu coba lagi.",
202
+ "npm install failed ({code}): {stderr}": "npm install gagal ({code}): {stderr}",
203
+ "install requires a package spec: bccli plugins install <spec>": "install butuh spesifikasi paket: bccli plugins install <spec>",
204
+ "Invalid npm package spec: {spec}. Use a name, @scope/name, name@version, or name@tag \u2014 URLs, git, paths, and flags are not accepted.": "Spesifikasi paket npm tidak valid: {spec}. Pakai nama, @scope/nama, nama@versi, atau nama@tag \u2014 URL, git, path, dan flag tidak diterima.",
205
+ "npm finished but the config could not be read: {reason} \u2014 the entry list is unchanged; fix {path}, then rerun the same command (safe to repeat).": "npm selesai tetapi config gagal dibaca: {reason} \u2014 daftar entry tidak berubah; perbaiki {path}, lalu jalankan ulang perintah yang sama (aman diulang).",
206
+ "npm finished but the config update failed: {reason}. {name} stays enabled through its existing entry {entry}; the package files may already be new. Fix the config error at {path} \u2014 no entry change was required.": "npm selesai tetapi pembaruan config gagal: {reason}. {name} tetap aktif lewat entry lama {entry}; file paket mungkin sudah baru. Perbaiki error config di {path} \u2014 tidak ada perubahan entry yang diperlukan.",
207
+ 'npm finished but the config update failed: {reason}. {name} is installed but NOT enabled \u2014 fix the config error, then run "bccli plugins install {name}" again (safe to repeat), or add {entry} to {path} manually.': 'npm selesai tetapi pembaruan config gagal: {reason}. {name} terpasang tetapi TIDAK aktif \u2014 perbaiki error config, lalu jalankan lagi "bccli plugins install {name}" (aman diulang), atau tambahkan {entry} ke {path} secara manual.',
208
+ "{name} is already enabled.": "{name} sudah aktif.",
209
+ "{name} installed and enabled.": "{name} terpasang dan aktif.",
210
+ "Malformed managed entry: {entry} \u2014 fix it manually in {path}; bccli will not pass it to npm.": "Entry terelola rusak: {entry} \u2014 perbaiki manual di {path}; bccli tidak akan meneruskannya ke npm.",
211
+ "{entry} is a manual plugin entry \u2014 edit the global config.json directly to remove it.": "{entry} adalah entry plugin manual \u2014 edit config.json global langsung untuk menghapusnya.",
212
+ "{name} is not an installed managed plugin.": "{name} bukan plugin terelola yang terpasang.",
213
+ "Unknown plugin: {arg}.": "Plugin tidak dikenal: {arg}.",
214
+ "remove requires a plugin name: bccli plugins remove <name>": "remove butuh nama plugin: bccli plugins remove <nama>",
215
+ 'npm removed the files of {name} but the plugin config could not be read: {reason} \u2014 the entry list is unchanged; fix {path}, then run "bccli plugins remove {name}" again (safe to repeat).': 'npm sudah menghapus file {name} tetapi config plugin gagal dibaca: {reason} \u2014 daftar entry tidak berubah; perbaiki {path}, lalu jalankan lagi "bccli plugins remove {name}" (aman diulang).',
216
+ 'npm removed the files of {name} but the config entry {entry} remains: {reason}. bccli will refuse to start while that entry is listed \u2014 fix the config error at {path}, then run "bccli plugins remove {name}" again (safe to repeat), or delete the entry manually.': 'npm sudah menghapus file {name} tetapi entry config {entry} tertinggal: {reason}. bccli menolak start selama entry itu terdaftar \u2014 perbaiki error config di {path}, lalu jalankan lagi "bccli plugins remove {name}" (aman diulang), atau hapus entry secara manual.',
217
+ "Skipping malformed entry: {entry} \u2014 fix it manually in {path}.": "Melewatkan entry rusak: {entry} \u2014 perbaiki manual di {path}.",
218
+ "No managed plugins to update.": "Tidak ada plugin terelola untuk diperbarui.",
219
+ "update requires a plugin name or no argument: bccli plugins update [name]": "update butuh nama plugin atau tanpa argumen: bccli plugins update [nama]",
220
+ "{name} updated to latest.": "{name} diperbarui ke versi terbaru.",
221
+ "Use either --key or --logout, not both.": "Pakai --key atau --logout, jangan keduanya.",
222
+ "Logout is not supported for {id}; use bccli provider remove {id} to delete its stored key and config.": "Logout tidak didukung untuk {id}; pakai bccli provider remove {id} untuk menghapus key dan config tersimpan.",
223
+ "bccli login openrouter needs a terminal. Use --key to paste an API key instead.": "bccli login openrouter butuh terminal. Pakai --key untuk menempel API key.",
224
+ "Could not open the browser automatically \u2014 open this URL manually: {url}": "Tidak bisa membuka browser otomatis \u2014 buka URL ini manual: {url}",
225
+ "Paste the authorization code from the browser: ": "Tempel kode otorisasi dari browser: ",
226
+ "Failed to read the authorization code: {reason}. Your stored credential was not changed.": "Gagal membaca kode otorisasi: {reason}. Credential tersimpan tidak berubah.",
227
+ "Authorization code is empty. Run bccli login openrouter again.": "Kode otorisasi kosong. Jalankan bccli login openrouter lagi.",
228
+ "Login cancelled.": "Login dibatalkan.",
229
+ "The exchange with OpenRouter timed out after {seconds}s. Your stored credential was not changed.": "Pertukaran dengan OpenRouter habis waktu setelah {seconds} dtk. Credential tersimpan tidak berubah.",
230
+ "Could not reach OpenRouter: {reason}. Your stored credential was not changed.": "Tidak bisa menghubungi OpenRouter: {reason}. Credential tersimpan tidak berubah.",
231
+ "Authorization code expired \u2014 codes are valid for 10 minutes. Run bccli login openrouter again.": "Kode otorisasi kedaluwarsa \u2014 kode berlaku 10 menit. Jalankan bccli login openrouter lagi.",
232
+ "OpenRouter rejected the authorization code (403): {detail}. Run bccli login openrouter again.": "OpenRouter menolak kode otorisasi (403): {detail}. Jalankan bccli login openrouter lagi.",
233
+ "OpenRouter did not return an API key in the expected format. Your stored credential was not changed.": "OpenRouter tidak mengembalikan API key dengan format yang diharapkan. Credential tersimpan tidak berubah.",
234
+ "OpenRouter exchange failed ({status}): {detail}. Your stored credential was not changed.": "Pertukaran OpenRouter gagal ({status}): {detail}. Credential tersimpan tidak berubah.",
235
+ "The key was created on your OpenRouter account but could not be saved locally ({reason}). Manage it (copy or revoke) at {dashboard}, then run bccli login openrouter again.": "Key sudah dibuat di akun OpenRouter kamu tetapi gagal disimpan lokal ({reason}). Kelola (salin atau cabut) di {dashboard}, lalu jalankan bccli login openrouter lagi.",
236
+ "Logged in: openrouter credential saved.": "Login berhasil: credential openrouter tersimpan.",
237
+ "Note: {env} is set in the environment and takes priority over the stored credential.": "Catatan: {env} ter-set di environment dan lebih diutamakan daripada credential tersimpan.",
238
+ "Verify with: bccli models openrouter (your key is never printed).": "Verifikasi dengan: bccli models openrouter (key kamu tidak pernah dicetak).",
239
+ "openrouter credential removed.": "credential openrouter dihapus.",
240
+ "openrouter credential was not stored.": "credential openrouter tidak tersimpan.",
241
+ "Note: {env} is still set in the environment and will keep being used.": "Catatan: {env} masih ter-set di environment dan akan terus dipakai.",
242
+ "To revoke keys on your account, open {dashboard}.": "Untuk mencabut key akun kamu, buka {dashboard}.",
182
243
  "Budget exceeded ({kind}): {used} of {limit}. Further model calls are blocked; raise usageCap in ~/.bccli/config.json.": "Anggaran terlampaui ({kind}): {used} dari {limit}. Panggilan model selanjutnya diblokir; naikkan usageCap di ~/.bccli/config.json.",
183
244
  "Verifying edits: {cmds}": "Memverifikasi edit: {cmds}",
184
245
  "Verification passed.": "Verifikasi lulus.",
@@ -377,7 +438,23 @@ Opsi:
377
438
  "Run: dsh web": "Jalankan: dsh web",
378
439
  "timeout after {n} seconds": "timeout {n} detik",
379
440
  "Could not start MCP servers: {error}": "Tidak bisa menjalankan server MCP: {error}",
380
- "Blocked: {host} resolves to a private address ({addr}). Fetching an internal host through a public DNS name is not allowed.": "Diblokir: {host} mengarah ke alamat privat ({addr}). Mengambil host internal lewat nama DNS publik tidak diizinkan."
441
+ "Blocked: {host} resolves to a private address ({addr}). Fetching an internal host through a public DNS name is not allowed.": "Diblokir: {host} mengarah ke alamat privat ({addr}). Mengambil host internal lewat nama DNS publik tidak diizinkan.",
442
+ "usage: bccli completion <{shells}>": "pakai: bccli completion <{shells}>",
443
+ "--days must be a positive integer": "--days harus bilangan bulat positif",
444
+ "no sessions in the last {days} day(s)": "tidak ada sesi dalam {days} hari terakhir",
445
+ "sessions (last {days} day(s)):": "sesi ({days} hari terakhir):",
446
+ "session(s)": "sesi",
447
+ "message(s)": "pesan",
448
+ "recorded": "tercatat",
449
+ "no session to export in this folder": "tidak ada sesi untuk diekspor di folder ini",
450
+ "exported {file}": "diekspor ke {file}",
451
+ "file not found: {file}": "file tidak ditemukan: {file}",
452
+ "invalid session file (non-JSON line): {file}": "file sesi tidak valid (baris bukan JSON): {file}",
453
+ "imported {n} record(s) into {file}": "impor {n} rekaman ke {file}",
454
+ "usage: bccli pr <number> [--repo owner/name] [task]": "pakai: bccli pr <nomor> [--repo owner/name] [tugas]",
455
+ "gh is not available ({error}); install GitHub CLI first": "gh tidak tersedia ({error}); pasang GitHub CLI dulu",
456
+ "gh pr checkout {n} failed (exit {code})": "gh pr checkout {n} gagal (exit {code})",
457
+ "checked out PR #{n}": "checkout PR #{n} selesai"
381
458
  };
382
459
 
383
460
  // src/i18n.ts
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  reasoningPayload
4
- } from "./chunk-NI5JZUZ3.js";
4
+ } from "./chunk-ZKMSTD6G.js";
5
5
  import {
6
6
  t
7
- } from "./chunk-M23QBX3V.js";
7
+ } from "./chunk-QHNWI3OT.js";
8
8
 
9
9
  // src/provider.ts
10
10
  import OpenAI from "openai";
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  runCommand,
4
4
  runHooks
5
- } from "./chunk-DBHDZ5EP.js";
5
+ } from "./chunk-PSRNKKGA.js";
6
6
  import {
7
7
  ConfigError
8
- } from "./chunk-M7LLJQ7M.js";
8
+ } from "./chunk-GIGWZFCY.js";
9
9
  import {
10
10
  t
11
- } from "./chunk-M23QBX3V.js";
11
+ } from "./chunk-QHNWI3OT.js";
12
12
 
13
13
  // src/verify.ts
14
14
  var MAX_VERIFY_ROUNDS = 2;
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/tokenBudget.ts
4
+ var estimateTokens = (text) => Math.ceil(text.length / 4);
5
+ var estimateMessages = (messages) => estimateTokens(JSON.stringify(messages));
6
+ function trimToFit(messages, maxTokens) {
7
+ let out = messages;
8
+ while (estimateMessages(out) > maxTokens) {
9
+ const boundary = out.findIndex((m, i) => i > 0 && m.role === "user");
10
+ if (boundary === -1) return out;
11
+ out = out.slice(boundary);
12
+ }
13
+ return out;
14
+ }
15
+
16
+ export {
17
+ estimateTokens,
18
+ estimateMessages,
19
+ trimToFit
20
+ };
@@ -5,7 +5,7 @@ import {
5
5
  readCredentials,
6
6
  readJsonConfig,
7
7
  removeCredential
8
- } from "./chunk-M7LLJQ7M.js";
8
+ } from "./chunk-GIGWZFCY.js";
9
9
 
10
10
  // src/providers.ts
11
11
  import { mkdirSync, writeFileSync } from "fs";