@smthrs/platform-node 1.0.0-rc.4 → 1.0.0-rc.6
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 -2
- package/bin/darwin-arm64/smithers-jj-export +0 -0
- package/bin/darwin-x64/smithers-jj-export +0 -0
- package/bin/linux-arm64/smithers-jj-export +0 -0
- package/bin/linux-x64/smithers-jj-export +2 -2
- package/bin/win32-x64/smithers-jj-export.exe +0 -0
- package/dist/cjs/EgressHttpClient.d.ts +1 -1
- package/dist/cjs/EgressHttpClient.d.ts.map +1 -1
- package/dist/cjs/EgressHttpClient.js +4 -4
- package/dist/cjs/EgressHttpClient.js.map +2 -2
- package/dist/cjs/NodeHost.d.ts +2 -2
- package/dist/cjs/NodeHost.d.ts.map +1 -1
- package/dist/cjs/NodeHost.js.map +2 -2
- package/dist/cjs/ProcessConfinement.js +1 -1
- package/dist/cjs/ProcessConfinement.js.map +2 -2
- package/dist/cjs/ProcessReaper.d.ts +1 -1
- package/dist/cjs/ProcessReaper.d.ts.map +1 -1
- package/dist/cjs/ProcessReaper.js +1 -1
- package/dist/cjs/ProcessReaper.js.map +1 -1
- package/dist/cjs/ScopedProcess.d.ts +2 -2
- package/dist/cjs/ScopedProcess.d.ts.map +1 -1
- package/dist/cjs/ScopedProcess.js +1 -1
- package/dist/cjs/ScopedProcess.js.map +2 -2
- package/dist/cjs/internal/PipedProcess.d.ts +2 -2
- package/dist/cjs/internal/PipedProcess.d.ts.map +1 -1
- package/dist/cjs/internal/PipedProcess.js +2 -2
- package/dist/cjs/internal/PipedProcess.js.map +2 -2
- package/dist/cjs/internal/ProcessCleanup.d.ts +1 -1
- package/dist/cjs/internal/ProcessCleanup.d.ts.map +1 -1
- package/dist/cjs/internal/ProcessCleanup.js.map +1 -1
- package/dist/cjs/internal/ProcessSupervisor.d.ts +2 -2
- package/dist/cjs/internal/ProcessSupervisor.d.ts.map +1 -1
- package/dist/cjs/internal/ProcessSupervisor.js +2 -2
- package/dist/cjs/internal/ProcessSupervisor.js.map +2 -2
- package/dist/esm/EgressHttpClient.d.ts +1 -1
- package/dist/esm/EgressHttpClient.d.ts.map +1 -1
- package/dist/esm/EgressHttpClient.js +4 -4
- package/dist/esm/EgressHttpClient.js.map +1 -1
- package/dist/esm/NodeHost.d.ts +2 -2
- package/dist/esm/NodeHost.d.ts.map +1 -1
- package/dist/esm/NodeHost.js.map +1 -1
- package/dist/esm/ProcessConfinement.js +1 -1
- package/dist/esm/ProcessConfinement.js.map +1 -1
- package/dist/esm/ProcessReaper.d.ts +1 -1
- package/dist/esm/ProcessReaper.d.ts.map +1 -1
- package/dist/esm/ProcessReaper.js +1 -1
- package/dist/esm/ProcessReaper.js.map +1 -1
- package/dist/esm/ScopedProcess.d.ts +2 -2
- package/dist/esm/ScopedProcess.d.ts.map +1 -1
- package/dist/esm/ScopedProcess.js +1 -1
- package/dist/esm/ScopedProcess.js.map +1 -1
- package/dist/esm/internal/PipedProcess.d.ts +2 -2
- package/dist/esm/internal/PipedProcess.d.ts.map +1 -1
- package/dist/esm/internal/PipedProcess.js +2 -2
- package/dist/esm/internal/PipedProcess.js.map +1 -1
- package/dist/esm/internal/ProcessCleanup.d.ts +1 -1
- package/dist/esm/internal/ProcessCleanup.d.ts.map +1 -1
- package/dist/esm/internal/ProcessCleanup.js.map +1 -1
- package/dist/esm/internal/ProcessSupervisor.d.ts +2 -2
- package/dist/esm/internal/ProcessSupervisor.d.ts.map +1 -1
- package/dist/esm/internal/ProcessSupervisor.js +2 -2
- package/dist/esm/internal/ProcessSupervisor.js.map +1 -1
- package/dist/vendor/adapters.json +622 -382
- package/dist/vendor/{chunk-42QKY6T6.js → chunk-2ZAGBWTH.js} +1 -1
- package/dist/vendor/{chunk-3GR5VZ2M.js → chunk-3SL3HKQA.js} +3 -3
- package/dist/vendor/{chunk-VANKHF46.js → chunk-423HXGL6.js} +55 -23
- package/dist/vendor/{chunk-6ME2W7TF.js → chunk-4WIQ2XN7.js} +2 -2
- package/dist/vendor/{chunk-Y35ZAO5U.js → chunk-6FSJ2PMW.js} +8 -8
- package/dist/vendor/{chunk-5ZMHBXIK.js → chunk-6L2NJEOV.js} +11 -4
- package/dist/vendor/{chunk-TFIKFFSC.js → chunk-7NMJM44J.js} +2 -2
- package/dist/vendor/{chunk-OXNGN5H7.js → chunk-A7UXCEJA.js} +1 -1
- package/dist/vendor/chunk-ADP5LRUF.js +274 -0
- package/dist/vendor/{chunk-DS7GF46S.js → chunk-AWNTTSHL.js} +2 -2
- package/dist/vendor/{chunk-IIJ52ZU6.js → chunk-BUKVIAEM.js} +2 -2
- package/dist/vendor/{chunk-BKTBUBQY.js → chunk-BY3SDXID.js} +71 -7
- package/dist/vendor/{chunk-JJ24ARBQ.js → chunk-C3PGUWW5.js} +53 -33
- package/dist/vendor/{chunk-J7A4CZDO.js → chunk-D2ZL4PLZ.js} +8 -7
- package/dist/vendor/{chunk-XDKNKFBW.js → chunk-D4HEMNGU.js} +2 -2
- package/dist/vendor/{chunk-DVOAHXPG.js → chunk-FFD6R5JZ.js} +3 -3
- package/dist/vendor/{chunk-UFH5UUZK.js → chunk-HDV6VIRM.js} +1 -1
- package/dist/vendor/chunk-IWSDM4CG.js +16 -0
- package/dist/vendor/{chunk-KUUXSID7.js → chunk-KABHKTVG.js} +2 -2
- package/dist/vendor/{chunk-B3FZ67QU.js → chunk-KFDBU6RR.js} +4 -3
- package/dist/vendor/chunk-LNWGIDIG.js +20 -0
- package/dist/vendor/{chunk-TXKLEBBL.js → chunk-MUEED3C3.js} +3 -2
- package/dist/vendor/{chunk-EZWY45HP.js → chunk-N6TK35N5.js} +2 -2
- package/dist/vendor/{chunk-QPLDT6A6.js → chunk-NQO6V4KI.js} +29 -13
- package/dist/vendor/{chunk-AMQKOQNT.js → chunk-NTEWGPPG.js} +9 -9
- package/dist/vendor/chunk-NUJQMLJP.js +325 -0
- package/dist/vendor/{chunk-54RLBMTZ.js → chunk-OF3N2FN4.js} +1 -1
- package/dist/vendor/{chunk-RO2R4MJH.js → chunk-PA32ARKD.js} +17 -17
- package/dist/vendor/{chunk-JG5TTWPT.js → chunk-PECOFLCU.js} +3 -3
- package/dist/vendor/{chunk-VZBDV3TV.js → chunk-PU7QVYND.js} +2 -2
- package/dist/vendor/{chunk-2Y7WC4KU.js → chunk-QHR2RC5M.js} +2 -2
- package/dist/vendor/{chunk-QYBKAIA6.js → chunk-R327POEZ.js} +2 -2
- package/dist/vendor/chunk-RKVXYKHJ.js +29 -0
- package/dist/vendor/{chunk-XH4U3JSV.js → chunk-RQH5DSBA.js} +2 -2
- package/dist/vendor/{chunk-DWSHTSVX.js → chunk-S6QUQLBV.js} +5 -5
- package/dist/vendor/{chunk-KOZMM5PZ.js → chunk-UPIQ52FQ.js} +12 -12
- package/dist/vendor/{chunk-EGBNVEEW.js → chunk-UUQXJRMK.js} +1 -1
- package/dist/vendor/{chunk-LEUPYT3Q.js → chunk-UUYTTEDH.js} +1 -1
- package/dist/vendor/{chunk-NBVRTDTV.js → chunk-V2EB7FHY.js} +2 -2
- package/dist/vendor/{chunk-M32LDTW7.js → chunk-VIWU4EBF.js} +2 -2
- package/dist/vendor/{chunk-SIR62W3Y.js → chunk-VWSWEUN5.js} +51 -31
- package/dist/vendor/{chunk-MBSKBQ5D.js → chunk-WPZDL2D7.js} +1 -1
- package/dist/vendor/chunk-YDY5P7GL.js +20 -0
- package/dist/vendor/{chunk-FNZOJHSV.js → chunk-YFD4QFIL.js} +17 -17
- package/dist/vendor/{chunk-GXCHI7BM.js → chunk-ZVJCBTJG.js} +5 -5
- package/dist/vendor/cjs/node/NodeAddressResolver.d.ts +16 -0
- package/dist/vendor/cjs/node/NodeAddressResolver.js +1 -0
- package/dist/vendor/cjs/node/NodeChildProcessSpawner.d.ts +1 -0
- package/dist/vendor/cjs/node/NodeClusterHttp.d.ts +13 -22
- package/dist/vendor/cjs/node/NodeClusterSocket.d.ts +14 -8
- package/dist/vendor/cjs/node/NodeCrypto.d.ts +1 -0
- package/dist/vendor/cjs/node/NodeDatagramSocket.d.ts +10 -0
- package/dist/vendor/cjs/node/NodeDatagramSocket.js +1 -0
- package/dist/vendor/cjs/node/NodeDns.d.ts +51 -0
- package/dist/vendor/cjs/node/NodeDns.js +1 -0
- package/dist/vendor/cjs/node/NodeFileSystem.d.ts +1 -0
- package/dist/vendor/cjs/node/NodeHttpClient.d.ts +21 -2
- package/dist/vendor/cjs/node/NodeHttpIncomingMessage.d.ts +5 -3
- package/dist/vendor/cjs/node/NodeHttpPlatform.d.ts +8 -6
- package/dist/vendor/cjs/node/NodeHttpServer.d.ts +21 -10
- package/dist/vendor/cjs/node/NodeHttpServerRequest.d.ts +4 -1
- package/dist/vendor/cjs/node/NodeMultipart.d.ts +5 -1
- package/dist/vendor/cjs/node/NodeMultipartParser.d.ts +9 -1
- package/dist/vendor/cjs/node/NodePath.d.ts +3 -0
- package/dist/vendor/cjs/node/NodeRedis.d.ts +5 -1
- package/dist/vendor/cjs/node/NodeRuntime.d.ts +3 -0
- package/dist/vendor/cjs/node/NodeServices.d.ts +4 -1
- package/dist/vendor/cjs/node/NodeSink.d.ts +1 -0
- package/dist/vendor/cjs/node/NodeSocket.d.ts +10 -3
- package/dist/vendor/cjs/node/NodeSocketServer.d.ts +1 -0
- package/dist/vendor/cjs/node/NodeStdio.d.ts +1 -0
- package/dist/vendor/cjs/node/NodeStream.d.ts +1 -0
- package/dist/vendor/cjs/node/NodeTerminal.d.ts +6 -3
- package/dist/vendor/cjs/node/NodeWorker.d.ts +3 -1
- package/dist/vendor/cjs/node/NodeWorkerRunner.d.ts +2 -1
- package/dist/vendor/cjs/node/Undici.d.ts +3 -0
- package/dist/vendor/cjs/node/index.d.ts +40 -0
- package/dist/vendor/cjs/node-shared/NodeAddressResolver.d.ts +13 -0
- package/dist/vendor/cjs/node-shared/NodeAddressResolver.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeChildProcessSpawner.d.ts +12 -3
- package/dist/vendor/cjs/node-shared/NodeClusterSocket.d.ts +17 -4
- package/dist/vendor/cjs/node-shared/NodeCrypto.d.ts +3 -0
- package/dist/vendor/cjs/node-shared/NodeDatagramSocket.d.ts +246 -0
- package/dist/vendor/cjs/node-shared/NodeDatagramSocket.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeDns.d.ts +221 -0
- package/dist/vendor/cjs/node-shared/NodeDns.js +1 -0
- package/dist/vendor/cjs/node-shared/NodeFileSystem.d.ts +1 -0
- package/dist/vendor/cjs/node-shared/NodeHttpCompression.d.ts +5 -1
- package/dist/vendor/cjs/node-shared/NodePath.d.ts +3 -0
- package/dist/vendor/cjs/node-shared/NodeRuntime.d.ts +4 -0
- package/dist/vendor/cjs/node-shared/NodeSink.d.ts +4 -0
- package/dist/vendor/cjs/node-shared/NodeSocket.d.ts +11 -1
- package/dist/vendor/cjs/node-shared/NodeSocketServer.d.ts +8 -1
- package/dist/vendor/cjs/node-shared/NodeStdio.d.ts +1 -0
- package/dist/vendor/cjs/node-shared/NodeStream.d.ts +15 -0
- package/dist/vendor/cjs/node-shared/NodeTerminal.d.ts +6 -4
- package/dist/vendor/cjs/node-shared/index.d.ts +29 -0
- package/dist/vendor/cjs/node-shared/internal/nodeChildProcessSpawner.d.ts +1 -1
- package/dist/vendor/cjs/platform-node-shared.d.ts +29 -0
- package/dist/vendor/cjs/platform-node.d.ts +40 -0
- package/dist/vendor/node/NodeAddressResolver.d.ts +16 -0
- package/dist/vendor/node/NodeAddressResolver.js +8 -0
- package/dist/vendor/node/NodeChildProcessSpawner.d.ts +1 -0
- package/dist/vendor/node/NodeChildProcessSpawner.js +6 -6
- package/dist/vendor/node/NodeClusterHttp.d.ts +13 -22
- package/dist/vendor/node/NodeClusterHttp.js +32 -32
- package/dist/vendor/node/NodeClusterSocket.d.ts +14 -8
- package/dist/vendor/node/NodeClusterSocket.js +15 -15
- package/dist/vendor/node/NodeCrypto.d.ts +1 -0
- package/dist/vendor/node/NodeCrypto.js +2 -2
- package/dist/vendor/node/NodeDatagramSocket.d.ts +10 -0
- package/dist/vendor/node/NodeDatagramSocket.js +12 -0
- package/dist/vendor/node/NodeDns.d.ts +51 -0
- package/dist/vendor/node/NodeDns.js +12 -0
- package/dist/vendor/node/NodeFileSystem.d.ts +1 -0
- package/dist/vendor/node/NodeFileSystem.js +3 -3
- package/dist/vendor/node/NodeHttpClient.d.ts +21 -2
- package/dist/vendor/node/NodeHttpClient.js +6 -6
- package/dist/vendor/node/NodeHttpIncomingMessage.d.ts +5 -3
- package/dist/vendor/node/NodeHttpIncomingMessage.js +4 -4
- package/dist/vendor/node/NodeHttpPlatform.d.ts +8 -6
- package/dist/vendor/node/NodeHttpPlatform.js +8 -8
- package/dist/vendor/node/NodeHttpServer.d.ts +21 -10
- package/dist/vendor/node/NodeHttpServer.js +26 -26
- package/dist/vendor/node/NodeHttpServerRequest.d.ts +4 -1
- package/dist/vendor/node/NodeHttpServerRequest.js +1 -1
- package/dist/vendor/node/NodeMultipart.d.ts +5 -1
- package/dist/vendor/node/NodeMultipart.js +5 -5
- package/dist/vendor/node/NodeMultipartParser.d.ts +9 -1
- package/dist/vendor/node/NodeMultipartParser.js +1 -1
- package/dist/vendor/node/NodePath.d.ts +3 -0
- package/dist/vendor/node/NodePath.js +2 -2
- package/dist/vendor/node/NodeRedis.d.ts +5 -1
- package/dist/vendor/node/NodeRedis.js +1 -1
- package/dist/vendor/node/NodeRuntime.d.ts +3 -0
- package/dist/vendor/node/NodeRuntime.js +2 -2
- package/dist/vendor/node/NodeServices.d.ts +4 -1
- package/dist/vendor/node/NodeServices.js +17 -17
- package/dist/vendor/node/NodeSink.d.ts +1 -0
- package/dist/vendor/node/NodeSink.js +2 -2
- package/dist/vendor/node/NodeSocket.d.ts +10 -3
- package/dist/vendor/node/NodeSocket.js +2 -2
- package/dist/vendor/node/NodeSocketServer.d.ts +1 -0
- package/dist/vendor/node/NodeSocketServer.js +3 -3
- package/dist/vendor/node/NodeStdio.d.ts +1 -0
- package/dist/vendor/node/NodeStdio.js +4 -4
- package/dist/vendor/node/NodeStream.d.ts +1 -0
- package/dist/vendor/node/NodeStream.js +3 -3
- package/dist/vendor/node/NodeTerminal.d.ts +6 -3
- package/dist/vendor/node/NodeTerminal.js +2 -2
- package/dist/vendor/node/NodeWorker.d.ts +3 -1
- package/dist/vendor/node/NodeWorker.js +1 -1
- package/dist/vendor/node/NodeWorkerRunner.d.ts +2 -1
- package/dist/vendor/node/NodeWorkerRunner.js +1 -1
- package/dist/vendor/node/Undici.d.ts +3 -0
- package/dist/vendor/node/Undici.js +1 -1
- package/dist/vendor/node/index.d.ts +40 -0
- package/dist/vendor/node/index.js +70 -55
- package/dist/vendor/node-shared/NodeAddressResolver.d.ts +13 -0
- package/dist/vendor/node-shared/NodeAddressResolver.js +7 -0
- package/dist/vendor/node-shared/NodeChildProcessSpawner.d.ts +12 -3
- package/dist/vendor/node-shared/NodeChildProcessSpawner.js +5 -5
- package/dist/vendor/node-shared/NodeClusterSocket.d.ts +17 -4
- package/dist/vendor/node-shared/NodeClusterSocket.js +3 -3
- package/dist/vendor/node-shared/NodeCrypto.d.ts +3 -0
- package/dist/vendor/node-shared/NodeCrypto.js +1 -1
- package/dist/vendor/node-shared/NodeDatagramSocket.d.ts +246 -0
- package/dist/vendor/node-shared/NodeDatagramSocket.js +11 -0
- package/dist/vendor/node-shared/NodeDns.d.ts +221 -0
- package/dist/vendor/node-shared/NodeDns.js +31 -0
- package/dist/vendor/node-shared/NodeFileSystem.d.ts +1 -0
- package/dist/vendor/node-shared/NodeFileSystem.js +2 -2
- package/dist/vendor/node-shared/NodeHttpCompression.d.ts +5 -1
- package/dist/vendor/node-shared/NodeHttpCompression.js +1 -1
- package/dist/vendor/node-shared/NodePath.d.ts +3 -0
- package/dist/vendor/node-shared/NodePath.js +1 -1
- package/dist/vendor/node-shared/NodeRuntime.d.ts +4 -0
- package/dist/vendor/node-shared/NodeRuntime.js +1 -1
- package/dist/vendor/node-shared/NodeSink.d.ts +4 -0
- package/dist/vendor/node-shared/NodeSink.js +1 -1
- package/dist/vendor/node-shared/NodeSocket.d.ts +11 -1
- package/dist/vendor/node-shared/NodeSocket.js +1 -1
- package/dist/vendor/node-shared/NodeSocketServer.d.ts +8 -1
- package/dist/vendor/node-shared/NodeSocketServer.js +2 -2
- package/dist/vendor/node-shared/NodeStdio.d.ts +1 -0
- package/dist/vendor/node-shared/NodeStdio.js +3 -3
- package/dist/vendor/node-shared/NodeStream.d.ts +15 -0
- package/dist/vendor/node-shared/NodeStream.js +2 -2
- package/dist/vendor/node-shared/NodeTerminal.d.ts +6 -4
- package/dist/vendor/node-shared/NodeTerminal.js +1 -1
- package/dist/vendor/node-shared/index.d.ts +29 -0
- package/dist/vendor/node-shared/index.js +34 -22
- package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.d.ts +1 -1
- package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.js +1 -1
- package/dist/vendor/node-shared/internal/utils.js +1 -1
- package/dist/vendor/platform-node-shared.d.ts +29 -0
- package/dist/vendor/platform-node-shared.js +34 -22
- package/dist/vendor/platform-node.d.ts +40 -0
- package/dist/vendor/platform-node.js +70 -55
- package/docs/README.md +2 -2
- package/docs/api.md +2 -2
- package/docs/concepts/host-bundle.md +2 -2
- package/docs/installation.md +8 -9
- package/docs/quickstart.md +2 -2
- package/package.json +12 -12
- package/src/EgressHttpClient.ts +4 -4
- package/src/NodeHost.ts +2 -2
- package/src/ProcessConfinement.ts +1 -1
- package/src/ProcessReaper.ts +2 -2
- package/src/ScopedProcess.ts +2 -2
- package/src/internal/PipedProcess.ts +2 -2
- package/src/internal/ProcessCleanup.ts +1 -1
- package/src/internal/ProcessSupervisor.ts +2 -2
- /package/dist/vendor/{chunk-M7CLUILA.js → chunk-3WUGYBFU.js} +0 -0
- /package/dist/vendor/{chunk-ZJMRMY57.js → chunk-ASGOJ3XA.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProcessConfinement.js","sourceRoot":"","sources":["../../src/ProcessConfinement.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The kernel's `ProcessConfinement` seam, filled with this host's native\n * sandbox: bubblewrap on Linux, seatbelt on macOS.\n *\n * `@smthrs/kernel`'s `ChildProcessSpawner.layer` hands every stage that passed\n * its `proc:spawn` check to the confinement in its context, together with the\n * `ProcessConfinement.Profile` the grants in force admit. This module turns\n * that profile into a {@link ProcessSandbox.Request}, plans it against the\n * workspace, and wraps the stage's argv in the mechanism the host has, so an\n * approved `bash` can write only where an `fs:write` grant says and reach the\n * network only when a `net:*` grant says. A stage that asked for the platform\n * shell is spelled out as `/bin/sh -c <line>` first: wrapping a `shell: true`\n * command line would otherwise leave its redirections and pipes to a shell\n * outside the sandbox.\n *\n * A host with no mechanism is the one decision this module leaves to its\n * caller: {@link Options.unavailable} either refuses the spawn, so nothing\n * runs that the profile would not have confined, or runs it unconfined with\n * a warning, the way every host did before this seam existed. A write set\n * the mechanism cannot enforce safely, a symbolic link below the workspace\n * root, is always refused.\n *\n * @since 1.0.0-rc.1\n */\n\nimport * as KernelProcessConfinement from \"@smthrs/kernel/ProcessConfinement\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as PlatformError from \"effect/PlatformError\"\nimport type * as Scope from \"effect/Scope\"\nimport * as ChildProcess from \"effect/unstable/process/ChildProcess\"\nimport * as NodeFs from \"node:fs\"\nimport * as NodeOs from \"node:os\"\nimport * as NodePath from \"node:path\"\nimport * as ProcessSandbox from \"./ProcessSandbox.ts\"\n\n/**\n * How the confinement is built.\n *\n * @category models\n * @since 1.0.0-rc.1\n */\nexport interface Options {\n /**\n * What happens when this host has no mechanism to enforce a profile with.\n * `\"refuse\"` fails the spawn, so a command never runs with more than the\n * profile allows; `\"unconfined\"` runs it as given and logs a\n * warning naming what the host lacks.\n */\n readonly unavailable?: \"refuse\" | \"unconfined\" | undefined\n /** The host facts mechanism selection reads; defaults to the real host. */\n readonly host?: ProcessSandbox.Host | undefined\n /** Where each run's private temporary directory is created; defaults to the OS temporary directory. */\n readonly temporaryDirectory?: string | undefined\n}\n\nconst shellLine = (command: ChildProcess.StandardCommand): string => [command.command, ...command.args].join(\" \")\n\n/**\n * The argv a stage executes, with a shell request made explicit.\n *\n * Node runs a `shell: true` stage as `/bin/sh -c <line>` on POSIX, and a\n * string shell as `<shell> -c <line>`; the wrapper needs that program to be\n * the one it confines, so the shell becomes the argv's first token and the\n * spawned stage no longer asks for one.\n */\nconst argvOf = (command: ChildProcess.StandardCommand): ReadonlyArray<string> => {\n const shell = command.options.shell\n if (shell === undefined || shell === false) return [command.command, ...command.args]\n return [shell === true ? \"/bin/sh\" : shell, \"-c\", shellLine(command)]\n}\n\nconst failure = (\n tag: \"NotFound\" | \"PermissionDenied\" | \"Unknown\",\n command: ChildProcess.StandardCommand,\n description: string,\n cause: unknown\n): PlatformError.PlatformError =>\n PlatformError.systemError({\n _tag: tag,\n module: \"ProcessConfinement\",\n method: \"confine\",\n pathOrDescriptor: shellLine(command),\n description,\n cause\n })\n\nconst messageOf = (cause: unknown): string =>\n ProcessSandbox.isUnenforceable(cause)\n ? cause.message\n : cause instanceof Error\n ? cause.message\n : String(cause)\n\n/** Classic BPF for seccomp_data: deny host Unix sockets and io_uring, preserving stream socketpair.\n * Closed networking additionally denies every IP socket family.\n * Wrong ABI and x32 syscall encodings fail closed rather than bypassing socket(). */\nconst networkFilter = (architecture: string, network: \"none\" | \"open\"): Uint8Array => {\n const abi = architecture === \"x64\"\n ? { audit: 0xc000003e, socket: 41, socketpair: 53 }\n : architecture === \"arm64\"\n ? { audit: 0xc00000b7, socket: 198, socketpair: 199 }\n : undefined\n if (abi === undefined) throw new Error(`native-network seccomp is unavailable on ${architecture}`)\n const instructions: Array<readonly [number, number, number, number]> = [\n [0x20, 0, 0, 4], // load audit architecture\n [0x15, 1, 0, abi.audit],\n [0x06, 0, 0, 0x80000000], // kill unsupported ABI\n [0x20, 0, 0, 0], // load syscall number\n [0x35, 0, 1, 0x40000000],\n [0x06, 0, 0, 0x80000000], // kill x32 / invalid high syscall numbers\n [0x15, 0, 1, 425], // io_uring_setup on both supported ABIs\n [0x06, 0, 0, 0x00050001], // io_uring can otherwise create sockets without socket()\n [0x15, 0, 6, abi.socketpair],\n [0x20, 0, 0, 16], // socketpair domain\n [0x15, 0, 4, 1], // AF_UNIX\n [0x20, 0, 0, 24], // socketpair type, low 32 bits of args[1]\n [0x54, 0, 0, 0xf], // strip SOCK_NONBLOCK and SOCK_CLOEXEC\n [0x15, 1, 0, 1], // only SOCK_STREAM; Linux aliases SOCK_RAW to datagram operations\n [0x06, 0, 0, 0x00050001],\n [0x20, 0, 0, 0] // reload syscall number before the socket() policy\n ]\n if (network === \"none\") {\n instructions.push([0x15, 0, 1, abi.socket], [0x06, 0, 0, 0x00050001]) // EPERM for every socket family\n } else {\n instructions.push(\n [0x15, 0, 3, abi.socket],\n [0x20, 0, 0, 16], // socket domain, low 32 bits of args[0]\n [0x15, 0, 1, 1], // AF_UNIX; IP families remain available\n [0x06, 0, 0, 0x00050001]\n )\n }\n instructions.push([0x06, 0, 0, 0x7fff0000]) // SECCOMP_RET_ALLOW\n const bytes = new Uint8Array(instructions.length * 8)\n const view = new DataView(bytes.buffer)\n for (const [index, [code, jt, jf, value]] of instructions.entries()) {\n view.setUint16(index * 8, code, true)\n view.setUint8(index * 8 + 2, jt)\n view.setUint8(index * 8 + 3, jf)\n view.setUint32(index * 8 + 4, value, true)\n }\n return bytes\n}\n\n/**\n * Builds the native confinement.\n *\n * @category constructors\n * @since 1.0.0-rc.1\n */\nexport const make = (options: Options = {}): KernelProcessConfinement.Service => {\n const hostFacts = options.host ?? ProcessSandbox.host()\n const temporaryRoot = options.temporaryDirectory ?? NodeOs.tmpdir()\n const unavailable = options.unavailable ?? \"refuse\"\n const confine = Effect.fn(\"ProcessConfinement.confine\")(function*(\n command: ChildProcess.StandardCommand,\n profile: KernelProcessConfinement.Profile\n ): Effect.fn.Return<ChildProcess.StandardCommand, PlatformError.PlatformError, Scope.Scope> {\n const request: ProcessSandbox.Request = {\n network: profile.network,\n unixSockets: false,\n strict: true,\n reads: profile.reads,\n writes: profile.writes,\n readOnly: profile.readOnly\n }\n const selected = ProcessSandbox.select(request, hostFacts)\n if (ProcessSandbox.isUnenforceable(selected)) {\n if (unavailable === \"refuse\") {\n return yield* failure(\n \"NotFound\",\n command,\n `${selected.message} This host refuses to spawn unconfined.`,\n selected\n )\n }\n yield* Effect.logWarning(`${selected.message} Running unconfined.`)\n return command\n }\n // The stage's directory is absolute: the kernel spawner roots it first.\n const cwd = command.options.cwd ?? profile.workspaceRoot\n const within = (root: string, path: string): boolean => {\n const relative = NodePath.relative(root, path)\n return relative !== \"..\" && !relative.startsWith(`..${NodePath.sep}`) && !NodePath.isAbsolute(relative)\n }\n if (!within(profile.workspaceRoot, cwd)) {\n return yield* failure(\"PermissionDenied\", command, \"command directory is outside the workspace\", undefined)\n }\n // A lexical workspace path can enter an unrelated host directory through\n // a symlink. Check the real directory before granting or preparing a run.\n const canonical = yield* Effect.try({\n try: () => {\n const root = NodeFs.realpathSync(profile.workspaceRoot)\n const directory = NodeFs.realpathSync(cwd)\n if (!within(root, directory)) throw new Error(\"command directory is outside the workspace\")\n for (const relative of profile.reads) {\n const lexical = NodePath.resolve(root, relative)\n if (!within(root, lexical)) continue\n // A read bind follows its source symlink. Refuse a grant that would\n // therefore mount unrelated host bytes inside the workspace.\n if (NodeFs.existsSync(lexical)) {\n const real = NodeFs.realpathSync(lexical)\n if (!within(root, real)) throw new Error(\"read grant resolves outside the workspace\")\n if (real !== lexical) throw new Error(\"read grant is a symbolic link\")\n }\n }\n return { root, cwd: directory }\n },\n catch: (cause) => failure(\"PermissionDenied\", command, messageOf(cause), cause)\n })\n // The private tmp lives as long as the spawn's scope, however preparation\n // ends; the declared write directories are created so the mechanism has\n // something to bind, which the grant that opened them already permits.\n const allocatedTmp = yield* Effect.acquireRelease(\n Effect.try({\n try: () => NodeFs.mkdtempSync(NodePath.join(temporaryRoot, \"smithers-confinement-\")),\n catch: (cause) => failure(\"Unknown\", command, `could not prepare the confinement: ${messageOf(cause)}`, cause)\n }),\n (directory) =>\n Effect.sync(() => {\n try {\n NodeFs.rmSync(directory, { recursive: true, force: true })\n } catch {\n // Cleanup is best-effort when the host refuses directory removal.\n }\n })\n )\n const tmp = yield* Effect.try({\n try: () => NodeFs.realpathSync(allocatedTmp),\n catch: (cause) => failure(\"Unknown\", command, `could not prepare the confinement: ${messageOf(cause)}`, cause)\n })\n const planned = yield* Effect.try({\n try: () => ProcessSandbox.plan(request, { workspaceRoot: canonical.root, cwd: canonical.cwd, tmp }, hostFacts),\n catch: (cause) => failure(\"Unknown\", command, `could not plan the confinement: ${messageOf(cause)}`, cause)\n })\n if (ProcessSandbox.isUnenforceable(planned)) {\n return yield* failure(\"PermissionDenied\", command, planned.message, planned)\n }\n // Build outputs may grant their parent directory. An agent grant must\n // never inherit that widening when a requested tree is already a file.\n const exactWrites = profile.writes.map((relative) => NodePath.resolve(planned.workspaceRoot, relative))\n if (planned.writes.some((write) => !exactWrites.includes(write))) {\n return yield* failure(\"PermissionDenied\", command, \"write grant is not a directory tree\", undefined)\n }\n // A workspace link does not grant authority to its target on the host.\n const confinement: ProcessSandbox.Plan = { ...planned, externalReads: [] }\n yield* Effect.try({\n try: () => {\n ProcessSandbox.validateWrites(confinement, hostFacts)\n NodeFs.mkdirSync(NodePath.join(tmp, \"home\"), { recursive: true })\n NodeFs.mkdirSync(NodePath.join(tmp, \"cache\"), { recursive: true })\n for (const write of planned.writes) NodeFs.mkdirSync(write, { recursive: true })\n },\n catch: (cause) => failure(\"Unknown\", command, `could not prepare the confinement: ${messageOf(cause)}`, cause)\n })\n // Only the target receives its requested environment. Dynamic-loader and\n // other startup variables must never configure the host sandbox launcher.\n const targetEnvironment: Record<string, string> = {}\n const inherited = command.options.env === undefined || command.options.extendEnv === true\n for (const [name, value] of Object.entries(inherited ? process.env : {})) {\n // Bash exports functions as names such as BASH_FUNC_which%%. These\n // ambient entries cannot be exported by the portable inner launcher.\n if (typeof value === \"string\" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) targetEnvironment[name] = value\n }\n for (const [name, value] of Object.entries(command.options.env ?? {})) {\n if (typeof value === \"string\") targetEnvironment[name] = value\n else delete targetEnvironment[name]\n }\n const privateEnvironment = ProcessSandbox.environment(confinement)\n const script = yield* Effect.try({\n try: () => {\n const quote = (value: string): string => `'${value.replaceAll(\"'\", \"'\\\\''\")}'`\n const exports: Array<string> = []\n for (const [name, value] of Object.entries({ ...targetEnvironment, ...privateEnvironment })) {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) throw new Error(\"environment variable name is not portable\")\n if (value.includes(\"\\0\")) throw new Error(\"environment variable contains a null byte\")\n exports.push(`export ${name}=${quote(value)}`)\n }\n const file = NodePath.join(tmp, \"environment.sh\")\n // Values stay off argv and journal receipts; the script is private,\n // removed with the scope, and interpreted only inside confinement.\n NodeFs.writeFileSync(\n file,\n [\n \"#!/bin/sh\",\n \"unset ENV BASH_ENV CDPATH PWD OLDPWD SHLVL _\",\n ...exports,\n \"exec \\\"$@\\\"\",\n \"\"\n ].join(\"\\n\"),\n { flag: \"wx\", mode: 0o600 }\n )\n return file\n },\n catch: (cause) => failure(\"PermissionDenied\", command, messageOf(cause), cause)\n })\n // Resolve the actual program before wrapping it in the environment shell.\n // Otherwise the sandbox sees only /usr/bin/env and omits a native helper\n // installed outside its ordinary runtime paths.\n const originalArgv = argvOf(command)\n const launch = ProcessSandbox.launcher(\n originalArgv[0]!,\n targetEnvironment.PATH,\n [...confinement.reads, ...confinement.writes, ...confinement.externalReads],\n confinement.workspaceRoot,\n hostFacts\n )\n const targetArgv = [\"/usr/bin/env\", \"-i\", \"/bin/sh\", script, launch.program, ...originalArgv.slice(1)]\n const wrapped = yield* Effect.try({\n try: () =>\n ProcessSandbox.wrap(\n { ...confinement, externalReads: [...confinement.externalReads, ...launch.reads, script] },\n targetArgv,\n targetEnvironment,\n hostFacts\n ),\n catch: (cause) => failure(\"Unknown\", command, `could not render the confinement: ${messageOf(cause)}`, cause)\n })\n let [executable, ...args] = wrapped.argv\n if (selected._tag === \"bubblewrap\") {\n const filter = yield* Effect.try({\n try: () => {\n const file = NodePath.join(tmp, \"network.seccomp\")\n NodeFs.writeFileSync(file, networkFilter(process.arch, profile.network), { flag: \"wx\", mode: 0o600 })\n return file\n },\n catch: (cause) => failure(\"PermissionDenied\", command, messageOf(cause), cause)\n })\n let fd = 3\n while (command.options.additionalFds?.[`fd${fd}`] !== undefined) fd++\n // A regular file avoids a filter-input pipe whose early closure can\n // surface as an unhandled ECONNRESET before bwrap reports its refusal.\n args = [\n \"-c\",\n `exec ${fd}<\"$1\"; shift; exec \"$@\"`,\n \"smithers-seccomp\",\n filter,\n executable!,\n \"--seccomp\",\n String(fd),\n ...args\n ]\n executable = \"/bin/sh\"\n }\n return ChildProcess.make(executable!, args, {\n ...command.options,\n cwd: canonical.cwd,\n shell: false,\n env: { PATH: \"/usr/bin:/bin:/usr/sbin:/sbin\", LANG: \"C\", ...privateEnvironment },\n extendEnv: false\n })\n })\n return KernelProcessConfinement.ProcessConfinement.of({ confine })\n}\n\n/**\n * Provides the native confinement.\n *\n * @category layers\n * @since 1.0.0-rc.1\n */\nexport const layer = (options: Options = {}): Layer.Layer<KernelProcessConfinement.ProcessConfinement> =>\n Layer.succeed(KernelProcessConfinement.ProcessConfinement)(make(options))\n"]}
|
|
1
|
+
{"version":3,"file":"ProcessConfinement.js","sourceRoot":"","sources":["../../src/ProcessConfinement.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The kernel's `ProcessConfinement` seam, filled with this host's native\n * sandbox: bubblewrap on Linux, seatbelt on macOS.\n *\n * `@smthrs/kernel`'s `ChildProcessSpawner.layer` hands every stage that passed\n * its `proc:spawn` check to the confinement in its context, together with the\n * `ProcessConfinement.Profile` the grants in force admit. This module turns\n * that profile into a {@link ProcessSandbox.Request}, plans it against the\n * workspace, and wraps the stage's argv in the mechanism the host has, so an\n * approved `bash` can write only where an `fs:write` grant says and reach the\n * network only when a `net:*` grant says. A stage that asked for the platform\n * shell is spelled out as `/bin/sh -c <line>` first: wrapping a `shell: true`\n * command line would otherwise leave its redirections and pipes to a shell\n * outside the sandbox.\n *\n * A host with no mechanism is the one decision this module leaves to its\n * caller: {@link Options.unavailable} either refuses the spawn, so nothing\n * runs that the profile would not have confined, or runs it unconfined with\n * a warning, the way every host did before this seam existed. A write set\n * the mechanism cannot enforce safely, a symbolic link below the workspace\n * root, is always refused.\n *\n * @since 1.0.0-rc.1\n */\n\nimport * as KernelProcessConfinement from \"@smthrs/kernel/ProcessConfinement\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as PlatformError from \"effect/PlatformError\"\nimport * as ChildProcess from \"effect/process/ChildProcess\"\nimport type * as Scope from \"effect/Scope\"\nimport * as NodeFs from \"node:fs\"\nimport * as NodeOs from \"node:os\"\nimport * as NodePath from \"node:path\"\nimport * as ProcessSandbox from \"./ProcessSandbox.ts\"\n\n/**\n * How the confinement is built.\n *\n * @category models\n * @since 1.0.0-rc.1\n */\nexport interface Options {\n /**\n * What happens when this host has no mechanism to enforce a profile with.\n * `\"refuse\"` fails the spawn, so a command never runs with more than the\n * profile allows; `\"unconfined\"` runs it as given and logs a\n * warning naming what the host lacks.\n */\n readonly unavailable?: \"refuse\" | \"unconfined\" | undefined\n /** The host facts mechanism selection reads; defaults to the real host. */\n readonly host?: ProcessSandbox.Host | undefined\n /** Where each run's private temporary directory is created; defaults to the OS temporary directory. */\n readonly temporaryDirectory?: string | undefined\n}\n\nconst shellLine = (command: ChildProcess.StandardCommand): string => [command.command, ...command.args].join(\" \")\n\n/**\n * The argv a stage executes, with a shell request made explicit.\n *\n * Node runs a `shell: true` stage as `/bin/sh -c <line>` on POSIX, and a\n * string shell as `<shell> -c <line>`; the wrapper needs that program to be\n * the one it confines, so the shell becomes the argv's first token and the\n * spawned stage no longer asks for one.\n */\nconst argvOf = (command: ChildProcess.StandardCommand): ReadonlyArray<string> => {\n const shell = command.options.shell\n if (shell === undefined || shell === false) return [command.command, ...command.args]\n return [shell === true ? \"/bin/sh\" : shell, \"-c\", shellLine(command)]\n}\n\nconst failure = (\n tag: \"NotFound\" | \"PermissionDenied\" | \"Unknown\",\n command: ChildProcess.StandardCommand,\n description: string,\n cause: unknown\n): PlatformError.PlatformError =>\n PlatformError.systemError({\n _tag: tag,\n module: \"ProcessConfinement\",\n method: \"confine\",\n pathOrDescriptor: shellLine(command),\n description,\n cause\n })\n\nconst messageOf = (cause: unknown): string =>\n ProcessSandbox.isUnenforceable(cause)\n ? cause.message\n : cause instanceof Error\n ? cause.message\n : String(cause)\n\n/** Classic BPF for seccomp_data: deny host Unix sockets and io_uring, preserving stream socketpair.\n * Closed networking additionally denies every IP socket family.\n * Wrong ABI and x32 syscall encodings fail closed rather than bypassing socket(). */\nconst networkFilter = (architecture: string, network: \"none\" | \"open\"): Uint8Array => {\n const abi = architecture === \"x64\"\n ? { audit: 0xc000003e, socket: 41, socketpair: 53 }\n : architecture === \"arm64\"\n ? { audit: 0xc00000b7, socket: 198, socketpair: 199 }\n : undefined\n if (abi === undefined) throw new Error(`native-network seccomp is unavailable on ${architecture}`)\n const instructions: Array<readonly [number, number, number, number]> = [\n [0x20, 0, 0, 4], // load audit architecture\n [0x15, 1, 0, abi.audit],\n [0x06, 0, 0, 0x80000000], // kill unsupported ABI\n [0x20, 0, 0, 0], // load syscall number\n [0x35, 0, 1, 0x40000000],\n [0x06, 0, 0, 0x80000000], // kill x32 / invalid high syscall numbers\n [0x15, 0, 1, 425], // io_uring_setup on both supported ABIs\n [0x06, 0, 0, 0x00050001], // io_uring can otherwise create sockets without socket()\n [0x15, 0, 6, abi.socketpair],\n [0x20, 0, 0, 16], // socketpair domain\n [0x15, 0, 4, 1], // AF_UNIX\n [0x20, 0, 0, 24], // socketpair type, low 32 bits of args[1]\n [0x54, 0, 0, 0xf], // strip SOCK_NONBLOCK and SOCK_CLOEXEC\n [0x15, 1, 0, 1], // only SOCK_STREAM; Linux aliases SOCK_RAW to datagram operations\n [0x06, 0, 0, 0x00050001],\n [0x20, 0, 0, 0] // reload syscall number before the socket() policy\n ]\n if (network === \"none\") {\n instructions.push([0x15, 0, 1, abi.socket], [0x06, 0, 0, 0x00050001]) // EPERM for every socket family\n } else {\n instructions.push(\n [0x15, 0, 3, abi.socket],\n [0x20, 0, 0, 16], // socket domain, low 32 bits of args[0]\n [0x15, 0, 1, 1], // AF_UNIX; IP families remain available\n [0x06, 0, 0, 0x00050001]\n )\n }\n instructions.push([0x06, 0, 0, 0x7fff0000]) // SECCOMP_RET_ALLOW\n const bytes = new Uint8Array(instructions.length * 8)\n const view = new DataView(bytes.buffer)\n for (const [index, [code, jt, jf, value]] of instructions.entries()) {\n view.setUint16(index * 8, code, true)\n view.setUint8(index * 8 + 2, jt)\n view.setUint8(index * 8 + 3, jf)\n view.setUint32(index * 8 + 4, value, true)\n }\n return bytes\n}\n\n/**\n * Builds the native confinement.\n *\n * @category constructors\n * @since 1.0.0-rc.1\n */\nexport const make = (options: Options = {}): KernelProcessConfinement.Service => {\n const hostFacts = options.host ?? ProcessSandbox.host()\n const temporaryRoot = options.temporaryDirectory ?? NodeOs.tmpdir()\n const unavailable = options.unavailable ?? \"refuse\"\n const confine = Effect.fn(\"ProcessConfinement.confine\")(function*(\n command: ChildProcess.StandardCommand,\n profile: KernelProcessConfinement.Profile\n ): Effect.fn.Return<ChildProcess.StandardCommand, PlatformError.PlatformError, Scope.Scope> {\n const request: ProcessSandbox.Request = {\n network: profile.network,\n unixSockets: false,\n strict: true,\n reads: profile.reads,\n writes: profile.writes,\n readOnly: profile.readOnly\n }\n const selected = ProcessSandbox.select(request, hostFacts)\n if (ProcessSandbox.isUnenforceable(selected)) {\n if (unavailable === \"refuse\") {\n return yield* failure(\n \"NotFound\",\n command,\n `${selected.message} This host refuses to spawn unconfined.`,\n selected\n )\n }\n yield* Effect.logWarning(`${selected.message} Running unconfined.`)\n return command\n }\n // The stage's directory is absolute: the kernel spawner roots it first.\n const cwd = command.options.cwd ?? profile.workspaceRoot\n const within = (root: string, path: string): boolean => {\n const relative = NodePath.relative(root, path)\n return relative !== \"..\" && !relative.startsWith(`..${NodePath.sep}`) && !NodePath.isAbsolute(relative)\n }\n if (!within(profile.workspaceRoot, cwd)) {\n return yield* failure(\"PermissionDenied\", command, \"command directory is outside the workspace\", undefined)\n }\n // A lexical workspace path can enter an unrelated host directory through\n // a symlink. Check the real directory before granting or preparing a run.\n const canonical = yield* Effect.try({\n try: () => {\n const root = NodeFs.realpathSync(profile.workspaceRoot)\n const directory = NodeFs.realpathSync(cwd)\n if (!within(root, directory)) throw new Error(\"command directory is outside the workspace\")\n for (const relative of profile.reads) {\n const lexical = NodePath.resolve(root, relative)\n if (!within(root, lexical)) continue\n // A read bind follows its source symlink. Refuse a grant that would\n // therefore mount unrelated host bytes inside the workspace.\n if (NodeFs.existsSync(lexical)) {\n const real = NodeFs.realpathSync(lexical)\n if (!within(root, real)) throw new Error(\"read grant resolves outside the workspace\")\n if (real !== lexical) throw new Error(\"read grant is a symbolic link\")\n }\n }\n return { root, cwd: directory }\n },\n catch: (cause) => failure(\"PermissionDenied\", command, messageOf(cause), cause)\n })\n // The private tmp lives as long as the spawn's scope, however preparation\n // ends; the declared write directories are created so the mechanism has\n // something to bind, which the grant that opened them already permits.\n const allocatedTmp = yield* Effect.acquireRelease(\n Effect.try({\n try: () => NodeFs.mkdtempSync(NodePath.join(temporaryRoot, \"smithers-confinement-\")),\n catch: (cause) => failure(\"Unknown\", command, `could not prepare the confinement: ${messageOf(cause)}`, cause)\n }),\n (directory) =>\n Effect.sync(() => {\n try {\n NodeFs.rmSync(directory, { recursive: true, force: true })\n } catch {\n // Cleanup is best-effort when the host refuses directory removal.\n }\n })\n )\n const tmp = yield* Effect.try({\n try: () => NodeFs.realpathSync(allocatedTmp),\n catch: (cause) => failure(\"Unknown\", command, `could not prepare the confinement: ${messageOf(cause)}`, cause)\n })\n const planned = yield* Effect.try({\n try: () => ProcessSandbox.plan(request, { workspaceRoot: canonical.root, cwd: canonical.cwd, tmp }, hostFacts),\n catch: (cause) => failure(\"Unknown\", command, `could not plan the confinement: ${messageOf(cause)}`, cause)\n })\n if (ProcessSandbox.isUnenforceable(planned)) {\n return yield* failure(\"PermissionDenied\", command, planned.message, planned)\n }\n // Build outputs may grant their parent directory. An agent grant must\n // never inherit that widening when a requested tree is already a file.\n const exactWrites = profile.writes.map((relative) => NodePath.resolve(planned.workspaceRoot, relative))\n if (planned.writes.some((write) => !exactWrites.includes(write))) {\n return yield* failure(\"PermissionDenied\", command, \"write grant is not a directory tree\", undefined)\n }\n // A workspace link does not grant authority to its target on the host.\n const confinement: ProcessSandbox.Plan = { ...planned, externalReads: [] }\n yield* Effect.try({\n try: () => {\n ProcessSandbox.validateWrites(confinement, hostFacts)\n NodeFs.mkdirSync(NodePath.join(tmp, \"home\"), { recursive: true })\n NodeFs.mkdirSync(NodePath.join(tmp, \"cache\"), { recursive: true })\n for (const write of planned.writes) NodeFs.mkdirSync(write, { recursive: true })\n },\n catch: (cause) => failure(\"Unknown\", command, `could not prepare the confinement: ${messageOf(cause)}`, cause)\n })\n // Only the target receives its requested environment. Dynamic-loader and\n // other startup variables must never configure the host sandbox launcher.\n const targetEnvironment: Record<string, string> = {}\n const inherited = command.options.env === undefined || command.options.extendEnv === true\n for (const [name, value] of Object.entries(inherited ? process.env : {})) {\n // Bash exports functions as names such as BASH_FUNC_which%%. These\n // ambient entries cannot be exported by the portable inner launcher.\n if (typeof value === \"string\" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) targetEnvironment[name] = value\n }\n for (const [name, value] of Object.entries(command.options.env ?? {})) {\n if (typeof value === \"string\") targetEnvironment[name] = value\n else delete targetEnvironment[name]\n }\n const privateEnvironment = ProcessSandbox.environment(confinement)\n const script = yield* Effect.try({\n try: () => {\n const quote = (value: string): string => `'${value.replaceAll(\"'\", \"'\\\\''\")}'`\n const exports: Array<string> = []\n for (const [name, value] of Object.entries({ ...targetEnvironment, ...privateEnvironment })) {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) throw new Error(\"environment variable name is not portable\")\n if (value.includes(\"\\0\")) throw new Error(\"environment variable contains a null byte\")\n exports.push(`export ${name}=${quote(value)}`)\n }\n const file = NodePath.join(tmp, \"environment.sh\")\n // Values stay off argv and journal receipts; the script is private,\n // removed with the scope, and interpreted only inside confinement.\n NodeFs.writeFileSync(\n file,\n [\n \"#!/bin/sh\",\n \"unset ENV BASH_ENV CDPATH PWD OLDPWD SHLVL _\",\n ...exports,\n \"exec \\\"$@\\\"\",\n \"\"\n ].join(\"\\n\"),\n { flag: \"wx\", mode: 0o600 }\n )\n return file\n },\n catch: (cause) => failure(\"PermissionDenied\", command, messageOf(cause), cause)\n })\n // Resolve the actual program before wrapping it in the environment shell.\n // Otherwise the sandbox sees only /usr/bin/env and omits a native helper\n // installed outside its ordinary runtime paths.\n const originalArgv = argvOf(command)\n const launch = ProcessSandbox.launcher(\n originalArgv[0]!,\n targetEnvironment.PATH,\n [...confinement.reads, ...confinement.writes, ...confinement.externalReads],\n confinement.workspaceRoot,\n hostFacts\n )\n const targetArgv = [\"/usr/bin/env\", \"-i\", \"/bin/sh\", script, launch.program, ...originalArgv.slice(1)]\n const wrapped = yield* Effect.try({\n try: () =>\n ProcessSandbox.wrap(\n { ...confinement, externalReads: [...confinement.externalReads, ...launch.reads, script] },\n targetArgv,\n targetEnvironment,\n hostFacts\n ),\n catch: (cause) => failure(\"Unknown\", command, `could not render the confinement: ${messageOf(cause)}`, cause)\n })\n let [executable, ...args] = wrapped.argv\n if (selected._tag === \"bubblewrap\") {\n const filter = yield* Effect.try({\n try: () => {\n const file = NodePath.join(tmp, \"network.seccomp\")\n NodeFs.writeFileSync(file, networkFilter(process.arch, profile.network), { flag: \"wx\", mode: 0o600 })\n return file\n },\n catch: (cause) => failure(\"PermissionDenied\", command, messageOf(cause), cause)\n })\n let fd = 3\n while (command.options.additionalFds?.[`fd${fd}`] !== undefined) fd++\n // A regular file avoids a filter-input pipe whose early closure can\n // surface as an unhandled ECONNRESET before bwrap reports its refusal.\n args = [\n \"-c\",\n `exec ${fd}<\"$1\"; shift; exec \"$@\"`,\n \"smithers-seccomp\",\n filter,\n executable!,\n \"--seccomp\",\n String(fd),\n ...args\n ]\n executable = \"/bin/sh\"\n }\n return ChildProcess.make(executable!, args, {\n ...command.options,\n cwd: canonical.cwd,\n shell: false,\n env: { PATH: \"/usr/bin:/bin:/usr/sbin:/sbin\", LANG: \"C\", ...privateEnvironment },\n extendEnv: false\n })\n })\n return KernelProcessConfinement.ProcessConfinement.of({ confine })\n}\n\n/**\n * Provides the native confinement.\n *\n * @category layers\n * @since 1.0.0-rc.1\n */\nexport const layer = (options: Options = {}): Layer.Layer<KernelProcessConfinement.ProcessConfinement> =>\n Layer.succeed(KernelProcessConfinement.ProcessConfinement)(make(options))\n"]}
|
|
@@ -53,7 +53,7 @@ import * as ProcessLedger from "@smthrs/kernel/ProcessLedger";
|
|
|
53
53
|
import * as Effect from "effect/Effect";
|
|
54
54
|
import * as Layer from "effect/Layer";
|
|
55
55
|
import * as Metric from "effect/Metric";
|
|
56
|
-
import { ChildProcessSpawner } from "effect/
|
|
56
|
+
import { ChildProcessSpawner } from "effect/process/ChildProcessSpawner";
|
|
57
57
|
import * as ProcessCleanup from "./internal/ProcessCleanup.ts";
|
|
58
58
|
/**
|
|
59
59
|
* What the operating system can say about a pid.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProcessReaper.d.ts","sourceRoot":"","sources":["../../src/ProcessReaper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,gBAAgB,MAAM,iCAAiC,CAAA;AACnE,OAAO,KAAK,aAAa,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,mBAAmB,EAAuB,MAAM,
|
|
1
|
+
{"version":3,"file":"ProcessReaper.d.ts","sourceRoot":"","sources":["../../src/ProcessReaper.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ import * as ProcessLedger from "@smthrs/kernel/ProcessLedger";
|
|
|
53
53
|
import * as Effect from "effect/Effect";
|
|
54
54
|
import * as Layer from "effect/Layer";
|
|
55
55
|
import * as Metric from "effect/Metric";
|
|
56
|
-
import { ChildProcessSpawner, make as makeSpawner } from "effect/
|
|
56
|
+
import { ChildProcessSpawner, make as makeSpawner } from "effect/process/ChildProcessSpawner";
|
|
57
57
|
import { spawnSync } from "node:child_process";
|
|
58
58
|
import { uptime } from "node:os";
|
|
59
59
|
import { parse, win32 } from "node:path";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProcessReaper.js","sourceRoot":"","sources":["../../src/ProcessReaper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,gBAAgB,MAAM,iCAAiC,CAAA;AACnE,OAAO,KAAK,aAAa,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,mBAAmB,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,6CAA6C,CAAA;AACtG,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAA;AAChG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAC1E,OAAO,KAAK,YAAY,MAAM,4BAA4B,CAAA;AAC1D,OAAO,KAAK,cAAc,MAAM,8BAA8B,CAAA;AAC9D,OAAO,KAAK,YAAY,MAAM,4BAA4B,CAAA;AAgF1D,MAAM,SAAS,GAAG,CAAC,KAAc,EAAsB,EAAE,CAAE,KAA2C,EAAE,IAAI,CAAA;AAE5G,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAY,EAAE;IACzC,IAAI,CAAC;QACH,yEAAyE;QACzE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACpB,OAAO,OAAO,CAAA;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,oEAAoE;QACpE,uEAAuE;QACvE,uEAAuE;QACvE,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1D,CAAC;AACH,CAAC,CAAA;AAED,MAAM,UAAU,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;AAEzE;;;;;;;;;GASG;AACH,MAAM,WAAW,GAAG,CAAC,UAAkB,EAAE,EAAE,CAAC,CAAC,GAAW,EAAa,EAAE;IACrE,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC5C,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,4EAA4E;QAC5E,0EAA0E;QAC1E,yEAAyE;QACzE,qDAAqD;QACrD,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;IACpE,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,CAAA;IAC/C,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,CAAA;AAClG,CAAC,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAA;AAE5C,6EAA6E;AAC7E,MAAM,WAAW,GAAG,IAAI,CAAA;AAExB;;GAEG;AACH,MAAM,WAAW,GAAG,GAAW,EAAE;IAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAA;IACzC,OAAO,UAAU,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAA;AAC9F,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,GAAW,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAA;AAE9F,iFAAiF;AACjF,MAAM,qBAAqB,GAAG,IAAI,CAAA;AAElC;;;;GAIG;AACH,MAAM,eAAe,GAAG,CAAC,IAAY,EAAuC,EAAE;IAC5E,MAAM,MAAM,GAAG,SAAS,CAAC,mBAAmB,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,0BAA0B,CAAC,EAAE;QACtF,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,qBAAqB;QAC9B,UAAU,EAAE,SAAS;QACrB,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE;KACvD,CAAC,CAAA;IACF,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IACjG,IAAI,GAAuB,CAAA;IAC3B,MAAM,OAAO,GAAiC,EAAE,CAAA;IAChD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,yCAAyC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClE,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,SAAS,CAAA;QACpC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAC9B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QAChF,IAAI,GAAG,KAAK,OAAO,CAAC,GAAG;YAAE,GAAG,GAAG,KAAK,CAAA;QACpC,IAAI,KAAK,KAAK,IAAI;YAAE,SAAQ;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,MAAM,CAAC,CAAA;QAC9C,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;YAAE,OAAO,SAAS,CAAA;QAC3C,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAChF,CAAC;IACD,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;AAC/E,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAyD,EAAE,CAC1G,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAA;AAE9F;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE;IACnD,qEAAqE;IACrE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1D,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;QACtB,OAAO,KAAK,CAAA;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK,OAAO,CAAA;IACrC,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC,SAAS,CAAC;IACvD,QAAQ,EAAE,OAAO,CAAC,QAAQ;IAC1B,QAAQ,EAAE,gBAAgB,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC5C,MAAM,EAAE,WAAW;CACpB,CAAC,CAAA;AAYF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,OAAwB,EAC8C,EAAE;IACxE,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,gBAAgB,CAAC,CAAA;IACrH,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,OAAO,EAAE,EAAE,CACvC,YAAY,CAAC,KAAK,CAAC,OAAuC,EAAE,SAAS,EAAE,IAAI,CAAC,CAC7E,CAAA;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC/E,CAAC,CAAA;AAED,4EAA4E;AAC5E,MAAM,OAAO,GAAG,UAAU,CAAA;AAE1B;;;;;;GAMG;AACH,MAAM,EAAE,GAAG,CACT,UAAkB,EAClB,MAAc,EACd,GAAW,EACsD,EAAE;IACnE,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,MAAM,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;QAC5E,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,WAAW;QACpB,4EAA4E;QAC5E,yEAAyE;QACzE,4EAA4E;QAC5E,wCAAwC;QACxC,UAAU,EAAE,SAAS;QACrB,6DAA6D;QAC7D,2EAA2E;QAC3E,4EAA4E;QAC5E,kEAAkE;QAClE,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE;KACvD,CAAC,CAAA;IACF,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QACnF,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;IAChC,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;IAChD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;IACpC,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AACtF,CAAC,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,QAAQ,GAAG,CAAC,UAAkB,EAAE,EAAE,CAAC,GAAkB,EAAE;IAC3D,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAClC,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;AACnE,CAAC,CAAA;AA8BD;;;;;;;;;;GAUG;AACH,MAAM,iBAAiB,GAAG,CAAC,MAAmC,EAAuB,EAAE;IACrF,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,UAAU,CAAA;IAC3C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC;QAAE,OAAO,gBAAgB,CAAA;IACjF,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC;QAAE,OAAO,gBAAgB,CAAA;IACnF,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAA;AAClE,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,CAAC,MAAmC,EAAuB,EAAE;IACvF,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,gBAAgB,CAAA;IACjD,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAA;AACvH,CAAC,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAuB,EAAU,EAAE,CACjE,eAAe,CAAC;IACd,WAAW,EAAE,WAAW,CAAC,OAAO,EAAE,YAAY,IAAI,mBAAmB,CAAC;IACtE,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAAE,YAAY,IAAI,mBAAmB,CAAC;IAChE,UAAU;CACX,EAAE,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAA;AAgBtC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAA2B,EAAU,EAAE;IACpE,MAAM,IAAI,GAAG,OAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,eAAe,CAAA;IAC9D,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAChD,OAAO,eAAe,CAAC;QACrB,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE;YACnB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;YAC7B,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;QAC9F,CAAC;QACD,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC;QACrC,UAAU,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE;KAC5D,EAAE,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAA;AACtC,CAAC,CAAA;AAED,2EAA2E;AAC3E,MAAM,eAAe,GAAG,CACtB,MAA+D,EAC/D,QAAgB,EACR,EAAE;IACV,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAA;IACpC,OAAO;QACL,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,YAAY;QACtB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,YAAY,EAAE,iBAAiB;QAC/B,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YACnB,yEAAyE;YACzE,wEAAwE;YACxE,IAAI,iBAAiB,CAAC,MAAM,CAAC,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAA;YAC5D,wEAAwE;YACxE,yEAAyE;YACzE,wEAAwE;YACxE,qEAAqE;YACrE,qEAAqE;YACrE,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,QAAQ,CAAA;YACxE,MAAM,KAAK,GAAG,YAAY,EAAE,CAAA;YAC5B,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,KAAK,KAAK,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK;gBAAE,OAAO,QAAQ,CAAA;YACpF,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,CAAE,MAAM,CAAC,IAAe,EAAE,SAAS,CAAC,CAAA;gBACjD,OAAO,WAAW,CAAA;YACpB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,uEAAuE;gBACvE,yEAAyE;gBACzE,6DAA6D;gBAC7D,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAA;YACjE,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAW,eAAe,EAAE,CAAA;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAAuB,EAAU,EAAE;IACnE,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAA;IACjD,MAAM,WAAW,GAAG,CAAC,GAAW,EAAa,EAAE;QAC7C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,WAAW;YAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;QAC/F,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,OAAO,EAAE,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAA;YAChG,MAAM,UAAU,GAAG,UAAU,KAAK,SAAS;gBACzC,CAAC,CAAC,wBAAwB,CAAC,WAAW,EAAE,SAAS,CAAC;gBAClD,CAAC,CAAC,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;YAC3C,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;gBACpE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI;gBACjC,GAAG,EAAE,EAAE;gBACP,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,WAAW;gBACpB,UAAU,EAAE,SAAS;gBACrB,SAAS,EAAE,IAAI;aAChB,CAAC,CAAA;YACF,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;YAC/G,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAyE,CAAA;YAC/G,IAAI,KAAK,EAAE,MAAM,KAAK,MAAM;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;YACrD,OAAO,KAAK,EAAE,MAAM,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;gBACvE,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC;gBACnE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;gBACrD,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;QAChC,CAAC;IACH,CAAC,CAAA;IACD,OAAO;QACL,OAAO,EAAE,QAAQ;QACjB,WAAW;QACX,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI;QACpB,UAAU;QACV,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC;QAC7F,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YACnB,IAAI,mBAAmB,CAAC,MAAM,CAAC,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAA;YAC9D,0EAA0E;YAC1E,qEAAqE;YACrE,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ;gBAAE,OAAO,QAAQ,CAAA;YAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,kBAAkB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;gBACvF,mEAAmE;gBACnE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI;gBACjC,GAAG,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE;gBAClC,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAA;YACF,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAA;YAC/C,uEAAuE;YACvE,4BAA4B;YAC5B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,WAAW,CAAA;YAC3C,OAAO,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC1D,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAW,iBAAiB,EAAE,CAAA;AAExD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAW,cAAc,EAAE,CAAA;AAElD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,QAAgB,EAAU,EAAE,CACpD,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAA;AAExF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAA;AA2CvC;;;;;;;;;GASG;AACH,MAAM,QAAQ,GAAyB,IAAI,GAAG,CAAU;IACtD,aAAa;IACb,qBAAqB;IACrB,mBAAmB;CACpB,CAAC,CAAA;AA4BF,+EAA+E;AAC/E,MAAM,gBAAgB,GAAG,CACvB,MAAc,EACd,MAAmC,EACnC,MAAc,EACO,EAAE;IACvB,4EAA4E;IAC5E,2EAA2E;IAC3E,4EAA4E;IAC5E,6EAA6E;IAC7E,YAAY;IACZ,EAAE;IACF,6EAA6E;IAC7E,8EAA8E;IAC9E,6EAA6E;IAC7E,8EAA8E;IAC9E,uEAAuE;IACvE,IAAI,MAAM,CAAC,WAAW,GAAG,MAAM,GAAG,mBAAmB;QAAE,OAAO,UAAU,CAAA;IACxE,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC9C,uEAAuE;IACvE,4EAA4E;IAC5E,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,cAAc,CAAA;IAClD,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa;QAAE,OAAO,qBAAqB,CAAA;IAChE,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,mBAAmB;QAC9E,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,mBAAmB,CAAA;AACzB,CAAC,CAAA;AAED,4EAA4E;AAC5E,MAAM,MAAM,GAAG,CACb,MAAc,EACd,MAAmC,EACnC,QAAgB,EAChB,QAAuB,EACvB,MAAc,EACO,EAAE;IACvB,2EAA2E;IAC3E,2EAA2E;IAC3E,0BAA0B;IAC1B,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ;QAAE,OAAO,WAAW,CAAA;IAC3E,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAA;IAClG,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;IAC1C,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IACvC,6EAA6E;IAC7E,6EAA6E;IAC7E,yEAAyE;IACzE,yCAAyC;IACzC,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,mBAAmB,CAAA;IACzE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,MAAM;QAAE,OAAO,aAAa,CAAA;IACpE,OAAO,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AACjD,CAAC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,OAAiB,EAC0F,EAAE,CAC7G,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,aAAa,CAAA;IACjD,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC7D,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAA;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,CAAA;IAClC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAA;IACrC,MAAM,OAAO,GAAkB,EAAE,CAAA;IACjC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;QAClE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;YACvC,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACzB,gEAAgE;gBAChE,0DAA0D;gBAC1D,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAA;gBAC/D,SAAQ;YACV,CAAC;YACD,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;YAC1D,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;YACtC,SAAQ;QACV,CAAC;QACD,0EAA0E;QAC1E,oCAAoC;QACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;QAC5E,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;IAClD,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC,CAAC,CAAA;AAEJ;;;;;;;GAOG;AACH,MAAM,MAAM,GAAG,CACb,KAAmC,EACnC,GAAW,EACX,IAAY,EACS,EAAE,CACvB,KAAK,CAAC,IAAI,CACR,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,oCAAoC,IAAI,QAAQ,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC,CACzG,CAAA;AAEH;;;GAGG;AACH,MAAM,QAAQ,GAAyB,IAAI,GAAG,CAAU,CAAC,qBAAqB,EAAE,mBAAmB,EAAE,aAAa,CAAC,CAAC,CAAA;AAEpH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,+BAA+B,EAAE;IACtE,WAAW,EAAE,+DAA+D;CAC7E,CAAC,CAAA;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAA8B,EAAuB,EAAE,CAC5E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IAChC,MAAM,MAAM,GAAqC,EAAE,CAAA;IACnD,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,CAAC,CAAA;YACX,SAAQ;QACV,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IAC1D,CAAC;IACD,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAA;IAC3E,CAAC;IACD,MAAM,WAAW,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAA;IACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IACtF,MAAM,IAAI,GAAG,wCAAwC,CAAA;IACrD,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAA;AAC3G,CAAC,CAAC,CAAA;AAEJ;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,OAAiB,EAA0D,EAAE,CACjG,KAAK,CAAC,aAAa,CACjB,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAChB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EACtB,MAAM,CAAC,QAAQ,CACb,yCAAyC,EACzC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,mEAAmE,EAAE,KAAK,CAAC,CACvG,CACF,CACF,CAAA","sourcesContent":["/**\n * Reaping the processes a dead host incarnation abandoned.\n *\n * Scope closure cleans up work a live host still owns. On POSIX, a prepared\n * supervisor also receives private-channel EOF when its host disappears and\n * independently requests group cleanup. The durable ledger remains the fallback\n * when that cleanup is incomplete or cannot be verified; the next incarnation\n * uses this module to examine the recorded process identities before acting.\n *\n * The rules are narrow on purpose, because the input is a durable record that\n * outlived the process that wrote it and a pid is reused. A record is signalled\n * only when ALL of these hold:\n *\n * - it belongs to a DIFFERENT incarnation of the SAME `hostId`\n * ({@link ProcessLedger.Service.orphans} already filters that);\n * - its owner is gone. A pid that exists but belongs to another user counts as\n * alive, exactly as {@link HostLiveness} counts it, so only `ESRCH` reads as\n * dead and every other answer keeps the record;\n * - it names a target the platform can actually signal. On POSIX that is a\n * process group the child leads itself, so `pgid` has to be a safe integer\n * above 1 and equal to `pid`; on Windows it is a pid, so `pgid` has to be\n * absent. The check is made against the DURABLE record rather than trusted\n * from it: `process.kill(-0, \"SIGKILL\")` signals this host's own process\n * group, and `@smthrs/kernel`'s ledger schema admits zero;\n * - that group is not THIS process's group, and its pid is not this process's\n * pid. The host's real process group is read from the operating system,\n * because a stored number can claim anything and the shell that started this\n * host shares its group. A host that cannot read its own group keeps the\n * record rather than signalling it on a guard that did not run;\n * - the number still names the process the record describes. A record written\n * before this machine booted names a pid from a pid space that no longer\n * exists, and within one boot the recorded start time has to match the start\n * time the operating system reports for that pid. A host that cannot ASK the\n * question answers {@link StartTime} `unavailable`, which refuses the kill\n * and keeps the record; no evidence never authorizes a signal.\n *\n * The outcome of the signal is part of the record. A kill that succeeds, or\n * that reports the group is already gone, retires the record through\n * {@link ProcessLedger.Service.reaped}; a kill that FAILS for any other reason\n * leaves the record inherited so the next incarnation tries again. A record\n * refused on grounds the operating system will not revisit — a number no\n * platform can signal, a pid that is gone, a start time that does not match — is\n * retired through {@link ProcessLedger.Service.skipped}, which says in the\n * journal that nothing was signalled and stops every later incarnation\n * re-examining a number the operating system has moved on from. The three\n * refusals a later incarnation CAN answer differently — `owner-alive`,\n * `identity-unverified`, and `own-group-unknown` — retire nothing.\n *\n * @since 0.1.0\n */\n\nimport * as ContainedSpawner from \"@smthrs/kernel/ContainedSpawner\"\nimport * as ProcessLedger from \"@smthrs/kernel/ProcessLedger\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Metric from \"effect/Metric\"\nimport type * as ChildProcess from \"effect/unstable/process/ChildProcess\"\nimport { ChildProcessSpawner, make as makeSpawner } from \"effect/unstable/process/ChildProcessSpawner\"\nimport { spawnSync } from \"node:child_process\"\nimport { uptime } from \"node:os\"\nimport { parse, win32 } from \"node:path\"\nimport { packageRoot, resolveDefaultExecutable } from \"./internal/AtomicFileSystemExecutable.ts\"\nimport { usableExecutable } from \"./internal/AtomicFileSystemTransport.ts\"\nimport * as PipedProcess from \"./internal/PipedProcess.ts\"\nimport * as ProcessCleanup from \"./internal/ProcessCleanup.ts\"\nimport * as ProcSnapshot from \"./internal/ProcSnapshot.ts\"\n\n/**\n * What the operating system can say about a pid.\n *\n * `unknown` is not `dead`. A pid this host may not signal answers `EPERM`, and\n * a reaper that read that as \"gone\" would kill another user's children on the\n * strength of a record it cannot verify.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Liveness = \"alive\" | \"dead\" | \"unknown\"\n\n/**\n * What happened when a process group was signalled.\n *\n * @category models\n * @since 0.1.0\n */\nexport type KillOutcome =\n /** The signal was delivered. */\n | \"signalled\"\n /** There was nothing left to signal, which is the same end state. */\n | \"already-gone\"\n /** The signal was refused, and the record must be tried again later. */\n | \"failed\"\n\n/**\n * What the operating system can say about when a pid started.\n *\n * The three negative answers are deliberately distinct, because they authorize\n * three different decisions. `gone` is evidence — the pid does not exist, so\n * the record describes nothing and is retired unsignalled. `unavailable` is the\n * ABSENCE of evidence: `ps` is missing, unanswerable, or printed something no\n * clock can read, so the record is kept for an incarnation that can ask.\n * `unsupported` is a platform that has no such column at all, which falls back\n * to the boot-time comparison alone.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type StartTime =\n /** The operating system reports this start time, in epoch milliseconds. */\n | { readonly _tag: \"started\"; readonly startedAtMs: number }\n /** The pid names no process. */\n | { readonly _tag: \"gone\" }\n /** The question could not be asked on this host. */\n | { readonly _tag: \"unavailable\" }\n /** The platform has no start-time column at all. */\n | { readonly _tag: \"unsupported\" }\n\n/**\n * The operating-system operations reaping needs.\n *\n * It is a seam, not an abstraction: `flows` ships exactly the two\n * implementations below and a test drives the Windows one on a POSIX host,\n * which is the only way that path is ever exercised in this repository.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface System {\n /** Whether a pid names a process that still exists. */\n readonly isAlive: (pid: number) => Liveness\n /** When the process behind a pid started. */\n readonly startedAtMs: (pid: number) => StartTime\n /** The process group THIS process belongs to, or `null` where there are none. */\n readonly ownGroup: () => number | null\n /** When this machine booted, in epoch milliseconds. */\n readonly bootedAtMs: () => number\n /**\n * Whether the numbers in a record name something this platform may signal,\n * checked before any other guard consults them.\n */\n readonly refuseTarget: (record: ProcessLedger.ProcessRecord) => Refusal | undefined\n /** Ends an abandoned process and everything below it. */\n readonly killTree: (record: ProcessLedger.ProcessRecord) => KillOutcome\n}\n\nconst errorCode = (cause: unknown): string | undefined => (cause as { readonly code?: string } | null)?.code\n\nconst liveness = (pid: number): Liveness => {\n try {\n // Signal 0 delivers nothing; it only asks whether the pid is signalable.\n process.kill(pid, 0)\n return \"alive\"\n } catch (cause) {\n // ESRCH is the only answer that means gone. EPERM means the process\n // exists and belongs to another user; anything else is a question this\n // host could not ask, and both keep the record rather than kill on it.\n return errorCode(cause) === \"ESRCH\" ? \"dead\" : \"unknown\"\n }\n}\n\nconst bootedAtMs = (): number => Date.now() - Math.round(uptime() * 1000)\n\n/**\n * The start time `ps` reports for a pid.\n *\n * `lstart` is the one start-time column both BSD (macOS) and procps (Linux)\n * spell the same way, and it prints an absolute time rather than an elapsed\n * one, so the answer does not drift between reading it and comparing it. It is\n * also a LOCALIZED column, so the probe pins `LC_ALL=C` and `TZ=UTC`.\n * Its text has no zone; parsing explicitly as UTC keeps the identity independent\n * of the host runtime's timezone.\n */\nconst startedAtMs = (executable: string) => (pid: number): StartTime => {\n const answer = ps(executable, \"lstart\", pid)\n if (answer._tag === \"gone\") {\n // A nonzero exit is `ps` saying the pid does not exist, but it is also what\n // a `ps` that rejected the column, or one that is not the `ps` this probe\n // expects, says about a pid that is very much alive. The kernel is asked\n // directly before a live process is retired as gone.\n return liveness(pid) === \"dead\" ? answer : { _tag: \"unavailable\" }\n }\n if (answer._tag !== \"printed\") return answer\n const parsed = Date.parse(`${answer.text} UTC`)\n return Number.isNaN(parsed) ? { _tag: \"unavailable\" } : { _tag: \"started\", startedAtMs: parsed }\n}\n\n/**\n * The absolute path the process probe is run from.\n *\n * Never a `PATH` lookup. The inherited environment belongs to whoever started\n * this host, and a planted `ps` that prints a fabricated start time — or none\n * at all — would decide whether a `SIGKILL` is authorized.\n *\n * @category constants\n * @since 1.0.0-rc.0\n */\nexport const defaultPsExecutable = \"/bin/ps\"\n\n/** How long the probe may take before it counts as an answer nobody gave. */\nconst psTimeoutMs = 5000\n\n/**\n * The Windows directory the host was started with, when it names one.\n */\nconst windowsRoot = (): string => {\n const systemRoot = process.env.SystemRoot\n return systemRoot !== undefined && win32.isAbsolute(systemRoot) ? systemRoot : \"C:\\\\Windows\"\n}\n\n/**\n * The system `taskkill`, by absolute path. Windows resolves a bare name from\n * the current directory before `PATH`, so a flow that wrote `taskkill.exe`\n * into the host's working directory would otherwise run as the host.\n */\nconst taskkillExecutable = (): string => win32.join(windowsRoot(), \"System32\", \"taskkill.exe\")\n\n/** A live-release probe has its own short bound within the shutdown deadline. */\nconst cleanupProbeTimeoutMs = 2000\n\n/**\n * One fixed-path snapshot supplies group membership, start identities and our\n * own group together. Only numeric fields and C-locale lstart are read; command\n * text and the caller's PATH never influence signal authority.\n */\nconst psGroupSnapshot = (pgid: number): ProcessCleanup.Snapshot | undefined => {\n const result = spawnSync(defaultPsExecutable, [\"-A\", \"-o\", \"pid=,pgid=,stat=,lstart=\"], {\n encoding: \"utf8\",\n timeout: cleanupProbeTimeoutMs,\n killSignal: \"SIGKILL\",\n env: { LC_ALL: \"C\", TZ: \"UTC\", PATH: \"/usr/bin:/bin\" }\n })\n if (result.error !== undefined || result.signal !== null || result.status !== 0) return undefined\n let own: number | undefined\n const members: Array<ProcessCleanup.Member> = []\n for (const line of result.stdout.trim().split(\"\\n\")) {\n const match = /^\\s*([0-9]+)\\s+([0-9]+)\\s+(\\S+)\\s+(.+)$/.exec(line)\n if (match === null) return undefined\n const pid = Number(match[1])\n const group = Number(match[2])\n if (!Number.isSafeInteger(pid) || !Number.isSafeInteger(group)) return undefined\n if (pid === process.pid) own = group\n if (group !== pgid) continue\n const started = Date.parse(`${match[4]!} UTC`)\n if (Number.isNaN(started)) return undefined\n members.push({ pid, startedAtMs: started, zombie: match[3]!.startsWith(\"Z\") })\n }\n return own === undefined || own <= 0 ? undefined : { ownGroup: own, members }\n}\n\n/**\n * The observation the supervisor polls, from the source that platform has.\n *\n * Linux publishes the whole process table as files under `/proc`, which is\n * where `ps` itself reads it, so the kernel is asked directly. That needs no\n * `procps` in the image, cannot be answered by a planted binary, and costs no\n * fork on a poll that runs every 10ms. A missing `/bin/ps` is not a\n * hypothetical: `procps` is not in `debian:bookworm-slim`, and on Cloud CI run\n * 11727 every spawned target in every task finished its work and then failed\n * cleanup verification with `Unknown: ChildProcess.kill`, because this\n * observation could not be made.\n *\n * Every other POSIX host keeps the `ps` reading, which is the only portable\n * spelling of this question off Linux.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const groupSnapshotFor = (platform: string): (pgid: number) => ProcessCleanup.Snapshot | undefined =>\n platform === \"linux\" ? ProcSnapshot.snapshot(ProcSnapshot.defaultProcRoot) : psGroupSnapshot\n\n/**\n * Whether the kernel reports no process at all in a group.\n *\n * Signal 0 delivers nothing; it only asks the kernel whether the group has a\n * member. `ESRCH` is the one answer that proves the group empty, with no fork\n * and no process table to parse, so it still answers on a loaded host where a\n * `ps` snapshot cannot be taken. A live member, a zombie (macOS answers\n * `EPERM`, Linux succeeds), another user's member or any other error answers\n * `false`, which leaves the question to the snapshot.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const groupVacant = (pgid: number): boolean => {\n // kill(0) and kill(-1) address the caller's group and every process.\n if (!Number.isSafeInteger(pgid) || pgid <= 1) return false\n try {\n process.kill(-pgid, 0)\n return false\n } catch (cause) {\n return errorCode(cause) === \"ESRCH\"\n }\n}\n\n/**\n * Live cleanup for Node and Bun contained spawners.\n *\n * A trusted supervisor remains the group owner after the target exits. It\n * enforces cleanup on target completion, parent loss and explicit release; the\n * target starts only after its owner is durably recorded. Host observations\n * never signal a pid: they only shorten the owner's deadline or verify an empty\n * group before retiring its record. Failed verification retains the record.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const processLifecycle = ProcessCleanup.lifecycle({\n platform: process.platform,\n snapshot: groupSnapshotFor(process.platform),\n vacant: groupVacant\n})\n\n/**\n * The default grace period for a contained host spawner.\n *\n * The platform is always the running platform; callers cannot describe a\n * Windows ledger identity for a process that actually leads a POSIX group.\n * @category models\n * @since 1.0.0\n */\nexport type SpawnerOptions = Omit<ContainedSpawner.Options, \"platform\">\n\n/**\n * Provides a ledger-backed spawner with this platform's prepared cleanup.\n *\n * Native pipe listeners live until their descriptors close, including writes\n * interrupted by owner loss. The kernel expands pipelines before this private\n * standard-command adapter is called. Windows owners join a native job before\n * activation; POSIX owners enforce their process-group cleanup deadline.\n *\n * The caller supplies the durable or in-memory ledger. This layer records new\n * owners; {@link layer} separately reaps\n * records inherited from a previous host incarnation.\n * @category layers\n * @since 1.0.0\n */\nexport const layerSpawner = (\n options?: SpawnerOptions\n): Layer.Layer<ChildProcessSpawner, never, ProcessLedger.ProcessLedger> => {\n const contained = ContainedSpawner.layer({ graceMs: options?.graceMs, platform: process.platform }, processLifecycle)\n const standard = makeSpawner((command) =>\n PipedProcess.spawn(command as ChildProcess.StandardCommand, undefined, true)\n )\n return Layer.provide(contained, Layer.succeed(ChildProcessSpawner)(standard))\n}\n\n/** A whole number and nothing else, which is all a `pgid` column may be. */\nconst decimal = /^[0-9]+$/\n\n/**\n * One `ps` column for one pid.\n *\n * `printed` is an answer; every other tag is the absence of one. A nonzero exit\n * with no error is `ps` saying the pid does not exist, which is evidence; a\n * spawn that failed, a signal, or a timeout is not.\n */\nconst ps = (\n executable: string,\n column: string,\n pid: number\n): { readonly _tag: \"printed\"; readonly text: string } | StartTime => {\n const result = spawnSync(executable, [\"-o\", `${column}=`, \"-p\", String(pid)], {\n encoding: \"utf8\",\n timeout: psTimeoutMs,\n // `SIGKILL` rather than the default `SIGTERM`, because this call blocks the\n // event loop while a host is being built: `spawnSync` keeps waiting past\n // the deadline for a process that ignores the signal, so a `TERM` the probe\n // can decline is not a deadline at all.\n killSignal: \"SIGKILL\",\n // An empty-ish environment for the same reason the helper in\n // `AtomicFileSystem` gets one: nothing the caller exported may change what\n // this answers. Pin both the column's spelling and its timezone; the parser\n // supplies UTC explicitly because `lstart` does not print a zone.\n env: { LC_ALL: \"C\", TZ: \"UTC\", PATH: \"/usr/bin:/bin\" }\n })\n if (result.error !== undefined || result.signal !== null || result.status === null) {\n return { _tag: \"unavailable\" }\n }\n if (result.status !== 0) return { _tag: \"gone\" }\n const printed = result.stdout.trim()\n return printed === \"\" ? { _tag: \"unavailable\" } : { _tag: \"printed\", text: printed }\n}\n\n/**\n * This process's own process group.\n *\n * Node exposes no `getpgrp`, so the answer comes from `ps`, which both BSD and\n * procps spell `pgid`. A host that cannot read it answers `null` and loses one\n * guard, which is why the pid comparison below is kept as well.\n *\n * The text is required to be one run of decimal digits naming a real group,\n * rather than run through `Number.parseInt`, which reads a PREFIX: `\"12 34\"`,\n * `\"12abc\"`, and `\"0x10\"` all become a number that is not this host's group. A\n * wrong number is worse here than no number at all. It silently passes the\n * own-group comparison in {@link refuse}, and because it is not `null` it also\n * suppresses the `own-group-unknown` refusal that exists to say the comparison\n * could not be made, so the guard neither runs nor reports that it did not run\n * and a `SIGKILL` goes out on it. Anything else answers `null`, which refuses.\n */\nconst ownGroup = (executable: string) => (): number | null => {\n const answer = ps(executable, \"pgid\", process.pid)\n if (answer._tag !== \"printed\") return null\n if (!decimal.test(answer.text)) return null\n const parsed = Number(answer.text)\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null\n}\n\n/**\n * How a {@link System} asks the operating system its questions, and whose\n * identity it must never signal.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface SystemOptions {\n /**\n * The absolute `ps` the identity probe runs. Default\n * {@link defaultPsExecutable}. It is configuration for a host that installs\n * `ps` somewhere else, and the seam the probe's own parsing is driven\n * through; it is never a `PATH` lookup. Windows has no such probe and\n * ignores it.\n */\n readonly psExecutable?: string | undefined\n /** Absolute native helper for Windows process identity queries; never a PATH lookup. */\n readonly processExecutable?: string | undefined\n /**\n * The pid this system must never signal, nor signal the group of. Default\n * `process.pid`. {@link Options.ownerPid} is the same identity at the sweep\n * level; this one is what {@link System.killTree} enforces on its own,\n * because that function is exported and a caller can reach it without going\n * through {@link reap}.\n */\n readonly ownerPid?: number | undefined\n}\n\n/**\n * Whether a durable record names a POSIX process group this host may signal.\n *\n * `process.kill(-pgid, ...)` turns the stored number into a target directly, so\n * every value that is not a real foreign group has to be refused before it gets\n * there: `0` signals THIS process's group, a negative value stops naming a\n * group at all and names a single pid, and a `pgid` that differs from `pid`\n * describes a child that does not lead the group it claims —\n * `ContainedSpawner.groupOf` writes `pgid === pid` for every detached POSIX\n * child, so anything else is a record no writer in this repository produced.\n */\nconst refusePosixTarget = (record: ProcessLedger.ProcessRecord): Refusal | undefined => {\n if (record.pgid === null) return \"no-group\"\n if (!Number.isSafeInteger(record.pid) || record.pid <= 1) return \"invalid-record\"\n if (!Number.isSafeInteger(record.pgid) || record.pgid <= 1) return \"invalid-record\"\n return record.pgid === record.pid ? undefined : \"invalid-record\"\n}\n\n/**\n * Whether a durable record names a Windows process tree this host may signal.\n *\n * Windows has no process groups, so `ContainedSpawner.groupOf` records `null`\n * there and `taskkill /T` walks the tree from the pid instead. A win32 record\n * carrying a number is therefore a record some other platform wrote.\n */\nconst refuseWindowsTarget = (record: ProcessLedger.ProcessRecord): Refusal | undefined => {\n if (record.pgid !== null) return \"invalid-record\"\n return Number.isSafeInteger(record.pid) && record.pid > 1 && record.pid <= 0xffff_ffff ? undefined : \"invalid-record\"\n}\n\n/**\n * Reaping on a POSIX host, with the identity probe configured.\n *\n * The group is killed outright rather than asked politely first. `SIGTERM`\n * buys a graceful shutdown only when someone is left to wait for it, and the\n * incarnation that owned these processes is by definition gone.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const posixSystemWith = (options?: SystemOptions): System =>\n posixSystemFrom({\n startedAtMs: startedAtMs(options?.psExecutable ?? defaultPsExecutable),\n ownGroup: ownGroup(options?.psExecutable ?? defaultPsExecutable),\n bootedAtMs\n }, options?.ownerPid ?? process.pid)\n\n/**\n * Where a Linux {@link System} reads the process table, and whose identity it\n * must never signal.\n *\n * @category models\n * @since 1.0.0-rc.1\n */\nexport interface ProcSystemOptions {\n /** The `/proc` mount the probes read. Default `/proc`. */\n readonly procRoot?: string | undefined\n /** The pid this system must never signal, nor signal the group of. Default `process.pid`. */\n readonly ownerPid?: number | undefined\n}\n\n/**\n * Reaping on Linux, with every identity question read from `/proc` rather\n * than from `ps`.\n *\n * `procps` is not in `debian:bookworm-slim` (Cloud CI run 11727), and a\n * `ps`-based reaper on such a host can read neither its own group nor any\n * start time, so it refuses every orphan as `own-group-unknown` on every\n * restart. The live-cleanup observation ({@link groupSnapshotFor}) already\n * reads `/proc` for the same reason; this is the crash-recovery half.\n *\n * A pid with no `/proc/<pid>/stat` is `gone` only when the kernel also says so,\n * because a `hidepid` mount hides another user's live process the same way.\n *\n * @category constructors\n * @since 1.0.0-rc.1\n */\nexport const procSystemWith = (options?: ProcSystemOptions): System => {\n const root = options?.procRoot ?? ProcSnapshot.defaultProcRoot\n const readStart = ProcSnapshot.startedAtMs(root)\n return posixSystemFrom({\n startedAtMs: (pid) => {\n const answer = readStart(pid)\n return answer._tag === \"gone\" && liveness(pid) !== \"dead\" ? { _tag: \"unavailable\" } : answer\n },\n ownGroup: ProcSnapshot.ownGroup(root),\n bootedAtMs: () => ProcSnapshot.bootMs(root) ?? bootedAtMs()\n }, options?.ownerPid ?? process.pid)\n}\n\n/** The POSIX kill path over whichever probes the platform answers with. */\nconst posixSystemFrom = (\n probes: Pick<System, \"startedAtMs\" | \"ownGroup\" | \"bootedAtMs\">,\n ownerPid: number\n): System => {\n const readOwnGroup = probes.ownGroup\n return {\n isAlive: liveness,\n startedAtMs: probes.startedAtMs,\n ownGroup: readOwnGroup,\n bootedAtMs: probes.bootedAtMs,\n refuseTarget: refusePosixTarget,\n killTree: (record) => {\n // Repeated here and not only in `refuse`: this function is exported, and\n // the negation below is the one place a stored number becomes a signal.\n if (refusePosixTarget(record) !== undefined) return \"failed\"\n // The host's own identity, repeated for the same reason. `refuse` holds\n // one `ownGroup` reading for the whole sweep; a caller that reaches this\n // function directly has made no such reading, and `process.kill(-pgid)`\n // does not care which way the number arrived. A group that cannot be\n // read is a comparison that did not happen, so nothing is signalled.\n if (record.pid === ownerPid || record.pgid === ownerPid) return \"failed\"\n const group = readOwnGroup()\n if (group === null || record.pid === group || record.pgid === group) return \"failed\"\n try {\n process.kill(-(record.pgid as number), \"SIGKILL\")\n return \"signalled\"\n } catch (cause) {\n // The group settled between the liveness check and the signal: the end\n // state is the one that was wanted. Anything else is a kill that did NOT\n // happen, and saying so is what gets the record tried again.\n return errorCode(cause) === \"ESRCH\" ? \"already-gone\" : \"failed\"\n }\n }\n }\n}\n\n/**\n * Reaping on a POSIX host: one `SIGKILL` to the abandoned process group, with\n * the identity probe at {@link defaultPsExecutable}.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const posixSystem: System = posixSystemWith()\n\n/**\n * Reaping on Windows, with the identity the sweep must never signal\n * configured.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const windowsSystemWith = (options?: SystemOptions): System => {\n const ownerPid = options?.ownerPid ?? process.pid\n const startedAtMs = (pid: number): StartTime => {\n if (!Number.isSafeInteger(pid) || pid <= 1 || pid > 0xffff_ffff) return { _tag: \"unavailable\" }\n try {\n const configured = options?.processExecutable ?? process.env.SMITHERS_WORKSPACE_JJ_EXPORT_BINARY\n const executable = configured === undefined\n ? resolveDefaultExecutable(packageRoot, undefined)\n : usableExecutable(configured, undefined)\n const result = spawnSync(executable, [\"--process-info\", String(pid)], {\n cwd: parse(process.execPath).root,\n env: {},\n encoding: \"utf8\",\n timeout: psTimeoutMs,\n killSignal: \"SIGKILL\",\n maxBuffer: 4096\n })\n if (result.error !== undefined || result.signal !== null || result.status !== 0) return { _tag: \"unavailable\" }\n const value = JSON.parse(result.stdout) as { readonly status?: unknown; readonly startedAtMs?: unknown } | null\n if (value?.status === \"gone\") return { _tag: \"gone\" }\n return value?.status === \"started\" && typeof value.startedAtMs === \"number\" &&\n Number.isSafeInteger(value.startedAtMs) && value.startedAtMs >= 0\n ? { _tag: \"started\", startedAtMs: value.startedAtMs }\n : { _tag: \"unavailable\" }\n } catch {\n return { _tag: \"unavailable\" }\n }\n }\n return {\n isAlive: liveness,\n startedAtMs,\n ownGroup: () => null,\n bootedAtMs,\n refuseTarget: (record) => record.pid === ownerPid ? \"own-group\" : refuseWindowsTarget(record),\n killTree: (record) => {\n if (refuseWindowsTarget(record) !== undefined) return \"failed\"\n // `taskkill /T` walks the tree DOWN from the pid it is given, so a record\n // naming this host takes the host and everything it started with it.\n if (record.pid === ownerPid) return \"failed\"\n const result = spawnSync(taskkillExecutable(), [\"/pid\", String(record.pid), \"/T\", \"/F\"], {\n // An inert cwd and only the variable Windows system binaries need.\n cwd: parse(process.execPath).root,\n env: { SystemRoot: windowsRoot() },\n stdio: \"ignore\"\n })\n if (result.error !== undefined) return \"failed\"\n // 128 is `taskkill`'s \"no such process\", which is the same end state a\n // successful kill produces.\n if (result.status === 0) return \"signalled\"\n return result.status === 128 ? \"already-gone\" : \"failed\"\n }\n }\n}\n\n/**\n * Reaping on Windows, which has no process groups: `taskkill /T /F` by pid.\n *\n * **Windows is outside the 1.0.0-rc.0 support contract**\n * (`docs/pages/installation.md`). Full Windows process containment remains\n * under verification. It is kept — and reachable through {@link reap} rather than only\n * by calling it directly — because a reaper that silently retired every win32\n * record would be the \"excluded feature that appears to work partially\" the\n * release policy forbids. Treat it as unsupported best-effort.\n *\n * The packaged native helper reads creation time from a pinned process handle.\n * A missing helper, malformed reply, or denied query keeps the durable record\n * for retry. Windows has no process groups, so own-group refusal uses the pid.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const windowsSystem: System = windowsSystemWith()\n\n/**\n * Reaping on Linux from the kernel's own `/proc`.\n *\n * @category constructors\n * @since 1.0.0-rc.1\n */\nexport const procSystem: System = procSystemWith()\n\n/**\n * Selects the reaping implementation a platform needs.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const systemFor = (platform: string): System =>\n platform === \"win32\" ? windowsSystem : platform === \"linux\" ? procSystem : posixSystem\n\n/**\n * How far apart a recorded start time and the operating system's may be and\n * still describe the same process.\n *\n * `lstart` has one-second granularity and the ledger writes its record just\n * after the spawn returns, so the two never agree exactly. Two seconds covers\n * the gap; a pid the operating system handed to somebody else is minutes or\n * hours away from it, not milliseconds.\n *\n * @category models\n * @since 0.1.0\n */\nexport const identityToleranceMs = 2000\n\n/**\n * Reaper configuration.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Options {\n /** The pid this host must never signal a group for. Default `process.pid`. */\n readonly ownerPid?: number | undefined\n /** The operating-system seam. Default {@link systemFor} of `process.platform`. */\n readonly system?: System | undefined\n}\n\n/**\n * Why a record was not signalled.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Refusal =\n /** The incarnation that started it is still running and will contain it. */\n | \"owner-alive\"\n /** It shared its owner's process group, so there is no group to signal. */\n | \"no-group\"\n /** It named this host's own process group or pid. */\n | \"own-group\"\n /** This host could not read its OWN process group, so it cannot rule that out. */\n | \"own-group-unknown\"\n /** Its numbers do not name anything this platform may signal. */\n | \"invalid-record\"\n /** It was written before this machine booted, so the pid space is not the same. */\n | \"pre-boot\"\n /** The pid it names does not exist, so there is no identity to confirm. */\n | \"process-gone\"\n /** The pid exists but did not start when the record says it did. */\n | \"identity-mismatch\"\n /** This host could not ask when the pid started, so it must not signal it. */\n | \"identity-unverified\"\n /** The signal was refused, so the record stays for the next incarnation. */\n | \"kill-failed\"\n\n/**\n * The refusals that leave a record inherited instead of retiring it.\n *\n * A refusal is final when the operating system has moved on from the number:\n * saying so in the journal is what stops every later incarnation re-examining\n * it. These three are not final. `owner-alive` means the incarnation that owns\n * the record will contain its own children; `identity-unverified` and\n * `own-group-unknown` mean this host could not ask a question at all — a host\n * that CAN ask has to get the chance.\n */\nconst retained: ReadonlySet<Refusal> = new Set<Refusal>([\n \"owner-alive\",\n \"identity-unverified\",\n \"own-group-unknown\"\n])\n\n/**\n * One record, and what the reaper decided about it.\n *\n * The two outcomes are a union rather than one shape with an optional field so\n * that `killed` narrows the reason: after `if (!entry.killed)` the\n * {@link Refusal} is there to read, and a killed record cannot be built\n * carrying a reason it never had. The runtime objects are unchanged — a killed\n * entry simply omits `refusal`.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Reaped =\n | {\n readonly record: ProcessLedger.ProcessRecord\n readonly killed: true\n /** Never present when `killed` is `true`. */\n readonly refusal?: never\n }\n | {\n readonly record: ProcessLedger.ProcessRecord\n readonly killed: false\n /** Present exactly when `killed` is `false`. */\n readonly refusal: Refusal\n }\n\n/** The identity half of the decision, split out because it reads as a list. */\nconst refuseOnIdentity = (\n system: System,\n record: ProcessLedger.ProcessRecord,\n bootMs: number\n): Refusal | undefined => {\n // A record older than this boot names a pid from a pid space that no longer\n // exists. The tolerance points BACKWARDS from the boot instant on purpose:\n // `uptime` is second-granular, so a record written moments after boot could\n // otherwise be read as predating it, and refusing to kill is the safe way to\n // be wrong.\n //\n // The consequence is a narrow, deliberate leak, and it is a leak rather than\n // a retry: `reap` retires a `pre-boot` refusal through `ledger.skipped`, so a\n // group spawned within `identityToleranceMs` of the computed boot instant is\n // never reaped by any later incarnation either. That is the price of refusing\n // to kill on an instant `uptime` can only place to the nearest second.\n if (record.startedAtMs < bootMs + identityToleranceMs) return \"pre-boot\"\n const started = system.startedAtMs(record.pid)\n // A platform with no start-time column at all has already been checked\n // against this boot, which is the whole of its documented weaker guarantee.\n if (started._tag === \"unsupported\") return undefined\n if (started._tag === \"gone\") return \"process-gone\"\n if (started._tag === \"unavailable\") return \"identity-unverified\"\n return Math.abs(started.startedAtMs - record.startedAtMs) <= identityToleranceMs\n ? undefined\n : \"identity-mismatch\"\n}\n\n/** Everything the reaper checks before it is willing to signal a record. */\nconst refuse = (\n system: System,\n record: ProcessLedger.ProcessRecord,\n ownerPid: number,\n ownGroup: number | null,\n bootMs: number\n): Refusal | undefined => {\n // The host's own identity comes first, before the platform is consulted at\n // all: a record naming this process is refused on every platform, whatever\n // shape its numbers have.\n if (record.pgid === ownerPid || record.pid === ownerPid) return \"own-group\"\n if (ownGroup !== null && (record.pgid === ownGroup || record.pid === ownGroup)) return \"own-group\"\n const target = system.refuseTarget(record)\n if (target !== undefined) return target\n // A record naming a group can only be cleared of naming THIS host's group by\n // reading that group. When the probe cannot answer, the comparison above was\n // not made rather than made and passed, so the record is kept instead of\n // signalled on a guard that did not run.\n if (record.pgid !== null && ownGroup === null) return \"own-group-unknown\"\n if (system.isAlive(record.ownerPid) !== \"dead\") return \"owner-alive\"\n return refuseOnIdentity(system, record, bootMs)\n}\n\n/**\n * Kills the process groups a previous incarnation of this host abandoned.\n *\n * Returns one entry per inherited record so a caller can log what it decided;\n * `killed: false` carries the {@link Refusal} that produced it. Fails with\n * {@link ProcessLedger.ProcessLedgerReplayError} when the inherited history\n * cannot be read to its end: nothing is signalled or retired, so the next\n * sweep inherits every record again.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const reap = (\n options?: Options\n): Effect.Effect<ReadonlyArray<Reaped>, ProcessLedger.ProcessLedgerReplayError, ProcessLedger.ProcessLedger> =>\n Effect.gen(function*() {\n const ledger = yield* ProcessLedger.ProcessLedger\n const system = options?.system ?? systemFor(process.platform)\n const ownerPid = options?.ownerPid ?? process.pid\n const ownGroup = system.ownGroup()\n const bootMs = system.bootedAtMs()\n const orphans = yield* ledger.orphans\n const decided: Array<Reaped> = []\n for (const record of orphans) {\n const refusal = refuse(system, record, ownerPid, ownGroup, bootMs)\n if (refusal === undefined) {\n const outcome = system.killTree(record)\n if (outcome === \"failed\") {\n // Nothing was killed, so nothing is retired: leaving the record\n // inherited is what makes the next incarnation try again.\n decided.push({ record, killed: false, refusal: \"kill-failed\" })\n continue\n }\n yield* retire(ledger.reaped(record), record.pid, \"reaped\")\n decided.push({ record, killed: true })\n continue\n }\n // A retained refusal is not this host's to retire; every other refusal is\n // final and says so in the journal.\n if (!retained.has(refusal)) {\n yield* retire(ledger.skipped(record, refusal), record.pid, \"reap-skipped\")\n }\n decided.push({ record, killed: false, refusal })\n }\n return decided\n })\n\n/**\n * Writes one ledger retirement, logging rather than failing the sweep.\n *\n * A retirement that does not commit is not a lost kill: the process is already\n * dead and the record stays inherited, so the next incarnation reads it, finds\n * the pid gone, and retires it then. Failing the whole sweep over it would\n * take the host down for a bookkeeping write.\n */\nconst retire = (\n write: Effect.Effect<void, unknown>,\n pid: number,\n what: string\n): Effect.Effect<void> =>\n write.pipe(\n Effect.catch((error) => Effect.logWarning(`process reaper could not journal ${what} for ${pid}`, error))\n )\n\n/**\n * Refusals that leave a dead incarnation's process running with no live owner\n * to contain it: the host could not ask, or its signal failed.\n */\nconst unreaped: ReadonlySet<Refusal> = new Set<Refusal>([\"identity-unverified\", \"own-group-unknown\", \"kill-failed\"])\n\n/**\n * Counter over inherited records the reaper did not kill, with a `refusal`\n * attribute naming why.\n *\n * @category metrics\n * @since 1.0.0-rc.1\n */\nexport const refusals = Metric.counter(\"flows_process_reaper_refusals\", {\n description: \"Inherited process records the reaper did not kill, by refusal\"\n})\n\n/**\n * Reports one sweep: a counter update per refusal and one summary line. The\n * line is a warning when a record stays inherited (a retained refusal) or a\n * signal failed, because either leaves a crashed incarnation's processes\n * running with nothing else to say so.\n *\n * @category layers\n * @since 1.0.0-rc.1\n */\nexport const report = (decided: ReadonlyArray<Reaped>): Effect.Effect<void> =>\n Effect.gen(function*() {\n if (decided.length === 0) return\n const counts: Partial<Record<Refusal, number>> = {}\n let killed = 0\n for (const entry of decided) {\n if (entry.killed) {\n killed += 1\n continue\n }\n counts[entry.refusal] = (counts[entry.refusal] ?? 0) + 1\n }\n for (const [refusal, count] of Object.entries(counts)) {\n yield* Metric.update(Metric.withAttributes(refusals, { refusal }), count)\n }\n const annotations = { killed, ...counts }\n const alarming = decided.some((entry) => !entry.killed && unreaped.has(entry.refusal))\n const line = \"process reaper swept inherited records\"\n yield* (alarming ? Effect.logWarning(line) : Effect.logInfo(line)).pipe(Effect.annotateLogs(annotations))\n })\n\n/**\n * Runs {@link reap} once while the layer is built.\n *\n * Compose it into a host layer so standing a host up is also what cleans up\n * after the incarnation that crashed. A history that cannot be read refuses\n * the sweep with an error log and leaves every record inherited; the host\n * still starts, because the processes it will spawn are recorded and\n * contained regardless. Every decision is {@link report}ed.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer = (options?: Options): Layer.Layer<never, never, ProcessLedger.ProcessLedger> =>\n Layer.effectDiscard(\n reap(options).pipe(\n Effect.flatMap(report),\n Effect.catchTag(\n \"@smthrs/kernel/ProcessLedgerReplayError\",\n (error) => Effect.logError(\"process reaper refused to sweep: the ledger history is incomplete\", error)\n )\n )\n )\n"]}
|
|
1
|
+
{"version":3,"file":"ProcessReaper.js","sourceRoot":"","sources":["../../src/ProcessReaper.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reaping the processes a dead host incarnation abandoned.\n *\n * Scope closure cleans up work a live host still owns. On POSIX, a prepared\n * supervisor also receives private-channel EOF when its host disappears and\n * independently requests group cleanup. The durable ledger remains the fallback\n * when that cleanup is incomplete or cannot be verified; the next incarnation\n * uses this module to examine the recorded process identities before acting.\n *\n * The rules are narrow on purpose, because the input is a durable record that\n * outlived the process that wrote it and a pid is reused. A record is signalled\n * only when ALL of these hold:\n *\n * - it belongs to a DIFFERENT incarnation of the SAME `hostId`\n * ({@link ProcessLedger.Service.orphans} already filters that);\n * - its owner is gone. A pid that exists but belongs to another user counts as\n * alive, exactly as {@link HostLiveness} counts it, so only `ESRCH` reads as\n * dead and every other answer keeps the record;\n * - it names a target the platform can actually signal. On POSIX that is a\n * process group the child leads itself, so `pgid` has to be a safe integer\n * above 1 and equal to `pid`; on Windows it is a pid, so `pgid` has to be\n * absent. The check is made against the DURABLE record rather than trusted\n * from it: `process.kill(-0, \"SIGKILL\")` signals this host's own process\n * group, and `@smthrs/kernel`'s ledger schema admits zero;\n * - that group is not THIS process's group, and its pid is not this process's\n * pid. The host's real process group is read from the operating system,\n * because a stored number can claim anything and the shell that started this\n * host shares its group. A host that cannot read its own group keeps the\n * record rather than signalling it on a guard that did not run;\n * - the number still names the process the record describes. A record written\n * before this machine booted names a pid from a pid space that no longer\n * exists, and within one boot the recorded start time has to match the start\n * time the operating system reports for that pid. A host that cannot ASK the\n * question answers {@link StartTime} `unavailable`, which refuses the kill\n * and keeps the record; no evidence never authorizes a signal.\n *\n * The outcome of the signal is part of the record. A kill that succeeds, or\n * that reports the group is already gone, retires the record through\n * {@link ProcessLedger.Service.reaped}; a kill that FAILS for any other reason\n * leaves the record inherited so the next incarnation tries again. A record\n * refused on grounds the operating system will not revisit — a number no\n * platform can signal, a pid that is gone, a start time that does not match — is\n * retired through {@link ProcessLedger.Service.skipped}, which says in the\n * journal that nothing was signalled and stops every later incarnation\n * re-examining a number the operating system has moved on from. The three\n * refusals a later incarnation CAN answer differently — `owner-alive`,\n * `identity-unverified`, and `own-group-unknown` — retire nothing.\n *\n * @since 0.1.0\n */\n\nimport * as ContainedSpawner from \"@smthrs/kernel/ContainedSpawner\"\nimport * as ProcessLedger from \"@smthrs/kernel/ProcessLedger\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Metric from \"effect/Metric\"\nimport type * as ChildProcess from \"effect/process/ChildProcess\"\nimport { ChildProcessSpawner, make as makeSpawner } from \"effect/process/ChildProcessSpawner\"\nimport { spawnSync } from \"node:child_process\"\nimport { uptime } from \"node:os\"\nimport { parse, win32 } from \"node:path\"\nimport { packageRoot, resolveDefaultExecutable } from \"./internal/AtomicFileSystemExecutable.ts\"\nimport { usableExecutable } from \"./internal/AtomicFileSystemTransport.ts\"\nimport * as PipedProcess from \"./internal/PipedProcess.ts\"\nimport * as ProcessCleanup from \"./internal/ProcessCleanup.ts\"\nimport * as ProcSnapshot from \"./internal/ProcSnapshot.ts\"\n\n/**\n * What the operating system can say about a pid.\n *\n * `unknown` is not `dead`. A pid this host may not signal answers `EPERM`, and\n * a reaper that read that as \"gone\" would kill another user's children on the\n * strength of a record it cannot verify.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Liveness = \"alive\" | \"dead\" | \"unknown\"\n\n/**\n * What happened when a process group was signalled.\n *\n * @category models\n * @since 0.1.0\n */\nexport type KillOutcome =\n /** The signal was delivered. */\n | \"signalled\"\n /** There was nothing left to signal, which is the same end state. */\n | \"already-gone\"\n /** The signal was refused, and the record must be tried again later. */\n | \"failed\"\n\n/**\n * What the operating system can say about when a pid started.\n *\n * The three negative answers are deliberately distinct, because they authorize\n * three different decisions. `gone` is evidence — the pid does not exist, so\n * the record describes nothing and is retired unsignalled. `unavailable` is the\n * ABSENCE of evidence: `ps` is missing, unanswerable, or printed something no\n * clock can read, so the record is kept for an incarnation that can ask.\n * `unsupported` is a platform that has no such column at all, which falls back\n * to the boot-time comparison alone.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type StartTime =\n /** The operating system reports this start time, in epoch milliseconds. */\n | { readonly _tag: \"started\"; readonly startedAtMs: number }\n /** The pid names no process. */\n | { readonly _tag: \"gone\" }\n /** The question could not be asked on this host. */\n | { readonly _tag: \"unavailable\" }\n /** The platform has no start-time column at all. */\n | { readonly _tag: \"unsupported\" }\n\n/**\n * The operating-system operations reaping needs.\n *\n * It is a seam, not an abstraction: `flows` ships exactly the two\n * implementations below and a test drives the Windows one on a POSIX host,\n * which is the only way that path is ever exercised in this repository.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface System {\n /** Whether a pid names a process that still exists. */\n readonly isAlive: (pid: number) => Liveness\n /** When the process behind a pid started. */\n readonly startedAtMs: (pid: number) => StartTime\n /** The process group THIS process belongs to, or `null` where there are none. */\n readonly ownGroup: () => number | null\n /** When this machine booted, in epoch milliseconds. */\n readonly bootedAtMs: () => number\n /**\n * Whether the numbers in a record name something this platform may signal,\n * checked before any other guard consults them.\n */\n readonly refuseTarget: (record: ProcessLedger.ProcessRecord) => Refusal | undefined\n /** Ends an abandoned process and everything below it. */\n readonly killTree: (record: ProcessLedger.ProcessRecord) => KillOutcome\n}\n\nconst errorCode = (cause: unknown): string | undefined => (cause as { readonly code?: string } | null)?.code\n\nconst liveness = (pid: number): Liveness => {\n try {\n // Signal 0 delivers nothing; it only asks whether the pid is signalable.\n process.kill(pid, 0)\n return \"alive\"\n } catch (cause) {\n // ESRCH is the only answer that means gone. EPERM means the process\n // exists and belongs to another user; anything else is a question this\n // host could not ask, and both keep the record rather than kill on it.\n return errorCode(cause) === \"ESRCH\" ? \"dead\" : \"unknown\"\n }\n}\n\nconst bootedAtMs = (): number => Date.now() - Math.round(uptime() * 1000)\n\n/**\n * The start time `ps` reports for a pid.\n *\n * `lstart` is the one start-time column both BSD (macOS) and procps (Linux)\n * spell the same way, and it prints an absolute time rather than an elapsed\n * one, so the answer does not drift between reading it and comparing it. It is\n * also a LOCALIZED column, so the probe pins `LC_ALL=C` and `TZ=UTC`.\n * Its text has no zone; parsing explicitly as UTC keeps the identity independent\n * of the host runtime's timezone.\n */\nconst startedAtMs = (executable: string) => (pid: number): StartTime => {\n const answer = ps(executable, \"lstart\", pid)\n if (answer._tag === \"gone\") {\n // A nonzero exit is `ps` saying the pid does not exist, but it is also what\n // a `ps` that rejected the column, or one that is not the `ps` this probe\n // expects, says about a pid that is very much alive. The kernel is asked\n // directly before a live process is retired as gone.\n return liveness(pid) === \"dead\" ? answer : { _tag: \"unavailable\" }\n }\n if (answer._tag !== \"printed\") return answer\n const parsed = Date.parse(`${answer.text} UTC`)\n return Number.isNaN(parsed) ? { _tag: \"unavailable\" } : { _tag: \"started\", startedAtMs: parsed }\n}\n\n/**\n * The absolute path the process probe is run from.\n *\n * Never a `PATH` lookup. The inherited environment belongs to whoever started\n * this host, and a planted `ps` that prints a fabricated start time — or none\n * at all — would decide whether a `SIGKILL` is authorized.\n *\n * @category constants\n * @since 1.0.0-rc.0\n */\nexport const defaultPsExecutable = \"/bin/ps\"\n\n/** How long the probe may take before it counts as an answer nobody gave. */\nconst psTimeoutMs = 5000\n\n/**\n * The Windows directory the host was started with, when it names one.\n */\nconst windowsRoot = (): string => {\n const systemRoot = process.env.SystemRoot\n return systemRoot !== undefined && win32.isAbsolute(systemRoot) ? systemRoot : \"C:\\\\Windows\"\n}\n\n/**\n * The system `taskkill`, by absolute path. Windows resolves a bare name from\n * the current directory before `PATH`, so a flow that wrote `taskkill.exe`\n * into the host's working directory would otherwise run as the host.\n */\nconst taskkillExecutable = (): string => win32.join(windowsRoot(), \"System32\", \"taskkill.exe\")\n\n/** A live-release probe has its own short bound within the shutdown deadline. */\nconst cleanupProbeTimeoutMs = 2000\n\n/**\n * One fixed-path snapshot supplies group membership, start identities and our\n * own group together. Only numeric fields and C-locale lstart are read; command\n * text and the caller's PATH never influence signal authority.\n */\nconst psGroupSnapshot = (pgid: number): ProcessCleanup.Snapshot | undefined => {\n const result = spawnSync(defaultPsExecutable, [\"-A\", \"-o\", \"pid=,pgid=,stat=,lstart=\"], {\n encoding: \"utf8\",\n timeout: cleanupProbeTimeoutMs,\n killSignal: \"SIGKILL\",\n env: { LC_ALL: \"C\", TZ: \"UTC\", PATH: \"/usr/bin:/bin\" }\n })\n if (result.error !== undefined || result.signal !== null || result.status !== 0) return undefined\n let own: number | undefined\n const members: Array<ProcessCleanup.Member> = []\n for (const line of result.stdout.trim().split(\"\\n\")) {\n const match = /^\\s*([0-9]+)\\s+([0-9]+)\\s+(\\S+)\\s+(.+)$/.exec(line)\n if (match === null) return undefined\n const pid = Number(match[1])\n const group = Number(match[2])\n if (!Number.isSafeInteger(pid) || !Number.isSafeInteger(group)) return undefined\n if (pid === process.pid) own = group\n if (group !== pgid) continue\n const started = Date.parse(`${match[4]!} UTC`)\n if (Number.isNaN(started)) return undefined\n members.push({ pid, startedAtMs: started, zombie: match[3]!.startsWith(\"Z\") })\n }\n return own === undefined || own <= 0 ? undefined : { ownGroup: own, members }\n}\n\n/**\n * The observation the supervisor polls, from the source that platform has.\n *\n * Linux publishes the whole process table as files under `/proc`, which is\n * where `ps` itself reads it, so the kernel is asked directly. That needs no\n * `procps` in the image, cannot be answered by a planted binary, and costs no\n * fork on a poll that runs every 10ms. A missing `/bin/ps` is not a\n * hypothetical: `procps` is not in `debian:bookworm-slim`, and on Cloud CI run\n * 11727 every spawned target in every task finished its work and then failed\n * cleanup verification with `Unknown: ChildProcess.kill`, because this\n * observation could not be made.\n *\n * Every other POSIX host keeps the `ps` reading, which is the only portable\n * spelling of this question off Linux.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const groupSnapshotFor = (platform: string): (pgid: number) => ProcessCleanup.Snapshot | undefined =>\n platform === \"linux\" ? ProcSnapshot.snapshot(ProcSnapshot.defaultProcRoot) : psGroupSnapshot\n\n/**\n * Whether the kernel reports no process at all in a group.\n *\n * Signal 0 delivers nothing; it only asks the kernel whether the group has a\n * member. `ESRCH` is the one answer that proves the group empty, with no fork\n * and no process table to parse, so it still answers on a loaded host where a\n * `ps` snapshot cannot be taken. A live member, a zombie (macOS answers\n * `EPERM`, Linux succeeds), another user's member or any other error answers\n * `false`, which leaves the question to the snapshot.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const groupVacant = (pgid: number): boolean => {\n // kill(0) and kill(-1) address the caller's group and every process.\n if (!Number.isSafeInteger(pgid) || pgid <= 1) return false\n try {\n process.kill(-pgid, 0)\n return false\n } catch (cause) {\n return errorCode(cause) === \"ESRCH\"\n }\n}\n\n/**\n * Live cleanup for Node and Bun contained spawners.\n *\n * A trusted supervisor remains the group owner after the target exits. It\n * enforces cleanup on target completion, parent loss and explicit release; the\n * target starts only after its owner is durably recorded. Host observations\n * never signal a pid: they only shorten the owner's deadline or verify an empty\n * group before retiring its record. Failed verification retains the record.\n *\n * @category constructors\n * @since 1.0.0\n */\nexport const processLifecycle = ProcessCleanup.lifecycle({\n platform: process.platform,\n snapshot: groupSnapshotFor(process.platform),\n vacant: groupVacant\n})\n\n/**\n * The default grace period for a contained host spawner.\n *\n * The platform is always the running platform; callers cannot describe a\n * Windows ledger identity for a process that actually leads a POSIX group.\n * @category models\n * @since 1.0.0\n */\nexport type SpawnerOptions = Omit<ContainedSpawner.Options, \"platform\">\n\n/**\n * Provides a ledger-backed spawner with this platform's prepared cleanup.\n *\n * Native pipe listeners live until their descriptors close, including writes\n * interrupted by owner loss. The kernel expands pipelines before this private\n * standard-command adapter is called. Windows owners join a native job before\n * activation; POSIX owners enforce their process-group cleanup deadline.\n *\n * The caller supplies the durable or in-memory ledger. This layer records new\n * owners; {@link layer} separately reaps\n * records inherited from a previous host incarnation.\n * @category layers\n * @since 1.0.0\n */\nexport const layerSpawner = (\n options?: SpawnerOptions\n): Layer.Layer<ChildProcessSpawner, never, ProcessLedger.ProcessLedger> => {\n const contained = ContainedSpawner.layer({ graceMs: options?.graceMs, platform: process.platform }, processLifecycle)\n const standard = makeSpawner((command) =>\n PipedProcess.spawn(command as ChildProcess.StandardCommand, undefined, true)\n )\n return Layer.provide(contained, Layer.succeed(ChildProcessSpawner)(standard))\n}\n\n/** A whole number and nothing else, which is all a `pgid` column may be. */\nconst decimal = /^[0-9]+$/\n\n/**\n * One `ps` column for one pid.\n *\n * `printed` is an answer; every other tag is the absence of one. A nonzero exit\n * with no error is `ps` saying the pid does not exist, which is evidence; a\n * spawn that failed, a signal, or a timeout is not.\n */\nconst ps = (\n executable: string,\n column: string,\n pid: number\n): { readonly _tag: \"printed\"; readonly text: string } | StartTime => {\n const result = spawnSync(executable, [\"-o\", `${column}=`, \"-p\", String(pid)], {\n encoding: \"utf8\",\n timeout: psTimeoutMs,\n // `SIGKILL` rather than the default `SIGTERM`, because this call blocks the\n // event loop while a host is being built: `spawnSync` keeps waiting past\n // the deadline for a process that ignores the signal, so a `TERM` the probe\n // can decline is not a deadline at all.\n killSignal: \"SIGKILL\",\n // An empty-ish environment for the same reason the helper in\n // `AtomicFileSystem` gets one: nothing the caller exported may change what\n // this answers. Pin both the column's spelling and its timezone; the parser\n // supplies UTC explicitly because `lstart` does not print a zone.\n env: { LC_ALL: \"C\", TZ: \"UTC\", PATH: \"/usr/bin:/bin\" }\n })\n if (result.error !== undefined || result.signal !== null || result.status === null) {\n return { _tag: \"unavailable\" }\n }\n if (result.status !== 0) return { _tag: \"gone\" }\n const printed = result.stdout.trim()\n return printed === \"\" ? { _tag: \"unavailable\" } : { _tag: \"printed\", text: printed }\n}\n\n/**\n * This process's own process group.\n *\n * Node exposes no `getpgrp`, so the answer comes from `ps`, which both BSD and\n * procps spell `pgid`. A host that cannot read it answers `null` and loses one\n * guard, which is why the pid comparison below is kept as well.\n *\n * The text is required to be one run of decimal digits naming a real group,\n * rather than run through `Number.parseInt`, which reads a PREFIX: `\"12 34\"`,\n * `\"12abc\"`, and `\"0x10\"` all become a number that is not this host's group. A\n * wrong number is worse here than no number at all. It silently passes the\n * own-group comparison in {@link refuse}, and because it is not `null` it also\n * suppresses the `own-group-unknown` refusal that exists to say the comparison\n * could not be made, so the guard neither runs nor reports that it did not run\n * and a `SIGKILL` goes out on it. Anything else answers `null`, which refuses.\n */\nconst ownGroup = (executable: string) => (): number | null => {\n const answer = ps(executable, \"pgid\", process.pid)\n if (answer._tag !== \"printed\") return null\n if (!decimal.test(answer.text)) return null\n const parsed = Number(answer.text)\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null\n}\n\n/**\n * How a {@link System} asks the operating system its questions, and whose\n * identity it must never signal.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface SystemOptions {\n /**\n * The absolute `ps` the identity probe runs. Default\n * {@link defaultPsExecutable}. It is configuration for a host that installs\n * `ps` somewhere else, and the seam the probe's own parsing is driven\n * through; it is never a `PATH` lookup. Windows has no such probe and\n * ignores it.\n */\n readonly psExecutable?: string | undefined\n /** Absolute native helper for Windows process identity queries; never a PATH lookup. */\n readonly processExecutable?: string | undefined\n /**\n * The pid this system must never signal, nor signal the group of. Default\n * `process.pid`. {@link Options.ownerPid} is the same identity at the sweep\n * level; this one is what {@link System.killTree} enforces on its own,\n * because that function is exported and a caller can reach it without going\n * through {@link reap}.\n */\n readonly ownerPid?: number | undefined\n}\n\n/**\n * Whether a durable record names a POSIX process group this host may signal.\n *\n * `process.kill(-pgid, ...)` turns the stored number into a target directly, so\n * every value that is not a real foreign group has to be refused before it gets\n * there: `0` signals THIS process's group, a negative value stops naming a\n * group at all and names a single pid, and a `pgid` that differs from `pid`\n * describes a child that does not lead the group it claims —\n * `ContainedSpawner.groupOf` writes `pgid === pid` for every detached POSIX\n * child, so anything else is a record no writer in this repository produced.\n */\nconst refusePosixTarget = (record: ProcessLedger.ProcessRecord): Refusal | undefined => {\n if (record.pgid === null) return \"no-group\"\n if (!Number.isSafeInteger(record.pid) || record.pid <= 1) return \"invalid-record\"\n if (!Number.isSafeInteger(record.pgid) || record.pgid <= 1) return \"invalid-record\"\n return record.pgid === record.pid ? undefined : \"invalid-record\"\n}\n\n/**\n * Whether a durable record names a Windows process tree this host may signal.\n *\n * Windows has no process groups, so `ContainedSpawner.groupOf` records `null`\n * there and `taskkill /T` walks the tree from the pid instead. A win32 record\n * carrying a number is therefore a record some other platform wrote.\n */\nconst refuseWindowsTarget = (record: ProcessLedger.ProcessRecord): Refusal | undefined => {\n if (record.pgid !== null) return \"invalid-record\"\n return Number.isSafeInteger(record.pid) && record.pid > 1 && record.pid <= 0xffff_ffff ? undefined : \"invalid-record\"\n}\n\n/**\n * Reaping on a POSIX host, with the identity probe configured.\n *\n * The group is killed outright rather than asked politely first. `SIGTERM`\n * buys a graceful shutdown only when someone is left to wait for it, and the\n * incarnation that owned these processes is by definition gone.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const posixSystemWith = (options?: SystemOptions): System =>\n posixSystemFrom({\n startedAtMs: startedAtMs(options?.psExecutable ?? defaultPsExecutable),\n ownGroup: ownGroup(options?.psExecutable ?? defaultPsExecutable),\n bootedAtMs\n }, options?.ownerPid ?? process.pid)\n\n/**\n * Where a Linux {@link System} reads the process table, and whose identity it\n * must never signal.\n *\n * @category models\n * @since 1.0.0-rc.1\n */\nexport interface ProcSystemOptions {\n /** The `/proc` mount the probes read. Default `/proc`. */\n readonly procRoot?: string | undefined\n /** The pid this system must never signal, nor signal the group of. Default `process.pid`. */\n readonly ownerPid?: number | undefined\n}\n\n/**\n * Reaping on Linux, with every identity question read from `/proc` rather\n * than from `ps`.\n *\n * `procps` is not in `debian:bookworm-slim` (Cloud CI run 11727), and a\n * `ps`-based reaper on such a host can read neither its own group nor any\n * start time, so it refuses every orphan as `own-group-unknown` on every\n * restart. The live-cleanup observation ({@link groupSnapshotFor}) already\n * reads `/proc` for the same reason; this is the crash-recovery half.\n *\n * A pid with no `/proc/<pid>/stat` is `gone` only when the kernel also says so,\n * because a `hidepid` mount hides another user's live process the same way.\n *\n * @category constructors\n * @since 1.0.0-rc.1\n */\nexport const procSystemWith = (options?: ProcSystemOptions): System => {\n const root = options?.procRoot ?? ProcSnapshot.defaultProcRoot\n const readStart = ProcSnapshot.startedAtMs(root)\n return posixSystemFrom({\n startedAtMs: (pid) => {\n const answer = readStart(pid)\n return answer._tag === \"gone\" && liveness(pid) !== \"dead\" ? { _tag: \"unavailable\" } : answer\n },\n ownGroup: ProcSnapshot.ownGroup(root),\n bootedAtMs: () => ProcSnapshot.bootMs(root) ?? bootedAtMs()\n }, options?.ownerPid ?? process.pid)\n}\n\n/** The POSIX kill path over whichever probes the platform answers with. */\nconst posixSystemFrom = (\n probes: Pick<System, \"startedAtMs\" | \"ownGroup\" | \"bootedAtMs\">,\n ownerPid: number\n): System => {\n const readOwnGroup = probes.ownGroup\n return {\n isAlive: liveness,\n startedAtMs: probes.startedAtMs,\n ownGroup: readOwnGroup,\n bootedAtMs: probes.bootedAtMs,\n refuseTarget: refusePosixTarget,\n killTree: (record) => {\n // Repeated here and not only in `refuse`: this function is exported, and\n // the negation below is the one place a stored number becomes a signal.\n if (refusePosixTarget(record) !== undefined) return \"failed\"\n // The host's own identity, repeated for the same reason. `refuse` holds\n // one `ownGroup` reading for the whole sweep; a caller that reaches this\n // function directly has made no such reading, and `process.kill(-pgid)`\n // does not care which way the number arrived. A group that cannot be\n // read is a comparison that did not happen, so nothing is signalled.\n if (record.pid === ownerPid || record.pgid === ownerPid) return \"failed\"\n const group = readOwnGroup()\n if (group === null || record.pid === group || record.pgid === group) return \"failed\"\n try {\n process.kill(-(record.pgid as number), \"SIGKILL\")\n return \"signalled\"\n } catch (cause) {\n // The group settled between the liveness check and the signal: the end\n // state is the one that was wanted. Anything else is a kill that did NOT\n // happen, and saying so is what gets the record tried again.\n return errorCode(cause) === \"ESRCH\" ? \"already-gone\" : \"failed\"\n }\n }\n }\n}\n\n/**\n * Reaping on a POSIX host: one `SIGKILL` to the abandoned process group, with\n * the identity probe at {@link defaultPsExecutable}.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const posixSystem: System = posixSystemWith()\n\n/**\n * Reaping on Windows, with the identity the sweep must never signal\n * configured.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const windowsSystemWith = (options?: SystemOptions): System => {\n const ownerPid = options?.ownerPid ?? process.pid\n const startedAtMs = (pid: number): StartTime => {\n if (!Number.isSafeInteger(pid) || pid <= 1 || pid > 0xffff_ffff) return { _tag: \"unavailable\" }\n try {\n const configured = options?.processExecutable ?? process.env.SMITHERS_WORKSPACE_JJ_EXPORT_BINARY\n const executable = configured === undefined\n ? resolveDefaultExecutable(packageRoot, undefined)\n : usableExecutable(configured, undefined)\n const result = spawnSync(executable, [\"--process-info\", String(pid)], {\n cwd: parse(process.execPath).root,\n env: {},\n encoding: \"utf8\",\n timeout: psTimeoutMs,\n killSignal: \"SIGKILL\",\n maxBuffer: 4096\n })\n if (result.error !== undefined || result.signal !== null || result.status !== 0) return { _tag: \"unavailable\" }\n const value = JSON.parse(result.stdout) as { readonly status?: unknown; readonly startedAtMs?: unknown } | null\n if (value?.status === \"gone\") return { _tag: \"gone\" }\n return value?.status === \"started\" && typeof value.startedAtMs === \"number\" &&\n Number.isSafeInteger(value.startedAtMs) && value.startedAtMs >= 0\n ? { _tag: \"started\", startedAtMs: value.startedAtMs }\n : { _tag: \"unavailable\" }\n } catch {\n return { _tag: \"unavailable\" }\n }\n }\n return {\n isAlive: liveness,\n startedAtMs,\n ownGroup: () => null,\n bootedAtMs,\n refuseTarget: (record) => record.pid === ownerPid ? \"own-group\" : refuseWindowsTarget(record),\n killTree: (record) => {\n if (refuseWindowsTarget(record) !== undefined) return \"failed\"\n // `taskkill /T` walks the tree DOWN from the pid it is given, so a record\n // naming this host takes the host and everything it started with it.\n if (record.pid === ownerPid) return \"failed\"\n const result = spawnSync(taskkillExecutable(), [\"/pid\", String(record.pid), \"/T\", \"/F\"], {\n // An inert cwd and only the variable Windows system binaries need.\n cwd: parse(process.execPath).root,\n env: { SystemRoot: windowsRoot() },\n stdio: \"ignore\"\n })\n if (result.error !== undefined) return \"failed\"\n // 128 is `taskkill`'s \"no such process\", which is the same end state a\n // successful kill produces.\n if (result.status === 0) return \"signalled\"\n return result.status === 128 ? \"already-gone\" : \"failed\"\n }\n }\n}\n\n/**\n * Reaping on Windows, which has no process groups: `taskkill /T /F` by pid.\n *\n * **Windows is outside the 1.0.0-rc.0 support contract**\n * (`docs/pages/installation.md`). Full Windows process containment remains\n * under verification. It is kept — and reachable through {@link reap} rather than only\n * by calling it directly — because a reaper that silently retired every win32\n * record would be the \"excluded feature that appears to work partially\" the\n * release policy forbids. Treat it as unsupported best-effort.\n *\n * The packaged native helper reads creation time from a pinned process handle.\n * A missing helper, malformed reply, or denied query keeps the durable record\n * for retry. Windows has no process groups, so own-group refusal uses the pid.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const windowsSystem: System = windowsSystemWith()\n\n/**\n * Reaping on Linux from the kernel's own `/proc`.\n *\n * @category constructors\n * @since 1.0.0-rc.1\n */\nexport const procSystem: System = procSystemWith()\n\n/**\n * Selects the reaping implementation a platform needs.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const systemFor = (platform: string): System =>\n platform === \"win32\" ? windowsSystem : platform === \"linux\" ? procSystem : posixSystem\n\n/**\n * How far apart a recorded start time and the operating system's may be and\n * still describe the same process.\n *\n * `lstart` has one-second granularity and the ledger writes its record just\n * after the spawn returns, so the two never agree exactly. Two seconds covers\n * the gap; a pid the operating system handed to somebody else is minutes or\n * hours away from it, not milliseconds.\n *\n * @category models\n * @since 0.1.0\n */\nexport const identityToleranceMs = 2000\n\n/**\n * Reaper configuration.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Options {\n /** The pid this host must never signal a group for. Default `process.pid`. */\n readonly ownerPid?: number | undefined\n /** The operating-system seam. Default {@link systemFor} of `process.platform`. */\n readonly system?: System | undefined\n}\n\n/**\n * Why a record was not signalled.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Refusal =\n /** The incarnation that started it is still running and will contain it. */\n | \"owner-alive\"\n /** It shared its owner's process group, so there is no group to signal. */\n | \"no-group\"\n /** It named this host's own process group or pid. */\n | \"own-group\"\n /** This host could not read its OWN process group, so it cannot rule that out. */\n | \"own-group-unknown\"\n /** Its numbers do not name anything this platform may signal. */\n | \"invalid-record\"\n /** It was written before this machine booted, so the pid space is not the same. */\n | \"pre-boot\"\n /** The pid it names does not exist, so there is no identity to confirm. */\n | \"process-gone\"\n /** The pid exists but did not start when the record says it did. */\n | \"identity-mismatch\"\n /** This host could not ask when the pid started, so it must not signal it. */\n | \"identity-unverified\"\n /** The signal was refused, so the record stays for the next incarnation. */\n | \"kill-failed\"\n\n/**\n * The refusals that leave a record inherited instead of retiring it.\n *\n * A refusal is final when the operating system has moved on from the number:\n * saying so in the journal is what stops every later incarnation re-examining\n * it. These three are not final. `owner-alive` means the incarnation that owns\n * the record will contain its own children; `identity-unverified` and\n * `own-group-unknown` mean this host could not ask a question at all — a host\n * that CAN ask has to get the chance.\n */\nconst retained: ReadonlySet<Refusal> = new Set<Refusal>([\n \"owner-alive\",\n \"identity-unverified\",\n \"own-group-unknown\"\n])\n\n/**\n * One record, and what the reaper decided about it.\n *\n * The two outcomes are a union rather than one shape with an optional field so\n * that `killed` narrows the reason: after `if (!entry.killed)` the\n * {@link Refusal} is there to read, and a killed record cannot be built\n * carrying a reason it never had. The runtime objects are unchanged — a killed\n * entry simply omits `refusal`.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Reaped =\n | {\n readonly record: ProcessLedger.ProcessRecord\n readonly killed: true\n /** Never present when `killed` is `true`. */\n readonly refusal?: never\n }\n | {\n readonly record: ProcessLedger.ProcessRecord\n readonly killed: false\n /** Present exactly when `killed` is `false`. */\n readonly refusal: Refusal\n }\n\n/** The identity half of the decision, split out because it reads as a list. */\nconst refuseOnIdentity = (\n system: System,\n record: ProcessLedger.ProcessRecord,\n bootMs: number\n): Refusal | undefined => {\n // A record older than this boot names a pid from a pid space that no longer\n // exists. The tolerance points BACKWARDS from the boot instant on purpose:\n // `uptime` is second-granular, so a record written moments after boot could\n // otherwise be read as predating it, and refusing to kill is the safe way to\n // be wrong.\n //\n // The consequence is a narrow, deliberate leak, and it is a leak rather than\n // a retry: `reap` retires a `pre-boot` refusal through `ledger.skipped`, so a\n // group spawned within `identityToleranceMs` of the computed boot instant is\n // never reaped by any later incarnation either. That is the price of refusing\n // to kill on an instant `uptime` can only place to the nearest second.\n if (record.startedAtMs < bootMs + identityToleranceMs) return \"pre-boot\"\n const started = system.startedAtMs(record.pid)\n // A platform with no start-time column at all has already been checked\n // against this boot, which is the whole of its documented weaker guarantee.\n if (started._tag === \"unsupported\") return undefined\n if (started._tag === \"gone\") return \"process-gone\"\n if (started._tag === \"unavailable\") return \"identity-unverified\"\n return Math.abs(started.startedAtMs - record.startedAtMs) <= identityToleranceMs\n ? undefined\n : \"identity-mismatch\"\n}\n\n/** Everything the reaper checks before it is willing to signal a record. */\nconst refuse = (\n system: System,\n record: ProcessLedger.ProcessRecord,\n ownerPid: number,\n ownGroup: number | null,\n bootMs: number\n): Refusal | undefined => {\n // The host's own identity comes first, before the platform is consulted at\n // all: a record naming this process is refused on every platform, whatever\n // shape its numbers have.\n if (record.pgid === ownerPid || record.pid === ownerPid) return \"own-group\"\n if (ownGroup !== null && (record.pgid === ownGroup || record.pid === ownGroup)) return \"own-group\"\n const target = system.refuseTarget(record)\n if (target !== undefined) return target\n // A record naming a group can only be cleared of naming THIS host's group by\n // reading that group. When the probe cannot answer, the comparison above was\n // not made rather than made and passed, so the record is kept instead of\n // signalled on a guard that did not run.\n if (record.pgid !== null && ownGroup === null) return \"own-group-unknown\"\n if (system.isAlive(record.ownerPid) !== \"dead\") return \"owner-alive\"\n return refuseOnIdentity(system, record, bootMs)\n}\n\n/**\n * Kills the process groups a previous incarnation of this host abandoned.\n *\n * Returns one entry per inherited record so a caller can log what it decided;\n * `killed: false` carries the {@link Refusal} that produced it. Fails with\n * {@link ProcessLedger.ProcessLedgerReplayError} when the inherited history\n * cannot be read to its end: nothing is signalled or retired, so the next\n * sweep inherits every record again.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const reap = (\n options?: Options\n): Effect.Effect<ReadonlyArray<Reaped>, ProcessLedger.ProcessLedgerReplayError, ProcessLedger.ProcessLedger> =>\n Effect.gen(function*() {\n const ledger = yield* ProcessLedger.ProcessLedger\n const system = options?.system ?? systemFor(process.platform)\n const ownerPid = options?.ownerPid ?? process.pid\n const ownGroup = system.ownGroup()\n const bootMs = system.bootedAtMs()\n const orphans = yield* ledger.orphans\n const decided: Array<Reaped> = []\n for (const record of orphans) {\n const refusal = refuse(system, record, ownerPid, ownGroup, bootMs)\n if (refusal === undefined) {\n const outcome = system.killTree(record)\n if (outcome === \"failed\") {\n // Nothing was killed, so nothing is retired: leaving the record\n // inherited is what makes the next incarnation try again.\n decided.push({ record, killed: false, refusal: \"kill-failed\" })\n continue\n }\n yield* retire(ledger.reaped(record), record.pid, \"reaped\")\n decided.push({ record, killed: true })\n continue\n }\n // A retained refusal is not this host's to retire; every other refusal is\n // final and says so in the journal.\n if (!retained.has(refusal)) {\n yield* retire(ledger.skipped(record, refusal), record.pid, \"reap-skipped\")\n }\n decided.push({ record, killed: false, refusal })\n }\n return decided\n })\n\n/**\n * Writes one ledger retirement, logging rather than failing the sweep.\n *\n * A retirement that does not commit is not a lost kill: the process is already\n * dead and the record stays inherited, so the next incarnation reads it, finds\n * the pid gone, and retires it then. Failing the whole sweep over it would\n * take the host down for a bookkeeping write.\n */\nconst retire = (\n write: Effect.Effect<void, unknown>,\n pid: number,\n what: string\n): Effect.Effect<void> =>\n write.pipe(\n Effect.catch((error) => Effect.logWarning(`process reaper could not journal ${what} for ${pid}`, error))\n )\n\n/**\n * Refusals that leave a dead incarnation's process running with no live owner\n * to contain it: the host could not ask, or its signal failed.\n */\nconst unreaped: ReadonlySet<Refusal> = new Set<Refusal>([\"identity-unverified\", \"own-group-unknown\", \"kill-failed\"])\n\n/**\n * Counter over inherited records the reaper did not kill, with a `refusal`\n * attribute naming why.\n *\n * @category metrics\n * @since 1.0.0-rc.1\n */\nexport const refusals = Metric.counter(\"flows_process_reaper_refusals\", {\n description: \"Inherited process records the reaper did not kill, by refusal\"\n})\n\n/**\n * Reports one sweep: a counter update per refusal and one summary line. The\n * line is a warning when a record stays inherited (a retained refusal) or a\n * signal failed, because either leaves a crashed incarnation's processes\n * running with nothing else to say so.\n *\n * @category layers\n * @since 1.0.0-rc.1\n */\nexport const report = (decided: ReadonlyArray<Reaped>): Effect.Effect<void> =>\n Effect.gen(function*() {\n if (decided.length === 0) return\n const counts: Partial<Record<Refusal, number>> = {}\n let killed = 0\n for (const entry of decided) {\n if (entry.killed) {\n killed += 1\n continue\n }\n counts[entry.refusal] = (counts[entry.refusal] ?? 0) + 1\n }\n for (const [refusal, count] of Object.entries(counts)) {\n yield* Metric.update(Metric.withAttributes(refusals, { refusal }), count)\n }\n const annotations = { killed, ...counts }\n const alarming = decided.some((entry) => !entry.killed && unreaped.has(entry.refusal))\n const line = \"process reaper swept inherited records\"\n yield* (alarming ? Effect.logWarning(line) : Effect.logInfo(line)).pipe(Effect.annotateLogs(annotations))\n })\n\n/**\n * Runs {@link reap} once while the layer is built.\n *\n * Compose it into a host layer so standing a host up is also what cleans up\n * after the incarnation that crashed. A history that cannot be read refuses\n * the sweep with an error log and leaves every record inherited; the host\n * still starts, because the processes it will spawn are recorded and\n * contained regardless. Every decision is {@link report}ed.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer = (options?: Options): Layer.Layer<never, never, ProcessLedger.ProcessLedger> =>\n Layer.effectDiscard(\n reap(options).pipe(\n Effect.flatMap(report),\n Effect.catchTag(\n \"@smthrs/kernel/ProcessLedgerReplayError\",\n (error) => Effect.logError(\"process reaper refused to sweep: the ledger history is incomplete\", error)\n )\n )\n )\n"]}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
6
|
import type * as PlatformError from "effect/PlatformError";
|
|
7
|
+
import * as ChildProcess from "effect/process/ChildProcess";
|
|
8
|
+
import type { ChildProcessHandle } from "effect/process/ChildProcessSpawner";
|
|
7
9
|
import * as Scope from "effect/Scope";
|
|
8
|
-
import * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
9
|
-
import type { ChildProcessHandle } from "effect/unstable/process/ChildProcessSpawner";
|
|
10
10
|
/**
|
|
11
11
|
* One command's literal argv, environment, pipes and termination policy.
|
|
12
12
|
* @category models
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScopedProcess.d.ts","sourceRoot":"","sources":["../../src/ScopedProcess.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,KAAK,aAAa,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ScopedProcess.d.ts","sourceRoot":"","sources":["../../src/ScopedProcess.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,KAAK,aAAa,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,YAAY,MAAM,6BAA6B,CAAA;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AAC5E,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC;;;;GAIG;AACH,MAAM,WAAW,OAAQ,SAAQ,YAAY,CAAC,WAAW;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;IACjD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,CAAA;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAA;IAC9C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACvD,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC3C;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAO,SAAQ,kBAAkB;IAChD,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,KAAK,GAChB,SAAS,OAAO,KACf,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,aAAa,EAAE,KAAK,CAAC,KAAK,CAqC9D,CAAA;AAEH;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,MAAM,GAAG,IAAI,CAAA;CAC5C;AAED;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GAAI,QAAQ,kBAAkB,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,aAAa,CAUlG,CAAA"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
6
|
import * as Exit from "effect/Exit";
|
|
7
|
+
import * as ChildProcess from "effect/process/ChildProcess";
|
|
7
8
|
import * as Scope from "effect/Scope";
|
|
8
|
-
import * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
9
9
|
import * as PipedProcess from "./internal/PipedProcess.js";
|
|
10
10
|
import { targetPidOf } from "./internal/ProcessSupervisor.js";
|
|
11
11
|
import * as ProcessReaper from "./ProcessReaper.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScopedProcess.js","sourceRoot":"","sources":["../../src/ScopedProcess.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AAEnC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ScopedProcess.js","sourceRoot":"","sources":["../../src/ScopedProcess.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Scoped transient commands with the host's process-tree cleanup policy.\n * @since 1.0.0\n */\n\nimport * as Effect from \"effect/Effect\"\nimport * as Exit from \"effect/Exit\"\nimport type * as PlatformError from \"effect/PlatformError\"\nimport * as ChildProcess from \"effect/process/ChildProcess\"\nimport type { ChildProcessHandle } from \"effect/process/ChildProcessSpawner\"\nimport * as Scope from \"effect/Scope\"\nimport * as PipedProcess from \"./internal/PipedProcess.ts\"\nimport { targetPidOf } from \"./internal/ProcessSupervisor.ts\"\nimport * as ProcessReaper from \"./ProcessReaper.ts\"\n\n/**\n * One command's literal argv, environment, pipes and termination policy.\n * @category models\n * @since 1.0.0\n */\nexport interface Options extends ChildProcess.KillOptions {\n readonly command: string\n readonly args?: ReadonlyArray<string> | undefined\n readonly cwd?: string | undefined\n readonly env?: Readonly<Record<string, string | undefined>> | undefined\n readonly stdin?: \"ignore\" | \"pipe\" | undefined\n readonly windowsVerbatimArguments?: boolean | undefined\n readonly windowsHide?: boolean | undefined\n}\n\n/**\n * The managed owner identity and the actual target identity are distinct.\n * @category models\n * @since 1.0.0\n */\nexport interface Handle extends ChildProcessHandle {\n /** The native target's pid, for diagnostics and service liveness. */\n readonly targetPid: number\n}\n\n/**\n * Starts a pipe-based command and contains its lifetime inside the caller's\n * scope. The returned pid names the live supervisor; exitCode reports\n * the actual target. The private parent connection stops the tree on host loss,\n * and the supervisor's group guardian stops the group on supervisor loss.\n * Transient commands have no durable ledger; durable hosts use NodeHost instead.\n *\n * Unconsumed output stays in bounded native buffers until it is read or the\n * scope closes. Consume stdout and stderr alongside exitCode: a command can\n * block when an unread pipe is full.\n *\n * Failed startup closes its child scope before returning an error, even when\n * the caller catches that error and retains the surrounding scope.\n * @category constructors\n * @since 1.0.0\n */\nexport const spawn = (\n options: Options\n): Effect.Effect<Handle, PlatformError.PlatformError, Scope.Scope> =>\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function*() {\n const scope = yield* Scope.fork(yield* Scope.Scope)\n const command = ChildProcess.make(options.command, [...options.args ?? []], {\n cwd: options.cwd,\n env: options.env,\n extendEnv: false,\n stdin: options.stdin ?? \"ignore\",\n stdout: \"pipe\",\n stderr: \"pipe\",\n detached: process.platform !== \"win32\",\n killSignal: options.killSignal ?? \"SIGTERM\",\n forceKillAfter: options.forceKillAfter ?? 2000,\n windowsHide: options.windowsHide ?? true,\n // Preserve the target's native option through the private protocol.\n ...{ windowsVerbatimArguments: options.windowsVerbatimArguments }\n })\n return yield* restore(\n Effect.gen(function*() {\n const prepared = yield* ProcessReaper.processLifecycle(\n command,\n (command) => PipedProcess.spawn(command, false, true)\n )\n yield* prepared.activate\n const targetPid = targetPidOf(prepared.handle)\n if (targetPid === undefined) {\n return yield* Effect.fail(\n PipedProcess.failure(\"spawn\", new Error(\"The supervisor did not identify its target\"))\n )\n }\n return Object.defineProperty(prepared.handle, \"targetPid\", { value: targetPid, enumerable: true }) as Handle\n }).pipe(Scope.provide(scope))\n ).pipe(\n Effect.onError((cause) => Scope.close(scope, Exit.failCause(cause)))\n )\n })\n )\n\n/**\n * The native command's result, preserving a signal instead of inventing a code.\n * @category models\n * @since 1.0.0\n */\nexport interface Status {\n readonly code: number | null\n readonly signal: ChildProcess.Signal | null\n}\n\n/**\n * Reads the target's result. Failures without an actual target signal remain\n * platform failures, including loss of the supervisor before a result arrives.\n * @category execution\n * @since 1.0.0\n */\nexport const status = (handle: ChildProcessHandle): Effect.Effect<Status, PlatformError.PlatformError> =>\n handle.exitCode.pipe(\n Effect.map((code): Status => ({ code, signal: null })),\n Effect.catch((error) => {\n const cause = \"cause\" in error.reason ? error.reason.cause : undefined\n const signal = typeof cause === \"object\" && cause !== null && \"signal\" in cause ? cause.signal : undefined\n return typeof signal === \"string\" && /^SIG[A-Z0-9]+$/.test(signal)\n ? Effect.succeed({ code: null, signal: signal as ChildProcess.Signal })\n : Effect.fail(error)\n })\n )\n"]}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
6
|
import * as PlatformError from "effect/PlatformError";
|
|
7
|
+
import * as ChildProcess from "effect/process/ChildProcess";
|
|
8
|
+
import { type ChildProcessHandle } from "effect/process/ChildProcessSpawner";
|
|
7
9
|
import type * as Scope from "effect/Scope";
|
|
8
|
-
import * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
9
|
-
import { type ChildProcessHandle } from "effect/unstable/process/ChildProcessSpawner";
|
|
10
10
|
/**
|
|
11
11
|
* Windows owners receive caller streams above the reserved CRT standard slots.
|
|
12
12
|
* @private
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PipedProcess.d.ts","sourceRoot":"","sources":["../../../src/internal/PipedProcess.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"PipedProcess.d.ts","sourceRoot":"","sources":["../../../src/internal/PipedProcess.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,YAAY,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,KAAK,kBAAkB,EAAmC,MAAM,oCAAoC,CAAA;AAC7G,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAA;AAQ1C;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,kBAAkB,KAAG,aAAa,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,SAChE,CAAA;AAa9B;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAAI,QAAQ,MAAM,EAAE,OAAO,OAAO,KAAG,aAAa,CAAC,aAUtE,CAAA;AAyCD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,KAAK,GAChB,SAAS,YAAY,CAAC,eAAe,EACrC,0BAA0B,OAAO,GAAG,SAAS,EAC7C,eAAa,KACZ,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,aAAa,CAAC,aAAa,EAAE,KAAK,CAAC,KAAK,CAsPzE,CAAA"}
|
|
@@ -6,10 +6,10 @@ import * as NodeSink from "../../vendor/node/NodeSink.js";
|
|
|
6
6
|
import * as NodeStream from "../../vendor/node/NodeStream.js";
|
|
7
7
|
import * as Effect from "effect/Effect";
|
|
8
8
|
import * as PlatformError from "effect/PlatformError";
|
|
9
|
+
import * as ChildProcess from "effect/process/ChildProcess";
|
|
10
|
+
import { ExitCode, makeHandle, ProcessId } from "effect/process/ChildProcessSpawner";
|
|
9
11
|
import * as Sink from "effect/Sink";
|
|
10
12
|
import * as Stream from "effect/Stream";
|
|
11
|
-
import * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
12
|
-
import { ExitCode, makeHandle, ProcessId } from "effect/unstable/process/ChildProcessSpawner";
|
|
13
13
|
import * as Native from "node:child_process";
|
|
14
14
|
import { NativeProcessError } from "./ProcessFault.js";
|
|
15
15
|
const ownerDescriptors = new WeakMap();
|