@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,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
VERSION
|
|
4
|
+
} from "./chunk-XP5MTJN2.js";
|
|
5
|
+
import {
|
|
6
|
+
t
|
|
7
|
+
} from "./chunk-IDZLHEVL.js";
|
|
8
|
+
|
|
9
|
+
// src/update.ts
|
|
10
|
+
import { spawnSync } from "child_process";
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
12
|
+
import { dirname, join } from "path";
|
|
13
|
+
var REGISTRY_URL = "https://registry.npmjs.org/-/package/@botconnector/bccli/dist-tags";
|
|
14
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
15
|
+
function splitVersion(v) {
|
|
16
|
+
const i = v.indexOf("-");
|
|
17
|
+
const coreStr = i < 0 ? v : v.slice(0, i);
|
|
18
|
+
const preStr = i < 0 ? "" : v.slice(i + 1);
|
|
19
|
+
return {
|
|
20
|
+
core: coreStr.split(".").map((p) => Number.parseInt(p, 10) || 0),
|
|
21
|
+
pre: preStr ? preStr.split(".") : []
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function compareVersions(a, b) {
|
|
25
|
+
const A = splitVersion(a);
|
|
26
|
+
const B = splitVersion(b);
|
|
27
|
+
for (let i = 0; i < Math.max(A.core.length, B.core.length); i++) {
|
|
28
|
+
const x = A.core[i] ?? 0;
|
|
29
|
+
const y = B.core[i] ?? 0;
|
|
30
|
+
if (x !== y) return x < y ? -1 : 1;
|
|
31
|
+
}
|
|
32
|
+
if (!A.pre.length && !B.pre.length) return 0;
|
|
33
|
+
if (!A.pre.length) return 1;
|
|
34
|
+
if (!B.pre.length) return -1;
|
|
35
|
+
for (let i = 0; i < Math.max(A.pre.length, B.pre.length); i++) {
|
|
36
|
+
const x = A.pre[i];
|
|
37
|
+
const y = B.pre[i];
|
|
38
|
+
if (x === void 0) return -1;
|
|
39
|
+
if (y === void 0) return 1;
|
|
40
|
+
const nx = Number.parseInt(x, 10);
|
|
41
|
+
const ny = Number.parseInt(y, 10);
|
|
42
|
+
if (String(nx) === x && String(ny) === y) {
|
|
43
|
+
if (nx !== ny) return nx < ny ? -1 : 1;
|
|
44
|
+
} else if (x !== y) {
|
|
45
|
+
return x < y ? -1 : 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
function channelFor(version) {
|
|
51
|
+
return version.includes("-") ? "next" : "latest";
|
|
52
|
+
}
|
|
53
|
+
function cachePath(home) {
|
|
54
|
+
return join(home, "update-check.json");
|
|
55
|
+
}
|
|
56
|
+
function readCache(home) {
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(readFileSync(cachePath(home), "utf8"));
|
|
59
|
+
return typeof parsed?.checkedAt === "string" ? parsed : void 0;
|
|
60
|
+
} catch {
|
|
61
|
+
return void 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function writeCache(home, cache) {
|
|
65
|
+
mkdirSync(home, { recursive: true });
|
|
66
|
+
const tmp = `${cachePath(home)}.tmp`;
|
|
67
|
+
writeFileSync(tmp, JSON.stringify(cache));
|
|
68
|
+
renameSync(tmp, cachePath(home));
|
|
69
|
+
}
|
|
70
|
+
function dueForCheck(cache, now, intervalMs = CHECK_INTERVAL_MS) {
|
|
71
|
+
if (!cache) return true;
|
|
72
|
+
const at = Date.parse(cache.checkedAt);
|
|
73
|
+
if (!Number.isFinite(at)) return true;
|
|
74
|
+
return now.getTime() - at >= intervalMs;
|
|
75
|
+
}
|
|
76
|
+
function updateNotice(current, latest) {
|
|
77
|
+
if (!latest || latest.length > 64 || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(latest) || compareVersions(current, latest) >= 0) return void 0;
|
|
78
|
+
return t("A new bccli is available: {latest} (you have {current}). Run: bccli update", { latest, current });
|
|
79
|
+
}
|
|
80
|
+
function notifyOnce(home, cache) {
|
|
81
|
+
const message = updateNotice(VERSION, cache?.latest);
|
|
82
|
+
if (!message || !cache?.latest || cache.notified === cache.latest) return void 0;
|
|
83
|
+
writeCache(home, { ...cache, notified: cache.latest });
|
|
84
|
+
return message;
|
|
85
|
+
}
|
|
86
|
+
async function checkForUpdate(deps) {
|
|
87
|
+
try {
|
|
88
|
+
const cached = readCache(deps.home);
|
|
89
|
+
if (!dueForCheck(cached, deps.now)) return notifyOnce(deps.home, cached);
|
|
90
|
+
const res = await deps.fetch(REGISTRY_URL, { signal: AbortSignal.timeout(deps.timeoutMs ?? 3e3) });
|
|
91
|
+
if (!res.ok) return notifyOnce(deps.home, cached);
|
|
92
|
+
const tags = await res.json();
|
|
93
|
+
const latest = tags[channelFor(VERSION)] ?? tags.latest;
|
|
94
|
+
const updated = { checkedAt: deps.now.toISOString(), latest, notified: cached?.notified };
|
|
95
|
+
writeCache(deps.home, updated);
|
|
96
|
+
return notifyOnce(deps.home, updated);
|
|
97
|
+
} catch {
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function updateSpawnCommand(version, platform = process.platform, nodeExecPath = process.execPath, targetVersion) {
|
|
102
|
+
const spec = `@botconnector/bccli@${targetVersion ?? channelFor(version)}`;
|
|
103
|
+
if (platform !== "win32") return { command: "npm", args: ["i", "-g", spec] };
|
|
104
|
+
const npmCli = join(dirname(nodeExecPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
105
|
+
return { command: nodeExecPath, args: [npmCli, "i", "-g", spec], npmCli };
|
|
106
|
+
}
|
|
107
|
+
async function runUpdateCommand(deps) {
|
|
108
|
+
const current = deps.env.BCCLI_VERSION_OVERRIDE ?? VERSION;
|
|
109
|
+
let target;
|
|
110
|
+
try {
|
|
111
|
+
const response = await (deps.fetch ?? fetch)(REGISTRY_URL, {
|
|
112
|
+
signal: AbortSignal.timeout(8e3),
|
|
113
|
+
cache: "no-store",
|
|
114
|
+
headers: { "cache-control": "no-cache" }
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
117
|
+
const tags = await response.json();
|
|
118
|
+
target = tags[channelFor(current)];
|
|
119
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(target ?? "")) throw new Error("invalid registry version");
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error(`Could not verify BCCLI update version: ${String(error)}. No changes made.`);
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
if (compareVersions(target, current) <= 0) {
|
|
125
|
+
console.log(`BCCLI ${current} is already up to date (registry: ${target}); no changes made.`);
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
const spec = updateSpawnCommand(current, deps.platform, deps.nodeExecPath, target);
|
|
129
|
+
if (spec.npmCli && !existsSync(spec.npmCli)) {
|
|
130
|
+
console.error(`npm CLI was not found at ${spec.npmCli}. Update manually with: npm install -g @botconnector/bccli@${channelFor(deps.env.BCCLI_VERSION_OVERRIDE ?? VERSION)}`);
|
|
131
|
+
return 1;
|
|
132
|
+
}
|
|
133
|
+
const r = (deps.spawn ?? spawnSync)(spec.command, spec.args, { stdio: "inherit", env: deps.env, shell: false });
|
|
134
|
+
if (r.error) console.error(`BCCLI update failed: ${r.error.message}. Try: npm install -g @botconnector/bccli@${channelFor(deps.env.BCCLI_VERSION_OVERRIDE ?? VERSION)}`);
|
|
135
|
+
return typeof r.status === "number" ? r.status : 1;
|
|
136
|
+
}
|
|
137
|
+
export {
|
|
138
|
+
channelFor,
|
|
139
|
+
checkForUpdate,
|
|
140
|
+
compareVersions,
|
|
141
|
+
dueForCheck,
|
|
142
|
+
runUpdateCommand,
|
|
143
|
+
updateNotice,
|
|
144
|
+
updateSpawnCommand
|
|
145
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
export interface UpdateCache {
|
|
3
|
+
checkedAt: string;
|
|
4
|
+
latest?: string;
|
|
5
|
+
notified?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Simplified semver: numeric cores, prerelease sorts below release, numeric prerelease parts compare numerically. */
|
|
8
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
9
|
+
export declare function channelFor(version: string): 'next' | 'latest';
|
|
10
|
+
export declare function dueForCheck(cache: UpdateCache | undefined, now: Date, intervalMs?: number): boolean;
|
|
11
|
+
export declare function updateNotice(current: string, latest: string | undefined): string | undefined;
|
|
12
|
+
/** Best-effort registry check with a 24h cache; never throws, never blocks startup for long. */
|
|
13
|
+
export declare function checkForUpdate(deps: {
|
|
14
|
+
home: string;
|
|
15
|
+
fetch: typeof fetch;
|
|
16
|
+
now: Date;
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
}): Promise<string | undefined>;
|
|
19
|
+
export declare function updateSpawnCommand(version: string, platform?: NodeJS.Platform, nodeExecPath?: string, targetVersion?: string): {
|
|
20
|
+
command: string;
|
|
21
|
+
args: string[];
|
|
22
|
+
npmCli?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function runUpdateCommand(deps: {
|
|
25
|
+
env: NodeJS.ProcessEnv;
|
|
26
|
+
spawn?: typeof spawnSync;
|
|
27
|
+
platform?: NodeJS.Platform;
|
|
28
|
+
nodeExecPath?: string;
|
|
29
|
+
fetch?: typeof fetch;
|
|
30
|
+
}): Promise<number>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { runCommand } from './tools/bash';
|
|
2
|
+
export interface VerifyFailure {
|
|
3
|
+
cmd: string;
|
|
4
|
+
exitCode: number;
|
|
5
|
+
output: string;
|
|
6
|
+
}
|
|
7
|
+
/** Fix rounds per user turn; keeps a failing verify command from looping forever. */
|
|
8
|
+
export declare const MAX_VERIFY_ROUNDS = 2;
|
|
9
|
+
export declare function runVerify(commands: string[], opts: {
|
|
10
|
+
cwd: string;
|
|
11
|
+
env: NodeJS.ProcessEnv;
|
|
12
|
+
signal: AbortSignal;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
run?: typeof runCommand;
|
|
15
|
+
}): Promise<VerifyFailure[]>;
|
|
16
|
+
export declare function verifyFollowup(failures: VerifyFailure[], maxBytes?: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VERSION: string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ChatMessage } from './provider';
|
|
2
|
+
export declare const isStub: (content: string) => boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Replaces old `fetch` results with a one-line stub, in one batch and only once they add up to more than
|
|
5
|
+
* PRUNE_MIN_TOKENS, so the prompt prefix (and its cache) changes rarely. The newest KEEP_TOKENS worth stay intact.
|
|
6
|
+
*/
|
|
7
|
+
export declare function pruneOldFetches(messages: ChatMessage[]): boolean;
|
|
8
|
+
export interface WebBudgetLimits {
|
|
9
|
+
perTurn?: number;
|
|
10
|
+
sessionChars?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class WebBudget {
|
|
13
|
+
private fetches;
|
|
14
|
+
private chars;
|
|
15
|
+
private readonly perTurn;
|
|
16
|
+
private readonly sessionChars;
|
|
17
|
+
constructor(limits?: WebBudgetLimits);
|
|
18
|
+
startTurn(): void;
|
|
19
|
+
/** Gives back a reservation, e.g. when the fetch was served from cache and cost nothing. */
|
|
20
|
+
refund(): void;
|
|
21
|
+
reset(): void;
|
|
22
|
+
/** Reserves one fetch; returns the refusal to show the model when over budget. */
|
|
23
|
+
take(): string | undefined;
|
|
24
|
+
record(chars: number): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface WorktreePlan {
|
|
2
|
+
path: string;
|
|
3
|
+
created: boolean;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Resolve (creating when needed) the sibling worktree for `-w <name>`: always derived from the
|
|
7
|
+
* MAIN checkout, so running inside an existing worktree nests nothing. The returned path becomes
|
|
8
|
+
* the session cwd, so config, prompts, sessions, and permissions all follow it.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveWorktree(cwd: string, name: string, bin?: string): Promise<WorktreePlan>;
|
|
11
|
+
/** Read-only status for /worktree: what exists and how to remove it safely. */
|
|
12
|
+
export declare function worktreeListText(cwd: string, bin?: string): Promise<string>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@botconnector/bccli",
|
|
3
|
+
"version": "0.4.17",
|
|
4
|
+
"description": "BCCLI — BotConnector AI coding agent for the terminal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"bccli": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=22"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/farijarifriyanto-debug/bccli.git"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup && tsc -p tsconfig.build.json",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "biome lint --error-on-warnings src test",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"coverage": "vitest run --coverage"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
29
|
+
"diff": "^9.0.0",
|
|
30
|
+
"ink": "^8.0.0",
|
|
31
|
+
"openai": "^7.27.0",
|
|
32
|
+
"react": "^19.3.0",
|
|
33
|
+
"undici": "^8.12.1",
|
|
34
|
+
"ws": "^8.22.0",
|
|
35
|
+
"yaml": "^2.9.1",
|
|
36
|
+
"zod": "^4.6.5"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@biomejs/biome": "^2.5.14",
|
|
40
|
+
"@types/node": "^26.6.3",
|
|
41
|
+
"@types/react": "^19.3.0",
|
|
42
|
+
"@types/ws": "^8.18.2",
|
|
43
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
44
|
+
"ink-testing-library": "^4.0.0",
|
|
45
|
+
"tsup": "^9.0.0",
|
|
46
|
+
"typescript": "^7.0.2",
|
|
47
|
+
"vitest": "^5.0.2"
|
|
48
|
+
},
|
|
49
|
+
"overrides": {
|
|
50
|
+
"esbuild": "0.28.2"
|
|
51
|
+
},
|
|
52
|
+
"main": "dist/sdk.js",
|
|
53
|
+
"types": "dist/sdk.d.ts",
|
|
54
|
+
"exports": {
|
|
55
|
+
".": {
|
|
56
|
+
"types": "./dist/sdk.d.ts",
|
|
57
|
+
"default": "./dist/sdk.js"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"keywords": [
|
|
61
|
+
"bccli",
|
|
62
|
+
"ai",
|
|
63
|
+
"coding-agent",
|
|
64
|
+
"agent",
|
|
65
|
+
"cli",
|
|
66
|
+
"tui",
|
|
67
|
+
"terminal",
|
|
68
|
+
"mcp",
|
|
69
|
+
"openai",
|
|
70
|
+
"indonesia"
|
|
71
|
+
],
|
|
72
|
+
"author": "BotConnector (https://botconnector.id)",
|
|
73
|
+
"bugs": {
|
|
74
|
+
"url": "https://github.com/farijarifriyanto-debug/bccli/issues"
|
|
75
|
+
},
|
|
76
|
+
"homepage": "https://github.com/farijarifriyanto-debug/bccli#readme"
|
|
77
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Stable CLI compatibility bridge. There is only one user-visible executable:
|
|
2
|
+
// bccli. Explicit legacy commands continue to use the original BCCLI 0.4.17
|
|
3
|
+
// implementation bundled within the same distribution. Never reinterpret a
|
|
4
|
+
// legacy subcommand as a chargeable AI prompt.
|
|
5
|
+
import { spawn } from 'node:child_process'
|
|
6
|
+
import { existsSync } from 'node:fs'
|
|
7
|
+
import { fileURLToPath } from 'node:url'
|
|
8
|
+
|
|
9
|
+
const LEGACY_COMMANDS = new Set([
|
|
10
|
+
'login', 'logout', 'mcp', 'connect', 'disconnect', 'integrations',
|
|
11
|
+
'update', 'serve', 'acp', 'plugins', 'gh-bot', 'completion',
|
|
12
|
+
'stats', 'export', 'import', 'pr',
|
|
13
|
+
])
|
|
14
|
+
const LEGACY_OPTIONS = new Set([
|
|
15
|
+
'--output-format', '--fail-on-tool-error', '--allow-all',
|
|
16
|
+
'--allowed-tools', '--reasoning', '--lang', '--permission-mode',
|
|
17
|
+
'--worktree', '-w', '--fallback-model', '--base-url',
|
|
18
|
+
])
|
|
19
|
+
|
|
20
|
+
export function legacyCompatibilityMode(argv) {
|
|
21
|
+
if (!Array.isArray(argv) || argv.length === 0) return false
|
|
22
|
+
if (LEGACY_COMMANDS.has(argv[0])) return true
|
|
23
|
+
// Explicit flags from BCCLI 0.4.17 preserve that version's exact
|
|
24
|
+
// semantics, rather than silently mapping to the new engine.
|
|
25
|
+
if (argv.some(arg => LEGACY_OPTIONS.has(arg) || [...LEGACY_OPTIONS].some(flag => arg.startsWith(flag + '=')))) return true
|
|
26
|
+
// The old provider CLI permits custom providers, whereas the new CLI
|
|
27
|
+
// accepts only fixed HTTPS presets. Keep the legacy route explicit.
|
|
28
|
+
if (argv[0] === 'provider' && argv[1] === 'add' && argv.some(arg => ['--url','--name','--key-env'].includes(arg))) return true
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function runLegacyCli(argv, { spawnImpl = spawn, node = process.execPath, env = process.env, cwd = process.cwd() } = {}) {
|
|
33
|
+
const entrypoint = fileURLToPath(new URL('./legacy/dist/cli.js', import.meta.url))
|
|
34
|
+
if (spawnImpl === spawn && !existsSync(entrypoint)) throw Error('Bundled BCCLI compatibility files are missing; reinstall the release package. No AI request was sent.')
|
|
35
|
+
const child = spawnImpl(node, [entrypoint, ...argv], {
|
|
36
|
+
cwd, env, stdio: 'inherit', shell: false, windowsHide: false,
|
|
37
|
+
})
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
child.once('error', reject)
|
|
40
|
+
child.once('exit', (code, signal) => resolve(code ?? (signal ? 130 : 1)))
|
|
41
|
+
})
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botconnector/bccli",
|
|
3
|
-
"version": "0.5.0
|
|
4
|
-
"description": "BCCLI | BotConnector coding agent
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "BCCLI | BotConnector multi-provider coding agent with stable CLI/SDK compatibility",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"bccli": "./cli.mjs"
|
|
@@ -10,6 +10,15 @@
|
|
|
10
10
|
"node": ">=22"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
14
|
+
"diff": "^9.0.0",
|
|
15
|
+
"ink": "^8.0.0",
|
|
16
|
+
"openai": "^7.27.0",
|
|
17
|
+
"react": "^19.3.0",
|
|
18
|
+
"undici": "^8.12.1",
|
|
19
|
+
"ws": "^8.22.0",
|
|
20
|
+
"yaml": "^2.9.1",
|
|
21
|
+
"zod": "^4.6.5",
|
|
13
22
|
"@qwen-code/qwen-code": "0.26.3"
|
|
14
23
|
},
|
|
15
24
|
"scripts": {
|
|
@@ -21,6 +30,7 @@
|
|
|
21
30
|
},
|
|
22
31
|
"license": "Apache-2.0",
|
|
23
32
|
"overrides": {
|
|
33
|
+
"esbuild": "0.28.2",
|
|
24
34
|
"sharp": "0.35.5"
|
|
25
35
|
},
|
|
26
36
|
"files": [
|
|
@@ -35,17 +45,27 @@
|
|
|
35
45
|
"model-command.mjs",
|
|
36
46
|
"providers.mjs",
|
|
37
47
|
"provider-cli.mjs",
|
|
38
|
-
"startup-menu.mjs"
|
|
48
|
+
"startup-menu.mjs",
|
|
49
|
+
"legacy-compat.mjs",
|
|
50
|
+
"legacy"
|
|
39
51
|
],
|
|
40
52
|
"repository": {
|
|
41
53
|
"type": "git",
|
|
42
|
-
"url": "git+https://github.com/farijarifriyanto-debug/bccli-
|
|
54
|
+
"url": "git+https://github.com/farijarifriyanto-debug/bccli-runtime.git"
|
|
43
55
|
},
|
|
44
56
|
"homepage": "https://github.com/farijarifriyanto-debug/bccli#readme",
|
|
45
57
|
"bugs": {
|
|
46
58
|
"url": "https://github.com/farijarifriyanto-debug/bccli/issues"
|
|
47
59
|
},
|
|
48
60
|
"author": "BICO Inovasi Digital / BotConnector",
|
|
61
|
+
"main": "./legacy/dist/sdk.js",
|
|
62
|
+
"types": "./legacy/dist/sdk.d.ts",
|
|
63
|
+
"exports": {
|
|
64
|
+
".": {
|
|
65
|
+
"types": "./legacy/dist/sdk.d.ts",
|
|
66
|
+
"default": "./legacy/dist/sdk.js"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
49
69
|
"publishConfig": {
|
|
50
70
|
"access": "public",
|
|
51
71
|
"tag": "next"
|
package/provider-cli.mjs
CHANGED
|
@@ -57,8 +57,7 @@ export async function runProviderCommand(words, {
|
|
|
57
57
|
}
|
|
58
58
|
providerDefinition(id)
|
|
59
59
|
if (action === 'add') {
|
|
60
|
-
|
|
61
|
-
out('Provider: ' + PROVIDERS[id].name + ' (direct API; provider billing and terms apply).')
|
|
60
|
+
out('Provider: ' + PROVIDERS[id].name + ' (API use may incur charges; entering a key does not send an AI prompt).')
|
|
62
61
|
const key = await getKey()
|
|
63
62
|
save(id, key)
|
|
64
63
|
select(id,{env})
|
package/providers.mjs
CHANGED
|
@@ -40,7 +40,7 @@ function ownerDirectory(root, { create = false } = {}) {
|
|
|
40
40
|
return true
|
|
41
41
|
}
|
|
42
42
|
function keyPath(root, id) {
|
|
43
|
-
if (!ID.test(id)
|
|
43
|
+
if (!ID.test(id)) throw Error('Provider key storage requires a supported provider.')
|
|
44
44
|
return join(root, 'provider-' + id + '.dpapi')
|
|
45
45
|
}
|
|
46
46
|
function dpapi(script, input, { platform = process.platform, runner = spawnSync } = {}) {
|
|
@@ -54,7 +54,6 @@ function dpapi(script, input, { platform = process.platform, runner = spawnSync
|
|
|
54
54
|
}
|
|
55
55
|
export function saveProviderKey(id, key, { root = providerRoot(), platform = process.platform, runner = spawnSync } = {}) {
|
|
56
56
|
providerDefinition(id)
|
|
57
|
-
if (id === 'botconnector') throw Error('Use bccli-legacy login bc-cloud or BOTCONNECTOR_API_KEY for BotConnector credentials.')
|
|
58
57
|
if (typeof key !== 'string' || !key.trim() || key.length > 8192 || /[\r\n]/.test(key)) throw Error('API key cannot be empty, multiline, or oversized.')
|
|
59
58
|
if (platform !== 'win32') throw Error('On non-Windows systems, use the provider API key environment variable.')
|
|
60
59
|
ownerDirectory(root, { create: true })
|
|
@@ -70,7 +69,6 @@ export function saveProviderKey(id, key, { root = providerRoot(), platform = pro
|
|
|
70
69
|
}
|
|
71
70
|
export function storedProviderKey(id, { root = providerRoot(), platform = process.platform, runner = spawnSync } = {}) {
|
|
72
71
|
providerDefinition(id)
|
|
73
|
-
if (id === 'botconnector') throw Error('BotConnector credentials are managed by public BCCLI.')
|
|
74
72
|
if (!ownerDirectory(root)) throw Error('Provider not configured. Run provider add.')
|
|
75
73
|
const path = keyPath(root, id)
|
|
76
74
|
let info
|
|
@@ -83,7 +81,16 @@ export function storedProviderKey(id, { root = providerRoot(), platform = proces
|
|
|
83
81
|
}
|
|
84
82
|
export function isConfigured(id, { env = process.env, root = providerRoot({env}) } = {}) {
|
|
85
83
|
providerDefinition(id)
|
|
86
|
-
if (id === 'botconnector')
|
|
84
|
+
if (id === 'botconnector') {
|
|
85
|
+
if (env.BOTCONNECTOR_API_KEY?.trim()) return true
|
|
86
|
+
try {
|
|
87
|
+
if (ownerDirectory(root)) {
|
|
88
|
+
const info = lstatSync(keyPath(root, id))
|
|
89
|
+
if (info.isFile() && !info.isSymbolicLink() && info.size <= MAX_BLOB_BYTES) return true
|
|
90
|
+
}
|
|
91
|
+
} catch {}
|
|
92
|
+
return botConnectorCredentialStatus({ env }).configured
|
|
93
|
+
}
|
|
87
94
|
if (env[PROVIDERS[id].env]?.trim()) return true
|
|
88
95
|
try { return ownerDirectory(root) && lstatSync(keyPath(root, id)).isFile() && !lstatSync(keyPath(root, id)).isSymbolicLink() }
|
|
89
96
|
catch { return false }
|
|
@@ -138,7 +145,6 @@ export function useProvider(id, { env = process.env, root = providerRoot({env})
|
|
|
138
145
|
}
|
|
139
146
|
export function removeProvider(id, { env = process.env, root = providerRoot({env}) } = {}) {
|
|
140
147
|
providerDefinition(id)
|
|
141
|
-
if (id === 'botconnector') throw Error('BotConnector credentials are managed by bccli-legacy or BOTCONNECTOR_API_KEY.')
|
|
142
148
|
if (!ownerDirectory(root)) return
|
|
143
149
|
const path = keyPath(root, id)
|
|
144
150
|
if (existsSync(path)) {
|
|
@@ -152,7 +158,14 @@ export function removeProvider(id, { env = process.env, root = providerRoot({env
|
|
|
152
158
|
}
|
|
153
159
|
export function resolveProvider(id, { env = process.env, root = providerRoot({env}) } = {}) {
|
|
154
160
|
const info = providerDefinition(id)
|
|
155
|
-
if (id === 'botconnector')
|
|
161
|
+
if (id === 'botconnector') {
|
|
162
|
+
// Saved keys take precedence; legacy credentials are read only as fallback.
|
|
163
|
+
try { return { id, ...info, key: storedProviderKey(id, { root }) } }
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (error?.message !== 'Provider not configured. Run provider add.') throw error
|
|
166
|
+
return { id, ...info, key: botConnectorKey({ env }) }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
156
169
|
// An explicit key saved through "provider add" must win over stale environment
|
|
157
170
|
// variables. Never silently fall back if the encrypted file is corrupted.
|
|
158
171
|
let key
|
package/startup-menu.mjs
CHANGED
|
@@ -74,22 +74,19 @@ export async function startupMenu({
|
|
|
74
74
|
providerId = selectedName(value, ids, active)
|
|
75
75
|
if (!providerId) { out('Pilihan provider tidak dikenal.'); continue }
|
|
76
76
|
replace = value.endsWith('!')
|
|
77
|
-
if (providerId === 'botconnector' && replace) {
|
|
78
|
-
out('Gunakan bccli-legacy login bc-cloud untuk mengubah key BotConnector lama; key tidak akan diubah dari menu ini.')
|
|
79
|
-
continue
|
|
80
|
-
}
|
|
81
77
|
break
|
|
82
78
|
}
|
|
83
|
-
|
|
79
|
+
let pendingKey
|
|
80
|
+
if (replace || !configured(providerId)) {
|
|
84
81
|
out('Masukkan API key ' + PROVIDERS[providerId].name + ' (input tersembunyi).')
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (!key) throw Error('Tidak ada API key; provider tidak diubah.')
|
|
88
|
-
saveKey(providerId, key)
|
|
89
|
-
out('API key disimpan terlindungi untuk akun Windows. Tidak ada request AI.')
|
|
82
|
+
pendingKey = await askSecret()
|
|
83
|
+
if (!pendingKey) throw Error('Tidak ada API key; provider tidak diubah.')
|
|
90
84
|
}
|
|
91
|
-
if (!configured(providerId)) throw Error('Provider ' + providerId + ' belum memiliki API key. Tidak ada permintaan AI.')
|
|
92
|
-
|
|
85
|
+
if (!pendingKey && !configured(providerId)) throw Error('Provider ' + providerId + ' belum memiliki API key. Tidak ada permintaan AI.')
|
|
86
|
+
// Validate before saving so a bad replacement never destroys a working key.
|
|
87
|
+
const profile = pendingKey
|
|
88
|
+
? { id: providerId, key: pendingKey, endpoint: PROVIDERS[providerId].endpoint }
|
|
89
|
+
: resolve(providerId)
|
|
93
90
|
const models = await list({ key: profile.key, endpoint: profile.endpoint })
|
|
94
91
|
if (!models.length) throw Error('Tidak ada model untuk provider ini.')
|
|
95
92
|
const all = [...models].sort((a, b) => a.id.localeCompare(b.id))
|
|
@@ -112,7 +109,11 @@ export async function startupMenu({
|
|
|
112
109
|
const candidate = !value ? preferred : /^[0-9]+$/.test(value) ? filtered[Number(value) - 1]?.id : value
|
|
113
110
|
if (!candidate || !all.some(m => m.id === candidate)) { out('Pilih nomor atau ID model yang tampil.'); continue }
|
|
114
111
|
selectModel(all, candidate)
|
|
115
|
-
// Save
|
|
112
|
+
// Save only after authenticated model discovery and selection.
|
|
113
|
+
if (pendingKey) {
|
|
114
|
+
saveKey(providerId, pendingKey)
|
|
115
|
+
out('API key tersimpan terlindungi. Tidak ada permintaan chat AI.')
|
|
116
|
+
}
|
|
116
117
|
use(providerId)
|
|
117
118
|
saveModel(providerId, candidate)
|
|
118
119
|
return { providerId, model: candidate, key: profile.key, endpoint: profile.endpoint }
|