replicas-mcp 0.1.6 → 0.1.7

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/dist/index.js CHANGED
@@ -24,8 +24,12 @@ function safeJsonParse(str, fallback) {
24
24
  function getStatusFromExitCode(exitCode) {
25
25
  return exitCode === 0 ? "completed" : "failed";
26
26
  }
27
- function findLastMessageByType(messages, type) {
28
- return messages.findLast((m) => m.type === type);
27
+ function parseShellOutput(raw) {
28
+ const exitCodeMatch = raw.match(/^Exit code: (\d+)/);
29
+ const exitCode = exitCodeMatch ? parseInt(exitCodeMatch[1], 10) : 0;
30
+ const outputIndex = raw.indexOf("Output:\n");
31
+ const output = outputIndex >= 0 ? raw.slice(outputIndex + "Output:\n".length) : raw;
32
+ return { exitCode, output };
29
33
  }
30
34
  function parsePatch(input) {
31
35
  const operations = [];
@@ -82,11 +86,12 @@ function parsePatch(input) {
82
86
  }
83
87
  function parseCodexEvents(events) {
84
88
  const messages = [];
89
+ const pendingCommands = /* @__PURE__ */ new Map();
85
90
  const pendingPatches = /* @__PURE__ */ new Map();
86
- events.forEach((event) => {
91
+ events.forEach((event, eventIndex) => {
87
92
  if (event.type === "event_msg" && event.payload?.type === "user_message") {
88
93
  messages.push({
89
- id: `user-${event.timestamp}`,
94
+ id: `user-${event.timestamp}-${eventIndex}`,
90
95
  type: "user",
91
96
  content: event.payload.message || "",
92
97
  timestamp: event.timestamp
@@ -94,7 +99,7 @@ function parseCodexEvents(events) {
94
99
  }
95
100
  if (event.type === "event_msg" && event.payload?.type === "agent_reasoning") {
96
101
  messages.push({
97
- id: `reasoning-${event.timestamp}-${messages.length}`,
102
+ id: `reasoning-${event.timestamp}-${eventIndex}-${messages.length}`,
98
103
  type: "reasoning",
99
104
  content: event.payload.text || "",
100
105
  status: "completed",
@@ -108,38 +113,40 @@ function parseCodexEvents(events) {
108
113
  const textContent = content.filter((c) => c.type === "output_text").map((c) => c.text || "").join("\n");
109
114
  if (textContent) {
110
115
  messages.push({
111
- id: `agent-${event.timestamp}`,
116
+ id: `agent-${event.timestamp}-${eventIndex}`,
112
117
  type: "agent",
113
118
  content: textContent,
114
119
  timestamp: event.timestamp
115
120
  });
116
121
  }
117
122
  }
118
- if (payloadType === "function_call" && event.payload?.name === "shell") {
123
+ if (payloadType === "function_call" && (event.payload?.name === "shell" || event.payload?.name === "shell_command")) {
124
+ const callId = event.payload.call_id;
119
125
  const args = safeJsonParse(event.payload.arguments || "{}", {});
120
126
  const command = Array.isArray(args.command) ? args.command.join(" ") : args.command || "";
121
- messages.push({
122
- id: `command-${event.timestamp}`,
127
+ const msg = {
128
+ id: `command-${callId || "no-call-id"}-${eventIndex}`,
123
129
  type: "command",
124
130
  command,
125
131
  output: "",
126
- // Will be filled by function_call_output
127
132
  status: "in_progress",
128
133
  timestamp: event.timestamp
129
- });
134
+ };
135
+ messages.push(msg);
136
+ if (callId) {
137
+ pendingCommands.set(callId, msg);
138
+ }
130
139
  }
131
140
  if (payloadType === "function_call_output") {
132
- const output = safeJsonParse(
133
- event.payload.output || "{}",
134
- {}
135
- );
136
- if (output.output !== void 0 && output.metadata) {
137
- const commandMsg = findLastMessageByType(messages, "command");
138
- if (commandMsg) {
139
- commandMsg.output = output.output || "";
140
- commandMsg.exitCode = output.metadata?.exit_code;
141
- commandMsg.status = getStatusFromExitCode(output.metadata?.exit_code);
142
- }
141
+ const callId = event.payload.call_id;
142
+ const rawOutput = event.payload.output || "";
143
+ const commandMsg = callId ? pendingCommands.get(callId) : void 0;
144
+ if (commandMsg) {
145
+ const { exitCode, output } = parseShellOutput(rawOutput);
146
+ commandMsg.output = output;
147
+ commandMsg.exitCode = exitCode;
148
+ commandMsg.status = getStatusFromExitCode(exitCode);
149
+ pendingCommands.delete(callId);
143
150
  }
144
151
  }
145
152
  if (payloadType === "custom_tool_call") {
@@ -152,7 +159,7 @@ function parseCodexEvents(events) {
152
159
  pendingPatches.set(callId, { input, status, timestamp: event.timestamp, operations });
153
160
  } else {
154
161
  messages.push({
155
- id: `toolcall-${event.timestamp}`,
162
+ id: `toolcall-${event.timestamp}-${eventIndex}`,
156
163
  type: "tool_call",
157
164
  server: "custom",
158
165
  tool: name,
@@ -170,7 +177,7 @@ function parseCodexEvents(events) {
170
177
  const pendingPatch = pendingPatches.get(callId);
171
178
  if (pendingPatch) {
172
179
  messages.push({
173
- id: `patch-${pendingPatch.timestamp}`,
180
+ id: `patch-${pendingPatch.timestamp}-${eventIndex}`,
174
181
  type: "patch",
175
182
  operations: pendingPatch.operations,
176
183
  output: output.output || "",
@@ -180,7 +187,7 @@ function parseCodexEvents(events) {
180
187
  });
181
188
  pendingPatches.delete(callId);
182
189
  } else {
183
- const toolCallMsg = findLastMessageByType(messages, "tool_call");
190
+ const toolCallMsg = messages.findLast((m) => m.type === "tool_call");
184
191
  if (toolCallMsg) {
185
192
  toolCallMsg.status = getStatusFromExitCode(output.metadata?.exit_code);
186
193
  }
@@ -197,7 +204,7 @@ function parseCodexEvents(events) {
197
204
  completed: item.status === "completed"
198
205
  }));
199
206
  messages.push({
200
- id: `todo-${event.timestamp}`,
207
+ id: `todo-${event.timestamp}-${eventIndex}`,
201
208
  type: "todo_list",
202
209
  items: todoItems,
203
210
  status: "completed",
@@ -477,7 +484,7 @@ registerTool(
477
484
  inputSchema: {
478
485
  name: z.string().regex(/^\S+$/, "Name cannot contain spaces"),
479
486
  message: z.string(),
480
- repository: z.string(),
487
+ repositories: z.array(z.string()).min(1),
481
488
  coding_agent: z.enum(["claude", "codex"]).optional()
482
489
  }
483
490
  },
@@ -486,7 +493,7 @@ registerTool(
486
493
  const body = {
487
494
  name: args.name,
488
495
  message: args.message,
489
- repository: args.repository
496
+ repositories: args.repositories
490
497
  };
491
498
  if (args.coding_agent) body.coding_agent = args.coding_agent;
492
499
  return result(await api("POST", "/v1/replica", body));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-mcp",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { z } from 'zod';
4
4
  import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
5
- import { parseAgentEvents, type AgentType, type ReadReplicaHistoryResponse } from '@replicas/shared';
5
+ import { parseAgentEvents, type AgentProvider, type ReadReplicaHistoryResponse } from '@replicas/shared';
6
6
 
7
7
  const API_URL = process.env.REPLICAS_API_URL || 'https://api.replicas.dev';
8
8
  const API_KEY = process.env.REPLICAS_API_KEY;
@@ -69,7 +69,7 @@ registerTool(
69
69
  inputSchema: {
70
70
  name: z.string().regex(/^\S+$/, 'Name cannot contain spaces'),
71
71
  message: z.string(),
72
- repository: z.string(),
72
+ repositories: z.array(z.string()).min(1),
73
73
  coding_agent: z.enum(['claude', 'codex']).optional(),
74
74
  },
75
75
  },
@@ -78,7 +78,7 @@ registerTool(
78
78
  const body: Record<string, unknown> = {
79
79
  name: args.name,
80
80
  message: args.message,
81
- repository: args.repository,
81
+ repositories: args.repositories,
82
82
  };
83
83
  if (args.coding_agent) body.coding_agent = args.coding_agent;
84
84
  return result(await api('POST', '/v1/replica', body));
@@ -205,7 +205,7 @@ registerTool(
205
205
  }
206
206
 
207
207
  // Parse raw events into DisplayMessage format
208
- const agentType = (response.coding_agent || 'claude') as AgentType;
208
+ const agentType = (response.coding_agent || 'claude') as AgentProvider;
209
209
  const messages = parseAgentEvents(response.events, agentType);
210
210
 
211
211
  return result({