@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
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ addProviderKey,
4
+ runProviderCommand
5
+ } from "./chunk-2ON3WIDP.js";
6
+ import "./chunk-25DSN3Y3.js";
7
+ import "./chunk-VO6MF6JJ.js";
8
+ import "./chunk-RMDW3OQ6.js";
9
+ import "./chunk-ZKMSTD6G.js";
10
+ import "./chunk-GIGWZFCY.js";
11
+ import "./chunk-QHNWI3OT.js";
12
+ export {
13
+ addProviderKey,
14
+ runProviderCommand
15
+ };
package/dist/sdk.js CHANGED
@@ -2,9 +2,9 @@
2
2
  import { parseArgs } from "util";
3
3
 
4
4
  // src/config.ts
5
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
5
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
6
6
  import { homedir } from "os";
7
- import { join } from "path";
7
+ import { dirname, join } from "path";
8
8
 
9
9
  // src/presets.ts
10
10
  var PRESETS = [
@@ -145,13 +145,20 @@ var ID = {
145
145
  Usage:
146
146
  bccli [task] interactive mode (optionally start with a task)
147
147
  bccli -p "task" run one task without interaction (scripts/CI)
148
- bccli login [provider] save an API key (default: bc-cloud)
148
+ bccli login [provider] OAuth login (or --key paste API key, --logout remove)
149
149
  bccli models [provider] list models (default: the active provider)
150
150
  bccli update install the newest bccli from npm
151
151
  bccli acp run as an ACP agent for editors (Zed, ...)
152
152
  bccli serve [--port N] serve sessions over HTTP+WS for IDEs/bots
153
+ bccli plugins list, install, remove, or update plugins
154
+ bccli gh-bot [serve] GitHub comment bot (off-by-default; needs config)
153
155
  bccli provider list|add <id>|remove <id> manage providers (custom: --url <url> [--name N] [--key-env ENV])
154
156
  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
157
+ bccli completion <shell> print a shell completion script (bash, zsh, fish, powershell)
158
+ bccli stats [--days N] show token usage from local sessions (default: last 7 days)
159
+ bccli export [session] [file] copy a session JSONL to a file (default: last session here)
160
+ bccli import <file> import a session JSONL into the current project
161
+ bccli pr <number> [--repo owner/name] [task] check out a GitHub PR and run a task on it
155
162
  bccli integrations show the status of external agent integrations
156
163
  bccli connect <agent> opencode, aider, cline, dsh, codex, claude-code, cursor, openai-cli, openai-sdk, openai-compatible, openclaw, hermes
157
164
  bccli disconnect <agent> remove an integration and restore the previous config
@@ -173,11 +180,13 @@ Options:
173
180
  Pemakaian:
174
181
  bccli [tugas] mode interaktif (opsional langsung dengan tugas)
175
182
  bccli -p "tugas" jalankan satu tugas tanpa interaksi (skrip/CI)
176
- bccli login [provider] simpan API key (default: bc-cloud)
183
+ bccli login [provider] login OAuth (atau --key tempel API key, --logout hapus)
177
184
  bccli models [provider] daftar model (default: provider aktif)
178
185
  bccli update pasang bccli terbaru dari npm
179
186
  bccli acp jalankan sebagai agen ACP untuk editor (Zed, ...)
180
187
  bccli serve [--port N] sajikan sesi lewat HTTP+WS untuk IDE/bot
188
+ bccli plugins daftar, install, remove, atau perbarui plugin
189
+ bccli gh-bot [serve] bot komentar GitHub (nonaktif default; butuh config)
181
190
  bccli provider list|add <id>|remove <id> kelola provider (custom: --url <url> [--name N] [--key-env ENV])
182
191
  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
183
192
  bccli integrations lihat status integrasi agent eksternal
@@ -221,6 +230,58 @@ Opsi:
221
230
  "A new bccli is available: {latest} (you have {current}). Run: bccli update": "bccli versi baru tersedia: {latest} (kamu punya {current}). Jalankan: bccli update",
222
231
  "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.",
223
232
  "No image on the clipboard.": "Tidak ada gambar di clipboard.",
233
+ "githubBot secret env {env} is empty \u2014 set it before enabling the bot.": "secret env githubBot {env} kosong \u2014 setel sebelum mengaktifkan bot.",
234
+ "githubBot.{name} must be an array of strings.": "githubBot.{name} harus berupa array of string.",
235
+ "githubBot.{name} must be a positive integer.": "githubBot.{name} harus bilangan bulat positif.",
236
+ "githubBot.enabled must be a boolean.": "githubBot.enabled harus boolean.",
237
+ "githubBot.path must be an absolute path like /github.": "githubBot.path harus path absolut seperti /github.",
238
+ "githubBot.secretEnv must be a non-empty string.": "githubBot.secretEnv harus string tidak kosong.",
239
+ "Ignored empty command in delivery {id}.": "Mengabaikan perintah kosong di delivery {id}.",
240
+ "Unknown action: {action}. Use serve.": "Aksi tidak dikenal: {action}. Gunakan serve.",
241
+ "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.",
242
+ "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].",
243
+ "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.",
244
+ "npm install failed ({code}): {stderr}": "npm install gagal ({code}): {stderr}",
245
+ "install requires a package spec: bccli plugins install <spec>": "install butuh spesifikasi paket: bccli plugins install <spec>",
246
+ "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.",
247
+ "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).",
248
+ "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.",
249
+ '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.',
250
+ "{name} is already enabled.": "{name} sudah aktif.",
251
+ "{name} installed and enabled.": "{name} terpasang dan aktif.",
252
+ "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.",
253
+ "{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.",
254
+ "{name} is not an installed managed plugin.": "{name} bukan plugin terelola yang terpasang.",
255
+ "Unknown plugin: {arg}.": "Plugin tidak dikenal: {arg}.",
256
+ "remove requires a plugin name: bccli plugins remove <name>": "remove butuh nama plugin: bccli plugins remove <nama>",
257
+ '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).',
258
+ '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.',
259
+ "Skipping malformed entry: {entry} \u2014 fix it manually in {path}.": "Melewatkan entry rusak: {entry} \u2014 perbaiki manual di {path}.",
260
+ "No managed plugins to update.": "Tidak ada plugin terelola untuk diperbarui.",
261
+ "update requires a plugin name or no argument: bccli plugins update [name]": "update butuh nama plugin atau tanpa argumen: bccli plugins update [nama]",
262
+ "{name} updated to latest.": "{name} diperbarui ke versi terbaru.",
263
+ "Use either --key or --logout, not both.": "Pakai --key atau --logout, jangan keduanya.",
264
+ "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.",
265
+ "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.",
266
+ "Could not open the browser automatically \u2014 open this URL manually: {url}": "Tidak bisa membuka browser otomatis \u2014 buka URL ini manual: {url}",
267
+ "Paste the authorization code from the browser: ": "Tempel kode otorisasi dari browser: ",
268
+ "Failed to read the authorization code: {reason}. Your stored credential was not changed.": "Gagal membaca kode otorisasi: {reason}. Credential tersimpan tidak berubah.",
269
+ "Authorization code is empty. Run bccli login openrouter again.": "Kode otorisasi kosong. Jalankan bccli login openrouter lagi.",
270
+ "Login cancelled.": "Login dibatalkan.",
271
+ "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.",
272
+ "Could not reach OpenRouter: {reason}. Your stored credential was not changed.": "Tidak bisa menghubungi OpenRouter: {reason}. Credential tersimpan tidak berubah.",
273
+ "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.",
274
+ "OpenRouter rejected the authorization code (403): {detail}. Run bccli login openrouter again.": "OpenRouter menolak kode otorisasi (403): {detail}. Jalankan bccli login openrouter lagi.",
275
+ "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.",
276
+ "OpenRouter exchange failed ({status}): {detail}. Your stored credential was not changed.": "Pertukaran OpenRouter gagal ({status}): {detail}. Credential tersimpan tidak berubah.",
277
+ "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.",
278
+ "Logged in: openrouter credential saved.": "Login berhasil: credential openrouter tersimpan.",
279
+ "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.",
280
+ "Verify with: bccli models openrouter (your key is never printed).": "Verifikasi dengan: bccli models openrouter (key kamu tidak pernah dicetak).",
281
+ "openrouter credential removed.": "credential openrouter dihapus.",
282
+ "openrouter credential was not stored.": "credential openrouter tidak tersimpan.",
283
+ "Note: {env} is still set in the environment and will keep being used.": "Catatan: {env} masih ter-set di environment dan akan terus dipakai.",
284
+ "To revoke keys on your account, open {dashboard}.": "Untuk mencabut key akun kamu, buka {dashboard}.",
224
285
  "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.",
225
286
  "Verifying edits: {cmds}": "Memverifikasi edit: {cmds}",
226
287
  "Verification passed.": "Verifikasi lulus.",
@@ -419,7 +480,23 @@ Opsi:
419
480
  "Run: dsh web": "Jalankan: dsh web",
420
481
  "timeout after {n} seconds": "timeout {n} detik",
421
482
  "Could not start MCP servers: {error}": "Tidak bisa menjalankan server MCP: {error}",
422
- "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."
483
+ "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.",
484
+ "usage: bccli completion <{shells}>": "pakai: bccli completion <{shells}>",
485
+ "--days must be a positive integer": "--days harus bilangan bulat positif",
486
+ "no sessions in the last {days} day(s)": "tidak ada sesi dalam {days} hari terakhir",
487
+ "sessions (last {days} day(s)):": "sesi ({days} hari terakhir):",
488
+ "session(s)": "sesi",
489
+ "message(s)": "pesan",
490
+ "recorded": "tercatat",
491
+ "no session to export in this folder": "tidak ada sesi untuk diekspor di folder ini",
492
+ "exported {file}": "diekspor ke {file}",
493
+ "file not found: {file}": "file tidak ditemukan: {file}",
494
+ "invalid session file (non-JSON line): {file}": "file sesi tidak valid (baris bukan JSON): {file}",
495
+ "imported {n} record(s) into {file}": "impor {n} rekaman ke {file}",
496
+ "usage: bccli pr <number> [--repo owner/name] [task]": "pakai: bccli pr <nomor> [--repo owner/name] [tugas]",
497
+ "gh is not available ({error}); install GitHub CLI first": "gh tidak tersedia ({error}); pasang GitHub CLI dulu",
498
+ "gh pr checkout {n} failed (exit {code})": "gh pr checkout {n} gagal (exit {code})",
499
+ "checked out PR #{n}": "checkout PR #{n} selesai"
423
500
  };
424
501
 
425
502
  // src/i18n.ts
@@ -820,10 +897,14 @@ function parseCliArgs(argv) {
820
897
  name: { type: "string" },
821
898
  "key-env": { type: "string" },
822
899
  value: { type: "string", multiple: true },
900
+ key: { type: "boolean" },
901
+ logout: { type: "boolean" },
823
902
  port: { type: "string" },
824
903
  host: { type: "string" },
825
904
  token: { type: "string" },
826
- "base-url": { type: "string" }
905
+ "base-url": { type: "string" },
906
+ days: { type: "string" },
907
+ repo: { type: "string" }
827
908
  }
828
909
  });
