@ricsam/r5d-worker 0.0.145 → 0.0.146
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 +2 -0
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/main.mjs +2 -2
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/personal/cli-entrypoint.mjs +59 -0
- package/dist/mjs/personal/client.mjs +6 -13
- package/dist/types/personal/cli-entrypoint.d.ts +13 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,3 +8,5 @@ r5d-worker manager /absolute/private/manager-config.json
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
The executor retains processes and durable receipts independently of application releases. The manager authenticates the approved workspace keeper and retains old adapters until their delivery receipts are settled. Configuration and host roots belong exclusively to one installation. Never share an executor's state directory, credentials or workspace root between environments.
|
|
11
|
+
|
|
12
|
+
The published worker has an exact-version dependency on `@ricsam/r5dctl`. A personal worker resolves that bundled CLI before the host `PATH`, verifies that its package version equals the running worker version, and exposes it to agent shells through a private worker-owned wrapper. Each worker remains bound to one server origin and installation, so stage, production, and review workers cannot accidentally select another environment's global CLI or credentials.
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/main.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { startManagerRpc } from "./runtime/releases/rpc-main.mjs";
|
|
|
7
7
|
import { ManagerRpcConfig } from "./runtime/releases/rpc-protocol.mjs";
|
|
8
8
|
const args = process.argv.slice(2);
|
|
9
9
|
if (args.includes("--version")) {
|
|
10
|
-
console.log(`r5d-worker ${true ? "0.0.
|
|
10
|
+
console.log(`r5d-worker ${true ? "0.0.146" : "development"}`);
|
|
11
11
|
} else if (!args.length || args.includes("--help")) {
|
|
12
12
|
console.log(
|
|
13
13
|
"Usage: r5d-worker start --label <label> [--root <dir>] [--base-url <url>] [--token <worker-token>]\n r5d-worker executor /absolute/private/config.json\n r5d-worker manager /absolute/private/config.json\n\nRun independently supervised durable runtime services. Provision configuration with r5dinfra."
|
|
@@ -15,7 +15,7 @@ if (args.includes("--version")) {
|
|
|
15
15
|
} else if (args[0] === "start") {
|
|
16
16
|
const runtime = await startPersonalWorker(
|
|
17
17
|
parsePersonalWorkerOptions(args.slice(1)),
|
|
18
|
-
true ? "0.0.
|
|
18
|
+
true ? "0.0.146" : "development"
|
|
19
19
|
);
|
|
20
20
|
console.log(`Worker connected: ${runtime.resourceId}`);
|
|
21
21
|
let closing = false;
|
package/dist/mjs/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { promises as fs } from "node:fs";
|
|
4
|
+
const PACKAGE_NAME = "@ricsam/r5dctl";
|
|
5
|
+
function packageMain(moduleUrl) {
|
|
6
|
+
const module = fileURLToPath(moduleUrl);
|
|
7
|
+
return path.join(path.dirname(module), path.extname(module) === ".cjs" ? "main.cjs" : "main.mjs");
|
|
8
|
+
}
|
|
9
|
+
async function inspectPackage(candidate) {
|
|
10
|
+
const entrypoint = await fs.realpath(candidate);
|
|
11
|
+
const entrypointStat = await fs.lstat(entrypoint);
|
|
12
|
+
if (!entrypointStat.isFile() || entrypointStat.nlink !== 1 || entrypointStat.mode & 18 || ![0, process.getuid?.()].includes(entrypointStat.uid))
|
|
13
|
+
throw new Error("Untrusted installed r5dctl entrypoint");
|
|
14
|
+
let directory = path.dirname(entrypoint);
|
|
15
|
+
for (let depth = 0; depth < 6; depth += 1) {
|
|
16
|
+
const manifest = path.join(directory, "package.json");
|
|
17
|
+
try {
|
|
18
|
+
const stat = await fs.lstat(manifest);
|
|
19
|
+
if (!stat.isFile() || stat.nlink !== 1 || stat.mode & 18 || ![0, process.getuid?.()].includes(stat.uid))
|
|
20
|
+
throw new Error("Untrusted installed r5dctl package manifest");
|
|
21
|
+
const parsed = JSON.parse(await fs.readFile(manifest, "utf8"));
|
|
22
|
+
if (parsed?.name === PACKAGE_NAME) {
|
|
23
|
+
if (typeof parsed.version !== "string" || !/^\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?$/.test(parsed.version))
|
|
24
|
+
throw new Error("Invalid installed r5dctl package version");
|
|
25
|
+
return { entrypoint, version: parsed.version };
|
|
26
|
+
}
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (error.code !== "ENOENT") throw error;
|
|
29
|
+
}
|
|
30
|
+
const parent = path.dirname(directory);
|
|
31
|
+
if (parent === directory) break;
|
|
32
|
+
directory = parent;
|
|
33
|
+
}
|
|
34
|
+
throw new Error("Resolved r5dctl entrypoint is not inside an @ricsam/r5dctl package");
|
|
35
|
+
}
|
|
36
|
+
async function resolvePersonalCliEntrypoint(explicit, workerVersion, dependencies = {}) {
|
|
37
|
+
let source, candidate;
|
|
38
|
+
if (explicit) {
|
|
39
|
+
source = "explicit";
|
|
40
|
+
candidate = explicit;
|
|
41
|
+
} else {
|
|
42
|
+
try {
|
|
43
|
+
const resolvePackage = dependencies.resolvePackage ?? ((specifier) => import.meta.resolve(specifier));
|
|
44
|
+
candidate = packageMain(resolvePackage(`${PACKAGE_NAME}/cli`));
|
|
45
|
+
source = "bundled";
|
|
46
|
+
} catch {
|
|
47
|
+
source = "path";
|
|
48
|
+
candidate = (dependencies.which ?? Bun.which)("r5dctl");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!candidate) throw new Error("Install @ricsam/r5dctl before starting this worker");
|
|
52
|
+
const inspected = await inspectPackage(candidate);
|
|
53
|
+
if (workerVersion !== "development" && inspected.version !== workerVersion)
|
|
54
|
+
throw new Error(`r5d-worker ${workerVersion} requires its bundled r5dctl ${workerVersion}; resolved ${inspected.version}`);
|
|
55
|
+
return { ...inspected, source };
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
resolvePersonalCliEntrypoint
|
|
59
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
2
|
import os from "node:os";
|
|
4
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
5
4
|
import { promises as fs, openSync, closeSync } from "node:fs";
|
|
@@ -7,9 +6,10 @@ import { Database } from "bun:sqlite";
|
|
|
7
6
|
import { canonicalJson } from "@ricsam/r5d-api/runtime-protocol";
|
|
8
7
|
import { privateDirectory, readPrivateJson } from "../runtime/storage.mjs";
|
|
9
8
|
import { openPersonalWorkerRuntime, PersonalWorkerGrant } from "./runtime.mjs";
|
|
10
|
-
import { installCliUpdate
|
|
9
|
+
import { installCliUpdate } from "../cli-update.mjs";
|
|
11
10
|
import { WorkspaceError } from "../runtime/workspace/contracts.mjs";
|
|
12
11
|
import { PersonalActionScheduler } from "./action-scheduler.mjs";
|
|
12
|
+
import { resolvePersonalCliEntrypoint } from "./cli-entrypoint.mjs";
|
|
13
13
|
class PersonalResponseError extends Error {
|
|
14
14
|
constructor(code, status, rejectedBeforeAdmission) {
|
|
15
15
|
super(`Personal worker request failed (${status})`);
|
|
@@ -95,9 +95,11 @@ async function startPersonalWorker(options, version) {
|
|
|
95
95
|
}
|
|
96
96
|
return data;
|
|
97
97
|
}
|
|
98
|
+
const cli = await resolvePersonalCliEntrypoint(options.cliEntrypoint, version);
|
|
98
99
|
const metadata = () => ({
|
|
99
100
|
version,
|
|
100
|
-
r5dctlVersion:
|
|
101
|
+
r5dctlVersion: cli.version,
|
|
102
|
+
r5dctlSource: cli.source,
|
|
101
103
|
platform: process.platform,
|
|
102
104
|
arch: process.arch,
|
|
103
105
|
hostname: os.hostname(),
|
|
@@ -106,18 +108,9 @@ async function startPersonalWorker(options, version) {
|
|
|
106
108
|
const grant = PersonalWorkerGrant.parse(
|
|
107
109
|
await request("/api/personal/resources/register", { kind: "worker", ...identity, label: options.label, metadata: metadata() })
|
|
108
110
|
);
|
|
109
|
-
let cliEntrypoint = options.cliEntrypoint ?? Bun.which("r5dctl");
|
|
110
|
-
if (!cliEntrypoint) {
|
|
111
|
-
try {
|
|
112
|
-
const module = fileURLToPath(import.meta.resolve("@ricsam/r5dctl/cli"));
|
|
113
|
-
cliEntrypoint = path.join(path.dirname(module), path.extname(module) === ".cjs" ? "main.cjs" : "main.mjs");
|
|
114
|
-
} catch {
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (!cliEntrypoint) throw new Error("Install @ricsam/r5dctl before starting this worker");
|
|
118
111
|
const runtime = await openPersonalWorkerRuntime({
|
|
119
112
|
root,
|
|
120
|
-
cliEntrypoint,
|
|
113
|
+
cliEntrypoint: cli.entrypoint,
|
|
121
114
|
grant,
|
|
122
115
|
storage: (sessionId) => async (storageRequest) => {
|
|
123
116
|
try {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type ResolutionDependencies = {
|
|
2
|
+
resolvePackage?: (specifier: string) => string;
|
|
3
|
+
which?: (command: string) => string | null;
|
|
4
|
+
};
|
|
5
|
+
export type PersonalCliEntrypoint = {
|
|
6
|
+
entrypoint: string;
|
|
7
|
+
version: string;
|
|
8
|
+
source: "explicit" | "bundled" | "path";
|
|
9
|
+
};
|
|
10
|
+
/** Resolve the CLI that agent shells receive. Published workers always prefer
|
|
11
|
+
* their exact npm dependency; PATH is only a development/source fallback. */
|
|
12
|
+
export declare function resolvePersonalCliEntrypoint(explicit: string | undefined, workerVersion: string, dependencies?: ResolutionDependencies): Promise<PersonalCliEntrypoint>;
|
|
13
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ricsam/r5d-worker",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.146",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/mjs/main.mjs",
|
|
6
6
|
"module": "./dist/mjs/main.mjs",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"r5d-worker": "dist/mjs/main.mjs"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@ricsam/r5d-api": "^0.0.
|
|
25
|
-
"@ricsam/r5dctl": "0.0.
|
|
24
|
+
"@ricsam/r5d-api": "^0.0.146",
|
|
25
|
+
"@ricsam/r5dctl": "0.0.146",
|
|
26
26
|
"node-pty": "1.1.0",
|
|
27
27
|
"zod": "^4.1.13",
|
|
28
28
|
"picomatch": "^4.0.3"
|