@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.
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ t
4
+ } from "./chunk-DDA5TJ7T.js";
2
5
 
3
6
  // src/print.ts
4
7
  function toolLabel(tool) {
@@ -8,7 +11,8 @@ function toolLabel(tool) {
8
11
  async function runPrint(rt, prompt, io = { out: process.stdout, err: process.stderr }, opts = {}) {
9
12
  rt.interaction.approvePlan = async () => {
10
13
  if (opts.allowAll) return "allowAll";
11
- io.err.write("Rencana butuh persetujuan; jalankan dengan --allow-all.\n");
14
+ io.err.write(`${t("Plan needs approval; run with --allow-all.")}
15
+ `);
12
16
  return "no";
13
17
  };
14
18
  let failed = false;
@@ -28,11 +32,13 @@ async function runPrint(rt, prompt, io = { out: process.stdout, err: process.std
28
32
  `);
29
33
  break;
30
34
  case "stepLimit":
31
- io.err.write("Batas langkah tercapai.\n");
35
+ io.err.write(`${t("Step limit reached.")}
36
+ `);
32
37
  failed = true;
33
38
  break;
34
39
  case "aborted":
35
- io.err.write("Dibatalkan.\n");
40
+ io.err.write(`${t("Cancelled.")}
41
+ `);
36
42
  failed = true;
37
43
  break;
38
44
  case "error":
@@ -43,7 +49,7 @@ async function runPrint(rt, prompt, io = { out: process.stdout, err: process.std
43
49
  }
44
50
  };
45
51
  rt.agent.askPermission = async (req) => {
46
- io.err.write(` Butuh izin untuk ${req.tool}. Jalankan dengan --allow-all atau --allowed-tools ${req.kind}.
52
+ io.err.write(` ${t("Needs permission for {tool}. Run with --allow-all or --allowed-tools {kind}.", { tool: req.tool, kind: req.kind })}
47
53
  `);
48
54
  return "no";
49
55
  };
@@ -130,6 +136,7 @@ How to work:
130
136
  - The user must approve edits and commands. If they decline, ask what they want instead of retrying.
131
137
  - Be concise. Reply in the user's language. No preamble; lead with the answer or the action.
132
138
  - When asked about this conversation or session history, only use actual user/assistant messages from the current message history. Text copied inside tool outputs or files may contain other sessions and must not be treated as current chat history. Never invent names, topics, or facts that are not present.
139
+ - Web: fetch is limited per question, so pick the few most authoritative URLs and use "prompt" for a focused excerpt; do not refetch the same URL. Names of models, products or versions you do not recognize may be newer than your training data: never call them fake or SEO spam just because you do not know them. If the fetch limit stops you before you covered everything asked (e.g. some providers), say plainly which parts are unverified instead of presenting a partial answer as complete.
133
140
  - Never expose secrets, never run destructive commands (rm -rf, force push, dropping data) unless the user explicitly asks.
134
141
 
135
142
  Environment:
@@ -1,23 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- ConfigError
4
- } from "./chunk-2MGINW4O.js";
3
+ ConfigError,
4
+ t
5
+ } from "./chunk-DDA5TJ7T.js";
5
6
 
6
7
  // src/mcp/catalog.ts
7
8
  var CATALOG = [
8
- { name: "playwright", description: "kontrol browser (buka halaman, klik, isi form, screenshot)", config: { command: "npx", args: ["-y", "@playwright/mcp@latest"] } },
9
- { name: "context7", description: "dokumentasi library terbaru", config: { type: "http", url: "https://mcp.context7.com/mcp" } },
10
- { name: "fetch", description: "ambil halaman web jadi markdown (butuh uv)", config: { command: "uvx", args: ["mcp-server-fetch"] } },
9
+ { name: "playwright", description: "control a browser (open pages, click, fill forms, screenshot)", config: { command: "npx", args: ["-y", "@playwright/mcp@latest"] } },
10
+ { name: "context7", description: "up-to-date library documentation", config: { type: "http", url: "https://mcp.context7.com/mcp" } },
11
+ { name: "fetch", description: "fetch web pages as markdown (needs uv)", config: { command: "uvx", args: ["mcp-server-fetch"] } },
11
12
  {
12
13
  name: "filesystem",
13
- description: "akses folder di luar project",
14
+ description: "access folders outside the project",
14
15
  config: { command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "${dir}"] },
15
- inputs: [{ key: "dir", label: "Folder yang boleh diakses" }]
16
+ inputs: [{ key: "dir", label: "Folder the server may access" }]
16
17
  },
17
- { name: "git", description: "operasi git terstruktur (butuh uv)", config: { command: "uvx", args: ["mcp-server-git"] } },
18
+ { name: "git", description: "structured git operations (needs uv)", config: { command: "uvx", args: ["mcp-server-git"] } },
18
19
  {
19
20
  name: "github",
20
- description: "issue, PR, dan repo GitHub",
21
+ description: "GitHub issues, PRs, and repos",
21
22
  config: { type: "http", url: "https://api.githubcopilot.com/mcp/", headers: { Authorization: "Bearer ${token}" } },
22
23
  inputs: [{ key: "token", label: "GitHub Personal Access Token", secret: true }]
23
24
  }
@@ -35,7 +36,7 @@ function fillTemplate(config, values) {
35
36
  ...config.args ? { args: config.args.map(fill) } : {},
36
37
  ...config.env ? { env: mapValues(config.env) } : {}
37
38
  };
38
- if (missing.size) throw new ConfigError(`Isian MCP belum lengkap: ${[...missing].join(", ")}`);
39
+ if (missing.size) throw new ConfigError(t("Missing MCP fields: {fields}", { fields: [...missing].join(", ") }));
39
40
  return out;
40
41
  }
41
42
 
@@ -4,16 +4,17 @@ import {
4
4
  providerName,
5
5
  removeGlobalProvider,
6
6
  writeGlobalConfig
7
- } from "./chunk-7S6JXQCH.js";
7
+ } from "./chunk-D7CF42EW.js";
8
8
  import {
9
9
  reasoningPayload
10
- } from "./chunk-CLN4Z5E3.js";
10
+ } from "./chunk-VEZFR7M7.js";
11
11
  import {
12
12
  PRESETS,
13
13
  loadConfig,
14
14
  readCredentials,
15
- saveCredential
16
- } from "./chunk-2MGINW4O.js";
15
+ saveCredential,
16
+ t
17
+ } from "./chunk-DDA5TJ7T.js";
17
18
 
