replicas-engine 0.1.366 → 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.
Files changed (2) hide show
  1. package/dist/src/index.js +84 -47
  2. 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-v1";
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 if the \`LINEAR_ACCESS_TOKEN\` environment variable is set:
1216
+ Check that the workspace has the Replicas engine credentials needed to proxy Linear requests:
1217
1217
 
1218
1218
  \`\`\`bash
1219
- echo "\${LINEAR_ACCESS_TOKEN:+set}"
1219
+ test -n "$MONOLITH_URL" && test -n "$REPLICAS_ENGINE_SECRET" && test -n "$WORKSPACE_ID" && echo set
1220
1220
  \`\`\`
1221
1221
 
1222
- - If **set**: Your workspace has Linear access. You can use the Linear GraphQL API as described below.
1223
- - If **not set**: Linear has not been configured for this workspace. The user needs to connect Linear in the [Replicas dashboard](https://replicas.dev) under their organization's integration settings. Let the user know and do not attempt Linear operations.
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 at \`https://api.linear.app/graphql\`. All requests use the \`$LINEAR_ACCESS_TOKEN\` for authentication.
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
- curl -s -X POST https://api.linear.app/graphql \\
1235
- -H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
1236
- -H "Content-Type: application/json" \\
1237
- -d '{
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
- curl -s -X POST https://api.linear.app/graphql \\
1246
- -H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
1247
- -H "Content-Type: application/json" \\
1248
- -d '{
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
- curl -s -X POST https://api.linear.app/graphql \\
1259
- -H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
1260
- -H "Content-Type: application/json" \\
1261
- -d '{
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
- curl -s -X POST https://api.linear.app/graphql \\
1270
- -H "Authorization: Bearer $LINEAR_ACCESS_TOKEN" \\
1271
- -H "Content-Type: application/json" \\
1272
- -d '{
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=$(curl -s -X POST https://api.linear.app/graphql \\
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 '![screenshot](%s)\\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
- curl -s -X POST https://api.linear.app/graphql \\
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 fetchImageAsBase64(url) {
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
- const token = ENGINE_ENV.LINEAR_ACCESS_TOKEN;
5618
- if (token) {
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
- const base64Source = await fetchImageAsBase64(image.source.url);
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.366";
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.366",
3
+ "version": "0.1.368",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",