@sym-bot/mesh-channel 0.1.18 → 0.1.20

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/bin/install.js CHANGED
@@ -1,199 +1,350 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * sym-mesh-channel install — interactive setup for the MCP server.
6
- *
7
- * Run: npx @sym-bot/mesh-channel init
8
- *
9
- * What it does:
10
- * 1. Detects the platform and the host name suggestion (claude-mac /
11
- * claude-win / claude-linux), or accepts an override.
12
- * 2. Resolves the absolute path to the installed server.js so Claude
13
- * Code can spawn it.
14
- * 3. Reads ~/.claude.json (the Claude Code settings file), backs it
15
- * up, adds an `mcpServers` entry under the current project for
16
- * `claude-sym-mesh`, atomically writes the result.
17
- * 4. Prints the launch command including the Channels dev flag.
18
- *
19
- * Safety:
20
- * - Backs up ~/.claude.json to ~/.claude.json.bak-<timestamp> before
21
- * any write.
22
- * - Validates JSON parses round-trip before writing.
23
- * - Atomic via write-to-tmp + rename.
24
- * - Refuses to overwrite an existing claude-sym-mesh entry without
25
- * --force.
26
- *
27
- * Copyright (c) 2026 SYM.BOT Ltd. Apache 2.0 License.
28
- */
29
-
30
- const fs = require('fs');
31
- const path = require('path');
32
- const os = require('os');
33
-
34
- const args = process.argv.slice(2);
35
- const force = args.includes('--force');
36
- const isPostinstall = args.includes('--postinstall');
37
- const cmd = args.find((a) => !a.startsWith('--')) || 'init';
38
-
39
- if (cmd !== 'init') {
40
- process.stderr.write(`Unknown command: ${cmd}\nUsage: npx @sym-bot/mesh-channel init [--force]\n`);
41
- process.exit(1);
42
- }
43
-
44
- // ── Detect platform & defaults ────────────────────────────────────
45
-
46
- // Default: hostname-based identity, unique per machine. Prevents
47
- // the ghost-peer bug where two machines with the same default name
48
- // create phantom peers that absorb messages.
49
- const defaultNodeName = `claude-${os.hostname().toLowerCase().replace(/[^a-z0-9-]/g, '-')}`;
50
-
51
- // SYM_NODE_NAME from env wins over default
52
- const nodeName = process.env.SYM_NODE_NAME || defaultNodeName;
53
-
54
- // ── Resolve server.js path ────────────────────────────────────────
55
-
56
- // Resolve server.js from the installed package location. require.resolve
57
- // returns the actual installed path regardless of where postinstall runs
58
- // from (npm on Windows may run postinstall from a temp staging directory).
59
- let serverJsPath;
60
- try {
61
- serverJsPath = require.resolve('@sym-bot/mesh-channel/server.js');
62
- } catch {
63
- // Fallback for local development / cloned repo
64
- serverJsPath = path.resolve(__dirname, '..', 'server.js');
65
- }
66
- if (!fs.existsSync(serverJsPath)) {
67
- process.stderr.write(`ERROR: cannot find server.js at ${serverJsPath}\n`);
68
- process.stderr.write('This installer must be run from a published @sym-bot/mesh-channel package.\n');
69
- process.exit(1);
70
- }
71
-
72
- // ── Locate Claude Code settings file ──────────────────────────────
73
-
74
- const claudeJsonPath = path.join(os.homedir(), '.claude.json');
75
-
76
- if (!fs.existsSync(claudeJsonPath)) {
77
- if (isPostinstall) {
78
- // During postinstall, skip silently if Claude Code isn't installed yet
79
- console.log('sym-mesh-channel: ~/.claude.json not found run `sym-mesh-channel init` after installing Claude Code.');
80
- process.exit(0);
81
- }
82
- process.stderr.write(`ERROR: ${claudeJsonPath} not found.\n`);
83
- process.stderr.write('Claude Code does not appear to be installed (or has not been launched yet).\n');
84
- process.stderr.write('Install Claude Code from https://claude.com/code first, launch it once, then re-run this installer.\n');
85
- process.exit(1);
86
- }
87
-
88
- // ── Read and back up ──────────────────────────────────────────────
89
-
90
- let claudeJson;
91
- try {
92
- const raw = fs.readFileSync(claudeJsonPath, 'utf8');
93
- claudeJson = JSON.parse(raw);
94
- } catch (e) {
95
- process.stderr.write(`ERROR: ${claudeJsonPath} is not valid JSON: ${e.message}\n`);
96
- process.stderr.write('Refusing to overwrite a corrupt Claude Code settings file.\n');
97
- process.exit(1);
98
- }
99
-
100
- const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
101
- const backupPath = `${claudeJsonPath}.bak-${ts}`;
102
- fs.copyFileSync(claudeJsonPath, backupPath);
103
-
104
- // ── Find the MCP servers entry to insert into ───────────────────
105
- // Write to global mcpServers (available in all Claude Code sessions),
106
- // not project-scoped. A mesh node should be available everywhere.
107
-
108
- if (!claudeJson.mcpServers) claudeJson.mcpServers = {};
109
-
110
- // ── Refuse to overwrite without --force ──────────────────────────
111
-
112
- if (claudeJson.mcpServers['claude-sym-mesh'] && !force) {
113
- if (isPostinstall) {
114
- // During postinstall, silently skip if already configured
115
- console.log('sym-mesh-channel: already configured in ~/.claude.json (skipping)');
116
- process.exit(0);
117
- }
118
- process.stderr.write(`'claude-sym-mesh' is already configured in ~/.claude.json.\n`);
119
- process.stderr.write('Re-run with --force to overwrite, or remove the existing entry first.\n');
120
- process.exit(2);
121
- }
122
-
123
- // ── Build the entry ───────────────────────────────────────────────
124
-
125
- const entry = {
126
- command: 'node',
127
- args: [serverJsPath],
128
- env: {
129
- SYM_NODE_NAME: nodeName,
130
- // Explicitly blank the relay vars so the MCP doesn't inherit them
131
- // from the parent shell (e.g. ~/.zshrc exports). Claude Code's env
132
- // block is ADDITIVE — omitting a key doesn't remove it from the
133
- // child process. Setting to '' makes process.env.SYM_RELAY_URL
134
- // falsy in JS, so the SymNode skips the relay and runs LAN-only.
135
- //
136
- // To enable cross-network connectivity later, replace these empty
137
- // values with your relay URL and token (see README).
138
- SYM_RELAY_URL: '',
139
- SYM_RELAY_TOKEN: '',
140
- },
141
- };
142
-
143
- claudeJson.mcpServers['claude-sym-mesh'] = entry;
144
-
145
- // ── Atomic write ──────────────────────────────────────────────────
146
-
147
- const serialized = JSON.stringify(claudeJson, null, 2);
148
-
149
- // Validate round-trip parses
150
- try {
151
- JSON.parse(serialized);
152
- } catch (e) {
153
- process.stderr.write(`ERROR: serialization produced invalid JSON: ${e.message}\n`);
154
- process.stderr.write(`Backup is at ${backupPath} — your original file is unchanged.\n`);
155
- process.exit(1);
156
- }
157
-
158
- const tmpPath = `${claudeJsonPath}.tmp-${process.pid}`;
159
- try {
160
- fs.writeFileSync(tmpPath, serialized);
161
- fs.renameSync(tmpPath, claudeJsonPath);
162
- } catch (e) {
163
- // EBUSY on Windows when Claude Code has ~/.claude.json locked
164
- if (e.code === 'EBUSY' || e.code === 'EPERM') {
165
- try { fs.unlinkSync(tmpPath); } catch {}
166
- if (isPostinstall) {
167
- console.log('sym-mesh-channel: ~/.claude.json is locked (Claude Code may be running).');
168
- console.log('Run `sym-mesh-channel init` after quitting Claude Code.');
169
- process.exit(0);
170
- }
171
- process.stderr.write(`ERROR: ${claudeJsonPath} is locked — Claude Code may be running.\n`);
172
- process.stderr.write('Quit Claude Code, then re-run: sym-mesh-channel init\n');
173
- process.stderr.write(`Backup is at ${backupPath}\n`);
174
- process.exit(1);
175
- }
176
- throw e;
177
- }
178
-
179
- // ── Print next steps ──────────────────────────────────────────────
180
-
181
- const launchCmd = `claude --dangerously-load-development-channels server:claude-sym-mesh`;
182
-
183
- console.log(`
184
- sym-mesh-channel configured globally in ~/.claude.json
185
-
186
- Node name: ${nodeName}
187
- Server path: ${serverJsPath}
188
- Backup: ${backupPath}
189
-
190
- Launch Claude Code with the Channels flag:
191
-
192
- ${launchCmd}
193
-
194
- Inside Claude Code, verify:
195
-
196
- sym_status → node id, relay state, peer count
197
- sym_peers → discovered peers via Bonjour or relay
198
- sym_send "hello mesh" → broadcast to all peers
199
- `);
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * sym-mesh-channel install — interactive setup for the MCP server.
6
+ *
7
+ * Run: npx @sym-bot/mesh-channel init
8
+ *
9
+ * What it does:
10
+ * 1. Detects the platform and the host name suggestion (claude-mac /
11
+ * claude-win / claude-linux), or accepts an override.
12
+ * 2. Resolves the absolute path to the installed server.js so Claude
13
+ * Code can spawn it.
14
+ * 3. Reads ~/.claude.json (the Claude Code settings file), backs it
15
+ * up, adds an `mcpServers` entry under the current project for
16
+ * `claude-sym-mesh`, atomically writes the result.
17
+ * 4. Prints the launch command including the Channels dev flag.
18
+ *
19
+ * Safety:
20
+ * - Backs up ~/.claude.json to ~/.claude.json.bak-<timestamp> before
21
+ * any write.
22
+ * - Validates JSON parses round-trip before writing.
23
+ * - Atomic via write-to-tmp + rename.
24
+ * - Refuses to overwrite an existing claude-sym-mesh entry without
25
+ * --force.
26
+ *
27
+ * Copyright (c) 2026 SYM.BOT Ltd. Apache 2.0 License.
28
+ */
29
+
30
+ const fs = require('fs');
31
+ const path = require('path');
32
+ const os = require('os');
33
+
34
+ const args = process.argv.slice(2);
35
+ const force = args.includes('--force');
36
+ const isPostinstall = args.includes('--postinstall');
37
+ const isProject = args.includes('--project');
38
+ const cmd = args.find((a) => !a.startsWith('--')) || 'init';
39
+
40
+ if (cmd !== 'init') {
41
+ process.stderr.write(`Unknown command: ${cmd}\nUsage: sym-mesh-channel init [--project] [--force]\n`);
42
+ process.exit(1);
43
+ }
44
+
45
+ // --postinstall always runs global install (npm postinstall runs from
46
+ // npm's staging directory, not the user's project dir). If both flags
47
+ // are passed, the --project flag is ignored during postinstall.
48
+ const useProjectMode = isProject && !isPostinstall;
49
+
50
+ // ── Detect platform & defaults ────────────────────────────────────
51
+
52
+ // Default: hostname-based identity, unique per machine. Prevents
53
+ // the ghost-peer bug where two machines with the same default name
54
+ // create phantom peers that absorb messages.
55
+ const defaultNodeName = `claude-${os.hostname().toLowerCase().replace(/[^a-z0-9-]/g, '-')}`;
56
+
57
+ // SYM_NODE_NAME from env wins over default
58
+ const nodeName = process.env.SYM_NODE_NAME || defaultNodeName;
59
+
60
+ // ── Resolve server.js path ────────────────────────────────────────
61
+
62
+ // Resolve server.js from the installed package location. require.resolve
63
+ // returns the actual installed path regardless of where postinstall runs
64
+ // from (npm on Windows may run postinstall from a temp staging directory).
65
+ let serverJsPath;
66
+ try {
67
+ serverJsPath = require.resolve('@sym-bot/mesh-channel/server.js');
68
+ } catch {
69
+ // Fallback for local development / cloned repo
70
+ serverJsPath = path.resolve(__dirname, '..', 'server.js');
71
+ }
72
+ if (!fs.existsSync(serverJsPath)) {
73
+ process.stderr.write(`ERROR: cannot find server.js at ${serverJsPath}\n`);
74
+ process.stderr.write('This installer must be run from a published @sym-bot/mesh-channel package.\n');
75
+ process.exit(1);
76
+ }
77
+
78
+ // Shared timestamp for backup filenames
79
+ const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
80
+
81
+ // ── Project-scoped install (--project flag) ───────────────────────
82
+ // Writes <cwd>/.mcp.json + merges <cwd>/.claude/settings.local.json
83
+ // instead of touching ~/.claude.json. Use this when you want multiple
84
+ // Claude Code sessions on one machine to appear as distinct mesh peers
85
+ // (one per project), each with its own SYM_NODE_NAME. Project-level
86
+ // .mcp.json overrides the global ~/.claude.json mcpServers entry when
87
+ // Claude Code is launched from that directory.
88
+
89
+ if (useProjectMode) {
90
+ const projectDir = process.cwd();
91
+ const mcpJsonPath = path.join(projectDir, '.mcp.json');
92
+ const claudeDir = path.join(projectDir, '.claude');
93
+ const settingsLocalPath = path.join(claudeDir, 'settings.local.json');
94
+
95
+ // Read existing .mcp.json (if any)
96
+ let mcpJson = null;
97
+ if (fs.existsSync(mcpJsonPath)) {
98
+ try {
99
+ mcpJson = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8'));
100
+ } catch (e) {
101
+ process.stderr.write(`ERROR: ${mcpJsonPath} is not valid JSON: ${e.message}\n`);
102
+ process.stderr.write('Refusing to overwrite a corrupt file. Fix or remove it and retry.\n');
103
+ process.exit(1);
104
+ }
105
+ }
106
+ mcpJson = mcpJson || {};
107
+ if (!mcpJson.mcpServers) mcpJson.mcpServers = {};
108
+
109
+ // Refuse to overwrite an existing claude-sym-mesh entry without --force
110
+ if (mcpJson.mcpServers['claude-sym-mesh'] && !force) {
111
+ process.stderr.write(`'claude-sym-mesh' is already configured in ${mcpJsonPath}.\n`);
112
+ process.stderr.write('Re-run with --force to overwrite, or remove the existing entry first.\n');
113
+ process.exit(2);
114
+ }
115
+
116
+ // Build the MCP entry (identical shape to global mode)
117
+ const projectEntry = {
118
+ command: 'node',
119
+ args: [serverJsPath],
120
+ env: {
121
+ SYM_NODE_NAME: nodeName,
122
+ // Explicitly blank relay env vars — see comment on the global
123
+ // install path below for why.
124
+ SYM_RELAY_URL: '',
125
+ SYM_RELAY_TOKEN: '',
126
+ },
127
+ };
128
+
129
+ // Backup existing .mcp.json if present
130
+ let mcpBackupPath = null;
131
+ if (fs.existsSync(mcpJsonPath)) {
132
+ mcpBackupPath = `${mcpJsonPath}.bak-${ts}`;
133
+ fs.copyFileSync(mcpJsonPath, mcpBackupPath);
134
+ }
135
+
136
+ mcpJson.mcpServers['claude-sym-mesh'] = projectEntry;
137
+
138
+ // Atomic write .mcp.json
139
+ const mcpSerialized = JSON.stringify(mcpJson, null, 2) + '\n';
140
+ try { JSON.parse(mcpSerialized); } catch (e) {
141
+ process.stderr.write(`ERROR: serialization produced invalid JSON: ${e.message}\n`);
142
+ process.exit(1);
143
+ }
144
+ const mcpTmpPath = `${mcpJsonPath}.tmp-${process.pid}`;
145
+ fs.writeFileSync(mcpTmpPath, mcpSerialized);
146
+ fs.renameSync(mcpTmpPath, mcpJsonPath);
147
+
148
+ // Merge <projectDir>/.claude/settings.local.json. Claude Code gates
149
+ // loading of project-scoped MCP servers on the enabledMcpjsonServers
150
+ // allowlist in this file — without the merge, the .mcp.json we just
151
+ // wrote would not actually be loaded.
152
+ if (!fs.existsSync(claudeDir)) {
153
+ fs.mkdirSync(claudeDir, { recursive: true });
154
+ }
155
+
156
+ let existingSettings = null;
157
+ if (fs.existsSync(settingsLocalPath)) {
158
+ try {
159
+ existingSettings = JSON.parse(fs.readFileSync(settingsLocalPath, 'utf8'));
160
+ } catch (e) {
161
+ process.stderr.write(`ERROR: ${settingsLocalPath} is not valid JSON: ${e.message}\n`);
162
+ process.exit(1);
163
+ }
164
+ }
165
+
166
+ // Snapshot serialized form BEFORE mutating so the change-detection
167
+ // below can't be fooled by object aliasing (existingSettings and
168
+ // settings point at the same object after the `|| {}`).
169
+ const beforeSerialized = existingSettings ? JSON.stringify(existingSettings) : null;
170
+ const settings = existingSettings || {};
171
+
172
+ const enabled = new Set(Array.isArray(settings.enabledMcpjsonServers) ? settings.enabledMcpjsonServers : []);
173
+ enabled.add('claude-sym-mesh');
174
+ settings.enabledMcpjsonServers = Array.from(enabled);
175
+ settings.enableAllProjectMcpServers = true;
176
+
177
+ const afterSerialized = JSON.stringify(settings);
178
+ const settingsChanged = beforeSerialized !== afterSerialized;
179
+
180
+ let settingsBackupPath = null;
181
+ if (settingsChanged) {
182
+ if (existingSettings) {
183
+ settingsBackupPath = `${settingsLocalPath}.bak-${ts}`;
184
+ fs.copyFileSync(settingsLocalPath, settingsBackupPath);
185
+ }
186
+ const settingsSerialized = JSON.stringify(settings, null, 2) + '\n';
187
+ const settingsTmpPath = `${settingsLocalPath}.tmp-${process.pid}`;
188
+ fs.writeFileSync(settingsTmpPath, settingsSerialized);
189
+ fs.renameSync(settingsTmpPath, settingsLocalPath);
190
+ }
191
+
192
+ // Print next steps
193
+ const launchCmdProject = `claude --dangerously-load-development-channels server:claude-sym-mesh`;
194
+ const lines = [
195
+ '',
196
+ `✓ sym-mesh-channel configured for project: ${projectDir}`,
197
+ '',
198
+ ` Node name: ${nodeName}`,
199
+ ` Server path: ${serverJsPath}`,
200
+ ` Wrote: ${mcpJsonPath}`,
201
+ ];
202
+ if (mcpBackupPath) lines.push(` Backup: ${mcpBackupPath}`);
203
+ if (settingsChanged) {
204
+ lines.push(` Updated: ${settingsLocalPath}`);
205
+ if (settingsBackupPath) lines.push(` Backup: ${settingsBackupPath}`);
206
+ }
207
+ lines.push(
208
+ '',
209
+ 'Launch Claude Code from this directory:',
210
+ '',
211
+ ` ${launchCmdProject}`,
212
+ '',
213
+ 'Project-level .mcp.json overrides the global ~/.claude.json entry',
214
+ 'when Claude Code runs from this directory. To give each project its',
215
+ 'own mesh identity, run `sym-mesh-channel init --project` from each',
216
+ 'project root with a distinct SYM_NODE_NAME.',
217
+ '',
218
+ );
219
+ console.log(lines.join('\n'));
220
+ process.exit(0);
221
+ }
222
+
223
+ // ── Locate Claude Code settings file ──────────────────────────────
224
+
225
+ const claudeJsonPath = path.join(os.homedir(), '.claude.json');
226
+
227
+ if (!fs.existsSync(claudeJsonPath)) {
228
+ if (isPostinstall) {
229
+ // During postinstall, skip silently if Claude Code isn't installed yet
230
+ console.log('sym-mesh-channel: ~/.claude.json not found — run `sym-mesh-channel init` after installing Claude Code.');
231
+ process.exit(0);
232
+ }
233
+ process.stderr.write(`ERROR: ${claudeJsonPath} not found.\n`);
234
+ process.stderr.write('Claude Code does not appear to be installed (or has not been launched yet).\n');
235
+ process.stderr.write('Install Claude Code from https://claude.com/code first, launch it once, then re-run this installer.\n');
236
+ process.exit(1);
237
+ }
238
+
239
+ // ── Read and back up ──────────────────────────────────────────────
240
+
241
+ let claudeJson;
242
+ try {
243
+ const raw = fs.readFileSync(claudeJsonPath, 'utf8');
244
+ claudeJson = JSON.parse(raw);
245
+ } catch (e) {
246
+ process.stderr.write(`ERROR: ${claudeJsonPath} is not valid JSON: ${e.message}\n`);
247
+ process.stderr.write('Refusing to overwrite a corrupt Claude Code settings file.\n');
248
+ process.exit(1);
249
+ }
250
+
251
+ // `ts` was defined above, shared with project-mode install
252
+ const backupPath = `${claudeJsonPath}.bak-${ts}`;
253
+ fs.copyFileSync(claudeJsonPath, backupPath);
254
+
255
+ // ── Find the MCP servers entry to insert into ───────────────────
256
+ // Write to global mcpServers (available in all Claude Code sessions),
257
+ // not project-scoped. A mesh node should be available everywhere.
258
+
259
+ if (!claudeJson.mcpServers) claudeJson.mcpServers = {};
260
+
261
+ // ── Refuse to overwrite without --force ──────────────────────────
262
+
263
+ if (claudeJson.mcpServers['claude-sym-mesh'] && !force) {
264
+ if (isPostinstall) {
265
+ // During postinstall, silently skip if already configured
266
+ console.log('sym-mesh-channel: already configured in ~/.claude.json (skipping)');
267
+ process.exit(0);
268
+ }
269
+ process.stderr.write(`'claude-sym-mesh' is already configured in ~/.claude.json.\n`);
270
+ process.stderr.write('Re-run with --force to overwrite, or remove the existing entry first.\n');
271
+ process.exit(2);
272
+ }
273
+
274
+ // ── Build the entry ───────────────────────────────────────────────
275
+
276
+ const entry = {
277
+ command: 'node',
278
+ args: [serverJsPath],
279
+ env: {
280
+ SYM_NODE_NAME: nodeName,
281
+ // Explicitly blank the relay vars so the MCP doesn't inherit them
282
+ // from the parent shell (e.g. ~/.zshrc exports). Claude Code's env
283
+ // block is ADDITIVE — omitting a key doesn't remove it from the
284
+ // child process. Setting to '' makes process.env.SYM_RELAY_URL
285
+ // falsy in JS, so the SymNode skips the relay and runs LAN-only.
286
+ //
287
+ // To enable cross-network connectivity later, replace these empty
288
+ // values with your relay URL and token (see README).
289
+ SYM_RELAY_URL: '',
290
+ SYM_RELAY_TOKEN: '',
291
+ },
292
+ };
293
+
294
+ claudeJson.mcpServers['claude-sym-mesh'] = entry;
295
+
296
+ // ── Atomic write ──────────────────────────────────────────────────
297
+
298
+ const serialized = JSON.stringify(claudeJson, null, 2);
299
+
300
+ // Validate round-trip parses
301
+ try {
302
+ JSON.parse(serialized);
303
+ } catch (e) {
304
+ process.stderr.write(`ERROR: serialization produced invalid JSON: ${e.message}\n`);
305
+ process.stderr.write(`Backup is at ${backupPath} — your original file is unchanged.\n`);
306
+ process.exit(1);
307
+ }
308
+
309
+ const tmpPath = `${claudeJsonPath}.tmp-${process.pid}`;
310
+ try {
311
+ fs.writeFileSync(tmpPath, serialized);
312
+ fs.renameSync(tmpPath, claudeJsonPath);
313
+ } catch (e) {
314
+ // EBUSY on Windows when Claude Code has ~/.claude.json locked
315
+ if (e.code === 'EBUSY' || e.code === 'EPERM') {
316
+ try { fs.unlinkSync(tmpPath); } catch {}
317
+ if (isPostinstall) {
318
+ console.log('sym-mesh-channel: ~/.claude.json is locked (Claude Code may be running).');
319
+ console.log('Run `sym-mesh-channel init` after quitting Claude Code.');
320
+ process.exit(0);
321
+ }
322
+ process.stderr.write(`ERROR: ${claudeJsonPath} is locked — Claude Code may be running.\n`);
323
+ process.stderr.write('Quit Claude Code, then re-run: sym-mesh-channel init\n');
324
+ process.stderr.write(`Backup is at ${backupPath}\n`);
325
+ process.exit(1);
326
+ }
327
+ throw e;
328
+ }
329
+
330
+ // ── Print next steps ──────────────────────────────────────────────
331
+
332
+ const launchCmd = `claude --dangerously-load-development-channels server:claude-sym-mesh`;
333
+
334
+ console.log(`
335
+ ✓ sym-mesh-channel configured globally in ~/.claude.json
336
+
337
+ Node name: ${nodeName}
338
+ Server path: ${serverJsPath}
339
+ Backup: ${backupPath}
340
+
341
+ Launch Claude Code with the Channels flag:
342
+
343
+ ${launchCmd}
344
+
345
+ Inside Claude Code, verify:
346
+
347
+ sym_status → node id, relay state, peer count
348
+ sym_peers → discovered peers via Bonjour or relay
349
+ sym_send "hello mesh" → broadcast to all peers
350
+ `);
package/package.json CHANGED
@@ -1,28 +1,32 @@
1
- {
2
- "name": "@sym-bot/mesh-channel",
3
- "version": "0.1.18",
4
- "description": "MCP server — real-time agent-to-agent cognition for Claude Code remote teams via the SYM mesh.",
5
- "main": "server.js",
6
- "bin": {
7
- "sym-mesh-channel": "server.js"
8
- },
9
- "scripts": {
10
- "postinstall": "node bin/install.js init --postinstall"
11
- },
12
- "files": [
13
- "server.js",
14
- "bin/",
15
- "README.md",
16
- "CHANGELOG.md",
17
- "LICENSE"
18
- ],
19
- "dependencies": {
20
- "@modelcontextprotocol/sdk": "^1.12.1",
21
- "@sym-bot/sym": "^0.3.78"
22
- },
23
- "engines": {
24
- "node": ">=18"
25
- },
26
- "author": "SYM.BOT Ltd <info@sym.bot> (https://sym.bot)",
27
- "license": "Apache-2.0"
28
- }
1
+ {
2
+ "name": "@sym-bot/mesh-channel",
3
+ "version": "0.1.20",
4
+ "description": "MCP server — real-time agent-to-agent cognition for Claude Code remote teams via the SYM mesh.",
5
+ "main": "server.js",
6
+ "bin": {
7
+ "sym-mesh-channel": "server.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node test/plugin.test.js",
11
+ "postinstall": "node bin/install.js init --postinstall"
12
+ },
13
+ "files": [
14
+ "server.js",
15
+ "bin/",
16
+ ".claude-plugin/",
17
+ ".mcp.json",
18
+ "SECURITY.md",
19
+ "README.md",
20
+ "CHANGELOG.md",
21
+ "LICENSE"
22
+ ],
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.12.1",
25
+ "@sym-bot/sym": "^0.3.78"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "author": "SYM.BOT Ltd <info@sym.bot> (https://sym.bot)",
31
+ "license": "Apache-2.0"
32
+ }