@ricsam/r5d-worker 0.0.47 → 0.0.49
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 +3 -1
- package/dist/cjs/main.cjs +201 -171
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/port-forward-client.cjs +148 -0
- package/dist/cjs/workspace-sync.cjs +38 -0
- package/dist/mjs/main.mjs +197 -171
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/port-forward-client.mjs +114 -0
- package/dist/mjs/workspace-sync.mjs +37 -0
- package/dist/types/main.d.ts +45 -6
- package/dist/types/port-forward-client.d.ts +8 -0
- package/dist/types/workspace-sync.d.ts +1 -0
- package/package.json +1 -1
package/dist/mjs/main.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { installCliUpdate, readInstalledCliVersion } from "./cli-update.mjs";
|
|
|
8
8
|
import { configureVisibleGitIdentity } from "./git-identity.mjs";
|
|
9
9
|
import { hasWorkerHeartbeatTimedOut, WORKER_HEARTBEAT_INTERVAL_MS } from "./heartbeat.mjs";
|
|
10
10
|
import { terminateProcessTree } from "./process-tree.mjs";
|
|
11
|
+
import { openWorkerPortForwardRelay } from "./port-forward-client.mjs";
|
|
11
12
|
import {
|
|
12
13
|
isRetryableWorkerServerStatus,
|
|
13
14
|
superviseWorkerRuntime,
|
|
@@ -294,8 +295,15 @@ function projectPlanDir(planRoot, projectId, branchName) {
|
|
|
294
295
|
validateBranchName(branchName);
|
|
295
296
|
return path.join(planRoot, projectId, branchName);
|
|
296
297
|
}
|
|
297
|
-
function
|
|
298
|
-
|
|
298
|
+
function targetPlanDir(planRoot, target) {
|
|
299
|
+
if (target.type === "project") return projectPlanDir(planRoot, target.projectId, target.branchName);
|
|
300
|
+
if (target.rootProfile === "canonical_sync") {
|
|
301
|
+
throw new Error("Ordinary plans are unavailable in canonical synchronization sessions");
|
|
302
|
+
}
|
|
303
|
+
return path.join(planRoot, "workspace");
|
|
304
|
+
}
|
|
305
|
+
function planEnv(planRoot, target, activePlanId) {
|
|
306
|
+
const plansDir = targetPlanDir(planRoot, target);
|
|
299
307
|
const env = {
|
|
300
308
|
[R5D_PLANS_DIR_ENV]: plansDir
|
|
301
309
|
};
|
|
@@ -313,14 +321,14 @@ function isArtifactEnvPath(filePath) {
|
|
|
313
321
|
return false;
|
|
314
322
|
}
|
|
315
323
|
}
|
|
316
|
-
function artifactApiBasePath(
|
|
317
|
-
return `/preview-api
|
|
324
|
+
function artifactApiBasePath(sessionId) {
|
|
325
|
+
return `/preview-api/artifacts/${encodeURIComponent(sessionId)}`;
|
|
318
326
|
}
|
|
319
|
-
function artifactManifestUrl(baseUrl,
|
|
320
|
-
return new URL(artifactApiBasePath(
|
|
327
|
+
function artifactManifestUrl(baseUrl, sessionId) {
|
|
328
|
+
return new URL(artifactApiBasePath(sessionId), baseUrl);
|
|
321
329
|
}
|
|
322
|
-
function artifactDownloadUrl(baseUrl,
|
|
323
|
-
return new URL(`${artifactApiBasePath(
|
|
330
|
+
function artifactDownloadUrl(baseUrl, sessionId, filename) {
|
|
331
|
+
return new URL(`${artifactApiBasePath(sessionId)}/${encodeURIComponent(filename)}`, baseUrl);
|
|
324
332
|
}
|
|
325
333
|
function sha256Path(filePath) {
|
|
326
334
|
return createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
|
|
@@ -412,7 +420,7 @@ async function syncRemoteFileSet(input) {
|
|
|
412
420
|
}
|
|
413
421
|
async function fetchSessionArtifactManifest(input) {
|
|
414
422
|
return fetchRemoteFileManifest({
|
|
415
|
-
url: artifactManifestUrl(input.baseUrl, input.
|
|
423
|
+
url: artifactManifestUrl(input.baseUrl, input.sessionId),
|
|
416
424
|
token: input.token,
|
|
417
425
|
collectionKey: "artifacts",
|
|
418
426
|
label: "artifact"
|
|
@@ -430,7 +438,7 @@ async function syncSessionArtifacts(input) {
|
|
|
430
438
|
files: artifacts,
|
|
431
439
|
label: "Artifact path",
|
|
432
440
|
download: (artifact) => downloadRemoteSyncedFile({
|
|
433
|
-
url: artifactDownloadUrl(input.baseUrl, input.
|
|
441
|
+
url: artifactDownloadUrl(input.baseUrl, input.sessionId, artifact.filename),
|
|
434
442
|
token: input.token,
|
|
435
443
|
targetDir,
|
|
436
444
|
file: artifact,
|
|
@@ -463,14 +471,12 @@ async function prepareBuiltInToolPaths(input) {
|
|
|
463
471
|
artifactsDir: await syncSessionArtifacts({
|
|
464
472
|
baseUrl: input.baseUrl,
|
|
465
473
|
token: input.token,
|
|
466
|
-
projectId: input.projectId,
|
|
467
|
-
branchName: input.branchName,
|
|
468
474
|
sessionId: input.sessionId,
|
|
469
475
|
artifactRoot: input.artifactRoot
|
|
470
476
|
})
|
|
471
477
|
};
|
|
472
478
|
}
|
|
473
|
-
const plansDir =
|
|
479
|
+
const plansDir = targetPlanDir(input.planRoot, input.target);
|
|
474
480
|
fs.mkdirSync(plansDir, { recursive: true });
|
|
475
481
|
if (parsed.ref === R5D_PLANS_DIR_REF) {
|
|
476
482
|
return { plansDir };
|
|
@@ -492,8 +498,6 @@ async function prepareArtifactEnvForShell(input) {
|
|
|
492
498
|
await syncSessionArtifacts({
|
|
493
499
|
baseUrl: input.baseUrl,
|
|
494
500
|
token: input.token,
|
|
495
|
-
projectId: input.projectId,
|
|
496
|
-
branchName: input.branchName,
|
|
497
501
|
sessionId: input.sessionId,
|
|
498
502
|
artifactRoot: input.artifactRoot
|
|
499
503
|
});
|
|
@@ -510,9 +514,9 @@ async function prepareArtifactEnvForShell(input) {
|
|
|
510
514
|
};
|
|
511
515
|
}
|
|
512
516
|
function preparePlanEnvForShell(input) {
|
|
513
|
-
const plansDir =
|
|
517
|
+
const plansDir = targetPlanDir(input.planRoot, input.target);
|
|
514
518
|
fs.mkdirSync(plansDir, { recursive: true });
|
|
515
|
-
return planEnv(input.planRoot, input.
|
|
519
|
+
return planEnv(input.planRoot, input.target, input.activePlanId);
|
|
516
520
|
}
|
|
517
521
|
async function verifyR5dctlAuth(baseUrl, token) {
|
|
518
522
|
const statusUrl = new URL("/api/r5dctl/auth/status", baseUrl);
|
|
@@ -1127,6 +1131,32 @@ function ensureBranchWorkspace(input) {
|
|
|
1127
1131
|
})
|
|
1128
1132
|
};
|
|
1129
1133
|
}
|
|
1134
|
+
function describeWorkerSessionTarget(target) {
|
|
1135
|
+
return target.type === "project" ? `${target.projectId}/${target.branchName}` : `${target.ownerUserId}/${target.rootProfile}`;
|
|
1136
|
+
}
|
|
1137
|
+
function resolveWorkerSessionTarget(input) {
|
|
1138
|
+
if (input.target.type === "workspace") {
|
|
1139
|
+
if (input.target.rootProfile === "visible_projects") {
|
|
1140
|
+
return { target: input.target, rootPath: input.projectsRoot };
|
|
1141
|
+
}
|
|
1142
|
+
if (!fs.existsSync(path.join(input.workspaceShadowRoot, ".git"))) {
|
|
1143
|
+
throw new Error("The canonical workspace checkout is not initialized on this worker");
|
|
1144
|
+
}
|
|
1145
|
+
return { target: input.target, rootPath: input.workspaceShadowRoot };
|
|
1146
|
+
}
|
|
1147
|
+
const manifest = input.manifestByProjectId.get(input.target.projectId);
|
|
1148
|
+
const projectRoot = projectRootFor(input.projectsRoot, input.target.projectId, input.manifestByProjectId);
|
|
1149
|
+
const workspace = ensureBranchWorkspace({
|
|
1150
|
+
projectId: input.target.projectId,
|
|
1151
|
+
baseUrl: input.baseUrl,
|
|
1152
|
+
token: input.token,
|
|
1153
|
+
projectRoot,
|
|
1154
|
+
syncRoot: input.syncRoot,
|
|
1155
|
+
branchName: input.target.branchName,
|
|
1156
|
+
manifest
|
|
1157
|
+
});
|
|
1158
|
+
return { target: input.target, rootPath: workspace.branchPath, manifest };
|
|
1159
|
+
}
|
|
1130
1160
|
function workspaceSyncCheckoutTargets(input) {
|
|
1131
1161
|
const selected = /* @__PURE__ */ new Map();
|
|
1132
1162
|
const add = (target) => {
|
|
@@ -1155,7 +1185,7 @@ function resolveCommandCwd(branchPath, cwd) {
|
|
|
1155
1185
|
const resolved = path.resolve(branchPath, cwd);
|
|
1156
1186
|
const relative = path.relative(branchPath, resolved);
|
|
1157
1187
|
if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
1158
|
-
throw new Error(`Relative cwd escapes the
|
|
1188
|
+
throw new Error(`Relative cwd escapes the execution root: ${cwd}`);
|
|
1159
1189
|
}
|
|
1160
1190
|
return resolved;
|
|
1161
1191
|
}
|
|
@@ -1190,8 +1220,8 @@ async function streamCommandOutput(stream, onData) {
|
|
|
1190
1220
|
reader.releaseLock();
|
|
1191
1221
|
}
|
|
1192
1222
|
}
|
|
1193
|
-
function
|
|
1194
|
-
return
|
|
1223
|
+
async function prepareBuiltInToolPathsForTarget(input) {
|
|
1224
|
+
return prepareBuiltInToolPaths(input);
|
|
1195
1225
|
}
|
|
1196
1226
|
function formatLineNumberedContent(content, offset, limit) {
|
|
1197
1227
|
const allLines = content.split("\n");
|
|
@@ -1317,11 +1347,11 @@ async function withFileMutationQueue(key, operation) {
|
|
|
1317
1347
|
}
|
|
1318
1348
|
}
|
|
1319
1349
|
}
|
|
1320
|
-
function mutationQueueKey(
|
|
1350
|
+
function mutationQueueKey(target, resolved) {
|
|
1321
1351
|
if (resolved.scope !== "project") {
|
|
1322
1352
|
return `${resolved.scope}:${path.normalize(resolved.absolutePath)}`;
|
|
1323
1353
|
}
|
|
1324
|
-
return
|
|
1354
|
+
return `${describeWorkerSessionTarget(target)}:${path.posix.normalize(resolved.repoRelativePath)}`;
|
|
1325
1355
|
}
|
|
1326
1356
|
function readWorkerTextFile(branchPath, filePath, offset, limit, builtInPaths) {
|
|
1327
1357
|
const resolved = resolveWorkerFilePath(branchPath, filePath, builtInPaths);
|
|
@@ -1396,57 +1426,51 @@ function editWorkerTextFile(branchPath, filePath, edits, builtInPaths) {
|
|
|
1396
1426
|
};
|
|
1397
1427
|
}
|
|
1398
1428
|
async function executeReadFileOperation(input) {
|
|
1399
|
-
const builtInPaths = await
|
|
1429
|
+
const builtInPaths = await prepareBuiltInToolPathsForTarget({
|
|
1430
|
+
target: input.resolvedTarget.target,
|
|
1400
1431
|
filePath: input.message.filePath,
|
|
1401
1432
|
baseUrl: input.baseUrl,
|
|
1402
1433
|
token: input.token,
|
|
1403
|
-
projectId: input.projectId,
|
|
1404
|
-
branchName: input.message.branchName,
|
|
1405
1434
|
sessionId: input.message.sessionId,
|
|
1406
1435
|
activePlanId: input.message.activePlanId,
|
|
1407
1436
|
artifactRoot: input.artifactRoot,
|
|
1408
1437
|
planRoot: input.planRoot,
|
|
1409
1438
|
access: "read"
|
|
1410
1439
|
});
|
|
1411
|
-
|
|
1412
|
-
return readWorkerTextFile(workspace.branchPath, input.message.filePath, input.message.offset, input.message.limit, builtInPaths);
|
|
1440
|
+
return readWorkerTextFile(input.resolvedTarget.rootPath, input.message.filePath, input.message.offset, input.message.limit, builtInPaths);
|
|
1413
1441
|
}
|
|
1414
1442
|
async function executeWriteFileOperation(input) {
|
|
1415
|
-
const builtInPaths = await
|
|
1443
|
+
const builtInPaths = await prepareBuiltInToolPathsForTarget({
|
|
1444
|
+
target: input.resolvedTarget.target,
|
|
1416
1445
|
filePath: input.message.filePath,
|
|
1417
1446
|
baseUrl: input.baseUrl,
|
|
1418
1447
|
token: input.token,
|
|
1419
|
-
projectId: input.projectId,
|
|
1420
|
-
branchName: input.message.branchName,
|
|
1421
1448
|
sessionId: input.message.sessionId,
|
|
1422
1449
|
activePlanId: input.message.activePlanId,
|
|
1423
1450
|
artifactRoot: input.artifactRoot,
|
|
1424
1451
|
planRoot: input.planRoot,
|
|
1425
1452
|
access: "write"
|
|
1426
1453
|
});
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
return writeWorkerTextFile(workspace.branchPath, input.message.filePath, input.message.content, builtInPaths);
|
|
1454
|
+
const resolved = resolveWorkerFilePath(input.resolvedTarget.rootPath, input.message.filePath, builtInPaths);
|
|
1455
|
+
return withFileMutationQueue(mutationQueueKey(input.resolvedTarget.target, resolved), async () => {
|
|
1456
|
+
return writeWorkerTextFile(input.resolvedTarget.rootPath, input.message.filePath, input.message.content, builtInPaths);
|
|
1431
1457
|
});
|
|
1432
1458
|
}
|
|
1433
1459
|
async function executeEditFileOperation(input) {
|
|
1434
|
-
const builtInPaths = await
|
|
1460
|
+
const builtInPaths = await prepareBuiltInToolPathsForTarget({
|
|
1461
|
+
target: input.resolvedTarget.target,
|
|
1435
1462
|
filePath: input.message.filePath,
|
|
1436
1463
|
baseUrl: input.baseUrl,
|
|
1437
1464
|
token: input.token,
|
|
1438
|
-
projectId: input.projectId,
|
|
1439
|
-
branchName: input.message.branchName,
|
|
1440
1465
|
sessionId: input.message.sessionId,
|
|
1441
1466
|
activePlanId: input.message.activePlanId,
|
|
1442
1467
|
artifactRoot: input.artifactRoot,
|
|
1443
1468
|
planRoot: input.planRoot,
|
|
1444
1469
|
access: "write"
|
|
1445
1470
|
});
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
return editWorkerTextFile(workspace.branchPath, input.message.filePath, input.message.edits, builtInPaths);
|
|
1471
|
+
const resolved = resolveWorkerFilePath(input.resolvedTarget.rootPath, input.message.filePath, builtInPaths);
|
|
1472
|
+
return withFileMutationQueue(mutationQueueKey(input.resolvedTarget.target, resolved), async () => {
|
|
1473
|
+
return editWorkerTextFile(input.resolvedTarget.rootPath, input.message.filePath, input.message.edits, builtInPaths);
|
|
1450
1474
|
});
|
|
1451
1475
|
}
|
|
1452
1476
|
const IGNORED_ENTRY_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".next", ".cache", "coverage", "target"]);
|
|
@@ -1559,21 +1583,19 @@ function grepWorkerFiles(branchPath, input, builtInPaths) {
|
|
|
1559
1583
|
}
|
|
1560
1584
|
async function executeGrepOperation(input) {
|
|
1561
1585
|
const toolPath = input.message.path ?? ".";
|
|
1562
|
-
const builtInPaths = await
|
|
1586
|
+
const builtInPaths = await prepareBuiltInToolPathsForTarget({
|
|
1587
|
+
target: input.resolvedTarget.target,
|
|
1563
1588
|
filePath: toolPath,
|
|
1564
1589
|
baseUrl: input.baseUrl,
|
|
1565
1590
|
token: input.token,
|
|
1566
|
-
projectId: input.projectId,
|
|
1567
|
-
branchName: input.message.branchName,
|
|
1568
1591
|
sessionId: input.message.sessionId,
|
|
1569
1592
|
activePlanId: input.message.activePlanId,
|
|
1570
1593
|
artifactRoot: input.artifactRoot,
|
|
1571
1594
|
planRoot: input.planRoot,
|
|
1572
1595
|
access: "read"
|
|
1573
1596
|
});
|
|
1574
|
-
const workspace = ensureOperationBranch({ ...input, branchName: input.message.branchName });
|
|
1575
1597
|
return grepWorkerFiles(
|
|
1576
|
-
|
|
1598
|
+
input.resolvedTarget.rootPath,
|
|
1577
1599
|
{
|
|
1578
1600
|
pattern: input.message.pattern,
|
|
1579
1601
|
path: input.message.path,
|
|
@@ -1620,21 +1642,19 @@ function findWorkerFiles(branchPath, input, builtInPaths) {
|
|
|
1620
1642
|
}
|
|
1621
1643
|
async function executeFindOperation(input) {
|
|
1622
1644
|
const toolPath = input.message.path ?? ".";
|
|
1623
|
-
const builtInPaths = await
|
|
1645
|
+
const builtInPaths = await prepareBuiltInToolPathsForTarget({
|
|
1646
|
+
target: input.resolvedTarget.target,
|
|
1624
1647
|
filePath: toolPath,
|
|
1625
1648
|
baseUrl: input.baseUrl,
|
|
1626
1649
|
token: input.token,
|
|
1627
|
-
projectId: input.projectId,
|
|
1628
|
-
branchName: input.message.branchName,
|
|
1629
1650
|
sessionId: input.message.sessionId,
|
|
1630
1651
|
activePlanId: input.message.activePlanId,
|
|
1631
1652
|
artifactRoot: input.artifactRoot,
|
|
1632
1653
|
planRoot: input.planRoot,
|
|
1633
1654
|
access: "read"
|
|
1634
1655
|
});
|
|
1635
|
-
const workspace = ensureOperationBranch({ ...input, branchName: input.message.branchName });
|
|
1636
1656
|
return findWorkerFiles(
|
|
1637
|
-
|
|
1657
|
+
input.resolvedTarget.rootPath,
|
|
1638
1658
|
{
|
|
1639
1659
|
pattern: input.message.pattern,
|
|
1640
1660
|
path: input.message.path,
|
|
@@ -1664,20 +1684,18 @@ function listWorkerDirectory(branchPath, inputPath = ".", inputLimit, builtInPat
|
|
|
1664
1684
|
}
|
|
1665
1685
|
async function executeLsOperation(input) {
|
|
1666
1686
|
const toolPath = input.message.path ?? ".";
|
|
1667
|
-
const builtInPaths = await
|
|
1687
|
+
const builtInPaths = await prepareBuiltInToolPathsForTarget({
|
|
1688
|
+
target: input.resolvedTarget.target,
|
|
1668
1689
|
filePath: toolPath,
|
|
1669
1690
|
baseUrl: input.baseUrl,
|
|
1670
1691
|
token: input.token,
|
|
1671
|
-
projectId: input.projectId,
|
|
1672
|
-
branchName: input.message.branchName,
|
|
1673
1692
|
sessionId: input.message.sessionId,
|
|
1674
1693
|
activePlanId: input.message.activePlanId,
|
|
1675
1694
|
artifactRoot: input.artifactRoot,
|
|
1676
1695
|
planRoot: input.planRoot,
|
|
1677
1696
|
access: "read"
|
|
1678
1697
|
});
|
|
1679
|
-
|
|
1680
|
-
return listWorkerDirectory(workspace.branchPath, input.message.path, input.message.limit, builtInPaths);
|
|
1698
|
+
return listWorkerDirectory(input.resolvedTarget.rootPath, input.message.path, input.message.limit, builtInPaths);
|
|
1681
1699
|
}
|
|
1682
1700
|
function readWorkerImageFile(branchPath, filePath, builtInPaths) {
|
|
1683
1701
|
const resolved = resolveWorkerFilePath(branchPath, filePath, builtInPaths);
|
|
@@ -1702,20 +1720,18 @@ function readWorkerImageFile(branchPath, filePath, builtInPaths) {
|
|
|
1702
1720
|
};
|
|
1703
1721
|
}
|
|
1704
1722
|
async function executeViewFileBytesOperation(input) {
|
|
1705
|
-
const builtInPaths = await
|
|
1723
|
+
const builtInPaths = await prepareBuiltInToolPathsForTarget({
|
|
1724
|
+
target: input.resolvedTarget.target,
|
|
1706
1725
|
filePath: input.message.filePath,
|
|
1707
1726
|
baseUrl: input.baseUrl,
|
|
1708
1727
|
token: input.token,
|
|
1709
|
-
projectId: input.projectId,
|
|
1710
|
-
branchName: input.message.branchName,
|
|
1711
1728
|
sessionId: input.message.sessionId,
|
|
1712
1729
|
activePlanId: input.message.activePlanId,
|
|
1713
1730
|
artifactRoot: input.artifactRoot,
|
|
1714
1731
|
planRoot: input.planRoot,
|
|
1715
1732
|
access: "read"
|
|
1716
1733
|
});
|
|
1717
|
-
|
|
1718
|
-
return readWorkerImageFile(workspace.branchPath, input.message.filePath, builtInPaths);
|
|
1734
|
+
return readWorkerImageFile(input.resolvedTarget.rootPath, input.message.filePath, builtInPaths);
|
|
1719
1735
|
}
|
|
1720
1736
|
async function executeOperation(input) {
|
|
1721
1737
|
switch (input.message.type) {
|
|
@@ -1735,38 +1751,56 @@ async function executeOperation(input) {
|
|
|
1735
1751
|
return executeViewFileBytesOperation({ ...input, message: input.message });
|
|
1736
1752
|
}
|
|
1737
1753
|
}
|
|
1754
|
+
function targetIdentityEnv(target) {
|
|
1755
|
+
return target.type === "project" ? {
|
|
1756
|
+
R5D_PROJECT_ID: target.projectId,
|
|
1757
|
+
R5D_BRANCH_NAME: target.branchName,
|
|
1758
|
+
R5D_WORKSPACE_OWNER_ID: "",
|
|
1759
|
+
R5D_WORKSPACE_ROOT_PROFILE: ""
|
|
1760
|
+
} : {
|
|
1761
|
+
R5D_WORKSPACE_OWNER_ID: target.ownerUserId,
|
|
1762
|
+
R5D_WORKSPACE_ROOT_PROFILE: target.rootProfile,
|
|
1763
|
+
R5D_PROJECT_ID: "",
|
|
1764
|
+
R5D_BRANCH_NAME: ""
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
async function prepareShellEnvForTarget(input) {
|
|
1768
|
+
const artifactProcessEnv = await prepareArtifactEnvForShell({
|
|
1769
|
+
baseUrl: input.baseUrl,
|
|
1770
|
+
token: input.token,
|
|
1771
|
+
sessionId: input.sessionId,
|
|
1772
|
+
artifactRoot: input.artifactRoot
|
|
1773
|
+
});
|
|
1774
|
+
if (input.target.type === "workspace" && input.target.rootProfile === "canonical_sync") {
|
|
1775
|
+
return {
|
|
1776
|
+
...artifactProcessEnv,
|
|
1777
|
+
...targetIdentityEnv(input.target)
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1780
|
+
return {
|
|
1781
|
+
...artifactProcessEnv,
|
|
1782
|
+
...preparePlanEnvForShell({
|
|
1783
|
+
target: input.target,
|
|
1784
|
+
planRoot: input.planRoot,
|
|
1785
|
+
activePlanId: input.activePlanId
|
|
1786
|
+
}),
|
|
1787
|
+
...targetIdentityEnv(input.target)
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1738
1790
|
async function executeCommand(input) {
|
|
1739
1791
|
const startedAt = Date.now();
|
|
1740
1792
|
let timeout;
|
|
1741
1793
|
try {
|
|
1742
|
-
const
|
|
1743
|
-
|
|
1744
|
-
baseUrl: input.baseUrl,
|
|
1745
|
-
token: input.token,
|
|
1746
|
-
projectRoot: input.projectRoot,
|
|
1747
|
-
syncRoot: input.syncRoot,
|
|
1748
|
-
branchName: input.message.branchName,
|
|
1749
|
-
manifest: input.manifest
|
|
1750
|
-
});
|
|
1751
|
-
const artifactProcessEnv = await prepareArtifactEnvForShell({
|
|
1794
|
+
const targetProcessEnv = await prepareShellEnvForTarget({
|
|
1795
|
+
target: input.resolvedTarget.target,
|
|
1752
1796
|
baseUrl: input.baseUrl,
|
|
1753
1797
|
token: input.token,
|
|
1754
|
-
projectId: input.projectId,
|
|
1755
|
-
branchName: input.message.branchName,
|
|
1756
1798
|
sessionId: input.message.sessionId,
|
|
1757
|
-
artifactRoot: input.artifactRoot
|
|
1758
|
-
});
|
|
1759
|
-
const planProcessEnv = preparePlanEnvForShell({
|
|
1760
|
-
projectId: input.projectId,
|
|
1761
|
-
branchName: input.message.branchName,
|
|
1799
|
+
artifactRoot: input.artifactRoot,
|
|
1762
1800
|
planRoot: input.planRoot,
|
|
1763
1801
|
activePlanId: input.message.env?.R5D_ACTIVE_PLAN_ID
|
|
1764
1802
|
});
|
|
1765
|
-
const
|
|
1766
|
-
if (input.message.env?.R5D_USE_WORKSPACE_GIT === "1" && !fs.existsSync(path.join(commandRoot, ".git"))) {
|
|
1767
|
-
throw new Error("The canonical workspace checkout is not initialized on this worker");
|
|
1768
|
-
}
|
|
1769
|
-
const cwd = resolveCommandCwd(commandRoot, input.message.cwd);
|
|
1803
|
+
const cwd = resolveCommandCwd(input.resolvedTarget.rootPath, input.message.cwd);
|
|
1770
1804
|
const subprocess = Bun.spawn(input.message.argv, {
|
|
1771
1805
|
cwd,
|
|
1772
1806
|
stdout: "pipe",
|
|
@@ -1776,15 +1810,13 @@ async function executeCommand(input) {
|
|
|
1776
1810
|
...process.env,
|
|
1777
1811
|
...githubProcessEnv(),
|
|
1778
1812
|
...input.message.env ?? {},
|
|
1779
|
-
...
|
|
1780
|
-
...planProcessEnv
|
|
1813
|
+
...targetProcessEnv
|
|
1781
1814
|
}
|
|
1782
1815
|
});
|
|
1783
1816
|
activeProcesses.set(input.message.runId, {
|
|
1784
1817
|
process: subprocess,
|
|
1785
|
-
|
|
1818
|
+
target: input.resolvedTarget.target,
|
|
1786
1819
|
sessionId: input.message.sessionId ?? "",
|
|
1787
|
-
branchName: input.message.branchName,
|
|
1788
1820
|
mode: "foreground",
|
|
1789
1821
|
pid: subprocess.pid,
|
|
1790
1822
|
processGroupId: process.platform === "win32" ? void 0 : subprocess.pid,
|
|
@@ -1848,34 +1880,16 @@ async function executeStreamingCommand(input) {
|
|
|
1848
1880
|
});
|
|
1849
1881
|
return;
|
|
1850
1882
|
}
|
|
1851
|
-
const
|
|
1852
|
-
|
|
1853
|
-
baseUrl: input.baseUrl,
|
|
1854
|
-
token: input.token,
|
|
1855
|
-
projectRoot: input.projectRoot,
|
|
1856
|
-
syncRoot: input.syncRoot,
|
|
1857
|
-
branchName: input.message.branchName,
|
|
1858
|
-
manifest: input.manifest
|
|
1859
|
-
});
|
|
1860
|
-
const artifactProcessEnv = await prepareArtifactEnvForShell({
|
|
1883
|
+
const targetProcessEnv = await prepareShellEnvForTarget({
|
|
1884
|
+
target: input.resolvedTarget.target,
|
|
1861
1885
|
baseUrl: input.baseUrl,
|
|
1862
1886
|
token: input.token,
|
|
1863
|
-
projectId: input.projectId,
|
|
1864
|
-
branchName: input.message.branchName,
|
|
1865
1887
|
sessionId: input.message.sessionId,
|
|
1866
|
-
artifactRoot: input.artifactRoot
|
|
1867
|
-
});
|
|
1868
|
-
const planProcessEnv = preparePlanEnvForShell({
|
|
1869
|
-
projectId: input.projectId,
|
|
1870
|
-
branchName: input.message.branchName,
|
|
1888
|
+
artifactRoot: input.artifactRoot,
|
|
1871
1889
|
planRoot: input.planRoot,
|
|
1872
1890
|
activePlanId: input.message.env?.R5D_ACTIVE_PLAN_ID
|
|
1873
1891
|
});
|
|
1874
|
-
const
|
|
1875
|
-
if (input.message.env?.R5D_USE_WORKSPACE_GIT === "1" && !fs.existsSync(path.join(commandRoot, ".git"))) {
|
|
1876
|
-
throw new Error("The canonical workspace checkout is not initialized on this worker");
|
|
1877
|
-
}
|
|
1878
|
-
const cwd = resolveCommandCwd(commandRoot, input.message.cwd);
|
|
1892
|
+
const cwd = resolveCommandCwd(input.resolvedTarget.rootPath, input.message.cwd);
|
|
1879
1893
|
const subprocess = Bun.spawn(input.message.argv, {
|
|
1880
1894
|
cwd,
|
|
1881
1895
|
stdout: "pipe",
|
|
@@ -1885,15 +1899,13 @@ async function executeStreamingCommand(input) {
|
|
|
1885
1899
|
...process.env,
|
|
1886
1900
|
...githubProcessEnv(),
|
|
1887
1901
|
...input.message.env ?? {},
|
|
1888
|
-
...
|
|
1889
|
-
...planProcessEnv
|
|
1902
|
+
...targetProcessEnv
|
|
1890
1903
|
}
|
|
1891
1904
|
});
|
|
1892
1905
|
activeProcesses.set(input.message.runId, {
|
|
1893
1906
|
process: subprocess,
|
|
1894
|
-
|
|
1907
|
+
target: input.resolvedTarget.target,
|
|
1895
1908
|
sessionId: input.message.sessionId,
|
|
1896
|
-
branchName: input.message.branchName,
|
|
1897
1909
|
mode: input.message.mode,
|
|
1898
1910
|
pid: subprocess.pid,
|
|
1899
1911
|
processGroupId: process.platform === "win32" ? void 0 : subprocess.pid,
|
|
@@ -1990,9 +2002,8 @@ function sendWorkerMessage(ws, message) {
|
|
|
1990
2002
|
function buildActiveProcessReports() {
|
|
1991
2003
|
return Array.from(activeProcesses.entries()).filter(([, active]) => active.sessionId.length > 0).map(([runId, active]) => ({
|
|
1992
2004
|
runId,
|
|
1993
|
-
|
|
2005
|
+
target: active.target,
|
|
1994
2006
|
sessionId: active.sessionId,
|
|
1995
|
-
branchName: active.branchName,
|
|
1996
2007
|
platform: process.platform,
|
|
1997
2008
|
arch: process.arch,
|
|
1998
2009
|
mode: active.mode,
|
|
@@ -2200,21 +2211,12 @@ function resolveHostShell(command, platform = process.platform) {
|
|
|
2200
2211
|
}
|
|
2201
2212
|
async function openPty(input) {
|
|
2202
2213
|
try {
|
|
2203
|
-
const
|
|
2204
|
-
|
|
2205
|
-
baseUrl: input.baseUrl,
|
|
2206
|
-
token: input.token,
|
|
2207
|
-
projectRoot: input.projectRoot,
|
|
2208
|
-
syncRoot: input.syncRoot,
|
|
2209
|
-
branchName: input.message.branchName,
|
|
2210
|
-
manifest: input.manifest
|
|
2211
|
-
});
|
|
2212
|
-
const planProcessEnv = preparePlanEnvForShell({
|
|
2213
|
-
projectId: input.projectId,
|
|
2214
|
-
branchName: input.message.branchName,
|
|
2214
|
+
const planProcessEnv = !(input.resolvedTarget.target.type === "workspace" && input.resolvedTarget.target.rootProfile === "canonical_sync") ? preparePlanEnvForShell({
|
|
2215
|
+
target: input.resolvedTarget.target,
|
|
2215
2216
|
planRoot: input.planRoot,
|
|
2216
2217
|
activePlanId: input.message.env?.R5D_ACTIVE_PLAN_ID
|
|
2217
|
-
});
|
|
2218
|
+
}) : {};
|
|
2219
|
+
const targetProcessEnv = targetIdentityEnv(input.resolvedTarget.target);
|
|
2218
2220
|
const shell = resolveHostShell(input.message.command);
|
|
2219
2221
|
const ptyProcess = createNodePtyBridge({
|
|
2220
2222
|
file: shell.file,
|
|
@@ -2223,14 +2225,13 @@ async function openPty(input) {
|
|
|
2223
2225
|
name: "xterm-256color",
|
|
2224
2226
|
cols: Math.max(1, Math.min(Math.floor(input.message.cols || 80), 500)),
|
|
2225
2227
|
rows: Math.max(1, Math.min(Math.floor(input.message.rows || 24), 500)),
|
|
2226
|
-
cwd:
|
|
2228
|
+
cwd: input.resolvedTarget.rootPath,
|
|
2227
2229
|
env: {
|
|
2228
2230
|
...process.env,
|
|
2229
2231
|
...githubProcessEnv(),
|
|
2230
2232
|
...input.message.env ?? {},
|
|
2231
2233
|
...planProcessEnv,
|
|
2232
|
-
|
|
2233
|
-
R5D_BRANCH_NAME: input.message.branchName
|
|
2234
|
+
...targetProcessEnv
|
|
2234
2235
|
}
|
|
2235
2236
|
},
|
|
2236
2237
|
onOpened: () => {
|
|
@@ -2268,8 +2269,7 @@ async function openPty(input) {
|
|
|
2268
2269
|
});
|
|
2269
2270
|
activePtys.set(input.message.ptyId, {
|
|
2270
2271
|
...ptyProcess,
|
|
2271
|
-
|
|
2272
|
-
branchName: input.message.branchName
|
|
2272
|
+
target: input.resolvedTarget.target
|
|
2273
2273
|
});
|
|
2274
2274
|
} catch (error) {
|
|
2275
2275
|
sendWorkerMessage(input.ws, {
|
|
@@ -2388,6 +2388,15 @@ async function startWorker(options) {
|
|
|
2388
2388
|
const allManifestCheckouts = () => [...manifestByProjectId.values()].flatMap(
|
|
2389
2389
|
(manifest) => manifest.branches.map((branchName) => ({ projectId: manifest.projectId, branchName }))
|
|
2390
2390
|
);
|
|
2391
|
+
const resolveMessageTarget = (target) => resolveWorkerSessionTarget({
|
|
2392
|
+
target,
|
|
2393
|
+
baseUrl,
|
|
2394
|
+
token,
|
|
2395
|
+
projectsRoot,
|
|
2396
|
+
syncRoot,
|
|
2397
|
+
workspaceShadowRoot,
|
|
2398
|
+
manifestByProjectId
|
|
2399
|
+
});
|
|
2391
2400
|
const ensureVisibleWorkspaceCheckouts = (targets, options2 = {}) => {
|
|
2392
2401
|
const created = [];
|
|
2393
2402
|
for (const target of targets) {
|
|
@@ -2530,7 +2539,8 @@ async function startWorker(options) {
|
|
|
2530
2539
|
r5dctlVersion: readInstalledCliVersion("r5dctl"),
|
|
2531
2540
|
capabilities: {
|
|
2532
2541
|
updateClis: true,
|
|
2533
|
-
canonicalResolverCheckout: true
|
|
2542
|
+
canonicalResolverCheckout: true,
|
|
2543
|
+
browserPortForwarding: true
|
|
2534
2544
|
},
|
|
2535
2545
|
projectRoot: projectsRoot,
|
|
2536
2546
|
artifactRoot,
|
|
@@ -2642,7 +2652,11 @@ async function startWorker(options) {
|
|
|
2642
2652
|
}
|
|
2643
2653
|
if (message.type === "workspace_head_updated") {
|
|
2644
2654
|
if (!activeWorkspaceIncidentId) {
|
|
2645
|
-
await runRequestedWorkspaceSync(
|
|
2655
|
+
await runRequestedWorkspaceSync(
|
|
2656
|
+
crypto.randomUUID(),
|
|
2657
|
+
{ type: "inbound_head", detail: message.commitHash },
|
|
2658
|
+
{ skipVisibleMirror: true }
|
|
2659
|
+
);
|
|
2646
2660
|
}
|
|
2647
2661
|
return;
|
|
2648
2662
|
}
|
|
@@ -2652,8 +2666,6 @@ async function startWorker(options) {
|
|
|
2652
2666
|
await syncSessionArtifacts({
|
|
2653
2667
|
baseUrl,
|
|
2654
2668
|
token,
|
|
2655
|
-
projectId: message.projectId,
|
|
2656
|
-
branchName: message.branchName,
|
|
2657
2669
|
sessionId: message.sessionId,
|
|
2658
2670
|
artifactRoot
|
|
2659
2671
|
});
|
|
@@ -2683,6 +2695,17 @@ async function startWorker(options) {
|
|
|
2683
2695
|
pendingProcessTerminals.delete(message.runId);
|
|
2684
2696
|
return;
|
|
2685
2697
|
}
|
|
2698
|
+
if (message.type === "port_forward_connect") {
|
|
2699
|
+
openWorkerPortForwardRelay({
|
|
2700
|
+
baseUrl,
|
|
2701
|
+
token,
|
|
2702
|
+
label,
|
|
2703
|
+
forwardId: message.forwardId,
|
|
2704
|
+
relayConnectionId: message.relayConnectionId,
|
|
2705
|
+
workerPort: message.workerPort
|
|
2706
|
+
});
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2686
2709
|
if (message.type === "update_clis") {
|
|
2687
2710
|
if (cliUpdateInProgress) {
|
|
2688
2711
|
sendWorkerMessage(ws, {
|
|
@@ -2762,11 +2785,19 @@ async function startWorker(options) {
|
|
|
2762
2785
|
});
|
|
2763
2786
|
return;
|
|
2764
2787
|
}
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2788
|
+
try {
|
|
2789
|
+
const resolvedTarget = resolveMessageTarget(message.target);
|
|
2790
|
+
process.stdout.write(`[r5d-worker] pty ${message.ptyId}: ${describeWorkerSessionTarget(message.target)}
|
|
2768
2791
|
`);
|
|
2769
|
-
|
|
2792
|
+
await openPty({ ws, message, resolvedTarget, planRoot });
|
|
2793
|
+
} catch (error) {
|
|
2794
|
+
sendWorkerMessage(ws, {
|
|
2795
|
+
type: "pty_error",
|
|
2796
|
+
requestId: message.requestId,
|
|
2797
|
+
ptyId: message.ptyId,
|
|
2798
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2799
|
+
});
|
|
2800
|
+
}
|
|
2770
2801
|
return;
|
|
2771
2802
|
}
|
|
2772
2803
|
if (message.type === "pty_input") {
|
|
@@ -2792,22 +2823,22 @@ async function startWorker(options) {
|
|
|
2792
2823
|
});
|
|
2793
2824
|
return;
|
|
2794
2825
|
}
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2826
|
+
let result;
|
|
2827
|
+
try {
|
|
2828
|
+
const resolvedTarget = resolveMessageTarget(message.target);
|
|
2829
|
+
process.stdout.write(`[r5d-worker] exec ${message.runId}: ${message.argv.join(" ")}
|
|
2798
2830
|
`);
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
});
|
|
2831
|
+
result = await executeCommand({ message, resolvedTarget, baseUrl, token, artifactRoot, planRoot });
|
|
2832
|
+
} catch (error) {
|
|
2833
|
+
result = {
|
|
2834
|
+
type: "exec_result",
|
|
2835
|
+
requestId: message.requestId,
|
|
2836
|
+
stdout: "",
|
|
2837
|
+
stderr: "",
|
|
2838
|
+
exitCode: 1,
|
|
2839
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2811
2842
|
ws.send(JSON.stringify(result));
|
|
2812
2843
|
return;
|
|
2813
2844
|
}
|
|
@@ -2827,22 +2858,17 @@ async function startWorker(options) {
|
|
|
2827
2858
|
runId: message.runId
|
|
2828
2859
|
});
|
|
2829
2860
|
try {
|
|
2830
|
-
const
|
|
2831
|
-
const projectRoot = projectRootFor(projectsRoot, message.projectId, manifestByProjectId);
|
|
2861
|
+
const resolvedTarget = resolveMessageTarget(message.target);
|
|
2832
2862
|
process.stdout.write(`[r5d-worker] exec_start ${message.runId}: ${message.argv.join(" ")}
|
|
2833
2863
|
`);
|
|
2834
2864
|
void executeStreamingCommand({
|
|
2835
2865
|
ws,
|
|
2836
2866
|
message,
|
|
2837
|
-
|
|
2867
|
+
resolvedTarget,
|
|
2838
2868
|
baseUrl,
|
|
2839
2869
|
token,
|
|
2840
|
-
projectRoot,
|
|
2841
|
-
syncRoot,
|
|
2842
2870
|
artifactRoot,
|
|
2843
|
-
planRoot
|
|
2844
|
-
workspaceShadowRoot,
|
|
2845
|
-
manifest
|
|
2871
|
+
planRoot
|
|
2846
2872
|
}).catch((error) => {
|
|
2847
2873
|
sendWorkerMessage(ws, {
|
|
2848
2874
|
type: "exec_start_error",
|
|
@@ -2863,18 +2889,14 @@ async function startWorker(options) {
|
|
|
2863
2889
|
}
|
|
2864
2890
|
if (message.type === "read" || message.type === "write" || message.type === "edit" || message.type === "grep" || message.type === "find" || message.type === "ls" || message.type === "view_file_bytes") {
|
|
2865
2891
|
try {
|
|
2866
|
-
const
|
|
2867
|
-
const projectRoot = projectRootFor(projectsRoot, message.projectId, manifestByProjectId);
|
|
2892
|
+
const resolvedTarget = resolveMessageTarget(message.target);
|
|
2868
2893
|
const result = await executeOperation({
|
|
2869
2894
|
message,
|
|
2870
|
-
|
|
2895
|
+
resolvedTarget,
|
|
2871
2896
|
baseUrl,
|
|
2872
2897
|
token,
|
|
2873
|
-
projectRoot,
|
|
2874
|
-
syncRoot,
|
|
2875
2898
|
artifactRoot,
|
|
2876
|
-
planRoot
|
|
2877
|
-
manifest
|
|
2899
|
+
planRoot
|
|
2878
2900
|
});
|
|
2879
2901
|
ws.send(
|
|
2880
2902
|
JSON.stringify({
|
|
@@ -3001,6 +3023,7 @@ if (isCliEntrypoint()) {
|
|
|
3001
3023
|
});
|
|
3002
3024
|
}
|
|
3003
3025
|
export {
|
|
3026
|
+
describeWorkerSessionTarget,
|
|
3004
3027
|
editWorkerTextFile,
|
|
3005
3028
|
ensureVisibleGitCheckout,
|
|
3006
3029
|
findWorkerFiles,
|
|
@@ -3009,11 +3032,14 @@ export {
|
|
|
3009
3032
|
isArtifactEnvPath,
|
|
3010
3033
|
listWorkerDirectory,
|
|
3011
3034
|
prepareArtifactEnvForShell,
|
|
3035
|
+
prepareBuiltInToolPathsForTarget,
|
|
3012
3036
|
preparePlanEnvForShell,
|
|
3037
|
+
prepareShellEnvForTarget,
|
|
3013
3038
|
readWorkerImageFile,
|
|
3014
3039
|
readWorkerTextFile,
|
|
3015
3040
|
resolveHostShell,
|
|
3016
3041
|
resolveWorkerFilePath,
|
|
3042
|
+
resolveWorkerSessionTarget,
|
|
3017
3043
|
syncSessionArtifacts,
|
|
3018
3044
|
visibleCheckoutGitTestHarness,
|
|
3019
3045
|
visibleCheckoutRemoteFor,
|