@botconnector/bccli 0.4.0-beta.50 → 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.
package/README.md CHANGED
@@ -1,8 +1,18 @@
1
1
  # BCCLI
2
2
 
3
- Agent AI coding dari BotConnector yang bekerja di terminal: membaca kode, mengedit file,
3
+ [![npm](https://img.shields.io/npm/v/@botconnector/bccli?label=@botconnector/bccli)](https://www.npmjs.com/package/@botconnector/bccli)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@botconnector/bccli)](https://www.npmjs.com/package/@botconnector/bccli)
5
+ [![Node.js](https://img.shields.io/node/v/@botconnector/bccli)](https://nodejs.org/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+ [![Website](https://img.shields.io/badge/website-botconnector.id-06305A)](https://botconnector.id/id/download)
8
+
9
+ Agent AI coding dari [BotConnector](https://botconnector.id/) yang bekerja di terminal: membaca kode, mengedit file,
4
10
  dan menjalankan perintah — dengan izin kamu.
5
11
 
12
+ ![BCCLI membuat hello.js dan menjalankannya dengan node](docs/demo.gif)
13
+
14
+ *Rekaman sesi asli: BCCLI membuat file `hello.js` lalu menjalankannya dengan `node`.*
15
+
6
16
  ```bash
7
17
  npm i -g @botconnector/bccli@next # beta terbaru, butuh Node.js 22+
8
18
  bccli login # simpan API key BotConnector Cloud
@@ -209,3 +219,9 @@ npm test && npm run typecheck && npm run lint && npm run build
209
219
  CI (`ci.yml`) menjalankan hal yang sama di Linux, macOS, dan Windows.
210
220
  Rilis: naikkan `version` di `package.json`, lalu push tag `v<version>` — `release.yml`
211
221
  menjalankan test, smoke test ke BotConnector Cloud, dan `npm publish --provenance`.
222
+
223
+ ## Pelajari lebih lanjut
224
+
225
+ - [Unduh & panduan BCCLI](https://botconnector.id/id/download)
226
+ - [Developer API BotConnector](https://botconnector.id/id/developers/api) — endpoint kompatibel OpenAI SDK
227
+ - [Switchboard](https://github.com/farijarifriyanto-debug/switchboard) — harness agent open source dari BotConnector
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/acp.ts
4
+ var ACP_PROTOCOL_VERSION = 1;
5
+ var TOOL_KINDS = {
6
+ read: "read",
7
+ repo_map: "read",
8
+ edit: "edit",
9
+ write: "edit",
10
+ grep: "search",
11
+ glob: "search",
12
+ bash: "execute",
13
+ powershell: "execute",
14
+ fetch: "fetch",
15
+ web_search: "fetch"
16
+ };
17
+ var kindOf = (tool) => TOOL_KINDS[tool] ?? "other";
18
+ var titleOf = (tool, target) => (target ? `${tool}: ${target}` : tool).slice(0, 200);
19
+ var MAX_OUTPUT = 4e3;
20
+ var PERMISSION_OPTIONS = [
21
+ { optionId: "allow", name: "Allow", kind: "allow_once" },
22
+ { optionId: "allow_session", name: "Allow for this session", kind: "allow_always" },
23
+ { optionId: "reject", name: "Reject", kind: "reject_once" }
24
+ ];
25
+ var ANSWERS = { allow: "yes", allow_session: "session", reject: "no" };
26
+ function runAcp(input, output, opts) {
27
+ const sessions = /* @__PURE__ */ new Map();
28
+ const awaiting = /* @__PURE__ */ new Map();
29
+ let nextSession = 1;
30
+ let nextRequest = 1;
31
+ const write = (msg) => {
32
+ output.write(`${JSON.stringify(msg)}
33
+ `);
34
+ };
35
+ const reply = (id, result) => write({ jsonrpc: "2.0", id, result });
36
+ const replyError = (id, code, message) => write({ jsonrpc: "2.0", id, error: { code, message } });
37
+ const update = (sessionId, body) => write({ jsonrpc: "2.0", method: "session/update", params: { sessionId, update: body } });
38
+ const ioFor = (sid, session) => ({
39
+ toolStart(id, tool, target) {
40
+ session.open.push({ id, tool, target });
41
+ update(sid, { sessionUpdate: "tool_call", toolCallId: id, title: titleOf(tool, target), kind: kindOf(tool), status: "in_progress", rawInput: { target } });
42
+ },
43
+ toolEnd(id, output2, isError) {
44
+ session.open = session.open.filter((c) => c.id !== id);
45
+ const text = output2.length > MAX_OUTPUT ? `${output2.slice(0, MAX_OUTPUT)}
46
+ [truncated]` : output2;
47
+ update(sid, {
48
+ sessionUpdate: "tool_call_update",
49
+ toolCallId: id,
50
+ status: isError ? "failed" : "completed",
51
+ ...text ? { content: [{ type: "content", content: { type: "text", text } }] } : {}
52
+ });
53
+ },
54
+ askPermission(req) {
55
+ return new Promise((resolve) => {
56
+ const requestId = nextRequest++;
57
+ const call = [...session.open].reverse().find((c) => c.tool === req.tool && c.target === req.target);
58
+ const settle = (answer) => {
59
+ session.pending.delete(settle);
60
+ awaiting.delete(requestId);
61
+ resolve(answer);
62
+ };
63
+ session.pending.add(settle);
64
+ awaiting.set(requestId, (message) => {
65
+ const outcome = message.result?.outcome;
66
+ settle(outcome?.outcome === "selected" ? ANSWERS[outcome.optionId ?? ""] ?? "no" : "no");
67
+ });
68
+ write({
69
+ jsonrpc: "2.0",
70
+ id: requestId,
71
+ method: "session/request_permission",
72
+ params: {
73
+ sessionId: sid,
74
+ toolCall: { toolCallId: call?.id ?? `permission-${requestId}`, title: titleOf(req.tool, req.target), kind: kindOf(req.tool), status: "pending" },
75
+ options: PERMISSION_OPTIONS
76
+ }
77
+ });
78
+ });
79
+ }
80
+ });
81
+ const handle = async (msg) => {
82
+ const { id, method, params } = msg ?? {};
83
+ if (method === void 0 && id !== void 0 && (msg.result !== void 0 || msg.error !== void 0)) {
84
+ awaiting.get(id)?.(msg);
85
+ return;
86
+ }
87
+ if (method === "initialize") {
88
+ return reply(id, {
89
+ protocolVersion: ACP_PROTOCOL_VERSION,
90
+ agentCapabilities: {
91
+ loadSession: false,
92
+ promptCapabilities: { image: false, audio: false, embeddedContext: false }
93
+ }
94
+ });
95
+ }
96
+ if (method === "session/new") {
97
+ const sessionId = `s${nextSession++}`;
98
+ sessions.set(sessionId, { controller: null, pending: /* @__PURE__ */ new Set(), open: [] });
99
+ return reply(id, { sessionId });
100
+ }
101
+ if (method === "session/cancel") {
102
+ const session = sessions.get(params?.sessionId ?? "");
103
+ session?.controller?.abort();
104
+ for (const settle of [...session?.pending ?? []]) settle("no");
105
+ return;
106
+ }
107
+ if (method === "session/prompt") {
108
+ const sid = params?.sessionId ?? "";
109
+ const session = sessions.get(sid);
110
+ if (!session) return replyError(id, -32602, "Unknown session");
111
+ const text = (params?.prompt ?? []).filter((p) => p?.type === "text").map((p) => String(p.text ?? "")).join("\n");
112
+ const controller = new AbortController();
113
+ session.controller = controller;
114
+ let cancelled = false;
115
+ controller.signal.addEventListener("abort", () => {
116
+ cancelled = true;
117
+ });
118
+ try {
119
+ session.agent ??= opts.newAgent(params?.cwd ?? opts.cwd);
120
+ await session.agent.run(text, (chunk) => update(sid, { sessionUpdate: "agent_message_chunk", content: { type: "text", text: chunk } }), controller.signal, ioFor(sid, session));
121
+ } catch (e) {
122
+ if (cancelled) return reply(id, { stopReason: "cancelled" });
123
+ return replyError(id, -32603, e.message);
124
+ } finally {
125
+ session.controller = null;
126
+ session.open = [];
127
+ }
128
+ return reply(id, { stopReason: cancelled ? "cancelled" : "end_turn" });
129
+ }
130
+ if (id !== void 0) return replyError(id, -32601, "Method not found");
131
+ };
132
+ return new Promise((resolve) => {
133
+ let buf = "";
134
+ const onData = (chunk) => {
135
+ buf += chunk.toString();
136
+ let idx = buf.indexOf("\n");
137
+ while (idx >= 0) {
138
+ const line = buf.slice(0, idx);
139
+ buf = buf.slice(idx + 1);
140
+ idx = buf.indexOf("\n");
141
+ if (!line.trim()) continue;
142
+ let msg;
143
+ try {
144
+ msg = JSON.parse(line);
145
+ } catch {
146
+ continue;
147
+ }
148
+ void handle(msg);
149
+ }
150
+ };
151
+ const onEnd = () => {
152
+ input.removeListener("data", onData);
153
+ resolve();
154
+ };
155
+ input.on("data", onData);
156
+ input.on("end", onEnd);
157
+ });
158
+ }
159
+ function runtimeAgent(cwd, allowAll = false) {
160
+ let rt;
161
+ return {
162
+ async run(text, onChunk, signal, io) {
163
+ if (!rt) {
164
+ const { parseCliArgs } = await import("./args-2R45YZ42.js");
165
+ const { createRuntime } = await import("./setup-LLWREJQH.js");
166
+ rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll } });
167
+ }
168
+ if (io && !allowAll) rt.agent.askPermission = (req) => io.askPermission(req);
169
+ rt.agent.onEvent = (event) => {
170
+ if (event.type === "text") onChunk(event.delta);
171
+ else if (event.type === "toolStart") io?.toolStart(event.id, event.tool, event.target);
172
+ else if (event.type === "toolEnd") io?.toolEnd(event.id, event.output, event.isError);
173
+ };
174
+ await rt.agent.run(text, signal);
175
+ }
176
+ };
177
+ }
178
+ export {
179
+ ACP_PROTOCOL_VERSION,
180
+ runAcp,
181
+ runtimeAgent
182
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/version.ts
4
- var VERSION = true ? "0.4.0-beta.50" : "0.0.0-dev";
4
+ var VERSION = true ? "0.4.0-beta.51" : "0.0.0-dev";
5
5
 
6
6
  export {
7
7
  VERSION
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import "./chunk-DP7EBW53.js";
12
12
  import "./chunk-PSO7R5AD.js";
13
13
  import {
14
14
  VERSION
15
- } from "./chunk-EUCSCUYP.js";
15
+ } from "./chunk-VU5HNQHX.js";
16
16
  import {
17
17
  helpText,
18
18
  parseCliArgs
@@ -108,16 +108,16 @@ async function main() {
108
108
  return runModelsCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), fetch: globalThis.fetch });
109
109
  }
110
110
  if (args.command === "update") {
111
- const { runUpdateCommand } = await import("./update-IQR346E5.js");
111
+ const { runUpdateCommand } = await import("./update-O4WCLKOO.js");
112
112
  return runUpdateCommand({ env: process.env });
113
113
  }
114
114
  if (args.command === "acp") {
115
- const { runtimeAgent, runAcp } = await import("./acp-V5RP42VB.js");
116
- await runAcp(process.stdin, process.stdout, { cwd, newAgent: (c) => runtimeAgent(c) });
115
+ const { runtimeAgent, runAcp } = await import("./acp-NWP4FFTG.js");
116
+ await runAcp(process.stdin, process.stdout, { cwd, newAgent: (c) => runtimeAgent(c, args.allowAll) });
117
117
  return 0;
118
118
  }
119
119
  if (args.command === "serve") {
120
- const { startServe } = await import("./serve-XDHMB7TO.js");
120
+ const { startServe } = await import("./serve-YSUJD57D.js");
121
121
  const handle = await startServe({ port: args.port, host: args.host, token: args.token, cwd, env: process.env });
122
122
  process.stderr.write(`bccli serve ${handle.url} \u2014 Authorization: Bearer ${handle.token}
123
123
  `);
@@ -195,7 +195,7 @@ async function main() {
195
195
  if (!process.stdin.isTTY) throw new ConfigError(t('Interactive mode needs a terminal. For scripts/CI use: bccli -p "task"'));
196
196
  if (rt.config.updateCheck !== "off" && !process.env.BCCLI_NO_UPDATE_CHECK) {
197
197
  try {
198
- const { checkForUpdate } = await import("./update-IQR346E5.js");
198
+ const { checkForUpdate } = await import("./update-O4WCLKOO.js");
199
199
  const update = await checkForUpdate({ home: rt.home, fetch: globalThis.fetch, now: /* @__PURE__ */ new Date() });
200
200
  if (update) console.error(update);
201
201
  } catch {
@@ -8,7 +8,7 @@ import "./chunk-DP7EBW53.js";
8
8
  import "./chunk-PSO7R5AD.js";
9
9
  import {
10
10
  VERSION
11
- } from "./chunk-EUCSCUYP.js";
11
+ } from "./chunk-VU5HNQHX.js";
12
12
  import {
13
13
  LOOPBACK_BIND,
14
14
  MAX_FRAME_BYTES,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-EUCSCUYP.js";
4
+ } from "./chunk-VU5HNQHX.js";
5
5
  import {
6
6
  t
7
7
  } from "./chunk-XLC6T4SX.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botconnector/bccli",
3
- "version": "0.4.0-beta.50",
3
+ "version": "0.4.0-beta.51",
4
4
  "description": "BCCLI — BotConnector AI coding agent for the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,114 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/acp.ts
4
- var ACP_PROTOCOL_VERSION = 1;
5
- function runAcp(input, output, opts) {
6
- const sessions = /* @__PURE__ */ new Map();
7
- let nextSession = 1;
8
- const write = (msg) => {
9
- output.write(`${JSON.stringify(msg)}
10
- `);
11
- };
12
- const reply = (id, result) => write({ jsonrpc: "2.0", id, result });
13
- const replyError = (id, code, message) => write({ jsonrpc: "2.0", id, error: { code, message } });
14
- const handle = async (msg) => {
15
- const { id, method, params } = msg ?? {};
16
- if (method === "initialize") {
17
- return reply(id, {
18
- protocolVersion: ACP_PROTOCOL_VERSION,
19
- agentCapabilities: {
20
- loadSession: false,
21
- promptCapabilities: { image: false, audio: false, embeddedContext: false }
22
- }
23
- });
24
- }
25
- if (method === "session/new") {
26
- const sessionId = `s${nextSession++}`;
27
- sessions.set(sessionId, { controller: null });
28
- return reply(id, { sessionId });
29
- }
30
- if (method === "session/cancel") {
31
- sessions.get(params?.sessionId ?? "")?.controller?.abort();
32
- return;
33
- }
34
- if (method === "session/prompt") {
35
- const sid = params?.sessionId ?? "";
36
- const session = sessions.get(sid);
37
- if (!session) return replyError(id, -32602, "Unknown session");
38
- const text = (params?.prompt ?? []).filter((p) => p?.type === "text").map((p) => String(p.text ?? "")).join("\n");
39
- const controller = new AbortController();
40
- session.controller = controller;
41
- let cancelled = false;
42
- controller.signal.addEventListener("abort", () => {
43
- cancelled = true;
44
- });
45
- try {
46
- const agent = opts.newAgent(params?.cwd ?? opts.cwd);
47
- await agent.run(
48
- text,
49
- (chunk) => {
50
- write({
51
- jsonrpc: "2.0",
52
- method: "session/update",
53
- params: {
54
- sessionId: sid,
55
- update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: chunk } }
56
- }
57
- });
58
- },
59
- controller.signal
60
- );
61
- } catch (e) {
62
- return replyError(id, -32603, e.message);
63
- } finally {
64
- session.controller = null;
65
- }
66
- return reply(id, { stopReason: cancelled ? "cancelled" : "end_turn" });
67
- }
68
- if (id !== void 0) return replyError(id, -32601, "Method not found");
69
- };
70
- return new Promise((resolve) => {
71
- let buf = "";
72
- const onData = (chunk) => {
73
- buf += chunk.toString();
74
- let idx = buf.indexOf("\n");
75
- while (idx >= 0) {
76
- const line = buf.slice(0, idx);
77
- buf = buf.slice(idx + 1);
78
- idx = buf.indexOf("\n");
79
- if (!line.trim()) continue;
80
- let msg;
81
- try {
82
- msg = JSON.parse(line);
83
- } catch {
84
- continue;
85
- }
86
- void handle(msg);
87
- }
88
- };
89
- const onEnd = () => {
90
- input.removeListener("data", onData);
91
- resolve();
92
- };
93
- input.on("data", onData);
94
- input.on("end", onEnd);
95
- });
96
- }
97
- function runtimeAgent(cwd) {
98
- return {
99
- async run(text, onChunk, signal) {
100
- const { parseCliArgs } = await import("./args-2R45YZ42.js");
101
- const { createRuntime } = await import("./setup-LLWREJQH.js");
102
- const rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll: true } });
103
- rt.agent.onEvent = (event) => {
104
- if (event.type === "text") onChunk(event.delta);
105
- };
106
- await rt.agent.run(text, signal);
107
- }
108
- };
109
- }
110
- export {
111
- ACP_PROTOCOL_VERSION,
112
- runAcp,
113
- runtimeAgent
114
- };