@ricsam/r5d-worker 0.0.179 → 0.0.181
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 +8 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/personal/client.mjs +11 -5
- package/dist/mjs/personal/runtime.mjs +12 -4
- package/dist/mjs/runtime/executor.mjs +5 -2
- package/dist/mjs/runtime/pty.mjs +4 -0
- package/dist/mjs/runtime/workspace/authority.mjs +27 -0
- package/dist/types/runtime/pty.d.ts +2 -0
- package/dist/types/runtime/workspace/authority.d.ts +7 -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.181";
|
|
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,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.181" : "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>] [--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."
|
|
@@ -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.181" : "development"
|
|
19
19
|
);
|
|
20
20
|
console.log(`Worker connected: ${runtime.resourceId}`);
|
|
21
21
|
let closing = false;
|
|
@@ -24,7 +24,12 @@ if (args.includes("--version")) {
|
|
|
24
24
|
closing = true;
|
|
25
25
|
void runtime.close().then(
|
|
26
26
|
() => process.exit(0),
|
|
27
|
-
() =>
|
|
27
|
+
(error) => {
|
|
28
|
+
const code = error?.code;
|
|
29
|
+
process.stderr.write(`[r5d-worker] stop did not complete cleanly: ${typeof code === "string" ? code : error instanceof Error ? error.message : String(error)}
|
|
30
|
+
`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
28
33
|
);
|
|
29
34
|
};
|
|
30
35
|
process.once("SIGTERM", close);
|
package/dist/mjs/package.json
CHANGED
|
@@ -254,11 +254,17 @@ async function startPersonalWorker(options, version) {
|
|
|
254
254
|
root,
|
|
255
255
|
async close() {
|
|
256
256
|
stopped = true;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
try {
|
|
258
|
+
await terminalStream.close();
|
|
259
|
+
await loop;
|
|
260
|
+
await scheduler.drain();
|
|
261
|
+
} finally {
|
|
262
|
+
try {
|
|
263
|
+
await runtime.close();
|
|
264
|
+
} finally {
|
|
265
|
+
ledger.close();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
262
268
|
}
|
|
263
269
|
};
|
|
264
270
|
}
|
|
@@ -509,10 +509,18 @@ exec ${quote(executable)} ${quote(cli)} "$@"
|
|
|
509
509
|
async close() {
|
|
510
510
|
closing = true;
|
|
511
511
|
clearInterval(publicationTimer);
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
512
|
+
try {
|
|
513
|
+
await publication;
|
|
514
|
+
} catch (error) {
|
|
515
|
+
process.stderr.write(`[r5d-worker] final publication cycle failed: ${error instanceof WorkspaceError ? error.code : "publication_failed"}
|
|
516
|
+
`);
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
await tcp.close();
|
|
520
|
+
await authority.close();
|
|
521
|
+
} finally {
|
|
522
|
+
await daemon.close();
|
|
523
|
+
}
|
|
516
524
|
}
|
|
517
525
|
};
|
|
518
526
|
} catch (error) {
|
|
@@ -327,7 +327,10 @@ class HostExecutor {
|
|
|
327
327
|
if (pty) {
|
|
328
328
|
pty.onData((data) => this.output(run2, "stdout", Buffer.from(data)));
|
|
329
329
|
pty.onExit(({ exitCode, signal }) => {
|
|
330
|
-
if (exitCode === -1)
|
|
330
|
+
if (exitCode === -1) {
|
|
331
|
+
receipt2.reason = "pty_helper_lost";
|
|
332
|
+
run2.cancelled = true;
|
|
333
|
+
}
|
|
331
334
|
onExit(exitCode, signal ? String(signal) : null);
|
|
332
335
|
});
|
|
333
336
|
} else {
|
|
@@ -467,7 +470,7 @@ class HostExecutor {
|
|
|
467
470
|
if (run.finishing) return run.finishing;
|
|
468
471
|
run.finishing = (async () => {
|
|
469
472
|
clearTimeout(run.timer);
|
|
470
|
-
let cleanupFailed =
|
|
473
|
+
let cleanupFailed = false;
|
|
471
474
|
try {
|
|
472
475
|
if (run.process.pid) await terminateProcessTree(run.process, { graceMs: 200, forceKillWaitMs: 1e3 });
|
|
473
476
|
await Promise.race([
|
package/dist/mjs/runtime/pty.mjs
CHANGED
|
@@ -10,6 +10,10 @@ function preflightNativePty() {
|
|
|
10
10
|
}
|
|
11
11
|
class PtySession {
|
|
12
12
|
pid = 0;
|
|
13
|
+
/** The helper process that owns the terminal, for tests that end it the way a stop signal would. */
|
|
14
|
+
get helperPid() {
|
|
15
|
+
return this.child.pid ?? 0;
|
|
16
|
+
}
|
|
13
17
|
sequence = 0;
|
|
14
18
|
pending = /* @__PURE__ */ new Map();
|
|
15
19
|
child;
|
|
@@ -2031,6 +2031,7 @@ class WorkspaceAuthority {
|
|
|
2031
2031
|
await Promise.allSettled([...this.actions]);
|
|
2032
2032
|
await Promise.allSettled([...this.queues.values()]);
|
|
2033
2033
|
for (const b of this.benches.values()) await this.refresh(b);
|
|
2034
|
+
await this.drainLiveRuns();
|
|
2034
2035
|
if ([...this.benches.values()].some(
|
|
2035
2036
|
(b) => b.state.blocked || Object.values(b.state.runs).some((r) => !["completed", "cancelled", "rejected_capacity"].includes(r.state))
|
|
2036
2037
|
))
|
|
@@ -2043,6 +2044,32 @@ class WorkspaceAuthority {
|
|
|
2043
2044
|
await fs.rm(path.join(this.config.root, ".sync-lock"), { recursive: true });
|
|
2044
2045
|
this.closed = true;
|
|
2045
2046
|
}
|
|
2047
|
+
/** A stop ends what the keeper tracks. Live runs (an open shell, an agent
|
|
2048
|
+
* command) are cancelled through the executor and waited for, the way a
|
|
2049
|
+
* supervisor drain would, so that an orderly stop leaves cancelled receipts
|
|
2050
|
+
* behind rather than a lock nobody can release: the process is going away
|
|
2051
|
+
* either way. Outcomes that stay unknown after the drain still retain the
|
|
2052
|
+
* lock for review. */
|
|
2053
|
+
async drainLiveRuns() {
|
|
2054
|
+
const live = (b) => Object.entries(b.state.runs).filter(([, run]) => !["completed", "cancelled", "rejected_capacity", "unknown"].includes(run.state));
|
|
2055
|
+
if (![...this.benches.values()].some((b) => live(b).length)) return;
|
|
2056
|
+
for (const b of this.benches.values()) {
|
|
2057
|
+
for (const [operationId, run] of live(b)) {
|
|
2058
|
+
try {
|
|
2059
|
+
const identity = { userId: b.config.userId, sessionId: run.sessionId ?? b.config.sessionId };
|
|
2060
|
+
const route = await this.route(b, identity);
|
|
2061
|
+
await route.client.cancel({ ...identity, operationId, fence: route.workerFence }, `drain-${this.lockId.slice(0, 8)}-${sha256(operationId).slice(0, 16)}`);
|
|
2062
|
+
} catch {
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
const deadline = Date.now() + 15e3;
|
|
2067
|
+
for (; ; ) {
|
|
2068
|
+
for (const b of this.benches.values()) await this.refresh(b);
|
|
2069
|
+
if (![...this.benches.values()].some((b) => live(b).length) || Date.now() >= deadline) return;
|
|
2070
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2046
2073
|
}
|
|
2047
2074
|
export {
|
|
2048
2075
|
WorkspaceAuthority
|
|
@@ -2,6 +2,8 @@ export declare function preflightNativePty(): void;
|
|
|
2
2
|
/** Node native FD keeper is a daemon child; replacing adapters cannot signal it. */
|
|
3
3
|
export declare class PtySession {
|
|
4
4
|
pid: number;
|
|
5
|
+
/** The helper process that owns the terminal, for tests that end it the way a stop signal would. */
|
|
6
|
+
get helperPid(): number;
|
|
5
7
|
private sequence;
|
|
6
8
|
private readonly pending;
|
|
7
9
|
private readonly child;
|
|
@@ -500,4 +500,11 @@ export declare class WorkspaceAuthority {
|
|
|
500
500
|
cancel(identity: WorkspaceIdentity, run: RunIdentity, actionId: string): Promise<import("..").ActionReceipt>;
|
|
501
501
|
close(): Promise<void>;
|
|
502
502
|
private finishClose;
|
|
503
|
+
/** A stop ends what the keeper tracks. Live runs (an open shell, an agent
|
|
504
|
+
* command) are cancelled through the executor and waited for, the way a
|
|
505
|
+
* supervisor drain would, so that an orderly stop leaves cancelled receipts
|
|
506
|
+
* behind rather than a lock nobody can release: the process is going away
|
|
507
|
+
* either way. Outcomes that stay unknown after the drain still retain the
|
|
508
|
+
* lock for review. */
|
|
509
|
+
private drainLiveRuns;
|
|
503
510
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ricsam/r5d-worker",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.181",
|
|
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.181",
|
|
25
25
|
"node-pty": "1.1.0",
|
|
26
26
|
"zod": "^4.1.13",
|
|
27
27
|
"picomatch": "^4.0.3"
|