829
910
  const reasoning = values.reasoning;
@@ -840,13 +921,17 @@ function parseCliArgs(argv) {
840
921
  throw new ConfigError(t("--output-format must be one of: {formats}", { formats: "text, json, stream-json" }));
841
922
  }
842
923
  const [first, ...rest] = positionals;
843
- const SUBCOMMANDS = ["login", "models", "update", "acp", "serve", "provider", "mcp", "connect", "disconnect", "integrations"];
924
+ const SUBCOMMANDS = ["login", "models", "update", "acp", "serve", "plugins", "gh-bot", "provider", "mcp", "connect", "disconnect", "integrations", "completion", "stats", "export", "import", "pr"];
844
925
  const command = SUBCOMMANDS.includes(first) ? first : "run";
845
926
  const words2 = command === "run" ? positionals : rest;
846
927
  const port = values.port !== void 0 ? Number(values.port) : void 0;
847
928
  if (port !== void 0 && (!Number.isInteger(port) || port < 0 || port > 65535)) {
848
929
  throw new ConfigError(t("--port must be a number between 0 and 65535"));
849
930
  }
931
+ const days = values.days !== void 0 ? Number(values.days) : void 0;
932
+ if (days !== void 0 && (!Number.isInteger(days) || days < 1)) {
933
+ throw new ConfigError(t("--days must be a positive integer"));
934
+ }
850
935
  if (values.host !== void 0 && !LOOPBACK_BIND.has(values.host)) {
851
936
  throw new ConfigError(t("serve only accepts loopback --host (127.0.0.1, localhost, ::1)"));
852
937
  }
