multiagents 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.
@@ -20,11 +20,12 @@ const MCP_JSON = path.join(CLAUDE_DIR, ".mcp.json");
20
20
  const SETTINGS_JSON = path.join(CLAUDE_DIR, "settings.json");
21
21
 
22
22
  function findBinary(name: string): string {
23
- const which = Bun.spawnSync(["which", name]);
24
- const found = new TextDecoder().decode(which.stdout).trim();
25
- if (found) return found;
23
+ try {
24
+ const which = Bun.spawnSync(["which", name]);
25
+ const found = new TextDecoder().decode(which.stdout).trim();
26
+ if (found) return found;
27
+ } catch { /* ok */ }
26
28
 
27
- // Fallback to common locations
28
29
  const candidates = [
29
30
  path.join(HOME, ".bun", "bin", name),
30
31
  `/usr/local/bin/${name}`,
@@ -33,20 +34,16 @@ function findBinary(name: string): string {
33
34
  for (const c of candidates) {
34
35
  if (fs.existsSync(c)) return c;
35
36
  }
36
- return name; // hope it's in PATH at runtime
37
+ return name;
37
38
  }
38
39
 
39
- export async function installMcp(): Promise<void> {
40
- console.log("\n\x1b[1m\x1b[36m multiagents install-mcp\x1b[0m");
41
- console.log("\x1b[90m Configure MCP servers for Claude Code\x1b[0m\n");
42
-
40
+ /** Core logic configures .mcp.json + settings.json. Returns log lines. */
41
+ function configureMcp(): string[] {
42
+ const logs: string[] = [];
43
43
  const serverBin = findBinary("multiagents-server");
44
44
  const orchBin = findBinary("multiagents-orch");
45
45
 
46
- console.log(` Server binary: ${serverBin}`);
47
- console.log(` Orchestrator binary: ${orchBin}\n`);
48
-
49
- // --- Step 1: Write ~/.claude/.mcp.json ---
46
+ // Step 1: Write ~/.claude/.mcp.json
50
47
  if (!fs.existsSync(CLAUDE_DIR)) {
51
48
  fs.mkdirSync(CLAUDE_DIR, { recursive: true });
52
49
  }
@@ -59,57 +56,49 @@ export async function installMcp(): Promise<void> {
59
56
  } catch {
60
57
  fs.copyFileSync(MCP_JSON, MCP_JSON + ".bak");
61
58
  mcpConfig = { mcpServers: {} };
62
- console.log(" \x1b[33m!\x1b[0m Existing .mcp.json was corrupted — backed up and recreated");
59
+ logs.push(" \x1b[33m!\x1b[0m Existing .mcp.json was corrupted — backed up and recreated");
63
60
  }
64
61
  }
65
62
 
66
- mcpConfig.mcpServers["multiagents"] = {
67
- command: serverBin,
68
- args: [],
69
- };
70
- mcpConfig.mcpServers["multiagents-orch"] = {
71
- command: orchBin,
72
- args: [],
73
- };
74
-
63
+ mcpConfig.mcpServers["multiagents"] = { command: serverBin, args: [] };
64
+ mcpConfig.mcpServers["multiagents-orch"] = { command: orchBin, args: [] };
75
65
  fs.writeFileSync(MCP_JSON, JSON.stringify(mcpConfig, null, 2) + "\n");
76
- console.log(" \x1b[32m✔\x1b[0m Wrote ~/.claude/.mcp.json");
66
+ logs.push(" \x1b[32m✔\x1b[0m Global MCP configured (~/.claude/.mcp.json)");
77
67
 
78
- // --- Step 2: Enable in ~/.claude/settings.json ---
68
+ // Step 2: Enable in ~/.claude/settings.json
79
69
  let settings: Record<string, unknown> = {};
80
70
  if (fs.existsSync(SETTINGS_JSON)) {
81
71
  try {
82
72
  settings = JSON.parse(fs.readFileSync(SETTINGS_JSON, "utf-8"));
83
73
  } catch {
84
- console.log(" \x1b[33m!\x1b[0m Could not parse settings.json — skipping auto-enable");
85
- printDone();
86
- return;
74
+ logs.push(" \x1b[33m!\x1b[0m Could not parse settings.json — skipping auto-enable");
75
+ return logs;
87
76
  }
88
77
  }
89
78
 
90
- // Ensure enabledMcpjsonServers includes our servers
91
- let enabled = (settings.enabledMcpjsonServers as string[]) ?? [];
79
+ const enabled = (settings.enabledMcpjsonServers as string[]) ?? [];
92
80
  let changed = false;
93
- if (!enabled.includes("multiagents")) {
94
- enabled.push("multiagents");
95
- changed = true;
96
- }
97
- if (!enabled.includes("multiagents-orch")) {
98
- enabled.push("multiagents-orch");
99
- changed = true;
100
- }
81
+ if (!enabled.includes("multiagents")) { enabled.push("multiagents"); changed = true; }
82
+ if (!enabled.includes("multiagents-orch")) { enabled.push("multiagents-orch"); changed = true; }
101
83
  if (changed) {
102
84
  settings.enabledMcpjsonServers = enabled;
103
85
  fs.writeFileSync(SETTINGS_JSON, JSON.stringify(settings, null, 2) + "\n");
104
- console.log(" \x1b[32m✔\x1b[0m Enabled in ~/.claude/settings.json");
86
+ logs.push(" \x1b[32m✔\x1b[0m Enabled in ~/.claude/settings.json");
105
87
  } else {
106
- console.log(" \x1b[32m✔\x1b[0m Already enabled in settings.json");
88
+ logs.push(" \x1b[32m✔\x1b[0m Already enabled in settings.json");
107
89
  }
108
90
 
109
- printDone();
91
+ return logs;
110
92
  }
111
93
 
112
- function printDone(): void {
94
+ /** Verbose version — standalone `multiagents install-mcp` command. */
95
+ export async function installMcp(): Promise<void> {
96
+ console.log("\n\x1b[1m\x1b[36m multiagents install-mcp\x1b[0m");
97
+ console.log("\x1b[90m Configure MCP servers for Claude Code\x1b[0m\n");
98
+
99
+ const logs = configureMcp();
100
+ for (const line of logs) console.log(line);
101
+
113
102
  console.log(`
114
103
  \x1b[1m\x1b[32mDone!\x1b[0m MCP servers configured.
115
104
 
@@ -128,3 +117,9 @@ And add to ~/.claude/settings.json:
128
117
  \x1b[90m "enabledMcpjsonServers": ["multiagents", "multiagents-orch"]\x1b[0m
129
118
  `);
130
119
  }
120
+
121
+ /** Quiet version — called from `setup` flow, prints compact output. */
122
+ export async function installMcpSilent(): Promise<void> {
123
+ const logs = configureMcp();
124
+ for (const line of logs) console.log(line);
125
+ }
package/cli/setup.ts CHANGED
@@ -1,58 +1,79 @@
1
1
  // ============================================================================
2
- // multiagents — Interactive Setup Wizard
2
+ // multiagents — Setup: detect agents + install MCP globally
3
3
  // ============================================================================
4
4
 
5
- import { DEFAULT_BROKER_PORT, BROKER_HOSTNAME, SESSION_DIR, SESSION_FILE } from "../shared/constants.ts";
5
+ import { DEFAULT_BROKER_PORT, BROKER_HOSTNAME } from "../shared/constants.ts";
6
6
  import { BrokerClient } from "../shared/broker-client.ts";
7
- import { expandHome, getGitRoot, slugify } from "../shared/utils.ts";
8
- import type { AgentType, SessionFile } from "../shared/types.ts";
9
- import * as readline from "node:readline";
10
7
  import * as path from "node:path";
11
8
  import * as fs from "node:fs";
9
+ import * as os from "node:os";
12
10
 
13
11
  const BROKER_PORT = parseInt(process.env.MULTIAGENTS_PORT ?? String(DEFAULT_BROKER_PORT), 10);
14
12
  const BROKER_URL = `http://${BROKER_HOSTNAME}:${BROKER_PORT}`;
15
13
 
16
- // --- Helpers ---
17
-
18
- function prompt(question: string, defaultValue?: string): Promise<string> {
19
- return new Promise((resolve) => {
20
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
21
- const suffix = defaultValue ? ` [${defaultValue}]` : "";
22
- rl.question(`${question}${suffix}: `, (answer) => {
23
- rl.close();
24
- resolve(answer.trim() || defaultValue || "");
25
- });
26
- });
27
- }
28
-
29
- function detectAgent(name: string): { available: boolean; version?: string } {
14
+ /** Known install locations per agent type. */
15
+ const KNOWN_PATHS: Record<string, string[]> = {
16
+ claude: [
17
+ path.join(os.homedir(), ".local", "bin", "claude"),
18
+ path.join(os.homedir(), ".claude", "bin", "claude"),
19
+ "/usr/local/bin/claude",
20
+ "/opt/homebrew/bin/claude",
21
+ ],
22
+ codex: [
23
+ "/usr/local/bin/codex",
24
+ path.join(os.homedir(), ".local", "bin", "codex"),
25
+ path.join(os.homedir(), ".npm-global", "bin", "codex"),
26
+ "/opt/homebrew/bin/codex",
27
+ ],
28
+ gemini: [
29
+ path.join(os.homedir(), ".local", "bin", "gemini"),
30
+ "/usr/local/bin/gemini",
31
+ "/opt/homebrew/bin/gemini",
32
+ path.join(os.homedir(), ".npm-global", "bin", "gemini"),
33
+ ],
34
+ };
35
+
36
+ function detectAgent(name: string): { available: boolean; version?: string; resolvedPath?: string } {
37
+ let agentPath: string | null = null;
30
38
  try {
31
39
  const which = Bun.spawnSync(["which", name]);
32
- if (which.exitCode !== 0) return { available: false };
40
+ if (which.exitCode === 0) {
41
+ agentPath = new TextDecoder().decode(which.stdout).trim();
42
+ }
43
+ } catch { /* which failed */ }
33
44
 
34
- const ver = Bun.spawnSync([name, "--version"]);
35
- const version = new TextDecoder().decode(ver.stdout).trim().split("\n")[0];
36
- return { available: true, version: version || undefined };
37
- } catch {
38
- return { available: false };
45
+ if (!agentPath) {
46
+ for (const p of (KNOWN_PATHS[name] ?? [])) {
47
+ if (fs.existsSync(p)) { agentPath = p; break; }
48
+ }
39
49
  }
50
+
51
+ if (!agentPath) return { available: false };
52
+
53
+ let version: string | undefined;
54
+ try {
55
+ const ver = Bun.spawnSync([agentPath, "--version"], { timeout: 5000 });
56
+ if (ver.exitCode === 0) {
57
+ version = new TextDecoder().decode(ver.stdout).trim().split("\n")[0] || undefined;
58
+ }
59
+ } catch { version = undefined; }
60
+
61
+ return { available: true, version, resolvedPath: agentPath };
40
62
  }
41
63
 
42
64
  export async function setup(): Promise<void> {
43
- // 1. Header banner
44
65
  console.log(`
45
- \x1b[1m\x1b[36m multiagents\x1b[0m
46
- \x1b[90m Interactive Setup Wizard\x1b[0m
66
+ \x1b[1m\x1b[36m multiagents setup\x1b[0m
67
+ \x1b[90m Configure MCP + detect agents\x1b[0m
47
68
  \x1b[90m ─────────────────────────────────\x1b[0m
48
69
  `);
49
70
 
50
- // 2. Detect installed agents
71
+ // 1. Detect agents
51
72
  console.log("\x1b[1mDetecting installed agents...\x1b[0m\n");
52
- const agents: { type: AgentType; name: string; cmd: string; info: ReturnType<typeof detectAgent> }[] = [
53
- { type: "claude", name: "Claude Code", cmd: "claude", info: detectAgent("claude") },
54
- { type: "codex", name: "Codex CLI", cmd: "codex", info: detectAgent("codex") },
55
- { type: "gemini", name: "Gemini CLI", cmd: "gemini", info: detectAgent("gemini") },
73
+ const agents = [
74
+ { name: "Claude Code", cmd: "claude", info: detectAgent("claude") },
75
+ { name: "Codex CLI", cmd: "codex", info: detectAgent("codex") },
76
+ { name: "Gemini CLI", cmd: "gemini", info: detectAgent("gemini") },
56
77
  ];
57
78
 
58
79
  for (const a of agents) {
@@ -61,197 +82,61 @@ export async function setup(): Promise<void> {
61
82
  console.log(` ${icon} ${a.name}${ver}`);
62
83
  }
63
84
 
64
- const available = agents.filter((a) => a.info.available);
85
+ const available = agents.filter(a => a.info.available);
65
86
  if (available.length === 0) {
66
- console.error("\n\x1b[31mNo supported agents found. Install at least one agent CLI first.\x1b[0m");
87
+ console.error("\n\x1b[31mNo supported agents found. Install at least one: claude, codex, or gemini.\x1b[0m");
67
88
  process.exit(1);
68
89
  }
69
90
 
70
- // 3. Prompt user to select agents
71
- console.log("\n\x1b[1mSelect agents to orchestrate:\x1b[0m\n");
72
- for (let i = 0; i < available.length; i++) {
73
- console.log(` ${i + 1}. ${available[i].name} (${available[i].cmd})`);
74
- }
75
- console.log(` a. All available agents`);
76
-
77
- const selection = await prompt("\nEnter numbers separated by commas, or 'a' for all", "a");
78
- let selected: typeof available;
79
- if (selection === "a" || selection === "A") {
80
- selected = available;
81
- } else {
82
- const indices = selection.split(",").map((s) => parseInt(s.trim(), 10) - 1);
83
- selected = indices
84
- .filter((i) => i >= 0 && i < available.length)
85
- .map((i) => available[i]);
86
- }
87
-
88
- if (selected.length === 0) {
89
- console.error("\n\x1b[31mNo agents selected.\x1b[0m");
90
- process.exit(1);
91
- }
92
- console.log(`\nSelected: ${selected.map((a) => a.name).join(", ")}`);
93
-
94
- // 4. Prompt for working directory
95
- const projectDir = await prompt("\nProject directory", process.cwd());
96
- const resolvedDir = path.resolve(expandHome(projectDir));
97
- if (!fs.existsSync(resolvedDir)) {
98
- console.error(`\n\x1b[31mDirectory does not exist: ${resolvedDir}\x1b[0m`);
99
- process.exit(1);
100
- }
101
-
102
- // 5. Prompt for session name
103
- const dirName = path.basename(resolvedDir);
104
- const sessionName = await prompt("Session name", dirName);
105
- const sessionId = slugify(sessionName);
106
-
107
- // 6. Configure each selected agent's MCP server
91
+ // 2. Install global MCP config
108
92
  console.log("\n\x1b[1mConfiguring MCP servers...\x1b[0m\n");
93
+ const { installMcpSilent } = await import("./install-mcp.ts");
94
+ await installMcpSilent();
109
95
 
110
- const cliPath = path.resolve(import.meta.dir, "..");
111
-
112
- for (const agent of selected) {
113
- try {
114
- switch (agent.type) {
115
- case "claude":
116
- await configureClaudeMcp(resolvedDir, cliPath);
117
- break;
118
- case "codex":
119
- await configureCodexMcp(resolvedDir, cliPath);
120
- break;
121
- case "gemini":
122
- await configureGeminiMcp(cliPath);
123
- break;
124
- }
125
- console.log(` \x1b[32m✔\x1b[0m ${agent.name} MCP configured`);
126
- } catch (e) {
127
- console.error(` \x1b[31m✗\x1b[0m ${agent.name}: ${e instanceof Error ? e.message : String(e)}`);
128
- }
129
- }
130
-
131
- // 7. Start broker
96
+ // 3. Start broker
132
97
  console.log("\n\x1b[1mStarting broker...\x1b[0m");
133
98
  const client = new BrokerClient(BROKER_URL);
134
99
  let brokerAlive = await client.isAlive();
135
100
  if (!brokerAlive) {
136
- const proc = Bun.spawn(["bun", path.resolve(cliPath, "broker.ts")], {
137
- stdio: ["ignore", "ignore", "ignore"],
138
- });
101
+ const brokerBin = findBrokerBinary();
102
+ const proc = Bun.spawn([brokerBin], { stdio: ["ignore", "ignore", "ignore"] });
139
103
  proc.unref();
140
104
  for (let i = 0; i < 30; i++) {
141
105
  if (await client.isAlive()) { brokerAlive = true; break; }
142
106
  await Bun.sleep(200);
143
107
  }
144
108
  }
145
- if (!brokerAlive) {
146
- console.error(" \x1b[31m✗\x1b[0m Broker failed to start");
147
- process.exit(1);
148
- }
149
- console.log(` \x1b[32m✔\x1b[0m Broker running on ${BROKER_URL}`);
150
-
151
- // 8. Create session
152
- console.log("\n\x1b[1mCreating session...\x1b[0m");
153
- const gitRoot = await getGitRoot(resolvedDir);
154
- try {
155
- await client.createSession({
156
- id: sessionId,
157
- name: sessionName,
158
- project_dir: resolvedDir,
159
- git_root: gitRoot,
160
- });
161
- console.log(` \x1b[32m✔\x1b[0m Session "${sessionName}" (${sessionId}) created`);
162
- } catch (e) {
163
- const msg = e instanceof Error ? e.message : String(e);
164
- if (msg.includes("409") || msg.includes("UNIQUE") || msg.includes("already")) {
165
- console.log(` \x1b[33m!\x1b[0m Session "${sessionId}" already exists, reusing`);
166
- } else {
167
- throw e;
168
- }
109
+ if (brokerAlive) {
110
+ console.log(` \x1b[32m✔\x1b[0m Broker running on ${BROKER_URL}`);
111
+ } else {
112
+ console.log(` \x1b[33m!\x1b[0m Broker not started — will auto-start when agents connect`);
169
113
  }
170
114
 
171
- // 9. Write session.json
172
- const sessionDir = path.join(resolvedDir, SESSION_DIR);
173
- if (!fs.existsSync(sessionDir)) fs.mkdirSync(sessionDir, { recursive: true });
174
-
175
- const sessionFile: SessionFile = {
176
- session_id: sessionId,
177
- created_at: new Date().toISOString(),
178
- broker_port: BROKER_PORT,
179
- };
180
- await Bun.write(path.join(resolvedDir, SESSION_FILE), JSON.stringify(sessionFile, null, 2));
181
- console.log(` \x1b[32m✔\x1b[0m Wrote ${SESSION_FILE}`);
182
-
183
- // 10. Print next steps
115
+ // 4. Done
184
116
  console.log(`
185
117
  \x1b[1m\x1b[32mSetup complete!\x1b[0m
186
118
 
187
- \x1b[1mNext steps:\x1b[0m
188
- 1. Open your agents in the project directory:
189
- \x1b[90mcd ${resolvedDir}\x1b[0m
190
- ${selected.map((a) => ` \x1b[90m${a.cmd}\x1b[0m`).join("\n")}
191
-
192
- 2. Each agent will auto-connect to the session via MCP.
193
-
194
- 3. Monitor with the dashboard:
195
- \x1b[90mmultiagents dashboard\x1b[0m
196
-
197
- 4. Or use the orchestrator for automated coordination:
198
- \x1b[90mmultiagents orchestrator\x1b[0m
119
+ \x1b[1mUsage:\x1b[0m
120
+ 1. Restart Claude Code to load the multiagents tools.
121
+ 2. In Claude Code, ask it to use the multiagents tools.
122
+ 3. Or use the orchestrator to create a team:
123
+ \x1b[90mmultiagents create-team --project /path/to/project\x1b[0m
124
+
125
+ \x1b[1mAvailable commands:\x1b[0m
126
+ \x1b[90mmultiagents dashboard\x1b[0m Live monitoring
127
+ \x1b[90mmultiagents status\x1b[0m Broker health + peers
128
+ \x1b[90mmultiagents peers\x1b[0m List connected agents
129
+ \x1b[90mmultiagents install-mcp\x1b[0m Reconfigure MCP if needed
199
130
  `);
200
131
  }
201
132
 
202
- // --- Agent MCP configuration ---
203
-
204
- async function configureClaudeMcp(projectDir: string, cliPath: string): Promise<void> {
205
- // Write project-level .mcp.json
206
- const mcpPath = path.join(projectDir, ".mcp.json");
207
- let config: Record<string, unknown> = {};
208
- try {
209
- const existing = await Bun.file(mcpPath).text();
210
- config = JSON.parse(existing);
211
- } catch { /* file doesn't exist */ }
212
-
213
- const mcpServers = (config.mcpServers as Record<string, unknown>) ?? {};
214
- mcpServers["multiagents"] = {
215
- command: "bun",
216
- args: [path.resolve(cliPath, "cli.ts"), "mcp-server", "--agent-type", "claude"],
217
- };
218
- config.mcpServers = mcpServers;
219
- await Bun.write(mcpPath, JSON.stringify(config, null, 2));
220
- }
221
-
222
- async function configureCodexMcp(projectDir: string, cliPath: string): Promise<void> {
223
- // Write .codex/config.toml
224
- const codexDir = path.join(projectDir, ".codex");
225
- if (!fs.existsSync(codexDir)) fs.mkdirSync(codexDir, { recursive: true });
226
-
227
- const tomlPath = path.join(codexDir, "config.toml");
228
- let existing = "";
229
- try { existing = await Bun.file(tomlPath).text(); } catch { /* ok */ }
230
-
231
- // Remove any existing multiagents section
232
- existing = existing.replace(/\[mcp_servers\.multiagents\][\s\S]*?(?=\n\[|$)/, "").trim();
233
-
234
- const entry = `\n\n[mcp_servers.multiagents]\ncommand = "bun"\nargs = [${JSON.stringify(path.resolve(cliPath, "cli.ts"))}, "mcp-server", "--agent-type", "codex"]\n`;
235
- await Bun.write(tomlPath, existing + entry);
236
- }
237
-
238
- async function configureGeminiMcp(cliPath: string): Promise<void> {
239
- // Write ~/.gemini/settings.json
240
- const geminiDir = expandHome("~/.gemini");
241
- if (!fs.existsSync(geminiDir)) fs.mkdirSync(geminiDir, { recursive: true });
242
-
243
- const settingsPath = path.join(geminiDir, "settings.json");
244
- let config: Record<string, unknown> = {};
133
+ function findBrokerBinary(): string {
245
134
  try {
246
- const existing = await Bun.file(settingsPath).text();
247
- config = JSON.parse(existing);
135
+ const which = Bun.spawnSync(["which", "multiagents-broker"]);
136
+ const found = new TextDecoder().decode(which.stdout).trim();
137
+ if (found) return found;
248
138
  } catch { /* ok */ }
249
-
250
- const mcpServers = (config.mcpServers as Record<string, unknown>) ?? {};
251
- mcpServers["multiagents"] = {
252
- command: "bun",
253
- args: [path.resolve(cliPath, "cli.ts"), "mcp-server", "--agent-type", "gemini"],
254
- };
255
- config.mcpServers = mcpServers;
256
- await Bun.write(settingsPath, JSON.stringify(config, null, 2));
139
+ const bun = path.join(os.homedir(), ".bun", "bin", "multiagents-broker");
140
+ if (fs.existsSync(bun)) return bun;
141
+ return "multiagents-broker";
257
142
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multiagents",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Multi-agent orchestration platform for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "module": "index.ts",
6
6
  "type": "module",
@@ -1,105 +1,16 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
3
  * Post-install script: auto-configures MCP servers for Claude Code.
4
- *
5
- * Adds multiagents and multiagents-orch to ~/.claude/.mcp.json
6
- * so Claude Code can discover the tools without manual configuration.
7
- *
8
- * Safe: only adds entries if they don't already exist. Never overwrites.
4
+ * Delegates to the same logic as `multiagents install-mcp`.
5
+ * If it fails, prints fallback instructions — never breaks the install.
9
6
  */
10
7
 
11
- import * as fs from "node:fs";
12
- import * as path from "node:path";
13
- import * as os from "node:os";
14
-
15
- const HOME = os.homedir();
16
- const CLAUDE_DIR = path.join(HOME, ".claude");
17
- const MCP_JSON = path.join(CLAUDE_DIR, ".mcp.json");
18
-
19
- // Use installed binary names — works regardless of install location
20
- function findBinary(name: string): string {
21
- try {
22
- const which = Bun.spawnSync(["which", name]);
23
- const found = new TextDecoder().decode(which.stdout).trim();
24
- if (found) return found;
25
- } catch { /* ok */ }
26
- const defaultPath = path.join(HOME, ".bun", "bin", name);
27
- if (fs.existsSync(defaultPath)) return defaultPath;
28
- return name; // fallback
29
- }
30
-
31
- const SERVER_BIN = findBinary("multiagents-server");
32
- const ORCH_BIN = findBinary("multiagents-orch");
33
-
34
8
  try {
35
- // Ensure ~/.claude/ exists
36
- if (!fs.existsSync(CLAUDE_DIR)) {
37
- fs.mkdirSync(CLAUDE_DIR, { recursive: true });
38
- }
39
-
40
- // Read or create .mcp.json
41
- let config: { mcpServers: Record<string, unknown> } = { mcpServers: {} };
42
- if (fs.existsSync(MCP_JSON)) {
43
- try {
44
- config = JSON.parse(fs.readFileSync(MCP_JSON, "utf-8"));
45
- if (!config.mcpServers) config.mcpServers = {};
46
- } catch {
47
- // Corrupted file — back up and recreate
48
- fs.copyFileSync(MCP_JSON, MCP_JSON + ".bak");
49
- config = { mcpServers: {} };
50
- }
51
- }
52
-
53
- let changed = false;
54
-
55
- // Add multiagents MCP server (using installed binary names)
56
- if (!config.mcpServers["multiagents"]) {
57
- config.mcpServers["multiagents"] = {
58
- command: SERVER_BIN,
59
- args: [],
60
- };
61
- changed = true;
62
- }
63
-
64
- // Add orchestrator MCP server
65
- if (!config.mcpServers["multiagents-orch"]) {
66
- config.mcpServers["multiagents-orch"] = {
67
- command: ORCH_BIN,
68
- args: [],
69
- };
70
- changed = true;
71
- }
72
-
73
- if (changed) {
74
- fs.writeFileSync(MCP_JSON, JSON.stringify(config, null, 2) + "\n");
75
- console.log("[multiagents] MCP servers configured in ~/.claude/.mcp.json");
76
- } else {
77
- console.log("[multiagents] MCP servers already configured in .mcp.json");
78
- }
79
-
80
- // Also enable in settings.json
81
- const SETTINGS_JSON = path.join(CLAUDE_DIR, "settings.json");
82
- if (fs.existsSync(SETTINGS_JSON)) {
83
- try {
84
- const settings = JSON.parse(fs.readFileSync(SETTINGS_JSON, "utf-8"));
85
- const enabled: string[] = settings.enabledMcpjsonServers ?? [];
86
- let settingsChanged = false;
87
- if (!enabled.includes("multiagents")) { enabled.push("multiagents"); settingsChanged = true; }
88
- if (!enabled.includes("multiagents-orch")) { enabled.push("multiagents-orch"); settingsChanged = true; }
89
- if (settingsChanged) {
90
- settings.enabledMcpjsonServers = enabled;
91
- fs.writeFileSync(SETTINGS_JSON, JSON.stringify(settings, null, 2) + "\n");
92
- console.log("[multiagents] Enabled in ~/.claude/settings.json");
93
- }
94
- } catch {
95
- // Don't fail install over settings.json
96
- }
97
- }
98
-
9
+ const { installMcpSilent } = await import("../cli/install-mcp.ts");
10
+ await installMcpSilent();
99
11
  console.log("[multiagents] Restart Claude Code to pick up the new tools.");
100
12
  console.log("[multiagents] If tools don't appear, run: multiagents install-mcp");
101
13
  } catch (e) {
102
- // Postinstall should never fail the install
103
14
  console.error(`[multiagents] postinstall warning: ${e instanceof Error ? e.message : String(e)}`);
104
15
  console.error("[multiagents] Run 'multiagents install-mcp' to configure manually.");
105
16
  }
package/.mcp.json DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "agent-peers": {
4
- "command": "/Users/armanandreasyan/.bun/bin/bun",
5
- "args": ["/Users/armanandreasyan/Documents/multi-agent-peers/server.ts"]
6
- },
7
- "agent-peers-orchestrator": {
8
- "command": "/Users/armanandreasyan/.bun/bin/bun",
9
- "args": ["/Users/armanandreasyan/Documents/multi-agent-peers/orchestrator/orchestrator-server.ts"]
10
- }
11
- }
12
- }