@botconnector/bccli 0.4.0-beta.5 → 0.4.0-beta.51

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 (58) hide show
  1. package/README.md +97 -2
  2. package/dist/acp-NWP4FFTG.js +182 -0
  3. package/dist/args-2R45YZ42.js +13 -0
  4. package/dist/{chunk-U7DLMVPZ.js → chunk-2QYHSESB.js} +2 -1
  5. package/dist/{chunk-UESQNU4A.js → chunk-4WVIPZFV.js} +14 -9
  6. package/dist/chunk-7F3IWBPQ.js +191 -0
  7. package/dist/chunk-DP7EBW53.js +341 -0
  8. package/dist/{chunk-SJH3YLW4.js → chunk-F6ACN47V.js} +60 -6
  9. package/dist/chunk-FTFVW7XD.js +235 -0
  10. package/dist/{chunk-ELML4KVQ.js → chunk-GAFJEQTJ.js} +32 -2
  11. package/dist/{chunk-NGLKANMD.js → chunk-H73FO5YK.js} +24 -2
  12. package/dist/chunk-KD2LMIS4.js +145 -0
  13. package/dist/chunk-KIZC5XV4.js +2141 -0
  14. package/dist/chunk-N7KP6RNP.js +76 -0
  15. package/dist/chunk-NDEJUL44.js +361 -0
  16. package/dist/chunk-PSO7R5AD.js +10 -0
  17. package/dist/chunk-QXOV4DUZ.js +56 -0
  18. package/dist/chunk-QZKLZELZ.js +64 -0
  19. package/dist/chunk-R4BJBTWC.js +940 -0
  20. package/dist/chunk-SNKVS26H.js +63 -0
  21. package/dist/chunk-TQWCM5RO.js +231 -0
  22. package/dist/chunk-VU5HNQHX.js +8 -0
  23. package/dist/chunk-XLC6T4SX.js +500 -0
  24. package/dist/chunk-YIYX3FFS.js +733 -0
  25. package/dist/cli.js +157 -1281
  26. package/dist/completion-OV3MW2N4.js +125 -0
  27. package/dist/{config-NPSYFAFD.js → config-AZZFOXKV.js} +5 -2
  28. package/dist/config-H5A7XHHK.js +30 -0
  29. package/dist/ghBotCli-7WDYF4L7.js +677 -0
  30. package/dist/integrationCli-ZMTSILYF.js +685 -0
  31. package/dist/login-W4Y6WHLV.js +16 -0
  32. package/dist/{mcpCli-Q2H63ISP.js → mcpCli-5QISTOFK.js} +42 -9
  33. package/dist/modelsCli-FZMBD4OE.js +36 -0
  34. package/dist/npmRunner-LU43GM3W.js +46 -0
  35. package/dist/oauthLogin-VESMXG4M.js +210 -0
  36. package/dist/pluginsCli-GEHR7FQR.js +284 -0
  37. package/dist/prCli-JXA7DJW4.js +72 -0
  38. package/dist/providerCli-EUZGKP5F.js +15 -0
  39. package/dist/sdk.js +5486 -0
  40. package/dist/serve-6KX4MXHC.js +178 -0
  41. package/dist/serve-YSUJD57D.js +515 -0
  42. package/dist/session-F6MG3UCU.js +12 -0
  43. package/dist/setup-LLWREJQH.js +24 -0
  44. package/dist/statsCli-H4HEY5ID.js +353 -0
  45. package/dist/transferCli-2XUKBG2L.js +71 -0
  46. package/dist/ui-6HJVYI46.js +2370 -0
  47. package/dist/update-O4WCLKOO.js +109 -0
  48. package/package.json +24 -3
  49. package/dist/args-FCLPQ7TO.js +0 -11
  50. package/dist/chunk-5O4HD7IU.js +0 -253
  51. package/dist/chunk-C5AFWX7H.js +0 -328
  52. package/dist/chunk-GW36UMHZ.js +0 -52
  53. package/dist/chunk-RZUJYAQV.js +0 -112
  54. package/dist/chunk-UN7QXPCB.js +0 -82
  55. package/dist/login-F4G5QXOU.js +0 -9
  56. package/dist/providerCli-MXV6PD6F.js +0 -11
  57. package/dist/session-7UB77CEG.js +0 -9
  58. package/dist/ui-RYTSKEIA.js +0 -1344
