@botconnector/bccli 0.4.0-beta.13 → 0.4.0-beta.15

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.
@@ -8,8 +8,8 @@ import {
8
8
  removeGlobalServer,
9
9
  serversToStart,
10
10
  setProjectTrust
11
- } from "./chunk-BFZXRKW5.js";
12
- import "./chunk-2MGINW4O.js";
11
+ } from "./chunk-ERVDVPKJ.js";
12
+ import "./chunk-DDA5TJ7T.js";
13
13
  export {
14
14
  addGlobalServer,
15
15
  globalMcpPath,
@@ -4,8 +4,9 @@ import {
4
4
  bccliHome,
5
5
  loadConfig,
6
6
  readCredentials,
7
- resolveModel
8
- } from "./chunk-2MGINW4O.js";
7
+ resolveModel,
8
+ t
9
+ } from "./chunk-DDA5TJ7T.js";
9
10
 
10
11
  // src/integrationCli.ts
11
12
  import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
@@ -26,17 +27,17 @@ function parseTarget(raw) {
26
27
  if (raw === "opencode" || raw === "aider" || raw === "cline" || raw === "deepseek-harness" || raw === "cursor" || raw === "openai-cli" || raw === "openai-sdk" || raw === "openai-compatible" || raw === "codex" || raw === "claude-code") return raw;
27
28
  if (raw === "dsh") return "deepseek-harness";
28
29
  throw new ConfigError(
29
- "Agent harus salah satu dari: opencode, aider, cline, deepseek-harness (dsh), cursor, openai-cli, openai-sdk, openai-compatible, codex, claude-code"
30
+ t("Agent must be one of: opencode, aider, cline, deepseek-harness (dsh), cursor, openai-cli, openai-sdk, openai-compatible, codex, claude-code")
30
31
  );
31
32
  }
32
33
  function homeDir(env) {
33
34
  const value = env.HOME || env.USERPROFILE;
34
- if (!value) throw new ConfigError("Home directory tidak dapat ditentukan.");
35
+ if (!value) throw new ConfigError(t("Cannot determine the home directory."));
35
36
  return value;
36
37
  }
37
38
  function ensureSecret(env) {
38
39
  const key = readCredentials(env)["bc-cloud"] || env.BOTCONNECTOR_API_KEY;
39
- if (!key) throw new ConfigError("API key BotConnector belum tersedia. Jalankan bccli login bc-cloud terlebih dahulu.");
40
+ if (!key) throw new ConfigError(t("No BotConnector API key yet. Run bccli login bc-cloud first."));
40
41
  const dir = integrationHome(env);
41
42
  mkdirSync(dir, { recursive: true });
42
43
  const path = keyPath(env);
@@ -76,11 +77,11 @@ async function botConnectorModels(deps) {
76
77
  const config = loadConfig(deps.cwd);
77
78
  const resolved = resolveModel(config, config.model, deps.env);
78
79
  const key = readCredentials(deps.env)["bc-cloud"] || resolved.apiKey;
79
- if (!key) throw new ConfigError("API key BotConnector belum tersedia. Jalankan bccli login bc-cloud terlebih dahulu.");
80
+ if (!key) throw new ConfigError(t("No BotConnector API key yet. Run bccli login bc-cloud first."));
80
81
  const response = await deps.fetch(`${BASE_URL}/models`, {
81
82
  headers: { authorization: `Bearer ${key}` }
82
83
  });
83
- if (!response.ok) throw new ConfigError(`Katalog model BotConnector gagal dimuat (HTTP ${response.status}).`);
84
+ if (!response.ok) throw new ConfigError(t("Could not load the BotConnector model catalog (HTTP {status}).", { status: response.status }));
84
85
  const payload = await response.json();
85
86
  return (payload.data ?? []).map((item) => item.id).filter((id) => typeof id === "string" && !!id);
86
87
  }
@@ -95,7 +96,7 @@ async function connectOpenCode(deps) {
95
96
  try {
96
97
  doc = JSON.parse(readFileSync(path, "utf8"));
97
98
  } catch {
98
- throw new ConfigError(`Config OpenCode tidak valid JSON: ${path}`);
99
+ throw new ConfigError(t("The OpenCode config is not valid JSON: {path}", { path }));
99
100
  }
100
101
  }
101
102
  const providers = doc.provider && typeof doc.provider === "object" && !Array.isArray(doc.provider) ? { ...doc.provider } : {};
@@ -118,7 +119,7 @@ async function connectOpenCode(deps) {
118
119
  files: [{ path, ...backup }],
119
120
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
120
121
  }, deps.env);