@@ -867,7 +952,9 @@ function parseCliArgs(argv) {
867
952
  help: !!values.help,
868
953
  version: !!values.version,
869
954
  loginProvider: command === "login" ? rest[0] ?? "bc-cloud" : void 0,
870
- subArgs: ["models", "provider", "mcp", "connect", "disconnect", "integrations"].includes(command) ? rest : [],
955
+ key: !!values.key,
956
+ logout: !!values.logout,
957
+ subArgs: ["models", "plugins", "gh-bot", "provider", "mcp", "connect", "disconnect", "integrations", "completion", "stats", "export", "import", "pr"].includes(command) ? rest : [],
871
958
  url: values.url,
872
959
  name: values.name,
873
960
  keyEnv: values["key-env"],
@@ -875,7 +962,9 @@ function parseCliArgs(argv) {
875
962
  port,
876
963
  host: values.host,
877
964
  token: values.token,
878
- baseUrl: values["base-url"]
965
+ baseUrl: values["base-url"],
966
+ days,
967
+ repo: values.repo
879
968
  };
880
969
  }
881
970
 
@@ -1815,6 +1904,42 @@ function recoverTextToolCalls(text, tools) {
1815
1904
 
1816
1905
  // src/hooks.ts
1817
1906
  import { spawn } from "child_process";
1907
+
1908
+ // src/tools/shell.ts
1909
+ import { existsSync as existsSync2 } from "fs";
1910
+ import { win32 } from "path";
1911
+ var PS_PRELUDE = "[Console]::OutputEncoding=[Text.Encoding]::UTF8; $OutputEncoding=[Text.Encoding]::UTF8; ";
1912
+ var PS_EPILOGUE = "\nif ($LASTEXITCODE -ne $null) { exit $LASTEXITCODE } elseif (-not $?) { exit 1 }";
1913
+ function gitBashCandidates(env) {
1914
+ const roots = [env.ProgramW6432, env.ProgramFiles, env["ProgramFiles(x86)"], env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "Programs")];
1915
+ const fromRoots = roots.filter((root) => !!root).map((root) => win32.join(root, "Git", "bin", "bash.exe"));
1916
+ const fromPath = (env.PATH ?? env.Path ?? "").split(";").filter(Boolean).map((dir) => win32.join(dir, "..", "bin", "bash.exe"));
1917
+ return [...fromRoots, ...fromPath];
1918
+ }
1919
+ function resolveShell(deps) {
1920
+ if (deps.platform !== "win32") return void 0;
1921
+ const bash = gitBashCandidates(deps.env).find((candidate) => deps.exists(candidate));
1922
+ if (bash) return { name: "bash", file: bash, args: (command) => ["-c", command] };
1923
+ return {
1924
+ name: "powershell",
1925
+ file: "powershell.exe",
1926
+ args: (command) => [
1927
+ "-NoProfile",
1928
+ "-NonInteractive",
1929
+ "-ExecutionPolicy",
1930
+ "Bypass",
1931
+ "-EncodedCommand",
1932
+ Buffer.from(PS_PRELUDE + command + PS_EPILOGUE, "utf16le").toString("base64")
1933
+ ]
1934
+ };
1935
+ }
1936
+ var cachedDefault = null;
1937
+ function defaultShell() {
1938
+ if (cachedDefault === null) cachedDefault = resolveShell({ platform: process.platform, env: process.env, exists: existsSync2 });
1939
+ return cachedDefault;
1940
+ }
1941
+
1942
+ // src/hooks.ts
1818
1943
  var DEFAULT_TIMEOUT_MS = 1e4;
