@smthrs/platform-node 0.0.0-stage → 1.0.0-rc.4

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.
Files changed (442) hide show
  1. package/CHANGELOG.md +211 -0
  2. package/LICENSE +21 -0
  3. package/README.md +165 -2
  4. package/bin/darwin-arm64/smithers-jj-export +0 -0
  5. package/bin/darwin-x64/smithers-jj-export +0 -0
  6. package/bin/linux-arm64/smithers-jj-export +0 -0
  7. package/bin/linux-x64/smithers-jj-export +4 -0
  8. package/bin/win32-x64/smithers-jj-export.exe +0 -0
  9. package/dist/cjs/AtomicFileSystem.d.ts +147 -0
  10. package/dist/cjs/AtomicFileSystem.d.ts.map +1 -0
  11. package/dist/cjs/AtomicFileSystem.js +234 -0
  12. package/dist/cjs/AtomicFileSystem.js.map +7 -0
  13. package/dist/cjs/EgressHttpClient.d.ts +106 -0
  14. package/dist/cjs/EgressHttpClient.d.ts.map +1 -0
  15. package/dist/cjs/EgressHttpClient.js +202 -0
  16. package/dist/cjs/EgressHttpClient.js.map +7 -0
  17. package/dist/cjs/HostLiveness.d.ts +81 -0
  18. package/dist/cjs/HostLiveness.d.ts.map +1 -0
  19. package/dist/cjs/HostLiveness.js +49 -0
  20. package/dist/cjs/HostLiveness.js.map +7 -0
  21. package/dist/cjs/NodeHost.d.ts +145 -0
  22. package/dist/cjs/NodeHost.d.ts.map +1 -0
  23. package/dist/cjs/NodeHost.js +128 -0
  24. package/dist/cjs/NodeHost.js.map +7 -0
  25. package/dist/cjs/ProcessConfinement.d.ts +61 -0
  26. package/dist/cjs/ProcessConfinement.d.ts.map +1 -0
  27. package/dist/cjs/ProcessConfinement.js +292 -0
  28. package/dist/cjs/ProcessConfinement.js.map +7 -0
  29. package/dist/cjs/ProcessReaper.d.ts +457 -0
  30. package/dist/cjs/ProcessReaper.d.ts.map +1 -0
  31. package/dist/cjs/ProcessReaper.js +349 -0
  32. package/dist/cjs/ProcessReaper.js.map +7 -0
  33. package/dist/cjs/ProcessSandbox.d.ts +391 -0
  34. package/dist/cjs/ProcessSandbox.d.ts.map +1 -0
  35. package/dist/cjs/ProcessSandbox.js +774 -0
  36. package/dist/cjs/ProcessSandbox.js.map +7 -0
  37. package/dist/cjs/ScopedProcess.d.ts +66 -0
  38. package/dist/cjs/ScopedProcess.d.ts.map +1 -0
  39. package/dist/cjs/ScopedProcess.js +87 -0
  40. package/dist/cjs/ScopedProcess.js.map +7 -0
  41. package/dist/cjs/index.d.ts +38 -0
  42. package/dist/cjs/index.d.ts.map +1 -0
  43. package/dist/cjs/index.js +47 -0
  44. package/dist/cjs/index.js.map +7 -0
  45. package/dist/cjs/internal/AtomicFileSystemExecutable.d.ts +61 -0
  46. package/dist/cjs/internal/AtomicFileSystemExecutable.d.ts.map +1 -0
  47. package/dist/cjs/internal/AtomicFileSystemExecutable.js +250 -0
  48. package/dist/cjs/internal/AtomicFileSystemExecutable.js.map +7 -0
  49. package/dist/cjs/internal/AtomicFileSystemProtocol.d.ts +78 -0
  50. package/dist/cjs/internal/AtomicFileSystemProtocol.d.ts.map +1 -0
  51. package/dist/cjs/internal/AtomicFileSystemProtocol.js +382 -0
  52. package/dist/cjs/internal/AtomicFileSystemProtocol.js.map +7 -0
  53. package/dist/cjs/internal/AtomicFileSystemTransport.d.ts +44 -0
  54. package/dist/cjs/internal/AtomicFileSystemTransport.d.ts.map +1 -0
  55. package/dist/cjs/internal/AtomicFileSystemTransport.js +197 -0
  56. package/dist/cjs/internal/AtomicFileSystemTransport.js.map +7 -0
  57. package/dist/cjs/internal/AtomicHelperError.d.ts +35 -0
  58. package/dist/cjs/internal/AtomicHelperError.d.ts.map +1 -0
  59. package/dist/cjs/internal/AtomicHelperError.js +45 -0
  60. package/dist/cjs/internal/AtomicHelperError.js.map +7 -0
  61. package/dist/cjs/internal/AtomicHelperFault.d.ts +59 -0
  62. package/dist/cjs/internal/AtomicHelperFault.d.ts.map +1 -0
  63. package/dist/cjs/internal/AtomicHelperFault.js +66 -0
  64. package/dist/cjs/internal/AtomicHelperFault.js.map +7 -0
  65. package/dist/cjs/internal/PipedProcess.d.ts +35 -0
  66. package/dist/cjs/internal/PipedProcess.d.ts.map +1 -0
  67. package/dist/cjs/internal/PipedProcess.js +309 -0
  68. package/dist/cjs/internal/PipedProcess.js.map +7 -0
  69. package/dist/cjs/internal/ProcSnapshot.d.ts +85 -0
  70. package/dist/cjs/internal/ProcSnapshot.d.ts.map +1 -0
  71. package/dist/cjs/internal/ProcSnapshot.js +123 -0
  72. package/dist/cjs/internal/ProcSnapshot.js.map +7 -0
  73. package/dist/cjs/internal/ProcessCleanup.d.ts +64 -0
  74. package/dist/cjs/internal/ProcessCleanup.d.ts.map +1 -0
  75. package/dist/cjs/internal/ProcessCleanup.js +62 -0
  76. package/dist/cjs/internal/ProcessCleanup.js.map +7 -0
  77. package/dist/cjs/internal/ProcessCleanupPolicyError.d.ts +30 -0
  78. package/dist/cjs/internal/ProcessCleanupPolicyError.d.ts.map +1 -0
  79. package/dist/cjs/internal/ProcessCleanupPolicyError.js +33 -0
  80. package/dist/cjs/internal/ProcessCleanupPolicyError.js.map +7 -0
  81. package/dist/cjs/internal/ProcessFault.d.ts +63 -0
  82. package/dist/cjs/internal/ProcessFault.d.ts.map +1 -0
  83. package/dist/cjs/internal/ProcessFault.js +63 -0
  84. package/dist/cjs/internal/ProcessFault.js.map +7 -0
  85. package/dist/cjs/internal/ProcessSupervisor.d.ts +143 -0
  86. package/dist/cjs/internal/ProcessSupervisor.d.ts.map +1 -0
  87. package/dist/cjs/internal/ProcessSupervisor.js +685 -0
  88. package/dist/cjs/internal/ProcessSupervisor.js.map +7 -0
  89. package/dist/cjs/internal/SupervisorProgram.d.ts +9 -0
  90. package/dist/cjs/internal/SupervisorProgram.d.ts.map +1 -0
  91. package/dist/cjs/internal/SupervisorProgram.js +326 -0
  92. package/dist/cjs/internal/SupervisorProgram.js.map +7 -0
  93. package/dist/cjs/internal/WindowsProcessJob.d.ts +39 -0
  94. package/dist/cjs/internal/WindowsProcessJob.d.ts.map +1 -0
  95. package/dist/cjs/internal/WindowsProcessJob.js +113 -0
  96. package/dist/cjs/internal/WindowsProcessJob.js.map +7 -0
  97. package/dist/cjs/package.json +1 -0
  98. package/dist/esm/AtomicFileSystem.d.ts +147 -0
  99. package/dist/esm/AtomicFileSystem.d.ts.map +1 -0
  100. package/dist/esm/AtomicFileSystem.js +290 -0
  101. package/dist/esm/AtomicFileSystem.js.map +1 -0
  102. package/dist/esm/EgressHttpClient.d.ts +106 -0
  103. package/dist/esm/EgressHttpClient.d.ts.map +1 -0
  104. package/dist/esm/EgressHttpClient.js +259 -0
  105. package/dist/esm/EgressHttpClient.js.map +1 -0
  106. package/dist/esm/HostLiveness.d.ts +81 -0
  107. package/dist/esm/HostLiveness.d.ts.map +1 -0
  108. package/dist/esm/HostLiveness.js +68 -0
  109. package/dist/esm/HostLiveness.js.map +1 -0
  110. package/dist/esm/NodeHost.d.ts +145 -0
  111. package/dist/esm/NodeHost.d.ts.map +1 -0
  112. package/dist/esm/NodeHost.js +162 -0
  113. package/dist/esm/NodeHost.js.map +1 -0
  114. package/dist/esm/ProcessConfinement.d.ts +61 -0
  115. package/dist/esm/ProcessConfinement.d.ts.map +1 -0
  116. package/dist/esm/ProcessConfinement.js +311 -0
  117. package/dist/esm/ProcessConfinement.js.map +1 -0
  118. package/dist/esm/ProcessReaper.d.ts +457 -0
  119. package/dist/esm/ProcessReaper.d.ts.map +1 -0
  120. package/dist/esm/ProcessReaper.js +711 -0
  121. package/dist/esm/ProcessReaper.js.map +1 -0
  122. package/dist/esm/ProcessSandbox.d.ts +391 -0
  123. package/dist/esm/ProcessSandbox.d.ts.map +1 -0
  124. package/dist/esm/ProcessSandbox.js +1043 -0
  125. package/dist/esm/ProcessSandbox.js.map +1 -0
  126. package/dist/esm/ScopedProcess.d.ts +66 -0
  127. package/dist/esm/ScopedProcess.d.ts.map +1 -0
  128. package/dist/esm/ScopedProcess.js +67 -0
  129. package/dist/esm/ScopedProcess.js.map +1 -0
  130. package/dist/esm/index.d.ts +38 -0
  131. package/dist/esm/index.d.ts.map +1 -0
  132. package/dist/esm/index.js +38 -0
  133. package/dist/esm/index.js.map +1 -0
  134. package/dist/esm/internal/AtomicFileSystemExecutable.d.ts +61 -0
  135. package/dist/esm/internal/AtomicFileSystemExecutable.d.ts.map +1 -0
  136. package/dist/esm/internal/AtomicFileSystemExecutable.js +350 -0
  137. package/dist/esm/internal/AtomicFileSystemExecutable.js.map +1 -0
  138. package/dist/esm/internal/AtomicFileSystemProtocol.d.ts +78 -0
  139. package/dist/esm/internal/AtomicFileSystemProtocol.d.ts.map +1 -0
  140. package/dist/esm/internal/AtomicFileSystemProtocol.js +412 -0
  141. package/dist/esm/internal/AtomicFileSystemProtocol.js.map +1 -0
  142. package/dist/esm/internal/AtomicFileSystemTransport.d.ts +44 -0
  143. package/dist/esm/internal/AtomicFileSystemTransport.d.ts.map +1 -0
  144. package/dist/esm/internal/AtomicFileSystemTransport.js +242 -0
  145. package/dist/esm/internal/AtomicFileSystemTransport.js.map +1 -0
  146. package/dist/esm/internal/AtomicHelperError.d.ts +35 -0
  147. package/dist/esm/internal/AtomicHelperError.d.ts.map +1 -0
  148. package/dist/esm/internal/AtomicHelperError.js +39 -0
  149. package/dist/esm/internal/AtomicHelperError.js.map +1 -0
  150. package/dist/esm/internal/AtomicHelperFault.d.ts +59 -0
  151. package/dist/esm/internal/AtomicHelperFault.d.ts.map +1 -0
  152. package/dist/esm/internal/AtomicHelperFault.js +66 -0
  153. package/dist/esm/internal/AtomicHelperFault.js.map +1 -0
  154. package/dist/esm/internal/PipedProcess.d.ts +35 -0
  155. package/dist/esm/internal/PipedProcess.d.ts.map +1 -0
  156. package/dist/esm/internal/PipedProcess.js +321 -0
  157. package/dist/esm/internal/PipedProcess.js.map +1 -0
  158. package/dist/esm/internal/ProcSnapshot.d.ts +85 -0
  159. package/dist/esm/internal/ProcSnapshot.d.ts.map +1 -0
  160. package/dist/esm/internal/ProcSnapshot.js +188 -0
  161. package/dist/esm/internal/ProcSnapshot.js.map +1 -0
  162. package/dist/esm/internal/ProcessCleanup.d.ts +64 -0
  163. package/dist/esm/internal/ProcessCleanup.d.ts.map +1 -0
  164. package/dist/esm/internal/ProcessCleanup.js +45 -0
  165. package/dist/esm/internal/ProcessCleanup.js.map +1 -0
  166. package/dist/esm/internal/ProcessCleanupPolicyError.d.ts +30 -0
  167. package/dist/esm/internal/ProcessCleanupPolicyError.d.ts.map +1 -0
  168. package/dist/esm/internal/ProcessCleanupPolicyError.js +25 -0
  169. package/dist/esm/internal/ProcessCleanupPolicyError.js.map +1 -0
  170. package/dist/esm/internal/ProcessFault.d.ts +63 -0
  171. package/dist/esm/internal/ProcessFault.d.ts.map +1 -0
  172. package/dist/esm/internal/ProcessFault.js +64 -0
  173. package/dist/esm/internal/ProcessFault.js.map +1 -0
  174. package/dist/esm/internal/ProcessSupervisor.d.ts +143 -0
  175. package/dist/esm/internal/ProcessSupervisor.d.ts.map +1 -0
  176. package/dist/esm/internal/ProcessSupervisor.js +689 -0
  177. package/dist/esm/internal/ProcessSupervisor.js.map +1 -0
  178. package/dist/esm/internal/SupervisorProgram.d.ts +9 -0
  179. package/dist/esm/internal/SupervisorProgram.d.ts.map +1 -0
  180. package/dist/esm/internal/SupervisorProgram.js +310 -0
  181. package/dist/esm/internal/SupervisorProgram.js.map +1 -0
  182. package/dist/esm/internal/WindowsProcessJob.d.ts +39 -0
  183. package/dist/esm/internal/WindowsProcessJob.d.ts.map +1 -0
  184. package/dist/esm/internal/WindowsProcessJob.js +115 -0
  185. package/dist/esm/internal/WindowsProcessJob.js.map +1 -0
  186. package/dist/vendor/adapters.json +1757 -0
  187. package/dist/vendor/chunk-2Y7WC4KU.js +109 -0
  188. package/dist/vendor/chunk-3GR5VZ2M.js +118 -0
  189. package/dist/vendor/chunk-42QKY6T6.js +40 -0
  190. package/dist/vendor/chunk-54RLBMTZ.js +61 -0
  191. package/dist/vendor/chunk-5ZMHBXIK.js +55 -0
  192. package/dist/vendor/chunk-6ME2W7TF.js +28 -0
  193. package/dist/vendor/chunk-AMQKOQNT.js +34 -0
  194. package/dist/vendor/chunk-B3FZ67QU.js +59 -0
  195. package/dist/vendor/chunk-BKTBUBQY.js +437 -0
  196. package/dist/vendor/chunk-DS7GF46S.js +34 -0
  197. package/dist/vendor/chunk-DVOAHXPG.js +104 -0
  198. package/dist/vendor/chunk-DWSHTSVX.js +229 -0
  199. package/dist/vendor/chunk-EGBNVEEW.js +14 -0
  200. package/dist/vendor/chunk-EZWY45HP.js +18 -0
  201. package/dist/vendor/chunk-FNZOJHSV.js +71 -0
  202. package/dist/vendor/chunk-GXCHI7BM.js +131 -0
  203. package/dist/vendor/chunk-IIJ52ZU6.js +20 -0
  204. package/dist/vendor/chunk-J7A4CZDO.js +92 -0
  205. package/dist/vendor/chunk-JG5TTWPT.js +85 -0
  206. package/dist/vendor/chunk-JJ24ARBQ.js +394 -0
  207. package/dist/vendor/chunk-KOZMM5PZ.js +426 -0
  208. package/dist/vendor/chunk-KUUXSID7.js +18 -0
  209. package/dist/vendor/chunk-LEUPYT3Q.js +36 -0
  210. package/dist/vendor/chunk-M32LDTW7.js +18 -0
  211. package/dist/vendor/chunk-M7CLUILA.js +0 -0
  212. package/dist/vendor/chunk-MBSKBQ5D.js +21 -0
  213. package/dist/vendor/chunk-MLKGABMK.js +9 -0
  214. package/dist/vendor/chunk-NBVRTDTV.js +129 -0
  215. package/dist/vendor/chunk-OXNGN5H7.js +81 -0
  216. package/dist/vendor/chunk-QPLDT6A6.js +564 -0
  217. package/dist/vendor/chunk-QYBKAIA6.js +18 -0
  218. package/dist/vendor/chunk-RO2R4MJH.js +62 -0
  219. package/dist/vendor/chunk-SIR62W3Y.js +398 -0
  220. package/dist/vendor/chunk-TFIKFFSC.js +26 -0
  221. package/dist/vendor/chunk-TXKLEBBL.js +143 -0
  222. package/dist/vendor/chunk-UFH5UUZK.js +48 -0
  223. package/dist/vendor/chunk-VANKHF46.js +96 -0
  224. package/dist/vendor/chunk-VZBDV3TV.js +18 -0
  225. package/dist/vendor/chunk-XDKNKFBW.js +22 -0
  226. package/dist/vendor/chunk-XH4U3JSV.js +249 -0
  227. package/dist/vendor/chunk-Y35ZAO5U.js +53 -0
  228. package/dist/vendor/chunk-ZJMRMY57.js +0 -0
  229. package/dist/vendor/cjs/node/NodeChildProcessSpawner.d.ts +7 -0
  230. package/dist/vendor/cjs/node/NodeChildProcessSpawner.js +1 -0
  231. package/dist/vendor/cjs/node/NodeClusterHttp.d.ts +63 -0
  232. package/dist/vendor/cjs/node/NodeClusterHttp.js +1 -0
  233. package/dist/vendor/cjs/node/NodeClusterSocket.d.ts +79 -0
  234. package/dist/vendor/cjs/node/NodeClusterSocket.js +1 -0
  235. package/dist/vendor/cjs/node/NodeCrypto.d.ts +10 -0
  236. package/dist/vendor/cjs/node/NodeCrypto.js +1 -0
  237. package/dist/vendor/cjs/node/NodeFileSystem.d.ts +10 -0
  238. package/dist/vendor/cjs/node/NodeFileSystem.js +1 -0
  239. package/dist/vendor/cjs/node/NodeHttpClient.d.ts +179 -0
  240. package/dist/vendor/cjs/node/NodeHttpClient.js +1 -0
  241. package/dist/vendor/cjs/node/NodeHttpIncomingMessage.d.ts +62 -0
  242. package/dist/vendor/cjs/node/NodeHttpIncomingMessage.js +1 -0
  243. package/dist/vendor/cjs/node/NodeHttpPlatform.d.ts +36 -0
  244. package/dist/vendor/cjs/node/NodeHttpPlatform.js +1 -0
  245. package/dist/vendor/cjs/node/NodeHttpServer.d.ts +120 -0
  246. package/dist/vendor/cjs/node/NodeHttpServer.js +1 -0
  247. package/dist/vendor/cjs/node/NodeHttpServerRequest.d.ts +29 -0
  248. package/dist/vendor/cjs/node/NodeHttpServerRequest.js +1 -0
  249. package/dist/vendor/cjs/node/NodeMultipart.d.ts +46 -0
  250. package/dist/vendor/cjs/node/NodeMultipart.js +1 -0
  251. package/dist/vendor/cjs/node/NodeMultipartParser.d.ts +97 -0
  252. package/dist/vendor/cjs/node/NodeMultipartParser.js +1 -0
  253. package/dist/vendor/cjs/node/NodePath.d.ts +27 -0
  254. package/dist/vendor/cjs/node/NodePath.js +1 -0
  255. package/dist/vendor/cjs/node/NodeRedis.d.ts +74 -0
  256. package/dist/vendor/cjs/node/NodeRedis.js +1 -0
  257. package/dist/vendor/cjs/node/NodeRuntime.d.ts +85 -0
  258. package/dist/vendor/cjs/node/NodeRuntime.js +1 -0
  259. package/dist/vendor/cjs/node/NodeServices.d.ts +34 -0
  260. package/dist/vendor/cjs/node/NodeServices.js +1 -0
  261. package/dist/vendor/cjs/node/NodeSink.d.ts +8 -0
  262. package/dist/vendor/cjs/node/NodeSink.js +1 -0
  263. package/dist/vendor/cjs/node/NodeSocket.d.ts +38 -0
  264. package/dist/vendor/cjs/node/NodeSocket.js +1 -0
  265. package/dist/vendor/cjs/node/NodeSocketServer.d.ts +8 -0
  266. package/dist/vendor/cjs/node/NodeSocketServer.js +1 -0
  267. package/dist/vendor/cjs/node/NodeStdio.d.ts +11 -0
  268. package/dist/vendor/cjs/node/NodeStdio.js +1 -0
  269. package/dist/vendor/cjs/node/NodeStream.d.ts +8 -0
  270. package/dist/vendor/cjs/node/NodeStream.js +1 -0
  271. package/dist/vendor/cjs/node/NodeTerminal.d.ts +21 -0
  272. package/dist/vendor/cjs/node/NodeTerminal.js +1 -0
  273. package/dist/vendor/cjs/node/NodeWorker.d.ts +22 -0
  274. package/dist/vendor/cjs/node/NodeWorker.js +1 -0
  275. package/dist/vendor/cjs/node/NodeWorkerRunner.d.ts +12 -0
  276. package/dist/vendor/cjs/node/NodeWorkerRunner.js +1 -0
  277. package/dist/vendor/cjs/node/Undici.d.ts +28 -0
  278. package/dist/vendor/cjs/node/Undici.js +1 -0
  279. package/dist/vendor/cjs/node/index.d.ts +100 -0
  280. package/dist/vendor/cjs/node/index.js +1 -0
  281. package/dist/vendor/cjs/node-shared/NodeChildProcessSpawner.d.ts +57 -0
  282. package/dist/vendor/cjs/node-shared/NodeChildProcessSpawner.js +1 -0
  283. package/dist/vendor/cjs/node-shared/NodeClusterSocket.d.ts +22 -0
  284. package/dist/vendor/cjs/node-shared/NodeClusterSocket.js +1 -0
  285. package/dist/vendor/cjs/node-shared/NodeCrypto.d.ts +27 -0
  286. package/dist/vendor/cjs/node-shared/NodeCrypto.js +1 -0
  287. package/dist/vendor/cjs/node-shared/NodeFileSystem.d.ts +11 -0
  288. package/dist/vendor/cjs/node-shared/NodeFileSystem.js +1 -0
  289. package/dist/vendor/cjs/node-shared/NodeHttpCompression.d.ts +36 -0
  290. package/dist/vendor/cjs/node-shared/NodeHttpCompression.js +1 -0
  291. package/dist/vendor/cjs/node-shared/NodePath.d.ts +27 -0
  292. package/dist/vendor/cjs/node-shared/NodePath.js +1 -0
  293. package/dist/vendor/cjs/node-shared/NodeRuntime.d.ts +47 -0
  294. package/dist/vendor/cjs/node-shared/NodeRuntime.js +1 -0
  295. package/dist/vendor/cjs/node-shared/NodeSink.d.ts +69 -0
  296. package/dist/vendor/cjs/node-shared/NodeSink.js +1 -0
  297. package/dist/vendor/cjs/node-shared/NodeSocket.d.ts +134 -0
  298. package/dist/vendor/cjs/node-shared/NodeSocket.js +1 -0
  299. package/dist/vendor/cjs/node-shared/NodeSocketServer.d.ts +80 -0
  300. package/dist/vendor/cjs/node-shared/NodeSocketServer.js +1 -0
  301. package/dist/vendor/cjs/node-shared/NodeStdio.d.ts +12 -0
  302. package/dist/vendor/cjs/node-shared/NodeStdio.js +1 -0
  303. package/dist/vendor/cjs/node-shared/NodeStream.d.ts +179 -0
  304. package/dist/vendor/cjs/node-shared/NodeStream.js +1 -0
  305. package/dist/vendor/cjs/node-shared/NodeTerminal.d.ts +22 -0
  306. package/dist/vendor/cjs/node-shared/NodeTerminal.js +1 -0
  307. package/dist/vendor/cjs/node-shared/index.d.ts +56 -0
  308. package/dist/vendor/cjs/node-shared/index.js +1 -0
  309. package/dist/vendor/cjs/node-shared/internal/nodeChildProcessSpawner.d.ts +4 -0
  310. package/dist/vendor/cjs/node-shared/internal/nodeChildProcessSpawner.js +1 -0
  311. package/dist/vendor/cjs/node-shared/internal/utils.d.ts +2 -0
  312. package/dist/vendor/cjs/node-shared/internal/utils.js +1 -0
  313. package/dist/vendor/cjs/package.json +1 -0
  314. package/dist/vendor/cjs/platform-node-shared.d.ts +56 -0
  315. package/dist/vendor/cjs/platform-node-shared.js +1 -0
  316. package/dist/vendor/cjs/platform-node.d.ts +100 -0
  317. package/dist/vendor/cjs/platform-node.js +1 -0
  318. package/dist/vendor/node/LICENSE +21 -0
  319. package/dist/vendor/node/NodeChildProcessSpawner.d.ts +7 -0
  320. package/dist/vendor/node/NodeChildProcessSpawner.js +14 -0
  321. package/dist/vendor/node/NodeClusterHttp.d.ts +63 -0
  322. package/dist/vendor/node/NodeClusterHttp.js +43 -0
  323. package/dist/vendor/node/NodeClusterSocket.d.ts +79 -0
  324. package/dist/vendor/node/NodeClusterSocket.js +30 -0
  325. package/dist/vendor/node/NodeCrypto.d.ts +10 -0
  326. package/dist/vendor/node/NodeCrypto.js +8 -0
  327. package/dist/vendor/node/NodeFileSystem.d.ts +10 -0
  328. package/dist/vendor/node/NodeFileSystem.js +9 -0
  329. package/dist/vendor/node/NodeHttpClient.d.ts +179 -0
  330. package/dist/vendor/node/NodeHttpClient.js +46 -0
  331. package/dist/vendor/node/NodeHttpIncomingMessage.d.ts +62 -0
  332. package/dist/vendor/node/NodeHttpIncomingMessage.js +10 -0
  333. package/dist/vendor/node/NodeHttpPlatform.d.ts +36 -0
  334. package/dist/vendor/node/NodeHttpPlatform.js +16 -0
  335. package/dist/vendor/node/NodeHttpServer.d.ts +120 -0
  336. package/dist/vendor/node/NodeHttpServer.js +46 -0
  337. package/dist/vendor/node/NodeHttpServerRequest.d.ts +29 -0
  338. package/dist/vendor/node/NodeHttpServerRequest.js +9 -0
  339. package/dist/vendor/node/NodeMultipart.d.ts +46 -0
  340. package/dist/vendor/node/NodeMultipart.js +15 -0
  341. package/dist/vendor/node/NodeMultipartParser.d.ts +97 -0
  342. package/dist/vendor/node/NodeMultipartParser.js +11 -0
  343. package/dist/vendor/node/NodePath.d.ts +27 -0
  344. package/dist/vendor/node/NodePath.js +12 -0
  345. package/dist/vendor/node/NodeRedis.d.ts +74 -0
  346. package/dist/vendor/node/NodeRedis.js +11 -0
  347. package/dist/vendor/node/NodeRuntime.d.ts +85 -0
  348. package/dist/vendor/node/NodeRuntime.js +8 -0
  349. package/dist/vendor/node/NodeServices.d.ts +34 -0
  350. package/dist/vendor/node/NodeServices.js +23 -0
  351. package/dist/vendor/node/NodeSink.d.ts +8 -0
  352. package/dist/vendor/node/NodeSink.js +12 -0
  353. package/dist/vendor/node/NodeSocket.d.ts +38 -0
  354. package/dist/vendor/node/NodeSocket.js +31 -0
  355. package/dist/vendor/node/NodeSocketServer.d.ts +8 -0
  356. package/dist/vendor/node/NodeSocketServer.js +21 -0
  357. package/dist/vendor/node/NodeStdio.d.ts +11 -0
  358. package/dist/vendor/node/NodeStdio.js +10 -0
  359. package/dist/vendor/node/NodeStream.d.ts +8 -0
  360. package/dist/vendor/node/NodeStream.js +27 -0
  361. package/dist/vendor/node/NodeTerminal.d.ts +21 -0
  362. package/dist/vendor/node/NodeTerminal.js +10 -0
  363. package/dist/vendor/node/NodeWorker.d.ts +22 -0
  364. package/dist/vendor/node/NodeWorker.js +9 -0
  365. package/dist/vendor/node/NodeWorkerRunner.d.ts +12 -0
  366. package/dist/vendor/node/NodeWorkerRunner.js +7 -0
  367. package/dist/vendor/node/Undici.d.ts +28 -0
  368. package/dist/vendor/node/Undici.js +9 -0
  369. package/dist/vendor/node/index.d.ts +100 -0
  370. package/dist/vendor/node/index.js +115 -0
  371. package/dist/vendor/node-shared/LICENSE +21 -0
  372. package/dist/vendor/node-shared/NodeChildProcessSpawner.d.ts +57 -0
  373. package/dist/vendor/node-shared/NodeChildProcessSpawner.js +13 -0
  374. package/dist/vendor/node-shared/NodeClusterSocket.d.ts +22 -0
  375. package/dist/vendor/node-shared/NodeClusterSocket.js +11 -0
  376. package/dist/vendor/node-shared/NodeCrypto.d.ts +27 -0
  377. package/dist/vendor/node-shared/NodeCrypto.js +9 -0
  378. package/dist/vendor/node-shared/NodeFileSystem.d.ts +11 -0
  379. package/dist/vendor/node-shared/NodeFileSystem.js +8 -0
  380. package/dist/vendor/node-shared/NodeHttpCompression.d.ts +36 -0
  381. package/dist/vendor/node-shared/NodeHttpCompression.js +13 -0
  382. package/dist/vendor/node-shared/NodePath.d.ts +27 -0
  383. package/dist/vendor/node-shared/NodePath.js +11 -0
  384. package/dist/vendor/node-shared/NodeRuntime.d.ts +47 -0
  385. package/dist/vendor/node-shared/NodeRuntime.js +7 -0
  386. package/dist/vendor/node-shared/NodeSink.d.ts +69 -0
  387. package/dist/vendor/node-shared/NodeSink.js +11 -0
  388. package/dist/vendor/node-shared/NodeSocket.d.ts +134 -0
  389. package/dist/vendor/node-shared/NodeSocket.js +23 -0
  390. package/dist/vendor/node-shared/NodeSocketServer.d.ts +80 -0
  391. package/dist/vendor/node-shared/NodeSocketServer.js +20 -0
  392. package/dist/vendor/node-shared/NodeStdio.d.ts +12 -0
  393. package/dist/vendor/node-shared/NodeStdio.js +9 -0
  394. package/dist/vendor/node-shared/NodeStream.d.ts +179 -0
  395. package/dist/vendor/node-shared/NodeStream.js +26 -0
  396. package/dist/vendor/node-shared/NodeTerminal.d.ts +22 -0
  397. package/dist/vendor/node-shared/NodeTerminal.js +9 -0
  398. package/dist/vendor/node-shared/index.d.ts +56 -0
  399. package/dist/vendor/node-shared/index.js +58 -0
  400. package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.d.ts +4 -0
  401. package/dist/vendor/node-shared/internal/nodeChildProcessSpawner.js +7 -0
  402. package/dist/vendor/node-shared/internal/utils.d.ts +2 -0
  403. package/dist/vendor/node-shared/internal/utils.js +7 -0
  404. package/dist/vendor/platform-node-shared.d.ts +56 -0
  405. package/dist/vendor/platform-node-shared.js +58 -0
  406. package/dist/vendor/platform-node.d.ts +100 -0
  407. package/dist/vendor/platform-node.js +115 -0
  408. package/docs/README.md +129 -0
  409. package/docs/api.md +553 -0
  410. package/docs/concepts/descriptor-relative-filesystem.md +181 -0
  411. package/docs/concepts/host-bundle.md +125 -0
  412. package/docs/concepts/process-containment.md +190 -0
  413. package/docs/guides/answer-run-ownership.md +87 -0
  414. package/docs/guides/configure-the-filesystem-helper.md +152 -0
  415. package/docs/guides/contain-child-processes.md +139 -0
  416. package/docs/guides/match-files-with-glob.md +151 -0
  417. package/docs/installation.md +204 -0
  418. package/docs/quickstart.md +147 -0
  419. package/docs/troubleshooting.md +130 -0
  420. package/package.json +202 -3
  421. package/src/AtomicFileSystem.ts +415 -0
  422. package/src/EgressHttpClient.ts +327 -0
  423. package/src/HostLiveness.ts +103 -0
  424. package/src/NodeHost.ts +253 -0
  425. package/src/ProcessConfinement.ts +363 -0
  426. package/src/ProcessReaper.ts +951 -0
  427. package/src/ProcessSandbox.ts +1307 -0
  428. package/src/ScopedProcess.ts +124 -0
  429. package/src/index.ts +44 -0
  430. package/src/internal/AtomicFileSystemExecutable.ts +379 -0
  431. package/src/internal/AtomicFileSystemProtocol.ts +502 -0
  432. package/src/internal/AtomicFileSystemTransport.ts +272 -0
  433. package/src/internal/AtomicHelperError.ts +50 -0
  434. package/src/internal/AtomicHelperFault.ts +84 -0
  435. package/src/internal/PipedProcess.ts +357 -0
  436. package/src/internal/ProcSnapshot.ts +193 -0
  437. package/src/internal/ProcessCleanup.ts +99 -0
  438. package/src/internal/ProcessCleanupPolicyError.ts +30 -0
  439. package/src/internal/ProcessFault.ts +82 -0
  440. package/src/internal/ProcessSupervisor.ts +807 -0
  441. package/src/internal/SupervisorProgram.ts +309 -0
  442. package/src/internal/WindowsProcessJob.ts +114 -0