121
- deps.out(`OpenCode terhubung ke BotConnector (${models.length} model).`);
122
+ deps.out(t("OpenCode is connected to BotConnector ({n} models).", { n: models.length }));
122
123
  deps.out(`Config: ${path}`);
123
124
  }
124
125
  var AIDER_BEGIN = "# BEGIN BCCLI BOTCONNECTOR";
@@ -150,7 +151,7 @@ async function connectAider(deps) {
150
151
  let existing = existsSync(configPath) ? readFileSync(configPath, "utf8") : "";
151
152
  existing = stripManagedBlock(existing);
152
153
  if (/^\s*(env-file|openai-api-base|openai-api-key)\s*:/m.test(existing)) {
153
- throw new ConfigError(`Config Aider sudah memiliki env-file/openai-api setting sendiri: ${configPath}. BCCLI tidak akan menimpanya.`);
154
+ throw new ConfigError(t("The Aider config already has its own env-file/openai-api settings: {path}. BCCLI will not overwrite them.", { path: configPath }));
154
155
  }
155
156
  mkdirSync(dirname(envPath), { recursive: true });
156
157
  writeFileSync(envPath, [
@@ -179,7 +180,7 @@ ${managed}
179
180
  files: [{ path: configPath, ...configBackup }, { path: envPath, ...envBackup }],
180
181
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
181
182
  }, deps.env);
182
- deps.out("Aider terhubung ke BotConnector.");
183
+ deps.out(t("Aider is connected to BotConnector."));
183
184
  deps.out(`Config: ${configPath}`);
184
185
  }
