replicas-engine 0.1.263 → 0.1.264

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.
Files changed (2) hide show
  1. package/dist/src/index.js +194 -28
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -286,7 +286,7 @@ var WORKSPACE_SIZES = ["small", "large"];
286
286
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
287
287
 
288
288
  // ../shared/src/e2b.ts
289
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-04-v5";
289
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-05-v1";
290
290
 
291
291
  // ../shared/src/runtime-env.ts
292
292
  function parsePosixEnvFile(content) {
@@ -1096,7 +1096,7 @@ var LINEAR_ABILITY = {
1096
1096
 
1097
1097
  // ../shared/src/default-skills/replicas-agent/abilities/media.ts
1098
1098
  var SECTION6 = `### Media
1099
- Share screenshots, screen recordings, generated diagrams, and audio clips inline in the Replicas chat (and as references in external messages).
1099
+ Share screenshots, screen recordings, generated diagrams, and audio clips inline in the Replicas chat and natively embedded in external messages.
1100
1100
 
1101
1101
  **Reference:** \`references/MEDIA.md\`
1102
1102
 
@@ -1106,7 +1106,7 @@ Use this when:
1106
1106
  - You need to embed media in a Slack/Linear/GitHub message AND keep a referenceable copy in the Replicas dashboard`;
1107
1107
  var REFERENCE6 = `# Media (Screenshots, Recordings, Audio)
1108
1108
 
1109
- This guide covers how to share screenshots, screen recordings, generated diagrams, and audio clips with the user inline in the Replicas chat.
1109
+ This guide covers how to share screenshots, screen recordings, generated diagrams, and audio clips \u2014 both inline in the Replicas chat and natively embedded in external surfaces (Slack, Linear, GitHub).
1110
1110
 
1111
1111
  ## Prerequisites
1112
1112
 
@@ -1122,7 +1122,7 @@ Upload to Replicas in these cases \u2014 and **only** these cases:
1122
1122
 
1123
1123
  If none of these apply, don't upload.
1124
1124
 
1125
- ## Uploading
1125
+ ## Uploading to Replicas
1126
1126
 
1127
1127
  \`\`\`bash
1128
1128
  replicas media upload <path-to-file> [<path-to-file> ...]
@@ -1132,47 +1132,185 @@ Pass one or more file paths. Uploading several files in a single invocation is p
1132
1132
 
1133
1133
  For each file, the CLI prints two lines:
1134
1134
 
1135
- 1. \`![filename](<api-url>)\` \u2014 the chat embed (renders inline in Replicas chat only; see below).
1135
+ 1. \`![filename](<api-url>)\` \u2014 the chat embed (renders inline in Replicas chat **only** \u2014 see below).
1136
1136
  2. \`View in Replicas: <deep-link>\` \u2014 a per-file dashboard URL of the form \`https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>\` that opens directly to that specific file.
1137
1137
 
1138
1138
  Match each "View in Replicas" line to the embed line directly above it \u2014 that's the deep link for that file.
1139
1139
 
1140
- ## How to use the output
1140
+ ## The two URLs the CLI gives you \u2014 and where each one is allowed
1141
1141
 
1142
- ### CRITICAL: the markdown embed URL is for Replicas chat only
1142
+ | URL | What it is | Where it's allowed |
1143
+ |---|---|---|
1144
+ | \`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. |
1145
+ | \`https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>\` | Public dashboard deep link to the media tab, scrolled to that specific file | Everywhere external \u2014 Slack, GitHub, Linear, PR bodies, comments, emails. |
1143
1146
 
1144
- The URL inside \`![filename](...)\` points at \`api.tryreplicas.com/v1/media/<id>\`. This is **not a public URL** \u2014 it requires the Replicas chat's authenticated session, which resolves it to a presigned download. 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.
1147
+ ### NEVER link the API redirect URL outside the Replicas chat reply
1145
1148
 
1146
- **Never paste this URL outside your Replicas chat reply.** Not in Slack messages, not in Linear comments, not in PR descriptions or commit messages, not in external docs \u2014 nowhere a non-Replicas surface will render it.
1149
+ 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.
1147
1150
 
1148
- ### Always render dashboard URLs as \`[View in Replicas](<url>)\` hyperlinks
1151
+ This rule has no exceptions:
1152
+ - \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).
1153
+ - \u274C Never paste it in a GitHub PR description, issue body, review comment, or commit message.
1154
+ - \u274C Never paste it in a Linear issue body or comment \u2014 upload via Linear's \`fileUpload\` mutation instead (see below).
1155
+ - \u274C Never link to it from any external doc, email, or external chat.
1156
+ - \u274C Never include it as a "backup link" in case the dashboard link breaks \u2014 it will always break externally.
1149
1157
 
1150
- Whenever you share a workspace dashboard URL \u2014 in chat or anywhere else \u2014 format it as a markdown hyperlink labeled **View in Replicas**:
1158
+ ### ALWAYS link the dashboard URL \u2014 never the API URL \u2014 when referencing media externally
1159
+
1160
+ When you reference an uploaded file from anywhere outside the Replicas chat reply, the link must be the dashboard form:
1151
1161
 
1152
- \`\`\`markdown
1153
- [View in Replicas](https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>)
1162
+ \`\`\`
1163
+ https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>
1154
1164
  \`\`\`
1155
1165
 
1156
- Never paste the raw URL. Raw URLs look unpolished.
1166
+ Both query params are required:
1167
+ - \`mode=media\` opens the media tab in the dashboard.
1168
+ - \`media=<media-id>\` scrolls to and opens that specific file.
1157
1169
 
1158
- Two flavors of dashboard URL the CLI gives you:
1170
+ Never link \`tryreplicas.com/workspaces/<id>?mode=media\` without the \`media=<id>\` param when you have a specific file in mind \u2014 that lands on the gallery, not the file. Never link the bare workspace URL.
1159
1171
 
1160
- - **Per-file deep link** (default \u2014 what \`replicas media upload\` prints): \`...?mode=media&media=<media-id>\` opens the dashboard scrolled to that specific file. Use this whenever you're linking to *one* file.
1161
- - **Media tab link** (no \`media=\` param): \`...?mode=media\` opens the workspace's media tab listing all files. Use this only when you're pointing at the collection, not a specific file (rare \u2014 you almost always have a specific file in mind).
1172
+ Always render as a markdown / mrkdwn hyperlink labeled **View in Replicas** \u2014 never paste a raw URL.
1162
1173
 
1163
- ### In your Replicas chat reply
1174
+ ## In your Replicas chat reply
1164
1175
 
1165
1176
  Include each markdown embed line **verbatim** where you want that file to render inline. The chat substitutes each one with an embedded image, video, or audio player. Multiple embeds can appear in a single reply.
1166
1177
 
1167
- After (or alongside) the embeds, include a \`[View in Replicas](<deep-link>)\` hyperlink for each file using the per-file URL the CLI printed for that file. This lets the user jump to the specific item in the media tab.
1178
+ 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 jump to the specific item in the media tab.
1179
+
1180
+ ## On external platforms \u2014 upload natively AND link the dashboard
1181
+
1182
+ Sharing media externally is a **two-step requirement** for every file:
1183
+
1184
+ 1. **Upload the raw bytes natively to that platform** so the recipient sees the media embedded inline in the message itself.
1185
+ 2. **Link the Replicas dashboard deep link** (\`?mode=media&media=<id>\` form) so the user can jump straight to the workspace.
1186
+
1187
+ A link alone is not enough. A native upload alone is not enough. Do both.
1188
+
1189
+ The one exception is GitHub, which has no public image upload API \u2014 there, the dashboard link is the only option (see below).
1190
+
1191
+ ### Slack \u2014 embed natively via the 3-step external file upload flow
1192
+
1193
+ 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.
1168
1194
 
1169
- ### On external platforms (Slack, Linear, GitHub, etc.)
1195
+ 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\`.)
1170
1196
 
1171
- Always include a \`[View in Replicas](<deep-link>)\` hyperlink \u2014 use the per-file deep link the CLI printed for that file (\`...?mode=media&media=<media-id>\`), so the recipient lands directly on that specific item.
1197
+ \`\`\`bash
1198
+ FILE=/abs/path/to/screenshot.png
1199
+ FILENAME=$(basename "$FILE")
1200
+ LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
1201
+
1202
+ # 1. Reserve an upload URL + file ID.
1203
+ RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
1204
+ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
1205
+ --data-urlencode "filename=$FILENAME" \\
1206
+ --data-urlencode "length=$LENGTH")
1207
+ UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
1208
+ FILE_ID=$(echo "$RESERVE" | jq -r '.file_id')
1209
+
1210
+ # 2. POST the raw bytes to the reserved URL.
1211
+ # Do not use -F / multipart here \u2014 the presigned URL expects the bytes
1212
+ # directly in the request body.
1213
+ curl -s -X POST "$UPLOAD_URL" \\
1214
+ -H "Content-Type: application/octet-stream" \\
1215
+ --data-binary @"$FILE"
1216
+
1217
+ # 3. Complete the upload, sharing it into the channel/thread with the dashboard link.
1218
+ curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
1219
+ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
1220
+ -H "Content-Type: application/json; charset=utf-8" \\
1221
+ -d "{
1222
+ \\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"Screenshot\\"}],
1223
+ \\"channel_id\\": \\"CHANNEL_ID\\",
1224
+ \\"thread_ts\\": \\"THREAD_TS\\",
1225
+ \\"initial_comment\\": \\"<https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>|View in Replicas>\\"
1226
+ }"
1227
+ \`\`\`
1172
1228
 
1173
- For platforms that support native uploads (Slack \`files.upload\`, Linear attachments, etc.), upload the raw bytes there too so the recipient sees the media inline in addition to the Replicas link. GitHub PRs/issues do not have a public upload API, so the \`View in Replicas\` link is the canonical way to share media there \u2014 do not commit screenshots to the repo and do not use placeholder URLs.
1229
+ Notes:
1230
+ - All three steps are required; do not try to POST to \`https://slack.com/api/files.uploadV2\` \u2014 that endpoint does not exist on the Web API.
1231
+ - \`initial_comment\` uses Slack mrkdwn (\`<url|label>\`), not GitHub-flavored markdown.
1232
+ - Omit \`thread_ts\` only when you genuinely want a top-level channel post.
1233
+ - 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.
1234
+ - 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.
1174
1235
 
1175
- Do **not** include the \`![filename](https://api.tryreplicas.com/...)\` markdown embed in external messages. It will render as a broken image / 401 for the recipient.
1236
+ 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.
1237
+
1238
+ ### Linear \u2014 embed natively via the GraphQL \`fileUpload\` mutation
1239
+
1240
+ Linear comments and issue bodies support markdown image embeds, but the image URL must be publicly accessible \u2014 so you upload the file to Linear's storage first, then reference the returned \`assetUrl\` in markdown. Three steps:
1241
+
1242
+ Use \`jq\` to build the JSON bodies \u2014 the GraphQL variables (\`size\`, \`filename\`, the comment body) need to be real JSON values, not unquoted placeholders, and \`jq -n --argjson / --arg\` is the safest way to interpolate shell values without quoting bugs.
1243
+
1244
+ \`\`\`bash
1245
+ FILE=/abs/path/to/screenshot.png
1246
+ FILENAME=$(basename "$FILE")
1247
+ SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
1248
+ CONTENT_TYPE=image/png
1249
+ ISSUE_UUID=... # the Linear issue's UUID
1250
+ WORKSPACE_ID=... # the Replicas workspace ID
1251
+ MEDIA_ID=... # the media ID printed by \`replicas media upload\`
1252
+
1253
+ # 1. Ask Linear for an upload URL + assetUrl.
1254
+ RESERVE=$(curl -s -X POST https://api.linear.app/graphql \\
1255
+ -H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
1256
+ -H "Content-Type: application/json" \\
1257
+ -d "$(jq -n \\
1258
+ --argjson size "$SIZE" \\
1259
+ --arg contentType "$CONTENT_TYPE" \\
1260
+ --arg filename "$FILENAME" \\
1261
+ '{
1262
+ query: "mutation($size: Int!, $contentType: String!, $filename: String!) { fileUpload(size: $size, contentType: $contentType, filename: $filename) { uploadFile { uploadUrl assetUrl headers { key value } } } }",
1263
+ variables: { size: $size, contentType: $contentType, filename: $filename }
1264
+ }')")
1265
+ UPLOAD_URL=$(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.uploadUrl')
1266
+ ASSET_URL=$(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.assetUrl')
1267
+
1268
+ # 2. PUT the bytes to uploadUrl, replaying every header Linear returned.
1269
+ # Linear's presigned URL requires the exact Content-Type / Cache-Control /
1270
+ # etc. it gave you back, so forward each {key, value} from the headers array.
1271
+ HEADER_ARGS=()
1272
+ while IFS=$'\\t' read -r k v; do
1273
+ HEADER_ARGS+=(-H "$k: $v")
1274
+ done < <(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.headers[] | "\\(.key)\\t\\(.value)"')
1275
+
1276
+ curl -s -X PUT "$UPLOAD_URL" \\
1277
+ "\${HEADER_ARGS[@]}" \\
1278
+ --data-binary @"$FILE"
1279
+
1280
+ # 3. Reference assetUrl inline in the comment body, alongside the dashboard link.
1281
+ BODY=$(printf '![screenshot](%s)\\n\\n[View in Replicas](https://tryreplicas.com/workspaces/%s?mode=media&media=%s)' \\
1282
+ "$ASSET_URL" "$WORKSPACE_ID" "$MEDIA_ID")
1283
+
1284
+ curl -s -X POST https://api.linear.app/graphql \\
1285
+ -H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
1286
+ -H "Content-Type: application/json" \\
1287
+ -d "$(jq -n \\
1288
+ --arg issueId "$ISSUE_UUID" \\
1289
+ --arg body "$BODY" \\
1290
+ '{
1291
+ query: "mutation($issueId: String!, $body: String!) { commentCreate(input: { issueId: $issueId, body: $body }) { success } }",
1292
+ variables: { issueId: $issueId, body: $body }
1293
+ }')"
1294
+ \`\`\`
1295
+
1296
+ The same flow works for issue bodies (use \`issueCreate\` / \`issueUpdate\` with the same markdown body).
1297
+
1298
+ 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.
1299
+
1300
+ ### GitHub \u2014 link the dashboard deep link (no public upload API exists)
1301
+
1302
+ GitHub has **no public API** for uploading images to PRs or issues. Their web UI uses an undocumented internal endpoint that's not available to API clients. So for GitHub specifically, the only correct way to share media is the dashboard deep link, rendered as a markdown hyperlink:
1303
+
1304
+ \`\`\`markdown
1305
+ [View in Replicas](https://tryreplicas.com/workspaces/<workspace-id>?mode=media&media=<media-id>)
1306
+ \`\`\`
1307
+
1308
+ Do **not**:
1309
+ - Commit screenshots as files to the repo as a workaround.
1310
+ - Use placeholder image URLs.
1311
+ - Embed the \`api.tryreplicas.com/v1/media/<id>\` URL in markdown \u2014 it renders as a broken image for every viewer.
1312
+
1313
+ This applies to PR descriptions, PR review comments, issue bodies, issue comments, and commit messages.
1176
1314
 
1177
1315
  ## Recording defaults
1178
1316
 
@@ -1593,14 +1731,42 @@ curl -s "https://slack.com/api/search.messages?query=YOUR_SEARCH_QUERY" \\
1593
1731
 
1594
1732
  ### Uploading Files
1595
1733
 
1734
+ Slack deprecated \`files.upload\`; the raw HTTP replacement is a 3-step flow. (\`files.uploadV2\` is **only** an SDK convenience wrapper and is NOT a real Web API HTTP endpoint \u2014 \`POST https://slack.com/api/files.uploadV2\` returns \`unknown_method\`.)
1735
+
1596
1736
  \`\`\`bash
1597
- curl -s -X POST "https://slack.com/api/files.uploadV2" \\
1737
+ FILE=/path/to/file
1738
+ FILENAME=$(basename "$FILE")
1739
+ LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
1740
+
1741
+ # 1. Reserve an upload URL + file ID.
1742
+ RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
1598
1743
  -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
1599
- -F "channel_id=CHANNEL_ID" \\
1600
- -F "file=@/path/to/file" \\
1601
- -F "title=File title"
1744
+ --data-urlencode "filename=$FILENAME" \\
1745
+ --data-urlencode "length=$LENGTH")
1746
+ UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
1747
+ FILE_ID=$(echo "$RESERVE" | jq -r '.file_id')
1748
+
1749
+ # 2. POST the raw bytes to the reserved URL.
1750
+ # Do not use -F / multipart here \u2014 the presigned URL expects the bytes
1751
+ # directly in the request body.
1752
+ curl -s -X POST "$UPLOAD_URL" \\
1753
+ -H "Content-Type: application/octet-stream" \\
1754
+ --data-binary @"$FILE"
1755
+
1756
+ # 3. Complete the upload and share into a channel (and optionally a thread).
1757
+ curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
1758
+ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \\
1759
+ -H "Content-Type: application/json; charset=utf-8" \\
1760
+ -d "{
1761
+ \\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"File title\\"}],
1762
+ \\"channel_id\\": \\"CHANNEL_ID\\",
1763
+ \\"thread_ts\\": \\"OPTIONAL_THREAD_TS\\",
1764
+ \\"initial_comment\\": \\"Optional message body\\"
1765
+ }"
1602
1766
  \`\`\`
1603
1767
 
1768
+ Omit \`thread_ts\` and/or \`initial_comment\` if you don't need them.
1769
+
1604
1770
  ### Other Operations
1605
1771
 
1606
1772
  You can list channels, read channel history, add reactions, and perform any other operation supported by the Slack Web API using the same authentication pattern.
@@ -6401,7 +6567,7 @@ var AspClient = class {
6401
6567
  // src/managers/codex-asp/app-server-process.ts
6402
6568
  var DEFAULT_CODEX_BINARY = "codex";
6403
6569
  var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
6404
- var ENGINE_PACKAGE_VERSION = "0.1.263";
6570
+ var ENGINE_PACKAGE_VERSION = "0.1.264";
6405
6571
  var INITIALIZE_METHOD = "initialize";
6406
6572
  var INITIALIZED_NOTIFICATION = "initialized";
6407
6573
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.263",
3
+ "version": "0.1.264",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",