@@ -0,0 +1,181 @@
1
+ ---
2
+ title: "The descriptor-relative filesystem"
3
+ description: "Why AtomicFileSystem runs every filesystem operation through the smithers-jj-export helper, what confinement that buys, which operations it covers, and what it costs per call."
4
+ sidebar:
5
+ order: 2
6
+ ---
7
+
8
+ `AtomicFileSystem` is `NodeHost`'s filesystem slot, and it is not Effect's
9
+ `NodeFileSystem`. It exists to close one race.
10
+
11
+ ## The race it closes
12
+
13
+ A capability check names a path. A path-based operation resolves that path
14
+ again when it runs. Between the two, anything with write access to the
15
+ workspace can replace a component of the path with a symlink, and the operation
16
+ that was authorized for one file performs on another.
17
+
18
+ POSIX has the answer: open a directory, keep the descriptor, and perform the
19
+ final syscall relative to it (`openat(2)`, `renameat(2)`, and the `dir_fd`
20
+ family). A descriptor names an inode, not a name, so a swap after the walk
21
+ cannot redirect anything.
22
+
23
+ Node's JavaScript filesystem API exposes none of that, and no root-handle
24
+ equivalent. So `AtomicFileSystem` delegates each operation to the native
25
+ `smithers-jj-export` helper, which does have it. For ordinary operations and batches, the helper walks
26
+ from the filesystem root to the canonical workspace root using descriptor-relative
27
+ `O_NOFOLLOW | O_DIRECTORY` opens for every component. It verifies the opened
28
+ root's device/inode against the identity captured when the kernel layer was
29
+ composed, then performs the operation relative to a pinned parent descriptor.
30
+ An ancestor symlink swap or replacement of the root by another directory fails
31
+ ordinary operations with `PermissionDenied` before any content is read or changed.
32
+
33
+ ## What the helper refuses
34
+
35
+ The confinement rules are strict, and two of them surprise people:
36
+
37
+ - **A regular file with more than one hard link cannot be opened.** A hard link
38
+ is not a symlink, so `O_NOFOLLOW` cannot confine it: the same inode is
39
+ reachable from outside the workspace under another name. Refusing the open is
40
+ the only confinement available.
41
+ - **A symlink is never traversed, opened, renamed, or removed.** Directory
42
+ listing is the single exception. It names a symlink entry and never descends
43
+ through it, because listing resolves nothing and refusing would buy no
44
+ confinement.
45
+
46
+ Two more rules follow from requiring the kind on the descriptor rather than on
47
+ a name:
48
+
49
+ - **Only regular files carry content.** A FIFO, a socket, a device, or a
50
+ directory is refused for every read and write, because the kind is checked on
51
+ the already-open descriptor and cannot be swapped afterwards.
52
+ - **Every open is non-blocking.** A named pipe planted at a path cannot park
53
+ the adapter inside `open()` until some other process opens the other end. A
54
+ write-only open of a reader-less pipe returns a typed failure instead. Node's
55
+ own filesystem waits there indefinitely, which is the one place this adapter
56
+ is deliberately stricter than the implementation it mirrors.
57
+
58
+ The workspace root itself is addressable like any other directory: `exists`,
59
+ `stat`, `readDirectory`, `realPath`, `glob`, and a recursive `makeDirectory`
60
+ all answer for it. Removing it, renaming it or onto it, reading it as a file,
61
+ writing over it, and a non-recursive `makeDirectory` on it stay refused.
62
+
63
+ ## Which operations it covers
64
+
65
+ Fifteen operations can be expressed as one descriptor-relative request, and
66
+ those are the ones the adapter implements:
67
+
68
+ ```text
69
+ readFile readFileString writeFile writeFileString exists stat
70
+ readLink realPath makeDirectory readDirectory remove rename glob
71
+ chmod chown
72
+ ```
73
+
74
+ `chmod` and `chown` change metadata through the descriptor of the resolved
75
+ target (`fchmod`, `fchown`), never through a path. They refuse a symbolic link,
76
+ a hard-linked file and the workspace root, a mode outside `0` to `0o7777`, and
77
+ an owner below `-1`; `-1` leaves a `uid` or `gid` unchanged. The change is
78
+ synced before the call returns. A refusal arrives as a typed failure and the
79
+ target keeps its previous mode and owner.
80
+
81
+ Everything else on Effect's `FileSystem` surface returns a live handle or a
82
+ stream that Node cannot open relative to a pinned descriptor: `open`, `stream`, `sink`, `watch`, `copy`,
83
+ `copyFile`, `link`, `symlink`, `access`, `truncate`, `utimes`, and the `makeTemp*` family.
84
+ Under the kernel decorator each of those fails closed with a typed
85
+ `PermissionDenied` rather than silently reverting to a path-based call. A
86
+ program that needs them reaches for the raw `NodeHost.NodeFileSystem` outside
87
+ the capability boundary.
88
+
89
+ Wrapping that raw layer directly also fails closed, because it carries no
90
+ atomic extension for the kernel to call.
91
+
92
+ ## How the helper is started
93
+
94
+ The helper is `smithers-jj-export --atomic-fs`, a Rust binary shipped with the
95
+ package. Three properties of how it is started are load-bearing:
96
+
97
+ - **Absolute path, never a `PATH` lookup.** A binary planted in the working
98
+ directory or on an injected `PATH` would run inside the process that holds
99
+ the pinned root descriptor.
100
+ - **Outside the workspace.** The resolved executable must be an executable
101
+ regular file outside the confined root. A packaged helper is copied out of
102
+ the workspace when the first host layer in the process is built, before any
103
+ flow runs; later layer builds copy nothing.
104
+ - **Inert process.** It starts with an empty environment and the filesystem
105
+ root as its working directory.
106
+
107
+ Both directions of the protocol are length-framed and bounded, so neither a
108
+ large file nor a malfunctioning helper can make the host allocate without
109
+ limit. See
110
+ [Configure the filesystem helper](../guides/configure-the-filesystem-helper.md)
111
+ for the ceilings and how to change them.
112
+
113
+ ## What it costs
114
+
115
+ An ordinary operation starts one helper. The guarded filesystem also
116
+ offers `FileSystem.batch(fs)` from `@smthrs/kernel/FileSystem`: one helper
117
+ serves up to 128 read requests against the same root descriptor. Requests may
118
+ stat, list directories, expand host globs, or collect SHA-256 digests, optionally
119
+ with file bytes. The helper exits after that request. There is no persistent
120
+ process.
121
+
122
+ Through the kernel's guarded filesystem, authorization resolves each path
123
+ through the helper too, never through a host pathname: once before the grant
124
+ decision and once after. A guarded operation therefore starts three helpers,
125
+ and so does a guarded batch, whose members are resolved together.
126
+
127
+ - Prefer one recursive `readDirectory` (one helper for the whole tree) to a read
128
+ per entry.
129
+ - Use bounded batches for a wide fan-out. Without a ceiling, an
130
+ `Effect.forEach(files, read, { concurrency: "unbounded" })` over fifty paths
131
+ would start fifty helpers at once, which is why the adapter carries a
132
+ process ceiling at all.
133
+
134
+ Each batch member keeps its own canonical resource and grant check. Denied
135
+ members never enter the helper. Results retain their request index and sort by
136
+ normalized path using JavaScript's UTF-16 order, including Unicode names and
137
+ duplicate requests. Directory and glob results also sort deterministically.
138
+
139
+ The guard captures the root's device/inode at composition. The helper walks to
140
+ that root without following any component symlink and verifies its identity
141
+ before and after measurement. Root loss is a boundary failure, not a collection
142
+ of absent files. Digest reads compare descriptor metadata before and after the
143
+ read, then compare the pathname against that descriptor. Directory walks check
144
+ their opened directories for observed mutations. These checks detect changes
145
+ during a measurement; they do not freeze a workspace or claim a simultaneous
146
+ snapshot of unrelated paths.
147
+
148
+ A workspace symlink is allowed when composed, but the kernel rechecks its
149
+ logical path before and after grants. Retargeting it refuses the batch even
150
+ while the old canonical root remains available to the helper.
151
+
152
+ An entry absent before measurement reports `NotFound`. An entry or ancestor
153
+ that disappears after measurement begins reports `Busy`, so an interrupted
154
+ read cannot become evidence that the file was initially absent.
155
+
156
+ The digest is SHA-256 of the original bytes. No JSON, encoding, or pathname is
157
+ added to its input. Boundary tree and read-set identities remain the engine's
158
+ existing canonical constructions.
159
+
160
+ `AtomicFileSystem.helperSpawns()` exposes a process-local count for diagnostics.
161
+ Elapsed timings from `scripts/observation-bench.ts` are local measurements and
162
+ do not establish a production speed claim.
163
+
164
+ ## Errors
165
+
166
+ Errno is normalized to the same reasons `@effect/platform-node` reports, so a
167
+ caller reads the same typed reason it would get from the native filesystem,
168
+ with one addition: a helper failure that carries no errno at all stays
169
+ `PermissionDenied`, so the boundary fails closed.
170
+
171
+ Writes follow Effect's `OpenFlag` contract exactly (`r`, `r+`, `w`, `wx`, `w+`,
172
+ `wx+`, `a`, `ax`, `a+`, `ax+`), and the test suite checks each flag against the
173
+ native Node filesystem. Truncation runs on the opened descriptor rather than
174
+ through `O_TRUNC`, so a hard link is refused before the file is modified.
175
+
176
+ `remove(path, { recursive: true })` walks iteratively with an explicit
177
+ descriptor stack, bounded at 512 levels deep and 100000 entries visited. One
178
+ directory's names are read before any of its entries is unlinked, because
179
+ unlinking from a directory while iterating it is undefined. Progress is partial
180
+ on refusal: entries already unlinked stay unlinked. `force: true` succeeds for
181
+ a path whose ancestors do not exist, exactly as `fs.rm` does.
@@ -0,0 +1,125 @@
1
+ ---
2
+ title: "The host bundle"
3
+ description: "Why the Host surface is a closed set of five tags, which of them this package composes and which it implements, and why there is no shell service, no HTTP wrapper, and no Windows support."
4
+ sidebar:
5
+ order: 1
6
+ ---
7
+
8
+ A Smithers **host** is the boundary between a durable flow and the machine
9
+ underneath it. The surface is closed: five service tags, no more, and
10
+ [`@smthrs/kernel`](/api/kernel) owns the list.
11
+
12
+ ```text
13
+ FileSystem Path ChildProcessSpawner Jj HttpClient
14
+ ```
15
+
16
+ Closing the list is what makes the capability check complete. The kernel
17
+ decorates each of the five with a permission check, so a program that reaches
18
+ the machine has to go through a tag the kernel is watching. A sixth capability
19
+ smuggled in beside them would be authority nobody checked.
20
+
21
+ Three of the five tags are Effect's own, from `effect/FileSystem`,
22
+ `effect/Path`, and `effect/unstable/process/ChildProcessSpawner` and
23
+ `effect/unstable/http/HttpClient`. Smithers provides implementations of them
24
+ rather than wrappers around them, so an ordinary Effect program runs on a
25
+ Smithers host unchanged. `Jj` is the one Smithers tag, and it lives in
26
+ [`@smthrs/jj`](/api/jj).
27
+
28
+ ## What this package composes
29
+
30
+ `@effect/platform-node` already ships most of a Node host. `NodeHost.layer` is
31
+ mostly assembly:
32
+
33
+ | Tag | Implementation |
34
+ | --------------------- | --------------------------------------- |
35
+ | `Path` | `NodePath.layer` |
36
+ | `ChildProcessSpawner` | `NodeChildProcessSpawner.layer` |
37
+ | `HttpClient` | `EgressHttpClient.layer(process.env)` |
38
+ | `Jj` | `@smthrs/jj`'s `NodeJj.layer` |
39
+ | `FileSystem` | this package's `AtomicFileSystem.layer` |
40
+
41
+ Only the filesystem slot is this package's own implementation, and
42
+ [it exists because Node cannot express what the kernel needs](./descriptor-relative-filesystem.md).
43
+
44
+ The HTTP slot is Undici either way. `EgressHttpClient.layer` routes it through
45
+ the egress proxy `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` name, and is exactly
46
+ `NodeHttpClient.layerUndici` when they name none, so an unproxied host is
47
+ unchanged. A bundle spans a whole host, and a host may be a sandbox whose only
48
+ way out is that proxy; a bare Undici `Agent` reads none of those variables and
49
+ dials every origin directly, which such a host drops.
50
+
51
+ `NodeHost` re-exports the pieces it composes, so a program that wants one slot
52
+ rather than the whole bundle needs no second dependency:
53
+ `NodeHost.AtomicFileSystem`, `NodeHost.ProcessReaper`, `NodeHost.NodeCrypto`,
54
+ `NodeHost.NodeFileSystem`, `NodeHost.NodeChildProcessSpawner`,
55
+ `NodeHost.NodeHttpClient`, and `NodeHost.EgressHttpClient`.
56
+
57
+ `NodeCrypto` is there for a different reason from the rest. `Crypto` is not a
58
+ Host service: it carries no host authority the kernel could attenuate, so it is
59
+ not in the closed list. Every durable composition needs one anyway, and a
60
+ program that already depends on this package for its host should not need a
61
+ second dependency for the digest.
62
+
63
+ ## The four layers
64
+
65
+ The bundle ships four layers, along two independent axes: where `Jj` is rooted,
66
+ and whether spawned processes are contained.
67
+
68
+ | Layer | `Jj` bound to | Containment |
69
+ | ------------------------------------------- | ----------------------------- | ----------- |
70
+ | `NodeHost.layer` | the process working directory | no |
71
+ | `NodeHost.layerAt(root)` | one absolute repository root | no |
72
+ | `NodeHost.layerContained(options?)` | the process working directory | yes |
73
+ | `NodeHost.layerContainedAt(root, options?)` | one absolute repository root | yes |
74
+
75
+ The rooted pair exists because a durable host outlives any one working
76
+ directory. `@smthrs/flows`' `NodeRuntime` composes `layerContainedAt`, so both
77
+ the repository and the process containment are pinned by the runtime rather
78
+ than inherited from whatever shell started it.
79
+
80
+ The contained pair carries a requirement the plain pair does not: a
81
+ `ProcessLedger`. See [Process containment](./process-containment.md) for what
82
+ it buys and why the ledger is not defaulted.
83
+
84
+ ## What the bundle does not provide
85
+
86
+ Each of these is a decision with a consequence, not a gap.
87
+
88
+ **There is no shell service.** Running a command is Effect's `ChildProcess` and
89
+ `ChildProcessSpawner`. That means a wall-clock budget is `Effect.timeout`
90
+ around the effect rather than an option on a command record, and cancellation
91
+ is fiber interruption rather than an `AbortSignal`. A Smithers shell service
92
+ would be a second way to express what Effect already expresses, and the kernel
93
+ would then have two spawn paths to check instead of one.
94
+
95
+ **There is no HTTP service.** An outgoing request is Effect's `HttpClient`, and
96
+ `@effect/platform-node` already ships the Undici-backed implementation. Undici
97
+ follows no redirect unless a redirect interceptor is installed, and this bundle
98
+ installs none, so every hop stays a separate request. That is what lets the
99
+ kernel check `net:get` and `net:post` against the host of every URL a request
100
+ actually reaches, redirect targets included.
101
+
102
+ **There is no Windows support.** `AtomicFileSystem` needs `O_NOFOLLOW`,
103
+ `O_DIRECTORY`, and `dir_fd`, none of which Windows has, so every filesystem
104
+ call fails closed there. `ProcessReaper` still reaches `taskkill /T /F` through
105
+ `systemFor("win32")` rather than retiring every record unsignalled, because a
106
+ reaper that silently discarded records would be worse than one that says what
107
+ it does. Treat it as unsupported best-effort.
108
+
109
+ **There is no path-based fallback.** A host with no usable `smithers-jj-export` helper fails
110
+ every guarded filesystem call with `PermissionDenied`. The adapter never
111
+ degrades to a check-then-path operation, because that is exactly the race it
112
+ exists to close.
113
+
114
+ ## Conformance
115
+
116
+ The bundle is not trusted to be correct because it is composed correctly. It
117
+ runs the shared host contract from `@smthrs/kernel/test/contract` twice: once
118
+ with explicit expectations, and once taking every default the suite offers,
119
+ against a loopback HTTP server so the `HttpClient` success path is asserted
120
+ rather than only its refusal.
121
+
122
+ On top of that, the atomic filesystem is compared row by row against
123
+ `@effect/platform-node`'s own adapter (open flags, errno classification, `stat`
124
+ fields, and the glob grammar), and containment is driven over real detached
125
+ process groups.
@@ -0,0 +1,190 @@
1
+ ---
2
+ title: "Process containment"
3
+ description: "How a crashed host's abandoned processes get killed: incarnations, the process ledger, and every guard ProcessReaper checks before it signals a durable record."
4
+ sidebar:
5
+ order: 3
6
+ ---
7
+
8
+ A target's exit does not mean its children exited. A host killed outright
9
+ runs no finalizers either. The contained Node host uses a live POSIX supervisor
10
+ to own each process group independently of the target and to observe host loss
11
+ through a private connection. A process ledger lets a later host reconcile
12
+ records whose cleanup was not confirmed.
13
+
14
+ ## Incarnations
15
+
16
+ A **host** has a durable `hostId`. Each time a process starts under that id, it
17
+ is a new **incarnation**, identified by its pid. The ledger records which
18
+ incarnation started each process, so a later incarnation can tell its own live
19
+ children from an abandoned one's.
20
+
21
+ That is the whole shape of the problem: the input to reaping is a durable
22
+ record that outlived the process that wrote it, on a machine where the
23
+ operating system reuses pid numbers.
24
+
25
+ ## The live half: the contained spawner
26
+
27
+ `NodeHost.layerContained` uses `ProcessReaper.layerSpawner` to compose
28
+ [`@smthrs/kernel`](/api/kernel)'s `ContainedSpawner` with a native process
29
+ adapter and `ProcessReaper.processLifecycle`:
30
+
31
+ - Preparation creates an owner without executing the target. The kernel
32
+ records its identity and the original command digest before activation.
33
+ - Every pipeline leg has a separate owner and ledger record. On POSIX the
34
+ handle's `pid` is that supervisor's; `exitCode` and `isRunning` describe the
35
+ target. Signals go through `handle.kill`.
36
+ - Cleanup keeps its deadline after the target exits, so a same-group child
37
+ cannot keep inherited output open indefinitely. Only verified cleanup retires
38
+ the record; failed cleanup fails scope close and retains it.
39
+ - The grace period is an upper bound. Once the target has exited and the group
40
+ holds no other live member and no captured escaped descendant, cleanup
41
+ finishes at once.
42
+ - A grouped supervisor starts a guardian in its group before the target: a
43
+ `/bin/sh` that waits on a pipe only the supervisor holds. A supervisor killed
44
+ outright (`SIGKILL`, the OOM killer) runs no handler, so at that pipe's EOF
45
+ the guardian kills its own group with `kill 0`, which names the caller's
46
+ group rather than a number that could be stale. It ignores the catchable
47
+ signals a stop sends the group and dies in the supervisor's final `SIGKILL`.
48
+ A host without `/bin/sh` refuses to start a grouped target. A lost
49
+ supervisor sends no cleanup receipt, so its release stays unverified.
50
+
51
+ Confined children use private directories for `HOME` and XDG config, cache, data, and state.
52
+
53
+ Default commands lead their own group. `detached: false` opts out of group
54
+ cleanup and signals only the native target. Explicit stopping of a still-live
55
+ grouped target additionally attempts a revalidated positive-PID sweep of
56
+ escaped descendants, with ordinary POSIX PID races remaining. Natural exit
57
+ does not promise cleanup of deliberately escaped sessions.
58
+
59
+ An explicit stop owns its deadline until cleanup is acknowledged. A target exit
60
+ received during that stop does not send another request. The helper preserves
61
+ the accepted signal and grace period across target exit and either socket's
62
+ closure, even when its configured default is `SIGKILL`. A still-live target
63
+ receives that policy even after calling `setsid()` to leave the supervisor's
64
+ group. Group membership selects the descendant sweep, not the target's signal
65
+ or grace period. Only an unactivated owner or verified natural completion can
66
+ use the host's immediate cleanup shortcut. After the target exits, the helper
67
+ reads the process table once: an empty group with no captured escaped
68
+ descendant ends the stop at once, since waiting cannot clean anything more.
69
+ A live group member, a captured escaped descendant or an unreadable table keeps
70
+ the full deadline. Requests and lifetime
71
+ status use separate private sockets, so an EPIPE on a late request cannot discard
72
+ a buffered target exit or cleanup receipt. The host drains that receipt and
73
+ verifies the process group before retiring the ledger record.
74
+
75
+ Delivery deadlines and verification retries use the platform clock. Freezing
76
+ the caller's Effect clock does not freeze native process cleanup or turn an
77
+ unverifiable group into an unbounded scope finalizer.
78
+
79
+ `jj` goes through that same spawner rather than around it. `NodeJj.layer`
80
+ spawns its own children, which is right for a host that has no spawner to
81
+ offer; under containment it would mean a `jj` invocation that leads no recorded
82
+ process group, appears in no ledger, and survives the incarnation that started
83
+ it.
84
+
85
+ ## The durable half: the sweep
86
+
87
+ `ProcessReaper.reap` runs once while the contained layer is built. It reads the
88
+ records a previous incarnation of the same `hostId` left behind and kills the
89
+ process groups they name. Standing a host up is therefore also what cleans up
90
+ after the incarnation that crashed.
91
+
92
+ The rules are narrow on purpose. A record is signalled only when every one of
93
+ these holds:
94
+
95
+ 1. It belongs to a different incarnation of the same `hostId`. The ledger
96
+ filters that before the reaper sees it.
97
+ 2. Its owner is gone. A pid that exists but belongs to another user counts as
98
+ alive, so only `ESRCH` reads as dead and every other answer keeps the
99
+ record.
100
+ 3. Its numbers name something this platform can signal. On POSIX that is a
101
+ process group the child leads itself, so `pgid` has to be a safe integer
102
+ above 1 and equal to `pid`. On Windows it is a pid, so `pgid` has to be
103
+ absent. The check is made against the durable record rather than trusted
104
+ from it, because `process.kill(-0, "SIGKILL")` would signal this host's own
105
+ process group.
106
+ 4. That group is not this process's group, and its pid is not this process's
107
+ pid. The host's real process group is read from the operating system,
108
+ because a stored number can claim anything and the shell that started this
109
+ host shares its group.
110
+ 5. The number still names the process the record describes. A record written
111
+ before this machine booted names a pid from a pid space that no longer
112
+ exists; within one boot, the recorded start time has to match the start time
113
+ the operating system reports for that pid.
114
+
115
+ ## No evidence never authorizes a kill
116
+
117
+ Two of those guards are questions put to `ps`: this process's own group, and
118
+ when the recorded pid started. Either can go unanswered on a host with no
119
+ usable `ps`.
120
+
121
+ An unanswered guard refuses. A guard that did not run is not a guard that
122
+ passed, so a record whose identity could not be verified is kept rather than
123
+ signalled.
124
+
125
+ The probe is deliberately unhelpful to anyone trying to fool it. It runs
126
+ `/bin/ps` by absolute path, never a `PATH` lookup, under `LC_ALL=C` and `TZ=UTC`
127
+ in a minimal environment, with a five-second `SIGKILL` deadline. Start times
128
+ are parsed explicitly as UTC, independent of the host runtime's timezone.
129
+ Live cleanup on Linux instead reads group membership, start times, and zombie
130
+ state directly from `/proc`, so it works without `procps`. Missing processes
131
+ are skipped; unreadable or malformed data leaves cleanup unverified. Other
132
+ POSIX hosts use `/bin/ps` for live cleanup with the same timezone and parsing.
133
+ The crash-recovery sweep still uses the `ps` probes described here.
134
+ The probe reads the
135
+ `pgid` column as one run of decimal digits and nothing else: `Number.parseInt`
136
+ reads a prefix, so `"12 34"`, `"12abc"`, and `"0x10"` would each become a
137
+ number that is not this host's group, silently pass the own-group comparison,
138
+ and suppress the refusal that exists to say the comparison could not be made.
139
+
140
+ ## Refusals, and which ones are final
141
+
142
+ Every refusal also decides whether the record is retired. Retiring says in the
143
+ journal that nothing was signalled, which stops every later incarnation
144
+ re-examining a number the operating system has moved on from. Only a refusal a
145
+ later incarnation cannot answer differently is final.
146
+
147
+ | Refusal | What it means | Retired |
148
+ | --------------------- | ----------------------------------------------------------- | ------- |
149
+ | `owner-alive` | the incarnation that started it is still running | no |
150
+ | `identity-unverified` | this host could not read the pid's start time | no |
151
+ | `own-group-unknown` | this host could not read its own process group | no |
152
+ | `kill-failed` | the signal was refused, so it is tried again | no |
153
+ | `no-group` | it shared its owner's group, so there is no group to signal | yes |
154
+ | `own-group` | it named this host's own group or pid | yes |
155
+ | `invalid-record` | its numbers name nothing this platform may signal | yes |
156
+ | `pre-boot` | it was written before this machine booted | yes |
157
+ | `process-gone` | the pid it names does not exist | yes |
158
+ | `identity-mismatch` | the pid exists but did not start when the record says | yes |
159
+
160
+ A retirement that fails to commit is logged rather than propagated. The process
161
+ is already dead and the record stays inherited, so the next incarnation reads
162
+ it, finds the pid gone, and retires it then; failing the whole sweep would take
163
+ the host down for a bookkeeping write.
164
+
165
+ ## The one deliberate leak
166
+
167
+ `identityToleranceMs` is 2000. It covers two gaps at once: `ps` reports
168
+ `lstart` with one-second granularity, and `uptime` places the boot instant to
169
+ the nearest second.
170
+
171
+ The boot tolerance points backwards, so a record written moments after boot is
172
+ read as predating it and refused. That refusal is `pre-boot`, which retires the
173
+ record, so a group spawned inside that two-second window is never reaped by any
174
+ later incarnation either. It is a leak rather than a retry, and it is the
175
+ deliberate price of refusing to kill on an instant the host can only place to
176
+ the nearest second.
177
+
178
+ ## Windows
179
+
180
+ Windows has no `lstart` and no process groups, so two guards cannot be answered
181
+ there: the identity check falls back to the boot-time comparison alone, and
182
+ there is no own-group refusal to make. `taskkill /T /F` walks the tree down
183
+ from the recorded pid instead. This is a documented weaker guarantee on an
184
+ unsupported platform, not an oversight.
185
+
186
+ ## Next
187
+
188
+ [Contain child processes](../guides/contain-child-processes.md) is the
189
+ task-shaped version of this page: the layers to compose, the ledger to choose,
190
+ and how to read what the sweep decided.
@@ -0,0 +1,87 @@
1
+ ---
2
+ title: "Answer whether a run owner is alive"
3
+ description: "Wire HostLiveness.isAlive as the probe the engine consults before it steals a run, understand why the rule errs toward alive, and know where the sibling implementation disagrees."
4
+ ---
5
+
6
+ A durable run records the owner that holds it: a `hostId` and a pid. When
7
+ another process wants that run, it asks whether the recorded owner is still
8
+ alive. `HostLiveness.isAlive` is this package's answer.
9
+
10
+ Both ways of being wrong are expensive, and they are not equally expensive. A
11
+ wrong `true` strands a run until an operator intervenes. A wrong `false` runs
12
+ one run twice.
13
+
14
+ ## Wire the probe
15
+
16
+ ```ts
17
+ import { HostLiveness } from "@smthrs/platform-node"
18
+
19
+ const isAlive = HostLiveness.isAlive({ hostId: "engine-1" })
20
+ ```
21
+
22
+ `isAlive` returns a function from an owner to `Effect<boolean>`. The owner type
23
+ is structural: `{ hostId: string, pid: number }`, which is exactly the shape of
24
+ [`@smthrs/journal`](/api/journal)'s `OwnerId` minus its nonce, so an `OwnerId`
25
+ is accepted without this package depending on the journal to name a type.
26
+
27
+ `@smthrs/flows`' `NodeRuntime` defaults to this function, so a program that
28
+ composes the runtime gets it without asking.
29
+
30
+ ## The rule
31
+
32
+ The rule is asymmetric on purpose:
33
+
34
+ - **An owner on a different host is alive.** A pid means nothing across
35
+ machines, and the process table this probe reads is only this machine's.
36
+ - **An owner on this host is dead only when the signal-0 probe reports
37
+ `ESRCH`.** Every other result preserves liveness.
38
+
39
+ `process.kill(pid, 0)` sends no signal. `EPERM` means
40
+ the process exists and belongs to another user, which is still a live owner
41
+ this host must not rob. A throw that is not an object at all carries no code,
42
+ and reading through it rather than off it is what keeps that from crashing the
43
+ probe: a thrown string or `null` is an answer nobody gave, which counts as a
44
+ live owner.
45
+
46
+ ## The residual risk
47
+
48
+ Pid reuse. An owner whose pid was recycled by an unrelated program reads as
49
+ alive, and its run waits for an operator.
50
+
51
+ That is the safe direction. Nothing about a recycled pid can tell this process
52
+ whether the run is still being driven, and the cost of guessing wrong the other
53
+ way is two hosts executing one run.
54
+
55
+ ## Substitute a better answer where you have one
56
+
57
+ A multi-process deployment with a supervisor or a lease system knows better
58
+ than any pid probe, and should answer from that instead. `isAlive` is one
59
+ implementation of a slot, not a fixed policy.
60
+
61
+ ## Know where the sibling disagrees
62
+
63
+ `@smthrs/run-store`'s `Ownership.sameHostPidProbe` fills the same
64
+ `LivenessCheck`. Both probes use the same `ESRCH`-only death rule.
65
+ `EPERM`, `EINVAL`, and unknown signal errors preserve liveness.
66
+
67
+ The signal-error rows describe valid same-host pids:
68
+
69
+ | Input | `HostLiveness.isAlive` | `Ownership.sameHostPidProbe` |
70
+ | ------------------------------------------------ | ---------------------- | ---------------------------- |
71
+ | signal error `ESRCH` | dead | dead |
72
+ | signal error `EPERM`, `EINVAL`, or unknown error | alive | alive |
73
+ | owner on a different `hostId` | alive | defer to expired lease |
74
+
75
+ `sameHostPidProbe` returns `false` for a foreign host without probing its pid.
76
+ The engine consults it after lease expiry, and the store verifies the expired
77
+ lease before allowing a steal. `HostLiveness.isAlive` returns `true` for a
78
+ foreign host, so runs on a permanently dead host wait for an operator.
79
+
80
+ Which answer a deployment gets depends on the entry point it used:
81
+ `@smthrs/flows`' `NodeRuntime` defaults to this function, while
82
+ [`@smthrs/cli`](/api/cli)'s `NodeControl` passes `sameHostPidProbe`.
83
+
84
+ `HostLiveness.isAlive` compares with its configured `hostId` and ignores the
85
+ `context` argument of `Ownership.LivenessCheck`. `sameHostPidProbe` compares
86
+ with `context.claimant.hostId`. Pick the probe for its cross-host policy and
87
+ source of host identity.