@botconnector/bccli 0.4.16 → 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.
Files changed (185) hide show
  1. package/LICENSE +203 -21
  2. package/THIRD_PARTY_NOTICES.md +9 -0
  3. package/branding.mjs +347 -0
  4. package/cli.mjs +120 -0
  5. package/core.mjs +260 -0
  6. package/credentials.mjs +52 -0
  7. package/gateway.mjs +2 -0
  8. package/model-command.mjs +61 -0
  9. package/package.json +35 -59
  10. package/provider-cli.mjs +77 -0
  11. package/providers.mjs +166 -0
  12. package/proxy.mjs +242 -0
  13. package/startup-menu.mjs +120 -0
  14. package/README.en.md +0 -253
  15. package/README.md +0 -250
  16. package/dist/abort.d.ts +0 -5
  17. package/dist/acp-JZW3XHE5.js +0 -221
  18. package/dist/acp.d.ts +0 -44
  19. package/dist/agent.d.ts +0 -147
  20. package/dist/agents.d.ts +0 -4
  21. package/dist/args-XVO7TB4C.js +0 -13
  22. package/dist/args.d.ts +0 -59
  23. package/dist/budget.d.ts +0 -26
  24. package/dist/checkpoints.d.ts +0 -35
  25. package/dist/chunk-3CYQYHPK.js +0 -202
  26. package/dist/chunk-6JK4IBGK.js +0 -1075
  27. package/dist/chunk-6SDRWEPN.js +0 -50
  28. package/dist/chunk-7GM6NN5E.js +0 -341
  29. package/dist/chunk-7XD47KN5.js +0 -71
  30. package/dist/chunk-INMSTUB2.js +0 -56
  31. package/dist/chunk-ISOKH5WB.js +0 -256
  32. package/dist/chunk-JUC3ZOCV.js +0 -50
  33. package/dist/chunk-KDVL2NP6.js +0 -861
  34. package/dist/chunk-KEKDRROL.js +0 -216
  35. package/dist/chunk-KJIXA6MP.js +0 -159
  36. package/dist/chunk-OK2USAXX.js +0 -88
  37. package/dist/chunk-PSO7R5AD.js +0 -10
  38. package/dist/chunk-Q42ZGVAQ.js +0 -91
  39. package/dist/chunk-R754XIBJ.js +0 -523
  40. package/dist/chunk-S3QEZDKB.js +0 -270
  41. package/dist/chunk-SWNRA3EW.js +0 -78
  42. package/dist/chunk-TLCL6DC7.js +0 -378
  43. package/dist/chunk-V5D6PJQN.js +0 -8
  44. package/dist/chunk-YYTFJUO2.js +0 -148
  45. package/dist/chunk-ZJRZTMJF.js +0 -2669
  46. package/dist/cli.d.ts +0 -1
  47. package/dist/cli.js +0 -233
  48. package/dist/clipboardImage.d.ts +0 -17
  49. package/dist/commands.d.ts +0 -16
  50. package/dist/completion-Q7VHOPPV.js +0 -125
  51. package/dist/completion.d.ts +0 -14
  52. package/dist/config-T7MKGJVG.js +0 -34
  53. package/dist/config-YYEAEN2C.js +0 -25
  54. package/dist/config.d.ts +0 -99
  55. package/dist/context.d.ts +0 -13
  56. package/dist/contextWindow.d.ts +0 -3
  57. package/dist/diff.d.ts +0 -7
  58. package/dist/exit.d.ts +0 -9
  59. package/dist/extensions.d.ts +0 -34
  60. package/dist/ghBotCli-7VUGI63S.js +0 -680
  61. package/dist/ghBotCli.d.ts +0 -9
  62. package/dist/ghBotDispatch.d.ts +0 -68
  63. package/dist/ghBotRunner.d.ts +0 -82
  64. package/dist/ghBotServe.d.ts +0 -21
  65. package/dist/ghBotWebhook.d.ts +0 -45
  66. package/dist/hooks.d.ts +0 -27
  67. package/dist/i18n/id.d.ts +0 -1
  68. package/dist/i18n.d.ts +0 -16
  69. package/dist/integrationCli-FBRSTF5F.js +0 -876
  70. package/dist/integrationCli.d.ts +0 -9
  71. package/dist/keybinds.d.ts +0 -22
  72. package/dist/login-BSMUGW7L.js +0 -18
  73. package/dist/login.d.ts +0 -21
  74. package/dist/lsp.d.ts +0 -73
  75. package/dist/mcp/catalog.d.ts +0 -14
  76. package/dist/mcp/config.d.ts +0 -36
  77. package/dist/mcp/manager.d.ts +0 -52
  78. package/dist/mcp/oauth.d.ts +0 -82
  79. package/dist/mcpCli-ZT7CRYMP.js +0 -113
  80. package/dist/mcpCli.d.ts +0 -3
  81. package/dist/mcpServer/serve.d.ts +0 -8
  82. package/dist/mcpServer/server.d.ts +0 -19
  83. package/dist/models.d.ts +0 -13
  84. package/dist/modelsCli-2ZRW4CC4.js +0 -36
  85. package/dist/modelsCli.d.ts +0 -15
  86. package/dist/npmRunner-LU43GM3W.js +0 -46
  87. package/dist/npmRunner.d.ts +0 -21
  88. package/dist/oauthLogin-THSM6FE7.js +0 -210
  89. package/dist/oauthLogin.d.ts +0 -47
  90. package/dist/permissions.d.ts +0 -30
  91. package/dist/pluginSpec.d.ts +0 -25
  92. package/dist/plugins.d.ts +0 -45
  93. package/dist/pluginsCli-EKQI4CJW.js +0 -288
  94. package/dist/pluginsCli.d.ts +0 -16
  95. package/dist/prCli-FMQTOBIV.js +0 -94
  96. package/dist/prCli.d.ts +0 -46
  97. package/dist/presets.d.ts +0 -8
  98. package/dist/print.d.ts +0 -17
  99. package/dist/provider.d.ts +0 -145
  100. package/dist/providerCli-3TFEKV4C.js +0 -15
  101. package/dist/providerCli.d.ts +0 -17
  102. package/dist/providers.d.ts +0 -6
  103. package/dist/reasoning.d.ts +0 -12
  104. package/dist/repomap.d.ts +0 -10
  105. package/dist/sdk.d.ts +0 -61
  106. package/dist/sdk.js +0 -6494
  107. package/dist/serve-3BODPEPR.js +0 -532
  108. package/dist/serve-V6YVZTNR.js +0 -178
  109. package/dist/serve.d.ts +0 -37
  110. package/dist/serveHeartbeat.d.ts +0 -14
  111. package/dist/serveProtocol.d.ts +0 -47
  112. package/dist/session-LX4UNPCD.js +0 -12
  113. package/dist/session.d.ts +0 -33
  114. package/dist/setup-MFG3BWEU.js +0 -24
  115. package/dist/setup.d.ts +0 -79
  116. package/dist/slash/copy.d.ts +0 -1
  117. package/dist/slash/diff.d.ts +0 -1
  118. package/dist/slash/doctor.d.ts +0 -18
  119. package/dist/slash/export.d.ts +0 -2
  120. package/dist/slash/info.d.ts +0 -46
  121. package/dist/slash/memory.d.ts +0 -10
  122. package/dist/statsCli-7MIQHLVW.js +0 -353
  123. package/dist/statsCli.d.ts +0 -62
  124. package/dist/textToolCalls.d.ts +0 -6
  125. package/dist/thinking.d.ts +0 -17
  126. package/dist/tokenBudget.d.ts +0 -22
  127. package/dist/tools/bash.d.ts +0 -54
  128. package/dist/tools/diagnostics.d.ts +0 -13
  129. package/dist/tools/edit.d.ts +0 -12
  130. package/dist/tools/fetch.d.ts +0 -41
  131. package/dist/tools/glob.d.ts +0 -5
  132. package/dist/tools/globSafety.d.ts +0 -7
  133. package/dist/tools/grep.d.ts +0 -25
  134. package/dist/tools/ignore.d.ts +0 -2
  135. package/dist/tools/index.d.ts +0 -12
  136. package/dist/tools/memory.d.ts +0 -13
  137. package/dist/tools/paths.d.ts +0 -4
  138. package/dist/tools/plan.d.ts +0 -10
  139. package/dist/tools/read.d.ts +0 -16
  140. package/dist/tools/repomap.d.ts +0 -2
  141. package/dist/tools/sandbox.d.ts +0 -15
  142. package/dist/tools/shell.d.ts +0 -18
  143. package/dist/tools/skill.d.ts +0 -3
  144. package/dist/tools/task.d.ts +0 -28
  145. package/dist/tools/todo.d.ts +0 -13
  146. package/dist/tools/types.d.ts +0 -52
  147. package/dist/tools/websearch.d.ts +0 -9
  148. package/dist/tools/write.d.ts +0 -5
  149. package/dist/transferCli-SRSYQLSJ.js +0 -73
  150. package/dist/transferCli.d.ts +0 -23
  151. package/dist/ui/App.d.ts +0 -7
  152. package/dist/ui/DiffView.d.ts +0 -3
  153. package/dist/ui/EditableText.d.ts +0 -7
  154. package/dist/ui/LinePrompt.d.ts +0 -6
  155. package/dist/ui/ListPicker.d.ts +0 -11
  156. package/dist/ui/Markdown.d.ts +0 -8
  157. package/dist/ui/McpMenu.d.ts +0 -11
  158. package/dist/ui/ModelPicker.d.ts +0 -6
  159. package/dist/ui/PermissionPrompt.d.ts +0 -5
  160. package/dist/ui/PlanApproval.d.ts +0 -5
  161. package/dist/ui/PromptInput.d.ts +0 -20
  162. package/dist/ui/ProviderMenu.d.ts +0 -10
  163. package/dist/ui/Spinner.d.ts +0 -4
  164. package/dist/ui/StatusBar.d.ts +0 -9
  165. package/dist/ui/TodoList.d.ts +0 -4
  166. package/dist/ui/ToolBlock.d.ts +0 -14
  167. package/dist/ui/complete.d.ts +0 -8
  168. package/dist/ui/index.d.ts +0 -7
  169. package/dist/ui/lineEdit.d.ts +0 -42
  170. package/dist/ui/liveCap.d.ts +0 -9
  171. package/dist/ui/replay.d.ts +0 -4
  172. package/dist/ui/stdinFilter.d.ts +0 -18
  173. package/dist/ui/table.d.ts +0 -20
  174. package/dist/ui/theme.d.ts +0 -5
  175. package/dist/ui/thinkingMouse.d.ts +0 -38
  176. package/dist/ui/transcript.d.ts +0 -55
  177. package/dist/ui/tty.d.ts +0 -11
  178. package/dist/ui/vim.d.ts +0 -26
  179. package/dist/ui-LZ4JGF2V.js +0 -2913
  180. package/dist/update-P7MU4ZM7.js +0 -145
  181. package/dist/update.d.ts +0 -30
  182. package/dist/verify.d.ts +0 -16
  183. package/dist/version.d.ts +0 -1
  184. package/dist/webBudget.d.ts +0 -25
  185. package/dist/worktree.d.ts +0 -12
@@ -1,378 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- t
4
- } from "./chunk-R754XIBJ.js";
5
-
6
- // src/config.ts
7
- import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
8
- import { homedir } from "os";
9
- import { dirname, join } from "path";
10
-
11
- // src/presets.ts
12
- var PRESETS = [
13
- { id: "bc-cloud", name: "BotConnector Cloud", baseURL: "https://api.botconnector.id/v1", apiKeyEnv: "BOTCONNECTOR_API_KEY" },
14
- { id: "openrouter", name: "OpenRouter", baseURL: "https://openrouter.ai/api/v1", apiKeyEnv: "OPENROUTER_API_KEY" },
15
- { id: "openai", name: "OpenAI", baseURL: "https://api.openai.com/v1", apiKeyEnv: "OPENAI_API_KEY" },
16
- { id: "gemini", name: "Google Gemini", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", apiKeyEnv: "GEMINI_API_KEY" },
17
- { id: "deepseek", name: "DeepSeek", baseURL: "https://api.deepseek.com/v1", apiKeyEnv: "DEEPSEEK_API_KEY" },
18
- { id: "groq", name: "Groq", baseURL: "https://api.groq.com/openai/v1", apiKeyEnv: "GROQ_API_KEY" },
19
- { id: "ollama-cloud", name: "Ollama Cloud", baseURL: "https://ollama.com/v1", apiKeyEnv: "OLLAMA_API_KEY" },
20
- { id: "ollama", name: "Ollama lokal", baseURL: "http://127.0.0.1:11434/v1", local: true },
21
- { id: "lmstudio", name: "LM Studio lokal", baseURL: "http://127.0.0.1:1234/v1", local: true }
22
- ];
23
-
24
- // src/keybinds.ts
25
- var KEYBIND_ACTIONS = ["thinking", "toolOutput", "pasteImage"];
26
- var DEFAULT_KEYBINDS = {
27
- thinking: "ctrl+t",
28
- toolOutput: "ctrl+o",
29
- pasteImage: "alt+v"
30
- };
31
- function defaultKeybinds() {
32
- return Object.fromEntries(KEYBIND_ACTIONS.map((action) => [action, parseKeybind(DEFAULT_KEYBINDS[action])]));
33
- }
34
- function parseKeybind(raw) {
35
- const spec = raw.trim().toLowerCase();
36
- const parts = spec.split("+");
37
- const key = parts.pop() ?? "";
38
- if (!/^[a-z]$/.test(key)) return void 0;
39
- if (!parts.length || new Set(parts).size !== parts.length) return void 0;
40
- if (parts.some((p) => p !== "ctrl" && p !== "alt")) return void 0;
41
- return { spec, ctrl: parts.includes("ctrl"), meta: parts.includes("alt"), key };
42
- }
43
- function matchKeybind(kb, input, key) {
44
- return kb.ctrl === !!key.ctrl && kb.meta === !!key.meta && input.toLowerCase() === kb.key;
45
- }
46
-
47
- // src/ui/theme.ts
48
- var THEMES = ["default", "blue", "amber", "magenta", "mono"];
49
- var REMAP = {
50
- blue: { green: "blue" },
51
- amber: { green: "yellow" },
52
- magenta: { green: "magenta" }
53
- };
54
- var theme = "default";
55
- function setTheme(name) {
56
- theme = name;
57
- }
58
- function color(name) {
59
- if (process.env.NO_COLOR) return void 0;
60
- if (theme === "mono") return void 0;
61
- return REMAP[theme]?.[name] ?? name;
62
- }
63
- var ACCENT = "green";
64
-
65
- // src/config.ts
66
- var ConfigError = class extends Error {
67
- };
68
- var DEFAULT_MAX_STEPS = null;
69
- var DEFAULT_CONFIG = {
70
- model: "bc-cloud/glm-5.3-flash",
71
- permissionMode: "default",
72
- reasoning: "auto",
73
- vision: true,
74
- networkPolicy: "allow",
75
- keybinds: defaultKeybinds(),
76
- verifyCommands: [],
77
- repoMap: false,
78
- theme: "default",
79
- editor: "emacs",
80
- sandbox: "off",
81
- providers: Object.fromEntries(PRESETS.map((p) => [p.id, { baseURL: p.baseURL, apiKeyEnv: p.apiKeyEnv }])),
82
- allow: []
83
- };
84
- function bccliHome(env = process.env) {
85
- return env.BCCLI_HOME ?? join(homedir(), ".bccli");
86
- }
87
- function readJsonConfig(path) {
88
- if (!existsSync(path)) return {};
89
- try {
90
- return JSON.parse(readFileSync(path, "utf8"));
91
- } catch (error) {
92
- throw new ConfigError(t("Invalid config: {path} ({error})", { path, error: error.message }));
93
- }
94
- }
95
- function resolvedMaxSteps(global) {
96
- const value = global.maxSteps;
97
- if (value === void 0) return DEFAULT_MAX_STEPS;
98
- if (value === null || value === 0) return null;
99
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
100
- throw new ConfigError(t("maxSteps must be a positive number, or 0/null to disable the limit."));
101
- }
102
- return Math.max(1, Math.floor(value));
103
- }
104
- function resolvedSessionRetentionDays(global) {
105
- const value = global.sessionRetentionDays;
106
- if (value === void 0 || value === null || value === 0) return null;
107
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
108
- throw new ConfigError(t("sessionRetentionDays must be a positive number of days, or 0/null to keep sessions."));
109
- }
110
- return Math.max(1, Math.floor(value));
111
- }
112
- function resolvedNetworkPolicy(global) {
113
- const value = global.networkPolicy ?? "allow";
114
- if (value !== "allow" && value !== "offline") {
115
- throw new ConfigError(t('networkPolicy must be "allow" or "offline".'));
116
- }
117
- return value;
118
- }
119
- function resolvedPlugins(global) {
120
- const value = global.plugins;
121
- if (value === void 0) return [];
122
- if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
123
- throw new ConfigError(t("plugins must be an array of strings."));
124
- }
125
- return [...value];
126
- }
127
- function resolvedUpdateCheck(global) {
128
- const value = global.updateCheck;
129
- if (value === void 0) return void 0;
130
- if (value !== "on" && value !== "off") throw new ConfigError(t('updateCheck must be "on" or "off".'));
131
- return value;
132
- }
133
- function resolvedUsageCap(global) {
134
- const cap = global.usageCap;
135
- if (cap === void 0) return void 0;
136
- if (typeof cap !== "object" || cap === null || Array.isArray(cap)) {
137
- throw new ConfigError(t('usageCap must be an object, e.g. { "tokens": 2000000 }.'));
138
- }
139
- const { tokens, usd, prices } = cap;
140
- const positive = (v) => typeof v === "number" && Number.isFinite(v) && v > 0;
141
- const nonNegative = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
142
- if (tokens !== void 0 && !positive(tokens)) throw new ConfigError(t("usageCap.tokens must be a number greater than 0."));
143
- if (usd !== void 0 && !positive(usd)) throw new ConfigError(t("usageCap.usd must be a number greater than 0."));
144
- if (usd !== void 0 && (prices === void 0 || !Object.keys(prices).length)) {
145
- throw new ConfigError(t("usageCap.usd requires usageCap.prices (USD per 1M tokens)."));
146
- }
147
- if (prices !== void 0) {
148
- for (const [key, price] of Object.entries(prices)) {
149
- if (!price || !nonNegative(price.input) || !nonNegative(price.output)) {
150
- throw new ConfigError(t('usageCap.prices["{key}"] must have numeric input and output (USD per 1M tokens).', { key }));
151
- }
152
- if (price.cachedInput !== void 0 && !nonNegative(price.cachedInput)) {
153
- throw new ConfigError(t('usageCap.prices["{key}"].cachedInput must be a number >= 0 (USD per 1M tokens).', { key }));
154
- }
155
- }
156
- }
157
- if (tokens === void 0 && usd === void 0) throw new ConfigError(t("usageCap needs at least one of: tokens, usd."));
158
- return { ...tokens !== void 0 ? { tokens } : {}, ...usd !== void 0 ? { usd } : {}, ...prices !== void 0 ? { prices } : {} };
159
- }
160
- function resolvedLsp(global) {
161
- if (global.lsp === void 0) return void 0;
162
- const lsp = global.lsp;
163
- if (typeof global.lsp !== "object" || global.lsp === null || !Array.isArray(lsp.servers)) {
164
- throw new ConfigError(t('lsp must be an object with a "servers" array.'));
165
- }
166
- for (const s of lsp.servers) {
167
- const server = s;
168
- if (typeof server?.command !== "string" || !server.command || !Array.isArray(server.extensions) || server.extensions.length === 0 || server.extensions.some((e) => typeof e !== "string" || !e.startsWith(".")) || server.args !== void 0 && (!Array.isArray(server.args) || server.args.some((a) => typeof a !== "string"))) {
169
- throw new ConfigError(t('Each lsp server needs { "extensions": [".ts"], "command": "...", "args": ["..."] }.'));
170
- }
171
- }
172
- return { servers: lsp.servers };
173
- }
174
- function resolvedSandbox(global) {
175
- const value = global.sandbox ?? "off";
176
- if (value !== "off" && value !== "on") throw new ConfigError(t('sandbox must be "off" or "on".'));
177
- return value;
178
- }
179
- function resolvedEditor(global) {
180
- const value = global.editor ?? "emacs";
181
- if (value !== "emacs" && value !== "vim") throw new ConfigError(t('editor must be "emacs" or "vim".'));
182
- return value;
183
- }
184
- function resolvedTheme(global) {
185
- const value = global.theme ?? "default";
186
- if (typeof value !== "string" || !THEMES.includes(value)) {
187
- throw new ConfigError(t("theme must be one of: {themes}.", { themes: THEMES.join(", ") }));
188
- }
189
- return value;
190
- }
191
- function resolvedRepoMap(global) {
192
- const value = global.repoMap ?? false;
193
- if (typeof value !== "boolean") throw new ConfigError(t("repoMap must be true or false."));
194
- return value;
195
- }
196
- function resolvedVerifyCommands(global) {
197
- const value = global.verifyCommands;
198
- if (value === void 0) return [];
199
- if (!Array.isArray(value) || value.some((c) => typeof c !== "string" || !c.trim())) {
200
- throw new ConfigError(t("verifyCommands must be an array of non-empty strings."));
201
- }
202
- return value.map((c) => c.trim());
203
- }
204
- function resolvedKeybinds(global) {
205
- const raw = global.keybinds ?? {};
206
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
207
- throw new ConfigError(t("keybinds must be an object mapping action to binding."));
208
- }
209
- const out = {};
210
- for (const action of KEYBIND_ACTIONS) {
211
- const spec = raw[action];
212
- const value = spec === void 0 ? DEFAULT_KEYBINDS[action] : spec;
213
- if (typeof value !== "string") {
214
- throw new ConfigError(t('Keybind for "{action}" must be a string like "ctrl+t".', { action }));
215
- }
216
- const parsed = parseKeybind(value);
217
- if (!parsed) {
218
- throw new ConfigError(t('Keybind "{spec}" for "{action}" is invalid: use ctrl or alt plus one letter, e.g. "ctrl+t".', { spec: value, action }));
219
- }
220
- out[action] = parsed;
221
- }
222
- for (const key of Object.keys(raw)) {
223
- if (!KEYBIND_ACTIONS.includes(key)) {
224
- throw new ConfigError(t('Unknown keybind action "{action}". Known actions: {list}.', { action: key, list: KEYBIND_ACTIONS.join(", ") }));
225
- }
226
- }
227
- return out;
228
- }
229
- function untrustedProviders(project, known) {
230
- const out = {};
231
- for (const [id, provider] of Object.entries(project.providers ?? {})) {
232
- if (known[id] || typeof provider?.baseURL !== "string") continue;
233
- out[id] = { baseURL: provider.baseURL };
234
- }
235
- return out;
236
- }
237
- function loadConfig(cwd, env = process.env) {
238
- const global = readJsonConfig(join(bccliHome(env), "config.json"));
239
- const project = readJsonConfig(join(cwd, ".bccli", "config.json"));
240
- const known = { ...DEFAULT_CONFIG.providers, ...global.providers };
241
- const fromProject = untrustedProviders(project, known);
242
- const rawFallbacks = global.fallbackModels;
243
- const fallbackModels = Array.isArray(rawFallbacks) ? rawFallbacks.filter((m) => typeof m === "string" && m.includes("/")) : void 0;
244
- return {
245
- model: project.model ?? global.model ?? DEFAULT_CONFIG.model,
246
- ...fallbackModels?.length ? { fallbackModels } : {},
247
- permissionMode: global.permissionMode ?? DEFAULT_CONFIG.permissionMode,
248
- reasoning: global.reasoning ?? DEFAULT_CONFIG.reasoning,
249
- thinkingVisible: global.thinkingVisible === true,
250
- thinkingClickCollapse: global.thinkingClickCollapse === true,
251
- sessionRetentionDays: resolvedSessionRetentionDays(global),
252
- maxSteps: resolvedMaxSteps(global),
253
- hooks: global.hooks,
254
- vision: global.vision ?? DEFAULT_CONFIG.vision,
255
- networkPolicy: resolvedNetworkPolicy(global),
256
- plugins: resolvedPlugins(global),
257
- keybinds: resolvedKeybinds(global),
258
- verifyCommands: resolvedVerifyCommands(global),
259
- repoMap: resolvedRepoMap(global),
260
- theme: resolvedTheme(global),
261
- editor: resolvedEditor(global),
262
- sandbox: resolvedSandbox(global),
263
- lsp: resolvedLsp(global),
264
- usageCap: resolvedUsageCap(global),
265
- updateCheck: resolvedUpdateCheck(global),
266
- providers: { ...known, ...fromProject },
267
- projectProviders: Object.keys(fromProject),
268
- allow: [...global.allow ?? []]
269
- };
270
- }
271
- function globalConfigPath(env = process.env) {
272
- return join(bccliHome(env), "config.json");
273
- }
274
- function readGlobalPlugins(env = process.env) {
275
- const raw = readJsonConfig(globalConfigPath(env));
276
- const value = raw.plugins;
277
- if (value === void 0) return [];
278
- if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
279
- throw new ConfigError(t("plugins must be an array of strings."));
280
- }
281
- return value;
282
- }
283
- function writeFileAtomic(path, data, mode) {
284
- const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
285
- try {
286
- writeFileSync(tmp, data, mode === void 0 ? void 0 : { mode });
287
- renameSync(tmp, path);
288
- if (mode !== void 0) chmodSync(path, mode);
289
- } catch (error) {
290
- try {
291
- rmSync(tmp, { force: true });
292
- } catch {
293
- }
294
- throw error;
295
- }
296
- }
297
- function quarantineCorruptFile(path, error) {
298
- const stamp = Date.now();
299
- let dest = `${path}.corrupt-${stamp}`;
300
- for (let n = 1; existsSync(dest); n++) dest = `${path}.corrupt-${stamp}-${n}`;
301
- try {
302
- renameSync(path, dest);
303
- } catch {
304
- return void 0;
305
- }
306
- console.error(`${path} is not valid JSON (${error.message}); moved it to ${dest} instead of overwriting it.`);
307
- return dest;
308
- }
309
- function updateGlobalConfig(env, mutate) {
310
- const path = globalConfigPath(env);
311
- const cfg = existsSync(path) ? readJsonConfig(path) : {};
312
- mutate(cfg);
313
- mkdirSync(dirname(path), { recursive: true });
314
- writeFileAtomic(path, `${JSON.stringify(cfg, null, 2)}
315
- `);
316
- }
317
- function readCredentials(env = process.env) {
318
- const path = join(bccliHome(env), "credentials");
319
- if (!existsSync(path)) return {};
320
- try {
321
- return JSON.parse(readFileSync(path, "utf8"));
322
- } catch (error) {
323
- quarantineCorruptFile(path, error);
324
- return {};
325
- }
326
- }
327
- function saveCredential(providerId, key, env = process.env) {
328
- const home = bccliHome(env);
329
- mkdirSync(home, { recursive: true });
330
- writeFileAtomic(join(home, "credentials"), JSON.stringify({ ...readCredentials(env), [providerId]: key }, null, 2), 384);
331
- }
332
- function resolveModel(config, modelRef, env = process.env) {
333
- const slash = modelRef.indexOf("/");
334
- if (slash <= 0 || slash === modelRef.length - 1) {
335
- throw new ConfigError(t("Model must be in provider/model format, e.g. bc-cloud/glm-5.3-flash (got: {ref})", { ref: modelRef }));
336
- }
337
- const providerId = modelRef.slice(0, slash);
338
- const provider = config.providers[providerId];
339
- if (!provider) {
340
- throw new ConfigError(t('Provider "{id}" is not in the config. Available: {list}', { id: providerId, list: Object.keys(config.providers).join(", ") }));
341
- }
342
- const untrusted = config.projectProviders?.includes(providerId) ?? false;
343
- const stored = untrusted ? void 0 : readCredentials(env)[providerId];
344
- const apiKey = stored || (provider.apiKeyEnv ? env[provider.apiKeyEnv] : void 0) || void 0;
345
- if (provider.apiKeyEnv && !apiKey) {
346
- throw new ConfigError(t("No API key for {id} yet. Run `bccli login` or set the env var {env}.", { id: providerId, env: provider.apiKeyEnv }));
347
- }
348
- return { providerId, model: modelRef.slice(slash + 1), baseURL: provider.baseURL.replace(/\/+$/, ""), apiKey };
349
- }
350
- function removeCredential(providerId, env = process.env) {
351
- const creds = readCredentials(env);
352
- if (!(providerId in creds)) return false;
353
- delete creds[providerId];
354
- writeFileAtomic(join(bccliHome(env), "credentials"), JSON.stringify(creds, null, 2), 384);
355
- return true;
356
- }
357
-
358
- export {
359
- PRESETS,
360
- matchKeybind,
361
- setTheme,
362
- color,
363
- ACCENT,
364
- ConfigError,
365
- DEFAULT_MAX_STEPS,
366
- bccliHome,
367
- readJsonConfig,
368
- loadConfig,
369
- globalConfigPath,
370
- readGlobalPlugins,
371
- writeFileAtomic,
372
- quarantineCorruptFile,
373
- updateGlobalConfig,
374
- readCredentials,
375
- saveCredential,
376
- resolveModel,
377
- removeCredential
378
- };
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/version.ts
4
- var VERSION = true ? "0.4.16" : "0.0.0-dev";
5
-
6
- export {
7
- VERSION
8
- };
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/permissions.ts
4
- import { isAbsolute, relative, resolve } from "path";
5
- var MODE_ORDER = ["default", "acceptEdits", "plan", "allowAll"];
6
- function nextMode(mode) {
7
- return MODE_ORDER[(MODE_ORDER.indexOf(mode) + 1) % MODE_ORDER.length];
8
- }
9
- var ALWAYS_ASK_COMMANDS = /* @__PURE__ */ new Set(["sudo", "sh", "bash", "zsh", "su"]);
10
- function isAlwaysAsk(segment) {
11
- const words = segment.trim().split(/\s+/);
12
- const first = words[0] ?? "";
13
- if (ALWAYS_ASK_COMMANDS.has(first)) return true;
14
- const flags = words.slice(1).filter((w) => w.startsWith("-"));
15
- if (first === "rm" && flags.some((w) => w.includes("r"))) return true;
16
- if (first === "chmod" && flags.some((w) => w.includes("R"))) return true;
17
- if (first === "kill" && words.slice(1).includes("-9")) return true;
18
- if (first === "git" && words[1] === "push") {
19
- return words.slice(2).some((w) => w === "-f" || w === "--force" || w.startsWith("--force="));
20
- }
21
- return false;
22
- }
23
- var RUNNER_COMMANDS = /* @__PURE__ */ new Set([
24
- "npm",
25
- "npx",
26
- "pnpm",
27
- "pnpx",
28
- "yarn",
29
- "bun",
30
- "bunx",
31
- "deno",
32
- "node",
33
- "tsx",
34
- "ts-node",
35
- "python",
36
- "python3",
37
- "py",
38
- "uv",
39
- "uvx",
40
- "pip",
41
- "pip3",
42
- "pipx",
43
- "pytest",
44
- "make",
45
- "cargo",
46
- "go",
47
- "dotnet",
48
- "java",
49
- "ruby",
50
- "bundle",
51
- "rake",
52
- "gradle",
53
- "mvn",
54
- "php",
55
- "composer"
56
- ]);
57
- function commandKey(segment) {
58
- const words = segment.trim().split(/\s+/);
59
- if (RUNNER_COMMANDS.has(words[0] ?? "") && words[2] && !words[2].startsWith("-")) return words.slice(0, 3).join(" ");
60
- return words[1] ? `${words[0]} ${words[1]}` : words[0];
61
- }
62
- function requiresSensitiveToolApproval(req) {
63
- const target = req.target.trim();
64
- if (req.kind === "read" || req.kind === "edit") {
65
- return /(?:^|[\s/\\])(?:\.env(?:\.[^\s/\\]+)?|\.ssh|\.aws|\.config[/\\]gcloud|\.npmrc|\.netrc|\.git-credentials|(?:secrets?|credentials?)(?:\.[a-z0-9_-]+)?)(?:[\s/\\]|$)/i.test(
66
- target
67
- ) || /(?:id_rsa|id_ed25519|\.pem|\.p12|\.key)(?:\s|$)/i.test(target);
68
- }
69
- if (req.kind === "bash") {
70
- return /\b(?:rm\s+-[a-z]*r[a-z]*f[a-z]*\s|rm\s+-[a-z]*f[a-z]*r[a-z]*\s|mkfs(?:\.|\s)|wipefs\b|shred\s|git\s+push\s+(?:--force|-f)\b|docker\s+(?:system\s+prune|volume\s+rm)|kubectl\s+delete\b|drop\s+(?:database|table)|npm\s+publish\b)/i.test(target) || /\b(?:deploy-service\.sh|aws\s+secretsmanager|cat\s+[^;&|]*\.env\b)/i.test(target);
71
- }
72
- if (req.kind === "mcp") {
73
- return /(?:delete|remove|revoke|transfer|send_email|publish|deploy|execute_command|run_command|read_secret)/i.test(req.tool);
74
- }
75
- return false;
76
- }
77
- var Permissions = class {
78
- constructor(mode, rules = [], cwd = process.cwd()) {
79
- this.mode = mode;
80
- this.cwd = cwd;
81
- this.rules = new Set(rules);
82
- this.configRules = new Set(rules);
83
- }
84
- mode;
85
- cwd;
86
- rules;
87
- configRules;
88
- /** Edits may only be auto-allowed inside the project and outside .git. */
89
- editInProject(target) {
90
- const rel = relative(this.cwd, resolve(this.cwd, target));
91
- if (!rel || rel.startsWith("..") || isAbsolute(rel)) return false;
92
- const parts = rel.split(/[/\\]/).map((p) => p.toLowerCase());
93
- return !parts.includes(".git");
94
- }
95
- /** Rules that "[a] allow for this session" would add; undefined when it must always be asked. */
96
- rulesFor(req) {
97
- if (requiresSensitiveToolApproval(req) && (req.kind === "read" || req.kind === "edit" || process.env.BC_TOOL_POLICY_ENFORCE === "true"))
98
- return void 0;
99
- if (req.kind === "edit") return this.editInProject(req.target) ? ["edit(project)"] : void 0;
100
- if (req.kind === "fetch") {
101
- try {
102
- return [`fetch(${new URL(req.target).hostname})`];
103
- } catch {
104
- return void 0;
105
- }
106
- }
107
- if (req.kind === "bash") {
108
- if (/`|\$\(|[<>]|^\s*[({]/.test(req.target)) return void 0;
109
- const segments = req.target.split(/&&|\|\||[;&|\n]/).map((s) => s.trim()).filter(Boolean);
110
- if (!segments.length) return void 0;
111
- if (segments.some((s) => /^[({]/.test(s) || isAlwaysAsk(s))) return void 0;
112
- return [...new Set(segments.map((s) => `bash(${commandKey(s)})`))];
113
- }
114
- if (req.kind === "mcp") return [`mcp(${req.tool})`];
115
- return [];
116
- }
117
- check(req) {
118
- if (this.mode === "plan" && req.kind !== "read") return "deny";
119
- if ((req.kind === "read" || req.kind === "edit") && this.mode !== "allowAll" && requiresSensitiveToolApproval(req))
120
- return "ask";
121
- if (process.env.BC_TOOL_POLICY_ENFORCE === "true" && requiresSensitiveToolApproval(req)) return "ask";
122
- if (req.kind === "read") return "allow";
123
- if (this.mode === "allowAll") return "allow";
124
- if (this.mode === "plan") return "deny";
125
- if (this.rules.has(req.kind)) return "allow";
126
- const needed = this.rulesFor(req);
127
- if (!needed) return "ask";
128
- if (req.kind === "edit" && this.mode === "acceptEdits") return "allow";
129
- return needed.every((rule) => this.rules.has(rule)) ? "allow" : "ask";
130
- }
131
- list() {
132
- return [...this.rules].map((rule) => ({ rule, source: this.configRules.has(rule) ? "config" : "session" }));
133
- }
134
- /** Removes a session grant; rules from config/flags stay until the user edits them. */
135
- revoke(rule) {
136
- if (!this.configRules.has(rule)) this.rules.delete(rule);
137
- }
138
- allowForSession(req) {
139
- for (const rule of this.rulesFor(req) ?? []) this.rules.add(rule);
140
- }
141
- };
142
-
143
- export {
144
- MODE_ORDER,
145
- nextMode,
146
- requiresSensitiveToolApproval,
147
- Permissions
148
- };