@botconnector/bccli 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +13 -2
- package/README.md +13 -2
- package/dist/abort.d.ts +5 -0
- package/dist/{acp-ATIL4JOZ.js → acp-3PHBAI64.js} +2 -2
- package/dist/acp.d.ts +27 -0
- package/dist/agent.d.ts +143 -0
- package/dist/agents.d.ts +4 -0
- package/dist/{args-J5ONVGIF.js → args-W6BNKY7K.js} +3 -3
- package/dist/args.d.ts +51 -0
- package/dist/budget.d.ts +23 -0
- package/dist/checkpoints.d.ts +34 -0
- package/dist/{chunk-L7QI6JN2.js → chunk-24JN75FZ.js} +6 -6
- package/dist/{chunk-XBO5GACQ.js → chunk-75BECX4F.js} +3 -3
- package/dist/{chunk-QDQU6VY2.js → chunk-BC7UXFE4.js} +10 -1
- package/dist/{chunk-M7CALSP3.js → chunk-BGXNR74O.js} +1 -1
- package/dist/{chunk-6M5X2KZE.js → chunk-BKGFA2PT.js} +1 -1
- package/dist/{chunk-BNA74HPN.js → chunk-BXQQCUAC.js} +4 -4
- package/dist/{chunk-LACUWBWS.js → chunk-FLQPE4S5.js} +21 -9
- package/dist/{chunk-JL5ZCSP2.js → chunk-GN4W3T6E.js} +3 -3
- package/dist/{chunk-SPRNLS7K.js → chunk-JHPGOAXU.js} +1 -1
- package/dist/{chunk-7F3IWBPQ.js → chunk-MFHCQQEN.js} +18 -8
- package/dist/{chunk-O7M3TGIW.js → chunk-MHIYLXJC.js} +35 -0
- package/dist/{chunk-TVALKHFB.js → chunk-PZRKU4UM.js} +10 -10
- package/dist/{chunk-TLPFQIS2.js → chunk-R5RE46CW.js} +2 -2
- package/dist/{chunk-BQ2IGPBR.js → chunk-WI22M2ID.js} +1 -1
- package/dist/{chunk-PUN4HMAG.js → chunk-WNACAUDK.js} +9 -3
- package/dist/{chunk-KEMYIGCP.js → chunk-XV7ZVL4J.js} +2 -2
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +34 -35
- package/dist/clipboardImage.d.ts +17 -0
- package/dist/commands.d.ts +16 -0
- package/dist/completion.d.ts +14 -0
- package/dist/{config-COPNMMV6.js → config-DIDLDONU.js} +2 -2
- package/dist/{config-RZ5JONMX.js → config-IU76CPK2.js} +7 -3
- package/dist/config.d.ts +97 -0
- package/dist/context.d.ts +13 -0
- package/dist/contextWindow.d.ts +3 -0
- package/dist/diff.d.ts +7 -0
- package/dist/exit.d.ts +9 -0
- package/dist/extensions.d.ts +34 -0
- package/dist/{ghBotCli-IBCZIWT5.js → ghBotCli-E3VPHNZY.js} +12 -12
- package/dist/ghBotCli.d.ts +9 -0
- package/dist/ghBotDispatch.d.ts +68 -0
- package/dist/ghBotRunner.d.ts +82 -0
- package/dist/ghBotServe.d.ts +21 -0
- package/dist/ghBotWebhook.d.ts +45 -0
- package/dist/hooks.d.ts +27 -0
- package/dist/i18n/id.d.ts +1 -0
- package/dist/i18n.d.ts +16 -0
- package/dist/{integrationCli-P75R2VSC.js → integrationCli-Q2YPDTPG.js} +1 -1
- package/dist/integrationCli.d.ts +9 -0
- package/dist/keybinds.d.ts +22 -0
- package/dist/{login-SYIQP46J.js → login-FP3BB44A.js} +3 -3
- package/dist/login.d.ts +19 -0
- package/dist/lsp.d.ts +47 -0
- package/dist/mcp/catalog.d.ts +14 -0
- package/dist/mcp/config.d.ts +36 -0
- package/dist/mcp/manager.d.ts +34 -0
- package/dist/mcp/oauth.d.ts +82 -0
- package/dist/{mcpCli-QUV5SD64.js → mcpCli-SNBDUWJN.js} +5 -5
- package/dist/mcpCli.d.ts +3 -0
- package/dist/mcpServer/serve.d.ts +8 -0
- package/dist/mcpServer/server.d.ts +19 -0
- package/dist/models.d.ts +13 -0
- package/dist/{modelsCli-TRRB5LX4.js → modelsCli-CZ2HNGKR.js} +4 -4
- package/dist/modelsCli.d.ts +15 -0
- package/dist/npmRunner.d.ts +21 -0
- package/dist/oauthLogin.d.ts +47 -0
- package/dist/permissions.d.ts +30 -0
- package/dist/pluginSpec.d.ts +25 -0
- package/dist/plugins.d.ts +45 -0
- package/dist/{pluginsCli-GNW4TPVV.js → pluginsCli-LPIUUDWB.js} +1 -1
- package/dist/pluginsCli.d.ts +16 -0
- package/dist/prCli.d.ts +33 -0
- package/dist/presets.d.ts +8 -0
- package/dist/print.d.ts +14 -0
- package/dist/provider.d.ts +140 -0
- package/dist/{providerCli-FAOZHOKW.js → providerCli-NMUFXAAS.js} +5 -5
- package/dist/providerCli.d.ts +17 -0
- package/dist/providers.d.ts +6 -0
- package/dist/reasoning.d.ts +12 -0
- package/dist/repomap.d.ts +10 -0
- package/dist/sdk.d.ts +57 -0
- package/dist/sdk.js +99 -18
- package/dist/{serve-6QLBJUYW.js → serve-KWOECK5W.js} +1 -1
- package/dist/{serve-JG7RLIUD.js → serve-X2ZV4S5U.js} +20 -14
- package/dist/serve.d.ts +37 -0
- package/dist/serveHeartbeat.d.ts +14 -0
- package/dist/serveProtocol.d.ts +47 -0
- package/dist/{session-KBAQ4BZ5.js → session-GKEXDJKZ.js} +2 -2
- package/dist/session.d.ts +30 -0
- package/dist/setup-OV3NWQN5.js +24 -0
- package/dist/setup.d.ts +74 -0
- package/dist/slash/copy.d.ts +1 -0
- package/dist/slash/diff.d.ts +1 -0
- package/dist/slash/doctor.d.ts +18 -0
- package/dist/slash/export.d.ts +2 -0
- package/dist/slash/info.d.ts +45 -0
- package/dist/slash/memory.d.ts +10 -0
- package/dist/statsCli.d.ts +62 -0
- package/dist/textToolCalls.d.ts +6 -0
- package/dist/thinking.d.ts +17 -0
- package/dist/tokenBudget.d.ts +22 -0
- package/dist/tools/bash.d.ts +52 -0
- package/dist/tools/diagnostics.d.ts +5 -0
- package/dist/tools/edit.d.ts +7 -0
- package/dist/tools/fetch.d.ts +41 -0
- package/dist/tools/glob.d.ts +5 -0
- package/dist/tools/globSafety.d.ts +7 -0
- package/dist/tools/grep.d.ts +13 -0
- package/dist/tools/ignore.d.ts +2 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/memory.d.ts +13 -0
- package/dist/tools/paths.d.ts +2 -0
- package/dist/tools/plan.d.ts +10 -0
- package/dist/tools/read.d.ts +16 -0
- package/dist/tools/repomap.d.ts +2 -0
- package/dist/tools/sandbox.d.ts +12 -0
- package/dist/tools/shell.d.ts +18 -0
- package/dist/tools/skill.d.ts +3 -0
- package/dist/tools/task.d.ts +28 -0
- package/dist/tools/todo.d.ts +13 -0
- package/dist/tools/types.d.ts +52 -0
- package/dist/tools/websearch.d.ts +9 -0
- package/dist/tools/write.d.ts +5 -0
- package/dist/{transferCli-TK2GSVRK.js → transferCli-YUFPI6AH.js} +3 -3
- package/dist/transferCli.d.ts +23 -0
- package/dist/ui/App.d.ts +7 -0
- package/dist/ui/DiffView.d.ts +3 -0
- package/dist/ui/EditableText.d.ts +7 -0
- package/dist/ui/LinePrompt.d.ts +6 -0
- package/dist/ui/ListPicker.d.ts +11 -0
- package/dist/ui/Markdown.d.ts +8 -0
- package/dist/ui/McpMenu.d.ts +11 -0
- package/dist/ui/ModelPicker.d.ts +6 -0
- package/dist/ui/PermissionPrompt.d.ts +5 -0
- package/dist/ui/PlanApproval.d.ts +5 -0
- package/dist/ui/PromptInput.d.ts +18 -0
- package/dist/ui/ProviderMenu.d.ts +10 -0
- package/dist/ui/Spinner.d.ts +4 -0
- package/dist/ui/StatusBar.d.ts +9 -0
- package/dist/ui/TodoList.d.ts +4 -0
- package/dist/ui/ToolBlock.d.ts +14 -0
- package/dist/ui/complete.d.ts +1 -0
- package/dist/ui/focusReport.d.ts +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/lineEdit.d.ts +42 -0
- package/dist/ui/replay.d.ts +4 -0
- package/dist/ui/table.d.ts +20 -0
- package/dist/ui/theme.d.ts +5 -0
- package/dist/ui/thinkingMouse.d.ts +33 -0
- package/dist/ui/transcript.d.ts +55 -0
- package/dist/ui/vim.d.ts +26 -0
- package/dist/{ui-B3CJ6TGE.js → ui-IVIFNUCC.js} +13 -11
- package/dist/{update-K5IQ2MYR.js → update-TZ2G6KQ3.js} +1 -1
- package/dist/update.d.ts +30 -0
- package/dist/verify.d.ts +16 -0
- package/dist/version.d.ts +1 -0
- package/dist/webBudget.d.ts +25 -0
- package/dist/worktree.d.ts +12 -0
- package/package.json +26 -13
- package/dist/setup-FJAWDWV4.js +0 -24
package/dist/sdk.js
CHANGED
|
@@ -715,21 +715,46 @@ function loadConfig(cwd, env = process.env) {
|
|
|
715
715
|
allow: [...global.allow ?? []]
|
|
716
716
|
};
|
|
717
717
|
}
|
|
718
|
+
function writeFileAtomic(path, data, mode) {
|
|
719
|
+
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
720
|
+
try {
|
|
721
|
+
writeFileSync(tmp, data, mode === void 0 ? void 0 : { mode });
|
|
722
|
+
renameSync(tmp, path);
|
|
723
|
+
if (mode !== void 0) chmodSync(path, mode);
|
|
724
|
+
} catch (error) {
|
|
725
|
+
try {
|
|
726
|
+
rmSync(tmp, { force: true });
|
|
727
|
+
} catch {
|
|
728
|
+
}
|
|
729
|
+
throw error;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
function quarantineCorruptFile(path, error) {
|
|
733
|
+
const stamp = Date.now();
|
|
734
|
+
let dest = `${path}.corrupt-${stamp}`;
|
|
735
|
+
for (let n = 1; existsSync(dest); n++) dest = `${path}.corrupt-${stamp}-${n}`;
|
|
736
|
+
try {
|
|
737
|
+
renameSync(path, dest);
|
|
738
|
+
} catch {
|
|
739
|
+
return void 0;
|
|
740
|
+
}
|
|
741
|
+
console.error(`${path} is not valid JSON (${error.message}); moved it to ${dest} instead of overwriting it.`);
|
|
742
|
+
return dest;
|
|
743
|
+
}
|
|
718
744
|
function readCredentials(env = process.env) {
|
|
719
745
|
const path = join(bccliHome(env), "credentials");
|
|
720
746
|
if (!existsSync(path)) return {};
|
|
721
747
|
try {
|
|
722
748
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
723
|
-
} catch {
|
|
749
|
+
} catch (error) {
|
|
750
|
+
quarantineCorruptFile(path, error);
|
|
724
751
|
return {};
|
|
725
752
|
}
|
|
726
753
|
}
|
|
727
754
|
function saveCredential(providerId, key, env = process.env) {
|
|
728
755
|
const home = bccliHome(env);
|
|
729
756
|
mkdirSync(home, { recursive: true });
|
|
730
|
-
|
|
731
|
-
writeFileSync(path, JSON.stringify({ ...readCredentials(env), [providerId]: key }, null, 2), { mode: 384 });
|
|
732
|
-
chmodSync(path, 384);
|
|
757
|
+
writeFileAtomic(join(home, "credentials"), JSON.stringify({ ...readCredentials(env), [providerId]: key }, null, 2), 384);
|
|
733
758
|
}
|
|
734
759
|
function resolveModel(config, modelRef, env = process.env) {
|
|
735
760
|
const slash = modelRef.indexOf("/");
|
|
@@ -765,8 +790,43 @@ function isAlwaysAsk(segment) {
|
|
|
765
790
|
}
|
|
766
791
|
return false;
|
|
767
792
|
}
|
|
793
|
+
var RUNNER_COMMANDS = /* @__PURE__ */ new Set([
|
|
794
|
+
"npm",
|
|
795
|
+
"npx",
|
|
796
|
+
"pnpm",
|
|
797
|
+
"pnpx",
|
|
798
|
+
"yarn",
|
|
799
|
+
"bun",
|
|
800
|
+
"bunx",
|
|
801
|
+
"deno",
|
|
802
|
+
"node",
|
|
803
|
+
"tsx",
|
|
804
|
+
"ts-node",
|
|
805
|
+
"python",
|
|
806
|
+
"python3",
|
|
807
|
+
"py",
|
|
808
|
+
"uv",
|
|
809
|
+
"uvx",
|
|
810
|
+
"pip",
|
|
811
|
+
"pip3",
|
|
812
|
+
"pipx",
|
|
813
|
+
"pytest",
|
|
814
|
+
"make",
|
|
815
|
+
"cargo",
|
|
816
|
+
"go",
|
|
817
|
+
"dotnet",
|
|
818
|
+
"java",
|
|
819
|
+
"ruby",
|
|
820
|
+
"bundle",
|
|
821
|
+
"rake",
|
|
822
|
+
"gradle",
|
|
823
|
+
"mvn",
|
|
824
|
+
"php",
|
|
825
|
+
"composer"
|
|
826
|
+
]);
|
|
768
827
|
function commandKey(segment) {
|
|
769
828
|
const words2 = segment.trim().split(/\s+/);
|
|
829
|
+
if (RUNNER_COMMANDS.has(words2[0] ?? "") && words2[2] && !words2[2].startsWith("-")) return words2.slice(0, 3).join(" ");
|
|
770
830
|
return words2[1] ? `${words2[0]} ${words2[1]}` : words2[0];
|
|
771
831
|
}
|
|
772
832
|
function requiresSensitiveToolApproval(req) {
|
|
@@ -1748,7 +1808,7 @@ function createProvider(options) {
|
|
|
1748
1808
|
const isBotConnectorCloud = /^https:\/\/api\.botconnector\.id\/v1\/?$/.test(baseURL) && apiKey?.startsWith("bc_live_");
|
|
1749
1809
|
if (isBotConnectorCloud) {
|
|
1750
1810
|
headers["x-botconnector-client"] = "bccli";
|
|
1751
|
-
headers["x-botconnector-client-version"] = "0.4.
|
|
1811
|
+
headers["x-botconnector-client-version"] = "0.4.1";
|
|
1752
1812
|
}
|
|
1753
1813
|
const useNativeResponses = isBotConnectorCloud && providerId === "bc-cloud" && model === "gpt-6-luna";
|
|
1754
1814
|
const useResponsesWebSocket = useNativeResponses && Boolean(apiKey) && (fetchOverride === void 0 || responsesWebSocketFactory !== void 0);
|
|
@@ -1779,7 +1839,7 @@ function createProvider(options) {
|
|
|
1779
1839
|
baseURL: baseURL.replace(/\/+$/, ""),
|
|
1780
1840
|
defaultHeaders: {
|
|
1781
1841
|
"x-botconnector-client": "bccli",
|
|
1782
|
-
"x-botconnector-client-version": "0.4.
|
|
1842
|
+
"x-botconnector-client-version": "0.4.1"
|
|
1783
1843
|
}
|
|
1784
1844
|
});
|
|
1785
1845
|
lunaWs = responsesWebSocketFactory ? responsesWebSocketFactory(client) : new ResponsesWS(client, { reconnect: null });
|
|
@@ -1842,8 +1902,13 @@ function createProvider(options) {
|
|
|
1842
1902
|
} catch (error) {
|
|
1843
1903
|
const err = error instanceof ProviderError ? error : new ProviderError(error.message);
|
|
1844
1904
|
const lostPrevious = err.code === "previous_response_not_found";
|
|
1905
|
+
const handshakeStatus = /unexpected server response:\s*(\d{3})\b/i.exec(err.message);
|
|
1906
|
+
const handshakeRejected = Boolean(handshakeStatus && Number(handshakeStatus[1]) >= 400);
|
|
1845
1907
|
const connectionLost = /websocket|connection closed|socket|network/i.test(err.message) || err.code === "websocket_connection_limit_reached";
|
|
1846
1908
|
resetLunaWebSocket();
|
|
1909
|
+
if (!emittedText && !signal?.aborted && handshakeRejected) {
|
|
1910
|
+
throw new ProviderError(err.message, Number(handshakeStatus?.[1]), "bc_ws_http_fallback");
|
|
1911
|
+
}
|
|
1847
1912
|
if (attempt === 0 && !emittedText && !signal?.aborted && (plan.incremental || lostPrevious || connectionLost)) {
|
|
1848
1913
|
continue;
|
|
1849
1914
|
}
|
|
@@ -1870,7 +1935,8 @@ function createProvider(options) {
|
|
|
1870
1935
|
if (res.ok) return res;
|
|
1871
1936
|
const text = await res.text().catch(() => "");
|
|
1872
1937
|
lastError = new ProviderError(t("{status} from {url}: {message}", { status: res.status, url: baseURL, message: errorMessage(text) }), res.status);
|
|
1873
|
-
|
|
1938
|
+
const deterministicQuota429 = res.status === 429 && /"code"\s*:\s*"(?:luna_monthly_quota_exhausted|plan_allowance_exhausted)"/i.test(text);
|
|
1939
|
+
if (!retryable(res.status) || deterministicQuota429) throw lastError;
|
|
1874
1940
|
}
|
|
1875
1941
|
throw lastError ?? new ProviderError(t("Request failed"));
|
|
1876
1942
|
}
|
|
@@ -3897,7 +3963,7 @@ import { z as z9 } from "zod";
|
|
|
3897
3963
|
|
|
3898
3964
|
// src/mcp/config.ts
|
|
3899
3965
|
import { createHash } from "crypto";
|
|
3900
|
-
import {
|
|
3966
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
3901
3967
|
import { dirname as dirname3, join as join3, resolve as resolve3 } from "path";
|
|
3902
3968
|
var ENV_REF = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
|
|
3903
3969
|
function expandEnvVars(config, env) {
|
|
@@ -3920,7 +3986,7 @@ function expandEnvVars(config, env) {
|
|
|
3920
3986
|
|
|
3921
3987
|
// src/mcp/oauth.ts
|
|
3922
3988
|
import { spawn as spawn3 } from "child_process";
|
|
3923
|
-
import {
|
|
3989
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync4 } from "fs";
|
|
3924
3990
|
import { createServer } from "http";
|
|
3925
3991
|
import { dirname as dirname4, join as join4 } from "path";
|
|
3926
3992
|
import { auth } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
@@ -3930,23 +3996,29 @@ function readStore(home) {
|
|
|
3930
3996
|
if (!existsSync7(path)) return {};
|
|
3931
3997
|
try {
|
|
3932
3998
|
return JSON.parse(readFileSync4(path, "utf8"));
|
|
3933
|
-
} catch {
|
|
3999
|
+
} catch (error) {
|
|
4000
|
+
quarantineCorruptFile(path, error);
|
|
3934
4001
|
return {};
|
|
3935
4002
|
}
|
|
3936
4003
|
}
|
|
3937
4004
|
function writeStore(home, store) {
|
|
3938
4005
|
const path = oauthStorePath(home);
|
|
3939
4006
|
mkdirSync3(dirname4(path), { recursive: true });
|
|
3940
|
-
|
|
3941
|
-
`,
|
|
3942
|
-
chmodSync3(path, 384);
|
|
4007
|
+
writeFileAtomic(path, `${JSON.stringify(store, null, 2)}
|
|
4008
|
+
`, 384);
|
|
3943
4009
|
}
|
|
3944
4010
|
function hasStoredTokens(home, serverUrl) {
|
|
3945
4011
|
return Boolean(readStore(home)[serverUrl]?.tokens);
|
|
3946
4012
|
}
|
|
3947
|
-
function
|
|
3948
|
-
|
|
3949
|
-
|
|
4013
|
+
function openCommand(url, platform) {
|
|
4014
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
|
|
4015
|
+
if (platform === "win32") return { command: "rundll32.exe", args: ["url.dll,FileProtocolHandler", url.href] };
|
|
4016
|
+
return { command: platform === "darwin" ? "open" : "xdg-open", args: [url.href] };
|
|
4017
|
+
}
|
|
4018
|
+
function defaultOpen(url, deps = {}) {
|
|
4019
|
+
const plan = openCommand(url, deps.platform ?? process.platform);
|
|
4020
|
+
if (!plan) return;
|
|
4021
|
+
const child = (deps.spawn ?? spawn3)(plan.command, plan.args, { detached: true, stdio: "ignore" });
|
|
3950
4022
|
child.unref();
|
|
3951
4023
|
child.on("error", () => {
|
|
3952
4024
|
});
|
|
@@ -4193,7 +4265,7 @@ import { homedir as homedir2 } from "os";
|
|
|
4193
4265
|
// src/context.ts
|
|
4194
4266
|
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
4195
4267
|
import { dirname as dirname5, join as join5 } from "path";
|
|
4196
|
-
var FILES = ["AGENTS.md", "BCCLI.md"];
|
|
4268
|
+
var FILES = ["AGENTS.md", "CLAUDE.md", "BCCLI.md"];
|
|
4197
4269
|
function readIf(path) {
|
|
4198
4270
|
try {
|
|
4199
4271
|
return existsSync8(path) ? readFileSync5(path, "utf8").trim() : void 0;
|
|
@@ -4346,7 +4418,7 @@ function loadAgentDefs(r) {
|
|
|
4346
4418
|
}
|
|
4347
4419
|
|
|
4348
4420
|
// src/providers.ts
|
|
4349
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
4421
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
4350
4422
|
import { join as join7 } from "path";
|
|
4351
4423
|
function providerName(config, id) {
|
|
4352
4424
|
return PRESETS.find((p) => p.id === id)?.name ?? config.providers[id]?.name ?? id;
|
|
@@ -4480,6 +4552,15 @@ var Session = class _Session {
|
|
|
4480
4552
|
}
|
|
4481
4553
|
return repairTail(messages);
|
|
4482
4554
|
}
|
|
4555
|
+
/** Model of the most recent turn that recorded usage — serve attach continues a session with its own model. */
|
|
4556
|
+
lastModel() {
|
|
4557
|
+
const records = this.records();
|
|
4558
|
+
for (let i = records.length - 1; i >= 0; i--) {
|
|
4559
|
+
const record = records[i];
|
|
4560
|
+
if (record.t === "usage" && record.model) return record.model;
|
|
4561
|
+
}
|
|
4562
|
+
return void 0;
|
|
4563
|
+
}
|
|
4483
4564
|
/**
|
|
4484
4565
|
* What the user sees on resume: the whole conversation. Compaction only shrinks what the model is sent, so
|
|
4485
4566
|
* its reset does not hide the older turns here. A real reset (/clear, rewind) still starts over, the
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createRuntime
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PZRKU4UM.js";
|
|
5
5
|
import "./chunk-QZKLZELZ.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-BGXNR74O.js";
|
|
7
7
|
import "./chunk-45SDLMTV.js";
|
|
8
8
|
import "./chunk-PSO7R5AD.js";
|
|
9
9
|
import {
|
|
10
10
|
VERSION
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-BKGFA2PT.js";
|
|
12
12
|
import {
|
|
13
13
|
LOOPBACK_BIND,
|
|
14
14
|
MAX_FRAME_BYTES,
|
|
@@ -17,24 +17,24 @@ import {
|
|
|
17
17
|
parseClientFrame,
|
|
18
18
|
randomToken,
|
|
19
19
|
trustFence
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
20
|
+
} from "./chunk-XV7ZVL4J.js";
|
|
21
|
+
import "./chunk-MHIYLXJC.js";
|
|
22
|
+
import "./chunk-GN4W3T6E.js";
|
|
23
23
|
import {
|
|
24
24
|
listAllModels
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-75BECX4F.js";
|
|
26
|
+
import "./chunk-JHPGOAXU.js";
|
|
27
|
+
import "./chunk-MFHCQQEN.js";
|
|
28
28
|
import {
|
|
29
29
|
Session
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
import "./chunk-
|
|
30
|
+
} from "./chunk-BC7UXFE4.js";
|
|
31
|
+
import "./chunk-WNACAUDK.js";
|
|
32
32
|
import "./chunk-BLOYFIAD.js";
|
|
33
|
-
import "./chunk-
|
|
33
|
+
import "./chunk-24JN75FZ.js";
|
|
34
34
|
import {
|
|
35
35
|
bccliHome,
|
|
36
36
|
loadConfig
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-FLQPE4S5.js";
|
|
38
38
|
import "./chunk-UZWJQF67.js";
|
|
39
39
|
|
|
40
40
|
// src/serve.ts
|
|
@@ -101,6 +101,11 @@ function readBody(req) {
|
|
|
101
101
|
function sendFrame(ws, frame) {
|
|
102
102
|
if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(frame));
|
|
103
103
|
}
|
|
104
|
+
function serveBanner(handle, opts = {}) {
|
|
105
|
+
const supplied = opts.token !== void 0 || (opts.env ?? process.env).BCCLI_SERVE_TOKEN !== void 0;
|
|
106
|
+
return `bccli serve ${handle.url}${supplied ? "" : ` \u2014 Authorization: Bearer ${handle.token}`}
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
104
109
|
async function startServe(opts = {}) {
|
|
105
110
|
const env = opts.env ?? process.env;
|
|
106
111
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -454,7 +459,7 @@ Connection: close\r
|
|
|
454
459
|
function attachSession(id, forCwd) {
|
|
455
460
|
const found = findSessionFile(id, forCwd);
|
|
456
461
|
if (!found) return void 0;
|
|
457
|
-
const rt = buildRuntime(found.cwd, "ask");
|
|
462
|
+
const rt = buildRuntime(found.cwd, "ask", found.session.lastModel());
|
|
458
463
|
rt.resume(found.session);
|
|
459
464
|
return registerSession(rt, found.cwd, "ask", id);
|
|
460
465
|
}
|
|
@@ -511,5 +516,6 @@ Connection: close\r
|
|
|
511
516
|
};
|
|
512
517
|
}
|
|
513
518
|
export {
|
|
519
|
+
serveBanner,
|
|
514
520
|
startServe
|
|
515
521
|
};
|
package/dist/serve.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Provider } from './provider';
|
|
2
|
+
export interface ServeOptions {
|
|
3
|
+
port?: number;
|
|
4
|
+
host?: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
env?: NodeJS.ProcessEnv;
|
|
8
|
+
provider?: Provider;
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
heartbeatMs?: number;
|
|
11
|
+
err?: (s: string) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface ServeHandle {
|
|
14
|
+
port: number;
|
|
15
|
+
token: string;
|
|
16
|
+
url: string;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export type PermissionMode = 'ask' | 'bypassPermissions';
|
|
20
|
+
/**
|
|
21
|
+
* One-line terminal banner for `bccli serve`. A token the user supplied (`--token` or
|
|
22
|
+
* `BCCLI_SERVE_TOKEN`) is left out so it cannot leak into logs; a token BCCLI generated
|
|
23
|
+
* itself must be printed or nobody could connect.
|
|
24
|
+
*/
|
|
25
|
+
export declare function serveBanner(handle: {
|
|
26
|
+
url: string;
|
|
27
|
+
token: string;
|
|
28
|
+
}, opts?: {
|
|
29
|
+
token?: string;
|
|
30
|
+
env?: NodeJS.ProcessEnv;
|
|
31
|
+
}): string;
|
|
32
|
+
/**
|
|
33
|
+
* Starts the loopback session server (HTTP unary + WS mux at /v1/mux). Refuses
|
|
34
|
+
* non-loopback bind addresses; every request passes the DSH-style trust fence
|
|
35
|
+
* (403) and, except /health, the bearer-token check (401).
|
|
36
|
+
*/
|
|
37
|
+
export declare function startServe(opts?: ServeOptions): Promise<ServeHandle>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Heartbeat {
|
|
2
|
+
/** Sends the first ping and schedules the check loop. Idempotent until stop(). */
|
|
3
|
+
start(): void;
|
|
4
|
+
/** Marks the last ping as answered (ws 'pong' event). */
|
|
5
|
+
pong(): void;
|
|
6
|
+
/** Clears the timer; no further pings or terminations. */
|
|
7
|
+
stop(): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* ws heartbeat with deadline: every interval a ping goes out; a ping left
|
|
11
|
+
* unanswered by the next tick terminates the socket (connection, not stream).
|
|
12
|
+
* Modeled on the DSH gateway's `websocketHeartbeatIntervalMs` behavior.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createHeartbeat(intervalMs: number, ping: () => void, terminate: () => void): Heartbeat;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Wire frames of the /v1/mux WebSocket (subset of the DSH stream protocol). */
|
|
2
|
+
export type ClientFrame = {
|
|
3
|
+
type: 'open';
|
|
4
|
+
streamId: string;
|
|
5
|
+
target: string;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'cancel';
|
|
8
|
+
streamId: string;
|
|
9
|
+
};
|
|
10
|
+
export type ServerFrame = {
|
|
11
|
+
type: 'item';
|
|
12
|
+
streamId: string;
|
|
13
|
+
value: unknown;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'end';
|
|
16
|
+
streamId: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'error';
|
|
19
|
+
streamId: string;
|
|
20
|
+
message: string;
|
|
21
|
+
};
|
|
22
|
+
/** Uplink frame size limit; oversized frames error their stream without closing the socket. */
|
|
23
|
+
export declare const MAX_FRAME_BYTES = 262144;
|
|
24
|
+
/**
|
|
25
|
+
* Parses one uplink mux frame. Malformed JSON, unknown types, an empty streamId,
|
|
26
|
+
* or an `open` without a target produce `{ error }` instead of throwing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseClientFrame(raw: string): ClientFrame | {
|
|
29
|
+
error: string;
|
|
30
|
+
};
|
|
31
|
+
/** Addresses `bccli serve` is allowed to bind (loopback only; 0.0.0.0 is refused). */
|
|
32
|
+
export declare const LOOPBACK_BIND: Set<string>;
|
|
33
|
+
/**
|
|
34
|
+
* DSH-style trust fence: loopback Host with a port matching the listener, a
|
|
35
|
+
* same-machine Origin when attached, and no cross-site sec-fetch-site. Returns
|
|
36
|
+
* null when trusted, else the 403 reason. Never establishes identity — the
|
|
37
|
+
* bearer token does.
|
|
38
|
+
*/
|
|
39
|
+
export declare function trustFence(headers: {
|
|
40
|
+
host?: string;
|
|
41
|
+
origin?: string;
|
|
42
|
+
'sec-fetch-site'?: string;
|
|
43
|
+
}, port: number): string | null;
|
|
44
|
+
/** Timing-safe `Authorization: Bearer <token>` check. */
|
|
45
|
+
export declare function bearerOk(header: string | undefined, token: string): boolean;
|
|
46
|
+
/** Fresh 32-byte hex serve token. */
|
|
47
|
+
export declare function randomToken(): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ChatMessage, type Usage } from './provider';
|
|
2
|
+
export declare class Session {
|
|
3
|
+
readonly file: string;
|
|
4
|
+
constructor(file: string);
|
|
5
|
+
static create(home: string, cwd: string, now?: Date): Session;
|
|
6
|
+
static list(home: string, cwd: string): {
|
|
7
|
+
session: Session;
|
|
8
|
+
mtime: Date;
|
|
9
|
+
preview: string;
|
|
10
|
+
}[];
|
|
11
|
+
static latest(home: string, cwd: string): Session | undefined;
|
|
12
|
+
private write;
|
|
13
|
+
append(message: ChatMessage): void;
|
|
14
|
+
appendUsage(usage: Usage & {
|
|
15
|
+
model?: string;
|
|
16
|
+
}): void;
|
|
17
|
+
reset(): void;
|
|
18
|
+
private records;
|
|
19
|
+
/** What the model continues from: everything after the last reset (after a compaction that is the summary and the recent turns). */
|
|
20
|
+
load(): ChatMessage[];
|
|
21
|
+
/** Model of the most recent turn that recorded usage — serve attach continues a session with its own model. */
|
|
22
|
+
lastModel(): string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* What the user sees on resume: the whole conversation. Compaction only shrinks what the model is sent, so
|
|
25
|
+
* its reset does not hide the older turns here. A real reset (/clear, rewind) still starts over, the
|
|
26
|
+
* synthetic summary pair is never shown, and the recent turns a compaction re-writes are not shown twice.
|
|
27
|
+
*/
|
|
28
|
+
loadHistory(): ChatMessage[];
|
|
29
|
+
}
|
|
30
|
+
export declare function pruneSessions(home: string, now?: number, maxAgeDays?: number): number;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createRuntime,
|
|
4
|
+
lunaPtcAutoEnabled
|
|
5
|
+
} from "./chunk-PZRKU4UM.js";
|
|
6
|
+
import "./chunk-QZKLZELZ.js";
|
|
7
|
+
import "./chunk-BGXNR74O.js";
|
|
8
|
+
import "./chunk-45SDLMTV.js";
|
|
9
|
+
import "./chunk-PSO7R5AD.js";
|
|
10
|
+
import "./chunk-MHIYLXJC.js";
|
|
11
|
+
import "./chunk-GN4W3T6E.js";
|
|
12
|
+
import "./chunk-75BECX4F.js";
|
|
13
|
+
import "./chunk-JHPGOAXU.js";
|
|
14
|
+
import "./chunk-MFHCQQEN.js";
|
|
15
|
+
import "./chunk-BC7UXFE4.js";
|
|
16
|
+
import "./chunk-WNACAUDK.js";
|
|
17
|
+
import "./chunk-BLOYFIAD.js";
|
|
18
|
+
import "./chunk-24JN75FZ.js";
|
|
19
|
+
import "./chunk-FLQPE4S5.js";
|
|
20
|
+
import "./chunk-UZWJQF67.js";
|
|
21
|
+
export {
|
|
22
|
+
createRuntime,
|
|
23
|
+
lunaPtcAutoEnabled
|
|
24
|
+
};
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Agent } from './agent';
|
|
2
|
+
import { CheckpointStore } from './checkpoints';
|
|
3
|
+
import type { McpServerSpec } from './mcp/config';
|
|
4
|
+
import { McpManager } from './mcp/manager';
|
|
5
|
+
import type { CliArgs } from './args';
|
|
6
|
+
import { type Config } from './config';
|
|
7
|
+
import { type AgentDef, type CommandDef, type SkillDef } from './extensions';
|
|
8
|
+
import { type ModelGroup } from './models';
|
|
9
|
+
import { type ChatMessage, type Provider } from './provider';
|
|
10
|
+
import type { ReasoningLevel } from './reasoning';
|
|
11
|
+
import { addProviderKey } from './providerCli';
|
|
12
|
+
import { Session } from './session';
|
|
13
|
+
import { type Interaction } from './tools/plan';
|
|
14
|
+
import { TodoStore } from './tools/todo';
|
|
15
|
+
import { type PluginPayload } from './plugins';
|
|
16
|
+
import type { HookEvent } from './hooks';
|
|
17
|
+
export interface Runtime {
|
|
18
|
+
cwd: string;
|
|
19
|
+
home: string;
|
|
20
|
+
config: Config;
|
|
21
|
+
modelRef: string;
|
|
22
|
+
reasoning: ReasoningLevel;
|
|
23
|
+
agent: Agent;
|
|
24
|
+
session: Session;
|
|
25
|
+
setModel(ref: string): void;
|
|
26
|
+
setReasoning(level: ReasoningLevel): void;
|
|
27
|
+
env: NodeJS.ProcessEnv;
|
|
28
|
+
skills: SkillDef[];
|
|
29
|
+
commands: CommandDef[];
|
|
30
|
+
agentDefs: AgentDef[];
|
|
31
|
+
todos: TodoStore;
|
|
32
|
+
interaction: Interaction;
|
|
33
|
+
mcp: McpManager;
|
|
34
|
+
startMcp(specs: McpServerSpec[]): Promise<void>;
|
|
35
|
+
reloadConfig(): void;
|
|
36
|
+
providerLabel(): string;
|
|
37
|
+
listModels: (only?: string) => Promise<ModelGroup[]>;
|
|
38
|
+
addProviderKey(id: string, key: string): ReturnType<typeof addProviderKey>;
|
|
39
|
+
/** Continue an earlier session: load its history and append new messages to its file. */
|
|
40
|
+
resume(session: Session): void;
|
|
41
|
+
/** Starts a fresh session file; the previous one stays on disk for /resume. */
|
|
42
|
+
newSession(): void;
|
|
43
|
+
/** Re-reads AGENTS.md/BCCLI.md into the system prompt (after /memory). */
|
|
44
|
+
rebuildSystemPrompt(): void;
|
|
45
|
+
/** Fires a plugin observer event (SessionStart/Stop are emitted here; tool events come from the agent). */
|
|
46
|
+
emitPlugins(event: HookEvent, payload?: PluginPayload): Promise<void>;
|
|
47
|
+
checkpoints: CheckpointStore;
|
|
48
|
+
/**
|
|
49
|
+
* Steps back n conversation turns: truncates the history (and the session log) to before
|
|
50
|
+
* them and restores the file snapshots they took. Returns undefined when nothing is left.
|
|
51
|
+
*/
|
|
52
|
+
rewindTurns(n: number): Promise<RewindResult | undefined>;
|
|
53
|
+
startedAt: Date;
|
|
54
|
+
}
|
|
55
|
+
export interface RewindResult {
|
|
56
|
+
turns: number;
|
|
57
|
+
restored: string[];
|
|
58
|
+
deleted: string[];
|
|
59
|
+
skipped: string[];
|
|
60
|
+
failed: string[];
|
|
61
|
+
}
|
|
62
|
+
/** PTC is automatic for Luna. This env var is only an emergency/internal kill switch. */
|
|
63
|
+
export declare function lunaPtcAutoEnabled(env: NodeJS.ProcessEnv): boolean;
|
|
64
|
+
export declare function createRuntime(opts: {
|
|
65
|
+
cwd: string;
|
|
66
|
+
args: CliArgs;
|
|
67
|
+
env?: NodeJS.ProcessEnv;
|
|
68
|
+
provider?: Provider;
|
|
69
|
+
history?: ChatMessage[];
|
|
70
|
+
fetch?: typeof fetch;
|
|
71
|
+
userHome?: string;
|
|
72
|
+
/** Override langkah agent (mis. githubBot.stepLimit) — menang atas config.maxSteps. */
|
|
73
|
+
maxSteps?: number | null;
|
|
74
|
+
}): Runtime;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function osc52(text: string, inTmux: boolean): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function gitDiff(cwd: string, maxLines?: number, bin?: string): Promise<string>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface DoctorDeps {
|
|
2
|
+
which: (cmd: string) => boolean | Promise<boolean>;
|
|
3
|
+
nodeVersion: string;
|
|
4
|
+
listModels: () => Promise<unknown[]>;
|
|
5
|
+
}
|
|
6
|
+
export declare function doctorText(input: {
|
|
7
|
+
providers: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
ready: boolean;
|
|
11
|
+
}[];
|
|
12
|
+
mcp: {
|
|
13
|
+
name: string;
|
|
14
|
+
status: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
}[];
|
|
17
|
+
activeProvider: string;
|
|
18
|
+
}, deps: DoctorDeps): Promise<string>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface StatusInput {
|
|
2
|
+
version: string;
|
|
3
|
+
modelRef: string;
|
|
4
|
+
providerLabel: string;
|
|
5
|
+
mode: string;
|
|
6
|
+
cwd: string;
|
|
7
|
+
mcp: {
|
|
8
|
+
name: string;
|
|
9
|
+
status: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
tools: number;
|
|
12
|
+
}[];
|
|
13
|
+
usage: {
|
|
14
|
+
inputTokens: number;
|
|
15
|
+
outputTokens: number;
|
|
16
|
+
cachedInputTokens?: number;
|
|
17
|
+
cacheWriteTokens?: number;
|
|
18
|
+
};
|
|
19
|
+
lastInputTokens: number;
|
|
20
|
+
}
|
|
21
|
+
export declare function statusText(s: StatusInput): string;
|
|
22
|
+
export declare function agentsText(defs: {
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
tools?: string[];
|
|
26
|
+
model?: string;
|
|
27
|
+
}[]): string;
|
|
28
|
+
export declare function skillsText(skills: {
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
dir: string;
|
|
32
|
+
}[], commands: {
|
|
33
|
+
name: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
}[]): string;
|
|
36
|
+
export declare function sessionText(s: {
|
|
37
|
+
file: string;
|
|
38
|
+
started: Date;
|
|
39
|
+
messages: number;
|
|
40
|
+
usage: {
|
|
41
|
+
inputTokens: number;
|
|
42
|
+
outputTokens: number;
|
|
43
|
+
};
|
|
44
|
+
modelRef: string;
|
|
45
|
+
}): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function instructionFiles(cwd: string, home: string): {
|
|
2
|
+
path: string;
|
|
3
|
+
lines: number;
|
|
4
|
+
}[];
|
|
5
|
+
export declare function appendMemory(file: string, text: string): void;
|
|
6
|
+
/** `/memory [global] <teks>` → target file and text; text is empty when nothing follows. */
|
|
7
|
+
export declare function parseMemoryArgs(args: string): {
|
|
8
|
+
global: boolean;
|
|
9
|
+
text: string;
|
|
10
|
+
};
|