replicas-engine 0.1.509 → 0.1.511
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 +73 -32
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -611,7 +611,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
611
611
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
612
612
|
|
|
613
613
|
// ../shared/src/e2b.ts
|
|
614
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-
|
|
614
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-27-v2";
|
|
615
615
|
|
|
616
616
|
// ../shared/src/runtime-env.ts
|
|
617
617
|
function shellQuotePosix(value) {
|
|
@@ -1293,37 +1293,86 @@ This guide covers how to work with GitLab-hosted repositories from within your R
|
|
|
1293
1293
|
Git credentials for the workspace's GitLab hosts are pre-configured in \`~/.git-credentials\` and refreshed automatically. Plain \`git fetch\` / \`git pull\` / \`git push\` over HTTPS work with no additional setup.
|
|
1294
1294
|
|
|
1295
1295
|
- Never ask the user for a GitLab token or PAT \u2014 credentials are already wired. If a push fails with an authentication error, report it to the user instead of working around it.
|
|
1296
|
+
- A workspace can hold credentials for several GitLab hosts, and \`origin\` is whatever the repo says it is. Always select the token by the host you are about to call, as the snippets below do. Grabbing the first entry in \`~/.git-credentials\` can send one host's token to another.
|
|
1296
1297
|
- There is no \`glab\` CLI in the workspace, and \`gh\` only works for GitHub remotes. Check a repo's host with \`git remote get-url origin\` before choosing the GitHub or GitLab workflow.
|
|
1297
1298
|
|
|
1299
|
+
### Reading the credential for a repo
|
|
1300
|
+
|
|
1301
|
+
A workspace can hold tokens for several GitLab hosts, so always ask git for the
|
|
1302
|
+
credential belonging to the host you are about to call. Never grep
|
|
1303
|
+
\`~/.git-credentials\` yourself: taking the first line sends one instance's token to
|
|
1304
|
+
another, and interpolating a host into a grep pattern makes it a regular
|
|
1305
|
+
expression. \`git credential fill\` matches the host exactly and returns nothing
|
|
1306
|
+
when there is no credential for it:
|
|
1307
|
+
|
|
1308
|
+
\`\`\`bash
|
|
1309
|
+
HOST=$(git remote get-url origin | sed -E 's#^[a-z]+://##; s#^[^@/]*@##; s#/.*##; s#:[^0-9].*##')
|
|
1310
|
+
TOKEN=$(printf 'protocol=https\\nhost=%s\\n\\n' "$HOST" | GIT_TERMINAL_PROMPT=0 git credential fill | sed -n 's/^password=//p')
|
|
1311
|
+
[ -n "$TOKEN" ] || { echo "no credential for $HOST"; exit 1; }
|
|
1312
|
+
\`\`\`
|
|
1313
|
+
|
|
1314
|
+
Every recipe below repeats these two lines so each block runs on its own, and
|
|
1315
|
+
every one calls \`https://$HOST\`, so the token only ever reaches the host it
|
|
1316
|
+
belongs to. Run them inside the repo whose API you are calling. An empty
|
|
1317
|
+
\`$TOKEN\` means the workspace has no credential for that host. Report that rather
|
|
1318
|
+
than reaching for another one.
|
|
1319
|
+
|
|
1298
1320
|
## Merge Requests
|
|
1299
1321
|
|
|
1300
1322
|
Create a merge request directly from a push using push options:
|
|
1301
1323
|
|
|
1302
1324
|
\`\`\`bash
|
|
1303
|
-
git push -o merge_request.create -o merge_request.target=<default-branch> origin HEAD
|
|
1325
|
+
git push -o merge_request.create -o merge_request.target=<default-branch> -o merge_request.title="Title" origin HEAD
|
|
1304
1326
|
\`\`\`
|
|
1305
1327
|
|
|
1306
1328
|
Useful options:
|
|
1307
1329
|
|
|
1308
1330
|
\`\`\`bash
|
|
1309
|
-
-o merge_request.title="Title"
|
|
1310
|
-
-o merge_request.description="Description"
|
|
1311
1331
|
-o merge_request.draft # open as draft
|
|
1312
1332
|
-o merge_request.remove_source_branch # delete branch on merge
|
|
1313
1333
|
\`\`\`
|
|
1314
1334
|
|
|
1315
1335
|
GitLab prints the MR URL in the push output \u2014 include it in your reply to the user.
|
|
1316
1336
|
|
|
1337
|
+
### Setting the description
|
|
1338
|
+
|
|
1339
|
+
Do **not** pass the description as a push option. Push option values are shell
|
|
1340
|
+
arguments on one line, so a real description \u2014 headings, lists, the Replicas
|
|
1341
|
+
footer HTML \u2014 gets mangled or truncated. Write the body to a file and PUT it as
|
|
1342
|
+
JSON instead, which preserves it exactly:
|
|
1343
|
+
|
|
1344
|
+
\`\`\`bash
|
|
1345
|
+
HOST=$(git remote get-url origin | sed -E 's#^[a-z]+://##; s#^[^@/]*@##; s#/.*##; s#:[^0-9].*##')
|
|
1346
|
+
TOKEN=$(printf 'protocol=https\\nhost=%s\\n\\n' "$HOST" | GIT_TERMINAL_PROMPT=0 git credential fill | sed -n 's/^password=//p')
|
|
1347
|
+
PROJECT=$(python3 -c 'import urllib.parse; print(urllib.parse.quote("group/project", safe=""))')
|
|
1348
|
+
cat > /tmp/mr-body.md <<'EOF'
|
|
1349
|
+
## Summary
|
|
1350
|
+
...your full description, ending with the Replicas footer...
|
|
1351
|
+
EOF
|
|
1352
|
+
jq -Rs '{description: .}' /tmp/mr-body.md > /tmp/mr-body.json
|
|
1353
|
+
curl -sS --request PUT \\
|
|
1354
|
+
--header "Authorization: Bearer $TOKEN" \\
|
|
1355
|
+
--header "Content-Type: application/json" \\
|
|
1356
|
+
--data @/tmp/mr-body.json \\
|
|
1357
|
+
"https://$HOST/api/v4/projects/$PROJECT/merge_requests/<iid>"
|
|
1358
|
+
\`\`\`
|
|
1359
|
+
|
|
1360
|
+
Use the same command to edit a description later. Editing replaces the whole
|
|
1361
|
+
body, so re-include the Replicas footer every time \u2014 it is how merge requests
|
|
1362
|
+
opened through Replicas are counted.
|
|
1363
|
+
|
|
1317
1364
|
## GitLab API (advanced)
|
|
1318
1365
|
|
|
1319
1366
|
For operations with no git equivalent (commenting on MRs, reading pipelines), call the REST API with the workspace credential:
|
|
1320
1367
|
|
|
1321
1368
|
\`\`\`bash
|
|
1322
|
-
|
|
1323
|
-
|
|
1369
|
+
HOST=$(git remote get-url origin | sed -E 's#^[a-z]+://##; s#^[^@/]*@##; s#/.*##; s#:[^0-9].*##')
|
|
1370
|
+
TOKEN=$(printf 'protocol=https\\nhost=%s\\n\\n' "$HOST" | GIT_TERMINAL_PROMPT=0 git credential fill | sed -n 's/^password=//p')
|
|
1371
|
+
curl -s -H "Authorization: Bearer $TOKEN" "https://$HOST/api/v4/projects/<url-encoded-path>/merge_requests"
|
|
1324
1372
|
\`\`\`
|
|
1325
1373
|
|
|
1326
|
-
|
|
1374
|
+
This works for gitlab.com and self-managed instances alike, because the base URL
|
|
1375
|
+
and the token both come from the repo's own host.
|
|
1327
1376
|
|
|
1328
1377
|
## Inline media in merge requests
|
|
1329
1378
|
|
|
@@ -1331,16 +1380,17 @@ GitLab provides a supported project Markdown uploads API. Upload media to Replic
|
|
|
1331
1380
|
|
|
1332
1381
|
\`\`\`bash
|
|
1333
1382
|
FILE=/abs/path/to/screenshot.png
|
|
1383
|
+
HOST=$(git remote get-url origin | sed -E 's#^[a-z]+://##; s#^[^@/]*@##; s#/.*##; s#:[^0-9].*##')
|
|
1334
1384
|
PROJECT=$(python3 -c 'import urllib.parse; print(urllib.parse.quote("group/project", safe=""))')
|
|
1335
|
-
TOKEN=$(
|
|
1385
|
+
TOKEN=$(printf 'protocol=https\\nhost=%s\\n\\n' "$HOST" | GIT_TERMINAL_PROMPT=0 git credential fill | sed -n 's/^password=//p')
|
|
1336
1386
|
UPLOAD=$(curl -sS --request POST \\
|
|
1337
1387
|
--header "Authorization: Bearer $TOKEN" \\
|
|
1338
1388
|
--form "file=@$FILE" \\
|
|
1339
|
-
"https
|
|
1389
|
+
"https://$HOST/api/v4/projects/$PROJECT/uploads")
|
|
1340
1390
|
echo "$UPLOAD" | jq -r .markdown
|
|
1341
1391
|
\`\`\`
|
|
1342
1392
|
|
|
1343
|
-
|
|
1393
|
+
Insert the returned \`markdown\` into the merge request description or comment and add the media's **View in Replicas** dashboard link. Images render inline; MP4, MOV, and WebM render as inline video players. Do not create a public Replicas forge share when this native upload succeeds.
|
|
1344
1394
|
`;
|
|
1345
1395
|
var GITLAB_ABILITY = {
|
|
1346
1396
|
label: "GitLab",
|
|
@@ -3479,7 +3529,6 @@ function parseAgentEventJsonlWithCodexAspTranscript(content, options = {}) {
|
|
|
3479
3529
|
}
|
|
3480
3530
|
|
|
3481
3531
|
// ../shared/src/display-message/parsers/utils.ts
|
|
3482
|
-
var INTERRUPTED_MESSAGE_REGEX = /^\[Request interrupted by user.*\]$/;
|
|
3483
3532
|
function userMessageImages(value) {
|
|
3484
3533
|
if (!Array.isArray(value)) return void 0;
|
|
3485
3534
|
const images = value.filter((item) => isRecord(item) && item.type === "image" && typeof item.mediaType === "string" && typeof item.data === "string");
|
|
@@ -4265,14 +4314,21 @@ function parseMcpToolName(name) {
|
|
|
4265
4314
|
}
|
|
4266
4315
|
|
|
4267
4316
|
// ../shared/src/display-message/parsers/claude-parser.ts
|
|
4317
|
+
var ABORTED_TERMINAL_REASONS = /* @__PURE__ */ new Set(["aborted_streaming", "aborted_tools"]);
|
|
4268
4318
|
function coerceClaudeResultPayload(payload) {
|
|
4269
4319
|
return {
|
|
4270
4320
|
is_error: typeof payload.is_error === "boolean" ? payload.is_error : void 0,
|
|
4271
4321
|
subtype: typeof payload.subtype === "string" ? payload.subtype : void 0,
|
|
4272
|
-
errors: Array.isArray(payload.errors) ? payload.errors.filter((e) => typeof e === "string") : void 0
|
|
4322
|
+
errors: Array.isArray(payload.errors) ? payload.errors.filter((e) => typeof e === "string") : void 0,
|
|
4323
|
+
terminal_reason: typeof payload.terminal_reason === "string" ? payload.terminal_reason : void 0
|
|
4273
4324
|
};
|
|
4274
4325
|
}
|
|
4326
|
+
function stripAgentDiagnosticErrors(errors) {
|
|
4327
|
+
return errors.filter((error) => !error.startsWith("[ede_diagnostic]"));
|
|
4328
|
+
}
|
|
4275
4329
|
function isClaudeResultError(payload) {
|
|
4330
|
+
if (payload.terminal_reason && ABORTED_TERMINAL_REASONS.has(payload.terminal_reason)) return false;
|
|
4331
|
+
if (payload.errors?.length && stripAgentDiagnosticErrors(payload.errors).length === 0) return false;
|
|
4276
4332
|
return Boolean(payload.is_error) || payload.subtype !== "success";
|
|
4277
4333
|
}
|
|
4278
4334
|
function upsertDisplayMessage(messages, message) {
|
|
@@ -4307,7 +4363,6 @@ function parseClaudeEvents(events, parentToolUseId) {
|
|
|
4307
4363
|
return message?.type === "user" && areUserMessagesWithinMatchWindow(message, { content, timestamp });
|
|
4308
4364
|
});
|
|
4309
4365
|
};
|
|
4310
|
-
let turnWasInterrupted = false;
|
|
4311
4366
|
const taskAccumulator = new TaskAccumulator();
|
|
4312
4367
|
const taskSnapshot = () => taskAccumulator.getTasks().map((task) => ({
|
|
4313
4368
|
text: task.subject,
|
|
@@ -4386,7 +4441,6 @@ function parseClaudeEvents(events, parentToolUseId) {
|
|
|
4386
4441
|
if (LOCAL_COMMAND_ECHO_REGEX.test(textContent.trim())) {
|
|
4387
4442
|
return;
|
|
4388
4443
|
}
|
|
4389
|
-
turnWasInterrupted = INTERRUPTED_MESSAGE_REGEX.test(textContent.trim());
|
|
4390
4444
|
const images = content.filter((c) => c.type === "image" && c.source).map((c) => {
|
|
4391
4445
|
const source = c.source;
|
|
4392
4446
|
return {
|
|
@@ -4635,26 +4689,12 @@ function parseClaudeEvents(events, parentToolUseId) {
|
|
|
4635
4689
|
}
|
|
4636
4690
|
if (event.type === "claude-result") {
|
|
4637
4691
|
const payload = coerceClaudeResultPayload(event.payload);
|
|
4638
|
-
const errorList = payload.errors || [];
|
|
4639
|
-
if (turnWasInterrupted) {
|
|
4640
|
-
turnWasInterrupted = false;
|
|
4641
|
-
const genuineErrors = errorList.filter((e) => !e.includes("[ede_diagnostic]"));
|
|
4642
|
-
if (genuineErrors.length > 0) {
|
|
4643
|
-
messages.push({
|
|
4644
|
-
id: `error-${event.timestamp}`,
|
|
4645
|
-
type: "error",
|
|
4646
|
-
message: genuineErrors.join("\n"),
|
|
4647
|
-
timestamp: event.timestamp
|
|
4648
|
-
});
|
|
4649
|
-
}
|
|
4650
|
-
return;
|
|
4651
|
-
}
|
|
4652
4692
|
if (isClaudeResultError(payload)) {
|
|
4653
|
-
const
|
|
4693
|
+
const genuineErrors = stripAgentDiagnosticErrors(payload.errors ?? []);
|
|
4654
4694
|
messages.push({
|
|
4655
4695
|
id: `error-${event.timestamp}`,
|
|
4656
4696
|
type: "error",
|
|
4657
|
-
message:
|
|
4697
|
+
message: genuineErrors.length > 0 ? genuineErrors.join("\n") : "Claude session encountered an unexpected error.",
|
|
4658
4698
|
timestamp: event.timestamp
|
|
4659
4699
|
});
|
|
4660
4700
|
}
|
|
@@ -10031,7 +10071,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
|
10031
10071
|
var MIN_CODEX_CLI_VERSION = "0.144.6";
|
|
10032
10072
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
10033
10073
|
var codexCliVersionEnsured = null;
|
|
10034
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
10074
|
+
var ENGINE_PACKAGE_VERSION = "0.1.511";
|
|
10035
10075
|
var INITIALIZE_METHOD = "initialize";
|
|
10036
10076
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
10037
10077
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -14667,7 +14707,8 @@ function terminalErrorsFromEvent(event, provider, codexTranscript) {
|
|
|
14667
14707
|
if (event.type === "claude-result") {
|
|
14668
14708
|
const payload = coerceClaudeResultPayload(event.payload);
|
|
14669
14709
|
if (!isClaudeResultError(payload)) return null;
|
|
14670
|
-
|
|
14710
|
+
const errors2 = stripAgentDiagnosticErrors(payload.errors ?? []);
|
|
14711
|
+
return errors2.length > 0 ? errors2 : ["Claude run failed"];
|
|
14671
14712
|
}
|
|
14672
14713
|
if (event.type === CODEX_QUOTA_STATUS_EVENT_TYPE) {
|
|
14673
14714
|
return event.payload.state === "out_of_credits" ? ["Codex is out of credits. Top up the connected OpenAI account to resume."] : null;
|