@botconnector/bccli 0.4.0-beta.10 → 0.4.0-beta.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.
package/README.md CHANGED
@@ -99,6 +99,12 @@ BCCLI dapat memasang BotConnector sebagai provider untuk agent lain:
99
99
  | `bccli connect aider` | hubungkan Aider ke BotConnector |
100
100
  | `bccli connect cline` | hubungkan Cline CLI ke BotConnector |
101
101
  | `bccli connect deepseek-harness` / `bccli connect dsh` | hubungkan DeepSeek Harness ke BotConnector |
102
+ | `bccli connect codex` | buat profile Codex Responses API + launcher BotConnector |
103
+ | `bccli connect claude-code` | buat launcher Claude Code via Anthropic Messages compatibility |
104
+ | `bccli connect cursor` | buat guided setup Cursor + warning override Base URL |
105
+ | `bccli connect openai-cli` | buat launcher OpenAI CLI khusus BotConnector |
106
+ | `bccli connect openai-sdk` | buat env profile untuk OpenAI Python/Node SDK |
107
+ | `bccli connect openai-compatible` | buat env profile universal OpenAI-compatible |
102
108
  | `bccli disconnect <agent>` | pulihkan config sebelum integrasi |
103
109
 
104
110
  OpenCode memakai config global `~/.config/opencode/opencode.json`. BCCLI mengambil katalog model BotConnector saat connect,
@@ -111,7 +117,13 @@ endpoint lain, BCCLI menolak menimpanya. Cline sendiri menyimpan API key provide
111
117
 
112
118
  DeepSeek Harness memakai custom provider `botconnector` di `$DSH_HOME/settings.yaml` dengan
113
119
  `api: openai-completions` dan `apiKeyEnv: BOTCONNECTOR_API_KEY`; key diletakkan pada blok BCCLI di
114
- `$DSH_HOME/.env`. Provider DSH lain tetap dipertahankan.
120
+ `$DSH_HOME/.env`. Provider DSH lain tetap dipertahankan. Setelah connect, jalankan profile web dengan
121
+ `dsh web` (setara dengan `dsh --profile web`); `dsh` tanpa profile memang ditolak oleh DSH 0.1.x.
122
+
123
+ Codex memakai profile `$CODEX_HOME/botconnector.config.toml` dengan `wire_api = "responses"` dan launcher
124
+ BCCLI yang membaca key dari storage BCCLI saat dijalankan. Claude Code memakai launcher terisolasi dengan
125
+ `ANTHROPIC_BASE_URL=https://api.botconnector.id` dan endpoint kompatibilitas `/v1/messages` + token counting.
126
+ Login/config utama Codex dan Claude Code tidak ditimpa.
115
127
 
116
128
  External agent memanggil BotConnector langsung, jadi discovery model tidak memakai identitas khusus BCCLI.
117
129
  Akses yang memang dibatasi ke BCCLI/Web App (misalnya Luna launch access) tidak otomatis diwariskan.
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  HELP_TEXT,
4
4
  parseCliArgs
5
- } from "./chunk-BJ337ABK.js";
5
+ } from "./chunk-TRMRDQ43.js";
6
6
  import "./chunk-ELML4KVQ.js";
7
7
  import "./chunk-CLN4Z5E3.js";
8
8
  import "./chunk-2MGINW4O.js";
@@ -36,7 +36,7 @@ function readSecret(prompt) {
36
36
  }
