@brain-mcps/setup 0.1.0 → 0.2.0
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 +17 -14
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -5
- package/package.json +2 -2
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.js +0 -302
package/README.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Configure AI assistant clients to connect to [Brain4AI](https://brain4ai.app) (Cerebro Externo) and [Mentor4AI](https://mentor4ai.app) (Forge Mentor) MCP servers.
|
|
4
4
|
|
|
5
|
-
One command writes the correct config entry for any supported client, handling format differences (
|
|
5
|
+
One command writes the correct config entry for any supported client, handling format differences (Antigravity's / Windsurf's `serverUrl`, Copilot's nested `mcp.servers` path, etc.).
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @brain-mcps/setup
|
|
11
|
-
npx @brain-mcps/setup
|
|
10
|
+
npx @brain-mcps/setup antigravity # Configure Antigravity (CLI + Desktop) for Cerebro Externo
|
|
11
|
+
npx @brain-mcps/setup antigravity mentor # Configure Antigravity (CLI + Desktop) for Forge Mentor
|
|
12
12
|
npx @brain-mcps/setup --detect # Auto-detect and configure all installed clients
|
|
13
13
|
```
|
|
14
14
|
|
|
@@ -16,15 +16,18 @@ After running, open the configured client. It will prompt you to authenticate vi
|
|
|
16
16
|
|
|
17
17
|
## Supported Clients
|
|
18
18
|
|
|
19
|
-
| Client
|
|
20
|
-
|
|
|
21
|
-
| Claude Code
|
|
22
|
-
| Claude Desktop
|
|
23
|
-
|
|
|
24
|
-
| Codex
|
|
25
|
-
| Cursor
|
|
26
|
-
| Windsurf
|
|
27
|
-
| GitHub Copilot
|
|
19
|
+
| Client | Config Format | Key Used |
|
|
20
|
+
| --------------------------- | ---------------------------------- | ---------------------------------- |
|
|
21
|
+
| Claude Code | `~/.claude/settings.json` | `url` |
|
|
22
|
+
| Claude Desktop | OS-specific config | `url` |
|
|
23
|
+
| Antigravity (CLI + Desktop) | `~/.gemini/config/mcp_config.json` | `serverUrl` |
|
|
24
|
+
| Codex | `~/.codex/config.toml` | `url` (TOML) |
|
|
25
|
+
| Cursor | `~/.cursor/mcp.json` | `url` |
|
|
26
|
+
| Windsurf | `~/.windsurf/mcp.json` | `serverUrl` |
|
|
27
|
+
| GitHub Copilot | `~/.vscode/mcp.json` | `url` (nested under `mcp.servers`) |
|
|
28
|
+
|
|
29
|
+
> **Antigravity CLI (`agy`) and the Antigravity Desktop/IDE share one central MCP
|
|
30
|
+
> config file**, so a single `antigravity` entry configures both.
|
|
28
31
|
|
|
29
32
|
## Usage
|
|
30
33
|
|
|
@@ -36,7 +39,7 @@ npx @brain-mcps/setup <client> [product]
|
|
|
36
39
|
npx @brain-mcps/setup --detect [product]
|
|
37
40
|
|
|
38
41
|
# Preview changes without writing files
|
|
39
|
-
npx @brain-mcps/setup
|
|
42
|
+
npx @brain-mcps/setup antigravity --dry-run
|
|
40
43
|
|
|
41
44
|
# List all supported clients and their config paths
|
|
42
45
|
npx @brain-mcps/setup --list
|
|
@@ -51,7 +54,7 @@ npx @brain-mcps/setup --list
|
|
|
51
54
|
|
|
52
55
|
Use any of these as the `<client>` argument:
|
|
53
56
|
|
|
54
|
-
`claude-code`, `claude-desktop`, `
|
|
57
|
+
`claude-code`, `claude-desktop`, `antigravity`, `codex`, `cursor`, `windsurf`, `copilot`
|
|
55
58
|
|
|
56
59
|
## How It Works
|
|
57
60
|
|
package/dist/cli.js
CHANGED
|
@@ -27,8 +27,8 @@ Options:
|
|
|
27
27
|
--help Show this help message
|
|
28
28
|
|
|
29
29
|
Examples:
|
|
30
|
-
npx @brain-mcps/setup
|
|
31
|
-
npx @brain-mcps/setup
|
|
30
|
+
npx @brain-mcps/setup antigravity # Configure Antigravity (CLI + Desktop) for Cerebro Externo
|
|
31
|
+
npx @brain-mcps/setup antigravity mentor # Configure Antigravity (CLI + Desktop) for Forge Mentor
|
|
32
32
|
npx @brain-mcps/setup claude-code brain # Configure Claude Code for Cerebro Externo
|
|
33
33
|
npx @brain-mcps/setup --detect # Configure all detected clients
|
|
34
34
|
npx @brain-mcps/setup --list # Show supported clients
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type Product = "brain" | "mentor";
|
|
2
|
-
export type ClientId = "claude-code" | "claude-desktop" | "
|
|
2
|
+
export type ClientId = "claude-code" | "claude-desktop" | "antigravity" | "codex" | "cursor" | "windsurf" | "copilot";
|
|
3
3
|
export type ConfigFormat = "json" | "toml";
|
|
4
4
|
export interface ClientDef {
|
|
5
5
|
id: ClientId;
|
package/dist/index.js
CHANGED
|
@@ -78,12 +78,15 @@ exports.CLIENT_DEFS = {
|
|
|
78
78
|
buildEntry: (url) => ({ url }),
|
|
79
79
|
supportedPlatforms: CLAUDE_DESKTOP_PLATFORMS,
|
|
80
80
|
},
|
|
81
|
-
|
|
82
|
-
id: "
|
|
83
|
-
name: "
|
|
84
|
-
|
|
81
|
+
antigravity: {
|
|
82
|
+
id: "antigravity",
|
|
83
|
+
name: "Antigravity (CLI + Desktop)",
|
|
84
|
+
// Antigravity CLI (`agy`) and the Antigravity IDE/Desktop share one central
|
|
85
|
+
// MCP config file. Confirmed against agy v1.1.2 binary strings.
|
|
86
|
+
configPathTemplate: "~/.gemini/config/mcp_config.json",
|
|
85
87
|
serversKey: ["mcpServers"],
|
|
86
|
-
|
|
88
|
+
// Remote HTTP servers use `serverUrl` (same key Windsurf uses), not `url`.
|
|
89
|
+
buildEntry: (url) => ({ serverUrl: url }),
|
|
87
90
|
},
|
|
88
91
|
codex: {
|
|
89
92
|
id: "codex",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brain-mcps/setup",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Configure AI assistant clients to connect to Brain4AI and Mentor4AI MCP servers",
|
|
5
5
|
"bin": {
|
|
6
6
|
"brain-mcp-setup": "dist/cli.js"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"brain4ai",
|
|
22
22
|
"mentor4ai",
|
|
23
23
|
"claude",
|
|
24
|
-
"
|
|
24
|
+
"antigravity",
|
|
25
25
|
"chatgpt"
|
|
26
26
|
],
|
|
27
27
|
"author": "SirGrimorum",
|
package/dist/index.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/index.test.js
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
const vitest_1 = require("vitest");
|
|
37
|
-
const fs = __importStar(require("node:fs"));
|
|
38
|
-
const path = __importStar(require("node:path"));
|
|
39
|
-
const os = __importStar(require("node:os"));
|
|
40
|
-
const smol_toml_1 = require("smol-toml");
|
|
41
|
-
const index_js_1 = require("./index.js");
|
|
42
|
-
/** Temporarily override process.platform for a test. */
|
|
43
|
-
function withPlatform(platform, fn) {
|
|
44
|
-
const original = Object.getOwnPropertyDescriptor(process, "platform");
|
|
45
|
-
Object.defineProperty(process, "platform", {
|
|
46
|
-
value: platform,
|
|
47
|
-
configurable: true,
|
|
48
|
-
});
|
|
49
|
-
try {
|
|
50
|
-
fn();
|
|
51
|
-
}
|
|
52
|
-
finally {
|
|
53
|
-
if (original)
|
|
54
|
-
Object.defineProperty(process, "platform", original);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
// ── Test helpers: use a real temp directory as fake $HOME ────────────────
|
|
58
|
-
let tmpHome;
|
|
59
|
-
(0, vitest_1.beforeEach)(() => {
|
|
60
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "brain-mcp-setup-test-"));
|
|
61
|
-
});
|
|
62
|
-
(0, vitest_1.afterEach)(() => {
|
|
63
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
64
|
-
});
|
|
65
|
-
/** Create the config directory for a client inside tmpHome. */
|
|
66
|
-
function ensureConfigDir(clientId) {
|
|
67
|
-
const configPath = (0, index_js_1.resolveConfigPath)(clientId, tmpHome);
|
|
68
|
-
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
69
|
-
}
|
|
70
|
-
/** Write a JSON config file for a client inside tmpHome. */
|
|
71
|
-
function writeConfig(clientId, data) {
|
|
72
|
-
const configPath = (0, index_js_1.resolveConfigPath)(clientId, tmpHome);
|
|
73
|
-
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
74
|
-
fs.writeFileSync(configPath, JSON.stringify(data, null, 2));
|
|
75
|
-
}
|
|
76
|
-
/** Read a JSON config file for a client from tmpHome. */
|
|
77
|
-
function readConfig(clientId) {
|
|
78
|
-
const configPath = (0, index_js_1.resolveConfigPath)(clientId, tmpHome);
|
|
79
|
-
return JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
80
|
-
}
|
|
81
|
-
/** Read a TOML config file for a client from tmpHome. */
|
|
82
|
-
function readTomlConfig(clientId) {
|
|
83
|
-
const configPath = (0, index_js_1.resolveConfigPath)(clientId, tmpHome);
|
|
84
|
-
return (0, smol_toml_1.parse)(fs.readFileSync(configPath, "utf-8"));
|
|
85
|
-
}
|
|
86
|
-
/** Write a raw string config file for a client inside tmpHome. */
|
|
87
|
-
function writeRawConfig(clientId, contents) {
|
|
88
|
-
const configPath = (0, index_js_1.resolveConfigPath)(clientId, tmpHome);
|
|
89
|
-
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
90
|
-
fs.writeFileSync(configPath, contents);
|
|
91
|
-
}
|
|
92
|
-
// ── Tests ───────────────────────────────────────────────────────────────
|
|
93
|
-
(0, vitest_1.describe)("listClients", () => {
|
|
94
|
-
(0, vitest_1.it)("returns all 7 supported clients", () => {
|
|
95
|
-
const clients = (0, index_js_1.listClients)();
|
|
96
|
-
(0, vitest_1.expect)(clients).toHaveLength(7);
|
|
97
|
-
const ids = clients.map((c) => c.id);
|
|
98
|
-
(0, vitest_1.expect)(ids).toContain("claude-code");
|
|
99
|
-
(0, vitest_1.expect)(ids).toContain("claude-desktop");
|
|
100
|
-
(0, vitest_1.expect)(ids).toContain("gemini");
|
|
101
|
-
(0, vitest_1.expect)(ids).toContain("codex");
|
|
102
|
-
(0, vitest_1.expect)(ids).toContain("cursor");
|
|
103
|
-
(0, vitest_1.expect)(ids).toContain("windsurf");
|
|
104
|
-
(0, vitest_1.expect)(ids).toContain("copilot");
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
(0, vitest_1.describe)("resolveConfigPath", () => {
|
|
108
|
-
(0, vitest_1.it)("replaces ~ with the provided home directory", () => {
|
|
109
|
-
const resolved = (0, index_js_1.resolveConfigPath)("gemini", "/fake/home");
|
|
110
|
-
(0, vitest_1.expect)(resolved).toBe("/fake/home/.gemini/settings.json");
|
|
111
|
-
});
|
|
112
|
-
(0, vitest_1.it)("uses os.homedir when no homeDir provided", () => {
|
|
113
|
-
const resolved = (0, index_js_1.resolveConfigPath)("gemini");
|
|
114
|
-
(0, vitest_1.expect)(resolved).toContain(os.homedir());
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
(0, vitest_1.describe)("setupClient", () => {
|
|
118
|
-
(0, vitest_1.it)("creates gemini config with httpUrl key", () => {
|
|
119
|
-
ensureConfigDir("gemini");
|
|
120
|
-
const result = (0, index_js_1.setupClient)("gemini", "brain", { homeDir: tmpHome });
|
|
121
|
-
(0, vitest_1.expect)(result.action).toBe("created");
|
|
122
|
-
(0, vitest_1.expect)(result.serverName).toBe("cerebro-externo");
|
|
123
|
-
const config = readConfig("gemini");
|
|
124
|
-
const servers = config.mcpServers;
|
|
125
|
-
(0, vitest_1.expect)(servers["cerebro-externo"].httpUrl).toBe("https://mcp.brain4ai.app/mcp");
|
|
126
|
-
// Gemini uses httpUrl, not url
|
|
127
|
-
(0, vitest_1.expect)(servers["cerebro-externo"].url).toBeUndefined();
|
|
128
|
-
});
|
|
129
|
-
(0, vitest_1.it)("creates claude-code config with type and url keys", () => {
|
|
130
|
-
ensureConfigDir("claude-code");
|
|
131
|
-
const result = (0, index_js_1.setupClient)("claude-code", "mentor", { homeDir: tmpHome });
|
|
132
|
-
(0, vitest_1.expect)(result.action).toBe("created");
|
|
133
|
-
(0, vitest_1.expect)(result.serverName).toBe("forge-mentor");
|
|
134
|
-
const config = readConfig("claude-code");
|
|
135
|
-
const servers = config.mcpServers;
|
|
136
|
-
(0, vitest_1.expect)(servers["forge-mentor"]).toEqual({
|
|
137
|
-
type: "url",
|
|
138
|
-
url: "https://mcp.mentor4ai.app/mcp",
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
(0, vitest_1.it)("creates windsurf config with serverUrl key", () => {
|
|
142
|
-
ensureConfigDir("windsurf");
|
|
143
|
-
const result = (0, index_js_1.setupClient)("windsurf", "brain", { homeDir: tmpHome });
|
|
144
|
-
(0, vitest_1.expect)(result.serverName).toBe("cerebro-externo");
|
|
145
|
-
const config = readConfig("windsurf");
|
|
146
|
-
const servers = config.mcpServers;
|
|
147
|
-
(0, vitest_1.expect)(servers["cerebro-externo"].serverUrl).toBe("https://mcp.brain4ai.app/mcp");
|
|
148
|
-
});
|
|
149
|
-
(0, vitest_1.it)("creates copilot config with nested mcp.servers path", () => {
|
|
150
|
-
ensureConfigDir("copilot");
|
|
151
|
-
(0, index_js_1.setupClient)("copilot", "brain", { homeDir: tmpHome });
|
|
152
|
-
const config = readConfig("copilot");
|
|
153
|
-
const mcp = config.mcp;
|
|
154
|
-
(0, vitest_1.expect)(mcp.servers["cerebro-externo"]).toEqual({
|
|
155
|
-
type: "http",
|
|
156
|
-
url: "https://mcp.brain4ai.app/mcp",
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
(0, vitest_1.it)("creates codex config as TOML with mcp_servers.<id>.url", () => {
|
|
160
|
-
ensureConfigDir("codex");
|
|
161
|
-
const result = (0, index_js_1.setupClient)("codex", "brain", { homeDir: tmpHome });
|
|
162
|
-
(0, vitest_1.expect)(result.action).toBe("created");
|
|
163
|
-
(0, vitest_1.expect)(result.serverName).toBe("cerebro-externo");
|
|
164
|
-
(0, vitest_1.expect)(result.configPath).toMatch(/config\.toml$/);
|
|
165
|
-
const config = readTomlConfig("codex");
|
|
166
|
-
const servers = config.mcp_servers;
|
|
167
|
-
(0, vitest_1.expect)(servers["cerebro-externo"]).toEqual({
|
|
168
|
-
url: "https://mcp.brain4ai.app/mcp",
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
(0, vitest_1.it)("merges codex config into existing TOML without losing other entries", () => {
|
|
172
|
-
writeRawConfig("codex", [
|
|
173
|
-
'model = "gpt-5"',
|
|
174
|
-
"",
|
|
175
|
-
"[mcp_servers.metalab]",
|
|
176
|
-
'command = "npx"',
|
|
177
|
-
'args = ["metalab-mcp-client"]',
|
|
178
|
-
"",
|
|
179
|
-
].join("\n"));
|
|
180
|
-
const result = (0, index_js_1.setupClient)("codex", "mentor", { homeDir: tmpHome });
|
|
181
|
-
(0, vitest_1.expect)(result.action).toBe("updated");
|
|
182
|
-
const config = readTomlConfig("codex");
|
|
183
|
-
(0, vitest_1.expect)(config.model).toBe("gpt-5");
|
|
184
|
-
const servers = config.mcp_servers;
|
|
185
|
-
(0, vitest_1.expect)(servers.metalab).toMatchObject({
|
|
186
|
-
command: "npx",
|
|
187
|
-
args: ["metalab-mcp-client"],
|
|
188
|
-
});
|
|
189
|
-
(0, vitest_1.expect)(servers["forge-mentor"]).toEqual({
|
|
190
|
-
url: "https://mcp.mentor4ai.app/mcp",
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
(0, vitest_1.it)("returns already_configured for codex when TOML URL matches", () => {
|
|
194
|
-
writeRawConfig("codex", [
|
|
195
|
-
"[mcp_servers.cerebro-externo]",
|
|
196
|
-
'url = "https://mcp.brain4ai.app/mcp"',
|
|
197
|
-
"",
|
|
198
|
-
].join("\n"));
|
|
199
|
-
const result = (0, index_js_1.setupClient)("codex", "brain", { homeDir: tmpHome });
|
|
200
|
-
(0, vitest_1.expect)(result.action).toBe("already_configured");
|
|
201
|
-
});
|
|
202
|
-
(0, vitest_1.it)("merges into existing config without overwriting other keys", () => {
|
|
203
|
-
writeConfig("gemini", {
|
|
204
|
-
mcpServers: { "other-server": { url: "https://other.example.com" } },
|
|
205
|
-
someOtherKey: "keep-me",
|
|
206
|
-
});
|
|
207
|
-
const result = (0, index_js_1.setupClient)("gemini", "brain", { homeDir: tmpHome });
|
|
208
|
-
(0, vitest_1.expect)(result.action).toBe("updated");
|
|
209
|
-
const config = readConfig("gemini");
|
|
210
|
-
(0, vitest_1.expect)(config.someOtherKey).toBe("keep-me");
|
|
211
|
-
const servers = config.mcpServers;
|
|
212
|
-
(0, vitest_1.expect)(servers["other-server"].url).toBe("https://other.example.com");
|
|
213
|
-
(0, vitest_1.expect)(servers["cerebro-externo"].httpUrl).toBe("https://mcp.brain4ai.app/mcp");
|
|
214
|
-
});
|
|
215
|
-
(0, vitest_1.it)("returns already_configured when URL matches", () => {
|
|
216
|
-
writeConfig("gemini", {
|
|
217
|
-
mcpServers: {
|
|
218
|
-
"cerebro-externo": { httpUrl: "https://mcp.brain4ai.app/mcp" },
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
const result = (0, index_js_1.setupClient)("gemini", "brain", { homeDir: tmpHome });
|
|
222
|
-
(0, vitest_1.expect)(result.action).toBe("already_configured");
|
|
223
|
-
});
|
|
224
|
-
(0, vitest_1.it)("dry-run does not write files", () => {
|
|
225
|
-
ensureConfigDir("gemini");
|
|
226
|
-
const configPath = (0, index_js_1.resolveConfigPath)("gemini", tmpHome);
|
|
227
|
-
const result = (0, index_js_1.setupClient)("gemini", "brain", {
|
|
228
|
-
homeDir: tmpHome,
|
|
229
|
-
dryRun: true,
|
|
230
|
-
});
|
|
231
|
-
(0, vitest_1.expect)(result.action).toBe("created");
|
|
232
|
-
(0, vitest_1.expect)(fs.existsSync(configPath)).toBe(false);
|
|
233
|
-
});
|
|
234
|
-
(0, vitest_1.it)("uses brain4ai.app for brain product", () => {
|
|
235
|
-
ensureConfigDir("claude-code");
|
|
236
|
-
(0, index_js_1.setupClient)("claude-code", "brain", { homeDir: tmpHome });
|
|
237
|
-
const config = readConfig("claude-code");
|
|
238
|
-
const servers = config.mcpServers;
|
|
239
|
-
(0, vitest_1.expect)(servers["cerebro-externo"].url).toContain("brain4ai.app");
|
|
240
|
-
});
|
|
241
|
-
(0, vitest_1.it)("uses mentor4ai.app for mentor product", () => {
|
|
242
|
-
ensureConfigDir("claude-code");
|
|
243
|
-
(0, index_js_1.setupClient)("claude-code", "mentor", { homeDir: tmpHome });
|
|
244
|
-
const config = readConfig("claude-code");
|
|
245
|
-
const servers = config.mcpServers;
|
|
246
|
-
(0, vitest_1.expect)(servers["forge-mentor"].url).toContain("mentor4ai.app");
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
(0, vitest_1.describe)("detectInstalledClients", () => {
|
|
250
|
-
(0, vitest_1.it)("detects clients whose config directories exist", () => {
|
|
251
|
-
// Create dirs for gemini and claude-code only
|
|
252
|
-
ensureConfigDir("gemini");
|
|
253
|
-
ensureConfigDir("claude-code");
|
|
254
|
-
const detected = (0, index_js_1.detectInstalledClients)(tmpHome);
|
|
255
|
-
(0, vitest_1.expect)(detected).toContain("gemini");
|
|
256
|
-
(0, vitest_1.expect)(detected).toContain("claude-code");
|
|
257
|
-
(0, vitest_1.expect)(detected).not.toContain("codex");
|
|
258
|
-
});
|
|
259
|
-
(0, vitest_1.it)("returns empty array when no clients are installed", () => {
|
|
260
|
-
const detected = (0, index_js_1.detectInstalledClients)(tmpHome);
|
|
261
|
-
(0, vitest_1.expect)(detected).toHaveLength(0);
|
|
262
|
-
});
|
|
263
|
-
(0, vitest_1.it)("excludes claude-desktop on linux even if config dir exists", () => {
|
|
264
|
-
ensureConfigDir("gemini");
|
|
265
|
-
ensureConfigDir("claude-desktop");
|
|
266
|
-
withPlatform("linux", () => {
|
|
267
|
-
const detected = (0, index_js_1.detectInstalledClients)(tmpHome);
|
|
268
|
-
(0, vitest_1.expect)(detected).toContain("gemini");
|
|
269
|
-
(0, vitest_1.expect)(detected).not.toContain("claude-desktop");
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
(0, vitest_1.describe)("isClientSupportedOnPlatform", () => {
|
|
274
|
-
(0, vitest_1.it)("returns true for any-platform clients on every OS", () => {
|
|
275
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("gemini", "linux")).toBe(true);
|
|
276
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("gemini", "darwin")).toBe(true);
|
|
277
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("gemini", "win32")).toBe(true);
|
|
278
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("codex", "linux")).toBe(true);
|
|
279
|
-
});
|
|
280
|
-
(0, vitest_1.it)("restricts claude-desktop to darwin and win32", () => {
|
|
281
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("claude-desktop", "darwin")).toBe(true);
|
|
282
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("claude-desktop", "win32")).toBe(true);
|
|
283
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("claude-desktop", "linux")).toBe(false);
|
|
284
|
-
(0, vitest_1.expect)((0, index_js_1.isClientSupportedOnPlatform)("claude-desktop", "freebsd")).toBe(false);
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
(0, vitest_1.describe)("setupClient platform restrictions", () => {
|
|
288
|
-
(0, vitest_1.it)("throws when configuring claude-desktop on linux", () => {
|
|
289
|
-
withPlatform("linux", () => {
|
|
290
|
-
(0, vitest_1.expect)(() => (0, index_js_1.setupClient)("claude-desktop", "brain", { homeDir: tmpHome })).toThrow(/not supported on linux/);
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
(0, vitest_1.it)("succeeds when configuring claude-desktop on darwin", () => {
|
|
294
|
-
ensureConfigDir("claude-desktop");
|
|
295
|
-
withPlatform("darwin", () => {
|
|
296
|
-
const result = (0, index_js_1.setupClient)("claude-desktop", "brain", {
|
|
297
|
-
homeDir: tmpHome,
|
|
298
|
-
});
|
|
299
|
-
(0, vitest_1.expect)(result.action).toBe("created");
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
});
|