@botconnector/bccli 0.4.17 → 0.5.0-rc.4
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/LICENSE +203 -21
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/branding.mjs +347 -0
- package/cli.mjs +120 -0
- package/core.mjs +260 -0
- package/credentials.mjs +52 -0
- package/gateway.mjs +2 -0
- package/model-command.mjs +61 -0
- package/package.json +35 -59
- package/provider-cli.mjs +77 -0
- package/providers.mjs +166 -0
- package/proxy.mjs +242 -0
- package/startup-menu.mjs +120 -0
- package/README.en.md +0 -253
- package/README.md +0 -250
- package/dist/abort.d.ts +0 -5
- package/dist/acp-HWHF25KU.js +0 -221
- package/dist/acp.d.ts +0 -44
- package/dist/agent.d.ts +0 -158
- package/dist/agents.d.ts +0 -4
- package/dist/args-XA77XUMD.js +0 -13
- package/dist/args.d.ts +0 -59
- package/dist/budget.d.ts +0 -26
- package/dist/checkpoints.d.ts +0 -35
- package/dist/chunk-2IP5F3EK.js +0 -56
- package/dist/chunk-5CVHTYBQ.js +0 -270
- package/dist/chunk-6LO6YRDY.js +0 -216
- package/dist/chunk-6PJRWKVI.js +0 -50
- package/dist/chunk-7OTFZK4B.js +0 -159
- package/dist/chunk-7U7CMKKI.js +0 -861
- package/dist/chunk-A3NBWIEQ.js +0 -2706
- package/dist/chunk-FY543EQW.js +0 -50
- package/dist/chunk-IDZLHEVL.js +0 -524
- package/dist/chunk-IF5RNXBI.js +0 -341
- package/dist/chunk-M5T4AM4I.js +0 -256
- package/dist/chunk-NGFWBVHD.js +0 -71
- package/dist/chunk-OCEQ2TRJ.js +0 -1075
- package/dist/chunk-OK2USAXX.js +0 -88
- package/dist/chunk-PSO7R5AD.js +0 -10
- package/dist/chunk-RLSQAZBT.js +0 -78
- package/dist/chunk-VPFCIUC6.js +0 -91
- package/dist/chunk-XP5MTJN2.js +0 -8
- package/dist/chunk-YGBTNDPK.js +0 -202
- package/dist/chunk-YYTFJUO2.js +0 -148
- package/dist/chunk-ZXWRLN7E.js +0 -378
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -233
- package/dist/clipboardImage.d.ts +0 -17
- package/dist/commands.d.ts +0 -16
- package/dist/completion-IRVEVW6H.js +0 -125
- package/dist/completion.d.ts +0 -14
- package/dist/config-OVWCUVY7.js +0 -25
- package/dist/config-S3CZUIBB.js +0 -34
- package/dist/config.d.ts +0 -99
- package/dist/context.d.ts +0 -13
- package/dist/contextWindow.d.ts +0 -3
- package/dist/diff.d.ts +0 -7
- package/dist/exit.d.ts +0 -9
- package/dist/extensions.d.ts +0 -34
- package/dist/ghBotCli-FYKJDJOD.js +0 -680
- package/dist/ghBotCli.d.ts +0 -9
- package/dist/ghBotDispatch.d.ts +0 -68
- package/dist/ghBotRunner.d.ts +0 -82
- package/dist/ghBotServe.d.ts +0 -21
- package/dist/ghBotWebhook.d.ts +0 -45
- package/dist/hooks.d.ts +0 -27
- package/dist/i18n/id.d.ts +0 -1
- package/dist/i18n.d.ts +0 -16
- package/dist/integrationCli-GY73S2K7.js +0 -876
- package/dist/integrationCli.d.ts +0 -9
- package/dist/keybinds.d.ts +0 -22
- package/dist/login-KSN63EM4.js +0 -18
- package/dist/login.d.ts +0 -21
- package/dist/lsp.d.ts +0 -73
- package/dist/mcp/catalog.d.ts +0 -14
- package/dist/mcp/config.d.ts +0 -36
- package/dist/mcp/manager.d.ts +0 -52
- package/dist/mcp/oauth.d.ts +0 -82
- package/dist/mcpCli-VWSCCDWT.js +0 -113
- package/dist/mcpCli.d.ts +0 -3
- package/dist/mcpServer/serve.d.ts +0 -8
- package/dist/mcpServer/server.d.ts +0 -19
- package/dist/models.d.ts +0 -13
- package/dist/modelsCli-4Q6KFWV2.js +0 -36
- package/dist/modelsCli.d.ts +0 -15
- package/dist/npmRunner-LU43GM3W.js +0 -46
- package/dist/npmRunner.d.ts +0 -21
- package/dist/oauthLogin-JWXQZTMZ.js +0 -210
- package/dist/oauthLogin.d.ts +0 -47
- package/dist/permissions.d.ts +0 -30
- package/dist/pluginSpec.d.ts +0 -25
- package/dist/plugins.d.ts +0 -45
- package/dist/pluginsCli-7XWDLJEL.js +0 -288
- package/dist/pluginsCli.d.ts +0 -16
- package/dist/prCli-FH7N26D4.js +0 -94
- package/dist/prCli.d.ts +0 -46
- package/dist/presets.d.ts +0 -8
- package/dist/print.d.ts +0 -17
- package/dist/provider.d.ts +0 -145
- package/dist/providerCli-YMG4G56R.js +0 -15
- package/dist/providerCli.d.ts +0 -17
- package/dist/providers.d.ts +0 -6
- package/dist/reasoning.d.ts +0 -12
- package/dist/repomap.d.ts +0 -10
- package/dist/sdk.d.ts +0 -61
- package/dist/sdk.js +0 -6532
- package/dist/serve-HSFF6MGB.js +0 -178
- package/dist/serve-HUQNVOSP.js +0 -532
- package/dist/serve.d.ts +0 -37
- package/dist/serveHeartbeat.d.ts +0 -14
- package/dist/serveProtocol.d.ts +0 -47
- package/dist/session-YM36TGU7.js +0 -12
- package/dist/session.d.ts +0 -33
- package/dist/setup-3YB6EKYX.js +0 -24
- package/dist/setup.d.ts +0 -79
- package/dist/slash/copy.d.ts +0 -1
- package/dist/slash/diff.d.ts +0 -1
- package/dist/slash/doctor.d.ts +0 -18
- package/dist/slash/export.d.ts +0 -2
- package/dist/slash/info.d.ts +0 -46
- package/dist/slash/memory.d.ts +0 -10
- package/dist/statsCli-I4TSDU3X.js +0 -353
- package/dist/statsCli.d.ts +0 -62
- package/dist/textToolCalls.d.ts +0 -6
- package/dist/thinking.d.ts +0 -17
- package/dist/tokenBudget.d.ts +0 -22
- package/dist/tools/bash.d.ts +0 -54
- package/dist/tools/diagnostics.d.ts +0 -13
- package/dist/tools/edit.d.ts +0 -12
- package/dist/tools/fetch.d.ts +0 -41
- package/dist/tools/glob.d.ts +0 -5
- package/dist/tools/globSafety.d.ts +0 -7
- package/dist/tools/grep.d.ts +0 -25
- package/dist/tools/ignore.d.ts +0 -2
- package/dist/tools/index.d.ts +0 -12
- package/dist/tools/memory.d.ts +0 -13
- package/dist/tools/paths.d.ts +0 -4
- package/dist/tools/plan.d.ts +0 -10
- package/dist/tools/read.d.ts +0 -16
- package/dist/tools/repomap.d.ts +0 -2
- package/dist/tools/sandbox.d.ts +0 -15
- package/dist/tools/shell.d.ts +0 -18
- package/dist/tools/skill.d.ts +0 -3
- package/dist/tools/task.d.ts +0 -28
- package/dist/tools/todo.d.ts +0 -13
- package/dist/tools/types.d.ts +0 -52
- package/dist/tools/websearch.d.ts +0 -9
- package/dist/tools/write.d.ts +0 -5
- package/dist/transferCli-3B4LMOYI.js +0 -73
- package/dist/transferCli.d.ts +0 -23
- package/dist/ui/App.d.ts +0 -7
- package/dist/ui/DiffView.d.ts +0 -3
- package/dist/ui/EditableText.d.ts +0 -7
- package/dist/ui/LinePrompt.d.ts +0 -6
- package/dist/ui/ListPicker.d.ts +0 -11
- package/dist/ui/Markdown.d.ts +0 -8
- package/dist/ui/McpMenu.d.ts +0 -11
- package/dist/ui/ModelPicker.d.ts +0 -6
- package/dist/ui/PermissionPrompt.d.ts +0 -5
- package/dist/ui/PlanApproval.d.ts +0 -5
- package/dist/ui/PromptInput.d.ts +0 -20
- package/dist/ui/ProviderMenu.d.ts +0 -10
- package/dist/ui/Spinner.d.ts +0 -4
- package/dist/ui/StatusBar.d.ts +0 -14
- package/dist/ui/TodoList.d.ts +0 -4
- package/dist/ui/ToolBlock.d.ts +0 -14
- package/dist/ui/complete.d.ts +0 -8
- package/dist/ui/index.d.ts +0 -7
- package/dist/ui/lineEdit.d.ts +0 -42
- package/dist/ui/liveCap.d.ts +0 -29
- package/dist/ui/markdownLayout.d.ts +0 -23
- package/dist/ui/replay.d.ts +0 -4
- package/dist/ui/stdinFilter.d.ts +0 -18
- package/dist/ui/table.d.ts +0 -20
- package/dist/ui/theme.d.ts +0 -5
- package/dist/ui/thinkingMouse.d.ts +0 -38
- package/dist/ui/transcript.d.ts +0 -55
- package/dist/ui/tty.d.ts +0 -11
- package/dist/ui/vim.d.ts +0 -26
- package/dist/ui-TAZMRXRI.js +0 -3044
- package/dist/update-5V425FIK.js +0 -145
- package/dist/update.d.ts +0 -30
- package/dist/verify.d.ts +0 -16
- package/dist/version.d.ts +0 -1
- package/dist/webBudget.d.ts +0 -25
- package/dist/worktree.d.ts +0 -12
package/dist/chunk-5CVHTYBQ.js
DELETED
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
runCommand,
|
|
4
|
-
runHooks
|
|
5
|
-
} from "./chunk-7U7CMKKI.js";
|
|
6
|
-
import {
|
|
7
|
-
ConfigError
|
|
8
|
-
} from "./chunk-ZXWRLN7E.js";
|
|
9
|
-
import {
|
|
10
|
-
t
|
|
11
|
-
} from "./chunk-IDZLHEVL.js";
|
|
12
|
-
|
|
13
|
-
// src/verify.ts
|
|
14
|
-
var MAX_VERIFY_ROUNDS = 2;
|
|
15
|
-
async function runVerify(commands, opts) {
|
|
16
|
-
const run = opts.run ?? runCommand;
|
|
17
|
-
const failures = [];
|
|
18
|
-
for (const cmd of commands) {
|
|
19
|
-
const r = await run(cmd, { cwd: opts.cwd, timeoutMs: opts.timeoutMs ?? 3e5, signal: opts.signal, env: opts.env });
|
|
20
|
-
const exitCode = r.exitCode ?? -1;
|
|
21
|
-
if (exitCode !== 0) failures.push({ cmd, exitCode, output: r.output });
|
|
22
|
-
}
|
|
23
|
-
return failures;
|
|
24
|
-
}
|
|
25
|
-
function verifyFollowup(failures, maxBytes = 8e3) {
|
|
26
|
-
const blocks = failures.map((f) => {
|
|
27
|
-
const output = f.output.length > maxBytes ? `${f.output.slice(0, maxBytes)}
|
|
28
|
-
[truncated]` : f.output;
|
|
29
|
-
return `$ ${f.cmd}
|
|
30
|
-
[exit code ${f.exitCode}]
|
|
31
|
-
${output}`;
|
|
32
|
-
});
|
|
33
|
-
return t("Automatic verification after your edits failed. Fix the problems so these commands pass, then stop.\n\n{blocks}", {
|
|
34
|
-
blocks: blocks.join("\n\n")
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// src/print.ts
|
|
39
|
-
function toolLabel(tool) {
|
|
40
|
-
if (tool === "web_search") return "Search";
|
|
41
|
-
return tool.charAt(0).toUpperCase() + tool.slice(1);
|
|
42
|
-
}
|
|
43
|
-
function resolvePrintPrompt(prompt, stdinText) {
|
|
44
|
-
const cleanStdin = stdinText?.trim();
|
|
45
|
-
const cleanPrompt = prompt?.trim();
|
|
46
|
-
if (cleanStdin && cleanPrompt) return `${cleanStdin}
|
|
47
|
-
|
|
48
|
-
${cleanPrompt}`;
|
|
49
|
-
return cleanPrompt || cleanStdin || void 0;
|
|
50
|
-
}
|
|
51
|
-
async function runPrint(rt, prompt, io = { out: process.stdout, err: process.stderr }, opts = {}) {
|
|
52
|
-
const format = opts.outputFormat ?? "text";
|
|
53
|
-
const emit = (line) => io.out.write(`${JSON.stringify(line)}
|
|
54
|
-
`);
|
|
55
|
-
const startedMs = Date.now();
|
|
56
|
-
let result = "";
|
|
57
|
-
const toolNames = /* @__PURE__ */ new Map();
|
|
58
|
-
rt.interaction.approvePlan = async () => {
|
|
59
|
-
if (opts.allowAll) return "allowAll";
|
|
60
|
-
io.err.write(`${t("Plan needs approval; run with --allow-all.")}
|
|
61
|
-
`);
|
|
62
|
-
return "no";
|
|
63
|
-
};
|
|
64
|
-
let failed = false;
|
|
65
|
-
let wroteText = false;
|
|
66
|
-
let edited = false;
|
|
67
|
-
rt.agent.onEvent = (event) => {
|
|
68
|
-
switch (event.type) {
|
|
69
|
-
case "text":
|
|
70
|
-
if (format === "text") {
|
|
71
|
-
io.out.write(event.delta);
|
|
72
|
-
wroteText = true;
|
|
73
|
-
} else {
|
|
74
|
-
result += event.delta;
|
|
75
|
-
if (format === "stream-json") emit({ type: "text_delta", delta: event.delta });
|
|
76
|
-
}
|
|
77
|
-
break;
|
|
78
|
-
case "thinking":
|
|
79
|
-
if (format === "stream-json") emit({ type: "thinking_delta", delta: event.delta });
|
|
80
|
-
break;
|
|
81
|
-
case "textReplace":
|
|
82
|
-
result = event.text;
|
|
83
|
-
break;
|
|
84
|
-
case "toolStart":
|
|
85
|
-
toolNames.set(event.id, event.tool);
|
|
86
|
-
io.err.write(`\u23BF ${toolLabel(event.tool)} ${event.target}
|
|
87
|
-
`);
|
|
88
|
-
if (format === "stream-json") emit({ type: "tool_use", tool: event.tool, target: event.target });
|
|
89
|
-
break;
|
|
90
|
-
case "toolEnd":
|
|
91
|
-
if (event.isError) io.err.write(` \u2717 ${event.output.split("\n")[0]}
|
|
92
|
-
`);
|
|
93
|
-
if (event.isError && opts.failOnToolError) failed = true;
|
|
94
|
-
if ((event.tool === "edit" || event.tool === "write") && !event.isError) edited = true;
|
|
95
|
-
if (format === "stream-json") emit({ type: "tool_result", tool: toolNames.get(event.id), isError: !!event.isError, output: event.output });
|
|
96
|
-
break;
|
|
97
|
-
case "stepLimit":
|
|
98
|
-
io.err.write(`${t("Step limit reached.")}
|
|
99
|
-
`);
|
|
100
|
-
failed = true;
|
|
101
|
-
break;
|
|
102
|
-
case "budgetExceeded":
|
|
103
|
-
io.err.write(`${t("Budget exceeded ({kind}): {used} of {limit}. Further model calls are blocked; raise usageCap in ~/.bccli/config.json.", { kind: event.kind, used: Math.round(event.used * 100) / 100, limit: event.limit })}
|
|
104
|
-
`);
|
|
105
|
-
if (format === "stream-json") emit({ type: "error", message: "budgetExceeded" });
|
|
106
|
-
failed = true;
|
|
107
|
-
break;
|
|
108
|
-
case "aborted":
|
|
109
|
-
io.err.write(`${t("Cancelled.")}
|
|
110
|
-
`);
|
|
111
|
-
failed = true;
|
|
112
|
-
break;
|
|
113
|
-
case "error":
|
|
114
|
-
io.err.write(`Error: ${event.message}
|
|
115
|
-
`);
|
|
116
|
-
if (format === "stream-json") emit({ type: "error", message: event.message });
|
|
117
|
-
failed = true;
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
rt.agent.askPermission = async (req) => {
|
|
122
|
-
io.err.write(` ${t("Needs permission for {tool}. Run with --allow-all or --allowed-tools {kind}.", { tool: req.tool, kind: req.kind })}
|
|
123
|
-
`);
|
|
124
|
-
return "no";
|
|
125
|
-
};
|
|
126
|
-
const controller = new AbortController();
|
|
127
|
-
const onSigint = () => controller.abort();
|
|
128
|
-
process.once("SIGINT", onSigint);
|
|
129
|
-
const onSigbreak = () => controller.abort();
|
|
130
|
-
const useSigbreak = process.platform === "win32";
|
|
131
|
-
if (useSigbreak) process.once("SIGBREAK", onSigbreak);
|
|
132
|
-
const start = await runHooks(rt.config.hooks, "SessionStart", {}, { env: rt.env, cwd: rt.cwd });
|
|
133
|
-
for (const warning of start.warnings) io.err.write(`${warning}
|
|
134
|
-
`);
|
|
135
|
-
await rt.emitPlugins("SessionStart");
|
|
136
|
-
try {
|
|
137
|
-
await rt.agent.run(prompt, controller.signal);
|
|
138
|
-
const commands = rt.config.verifyCommands;
|
|
139
|
-
if (edited && commands.length && !controller.signal.aborted) {
|
|
140
|
-
for (let round = 0; round < MAX_VERIFY_ROUNDS; round++) {
|
|
141
|
-
io.err.write(`${t("Verifying edits: {cmds}", { cmds: commands.join(", ") })}
|
|
142
|
-
`);
|
|
143
|
-
const failures = await runVerify(commands, { cwd: rt.cwd, env: rt.env, signal: controller.signal });
|
|
144
|
-
if (!failures.length) {
|
|
145
|
-
io.err.write(`${t("Verification passed.")}
|
|
146
|
-
`);
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
if (round === MAX_VERIFY_ROUNDS - 1 || controller.signal.aborted) {
|
|
150
|
-
io.err.write(`${t("Verification still failing after {n} fix round(s). Run the commands manually to see why.", { n: MAX_VERIFY_ROUNDS })}
|
|
151
|
-
`);
|
|
152
|
-
failed = true;
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
await rt.agent.run(verifyFollowup(failures), controller.signal);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
} finally {
|
|
159
|
-
process.off("SIGINT", onSigint);
|
|
160
|
-
if (useSigbreak) process.off("SIGBREAK", onSigbreak);
|
|
161
|
-
}
|
|
162
|
-
const stop = await runHooks(rt.config.hooks, "Stop", {}, { env: rt.env, cwd: rt.cwd });
|
|
163
|
-
for (const warning of stop.warnings) io.err.write(`${warning}
|
|
164
|
-
`);
|
|
165
|
-
await rt.emitPlugins("Stop");
|
|
166
|
-
const durationMs = Math.max(0, Date.now() - startedMs);
|
|
167
|
-
if (format === "json") {
|
|
168
|
-
io.out.write(
|
|
169
|
-
`${JSON.stringify({
|
|
170
|
-
status: failed ? "failed" : "ok",
|
|
171
|
-
model: rt.modelRef,
|
|
172
|
-
session_id: rt.session.id,
|
|
173
|
-
usage: rt.agent.totalUsage,
|
|
174
|
-
duration_ms: durationMs,
|
|
175
|
-
result
|
|
176
|
-
})}
|
|
177
|
-
`
|
|
178
|
-
);
|
|
179
|
-
} else if (format === "stream-json") {
|
|
180
|
-
if (result) emit({ type: "message", text: result });
|
|
181
|
-
emit({
|
|
182
|
-
type: "result",
|
|
183
|
-
status: failed ? "failed" : "ok",
|
|
184
|
-
model: rt.modelRef,
|
|
185
|
-
session_id: rt.session.id,
|
|
186
|
-
usage: rt.agent.totalUsage,
|
|
187
|
-
duration_ms: durationMs
|
|
188
|
-
});
|
|
189
|
-
} else if (wroteText) {
|
|
190
|
-
io.out.write("\n");
|
|
191
|
-
}
|
|
192
|
-
return failed ? 1 : 0;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// src/worktree.ts
|
|
196
|
-
import { execFile } from "child_process";
|
|
197
|
-
import { existsSync } from "fs";
|
|
198
|
-
import { basename, dirname, join } from "path";
|
|
199
|
-
function git(cwd, args, bin = "git") {
|
|
200
|
-
return new Promise((resolve) => {
|
|
201
|
-
execFile(
|
|
202
|
-
bin,
|
|
203
|
-
args,
|
|
204
|
-
{ cwd, maxBuffer: 20 * 1024 * 1024 },
|
|
205
|
-
(error, stdout, stderr) => resolve({ ok: !error, out: error ? stderr : stdout, missing: error?.code === "ENOENT" })
|
|
206
|
-
);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
var NAME_RE = /^[A-Za-z0-9._-]+$/;
|
|
210
|
-
function samePath(a, b) {
|
|
211
|
-
const norm = (p) => process.platform === "win32" ? p.replace(/\//g, "\\").toLowerCase() : p.replace(/\\/g, "/");
|
|
212
|
-
return norm(a) === norm(b);
|
|
213
|
-
}
|
|
214
|
-
function worktreeEntries(porcelain) {
|
|
215
|
-
return porcelain.split(/\r?\n\r?\n/).map((block) => {
|
|
216
|
-
const path = /^worktree (.+)$/m.exec(block)?.[1]?.trim();
|
|
217
|
-
if (!path) return void 0;
|
|
218
|
-
const branch = /^branch refs\/heads\/(.+)$/m.exec(block)?.[1];
|
|
219
|
-
return branch ? { path, branch } : { path };
|
|
220
|
-
}).filter((entry) => !!entry);
|
|
221
|
-
}
|
|
222
|
-
async function resolveWorktree(cwd, name, bin = "git") {
|
|
223
|
-
if (!NAME_RE.test(name)) {
|
|
224
|
-
throw new ConfigError(t('Invalid worktree name "{name}": use letters, digits, dot, dash, or underscore (no slashes).', { name }));
|
|
225
|
-
}
|
|
226
|
-
const inside = await git(cwd, ["rev-parse", "--is-inside-work-tree"], bin);
|
|
227
|
-
if (inside.missing) throw new ConfigError(t("git is not installed or not on PATH, so -w cannot be used."));
|
|
228
|
-
if (!inside.ok || inside.out.trim() !== "true") throw new ConfigError(t("This folder is not a git repository, so -w cannot create a worktree."));
|
|
229
|
-
const list = await git(cwd, ["worktree", "list", "--porcelain"], bin);
|
|
230
|
-
if (!list.ok) throw new ConfigError(t("This folder is not a git repository, so -w cannot create a worktree."));
|
|
231
|
-
const entries = worktreeEntries(list.out);
|
|
232
|
-
const main = entries[0]?.path;
|
|
233
|
-
if (!main) throw new ConfigError(t("This folder is not a git repository, so -w cannot create a worktree."));
|
|
234
|
-
const path = join(dirname(main), `${basename(main)}.worktrees`, name);
|
|
235
|
-
if (entries.some((entry) => samePath(entry.path, path))) return { path, created: false };
|
|
236
|
-
if (existsSync(path)) {
|
|
237
|
-
throw new ConfigError(t("Worktree path {path} already exists but is not a registered worktree; remove or rename it first.", { path }));
|
|
238
|
-
}
|
|
239
|
-
const branch = `bccli/${name}`;
|
|
240
|
-
const hasBranch = (await git(main, ["rev-parse", "--verify", "-q", `refs/heads/${branch}`], bin)).ok;
|
|
241
|
-
const add = hasBranch ? await git(main, ["worktree", "add", path, branch], bin) : await git(main, ["worktree", "add", "-b", branch, path], bin);
|
|
242
|
-
if (!add.ok) throw new ConfigError(add.out.trim() || t("This folder is not a git repository, so -w cannot create a worktree."));
|
|
243
|
-
return { path, created: true };
|
|
244
|
-
}
|
|
245
|
-
async function worktreeListText(cwd, bin = "git") {
|
|
246
|
-
const inside = await git(cwd, ["rev-parse", "--is-inside-work-tree"], bin);
|
|
247
|
-
if (inside.missing) return t("git is not installed or not on PATH, so /worktree cannot be used.");
|
|
248
|
-
if (!inside.ok || inside.out.trim() !== "true") return t("This folder is not a git repository, so there is no diff.");
|
|
249
|
-
const list = await git(cwd, ["worktree", "list", "--porcelain"], bin);
|
|
250
|
-
if (!list.ok) return t("This folder is not a git repository, so there is no diff.");
|
|
251
|
-
const rows = worktreeEntries(list.out).map((entry) => ` ${entry.path}${entry.branch ? ` (${entry.branch})` : ""}`);
|
|
252
|
-
return [
|
|
253
|
-
t("Git worktrees:"),
|
|
254
|
-
...rows,
|
|
255
|
-
"",
|
|
256
|
-
t("Create one with: bccli -w <name>"),
|
|
257
|
-
t("Remove with: git worktree remove <path>")
|
|
258
|
-
].join("\n");
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export {
|
|
262
|
-
MAX_VERIFY_ROUNDS,
|
|
263
|
-
runVerify,
|
|
264
|
-
verifyFollowup,
|
|
265
|
-
toolLabel,
|
|
266
|
-
resolvePrintPrompt,
|
|
267
|
-
runPrint,
|
|
268
|
-
resolveWorktree,
|
|
269
|
-
worktreeListText
|
|
270
|
-
};
|
package/dist/chunk-6LO6YRDY.js
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
contentText
|
|
4
|
-
} from "./chunk-OCEQ2TRJ.js";
|
|
5
|
-
|
|
6
|
-
// src/session.ts
|
|
7
|
-
import { randomBytes } from "crypto";
|
|
8
|
-
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from "fs";
|
|
9
|
-
import { basename, dirname, join } from "path";
|
|
10
|
-
function projectDir(home, cwd) {
|
|
11
|
-
const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(-100) || "root";
|
|
12
|
-
return join(home, "sessions", slug);
|
|
13
|
-
}
|
|
14
|
-
function repairTail(messages) {
|
|
15
|
-
const out = [...messages];
|
|
16
|
-
for (let i = out.length - 1; i >= 0; i--) {
|
|
17
|
-
const m = out[i];
|
|
18
|
-
if (m.role !== "assistant" || !m.tool_calls?.length) continue;
|
|
19
|
-
const answered = new Set(out.slice(i + 1).flatMap((x) => x.role === "tool" ? [x.tool_call_id] : []));
|
|
20
|
-
if (!m.tool_calls.every((c) => answered.has(c.id))) out.length = i;
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
return out;
|
|
24
|
-
}
|
|
25
|
-
var Session = class _Session {
|
|
26
|
-
constructor(file) {
|
|
27
|
-
this.file = file;
|
|
28
|
-
}
|
|
29
|
-
file;
|
|
30
|
-
get id() {
|
|
31
|
-
return basename(this.file, ".jsonl");
|
|
32
|
-
}
|
|
33
|
-
static create(home, cwd, now = /* @__PURE__ */ new Date()) {
|
|
34
|
-
const dir = projectDir(home, cwd);
|
|
35
|
-
const stamp = now.toISOString().replace(/[:.]/g, "-");
|
|
36
|
-
return new _Session(join(dir, `${stamp}-${randomBytes(3).toString("hex")}.jsonl`));
|
|
37
|
-
}
|
|
38
|
-
static list(home, cwd) {
|
|
39
|
-
const dir = projectDir(home, cwd);
|
|
40
|
-
if (!existsSync(dir)) return [];
|
|
41
|
-
return readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => {
|
|
42
|
-
const session = new _Session(join(dir, f));
|
|
43
|
-
const first = session.loadHistory().find((m) => m.role === "user");
|
|
44
|
-
return { session, mtime: statSync(session.file).mtime, preview: first ? contentText(first.content).slice(0, 80) : "" };
|
|
45
|
-
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime() || b.session.file.localeCompare(a.session.file));
|
|
46
|
-
}
|
|
47
|
-
static latest(home, cwd) {
|
|
48
|
-
return _Session.list(home, cwd)[0]?.session;
|
|
49
|
-
}
|
|
50
|
-
write(record) {
|
|
51
|
-
mkdirSync(dirname(this.file), { recursive: true });
|
|
52
|
-
appendFileSync(this.file, `${JSON.stringify(record)}
|
|
53
|
-
`);
|
|
54
|
-
}
|
|
55
|
-
append(message) {
|
|
56
|
-
this.write({ t: "msg", m: message });
|
|
57
|
-
}
|
|
58
|
-
appendUsage(usage) {
|
|
59
|
-
this.write({ t: "usage", ...usage });
|
|
60
|
-
}
|
|
61
|
-
reset() {
|
|
62
|
-
this.write({ t: "reset" });
|
|
63
|
-
}
|
|
64
|
-
records() {
|
|
65
|
-
if (!existsSync(this.file)) return [];
|
|
66
|
-
const out = [];
|
|
67
|
-
for (const line of readFileSync(this.file, "utf8").split("\n")) {
|
|
68
|
-
if (!line.trim()) continue;
|
|
69
|
-
try {
|
|
70
|
-
out.push(JSON.parse(line));
|
|
71
|
-
} catch {
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return out;
|
|
75
|
-
}
|
|
76
|
-
/** What the model continues from: everything after the last reset (after a compaction that is the summary and the recent turns). */
|
|
77
|
-
load() {
|
|
78
|
-
let messages = [];
|
|
79
|
-
for (const record of this.records()) {
|
|
80
|
-
if (record.t === "reset") messages = [];
|
|
81
|
-
else if (record.t === "msg") messages.push(record.m);
|
|
82
|
-
}
|
|
83
|
-
return repairTail(messages);
|
|
84
|
-
}
|
|
85
|
-
/** Model of the most recent turn that recorded usage — serve attach continues a session with its own model. */
|
|
86
|
-
lastModel() {
|
|
87
|
-
const records = this.records();
|
|
88
|
-
for (let i = records.length - 1; i >= 0; i--) {
|
|
89
|
-
const record = records[i];
|
|
90
|
-
if (record.t === "usage" && record.model) return record.model;
|
|
91
|
-
}
|
|
92
|
-
return void 0;
|
|
93
|
-
}
|
|
94
|
-
/** Accumulated token usage since the last non-compaction reset. */
|
|
95
|
-
totalUsage() {
|
|
96
|
-
const segments = [{ msgs: [], usage: { inputTokens: 0, outputTokens: 0 } }];
|
|
97
|
-
for (const record of this.records()) {
|
|
98
|
-
const cur = segments[segments.length - 1];
|
|
99
|
-
if (record.t === "reset") {
|
|
100
|
-
segments.push({ msgs: [], usage: { inputTokens: 0, outputTokens: 0 } });
|
|
101
|
-
} else if (record.t === "msg") {
|
|
102
|
-
cur.msgs.push(record.m);
|
|
103
|
-
} else if (record.t === "usage") {
|
|
104
|
-
cur.usage.inputTokens += record.inputTokens;
|
|
105
|
-
cur.usage.outputTokens += record.outputTokens;
|
|
106
|
-
if (record.cachedInputTokens) cur.usage.cachedInputTokens = (cur.usage.cachedInputTokens ?? 0) + record.cachedInputTokens;
|
|
107
|
-
if (record.cacheWriteTokens) cur.usage.cacheWriteTokens = (cur.usage.cacheWriteTokens ?? 0) + record.cacheWriteTokens;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
let total = { ...segments[0].usage };
|
|
111
|
-
for (const seg of segments.slice(1)) {
|
|
112
|
-
if (!isCompactionSummary(seg.msgs[0])) {
|
|
113
|
-
total = { ...seg.usage };
|
|
114
|
-
} else {
|
|
115
|
-
total.inputTokens += seg.usage.inputTokens;
|
|
116
|
-
total.outputTokens += seg.usage.outputTokens;
|
|
117
|
-
if (seg.usage.cachedInputTokens) total.cachedInputTokens = (total.cachedInputTokens ?? 0) + seg.usage.cachedInputTokens;
|
|
118
|
-
if (seg.usage.cacheWriteTokens) total.cacheWriteTokens = (total.cacheWriteTokens ?? 0) + seg.usage.cacheWriteTokens;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return total;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* What the user sees on resume: the whole conversation. Compaction only shrinks what the model is sent, so
|
|
125
|
-
* its reset does not hide the older turns here. A real reset (/clear, rewind) still starts over, the
|
|
126
|
-
* synthetic summary pair is never shown, and the recent turns a compaction re-writes are not shown twice.
|
|
127
|
-
*/
|
|
128
|
-
loadHistory() {
|
|
129
|
-
const segments = [[]];
|
|
130
|
-
for (const record of this.records()) {
|
|
131
|
-
if (record.t === "reset") segments.push([]);
|
|
132
|
-
else if (record.t === "msg") segments[segments.length - 1].push(record.m);
|
|
133
|
-
}
|
|
134
|
-
let shown = segments[0];
|
|
135
|
-
let lastSummary;
|
|
136
|
-
for (const segment of segments.slice(1)) {
|
|
137
|
-
if (!isCompactionSummary(segment[0])) {
|
|
138
|
-
shown = segment;
|
|
139
|
-
lastSummary = void 0;
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
const kept = segment.slice(2);
|
|
143
|
-
if (lastSummary && sameMessage(segment[0], lastSummary)) {
|
|
144
|
-
const subIdx = findContiguousSlice(shown, kept);
|
|
145
|
-
if (subIdx !== -1) {
|
|
146
|
-
shown = shown.slice(0, subIdx + kept.length);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
lastSummary = segment[0];
|
|
151
|
-
let at = 0;
|
|
152
|
-
while (at <= shown.length && !endsWithPrefixOf(shown, at, kept)) at++;
|
|
153
|
-
shown = [...shown, ...kept.slice(shown.length - at)];
|
|
154
|
-
}
|
|
155
|
-
return repairTail(shown.filter((m) => !isCompactionSummary(m) && !isCompactionAck(m)));
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
var SUMMARY_PREFIX = "Summary of the previous conversation:";
|
|
159
|
-
var SUMMARY_ACK = "OK, I will continue from this summary.";
|
|
160
|
-
function isCompactionSummary(m) {
|
|
161
|
-
return m?.role === "user" && typeof m.content === "string" && m.content.startsWith(SUMMARY_PREFIX);
|
|
162
|
-
}
|
|
163
|
-
function isCompactionAck(m) {
|
|
164
|
-
return m.role === "assistant" && m.content === SUMMARY_ACK;
|
|
165
|
-
}
|
|
166
|
-
function sameMessage(a, b) {
|
|
167
|
-
if (a.role !== b.role) return false;
|
|
168
|
-
if (a.role === "tool" && b.role === "tool") return a.tool_call_id === b.tool_call_id;
|
|
169
|
-
return JSON.stringify(a.content) === JSON.stringify(b.content) && JSON.stringify("tool_calls" in a && a.tool_calls) === JSON.stringify("tool_calls" in b && b.tool_calls);
|
|
170
|
-
}
|
|
171
|
-
function endsWithPrefixOf(shown, at, kept) {
|
|
172
|
-
const n = shown.length - at;
|
|
173
|
-
if (n > kept.length) return false;
|
|
174
|
-
for (let j = 0; j < n; j++) if (!sameMessage(shown[at + j], kept[j])) return false;
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
function findContiguousSlice(shown, slice) {
|
|
178
|
-
if (slice.length === 0) return shown.length;
|
|
179
|
-
for (let i = 0; i + slice.length <= shown.length; i++) {
|
|
180
|
-
let ok = true;
|
|
181
|
-
for (let j = 0; j < slice.length; j++) {
|
|
182
|
-
if (!sameMessage(shown[i + j], slice[j])) {
|
|
183
|
-
ok = false;
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
if (ok) return i;
|
|
188
|
-
}
|
|
189
|
-
return -1;
|
|
190
|
-
}
|
|
191
|
-
function pruneSessions(home, now = Date.now(), maxAgeDays = 30) {
|
|
192
|
-
const root = join(home, "sessions");
|
|
193
|
-
if (!existsSync(root)) return 0;
|
|
194
|
-
let removed = 0;
|
|
195
|
-
for (const project of readdirSync(root)) {
|
|
196
|
-
const dir = join(root, project);
|
|
197
|
-
try {
|
|
198
|
-
if (!statSync(dir).isDirectory()) continue;
|
|
199
|
-
} catch {
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
for (const file of readdirSync(dir)) {
|
|
203
|
-
const path = join(dir, file);
|
|
204
|
-
if (now - statSync(path).mtimeMs > maxAgeDays * 864e5) {
|
|
205
|
-
rmSync(path);
|
|
206
|
-
removed++;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return removed;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export {
|
|
214
|
-
Session,
|
|
215
|
-
pruneSessions
|
|
216
|
-
};
|
package/dist/chunk-6PJRWKVI.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
ConfigError
|
|
4
|
-
} from "./chunk-ZXWRLN7E.js";
|
|
5
|
-
import {
|
|
6
|
-
t
|
|
7
|
-
} from "./chunk-IDZLHEVL.js";
|
|
8
|
-
|
|
9
|
-
// src/mcp/catalog.ts
|
|
10
|
-
var CATALOG = [
|
|
11
|
-
{ name: "playwright", description: "control a browser (open pages, click, fill forms, screenshot)", config: { command: "npx", args: ["-y", "@playwright/mcp@latest"] } },
|
|
12
|
-
{ name: "context7", description: "up-to-date library documentation", config: { type: "http", url: "https://mcp.context7.com/mcp" } },
|
|
13
|
-
{ name: "fetch", description: "fetch web pages as markdown (needs uv)", config: { command: "uvx", args: ["mcp-server-fetch"] } },
|
|
14
|
-
{
|
|
15
|
-
name: "filesystem",
|
|
16
|
-
description: "access folders outside the project",
|
|
17
|
-
// biome-ignore lint/suspicious/noTemplateCurlyInString: ${dir} is filled by fillTemplate, not a template literal
|
|
18
|
-
config: { command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "${dir}"] },
|
|
19
|
-
inputs: [{ key: "dir", label: "Folder the server may access" }]
|
|
20
|
-
},
|
|
21
|
-
{ name: "git", description: "structured git operations (needs uv)", config: { command: "uvx", args: ["mcp-server-git"] } },
|
|
22
|
-
{
|
|
23
|
-
name: "github",
|
|
24
|
-
description: "GitHub issues, PRs, and repos",
|
|
25
|
-
// biome-ignore lint/suspicious/noTemplateCurlyInString: ${token} is filled by fillTemplate, not a template literal
|
|
26
|
-
config: { type: "http", url: "https://api.githubcopilot.com/mcp/", headers: { Authorization: "Bearer ${token}" } },
|
|
27
|
-
inputs: [{ key: "token", label: "GitHub Personal Access Token", secret: true }]
|
|
28
|
-
}
|
|
29
|
-
];
|
|
30
|
-
function fillTemplate(config, values) {
|
|
31
|
-
const missing = /* @__PURE__ */ new Set();
|
|
32
|
-
const fill = (s) => s.replace(/\$\{([A-Za-z0-9_]+)\}/g, (_m, key) => {
|
|
33
|
-
if (!values[key]) missing.add(key);
|
|
34
|
-
return values[key] ?? "";
|
|
35
|
-
});
|
|
36
|
-
const mapValues = (o) => Object.fromEntries(Object.entries(o).map(([k, v]) => [k, fill(v)]));
|
|
37
|
-
const out = config.type === "http" ? { type: "http", url: fill(config.url), ...config.headers ? { headers: mapValues(config.headers) } : {} } : {
|
|
38
|
-
...config.type ? { type: config.type } : {},
|
|
39
|
-
command: fill(config.command),
|
|
40
|
-
...config.args ? { args: config.args.map(fill) } : {},
|
|
41
|
-
...config.env ? { env: mapValues(config.env) } : {}
|
|
42
|
-
};
|
|
43
|
-
if (missing.size) throw new ConfigError(t("Missing MCP fields: {fields}", { fields: [...missing].join(", ") }));
|
|
44
|
-
return out;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export {
|
|
48
|
-
CATALOG,
|
|
49
|
-
fillTemplate
|
|
50
|
-
};
|
package/dist/chunk-7OTFZK4B.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
defaultOpen
|
|
4
|
-
} from "./chunk-YGBTNDPK.js";
|
|
5
|
-
import {
|
|
6
|
-
removeCredential,
|
|
7
|
-
saveCredential
|
|
8
|
-
} from "./chunk-ZXWRLN7E.js";
|
|
9
|
-
import {
|
|
10
|
-
t
|
|
11
|
-
} from "./chunk-IDZLHEVL.js";
|
|
12
|
-
|
|
13
|
-
// src/login.ts
|
|
14
|
-
function readSecret(prompt) {
|
|
15
|
-
return new Promise((resolve) => {
|
|
16
|
-
process.stdout.write(prompt);
|
|
17
|
-
const stdin = process.stdin;
|
|
18
|
-
if (!stdin.isTTY) {
|
|
19
|
-
let data = "";
|
|
20
|
-
stdin.on("data", (d) => {
|
|
21
|
-
data += d;
|
|
22
|
-
});
|
|
23
|
-
stdin.on("end", () => resolve(data.trim()));
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
let value = "";
|
|
27
|
-
stdin.setRawMode(true);
|
|
28
|
-
stdin.resume();
|
|
29
|
-
const onData = (buffer) => {
|
|
30
|
-
for (const ch of buffer.toString()) {
|
|
31
|
-
if (ch === "\r" || ch === "\n") {
|
|
32
|
-
stdin.setRawMode(false);
|
|
33
|
-
stdin.pause();
|
|
34
|
-
stdin.off("data", onData);
|
|
35
|
-
process.stdout.write("\n");
|
|
36
|
-
resolve(value.trim());
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (ch === "") process.exit(130);
|
|
40
|
-
if (ch === "\x7F" || ch === "\b") value = value.slice(0, -1);
|
|
41
|
-
else value += ch;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
stdin.on("data", onData);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
function echoFor(ch) {
|
|
48
|
-
const code = ch.codePointAt(0) ?? 0;
|
|
49
|
-
if (code < 32 || code === 127) return void 0;
|
|
50
|
-
return ch;
|
|
51
|
-
}
|
|
52
|
-
function readLine(prompt) {
|
|
53
|
-
return new Promise((resolve) => {
|
|
54
|
-
process.stdout.write(prompt);
|
|
55
|
-
const stdin = process.stdin;
|
|
56
|
-
if (!stdin.isTTY) {
|
|
57
|
-
let data = "";
|
|
58
|
-
stdin.on("data", (d) => {
|
|
59
|
-
data += d;
|
|
60
|
-
});
|
|
61
|
-
stdin.on("end", () => resolve(data.trim()));
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
let value = "";
|
|
65
|
-
stdin.setRawMode(true);
|
|
66
|
-
stdin.resume();
|
|
67
|
-
const onData = (buffer) => {
|
|
68
|
-
for (const ch of buffer.toString()) {
|
|
69
|
-
const code = ch.charCodeAt(0);
|
|
70
|
-
if (code === 13 || code === 10) {
|
|
71
|
-
stdin.setRawMode(false);
|
|
72
|
-
stdin.pause();
|
|
73
|
-
stdin.off("data", onData);
|
|
74
|
-
process.stdout.write("\n");
|
|
75
|
-
resolve(value.trim());
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (code === 3) process.exit(130);
|
|
79
|
-
if (code === 127 || code === 8) {
|
|
80
|
-
if (value) {
|
|
81
|
-
value = value.slice(0, -1);
|
|
82
|
-
process.stdout.write("\b \b");
|
|
83
|
-
}
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
const echo = echoFor(ch);
|
|
87
|
-
if (echo) process.stdout.write(echo);
|
|
88
|
-
value += ch;
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
stdin.on("data", onData);
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
function defaultLoginDeps() {
|
|
95
|
-
return {
|
|
96
|
-
out: (s) => console.log(s),
|
|
97
|
-
err: (s) => console.error(s),
|
|
98
|
-
env: process.env,
|
|
99
|
-
isTTY: process.stdin.isTTY ?? false,
|
|
100
|
-
open: (url) => defaultOpen(new URL(url)),
|
|
101
|
-
readLine,
|
|
102
|
-
saveCredential: (id, key) => saveCredential(id, key, process.env),
|
|
103
|
-
removeCredential: (id) => removeCredential(id, process.env),
|
|
104
|
-
fetch: globalThis.fetch,
|
|
105
|
-
// Wiring NYATA jalur lama: persis runLogin lama (provider add + prompt key).
|
|
106
|
-
legacyAdd: async (providerId, targetCwd) => {
|
|
107
|
-
const { runProviderCommand } = await import("./providerCli-YMG4G56R.js");
|
|
108
|
-
const { parseCliArgs: parse } = await import("./args-XA77XUMD.js");
|
|
109
|
-
return runProviderCommand(parse(["provider", "add", providerId]), {
|
|
110
|
-
env: process.env,
|
|
111
|
-
cwd: targetCwd,
|
|
112
|
-
out: (s) => console.log(s),
|
|
113
|
-
err: (s) => console.error(s),
|
|
114
|
-
readSecret
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
async function runLogin(providerId, cwd, args, deps) {
|
|
120
|
-
if (args.key && args.logout) {
|
|
121
|
-
deps.err(t("Use either --key or --logout, not both."));
|
|
122
|
-
return 1;
|
|
123
|
-
}
|
|
124
|
-
if (args.logout) {
|
|
125
|
-
if (providerId !== "openrouter") {
|
|
126
|
-
deps.err(
|
|
127
|
-
t("Logout is not supported for {id}; use bccli provider remove {id} to delete its stored key and config.", {
|
|
128
|
-
id: providerId
|
|
129
|
-
})
|
|
130
|
-
);
|
|
131
|
-
return 1;
|
|
132
|
-
}
|
|
133
|
-
const { runOauthLogout } = await import("./oauthLogin-JWXQZTMZ.js");
|
|
134
|
-
return runOauthLogout({ out: deps.out, err: deps.err, env: deps.env, removeCredential: deps.removeCredential });
|
|
135
|
-
}
|
|
136
|
-
if (args.key) return deps.legacyAdd(providerId, cwd);
|
|
137
|
-
if (providerId === "openrouter") {
|
|
138
|
-
const { runOauthLogin } = await import("./oauthLogin-JWXQZTMZ.js");
|
|
139
|
-
return runOauthLogin({
|
|
140
|
-
out: deps.out,
|
|
141
|
-
err: deps.err,
|
|
142
|
-
env: deps.env,
|
|
143
|
-
isTTY: deps.isTTY,
|
|
144
|
-
open: deps.open,
|
|
145
|
-
readLine: deps.readLine,
|
|
146
|
-
saveCredential: deps.saveCredential,
|
|
147
|
-
fetch: deps.fetch
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
return deps.legacyAdd(providerId, cwd);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export {
|
|
154
|
-
readSecret,
|
|
155
|
-
echoFor,
|
|
156
|
-
readLine,
|
|
157
|
-
defaultLoginDeps,
|
|
158
|
-
runLogin
|
|
159
|
-
};
|