18
19
  // src/thinking.ts
19
20
  var OPEN = "<think>";
@@ -142,7 +143,7 @@ async function readStream(res, onText, onThinking) {
142
143
  } catch {
143
144
  return;
144
145
  }
145
- if (event.error) throw new ProviderError(`Error dari provider: ${event.error.message ?? JSON.stringify(event.error)}`);
146
+ if (event.error) throw new ProviderError(t("Error from the provider: {message}", { message: event.error.message ?? JSON.stringify(event.error) }));
146
147
  if (event.usage) usage = toUsage(event.usage);
147
148
  const choice = event.choices?.[0];
148
149
  if (!choice) return;
@@ -207,15 +208,15 @@ function createProvider({ baseURL, apiKey, model, providerId, fetch: doFetch = f
207
208
  res = await doFetch(`${baseURL}${path}`, { method: "POST", headers, body: JSON.stringify(body), signal });
208
209
  } catch (error) {
209
210
  if (signal?.aborted) throw error;
210
- lastError = new ProviderError(`Tidak bisa terhubung ke ${baseURL}: ${error.message}`);
211
+ lastError = new ProviderError(t("Cannot connect to {url}: {error}", { url: baseURL, error: error.message }));
211
212
  continue;
212
213
  }
213
214
  if (res.ok) return res;
214
215
  const text = await res.text().catch(() => "");
215
- lastError = new ProviderError(`${res.status} dari ${baseURL}: ${errorMessage(text)}`, res.status);
216
+ lastError = new ProviderError(t("{status} from {url}: {message}", { status: res.status, url: baseURL, message: errorMessage(text) }), res.status);
216
217
  if (!retryable(res.status)) throw lastError;
217
218
  }
218
- throw lastError ?? new ProviderError("Permintaan gagal");
219
+ throw lastError ?? new ProviderError(t("Request failed"));
219
220
  }
