replicas-engine 0.1.367 → 0.1.368
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/src/index.js +84 -47
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -295,7 +295,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
295
295
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
296
296
|
|
|
297
297
|
// ../shared/src/e2b.ts
|
|
298
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-29-
|
|
298
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-29-v3";
|
|
299
299
|
|
|
300
300
|
// ../shared/src/runtime-env.ts
|
|
301
301
|
function parsePosixEnvFile(content) {
|
|
@@ -1213,41 +1213,59 @@ This guide covers how to interact with Linear from within your Replicas workspac
|
|
|
1213
1213
|
|
|
1214
1214
|
## Prerequisites
|
|
1215
1215
|
|
|
1216
|
-
Check
|
|
1216
|
+
Check that the workspace has the Replicas engine credentials needed to proxy Linear requests:
|
|
1217
1217
|
|
|
1218
1218
|
\`\`\`bash
|
|
1219
|
-
echo
|
|
1219
|
+
test -n "$MONOLITH_URL" && test -n "$REPLICAS_ENGINE_SECRET" && test -n "$WORKSPACE_ID" && echo set
|
|
1220
1220
|
\`\`\`
|
|
1221
1221
|
|
|
1222
|
-
- If **set**:
|
|
1223
|
-
- If **not set**:
|
|
1222
|
+
- If **set**: Use the Replicas Linear proxy below. It refreshes Linear OAuth tokens for you.
|
|
1223
|
+
- If **not set**: The workspace cannot authenticate to Replicas. Let the user know and do not attempt Linear operations.
|
|
1224
|
+
|
|
1225
|
+
Then verify Linear is connected:
|
|
1226
|
+
|
|
1227
|
+
\`\`\`bash
|
|
1228
|
+
curl -fsS -X POST "$MONOLITH_URL/v1/engine/linear/refresh-token" \\
|
|
1229
|
+
-H "Authorization: Bearer $REPLICAS_ENGINE_SECRET" \\
|
|
1230
|
+
-H "X-Workspace-Id: $WORKSPACE_ID" \\
|
|
1231
|
+
-H "Content-Type: application/json" \\
|
|
1232
|
+
-d '{}' >/dev/null
|
|
1233
|
+
\`\`\`
|
|
1234
|
+
|
|
1235
|
+
If this fails because no Linear credential is connected, the user needs to connect Linear in the [Replicas dashboard](https://replicas.dev) under their organization's integration settings.
|
|
1224
1236
|
|
|
1225
1237
|
## Using the Linear API
|
|
1226
1238
|
|
|
1227
|
-
Linear uses a GraphQL API
|
|
1239
|
+
Linear uses a GraphQL API. Always call it through Replicas so the access token stays fresh:
|
|
1240
|
+
|
|
1241
|
+
\`\`\`bash
|
|
1242
|
+
linear_graphql() {
|
|
1243
|
+
curl -sS -X POST "$MONOLITH_URL/v1/engine/linear/graphql" \\
|
|
1244
|
+
-H "Authorization: Bearer $REPLICAS_ENGINE_SECRET" \\
|
|
1245
|
+
-H "X-Workspace-Id: $WORKSPACE_ID" \\
|
|
1246
|
+
-H "Content-Type: application/json" \\
|
|
1247
|
+
--data-binary @-
|
|
1248
|
+
}
|
|
1249
|
+
\`\`\`
|
|
1228
1250
|
|
|
1229
1251
|
### Fetching an Issue
|
|
1230
1252
|
|
|
1231
1253
|
If you encounter a Linear issue link (e.g. \`https://linear.app/team/issue/ENG-123\`), the identifier is the last path segment (\`ENG-123\`).
|
|
1232
1254
|
|
|
1233
1255
|
\`\`\`bash
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
"query": "query { issues(filter: { identifier: { eq: \\"ENG-123\\" } }) { nodes { id identifier title description state { name } assignee { name } parent { identifier title description } } } }"
|
|
1239
|
-
}'
|
|
1256
|
+
jq -n --arg identifier "ENG-123" '{
|
|
1257
|
+
query: "query($identifier: String!) { issues(filter: { identifier: { eq: $identifier } }) { nodes { id identifier title description state { name } assignee { name } parent { identifier title description } } } }",
|
|
1258
|
+
variables: { identifier: $identifier }
|
|
1259
|
+
}' | linear_graphql
|
|
1240
1260
|
\`\`\`
|
|
1241
1261
|
|
|
1242
1262
|
### Updating Issue State
|
|
1243
1263
|
|
|
1244
1264
|
\`\`\`bash
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
"query": "mutation { issueUpdate(id: \\"ISSUE_UUID\\", input: { stateId: \\"STATE_UUID\\" }) { success issue { identifier state { name } } } }"
|
|
1250
|
-
}'
|
|
1265
|
+
jq -n --arg issueId "ISSUE_UUID" --arg stateId "STATE_UUID" '{
|
|
1266
|
+
query: "mutation($issueId: String!, $stateId: String!) { issueUpdate(id: $issueId, input: { stateId: $stateId }) { success issue { identifier state { name } } } }",
|
|
1267
|
+
variables: { issueId: $issueId, stateId: $stateId }
|
|
1268
|
+
}' | linear_graphql
|
|
1251
1269
|
\`\`\`
|
|
1252
1270
|
|
|
1253
1271
|
To find available states, query: \`query { workflowStates { nodes { id name } } }\`
|
|
@@ -1255,23 +1273,19 @@ To find available states, query: \`query { workflowStates { nodes { id name } }
|
|
|
1255
1273
|
### Adding a Comment
|
|
1256
1274
|
|
|
1257
1275
|
\`\`\`bash
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
"query": "mutation { commentCreate(input: { issueId: \\"ISSUE_UUID\\", body: \\"Your comment here\\" }) { success comment { id } } }"
|
|
1263
|
-
}'
|
|
1276
|
+
jq -n --arg issueId "ISSUE_UUID" --arg body "Your comment here" '{
|
|
1277
|
+
query: "mutation($issueId: String!, $body: String!) { commentCreate(input: { issueId: $issueId, body: $body }) { success comment { id } } }",
|
|
1278
|
+
variables: { issueId: $issueId, body: $body }
|
|
1279
|
+
}' | linear_graphql
|
|
1264
1280
|
\`\`\`
|
|
1265
1281
|
|
|
1266
1282
|
### Searching Issues
|
|
1267
1283
|
|
|
1268
1284
|
\`\`\`bash
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
"query": "query { issueSearch(query: \\"search terms\\", first: 10) { nodes { identifier title state { name } } } }"
|
|
1274
|
-
}'
|
|
1285
|
+
jq -n --arg query "search terms" '{
|
|
1286
|
+
query: "query($query: String!) { issueSearch(query: $query, first: 10) { nodes { identifier title state { name } } } }",
|
|
1287
|
+
variables: { query: $query }
|
|
1288
|
+
}' | linear_graphql
|
|
1275
1289
|
\`\`\`
|
|
1276
1290
|
|
|
1277
1291
|
### Other Operations
|
|
@@ -1439,21 +1453,25 @@ FILENAME=$(basename "$FILE")
|
|
|
1439
1453
|
SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
|
|
1440
1454
|
CONTENT_TYPE=image/png
|
|
1441
1455
|
ISSUE_UUID=... # the Linear issue's UUID
|
|
1442
|
-
WORKSPACE_ID=... # the Replicas workspace ID
|
|
1443
1456
|
MEDIA_ID=... # the media ID printed by \`replicas media upload\`
|
|
1444
1457
|
|
|
1458
|
+
linear_graphql() {
|
|
1459
|
+
curl -sS -X POST "$MONOLITH_URL/v1/engine/linear/graphql" \\
|
|
1460
|
+
-H "Authorization: Bearer $REPLICAS_ENGINE_SECRET" \\
|
|
1461
|
+
-H "X-Workspace-Id: $WORKSPACE_ID" \\
|
|
1462
|
+
-H "Content-Type: application/json" \\
|
|
1463
|
+
--data-binary @-
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1445
1466
|
# 1. Ask Linear for an upload URL + assetUrl.
|
|
1446
|
-
RESERVE=$(
|
|
1447
|
-
-H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
|
|
1448
|
-
-H "Content-Type: application/json" \\
|
|
1449
|
-
-d "$(jq -n \\
|
|
1467
|
+
RESERVE=$(jq -n \\
|
|
1450
1468
|
--argjson size "$SIZE" \\
|
|
1451
1469
|
--arg contentType "$CONTENT_TYPE" \\
|
|
1452
1470
|
--arg filename "$FILENAME" \\
|
|
1453
1471
|
'{
|
|
1454
1472
|
query: "mutation($size: Int!, $contentType: String!, $filename: String!) { fileUpload(size: $size, contentType: $contentType, filename: $filename) { uploadFile { uploadUrl assetUrl headers { key value } } } }",
|
|
1455
1473
|
variables: { size: $size, contentType: $contentType, filename: $filename }
|
|
1456
|
-
}')
|
|
1474
|
+
}' | linear_graphql)
|
|
1457
1475
|
UPLOAD_URL=$(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.uploadUrl')
|
|
1458
1476
|
ASSET_URL=$(echo "$RESERVE" | jq -r '.data.fileUpload.uploadFile.assetUrl')
|
|
1459
1477
|
|
|
@@ -1473,16 +1491,13 @@ curl -s -X PUT "$UPLOAD_URL" \\
|
|
|
1473
1491
|
BODY=$(printf '\\n\\n[View in Replicas](https://tryreplicas.com/workspaces/%s?mode=media&media=%s)' \\
|
|
1474
1492
|
"$ASSET_URL" "$WORKSPACE_ID" "$MEDIA_ID")
|
|
1475
1493
|
|
|
1476
|
-
|
|
1477
|
-
-H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
|
|
1478
|
-
-H "Content-Type: application/json" \\
|
|
1479
|
-
-d "$(jq -n \\
|
|
1494
|
+
jq -n \\
|
|
1480
1495
|
--arg issueId "$ISSUE_UUID" \\
|
|
1481
1496
|
--arg body "$BODY" \\
|
|
1482
1497
|
'{
|
|
1483
1498
|
query: "mutation($issueId: String!, $body: String!) { commentCreate(input: { issueId: $issueId, body: $body }) { success } }",
|
|
1484
1499
|
variables: { issueId: $issueId, body: $body }
|
|
1485
|
-
}'
|
|
1500
|
+
}' | linear_graphql
|
|
1486
1501
|
\`\`\`
|
|
1487
1502
|
|
|
1488
1503
|
The same flow works for issue bodies (use \`issueCreate\` / \`issueUpdate\` with the same markdown body).
|
|
@@ -5610,13 +5625,29 @@ function inferMediaType(url, contentType) {
|
|
|
5610
5625
|
if (urlLower.includes(".webp")) return "image/webp";
|
|
5611
5626
|
return "image/jpeg";
|
|
5612
5627
|
}
|
|
5613
|
-
async function
|
|
5628
|
+
async function getLinearAccessToken() {
|
|
5629
|
+
try {
|
|
5630
|
+
const response = await monolithRequest("/v1/engine/linear/refresh-token");
|
|
5631
|
+
if (!response.ok) {
|
|
5632
|
+
console.warn(`[ImageUtils] Failed to refresh Linear token: ${response.status} ${await response.text()}`);
|
|
5633
|
+
return ENGINE_ENV.LINEAR_ACCESS_TOKEN;
|
|
5634
|
+
}
|
|
5635
|
+
const data = await response.json();
|
|
5636
|
+
return data.token;
|
|
5637
|
+
} catch (error) {
|
|
5638
|
+
console.warn("[ImageUtils] Failed to refresh Linear token:", error);
|
|
5639
|
+
return ENGINE_ENV.LINEAR_ACCESS_TOKEN;
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
function isLinearUploadUrl(url) {
|
|
5643
|
+
return new URL(url).hostname === "uploads.linear.app";
|
|
5644
|
+
}
|
|
5645
|
+
async function fetchImageAsBase64(url, linearAccessToken) {
|
|
5614
5646
|
const headers = {};
|
|
5615
5647
|
const hostname = new URL(url).hostname;
|
|
5616
5648
|
if (hostname === "uploads.linear.app") {
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
5649
|
+
if (linearAccessToken) {
|
|
5650
|
+
headers["Authorization"] = `Bearer ${linearAccessToken}`;
|
|
5620
5651
|
}
|
|
5621
5652
|
}
|
|
5622
5653
|
if (hostname === "files.slack.com") {
|
|
@@ -5651,6 +5682,8 @@ async function fetchImageAsBase64(url) {
|
|
|
5651
5682
|
}
|
|
5652
5683
|
async function normalizeImages(images) {
|
|
5653
5684
|
const normalized = [];
|
|
5685
|
+
let linearAccessToken;
|
|
5686
|
+
let linearAccessTokenLoaded = false;
|
|
5654
5687
|
for (const image of images) {
|
|
5655
5688
|
if (image.source.type === "base64") {
|
|
5656
5689
|
normalized.push({
|
|
@@ -5658,7 +5691,11 @@ async function normalizeImages(images) {
|
|
|
5658
5691
|
source: image.source
|
|
5659
5692
|
});
|
|
5660
5693
|
} else if (image.source.type === "url") {
|
|
5661
|
-
|
|
5694
|
+
if (!linearAccessTokenLoaded && isLinearUploadUrl(image.source.url)) {
|
|
5695
|
+
linearAccessToken = await getLinearAccessToken();
|
|
5696
|
+
linearAccessTokenLoaded = true;
|
|
5697
|
+
}
|
|
5698
|
+
const base64Source = await fetchImageAsBase64(image.source.url, linearAccessToken);
|
|
5662
5699
|
normalized.push({
|
|
5663
5700
|
type: "image",
|
|
5664
5701
|
source: base64Source
|
|
@@ -7691,7 +7728,7 @@ var AspClient = class {
|
|
|
7691
7728
|
// src/managers/codex-asp/app-server-process.ts
|
|
7692
7729
|
var DEFAULT_CODEX_BINARY = "codex";
|
|
7693
7730
|
var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
7694
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
7731
|
+
var ENGINE_PACKAGE_VERSION = "0.1.368";
|
|
7695
7732
|
var INITIALIZE_METHOD = "initialize";
|
|
7696
7733
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
7697
7734
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|