37
37
  async function runLogin(providerId, cwd) {
38
38
  const { runProviderCommand } = await import("./providerCli-Q7LRM2NP.js");
39
- const { parseCliArgs } = await import("./args-AWLROI65.js");
39
+ const { parseCliArgs } = await import("./args-SKWUZOJD.js");
40
40
  return runProviderCommand(parseCliArgs(["provider", "add", providerId]), {
41
41
  env: process.env,
42
42
  cwd,
@@ -22,7 +22,7 @@ Pemakaian:
22
22
  bccli provider list|add <id>|remove <id> kelola provider (custom: --url <url> [--name N] [--key-env ENV])
23
23
  bccli mcp list|add <nama>|remove <nama> kelola server MCP (katalog, atau --url <url>)
24
24
  bccli integrations lihat status integrasi agent eksternal
25
- bccli connect <agent> hubungkan BotConnector ke agent (opencode, aider, cline, deepseek-harness/dsh)
25
+ bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, cursor, openai-cli, openai-sdk, openai-compatible
26
26
  bccli disconnect <agent> lepas integrasi dan pulihkan config sebelumnya
27
27
 
28
28
  Opsi:
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  HELP_TEXT,
14
14
  parseCliArgs
15
- } from "./chunk-BJ337ABK.js";
15
+ } from "./chunk-TRMRDQ43.js";
16
16
  import {
17
17
  Permissions
18
18
  } from "./chunk-ELML4KVQ.js";
@@ -27,7 +27,7 @@ import {
27
27
  import "./chunk-CLN4Z5E3.js";
28
28
  import {
29
29
  runLogin
30
- } from "./chunk-IOWDWOXS.js";
30
+ } from "./chunk-6BLZELE6.js";
31
31
  import {
32
32
  Session,
33
33
  pruneSessions
@@ -1374,7 +1374,7 @@ function createRuntime(opts) {
1374
1374
  }
1375
1375
 
1376
1376
  // src/version.ts
1377
- var VERSION = true ? "0.4.0-beta.10" : "0.0.0-dev";
1377
+ var VERSION = true ? "0.4.0-beta.12" : "0.0.0-dev";
1378
1378
 
1379
1379
  // src/cli.ts
1380
1380
  async function main() {
@@ -1391,16 +1391,16 @@ async function main() {
1391
1391
  if (args.command === "login") return runLogin(args.loginProvider ?? "bc-cloud", cwd);
1392
1392
  if (args.command === "mcp") {
1393
1393
  const { runMcpCommand } = await import("./mcpCli-DZWQPTOS.js");
1394
- const { readSecret } = await import("./login-4C262MEI.js");
1394
+ const { readSecret } = await import("./login-N2CJC6RU.js");
1395
1395
  return runMcpCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
1396
1396
  }
1397
1397
  if (args.command === "provider") {
1398
1398
  const { runProviderCommand } = await import("./providerCli-Q7LRM2NP.js");
1399
- const { readSecret } = await import("./login-4C262MEI.js");
1399
+ const { readSecret } = await import("./login-N2CJC6RU.js");
1400
1400
  return runProviderCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
1401
1401
  }
1402
1402
  if (args.command === "connect" || args.command === "disconnect" || args.command === "integrations") {
1403
- const { runIntegrationCommand } = await import("./integrationCli-GEIMUL3M.js");
1403
+ const { runIntegrationCommand } = await import("./integrationCli-3CGHHTM2.js");
1404
1404
  return runIntegrationCommand(args, {
1405
1405
  env: process.env,
1406
1406
  cwd,
@@ -23,9 +23,11 @@ function keyPath(env) {
23
23
  return join(integrationHome(env), "bc-cloud.key");
24
24
  }
25
25
  function parseTarget(raw) {
26
- if (raw === "opencode" || raw === "aider" || raw === "cline" || raw === "deepseek-harness") return raw;
26
+ 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
27
  if (raw === "dsh") return "deepseek-harness";
28
- throw new ConfigError("Agent harus salah satu dari: opencode, aider, cline, deepseek-harness (alias: dsh)");
28
+ 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
+ );
29
31
  }
30
32
  function homeDir(env) {
31
33
  const value = env.HOME || env.USERPROFILE;
@@ -303,6 +305,236 @@ ${managed}
303
305
  deps.out(`DeepSeek Harness terhubung ke BotConnector (${models.length} model).`);
304
306
  deps.out(`Config: ${settingsPath}`);
305
307
  deps.out("Provider: botconnector (OpenAI Chat Completions)");
308
+ deps.out("Jalankan: dsh web");
309
+ deps.out("Bentuk panjang yang setara: dsh --profile web");
310
+ }
311
+ function managedProfilePath(target, env, ext = "env") {
312
+ return join(integrationHome(env), `${target}.${ext}`);
313
+ }
314
+ function writeOpenAiEnvProfile(target, deps) {
315
+ const secret = ensureSecret(deps.env);
316
+ const key = readFileSync(secret, "utf8").trim();
317
+ const path = managedProfilePath(target, deps.env);
318
+ const backup = safeBackup(path, deps.env);
319
+ mkdirSync(dirname(path), { recursive: true });
320
+ writeFileSync(path, [
321
+ `OPENAI_BASE_URL=${BASE_URL}`,
322
+ `OPENAI_API_KEY=${key}`,
323
+ ""
324
+ ].join("\n"), { mode: 384 });
325
+ try {
326
+ chmodSync(path, 384);
327
+ } catch {
328
+ }
329
+ writeState(target, {
330
+ target,
331
+ files: [{ path, ...backup }],
332
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
333
+ }, deps.env);
334
+ return path;
335
+ }
336
+ async function connectOpenAiCli(deps) {
337
+ const secret = ensureSecret(deps.env);
338
+ const dir = integrationHome(deps.env);
339
+ const launcher = join(dir, process.platform === "win32" ? "openai-botconnector.cmd" : "openai-botconnector");
340
+ const backup = safeBackup(launcher, deps.env);
341
+ mkdirSync(dir, { recursive: true });
342
+ if (process.platform === "win32") {
343
+ const keyFile = secret.replace(/\//g, "\\");
344
+ writeFileSync(launcher, [
345
+ "@echo off",
346
+ `set "OPENAI_BASE_URL=${BASE_URL}"`,
347
+ `for /f "usebackq delims=" %%A in ("${keyFile}") do set "OPENAI_API_KEY=%%A"`,
348
+ "openai %*",
349
+ ""
350
+ ].join("\r\n"));
351
+ } else {
352
+ const keyFile = secret.replace(/'/g, "'\\''");
353
+ writeFileSync(launcher, [
354
+ "#!/bin/sh",
355
+ `export OPENAI_BASE_URL='${BASE_URL}'`,
356
+ `export OPENAI_API_KEY="$(cat '${keyFile}')"`,
357
+ 'exec openai "$@"',
358
+ ""
359
+ ].join("\n"), { mode: 448 });
360
+ try {
361
+ chmodSync(launcher, 448);
362
+ } catch {
363
+ }
364
+ }
365
+ writeState("openai-cli", {
366
+ target: "openai-cli",
367
+ files: [{ path: launcher, ...backup }],
368
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
369
+ }, deps.env);
370
+ deps.out("OpenAI CLI profile BotConnector siap.");
371
+ deps.out(`Launcher: ${launcher}`);
372
+ deps.out("Launcher tidak menyimpan API key di dalam script; key dibaca dari storage BCCLI saat dijalankan.");
373
+ }
374
+ async function connectOpenAiSdk(deps) {
375
+ const path = writeOpenAiEnvProfile("openai-sdk", deps);
376
+ deps.out("OpenAI SDK profile BotConnector siap.");
377
+ 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
+ }
380
+ async function connectOpenAiCompatible(deps) {
381
+ const path = writeOpenAiEnvProfile("openai-compatible", deps);
382
+ deps.out("Profile OpenAI-compatible BotConnector siap.");
383
+ deps.out(`Env profile: ${path}`);
384
+ deps.out(`Base URL: ${BASE_URL}`);
385
+ }
386
+ async function connectCursor(deps) {
387
+ const secret = ensureSecret(deps.env);
388
+ const path = managedProfilePath("cursor", deps.env, "txt");
389
+ const backup = safeBackup(path, deps.env);
390
+ const keyFile = secret.replace(/\\/g, "/");
391
+ mkdirSync(dirname(path), { recursive: true });
392
+ writeFileSync(path, [
393
+ "BotConnector -> Cursor guided setup",
394
+ "",
395
+ `Base URL: ${BASE_URL}`,
396
+ `API key file: ${keyFile}`,
397
+ "",
398
+ "Cursor Settings -> Models:",
399
+ "1. Enable/add your OpenAI API key.",
400
+ "2. Enable Override OpenAI Base URL.",
401
+ `3. Set the override URL to ${BASE_URL}.`,
402
+ "4. Use Chat/Agent only; Cursor Tab/autocomplete remains on Cursor infrastructure.",
403
+ "",
404
+ "Important: Cursor currently applies the OpenAI Base URL override globally to OpenAI-family model requests.",
405
+ "Disable the override before switching back to Cursor-managed OpenAI-family models.",
406
+ ""
407
+ ].join("\n"));
408
+ writeState("cursor", {
409
+ target: "cursor",
410
+ files: [{ path, ...backup }],
411
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
412
+ }, deps.env);
413
+ deps.out("Cursor guided setup profile dibuat.");
414
+ deps.out(`Panduan: ${path}`);
415
+ deps.out("BCCLI tidak mengedit storage internal Cursor karena format override tersebut bukan konfigurasi eksternal yang stabil.");
416
+ }
417
+ function agentToolDefaultModel(models) {
418
+ for (const id of ["ling-3.0-flash", "mimo-v2.5", "deepseek-v4-flash"]) {
419
+ if (models.includes(id)) return id;
420
+ }
421
+ const first = models[0];
422
+ if (!first) throw new ConfigError("Katalog BotConnector tidak memiliki model untuk coding agent eksternal.");
423
+ return first;
424
+ }
425
+ async function connectCodex(deps) {
426
+ if (readState("codex", deps.env)) disconnect("codex", deps);
427
+ const home = homeDir(deps.env);
428
+ const codexHome = deps.env.CODEX_HOME || join(home, ".codex");
429
+ const profilePath = join(codexHome, "botconnector.config.toml");
430
+ const launcher = join(integrationHome(deps.env), process.platform === "win32" ? "codex-botconnector.cmd" : "codex-botconnector");
431
+ if (existsSync(profilePath)) {
432
+ throw new ConfigError("Codex sudah memiliki botconnector.config.toml. BCCLI tidak akan menimpanya.");
433
+ }
434
+ const profileBackup = safeBackup(profilePath, deps.env);
435
+ const launcherBackup = safeBackup(launcher, deps.env);
436
+ const secret = ensureSecret(deps.env);
437
+ const models = await botConnectorModels(deps);
438
+ const model = agentToolDefaultModel(models);
439
+ const profile = [
440
+ `model = ${JSON.stringify(model)}`,
441
+ 'model_provider = "botconnector"',
442
+ "",
443
+ "[model_providers.botconnector]",
444
+ 'name = "BotConnector"',
445
+ `base_url = "${BASE_URL}"`,
446
+ 'env_key = "BOTCONNECTOR_API_KEY"',
447
+ 'wire_api = "responses"',
448
+ "requires_openai_auth = false",
449
+ "supports_websockets = false",
450
+ "supports_standalone_web_search = false",
451
+ ""
452
+ ].join("\n");
453
+ mkdirSync(codexHome, { recursive: true });
454
+ writeFileSync(profilePath, profile);
455
+ mkdirSync(dirname(launcher), { recursive: true });
456
+ if (process.platform === "win32") {
457
+ const keyFile = secret.replace(/\//g, "\\");
458
+ writeFileSync(launcher, [
459
+ "@echo off",
460
+ 'set "BOTCONNECTOR_API_KEY="',
461
+ `for /f "usebackq delims=" %%A in ("${keyFile}") do set "BOTCONNECTOR_API_KEY=%%A"`,
462
+ "codex -p botconnector %*",
463
+ ""
464
+ ].join("\r\n"));
465
+ } else {
466
+ const keyFile = secret.replace(/'/g, "'\\''");
467
+ writeFileSync(launcher, [
468
+ "#!/bin/sh",
469
+ `export BOTCONNECTOR_API_KEY="$(cat '${keyFile}')"`,
470
+ 'exec codex -p botconnector "$@"',
471
+ ""
472
+ ].join("\n"), { mode: 448 });
473
+ try {
474
+ chmodSync(launcher, 448);
475
+ } catch {
476
+ }
477
+ }
478
+ writeState("codex", {
479
+ target: "codex",
480
+ files: [{ path: profilePath, ...profileBackup }, { path: launcher, ...launcherBackup }],
481
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
482
+ }, deps.env);
483
+ deps.out("Codex CLI terhubung ke BotConnector Responses API.");
484
+ deps.out(`Profile: ${profilePath}`);
485
+ deps.out(`Launcher: ${launcher}`);
486
+ deps.out(`Default coding model: ${model}`);
487
+ }
488
+ async function connectClaudeCode(deps) {
489
+ const secret = ensureSecret(deps.env);
490
+ const models = await botConnectorModels(deps);
491
+ const model = agentToolDefaultModel(models);
492
+ const launcher = join(integrationHome(deps.env), process.platform === "win32" ? "claude-botconnector.cmd" : "claude-botconnector");
493
+ const backup = safeBackup(launcher, deps.env);
494
+ mkdirSync(dirname(launcher), { recursive: true });
495
+ if (process.platform === "win32") {
496
+ const keyFile = secret.replace(/\//g, "\\");
497
+ writeFileSync(launcher, [
498
+ "@echo off",
499
+ 'set "ANTHROPIC_AUTH_TOKEN="',
500
+ 'set "CLAUDE_CODE_OAUTH_TOKEN="',
501
+ 'set "ANTHROPIC_API_KEY="',
502
+ `for /f "usebackq delims=" %%A in ("${keyFile}") do set "ANTHROPIC_API_KEY=%%A"`,
503
+ 'set "ANTHROPIC_BASE_URL=https://api.botconnector.id"',
504
+ `set "ANTHROPIC_MODEL=${model}"`,
505
+ `set "ANTHROPIC_DEFAULT_OPUS_MODEL=${model}"`,
506
+ `set "ANTHROPIC_DEFAULT_SONNET_MODEL=${model}"`,
507
+ `set "ANTHROPIC_DEFAULT_HAIKU_MODEL=${model}"`,
508
+ "claude %*",
509
+ ""
510
+ ].join("\r\n"));
511
+ } else {
512
+ const keyFile = secret.replace(/'/g, "'\\''");
513
+ writeFileSync(launcher, [
514
+ "#!/bin/sh",
515
+ "unset ANTHROPIC_AUTH_TOKEN CLAUDE_CODE_OAUTH_TOKEN",
516
+ `export ANTHROPIC_API_KEY="$(cat '${keyFile}')"`,
517
+ "export ANTHROPIC_BASE_URL='https://api.botconnector.id'",
518
+ `export ANTHROPIC_MODEL='${model}'`,
519
+ `export ANTHROPIC_DEFAULT_OPUS_MODEL='${model}'`,
520
+ `export ANTHROPIC_DEFAULT_SONNET_MODEL='${model}'`,
521
+ `export ANTHROPIC_DEFAULT_HAIKU_MODEL='${model}'`,
522
+ 'exec claude "$@"',
523
+ ""
524
+ ].join("\n"), { mode: 448 });
525
+ try {
526
+ chmodSync(launcher, 448);
527
+ } catch {
528
+ }
529
+ }
530
+ writeState("claude-code", {
531
+ target: "claude-code",
532
+ files: [{ path: launcher, ...backup }],
533
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
534
+ }, deps.env);
535
+ deps.out("Claude Code terhubung ke BotConnector Anthropic Messages compatibility API.");
536
+ deps.out(`Launcher: ${launcher}`);
537
+ deps.out(`Default coding model: ${model}`);
306
538
  }
307
539
  function disconnect(target, deps) {
308
540
  const state = readState(target, deps.env);
@@ -322,7 +554,7 @@ function disconnect(target, deps) {
322
554
  deps.out(`${target}: integrasi BotConnector dilepas dan config dipulihkan.`);
323
555
  }
324
556
  function listIntegrations(deps) {
325
- for (const target of ["opencode", "aider", "cline", "deepseek-harness"]) {
557
+ for (const target of ["opencode", "aider", "cline", "deepseek-harness", "cursor", "openai-cli", "openai-sdk", "openai-compatible", "codex", "claude-code"]) {
326
558
  deps.out(`${target} ${readState(target, deps.env) ? "connected" : "not connected"}`);
327
559
  }
328
560
  }
@@ -339,7 +571,13 @@ async function runIntegrationCommand(args, deps) {
339
571
  if (target === "opencode") await connectOpenCode(deps);
340
572
  else if (target === "aider") await connectAider(deps);
341
573
  else if (target === "cline") await connectCline(deps);
342
- else await connectDeepSeekHarness(deps);
574
+ else if (target === "deepseek-harness") await connectDeepSeekHarness(deps);
575
+ else if (target === "cursor") await connectCursor(deps);
576
+ else if (target === "openai-cli") await connectOpenAiCli(deps);
577
+ else if (target === "openai-sdk") await connectOpenAiSdk(deps);
578
+ else if (target === "openai-compatible") await connectOpenAiCompatible(deps);
579
+ else if (target === "codex") await connectCodex(deps);
580
+ else await connectClaudeCode(deps);
343
581
  return 0;
344
582
  }
345
583
  export {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  readSecret,
4
4
  runLogin
5
- } from "./chunk-IOWDWOXS.js";
5
+ } from "./chunk-6BLZELE6.js";
6
6
  export {
7
7
  readSecret,
8
8
  runLogin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.0-beta.10",
3
+ "version": "0.4.0-beta.12",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {