@botconnector/bccli 0.4.0-beta.9 → 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.
Files changed (183) hide show
  1. package/README.en.md +253 -0
  2. package/README.md +93 -6
  3. package/dist/abort.d.ts +5 -0
  4. package/dist/acp-3PHBAI64.js +182 -0
  5. package/dist/acp.d.ts +27 -0
  6. package/dist/agent.d.ts +143 -0
  7. package/dist/agents.d.ts +4 -0
  8. package/dist/args-W6BNKY7K.js +13 -0
  9. package/dist/args.d.ts +51 -0
  10. package/dist/budget.d.ts +23 -0
  11. package/dist/checkpoints.d.ts +34 -0
  12. package/dist/{chunk-BFZXRKW5.js → chunk-24JN75FZ.js} +29 -7
  13. package/dist/chunk-45SDLMTV.js +341 -0
  14. package/dist/chunk-75BECX4F.js +56 -0
  15. package/dist/{chunk-SJH3YLW4.js → chunk-BC7UXFE4.js} +69 -6
  16. package/dist/chunk-BGXNR74O.js +733 -0
  17. package/dist/chunk-BKGFA2PT.js +8 -0
  18. package/dist/{chunk-CLN4Z5E3.js → chunk-BLOYFIAD.js} +6 -3
  19. package/dist/chunk-BXQQCUAC.js +145 -0
  20. package/dist/chunk-FLQPE4S5.js +373 -0
  21. package/dist/chunk-GN4W3T6E.js +76 -0
  22. package/dist/{chunk-7S6JXQCH.js → chunk-JHPGOAXU.js} +2 -1
  23. package/dist/chunk-MFHCQQEN.js +201 -0
  24. package/dist/chunk-MHIYLXJC.js +143 -0
  25. package/dist/chunk-PSO7R5AD.js +10 -0
  26. package/dist/chunk-PZRKU4UM.js +2143 -0
  27. package/dist/chunk-QZKLZELZ.js +64 -0
  28. package/dist/chunk-R5RE46CW.js +231 -0
  29. package/dist/chunk-UZWJQF67.js +500 -0
  30. package/dist/{chunk-DX7CZTBB.js → chunk-WI22M2ID.js} +14 -9
  31. package/dist/chunk-WNACAUDK.js +946 -0
  32. package/dist/chunk-XV7ZVL4J.js +235 -0
  33. package/dist/cli.d.ts +1 -0
  34. package/dist/cli.js +150 -1382
  35. package/dist/clipboardImage.d.ts +17 -0
  36. package/dist/commands.d.ts +16 -0
  37. package/dist/completion-HPPFDAPB.js +125 -0
  38. package/dist/completion.d.ts +14 -0
  39. package/dist/{config-YUNKPCNB.js → config-DIDLDONU.js} +5 -2
  40. package/dist/config-IU76CPK2.js +34 -0
  41. package/dist/config.d.ts +97 -0
  42. package/dist/context.d.ts +13 -0
  43. package/dist/contextWindow.d.ts +3 -0
  44. package/dist/diff.d.ts +7 -0
  45. package/dist/exit.d.ts +9 -0
  46. package/dist/extensions.d.ts +34 -0
  47. package/dist/ghBotCli-E3VPHNZY.js +677 -0
  48. package/dist/ghBotCli.d.ts +9 -0
  49. package/dist/ghBotDispatch.d.ts +68 -0
  50. package/dist/ghBotRunner.d.ts +82 -0
  51. package/dist/ghBotServe.d.ts +21 -0
  52. package/dist/ghBotWebhook.d.ts +45 -0
  53. package/dist/hooks.d.ts +27 -0
  54. package/dist/i18n/id.d.ts +1 -0
  55. package/dist/i18n.d.ts +16 -0
  56. package/dist/integrationCli-Q2YPDTPG.js +685 -0
  57. package/dist/integrationCli.d.ts +9 -0
  58. package/dist/keybinds.d.ts +22 -0
  59. package/dist/login-FP3BB44A.js +16 -0
  60. package/dist/login.d.ts +19 -0
  61. package/dist/lsp.d.ts +47 -0
  62. package/dist/mcp/catalog.d.ts +14 -0
  63. package/dist/mcp/config.d.ts +36 -0
  64. package/dist/mcp/manager.d.ts +34 -0
  65. package/dist/mcp/oauth.d.ts +82 -0
  66. package/dist/{mcpCli-DZWQPTOS.js → mcpCli-SNBDUWJN.js} +42 -9
  67. package/dist/mcpCli.d.ts +3 -0
  68. package/dist/mcpServer/serve.d.ts +8 -0
  69. package/dist/mcpServer/server.d.ts +19 -0
  70. package/dist/models.d.ts +13 -0
  71. package/dist/modelsCli-CZ2HNGKR.js +36 -0
  72. package/dist/modelsCli.d.ts +15 -0
  73. package/dist/npmRunner-LU43GM3W.js +46 -0
  74. package/dist/npmRunner.d.ts +21 -0
  75. package/dist/oauthLogin-6FWQABJ7.js +210 -0
  76. package/dist/oauthLogin.d.ts +47 -0
  77. package/dist/permissions.d.ts +30 -0
  78. package/dist/pluginSpec.d.ts +25 -0
  79. package/dist/plugins.d.ts +45 -0
  80. package/dist/pluginsCli-LPIUUDWB.js +284 -0
  81. package/dist/pluginsCli.d.ts +16 -0
  82. package/dist/prCli-5IMV3VNQ.js +78 -0
  83. package/dist/prCli.d.ts +33 -0
  84. package/dist/presets.d.ts +8 -0
  85. package/dist/print.d.ts +14 -0
  86. package/dist/provider.d.ts +140 -0
  87. package/dist/providerCli-NMUFXAAS.js +15 -0
  88. package/dist/providerCli.d.ts +17 -0
  89. package/dist/providers.d.ts +6 -0
  90. package/dist/reasoning.d.ts +12 -0
  91. package/dist/repomap.d.ts +10 -0
  92. package/dist/sdk.d.ts +57 -0
  93. package/dist/sdk.js +5571 -0
  94. package/dist/serve-KWOECK5W.js +178 -0
  95. package/dist/serve-X2ZV4S5U.js +521 -0
  96. package/dist/serve.d.ts +37 -0
  97. package/dist/serveHeartbeat.d.ts +14 -0
  98. package/dist/serveProtocol.d.ts +47 -0
  99. package/dist/session-GKEXDJKZ.js +12 -0
  100. package/dist/session.d.ts +30 -0
  101. package/dist/setup-OV3NWQN5.js +24 -0
  102. package/dist/setup.d.ts +74 -0
  103. package/dist/slash/copy.d.ts +1 -0
  104. package/dist/slash/diff.d.ts +1 -0
  105. package/dist/slash/doctor.d.ts +18 -0
  106. package/dist/slash/export.d.ts +2 -0
  107. package/dist/slash/info.d.ts +45 -0
  108. package/dist/slash/memory.d.ts +10 -0
  109. package/dist/statsCli-CF3R7ATL.js +353 -0
  110. package/dist/statsCli.d.ts +62 -0
  111. package/dist/textToolCalls.d.ts +6 -0
  112. package/dist/thinking.d.ts +17 -0
  113. package/dist/tokenBudget.d.ts +22 -0
  114. package/dist/tools/bash.d.ts +52 -0
  115. package/dist/tools/diagnostics.d.ts +5 -0
  116. package/dist/tools/edit.d.ts +7 -0
  117. package/dist/tools/fetch.d.ts +41 -0
  118. package/dist/tools/glob.d.ts +5 -0
  119. package/dist/tools/globSafety.d.ts +7 -0
  120. package/dist/tools/grep.d.ts +13 -0
  121. package/dist/tools/ignore.d.ts +2 -0
  122. package/dist/tools/index.d.ts +12 -0
  123. package/dist/tools/memory.d.ts +13 -0
  124. package/dist/tools/paths.d.ts +2 -0
  125. package/dist/tools/plan.d.ts +10 -0
  126. package/dist/tools/read.d.ts +16 -0
  127. package/dist/tools/repomap.d.ts +2 -0
  128. package/dist/tools/sandbox.d.ts +12 -0
  129. package/dist/tools/shell.d.ts +18 -0
  130. package/dist/tools/skill.d.ts +3 -0
  131. package/dist/tools/task.d.ts +28 -0
  132. package/dist/tools/todo.d.ts +13 -0
  133. package/dist/tools/types.d.ts +52 -0
  134. package/dist/tools/websearch.d.ts +9 -0
  135. package/dist/tools/write.d.ts +5 -0
  136. package/dist/transferCli-YUFPI6AH.js +71 -0
  137. package/dist/transferCli.d.ts +23 -0
  138. package/dist/ui/App.d.ts +7 -0
  139. package/dist/ui/DiffView.d.ts +3 -0
  140. package/dist/ui/EditableText.d.ts +7 -0
  141. package/dist/ui/LinePrompt.d.ts +6 -0
  142. package/dist/ui/ListPicker.d.ts +11 -0
  143. package/dist/ui/Markdown.d.ts +8 -0
  144. package/dist/ui/McpMenu.d.ts +11 -0
  145. package/dist/ui/ModelPicker.d.ts +6 -0
  146. package/dist/ui/PermissionPrompt.d.ts +5 -0
  147. package/dist/ui/PlanApproval.d.ts +5 -0
  148. package/dist/ui/PromptInput.d.ts +18 -0
  149. package/dist/ui/ProviderMenu.d.ts +10 -0
  150. package/dist/ui/Spinner.d.ts +4 -0
  151. package/dist/ui/StatusBar.d.ts +9 -0
  152. package/dist/ui/TodoList.d.ts +4 -0
  153. package/dist/ui/ToolBlock.d.ts +14 -0
  154. package/dist/ui/complete.d.ts +1 -0
  155. package/dist/ui/focusReport.d.ts +1 -0
  156. package/dist/ui/index.d.ts +7 -0
  157. package/dist/ui/lineEdit.d.ts +42 -0
  158. package/dist/ui/replay.d.ts +4 -0
  159. package/dist/ui/table.d.ts +20 -0
  160. package/dist/ui/theme.d.ts +5 -0
  161. package/dist/ui/thinkingMouse.d.ts +33 -0
  162. package/dist/ui/transcript.d.ts +55 -0
  163. package/dist/ui/vim.d.ts +26 -0
  164. package/dist/ui-IVIFNUCC.js +2367 -0
  165. package/dist/update-TZ2G6KQ3.js +145 -0
  166. package/dist/update.d.ts +30 -0
  167. package/dist/verify.d.ts +16 -0
  168. package/dist/version.d.ts +1 -0
  169. package/dist/webBudget.d.ts +25 -0
  170. package/dist/worktree.d.ts +12 -0
  171. package/package.json +42 -8
  172. package/dist/args-JPVSGCGY.js +0 -12
  173. package/dist/chunk-2MGINW4O.js +0 -114
  174. package/dist/chunk-ELML4KVQ.js +0 -76
  175. package/dist/chunk-ISGBGFSU.js +0 -52
  176. package/dist/chunk-KV27KTOX.js +0 -254
  177. package/dist/chunk-U7GK73CK.js +0 -341
  178. package/dist/chunk-ZYCYTEKD.js +0 -96
  179. package/dist/integrationCli-BGT5UZU4.js +0 -223
  180. package/dist/login-6K32PIXV.js +0 -9
  181. package/dist/providerCli-Q7LRM2NP.js +0 -12
  182. package/dist/session-7UB77CEG.js +0 -9
  183. package/dist/ui-6GTQUJOE.js +0 -1415
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ quarantineCorruptFile,
4
+ writeFileAtomic
5
+ } from "./chunk-FLQPE4S5.js";
6
+
7
+ // src/mcp/oauth.ts
8
+ import { spawn } from "child_process";
9
+ import { existsSync, mkdirSync, readFileSync } from "fs";
10
+ import { createServer } from "http";
11
+ import { dirname, join } from "path";
12
+ import { auth } from "@modelcontextprotocol/sdk/client/auth.js";
13
+ var oauthStorePath = (home) => join(home, "mcp-oauth.json");
14
+ function readStore(home) {
15
+ const path = oauthStorePath(home);
16
+ if (!existsSync(path)) return {};
17
+ try {
18
+ return JSON.parse(readFileSync(path, "utf8"));
19
+ } catch (error) {
20
+ quarantineCorruptFile(path, error);
21
+ return {};
22
+ }
23
+ }
24
+ function writeStore(home, store) {
25
+ const path = oauthStorePath(home);
26
+ mkdirSync(dirname(path), { recursive: true });
27
+ writeFileAtomic(path, `${JSON.stringify(store, null, 2)}
28
+ `, 384);
29
+ }
30
+ function hasStoredTokens(home, serverUrl) {
31
+ return Boolean(readStore(home)[serverUrl]?.tokens);
32
+ }
33
+ function clearTokens(home, serverUrl) {
34
+ const store = readStore(home);
35
+ const entry = store[serverUrl];
36
+ if (!entry?.tokens && !entry?.client && !entry?.codeVerifier && !entry?.discovery) return false;
37
+ delete store[serverUrl];
38
+ writeStore(home, store);
39
+ return true;
40
+ }
41
+ function openCommand(url, platform) {
42
+ if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
43
+ if (platform === "win32") return { command: "rundll32.exe", args: ["url.dll,FileProtocolHandler", url.href] };
44
+ return { command: platform === "darwin" ? "open" : "xdg-open", args: [url.href] };
45
+ }
46
+ function defaultOpen(url, deps = {}) {
47
+ const plan = openCommand(url, deps.platform ?? process.platform);
48
+ if (!plan) return;
49
+ const child = (deps.spawn ?? spawn)(plan.command, plan.args, { detached: true, stdio: "ignore" });
50
+ child.unref();
51
+ child.on("error", () => {
52
+ });
53
+ }
54
+ var FileOAuthProvider = class {
55
+ opts;
56
+ constructor(opts) {
57
+ this.opts = opts;
58
+ }
59
+ /**
60
+ * Always defined: MCP SDK treats a missing redirectUrl as a non-interactive
61
+ * (client_credentials) flow and would try a token exchange without a code.
62
+ */
63
+ get redirectUrl() {
64
+ return this.opts.redirectUrl ?? "http://127.0.0.1:1/callback";
65
+ }
66
+ get clientMetadata() {
67
+ return {
68
+ client_name: "BCCLI",
69
+ redirect_uris: [String(this.redirectUrl)],
70
+ grant_types: ["authorization_code", "refresh_token"],
71
+ response_types: ["code"],
72
+ token_endpoint_auth_method: "none"
73
+ };
74
+ }
75
+ entry() {
76
+ return readStore(this.opts.home)[this.opts.serverUrl] ?? {};
77
+ }
78
+ patch(patch) {
79
+ const store = readStore(this.opts.home);
80
+ const next = { ...store[this.opts.serverUrl], ...patch };
81
+ for (const key of Object.keys(next)) {
82
+ if (next[key] === void 0) delete next[key];
83
+ }
84
+ store[this.opts.serverUrl] = next;
85
+ if (Object.keys(next).length === 0) delete store[this.opts.serverUrl];
86
+ writeStore(this.opts.home, store);
87
+ }
88
+ clientInformation() {
89
+ return this.entry().client;
90
+ }
91
+ saveClientInformation(clientInformation) {
92
+ this.patch({ client: clientInformation });
93
+ }
94
+ tokens() {
95
+ return this.entry().tokens;
96
+ }
97
+ saveTokens(tokens) {
98
+ this.patch({ tokens });
99
+ }
100
+ saveCodeVerifier(codeVerifier) {
101
+ this.patch({ codeVerifier });
102
+ }
103
+ codeVerifier() {
104
+ return this.entry().codeVerifier ?? "";
105
+ }
106
+ redirectToAuthorization(authorizationUrl) {
107
+ return (this.opts.open ?? defaultOpen)(authorizationUrl);
108
+ }
109
+ saveDiscoveryState(state) {
110
+ this.patch({ discovery: state });
111
+ }
112
+ discoveryState() {
113
+ return this.entry().discovery;
114
+ }
115
+ invalidateCredentials(scope) {
116
+ if (scope === "all") {
117
+ this.patch({ client: void 0, tokens: void 0, codeVerifier: void 0, discovery: void 0 });
118
+ return;
119
+ }
120
+ if (scope === "client") this.patch({ client: void 0 });
121
+ if (scope === "tokens") this.patch({ tokens: void 0 });
122
+ if (scope === "verifier") this.patch({ codeVerifier: void 0 });
123
+ if (scope === "discovery") this.patch({ discovery: void 0 });
124
+ }
125
+ };
126
+ function parseCallback(input) {
127
+ const url = typeof input === "string" ? new URL(input) : input;
128
+ const error = url.searchParams.get("error");
129
+ if (error) {
130
+ const description = url.searchParams.get("error_description");
131
+ throw new Error(description ? `OAuth ${error}: ${description}` : `OAuth ${error}`);
132
+ }
133
+ const code = url.searchParams.get("code");
134
+ if (!code) throw new Error("OAuth callback is missing the code parameter.");
135
+ const state = url.searchParams.get("state") ?? void 0;
136
+ return { code, state };
137
+ }
138
+ var CALLBACK_TIMEOUT_MS = 18e4;
139
+ async function authorizeMcpServer(spec, deps) {
140
+ let settle;
141
+ const codeReceived = new Promise((resolve, reject) => {
142
+ settle = { resolve, reject };
143
+ });
144
+ codeReceived.catch(() => {
145
+ });
146
+ const server = createServer((req, res) => {
147
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
148
+ if (url.pathname !== "/callback") {
149
+ res.writeHead(404);
150
+ res.end();
151
+ return;
152
+ }
153
+ try {
154
+ const { code } = parseCallback(url);
155
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
156
+ res.end("<html><body><p>BCCLI is connected. You can close this tab.</p></body></html>");
157
+ settle.resolve(code);
158
+ } catch (error) {
159
+ res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
160
+ res.end(`<html><body><p>${error.message}</p></body></html>`);
161
+ settle.reject(error);
162
+ }
163
+ });
164
+ const port = await new Promise((resolve, reject) => {
165
+ server.once("error", reject);
166
+ server.listen(0, "127.0.0.1", () => {
167
+ const address = server.address();
168
+ resolve(typeof address === "object" && address ? address.port : 0);
169
+ });
170
+ });
171
+ try {
172
+ const provider = new FileOAuthProvider({
173
+ home: deps.home,
174
+ serverUrl: spec.config.url,
175
+ redirectUrl: `http://127.0.0.1:${port}/callback`,
176
+ open: deps.open
177
+ });
178
+ const serverUrl = new URL(spec.config.url);
179
+ const result = await auth(provider, { serverUrl, fetchFn: deps.fetchFn });
180
+ if (result === "AUTHORIZED") return;
181
+ const timer = setTimeout(() => settle.reject(new Error("Timed out waiting for the OAuth callback.")), CALLBACK_TIMEOUT_MS);
182
+ let code;
183
+ try {
184
+ code = await codeReceived;
185
+ } finally {
186
+ clearTimeout(timer);
187
+ }
188
+ const second = await auth(provider, { serverUrl, authorizationCode: code, fetchFn: deps.fetchFn });
189
+ if (second !== "AUTHORIZED") throw new Error("OAuth authorization did not complete.");
190
+ } finally {
191
+ server.close();
192
+ }
193
+ }
194
+
195
+ export {
196
+ hasStoredTokens,
197
+ clearTokens,
198
+ defaultOpen,
199
+ FileOAuthProvider,
200
+ authorizeMcpServer
201
+ };
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/permissions.ts
4
+ import { isAbsolute, relative, resolve, sep } 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 /(?:^|[/\\])(?:\.env(?:\..*)?|\.ssh|\.aws|\.config\/gcloud|secrets?|credentials?)(?:[/\\]|$)/i.test(target) || /(?:id_rsa|id_ed25519|\.pem|\.p12|\.key)$/i.test(target);
66
+ }
67
+ if (req.kind === "bash") {
68
+ 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);
69
+ }
70
+ if (req.kind === "mcp") {
71
+ return /(?:delete|remove|revoke|transfer|send_email|publish|deploy|execute_command|run_command|read_secret)/i.test(req.tool);
72
+ }
73
+ return false;
74
+ }
75
+ var Permissions = class {
76
+ constructor(mode, rules = [], cwd = process.cwd()) {
77
+ this.mode = mode;
78
+ this.cwd = cwd;
79
+ this.rules = new Set(rules);
80
+ this.configRules = new Set(rules);
81
+ }
82
+ mode;
83
+ cwd;
84
+ rules;
85
+ configRules;
86
+ /** Edits may only be auto-allowed inside the project and outside .git. */
87
+ editInProject(target) {
88
+ const rel = relative(this.cwd, resolve(this.cwd, target));
89
+ if (!rel || rel.startsWith("..") || isAbsolute(rel)) return false;
90
+ return !rel.split(sep).includes(".git") && !rel.split("/").includes(".git");
91
+ }
92
+ /** Rules that "[a] allow for this session" would add; undefined when it must always be asked. */
93
+ rulesFor(req) {
94
+ if (requiresSensitiveToolApproval(req) && (req.kind === "read" || process.env.BC_TOOL_POLICY_ENFORCE === "true"))
95
+ return void 0;
96
+ if (req.kind === "edit") return this.editInProject(req.target) ? ["edit(project)"] : void 0;
97
+ if (req.kind === "fetch") {
98
+ try {
99
+ return [`fetch(${new URL(req.target).hostname})`];
100
+ } catch {
101
+ return void 0;
102
+ }
103
+ }
104
+ if (req.kind === "bash") {
105
+ if (/`|\$\(|[<>]|^\s*[({]/.test(req.target)) return void 0;
106
+ const segments = req.target.split(/&&|\|\||[;&|\n]/).map((s) => s.trim()).filter(Boolean);
107
+ if (!segments.length) return void 0;
108
+ if (segments.some(isAlwaysAsk)) return void 0;
109
+ return [...new Set(segments.map((s) => `bash(${commandKey(s)})`))];
110
+ }
111
+ if (req.kind === "mcp") return [`mcp(${req.tool})`];
112
+ return [];
113
+ }
114
+ check(req) {
115
+ if (this.mode === "plan" && req.kind !== "read") return "deny";
116
+ if (req.kind === "read" && this.mode !== "allowAll" && requiresSensitiveToolApproval(req)) return "ask";
117
+ if (process.env.BC_TOOL_POLICY_ENFORCE === "true" && requiresSensitiveToolApproval(req)) return "ask";
118
+ if (req.kind === "read") return "allow";
119
+ if (this.mode === "allowAll") return "allow";
120
+ if (this.mode === "plan") return "deny";
121
+ if (this.rules.has(req.kind)) return "allow";
122
+ const needed = this.rulesFor(req);
123
+ if (!needed) return "ask";
124
+ if (req.kind === "edit" && this.mode === "acceptEdits") return "allow";
125
+ return needed.every((rule) => this.rules.has(rule)) ? "allow" : "ask";
126
+ }
127
+ list() {
128
+ return [...this.rules].map((rule) => ({ rule, source: this.configRules.has(rule) ? "config" : "session" }));
129
+ }
130
+ /** Removes a session grant; rules from config/flags stay until the user edits them. */
131
+ revoke(rule) {
132
+ if (!this.configRules.has(rule)) this.rules.delete(rule);
133
+ }
134
+ allowForSession(req) {
135
+ for (const rule of this.rulesFor(req) ?? []) this.rules.add(rule);
136
+ }
137
+ };
138
+
139
+ export {
140
+ MODE_ORDER,
141
+ nextMode,
142
+ Permissions
143
+ };
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/tools/types.ts
4
+ function defineTool(tool) {
5
+ return tool;
6
+ }
7
+
8
+ export {
9
+ defineTool
10
+ };