replicas-mcp 0.2.14 → 0.2.15

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # replicas-mcp
2
2
 
3
- Stdio MCP server for [Replicas](https://tryreplicas.com) - cloud workspaces for AI coding agents.
3
+ Stdio MCP server for [Replicas](https://replicas.dev) - cloud workspaces for AI coding agents.
4
4
 
5
- For MCP clients that require a remote server URL instead of stdio, use the streamable HTTP endpoint at `https://api.tryreplicas.com/v1/mcp`.
5
+ For MCP clients that require a remote server URL instead of stdio, use the streamable HTTP endpoint at `https://api.replicas.dev/v1/mcp`.
6
6
 
7
7
  ## Installation
8
8
 
@@ -20,7 +20,7 @@ For MCP clients that require a remote server URL instead of stdio, use the strea
20
20
  }
21
21
  ```
22
22
 
23
- Get your API key from [Settings > API Keys](https://tryreplicas.com/dashboard/settings?tab=api-keys).
23
+ Get your API key from [Settings > API Keys](https://replicas.dev/dashboard/settings?tab=api-keys).
24
24
 
25
25
  ## Tools
26
26
 
package/dist/index.js CHANGED
@@ -181,6 +181,7 @@ var WEB_APP_PATHS = {
181
181
  automations: `${HOME_PATH}/automations`,
182
182
  environment: `${HOME_PATH}/environment`,
183
183
  analytics: `${HOME_PATH}/analytics`,
184
+ memory: `${HOME_PATH}/memory`,
184
185
  dashboard: DASHBOARD_PATH,
185
186
  agents: `${DASHBOARD_PATH}/agents`,
186
187
  integrations: `${DASHBOARD_PATH}/integrations`,
@@ -192,6 +193,7 @@ var WEB_APP_PATHS = {
192
193
  "audit-logs": `${DASHBOARD_PATH}/audit-logs`,
193
194
  accountAgents: `${DASHBOARD_PATH}/account/agents`,
194
195
  accountProfile: `${DASHBOARD_PATH}/account/profile`,
196
+ accountConnections: `${DASHBOARD_PATH}/account/connections`,
195
197
  accountIntegrations: `${DASHBOARD_PATH}/account/integrations`,
196
198
  accountApiKeys: `${DASHBOARD_PATH}/account/api-keys`,
197
199
  accountPreferences: `${DASHBOARD_PATH}/account/preferences`,
@@ -264,10 +266,12 @@ replicas computer record stop
264
266
  replicas media upload /tmp/demo.mp4 --name "Demo recording"
265
267
  \`\`\`
266
268
 
269
+ For any external destination, continue with the required delivery flow in \`MEDIA.md\`.
270
+
267
271
  ## Command reference
268
272
 
269
273
  ### \`replicas computer info\`
270
- Prints the live desktop viewer URL (\`https://6080-<hash>.tryreplicas.com/\`). The engine auto-registers this authenticated preview on startup; \`info\` just looks it up. Use it when you want to share the live stream URL with the user out-of-band (e.g. in a Slack reply) - the dashboard \`Desktop\` tab already points at the same URL automatically.
274
+ Prints the live desktop viewer URL (\`https://6080-<hash>.replicas.dev/\`). The engine auto-registers this authenticated preview on startup; \`info\` just looks it up. Use it when you want to share the live stream URL with the user out-of-band (e.g. in a Slack reply) - the dashboard \`Desktop\` tab already points at the same URL automatically.
271
275
 
272
276
  If invoked very early in the workspace lifecycle, \`info\` will poll briefly while the engine finishes registering the preview, then error if it's still not available.
273
277
 
@@ -398,7 +402,7 @@ replicas computer record start /tmp/walkthrough.mp4
398
402
  replicas computer record stop
399
403
  replicas media upload /tmp/walkthrough.mp4 --name "Walkthrough recording"
400
404
  \`\`\`
401
- Then embed the printed \`![\u2026](\u2026)\` line in your chat reply. See \`MEDIA.md\`.
405
+ Then embed the printed \`![\u2026](\u2026)\` line in your chat reply and follow \`MEDIA.md\` for any external destination.
402
406
 
403
407
  ## Failure modes
404
408
 
@@ -598,16 +602,9 @@ gh pr review 123 --approve
598
602
  gh pr review 123 --request-changes --body "Changes needed"
599
603
  \`\`\`
600
604
 
601
- ## Image Uploads in PRs
605
+ ## Media in GitHub workflows
602
606
 
603
- GitHub does NOT have a public API for uploading images to PRs/issues. When you need to include images:
604
- - Do NOT use placeholder image URLs
605
- - Do NOT commit screenshots as files to the repository
606
- - Run \`replicas media upload <image> --name "<display name>" --share\` and put the printed \`Forge embed\` Markdown in the PR body or comment
607
- - For a self-contained HTML report, run \`replicas media upload <page.html> --name "<display name>" --access organization\` and put the printed \`Forge link\` Markdown in the PR body or comment. Organization members who are already signed in open it directly; others sign in and return to the page
608
- - For video, embed a shared poster image linked to the recording's **View in Replicas** URL; GitHub does not reliably render externally hosted video inline
609
- - Treat the public URL as an opt-in bearer capability; revoke it with \`replicas media revoke <media-id>\` only when the user asks or the media should stop rendering \u2014 revoking breaks embeds already posted on the PR
610
- - If you were triggered from Slack, also upload the image to the Slack thread so the user can see it directly
607
+ Media delivery is owned by \`references/MEDIA.md\`. Read its GitHub section before adding screenshots, recordings, diagrams, or HTML reports to a pull request, issue, review comment, or commit; it covers the Replicas upload, GitHub's inline fallback, and the required **View in Replicas** link.
611
608
  `;
612
609
  var GITHUB_ABILITY = {
613
610
  label: "GitHub",
@@ -669,7 +666,7 @@ await replicas.gitlab.request('/projects/group%2Frepo/pipelines', {
669
666
 
670
667
  ## Descriptions and media
671
668
 
672
- API updates replace the entire merge request description, so always preserve the required Replicas footer and co-author trailers. For media, first run \`replicas media upload\` as documented in \`MEDIA.md\`; use GitLab's project uploads endpoint only when a native repository-protected embed is required.
669
+ API updates replace the entire merge request description, so always preserve the required Replicas footer and co-author trailers. Media delivery is owned by \`references/MEDIA.md\`; read its GitLab section before adding media so the original bytes are uploaded to Replicas and GitLab and the dashboard link remains secondary.
673
670
  `;
674
671
  var GITLAB_ABILITY = {
675
672
  label: "GitLab",
@@ -734,6 +731,8 @@ await replicas.linear.graphql({
734
731
  \`\`\`
735
732
 
736
733
  Search with \`containsIgnoreCase: $query\` filters, for example on both \`title\` and \`description\`. Batch independent queries with \`Promise.all\` to save round trips.
734
+
735
+ For screenshots, recordings, diagrams, or other media, read \`references/MEDIA.md\` before adding it to an issue or comment. It is the single source of truth for uploading the Replicas copy and the raw file to Linear; a dashboard link alone is not an inline attachment.
737
736
  `;
738
737
  var LINEAR_ABILITY = {
739
738
  label: "Linear",
@@ -745,18 +744,19 @@ var LINEAR_ABILITY = {
745
744
 
746
745
  // ../shared/src/default-skills/replicas-agent/abilities/media.ts
747
746
  var SECTION6 = `### Media
748
- Share screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external messages.
747
+ Deliver screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages to the Replicas dashboard and, when applicable, inline in the destination workflow.
749
748
 
750
749
  **Reference:** \`references/MEDIA.md\`
751
750
 
752
751
  Use this when:
752
+ - You are about to run \`replicas media upload\`; this reference owns the complete Replicas-first, destination-second workflow
753
753
  - You produce a screenshot, recording, generated image, or audio clip the user should see
754
754
  - You produce a self-contained HTML report that should be linked from a pull request
755
755
  - You record video output (browser automation, screen capture) \u2014 including the recommended aspect ratio and FPS
756
- - You need to embed media in a Slack/Linear/GitHub message AND keep a referenceable copy in the Replicas dashboard`;
756
+ - You need to embed media in a Slack/Linear/GitHub/GitLab message AND keep a referenceable copy in the Replicas dashboard`;
757
757
  var REFERENCE6 = `# Media (Screenshots, Recordings, Audio, HTML)
758
758
 
759
- 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).
759
+ This is the single source of truth for delivering screenshots, screen recordings, generated diagrams, audio clips, and self-contained HTML pages through Replicas and external surfaces (Slack, Linear, GitHub, GitLab).
760
760
 
761
761
  ## Prerequisites
762
762
 
@@ -766,12 +766,32 @@ The \`replicas\` CLI is pre-installed and authenticated in your workspace. No ad
766
766
 
767
767
  Upload to Replicas in these cases \u2014 and **only** these cases:
768
768
 
769
- 1. **Media you produce.** Any screenshot, screen recording, generated diagram, or audio clip you create that the user might want to see. Upload before doing anything else with the file (analyzing, deleting, sending elsewhere). This applies even when you're also sending the file to Slack, Linear, GitHub, etc.
769
+ 1. **Media you produce.** Any screenshot, screen recording, generated diagram, audio clip, or HTML page you create that the user might want to see. Upload before doing anything else with the file (analyzing, deleting, sending elsewhere). This applies even when you're also sending the file to Slack, Linear, GitHub, or GitLab.
770
770
  2. **Files the user explicitly asks you to upload.** If the user sends or points at a file (image, video, audio, HTML) and asks you to upload it, run \`replicas media upload\`. Otherwise leave it alone \u2014 files in the workspace the user did not ask about should not be auto-uploaded as media.
771
- 3. **Anything you plan to share externally (Slack, Linear, GitHub, etc.).** Upload to Replicas *in addition to* the platform's native upload. Never as a replacement.
771
+ 3. **Anything you plan to share externally (Slack, Linear, GitHub, GitLab, etc.).** Upload to Replicas *in addition to* the platform's destination upload. Never as a replacement.
772
772
 
773
773
  If none of these apply, don't upload.
774
774
 
775
+ ## Required delivery contract
776
+
777
+ \`replicas media upload\` is always the first delivery action. When the current task has an external destination, every other delivery step follows only after that command succeeds. For every file:
778
+
779
+ 1. First, run \`replicas media upload\` with the original file. Do not begin any destination upload until the command succeeds. This creates the canonical dashboard copy and prints the authenticated chat embed plus a per-file dashboard link.
780
+ 2. Include the printed embed line in the Replicas chat reply, followed by the matching **View in Replicas** link. HTML uses its printed page link instead of an image embed.
781
+ 3. Identify every destination in the task and attempt to upload the same original bytes there. Use the destination's inline representation from the table below; do not replace the file with a Replicas link.
782
+ 4. Put the **View in Replicas** dashboard link next to the destination embed as a secondary link.
783
+ 5. Check each destination response. If a native upload is unavailable or fails, say so explicitly and keep the dashboard link; never claim that a link is an inline upload.
784
+
785
+ | Destination | Required file delivery | Inline result |
786
+ |---|---|---|
787
+ | Replicas dashboard/chat | \`replicas media upload\` | Printed \`![\u2026](\u2026)\` line in chat |
788
+ | Slack | \`files.getUploadURLExternal\` \u2192 raw-byte POST \u2192 \`files.completeUploadExternal\` | Uploaded file in the channel or thread |
789
+ | Linear | \`fileUpload\` mutation \u2192 presigned upload \u2192 issue/comment mutation | Returned \`assetUrl\` in Markdown |
790
+ | GitLab | Project \`/uploads\` endpoint with the original bytes | Returned GitLab Markdown |
791
+ | GitHub | No supported attachment API; use a Replicas public forge share for the inline image or video poster | Printed Forge embed, linked to the recording when needed |
792
+
793
+ The dashboard link is the subtitle and jump-back path. It is never a substitute for the destination upload.
794
+
775
795
  ## Uploading to Replicas
776
796
 
777
797
  \`\`\`bash
@@ -799,7 +819,7 @@ Names are normalized to hyphen-case (spaces become hyphens, e.g. \`Login page\`
799
819
  For each media file, the CLI prints two lines:
800
820
 
801
821
  1. \`![filename](<api-url>)\` \u2014 the chat embed (renders inline in Replicas chat **only** \u2014 see below).
802
- 2. \`View in Replicas: <deep-link>\` \u2014 a per-file dashboard URL of the form \`https://tryreplicas.com/workspaces/<workspace-id>?media=<media-id>\` that opens directly to that specific file.
822
+ 2. \`View in Replicas: <deep-link>\` \u2014 a per-file dashboard URL of the form \`https://replicas.dev/workspaces/<workspace-id>?media=<media-id>\` that opens directly to that specific file.
803
823
 
804
824
  Match each "View in Replicas" line to the embed line directly above it \u2014 that's the deep link for that file.
805
825
 
@@ -825,19 +845,20 @@ replicas media upload screenshot.png --name "Login page" --access public
825
845
 
826
846
  | URL | What it is | Where it's allowed |
827
847
  |---|---|---|
828
- | \`https://api.tryreplicas.com/v1/media/<id>\` (inside \`![\u2026](\u2026)\`) | Authenticated API redirect to a presigned blob \u2014 requires the Replicas chat session | **Only** in the Replicas chat reply. Nowhere else. |
829
- | \`https://tryreplicas.com/organizations/<organization-id>/media/<media-id>\` | Organization-only page printed by \`--access organization\` | Pull requests and other places where every viewer belongs to the Replicas organization. |
830
- | \`https://api.tryreplicas.com/v1/media/public/<id>/<token>\` | Opt-in public bearer URL printed by \`--access public\` or \`--share\` | GitHub embeds for image, video, or audio media. |
831
- | \`https://tryreplicas.com/workspaces/<workspace-id>?media=<media-id>\` | Authenticated dashboard deep link that opens the media file in the workspace | Everywhere external \u2014 Slack, GitHub, Linear, PR bodies, comments, emails. |
848
+ | \`https://api.replicas.dev/v1/media/<id>\` (inside \`![\u2026](\u2026)\`) | Authenticated API redirect to a presigned blob \u2014 requires the Replicas chat session | **Only** in the Replicas chat reply. Nowhere else. |
849
+ | \`https://replicas.dev/organizations/<organization-id>/media/<media-id>\` | Organization-only page printed by \`--access organization\` | Pull requests and other places where every viewer belongs to the Replicas organization. |
850
+ | \`https://api.replicas.dev/v1/media/public/<id>/<token>\` | Opt-in public bearer URL printed by \`--access public\` or \`--share\` | GitHub embeds for image, video, or audio media. |
851
+ | \`https://replicas.dev/workspaces/<workspace-id>?media=<media-id>\` | Authenticated dashboard deep link that opens the media file in the workspace | Everywhere external: Slack, GitHub, GitLab, Linear, PR bodies, comments, emails. |
832
852
 
833
853
  ### NEVER link the API redirect URL outside the Replicas chat reply
834
854
 
835
- The \`api.tryreplicas.com/v1/media/<id>\` URL is **not public**. It's an authenticated redirect that only resolves to a presigned download when the Replicas chat session token is present. Anywhere else (Slack, Linear, GitHub, a browser tab the user opens directly, a customer copy-pasting from chat) it returns \`{"error":"Missing authorization token"}\` and renders as a broken image.
855
+ The \`api.replicas.dev/v1/media/<id>\` URL is **not public**. It's an authenticated redirect that only resolves to a presigned download when the Replicas chat session token is present. Anywhere else (Slack, Linear, GitHub, a browser tab the user opens directly, a customer copy-pasting from chat) it returns \`{"error":"Missing authorization token"}\` and renders as a broken image.
836
856
 
837
857
  This rule has no exceptions:
838
858
  - \u274C Never paste it in a Slack message \u2014 upload the actual bytes via the 3-step \`files.getUploadURLExternal\` \u2192 POST bytes \u2192 \`files.completeUploadExternal\` flow instead (see below).
839
859
  - \u274C Never paste it in a GitHub PR description, issue body, review comment, or commit message.
840
860
  - \u274C Never paste it in a Linear issue body or comment \u2014 upload via Linear's \`fileUpload\` mutation instead (see below).
861
+ - \u274C Never paste it in a GitLab merge request or issue; upload the original bytes through GitLab's project upload endpoint instead (see below).
841
862
  - \u274C Never link to it from any external doc, email, or external chat.
842
863
  - \u274C Never include it as a "backup link" in case the dashboard link breaks \u2014 it will always break externally.
843
864
 
@@ -846,7 +867,7 @@ This rule has no exceptions:
846
867
  For an organization-only HTML page, use the \`Forge link\` printed by \`--access organization\`. For other authenticated media references, use the dashboard form:
847
868
 
848
869
  \`\`\`
849
- https://tryreplicas.com/workspaces/<workspace-id>?media=<media-id>
870
+ https://replicas.dev/workspaces/<workspace-id>?media=<media-id>
850
871
  \`\`\`
851
872
 
852
873
  The \`media=<media-id>\` query param opens that specific file in the workspace.
@@ -861,20 +882,20 @@ Include each markdown embed line **verbatim** where you want that file to render
861
882
 
862
883
  After (or alongside) the embeds, include a \`[View in Replicas](<deep-link>)\` hyperlink for each file using the per-file dashboard URL from the CLI. This lets the user open the specific item in the workspace.
863
884
 
864
- ## On external platforms \u2014 upload natively AND link the dashboard
885
+ ## On external platforms: embed the file AND link the dashboard
865
886
 
866
- Sharing media externally is a **two-step requirement** for every file:
887
+ After \`replicas media upload\` succeeds, external delivery has two required follow-up steps for every file:
867
888
 
868
- 1. **Upload the raw bytes natively to that platform** so the recipient sees the media embedded inline in the message itself.
889
+ 1. **Upload the raw bytes through that platform's supported inline path** so the recipient sees the media embedded in the message itself.
869
890
  2. **Link the Replicas dashboard deep link** (\`?media=<id>\` form) so the user can jump straight to the file in the workspace.
870
891
 
871
- A link alone is not enough. A native upload alone is not enough. Do both.
892
+ A link alone is not enough. An upload without the dashboard link is not enough. Do both.
872
893
 
873
- GitHub has no native upload API, so use an explicit Replicas public share for screenshots and recording previews. GitLab has a native upload API and should receive the original bytes.
894
+ Slack, Linear, and GitLab receive the original bytes through their native upload APIs. GitHub has no supported attachment API, so use an explicit Replicas public share for screenshots and recording previews.
874
895
 
875
896
  ### Slack \u2014 embed natively via the 3-step external file upload flow
876
897
 
877
- A Slack message that just contains a \`tryreplicas.com\` link is not acceptable when the message is supposed to show an image. The recipient should see the image inline in the thread.
898
+ A Slack message that just contains a \`replicas.dev\` link is not acceptable when the message is supposed to show an image. The recipient should see the image inline in the thread.
878
899
 
879
900
  Slack deprecated the single-shot \`files.upload\` endpoint. The raw HTTP replacement is a 3-step flow: reserve an upload URL with \`files.getUploadURLExternal\`, POST the bytes to it, then share into the channel/thread with \`files.completeUploadExternal\`. (\`files.uploadV2\` is **only** an SDK convenience wrapper \u2014 it is NOT a real Web API HTTP endpoint and \`POST https://slack.com/api/files.uploadV2\` will return \`unknown_method\`.)
880
901
 
@@ -906,7 +927,7 @@ curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
906
927
  \\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"Screenshot\\"}],
907
928
  \\"channel_id\\": \\"CHANNEL_ID\\",
908
929
  \\"thread_ts\\": \\"THREAD_TS\\",
909
- \\"initial_comment\\": \\"<https://tryreplicas.com/workspaces/<workspace-id>?media=<media-id>|View in Replicas>\\"
930
+ \\"initial_comment\\": \\"<https://replicas.dev/workspaces/<workspace-id>?media=<media-id>|View in Replicas>\\"
910
931
  }"
911
932
  \`\`\`
912
933
 
@@ -917,7 +938,7 @@ Notes:
917
938
  - For multiple files in the same message, run steps 1\u20132 per file and pass all \`{id, title}\` objects in the \`files\` array of a single \`files.completeUploadExternal\` call \u2014 they share into the thread together.
918
939
  - If you also need to post a separate text reply in the thread, send it with \`chat.postMessage\` after the upload \u2014 but the upload itself must carry the image.
919
940
 
920
- Never paste the \`api.tryreplicas.com/v1/media/<id>\` URL into a Slack message body or \`initial_comment\` \u2014 it will render as a broken image attempt.
941
+ Never paste the \`api.replicas.dev/v1/media/<id>\` URL into a Slack message body or \`initial_comment\` \u2014 it will render as a broken image attempt.
921
942
 
922
943
  ### Linear \u2014 embed natively via the GraphQL \`fileUpload\` mutation
923
944
 
@@ -966,7 +987,7 @@ curl -s -X PUT "$UPLOAD_URL" \\
966
987
  --data-binary @"$FILE"
967
988
 
968
989
  # 3. Reference assetUrl inline in the comment body, alongside the dashboard link.
969
- BODY=$(printf '![screenshot](%s)\\n\\n[View in Replicas](https://tryreplicas.com/workspaces/%s?media=%s)' \\
990
+ BODY=$(printf '![screenshot](%s)\\n\\n[View in Replicas](https://replicas.dev/workspaces/%s?media=%s)' \\
970
991
  "$ASSET_URL" "$REPLICAS_WORKSPACE_ID" "$MEDIA_ID")
971
992
 
972
993
  jq -n \\
@@ -980,7 +1001,7 @@ jq -n \\
980
1001
 
981
1002
  The same flow works for issue bodies (use \`issueCreate\` / \`issueUpdate\` with the same markdown body).
982
1003
 
983
- Never paste the \`api.tryreplicas.com/v1/media/<id>\` URL into a Linear body or comment \u2014 it will render as a broken image to anyone outside your Replicas chat.
1004
+ Never paste the \`api.replicas.dev/v1/media/<id>\` URL into a Linear body or comment \u2014 it will render as a broken image to anyone outside your Replicas chat.
984
1005
 
985
1006
  ### GitHub: inline screenshots and recording previews
986
1007
 
@@ -1001,7 +1022,7 @@ GitHub does not reliably render arbitrary external videos as inline players. For
1001
1022
  [![Demo recording](<public-poster-url>)](<recording-dashboard-url>)
1002
1023
  \`\`\`
1003
1024
 
1004
- Public forge shares are bearer capabilities. For private repositories, create one only when the user asked for inline PR media. Revoke with \`replicas media revoke <media-id>\` **only** when the user asks or the media should intentionally stop rendering \u2014 never as routine post-task cleanup, since revoking breaks every embed already posted on the PR.
1025
+ Public forge shares are unauthenticated bearer capabilities. For private repositories, create one only when the user explicitly asked for inline PR media. Without that consent, keep the media private in Replicas and report that GitHub has no supported attachment API; do not publish a bearer share or pretend the dashboard link is an embed. Revoke with \`replicas media revoke <media-id>\` **only** when the user asks or the media should intentionally stop rendering; never as routine post-task cleanup, since revoking breaks every embed already posted on the PR.
1005
1026
 
1006
1027
  For a self-contained HTML report, upload it with \`--access organization\` and put the printed \`Forge link\` Markdown in the PR body or comment. GitHub cannot render the page inline, so use the normal link rather than image syntax. HTML pages cannot be shared publicly.
1007
1028
 
@@ -1009,7 +1030,7 @@ Do **not** commit screenshots to the repo, use placeholder URLs, expose the auth
1009
1030
 
1010
1031
  ### GitLab: native inline screenshots and videos
1011
1032
 
1012
- GitLab supports native project Markdown uploads. Always upload the media to Replicas first, then POST the same original file to the repository's \`/projects/:id/uploads\` API using the workspace GitLab credential. Insert the returned \`markdown\` value into the merge request body or comment and include the Replicas dashboard link. Image uploads render inline; MP4, MOV, and WebM uploads render as inline video players.
1033
+ GitLab supports native project Markdown uploads. For a GitLab destination, always upload the media to Replicas first, then POST the same original file to the repository's \`/projects/:id/uploads\` API using the workspace GitLab credential. Insert the returned \`markdown\` value into the merge request body or comment and include the Replicas dashboard link. Image uploads render inline; MP4, MOV, and WebM uploads render as inline video players.
1013
1034
 
1014
1035
  Do not use a Replicas public forge share for GitLab when the native project upload succeeds; native uploads preserve project access controls.
1015
1036
 
@@ -1058,7 +1079,7 @@ replicas media upload chart-a.svg chart-b.svg --name "Latency chart" --name "Err
1058
1079
  `;
1059
1080
  var MEDIA_ABILITY = {
1060
1081
  label: "Media",
1061
- description: "Share screenshots, recordings, generated images, audio clips, and HTML pages.",
1082
+ description: "Deliver media to Replicas and destination workflows with inline uploads.",
1062
1083
  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",
1063
1084
  section: SECTION6,
1064
1085
  referenceFile: { name: "MEDIA.md", content: REFERENCE6 }
@@ -1161,19 +1182,16 @@ Discover and execute installed marketplace tools through the workspace-scoped Ty
1161
1182
  **Reference:** \`references/PLUGINS.md\`
1162
1183
 
1163
1184
  Use this when:
1164
- - The user asks for CRM data from Attio
1165
- - The user asks to manage Calendly events, invitees, or scheduling links
1166
- - The user asks to read or change Google Ads, Docs, Drive, Search Console, or Sheets data
1167
- - The user asks for ClickHouse analytics or PostHog product data
1185
+ - The user asks to work with an installed productivity, data, engineering, or business plugin
1186
+ - The user asks to discover which external services are connected
1168
1187
  - The user asks to create or control an E2B sandbox
1169
1188
  - The user asks to invoke a connected Modal function
1170
1189
  - The user asks to query or update a connected turbopuffer namespace
1171
1190
  - The user asks for PlanetScale organizations, databases, branches, or Insights data
1172
- - The user asks to analyze text with Pangram
1173
- - The user asks for Stripe customers, payments, invoices, subscriptions, or balances`;
1191
+ - The user asks to analyze text with Pangram`;
1174
1192
  var REFERENCE8 = `# Plugins
1175
1193
 
1176
- 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.
1194
+ Plugins are TypeScript libraries, not MCP servers. Import \`@replicas/sdk\`; Replicas authenticates the workspace and selects the owner\u2019s personal connection first, then the most specific environment the workspace inherits from, then Global. Provider credentials, sessions, and project keys are never exposed.
1177
1195
 
1178
1196
  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.
1179
1197
 
@@ -1186,7 +1204,7 @@ const plugins = await replicas.plugins.list();
1186
1204
  const installed = plugins.filter((plugin) => plugin.connected);
1187
1205
  \`\`\`
1188
1206
 
1189
- If a plugin is not connected, ask the user to install it under personal or organization Integrations in the Replicas dashboard.
1207
+ If a plugin is not connected, ask the user to connect it under personal Connections or the relevant environment's Plugins tab. A connection on Global reaches every workspace unless a more specific environment overrides it.
1190
1208
 
1191
1209
  ## Search, inspect, execute
1192
1210
 
@@ -1343,7 +1361,7 @@ In agent mode the CLI hides commands that don't make sense for in-workspace agen
1343
1361
  | \`replicas automation ...\` | Manage automations (cron + GitHub/GitLab event triggers) |
1344
1362
  | \`replicas preview ...\` | Register / list preview URLs (covered in \`PREVIEWS.md\`) |
1345
1363
  | \`replicas service ...\` | Run long-lived services detached so they survive workspace sleep/wake (see below) |
1346
- | \`replicas media ...\` | Upload screenshots, videos, audio (covered in \`MEDIA.md\`) |
1364
+ | \`replicas media ...\` | Upload media to the dashboard and follow \`MEDIA.md\` for destination embedding |
1347
1365
  | \`replicas slack thread ...\` | Attach or switch Slack thread routing (covered in \`SLACK.md\`) |
1348
1366
 
1349
1367
  \`replicas <command> --help\` is always the source of truth for flags.
@@ -1637,6 +1655,8 @@ await replicas.slack.call('chat.postMessage', {
1637
1655
 
1638
1656
  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").
1639
1657
 
1658
+ For screenshots, recordings, diagrams, or other media, read \`references/MEDIA.md\` before posting. It is the single source of truth for uploading the Replicas copy and the raw file to Slack; a dashboard link in \`text\` is not an inline attachment.
1659
+
1640
1660
  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.
1641
1661
 
1642
1662
  ## Search and batch
@@ -1758,12 +1778,14 @@ var GPT_5_6_TERRA_MODEL = "gpt-5.6-terra";
1758
1778
  var GPT_5_6_LUNA_MODEL = "gpt-5.6-luna";
1759
1779
  var DEFAULT_CODEX_MODEL = GPT_5_6_SOL_MODEL;
1760
1780
  var DEFAULT_OPENCODE_MODEL = "z-ai/glm-5.2";
1781
+ var OX_ALPHA_MODEL = "stealth/ox-alpha";
1761
1782
  var DEEPSEEK_V4_PRO_MODEL = "deepseek/deepseek-v4-pro-0813";
1762
1783
  var DEEPSEEK_V4_FLASH_MODEL = "deepseek/deepseek-v4-flash-0731";
1763
1784
  var DEFAULT_FX_MODEL = "zai/glm-5.2";
1764
1785
  var DEFAULT_KIMI_MODEL = "moonshotai/kimi-k2.6";
1765
1786
  var OPENROUTER_MODELS = [
1766
1787
  DEFAULT_OPENCODE_MODEL,
1788
+ OX_ALPHA_MODEL,
1767
1789
  DEEPSEEK_V4_PRO_MODEL,
1768
1790
  DEEPSEEK_V4_FLASH_MODEL,
1769
1791
  "minimax/minimax-m3",
@@ -1853,6 +1875,7 @@ var MODEL_LABELS = {
1853
1875
  [GPT_5_6_LUNA_MODEL]: "GPT-5.6 Luna",
1854
1876
  "gpt-5.5": "GPT-5.5",
1855
1877
  [DEFAULT_OPENCODE_MODEL]: "GLM 5.2 via OpenRouter",
1878
+ [OX_ALPHA_MODEL]: "Ox Alpha via OpenRouter",
1856
1879
  [DEEPSEEK_V4_PRO_MODEL]: "DeepSeek V4 Pro via OpenRouter",
1857
1880
  [DEEPSEEK_V4_FLASH_MODEL]: "DeepSeek V4 Flash via OpenRouter",
1858
1881
  "minimax/minimax-m3": "MiniMax M3 via OpenRouter",
@@ -3274,7 +3297,11 @@ function parseClaudeEvents(events, parentToolUseId) {
3274
3297
  const assistantTextCounts = /* @__PURE__ */ new Map();
3275
3298
  const acceptedUserMessageIndexes = /* @__PURE__ */ new Set();
3276
3299
  const canonicalUserMessageIndexes = /* @__PURE__ */ new Set();
3277
- const findMatchingUserMessageIndex = (indexes, content, timestamp) => {
3300
+ const findMatchingUserMessageIndex = (indexes, content, timestamp, messageId) => {
3301
+ if (typeof messageId === "string") {
3302
+ const byId = messages.findIndex((message) => message.type === "user" && message.id === messageId);
3303
+ if (byId !== -1) return byId;
3304
+ }
3278
3305
  return [...indexes].find((index) => {
3279
3306
  const message = messages[index];
3280
3307
  return message?.type === "user" && areUserMessagesWithinMatchWindow(message, { content, timestamp });
@@ -3292,7 +3319,7 @@ function parseClaudeEvents(events, parentToolUseId) {
3292
3319
  const images = userMessageImages(event.payload.images);
3293
3320
  if (content || images) {
3294
3321
  const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
3295
- const canonicalIndex = findMatchingUserMessageIndex(canonicalUserMessageIndexes, content, event.timestamp);
3322
+ const canonicalIndex = findMatchingUserMessageIndex(canonicalUserMessageIndexes, content, event.timestamp, messageId);
3296
3323
  const canonical = canonicalIndex === void 0 ? void 0 : messages[canonicalIndex];
3297
3324
  const message = {
3298
3325
  id: typeof messageId === "string" ? messageId : `user-${event.timestamp}`,
@@ -3367,14 +3394,16 @@ function parseClaudeEvents(events, parentToolUseId) {
3367
3394
  };
3368
3395
  }).filter((img) => img.data);
3369
3396
  if (textContent || images.length > 0) {
3397
+ const stampedId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
3370
3398
  const acceptedIndex = findMatchingUserMessageIndex(
3371
3399
  acceptedUserMessageIndexes,
3372
3400
  textContent,
3373
- event.timestamp
3401
+ event.timestamp,
3402
+ stampedId
3374
3403
  );
3375
3404
  const accepted = acceptedIndex === void 0 ? void 0 : messages[acceptedIndex];
3376
3405
  const message = {
3377
- id: accepted?.id ?? `user-${event.timestamp}`,
3406
+ id: accepted?.id ?? (typeof stampedId === "string" ? stampedId : `user-${event.timestamp}`),
3378
3407
  type: "user",
3379
3408
  content: textContent || (images.length > 0 ? `[${images.length} image${images.length > 1 ? "s" : ""} attached]` : ""),
3380
3409
  images: images.length > 0 ? images : accepted?.type === "user" ? accepted.images : void 0,
@@ -3878,7 +3907,7 @@ var DEFAULT_WORKSPACE_FILTERS = {
3878
3907
  var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
3879
3908
 
3880
3909
  // src/index.ts
3881
- var API_URL = process.env.REPLICAS_API_URL || "https://api.tryreplicas.com";
3910
+ var API_URL = process.env.REPLICAS_API_URL || "https://api.replicas.dev";
3882
3911
  var API_KEY = process.env.REPLICAS_API_KEY;
3883
3912
  if (!API_KEY) {
3884
3913
  console.error("REPLICAS_API_KEY environment variable required");
@@ -3910,7 +3939,7 @@ function result(data, isError = false) {
3910
3939
  }
3911
3940
  var server = new McpServer({
3912
3941
  name: "replicas-mcp",
3913
- version: "0.2.14"
3942
+ version: "0.2.15"
3914
3943
  });
3915
3944
  var registerTool = server.registerTool.bind(server);
3916
3945
  var codingAgentSchema = z3.string().refine(isValidCodingAgentProvider, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-mcp",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  VALID_LIFECYCLE_POLICIES,
19
19
  } from '../../shared/src/routes/workspaces';
20
20
 
21
- const API_URL = process.env.REPLICAS_API_URL || 'https://api.tryreplicas.com';
21
+ const API_URL = process.env.REPLICAS_API_URL || 'https://api.replicas.dev';
22
22
  const API_KEY = process.env.REPLICAS_API_KEY;
23
23
 
24
24
  if (!API_KEY) {
@@ -71,7 +71,7 @@ type RegisterToolFn = (
71
71
 
72
72
  const server = new McpServer({
73
73
  name: 'replicas-mcp',
74
- version: '0.2.14',
74
+ version: '0.2.15',
75
75
  });
76
76
 
77
77
  const registerTool = server.registerTool.bind(server) as RegisterToolFn;