@brainmcp/brainmcp 0.1.1 → 0.1.3
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.md +69 -35
- package/dist/agent-config.js +75 -12
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +118 -26
- package/dist/commands/index.js.map +1 -1
- package/dist/index.js +19 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.js +29 -13
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/files.js +75 -10
- package/dist/lib/files.js.map +1 -1
- package/dist/lib/managed.js +356 -15
- package/dist/lib/managed.js.map +1 -1
- package/dist/types/agent-config-stub.d.ts +18 -0
- package/dist/types/agent-config-stub.js +18 -0
- package/dist/types/agent-config-stub.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { argv, cwd, stdin, stdout } from 'node:process';
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
|
-
import {
|
|
4
|
+
import { BRAINMCP_CLI_PACKAGE_SPEC } from './agent-config.js';
|
|
5
|
+
import { doctor, init, initAll, printConfig, remove } from './commands/index.js';
|
|
5
6
|
import { assertClientId } from './lib/config.js';
|
|
6
|
-
const HELP = `brainmcp — configure BrainMCP for
|
|
7
|
+
const HELP = `brainmcp — configure BrainMCP for agent projects
|
|
8
|
+
|
|
9
|
+
Recommended setup (supported agents, all projects):
|
|
10
|
+
npx --yes ${BRAINMCP_CLI_PACKAGE_SPEC} init --all --scope user
|
|
7
11
|
|
|
8
12
|
Usage:
|
|
9
13
|
brainmcp init [--client <client>] [--workspace <id>] [--scope project|user] [--yes]
|
|
14
|
+
brainmcp init --all [--workspace <id>] [--scope project|user] [--yes]
|
|
10
15
|
brainmcp doctor [--client <client>] [--workspace <id>] [--scope project|user]
|
|
11
16
|
brainmcp print [--client <client>] [--workspace <id>] [--scope project|user]
|
|
12
17
|
brainmcp remove [--client <client>] [--scope project|user] [--yes]
|
|
13
18
|
|
|
14
19
|
Clients: claude-code, cursor, codex, vscode, generic
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
--all configures Claude Code, Cursor, Codex, and VS Code (generic is client-specific).
|
|
21
|
+
Project scope is the default. User scope writes to each host's supported per-user locations.
|
|
22
|
+
Every mutation previews a diff and needs confirmation unless a trailing CLI --yes is supplied.
|
|
23
|
+
The leading npx --yes above accepts npm's package download; it does not skip the file preview.`;
|
|
17
24
|
async function main() {
|
|
18
25
|
const [command, ...rawOptions] = argv.slice(2);
|
|
19
26
|
if (!command || command === '--help' || command === '-h' || command === 'help') {
|
|
@@ -21,6 +28,10 @@ async function main() {
|
|
|
21
28
|
return;
|
|
22
29
|
}
|
|
23
30
|
const values = parseOptions(rawOptions);
|
|
31
|
+
if (values.all && values.client)
|
|
32
|
+
throw new Error('Use either --all or --client, not both.');
|
|
33
|
+
if (values.all && command !== 'init')
|
|
34
|
+
throw new Error('--all is currently supported only by init.');
|
|
24
35
|
const options = {
|
|
25
36
|
root: values.root ?? cwd(),
|
|
26
37
|
client: values.client,
|
|
@@ -32,7 +43,7 @@ async function main() {
|
|
|
32
43
|
};
|
|
33
44
|
switch (command) {
|
|
34
45
|
case 'init':
|
|
35
|
-
await init(options);
|
|
46
|
+
await (values.all ? initAll(options) : init(options));
|
|
36
47
|
return;
|
|
37
48
|
case 'doctor':
|
|
38
49
|
await doctor(options);
|
|
@@ -48,11 +59,13 @@ async function main() {
|
|
|
48
59
|
}
|
|
49
60
|
}
|
|
50
61
|
function parseOptions(args) {
|
|
51
|
-
const result = { yes: false };
|
|
62
|
+
const result = { yes: false, all: false };
|
|
52
63
|
for (let index = 0; index < args.length; index += 1) {
|
|
53
64
|
const option = args[index];
|
|
54
65
|
if (option === '--yes' || option === '-y')
|
|
55
66
|
result.yes = true;
|
|
67
|
+
else if (option === '--all')
|
|
68
|
+
result.all = true;
|
|
56
69
|
else if (option === '--client')
|
|
57
70
|
result.client = assertClientId(readValue(args, ++index, option));
|
|
58
71
|
else if (option === '--workspace')
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAY,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAuB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare const TOML_MARKER_END = "# brainmcp:managed:end";
|
|
|
19
19
|
export declare function targetFor(client: ClientId, scope: Scope): ClientTarget;
|
|
20
20
|
export declare function clientLabel(client: ClientId): string;
|
|
21
21
|
export declare function resolveWorkspace(value: string | undefined): string | undefined;
|
|
22
|
+
export declare function guidancePreamble(client: ClientId, scope: Scope): string | undefined;
|
|
22
23
|
export declare function renderGuidance(client: ClientId, workspaceId?: string): string;
|
|
23
24
|
export declare function brainServerConfig(client: ClientId): Record<string, unknown>;
|
|
24
25
|
export declare function renderTomlServer(client: ClientId): string;
|
package/dist/lib/config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BRAIN_MCP_ENDPOINT, MCP_CLIENT_PROFILES, buildCodexConfigToml, buildProjectInstructionBlock, renderCursorMdc, } from '../agent-config.js';
|
|
1
|
+
import { BRAIN_MCP_ENDPOINT, MCP_CLIENT_PROFILES, VSCODE_USER_INSTRUCTIONS_FRONTMATTER, buildCodexConfigToml, buildProjectInstructionBlock, renderCursorMdc, } from '../agent-config.js';
|
|
2
2
|
export const BRAIN_ENDPOINT = BRAIN_MCP_ENDPOINT;
|
|
3
3
|
export const CLIENT_IDS = ['claude-code', 'cursor', 'codex', 'vscode', 'generic'];
|
|
4
4
|
export function assertClientId(value) {
|
|
@@ -12,45 +12,48 @@ export const TOML_MARKER_START = '# brainmcp:managed:start version=2026.07.10';
|
|
|
12
12
|
export const TOML_MARKER_END = '# brainmcp:managed:end';
|
|
13
13
|
export function targetFor(client, scope) {
|
|
14
14
|
const home = scope === 'user';
|
|
15
|
-
const prefix = home ? '~/' : '';
|
|
16
15
|
switch (client) {
|
|
17
16
|
case 'cursor':
|
|
18
17
|
return {
|
|
19
18
|
client,
|
|
20
|
-
configPath:
|
|
21
|
-
guidancePath:
|
|
19
|
+
configPath: '.cursor/mcp.json',
|
|
20
|
+
guidancePath: '.cursor/rules/brainmcp-workspace.mdc',
|
|
22
21
|
configFormat: 'jsonc',
|
|
23
22
|
configRootKey: 'mcpServers',
|
|
24
23
|
};
|
|
25
24
|
case 'claude-code':
|
|
26
25
|
return {
|
|
27
26
|
client,
|
|
28
|
-
configPath:
|
|
29
|
-
guidancePath:
|
|
27
|
+
configPath: home ? '.claude.json' : '.mcp.json',
|
|
28
|
+
guidancePath: home ? '.claude/CLAUDE.md' : 'CLAUDE.md',
|
|
30
29
|
configFormat: 'jsonc',
|
|
31
30
|
configRootKey: 'mcpServers',
|
|
32
31
|
};
|
|
33
32
|
case 'codex':
|
|
34
33
|
return {
|
|
35
34
|
client,
|
|
36
|
-
configPath:
|
|
37
|
-
guidancePath:
|
|
35
|
+
configPath: '.codex/config.toml',
|
|
36
|
+
guidancePath: home ? '.codex/AGENTS.md' : 'AGENTS.md',
|
|
38
37
|
configFormat: 'toml',
|
|
39
38
|
configRootKey: 'mcpServers',
|
|
40
39
|
};
|
|
41
40
|
case 'vscode':
|
|
42
41
|
return {
|
|
43
42
|
client,
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
// User-scope resolution maps this logical path to the platform's
|
|
44
|
+
// default VS Code user-profile directory.
|
|
45
|
+
configPath: '.vscode/mcp.json',
|
|
46
|
+
guidancePath: home
|
|
47
|
+
? '.copilot/instructions/brainmcp.instructions.md'
|
|
48
|
+
: 'AGENTS.md',
|
|
46
49
|
configFormat: 'jsonc',
|
|
47
50
|
configRootKey: 'servers',
|
|
48
51
|
};
|
|
49
52
|
case 'generic':
|
|
50
53
|
return {
|
|
51
54
|
client,
|
|
52
|
-
configPath:
|
|
53
|
-
guidancePath:
|
|
55
|
+
configPath: '.mcp.json',
|
|
56
|
+
guidancePath: 'AGENTS.md',
|
|
54
57
|
configFormat: 'jsonc',
|
|
55
58
|
configRootKey: 'mcpServers',
|
|
56
59
|
};
|
|
@@ -68,13 +71,26 @@ export function resolveWorkspace(value) {
|
|
|
68
71
|
}
|
|
69
72
|
return workspace;
|
|
70
73
|
}
|
|
74
|
+
export function guidancePreamble(client, scope) {
|
|
75
|
+
if (client === 'cursor') {
|
|
76
|
+
const rendered = renderCursorMdc();
|
|
77
|
+
const frontmatter = rendered.match(/^---\n[\s\S]*?\n---\n*/)?.[0];
|
|
78
|
+
if (!frontmatter)
|
|
79
|
+
throw new Error('Cursor guidance renderer did not return frontmatter.');
|
|
80
|
+
return frontmatter.trimEnd();
|
|
81
|
+
}
|
|
82
|
+
if (client === 'vscode' && scope === 'user') {
|
|
83
|
+
return VSCODE_USER_INSTRUCTIONS_FRONTMATTER;
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
71
87
|
export function renderGuidance(client, workspaceId) {
|
|
72
88
|
if (client === 'cursor') {
|
|
73
89
|
const rendered = renderCursorMdc({ workspaceId });
|
|
74
90
|
const frontmatter = rendered.match(/^---\n[\s\S]*?\n---\n*/)?.[0];
|
|
75
91
|
if (!frontmatter)
|
|
76
92
|
throw new Error('Cursor guidance renderer did not return frontmatter.');
|
|
77
|
-
return `${
|
|
93
|
+
return `${MARKER_START}\n${rendered.slice(frontmatter.length).trim()}\n${MARKER_END}\n`;
|
|
78
94
|
}
|
|
79
95
|
return `${MARKER_START}\n${buildProjectInstructionBlock({ workspaceId })}\n${MARKER_END}\n`;
|
|
80
96
|
}
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,4BAA4B,EAC5B,eAAe,GAEhB,MAAM,uBAAuB,CAAC;AAK/B,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAEjD,MAAM,CAAC,MAAM,UAAU,GAAwB,CAAC,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEvG,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAK,UAAgC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAiB,CAAC;IAChF,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,uBAAuB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7F,CAAC;AAWD,MAAM,CAAC,MAAM,YAAY,GAAG,oDAAoD,CAAC;AACjF,MAAM,CAAC,MAAM,UAAU,GAAG,+BAA+B,CAAC;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,6CAA6C,CAAC;AAC/E,MAAM,CAAC,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAExD,MAAM,UAAU,SAAS,CAAC,MAAgB,EAAE,KAAY;IACtD,MAAM,IAAI,GAAG,KAAK,KAAK,MAAM,CAAC;IAC9B,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/files.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
-
import { access, copyFile, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { access, chmod, copyFile, lstat, mkdir, readFile, realpath, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, resolve } from 'node:path';
|
|
4
4
|
export async function readText(path) {
|
|
5
5
|
try {
|
|
@@ -27,17 +27,71 @@ export function renderDiff(change) {
|
|
|
27
27
|
const before = change.before?.split('\n') ?? [];
|
|
28
28
|
const after = change.after?.split('\n') ?? [];
|
|
29
29
|
const header = `--- ${change.before === undefined ? '/dev/null' : change.path}\n+++ ${change.after === undefined ? '/dev/null' : change.path}`;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
let start = 0;
|
|
31
|
+
while (start < before.length && start < after.length && before[start] === after[start])
|
|
32
|
+
start += 1;
|
|
33
|
+
let beforeEnd = before.length;
|
|
34
|
+
let afterEnd = after.length;
|
|
35
|
+
while (beforeEnd > start &&
|
|
36
|
+
afterEnd > start &&
|
|
37
|
+
before[beforeEnd - 1] === after[afterEnd - 1]) {
|
|
38
|
+
beforeEnd -= 1;
|
|
39
|
+
afterEnd -= 1;
|
|
40
|
+
}
|
|
41
|
+
const contextStart = Math.max(0, start - 2);
|
|
42
|
+
const contextBeforeEnd = Math.min(before.length, beforeEnd + 2);
|
|
43
|
+
const contextAfterEnd = Math.min(after.length, afterEnd + 2);
|
|
44
|
+
const hunk = `@@ -${contextStart + 1},${contextBeforeEnd - contextStart} +${contextStart + 1},${contextAfterEnd - contextStart} @@`;
|
|
45
|
+
return [
|
|
46
|
+
header,
|
|
47
|
+
hunk,
|
|
48
|
+
...before.slice(contextStart, start).map((line) => ` ${line}`),
|
|
49
|
+
...before.slice(start, beforeEnd).map((line) => `-${line}`),
|
|
50
|
+
...after.slice(start, afterEnd).map((line) => `+${line}`),
|
|
51
|
+
...after.slice(afterEnd, contextAfterEnd).map((line) => ` ${line}`),
|
|
52
|
+
].join('\n');
|
|
33
53
|
}
|
|
34
54
|
export async function applyChanges(changes) {
|
|
35
|
-
const
|
|
55
|
+
const prepared = [];
|
|
56
|
+
// Validate the whole preview before touching any file. This prevents a long
|
|
57
|
+
// confirmation prompt (or another client) from turning a reviewed diff into
|
|
58
|
+
// an overwrite of newer configuration.
|
|
36
59
|
for (const change of changes) {
|
|
37
60
|
if (change.before === change.after)
|
|
38
61
|
continue;
|
|
39
|
-
await
|
|
40
|
-
if (
|
|
62
|
+
const current = await readText(change.path);
|
|
63
|
+
if (current !== change.before)
|
|
64
|
+
throw changedSincePreview(change.path);
|
|
65
|
+
let writePath = change.path;
|
|
66
|
+
let existingMode;
|
|
67
|
+
let symbolicLink = false;
|
|
68
|
+
if (current !== undefined) {
|
|
69
|
+
const metadata = await lstat(change.path);
|
|
70
|
+
symbolicLink = metadata.isSymbolicLink();
|
|
71
|
+
if (symbolicLink) {
|
|
72
|
+
if (change.after === undefined) {
|
|
73
|
+
throw new Error(`Refusing to remove symlinked configuration ${change.path}; remove its managed block or target manually.`);
|
|
74
|
+
}
|
|
75
|
+
writePath = await realpath(change.path);
|
|
76
|
+
}
|
|
77
|
+
existingMode = (await stat(writePath)).mode & 0o777;
|
|
78
|
+
}
|
|
79
|
+
prepared.push({ change, writePath, existingMode, symbolicLink });
|
|
80
|
+
}
|
|
81
|
+
const backups = [];
|
|
82
|
+
for (const item of prepared) {
|
|
83
|
+
const { change, writePath, existingMode, symbolicLink } = item;
|
|
84
|
+
if ((await readText(change.path)) !== change.before)
|
|
85
|
+
throw changedSincePreview(change.path);
|
|
86
|
+
if (change.before !== undefined) {
|
|
87
|
+
const currentMetadata = await lstat(change.path);
|
|
88
|
+
if (currentMetadata.isSymbolicLink() !== symbolicLink)
|
|
89
|
+
throw changedSincePreview(change.path);
|
|
90
|
+
if (symbolicLink && (await realpath(change.path)) !== writePath)
|
|
91
|
+
throw changedSincePreview(change.path);
|
|
92
|
+
}
|
|
93
|
+
await mkdir(dirname(writePath), { recursive: true });
|
|
94
|
+
if (change.before !== undefined) {
|
|
41
95
|
const backup = `${change.path}.brainmcp.bak-${Date.now()}-${createHash('sha1').update(change.path).digest('hex').slice(0, 6)}`;
|
|
42
96
|
await copyFile(change.path, backup);
|
|
43
97
|
backups.push(backup);
|
|
@@ -46,12 +100,23 @@ export async function applyChanges(changes) {
|
|
|
46
100
|
await rm(change.path, { force: true });
|
|
47
101
|
continue;
|
|
48
102
|
}
|
|
49
|
-
const temporary = `${
|
|
50
|
-
|
|
51
|
-
|
|
103
|
+
const temporary = `${writePath}.brainmcp-tmp-${randomUUID()}`;
|
|
104
|
+
try {
|
|
105
|
+
await writeFile(temporary, change.after, 'utf8');
|
|
106
|
+
if (existingMode !== undefined)
|
|
107
|
+
await chmod(temporary, existingMode);
|
|
108
|
+
await rename(temporary, writePath);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
await rm(temporary, { force: true });
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
52
114
|
}
|
|
53
115
|
return backups;
|
|
54
116
|
}
|
|
117
|
+
function changedSincePreview(path) {
|
|
118
|
+
return new Error(`Refusing to overwrite ${path}: it changed after the preview. Re-run the command and review the new diff.`);
|
|
119
|
+
}
|
|
55
120
|
function isNotFound(error) {
|
|
56
121
|
return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';
|
|
57
122
|
}
|
package/dist/lib/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/lib/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/lib/files.ts"],"names":[],"mappings":"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"}
|