@@ -1,328 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- hasKey,
4
- providerName,
5
- removeGlobalProvider,
6
- writeGlobalConfig
7
- } from "./chunk-U7DLMVPZ.js";
8
- import {
9
- PRESETS,
10
- loadConfig,
11
- readCredentials,
12
- saveCredential
13
- } from "./chunk-RZUJYAQV.js";
14
-
15
- // src/thinking.ts
16
- var OPEN = "<think>";
17
- var CLOSE = "</think>";
18
- function partialTag(text, tag) {
19
- for (let n = Math.min(tag.length - 1, text.length); n > 0; n--) if (tag.startsWith(text.slice(-n))) return n;
20
- return 0;
21
- }
22
- var ThinkSplitter = class {
23
- inside = false;
24
- held = "";
25
- push(delta) {
26
- let rest = this.held + delta;
27
- this.held = "";
28
- let text = "";
29
- let thinking = "";
30
- while (rest) {
31
- const tag = this.inside ? CLOSE : OPEN;
32
- const at = rest.indexOf(tag);
33
- if (at >= 0) {
34
- if (this.inside) thinking += rest.slice(0, at);
35
- else text += rest.slice(0, at);
36
- rest = rest.slice(at + tag.length);
37
- this.inside = !this.inside;
38
- continue;
39
- }
40
- const keep = partialTag(rest, tag);
41
- const out = rest.slice(0, rest.length - keep);
42
- if (this.inside) thinking += out;
43
- else text += out;
44
- this.held = rest.slice(rest.length - keep);
45
- break;
46
- }
47
- return { text, thinking };
48
- }
49
- /** Whatever was held back as a possible tag start is plain text after all. */
50
- flush() {
51
- const held = this.held;
52
- this.held = "";
53
- return this.inside ? { text: "", thinking: held } : { text: held, thinking: "" };
54
- }
55
- };
56
- function splitThinking(text) {
57
- const s = new ThinkSplitter();
58
- const a = s.push(text);
59
- const b = s.flush();
60
- return { text: a.text + b.text, thinking: a.thinking + b.thinking };
61
- }
62
-
63
- // src/provider.ts
64
- var ProviderError = class extends Error {
65
- constructor(message, status) {
66
- super(message);
67
- this.status = status;
68
- }
69
- status;
70
- };
71
- var retryable = (status) => status === 429 || status >= 500;
72
- function detectRepetition(text) {
73
- const tail = text.slice(-600);
74
- for (let len = 1; len <= 12; len++) {
75
- const unit = tail.slice(-len);
76
- if (unit.length < len || !unit.trim()) continue;
77
- let i = tail.length;
78
- let count = 0;
79
- while (i >= len && tail.slice(i - len, i) === unit) {
80
- count++;
81
- i -= len;
82
- }
83
- if (count >= 20 && count * len >= 300) return text.length - count * len;
84
- }
85
- return -1;
86
- }
87
- function sleep(ms, signal) {
88
- return new Promise((resolve, reject) => {
89
- const timer = setTimeout(resolve, ms);
90
- signal?.addEventListener(
91
- "abort",
92
- () => {
93
- clearTimeout(timer);
94
- reject(signal.reason);
95
- },
96
- { once: true }
97
- );
98
- });
99
- }
100
- function errorMessage(body) {
101
- try {
102
- const parsed = JSON.parse(body);
103
- return parsed?.error?.message ?? parsed?.message ?? body.slice(0, 300);
104
- } catch {
105
- return body.slice(0, 300);
106
- }
107
- }
108
- var toUsage = (u) => u ? { inputTokens: u.prompt_tokens ?? 0, outputTokens: u.completion_tokens ?? 0 } : void 0;
109
- async function readStream(res, onText, onThinking) {
110
- let text = "";
111
- let thinking = "";
112
- const splitter = new ThinkSplitter();
113
- const emit = (part) => {
114
- if (part.thinking) {
115
- thinking += part.thinking;
116
- onThinking?.(part.thinking);
117
- }
118
- if (part.text) {
119
- text += part.text;
120
- onText?.(part.text);
121
- if (loopAt < 0) loopAt = detectRepetition(text);
122
- }
123
- };
124
- let usage;
125
- let finishReason;
126
- const calls = [];
127
- const byIndex = /* @__PURE__ */ new Map();
128
- let current;
129
- const decoder = new TextDecoder();
130
- let buffer = "";
131
- let loopAt = -1;
132
- const handle = (line) => {
133
- if (!line.startsWith("data:")) return;
134
- const data = line.slice(5).trim();
135
- if (!data || data === "[DONE]") return;
136
- let event;
137
- try {
138
- event = JSON.parse(data);
139
- } catch {
140
- return;
141
- }
142
- if (event.error) throw new ProviderError(`Error dari provider: ${event.error.message ?? JSON.stringify(event.error)}`);
143
- if (event.usage) usage = toUsage(event.usage);
144
- const choice = event.choices?.[0];
145
- if (!choice) return;
146
- if (choice.finish_reason) finishReason = choice.finish_reason;
147
- const delta = choice.delta ?? {};
148
- const reasoning = delta.reasoning_content || delta.reasoning;
149
- if (reasoning) emit({ text: "", thinking: reasoning });
150
- if (delta.content) emit(splitter.push(delta.content));
151
- for (const tc of delta.tool_calls ?? []) {
152
- let target = tc.index !== void 0 ? byIndex.get(tc.index) : current;
153
- if (!target || tc.index === void 0 && tc.id && target.id && target.id !== tc.id) {
154
- target = { id: "", name: "", arguments: "" };
155
- calls.push(target);
156
- if (tc.index !== void 0) byIndex.set(tc.index, target);
157
- }
158
- current = target;
159
- if (tc.id) target.id = tc.id;
160
- if (tc.function?.name && !target.name) target.name = tc.function.name;
161
- if (tc.function?.arguments) target.arguments += tc.function.arguments;
162
- }
163
- };
164
- for await (const chunk of res.body) {
165
- buffer += decoder.decode(chunk, { stream: true });
166
- let newline = buffer.indexOf("\n");
167
- while (newline >= 0 && loopAt < 0) {
168
- handle(buffer.slice(0, newline).trim());
169
- buffer = buffer.slice(newline + 1);
170
- newline = buffer.indexOf("\n");
171
- }
172
- if (loopAt >= 0) return { text: text.slice(0, loopAt), toolCalls: [], thinking: thinking || void 0, usage, finishReason: "repetition" };
173
- }
174
- handle(buffer.trim());
175
- emit(splitter.flush());
176
- const toolCalls = calls.map((call, index) => ({ ...call, id: call.id || `call_${index}` }));
177
- return { text, toolCalls, thinking: thinking || void 0, usage, finishReason };
178
- }
179
- async function readJson(res) {
180
- const body = await res.json();
181
- const choice = body.choices?.[0];
182
- const toolCalls = (choice?.message?.tool_calls ?? []).map((tc, i) => ({
183
- id: tc.id || `call_${i}`,
184
- name: tc.function?.name ?? "",
185
- arguments: tc.function?.arguments ?? ""
186
- }));
187
- const split = splitThinking(choice?.message?.content ?? "");
188
- const thinking = (choice?.message?.reasoning_content || choice?.message?.reasoning || "") + split.thinking;
189
- return { text: split.text, toolCalls, thinking: thinking || void 0, usage: toUsage(body.usage), finishReason: choice?.finish_reason };
190
- }
191
- function createProvider({ baseURL, apiKey, model, fetch: doFetch = fetch, retryDelayMs = 1e3 }) {
192
- const headers = { "content-type": "application/json" };
193
- if (apiKey) headers.authorization = `Bearer ${apiKey}`;
194
- async function post(path, body, signal) {
195
- let lastError;
196
- for (let attempt = 0; attempt < 4; attempt++) {
197
- if (attempt > 0) await sleep(retryDelayMs * 2 ** (attempt - 1), signal);
198
- let res;
199
- try {
200
- res = await doFetch(`${baseURL}${path}`, { method: "POST", headers, body: JSON.stringify(body), signal });
201
- } catch (error) {
202
- if (signal?.aborted) throw error;
203
- lastError = new ProviderError(`Tidak bisa terhubung ke ${baseURL}: ${error.message}`);
204
- continue;
205
- }
206
- if (res.ok) return res;
207
- const text = await res.text().catch(() => "");
208
- lastError = new ProviderError(`${res.status} dari ${baseURL}: ${errorMessage(text)}`, res.status);
209
- if (!retryable(res.status)) throw lastError;
210
- }
211
- throw lastError ?? new ProviderError("Permintaan gagal");
212
- }
213
- return {
214
- async chat({ messages, tools, signal, onText, onThinking }) {
215
- const res = await post(
216
- "/chat/completions",
217
- { model, messages, stream: true, stream_options: { include_usage: true }, ...tools?.length ? { tools } : {} },
218
- signal
219
- );
220
- if ((res.headers.get("content-type") ?? "").includes("application/json")) return readJson(res);
221
- if (!res.body) throw new ProviderError("Respons provider kosong");
222
- return readStream(res, onText, onThinking);
223
- },
224
- async listModels() {
225
- const res = await doFetch(`${baseURL}/models`, { headers });
226
- if (!res.ok) throw new ProviderError(`${res.status} saat mengambil daftar model`, res.status);
227
- const body = await res.json();
228
- return (body.data ?? []).map((m) => m.id).sort();
229
- }
230
- };
231
- }
232
-
233
- // src/models.ts
234
- function order(ids) {
235
- const presetIds = PRESETS.map((p) => p.id);
236
- const presets = presetIds.filter((id) => ids.includes(id));
237
- const custom = ids.filter((id) => !presetIds.includes(id)).sort();
238
- return [...presets, ...custom];
239
- }
240
- async function listAllModels(config, env = process.env, opts = {}) {
241
- const timeoutMs = opts.timeoutMs ?? 5e3;
242
- const baseFetch = opts.fetch ?? fetch;
243
- const untrusted = new Set(config.projectProviders ?? []);
244
- const ids = order(Object.keys(config.providers)).filter((id) => opts.only ? id === opts.only : !untrusted.has(id) && hasKey(config, id, env));
245
- const results = await Promise.all(
246
- ids.map(async (id) => {
247
- const provider = config.providers[id];
248
- const apiKey = (opts.keyOverride && id === opts.only ? opts.keyOverride : void 0) || (provider.apiKeyEnv ? env[provider.apiKeyEnv] : void 0) || readCredentials(env)[id] || void 0;
249
- const local = !provider.apiKeyEnv;
250
- const timedFetch = ((input, init) => baseFetch(input, { ...init, signal: AbortSignal.timeout(timeoutMs) }));
251
- const list = createProvider({ baseURL: provider.baseURL.replace(/\/+$/, ""), apiKey, model: "", fetch: timedFetch }).listModels();
252
- let timer;
253
- const timeout = new Promise((_, reject) => {
254
- timer = setTimeout(() => reject(new Error("timeout")), timeoutMs);
255
- });
256
- try {
257
- const models = await Promise.race([list, timeout]);
258
- return { providerId: id, providerName: providerName(config, id), models };
259
- } catch {
260
- if (local && !opts.only) return void 0;
261
- return { providerId: id, providerName: providerName(config, id), models: [], error: "tidak bisa dihubungi" };
262
- } finally {
263
- clearTimeout(timer);
264
- }
265
- })
266
- );
267
- return results.filter((g) => !!g);
268
- }
269
-
270
- // src/providerCli.ts
271
- async function addProviderKey(providerId, key, deps) {
272
- const config = loadConfig(deps.cwd, deps.env);
273
- const [group] = await listAllModels(config, deps.env, { only: providerId, fetch: deps.fetch, keyOverride: key || void 0 });
274
- if (!group || group.error) return { ok: false, error: `API key ditolak atau ${providerName(config, providerId)} tidak bisa dihubungi.` };
275
- if (key) saveCredential(providerId, key, deps.env);
276
- return { ok: true, models: group.models.length };
277
- }
278
- async function runProviderCommand(args, deps) {
279
- const [action = "list", id] = args.subArgs;
280
- const config = loadConfig(deps.cwd, deps.env);
281
- if (action === "list") {
282
- for (const pid of Object.keys(config.providers)) {
283
- const mark = hasKey(config, pid, deps.env) ? "\u2713" : "\u25CB";
284
- deps.out(`${mark} ${pid.padEnd(14)} ${providerName(config, pid).padEnd(20)} ${config.providers[pid].baseURL}`);
285
- }
286
- return 0;
287
- }
288
- if (!id) {
289
- deps.err(`Pemakaian: bccli provider ${action} <id>`);
290
- return 1;
291
- }
292
- if (action === "remove") {
293
- removeGlobalProvider(id, deps.env);
294
- deps.out(`${id} dihapus.`);
295
- return 0;
296
- }
297
- if (action !== "add") {
298
- deps.err(`Aksi tidak dikenal: ${action}. Pakai list, add, atau remove.`);
299
- return 1;
300
- }
301
- const preset = PRESETS.find((p) => p.id === id);
302
- if (!preset && !config.providers[id]) {
303
- if (!args.url) {
304
- deps.err(`${id} bukan preset. Untuk provider custom tambahkan --url <base URL OpenAI-compatible>.`);
305
- return 1;
306
- }
307
- writeGlobalConfig(
308
- { providers: { [id]: { baseURL: args.url, ...args.name ? { name: args.name } : {}, ...args.keyEnv ? { apiKeyEnv: args.keyEnv } : {} } } },
309
- deps.env
310
- );
311
- }
312
- const needsKey = !!loadConfig(deps.cwd, deps.env).providers[id].apiKeyEnv || !preset;
313
- const key = needsKey ? await deps.readSecret(`API key untuk ${id} (kosongkan bila tidak perlu): `) : "";
314
- const result = await addProviderKey(id, key, deps);
315
- if (!result.ok) {
316
- deps.err(result.error);
317
- return 1;
318
- }
319
- deps.out(`${id} siap. ${result.models} model tersedia.`);
320
- return 0;
321
- }
322
-
323
- export {
324
- createProvider,
325
- listAllModels,
326
- addProviderKey,
327
- runProviderCommand
328
- };
@@ -1,52 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/login.ts
4
- function readSecret(prompt) {
5
- return new Promise((resolve) => {
6
- process.stdout.write(prompt);
7
- const stdin = process.stdin;
8
- if (!stdin.isTTY) {
9
- let data = "";
10
- stdin.on("data", (d) => {
11
- data += d;
12
- });
13
- stdin.on("end", () => resolve(data.trim()));
14
- return;
15
- }
16
- let value = "";
17
- stdin.setRawMode(true);
18
- stdin.resume();
19
- const onData = (buffer) => {
20
- for (const ch of buffer.toString()) {
21
- if (ch === "\r" || ch === "\n") {
22
- stdin.setRawMode(false);
23
- stdin.pause();
24
- stdin.off("data", onData);
25
- process.stdout.write("\n");
26
- resolve(value.trim());
27
- return;
28
- }
29
- if (ch === "") process.exit(130);
30
- if (ch === "\x7F" || ch === "\b") value = value.slice(0, -1);
31
- else value += ch;
32
- }
33
- };
34
- stdin.on("data", onData);
35
- });
36
- }
37
- async function runLogin(providerId, cwd) {
38
- const { runProviderCommand } = await import("./providerCli-MXV6PD6F.js");
39
- const { parseCliArgs } = await import("./args-FCLPQ7TO.js");
40
- return runProviderCommand(parseCliArgs(["provider", "add", providerId]), {
41
- env: process.env,
42
- cwd,
43
- out: (s) => console.log(s),
44
- err: (s) => console.error(s),
45
- readSecret
46
- });
47
- }
48
-
49
- export {
50
- readSecret,
51
- runLogin
52
- };
@@ -1,112 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/presets.ts
4
- var PRESETS = [
5
- { id: "bc-cloud", name: "BotConnector Cloud", baseURL: "https://api.botconnector.id/v1", apiKeyEnv: "BOTCONNECTOR_API_KEY" },
6
- { id: "openrouter", name: "OpenRouter", baseURL: "https://openrouter.ai/api/v1", apiKeyEnv: "OPENROUTER_API_KEY" },
7
- { id: "openai", name: "OpenAI", baseURL: "https://api.openai.com/v1", apiKeyEnv: "OPENAI_API_KEY" },
8
- { id: "gemini", name: "Google Gemini", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", apiKeyEnv: "GEMINI_API_KEY" },
9
- { id: "deepseek", name: "DeepSeek", baseURL: "https://api.deepseek.com/v1", apiKeyEnv: "DEEPSEEK_API_KEY" },
10
- { id: "groq", name: "Groq", baseURL: "https://api.groq.com/openai/v1", apiKeyEnv: "GROQ_API_KEY" },
11
- { id: "ollama-cloud", name: "Ollama Cloud", baseURL: "https://ollama.com/v1", apiKeyEnv: "OLLAMA_API_KEY" },
12
- { id: "ollama", name: "Ollama lokal", baseURL: "http://127.0.0.1:11434/v1", local: true },
13
- { id: "lmstudio", name: "LM Studio lokal", baseURL: "http://127.0.0.1:1234/v1", local: true }
14
- ];
15
-
16
- // src/config.ts
17
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
18
- import { homedir } from "os";
19
- import { join } from "path";
20
- var ConfigError = class extends Error {
21
- };
22
- var DEFAULT_CONFIG = {
23
- model: "bc-cloud/glm-5.3-flash",
24
- permissionMode: "default",
25
- providers: Object.fromEntries(PRESETS.map((p) => [p.id, { baseURL: p.baseURL, apiKeyEnv: p.apiKeyEnv }])),
26
- allow: []
27
- };
28
- function bccliHome(env = process.env) {
29
- return env.BCCLI_HOME ?? join(homedir(), ".bccli");
30
- }
31
- function readJsonConfig(path) {
32
- if (!existsSync(path)) return {};
33
- try {
34
- return JSON.parse(readFileSync(path, "utf8"));
35
- } catch (error) {
36
- throw new ConfigError(`Config tidak valid: ${path} (${error.message})`);
37
- }
38
- }
39
- function untrustedProviders(project, known) {
40
- const out = {};
41
- for (const [id, provider] of Object.entries(project.providers ?? {})) {
42
- if (known[id] || typeof provider?.baseURL !== "string") continue;
43
- out[id] = { baseURL: provider.baseURL };
44
- }
45
- return out;
46
- }
47
- function loadConfig(cwd, env = process.env) {
48
- const global = readJsonConfig(join(bccliHome(env), "config.json"));
49
- const project = readJsonConfig(join(cwd, ".bccli", "config.json"));
50
- const known = { ...DEFAULT_CONFIG.providers, ...global.providers };
51
- const fromProject = untrustedProviders(project, known);
52
- return {
53
- model: project.model ?? global.model ?? DEFAULT_CONFIG.model,
54
- permissionMode: global.permissionMode ?? DEFAULT_CONFIG.permissionMode,
55
- providers: { ...known, ...fromProject },
56
- projectProviders: Object.keys(fromProject),
57
- allow: [...global.allow ?? []]
58
- };
59
- }
60
- function readCredentials(env = process.env) {
61
- const path = join(bccliHome(env), "credentials");
62
- if (!existsSync(path)) return {};
63
- try {
64
- return JSON.parse(readFileSync(path, "utf8"));
65
- } catch {
66
- return {};
67
- }
68
- }
69
- function saveCredential(providerId, key, env = process.env) {
70
- const home = bccliHome(env);
71
- mkdirSync(home, { recursive: true });
72
- const path = join(home, "credentials");
73
- writeFileSync(path, JSON.stringify({ ...readCredentials(env), [providerId]: key }, null, 2), { mode: 384 });
74
- chmodSync(path, 384);
75
- }
76
- function resolveModel(config, modelRef, env = process.env) {
77
- const slash = modelRef.indexOf("/");
78
- if (slash <= 0 || slash === modelRef.length - 1) {
79
- throw new ConfigError(`Model harus berformat provider/model, contoh bc-cloud/glm-5.3-flash (dapat: ${modelRef})`);
80
- }
81
- const providerId = modelRef.slice(0, slash);
82
- const provider = config.providers[providerId];
83
- if (!provider) {
84
- throw new ConfigError(`Provider "${providerId}" tidak ada di config. Tersedia: ${Object.keys(config.providers).join(", ")}`);
85
- }
86
- const apiKey = (provider.apiKeyEnv ? env[provider.apiKeyEnv] : void 0) || readCredentials(env)[providerId] || void 0;
87
- if (provider.apiKeyEnv && !apiKey) {
88
- throw new ConfigError(`API key untuk ${providerId} belum ada. Jalankan \`bccli login\` atau set env ${provider.apiKeyEnv}.`);
89
- }
90
- return { providerId, model: modelRef.slice(slash + 1), baseURL: provider.baseURL.replace(/\/+$/, ""), apiKey };
91
- }
92
- function removeCredential(providerId, env = process.env) {
93
- const creds = readCredentials(env);
94
- if (!(providerId in creds)) return false;
95
- delete creds[providerId];
96
- const path = join(bccliHome(env), "credentials");
97
- writeFileSync(path, JSON.stringify(creds, null, 2), { mode: 384 });
98
- chmodSync(path, 384);
99
- return true;
100
- }
101
-
102
- export {
103
- PRESETS,
104
- ConfigError,
105
- bccliHome,
106
- readJsonConfig,
107
- loadConfig,
108
- readCredentials,
109
- saveCredential,
110
- resolveModel,
111
- removeCredential
112
- };
@@ -1,82 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- MODE_ORDER
4
- } from "./chunk-ELML4KVQ.js";
5
- import {
6
- ConfigError
7
- } from "./chunk-RZUJYAQV.js";
8
-
9
- // src/args.ts
10
- import { parseArgs } from "util";
11
- var HELP_TEXT = `BCCLI \u2014 agent AI BotConnector di terminal
12
-
13
- Pemakaian:
14
- bccli [tugas] mode interaktif (opsional langsung dengan tugas)
15
- bccli -p "tugas" jalankan satu tugas tanpa interaksi (skrip/CI)
16
- bccli login [provider] simpan API key (default: bc-cloud)
17
- bccli models daftar model dari provider aktif
18
- bccli provider list|add <id>|remove <id> kelola provider (custom: --url <url> [--name N] [--key-env ENV])
19
- bccli mcp list|add <nama>|remove <nama> kelola server MCP (katalog, atau --url <url>)
20
-
21
- Opsi:
22
- -m, --model <provider/model> pilih model, contoh bc-cloud/glm-5.3-flash
23
- -c, --continue lanjutkan sesi terakhir di folder ini
24
- -r, --resume pilih sesi untuk dilanjutkan
25
- --allow-all jalankan semua alat tanpa minta izin
26
- --allowed-tools <a,b> alat yang boleh tanpa izin: bash, edit, fetch
27
- --permission-mode <mode> default | acceptEdits | plan | allowAll
28
- -v, --version versi
29
- -h, --help bantuan ini`;
30
- function parseCliArgs(argv) {
31
- const { values, positionals } = parseArgs({
32
- args: argv,
33
- allowPositionals: true,
34
- options: {
35
- print: { type: "boolean", short: "p" },
36
- model: { type: "string", short: "m" },
37
- continue: { type: "boolean", short: "c" },
38
- resume: { type: "boolean", short: "r" },
39
- "allow-all": { type: "boolean" },
40
- "allowed-tools": { type: "string" },
41
- "permission-mode": { type: "string" },
42
- help: { type: "boolean", short: "h" },
43
- version: { type: "boolean", short: "v" },
44
- url: { type: "string" },
45
- name: { type: "string" },
46
- "key-env": { type: "string" },
47
- value: { type: "string", multiple: true }
48
- }
49
- });
50
- const mode = values["permission-mode"];
51
- if (mode && !MODE_ORDER.includes(mode)) {
52
- throw new ConfigError(`--permission-mode harus salah satu dari: ${MODE_ORDER.join(", ")}`);
53
- }
54
- const [first, ...rest] = positionals;
55
- const SUBCOMMANDS = ["login", "models", "provider", "mcp"];
56
- const command = SUBCOMMANDS.includes(first) ? first : "run";
57
- const words = command === "run" ? positionals : rest;
58
- return {
59
- command,
60
- prompt: command === "run" && words.length ? words.join(" ") : void 0,
61
- print: !!values.print,
62
- model: values.model,
63
- continue: !!values.continue,
64
- resume: !!values.resume,
65
- allowAll: !!values["allow-all"],
66
- allowedTools: (values["allowed-tools"] ?? "").split(",").map((s) => s.trim()).filter(Boolean),
67
- permissionMode: mode,
68
- help: !!values.help,
69
- version: !!values.version,
70
- loginProvider: command === "login" ? rest[0] ?? "bc-cloud" : void 0,
71
- subArgs: command === "provider" || command === "mcp" ? rest : [],
72
- url: values.url,
73
- name: values.name,
74
- keyEnv: values["key-env"],
75
- values: values.value ?? []
76
- };
77
- }
78
-
79
- export {
80
- HELP_TEXT,
81
- parseCliArgs
82
- };
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- readSecret,
4
- runLogin
5
- } from "./chunk-GW36UMHZ.js";
6
- export {
7
- readSecret,
8
- runLogin
9
- };
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- addProviderKey,
4
- runProviderCommand
5
- } from "./chunk-C5AFWX7H.js";
6
- import "./chunk-U7DLMVPZ.js";
7
- import "./chunk-RZUJYAQV.js";
8
- export {
9
- addProviderKey,
10
- runProviderCommand
11
- };
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- Session,
4
- pruneSessions
5
- } from "./chunk-SJH3YLW4.js";
6
- export {
7
- Session,
8
- pruneSessions
9
- };