@brunobracaioli/aibrain 0.4.0-beta.7 → 0.4.0-beta.8
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/dist/claude-observation.mjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/extensions-catalog.mjs +13 -2
- package/dist/extensions-cli.mjs +15 -0
- package/dist/launch.mjs +16 -1
- package/dist/mcp-servers.mjs +29 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -16,7 +16,7 @@ export const MAX_LOG_FILES = 3;
|
|
|
16
16
|
const LOCK_WAIT_MS = 250;
|
|
17
17
|
const LOCK_STALE_MS = 30_000;
|
|
18
18
|
const ADMISSION_MS = 60 * 60 * 1000;
|
|
19
|
-
export const ADAPTER_VERSION = '0.4.0-beta.
|
|
19
|
+
export const ADAPTER_VERSION = '0.4.0-beta.8';
|
|
20
20
|
const MAX_DIAGNOSTIC_COUNT = 10_000_000;
|
|
21
21
|
const MAX_DIAGNOSTIC_BYTES = 128 * 1024 * 1024;
|
|
22
22
|
const CHECKPOINT_BACKENDS = new Set(['native_store', 'private_file']);
|
package/dist/cli.mjs
CHANGED
|
@@ -40,7 +40,7 @@ import { extensionsSummary, hooksCommand, mcpCommand } from './extensions-cli.mj
|
|
|
40
40
|
import { sessionServers } from './mcp-servers.mjs';
|
|
41
41
|
import { anyFormatter } from './guardrails/format.mjs';
|
|
42
42
|
|
|
43
|
-
const VERSION = '0.4.0-beta.
|
|
43
|
+
const VERSION = '0.4.0-beta.8';
|
|
44
44
|
// The command is `aisac`; `aibrain` is an alias installed from the same entry.
|
|
45
45
|
const COMMAND = 'aisac';
|
|
46
46
|
const ENDPOINT = 'https://mcp.ai-brain.aisac.cloud/mcp';
|
|
@@ -167,6 +167,10 @@ export function hookIds() {
|
|
|
167
167
|
* @property {Readonly<Record<CatalogLocale, string>>} [loginNote] Why and how this login differs.
|
|
168
168
|
* @property {Readonly<Record<CatalogLocale, string>>} description
|
|
169
169
|
* @property {Readonly<Record<CatalogLocale, string>>} reaches What the server can reach (FR7).
|
|
170
|
+
* @property {readonly string[]} [blockedTools] Tools that spend money, removed in both
|
|
171
|
+
* clients whatever the user's permission mode is (FR7.2). Exact names.
|
|
172
|
+
* @property {readonly string[]} [blockedToolPrefixes] Name prefixes removed in Claude Code
|
|
173
|
+
* only, through a glob deny rule; Codex documents exact names only (FR7.2).
|
|
170
174
|
*/
|
|
171
175
|
|
|
172
176
|
/** Session name of a catalog server, so it never collides with the user's own. */
|
|
@@ -215,6 +219,9 @@ export const MCP_CATALOG = Object.freeze([
|
|
|
215
219
|
source: 'https://github.com/supabase-community/supabase-mcp',
|
|
216
220
|
transport: { type: 'http', url: 'https://mcp.supabase.com/mcp?read_only=true' },
|
|
217
221
|
login: 'host-oauth',
|
|
222
|
+
// read_only=true should already leave these out; the vendor does not publish
|
|
223
|
+
// what it removes, so they are blocked as a second layer (FR7.2).
|
|
224
|
+
blockedTools: ['create_project', 'confirm_cost', 'create_branch'],
|
|
218
225
|
description: {
|
|
219
226
|
en: "Supabase's hosted server, read-only: tables, SQL, logs, advisors and docs.",
|
|
220
227
|
'pt-BR':
|
|
@@ -234,15 +241,19 @@ export const MCP_CATALOG = Object.freeze([
|
|
|
234
241
|
source: 'https://vercel.com/docs/agent-resources/vercel-mcp',
|
|
235
242
|
transport: { type: 'http', url: 'https://mcp.vercel.com' },
|
|
236
243
|
login: 'host-oauth',
|
|
244
|
+
// buy_domain charges the team after a quote, and its confirm flag is a model
|
|
245
|
+
// argument; a domain transfer may be charged (FR7.1, FR7.2).
|
|
246
|
+
blockedTools: ['buy_domain', 'create_or_transfer_domain'],
|
|
247
|
+
blockedToolPrefixes: ['buy_'],
|
|
237
248
|
description: {
|
|
238
249
|
en: "Vercel's hosted server: projects, deployments, logs, domains and environment variables.",
|
|
239
250
|
'pt-BR':
|
|
240
251
|
'Servidor hospedado da Vercel: projetos, deploys, logs, domínios e variáveis de ambiente.',
|
|
241
252
|
},
|
|
242
253
|
reaches: {
|
|
243
|
-
en: 'The teams you grant at login, with the access of your Vercel user: projects, deployments, build and runtime logs, domains and DNS, and environment variables, including decrypted values. It also has write tools (
|
|
254
|
+
en: 'The teams you grant at login, with the access of your Vercel user: projects, deployments, build and runtime logs, domains and DNS, and environment variables, including decrypted values. It also has write tools (deployments, environment variables, DNS records, firewall rules, project settings) and no read-only mode, so keep the confirmation of each call on. Buying domains is blocked by AISAC.',
|
|
244
255
|
'pt-BR':
|
|
245
|
-
'Os times que você liberar no login, com o acesso do seu usuário Vercel: projetos, deploys, logs de build e de execução, domínios e DNS, e variáveis de ambiente, inclusive valores decifrados. Também tem ferramentas de escrita (
|
|
256
|
+
'Os times que você liberar no login, com o acesso do seu usuário Vercel: projetos, deploys, logs de build e de execução, domínios e DNS, e variáveis de ambiente, inclusive valores decifrados. Também tem ferramentas de escrita (deploys, variáveis de ambiente, registros DNS, regras de firewall, configurações de projeto) e não tem modo somente leitura, então mantenha a confirmação de cada chamada ligada. A compra de domínios é bloqueada pela AISAC.',
|
|
246
257
|
},
|
|
247
258
|
},
|
|
248
259
|
{
|
package/dist/extensions-cli.mjs
CHANGED
|
@@ -273,6 +273,11 @@ export function serverInfo(entry, locale, item) {
|
|
|
273
273
|
note: 'Hosted by the vendor: its tools can change without a client release, so keep the confirmation of each call on.',
|
|
274
274
|
},
|
|
275
275
|
reaches: entry.reaches[locale],
|
|
276
|
+
// Tools that spend money, removed whatever the permission mode is (FR7.2).
|
|
277
|
+
blockedTools: [...(entry.blockedTools ?? [])],
|
|
278
|
+
...(entry.blockedToolPrefixes === undefined
|
|
279
|
+
? {}
|
|
280
|
+
: { blockedToolPrefixes: [...entry.blockedToolPrefixes] }),
|
|
276
281
|
login,
|
|
277
282
|
...(variable === undefined ? {} : { tokenVariable: variable }),
|
|
278
283
|
...(entry.loginNote === undefined ? {} : { loginNote: entry.loginNote[locale] }),
|
|
@@ -293,6 +298,16 @@ function printInfo(info) {
|
|
|
293
298
|
const where = info.transport.type === 'local' ? info.transport.command : info.transport.url;
|
|
294
299
|
console.log(`Transport: ${info.transport.type}, ${where}. ${info.transport.note}`);
|
|
295
300
|
console.log(`Reaches: ${info.reaches}`);
|
|
301
|
+
if (info.blockedTools.length > 0) {
|
|
302
|
+
const prefixes = info.blockedToolPrefixes ?? [];
|
|
303
|
+
const claudeOnly =
|
|
304
|
+
prefixes.length === 0
|
|
305
|
+
? ''
|
|
306
|
+
: ` In Claude Code, also any tool whose name starts with ${prefixes.join(', ')}.`;
|
|
307
|
+
console.log(
|
|
308
|
+
`Blocked by AISAC, because they spend money: ${info.blockedTools.join(', ')}.${claudeOnly} They stay blocked even if you allow every tool or skip permission prompts.`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
296
311
|
if (info.loginNote !== undefined) console.log(`Login: ${info.loginNote}`);
|
|
297
312
|
console.log(`Log in from Claude Code: ${info.login.claude}`);
|
|
298
313
|
console.log(`Log in from Codex: ${info.login.codex}`);
|
package/dist/launch.mjs
CHANGED
|
@@ -19,7 +19,13 @@ import {
|
|
|
19
19
|
writeLaunchMarker,
|
|
20
20
|
} from './engineering-pack.mjs';
|
|
21
21
|
import { prepareGuardrails } from './guardrails-plugin.mjs';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
CODEX_MCP_ENV,
|
|
24
|
+
claudeDenyRules,
|
|
25
|
+
claudeMcpEntries,
|
|
26
|
+
mcpLaunchLines,
|
|
27
|
+
sessionServers,
|
|
28
|
+
} from './mcp-servers.mjs';
|
|
23
29
|
import { enabledServerIds, readPreferences } from './extensions-preferences.mjs';
|
|
24
30
|
import {
|
|
25
31
|
CODEX_ENGINEERING_ENV,
|
|
@@ -561,6 +567,14 @@ export async function launchClaude(config, root, args, dependencies = {}) {
|
|
|
561
567
|
for (const rule of [...userAllow, ...requiredAllow]) {
|
|
562
568
|
if (!mergedAllow.includes(rule)) mergedAllow.push(rule);
|
|
563
569
|
}
|
|
570
|
+
// Catalog tools that spend money stay denied whatever the user allows or the
|
|
571
|
+
// permission mode is (spec aisac-engineering-extensions FR7.2).
|
|
572
|
+
const userDeny = Array.isArray(userPermissions.deny) ? userPermissions.deny : [];
|
|
573
|
+
/** @type {unknown[]} */
|
|
574
|
+
const mergedDeny = [];
|
|
575
|
+
for (const rule of [...userDeny, ...claudeDenyRules()]) {
|
|
576
|
+
if (!mergedDeny.includes(rule)) mergedDeny.push(rule);
|
|
577
|
+
}
|
|
564
578
|
const settings = {
|
|
565
579
|
...(launchArgs.settings?.sandbox === undefined ? {} : { sandbox: launchArgs.settings.sandbox }),
|
|
566
580
|
pluginConfigs: {
|
|
@@ -570,6 +584,7 @@ export async function launchClaude(config, root, args, dependencies = {}) {
|
|
|
570
584
|
permissions: {
|
|
571
585
|
...userPermissions,
|
|
572
586
|
allow: mergedAllow,
|
|
587
|
+
deny: mergedDeny,
|
|
573
588
|
},
|
|
574
589
|
};
|
|
575
590
|
try {
|
package/dist/mcp-servers.mjs
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* third-party credential: logins live in the host's own store, and a token
|
|
9
9
|
* variable is only named, never read here.
|
|
10
10
|
*/
|
|
11
|
-
import { MCP_SERVER_PREFIX, mcpById } from './extensions-catalog.mjs';
|
|
11
|
+
import { MCP_CATALOG, MCP_SERVER_PREFIX, mcpById } from './extensions-catalog.mjs';
|
|
12
12
|
import { tomlBasicString } from './codex-engineering.mjs';
|
|
13
13
|
|
|
14
14
|
/** @typedef {import('./extensions-catalog.mjs').McpEntry} McpEntry */
|
|
@@ -80,7 +80,27 @@ export function claudeMcpEntries(entries) {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
|
-
*
|
|
83
|
+
* Claude Code deny rules for the tools that spend money (FR7.2). They cover every
|
|
84
|
+
* catalog server, loaded or not, so the settings file can be written before the
|
|
85
|
+
* license is confirmed; a rule for a server that is not loaded matches nothing.
|
|
86
|
+
* Claude evaluates deny rules before allow rules, in every permission mode, and a
|
|
87
|
+
* deny rule removes the tool from the model's context (measured M1, Claude 2.1.318).
|
|
88
|
+
* @param {readonly McpEntry[]} [entries]
|
|
89
|
+
* @returns {string[]}
|
|
90
|
+
*/
|
|
91
|
+
export function claudeDenyRules(entries = MCP_CATALOG) {
|
|
92
|
+
return entries.flatMap((entry) => {
|
|
93
|
+
const prefix = `mcp__${serverName(entry.id)}__`;
|
|
94
|
+
return [
|
|
95
|
+
...(entry.blockedTools ?? []).map((tool) => `${prefix}${tool}`),
|
|
96
|
+
...(entry.blockedToolPrefixes ?? []).map((start) => `${prefix}${start}*`),
|
|
97
|
+
];
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Session-only `-c` overrides for the owned Codex app-server. A server with
|
|
103
|
+
* blocked tools gets `disabled_tools` (FR7.2; measured M2, Codex 0.164.0).
|
|
84
104
|
* @param {readonly McpEntry[]} entries
|
|
85
105
|
* @returns {string[]}
|
|
86
106
|
*/
|
|
@@ -88,6 +108,11 @@ export function codexMcpConfigArgs(entries) {
|
|
|
88
108
|
return entries.flatMap((entry) => {
|
|
89
109
|
const key = `mcp_servers.${serverName(entry.id)}`;
|
|
90
110
|
const { transport } = entry;
|
|
111
|
+
const blocked = entry.blockedTools ?? [];
|
|
112
|
+
const disabled =
|
|
113
|
+
blocked.length === 0
|
|
114
|
+
? []
|
|
115
|
+
: ['-c', `${key}.disabled_tools=[${blocked.map(tomlBasicString).join(',')}]`];
|
|
91
116
|
if (transport.type === 'stdio')
|
|
92
117
|
return [
|
|
93
118
|
'-c',
|
|
@@ -96,6 +121,7 @@ export function codexMcpConfigArgs(entries) {
|
|
|
96
121
|
`${key}.args=[${transport.args.map(tomlBasicString).join(',')}]`,
|
|
97
122
|
'-c',
|
|
98
123
|
`${key}.startup_timeout_sec=${STDIO_STARTUP_TIMEOUT_SEC}`,
|
|
124
|
+
...disabled,
|
|
99
125
|
];
|
|
100
126
|
return [
|
|
101
127
|
'-c',
|
|
@@ -103,6 +129,7 @@ export function codexMcpConfigArgs(entries) {
|
|
|
103
129
|
...(transport.bearerEnv === undefined
|
|
104
130
|
? []
|
|
105
131
|
: ['-c', `${key}.bearer_token_env_var=${tomlBasicString(transport.bearerEnv)}`]),
|
|
132
|
+
...disabled,
|
|
106
133
|
];
|
|
107
134
|
});
|
|
108
135
|
}
|
package/dist/package.json
CHANGED
package/package.json
CHANGED