@ricsam/r5d-worker 0.0.12 → 0.0.14
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/cjs/main.cjs +55 -20
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/main.mjs +53 -20
- package/dist/mjs/package.json +1 -1
- package/dist/types/main.d.ts +13 -0
- package/package.json +1 -1
package/dist/cjs/main.cjs
CHANGED
|
@@ -31,6 +31,8 @@ var main_exports = {};
|
|
|
31
31
|
__export(main_exports, {
|
|
32
32
|
ensureVisibleGitCheckout: () => ensureVisibleGitCheckout,
|
|
33
33
|
isArtifactEnvPath: () => isArtifactEnvPath,
|
|
34
|
+
prepareArtifactEnvForShell: () => prepareArtifactEnvForShell,
|
|
35
|
+
resolveProjectFilePath: () => resolveProjectFilePath,
|
|
34
36
|
syncSessionArtifacts: () => syncSessionArtifacts
|
|
35
37
|
});
|
|
36
38
|
module.exports = __toCommonJS(main_exports);
|
|
@@ -410,6 +412,29 @@ function rejectArtifactWritePath(filePath) {
|
|
|
410
412
|
throw new Error(`${R5D_ARTIFACTS_DIR_REF} attachments are read-only. Copy them into a project path before editing or creating files.`);
|
|
411
413
|
}
|
|
412
414
|
}
|
|
415
|
+
async function prepareArtifactEnvForShell(input) {
|
|
416
|
+
if (!input.sessionId) {
|
|
417
|
+
return {};
|
|
418
|
+
}
|
|
419
|
+
try {
|
|
420
|
+
await syncSessionArtifacts({
|
|
421
|
+
baseUrl: input.baseUrl,
|
|
422
|
+
token: input.token,
|
|
423
|
+
projectId: input.projectId,
|
|
424
|
+
branchName: input.branchName,
|
|
425
|
+
sessionId: input.sessionId,
|
|
426
|
+
artifactRoot: input.artifactRoot
|
|
427
|
+
});
|
|
428
|
+
} catch (error) {
|
|
429
|
+
process.stderr.write(`[r5d-worker] artifact sync skipped for ${input.sessionId}: ${error instanceof Error ? error.message : String(error)}
|
|
430
|
+
`);
|
|
431
|
+
}
|
|
432
|
+
const artifactsDir = sessionArtifactDir(input.artifactRoot, input.sessionId);
|
|
433
|
+
import_node_fs.default.mkdirSync(artifactsDir, { recursive: true });
|
|
434
|
+
return {
|
|
435
|
+
R5D_ARTIFACTS_DIR: artifactsDir
|
|
436
|
+
};
|
|
437
|
+
}
|
|
413
438
|
async function verifyR5dctlAuth(baseUrl, token) {
|
|
414
439
|
const statusUrl = new URL("/api/r5dctl/auth/status", baseUrl);
|
|
415
440
|
let response;
|
|
@@ -524,9 +549,12 @@ function getInternalStatus(context) {
|
|
|
524
549
|
function hasInternalWorktreeChanges(context) {
|
|
525
550
|
return getInternalStatus(context).trim().length > 0;
|
|
526
551
|
}
|
|
552
|
+
function isInsideBranchPath(branchPath, filePath) {
|
|
553
|
+
const relative = import_node_path.default.relative(import_node_path.default.resolve(branchPath), import_node_path.default.resolve(filePath));
|
|
554
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${import_node_path.default.sep}`) && !import_node_path.default.isAbsolute(relative);
|
|
555
|
+
}
|
|
527
556
|
function assertInsideBranch(branchPath, filePath) {
|
|
528
|
-
|
|
529
|
-
if (relative === ".." || relative.startsWith(`..${import_node_path.default.sep}`) || import_node_path.default.isAbsolute(relative)) {
|
|
557
|
+
if (!isInsideBranchPath(branchPath, filePath)) {
|
|
530
558
|
throw new Error("File path escapes the project branch");
|
|
531
559
|
}
|
|
532
560
|
}
|
|
@@ -534,17 +562,27 @@ function resolveProjectFilePath(branchPath, virtualPath) {
|
|
|
534
562
|
if (typeof virtualPath !== "string" || !virtualPath.startsWith("/") || virtualPath.includes("\0")) {
|
|
535
563
|
throw new Error(`File path must be an absolute project path starting with /. Got: ${JSON.stringify(virtualPath)}`);
|
|
536
564
|
}
|
|
565
|
+
const checkoutAbsolutePath = import_node_path.default.resolve(virtualPath);
|
|
566
|
+
if (isInsideBranchPath(branchPath, checkoutAbsolutePath)) {
|
|
567
|
+
const checkoutVirtualPath = toVirtualPath(import_node_path.default.resolve(branchPath), checkoutAbsolutePath);
|
|
568
|
+
if (checkoutVirtualPath !== virtualPath) {
|
|
569
|
+
return resolveProjectFilePath(branchPath, checkoutVirtualPath);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (virtualPath.split("/").includes("..")) {
|
|
573
|
+
throw new Error(`Invalid project file path: ${virtualPath}`);
|
|
574
|
+
}
|
|
537
575
|
const normalized = import_node_path.default.posix.normalize(virtualPath);
|
|
538
|
-
if (normalized
|
|
576
|
+
if (normalized.startsWith("/../")) {
|
|
539
577
|
throw new Error(`Invalid project file path: ${virtualPath}`);
|
|
540
578
|
}
|
|
541
|
-
const repoRelativePath = normalized.slice(1);
|
|
579
|
+
const repoRelativePath = normalized === "/" ? "" : normalized.slice(1);
|
|
542
580
|
if (repoRelativePath === ".git" || repoRelativePath.startsWith(".git/")) {
|
|
543
581
|
throw new Error("Refusing to access .git through worker file tools");
|
|
544
582
|
}
|
|
545
|
-
const absolutePath = import_node_path.default.resolve(branchPath, ...repoRelativePath.split("/"));
|
|
583
|
+
const absolutePath = repoRelativePath ? import_node_path.default.resolve(branchPath, ...repoRelativePath.split("/")) : import_node_path.default.resolve(branchPath);
|
|
546
584
|
assertInsideBranch(branchPath, absolutePath);
|
|
547
|
-
return { absolutePath, virtualPath: `/${repoRelativePath}
|
|
585
|
+
return { absolutePath, virtualPath: repoRelativePath ? `/${repoRelativePath}` : "/", repoRelativePath };
|
|
548
586
|
}
|
|
549
587
|
function branchLockKey(projectId, branchName) {
|
|
550
588
|
return `${projectId}:${branchName}`;
|
|
@@ -1486,18 +1524,14 @@ async function executeCommand(input) {
|
|
|
1486
1524
|
branchName: input.message.branchName,
|
|
1487
1525
|
manifest: input.manifest
|
|
1488
1526
|
});
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
artifactRoot: input.artifactRoot
|
|
1498
|
-
});
|
|
1499
|
-
artifactProcessEnv = artifactEnv(input.artifactRoot, input.message.sessionId);
|
|
1500
|
-
}
|
|
1527
|
+
const artifactProcessEnv = await prepareArtifactEnvForShell({
|
|
1528
|
+
baseUrl: input.baseUrl,
|
|
1529
|
+
token: input.token,
|
|
1530
|
+
projectId: input.projectId,
|
|
1531
|
+
branchName: input.message.branchName,
|
|
1532
|
+
sessionId: input.message.sessionId,
|
|
1533
|
+
artifactRoot: input.artifactRoot
|
|
1534
|
+
});
|
|
1501
1535
|
const cwd = resolveCommandCwd(workspace.branchPath, input.message.cwd);
|
|
1502
1536
|
const subprocess = Bun.spawn(input.message.argv, {
|
|
1503
1537
|
cwd,
|
|
@@ -1571,7 +1605,7 @@ async function executeStreamingCommand(input) {
|
|
|
1571
1605
|
branchName: input.message.branchName,
|
|
1572
1606
|
manifest: input.manifest
|
|
1573
1607
|
});
|
|
1574
|
-
await
|
|
1608
|
+
const artifactProcessEnv = await prepareArtifactEnvForShell({
|
|
1575
1609
|
baseUrl: input.baseUrl,
|
|
1576
1610
|
token: input.token,
|
|
1577
1611
|
projectId: input.projectId,
|
|
@@ -1579,7 +1613,6 @@ async function executeStreamingCommand(input) {
|
|
|
1579
1613
|
sessionId: input.message.sessionId,
|
|
1580
1614
|
artifactRoot: input.artifactRoot
|
|
1581
1615
|
});
|
|
1582
|
-
const artifactProcessEnv = artifactEnv(input.artifactRoot, input.message.sessionId);
|
|
1583
1616
|
const cwd = resolveCommandCwd(workspace.branchPath, input.message.cwd);
|
|
1584
1617
|
const subprocess = Bun.spawn(input.message.argv, {
|
|
1585
1618
|
cwd,
|
|
@@ -2218,5 +2251,7 @@ if (isCliEntrypoint()) {
|
|
|
2218
2251
|
0 && (module.exports = {
|
|
2219
2252
|
ensureVisibleGitCheckout,
|
|
2220
2253
|
isArtifactEnvPath,
|
|
2254
|
+
prepareArtifactEnvForShell,
|
|
2255
|
+
resolveProjectFilePath,
|
|
2221
2256
|
syncSessionArtifacts
|
|
2222
2257
|
});
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/main.mjs
CHANGED
|
@@ -374,6 +374,29 @@ function rejectArtifactWritePath(filePath) {
|
|
|
374
374
|
throw new Error(`${R5D_ARTIFACTS_DIR_REF} attachments are read-only. Copy them into a project path before editing or creating files.`);
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
|
+
async function prepareArtifactEnvForShell(input) {
|
|
378
|
+
if (!input.sessionId) {
|
|
379
|
+
return {};
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
await syncSessionArtifacts({
|
|
383
|
+
baseUrl: input.baseUrl,
|
|
384
|
+
token: input.token,
|
|
385
|
+
projectId: input.projectId,
|
|
386
|
+
branchName: input.branchName,
|
|
387
|
+
sessionId: input.sessionId,
|
|
388
|
+
artifactRoot: input.artifactRoot
|
|
389
|
+
});
|
|
390
|
+
} catch (error) {
|
|
391
|
+
process.stderr.write(`[r5d-worker] artifact sync skipped for ${input.sessionId}: ${error instanceof Error ? error.message : String(error)}
|
|
392
|
+
`);
|
|
393
|
+
}
|
|
394
|
+
const artifactsDir = sessionArtifactDir(input.artifactRoot, input.sessionId);
|
|
395
|
+
fs.mkdirSync(artifactsDir, { recursive: true });
|
|
396
|
+
return {
|
|
397
|
+
R5D_ARTIFACTS_DIR: artifactsDir
|
|
398
|
+
};
|
|
399
|
+
}
|
|
377
400
|
async function verifyR5dctlAuth(baseUrl, token) {
|
|
378
401
|
const statusUrl = new URL("/api/r5dctl/auth/status", baseUrl);
|
|
379
402
|
let response;
|
|
@@ -488,9 +511,12 @@ function getInternalStatus(context) {
|
|
|
488
511
|
function hasInternalWorktreeChanges(context) {
|
|
489
512
|
return getInternalStatus(context).trim().length > 0;
|
|
490
513
|
}
|
|
514
|
+
function isInsideBranchPath(branchPath, filePath) {
|
|
515
|
+
const relative = path.relative(path.resolve(branchPath), path.resolve(filePath));
|
|
516
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
517
|
+
}
|
|
491
518
|
function assertInsideBranch(branchPath, filePath) {
|
|
492
|
-
|
|
493
|
-
if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
519
|
+
if (!isInsideBranchPath(branchPath, filePath)) {
|
|
494
520
|
throw new Error("File path escapes the project branch");
|
|
495
521
|
}
|
|
496
522
|
}
|
|
@@ -498,17 +524,27 @@ function resolveProjectFilePath(branchPath, virtualPath) {
|
|
|
498
524
|
if (typeof virtualPath !== "string" || !virtualPath.startsWith("/") || virtualPath.includes("\0")) {
|
|
499
525
|
throw new Error(`File path must be an absolute project path starting with /. Got: ${JSON.stringify(virtualPath)}`);
|
|
500
526
|
}
|
|
527
|
+
const checkoutAbsolutePath = path.resolve(virtualPath);
|
|
528
|
+
if (isInsideBranchPath(branchPath, checkoutAbsolutePath)) {
|
|
529
|
+
const checkoutVirtualPath = toVirtualPath(path.resolve(branchPath), checkoutAbsolutePath);
|
|
530
|
+
if (checkoutVirtualPath !== virtualPath) {
|
|
531
|
+
return resolveProjectFilePath(branchPath, checkoutVirtualPath);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (virtualPath.split("/").includes("..")) {
|
|
535
|
+
throw new Error(`Invalid project file path: ${virtualPath}`);
|
|
536
|
+
}
|
|
501
537
|
const normalized = path.posix.normalize(virtualPath);
|
|
502
|
-
if (normalized
|
|
538
|
+
if (normalized.startsWith("/../")) {
|
|
503
539
|
throw new Error(`Invalid project file path: ${virtualPath}`);
|
|
504
540
|
}
|
|
505
|
-
const repoRelativePath = normalized.slice(1);
|
|
541
|
+
const repoRelativePath = normalized === "/" ? "" : normalized.slice(1);
|
|
506
542
|
if (repoRelativePath === ".git" || repoRelativePath.startsWith(".git/")) {
|
|
507
543
|
throw new Error("Refusing to access .git through worker file tools");
|
|
508
544
|
}
|
|
509
|
-
const absolutePath = path.resolve(branchPath, ...repoRelativePath.split("/"));
|
|
545
|
+
const absolutePath = repoRelativePath ? path.resolve(branchPath, ...repoRelativePath.split("/")) : path.resolve(branchPath);
|
|
510
546
|
assertInsideBranch(branchPath, absolutePath);
|
|
511
|
-
return { absolutePath, virtualPath: `/${repoRelativePath}
|
|
547
|
+
return { absolutePath, virtualPath: repoRelativePath ? `/${repoRelativePath}` : "/", repoRelativePath };
|
|
512
548
|
}
|
|
513
549
|
function branchLockKey(projectId, branchName) {
|
|
514
550
|
return `${projectId}:${branchName}`;
|
|
@@ -1450,18 +1486,14 @@ async function executeCommand(input) {
|
|
|
1450
1486
|
branchName: input.message.branchName,
|
|
1451
1487
|
manifest: input.manifest
|
|
1452
1488
|
});
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
artifactRoot: input.artifactRoot
|
|
1462
|
-
});
|
|
1463
|
-
artifactProcessEnv = artifactEnv(input.artifactRoot, input.message.sessionId);
|
|
1464
|
-
}
|
|
1489
|
+
const artifactProcessEnv = await prepareArtifactEnvForShell({
|
|
1490
|
+
baseUrl: input.baseUrl,
|
|
1491
|
+
token: input.token,
|
|
1492
|
+
projectId: input.projectId,
|
|
1493
|
+
branchName: input.message.branchName,
|
|
1494
|
+
sessionId: input.message.sessionId,
|
|
1495
|
+
artifactRoot: input.artifactRoot
|
|
1496
|
+
});
|
|
1465
1497
|
const cwd = resolveCommandCwd(workspace.branchPath, input.message.cwd);
|
|
1466
1498
|
const subprocess = Bun.spawn(input.message.argv, {
|
|
1467
1499
|
cwd,
|
|
@@ -1535,7 +1567,7 @@ async function executeStreamingCommand(input) {
|
|
|
1535
1567
|
branchName: input.message.branchName,
|
|
1536
1568
|
manifest: input.manifest
|
|
1537
1569
|
});
|
|
1538
|
-
await
|
|
1570
|
+
const artifactProcessEnv = await prepareArtifactEnvForShell({
|
|
1539
1571
|
baseUrl: input.baseUrl,
|
|
1540
1572
|
token: input.token,
|
|
1541
1573
|
projectId: input.projectId,
|
|
@@ -1543,7 +1575,6 @@ async function executeStreamingCommand(input) {
|
|
|
1543
1575
|
sessionId: input.message.sessionId,
|
|
1544
1576
|
artifactRoot: input.artifactRoot
|
|
1545
1577
|
});
|
|
1546
|
-
const artifactProcessEnv = artifactEnv(input.artifactRoot, input.message.sessionId);
|
|
1547
1578
|
const cwd = resolveCommandCwd(workspace.branchPath, input.message.cwd);
|
|
1548
1579
|
const subprocess = Bun.spawn(input.message.argv, {
|
|
1549
1580
|
cwd,
|
|
@@ -2181,5 +2212,7 @@ if (isCliEntrypoint()) {
|
|
|
2181
2212
|
export {
|
|
2182
2213
|
ensureVisibleGitCheckout,
|
|
2183
2214
|
isArtifactEnvPath,
|
|
2215
|
+
prepareArtifactEnvForShell,
|
|
2216
|
+
resolveProjectFilePath,
|
|
2184
2217
|
syncSessionArtifacts
|
|
2185
2218
|
};
|
package/dist/mjs/package.json
CHANGED
package/dist/types/main.d.ts
CHANGED
|
@@ -8,10 +8,23 @@ export declare function syncSessionArtifacts(input: {
|
|
|
8
8
|
sessionId: string;
|
|
9
9
|
artifactRoot: string;
|
|
10
10
|
}): Promise<string>;
|
|
11
|
+
export declare function prepareArtifactEnvForShell(input: {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
token: string;
|
|
14
|
+
projectId: string;
|
|
15
|
+
branchName: string;
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
artifactRoot: string;
|
|
18
|
+
}): Promise<Record<string, string>>;
|
|
11
19
|
type GitAuth = {
|
|
12
20
|
extraHeaderUrl: string;
|
|
13
21
|
header: string;
|
|
14
22
|
};
|
|
23
|
+
export declare function resolveProjectFilePath(branchPath: string, virtualPath: string): {
|
|
24
|
+
absolutePath: string;
|
|
25
|
+
virtualPath: string;
|
|
26
|
+
repoRelativePath: string;
|
|
27
|
+
};
|
|
15
28
|
export declare function ensureVisibleGitCheckout(input: {
|
|
16
29
|
projectRoot: string;
|
|
17
30
|
branchName: string;
|