Files
rea/src/process/PrivateRuntimeRoot.ts
T
N0zoM1z0 70e1a0f532 refactor(process): extract reusable provider lifecycle primitives
Introduce provider-neutral ownership, private runtime roots, absolute startup deadlines, pending-operation correlation, bounded output capture, and verified TERM-to-KILL process supervision.\n\nMigrate Hopper onto the shared lifecycle pieces while keeping its Unix-socket protocol and health/shutdown parsing adapter-specific. Preserve exact ownership checks and fail-closed cleanup, including descendant cleanup after the launcher leader exits.\n\nAdd reusable process fixtures and deterministic coverage for startup timeout, cancellation, output bounds, exit diagnostics, cleanup escalation, repeated close, spawn failure, and resource disposal. Update architecture, provider evaluation, contributor guidance, and generated API documentation.
2026-07-15 23:20:48 +09:00

44 lines
1.4 KiB
TypeScript

import { chmod, mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
/** Filesystem coordinates for one provider-owned private runtime directory. */
export interface PrivateRuntimeRootOptions {
readonly parent?: string;
readonly prefix?: string;
}
/**
* Owns one mode-0700 temporary runtime root and removes it idempotently.
*
* Protocol adapters decide what belongs inside the directory; this primitive
* only establishes a private filesystem boundary and deterministic cleanup.
*/
export class PrivateRuntimeRoot {
#closePromise: Promise<void> | undefined;
private constructor(readonly path: string) {}
/** Allocate a new private runtime root without performing protocol work. */
static async create(
options: PrivateRuntimeRootOptions = {},
): Promise<PrivateRuntimeRoot> {
const path = await mkdtemp(
join(options.parent ?? tmpdir(), options.prefix ?? "rea-provider-"),
);
try {
await chmod(path, 0o700);
return new PrivateRuntimeRoot(path);
} catch (cause: unknown) {
await rm(path, { recursive: true, force: true });
throw cause;
}
}
/** Remove the runtime root; concurrent and repeated callers share cleanup. */
close(): Promise<void> {
this.#closePromise ??= rm(this.path, { recursive: true, force: true });
return this.#closePromise;
}
}