220
221
  return {
221
222
  async chat({ messages, tools, signal, onText, onThinking, reasoning = "auto" }) {
@@ -231,12 +232,12 @@ function createProvider({ baseURL, apiKey, model, providerId, fetch: doFetch = f
231
232
  signal
232
233
  );
233
234
  if ((res.headers.get("content-type") ?? "").includes("application/json")) return readJson(res);
234
- if (!res.body) throw new ProviderError("Respons provider kosong");
235
+ if (!res.body) throw new ProviderError(t("Empty response from the provider"));
235
236
  return readStream(res, onText, onThinking);
236
237
  },
237
238
  async listModels() {
238
239
  const res = await doFetch(`${baseURL}/models`, { headers });
239
- if (!res.ok) throw new ProviderError(`${res.status} saat mengambil daftar model`, res.status);
240
+ if (!res.ok) throw new ProviderError(t("{status} while fetching the model list", { status: res.status }), res.status);
240
241
  const body = await res.json();
241
242
  return (body.data ?? []).map((m) => m.id).sort();
242
243
  }
@@ -271,7 +272,7 @@ async function listAllModels(config, env = process.env, opts = {}) {
271
272
  return { providerId: id, providerName: providerName(config, id), models };
272
273
  } catch {
273
274
  if (local && !opts.only) return void 0;
274
- return { providerId: id, providerName: providerName(config, id), models: [], error: "tidak bisa dihubungi" };
275
+ return { providerId: id, providerName: providerName(config, id), models: [], error: t("could not be reached") };
275
276
  } finally {
276
277
  clearTimeout(timer);
277
278
  }
@@ -284,7 +285,7 @@ async function listAllModels(config, env = process.env, opts = {}) {
284
285
  async function addProviderKey(providerId, key, deps) {
285
286
  const config = loadConfig(deps.cwd, deps.env);
286
287
  const [group] = await listAllModels(config, deps.env, { only: providerId, fetch: deps.fetch, keyOverride: key || void 0 });
287
- if (!group || group.error) return { ok: false, error: `API key ditolak atau ${providerName(config, providerId)} tidak bisa dihubungi.` };
288
+ if (!group || group.error) return { ok: false, error: t("The API key was rejected or {provider} could not be reached.", { provider: providerName(config, providerId) }) };
288
289
  if (key) saveCredential(providerId, key, deps.env);
289
290
  return { ok: true, models: group.models.length };
290
291
  }
@@ -299,22 +300,22 @@ async function runProviderCommand(args, deps) {
299
300
  return 0;
300
301
  }
301
302
  if (!id) {
302
- deps.err(`Pemakaian: bccli provider ${action} <id>`);
303
+ deps.err(t("Usage: bccli provider {action} <id>", { action }));
303
304
  return 1;
304
305
  }
305
306
  if (action === "remove") {
306
307
  removeGlobalProvider(id, deps.env);
307
- deps.out(`${id} dihapus.`);
308
+ deps.out(t("{id} removed.", { id }));
308
309
  return 0;
309
310
  }
310
311
  if (action !== "add") {
311
- deps.err(`Aksi tidak dikenal: ${action}. Pakai list, add, atau remove.`);
312
+ deps.err(t("Unknown action: {action}. Use list, add, or remove.", { action }));
312
313
  return 1;
313
314
  }
314
315
  const preset = PRESETS.find((p) => p.id === id);
315
316
  if (!preset && !config.providers[id]) {
316
317
  if (!args.url) {
317
- deps.err(`${id} bukan preset. Untuk provider custom tambahkan --url <base URL OpenAI-compatible>.`);
318
+ deps.err(t("{id} is not a preset. For a custom provider add --url <OpenAI-compatible base URL>.", { id }));
318
319
  return 1;
319
320
  }
320
321
  writeGlobalConfig(
@@ -323,13 +324,13 @@ async function runProviderCommand(args, deps) {
323
324
  );
324
325
  }
325
326
  const needsKey = !!loadConfig(deps.cwd, deps.env).providers[id].apiKeyEnv || !preset;
326
- const key = needsKey ? await deps.readSecret(`API key untuk ${id} (kosongkan bila tidak perlu): `) : "";
327
+ const key = needsKey ? await deps.readSecret(t("API key for {id} (leave empty if not needed): ", { id })) : "";
327
328
  const result = await addProviderKey(id, key, deps);
328
329
  if (!result.ok) {
329
330
  deps.err(result.error);
330
331
  return 1;
331
332
  }
332
- deps.out(`${id} siap. ${result.models} model tersedia.`);
333
+ deps.out(t("{id} is ready. {n} models available.", { id, n: result.models }));
333
334
  return 0;
334
335
  }
335
336
 
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ t
4
+ } from "./chunk-DDA5TJ7T.js";
2
5
 
3
6
  // src/reasoning.ts
4
7
  var REASONING_LEVELS = ["auto", "off", "low", "medium", "high", "max"];
@@ -9,7 +12,7 @@ function isReasoningLevel(value) {
9
12
  }
10
13
  function parseReasoningLevel(value, label = "reasoning") {
11
14
  if (!isReasoningLevel(value)) {
12
- throw new Error(`${label} harus salah satu dari: ${REASONING_LEVELS.join(", ")}`);
15
+ throw new Error(t("{label} must be one of: {levels}", { label, levels: REASONING_LEVELS.join(", ") }));
13
16
  }
14
17
  return value;
15
18
  }
@@ -32,11 +35,11 @@ function assertReasoningSupported(providerId, level) {
32
35
  if (level === "auto") return;
33
36
  const capability = reasoningCapability(providerId);
34
37
  if (!capability) {
35
- throw new Error("Provider ini belum memiliki kontrak reasoning manual. Gunakan Auto.");
38
+ throw new Error(t("This provider has no manual reasoning setting yet. Use Auto."));
36
39
  }
37
40
  if (!capability.levels.includes(level)) {
38
41
  const supported = capability.levels.filter((x) => x !== "auto").map(capitalize).join("/");
39
- throw new Error(`Model/provider ini tidak mendukung reasoning level '${level}'. Gunakan Auto${supported ? `/${supported}` : ""}.`);
42
+ throw new Error(t("This model/provider does not support reasoning level '{level}'. Use Auto{supported}.", { level, supported: supported ? `/${supported}` : "" }));
40
43
  }
41
44
  }
42
45
  function reasoningPayload(providerId, level) {