replicas-mcp 0.1.5 → 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 +43 -30
- package/package.json +1 -1
- package/src/index.ts +4 -6
package/dist/index.js
CHANGED
|
@@ -5,6 +5,14 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
|
+
// ../shared/src/sandbox.ts
|
|
9
|
+
var SANDBOX_LIFECYCLE = {
|
|
10
|
+
AUTO_STOP_MINUTES: 60,
|
|
11
|
+
AUTO_ARCHIVE_MINUTES: 60 * 24 * 7,
|
|
12
|
+
AUTO_DELETE_MINUTES: -1,
|
|
13
|
+
SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
|
|
14
|
+
};
|
|
15
|
+
|
|
8
16
|
// ../shared/src/display-message/parsers/codex-parser.ts
|
|
9
17
|
function safeJsonParse(str, fallback) {
|
|
10
18
|
try {
|
|
@@ -16,8 +24,12 @@ function safeJsonParse(str, fallback) {
|
|
|
16
24
|
function getStatusFromExitCode(exitCode) {
|
|
17
25
|
return exitCode === 0 ? "completed" : "failed";
|
|
18
26
|
}
|
|
19
|
-
function
|
|
20
|
-
|
|
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 };
|
|
21
33
|
}
|
|
22
34
|
function parsePatch(input) {
|
|
23
35
|
const operations = [];
|
|
@@ -74,11 +86,12 @@ function parsePatch(input) {
|
|
|
74
86
|
}
|
|
75
87
|
function parseCodexEvents(events) {
|
|
76
88
|
const messages = [];
|
|
89
|
+
const pendingCommands = /* @__PURE__ */ new Map();
|
|
77
90
|
const pendingPatches = /* @__PURE__ */ new Map();
|
|
78
|
-
events.forEach((event) => {
|
|
91
|
+
events.forEach((event, eventIndex) => {
|
|
79
92
|
if (event.type === "event_msg" && event.payload?.type === "user_message") {
|
|
80
93
|
messages.push({
|
|
81
|
-
id: `user-${event.timestamp}`,
|
|
94
|
+
id: `user-${event.timestamp}-${eventIndex}`,
|
|
82
95
|
type: "user",
|
|
83
96
|
content: event.payload.message || "",
|
|
84
97
|
timestamp: event.timestamp
|
|
@@ -86,7 +99,7 @@ function parseCodexEvents(events) {
|
|
|
86
99
|
}
|
|
87
100
|
if (event.type === "event_msg" && event.payload?.type === "agent_reasoning") {
|
|
88
101
|
messages.push({
|
|
89
|
-
id: `reasoning-${event.timestamp}-${messages.length}`,
|
|
102
|
+
id: `reasoning-${event.timestamp}-${eventIndex}-${messages.length}`,
|
|
90
103
|
type: "reasoning",
|
|
91
104
|
content: event.payload.text || "",
|
|
92
105
|
status: "completed",
|
|
@@ -100,38 +113,40 @@ function parseCodexEvents(events) {
|
|
|
100
113
|
const textContent = content.filter((c) => c.type === "output_text").map((c) => c.text || "").join("\n");
|
|
101
114
|
if (textContent) {
|
|
102
115
|
messages.push({
|
|
103
|
-
id: `agent-${event.timestamp}`,
|
|
116
|
+
id: `agent-${event.timestamp}-${eventIndex}`,
|
|
104
117
|
type: "agent",
|
|
105
118
|
content: textContent,
|
|
106
119
|
timestamp: event.timestamp
|
|
107
120
|
});
|
|
108
121
|
}
|
|
109
122
|
}
|
|
110
|
-
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;
|
|
111
125
|
const args = safeJsonParse(event.payload.arguments || "{}", {});
|
|
112
126
|
const command = Array.isArray(args.command) ? args.command.join(" ") : args.command || "";
|
|
113
|
-
|
|
114
|
-
id: `command-${
|
|
127
|
+
const msg = {
|
|
128
|
+
id: `command-${callId || "no-call-id"}-${eventIndex}`,
|
|
115
129
|
type: "command",
|
|
116
130
|
command,
|
|
117
131
|
output: "",
|
|
118
|
-
// Will be filled by function_call_output
|
|
119
132
|
status: "in_progress",
|
|
120
133
|
timestamp: event.timestamp
|
|
121
|
-
}
|
|
134
|
+
};
|
|
135
|
+
messages.push(msg);
|
|
136
|
+
if (callId) {
|
|
137
|
+
pendingCommands.set(callId, msg);
|
|
138
|
+
}
|
|
122
139
|
}
|
|
123
140
|
if (payloadType === "function_call_output") {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
commandMsg.status = getStatusFromExitCode(output.metadata?.exit_code);
|
|
134
|
-
}
|
|
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);
|
|
135
150
|
}
|
|
136
151
|
}
|
|
137
152
|
if (payloadType === "custom_tool_call") {
|
|
@@ -144,7 +159,7 @@ function parseCodexEvents(events) {
|
|
|
144
159
|
pendingPatches.set(callId, { input, status, timestamp: event.timestamp, operations });
|
|
145
160
|
} else {
|
|
146
161
|
messages.push({
|
|
147
|
-
id: `toolcall-${event.timestamp}`,
|
|
162
|
+
id: `toolcall-${event.timestamp}-${eventIndex}`,
|
|
148
163
|
type: "tool_call",
|
|
149
164
|
server: "custom",
|
|
150
165
|
tool: name,
|
|
@@ -162,7 +177,7 @@ function parseCodexEvents(events) {
|
|
|
162
177
|
const pendingPatch = pendingPatches.get(callId);
|
|
163
178
|
if (pendingPatch) {
|
|
164
179
|
messages.push({
|
|
165
|
-
id: `patch-${pendingPatch.timestamp}`,
|
|
180
|
+
id: `patch-${pendingPatch.timestamp}-${eventIndex}`,
|
|
166
181
|
type: "patch",
|
|
167
182
|
operations: pendingPatch.operations,
|
|
168
183
|
output: output.output || "",
|
|
@@ -172,7 +187,7 @@ function parseCodexEvents(events) {
|
|
|
172
187
|
});
|
|
173
188
|
pendingPatches.delete(callId);
|
|
174
189
|
} else {
|
|
175
|
-
const toolCallMsg =
|
|
190
|
+
const toolCallMsg = messages.findLast((m) => m.type === "tool_call");
|
|
176
191
|
if (toolCallMsg) {
|
|
177
192
|
toolCallMsg.status = getStatusFromExitCode(output.metadata?.exit_code);
|
|
178
193
|
}
|
|
@@ -189,7 +204,7 @@ function parseCodexEvents(events) {
|
|
|
189
204
|
completed: item.status === "completed"
|
|
190
205
|
}));
|
|
191
206
|
messages.push({
|
|
192
|
-
id: `todo-${event.timestamp}`,
|
|
207
|
+
id: `todo-${event.timestamp}-${eventIndex}`,
|
|
193
208
|
type: "todo_list",
|
|
194
209
|
items: todoItems,
|
|
195
210
|
status: "completed",
|
|
@@ -469,8 +484,7 @@ registerTool(
|
|
|
469
484
|
inputSchema: {
|
|
470
485
|
name: z.string().regex(/^\S+$/, "Name cannot contain spaces"),
|
|
471
486
|
message: z.string(),
|
|
472
|
-
|
|
473
|
-
instance_type: z.enum(["standard", "large", "power"]).optional(),
|
|
487
|
+
repositories: z.array(z.string()).min(1),
|
|
474
488
|
coding_agent: z.enum(["claude", "codex"]).optional()
|
|
475
489
|
}
|
|
476
490
|
},
|
|
@@ -479,9 +493,8 @@ registerTool(
|
|
|
479
493
|
const body = {
|
|
480
494
|
name: args.name,
|
|
481
495
|
message: args.message,
|
|
482
|
-
|
|
496
|
+
repositories: args.repositories
|
|
483
497
|
};
|
|
484
|
-
if (args.instance_type) body.instance_type = args.instance_type;
|
|
485
498
|
if (args.coding_agent) body.coding_agent = args.coding_agent;
|
|
486
499
|
return result(await api("POST", "/v1/replica", body));
|
|
487
500
|
} catch (e) {
|
package/package.json
CHANGED
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
|
|
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,8 +69,7 @@ registerTool(
|
|
|
69
69
|
inputSchema: {
|
|
70
70
|
name: z.string().regex(/^\S+$/, 'Name cannot contain spaces'),
|
|
71
71
|
message: z.string(),
|
|
72
|
-
|
|
73
|
-
instance_type: z.enum(['standard', 'large', 'power']).optional(),
|
|
72
|
+
repositories: z.array(z.string()).min(1),
|
|
74
73
|
coding_agent: z.enum(['claude', 'codex']).optional(),
|
|
75
74
|
},
|
|
76
75
|
},
|
|
@@ -79,9 +78,8 @@ registerTool(
|
|
|
79
78
|
const body: Record<string, unknown> = {
|
|
80
79
|
name: args.name,
|
|
81
80
|
message: args.message,
|
|
82
|
-
|
|
81
|
+
repositories: args.repositories,
|
|
83
82
|
};
|
|
84
|
-
if (args.instance_type) body.instance_type = args.instance_type;
|
|
85
83
|
if (args.coding_agent) body.coding_agent = args.coding_agent;
|
|
86
84
|
return result(await api('POST', '/v1/replica', body));
|
|
87
85
|
} catch (e) {
|
|
@@ -207,7 +205,7 @@ registerTool(
|
|
|
207
205
|
}
|
|
208
206
|
|
|
209
207
|
// Parse raw events into DisplayMessage format
|
|
210
|
-
const agentType = (response.coding_agent || 'claude') as
|
|
208
|
+
const agentType = (response.coding_agent || 'claude') as AgentProvider;
|
|
211
209
|
const messages = parseAgentEvents(response.events, agentType);
|
|
212
210
|
|
|
213
211
|
return result({
|