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