@botconnector/bccli 0.4.0-beta.3 → 0.4.0-beta.30
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 +71 -1
- package/dist/args-XQYEBOKB.js +12 -0
- package/dist/{chunk-OSWQPSA4.js → chunk-22CEHQVR.js} +44 -4
- package/dist/{chunk-NGLKANMD.js → chunk-44MXWCFN.js} +4 -3
- package/dist/{chunk-UESQNU4A.js → chunk-BEXQSEBI.js} +11 -10
- package/dist/{chunk-L7L4RGKG.js → chunk-DJR4EAVL.js} +2 -2
- package/dist/chunk-EO7IVVX4.js +443 -0
- package/dist/{chunk-U7DLMVPZ.js → chunk-K5JNR3HL.js} +2 -1
- package/dist/chunk-ON6JYPE7.js +103 -0
- package/dist/chunk-SN3ODJZN.js +63 -0
- package/dist/chunk-WWQVALA5.js +952 -0
- package/dist/cli.js +657 -233
- package/dist/{config-NPSYFAFD.js → config-PBEZ3IGD.js} +2 -2
- package/dist/integrationCli-ZTZSZLO7.js +586 -0
- package/dist/{login-KHU7ONSR.js → login-HUPT4247.js} +1 -1
- package/dist/{mcpCli-Q2H63ISP.js → mcpCli-J43FHF2H.js} +11 -10
- package/dist/providerCli-II7TQDYQ.js +12 -0
- package/dist/{ui-A32PTF4F.js → ui-HO3Z5LYD.js} +792 -238
- package/package.json +20 -3
- package/dist/args-FCLPQ7TO.js +0 -11
- package/dist/chunk-2JBRLGKD.js +0 -266
- package/dist/chunk-RZUJYAQV.js +0 -112
- package/dist/chunk-UN7QXPCB.js +0 -82
- package/dist/providerCli-G3X7KENO.js +0 -11
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Agent AI coding dari BotConnector yang bekerja di terminal: membaca kode, menged
|
|
|
4
4
|
dan menjalankan perintah — dengan izin kamu.
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
|
-
npm i -g @botconnector/bccli@next #
|
|
7
|
+
npm i -g @botconnector/bccli@next # beta terbaru, butuh Node.js 22+
|
|
8
8
|
bccli login # simpan API key BotConnector Cloud
|
|
9
9
|
cd project-kamu && bccli
|
|
10
10
|
```
|
|
@@ -17,6 +17,7 @@ cd project-kamu && bccli
|
|
|
17
17
|
| `bccli -p "tugas"` | satu tugas tanpa interaksi (skrip/CI) |
|
|
18
18
|
| `bccli -c` / `bccli -r` | lanjutkan sesi terakhir / pilih sesi |
|
|
19
19
|
| `bccli -m provider/model` | pilih model |
|
|
20
|
+
| `bccli --reasoning <auto|off|low|medium|high|max>` | pilih level reasoning untuk invocation ini |
|
|
20
21
|
| `bccli models` | daftar model |
|
|
21
22
|
|
|
22
23
|
Perintah di dalam sesi (ketik `/` untuk saran, ↑↓ pilih, Enter jalankan):
|
|
@@ -25,7 +26,9 @@ Perintah di dalam sesi (ketik `/` untuk saran, ↑↓ pilih, Enter jalankan):
|
|
|
25
26
|
|---|---|
|
|
26
27
|
| `/help` | daftar perintah dan pintasan |
|
|
27
28
|
| `/model` | ganti model |
|
|
29
|
+
| `/reasoning` | pilih Auto / Off / Low / Medium / High / Max |
|
|
28
30
|
| `/provider` | tambah/pilih provider AI |
|
|
31
|
+
| `/language` | ganti bahasa tampilan (`en` / `id`) |
|
|
29
32
|
| `/mcp` | pasang/kelola server MCP |
|
|
30
33
|
| `/new` | sesi baru (sesi lama tetap tersimpan) |
|
|
31
34
|
| `/resume` | lanjutkan sesi lain di folder ini |
|
|
@@ -54,6 +57,19 @@ Shift+Tab ganti mode izin: `default` → `acceptEdits` → `plan` → `allowAll`
|
|
|
54
57
|
Mode `-p` tidak pernah bertanya: alat yang butuh izin ditolak, kecuali memakai
|
|
55
58
|
`--allow-all` atau `--allowed-tools bash,edit,fetch`.
|
|
56
59
|
|
|
60
|
+
## Bahasa
|
|
61
|
+
|
|
62
|
+
Tampilan BCCLI (bantuan, pesan, prompt izin) memakai **bahasa Inggris secara default**. Bahasa Indonesia tetap tersedia:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
bccli --lang id # hanya untuk satu kali jalan
|
|
66
|
+
BCCLI_LANG=id bccli # lewat environment
|
|
67
|
+
/language id # di dalam sesi; disimpan di ~/.bccli/config.json ("language")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Urutan prioritas: `--lang`, lalu `BCCLI_LANG`, lalu `language` di config, lalu Inggris. Bahasa jawaban model mengikuti bahasa yang kamu tulis, dan
|
|
71
|
+
pesan alat yang dibaca model (hasil tool, galat) selalu berbahasa Inggris supaya tidak mengganggu bahasa jawabannya.
|
|
72
|
+
|
|
57
73
|
## Provider
|
|
58
74
|
|
|
59
75
|
`/provider` di dalam sesi (atau `bccli provider add <id>`) memasang provider hanya dengan API key:
|
|
@@ -76,10 +92,64 @@ Provider lain yang OpenAI-compatible: pilih **Custom…** di `/provider`, atau
|
|
|
76
92
|
`/model` menampilkan model dari **semua** provider yang sudah punya key, dikelompokkan
|
|
77
93
|
per provider; ketik untuk menyaring. Pilihan tersimpan sebagai default.
|
|
78
94
|
|
|
95
|
+
Reasoning dapat dipilih lewat `bccli --reasoning <auto|off|low|medium|high|max>` atau `/reasoning`.
|
|
96
|
+
**Auto** memakai default model/provider dan BCCLI tidak mengirim override reasoning apa pun. BCCLI tidak
|
|
97
|
+
otomatis menurunkan atau menaikkan reasoning effort. Level manual diteruskan bila kontrak provider/model
|
|
98
|
+
mendukungnya; level yang tidak didukung menghasilkan error yang jelas dan tidak di-downgrade diam-diam.
|
|
99
|
+
|
|
79
100
|
`.bccli/config.json` di dalam project hanya boleh memilih `model` dan menambah provider baru tanpa API key —
|
|
101
|
+
preference `reasoning` hanya dibaca dari config user `~/.bccli/config.json`, bukan dari repo yang di-clone —
|
|
80
102
|
izin (`permissionMode`, `allow`) dan provider yang sudah ada hanya diatur dari `~/.bccli/config.json`,
|
|
81
103
|
supaya repo yang kamu clone tidak bisa memberi dirinya izin penuh atau mencuri API key.
|
|
82
104
|
|
|
105
|
+
## Integrasi agent eksternal
|
|
106
|
+
|
|
107
|
+
BCCLI dapat memasang BotConnector sebagai provider untuk agent lain:
|
|
108
|
+
|
|
109
|
+
| Perintah | Fungsi |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `bccli integrations` | lihat status integrasi |
|
|
112
|
+
| `bccli connect opencode` | hubungkan OpenCode ke BotConnector |
|
|
113
|
+
| `bccli connect aider` | hubungkan Aider ke BotConnector |
|
|
114
|
+
| `bccli connect cline` | hubungkan Cline CLI ke BotConnector |
|
|
115
|
+
| `bccli connect deepseek-harness` / `bccli connect dsh` | hubungkan DeepSeek Harness ke BotConnector |
|
|
116
|
+
| `bccli connect codex` | buat profile Codex Responses API + launcher BotConnector |
|
|
117
|
+
| `bccli connect claude-code` | buat launcher Claude Code via Anthropic Messages compatibility |
|
|
118
|
+
| `bccli connect cursor` | buat guided setup Cursor + warning override Base URL |
|
|
119
|
+
| `bccli connect openai-cli` | buat launcher OpenAI CLI khusus BotConnector |
|
|
120
|
+
| `bccli connect openai-sdk` | buat env profile untuk OpenAI Python/Node SDK |
|
|
121
|
+
| `bccli connect openai-compatible` | buat env profile universal OpenAI-compatible |
|
|
122
|
+
| `bccli disconnect <agent>` | pulihkan config sebelum integrasi |
|
|
123
|
+
|
|
124
|
+
OpenCode memakai config global `~/.config/opencode/opencode.json`. BCCLI mengambil katalog model BotConnector saat connect,
|
|
125
|
+
menjaga config provider lain, dan menyimpan secret di file terpisah di `~/.bccli/integrations/`.
|
|
126
|
+
Aider memakai `~/.aider.conf.yml` yang menunjuk ke env file BCCLI terpisah; BCCLI menolak menimpa setting
|
|
127
|
+
OpenAI/env-file Aider yang sudah ada.
|
|
128
|
+
|
|
129
|
+
Cline memakai provider `openai-compatible` di `~/.cline/data/settings/providers.json`. Jika slot itu sudah dipakai
|
|
130
|
+
endpoint lain, BCCLI menolak menimpanya. Cline sendiri menyimpan API key provider di file tersebut.
|
|
131
|
+
|
|
132
|
+
DeepSeek Harness memakai custom provider `botconnector` di `$DSH_HOME/settings.yaml` dengan
|
|
133
|
+
`api: openai-completions` dan `apiKeyEnv: BOTCONNECTOR_API_KEY`; key diletakkan pada blok BCCLI di
|
|
134
|
+
`$DSH_HOME/.env`. Provider DSH lain tetap dipertahankan. Setelah connect, jalankan profile web dengan
|
|
135
|
+
`dsh web` (setara dengan `dsh --profile web`); `dsh` tanpa profile memang ditolak oleh DSH 0.1.x.
|
|
136
|
+
|
|
137
|
+
Codex memakai profile `$CODEX_HOME/botconnector.config.toml` dengan `wire_api = "responses"` dan launcher
|
|
138
|
+
BCCLI yang membaca key dari storage BCCLI saat dijalankan. Claude Code memakai launcher terisolasi dengan
|
|
139
|
+
`ANTHROPIC_BASE_URL=https://api.botconnector.id` dan endpoint kompatibilitas `/v1/messages` + token counting.
|
|
140
|
+
Login/config utama Codex dan Claude Code tidak ditimpa.
|
|
141
|
+
|
|
142
|
+
External agent memanggil BotConnector langsung, jadi discovery model tidak memakai identitas khusus BCCLI.
|
|
143
|
+
Akses yang memang dibatasi ke BCCLI/Web App (misalnya Luna launch access) tidak otomatis diwariskan.
|
|
144
|
+
Sebelum mengubah config eksternal, BCCLI membuat backup agar disconnect dapat memulihkannya.
|
|
145
|
+
|
|
146
|
+
## Internet
|
|
147
|
+
|
|
148
|
+
- `web_search`: mencari di web tanpa perlu izin. Memakai akun BotConnector Cloud
|
|
149
|
+
bila ada key, kalau tidak langsung ke Keenable (gratis, tanpa key). Hasilnya
|
|
150
|
+
judul, URL, dan cuplikan singkat, jadi hemat token.
|
|
151
|
+
- `fetch`: membuka satu URL dari komputer ini (butuh izin per host).
|
|
152
|
+
|
|
83
153
|
## MCP
|
|
84
154
|
|
|
85
155
|
`/mcp` (atau `bccli mcp add <nama>`) memasang server dari katalog:
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
t
|
|
4
|
+
} from "./chunk-EO7IVVX4.js";
|
|
2
5
|
|
|
3
6
|
// src/print.ts
|
|
4
7
|
function toolLabel(tool) {
|
|
8
|
+
if (tool === "web_search") return "Search";
|
|
5
9
|
return tool.charAt(0).toUpperCase() + tool.slice(1);
|
|
6
10
|
}
|
|
7
11
|
async function runPrint(rt, prompt, io = { out: process.stdout, err: process.stderr }, opts = {}) {
|
|
8
12
|
rt.interaction.approvePlan = async () => {
|
|
9
13
|
if (opts.allowAll) return "allowAll";
|
|
10
|
-
io.err.write("
|
|
14
|
+
io.err.write(`${t("Plan needs approval; run with --allow-all.")}
|
|
15
|
+
`);
|
|
11
16
|
return "no";
|
|
12
17
|
};
|
|
13
18
|
let failed = false;
|
|
@@ -27,11 +32,13 @@ async function runPrint(rt, prompt, io = { out: process.stdout, err: process.std
|
|
|
27
32
|
`);
|
|
28
33
|
break;
|
|
29
34
|
case "stepLimit":
|
|
30
|
-
io.err.write("
|
|
35
|
+
io.err.write(`${t("Step limit reached.")}
|
|
36
|
+
`);
|
|
31
37
|
failed = true;
|
|
32
38
|
break;
|
|
33
39
|
case "aborted":
|
|
34
|
-
io.err.write("
|
|
40
|
+
io.err.write(`${t("Cancelled.")}
|
|
41
|
+
`);
|
|
35
42
|
failed = true;
|
|
36
43
|
break;
|
|
37
44
|
case "error":
|
|
@@ -42,7 +49,7 @@ async function runPrint(rt, prompt, io = { out: process.stdout, err: process.std
|
|
|
42
49
|
}
|
|
43
50
|
};
|
|
44
51
|
rt.agent.askPermission = async (req) => {
|
|
45
|
-
io.err.write(`
|
|
52
|
+
io.err.write(` ${t("Needs permission for {tool}. Run with --allow-all or --allowed-tools {kind}.", { tool: req.tool, kind: req.kind })}
|
|
46
53
|
`);
|
|
47
54
|
return "no";
|
|
48
55
|
};
|
|
@@ -128,6 +135,8 @@ How to work:
|
|
|
128
135
|
- Verify your work: run the tests, build or the command that proves the change works, and report the real result.
|
|
129
136
|
- The user must approve edits and commands. If they decline, ask what they want instead of retrying.
|
|
130
137
|
- Be concise. Reply in the user's language. No preamble; lead with the answer or the action.
|
|
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.
|
|
131
140
|
- Never expose secrets, never run destructive commands (rm -rf, force push, dropping data) unless the user explicitly asks.
|
|
132
141
|
|
|
133
142
|
Environment:
|
|
@@ -238,10 +247,41 @@ function ignorePatterns(root) {
|
|
|
238
247
|
return patterns;
|
|
239
248
|
}
|
|
240
249
|
|
|
250
|
+
// src/tools/globSafety.ts
|
|
251
|
+
var MAX_GLOB_LENGTH = 4096;
|
|
252
|
+
var MAX_BRACE_DEPTH = 16;
|
|
253
|
+
function validateGlobPattern(pattern) {
|
|
254
|
+
if (pattern.length > MAX_GLOB_LENGTH) return `Glob pattern is too long (max ${MAX_GLOB_LENGTH} characters).`;
|
|
255
|
+
let depth = 0;
|
|
256
|
+
let escaped = false;
|
|
257
|
+
for (const char of pattern) {
|
|
258
|
+
if (escaped) {
|
|
259
|
+
escaped = false;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (char === "\\") {
|
|
263
|
+
escaped = true;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (char === "{") {
|
|
267
|
+
depth++;
|
|
268
|
+
if (depth > MAX_BRACE_DEPTH) return `Glob brace nesting is too deep (max ${MAX_BRACE_DEPTH}).`;
|
|
269
|
+
} else if (char === "}" && depth > 0) {
|
|
270
|
+
depth--;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
function normalizeGlobPath(path) {
|
|
276
|
+
return path.replaceAll("\\", "/");
|
|
277
|
+
}
|
|
278
|
+
|
|
241
279
|
export {
|
|
242
280
|
toolLabel,
|
|
243
281
|
runPrint,
|
|
244
282
|
ignorePatterns,
|
|
283
|
+
validateGlobPattern,
|
|
284
|
+
normalizeGlobPath,
|
|
245
285
|
BUILTIN_AGENTS,
|
|
246
286
|
instructionPaths,
|
|
247
287
|
buildSystemPrompt,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
ConfigError
|
|
4
|
-
|
|
3
|
+
ConfigError,
|
|
4
|
+
t
|
|
5
|
+
} from "./chunk-EO7IVVX4.js";
|
|
5
6
|
|
|
6
7
|
// src/mcp/config.ts
|
|
7
8
|
import { createHash } from "crypto";
|
|
@@ -15,7 +16,7 @@ function readJson(path, fallback) {
|
|
|
15
16
|
try {
|
|
16
17
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
17
18
|
} catch (error) {
|
|
18
|
-
throw new ConfigError(
|
|
19
|
+
throw new ConfigError(t("Invalid MCP file: {path} ({error})", { path, error: error.message }));
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
function writePrivate(path, data) {
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
ConfigError
|
|
4
|
-
|
|
3
|
+
ConfigError,
|
|
4
|
+
t
|
|
5
|
+
} from "./chunk-EO7IVVX4.js";
|
|
5
6
|
|
|
6
7
|
// src/mcp/catalog.ts
|
|
7
8
|
var CATALOG = [
|
|
8
|
-
{ name: "playwright", description: "
|
|
9
|
-
{ name: "context7", description: "
|
|
10
|
-
{ name: "fetch", description: "
|
|
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: "
|
|
14
|
+
description: "access folders outside the project",
|
|
14
15
|
config: { command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "${dir}"] },
|
|
15
|
-
inputs: [{ key: "dir", label: "Folder
|
|
16
|
+
inputs: [{ key: "dir", label: "Folder the server may access" }]
|
|
16
17
|
},
|
|
17
|
-
{ name: "git", description: "
|
|
18
|
+
{ name: "git", description: "structured git operations (needs uv)", config: { command: "uvx", args: ["mcp-server-git"] } },
|
|
18
19
|
{
|
|
19
20
|
name: "github",
|
|
20
|
-
description: "
|
|
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(
|
|
39
|
+
if (missing.size) throw new ConfigError(t("Missing MCP fields: {fields}", { fields: [...missing].join(", ") }));
|
|
39
40
|
return out;
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -35,8 +35,8 @@ function readSecret(prompt) {
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
async function runLogin(providerId, cwd) {
|
|
38
|
-
const { runProviderCommand } = await import("./providerCli-
|
|
39
|
-
const { parseCliArgs } = await import("./args-
|
|
38
|
+
const { runProviderCommand } = await import("./providerCli-II7TQDYQ.js");
|
|
39
|
+
const { parseCliArgs } = await import("./args-XQYEBOKB.js");
|
|
40
40
|
return runProviderCommand(parseCliArgs(["provider", "add", providerId]), {
|
|
41
41
|
env: process.env,
|
|
42
42
|
cwd,
|