185
186
  function externalDefaultModel(models, deps) {
@@ -187,7 +188,7 @@ function externalDefaultModel(models, deps) {
187
188
  const preferred = config.model.startsWith("bc-cloud/") ? config.model.slice("bc-cloud/".length) : "";
188
189
  if (preferred && models.includes(preferred)) return preferred;
189
190
  const first = models[0];
190
- if (!first) throw new ConfigError("Katalog BotConnector tidak memiliki model yang dapat dipakai agent eksternal.");
191
+ if (!first) throw new ConfigError(t("The BotConnector catalog has no model that external agents can use."));
191
192
  return first;
192
193
  }
193
194
  async function connectCline(deps) {
@@ -204,7 +205,7 @@ async function connectCline(deps) {
204
205
  try {
205
206
  doc = JSON.parse(readFileSync(path, "utf8"));
206
207
  } catch {
207
- throw new ConfigError(`Config Cline tidak valid JSON: ${path}`);
208
+ throw new ConfigError(t("The Cline config is not valid JSON: {path}", { path }));
208
209
  }
209
210
  }
210
211
  const providers = doc.providers && typeof doc.providers === "object" && !Array.isArray(doc.providers) ? { ...doc.providers } : {};
@@ -212,7 +213,7 @@ async function connectCline(deps) {
212
213
  const currentBase = current?.settings?.baseUrl;
213
214
  if (currentBase && currentBase.replace(/\/+$/, "") !== BASE_URL) {
214
215
  throw new ConfigError(
215
- "Cline sudah memakai provider openai-compatible lain (" + currentBase + "). BCCLI tidak akan menimpanya; disconnect/ubah provider tersebut lebih dulu."
216
+ t("Cline already uses another openai-compatible provider ({base}). BCCLI will not overwrite it; disconnect or change that provider first.", { base: currentBase })
216
217
  );
217
218
  }
218
219
  providers["openai-compatible"] = {
@@ -236,7 +237,7 @@ async function connectCline(deps) {
236
237
  files: [{ path, ...backup }],
237
238
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
238
239
  }, deps.env);
239
- deps.out(`Cline terhubung ke BotConnector (${models.length} model tersedia; default ${model}).`);
240
+ deps.out(t("Cline is connected to BotConnector ({n} models available; default {model}).", { n: models.length, model }));
240
241
  deps.out(`Config: ${path}`);
241
242
  deps.out("Catatan: Cline menyimpan API key provider di providers.json miliknya.");
242
243
  }
@@ -265,10 +266,10 @@ async function connectDeepSeekHarness(deps) {
265
266
  const models = await botConnectorModels(deps);
266
267
  const source = existsSync(settingsPath) ? readFileSync(settingsPath, "utf8") : "{}\n";
267
268
  const doc = parseDocument(source);
268
- if (doc.errors.length) throw new ConfigError(`Config DeepSeek Harness tidak valid YAML: ${settingsPath}`);
269
+ if (doc.errors.length) throw new ConfigError(t("The DeepSeek Harness config is not valid YAML: {path}", { path: settingsPath }));
269
270
  const existingProvider = doc.getIn(["llm-pi-ai", "providers", PROVIDER_ID]);
270
271
  if (existingProvider?.baseURL && existingProvider.baseURL.replace(/\/+$/, "") !== BASE_URL) {
271
- throw new ConfigError(`DeepSeek Harness sudah memiliki provider "${PROVIDER_ID}" dengan endpoint lain.`);
272
+ throw new ConfigError(t('DeepSeek Harness already has a provider "{id}" with a different endpoint.', { id: PROVIDER_ID }));
272
273
  }
273
274
  doc.setIn(["llm-pi-ai", "providers", PROVIDER_ID], {
274
275
  displayName: "BotConnector",
@@ -282,7 +283,7 @@ async function connectDeepSeekHarness(deps) {
282
283
  let envText = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
283
284
  envText = stripDshEnvBlock(envText);
284
285
  if (/^\s*BOTCONNECTOR_API_KEY\s*=/m.test(envText)) {
285
- throw new ConfigError(`$DSH_HOME/.env sudah memiliki BOTCONNECTOR_API_KEY di luar blok BCCLI: ${envPath}`);
286
+ throw new ConfigError(t("$DSH_HOME/.env already has BOTCONNECTOR_API_KEY outside the BCCLI block: {path}", { path: envPath }));
286
287
  }
287
288
  const managed = [DSH_ENV_BEGIN, `BOTCONNECTOR_API_KEY=${key}`, DSH_ENV_END].join("\n");
288
289
  const mergedEnv = envText.trim() ? `${envText.trimEnd()}
@@ -302,11 +303,11 @@ ${managed}
302
303
  files: [{ path: settingsPath, ...settingsBackup }, { path: envPath, ...envBackup }],
303
304
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
304
305
  }, deps.env);
305
- deps.out(`DeepSeek Harness terhubung ke BotConnector (${models.length} model).`);
306
+ deps.out(t("DeepSeek Harness is connected to BotConnector ({n} models).", { n: models.length }));
306
307
  deps.out(`Config: ${settingsPath}`);
307
308
  deps.out("Provider: botconnector (OpenAI Chat Completions)");
308
- deps.out("Jalankan: dsh web");
309
- deps.out("Bentuk panjang yang setara: dsh --profile web");
309
+ deps.out(t("Run: dsh web"));
310
+ deps.out(t("Equivalent long form: dsh --profile web"));
310
311
  }
311
312
  function managedProfilePath(target, env, ext = "env") {
312
313
  return join(integrationHome(env), `${target}.${ext}`);
@@ -369,13 +370,13 @@ async function connectOpenAiCli(deps) {
369
370
  }, deps.env);
370
371
  deps.out("OpenAI CLI profile BotConnector siap.");
371
372
  deps.out(`Launcher: ${launcher}`);
372
- deps.out("Launcher tidak menyimpan API key di dalam script; key dibaca dari storage BCCLI saat dijalankan.");
373
+ deps.out(t("The launcher does not store the API key in the script; the key is read from BCCLI storage when it runs."));
373
374
  }
374
375
  async function connectOpenAiSdk(deps) {
375
376
  const path = writeOpenAiEnvProfile("openai-sdk", deps);
376
377
  deps.out("OpenAI SDK profile BotConnector siap.");
377
378
  deps.out(`Env profile: ${path}`);
378
- deps.out("Python dan Node OpenAI SDK dapat membaca OPENAI_BASE_URL dan OPENAI_API_KEY dari profile ini.");
379
+ deps.out(t("The Python and Node OpenAI SDKs can read OPENAI_BASE_URL and OPENAI_API_KEY from this profile."));
379
380
  }
380
381
  async function connectOpenAiCompatible(deps) {
381
382
  const path = writeOpenAiEnvProfile("openai-compatible", deps);
@@ -412,14 +413,14 @@ async function connectCursor(deps) {
412
413
  }, deps.env);
413
414
  deps.out("Cursor guided setup profile dibuat.");
414
415
  deps.out(`Panduan: ${path}`);
415
- deps.out("BCCLI tidak mengedit storage internal Cursor karena format override tersebut bukan konfigurasi eksternal yang stabil.");
416
+ deps.out(t("BCCLI does not edit Cursor\u2019s internal storage because that override format is not a stable external configuration."));
416
417
  }
417
418
  function agentToolDefaultModel(models) {
418
419
  for (const id of ["ling-3.0-flash", "mimo-v2.5", "deepseek-v4-flash"]) {
419
420
  if (models.includes(id)) return id;
420
421
  }
421
422
  const first = models[0];
422
- if (!first) throw new ConfigError("Katalog BotConnector tidak memiliki model untuk coding agent eksternal.");
423
+ if (!first) throw new ConfigError(t("The BotConnector catalog has no model for external coding agents."));
423
424
  return first;
424
425
  }
425
426
  async function connectCodex(deps) {
@@ -429,7 +430,7 @@ async function connectCodex(deps) {
429
430
  const profilePath = join(codexHome, "botconnector.config.toml");
430
431
  const launcher = join(integrationHome(deps.env), process.platform === "win32" ? "codex-botconnector.cmd" : "codex-botconnector");
431
432
  if (existsSync(profilePath)) {
432
- throw new ConfigError("Codex sudah memiliki botconnector.config.toml. BCCLI tidak akan menimpanya.");
433
+ throw new ConfigError(t("Codex already has botconnector.config.toml. BCCLI will not overwrite it."));
433
434
  }
434
435
  const profileBackup = safeBackup(profilePath, deps.env);
435
436
  const launcherBackup = safeBackup(launcher, deps.env);
@@ -480,7 +481,7 @@ async function connectCodex(deps) {
480
481
  files: [{ path: profilePath, ...profileBackup }, { path: launcher, ...launcherBackup }],
481
482
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
482
483
  }, deps.env);
483
- deps.out("Codex CLI terhubung ke BotConnector Responses API.");
484
+ deps.out(t("Codex CLI is connected to the BotConnector Responses API."));
484
485
  deps.out(`Profile: ${profilePath}`);
485
486
  deps.out(`Launcher: ${launcher}`);
486
487
  deps.out(`Default coding model: ${model}`);
@@ -532,14 +533,14 @@ async function connectClaudeCode(deps) {
532
533
  files: [{ path: launcher, ...backup }],
533
534
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
534
535
  }, deps.env);
535
- deps.out("Claude Code terhubung ke BotConnector Anthropic Messages compatibility API.");
536
+ deps.out(t("Claude Code is connected to the BotConnector Anthropic Messages compatibility API."));
536
537
  deps.out(`Launcher: ${launcher}`);
537
538
  deps.out(`Default coding model: ${model}`);
538
539
  }
539
540
  function disconnect(target, deps) {
540
541
  const state = readState(target, deps.env);
541
542
  if (!state) {
542
- deps.out(`${target}: belum dikelola oleh BCCLI.`);
543
+ deps.out(t("{target}: not managed by BCCLI yet.", { target }));
543
544
  return;
544
545
  }
545
546
  for (const file of [...state.files].reverse()) {
@@ -551,7 +552,7 @@ function disconnect(target, deps) {
551
552
  }
552
553
  }
553
554
  rmSync(statePath(target, deps.env), { force: true });
554
- deps.out(`${target}: integrasi BotConnector dilepas dan config dipulihkan.`);
555
+ deps.out(t("{target}: the BotConnector integration was removed and the config restored.", { target }));
555
556
  }
556
557
  function listIntegrations(deps) {
557
558
  for (const target of ["opencode", "aider", "cline", "deepseek-harness", "cursor", "openai-cli", "openai-sdk", "openai-compatible", "codex", "claude-code"]) {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  readSecret,
4
4
  runLogin
5
- } from "./chunk-6BLZELE6.js";
5
+ } from "./chunk-4KMOCORM.js";
6
6
  export {
7
7
  readSecret,
8
8
  runLogin
@@ -2,16 +2,17 @@
2
2
  import {
3
3
  CATALOG,
4
4
  fillTemplate
5
- } from "./chunk-DX7CZTBB.js";
5
+ } from "./chunk-RQGMYLVH.js";
6
6
  import {
7
7
  addGlobalServer,
8
8
  globalMcpPath,
9
9
  readMcpFile,
10
10
  removeGlobalServer
11
- } from "./chunk-BFZXRKW5.js";
11
+ } from "./chunk-ERVDVPKJ.js";
12
12
  import {
13
- bccliHome
14
- } from "./chunk-2MGINW4O.js";
13
+ bccliHome,
14
+ t
15
+ } from "./chunk-DDA5TJ7T.js";
15
16
 
16
17
  // src/mcpCli.ts
17
18
  async function runMcpCommand(args, deps) {
@@ -24,26 +25,26 @@ async function runMcpCommand(args, deps) {
24
25
  return 0;
25
26
  }
26
27
  if (!name) {
27
- deps.err(`Pemakaian: bccli mcp ${action} <nama>`);
28
+ deps.err(t("Usage: bccli mcp {action} <name>", { action }));
28
29
  return 1;
29
30
  }
30
31
  if (action === "remove") {
31
32
  removeGlobalServer(home, name);
32
- deps.out(`${name} dihapus.`);
33
+ deps.out(t("{name} removed.", { name }));
33
34
  return 0;
34
35
  }
35
36
  if (action !== "add") {
36
- deps.err(`Aksi tidak dikenal: ${action}. Pakai list, add, atau remove.`);
37
+ deps.err(t("Unknown action: {action}. Use list, add, or remove.", { action }));
37
38
  return 1;
38
39
  }
39
40
  if (args.url) {
40
41
  addGlobalServer(home, name, { type: "http", url: args.url });
41
- deps.out(`${name} terpasang (${args.url}).`);
42
+ deps.out(t("{name} installed ({url}).", { name, url: args.url }));
42
43
  return 0;
43
44
  }
44
45
  const entry = CATALOG.find((c) => c.name === name);
45
46
  if (!entry) {
46
- deps.err(`${name} tidak ada di katalog. Untuk server remote lain pakai: bccli mcp add ${name} --url <url>`);
47
+ deps.err(t("{name} is not in the catalog. For another remote server use: bccli mcp add {name} --url <url>", { name }));
47
48
  return 1;
48
49
  }
49
50
  const values = Object.fromEntries(args.values.map((v) => [v.slice(0, v.indexOf("=")), v.slice(v.indexOf("=") + 1)]));
@@ -57,7 +58,7 @@ async function runMcpCommand(args, deps) {
57
58
  deps.err(`${error.message}${hint ? `. Contoh: bccli mcp add ${name} ${hint}` : ""}`);
58
59
  return 1;
59
60
  }
60
- deps.out(`${name} terpasang. Aktif di sesi bccli berikutnya.`);
61
+ deps.out(t("{name} installed. Active in the next bccli session.", { name }));
61
62
  return 0;
62
63
  }
63
64
  export {
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ addProviderKey,
4
+ runProviderCommand
5
+ } from "./chunk-RY7NCJXH.js";
6
+ import "./chunk-D7CF42EW.js";
7
+ import "./chunk-VEZFR7M7.js";
8
+ import "./chunk-DDA5TJ7T.js";
9
+ export {
10
+ addProviderKey,
11
+ runProviderCommand
12
+ };