@ricsam/r5d-worker 0.0.176 → 0.0.177
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/package.json +1 -1
- package/dist/mjs/internal-r5dctl.cjs +1 -1
- package/dist/mjs/main.mjs +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/personal/client.mjs +14 -2
- package/dist/mjs/personal/runtime.mjs +19 -2
- package/dist/mjs/runtime/workspace/authority.mjs +1 -1
- package/dist/types/personal/client.d.ts +7 -0
- package/dist/types/personal/runtime.d.ts +5 -0
- package/package.json +2 -2
package/dist/cjs/package.json
CHANGED
|
@@ -20605,7 +20605,7 @@ function resolveEntrypointPath(entrypoint) {
|
|
|
20605
20605
|
}
|
|
20606
20606
|
}
|
|
20607
20607
|
function getR5dctlVersion() {
|
|
20608
|
-
if (true) return "0.0.
|
|
20608
|
+
if (true) return "0.0.177";
|
|
20609
20609
|
const entrypoint = process.argv[1] ? resolveEntrypointPath(process.argv[1]) : null;
|
|
20610
20610
|
let current = entrypoint ? import_node_path2.default.dirname(entrypoint) : process.cwd();
|
|
20611
20611
|
for (let index = 0; index < 12; index += 1) {
|
package/dist/mjs/main.mjs
CHANGED
|
@@ -7,15 +7,15 @@ 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.177" : "development"}`);
|
|
11
11
|
} else if (!args.length || args.includes("--help")) {
|
|
12
12
|
console.log(
|
|
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."
|
|
13
|
+
"Usage: r5d-worker start --label <label> [--root <dir>] [--base-url <url>] [--token <worker-token>] [--initial-sync merge|reset]\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."
|
|
14
14
|
);
|
|
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.177" : "development"
|
|
19
19
|
);
|
|
20
20
|
console.log(`Worker connected: ${runtime.resourceId}`);
|
|
21
21
|
let closing = false;
|
package/dist/mjs/package.json
CHANGED
|
@@ -27,7 +27,7 @@ class PersonalResponseError extends Error {
|
|
|
27
27
|
const storageErrorCodes = /* @__PURE__ */ new Set(["invalid_input", "conflict", "not_found", "busy", "stale_fence", "unknown", "unsafe_path", "git_failed"]);
|
|
28
28
|
function parsePersonalWorkerOptions(args, environment = process.env) {
|
|
29
29
|
const values = {};
|
|
30
|
-
const allowed = /* @__PURE__ */ new Set(["label", "base-url", "token", "api-key", "config", "root"]);
|
|
30
|
+
const allowed = /* @__PURE__ */ new Set(["label", "base-url", "token", "api-key", "config", "root", "initial-sync"]);
|
|
31
31
|
for (let index = 0; index < args.length; index++) {
|
|
32
32
|
const arg = args[index];
|
|
33
33
|
const match = /^--([^=]+)(?:=(.*))?$/.exec(arg);
|
|
@@ -54,17 +54,21 @@ function parsePersonalWorkerOptions(args, environment = process.env) {
|
|
|
54
54
|
throw new Error("Worker base URL must use HTTPS or local loopback");
|
|
55
55
|
const credential = values.token ?? values["api-key"] ?? environment.R5D_TOKEN ?? environment.R5D_API_KEY ?? string(saved.token) ?? string(saved.apiKey);
|
|
56
56
|
if (!credential) throw new Error(`Authenticate this worker with: r5dctl auth login --worker-label ${label}`);
|
|
57
|
+
const initialSync = values["initial-sync"] ?? "merge";
|
|
58
|
+
if (initialSync !== "merge" && initialSync !== "reset") throw new Error("--initial-sync must be merge or reset");
|
|
57
59
|
return {
|
|
58
60
|
label,
|
|
59
61
|
baseUrl: origin.origin,
|
|
60
62
|
credential,
|
|
61
|
-
root: path.resolve(values.root ?? environment.R5D_ROOT ?? path.join(os.homedir(), ".r5d"))
|
|
63
|
+
root: path.resolve(values.root ?? environment.R5D_ROOT ?? path.join(os.homedir(), ".r5d")),
|
|
64
|
+
initialSync
|
|
62
65
|
};
|
|
63
66
|
}
|
|
64
67
|
function safeError(error) {
|
|
65
68
|
const value = error.code;
|
|
66
69
|
return typeof value === "string" && /^[a-zA-Z0-9_-]{1,100}$/.test(value) ? value : "personal_operation_unknown";
|
|
67
70
|
}
|
|
71
|
+
const resetBatchId = (instanceId) => `${instanceId.slice(0, 16)}-${Date.now().toString(36)}`;
|
|
68
72
|
const rejectedBeforeAdmission = (error) => error?.rejectedBeforeAdmission === true;
|
|
69
73
|
const CliUpdateRequest = z.object({ kind: z.literal("update-clis"), userId: z.string(), command: z.object({ version: z.string() }).passthrough() }).passthrough();
|
|
70
74
|
async function startPersonalWorker(options, version) {
|
|
@@ -139,6 +143,14 @@ async function startPersonalWorker(options, version) {
|
|
|
139
143
|
return result && typeof result === "object" && typeof result.incidentId === "string" ? { incidentId: result.incidentId } : void 0;
|
|
140
144
|
}
|
|
141
145
|
});
|
|
146
|
+
if (options.initialSync === "reset") {
|
|
147
|
+
const results = await runtime.resetProjectCheckouts(`initial-sync-${resetBatchId(identity.instanceId)}`);
|
|
148
|
+
const reset = results.filter((entry) => !entry.error), refused = results.filter((entry) => entry.error);
|
|
149
|
+
process.stderr.write(`[r5d-worker] initial sync reset: ${reset.length} checkout(s) restored to the server state${reset.length ? ` (${reset.map((entry) => entry.workbenchId).join(", ")}); discarded changes retained beside each checkout's state` : ""}
|
|
150
|
+
`);
|
|
151
|
+
for (const entry of refused) process.stderr.write(`[r5d-worker] initial sync reset skipped ${entry.workbenchId}: ${entry.error}
|
|
152
|
+
`);
|
|
153
|
+
}
|
|
142
154
|
const ledgerFile = path.join(root, "relay.sqlite");
|
|
143
155
|
try {
|
|
144
156
|
closeSync(openSync(ledgerFile, "wx", 384));
|
|
@@ -226,8 +226,8 @@ exec ${quote(executable)} ${quote(cli)} "$@"
|
|
|
226
226
|
return binding;
|
|
227
227
|
};
|
|
228
228
|
if (previous && canonicalJson(stable(previous)) !== canonicalJson(stable(row))) throw new Error("Personal workbench identity changed");
|
|
229
|
-
if (!previous) {
|
|
230
|
-
manifests.set(input.id, row);
|
|
229
|
+
if (!previous || previous.sessionId !== row.sessionId) {
|
|
230
|
+
manifests.set(input.id, previous ? { ...previous, sessionId: row.sessionId, ...row.sharedSessionId ? { sharedSessionId: row.sharedSessionId } : {}, ...row.baseCommitHash ? { baseCommitHash: row.baseCommitHash } : {} } : row);
|
|
231
231
|
const tmp = `${manifestFile}.${randomBytes(8).toString("hex")}.next`;
|
|
232
232
|
const handle = await fs.open(tmp, "wx", 384);
|
|
233
233
|
try {
|
|
@@ -481,6 +481,22 @@ exec ${quote(executable)} ${quote(cli)} "$@"
|
|
|
481
481
|
const identity = { userId: grant.userId, sessionId: RuntimeId.parse(input.sessionId) };
|
|
482
482
|
return authority.streamInput(identity, { ...identity, operationId: RuntimeId.parse(input.operationId), fence: current.workerFence }, input.data, input.resize);
|
|
483
483
|
}
|
|
484
|
+
async function resetProjectCheckouts(idPrefix) {
|
|
485
|
+
const results = [];
|
|
486
|
+
for (const [workbenchId, sessionId] of publicationSessions) {
|
|
487
|
+
const manifest = manifests.get(workbenchId);
|
|
488
|
+
if (!manifest || manifest.rootProfile !== "project") continue;
|
|
489
|
+
const identity = { userId: grant.userId, sessionId };
|
|
490
|
+
try {
|
|
491
|
+
if (!(await authority.status(identity)).initialized) continue;
|
|
492
|
+
const result = await authority.reset(identity, { id: `${idPrefix}-${workbenchId}` });
|
|
493
|
+
results.push({ workbenchId, head: result.head ?? null });
|
|
494
|
+
} catch (error) {
|
|
495
|
+
results.push({ workbenchId, head: null, error: error instanceof WorkspaceError ? error.code : error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : "reset_failed" });
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return results;
|
|
499
|
+
}
|
|
484
500
|
return {
|
|
485
501
|
grant,
|
|
486
502
|
renew,
|
|
@@ -489,6 +505,7 @@ exec ${quote(executable)} ${quote(cli)} "$@"
|
|
|
489
505
|
synchronize,
|
|
490
506
|
subscribeTerminal,
|
|
491
507
|
terminalInput,
|
|
508
|
+
resetProjectCheckouts,
|
|
492
509
|
async close() {
|
|
493
510
|
closing = true;
|
|
494
511
|
clearInterval(publicationTimer);
|
|
@@ -1210,7 +1210,7 @@ class WorkspaceAuthority {
|
|
|
1210
1210
|
/** An explicit user reset retains the complete old tree/index before hydration. */
|
|
1211
1211
|
async reset(identity, input) {
|
|
1212
1212
|
const b = await this.bench(identity);
|
|
1213
|
-
return this.serial(b, () => this.productAction(b, input.id, { method: "reset", expectedHead: input.expectedHead }, async () => {
|
|
1213
|
+
return this.serial(b, () => this.productAction(b, input.id, { method: "reset", expectedHead: input.expectedHead ?? null }, async () => {
|
|
1214
1214
|
await this.assertAvailable(b, true);
|
|
1215
1215
|
if (input.expectedHead !== void 0 && input.expectedHead !== b.state.head) throw new WorkspaceError("conflict", "Workbench base changed before reset");
|
|
1216
1216
|
if (b.state.blocked?.code === "archived") throw new WorkspaceError("archived", "A deleted branch cannot be reset");
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
/** What the first synchronization after `r5d-worker start` does to checkouts
|
|
2
|
+
* that diverged from the server while the worker was away: `merge` integrates
|
|
3
|
+
* them and opens a conflict remediation when needed (the default); `reset`
|
|
4
|
+
* takes the server state and keeps the discarded local changes aside under
|
|
5
|
+
* the checkout's retained directory. */
|
|
6
|
+
export type PersonalWorkerInitialSync = "merge" | "reset";
|
|
1
7
|
export type PersonalWorkerOptions = {
|
|
2
8
|
label: string;
|
|
3
9
|
baseUrl: string;
|
|
4
10
|
credential: string;
|
|
5
11
|
root: string;
|
|
6
12
|
cliEntrypoint?: string;
|
|
13
|
+
initialSync?: PersonalWorkerInitialSync;
|
|
7
14
|
};
|
|
8
15
|
export declare function parsePersonalWorkerOptions(args: string[], environment?: Record<string, string | undefined>): PersonalWorkerOptions;
|
|
9
16
|
/** HTTP reconnects never replace the local source/PTY keeper. */
|
|
@@ -179,6 +179,11 @@ export declare function openPersonalWorkerRuntime(options: {
|
|
|
179
179
|
rows: number;
|
|
180
180
|
};
|
|
181
181
|
}) => Promise<import("../runtime/protocol").InputResult>;
|
|
182
|
+
resetProjectCheckouts: (idPrefix: string) => Promise<{
|
|
183
|
+
workbenchId: string;
|
|
184
|
+
head: string | null;
|
|
185
|
+
error?: string;
|
|
186
|
+
}[]>;
|
|
182
187
|
close(): Promise<void>;
|
|
183
188
|
}>;
|
|
184
189
|
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.177",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/mjs/main.mjs",
|
|
6
6
|
"module": "./dist/mjs/main.mjs",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"r5d-worker": "dist/mjs/main.mjs"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@ricsam/r5d-api": "^0.0.
|
|
24
|
+
"@ricsam/r5d-api": "^0.0.177",
|
|
25
25
|
"node-pty": "1.1.0",
|
|
26
26
|
"zod": "^4.1.13",
|
|
27
27
|
"picomatch": "^4.0.3"
|