meshwire 0.1.3 → 0.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meshwire",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "CLI and MCP tools for the MeshWire multi-agent messaging service",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -11,7 +11,7 @@ export async function cmdStatus() {
11
11
  if (!config.token) {
12
12
  console.log(chalk.yellow(' Not configured.'));
13
13
  console.log(chalk.dim(' Run `meshwire init` to set up your token and mesh.\n'));
14
- process.exit(0); // not configured is not an error
14
+ process.exit(0);
15
15
  }
16
16
 
17
17
  // Print config
@@ -16,7 +16,7 @@ const EXTENSION_FILE = join(EXTENSION_DIR, 'meshwire.mjs');
16
16
 
17
17
  // The generated extension template
18
18
  function buildExtensionSource({ meshwireUrl }) {
19
- return `// MeshWire Copilot CLI Extension
19
+ return `// MeshWire ΓÇö Copilot CLI Extension
20
20
  // Auto-generated by: meshwire init --harness copilot
21
21
  // Reads credentials from ~/.meshwire/credentials.json
22
22
  // Reads workspace mesh from .mesh.json in the current directory
@@ -61,7 +61,7 @@ async function api(path, method = 'GET', body = null) {
61
61
  return res.json();
62
62
  }
63
63
 
64
- // ─── Tool Definitions ────────────────────────────────────────────────────────
64
+ // ΓöÇΓöÇΓöÇ Tool Definitions ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
65
65
 
66
66
  export const tools = [
67
67
  {
@@ -122,6 +122,31 @@ export const tools = [
122
122
  },
123
123
  },
124
124
 
125
+ {
126
+ name: 'mesh_reply_to_message',
127
+ description: 'Reply to a specific message in the mesh. Sends the reply to the original sender and links it via metadata.reply_to.',
128
+ parameters: {
129
+ type: 'object',
130
+ properties: {
131
+ message_id: { type: 'integer', description: 'message_id of the original message to reply to' },
132
+ content: { type: 'string', description: 'Reply content (max 10KB)' },
133
+ },
134
+ required: ['message_id', 'content'],
135
+ },
136
+ async execute({ message_id, content }) {
137
+ const creds = loadCreds();
138
+ const meshJson = loadMeshJson();
139
+ if (!meshJson?.mesh_id) throw new Error('No mesh configured. Add .mesh.json to this workspace.');
140
+ const sender_id = creds?.agentId || globalThis.__meshwire_agent_id__ || 'copilot-cli';
141
+ const reply = await api(
142
+ '/mesh/{meshId}/messages/' + message_id + '/reply',
143
+ 'POST',
144
+ { sender_id, content }
145
+ );
146
+ return { sent: true, reply_id: reply.message_id, reply_to: message_id, to: reply.recipient_id };
147
+ },
148
+ },
149
+
125
150
  {
126
151
  name: 'mesh_list_agents',
127
152
  description: 'List all agents currently registered in this workspace mesh.',
@@ -163,10 +188,10 @@ export const tools = [
163
188
  },
164
189
  ];
165
190
 
166
- // ─── Hooks ───────────────────────────────────────────────────────────────────
191
+ // ΓöÇΓöÇΓöÇ Hooks ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
167
192
 
168
193
  export const hooks = {
169
- // Called on session start register this agent in the mesh
194
+ // Called on session start ΓÇö register this agent in the mesh
170
195
  async onSessionStart({ agentName } = {}) {
171
196
  const creds = loadCreds();
172
197
  const meshJson = loadMeshJson();
@@ -190,7 +215,7 @@ export const hooks = {
190
215
  }
191
216
  },
192
217
 
193
- // Called periodically keep heartbeat alive
218
+ // Called periodically ΓÇö keep heartbeat alive
194
219
  async onHeartbeat() {
195
220
  const creds = loadCreds();
196
221
  const meshJson = loadMeshJson();
@@ -203,11 +228,11 @@ export const hooks = {
203
228
  }
204
229
 
205
230
  export async function setupCopilot({ meshId, agentName, meshwireUrl, workspaceName }) {
206
- console.log('\n' + chalk.bold('⚙️ Setting up Copilot CLI harness') + '\n');
231
+ console.log('\n' + chalk.bold('⚙️ Setting up Copilot CLI harness') + '\n');
207
232
 
208
233
  const creds = readCredentials();
209
234
  if (!creds?.token) {
210
- console.error(chalk.red(' Not authenticated. Run `meshwire login` first.\n'));
235
+ console.error(chalk.red(' Γ£ù Not authenticated. Run `meshwire login` first.\n'));
211
236
  process.exit(1);
212
237
  }
213
238
 
@@ -221,12 +246,12 @@ export async function setupCopilot({ meshId, agentName, meshwireUrl, workspaceNa
221
246
  };
222
247
 
223
248
  if (!meshJsonData.mesh_id) {
224
- console.error(chalk.red(' No mesh ID. Create a mesh first: meshwire mesh create\n'));
249
+ console.error(chalk.red(' Γ£ù No mesh ID. Create a mesh first: meshwire mesh create\n'));
225
250
  process.exit(1);
226
251
  }
227
252
 
228
253
  writeMeshJson(meshJsonData);
229
- console.log(chalk.green(' .mesh.json written'));
254
+ console.log(chalk.green(' Γ£ô .mesh.json written'));
230
255
  console.log(chalk.dim(` mesh_id: ${meshJsonData.mesh_id}`));
231
256
  console.log(chalk.dim(` agent_name: ${meshJsonData.agent_name}`));
232
257
  console.log(chalk.dim(` harness: copilot`));
@@ -235,7 +260,7 @@ export async function setupCopilot({ meshId, agentName, meshwireUrl, workspaceNa
235
260
  mkdirSync(EXTENSION_DIR, { recursive: true });
236
261
  const source = buildExtensionSource({ meshwireUrl: meshwireUrl || 'https://meshwire.io' });
237
262
  writeFileSync(EXTENSION_FILE, source, 'utf8');
238
- console.log(chalk.green(`\n Extension installed at ${EXTENSION_FILE}`));
263
+ console.log(chalk.green(`\n Γ£ô Extension installed at ${EXTENSION_FILE}`));
239
264
 
240
265
  // 3. Register the agent in the mesh now
241
266
  console.log(chalk.dim('\n Registering agent in mesh...'));
@@ -247,19 +272,19 @@ export async function setupCopilot({ meshId, agentName, meshwireUrl, workspaceNa
247
272
  workspace: meshJsonData.workspace_name,
248
273
  metadata: { platform: 'copilot-cli', harness: 'meshwire' },
249
274
  });
250
- console.log(chalk.green(` Registered as ${agent.name} (${agent.agent_id})`));
275
+ console.log(chalk.green(` Γ£ô Registered as ${agent.name} (${agent.agent_id})`));
251
276
  } catch (err) {
252
- console.log(chalk.yellow(` Could not register now: ${err.message}`));
277
+ console.log(chalk.yellow(` ΓÜá Could not register now: ${err.message}`));
253
278
  console.log(chalk.dim(' The extension will auto-register on next Copilot CLI session.'));
254
279
  }
255
280
 
256
281
  // 4. Print summary
257
- console.log('\n' + chalk.bold.green(' Copilot harness ready!\n'));
282
+ console.log('\n' + chalk.bold.green(' ✅ Copilot harness ready!\n'));
258
283
  console.log(chalk.dim(' The extension provides these tools in every Copilot session:'));
259
- console.log(chalk.cyan(' mesh_send_message') + chalk.dim(' broadcast or target a specific agent'));
260
- console.log(chalk.cyan(' mesh_get_messages') + chalk.dim(' poll for new messages'));
261
- console.log(chalk.cyan(' mesh_list_agents') + chalk.dim(' discover agents in the mesh'));
262
- console.log(chalk.cyan(' mesh_status') + chalk.dim(' check connection health'));
284
+ console.log(chalk.cyan(' mesh_send_message') + chalk.dim(' ΓÇö broadcast or target a specific agent'));
285
+ console.log(chalk.cyan(' mesh_get_messages') + chalk.dim(' ΓÇö poll for new messages'));
286
+ console.log(chalk.cyan(' mesh_list_agents') + chalk.dim(' ΓÇö discover agents in the mesh'));
287
+ console.log(chalk.cyan(' mesh_status') + chalk.dim(' ΓÇö check connection health'));
263
288
  console.log('');
264
289
  console.log(chalk.dim(' The .mesh.json file in this repo defines which mesh Copilot connects to.'));
265
290
  console.log(chalk.dim(' Commit .mesh.json so your teammates auto-join the same mesh.\n'));
package/src/mcp/server.js CHANGED
@@ -1,20 +1,20 @@
1
- // meshwire mcp MCP stdio server for Copilot CLI and MCP-compatible agents
1
+ // meshwire mcp ΓÇö MCP stdio server for Copilot CLI and MCP-compatible agents
2
2
  // Starts an MCP server over stdio that exposes MeshWire tools.
3
3
  // Usage: meshwire mcp --mesh <meshId> --agent <name>
4
4
  //
5
5
  // Tool inventory:
6
- // meshwire_send_message send a message to the mesh
7
- // meshwire_get_messages long-poll for incoming messages
8
- // meshwire_register_agent register as an agent (auto-called on start)
9
- // meshwire_list_agents list agents in the mesh
10
- // meshwire_heartbeat send heartbeat to stay active
11
- // meshwire_mesh_info get mesh metadata
6
+ // meshwire_send_message ΓÇö send a message to the mesh
7
+ // meshwire_get_messages ΓÇö long-poll for incoming messages
8
+ // meshwire_register_agent ΓÇö register as an agent (auto-called on start)
9
+ // meshwire_list_agents ΓÇö list agents in the mesh
10
+ // meshwire_heartbeat ΓÇö send heartbeat to stay active
11
+ // meshwire_mesh_info ΓÇö get mesh metadata
12
12
 
13
13
  import chalk from 'chalk';
14
14
  import { readConfig, writeConfig } from '../config.js';
15
15
  import { MeshWireClient } from '../api.js';
16
16
 
17
- // ─── MCP Protocol Helpers ─────────────────────────────────────────────────────
17
+ // ΓöÇΓöÇΓöÇ MCP Protocol Helpers ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
18
18
 
19
19
  function mcpResponse(id, result) {
20
20
  return JSON.stringify({ jsonrpc: '2.0', id, result });
@@ -28,7 +28,7 @@ function mcpNotification(method, params) {
28
28
  return JSON.stringify({ jsonrpc: '2.0', method, params });
29
29
  }
30
30
 
31
- // ─── Tool Definitions ─────────────────────────────────────────────────────────
31
+ // ΓöÇΓöÇΓöÇ Tool Definitions ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
32
32
 
33
33
  function buildTools(meshId) {
34
34
  return [
@@ -57,6 +57,18 @@ function buildTools(meshId) {
57
57
  },
58
58
  },
59
59
  },
60
+ {
61
+ name: 'meshwire_reply_to_message',
62
+ description: `Reply to a specific message in mesh '${meshId}'. The reply is routed to the original sender and tagged with metadata.reply_to.`,
63
+ inputSchema: {
64
+ type: 'object',
65
+ properties: {
66
+ message_id: { type: 'integer', description: 'message_id of the original message' },
67
+ content: { type: 'string', description: 'Reply content (max 10KB)' },
68
+ },
69
+ required: ['message_id', 'content'],
70
+ },
71
+ },
60
72
  {
61
73
  name: 'meshwire_list_agents',
62
74
  description: `List all agents currently registered in mesh '${meshId}'.`,
@@ -75,7 +87,7 @@ function buildTools(meshId) {
75
87
  ];
76
88
  }
77
89
 
78
- // ─── MCP Server ───────────────────────────────────────────────────────────────
90
+ // ΓöÇΓöÇΓöÇ MCP Server ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
79
91
 
80
92
  export async function cmdMcp(opts) {
81
93
  const config = readConfig();
@@ -106,7 +118,7 @@ export async function cmdMcp(opts) {
106
118
  writeConfig({ agentId, agentName });
107
119
  process.stderr.write(`meshwire-mcp: registered as ${agentName} (${agentId})\n`);
108
120
  } catch (err) {
109
- process.stderr.write(`meshwire-mcp: agent registration failed ${err.message}\n`);
121
+ process.stderr.write(`meshwire-mcp: agent registration failed ΓÇö ${err.message}\n`);
110
122
  }
111
123
 
112
124
  // Heartbeat every 20s
@@ -119,7 +131,7 @@ export async function cmdMcp(opts) {
119
131
  process.on('SIGINT', () => { clearInterval(hbInterval); process.exit(0); });
120
132
  process.on('SIGTERM', () => { clearInterval(hbInterval); process.exit(0); });
121
133
 
122
- // MCP stdio protocol read JSON-RPC from stdin, write to stdout
134
+ // MCP stdio protocol ΓÇö read JSON-RPC from stdin, write to stdout
123
135
  process.stdin.setEncoding('utf8');
124
136
  let buf = '';
125
137
 
@@ -137,7 +149,7 @@ export async function cmdMcp(opts) {
137
149
  const response = await handleMcpMessage(msg, { client, meshId, agentId, agentName });
138
150
  if (response) process.stdout.write(response + '\n');
139
151
  } catch (err) {
140
- process.stderr.write(`meshwire-mcp: parse error ${err.message}\n`);
152
+ process.stderr.write(`meshwire-mcp: parse error ΓÇö ${err.message}\n`);
141
153
  }
142
154
  }
143
155
  });
@@ -149,7 +161,7 @@ async function handleMcpMessage(msg, { client, meshId, agentId }) {
149
161
  const { id, method, params } = msg;
150
162
 
151
163
  switch (method) {
152
- // ── Capability negotiation ──────────────────────────────────
164
+ // ΓöÇΓöÇ Capability negotiation ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
153
165
  case 'initialize':
154
166
  return mcpResponse(id, {
155
167
  protocolVersion: '2024-11-05',
@@ -160,11 +172,11 @@ async function handleMcpMessage(msg, { client, meshId, agentId }) {
160
172
  case 'notifications/initialized':
161
173
  return null; // Notification, no response
162
174
 
163
- // ── Tool listing ────────────────────────────────────────────
175
+ // ΓöÇΓöÇ Tool listing ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
164
176
  case 'tools/list':
165
177
  return mcpResponse(id, { tools: buildTools(meshId) });
166
178
 
167
- // ── Tool execution ──────────────────────────────────────────
179
+ // ΓöÇΓöÇ Tool execution ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
168
180
  case 'tools/call': {
169
181
  const { name, arguments: args = {} } = params;
170
182
  try {
@@ -202,20 +214,30 @@ async function executeTool(name, args, { client, meshId, agentId }) {
202
214
  });
203
215
  if (count === 0) return 'No new messages.';
204
216
  return messages.map((m) =>
205
- `[${m.message_id}] from:${m.sender_id} to:${m.recipient_id} ${m.content}`
217
+ `[${m.message_id}] from:${m.sender_id} to:${m.recipient_id} ΓÇö ${m.content}`
206
218
  ).join('\n');
207
219
  }
208
220
 
221
+ case 'meshwire_reply_to_message': {
222
+ if (!args.message_id) throw new Error('message_id is required');
223
+ if (!args.content) throw new Error('content is required');
224
+ const reply = await client.replyToMessage(meshId, args.message_id, {
225
+ senderId: agentId,
226
+ content: args.content,
227
+ });
228
+ return `Reply sent (id: ${reply.message_id}) to ${reply.recipient_id} (in reply to ${args.message_id})`;
229
+ }
230
+
209
231
  case 'meshwire_list_agents': {
210
232
  const { agents, count } = await client.listAgents(meshId);
211
233
  if (count === 0) return 'No agents registered.';
212
234
  return agents.map((a) =>
213
- `${a.status === 'active' ? '' : ''} ${a.name} (${a.agent_id})`
235
+ `${a.status === 'active' ? 'ΓùÅ' : 'Γùï'} ${a.name} (${a.agent_id})`
214
236
  ).join('\n');
215
237
  }
216
238
 
217
239
  case 'meshwire_heartbeat': {
218
- if (!agentId) return 'No agent ID run meshwire init first.';
240
+ if (!agentId) return 'No agent ID ΓÇö run meshwire init first.';
219
241
  await client.heartbeat(meshId, agentId);
220
242
  return `Heartbeat sent (${new Date().toISOString()})`;
221
243
  }