@botconnector/bccli 0.5.0-rc.4 → 0.5.0
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/cli.mjs +14 -6
- package/legacy/LICENSE +21 -0
- package/legacy/README.en.md +253 -0
- package/legacy/README.md +250 -0
- package/legacy/dist/abort.d.ts +5 -0
- package/legacy/dist/acp-HWHF25KU.js +221 -0
- package/legacy/dist/acp.d.ts +44 -0
- package/legacy/dist/agent.d.ts +158 -0
- package/legacy/dist/agents.d.ts +4 -0
- package/legacy/dist/args-XA77XUMD.js +13 -0
- package/legacy/dist/args.d.ts +59 -0
- package/legacy/dist/budget.d.ts +26 -0
- package/legacy/dist/checkpoints.d.ts +35 -0
- package/legacy/dist/chunk-2IP5F3EK.js +56 -0
- package/legacy/dist/chunk-5CVHTYBQ.js +270 -0
- package/legacy/dist/chunk-6LO6YRDY.js +216 -0
- package/legacy/dist/chunk-6PJRWKVI.js +50 -0
- package/legacy/dist/chunk-7OTFZK4B.js +159 -0
- package/legacy/dist/chunk-7U7CMKKI.js +861 -0
- package/legacy/dist/chunk-A3NBWIEQ.js +2706 -0
- package/legacy/dist/chunk-FY543EQW.js +50 -0
- package/legacy/dist/chunk-IDZLHEVL.js +524 -0
- package/legacy/dist/chunk-IF5RNXBI.js +341 -0
- package/legacy/dist/chunk-M5T4AM4I.js +256 -0
- package/legacy/dist/chunk-NGFWBVHD.js +71 -0
- package/legacy/dist/chunk-OCEQ2TRJ.js +1075 -0
- package/legacy/dist/chunk-OK2USAXX.js +88 -0
- package/legacy/dist/chunk-PSO7R5AD.js +10 -0
- package/legacy/dist/chunk-RLSQAZBT.js +78 -0
- package/legacy/dist/chunk-VPFCIUC6.js +91 -0
- package/legacy/dist/chunk-XP5MTJN2.js +8 -0
- package/legacy/dist/chunk-YGBTNDPK.js +202 -0
- package/legacy/dist/chunk-YYTFJUO2.js +148 -0
- package/legacy/dist/chunk-ZXWRLN7E.js +378 -0
- package/legacy/dist/cli.d.ts +1 -0
- package/legacy/dist/cli.js +233 -0
- package/legacy/dist/clipboardImage.d.ts +17 -0
- package/legacy/dist/commands.d.ts +16 -0
- package/legacy/dist/completion-IRVEVW6H.js +125 -0
- package/legacy/dist/completion.d.ts +14 -0
- package/legacy/dist/config-OVWCUVY7.js +25 -0
- package/legacy/dist/config-S3CZUIBB.js +34 -0
- package/legacy/dist/config.d.ts +99 -0
- package/legacy/dist/context.d.ts +13 -0
- package/legacy/dist/contextWindow.d.ts +3 -0
- package/legacy/dist/diff.d.ts +7 -0
- package/legacy/dist/exit.d.ts +9 -0
- package/legacy/dist/extensions.d.ts +34 -0
- package/legacy/dist/ghBotCli-FYKJDJOD.js +680 -0
- package/legacy/dist/ghBotCli.d.ts +9 -0
- package/legacy/dist/ghBotDispatch.d.ts +68 -0
- package/legacy/dist/ghBotRunner.d.ts +82 -0
- package/legacy/dist/ghBotServe.d.ts +21 -0
- package/legacy/dist/ghBotWebhook.d.ts +45 -0
- package/legacy/dist/hooks.d.ts +27 -0
- package/legacy/dist/i18n/id.d.ts +1 -0
- package/legacy/dist/i18n.d.ts +16 -0
- package/legacy/dist/integrationCli-GY73S2K7.js +876 -0
- package/legacy/dist/integrationCli.d.ts +9 -0
- package/legacy/dist/keybinds.d.ts +22 -0
- package/legacy/dist/login-KSN63EM4.js +18 -0
- package/legacy/dist/login.d.ts +21 -0
- package/legacy/dist/lsp.d.ts +73 -0
- package/legacy/dist/mcp/catalog.d.ts +14 -0
- package/legacy/dist/mcp/config.d.ts +36 -0
- package/legacy/dist/mcp/manager.d.ts +52 -0
- package/legacy/dist/mcp/oauth.d.ts +82 -0
- package/legacy/dist/mcpCli-VWSCCDWT.js +113 -0
- package/legacy/dist/mcpCli.d.ts +3 -0
- package/legacy/dist/mcpServer/serve.d.ts +8 -0
- package/legacy/dist/mcpServer/server.d.ts +19 -0
- package/legacy/dist/models.d.ts +13 -0
- package/legacy/dist/modelsCli-4Q6KFWV2.js +36 -0
- package/legacy/dist/modelsCli.d.ts +15 -0
- package/legacy/dist/npmRunner-LU43GM3W.js +46 -0
- package/legacy/dist/npmRunner.d.ts +21 -0
- package/legacy/dist/oauthLogin-JWXQZTMZ.js +210 -0
- package/legacy/dist/oauthLogin.d.ts +47 -0
- package/legacy/dist/permissions.d.ts +30 -0
- package/legacy/dist/pluginSpec.d.ts +25 -0
- package/legacy/dist/plugins.d.ts +45 -0
- package/legacy/dist/pluginsCli-7XWDLJEL.js +288 -0
- package/legacy/dist/pluginsCli.d.ts +16 -0
- package/legacy/dist/prCli-FH7N26D4.js +94 -0
- package/legacy/dist/prCli.d.ts +46 -0
- package/legacy/dist/presets.d.ts +8 -0
- package/legacy/dist/print.d.ts +17 -0
- package/legacy/dist/provider.d.ts +145 -0
- package/legacy/dist/providerCli-YMG4G56R.js +15 -0
- package/legacy/dist/providerCli.d.ts +17 -0
- package/legacy/dist/providers.d.ts +6 -0
- package/legacy/dist/reasoning.d.ts +12 -0
- package/legacy/dist/repomap.d.ts +10 -0
- package/legacy/dist/sdk.d.ts +61 -0
- package/legacy/dist/sdk.js +6532 -0
- package/legacy/dist/serve-HSFF6MGB.js +178 -0
- package/legacy/dist/serve-HUQNVOSP.js +532 -0
- package/legacy/dist/serve.d.ts +37 -0
- package/legacy/dist/serveHeartbeat.d.ts +14 -0
- package/legacy/dist/serveProtocol.d.ts +47 -0
- package/legacy/dist/session-YM36TGU7.js +12 -0
- package/legacy/dist/session.d.ts +33 -0
- package/legacy/dist/setup-3YB6EKYX.js +24 -0
- package/legacy/dist/setup.d.ts +79 -0
- package/legacy/dist/slash/copy.d.ts +1 -0
- package/legacy/dist/slash/diff.d.ts +1 -0
- package/legacy/dist/slash/doctor.d.ts +18 -0
- package/legacy/dist/slash/export.d.ts +2 -0
- package/legacy/dist/slash/info.d.ts +46 -0
- package/legacy/dist/slash/memory.d.ts +10 -0
- package/legacy/dist/statsCli-I4TSDU3X.js +353 -0
- package/legacy/dist/statsCli.d.ts +62 -0
- package/legacy/dist/textToolCalls.d.ts +6 -0
- package/legacy/dist/thinking.d.ts +17 -0
- package/legacy/dist/tokenBudget.d.ts +22 -0
- package/legacy/dist/tools/bash.d.ts +54 -0
- package/legacy/dist/tools/diagnostics.d.ts +13 -0
- package/legacy/dist/tools/edit.d.ts +12 -0
- package/legacy/dist/tools/fetch.d.ts +41 -0
- package/legacy/dist/tools/glob.d.ts +5 -0
- package/legacy/dist/tools/globSafety.d.ts +7 -0
- package/legacy/dist/tools/grep.d.ts +25 -0
- package/legacy/dist/tools/ignore.d.ts +2 -0
- package/legacy/dist/tools/index.d.ts +12 -0
- package/legacy/dist/tools/memory.d.ts +13 -0
- package/legacy/dist/tools/paths.d.ts +4 -0
- package/legacy/dist/tools/plan.d.ts +10 -0
- package/legacy/dist/tools/read.d.ts +16 -0
- package/legacy/dist/tools/repomap.d.ts +2 -0
- package/legacy/dist/tools/sandbox.d.ts +15 -0
- package/legacy/dist/tools/shell.d.ts +18 -0
- package/legacy/dist/tools/skill.d.ts +3 -0
- package/legacy/dist/tools/task.d.ts +28 -0
- package/legacy/dist/tools/todo.d.ts +13 -0
- package/legacy/dist/tools/types.d.ts +52 -0
- package/legacy/dist/tools/websearch.d.ts +9 -0
- package/legacy/dist/tools/write.d.ts +5 -0
- package/legacy/dist/transferCli-3B4LMOYI.js +73 -0
- package/legacy/dist/transferCli.d.ts +23 -0
- package/legacy/dist/ui/App.d.ts +7 -0
- package/legacy/dist/ui/DiffView.d.ts +3 -0
- package/legacy/dist/ui/EditableText.d.ts +7 -0
- package/legacy/dist/ui/LinePrompt.d.ts +6 -0
- package/legacy/dist/ui/ListPicker.d.ts +11 -0
- package/legacy/dist/ui/Markdown.d.ts +8 -0
- package/legacy/dist/ui/McpMenu.d.ts +11 -0
- package/legacy/dist/ui/ModelPicker.d.ts +6 -0
- package/legacy/dist/ui/PermissionPrompt.d.ts +5 -0
- package/legacy/dist/ui/PlanApproval.d.ts +5 -0
- package/legacy/dist/ui/PromptInput.d.ts +20 -0
- package/legacy/dist/ui/ProviderMenu.d.ts +10 -0
- package/legacy/dist/ui/Spinner.d.ts +4 -0
- package/legacy/dist/ui/StatusBar.d.ts +14 -0
- package/legacy/dist/ui/TodoList.d.ts +4 -0
- package/legacy/dist/ui/ToolBlock.d.ts +14 -0
- package/legacy/dist/ui/complete.d.ts +8 -0
- package/legacy/dist/ui/index.d.ts +7 -0
- package/legacy/dist/ui/lineEdit.d.ts +42 -0
- package/legacy/dist/ui/liveCap.d.ts +29 -0
- package/legacy/dist/ui/markdownLayout.d.ts +23 -0
- package/legacy/dist/ui/replay.d.ts +4 -0
- package/legacy/dist/ui/stdinFilter.d.ts +18 -0
- package/legacy/dist/ui/table.d.ts +20 -0
- package/legacy/dist/ui/theme.d.ts +5 -0
- package/legacy/dist/ui/thinkingMouse.d.ts +38 -0
- package/legacy/dist/ui/transcript.d.ts +55 -0
- package/legacy/dist/ui/tty.d.ts +11 -0
- package/legacy/dist/ui/vim.d.ts +26 -0
- package/legacy/dist/ui-TAZMRXRI.js +3044 -0
- package/legacy/dist/update-5V425FIK.js +145 -0
- package/legacy/dist/update.d.ts +30 -0
- package/legacy/dist/verify.d.ts +16 -0
- package/legacy/dist/version.d.ts +1 -0
- package/legacy/dist/webBudget.d.ts +25 -0
- package/legacy/dist/worktree.d.ts +12 -0
- package/legacy/package.json +77 -0
- package/legacy-compat.mjs +42 -0
- package/package.json +24 -4
- package/provider-cli.mjs +1 -2
- package/providers.mjs +19 -6
- package/startup-menu.mjs +14 -13
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
t
|
|
4
|
+
} from "./chunk-IDZLHEVL.js";
|
|
5
|
+
|
|
6
|
+
// src/acp.ts
|
|
7
|
+
var ACP_PROTOCOL_VERSION = 1;
|
|
8
|
+
var TOOL_KINDS = {
|
|
9
|
+
read: "read",
|
|
10
|
+
repo_map: "read",
|
|
11
|
+
edit: "edit",
|
|
12
|
+
write: "edit",
|
|
13
|
+
grep: "search",
|
|
14
|
+
glob: "search",
|
|
15
|
+
bash: "execute",
|
|
16
|
+
powershell: "execute",
|
|
17
|
+
fetch: "fetch",
|
|
18
|
+
web_search: "fetch"
|
|
19
|
+
};
|
|
20
|
+
var kindOf = (tool) => TOOL_KINDS[tool] ?? "other";
|
|
21
|
+
var titleOf = (tool, target) => (target ? `${tool}: ${target}` : tool).slice(0, 200);
|
|
22
|
+
var MAX_OUTPUT = 4e3;
|
|
23
|
+
var PERMISSION_OPTIONS = [
|
|
24
|
+
{ optionId: "allow", name: "Allow", kind: "allow_once" },
|
|
25
|
+
{ optionId: "allow_session", name: "Allow for this session", kind: "allow_always" },
|
|
26
|
+
{ optionId: "reject", name: "Reject", kind: "reject_once" }
|
|
27
|
+
];
|
|
28
|
+
var ANSWERS = { allow: "yes", allow_session: "session", reject: "no" };
|
|
29
|
+
function runAcp(input, output, opts) {
|
|
30
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
31
|
+
const awaiting = /* @__PURE__ */ new Map();
|
|
32
|
+
let nextSession = 1;
|
|
33
|
+
let nextRequest = 1;
|
|
34
|
+
const write = (msg) => {
|
|
35
|
+
output.write(`${JSON.stringify(msg)}
|
|
36
|
+
`);
|
|
37
|
+
};
|
|
38
|
+
const reply = (id, result) => write({ jsonrpc: "2.0", id, result });
|
|
39
|
+
const replyError = (id, code, message) => write({ jsonrpc: "2.0", id, error: { code, message } });
|
|
40
|
+
const update = (sessionId, body) => write({ jsonrpc: "2.0", method: "session/update", params: { sessionId, update: body } });
|
|
41
|
+
const ioFor = (sid, session) => ({
|
|
42
|
+
onThinking(delta) {
|
|
43
|
+
update(sid, { sessionUpdate: "agent_thought_chunk", content: { type: "text", text: delta } });
|
|
44
|
+
},
|
|
45
|
+
toolStart(id, tool, target) {
|
|
46
|
+
session.open.push({ id, tool, target });
|
|
47
|
+
update(sid, { sessionUpdate: "tool_call", toolCallId: id, title: titleOf(tool, target), kind: kindOf(tool), status: "in_progress", rawInput: { target } });
|
|
48
|
+
},
|
|
49
|
+
toolEnd(id, output2, isError) {
|
|
50
|
+
session.open = session.open.filter((c) => c.id !== id);
|
|
51
|
+
const text = output2.length > MAX_OUTPUT ? `${output2.slice(0, MAX_OUTPUT)}
|
|
52
|
+
[truncated]` : output2;
|
|
53
|
+
update(sid, {
|
|
54
|
+
sessionUpdate: "tool_call_update",
|
|
55
|
+
toolCallId: id,
|
|
56
|
+
status: isError ? "failed" : "completed",
|
|
57
|
+
...text ? { content: [{ type: "content", content: { type: "text", text } }] } : {}
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
askPermission(req) {
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
const requestId = nextRequest++;
|
|
63
|
+
const call = [...session.open].reverse().find((c) => c.tool === req.tool && c.target === req.target);
|
|
64
|
+
const settle = (answer) => {
|
|
65
|
+
session.pending.delete(settle);
|
|
66
|
+
awaiting.delete(requestId);
|
|
67
|
+
resolve(answer);
|
|
68
|
+
};
|
|
69
|
+
session.pending.add(settle);
|
|
70
|
+
awaiting.set(requestId, (message) => {
|
|
71
|
+
const outcome = message.result?.outcome;
|
|
72
|
+
settle(outcome?.outcome === "selected" ? ANSWERS[outcome.optionId ?? ""] ?? "no" : "no");
|
|
73
|
+
});
|
|
74
|
+
write({
|
|
75
|
+
jsonrpc: "2.0",
|
|
76
|
+
id: requestId,
|
|
77
|
+
method: "session/request_permission",
|
|
78
|
+
params: {
|
|
79
|
+
sessionId: sid,
|
|
80
|
+
toolCall: { toolCallId: call?.id ?? `permission-${requestId}`, title: titleOf(req.tool, req.target), kind: kindOf(req.tool), status: "pending" },
|
|
81
|
+
options: PERMISSION_OPTIONS
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const handle = async (msg) => {
|
|
88
|
+
const { id, method, params } = msg ?? {};
|
|
89
|
+
if (method === void 0 && id !== void 0 && (msg.result !== void 0 || msg.error !== void 0)) {
|
|
90
|
+
awaiting.get(id)?.(msg);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (method === "initialize") {
|
|
94
|
+
return reply(id, {
|
|
95
|
+
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
96
|
+
agentCapabilities: {
|
|
97
|
+
loadSession: false,
|
|
98
|
+
promptCapabilities: { image: false, audio: false, embeddedContext: true }
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (method === "session/new") {
|
|
103
|
+
const sessionId = `s${nextSession++}`;
|
|
104
|
+
sessions.set(sessionId, { controller: null, pending: /* @__PURE__ */ new Set(), open: [] });
|
|
105
|
+
return reply(id, { sessionId });
|
|
106
|
+
}
|
|
107
|
+
if (method === "session/cancel") {
|
|
108
|
+
const session = sessions.get(params?.sessionId ?? "");
|
|
109
|
+
session?.controller?.abort();
|
|
110
|
+
for (const settle of [...session?.pending ?? []]) settle("no");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (method === "session/prompt") {
|
|
114
|
+
const sid = params?.sessionId ?? "";
|
|
115
|
+
const session = sessions.get(sid);
|
|
116
|
+
if (!session) return replyError(id, -32602, "Unknown session");
|
|
117
|
+
if (session.controller) return replyError(id, -32e3, "Session is busy");
|
|
118
|
+
const text = (params?.prompt ?? []).map((p) => {
|
|
119
|
+
if (p?.type === "text") return String(p.text ?? "");
|
|
120
|
+
if ((p?.type === "resource" || p?.type === "embeddedContext") && p.resource?.text) {
|
|
121
|
+
const label = p.resource.uri ? `
|
|
122
|
+
[${p.resource.uri}]
|
|
123
|
+
` : "\n";
|
|
124
|
+
return `${label}${p.resource.text}`;
|
|
125
|
+
}
|
|
126
|
+
return "";
|
|
127
|
+
}).filter(Boolean).join("\n");
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
session.controller = controller;
|
|
130
|
+
let cancelled = false;
|
|
131
|
+
controller.signal.addEventListener("abort", () => {
|
|
132
|
+
cancelled = true;
|
|
133
|
+
});
|
|
134
|
+
try {
|
|
135
|
+
session.agent ??= opts.newAgent(params?.cwd ?? opts.cwd);
|
|
136
|
+
await session.agent.run(text, (chunk) => update(sid, { sessionUpdate: "agent_message_chunk", content: { type: "text", text: chunk } }), controller.signal, ioFor(sid, session));
|
|
137
|
+
} catch (e) {
|
|
138
|
+
if (cancelled) return reply(id, { stopReason: "cancelled" });
|
|
139
|
+
return replyError(id, -32603, e.message);
|
|
140
|
+
} finally {
|
|
141
|
+
if (session.controller === controller) {
|
|
142
|
+
session.controller = null;
|
|
143
|
+
session.open = [];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return reply(id, { stopReason: cancelled ? "cancelled" : "end_turn" });
|
|
147
|
+
}
|
|
148
|
+
if (id !== void 0) return replyError(id, -32601, "Method not found");
|
|
149
|
+
};
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
let buf = "";
|
|
152
|
+
const onData = (chunk) => {
|
|
153
|
+
buf += chunk.toString();
|
|
154
|
+
let idx = buf.indexOf("\n");
|
|
155
|
+
while (idx >= 0) {
|
|
156
|
+
const line = buf.slice(0, idx);
|
|
157
|
+
buf = buf.slice(idx + 1);
|
|
158
|
+
idx = buf.indexOf("\n");
|
|
159
|
+
if (!line.trim()) continue;
|
|
160
|
+
let msg;
|
|
161
|
+
try {
|
|
162
|
+
msg = JSON.parse(line);
|
|
163
|
+
} catch {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
void handle(msg);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const onEnd = () => {
|
|
170
|
+
input.removeListener("data", onData);
|
|
171
|
+
for (const session of sessions.values()) {
|
|
172
|
+
session.controller?.abort();
|
|
173
|
+
for (const settle of [...session.pending]) settle("no");
|
|
174
|
+
}
|
|
175
|
+
resolve();
|
|
176
|
+
};
|
|
177
|
+
input.on("data", onData);
|
|
178
|
+
input.on("end", onEnd);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function planDecisionFrom(answer) {
|
|
182
|
+
if (answer === "no") return "no";
|
|
183
|
+
if (answer === "session") return "acceptEdits";
|
|
184
|
+
return "default";
|
|
185
|
+
}
|
|
186
|
+
function runtimeAgent(cwd, allowAll = false, deps = {}) {
|
|
187
|
+
let rt;
|
|
188
|
+
return {
|
|
189
|
+
async run(text, onChunk, signal, io) {
|
|
190
|
+
if (!rt) {
|
|
191
|
+
if (deps.createRuntime) rt = deps.createRuntime({ cwd, allowAll });
|
|
192
|
+
else {
|
|
193
|
+
const { parseCliArgs } = await import("./args-XA77XUMD.js");
|
|
194
|
+
const { createRuntime } = await import("./setup-3YB6EKYX.js");
|
|
195
|
+
rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll } });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (io && !allowAll) {
|
|
199
|
+
rt.agent.askPermission = (req) => io.askPermission(req);
|
|
200
|
+
rt.interaction.approvePlan = async (plan) => planDecisionFrom(await io.askPermission({ tool: "exit_plan", kind: "edit", target: t("plan"), preview: plan }));
|
|
201
|
+
}
|
|
202
|
+
let turnError;
|
|
203
|
+
rt.agent.onEvent = (event) => {
|
|
204
|
+
if (event.type === "text") onChunk(event.delta);
|
|
205
|
+
else if (event.type === "thinking") io?.onThinking?.(event.delta);
|
|
206
|
+
else if (event.type === "toolStart") io?.toolStart(event.id, event.tool, event.target);
|
|
207
|
+
else if (event.type === "toolEnd") io?.toolEnd(event.id, event.output, event.isError);
|
|
208
|
+
else if (event.type === "error") turnError = event.message;
|
|
209
|
+
else if (event.type === "budgetExceeded") turnError = `Budget exceeded (${event.kind})`;
|
|
210
|
+
};
|
|
211
|
+
await rt.agent.run(text, signal);
|
|
212
|
+
if (turnError) throw new Error(turnError);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
export {
|
|
217
|
+
ACP_PROTOCOL_VERSION,
|
|
218
|
+
planDecisionFrom,
|
|
219
|
+
runAcp,
|
|
220
|
+
runtimeAgent
|
|
221
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { PermissionAnswer, PermissionAsk } from './agent';
|
|
2
|
+
import type { Runtime } from './setup';
|
|
3
|
+
import type { PlanDecision } from './tools/plan';
|
|
4
|
+
export declare const ACP_PROTOCOL_VERSION = 1;
|
|
5
|
+
/** What the agent reports to the editor besides text: tool calls, and permission questions the editor answers. */
|
|
6
|
+
export interface AcpIo {
|
|
7
|
+
toolStart(id: string, tool: string, target: string): void;
|
|
8
|
+
toolEnd(id: string, output: string, isError: boolean): void;
|
|
9
|
+
askPermission(req: PermissionAsk): Promise<PermissionAnswer>;
|
|
10
|
+
onThinking?(delta: string): void;
|
|
11
|
+
}
|
|
12
|
+
/** The minimum an ACP client needs: run one prompt, stream text chunks, allow cancellation. */
|
|
13
|
+
export interface AcpAgent {
|
|
14
|
+
run(text: string, onChunk: (text: string) => void, signal: AbortSignal, io?: AcpIo): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Agent Client Protocol over newline-delimited JSON-RPC (the transport editors like Zed use).
|
|
18
|
+
* Implements the subset: initialize, session/new, session/prompt (streaming session/update
|
|
19
|
+
* notifications: text chunks and tool calls), session/request_permission, session/cancel;
|
|
20
|
+
* anything else with an id gets -32601.
|
|
21
|
+
*/
|
|
22
|
+
export declare function runAcp(input: NodeJS.ReadableStream, output: NodeJS.WritableStream, opts: {
|
|
23
|
+
cwd: string;
|
|
24
|
+
newAgent: (cwd: string) => AcpAgent;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* A plan has no ACP primitive of its own, so it is asked through session/request_permission.
|
|
28
|
+
* 'yes' approves and keeps the normal per-tool prompts; 'session' also stops asking for edits
|
|
29
|
+
* for the rest of the session (acceptEdits). A plan answer never turns on allowAll, which stays
|
|
30
|
+
* an explicit user choice.
|
|
31
|
+
*/
|
|
32
|
+
export declare function planDecisionFrom(answer: PermissionAnswer): PlanDecision;
|
|
33
|
+
export interface AcpRuntimeDeps {
|
|
34
|
+
/** Test seam: build the runtime without reading config/plugins. */
|
|
35
|
+
createRuntime?: (opts: {
|
|
36
|
+
cwd: string;
|
|
37
|
+
allowAll: boolean;
|
|
38
|
+
}) => Runtime;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Production agent: one bccli runtime per ACP session. Permission questions go to the editor
|
|
42
|
+
* (session/request_permission); `allowAll` skips them and runs everything unasked.
|
|
43
|
+
*/
|
|
44
|
+
export declare function runtimeAgent(cwd: string, allowAll?: boolean, deps?: AcpRuntimeDeps): AcpAgent;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { PermissionRequest, Permissions } from './permissions';
|
|
2
|
+
import { type ChatMessage, type Provider, type Usage } from './provider';
|
|
3
|
+
import type { ReasoningLevel } from './reasoning';
|
|
4
|
+
import { type HookEvent, type HooksConfig } from './hooks';
|
|
5
|
+
import type { Tool } from './tools/types';
|
|
6
|
+
import { type UsageCap } from './budget';
|
|
7
|
+
export type AgentEvent = {
|
|
8
|
+
type: 'text';
|
|
9
|
+
delta: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'thinking';
|
|
12
|
+
delta: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'textReplace';
|
|
15
|
+
text: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'toolStart';
|
|
18
|
+
id: string;
|
|
19
|
+
tool: string;
|
|
20
|
+
target: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'toolEnd';
|
|
23
|
+
id: string;
|
|
24
|
+
tool: string;
|
|
25
|
+
output: string;
|
|
26
|
+
display?: string;
|
|
27
|
+
isError: boolean;
|
|
28
|
+
} | {
|
|
29
|
+
type: 'usage';
|
|
30
|
+
inputTokens: number;
|
|
31
|
+
outputTokens: number;
|
|
32
|
+
cachedInputTokens?: number;
|
|
33
|
+
cacheWriteTokens?: number;
|
|
34
|
+
/** Prompt tokens of the most recent model call: the size of the context, not the session total. */
|
|
35
|
+
lastInputTokens?: number;
|
|
36
|
+
/** Cache reads for the most recent model call, rather than the session total. */
|
|
37
|
+
lastCachedInputTokens?: number;
|
|
38
|
+
/** True when the provider omitted usage and token counts use the local chars/4 estimate. */
|
|
39
|
+
estimated?: boolean;
|
|
40
|
+
} | {
|
|
41
|
+
type: 'compacted';
|
|
42
|
+
} | {
|
|
43
|
+
type: 'stepLimit';
|
|
44
|
+
maxSteps: number;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'budgetExceeded';
|
|
47
|
+
kind: 'tokens' | 'usd';
|
|
48
|
+
used: number;
|
|
49
|
+
limit: number;
|
|
50
|
+
} | {
|
|
51
|
+
type: 'aborted';
|
|
52
|
+
} | {
|
|
53
|
+
type: 'error';
|
|
54
|
+
message: string;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'done';
|
|
57
|
+
} | {
|
|
58
|
+
type: 'subagent';
|
|
59
|
+
parentId: string;
|
|
60
|
+
agent: string;
|
|
61
|
+
event: AgentEvent;
|
|
62
|
+
};
|
|
63
|
+
export type PermissionAnswer = 'yes' | 'session' | 'all' | 'no';
|
|
64
|
+
export type PermissionAsk = PermissionRequest & {
|
|
65
|
+
preview?: string;
|
|
66
|
+
sessionRules?: string[];
|
|
67
|
+
agent?: string;
|
|
68
|
+
};
|
|
69
|
+
export type AskPermission = (req: PermissionAsk) => Promise<PermissionAnswer>;
|
|
70
|
+
export interface AgentOptions {
|
|
71
|
+
provider: Provider;
|
|
72
|
+
tools: Tool[];
|
|
73
|
+
permissions: Permissions;
|
|
74
|
+
systemPrompt: string;
|
|
75
|
+
cwd: string;
|
|
76
|
+
history?: ChatMessage[];
|
|
77
|
+
maxSteps?: number | null;
|
|
78
|
+
contextWindow?: number;
|
|
79
|
+
onMessage?: (message: ChatMessage) => void;
|
|
80
|
+
onReset?: () => void;
|
|
81
|
+
/** Per-turn token usage delta (provider-reported or estimated); the session persists it for stats. */
|
|
82
|
+
onUsage?: (usage: Usage) => void;
|
|
83
|
+
/** Marks the start of a user turn (undo boundary). */
|
|
84
|
+
onTurnStart?: () => void;
|
|
85
|
+
checkpoint?: (absPath: string) => Promise<void>;
|
|
86
|
+
/** Subagent name, shown on its permission prompts. */
|
|
87
|
+
label?: string;
|
|
88
|
+
reasoning?: ReasoningLevel;
|
|
89
|
+
/** Tool/session hooks (global config only). */
|
|
90
|
+
hooks?: HooksConfig;
|
|
91
|
+
/** In-process plugin observers fired alongside the shell hooks (global config plugins). */
|
|
92
|
+
pluginEmit?: (event: HookEvent, payload?: {
|
|
93
|
+
tool?: string;
|
|
94
|
+
input?: unknown;
|
|
95
|
+
output?: string;
|
|
96
|
+
}) => Promise<void>;
|
|
97
|
+
/** Base environment handed to hook processes (defaults to the process env at spawn). */
|
|
98
|
+
env?: NodeJS.ProcessEnv;
|
|
99
|
+
/** Per-session token/USD budget (global config usageCap); blocks model calls once exceeded. */
|
|
100
|
+
usageCap?: UsageCap;
|
|
101
|
+
/** Model ref used to match usageCap.prices keys. */
|
|
102
|
+
budgetModel?: string;
|
|
103
|
+
}
|
|
104
|
+
export declare class Agent {
|
|
105
|
+
private readonly opts;
|
|
106
|
+
provider: Provider;
|
|
107
|
+
permissions: Permissions;
|
|
108
|
+
messages: ChatMessage[];
|
|
109
|
+
totalUsage: Usage;
|
|
110
|
+
lastInputTokens: number;
|
|
111
|
+
lastInputEstimated: boolean;
|
|
112
|
+
onEvent: (event: AgentEvent) => void;
|
|
113
|
+
reasoning: ReasoningLevel;
|
|
114
|
+
askPermission: AskPermission;
|
|
115
|
+
tools: Tool[];
|
|
116
|
+
private definitions;
|
|
117
|
+
private turnTools;
|
|
118
|
+
private turnDefinitions;
|
|
119
|
+
readonly readFiles: Set<string>;
|
|
120
|
+
private readonly webBudget;
|
|
121
|
+
private readonly maxSteps?;
|
|
122
|
+
private contextWindow;
|
|
123
|
+
private budgetModel;
|
|
124
|
+
private systemPrompt;
|
|
125
|
+
constructor(opts: AgentOptions);
|
|
126
|
+
setSystemPrompt(text: string): void;
|
|
127
|
+
setContextWindow(window: number): void;
|
|
128
|
+
getContextWindow(): number;
|
|
129
|
+
setBudgetModel(model: string): void;
|
|
130
|
+
getBudgetModel(): string;
|
|
131
|
+
setTools(tools: Tool[]): void;
|
|
132
|
+
private isParallelSafe;
|
|
133
|
+
private push;
|
|
134
|
+
private estimateCurrentInputTokens;
|
|
135
|
+
private seedEstimatedContext;
|
|
136
|
+
/** Publish the latest context after prompt/history changes, without changing session usage totals. */
|
|
137
|
+
private publishContextMetadata;
|
|
138
|
+
/** Swaps in another conversation (resume, new session) without writing to the session log. */
|
|
139
|
+
load(messages: ChatMessage[]): void;
|
|
140
|
+
clear(): void;
|
|
141
|
+
compact(signal: AbortSignal): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* Events of one tool execution. A cancelled turn gives up on a tool that does not stop, and whatever that tool
|
|
144
|
+
* reports later must not reach the screen or a newer turn, so this is per execution and not per call id (ids repeat).
|
|
145
|
+
*/
|
|
146
|
+
private report;
|
|
147
|
+
run(text: string, signal: AbortSignal): Promise<void>;
|
|
148
|
+
/** Current cap status; undefined means the budget is not exhausted. */
|
|
149
|
+
private overBudget;
|
|
150
|
+
/** Every tool call needs an answer in the history, or the next request to the model is rejected. */
|
|
151
|
+
private cancelCalls;
|
|
152
|
+
/**
|
|
153
|
+
* Every tool call must resolve with text: a rejected one would leave the assistant tool_calls
|
|
154
|
+
* without answers, and the next request to the model would be rejected until a restart.
|
|
155
|
+
*/
|
|
156
|
+
private runTool;
|
|
157
|
+
private executeTool;
|
|
158
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AgentDef } from './extensions';
|
|
2
|
+
export declare const EXPLORE_PROMPT = "You are a read-only research agent working for another agent. Search and read the codebase to answer the request. You cannot edit files or run commands. Reply with a concise report: the answer, the relevant file paths with line numbers, and nothing else.";
|
|
3
|
+
export declare const GENERAL_PROMPT = "You are an agent handling a delegated task for another agent. Complete the task end to end with the tools you have, verify the result, and reply with a short report of what you did and what you found.";
|
|
4
|
+
export declare const BUILTIN_AGENTS: AgentDef[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
helpText,
|
|
4
|
+
parseCliArgs
|
|
5
|
+
} from "./chunk-M5T4AM4I.js";
|
|
6
|
+
import "./chunk-YYTFJUO2.js";
|
|
7
|
+
import "./chunk-NGFWBVHD.js";
|
|
8
|
+
import "./chunk-ZXWRLN7E.js";
|
|
9
|
+
import "./chunk-IDZLHEVL.js";
|
|
10
|
+
export {
|
|
11
|
+
helpText,
|
|
12
|
+
parseCliArgs
|
|
13
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type PermissionMode } from './config';
|
|
2
|
+
import { type ReasoningLevel } from './reasoning';
|
|
3
|
+
import { type Lang } from './i18n';
|
|
4
|
+
export interface CliArgs {
|
|
5
|
+
command: 'run' | 'login' | 'models' | 'update' | 'acp' | 'serve' | 'plugins' | 'gh-bot' | 'provider' | 'mcp' | 'connect' | 'disconnect' | 'integrations' | 'completion' | 'stats' | 'export' | 'import' | 'pr';
|
|
6
|
+
subArgs: string[];
|
|
7
|
+
url?: string;
|
|
8
|
+
/** `bccli mcp add <name> --command <cmd>`: server stdio, bukan HTTP. */
|
|
9
|
+
stdioCommand?: string;
|
|
10
|
+
/** Argumen untuk server stdio (dipisah spasi). */
|
|
11
|
+
stdioArgs?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
keyEnv?: string;
|
|
14
|
+
values: string[];
|
|
15
|
+
prompt?: string;
|
|
16
|
+
print: boolean;
|
|
17
|
+
model?: string;
|
|
18
|
+
reasoning?: ReasoningLevel;
|
|
19
|
+
lang?: Lang;
|
|
20
|
+
continue: boolean;
|
|
21
|
+
resume: boolean;
|
|
22
|
+
allowAll: boolean;
|
|
23
|
+
/** `-p` untuk CI: kegagalan tool apa pun membuat exit code 1. */
|
|
24
|
+
failOnToolError: boolean;
|
|
25
|
+
allowedTools: string[];
|
|
26
|
+
worktree?: string;
|
|
27
|
+
outputFormat?: 'text' | 'json' | 'stream-json';
|
|
28
|
+
permissionMode?: PermissionMode;
|
|
29
|
+
help: boolean;
|
|
30
|
+
version: boolean;
|
|
31
|
+
loginProvider?: string;
|
|
32
|
+
/** `bccli login` — pakai prompt API key lama, bukan OAuth. */
|
|
33
|
+
key: boolean;
|
|
34
|
+
/** `bccli login` — hapus credential tersimpan (hanya openrouter via OAuth path). */
|
|
35
|
+
logout: boolean;
|
|
36
|
+
/** `bccli serve` listener port (0 = ephemeral). */
|
|
37
|
+
port?: number;
|
|
38
|
+
/** `bccli serve` bind address — loopback only. */
|
|
39
|
+
host?: string;
|
|
40
|
+
/** `bccli serve` bearer token override. */
|
|
41
|
+
token?: string;
|
|
42
|
+
/** Base URL override for `bccli mcp serve`. */
|
|
43
|
+
baseUrl?: string;
|
|
44
|
+
/** `bccli stats` — only count sessions from the last N days (default 7). */
|
|
45
|
+
days?: number;
|
|
46
|
+
/** `bccli stats` - cap the tool-usage list to the top N tools. */
|
|
47
|
+
tools?: number;
|
|
48
|
+
/** `bccli stats [--models [N|all]]` - show per-model token usage (top N or all). */
|
|
49
|
+
models?: string;
|
|
50
|
+
/** `bccli stats --project <slug>` - filter rows; empty string = current project. */
|
|
51
|
+
project?: string;
|
|
52
|
+
/** `bccli pr` — explicit owner/name repo when cwd is not a git checkout of the PR. */
|
|
53
|
+
repo?: string;
|
|
54
|
+
/** Automatic fallback model ref when the primary model fails with 429 or 5xx. */
|
|
55
|
+
fallbackModel?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Help text in the current language (call it after the language is set). */
|
|
58
|
+
export declare const helpText: () => string;
|
|
59
|
+
export declare function parseCliArgs(argv: string[]): CliArgs;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface UsageCap {
|
|
2
|
+
/** Total tokens (input + output) per session. */
|
|
3
|
+
tokens?: number;
|
|
4
|
+
/** Total USD per session; requires `prices`. */
|
|
5
|
+
usd?: number;
|
|
6
|
+
/** USD per 1M tokens. `cachedInput` is optional: without it cache reads cost the input price. */
|
|
7
|
+
prices?: Record<string, {
|
|
8
|
+
input: number;
|
|
9
|
+
output: number;
|
|
10
|
+
cachedInput?: number;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
export declare function priceFor(cap: UsageCap, model: string): {
|
|
14
|
+
input: number;
|
|
15
|
+
output: number;
|
|
16
|
+
cachedInput?: number;
|
|
17
|
+
} | undefined;
|
|
18
|
+
export declare function budgetStatus(usage: {
|
|
19
|
+
inputTokens: number;
|
|
20
|
+
outputTokens: number;
|
|
21
|
+
cachedInputTokens?: number;
|
|
22
|
+
}, cap: UsageCap | undefined, model: string): {
|
|
23
|
+
kind: 'tokens' | 'usd';
|
|
24
|
+
used: number;
|
|
25
|
+
limit: number;
|
|
26
|
+
} | undefined;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
interface UndoResult {
|
|
2
|
+
restored: string[];
|
|
3
|
+
deleted: string[];
|
|
4
|
+
skipped: string[];
|
|
5
|
+
failed: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare class CheckpointStore {
|
|
8
|
+
private readonly history;
|
|
9
|
+
private current;
|
|
10
|
+
private pendingRedo;
|
|
11
|
+
private offset;
|
|
12
|
+
beginTurn(): void;
|
|
13
|
+
/** Call before writing a file; only the first snapshot per file per turn is kept. */
|
|
14
|
+
snapshot(path: string): Promise<void>;
|
|
15
|
+
turns(): number;
|
|
16
|
+
/** Total entries including empty ones; used to align file snapshots with conversation turns. */
|
|
17
|
+
entries(): number;
|
|
18
|
+
undo(): Promise<UndoResult | undefined>;
|
|
19
|
+
/**
|
|
20
|
+
* Revert every snapshot taken at or after the `keep`-th entry, newest first, so the files
|
|
21
|
+
* end in the state from before the turn that created entry `keep`. Used by /rewind, which
|
|
22
|
+
* pairs conversation turns with the entry count recorded when each turn started.
|
|
23
|
+
*/
|
|
24
|
+
undoTo(keep: number): Promise<UndoResult | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Re-apply the file state captured right before the last undo/undoTo.
|
|
27
|
+
* Only file edits are redone, never conversation history. Invalidated by
|
|
28
|
+
* any new snapshot turn or clear(), so redo can't resurrect stale content.
|
|
29
|
+
*/
|
|
30
|
+
redo(): Promise<UndoResult | undefined>;
|
|
31
|
+
/** Records the on-disk state of a turn's paths so redo() can put it back. */
|
|
32
|
+
private captureFor;
|
|
33
|
+
clear(): void;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
hasKey,
|
|
4
|
+
providerName
|
|
5
|
+
} from "./chunk-FY543EQW.js";
|
|
6
|
+
import {
|
|
7
|
+
createProvider
|
|
8
|
+
} from "./chunk-OCEQ2TRJ.js";
|
|
9
|
+
import {
|
|
10
|
+
PRESETS,
|
|
11
|
+
readCredentials
|
|
12
|
+
} from "./chunk-ZXWRLN7E.js";
|
|
13
|
+
import {
|
|
14
|
+
t
|
|
15
|
+
} from "./chunk-IDZLHEVL.js";
|
|
16
|
+
|
|
17
|
+
// src/models.ts
|
|
18
|
+
function order(ids) {
|
|
19
|
+
const presetIds = PRESETS.map((p) => p.id);
|
|
20
|
+
const presets = presetIds.filter((id) => ids.includes(id));
|
|
21
|
+
const custom = ids.filter((id) => !presetIds.includes(id)).sort();
|
|
22
|
+
return [...presets, ...custom];
|
|
23
|
+
}
|
|
24
|
+
async function listAllModels(config, env = process.env, opts = {}) {
|
|
25
|
+
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
26
|
+
const baseFetch = opts.fetch ?? fetch;
|
|
27
|
+
const untrusted = new Set(config.projectProviders ?? []);
|
|
28
|
+
const ids = order(Object.keys(config.providers)).filter((id) => opts.only ? id === opts.only : !untrusted.has(id) && hasKey(config, id, env));
|
|
29
|
+
const results = await Promise.all(
|
|
30
|
+
ids.map(async (id) => {
|
|
31
|
+
const provider = config.providers[id];
|
|
32
|
+
const apiKey = (opts.keyOverride && id === opts.only ? opts.keyOverride : void 0) || readCredentials(env)[id] || (provider.apiKeyEnv ? env[provider.apiKeyEnv] : void 0) || void 0;
|
|
33
|
+
const local = !provider.apiKeyEnv;
|
|
34
|
+
const timedFetch = ((input, init) => baseFetch(input, { ...init, signal: AbortSignal.timeout(timeoutMs) }));
|
|
35
|
+
const list = createProvider({ baseURL: provider.baseURL.replace(/\/+$/, ""), apiKey, model: "", fetch: timedFetch }).listModels();
|
|
36
|
+
let timer;
|
|
37
|
+
const timeout = new Promise((_, reject) => {
|
|
38
|
+
timer = setTimeout(() => reject(new Error("timeout")), timeoutMs);
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
const models = await Promise.race([list, timeout]);
|
|
42
|
+
return { providerId: id, providerName: providerName(config, id), models };
|
|
43
|
+
} catch {
|
|
44
|
+
if (local && !opts.only) return void 0;
|
|
45
|
+
return { providerId: id, providerName: providerName(config, id), models: [], error: t("could not be reached") };
|
|
46
|
+
} finally {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
return results.filter((g) => !!g);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
listAllModels
|
|
56
|
+
};
|