replicas-mcp 0.2.12 → 0.2.13
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 +560 -133
- package/package.json +1 -1
- package/src/index.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
-
import { z as
|
|
6
|
+
import { z as z3 } from "zod";
|
|
7
7
|
|
|
8
8
|
// ../shared/src/agent.ts
|
|
9
9
|
var AGENT = {
|
|
10
10
|
CLAUDE: "claude",
|
|
11
11
|
CODEX: "codex",
|
|
12
12
|
CURSOR: "cursor",
|
|
13
|
+
DEEPSEEK: "deepseek",
|
|
14
|
+
FX: "fx",
|
|
13
15
|
OPENCODE: "opencode",
|
|
14
16
|
PI: "pi",
|
|
15
17
|
RELAY: "relay"
|
|
@@ -28,6 +30,8 @@ var THINKING_LEVELS_BY_AGENT = {
|
|
|
28
30
|
claude: [...STANDARD_THINKING_LEVELS, "ultracode"],
|
|
29
31
|
codex: [...STANDARD_THINKING_LEVELS, "ultra"],
|
|
30
32
|
cursor: STANDARD_THINKING_LEVELS,
|
|
33
|
+
deepseek: STANDARD_THINKING_LEVELS,
|
|
34
|
+
fx: STANDARD_THINKING_LEVELS,
|
|
31
35
|
opencode: STANDARD_THINKING_LEVELS,
|
|
32
36
|
pi: STANDARD_THINKING_LEVELS,
|
|
33
37
|
relay: [...STANDARD_THINKING_LEVELS, "ultracode"]
|
|
@@ -41,6 +45,10 @@ function getProviderDisplayName(provider, variant = "short") {
|
|
|
41
45
|
return "Codex";
|
|
42
46
|
case "cursor":
|
|
43
47
|
return "Cursor";
|
|
48
|
+
case "deepseek":
|
|
49
|
+
return variant === "long" ? "DeepSeek Harness" : "DeepSeek";
|
|
50
|
+
case "fx":
|
|
51
|
+
return "fx";
|
|
44
52
|
case "opencode":
|
|
45
53
|
return "Opencode";
|
|
46
54
|
case "pi":
|
|
@@ -55,6 +63,9 @@ function getCodingAgentDisplayNames() {
|
|
|
55
63
|
return VALID_CODING_AGENT_PROVIDERS.map((provider) => getProviderDisplayName(provider)).join(", ");
|
|
56
64
|
}
|
|
57
65
|
|
|
66
|
+
// ../shared/src/analytics/types.ts
|
|
67
|
+
import { z } from "zod";
|
|
68
|
+
|
|
58
69
|
// ../shared/src/credentials/types.ts
|
|
59
70
|
var CREDENTIAL_SCOPE = {
|
|
60
71
|
USER: "user",
|
|
@@ -76,7 +87,8 @@ var CREDENTIAL_METHOD = {
|
|
|
76
87
|
BEDROCK: "bedrock",
|
|
77
88
|
OPENCODE_GO: "opencode-go",
|
|
78
89
|
ASTER: "aster",
|
|
79
|
-
OPENROUTER: "openrouter"
|
|
90
|
+
OPENROUTER: "openrouter",
|
|
91
|
+
AI_GATEWAY: "ai-gateway"
|
|
80
92
|
};
|
|
81
93
|
var CREDENTIAL_TYPE = {
|
|
82
94
|
CLAUDE_OAUTH: "claude",
|
|
@@ -89,7 +101,8 @@ var CREDENTIAL_TYPE = {
|
|
|
89
101
|
CURSOR_API_KEY: "cursor_api_key",
|
|
90
102
|
OPENCODE_GO_API_KEY: "opencode_go_api_key",
|
|
91
103
|
ASTER_API_KEY: "aster_api_key",
|
|
92
|
-
OPENROUTER_API_KEY: "openrouter_api_key"
|
|
104
|
+
OPENROUTER_API_KEY: "openrouter_api_key",
|
|
105
|
+
AI_GATEWAY_API_KEY: "ai_gateway_api_key"
|
|
93
106
|
};
|
|
94
107
|
var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
|
|
95
108
|
[AGENT.CLAUDE]: [
|
|
@@ -106,6 +119,12 @@ var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
|
|
|
106
119
|
[AGENT.CURSOR]: [
|
|
107
120
|
{ method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.CURSOR_API_KEY }
|
|
108
121
|
],
|
|
122
|
+
[AGENT.DEEPSEEK]: [
|
|
123
|
+
{ method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
|
|
124
|
+
],
|
|
125
|
+
[AGENT.FX]: [
|
|
126
|
+
{ method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY }
|
|
127
|
+
],
|
|
109
128
|
[AGENT.OPENCODE]: [
|
|
110
129
|
{ method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
|
|
111
130
|
{ method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
|
|
@@ -117,6 +136,13 @@ var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
|
|
|
117
136
|
]
|
|
118
137
|
};
|
|
119
138
|
|
|
139
|
+
// ../shared/src/analytics/types.ts
|
|
140
|
+
var agentCredentialSnapshotSchema = z.object({
|
|
141
|
+
method: z.enum(CREDENTIAL_METHOD),
|
|
142
|
+
scope: z.enum(CREDENTIAL_SCOPE),
|
|
143
|
+
revision: z.string().optional()
|
|
144
|
+
});
|
|
145
|
+
|
|
120
146
|
// ../shared/src/event.ts
|
|
121
147
|
var CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE = "claude-partial-message";
|
|
122
148
|
function coerceClaudePartialMessagePayload(payload) {
|
|
@@ -138,6 +164,37 @@ var USER_MESSAGE_ID_PAYLOAD_KEY = "replicasMessageId";
|
|
|
138
164
|
var CODEX_ASP_ITEM_ID_PAYLOAD_KEY = "codexAspItemId";
|
|
139
165
|
var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
|
|
140
166
|
|
|
167
|
+
// ../shared/src/urls.ts
|
|
168
|
+
var HOME_PATH = "/home";
|
|
169
|
+
var DASHBOARD_PATH = "/dashboard";
|
|
170
|
+
var WEB_APP_PATHS = {
|
|
171
|
+
home: HOME_PATH,
|
|
172
|
+
onboarding: `${HOME_PATH}/onboarding`,
|
|
173
|
+
workspaces: `${HOME_PATH}/workspace`,
|
|
174
|
+
automations: `${HOME_PATH}/automations`,
|
|
175
|
+
environment: `${HOME_PATH}/environment`,
|
|
176
|
+
analytics: `${HOME_PATH}/analytics`,
|
|
177
|
+
dashboard: DASHBOARD_PATH,
|
|
178
|
+
agents: `${DASHBOARD_PATH}/agents`,
|
|
179
|
+
integrations: `${DASHBOARD_PATH}/integrations`,
|
|
180
|
+
integrationsGithub: `${DASHBOARD_PATH}/integrations/github`,
|
|
181
|
+
integrationsGitlab: `${DASHBOARD_PATH}/integrations/gitlab`,
|
|
182
|
+
settings: `${DASHBOARD_PATH}/settings`,
|
|
183
|
+
billing: `${DASHBOARD_PATH}/billing`,
|
|
184
|
+
members: `${DASHBOARD_PATH}/members`,
|
|
185
|
+
"audit-logs": `${DASHBOARD_PATH}/audit-logs`,
|
|
186
|
+
accountAgents: `${DASHBOARD_PATH}/account/agents`,
|
|
187
|
+
accountProfile: `${DASHBOARD_PATH}/account/profile`,
|
|
188
|
+
accountIntegrations: `${DASHBOARD_PATH}/account/integrations`,
|
|
189
|
+
accountApiKeys: `${DASHBOARD_PATH}/account/api-keys`,
|
|
190
|
+
accountPreferences: `${DASHBOARD_PATH}/account/preferences`,
|
|
191
|
+
fullscreenWorkspaces: "/workspaces"
|
|
192
|
+
};
|
|
193
|
+
var LEGACY_WEB_APP_PATHS = {
|
|
194
|
+
app: "/app",
|
|
195
|
+
dashboardWorkspaces: `${DASHBOARD_PATH}/workspaces`
|
|
196
|
+
};
|
|
197
|
+
|
|
141
198
|
// ../shared/src/default-skills/replicas-agent/abilities/computer.ts
|
|
142
199
|
var SECTION = `### Computer use (Linux desktop control)
|
|
143
200
|
Drive the workspace's Linux desktop - open a browser, click, type, scroll, screenshot, record - via the \`replicas computer\` CLI. Every Replicas workspace boots with a live H.264 and Opus stream published as an authenticated preview, so a \`Desktop\` tab is always available in the dashboard. Use \`replicas computer info\` to get the viewer URL when you want to share it (e.g. point a user on Slack at the live stream).
|
|
@@ -615,35 +672,8 @@ var GITLAB_ABILITY = {
|
|
|
615
672
|
referenceFile: { name: "GITLAB.md", content: REFERENCE4 }
|
|
616
673
|
};
|
|
617
674
|
|
|
618
|
-
// ../shared/src/default-skills/replicas-agent/abilities/learnings.ts
|
|
619
|
-
var SECTION5 = `### Learnings
|
|
620
|
-
Propose additions, updates, or deletions to curated organization knowledge.
|
|
621
|
-
|
|
622
|
-
**Reference:** \`references/LEARNINGS.md\``;
|
|
623
|
-
var REFERENCE5 = `# Learnings
|
|
624
|
-
|
|
625
|
-
Learnings are curated, human-approved knowledge entries your organization maintains: conventions, gotchas, environment facts, and process rules.
|
|
626
|
-
|
|
627
|
-
All writes are proposals: a human reviews them in the dashboard, and nothing takes effect until approved.
|
|
628
|
-
|
|
629
|
-
Use \`replicas learnings --help\` and subcommand help such as \`replicas learnings add --help\`, \`replicas learnings update --help\`, or \`replicas learnings delete --help\` for current command syntax.
|
|
630
|
-
|
|
631
|
-
A human approves every proposal before it takes effect, so don't agonize over borderline calls \u2014 but keep proposals genuinely useful rather than reflexive.
|
|
632
|
-
|
|
633
|
-
- Propose \`add\` for anything repeatable and org-useful: user corrections and preferences, hard-won environment or process knowledge, conventions and decisions worth following, and gotchas that would waste time again. If you learned it the hard way this task, capture it.
|
|
634
|
-
- Never store task-specific details that won't recur, facts trivially derivable by reading the repo, or secrets/credentials.
|
|
635
|
-
- Propose \`update\` or \`delete\` when a learning is contradicted by the current code or docs, especially if the outdated guidance would affect future repeated work.
|
|
636
|
-
- Write narrow triggers describing when the entry should surface (e.g. "UI/UX work on the admin panel"), not vague topics.`;
|
|
637
|
-
var LEARNINGS_ABILITY = {
|
|
638
|
-
label: "Learnings",
|
|
639
|
-
description: "Propose changes to curated org knowledge for human review.",
|
|
640
|
-
bullet: "- Proposing changes to organization Learnings (curated, human-approved knowledge)",
|
|
641
|
-
section: SECTION5,
|
|
642
|
-
referenceFile: { name: "LEARNINGS.md", content: REFERENCE5 }
|
|
643
|
-
};
|
|
644
|
-
|
|
645
675
|
// ../shared/src/default-skills/replicas-agent/abilities/linear.ts
|
|
646
|
-
var
|
|
676
|
+
var SECTION5 = `### Linear
|
|
647
677
|
Fetch issues, update state, add comments, and search through the workspace-scoped TypeScript SDK.
|
|
648
678
|
|
|
649
679
|
**Reference:** \`references/LINEAR.md\`
|
|
@@ -652,7 +682,7 @@ Use this when:
|
|
|
652
682
|
- You encounter a Linear issue link and need to understand the task
|
|
653
683
|
- You need to update an issue's state or add a comment
|
|
654
684
|
- You need to search Linear issues`;
|
|
655
|
-
var
|
|
685
|
+
var REFERENCE5 = `# Linear Integration
|
|
656
686
|
|
|
657
687
|
Use \`@replicas/sdk\`; never request or handle a Linear OAuth token. Replicas refreshes the organization credential behind the gateway.
|
|
658
688
|
|
|
@@ -702,12 +732,12 @@ var LINEAR_ABILITY = {
|
|
|
702
732
|
label: "Linear",
|
|
703
733
|
description: "Fetch issues, comment, and update state through @replicas/sdk.",
|
|
704
734
|
bullet: "- Interacting with Linear (fetching issues, updating state, commenting, etc.)",
|
|
705
|
-
section:
|
|
706
|
-
referenceFile: { name: "LINEAR.md", content:
|
|
735
|
+
section: SECTION5,
|
|
736
|
+
referenceFile: { name: "LINEAR.md", content: REFERENCE5 }
|
|
707
737
|
};
|
|
708
738
|
|
|
709
739
|
// ../shared/src/default-skills/replicas-agent/abilities/media.ts
|
|
710
|
-
var
|
|
740
|
+
var SECTION6 = `### Media
|
|
711
741
|
Share screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external messages.
|
|
712
742
|
|
|
713
743
|
**Reference:** \`references/MEDIA.md\`
|
|
@@ -717,7 +747,7 @@ Use this when:
|
|
|
717
747
|
- You produce a self-contained HTML report that should be linked from a pull request
|
|
718
748
|
- You record video output (browser automation, screen capture) \u2014 including the recommended aspect ratio and FPS
|
|
719
749
|
- You need to embed media in a Slack/Linear/GitHub message AND keep a referenceable copy in the Replicas dashboard`;
|
|
720
|
-
var
|
|
750
|
+
var REFERENCE6 = `# Media (Screenshots, Recordings, Audio, HTML)
|
|
721
751
|
|
|
722
752
|
This guide covers how to share screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external surfaces (Slack, Linear, GitHub).
|
|
723
753
|
|
|
@@ -1023,12 +1053,12 @@ var MEDIA_ABILITY = {
|
|
|
1023
1053
|
label: "Media",
|
|
1024
1054
|
description: "Share screenshots, recordings, generated images, audio clips, and HTML pages.",
|
|
1025
1055
|
bullet: "- Producing or showing the user any media \u2014 screenshots, screen recordings, generated images or diagrams, audio clips, or HTML recap pages \u2014 including in your Replicas chat reply, PR descriptions/comments, and other external platforms",
|
|
1026
|
-
section:
|
|
1027
|
-
referenceFile: { name: "MEDIA.md", content:
|
|
1056
|
+
section: SECTION6,
|
|
1057
|
+
referenceFile: { name: "MEDIA.md", content: REFERENCE6 }
|
|
1028
1058
|
};
|
|
1029
1059
|
|
|
1030
1060
|
// ../shared/src/default-skills/replicas-agent/abilities/previews.ts
|
|
1031
|
-
var
|
|
1061
|
+
var SECTION7 = `### Previews
|
|
1032
1062
|
Expose locally running services (web apps, APIs, databases) as public preview URLs so humans can interact with them directly.
|
|
1033
1063
|
|
|
1034
1064
|
**Reference:** \`references/PREVIEWS.md\`
|
|
@@ -1037,7 +1067,7 @@ Use this when:
|
|
|
1037
1067
|
- You need to start a service that a human should view or interact with
|
|
1038
1068
|
- The task involves UI work that benefits from human review
|
|
1039
1069
|
- You are verifying frontend/backend integrations visually`;
|
|
1040
|
-
var
|
|
1070
|
+
var REFERENCE7 = `# Preview URLs
|
|
1041
1071
|
|
|
1042
1072
|
When you run services on ports \u2014 such as a web app, API server, or database \u2014 humans may want to interact with them directly. You can expose your locally running services as public preview URLs.
|
|
1043
1073
|
|
|
@@ -1113,12 +1143,12 @@ var PREVIEWS_ABILITY = {
|
|
|
1113
1143
|
label: "Previews",
|
|
1114
1144
|
description: "Expose locally running services on public preview URLs for humans.",
|
|
1115
1145
|
bullet: "- Creating preview URLs for locally running services",
|
|
1116
|
-
section:
|
|
1117
|
-
referenceFile: { name: "PREVIEWS.md", content:
|
|
1146
|
+
section: SECTION7,
|
|
1147
|
+
referenceFile: { name: "PREVIEWS.md", content: REFERENCE7 }
|
|
1118
1148
|
};
|
|
1119
1149
|
|
|
1120
1150
|
// ../shared/src/default-skills/replicas-agent/abilities/plugins.ts
|
|
1121
|
-
var
|
|
1151
|
+
var SECTION8 = `### Plugins
|
|
1122
1152
|
Discover and execute installed marketplace tools through the workspace-scoped TypeScript SDK.
|
|
1123
1153
|
|
|
1124
1154
|
**Reference:** \`references/PLUGINS.md\`
|
|
@@ -1128,10 +1158,15 @@ Use this when:
|
|
|
1128
1158
|
- The user asks to manage Calendly events, invitees, or scheduling links
|
|
1129
1159
|
- The user asks to read or change Google Ads, Docs, Drive, Search Console, or Sheets data
|
|
1130
1160
|
- The user asks for ClickHouse analytics or PostHog product data
|
|
1161
|
+
- The user asks to create or control an E2B sandbox
|
|
1162
|
+
- The user asks to invoke a connected Modal function
|
|
1163
|
+
- The user asks to query or update a connected turbopuffer namespace
|
|
1164
|
+
- The user asks for PlanetScale organizations, databases, branches, or Insights data
|
|
1165
|
+
- The user asks to analyze text with Pangram
|
|
1131
1166
|
- The user asks for Stripe customers, payments, invoices, subscriptions, or balances`;
|
|
1132
|
-
var
|
|
1167
|
+
var REFERENCE8 = `# Plugins
|
|
1133
1168
|
|
|
1134
|
-
Plugins are TypeScript libraries, not MCP servers. Import \`@replicas/sdk\`; Replicas authenticates the workspace and selects only the owner\u2019s personal connection or the organization fallback.
|
|
1169
|
+
Plugins are TypeScript libraries, not MCP servers. Import \`@replicas/sdk\`; Replicas authenticates the workspace and selects only the owner\u2019s personal connection or the organization fallback. Provider credentials, sessions, and project keys are never exposed.
|
|
1135
1170
|
|
|
1136
1171
|
Plugin tools may read or write provider data according to the connected account's permissions. Only execute write or destructive tools when they match the user's request.
|
|
1137
1172
|
|
|
@@ -1181,17 +1216,80 @@ const results = await Promise.all(customerIds.map((customer) =>
|
|
|
1181
1216
|
\`\`\`
|
|
1182
1217
|
|
|
1183
1218
|
Never attempt to import Composio, create a session, manage a connection, or call a provider with raw credentials. Those operations are intentionally unavailable inside the workspace.
|
|
1219
|
+
|
|
1220
|
+
## PlanetScale
|
|
1221
|
+
|
|
1222
|
+
PlanetScale is a native OAuth integration. Pass a relative path from the PlanetScale v1 API; Replicas refreshes access tokens server-side:
|
|
1223
|
+
|
|
1224
|
+
\`\`\`ts
|
|
1225
|
+
const organizations = await replicas.planetscale.request('/organizations');
|
|
1226
|
+
const databases = await replicas.planetscale.request('/organizations/acme/databases');
|
|
1227
|
+
\`\`\`
|
|
1228
|
+
|
|
1229
|
+
OAuth scopes control permitted operations. Confirm mutations before using POST, PUT, PATCH, or DELETE.
|
|
1230
|
+
|
|
1231
|
+
## Modal
|
|
1232
|
+
|
|
1233
|
+
Modal is a native integration and uses its official JavaScript SDK behind the Replicas gateway. Invoke a deployed function by name:
|
|
1234
|
+
|
|
1235
|
+
\`\`\`ts
|
|
1236
|
+
const result = await replicas.modal.call({
|
|
1237
|
+
app: 'my-app',
|
|
1238
|
+
function: 'my-function',
|
|
1239
|
+
args: ['input'],
|
|
1240
|
+
environment: 'main',
|
|
1241
|
+
});
|
|
1242
|
+
\`\`\`
|
|
1243
|
+
|
|
1244
|
+
Function calls execute with the connected Modal token and may mutate external state. Confirm the requested action before invoking a function with side effects.
|
|
1245
|
+
|
|
1246
|
+
## turbopuffer
|
|
1247
|
+
|
|
1248
|
+
turbopuffer is a native integration backed by its official TypeScript SDK. Use the provider-shaped helpers:
|
|
1249
|
+
|
|
1250
|
+
\`\`\`ts
|
|
1251
|
+
const namespaces = await replicas.turbopuffer.namespaces({ prefix: 'products' });
|
|
1252
|
+
const results = await replicas.turbopuffer.query('products', {
|
|
1253
|
+
rank_by: ['text', 'BM25', 'wireless headphones'],
|
|
1254
|
+
top_k: 10,
|
|
1255
|
+
});
|
|
1256
|
+
\`\`\`
|
|
1257
|
+
|
|
1258
|
+
\`write\` mutates namespace data. Confirm the requested change before calling it.
|
|
1259
|
+
|
|
1260
|
+
## Pangram
|
|
1261
|
+
|
|
1262
|
+
Pangram is a native integration. Text sent to either method is processed by Pangram and consumes the connected account's credits:
|
|
1263
|
+
|
|
1264
|
+
\`\`\`ts
|
|
1265
|
+
const detection = await replicas.pangram.detect({ text });
|
|
1266
|
+
const plagiarism = await replicas.pangram.plagiarism(text);
|
|
1267
|
+
\`\`\`
|
|
1268
|
+
|
|
1269
|
+
Do not send private or sensitive text without the user's authorization.
|
|
1270
|
+
|
|
1271
|
+
## E2B
|
|
1272
|
+
|
|
1273
|
+
E2B is a native integration backed by its official JavaScript SDK. Create a sandbox, run commands, and remove it when finished:
|
|
1274
|
+
|
|
1275
|
+
\`\`\`ts
|
|
1276
|
+
const { sandboxId } = await replicas.e2b.create({ timeoutMs: 300_000 });
|
|
1277
|
+
const result = await replicas.e2b.run(sandboxId, 'python analysis.py', { cwd: '/home/user' });
|
|
1278
|
+
await replicas.e2b.kill(sandboxId);
|
|
1279
|
+
\`\`\`
|
|
1280
|
+
|
|
1281
|
+
Sandbox operations consume the connected account's E2B credits. Kill sandboxes after use unless the user asked to keep one running.
|
|
1184
1282
|
`;
|
|
1185
1283
|
var PLUGINS_ABILITY = {
|
|
1186
1284
|
label: "Plugins",
|
|
1187
1285
|
description: "Use installed marketplace tools through @replicas/sdk.",
|
|
1188
1286
|
bullet: "- Interacting with installed marketplace plugins through TypeScript",
|
|
1189
|
-
section:
|
|
1190
|
-
referenceFile: { name: "PLUGINS.md", content:
|
|
1287
|
+
section: SECTION8,
|
|
1288
|
+
referenceFile: { name: "PLUGINS.md", content: REFERENCE8 }
|
|
1191
1289
|
};
|
|
1192
1290
|
|
|
1193
1291
|
// ../shared/src/default-skills/replicas-agent/abilities/replicas.ts
|
|
1194
|
-
var
|
|
1292
|
+
var SECTION9 = `### Replicas (in-workspace CLI)
|
|
1195
1293
|
Take action *with* Replicas itself \u2014 manage automations, environments (variables, files), repos, and \`replicas.json\` config \u2014 using the pre-installed, pre-authenticated \`replicas\` CLI.
|
|
1196
1294
|
|
|
1197
1295
|
**Reference:** \`references/REPLICAS.md\`
|
|
@@ -1202,7 +1300,7 @@ Use this when:
|
|
|
1202
1300
|
- The user asks "what envs / repos / automations do I have?"
|
|
1203
1301
|
- The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo
|
|
1204
1302
|
- You need to run a long-lived service (dev server, daemon) \u2014 always use \`replicas service start\` so it survives workspace sleep/wake`;
|
|
1205
|
-
var
|
|
1303
|
+
var REFERENCE9 = `# Replicas (in-workspace CLI)
|
|
1206
1304
|
|
|
1207
1305
|
This guide covers how to take action *with* Replicas itself from inside a Replicas workspace \u2014 managing automations, environments (and their variables/files), repos, previews, and the user's \`replicas.json\` config \u2014 using the pre-installed \`replicas\` CLI.
|
|
1208
1306
|
|
|
@@ -1429,13 +1527,13 @@ var REPLICAS_ABILITY = {
|
|
|
1429
1527
|
description: "Teach the agent about Replicas itself \u2014 automations, environments, the in-workspace CLI.",
|
|
1430
1528
|
// No bullet — help_instructions covers the `replicas` CLI surface in detail.
|
|
1431
1529
|
bullet: "",
|
|
1432
|
-
section:
|
|
1433
|
-
referenceFile: { name: "REPLICAS.md", content:
|
|
1530
|
+
section: SECTION9,
|
|
1531
|
+
referenceFile: { name: "REPLICAS.md", content: REFERENCE9 },
|
|
1434
1532
|
locked: true
|
|
1435
1533
|
};
|
|
1436
1534
|
|
|
1437
1535
|
// ../shared/src/default-skills/replicas-agent/abilities/sentry.ts
|
|
1438
|
-
var
|
|
1536
|
+
var SECTION10 = `### Sentry
|
|
1439
1537
|
Read issues and project data through the workspace-scoped TypeScript SDK.
|
|
1440
1538
|
|
|
1441
1539
|
**Reference:** \`references/SENTRY.md\`
|
|
@@ -1443,7 +1541,7 @@ Read issues and project data through the workspace-scoped TypeScript SDK.
|
|
|
1443
1541
|
Use this when:
|
|
1444
1542
|
- You need to inspect Sentry projects or issues
|
|
1445
1543
|
- A user asks for error-monitoring context outside a webhook-triggered task`;
|
|
1446
|
-
var
|
|
1544
|
+
var REFERENCE10 = `# Sentry Integration
|
|
1447
1545
|
|
|
1448
1546
|
Use \`@replicas/sdk\`; never request or read a Sentry token. Sentry access is organization-scoped and read-only.
|
|
1449
1547
|
|
|
@@ -1462,12 +1560,12 @@ var SENTRY_ABILITY = {
|
|
|
1462
1560
|
label: "Sentry",
|
|
1463
1561
|
description: "Read Sentry projects and issues through @replicas/sdk.",
|
|
1464
1562
|
bullet: "- Interacting with Sentry (reading projects, issues, and error context)",
|
|
1465
|
-
section:
|
|
1466
|
-
referenceFile: { name: "SENTRY.md", content:
|
|
1563
|
+
section: SECTION10,
|
|
1564
|
+
referenceFile: { name: "SENTRY.md", content: REFERENCE10 }
|
|
1467
1565
|
};
|
|
1468
1566
|
|
|
1469
1567
|
// ../shared/src/default-skills/replicas-agent/abilities/slack.ts
|
|
1470
|
-
var
|
|
1568
|
+
var SECTION11 = `### Slack
|
|
1471
1569
|
Send messages, read threads, search conversations, and upload files through the workspace-scoped TypeScript SDK.
|
|
1472
1570
|
|
|
1473
1571
|
**Reference:** \`references/SLACK.md\`
|
|
@@ -1476,7 +1574,7 @@ Use this when:
|
|
|
1476
1574
|
- You need to send a message to a Slack channel or thread
|
|
1477
1575
|
- You need to read or search Slack conversations
|
|
1478
1576
|
- You encounter a Slack message link and need its full thread`;
|
|
1479
|
-
var
|
|
1577
|
+
var REFERENCE11 = `# Slack Integration
|
|
1480
1578
|
|
|
1481
1579
|
Use \`@replicas/sdk\`; never read or send a Slack token directly. The SDK calls Replicas, which selects only this workspace's organization connection.
|
|
1482
1580
|
|
|
@@ -1511,7 +1609,7 @@ const message = await replicas.slack.call<{ channel: string; ts: string }>('chat
|
|
|
1511
1609
|
await replicas.slack.attachThread({ channel: message.channel, threadTs: message.ts });
|
|
1512
1610
|
\`\`\`
|
|
1513
1611
|
|
|
1514
|
-
A link in the message text stays plain text, so
|
|
1612
|
+
A link in the message text stays plain text, so the message that first shares a pull request or merge request link passes \`blocks\` alongside \`text\` to render a button for it. Keep \`text\` set to the same message \u2014 Slack uses it for notifications and fallback.
|
|
1515
1613
|
|
|
1516
1614
|
\`\`\`ts
|
|
1517
1615
|
await replicas.slack.call('chat.postMessage', {
|
|
@@ -1523,14 +1621,14 @@ await replicas.slack.call('chat.postMessage', {
|
|
|
1523
1621
|
{
|
|
1524
1622
|
type: 'actions',
|
|
1525
1623
|
elements: [
|
|
1526
|
-
{ type: 'button', text: { type: 'plain_text', text: 'View PR' }, url: prUrl, action_id: 'view_pr' },
|
|
1624
|
+
{ type: 'button', style: 'primary', text: { type: 'plain_text', text: 'View PR' }, url: prUrl, action_id: 'view_pr' },
|
|
1527
1625
|
],
|
|
1528
1626
|
},
|
|
1529
1627
|
],
|
|
1530
1628
|
});
|
|
1531
1629
|
\`\`\`
|
|
1532
1630
|
|
|
1533
|
-
Use "View MR" for GitLab. With several links, give each button a unique \`action_id\` and name its repository in the label ("View PR \xB7 web").
|
|
1631
|
+
Only the announcing message gets the button \u2014 follow-ups about a pull request already linked in the thread keep the link in the text and drop the \`blocks\`. Use "View MR" for GitLab. With several links, give each button a unique \`action_id\` and name its repository in the label ("View PR \xB7 web").
|
|
1534
1632
|
|
|
1535
1633
|
Attach every new top-level conversation so future replies route to this workspace. For a reply in another thread, attach its root \`thread_ts\`, not the reply timestamp. Do not attach the originating thread again.
|
|
1536
1634
|
|
|
@@ -1549,8 +1647,8 @@ var SLACK_ABILITY = {
|
|
|
1549
1647
|
label: "Slack",
|
|
1550
1648
|
description: "Send messages, read threads, and search through @replicas/sdk.",
|
|
1551
1649
|
bullet: "- Interacting with Slack (sending messages, reading threads, etc.)",
|
|
1552
|
-
section:
|
|
1553
|
-
referenceFile: { name: "SLACK.md", content:
|
|
1650
|
+
section: SECTION11,
|
|
1651
|
+
referenceFile: { name: "SLACK.md", content: REFERENCE11 }
|
|
1554
1652
|
};
|
|
1555
1653
|
|
|
1556
1654
|
// ../shared/src/default-skills/replicas-agent/registry.ts
|
|
@@ -1560,7 +1658,6 @@ var REPLICAS_AGENT_ABILITY_REGISTRY = {
|
|
|
1560
1658
|
docker: DOCKER_ABILITY,
|
|
1561
1659
|
github: GITHUB_ABILITY,
|
|
1562
1660
|
gitlab: GITLAB_ABILITY,
|
|
1563
|
-
learnings: LEARNINGS_ABILITY,
|
|
1564
1661
|
linear: LINEAR_ABILITY,
|
|
1565
1662
|
media: MEDIA_ABILITY,
|
|
1566
1663
|
plugins: PLUGINS_ABILITY,
|
|
@@ -1654,12 +1751,23 @@ var GPT_5_6_TERRA_MODEL = "gpt-5.6-terra";
|
|
|
1654
1751
|
var GPT_5_6_LUNA_MODEL = "gpt-5.6-luna";
|
|
1655
1752
|
var DEFAULT_CODEX_MODEL = GPT_5_6_SOL_MODEL;
|
|
1656
1753
|
var DEFAULT_OPENCODE_MODEL = "z-ai/glm-5.2";
|
|
1754
|
+
var DEEPSEEK_V4_PRO_MODEL = "deepseek/deepseek-v4-pro-0813";
|
|
1755
|
+
var DEEPSEEK_V4_FLASH_MODEL = "deepseek/deepseek-v4-flash-0731";
|
|
1756
|
+
var DEFAULT_FX_MODEL = "zai/glm-5.2";
|
|
1657
1757
|
var OPENROUTER_MODELS = [
|
|
1658
1758
|
DEFAULT_OPENCODE_MODEL,
|
|
1759
|
+
DEEPSEEK_V4_PRO_MODEL,
|
|
1760
|
+
DEEPSEEK_V4_FLASH_MODEL,
|
|
1659
1761
|
"minimax/minimax-m3",
|
|
1660
1762
|
"xiaomi/mimo-v2.5-pro",
|
|
1661
1763
|
"moonshotai/kimi-k2.6"
|
|
1662
1764
|
];
|
|
1765
|
+
function prioritizeDeepseekModels(models) {
|
|
1766
|
+
return [
|
|
1767
|
+
...models.filter((model) => model.startsWith("deepseek/")),
|
|
1768
|
+
...models.filter((model) => !model.startsWith("deepseek/"))
|
|
1769
|
+
];
|
|
1770
|
+
}
|
|
1663
1771
|
var CLAUDE_MODEL_CONTEXT_WINDOWS = {
|
|
1664
1772
|
[CLAUDE_FABLE_5_MODEL]: 1e6,
|
|
1665
1773
|
[CLAUDE_OPUS_5_MODEL]: 1e6,
|
|
@@ -1709,11 +1817,14 @@ var AGENT_MODELS = {
|
|
|
1709
1817
|
"gpt-5-mini",
|
|
1710
1818
|
"gemini-3.1-pro",
|
|
1711
1819
|
"gemini-3-flash",
|
|
1820
|
+
"grok-4.6",
|
|
1712
1821
|
"grok-4.5",
|
|
1713
1822
|
"grok-4.3",
|
|
1714
1823
|
CLAUDE_HAIKU_4_5_MODEL,
|
|
1715
1824
|
"kimi-k2.5"
|
|
1716
1825
|
],
|
|
1826
|
+
deepseek: prioritizeDeepseekModels(OPENROUTER_MODELS),
|
|
1827
|
+
fx: [DEFAULT_FX_MODEL],
|
|
1717
1828
|
opencode: [...OPENROUTER_MODELS, ...ASTER_MODELS],
|
|
1718
1829
|
pi: [...OPENROUTER_MODELS, ...ASTER_MODELS],
|
|
1719
1830
|
relay: [CLAUDE_FABLE_5_MODEL, CLAUDE_OPUS_5_MODEL, CLAUDE_OPUS_4_8_MODEL, CLAUDE_SONNET_5_MODEL]
|
|
@@ -1733,6 +1844,8 @@ var MODEL_LABELS = {
|
|
|
1733
1844
|
[GPT_5_6_LUNA_MODEL]: "GPT-5.6 Luna",
|
|
1734
1845
|
"gpt-5.5": "GPT-5.5",
|
|
1735
1846
|
[DEFAULT_OPENCODE_MODEL]: "GLM 5.2 via OpenRouter",
|
|
1847
|
+
[DEEPSEEK_V4_PRO_MODEL]: "DeepSeek V4 Pro via OpenRouter",
|
|
1848
|
+
[DEEPSEEK_V4_FLASH_MODEL]: "DeepSeek V4 Flash via OpenRouter",
|
|
1736
1849
|
"minimax/minimax-m3": "MiniMax M3 via OpenRouter",
|
|
1737
1850
|
"xiaomi/mimo-v2.5-pro": "MiMo V2.5 Pro via OpenRouter",
|
|
1738
1851
|
"moonshotai/kimi-k2.6": "Kimi K2.6 via OpenRouter",
|
|
@@ -1753,6 +1866,7 @@ var MODEL_LABELS = {
|
|
|
1753
1866
|
[CLAUDE_HAIKU_4_5_MODEL]: "Haiku 4.5",
|
|
1754
1867
|
"gemini-3.1-pro": "Gemini 3.1 Pro",
|
|
1755
1868
|
"gemini-3-flash": "Gemini 3 Flash",
|
|
1869
|
+
"grok-4.6": "Grok 4.6",
|
|
1756
1870
|
"grok-4.5": "Grok 4.5",
|
|
1757
1871
|
"grok-4.3": "Grok 4.3",
|
|
1758
1872
|
"kimi-k2.5": "Kimi K2.5"
|
|
@@ -1762,51 +1876,51 @@ var MAX_CANVAS_FILE_BYTES = 25 * 1024 * 1024;
|
|
|
1762
1876
|
var MAX_CANVAS_PREVIEW_BYTES = 5 * 1024 * 1024;
|
|
1763
1877
|
|
|
1764
1878
|
// ../shared/src/engine/v1.ts
|
|
1765
|
-
import { z } from "zod";
|
|
1766
|
-
var createChatRequestSchema =
|
|
1767
|
-
id:
|
|
1768
|
-
createdAt:
|
|
1769
|
-
provider:
|
|
1770
|
-
title:
|
|
1771
|
-
parentChatId:
|
|
1772
|
-
clientRequestId:
|
|
1879
|
+
import { z as z2 } from "zod";
|
|
1880
|
+
var createChatRequestSchema = z2.object({
|
|
1881
|
+
id: z2.string().uuid().optional(),
|
|
1882
|
+
createdAt: z2.string().datetime().optional(),
|
|
1883
|
+
provider: z2.enum(VALID_AGENT_PROVIDERS),
|
|
1884
|
+
title: z2.string().min(1).optional(),
|
|
1885
|
+
parentChatId: z2.string().uuid().optional(),
|
|
1886
|
+
clientRequestId: z2.string().min(1).max(128).optional()
|
|
1773
1887
|
});
|
|
1774
|
-
var sendChatMessageRequestSchema =
|
|
1775
|
-
messageId:
|
|
1776
|
-
submittedAt:
|
|
1777
|
-
message:
|
|
1778
|
-
model:
|
|
1779
|
-
customInstructions:
|
|
1780
|
-
planMode:
|
|
1781
|
-
images:
|
|
1782
|
-
type:
|
|
1783
|
-
source:
|
|
1784
|
-
|
|
1785
|
-
|
|
1888
|
+
var sendChatMessageRequestSchema = z2.object({
|
|
1889
|
+
messageId: z2.string().optional(),
|
|
1890
|
+
submittedAt: z2.string().optional(),
|
|
1891
|
+
message: z2.string(),
|
|
1892
|
+
model: z2.string().optional(),
|
|
1893
|
+
customInstructions: z2.string().optional(),
|
|
1894
|
+
planMode: z2.boolean().optional(),
|
|
1895
|
+
images: z2.array(z2.object({
|
|
1896
|
+
type: z2.literal("image"),
|
|
1897
|
+
source: z2.discriminatedUnion("type", [
|
|
1898
|
+
z2.object({ type: z2.literal("base64"), media_type: z2.enum(IMAGE_MEDIA_TYPES), data: z2.string() }),
|
|
1899
|
+
z2.object({ type: z2.literal("url"), url: z2.string() })
|
|
1786
1900
|
])
|
|
1787
1901
|
})).optional(),
|
|
1788
|
-
thinkingLevel:
|
|
1789
|
-
goalMode:
|
|
1790
|
-
fastMode:
|
|
1791
|
-
enableInteractiveTools:
|
|
1792
|
-
type:
|
|
1793
|
-
merge:
|
|
1794
|
-
idempotencyKey:
|
|
1795
|
-
senderUserId:
|
|
1796
|
-
senderEmail:
|
|
1797
|
-
senderDisplayName:
|
|
1798
|
-
senderAvatarUrl:
|
|
1799
|
-
errorNotificationTarget:
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
type:
|
|
1804
|
-
provider:
|
|
1805
|
-
resource:
|
|
1806
|
-
repositoryId:
|
|
1807
|
-
resourceNumber:
|
|
1902
|
+
thinkingLevel: z2.enum(VALID_THINKING_LEVELS).optional(),
|
|
1903
|
+
goalMode: z2.boolean().optional(),
|
|
1904
|
+
fastMode: z2.boolean().optional(),
|
|
1905
|
+
enableInteractiveTools: z2.boolean().optional(),
|
|
1906
|
+
type: z2.string().optional(),
|
|
1907
|
+
merge: z2.boolean().optional(),
|
|
1908
|
+
idempotencyKey: z2.string().optional(),
|
|
1909
|
+
senderUserId: z2.string().optional(),
|
|
1910
|
+
senderEmail: z2.string().optional(),
|
|
1911
|
+
senderDisplayName: z2.string().optional(),
|
|
1912
|
+
senderAvatarUrl: z2.string().optional(),
|
|
1913
|
+
errorNotificationTarget: z2.discriminatedUnion("type", [
|
|
1914
|
+
z2.object({ type: z2.literal("slack") }),
|
|
1915
|
+
z2.object({ type: z2.literal("linear"), sessionId: z2.string() }),
|
|
1916
|
+
z2.object({
|
|
1917
|
+
type: z2.literal("code_host"),
|
|
1918
|
+
provider: z2.enum(["github", "gitlab"]),
|
|
1919
|
+
resource: z2.enum(["issue", "pull_request"]),
|
|
1920
|
+
repositoryId: z2.string(),
|
|
1921
|
+
resourceNumber: z2.number()
|
|
1808
1922
|
}),
|
|
1809
|
-
|
|
1923
|
+
z2.object({ type: z2.literal("automation"), executionId: z2.string() })
|
|
1810
1924
|
]).optional()
|
|
1811
1925
|
}).passthrough();
|
|
1812
1926
|
|
|
@@ -2156,6 +2270,15 @@ function areUserMessagesWithinMatchWindow(a, b) {
|
|
|
2156
2270
|
return a.content === b.content && Math.abs(parseTimestampMs(a.timestamp) - parseTimestampMs(b.timestamp)) <= USER_MESSAGE_MATCH_GRACE_PERIOD_MS;
|
|
2157
2271
|
}
|
|
2158
2272
|
|
|
2273
|
+
// ../shared/src/agent-event-utils.ts
|
|
2274
|
+
function getUserMessage(event) {
|
|
2275
|
+
return event.type === "event_msg" && event.payload.type === "user_message" && typeof event.payload.message === "string" ? event.payload.message : null;
|
|
2276
|
+
}
|
|
2277
|
+
function getUserMessageId(event) {
|
|
2278
|
+
const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
|
|
2279
|
+
return typeof messageId === "string" ? messageId : null;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2159
2282
|
// ../shared/src/display-message/parsers/codex-parser.ts
|
|
2160
2283
|
function getStatusFromExitCode(exitCode) {
|
|
2161
2284
|
return exitCode === 0 ? "completed" : "failed";
|
|
@@ -2581,6 +2704,230 @@ function parseCursorEvents(events) {
|
|
|
2581
2704
|
return messages;
|
|
2582
2705
|
}
|
|
2583
2706
|
|
|
2707
|
+
// ../shared/src/display-message/parsers/deepseek-parser.ts
|
|
2708
|
+
function parseArguments(value) {
|
|
2709
|
+
if (typeof value !== "string") return void 0;
|
|
2710
|
+
const parsed = safeJsonParse(value, value);
|
|
2711
|
+
return isRecord(parsed) ? parsed : stringifyDisplayValue(parsed);
|
|
2712
|
+
}
|
|
2713
|
+
function getDeepseekAssistantMessageText(event, blockType) {
|
|
2714
|
+
if (!isRecord(event) || event.type !== "assistant/message" || !isRecord(event.data) || !isRecord(event.data.message) || !Array.isArray(event.data.message.content)) return "";
|
|
2715
|
+
return event.data.message.content.flatMap((block) => isRecord(block) && block.type === blockType && typeof block.text === "string" ? [block.text] : []).join("");
|
|
2716
|
+
}
|
|
2717
|
+
function parseDeepseekEvents(events) {
|
|
2718
|
+
const messages = [];
|
|
2719
|
+
for (const source of events) {
|
|
2720
|
+
if (source.type === "event_msg" && source.payload.type === "user_message") {
|
|
2721
|
+
if (typeof source.payload.message === "string" && source.payload.message.trim()) {
|
|
2722
|
+
const messageId = source.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
|
|
2723
|
+
messages.push({
|
|
2724
|
+
id: typeof messageId === "string" ? messageId : `deepseek-user-${source.timestamp}`,
|
|
2725
|
+
type: "user",
|
|
2726
|
+
content: source.payload.message,
|
|
2727
|
+
timestamp: source.timestamp
|
|
2728
|
+
});
|
|
2729
|
+
}
|
|
2730
|
+
continue;
|
|
2731
|
+
}
|
|
2732
|
+
if (source.type === "deepseek-error") {
|
|
2733
|
+
messages.push({
|
|
2734
|
+
id: `deepseek-error-${source.timestamp}`,
|
|
2735
|
+
type: "error",
|
|
2736
|
+
message: typeof source.payload.message === "string" ? source.payload.message : "DeepSeek Harness failed",
|
|
2737
|
+
timestamp: source.timestamp
|
|
2738
|
+
});
|
|
2739
|
+
continue;
|
|
2740
|
+
}
|
|
2741
|
+
if (source.type === "deepseek-input-request") {
|
|
2742
|
+
const requestId = typeof source.payload.requestId === "string" ? source.payload.requestId : `deepseek-input-${source.timestamp}`;
|
|
2743
|
+
if (source.payload.kind === "approval") {
|
|
2744
|
+
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
2745
|
+
id: requestId,
|
|
2746
|
+
server: "deepseek",
|
|
2747
|
+
tool: typeof source.payload.toolName === "string" ? source.payload.toolName : "approval",
|
|
2748
|
+
input: typeof source.payload.reason === "string" ? source.payload.reason : void 0,
|
|
2749
|
+
status: "in_progress",
|
|
2750
|
+
timestamp: source.timestamp,
|
|
2751
|
+
inputRequest: {
|
|
2752
|
+
requestId,
|
|
2753
|
+
status: "pending",
|
|
2754
|
+
options: [
|
|
2755
|
+
{ id: "deny", label: "Deny", variant: "secondary" },
|
|
2756
|
+
{ id: "allow", label: "Allow once", variant: "primary" }
|
|
2757
|
+
]
|
|
2758
|
+
}
|
|
2759
|
+
}));
|
|
2760
|
+
} else {
|
|
2761
|
+
const questions = Array.isArray(source.payload.questions) ? source.payload.questions : [];
|
|
2762
|
+
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
2763
|
+
id: requestId,
|
|
2764
|
+
server: "deepseek",
|
|
2765
|
+
tool: "ask_user",
|
|
2766
|
+
status: "in_progress",
|
|
2767
|
+
timestamp: source.timestamp,
|
|
2768
|
+
inputRequest: {
|
|
2769
|
+
requestId,
|
|
2770
|
+
status: "pending",
|
|
2771
|
+
questions: questions.flatMap((question) => {
|
|
2772
|
+
if (!isRecord(question) || typeof question.id !== "string" || typeof question.question !== "string") return [];
|
|
2773
|
+
const options = Array.isArray(question.options) ? question.options : [];
|
|
2774
|
+
return [{
|
|
2775
|
+
id: question.id,
|
|
2776
|
+
prompt: question.question,
|
|
2777
|
+
multiSelect: question.multiSelect === true,
|
|
2778
|
+
options: options.flatMap((option) => isRecord(option) && typeof option.label === "string" ? [{ id: `${question.id}:${option.label}`, label: option.label, ...typeof option.description === "string" ? { description: option.description } : {} }] : [])
|
|
2779
|
+
}];
|
|
2780
|
+
})
|
|
2781
|
+
}
|
|
2782
|
+
}));
|
|
2783
|
+
}
|
|
2784
|
+
continue;
|
|
2785
|
+
}
|
|
2786
|
+
if (source.type === "deepseek-input-resolved") {
|
|
2787
|
+
const requestId = typeof source.payload.requestId === "string" ? source.payload.requestId : "";
|
|
2788
|
+
const existing = messages.find((message) => message.type === "tool_call" && message.inputRequest?.requestId === requestId);
|
|
2789
|
+
if (existing?.type === "tool_call" && existing.inputRequest) {
|
|
2790
|
+
existing.inputRequest.status = source.payload.status === "aborted" ? "aborted" : "resolved";
|
|
2791
|
+
existing.status = source.payload.status === "aborted" ? "failed" : "completed";
|
|
2792
|
+
}
|
|
2793
|
+
continue;
|
|
2794
|
+
}
|
|
2795
|
+
if (source.type === "deepseek-jobs" && Array.isArray(source.payload.jobs)) {
|
|
2796
|
+
for (const job of source.payload.jobs) {
|
|
2797
|
+
if (!isRecord(job) || typeof job.id !== "string") continue;
|
|
2798
|
+
const existing = messages.find((message) => message.type === "background_task" && message.taskId === job.id);
|
|
2799
|
+
const status = normalizeBackgroundTaskStatus(job.status);
|
|
2800
|
+
const next = {
|
|
2801
|
+
id: existing?.id ?? `deepseek-job-${job.id}`,
|
|
2802
|
+
type: "background_task",
|
|
2803
|
+
taskId: job.id,
|
|
2804
|
+
status,
|
|
2805
|
+
description: typeof job.label === "string" ? job.label : void 0,
|
|
2806
|
+
taskType: typeof job.kind === "string" ? job.kind : void 0,
|
|
2807
|
+
error: status === "failed" && typeof job.detail === "string" ? job.detail : void 0,
|
|
2808
|
+
timestamp: existing?.timestamp ?? source.timestamp
|
|
2809
|
+
};
|
|
2810
|
+
if (existing?.type === "background_task") Object.assign(existing, next);
|
|
2811
|
+
else messages.push(next);
|
|
2812
|
+
}
|
|
2813
|
+
continue;
|
|
2814
|
+
}
|
|
2815
|
+
if (source.type !== "deepseek-session-event" || !isRecord(source.payload.event)) continue;
|
|
2816
|
+
const event = source.payload.event;
|
|
2817
|
+
const data = isRecord(event.data) ? event.data : {};
|
|
2818
|
+
const seq = typeof event.seq === "number" ? event.seq : source.timestamp;
|
|
2819
|
+
if (event.type === "assistant/message") {
|
|
2820
|
+
const content = getDeepseekAssistantMessageText(event, "text");
|
|
2821
|
+
const reasoning = getDeepseekAssistantMessageText(event, "reasoning");
|
|
2822
|
+
if (reasoning.trim()) messages.push({ id: `deepseek-reasoning-${seq}`, type: "reasoning", content: reasoning, status: "completed", timestamp: source.timestamp });
|
|
2823
|
+
if (content.trim()) messages.push({ id: `deepseek-assistant-${seq}`, type: "agent", content, timestamp: source.timestamp });
|
|
2824
|
+
continue;
|
|
2825
|
+
}
|
|
2826
|
+
if (event.type === "tool/call") {
|
|
2827
|
+
const callId = typeof data.callId === "string" ? data.callId : String(seq);
|
|
2828
|
+
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
2829
|
+
id: `deepseek-tool-${callId}`,
|
|
2830
|
+
server: "deepseek",
|
|
2831
|
+
tool: typeof data.name === "string" ? data.name : "tool",
|
|
2832
|
+
input: parseArguments(data.arguments),
|
|
2833
|
+
status: "in_progress",
|
|
2834
|
+
timestamp: source.timestamp
|
|
2835
|
+
}));
|
|
2836
|
+
continue;
|
|
2837
|
+
}
|
|
2838
|
+
if (event.type === "tool/result") {
|
|
2839
|
+
const message = isRecord(data.message) ? data.message : {};
|
|
2840
|
+
const messageSource = isRecord(message.source) ? message.source : {};
|
|
2841
|
+
const result2 = Array.isArray(message.content) && isRecord(message.content[0]) ? message.content[0] : {};
|
|
2842
|
+
const callId = typeof messageSource.callId === "string" ? messageSource.callId : typeof data.callId === "string" ? data.callId : String(seq);
|
|
2843
|
+
const existing = messages.find((message2) => message2.id === `deepseek-tool-${callId}` && message2.type === "tool_call");
|
|
2844
|
+
if (existing?.type === "tool_call") {
|
|
2845
|
+
existing.output = stringifyDisplayValue(result2.content ?? data.result);
|
|
2846
|
+
existing.status = result2.isError === true || data.isError === true ? "failed" : "completed";
|
|
2847
|
+
}
|
|
2848
|
+
continue;
|
|
2849
|
+
}
|
|
2850
|
+
if (event.type === "todo/write" && Array.isArray(data.items)) {
|
|
2851
|
+
messages.push({
|
|
2852
|
+
id: `deepseek-todo-${seq}`,
|
|
2853
|
+
type: "todo_list",
|
|
2854
|
+
items: data.items.flatMap((item) => {
|
|
2855
|
+
if (!isRecord(item) || typeof item.content !== "string") return [];
|
|
2856
|
+
const itemStatus = item.status === "in_progress" || item.status === "completed" ? item.status : "pending";
|
|
2857
|
+
return [{ text: item.content, completed: itemStatus === "completed", itemStatus }];
|
|
2858
|
+
}),
|
|
2859
|
+
timestamp: source.timestamp
|
|
2860
|
+
});
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
return messages;
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
// ../shared/src/display-message/parsers/fx-parser.ts
|
|
2867
|
+
function getFxTextChunk(update, kind) {
|
|
2868
|
+
if (!isRecord(update) || update.sessionUpdate !== kind || !isRecord(update.content) || update.content.type !== "text") return null;
|
|
2869
|
+
return typeof update.content.text === "string" && update.content.text ? update.content.text : null;
|
|
2870
|
+
}
|
|
2871
|
+
function parseFxEvents(events) {
|
|
2872
|
+
const messages = [];
|
|
2873
|
+
for (const event of events) {
|
|
2874
|
+
const content = getUserMessage(event);
|
|
2875
|
+
if (content !== null) {
|
|
2876
|
+
if (content.trim()) {
|
|
2877
|
+
messages.push({
|
|
2878
|
+
id: getUserMessageId(event) ?? `fx-user-${event.timestamp}`,
|
|
2879
|
+
type: "user",
|
|
2880
|
+
content,
|
|
2881
|
+
timestamp: event.timestamp
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2884
|
+
continue;
|
|
2885
|
+
}
|
|
2886
|
+
if (event.type === "fx-error") {
|
|
2887
|
+
messages.push({
|
|
2888
|
+
id: `fx-error-${event.timestamp}`,
|
|
2889
|
+
type: "error",
|
|
2890
|
+
message: typeof event.payload.message === "string" ? event.payload.message : "fx failed",
|
|
2891
|
+
timestamp: event.timestamp
|
|
2892
|
+
});
|
|
2893
|
+
continue;
|
|
2894
|
+
}
|
|
2895
|
+
if (event.type === "fx-turn-complete") {
|
|
2896
|
+
for (const message of messages) {
|
|
2897
|
+
if (message.type === "reasoning" && message.status === "in_progress") message.status = "completed";
|
|
2898
|
+
}
|
|
2899
|
+
continue;
|
|
2900
|
+
}
|
|
2901
|
+
if (event.type !== "fx-session-update" || !isRecord(event.payload.update)) continue;
|
|
2902
|
+
const update = event.payload.update;
|
|
2903
|
+
const kind = update.sessionUpdate;
|
|
2904
|
+
if (kind === "agent_message_chunk" || kind === "agent_thought_chunk") {
|
|
2905
|
+
const content2 = getFxTextChunk(update, kind);
|
|
2906
|
+
if (!content2) continue;
|
|
2907
|
+
const id = typeof update.messageId === "string" ? `fx-${update.messageId}` : `fx-${kind}-${event.timestamp}`;
|
|
2908
|
+
const existing = messages.find((message) => message.id === id);
|
|
2909
|
+
const text = `${existing && "content" in existing && typeof existing.content === "string" ? existing.content : ""}${content2}`;
|
|
2910
|
+
upsertDisplayMessage(messages, kind === "agent_thought_chunk" ? { id, type: "reasoning", content: text, status: "in_progress", timestamp: existing?.timestamp ?? event.timestamp } : { id, type: "agent", content: text, timestamp: existing?.timestamp ?? event.timestamp });
|
|
2911
|
+
continue;
|
|
2912
|
+
}
|
|
2913
|
+
if ((kind === "tool_call" || kind === "tool_call_update") && typeof update.toolCallId === "string") {
|
|
2914
|
+
const id = `fx-tool-${update.toolCallId}`;
|
|
2915
|
+
const existing = messages.find((message) => message.id === id && message.type === "tool_call");
|
|
2916
|
+
const status = update.status === "completed" || update.status === "failed" ? update.status === "failed" ? "failed" : "completed" : "in_progress";
|
|
2917
|
+
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
2918
|
+
id,
|
|
2919
|
+
server: "fx",
|
|
2920
|
+
tool: typeof update.name === "string" ? update.name : typeof update.title === "string" ? update.title : existing?.tool ?? "tool",
|
|
2921
|
+
input: update.rawInput === void 0 ? existing?.input : isRecord(update.rawInput) ? update.rawInput : stringifyDisplayValue(update.rawInput),
|
|
2922
|
+
output: update.rawOutput === void 0 ? existing?.output : stringifyDisplayValue(update.rawOutput),
|
|
2923
|
+
status,
|
|
2924
|
+
timestamp: event.timestamp
|
|
2925
|
+
}));
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
return messages;
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2584
2931
|
// ../shared/src/display-message/parsers/opencode-parser.ts
|
|
2585
2932
|
function timestampFromMs(value, fallback) {
|
|
2586
2933
|
return typeof value === "number" && Number.isFinite(value) ? new Date(value).toISOString() : fallback;
|
|
@@ -3327,6 +3674,12 @@ function parseAgentEvents(events, agentType) {
|
|
|
3327
3674
|
if (agentType === "cursor") {
|
|
3328
3675
|
return parseCursorEvents(events);
|
|
3329
3676
|
}
|
|
3677
|
+
if (agentType === "deepseek") {
|
|
3678
|
+
return parseDeepseekEvents(events);
|
|
3679
|
+
}
|
|
3680
|
+
if (agentType === "fx") {
|
|
3681
|
+
return parseFxEvents(events);
|
|
3682
|
+
}
|
|
3330
3683
|
if (agentType === "opencode") {
|
|
3331
3684
|
return parseOpencodeEvents(events);
|
|
3332
3685
|
}
|
|
@@ -3336,6 +3689,80 @@ function parseAgentEvents(events, agentType) {
|
|
|
3336
3689
|
return parseClaudeEvents(events);
|
|
3337
3690
|
}
|
|
3338
3691
|
|
|
3692
|
+
// ../shared/src/pricing.ts
|
|
3693
|
+
var AUTOMATED_SOURCES = ["api", "automation"];
|
|
3694
|
+
var AUTOMATED_SOURCES_SQL = AUTOMATED_SOURCES.map((s) => `'${s}'`).join(", ");
|
|
3695
|
+
var PLANS = {
|
|
3696
|
+
trial: {
|
|
3697
|
+
id: "trial",
|
|
3698
|
+
name: "Free Trial",
|
|
3699
|
+
monthlyPrice: 0,
|
|
3700
|
+
seatPriceCents: 0,
|
|
3701
|
+
features: [
|
|
3702
|
+
"14 days free, no credit card required",
|
|
3703
|
+
"Unlimited manual workspace minutes",
|
|
3704
|
+
"15,000 automated workspace minutes",
|
|
3705
|
+
"Unlimited repositories and environments",
|
|
3706
|
+
"Unlimited automations",
|
|
3707
|
+
"Warm pools and warm hooks",
|
|
3708
|
+
"API access"
|
|
3709
|
+
]
|
|
3710
|
+
},
|
|
3711
|
+
developer: {
|
|
3712
|
+
id: "developer",
|
|
3713
|
+
name: "Developer",
|
|
3714
|
+
monthlyPrice: 120,
|
|
3715
|
+
seatPriceCents: 12e3,
|
|
3716
|
+
features: [
|
|
3717
|
+
"Unlimited manual workspace minutes",
|
|
3718
|
+
"5,000 automated workspace minutes per month",
|
|
3719
|
+
"Up to 10 repositories",
|
|
3720
|
+
"Up to 15 environments",
|
|
3721
|
+
"Up to 5 automations",
|
|
3722
|
+
"Warm pools and warm hooks",
|
|
3723
|
+
"API access"
|
|
3724
|
+
]
|
|
3725
|
+
},
|
|
3726
|
+
team: {
|
|
3727
|
+
id: "team",
|
|
3728
|
+
name: "Team",
|
|
3729
|
+
monthlyPrice: 300,
|
|
3730
|
+
seatPriceCents: 3e4,
|
|
3731
|
+
features: [
|
|
3732
|
+
"Unlimited manual workspace minutes",
|
|
3733
|
+
"15,000 automated workspace minutes per month",
|
|
3734
|
+
"Unlimited repositories",
|
|
3735
|
+
"Unlimited automations",
|
|
3736
|
+
"Warm pools and warm hooks",
|
|
3737
|
+
"Higher API rate limits",
|
|
3738
|
+
"Access to a static egress IP",
|
|
3739
|
+
"Auto-upgraded sandbox resources (4 vCPU, 32 GB disk, 16 GB memory)",
|
|
3740
|
+
"Shared Slack support channel"
|
|
3741
|
+
]
|
|
3742
|
+
},
|
|
3743
|
+
enterprise: {
|
|
3744
|
+
id: "enterprise",
|
|
3745
|
+
name: "Enterprise",
|
|
3746
|
+
monthlyPrice: 0,
|
|
3747
|
+
seatPriceCents: 0,
|
|
3748
|
+
features: [
|
|
3749
|
+
"Unlimited manual workspace minutes",
|
|
3750
|
+
"Unlimited automated workspace minutes",
|
|
3751
|
+
"Unlimited automations",
|
|
3752
|
+
"Custom warm hooks and pools",
|
|
3753
|
+
"Custom API rates",
|
|
3754
|
+
"Custom rate limits",
|
|
3755
|
+
"Shared Slack support channel",
|
|
3756
|
+
"SOC 2",
|
|
3757
|
+
"Data Processing Agreement (DPA)",
|
|
3758
|
+
"SCIM user provisioning",
|
|
3759
|
+
"Custom security and privacy settings"
|
|
3760
|
+
]
|
|
3761
|
+
}
|
|
3762
|
+
};
|
|
3763
|
+
var TEAM_PLAN = PLANS.team;
|
|
3764
|
+
var ENTERPRISE_PLAN = PLANS.enterprise;
|
|
3765
|
+
|
|
3339
3766
|
// ../shared/src/routes/workspaces.ts
|
|
3340
3767
|
var WORKSPACE_STATUSES = ["active", "sleeping", "archived", "preparing", "error"];
|
|
3341
3768
|
var VALID_LIFECYCLE_POLICIES = ["default", "archive_when_done", "sleep_when_done", "delete_after_inactivity"];
|
|
@@ -3396,24 +3823,24 @@ function result(data, isError = false) {
|
|
|
3396
3823
|
}
|
|
3397
3824
|
var server = new McpServer({
|
|
3398
3825
|
name: "replicas-mcp",
|
|
3399
|
-
version: "0.2.
|
|
3826
|
+
version: "0.2.13"
|
|
3400
3827
|
});
|
|
3401
3828
|
var registerTool = server.registerTool.bind(server);
|
|
3402
|
-
var codingAgentSchema =
|
|
3829
|
+
var codingAgentSchema = z3.string().refine(isValidCodingAgentProvider, {
|
|
3403
3830
|
message: `Coding agent must be ${getCodingAgentDisplayNames()}`
|
|
3404
3831
|
});
|
|
3405
|
-
var lifecyclePolicySchema =
|
|
3832
|
+
var lifecyclePolicySchema = z3.enum(VALID_LIFECYCLE_POLICIES);
|
|
3406
3833
|
registerTool(
|
|
3407
3834
|
"create_replica",
|
|
3408
3835
|
{
|
|
3409
3836
|
description: "Create a new replica workspace and send initial message",
|
|
3410
3837
|
inputSchema: {
|
|
3411
|
-
name:
|
|
3412
|
-
message:
|
|
3413
|
-
repository_ids:
|
|
3414
|
-
repository_set_id:
|
|
3838
|
+
name: z3.string().regex(/^\S+$/, "Name cannot contain spaces"),
|
|
3839
|
+
message: z3.string(),
|
|
3840
|
+
repository_ids: z3.array(z3.string()).min(1).optional().describe("Repository IDs to include. Mutually exclusive with repository_set_id."),
|
|
3841
|
+
repository_set_id: z3.string().optional().describe("Repository set ID to use. Mutually exclusive with repository_ids."),
|
|
3415
3842
|
coding_agent: codingAgentSchema.optional().describe("Coding agent to use (default: claude)"),
|
|
3416
|
-
model:
|
|
3843
|
+
model: z3.string().optional().describe("Model to use for the coding agent"),
|
|
3417
3844
|
lifecycle_policy: lifecyclePolicySchema.optional().describe("Lifecycle policy for the workspace")
|
|
3418
3845
|
}
|
|
3419
3846
|
},
|
|
@@ -3439,11 +3866,11 @@ registerTool(
|
|
|
3439
3866
|
{
|
|
3440
3867
|
description: "List all replicas with pagination and optional filters",
|
|
3441
3868
|
inputSchema: {
|
|
3442
|
-
page:
|
|
3443
|
-
limit:
|
|
3444
|
-
user_id:
|
|
3445
|
-
source:
|
|
3446
|
-
status:
|
|
3869
|
+
page: z3.number().optional(),
|
|
3870
|
+
limit: z3.number().optional(),
|
|
3871
|
+
user_id: z3.string().optional().describe("Filter by creator user ID"),
|
|
3872
|
+
source: z3.enum(["api", "dashboard", "slack", "linear", "github", "gitlab", "automation"]).optional().describe("Filter by creation source"),
|
|
3873
|
+
status: z3.enum(["active", "sleeping", "preparing"]).optional().describe("Filter by workspace status")
|
|
3447
3874
|
}
|
|
3448
3875
|
},
|
|
3449
3876
|
async (args) => {
|
|
@@ -3466,8 +3893,8 @@ registerTool(
|
|
|
3466
3893
|
{
|
|
3467
3894
|
description: "Get replica details by ID, including current status, chats, and repository statuses",
|
|
3468
3895
|
inputSchema: {
|
|
3469
|
-
id:
|
|
3470
|
-
include:
|
|
3896
|
+
id: z3.string(),
|
|
3897
|
+
include: z3.array(z3.enum(["environment", "diffs"])).optional().describe("Extra data to include in response")
|
|
3471
3898
|
}
|
|
3472
3899
|
},
|
|
3473
3900
|
async (args) => {
|
|
@@ -3486,12 +3913,12 @@ registerTool(
|
|
|
3486
3913
|
{
|
|
3487
3914
|
description: "Send a message to an existing replica. Automatically handles waking sleeping replicas.",
|
|
3488
3915
|
inputSchema: {
|
|
3489
|
-
id:
|
|
3490
|
-
message:
|
|
3916
|
+
id: z3.string(),
|
|
3917
|
+
message: z3.string(),
|
|
3491
3918
|
coding_agent: codingAgentSchema.optional().describe("Coding agent to use"),
|
|
3492
|
-
chat_id:
|
|
3493
|
-
model:
|
|
3494
|
-
plan_mode:
|
|
3919
|
+
chat_id: z3.string().optional().describe("Chat ID to send the message to (uses default chat if omitted)"),
|
|
3920
|
+
model: z3.string().optional().describe("Model to use"),
|
|
3921
|
+
plan_mode: z3.boolean().optional().describe("Whether to use plan mode")
|
|
3495
3922
|
}
|
|
3496
3923
|
},
|
|
3497
3924
|
async (args) => {
|
|
@@ -3512,7 +3939,7 @@ registerTool(
|
|
|
3512
3939
|
{
|
|
3513
3940
|
description: "Delete a replica. This terminates the workspace and cannot be undone.",
|
|
3514
3941
|
inputSchema: {
|
|
3515
|
-
id:
|
|
3942
|
+
id: z3.string()
|
|
3516
3943
|
}
|
|
3517
3944
|
},
|
|
3518
3945
|
async (args) => {
|
|
@@ -3554,7 +3981,7 @@ registerTool(
|
|
|
3554
3981
|
{
|
|
3555
3982
|
description: "List chats in a replica workspace",
|
|
3556
3983
|
inputSchema: {
|
|
3557
|
-
id:
|
|
3984
|
+
id: z3.string().describe("Replica ID")
|
|
3558
3985
|
}
|
|
3559
3986
|
},
|
|
3560
3987
|
async (args) => {
|
|
@@ -3570,9 +3997,9 @@ registerTool(
|
|
|
3570
3997
|
{
|
|
3571
3998
|
description: "Create a new chat in a replica workspace",
|
|
3572
3999
|
inputSchema: {
|
|
3573
|
-
id:
|
|
4000
|
+
id: z3.string().describe("Replica ID"),
|
|
3574
4001
|
provider: codingAgentSchema.describe("Coding agent provider for the chat"),
|
|
3575
|
-
title:
|
|
4002
|
+
title: z3.string().optional().describe("Optional title for the chat")
|
|
3576
4003
|
}
|
|
3577
4004
|
},
|
|
3578
4005
|
async (args) => {
|
|
@@ -3590,8 +4017,8 @@ registerTool(
|
|
|
3590
4017
|
{
|
|
3591
4018
|
description: "Delete a chat from a replica workspace",
|
|
3592
4019
|
inputSchema: {
|
|
3593
|
-
id:
|
|
3594
|
-
chat_id:
|
|
4020
|
+
id: z3.string().describe("Replica ID"),
|
|
4021
|
+
chat_id: z3.string().describe("Chat ID to delete")
|
|
3595
4022
|
}
|
|
3596
4023
|
},
|
|
3597
4024
|
async (args) => {
|
|
@@ -3607,8 +4034,8 @@ registerTool(
|
|
|
3607
4034
|
{
|
|
3608
4035
|
description: "Read conversation history of a replica. Returns parsed DisplayMessage objects (user messages, agent responses, commands, file changes, tool calls, etc). If the workspace is sleeping, it will be woken and you should retry in 30-90 seconds.",
|
|
3609
4036
|
inputSchema: {
|
|
3610
|
-
id:
|
|
3611
|
-
chat_id:
|
|
4037
|
+
id: z3.string(),
|
|
4038
|
+
chat_id: z3.string().optional().describe("Read history for a specific chat (uses default chat if omitted)")
|
|
3612
4039
|
}
|
|
3613
4040
|
},
|
|
3614
4041
|
async (args) => {
|
|
@@ -3642,7 +4069,7 @@ registerTool(
|
|
|
3642
4069
|
{
|
|
3643
4070
|
description: "Get warm and start hook logs for a replica workspace",
|
|
3644
4071
|
inputSchema: {
|
|
3645
|
-
id:
|
|
4072
|
+
id: z3.string().describe("Replica ID")
|
|
3646
4073
|
}
|
|
3647
4074
|
},
|
|
3648
4075
|
async (args) => {
|
package/package.json
CHANGED