brainctl 0.1.5 → 0.1.6
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 +160 -136
- package/dist/mcp/server.js +149 -0
- package/dist/services/agent-config-service.d.ts +20 -0
- package/dist/services/agent-config-service.js +189 -0
- package/dist/services/profile-service.d.ts +9 -0
- package/dist/services/profile-service.js +28 -1
- package/dist/services/sync/agent-reader.d.ts +25 -0
- package/dist/services/sync/agent-reader.js +221 -0
- package/dist/ui/routes.js +165 -1
- package/dist/web/assets/{index-CRJ6cM0Q.css → index-364NYWPA.css} +1 -1
- package/dist/web/assets/index-BmfE7rus.js +16 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -1
- package/dist/web/assets/index-Cr8gt3VF.js +0 -9
package/README.md
CHANGED
|
@@ -1,121 +1,120 @@
|
|
|
1
1
|
# 🧠 brainctl
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> One AI setup. Multiple agents. Zero reconfiguration.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**brainctl** is a cross-agent AI workflow manager that unifies your environment across Claude Code, Codex, and Gemini CLI — with a web dashboard, MCP server, and portable profiles.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/brainctl)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://github.com/Rorogogogo/brainctl/actions)
|
|
8
10
|
|
|
9
11
|
---
|
|
10
12
|
|
|
11
|
-
## ✨
|
|
13
|
+
## ✨ Features
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## 🚀 Features
|
|
26
|
-
|
|
27
|
-
- 🧠 File-based memory from Markdown files
|
|
28
|
-
- 🧩 Reusable skills stored in `ai-stack.yaml`
|
|
29
|
-
- 🔌 Multi-agent execution with Claude and Codex
|
|
30
|
-
- ⚙️ Unified context builder
|
|
31
|
-
- 🛠 CLI-first workflow
|
|
32
|
-
- 🔍 `status` and `doctor` for visibility
|
|
33
|
-
- 🔁 Optional fallback agent support with `--fallback`
|
|
15
|
+
- 🔀 **Multi-agent support** — Claude Code, Codex, and Gemini CLI from one config
|
|
16
|
+
- 🖥️ **Web dashboard** — Visual drag-and-drop MCP management across agents
|
|
17
|
+
- 🔌 **MCP server** — 20 tools exposable to any MCP-compatible agent
|
|
18
|
+
- 📦 **Portable profiles** — Export/import skill + MCP bundles as tarballs
|
|
19
|
+
- 🧠 **Shared memory** — Markdown-based context files shared across agents
|
|
20
|
+
- 🧩 **Reusable skills** — Prompt templates stored in `ai-stack.yaml`
|
|
21
|
+
- 🔄 **Profile sync** — Push configs to all agents in one command
|
|
22
|
+
- 🩺 **Health checks** — `status` and `doctor` commands for visibility
|
|
23
|
+
- 🔁 **Fallback agents** — Automatic failover if primary agent is unavailable
|
|
34
24
|
|
|
35
25
|
---
|
|
36
26
|
|
|
37
|
-
##
|
|
27
|
+
## 📸 Demo
|
|
38
28
|
|
|
39
|
-
###
|
|
29
|
+
### Web Dashboard — Drag MCPs between agents
|
|
40
30
|
|
|
41
|
-
```bash
|
|
42
|
-
npm install -g brainctl
|
|
43
31
|
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
brainctl
|
|
32
|
+
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
33
|
+
│ Claude │ │ Codex │ │ Gemini │
|
|
34
|
+
│ ┌──────────┐ │ │ ┌──────────┐ │ │ │
|
|
35
|
+
│ │ github │◄├──┤►│ github │ │ │ Drop here │
|
|
36
|
+
│ │ brainctl │ │ │ │ brainctl │ │ │ to copy │
|
|
37
|
+
│ └──────────┘ │ │ └──────────┘ │ │ │
|
|
38
|
+
│ Skills: 11 │ │ Skills: 3 │ │ Skills: 0 │
|
|
39
|
+
└──────────────┘ └──────────────┘ └──────────────┘
|
|
49
40
|
```
|
|
50
41
|
|
|
51
|
-
|
|
42
|
+
The dashboard reads **live config files** from each agent (`~/.claude.json`, `~/.codex/config.toml`, `~/.gemini/settings.json`) and lets you drag MCPs between them. Changes are staged and only applied on confirm.
|
|
52
43
|
|
|
53
|
-
|
|
54
|
-
npm install
|
|
55
|
-
npm run build
|
|
56
|
-
npm link
|
|
57
|
-
```
|
|
44
|
+
---
|
|
58
45
|
|
|
59
|
-
|
|
46
|
+
## 📦 Installation
|
|
60
47
|
|
|
61
48
|
```bash
|
|
62
|
-
brainctl
|
|
49
|
+
npm install -g brainctl
|
|
63
50
|
```
|
|
64
51
|
|
|
65
|
-
|
|
52
|
+
Or from source:
|
|
66
53
|
|
|
67
54
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
55
|
+
git clone https://github.com/Rorogogogo/brainctl.git
|
|
56
|
+
cd brainctl
|
|
57
|
+
npm install && npm run build && npm link
|
|
71
58
|
```
|
|
72
59
|
|
|
73
|
-
|
|
60
|
+
> **Prerequisite:** At least one supported agent CLI must be installed and on your `PATH` (`claude`, `codex`, or `gemini`).
|
|
74
61
|
|
|
75
62
|
---
|
|
76
63
|
|
|
77
|
-
##
|
|
78
|
-
|
|
79
|
-
### 1. Initialize a project
|
|
64
|
+
## 🚀 Quick Start
|
|
80
65
|
|
|
81
66
|
```bash
|
|
67
|
+
# 1. Initialize a project
|
|
82
68
|
brainctl init
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
This creates:
|
|
86
|
-
|
|
87
|
-
- `ai-stack.yaml`
|
|
88
|
-
- `memory/`
|
|
89
|
-
- `memory/notes.md`
|
|
90
69
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
```bash
|
|
70
|
+
# 2. Check your setup
|
|
94
71
|
brainctl status
|
|
95
72
|
brainctl doctor
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### 3. Run a task
|
|
99
73
|
|
|
100
|
-
|
|
74
|
+
# 3. Run a skill
|
|
101
75
|
brainctl run summarize ./memory/notes.md --with claude
|
|
76
|
+
|
|
77
|
+
# 4. Launch the web dashboard
|
|
78
|
+
brainctl ui
|
|
79
|
+
# → http://127.0.0.1:3333
|
|
102
80
|
```
|
|
103
81
|
|
|
104
|
-
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 📖 Usage
|
|
105
85
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
86
|
+
### CLI Commands
|
|
87
|
+
|
|
88
|
+
| Command | Description |
|
|
89
|
+
|---------|-------------|
|
|
90
|
+
| `brainctl init` | Scaffold `ai-stack.yaml` and `memory/` directory |
|
|
91
|
+
| `brainctl status` | Show memory, skills, MCPs, and agent availability |
|
|
92
|
+
| `brainctl doctor` | Validate config, paths, and installed agents |
|
|
93
|
+
| `brainctl run <skill> <file> --with <agent>` | Execute a skill through an agent |
|
|
94
|
+
| `brainctl profile list` | List available profiles |
|
|
95
|
+
| `brainctl profile create <name>` | Create a new profile |
|
|
96
|
+
| `brainctl profile use <name>` | Switch active profile |
|
|
97
|
+
| `brainctl profile export <name>` | Export profile as portable tarball |
|
|
98
|
+
| `brainctl profile import <archive>` | Import profile from tarball |
|
|
99
|
+
| `brainctl sync` | Sync active profile to all agent configs |
|
|
100
|
+
| `brainctl ui` | Start the web dashboard |
|
|
109
101
|
|
|
110
|
-
|
|
102
|
+
### Run Examples
|
|
111
103
|
|
|
112
104
|
```bash
|
|
113
|
-
|
|
105
|
+
# Basic execution
|
|
106
|
+
brainctl run summarize ./notes.md --with claude
|
|
107
|
+
|
|
108
|
+
# With fallback agent
|
|
109
|
+
brainctl run analyze ./report.md --with codex --fallback claude
|
|
110
|
+
|
|
111
|
+
# Using Gemini
|
|
112
|
+
brainctl run review ./code.md --with gemini
|
|
114
113
|
```
|
|
115
114
|
|
|
116
115
|
---
|
|
117
116
|
|
|
118
|
-
## 🧠
|
|
117
|
+
## 🧠 Config: `ai-stack.yaml`
|
|
119
118
|
|
|
120
119
|
```yaml
|
|
121
120
|
memory:
|
|
@@ -124,119 +123,144 @@ memory:
|
|
|
124
123
|
|
|
125
124
|
skills:
|
|
126
125
|
summarize:
|
|
127
|
-
description: Summarize content
|
|
126
|
+
description: Summarize content into bullet points
|
|
128
127
|
prompt: |
|
|
129
128
|
Summarize the following content into concise bullet points.
|
|
130
129
|
|
|
131
|
-
|
|
132
|
-
description:
|
|
130
|
+
review:
|
|
131
|
+
description: Code review with actionable feedback
|
|
133
132
|
prompt: |
|
|
134
|
-
|
|
133
|
+
Review the following code and provide actionable feedback.
|
|
135
134
|
|
|
136
135
|
mcps: {}
|
|
137
136
|
```
|
|
138
137
|
|
|
139
|
-
|
|
138
|
+
### How Context Assembly Works
|
|
140
139
|
|
|
141
|
-
|
|
140
|
+
```
|
|
141
|
+
┌─────────────┐
|
|
142
|
+
│ MEMORY │ ← Markdown files from configured paths
|
|
143
|
+
├─────────────┤
|
|
144
|
+
│ SKILL │ ← Prompt template from ai-stack.yaml
|
|
145
|
+
├─────────────┤
|
|
146
|
+
│ INPUT │ ← Your file
|
|
147
|
+
└─────────────┘
|
|
148
|
+
↓
|
|
149
|
+
Agent CLI (claude / codex / gemini)
|
|
150
|
+
```
|
|
142
151
|
|
|
143
|
-
|
|
152
|
+
---
|
|
144
153
|
|
|
145
|
-
|
|
146
|
-
--- MEMORY ---
|
|
147
|
-
[your markdown files]
|
|
154
|
+
## 🔌 MCP Server
|
|
148
155
|
|
|
149
|
-
|
|
150
|
-
[prompt template]
|
|
156
|
+
brainctl exposes **20 MCP tools** that any compatible agent can call:
|
|
151
157
|
|
|
152
|
-
|
|
153
|
-
|
|
158
|
+
```bash
|
|
159
|
+
# Add brainctl as an MCP server in your agent config
|
|
160
|
+
# Claude (~/.claude.json):
|
|
161
|
+
{
|
|
162
|
+
"mcpServers": {
|
|
163
|
+
"brainctl": {
|
|
164
|
+
"type": "stdio",
|
|
165
|
+
"command": "npx",
|
|
166
|
+
"args": ["-y", "brainctl", "mcp"]
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
154
170
|
```
|
|
155
171
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## 🛠 Usage
|
|
172
|
+
**Available tools:**
|
|
161
173
|
|
|
162
|
-
|
|
174
|
+
| Category | Tools |
|
|
175
|
+
|----------|-------|
|
|
176
|
+
| **Skills** | `list_skills`, `get_skill`, `run` |
|
|
177
|
+
| **Memory** | `read_memory`, `write_memory` |
|
|
178
|
+
| **Profiles** | `list_profiles`, `get_profile`, `create_profile`, `update_profile`, `delete_profile`, `switch_profile`, `copy_profile_items`, `export_profile`, `import_profile` |
|
|
179
|
+
| **Agent Configs** | `read_agent_configs`, `add_agent_mcp`, `remove_agent_mcp` |
|
|
180
|
+
| **System** | `status`, `doctor`, `sync` |
|
|
163
181
|
|
|
164
|
-
|
|
165
|
-
| --- | --- |
|
|
166
|
-
| `brainctl init` | Initialize `ai-stack.yaml` and memory files |
|
|
167
|
-
| `brainctl status` | Show memory, skills, MCP count, and agent availability |
|
|
168
|
-
| `brainctl doctor` | Validate config, memory paths, skills, and installed agents |
|
|
169
|
-
| `brainctl run <skill> <file> --with <agent>` | Build context and execute with an agent |
|
|
182
|
+
---
|
|
170
183
|
|
|
171
|
-
|
|
184
|
+
## 🖥️ Web Dashboard
|
|
172
185
|
|
|
173
186
|
```bash
|
|
174
|
-
brainctl
|
|
175
|
-
brainctl run analyze ./memory/notes.md --with codex
|
|
176
|
-
brainctl run summarize ./memory/notes.md --with claude --fallback codex
|
|
187
|
+
brainctl ui
|
|
177
188
|
```
|
|
178
189
|
|
|
190
|
+
Opens a local dashboard at `http://127.0.0.1:3333` with:
|
|
191
|
+
|
|
192
|
+
- **Agent Profiles** — See live MCPs and skills for Claude, Codex, and Gemini side-by-side
|
|
193
|
+
- **Drag & Drop** — Copy MCPs between agents by dragging cards
|
|
194
|
+
- **Staged Changes** — Preview adds/removes before applying, with undo support
|
|
195
|
+
- **Skills Editor** — Edit skill prompts with live preview
|
|
196
|
+
- **MCP Manager** — View and edit MCP configurations
|
|
197
|
+
- **Memory Viewer** — Browse shared markdown memory files
|
|
198
|
+
- **Run Console** — Execute skills with real-time streaming output
|
|
199
|
+
|
|
179
200
|
---
|
|
180
201
|
|
|
181
|
-
##
|
|
202
|
+
## 🏗️ Architecture
|
|
182
203
|
|
|
183
|
-
```
|
|
204
|
+
```
|
|
184
205
|
brainctl/
|
|
185
206
|
├── src/
|
|
186
|
-
│ ├── cli.ts
|
|
187
|
-
│ ├──
|
|
188
|
-
│ ├──
|
|
189
|
-
│
|
|
190
|
-
│ ├──
|
|
191
|
-
│
|
|
192
|
-
├──
|
|
193
|
-
|
|
194
|
-
├──
|
|
195
|
-
├──
|
|
196
|
-
└──
|
|
207
|
+
│ ├── cli.ts # CLI entry point (Commander)
|
|
208
|
+
│ ├── commands/ # 8 command handlers
|
|
209
|
+
│ ├── services/ # 11 business logic services
|
|
210
|
+
│ │ └── sync/ # Agent config readers/writers
|
|
211
|
+
│ ├── context/ # Memory loader, skill resolver, context builder
|
|
212
|
+
│ ├── executor/ # Agent spawning (Claude, Codex, Gemini)
|
|
213
|
+
│ ├── mcp/ # FastMCP server (20 tools)
|
|
214
|
+
│ └── ui/ # HTTP server with SSE streaming
|
|
215
|
+
├── web/src/ # React dashboard (Vite + dnd-kit)
|
|
216
|
+
├── tests/ # Vitest test suite
|
|
217
|
+
└── ai-stack.yaml # Project config
|
|
197
218
|
```
|
|
198
219
|
|
|
220
|
+
### Agent Config Locations
|
|
221
|
+
|
|
222
|
+
| Agent | Config Path | MCP Location |
|
|
223
|
+
|-------|-------------|-------------|
|
|
224
|
+
| Claude | `~/.claude.json` | `projects[cwd].mcpServers` |
|
|
225
|
+
| Codex | `~/.codex/config.toml` | `[mcp_servers.*]` |
|
|
226
|
+
| Gemini | `~/.gemini/settings.json` | `mcpServers` |
|
|
227
|
+
|
|
199
228
|
---
|
|
200
229
|
|
|
201
230
|
## 🧪 Development
|
|
202
231
|
|
|
203
232
|
```bash
|
|
204
233
|
npm install
|
|
205
|
-
npm test
|
|
206
|
-
npm run build
|
|
234
|
+
npm test # Run all tests (Vitest)
|
|
235
|
+
npm run build # Build server (tsc) + web (Vite)
|
|
236
|
+
npm run dev -- <args> # Run CLI via tsx
|
|
207
237
|
```
|
|
208
238
|
|
|
209
239
|
---
|
|
210
240
|
|
|
211
|
-
##
|
|
212
|
-
|
|
213
|
-
`brainctl` does not replace your AI tools.
|
|
214
|
-
|
|
215
|
-
It sits between you and them as a thin orchestration layer:
|
|
241
|
+
## 🤝 Contributing
|
|
216
242
|
|
|
217
|
-
|
|
218
|
-
- `brainctl` keeps the environment consistent
|
|
243
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
219
244
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
- [ ] MCP runtime integration
|
|
227
|
-
- [ ] Better execution tracing and logs
|
|
228
|
-
- [ ] UI / dashboard
|
|
245
|
+
```bash
|
|
246
|
+
git clone https://github.com/Rorogogogo/brainctl.git
|
|
247
|
+
cd brainctl
|
|
248
|
+
npm install
|
|
249
|
+
npm test
|
|
250
|
+
```
|
|
229
251
|
|
|
230
252
|
---
|
|
231
253
|
|
|
232
|
-
## 💡
|
|
254
|
+
## 💡 Philosophy
|
|
233
255
|
|
|
234
|
-
AI tools
|
|
256
|
+
brainctl doesn't replace your AI tools. It sits between you and them as a thin orchestration layer:
|
|
235
257
|
|
|
236
|
-
|
|
258
|
+
- **You keep using** Claude Code, Codex, and Gemini CLI directly
|
|
259
|
+
- **brainctl keeps** the environment consistent across all of them
|
|
260
|
+
- **Profiles make it portable** — share your setup with your team
|
|
237
261
|
|
|
238
262
|
---
|
|
239
263
|
|
|
240
264
|
## 📄 License
|
|
241
265
|
|
|
242
|
-
MIT
|
|
266
|
+
[MIT](https://opensource.org/licenses/MIT) — use it however you want.
|
package/dist/mcp/server.js
CHANGED
|
@@ -4,6 +4,7 @@ import { FastMCP } from 'fastmcp';
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { loadConfig } from '../config.js';
|
|
6
6
|
import { loadMemory } from '../context/memory.js';
|
|
7
|
+
import { createAgentConfigService } from '../services/agent-config-service.js';
|
|
7
8
|
import { createDoctorService } from '../services/doctor-service.js';
|
|
8
9
|
import { createMemoryWriteService } from '../services/memory-write-service.js';
|
|
9
10
|
import { createProfileExportService } from '../services/profile-export-service.js';
|
|
@@ -177,6 +178,111 @@ export function createMcpServer(options = {}) {
|
|
|
177
178
|
return JSON.stringify(result, null, 2);
|
|
178
179
|
},
|
|
179
180
|
});
|
|
181
|
+
server.addTool({
|
|
182
|
+
name: 'brainctl_get_profile',
|
|
183
|
+
description: 'Get the full config of a profile including all skills, MCPs, and memory paths.',
|
|
184
|
+
parameters: z.object({
|
|
185
|
+
name: z.string().describe('Profile name'),
|
|
186
|
+
}),
|
|
187
|
+
execute: async (args) => {
|
|
188
|
+
const profileService = createProfileService();
|
|
189
|
+
const profile = await profileService.get({ cwd, name: args.name });
|
|
190
|
+
return JSON.stringify(profile, null, 2);
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
server.addTool({
|
|
194
|
+
name: 'brainctl_create_profile',
|
|
195
|
+
description: 'Create a new profile with a default example skill.',
|
|
196
|
+
parameters: z.object({
|
|
197
|
+
name: z.string().describe('Profile name to create'),
|
|
198
|
+
description: z.string().optional().describe('Profile description'),
|
|
199
|
+
}),
|
|
200
|
+
execute: async (args) => {
|
|
201
|
+
const profileService = createProfileService();
|
|
202
|
+
const result = await profileService.create({
|
|
203
|
+
cwd,
|
|
204
|
+
name: args.name,
|
|
205
|
+
description: args.description,
|
|
206
|
+
});
|
|
207
|
+
return JSON.stringify(result, null, 2);
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
server.addTool({
|
|
211
|
+
name: 'brainctl_update_profile',
|
|
212
|
+
description: 'Update a profile config. Pass the full profile object with skills, mcps, and memory fields. Use this to add, remove, or modify skills and MCPs within a profile.',
|
|
213
|
+
parameters: z.object({
|
|
214
|
+
name: z.string().describe('Profile name to update'),
|
|
215
|
+
config: z.object({
|
|
216
|
+
name: z.string(),
|
|
217
|
+
description: z.string().optional(),
|
|
218
|
+
skills: z.record(z.string(), z.object({
|
|
219
|
+
description: z.string().optional(),
|
|
220
|
+
prompt: z.string(),
|
|
221
|
+
})),
|
|
222
|
+
mcps: z.record(z.string(), z.unknown()),
|
|
223
|
+
memory: z.object({
|
|
224
|
+
paths: z.array(z.string()),
|
|
225
|
+
}),
|
|
226
|
+
}).describe('Full profile config object'),
|
|
227
|
+
}),
|
|
228
|
+
execute: async (args) => {
|
|
229
|
+
const profileService = createProfileService();
|
|
230
|
+
await profileService.update({
|
|
231
|
+
cwd,
|
|
232
|
+
name: args.name,
|
|
233
|
+
config: args.config,
|
|
234
|
+
});
|
|
235
|
+
return JSON.stringify({ ok: true, updated: args.name });
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
server.addTool({
|
|
239
|
+
name: 'brainctl_delete_profile',
|
|
240
|
+
description: 'Delete a profile. Cannot delete the currently active profile.',
|
|
241
|
+
parameters: z.object({
|
|
242
|
+
name: z.string().describe('Profile name to delete'),
|
|
243
|
+
}),
|
|
244
|
+
execute: async (args) => {
|
|
245
|
+
const profileService = createProfileService();
|
|
246
|
+
await profileService.delete({ cwd, name: args.name });
|
|
247
|
+
return JSON.stringify({ ok: true, deleted: args.name });
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
server.addTool({
|
|
251
|
+
name: 'brainctl_copy_profile_items',
|
|
252
|
+
description: 'Copy skills and/or MCPs from one profile to another. Specify which skill and MCP keys to copy. Existing items with the same key in the target are overwritten.',
|
|
253
|
+
parameters: z.object({
|
|
254
|
+
source: z.string().describe('Source profile name'),
|
|
255
|
+
target: z.string().describe('Target profile name'),
|
|
256
|
+
skills: z.array(z.string()).default([]).describe('Skill keys to copy'),
|
|
257
|
+
mcps: z.array(z.string()).default([]).describe('MCP keys to copy'),
|
|
258
|
+
}),
|
|
259
|
+
execute: async (args) => {
|
|
260
|
+
const profileService = createProfileService();
|
|
261
|
+
const sourceProfile = await profileService.get({ cwd, name: args.source });
|
|
262
|
+
const targetProfile = await profileService.get({ cwd, name: args.target });
|
|
263
|
+
const copiedSkills = [];
|
|
264
|
+
const copiedMcps = [];
|
|
265
|
+
for (const key of args.skills) {
|
|
266
|
+
if (sourceProfile.skills[key]) {
|
|
267
|
+
targetProfile.skills[key] = sourceProfile.skills[key];
|
|
268
|
+
copiedSkills.push(key);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
for (const key of args.mcps) {
|
|
272
|
+
if (sourceProfile.mcps[key]) {
|
|
273
|
+
targetProfile.mcps[key] = sourceProfile.mcps[key];
|
|
274
|
+
copiedMcps.push(key);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
await profileService.update({ cwd, name: args.target, config: targetProfile });
|
|
278
|
+
return JSON.stringify({
|
|
279
|
+
source: args.source,
|
|
280
|
+
target: args.target,
|
|
281
|
+
copiedSkills,
|
|
282
|
+
copiedMcps,
|
|
283
|
+
}, null, 2);
|
|
284
|
+
},
|
|
285
|
+
});
|
|
180
286
|
server.addTool({
|
|
181
287
|
name: 'brainctl_export_profile',
|
|
182
288
|
description: 'Export a profile as a portable tarball. Packages the profile config and bundled MCP source code for sharing.',
|
|
@@ -211,6 +317,49 @@ export function createMcpServer(options = {}) {
|
|
|
211
317
|
return JSON.stringify(result, null, 2);
|
|
212
318
|
},
|
|
213
319
|
});
|
|
320
|
+
server.addTool({
|
|
321
|
+
name: 'brainctl_read_agent_configs',
|
|
322
|
+
description: 'Read the live MCP configs from all agents (Claude, Codex, Gemini). Shows what is actually configured in each agent right now, by reading their real config files.',
|
|
323
|
+
parameters: z.object({}),
|
|
324
|
+
execute: async () => {
|
|
325
|
+
const agentConfigService = createAgentConfigService();
|
|
326
|
+
const configs = await agentConfigService.readAll({ cwd });
|
|
327
|
+
return JSON.stringify(configs, null, 2);
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
server.addTool({
|
|
331
|
+
name: 'brainctl_add_agent_mcp',
|
|
332
|
+
description: 'Add or overwrite an MCP server entry in a specific agent config. Writes directly to the agent config file (e.g., ~/.claude.json).',
|
|
333
|
+
parameters: z.object({
|
|
334
|
+
agent: z.enum(['claude', 'codex', 'gemini']).describe('Target agent'),
|
|
335
|
+
key: z.string().describe('MCP server name/key'),
|
|
336
|
+
command: z.string().describe('Command to run the MCP server'),
|
|
337
|
+
args: z.array(z.string()).default([]).describe('Arguments for the command'),
|
|
338
|
+
}),
|
|
339
|
+
execute: async (args) => {
|
|
340
|
+
const agentConfigService = createAgentConfigService();
|
|
341
|
+
await agentConfigService.addMcp({
|
|
342
|
+
cwd,
|
|
343
|
+
agent: args.agent,
|
|
344
|
+
key: args.key,
|
|
345
|
+
entry: { command: args.command, args: args.args },
|
|
346
|
+
});
|
|
347
|
+
return JSON.stringify({ ok: true, agent: args.agent, key: args.key });
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
server.addTool({
|
|
351
|
+
name: 'brainctl_remove_agent_mcp',
|
|
352
|
+
description: 'Remove an MCP server entry from a specific agent config.',
|
|
353
|
+
parameters: z.object({
|
|
354
|
+
agent: z.enum(['claude', 'codex', 'gemini']).describe('Target agent'),
|
|
355
|
+
key: z.string().describe('MCP server name/key to remove'),
|
|
356
|
+
}),
|
|
357
|
+
execute: async (args) => {
|
|
358
|
+
const agentConfigService = createAgentConfigService();
|
|
359
|
+
await agentConfigService.removeMcp({ cwd, agent: args.agent, key: args.key });
|
|
360
|
+
return JSON.stringify({ ok: true, agent: args.agent, removed: args.key });
|
|
361
|
+
},
|
|
362
|
+
});
|
|
214
363
|
return server;
|
|
215
364
|
}
|
|
216
365
|
export async function startMcpServer(options = {}) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AgentName } from '../types.js';
|
|
2
|
+
import { type AgentLiveConfig, type AgentMcpEntry } from './sync/agent-reader.js';
|
|
3
|
+
export type { AgentLiveConfig, AgentMcpEntry, AgentSkillEntry } from './sync/agent-reader.js';
|
|
4
|
+
export interface AgentConfigService {
|
|
5
|
+
readAll(options: {
|
|
6
|
+
cwd: string;
|
|
7
|
+
}): Promise<AgentLiveConfig[]>;
|
|
8
|
+
addMcp(options: {
|
|
9
|
+
cwd: string;
|
|
10
|
+
agent: AgentName;
|
|
11
|
+
key: string;
|
|
12
|
+
entry: AgentMcpEntry;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
removeMcp(options: {
|
|
15
|
+
cwd: string;
|
|
16
|
+
agent: AgentName;
|
|
17
|
+
key: string;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare function createAgentConfigService(): AgentConfigService;
|