1819
1944
  var MAX_CAPTURE = 8192;
1820
1945
  function globToRegExp(pattern) {
@@ -1842,8 +1967,18 @@ function runOne(command, event, payload, opts) {
1842
1967
  resolve4(result);
1843
1968
  };
1844
1969
  let child;
1970
+ const shell = defaultShell();
1845
1971
  try {
1846
- child = spawn(command, { shell: true, env, cwd: opts.cwd ?? process.cwd(), stdio: ["ignore", "pipe", "pipe"] });
1972
+ if (shell) {
1973
+ child = spawn(shell.file, shell.args(command), {
1974
+ shell: false,
1975
+ env,
1976
+ cwd: opts.cwd ?? process.cwd(),
1977
+ stdio: ["ignore", "pipe", "pipe"]
1978
+ });
1979
+ } else {
1980
+ child = spawn(command, { shell: true, env, cwd: opts.cwd ?? process.cwd(), stdio: ["ignore", "pipe", "pipe"] });
1981
+ }
1847
1982
  } catch (error) {
1848
1983
  resolve4({ failure: error.message });
1849
1984
  return;
@@ -1950,40 +2085,6 @@ function sandboxArgv(command, opts) {
1950
2085
  return void 0;
1951
2086
  }
1952
2087
 
1953
- // src/tools/shell.ts
1954
- import { existsSync as existsSync2 } from "fs";
1955
- import { win32 } from "path";
1956
- var PS_PRELUDE = "[Console]::OutputEncoding=[Text.Encoding]::UTF8; $OutputEncoding=[Text.Encoding]::UTF8; ";
1957
- var PS_EPILOGUE = "\nif ($LASTEXITCODE -ne $null) { exit $LASTEXITCODE } elseif (-not $?) { exit 1 }";
1958
- function gitBashCandidates(env) {
1959
- const roots = [env.ProgramW6432, env.ProgramFiles, env["ProgramFiles(x86)"], env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "Programs")];
1960
- const fromRoots = roots.filter((root) => !!root).map((root) => win32.join(root, "Git", "bin", "bash.exe"));
1961
- const fromPath = (env.PATH ?? env.Path ?? "").split(";").filter(Boolean).map((dir) => win32.join(dir, "..", "bin", "bash.exe"));
1962
- return [...fromRoots, ...fromPath];
1963
- }
1964
- function resolveShell(deps) {
1965
- if (deps.platform !== "win32") return void 0;
1966
- const bash = gitBashCandidates(deps.env).find((candidate) => deps.exists(candidate));
1967
- if (bash) return { name: "bash", file: bash, args: (command) => ["-c", command] };
1968
- return {
1969
- name: "powershell",
1970
- file: "powershell.exe",
1971
- args: (command) => [
1972
- "-NoProfile",
1973
- "-NonInteractive",
1974
- "-ExecutionPolicy",
1975
- "Bypass",
1976
- "-EncodedCommand",
1977
- Buffer.from(PS_PRELUDE + command + PS_EPILOGUE, "utf16le").toString("base64")
1978
- ]
1979
- };
1980
- }
1981
- var cachedDefault = null;
1982
- function defaultShell() {
1983
- if (cachedDefault === null) cachedDefault = resolveShell({ platform: process.platform, env: process.env, exists: existsSync2 });
1984
- return cachedDefault;
1985
- }
1986
-
1987
2088
  // src/tools/types.ts
1988
2089
  function defineTool(tool) {
1989
2090
  return tool;
@@ -2070,8 +2171,8 @@ function startBackground(command, cwd, env, shell) {
2070
2171
  return task;
2071
2172
  }
2072
2173
  function backgroundStatus(task) {
2073
- if (task.status === "running") return `[running ${Math.round((Date.now() - task.startedAt) / 1e3)}s]`;
2074
2174
  if (task.killed) return "[killed]";
2175
+ if (task.status === "running") return `[running ${Math.round((Date.now() - task.startedAt) / 1e3)}s]`;
2075
2176
  return `[exit code ${task.exitCode}]`;
2076
2177
  }
2077
2178
  function backgroundOutput(task) {
@@ -2977,7 +3078,7 @@ var readTool = createReadTool({ vision: true });
2977
3078
  // src/tools/write.ts
2978
3079
  import { existsSync as existsSync4 } from "fs";
2979
3080
  import { mkdir, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
2980
- import { dirname } from "path";
3081
+ import { dirname as dirname2 } from "path";
2981
3082
  import { z as z7 } from "zod";
2982
3083
  var writeTool = defineTool({
2983
3084
  name: "write",
@@ -3004,7 +3105,7 @@ var writeTool = defineTool({
3004
3105
  }
3005
3106
  try {
3006
3107
  await ctx.checkpoint?.(abs);
3007
- await mkdir(dirname(abs), { recursive: true });
3108
+ await mkdir(dirname2(abs), { recursive: true });
3008
3109
  await writeFile2(abs, input.content);
3009
3110
  } catch (error) {
3010
3111
  return { output: `Failed to write ${input.path}: ${errorCode(error)}`, isError: true };
@@ -3643,7 +3744,7 @@ import { z as z9 } from "zod";
3643
3744
  // src/mcp/config.ts
3644
3745
  import { createHash } from "crypto";
3645
3746
  import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3646
- import { dirname as dirname2, join as join3, resolve as resolve3 } from "path";
3747
+ import { dirname as dirname3, join as join3, resolve as resolve3 } from "path";
3647
3748
  var ENV_REF = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
3648
3749
  function expandEnvVars(config, env) {
3649
3750
  const expand = (value) => value.replace(ENV_REF, (match, name, fallback) => {
@@ -3667,7 +3768,7 @@ function expandEnvVars(config, env) {
3667
3768
  import { spawn as spawn3 } from "child_process";
3668
3769
  import { chmodSync as chmodSync3, existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
3669
3770
  import { createServer } from "http";
3670
- import { dirname as dirname3, join as join4 } from "path";
3771
+ import { dirname as dirname4, join as join4 } from "path";
3671
3772
  import { auth } from "@modelcontextprotocol/sdk/client/auth.js";
3672
3773
  var oauthStorePath = (home) => join4(home, "mcp-oauth.json");
3673
3774
  function readStore(home) {
@@ -3681,7 +3782,7 @@ function readStore(home) {
3681
3782
  }
3682
3783
  function writeStore(home, store) {
3683
3784
  const path = oauthStorePath(home);
3684
- mkdirSync3(dirname3(path), { recursive: true });
3785
+ mkdirSync3(dirname4(path), { recursive: true });
3685
3786
  writeFileSync3(path, `${JSON.stringify(store, null, 2)}
3686
3787
  `, { mode: 384 });
3687
3788
  chmodSync3(path, 384);
@@ -3937,7 +4038,7 @@ import { homedir as homedir2 } from "os";
3937
4038
 
3938
4039
  // src/context.ts
3939
4040
  import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
3940
- import { dirname as dirname4, join as join5 } from "path";
4041
+ import { dirname as dirname5, join as join5 } from "path";
3941
4042
  var FILES = ["AGENTS.md", "BCCLI.md"];
3942
4043
  function readIf(path) {
3943
4044
  try {
@@ -3948,9 +4049,9 @@ function readIf(path) {
3948
4049
  }
3949
4050
  function instructionPaths(cwd, home) {
3950
4051
  const dirs2 = [];
3951
- for (let dir = cwd; ; dir = dirname4(dir)) {
4052
+ for (let dir = cwd; ; dir = dirname5(dir)) {
3952
4053
  dirs2.unshift(dir);
3953
- if (dirname4(dir) === dir) break;
4054
+ if (dirname5(dir) === dir) break;
3954
4055
  }
3955
4056
  return [join5(home, "BCCLI.md"), ...dirs2.flatMap((dir) => FILES.map((name) => join5(dir, name)))];
3956
4057
  }
@@ -3964,9 +4065,9 @@ ${text}`);
3964
4065
  return parts.join("\n\n");
3965
4066
  }
3966
4067
  function isGitRepo(cwd) {
3967
- for (let dir = cwd; ; dir = dirname4(dir)) {
4068
+ for (let dir = cwd; ; dir = dirname5(dir)) {
3968
4069
  if (existsSync8(join5(dir, ".git"))) return true;
3969
- if (dirname4(dir) === dir) return false;
4070
+ if (dirname5(dir) === dir) return false;
3970
4071
  }
3971
4072
  }
3972
4073
  function buildSystemPrompt(opts) {
@@ -4151,7 +4252,7 @@ async function addProviderKey(providerId, key, deps) {
4151
4252
 
4152
4253
  // src/session.ts
4153
4254
  import { randomBytes as randomBytes2 } from "crypto";
4154
- import { appendFileSync, existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync7, rmSync, statSync as statSync3 } from "fs";
4255
+ import { appendFileSync, existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync7, rmSync as rmSync2, statSync as statSync3 } from "fs";
4155
4256
  import { join as join8 } from "path";
4156
4257
  function projectDir(home, cwd) {
4157
4258
  const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(-100) || "root";
@@ -4871,6 +4972,8 @@ function createRuntime(opts) {
4871
4972
  apiKey: resolved.apiKey,
4872
4973
  model: resolved.model,
4873
4974
  providerId: resolved.providerId,
4975
+ fetch: opts.fetch,
4976
+ // diteruskan penuh (spec gh-bot §6.6 — juga memperbaiki sdk fetch-injection)
4874
4977
  enableProgrammaticToolCalling: lunaPtcAutoEnabled(env)
4875
4978
  });
4876
4979
  };
@@ -4955,7 +5058,7 @@ function createRuntime(opts) {
4955
5058
  cwd: opts.cwd,
4956
5059
  history,
4957
5060
  reasoning,
4958
- maxSteps: config.maxSteps,
5061
+ maxSteps: opts.maxSteps ?? config.maxSteps,
4959
5062
  hooks: config.hooks,
4960
5063
  pluginEmit,
4961
5064
  env,
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ createRuntime
4
+ } from "./chunk-ZGH4B7OU.js";
5
+ import "./chunk-U6PCNS4B.js";
6
+ import "./chunk-PSRNKKGA.js";
7
+ import "./chunk-NVRNFR4S.js";
8
+ import "./chunk-PSO7R5AD.js";
2
9
  import {
3
10
  VERSION
4
- } from "./chunk-EQQTTE2K.js";
11
+ } from "./chunk-DUSVS3XK.js";
5
12
  import {
6
13
  LOOPBACK_BIND,
7
14
  MAX_FRAME_BYTES,
@@ -10,31 +17,25 @@ import {
10
17
  parseClientFrame,
11
18
  randomToken,
12
19
  trustFence
13
- } from "./chunk-AS7VV7D3.js";
14
- import {
15
- createRuntime
16
- } from "./chunk-M4IYXI3V.js";
17
- import "./chunk-3HCOAJEQ.js";
18
- import "./chunk-DBHDZ5EP.js";
20
+ } from "./chunk-CYTRCZXI.js";
19
21
  import "./chunk-GAFJEQTJ.js";
20
- import "./chunk-JROUQ5YS.js";
22
+ import "./chunk-2ON3WIDP.js";
21
23
  import {
22
24
  listAllModels
23
- } from "./chunk-LN32JIZR.js";
24
- import "./chunk-SESBH44L.js";
25
+ } from "./chunk-25DSN3Y3.js";
26
+ import "./chunk-VO6MF6JJ.js";
27
+ import "./chunk-7F3IWBPQ.js";
25
28
  import {
26
29
  Session
27
- } from "./chunk-VM7HYAJS.js";
28
- import "./chunk-GGNXHJL6.js";
29
- import "./chunk-NI5JZUZ3.js";
30
- import "./chunk-AVB6M4JE.js";
31
- import "./chunk-HE33XAPZ.js";
32
- import "./chunk-PSO7R5AD.js";
30
+ } from "./chunk-BQHKN7JI.js";
31
+ import "./chunk-RMDW3OQ6.js";
32
+ import "./chunk-ZKMSTD6G.js";
33
+ import "./chunk-PZC2Q6MJ.js";
33
34
  import {
34
35
  bccliHome,
35
36
  loadConfig
36
- } from "./chunk-M7LLJQ7M.js";
37
- import "./chunk-M23QBX3V.js";
37
+ } from "./chunk-GIGWZFCY.js";
38
+ import "./chunk-QHNWI3OT.js";
38
39
 
39
40
  // src/serve.ts
40
41
  import { randomBytes } from "crypto";
@@ -3,15 +3,15 @@ import {
3
3
  createFetchTool,
4
4
  createWebSearchTool,
5
5
  isPrivateHost
6
- } from "./chunk-HE33XAPZ.js";
6
+ } from "./chunk-NVRNFR4S.js";
7
7
  import "./chunk-PSO7R5AD.js";
8
8
  import {
9
9
  loadConfig,
10
10
  readCredentials
11
- } from "./chunk-M7LLJQ7M.js";
11
+ } from "./chunk-GIGWZFCY.js";
12
12
  import {
13
13
  t
14
- } from "./chunk-M23QBX3V.js";
14
+ } from "./chunk-QHNWI3OT.js";
15
15
 
16
16
  // src/mcpServer/serve.ts
17
17
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Session,
4
+ pruneSessions
5
+ } from "./chunk-BQHKN7JI.js";
6
+ import "./chunk-RMDW3OQ6.js";
7
+ import "./chunk-ZKMSTD6G.js";
8
+ import "./chunk-QHNWI3OT.js";
9
+ export {
10
+ Session,
11
+ pruneSessions
12
+ };
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createRuntime,
4
+ lunaPtcAutoEnabled
5
+ } from "./chunk-ZGH4B7OU.js";
6
+ import "./chunk-U6PCNS4B.js";
7
+ import "./chunk-PSRNKKGA.js";
8
+ import "./chunk-NVRNFR4S.js";
9
+ import "./chunk-PSO7R5AD.js";
10
+ import "./chunk-GAFJEQTJ.js";
11
+ import "./chunk-2ON3WIDP.js";
12
+ import "./chunk-25DSN3Y3.js";
13
+ import "./chunk-VO6MF6JJ.js";
14
+ import "./chunk-7F3IWBPQ.js";
15
+ import "./chunk-BQHKN7JI.js";
16
+ import "./chunk-RMDW3OQ6.js";
17
+ import "./chunk-ZKMSTD6G.js";
18
+ import "./chunk-PZC2Q6MJ.js";
19
+ import "./chunk-GIGWZFCY.js";
20
+ import "./chunk-QHNWI3OT.js";
21
+ export {
22
+ createRuntime,
23
+ lunaPtcAutoEnabled
24
+ };
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ estimateTokens
4
+ } from "./chunk-U6PCNS4B.js";
5
+ import {
6
+ t
7
+ } from "./chunk-QHNWI3OT.js";
8
+
9
+ // src/statsCli.ts
10
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs";
11
+ import { join } from "path";
12
+ function isUsageRecord(value) {
13
+ if (!value || typeof value !== "object") return false;
14
+ const v = value;
15
+ return v.t === "usage" && typeof v.inputTokens === "number" && typeof v.outputTokens === "number";
16
+ }
17
+ function aggregateSessions(home, opts) {
18
+ const now = opts.now ?? Date.now();
19
+ const cutoff = now - opts.days * 864e5;
20
+ const root = join(home, "sessions");
21
+ if (!existsSync(root)) return [];
22
+ const byProject = /* @__PURE__ */ new Map();
23
+ for (const project of readdirSync(root)) {
24
+ const dir = join(root, project);
25
+ let st;
26
+ try {
27
+ st = statSync(dir);
28
+ } catch {
29
+ continue;
30
+ }
31
+ if (!st.isDirectory()) continue;
32
+ for (const file of readdirSync(dir)) {
33
+ if (!file.endsWith(".jsonl")) continue;
34
+ const path = join(dir, file);
35
+ let fst;
36
+ try {
37
+ fst = statSync(path);
38
+ } catch {
39
+ continue;
40
+ }
41
+ if (fst.mtimeMs < cutoff) continue;
42
+ let row = byProject.get(project);
43
+ if (!row) {
44
+ row = { project, sessions: 0, messages: 0, inputTokens: 0, outputTokens: 0, usageInputTokens: 0, usageOutputTokens: 0 };
45
+ byProject.set(project, row);
46
+ }
47
+ row.sessions++;
48
+ for (const line of readFileSync(path, "utf8").split("\n")) {
49
+ if (!line.trim()) continue;
50
+ let record;
51
+ try {
52
+ record = JSON.parse(line);
53
+ } catch {
54
+ continue;
55
+ }
56
+ if (isUsageRecord(record)) {
57
+ row.usageInputTokens += record.inputTokens;
58
+ row.usageOutputTokens += record.outputTokens;
59
+ continue;
60
+ }
61
+ const r = record;
62
+ if (r?.t !== "msg" || !r.m) continue;
63
+ row.messages++;
64
+ const text = typeof r.m.content === "string" ? r.m.content : JSON.stringify(r.m.content ?? "");
65
+ const tokens = estimateTokens(text);
66
+ if (r.m.role === "user") row.inputTokens += tokens;
67
+ else if (r.m.role === "assistant") row.outputTokens += tokens;
68
+ }
69
+ }
70
+ }
71
+ return [...byProject.values()].sort((a, b) => b.messages - a.messages || a.project.localeCompare(b.project));
72
+ }
73
+ function runStatsCommand(args, deps) {
74
+ let days = 7;
75
+ const rest = args.subArgs;
76
+ for (let i = 0; i < rest.length; i++) {
77
+ if (rest[i] === "--days") {
78
+ const raw = rest[++i];
79
+ const n = Number(raw);
80
+ if (!Number.isInteger(n) || n < 1) {
81
+ deps.err?.(t("--days must be a positive integer"));
82
+ return 1;
83
+ }
84
+ days = n;
85
+ } else if (rest[i].startsWith("--days=")) {
86
+ const n = Number(rest[i].slice("--days=".length));
87
+ if (!Number.isInteger(n) || n < 1) {
88
+ deps.err?.(t("--days must be a positive integer"));
89
+ return 1;
90
+ }
91
+ days = n;
92
+ }
93
+ }
94
+ const rows = aggregateSessions(args.home, { days, now: args.now });
95
+ if (!rows.length) {
96
+ deps.out(t("no sessions in the last {days} day(s)", { days: String(days) }));
97
+ return 0;
98
+ }
99
+ deps.out(t("sessions (last {days} day(s)):", { days: String(days) }));
100
+ for (const r of rows) {
101
+ const usage = r.usageInputTokens + r.usageOutputTokens > 0 ? ` ${t("recorded")}: ${r.usageInputTokens}in/${r.usageOutputTokens}out` : "";
102
+ deps.out(`${r.project} ${r.sessions} ${t("session(s)")} ${r.messages} ${t("message(s)")} ~${r.inputTokens}in/~${r.outputTokens}out${usage}`);
103
+ }
104
+ return 0;
105
+ }
106
+ export {
107
+ aggregateSessions,
108
+ runStatsCommand
109
+ };