@ricsam/r5d-worker 0.0.139 → 0.0.141

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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5d-worker",
3
- "version": "0.0.139",
3
+ "version": "0.0.141",
4
4
  "type": "commonjs"
5
5
  }
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.139" : "development"}`);
10
+ console.log(`r5d-worker ${true ? "0.0.141" : "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.139" : "development"
18
+ true ? "0.0.141" : "development"
19
19
  );
20
20
  console.log(`Worker connected: ${runtime.resourceId}`);
21
21
  let closing = false;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5d-worker",
3
- "version": "0.0.139",
3
+ "version": "0.0.141",
4
4
  "type": "module"
5
5
  }
@@ -17,6 +17,7 @@ import { WorkspaceFileWrite, WorkspaceFileWriteLookup } from "./file-write.mjs";
17
17
  import { WorkspaceStorageClient } from "./storage-client.mjs";
18
18
  import {
19
19
  durableJson,
20
+ ensureAuthorityGitRepositoryLayout,
20
21
  git,
21
22
  noSymlinkAncestors,
22
23
  privateRoot,
@@ -86,7 +87,9 @@ class WorkspaceAuthority {
86
87
  const state = JSON.parse((await readRegular(path.join(directory, "state.json"), 1024 * 1024)).toString());
87
88
  if (typeof state.initialized !== "boolean" || !state.runs || !(state.head === null || GitOid.safeParse(state.head).success))
88
89
  throw new WorkspaceError("invalid_state", "Invalid durable workspace state; maintenance required");
89
- authority.benches.set(b.id, { config: b, state, directory, repo: path.join(directory, "repo") });
90
+ const repo = path.join(directory, "repo");
91
+ await ensureAuthorityGitRepositoryLayout(repo);
92
+ authority.benches.set(b.id, { config: b, state, directory, repo });
90
93
  }
91
94
  if (config.dynamicWorkbenches) {
92
95
  for (const id of await fs.readdir(path.join(config.root, "state"))) {
@@ -98,7 +101,9 @@ class WorkspaceAuthority {
98
101
  await noSymlinkAncestors(b.cwd);
99
102
  const state = JSON.parse((await readRegular(path.join(directory, "state.json"), 1024 * 1024)).toString());
100
103
  if (typeof state.initialized !== "boolean" || !state.runs || !(state.head === null || GitOid.safeParse(state.head).success)) throw new WorkspaceError("invalid_state", "Invalid dynamic workspace state");
101
- authority.benches.set(id, { config: b, state, directory, repo: path.join(directory, "repo") });
104
+ const repo = path.join(directory, "repo");
105
+ await ensureAuthorityGitRepositoryLayout(repo);
106
+ authority.benches.set(id, { config: b, state, directory, repo });
102
107
  }
103
108
  }
104
109
  return authority;
@@ -145,7 +150,9 @@ class WorkspaceAuthority {
145
150
  await noSymlinkAncestors(config.cwd);
146
151
  const state = JSON.parse((await readRegular(path.join(directory, "state.json"), 1024 * 1024)).toString());
147
152
  if (typeof state.initialized !== "boolean" || !state.runs || !(state.head === null || GitOid.safeParse(state.head).success)) throw new WorkspaceError("invalid_state", "Invalid workspace state");
148
- const bench = { config, state, directory, repo: path.join(directory, "repo") };
153
+ const repo = path.join(directory, "repo");
154
+ await ensureAuthorityGitRepositoryLayout(repo);
155
+ const bench = { config, state, directory, repo };
149
156
  this.benches.set(config.id, bench);
150
157
  return bench;
151
158
  })();
@@ -1287,6 +1294,8 @@ ${DEFAULT_WORKSPACE_IGNORE}`, { mode: 384 });
1287
1294
  if (result.state !== "completed") throw new WorkspaceError("action_unknown", "Executor action receipt is unsettled");
1288
1295
  return result;
1289
1296
  } catch (error) {
1297
+ if (error instanceof ExecutorError && error.code === "run_not_running")
1298
+ throw new WorkspaceError(error.code, error.message, true);
1290
1299
  await this.serial(
1291
1300
  b,
1292
1301
  async () => {
@@ -35,6 +35,33 @@ async function readRegular(file, limit = 32 * 1024 * 1024) {
35
35
  await handle.close();
36
36
  }
37
37
  }
38
+ async function ensureAuthorityGitRepositoryLayout(repo) {
39
+ await noSymlinkAncestors(repo);
40
+ const repository = await fs.lstat(repo);
41
+ if (!repository.isDirectory() || repository.isSymbolicLink()) throw new WorkspaceError("unsafe_git", "Authority Git repository is invalid");
42
+ await readRegular(path.join(repo, "HEAD"), 4096);
43
+ await readRegular(path.join(repo, "config"), 128 * 1024);
44
+ for (const relative of ["objects", "objects/info", "objects/pack", "refs", "refs/heads", "refs/tags"]) {
45
+ const target = path.join(repo, relative);
46
+ let created = false;
47
+ try {
48
+ await fs.mkdir(target, { mode: 448 });
49
+ created = true;
50
+ } catch (error) {
51
+ if (error.code !== "EEXIST") throw error;
52
+ }
53
+ const entry = await fs.lstat(target);
54
+ if (!entry.isDirectory() || entry.isSymbolicLink()) throw new WorkspaceError("unsafe_git", "Authority Git structure is invalid");
55
+ if (created) {
56
+ const parent = await fs.open(path.dirname(target), constants.O_RDONLY);
57
+ try {
58
+ await parent.sync();
59
+ } finally {
60
+ await parent.close();
61
+ }
62
+ }
63
+ }
64
+ }
38
65
  async function durableJson(file, value) {
39
66
  const temporary = `${file}.next`;
40
67
  const handle = await fs.open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 384);
@@ -295,6 +322,7 @@ async function snapshotTree(repo, cwd, canonicalHead) {
295
322
  }
296
323
  export {
297
324
  durableJson,
325
+ ensureAuthorityGitRepositoryLayout,
298
326
  git,
299
327
  noSymlinkAncestors,
300
328
  privateRoot,
@@ -2,6 +2,10 @@ export declare const sha256: (bytes: Buffer | string) => string;
2
2
  export declare function privateRoot(root: string, installationId: string): Promise<void>;
3
3
  export declare function noSymlinkAncestors(file: string): Promise<void>;
4
4
  export declare function readRegular(file: string, limit?: number): Promise<Buffer>;
5
+ /** File-only migration capsules can omit Git's empty structural directories.
6
+ * Restore only that directory skeleton after confirming the authority-owned
7
+ * repository markers; refs, objects, indexes and configuration are untouched. */
8
+ export declare function ensureAuthorityGitRepositoryLayout(repo: string): Promise<void>;
5
9
  export declare function durableJson(file: string, value: unknown): Promise<void>;
6
10
  /** All Git operates in authority-created repos; NEVER workbench .git/config/index.
7
11
  * hash-object --no-filters and update-index --index-info replace git add/checkout.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5d-worker",
3
- "version": "0.0.139",
3
+ "version": "0.0.141",
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.139",
25
- "@ricsam/r5dctl": "0.0.139",
24
+ "@ricsam/r5d-api": "^0.0.141",
25
+ "@ricsam/r5dctl": "0.0.141",
26
26
  "node-pty": "1.1.0",
27
27
  "zod": "^4.1.13",
28
28
  "picomatch": "^4.0.3"