@graftland/plugin-remote 0.0.0-placeholder.0 → 0.2.0-beta.2

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 (380) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +75 -2
  3. package/README.zh-CN.md +71 -0
  4. package/README.zh-TW.md +71 -0
  5. package/dist/Auth-BElTC9_X.js +6 -0
  6. package/dist/Auth.d.ts +49 -0
  7. package/dist/Auth.d.ts.map +1 -0
  8. package/dist/Auth.js +8 -0
  9. package/dist/Auth.js.map +1 -0
  10. package/dist/Bootstrap-MCwivGN1.js +9 -0
  11. package/dist/ConfigDirectory-BCC6q2R4.js +5 -0
  12. package/dist/Contract-CcpSIJm4.js +121 -0
  13. package/dist/Contract.d.ts +71 -0
  14. package/dist/Contract.d.ts.map +1 -0
  15. package/dist/Contract.js +1 -0
  16. package/dist/Contract.js.map +1 -0
  17. package/dist/Errors-oPsTLY7l.js +45 -0
  18. package/dist/Errors.d.ts +67 -0
  19. package/dist/Errors.d.ts.map +1 -0
  20. package/dist/Errors.js +47 -0
  21. package/dist/Errors.js.map +1 -0
  22. package/dist/FailureGroup-BcH0XOBi.js +53 -0
  23. package/dist/Framing-zaYdOJnT.js +61 -0
  24. package/dist/Graft-BsYq3F-J.js +985 -0
  25. package/dist/Instance.d.ts +7 -0
  26. package/dist/Instance.d.ts.map +1 -0
  27. package/dist/Instance.js +14 -0
  28. package/dist/Instance.js.map +1 -0
  29. package/dist/Packages-B1TPk8pa.js +111 -0
  30. package/dist/Peer-IJgFK6mD.js +342 -0
  31. package/dist/ProcessObservation-DEGrEMfP.js +38 -0
  32. package/dist/ServeLifecycle-CJM0gG5B.js +24 -0
  33. package/dist/Testing.d.ts +26 -0
  34. package/dist/Testing.d.ts.map +1 -0
  35. package/dist/Testing.js +69 -0
  36. package/dist/Testing.js.map +1 -0
  37. package/dist/Transport-DULzpsgR.js +6 -0
  38. package/dist/Transport.d.ts +39 -0
  39. package/dist/Transport.d.ts.map +1 -0
  40. package/dist/Transport.js +8 -0
  41. package/dist/Transport.js.map +1 -0
  42. package/dist/WatchdogProtocol-BZmVxrBP.js +17 -0
  43. package/dist/_virtual/_rolldown/runtime.js +12 -0
  44. package/dist/bin.d.ts +1 -0
  45. package/dist/bin.js +28275 -0
  46. package/dist/bin.js.map +1 -0
  47. package/dist/childRuntime-DSqtFN9o.js +188 -0
  48. package/dist/cleanup-BPWr-5U9.js +13 -0
  49. package/dist/command-9zrHdbwT.js +7 -0
  50. package/dist/connectionEnded-DUgcobEd.js +9 -0
  51. package/dist/directTransport-DrexuPSm.js +5 -0
  52. package/dist/entry-SYsx9VNb.js +708 -0
  53. package/dist/host/auth/bearer.d.ts +5 -0
  54. package/dist/host/auth/bearer.d.ts.map +1 -0
  55. package/dist/host/auth/bearer.js +4 -0
  56. package/dist/host/auth/bearer.js.map +1 -0
  57. package/dist/host/auth/jwt.d.ts +5 -0
  58. package/dist/host/auth/jwt.d.ts.map +1 -0
  59. package/dist/host/auth/jwt.js +4 -0
  60. package/dist/host/auth/jwt.js.map +1 -0
  61. package/dist/host/auth/mtls.d.ts +8 -0
  62. package/dist/host/auth/mtls.d.ts.map +1 -0
  63. package/dist/host/auth/mtls.js +34 -0
  64. package/dist/host/auth/mtls.js.map +1 -0
  65. package/dist/host/auth/none.d.ts +3 -0
  66. package/dist/host/auth/none.d.ts.map +1 -0
  67. package/dist/host/auth/none.js +13 -0
  68. package/dist/host/auth/none.js.map +1 -0
  69. package/dist/host/command.d.ts +22 -0
  70. package/dist/host/command.d.ts.map +1 -0
  71. package/dist/host/command.js +61 -0
  72. package/dist/host/command.js.map +1 -0
  73. package/dist/host/local.d.ts +4 -0
  74. package/dist/host/local.d.ts.map +1 -0
  75. package/dist/host/local.js +52 -0
  76. package/dist/host/local.js.map +1 -0
  77. package/dist/host/unix.d.ts +11 -0
  78. package/dist/host/unix.d.ts.map +1 -0
  79. package/dist/host/unix.js +39 -0
  80. package/dist/host/unix.js.map +1 -0
  81. package/dist/host/websocket.d.ts +13 -0
  82. package/dist/host/websocket.d.ts.map +1 -0
  83. package/dist/host/websocket.js +36 -0
  84. package/dist/host/websocket.js.map +1 -0
  85. package/dist/host/worker.d.ts +4 -0
  86. package/dist/host/worker.d.ts.map +1 -0
  87. package/dist/host/worker.js +52 -0
  88. package/dist/host/worker.js.map +1 -0
  89. package/dist/importer-D7zSgqxq.js +347 -0
  90. package/dist/index.d.ts +29 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +86 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/internal/Certificates.js +182 -0
  95. package/dist/internal/Certificates.js.map +1 -0
  96. package/dist/internal/FailureGroup.js +55 -0
  97. package/dist/internal/FailureGroup.js.map +1 -0
  98. package/dist/internal/Limits.d.ts +1 -0
  99. package/dist/internal/Limits.js +17 -0
  100. package/dist/internal/Limits.js.map +1 -0
  101. package/dist/internal/Peer.js +6 -0
  102. package/dist/internal/Peer.js.map +1 -0
  103. package/dist/internal/ServeLifecycle.js +26 -0
  104. package/dist/internal/ServeLifecycle.js.map +1 -0
  105. package/dist/internal/Supervisor.js +7 -0
  106. package/dist/internal/Supervisor.js.map +1 -0
  107. package/dist/internal/assembly.d.ts +5 -0
  108. package/dist/internal/assembly.js +138 -0
  109. package/dist/internal/assembly.js.map +1 -0
  110. package/dist/internal/auth/mtls.js +23 -0
  111. package/dist/internal/auth/mtls.js.map +1 -0
  112. package/dist/internal/auth/token.js +19 -0
  113. package/dist/internal/auth/token.js.map +1 -0
  114. package/dist/internal/auth/tokenCredentials.d.ts +8 -0
  115. package/dist/internal/auth/tokenCredentials.d.ts.map +1 -0
  116. package/dist/internal/auth/tokenCredentials.js +33 -0
  117. package/dist/internal/auth/tokenCredentials.js.map +1 -0
  118. package/dist/internal/child.js +125 -0
  119. package/dist/internal/child.js.map +1 -0
  120. package/dist/internal/childErrors.d.ts +33 -0
  121. package/dist/internal/childErrors.d.ts.map +1 -0
  122. package/dist/internal/childErrors.js +29 -0
  123. package/dist/internal/childErrors.js.map +1 -0
  124. package/dist/internal/childRuntime.js +59 -0
  125. package/dist/internal/childRuntime.js.map +1 -0
  126. package/dist/internal/cleanup.js +15 -0
  127. package/dist/internal/cleanup.js.map +1 -0
  128. package/dist/internal/config.js +6 -0
  129. package/dist/internal/config.js.map +1 -0
  130. package/dist/internal/control.js +42 -0
  131. package/dist/internal/control.js.map +1 -0
  132. package/dist/internal/credentials.d.ts +44 -0
  133. package/dist/internal/credentials.d.ts.map +1 -0
  134. package/dist/internal/credentials.js +54 -0
  135. package/dist/internal/credentials.js.map +1 -0
  136. package/dist/internal/directTransport.d.ts +3 -0
  137. package/dist/internal/directTransport.js +7 -0
  138. package/dist/internal/directTransport.js.map +1 -0
  139. package/dist/internal/entry.d.ts +9 -0
  140. package/dist/internal/entry.d.ts.map +1 -0
  141. package/dist/internal/entry.js +144 -0
  142. package/dist/internal/entry.js.map +1 -0
  143. package/dist/internal/entryConfig.d.ts +202 -0
  144. package/dist/internal/entryConfig.d.ts.map +1 -0
  145. package/dist/internal/entryConfig.js +176 -0
  146. package/dist/internal/entryConfig.js.map +1 -0
  147. package/dist/internal/execution.d.ts +5 -0
  148. package/dist/internal/execution.js +43 -0
  149. package/dist/internal/execution.js.map +1 -0
  150. package/dist/internal/follow.js +11 -0
  151. package/dist/internal/follow.js.map +1 -0
  152. package/dist/internal/forkTree.js +7 -0
  153. package/dist/internal/forkTree.js.map +1 -0
  154. package/dist/internal/host/local.js +28 -0
  155. package/dist/internal/host/local.js.map +1 -0
  156. package/dist/internal/host/runner.js +100 -0
  157. package/dist/internal/host/runner.js.map +1 -0
  158. package/dist/internal/host.js +71 -0
  159. package/dist/internal/host.js.map +1 -0
  160. package/dist/internal/importer.js +18 -0
  161. package/dist/internal/importer.js.map +1 -0
  162. package/dist/internal/listenerStartup.js +17 -0
  163. package/dist/internal/listenerStartup.js.map +1 -0
  164. package/dist/internal/loadModule.js +20 -0
  165. package/dist/internal/loadModule.js.map +1 -0
  166. package/dist/internal/platform.js +9 -0
  167. package/dist/internal/platform.js.map +1 -0
  168. package/dist/internal/port.d.ts +13 -0
  169. package/dist/internal/port.d.ts.map +1 -0
  170. package/dist/internal/port.js +275 -0
  171. package/dist/internal/port.js.map +1 -0
  172. package/dist/internal/release.js +25 -0
  173. package/dist/internal/release.js.map +1 -0
  174. package/dist/internal/runner/Bootstrap.js +11 -0
  175. package/dist/internal/runner/Bootstrap.js.map +1 -0
  176. package/dist/internal/runner/Connection.d.ts +11 -0
  177. package/dist/internal/runner/Connection.js +56 -0
  178. package/dist/internal/runner/Connection.js.map +1 -0
  179. package/dist/internal/runner/Execution.js +115 -0
  180. package/dist/internal/runner/Execution.js.map +1 -0
  181. package/dist/internal/runner/Framing.d.ts +11 -0
  182. package/dist/internal/runner/Framing.d.ts.map +1 -0
  183. package/dist/internal/runner/Framing.js +63 -0
  184. package/dist/internal/runner/Framing.js.map +1 -0
  185. package/dist/internal/runner/Local.js +46 -0
  186. package/dist/internal/runner/Local.js.map +1 -0
  187. package/dist/internal/runner/Lock.js +25 -0
  188. package/dist/internal/runner/Lock.js.map +1 -0
  189. package/dist/internal/runner/Multiplex.d.ts +5 -0
  190. package/dist/internal/runner/Multiplex.js +49 -0
  191. package/dist/internal/runner/Multiplex.js.map +1 -0
  192. package/dist/internal/runner/Packages.d.ts +3 -0
  193. package/dist/internal/runner/Packages.js +108 -0
  194. package/dist/internal/runner/Packages.js.map +1 -0
  195. package/dist/internal/runner/ProcessObservation.js +40 -0
  196. package/dist/internal/runner/ProcessObservation.js.map +1 -0
  197. package/dist/internal/runner/Processes.js +83 -0
  198. package/dist/internal/runner/Processes.js.map +1 -0
  199. package/dist/internal/runner/Retention.js +13 -0
  200. package/dist/internal/runner/Retention.js.map +1 -0
  201. package/dist/internal/runner/Store.js +78 -0
  202. package/dist/internal/runner/Store.js.map +1 -0
  203. package/dist/internal/runner/Supervisor.js +375 -0
  204. package/dist/internal/runner/Supervisor.js.map +1 -0
  205. package/dist/internal/runner/Watchdog.js +47 -0
  206. package/dist/internal/runner/Watchdog.js.map +1 -0
  207. package/dist/internal/runner/WatchdogProtocol.js +19 -0
  208. package/dist/internal/runner/WatchdogProtocol.js.map +1 -0
  209. package/dist/internal/runner/Wire.d.ts +5 -0
  210. package/dist/internal/runner/Wire.js +64 -0
  211. package/dist/internal/runner/Wire.js.map +1 -0
  212. package/dist/internal/runner/accept.js +57 -0
  213. package/dist/internal/runner/accept.js.map +1 -0
  214. package/dist/internal/runner/command.js +9 -0
  215. package/dist/internal/runner/command.js.map +1 -0
  216. package/dist/internal/runner/connectionEnded.js +11 -0
  217. package/dist/internal/runner/connectionEnded.js.map +1 -0
  218. package/dist/internal/runner/model.d.ts +17 -0
  219. package/dist/internal/runner/model.d.ts.map +1 -0
  220. package/dist/internal/runner/model.js +231 -0
  221. package/dist/internal/runner/model.js.map +1 -0
  222. package/dist/internal/serve.js +60 -0
  223. package/dist/internal/serve.js.map +1 -0
  224. package/dist/internal/services.d.ts +18 -0
  225. package/dist/internal/services.d.ts.map +1 -0
  226. package/dist/internal/services.js +22 -0
  227. package/dist/internal/services.js.map +1 -0
  228. package/dist/internal/socketChannel.js +24 -0
  229. package/dist/internal/socketChannel.js.map +1 -0
  230. package/dist/internal/stdioChannel.js +23 -0
  231. package/dist/internal/stdioChannel.js.map +1 -0
  232. package/dist/internal/supervisorPlugin.js +1 -0
  233. package/dist/internal/supervisorPlugin.js.map +1 -0
  234. package/dist/internal/transportOptions.d.ts +18 -0
  235. package/dist/internal/transportOptions.d.ts.map +1 -0
  236. package/dist/internal/watchdogMain.d.ts +1 -0
  237. package/dist/internal/watchdogMain.js +55 -0
  238. package/dist/internal/watchdogMain.js.map +1 -0
  239. package/dist/internal/websocket.js +46 -0
  240. package/dist/internal/websocket.js.map +1 -0
  241. package/dist/internal/websocketServer.js +61 -0
  242. package/dist/internal/websocketServer.js.map +1 -0
  243. package/dist/internal/workerBootstrap.js +9 -0
  244. package/dist/internal/workerBootstrap.js.map +1 -0
  245. package/dist/internal/workerChannel.js +24 -0
  246. package/dist/internal/workerChannel.js.map +1 -0
  247. package/dist/internal/workerMain.d.ts +1 -0
  248. package/dist/internal/workerMain.js +18 -0
  249. package/dist/internal/workerMain.js.map +1 -0
  250. package/dist/port-Blbh8tms.js +285 -0
  251. package/dist/release-BY4Mlluy.js +23 -0
  252. package/dist/rolldown-runtime-DYf_mQCB.js +34 -0
  253. package/dist/runner/auth/bearer.d.ts +7 -0
  254. package/dist/runner/auth/bearer.d.ts.map +1 -0
  255. package/dist/runner/auth/bearer.js +42 -0
  256. package/dist/runner/auth/bearer.js.map +1 -0
  257. package/dist/runner/auth/jwt.d.ts +19 -0
  258. package/dist/runner/auth/jwt.d.ts.map +1 -0
  259. package/dist/runner/auth/jwt.js +65 -0
  260. package/dist/runner/auth/jwt.js.map +1 -0
  261. package/dist/runner/auth/mtls.d.ts +11 -0
  262. package/dist/runner/auth/mtls.d.ts.map +1 -0
  263. package/dist/runner/auth/mtls.js +48 -0
  264. package/dist/runner/auth/mtls.js.map +1 -0
  265. package/dist/runner/auth/none.d.ts +3 -0
  266. package/dist/runner/auth/none.d.ts.map +1 -0
  267. package/dist/runner/auth/none.js +13 -0
  268. package/dist/runner/auth/none.js.map +1 -0
  269. package/dist/runner/index.d.ts +3 -0
  270. package/dist/runner/index.d.ts.map +1 -0
  271. package/dist/runner/index.js +71 -0
  272. package/dist/runner/index.js.map +1 -0
  273. package/dist/runner/stdio.d.ts +7 -0
  274. package/dist/runner/stdio.d.ts.map +1 -0
  275. package/dist/runner/stdio.js +39 -0
  276. package/dist/runner/stdio.js.map +1 -0
  277. package/dist/runner/unix.d.ts +7 -0
  278. package/dist/runner/unix.d.ts.map +1 -0
  279. package/dist/runner/unix.js +42 -0
  280. package/dist/runner/unix.js.map +1 -0
  281. package/dist/runner/websocket.d.ts +28 -0
  282. package/dist/runner/websocket.d.ts.map +1 -0
  283. package/dist/runner/websocket.js +77 -0
  284. package/dist/runner/websocket.js.map +1 -0
  285. package/dist/socketChannel-KmtzF-9G.js +3658 -0
  286. package/dist/supervisorPlugin-Inb1S5IV.js +737 -0
  287. package/dist/token-v5ne2I0-.js +17 -0
  288. package/dist/tokenCredentials-WUJm2AKm.js +31 -0
  289. package/dist/websocketServer-MXcCJx0v.js +58 -0
  290. package/dist/workerChannel-P82YdNjh.js +27 -0
  291. package/package.json +71 -11
  292. package/src/Auth.ts +62 -0
  293. package/src/Contract.ts +100 -0
  294. package/src/Errors.ts +82 -0
  295. package/src/Instance.ts +12 -0
  296. package/src/Testing.ts +135 -0
  297. package/src/Transport.ts +52 -0
  298. package/src/bin.ts +145 -0
  299. package/src/host/auth/bearer.ts +10 -0
  300. package/src/host/auth/jwt.ts +10 -0
  301. package/src/host/auth/mtls.ts +48 -0
  302. package/src/host/auth/none.ts +13 -0
  303. package/src/host/command.ts +131 -0
  304. package/src/host/local.ts +41 -0
  305. package/src/host/unix.ts +65 -0
  306. package/src/host/websocket.ts +66 -0
  307. package/src/host/worker.ts +90 -0
  308. package/src/index.ts +115 -0
  309. package/src/internal/Certificates.ts +330 -0
  310. package/src/internal/FailureGroup.ts +176 -0
  311. package/src/internal/Limits.ts +12 -0
  312. package/src/internal/Peer.ts +4 -0
  313. package/src/internal/ServeLifecycle.ts +53 -0
  314. package/src/internal/Supervisor.ts +14 -0
  315. package/src/internal/assembly.ts +337 -0
  316. package/src/internal/auth/mtls.ts +40 -0
  317. package/src/internal/auth/token.ts +26 -0
  318. package/src/internal/auth/tokenCredentials.ts +65 -0
  319. package/src/internal/child.ts +323 -0
  320. package/src/internal/childErrors.ts +44 -0
  321. package/src/internal/childRuntime.ts +111 -0
  322. package/src/internal/cleanup.ts +34 -0
  323. package/src/internal/config.ts +8 -0
  324. package/src/internal/control.ts +49 -0
  325. package/src/internal/credentials.ts +112 -0
  326. package/src/internal/directTransport.ts +38 -0
  327. package/src/internal/entry.ts +288 -0
  328. package/src/internal/entryConfig.ts +190 -0
  329. package/src/internal/execution.ts +121 -0
  330. package/src/internal/follow.ts +17 -0
  331. package/src/internal/forkTree.ts +13 -0
  332. package/src/internal/host/local.ts +53 -0
  333. package/src/internal/host/runner.ts +187 -0
  334. package/src/internal/host.ts +209 -0
  335. package/src/internal/importer.ts +27 -0
  336. package/src/internal/listenerStartup.ts +55 -0
  337. package/src/internal/loadModule.ts +23 -0
  338. package/src/internal/platform.ts +12 -0
  339. package/src/internal/port.ts +623 -0
  340. package/src/internal/release.ts +71 -0
  341. package/src/internal/runner/Bootstrap.ts +9 -0
  342. package/src/internal/runner/Connection.ts +184 -0
  343. package/src/internal/runner/Execution.ts +244 -0
  344. package/src/internal/runner/Framing.ts +122 -0
  345. package/src/internal/runner/Local.ts +73 -0
  346. package/src/internal/runner/Lock.ts +29 -0
  347. package/src/internal/runner/Multiplex.ts +120 -0
  348. package/src/internal/runner/Packages.ts +178 -0
  349. package/src/internal/runner/ProcessObservation.ts +63 -0
  350. package/src/internal/runner/Processes.ts +109 -0
  351. package/src/internal/runner/Retention.ts +49 -0
  352. package/src/internal/runner/Store.ts +160 -0
  353. package/src/internal/runner/Supervisor.ts +901 -0
  354. package/src/internal/runner/Watchdog.ts +83 -0
  355. package/src/internal/runner/WatchdogProtocol.ts +12 -0
  356. package/src/internal/runner/Wire.ts +99 -0
  357. package/src/internal/runner/accept.ts +103 -0
  358. package/src/internal/runner/command.ts +15 -0
  359. package/src/internal/runner/connectionEnded.ts +28 -0
  360. package/src/internal/runner/model.ts +364 -0
  361. package/src/internal/serve.ts +117 -0
  362. package/src/internal/services.ts +74 -0
  363. package/src/internal/socketChannel.ts +64 -0
  364. package/src/internal/stdioChannel.ts +25 -0
  365. package/src/internal/supervisorPlugin.ts +67 -0
  366. package/src/internal/transportOptions.ts +17 -0
  367. package/src/internal/watchdogMain.ts +72 -0
  368. package/src/internal/websocket.ts +81 -0
  369. package/src/internal/websocketServer.ts +152 -0
  370. package/src/internal/workerBootstrap.ts +6 -0
  371. package/src/internal/workerChannel.ts +54 -0
  372. package/src/internal/workerMain.ts +23 -0
  373. package/src/runner/auth/bearer.ts +66 -0
  374. package/src/runner/auth/jwt.ts +114 -0
  375. package/src/runner/auth/mtls.ts +37 -0
  376. package/src/runner/auth/none.ts +13 -0
  377. package/src/runner/index.ts +97 -0
  378. package/src/runner/stdio.ts +76 -0
  379. package/src/runner/unix.ts +53 -0
  380. package/src/runner/websocket.ts +143 -0
@@ -0,0 +1,11 @@
1
+ import { Effect, Result, Schema } from "effect";
2
+ declare const FrameError_base: Schema.Class<FrameError, Schema.TaggedStruct<"FrameError", {
3
+ readonly detail: Schema.String;
4
+ }>, import("effect/Cause").YieldableError & {
5
+ readonly brand: unique symbol;
6
+ }>;
7
+ export declare class FrameError extends FrameError_base {
8
+ get message(): string;
9
+ }
10
+ export {};
11
+ //# sourceMappingURL=Framing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Framing.d.ts","names":[],"sources":["../../../src/internal/runner/Framing.ts"],"mappings":";;;;WAImB;;qBAFN,mBAAmB;MAIlB"}
@@ -0,0 +1,63 @@
1
+ import { Array, Effect, MutableRef, Option, Result, Schema } from "effect";
2
+ // src/internal/runner/Framing.ts
3
+ var FrameError = class extends Schema.TaggedError()("FrameError", { detail: Schema.String }) {
4
+ get message() {
5
+ return this.detail;
6
+ }
7
+ };
8
+ /** A complete byte stream ended; malformed trailing bytes remain FrameError. */
9
+ var EndOfStream = class extends Schema.TaggedError()("RunnerEndOfStream", {}) {
10
+ get message() {
11
+ return "Runner byte channel ended";
12
+ }
13
+ };
14
+ const maxPayload = 1048576;
15
+ const invalid = (detail) => FrameError.make({ detail });
16
+ /** Version 2 carries only channel and length; request admission belongs to port. */
17
+ const encode = (frame) => Effect.gen(function* () {
18
+ if (frame.payload.byteLength > 1048576) return yield* invalid("Runner frame exceeds the payload limit");
19
+ const bytes = new Uint8Array(8 + frame.payload.byteLength);
20
+ bytes.set([
21
+ 2,
22
+ frame.channel,
23
+ 0,
24
+ 0
25
+ ]);
26
+ new DataView(bytes.buffer).setUint32(4, frame.payload.byteLength);
27
+ bytes.set(frame.payload, 8);
28
+ return bytes;
29
+ });
30
+ /** Check a message boundary; the decoder still validates the frame's contents. */
31
+ const isCompleteFrame = (bytes) => bytes.byteLength >= 8 && new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(4) === bytes.byteLength - 8;
32
+ /** The decoder owns its byte buffer. Results expose malformed frames without throwing through a generator. */
33
+ const decoder = () => {
34
+ const pending = MutableRef.make(Result.succeed(/* @__PURE__ */ new Uint8Array(0)));
35
+ const decode = (chunk) => Result.flatMap(MutableRef.get(pending), (previous) => {
36
+ const bytes = new Uint8Array(previous.length + chunk.length);
37
+ bytes.set(previous);
38
+ bytes.set(chunk, previous.length);
39
+ const frames = Array.unfold(0, (offset) => {
40
+ if (bytes.length - offset < 8) return Option.none();
41
+ const header = new DataView(bytes.buffer, offset, 8);
42
+ const channel = header.getUint8(1);
43
+ const length = header.getUint32(4);
44
+ if (header.getUint8(0) !== 2 || channel !== 0 && channel !== 1 || header.getUint16(2) !== 0 || length > 1048576) return Option.some([Result.fail(invalid("Invalid runner frame header or payload length")), bytes.length]);
45
+ const end = offset + 8 + length;
46
+ if (end > bytes.length) return Option.none();
47
+ return Option.some([Result.succeed({
48
+ channel,
49
+ payload: bytes.subarray(offset + 8, end)
50
+ }), end]);
51
+ });
52
+ const result = Result.all(frames);
53
+ MutableRef.set(pending, Result.map(result, (frames) => bytes.subarray(Array.reduce(frames, 0, (used, frame) => used + 8 + frame.payload.length))));
54
+ return result;
55
+ });
56
+ return {
57
+ decode,
58
+ finish: Effect.suspend(() => Effect.fromResult(Result.flatMap(MutableRef.get(pending), (bytes) => bytes.length === 0 ? Result.succeed(void 0) : Result.fail(invalid("Runner connection ended inside a frame")))))
59
+ };
60
+ };
61
+ export { EndOfStream, FrameError, decoder, encode, isCompleteFrame, maxPayload };
62
+
63
+ //# sourceMappingURL=Framing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Framing.js","names":[],"sources":["../../../src/internal/runner/Framing.ts"],"sourcesContent":["import { Array, Effect, MutableRef, Option, Result, Schema } from \"effect\"\n\nexport class FrameError extends Schema.TaggedError<\n\tFrameError,\n\t{ readonly brand: unique symbol }\n>()(\"FrameError\", { detail: Schema.String }) {\n\toverride get message() {\n\t\treturn this.detail\n\t}\n}\n/** A complete byte stream ended; malformed trailing bytes remain FrameError. */\nexport class EndOfStream extends Schema.TaggedError<\n\tEndOfStream,\n\t{ readonly brand: unique symbol }\n>()(\"RunnerEndOfStream\", {}) {\n\toverride get message() {\n\t\treturn \"Runner byte channel ended\"\n\t}\n}\nexport type Channel = 0 | 1\nexport interface Frame {\n\treadonly channel: Channel\n\treadonly payload: Uint8Array\n}\nexport const headerSize = 8\nexport const maxPayload = 1024 * 1024\nconst invalid = (detail: string) => FrameError.make({ detail })\n\n/** Version 2 carries only channel and length; request admission belongs to port. */\nexport const encode = (frame: Frame) =>\n\tEffect.gen(function* () {\n\t\tif (frame.payload.byteLength > maxPayload)\n\t\t\treturn yield* invalid(\"Runner frame exceeds the payload limit\")\n\t\tconst bytes = new Uint8Array(headerSize + frame.payload.byteLength)\n\t\tbytes.set([2, frame.channel, 0, 0])\n\t\tnew DataView(bytes.buffer).setUint32(4, frame.payload.byteLength)\n\t\tbytes.set(frame.payload, headerSize)\n\t\treturn bytes\n\t})\n\n/** Check a message boundary; the decoder still validates the frame's contents. */\nexport const isCompleteFrame = (bytes: Uint8Array): boolean =>\n\tbytes.byteLength >= headerSize &&\n\tnew DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(\n\t\t4,\n\t) ===\n\t\tbytes.byteLength - headerSize\n\n/** The decoder owns its byte buffer. Results expose malformed frames without throwing through a generator. */\nexport const decoder = () => {\n\tconst pending = MutableRef.make<Result.Result<Uint8Array, FrameError>>(\n\t\tResult.succeed(new Uint8Array(0)),\n\t)\n\tconst decode = (\n\t\tchunk: Uint8Array,\n\t): Result.Result<ReadonlyArray<Frame>, FrameError> =>\n\t\tResult.flatMap(MutableRef.get(pending), (previous) => {\n\t\t\tconst bytes = new Uint8Array(previous.length + chunk.length)\n\t\t\tbytes.set(previous)\n\t\t\tbytes.set(chunk, previous.length)\n\t\t\tconst frames = Array.unfold(\n\t\t\t\t0,\n\t\t\t\t(\n\t\t\t\t\toffset,\n\t\t\t\t): Option.Option<\n\t\t\t\t\treadonly [Result.Result<Frame, FrameError>, number]\n\t\t\t\t> => {\n\t\t\t\t\tif (bytes.length - offset < headerSize) return Option.none()\n\t\t\t\t\tconst header = new DataView(bytes.buffer, offset, headerSize)\n\t\t\t\t\tconst channel = header.getUint8(1)\n\t\t\t\t\tconst length = header.getUint32(4)\n\t\t\t\t\tif (\n\t\t\t\t\t\theader.getUint8(0) !== 2 ||\n\t\t\t\t\t\t(channel !== 0 && channel !== 1) ||\n\t\t\t\t\t\theader.getUint16(2) !== 0 ||\n\t\t\t\t\t\tlength > maxPayload\n\t\t\t\t\t)\n\t\t\t\t\t\treturn Option.some([\n\t\t\t\t\t\t\tResult.fail(\n\t\t\t\t\t\t\t\tinvalid(\"Invalid runner frame header or payload length\"),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tbytes.length,\n\t\t\t\t\t\t])\n\t\t\t\t\tconst end = offset + headerSize + length\n\t\t\t\t\tif (end > bytes.length) return Option.none()\n\t\t\t\t\treturn Option.some([\n\t\t\t\t\t\tResult.succeed({\n\t\t\t\t\t\t\tchannel,\n\t\t\t\t\t\t\tpayload: bytes.subarray(offset + headerSize, end),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tend,\n\t\t\t\t\t])\n\t\t\t\t},\n\t\t\t)\n\t\t\tconst result = Result.all(frames)\n\t\t\tMutableRef.set(\n\t\t\t\tpending,\n\t\t\t\tResult.map(result, (frames) =>\n\t\t\t\t\tbytes.subarray(\n\t\t\t\t\t\tArray.reduce(\n\t\t\t\t\t\t\tframes,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t(used, frame) => used + headerSize + frame.payload.length,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\treturn result\n\t\t})\n\treturn {\n\t\tdecode,\n\t\tfinish: Effect.suspend(() =>\n\t\t\tEffect.fromResult(\n\t\t\t\tResult.flatMap(MutableRef.get(pending), (bytes) =>\n\t\t\t\t\tbytes.length === 0\n\t\t\t\t\t\t? Result.succeed(undefined)\n\t\t\t\t\t\t: Result.fail(invalid(\"Runner connection ended inside a frame\")),\n\t\t\t\t),\n\t\t\t),\n\t\t),\n\t}\n}\n"],"mappings":";;AAEA,IAAa,aAAb,cAAgC,OAAO,YAGrC,CAAC,CAAC,cAAc,EAAE,QAAQ,OAAO,OAAO,CAAC,CAAC,CAAC;CAC5C,IAAa,UAAU;EACtB,OAAO,KAAK;CACb;AACD;;AAEA,IAAa,cAAb,cAAiC,OAAO,YAGtC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;CAC5B,IAAa,UAAU;EACtB,OAAO;CACR;AACD;AAOA,MAAa,aAAa;AAC1B,MAAM,WAAW,WAAmB,WAAW,KAAK,EAAE,OAAO,CAAC;;AAG9D,MAAa,UAAU,UACtB,OAAO,IAAI,aAAa;CACvB,IAAI,MAAM,QAAQ,aAAA,SACjB,OAAO,OAAO,QAAQ,wCAAwC;CAC/D,MAAM,QAAQ,IAAI,WAAA,IAAwB,MAAM,QAAQ,UAAU;CAClE,MAAM,IAAI;EAAC;EAAG,MAAM;EAAS;EAAG;CAAC,CAAC;CAClC,IAAI,SAAS,MAAM,MAAM,CAAC,CAAC,UAAU,GAAG,MAAM,QAAQ,UAAU;CAChE,MAAM,IAAI,MAAM,SAAA,CAAmB;CACnC,OAAO;AACR,CAAC;;AAGF,MAAa,mBAAmB,UAC/B,MAAM,cAAA,KACN,IAAI,SAAS,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU,CAAC,CAAC,UAC9D,CACD,MACC,MAAM,aAAA;;AAGR,MAAa,gBAAgB;CAC5B,MAAM,UAAU,WAAW,KAC1B,OAAO,wBAAQ,IAAI,WAAW,CAAC,CAAC,CACjC;CACA,MAAM,UACL,UAEA,OAAO,QAAQ,WAAW,IAAI,OAAO,IAAI,aAAa;EACrD,MAAM,QAAQ,IAAI,WAAW,SAAS,SAAS,MAAM,MAAM;EAC3D,MAAM,IAAI,QAAQ;EAClB,MAAM,IAAI,OAAO,SAAS,MAAM;EAChC,MAAM,SAAS,MAAM,OACpB,IAEC,WAGI;GACJ,IAAI,MAAM,SAAS,SAAA,GAAqB,OAAO,OAAO,KAAK;GAC3D,MAAM,SAAS,IAAI,SAAS,MAAM,QAAQ,QAAA,CAAkB;GAC5D,MAAM,UAAU,OAAO,SAAS,CAAC;GACjC,MAAM,SAAS,OAAO,UAAU,CAAC;GACjC,IACC,OAAO,SAAS,CAAC,MAAM,KACtB,YAAY,KAAK,YAAY,KAC9B,OAAO,UAAU,CAAC,MAAM,KACxB,SAAA,SAEA,OAAO,OAAO,KAAK,CAClB,OAAO,KACN,QAAQ,+CAA+C,CACxD,GACA,MAAM,MACP,CAAC;GACF,MAAM,MAAM,SAAA,IAAsB;GAClC,IAAI,MAAM,MAAM,QAAQ,OAAO,OAAO,KAAK;GAC3C,OAAO,OAAO,KAAK,CAClB,OAAO,QAAQ;IACd;IACA,SAAS,MAAM,SAAS,SAAA,GAAqB,GAAG;GACjD,CAAC,GACD,GACD,CAAC;EACF,CACD;EACA,MAAM,SAAS,OAAO,IAAI,MAAM;EAChC,WAAW,IACV,SACA,OAAO,IAAI,SAAS,WACnB,MAAM,SACL,MAAM,OACL,QACA,IACC,MAAM,UAAU,OAAA,IAAoB,MAAM,QAAQ,MACpD,CACD,CACD,CACD;EACA,OAAO;CACR,CAAC;CACF,OAAO;EACN;EACA,QAAQ,OAAO,cACd,OAAO,WACN,OAAO,QAAQ,WAAW,IAAI,OAAO,IAAI,UACxC,MAAM,WAAW,IACd,OAAO,QAAQ,KAAA,CAAS,IACxB,OAAO,KAAK,QAAQ,wCAAwC,CAAC,CACjE,CACD,CACD;CACD;AACD"}
@@ -0,0 +1,46 @@
1
+ import { make } from "../FailureGroup.js";
2
+ import { LocalTerminationTimeout, TransportError } from "../../Errors.js";
3
+ import { make as make$1 } from "../port.js";
4
+ import { stdinExitTimeout } from "./ProcessObservation.js";
5
+ import { Cause, Effect, Fiber, Option } from "effect";
6
+ // src/internal/runner/Local.ts
7
+ /** Direct execution observers stay alive until exit, including forced cleanup. */
8
+ const connect = Effect.fnUntraced(function* (execution, options) {
9
+ const failures = yield* make();
10
+ const exited = yield* execution.exited.pipe(Effect.forkScoped);
11
+ const peer = yield* make$1(execution.channel, options);
12
+ yield* failures.run(Effect.raceFirst(peer.await, Fiber.join(exited).pipe(Effect.flatMap(Effect.fail))));
13
+ const report = (cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : failures.fail(TransportError.make({ cause })).pipe(Effect.andThen(peer.fail(TransportError.make({ cause }))));
14
+ yield* failures.run(execution.failure);
15
+ return {
16
+ ...peer,
17
+ pid: execution.pid,
18
+ ...execution.threadId === void 0 ? {} : { threadId: execution.threadId },
19
+ exited,
20
+ resources: yield* Effect.scope,
21
+ transport: {
22
+ ...peer,
23
+ failure: failures.await,
24
+ report
25
+ },
26
+ diagnostics: Fiber.await(exited).pipe(Effect.andThen(failures.cause)),
27
+ terminate: (graceful) => Effect.gen(function* () {
28
+ yield* failures.close;
29
+ if (!graceful) return;
30
+ const status = yield* peer.end.pipe(Effect.catchCauseIf(Cause.hasInterruptsOnly, () => Effect.void), Effect.andThen(Fiber.join(exited)), Effect.interruptible, Effect.timeoutOrElse({
31
+ duration: stdinExitTimeout,
32
+ orElse: () => LocalTerminationTimeout.make({
33
+ ...Option.match(execution.pid, {
34
+ onNone: () => ({}),
35
+ onSome: (pid) => ({ pid })
36
+ }),
37
+ ...execution.threadId === void 0 ? {} : { threadId: execution.threadId }
38
+ })
39
+ }));
40
+ if (status.exitCode !== 0 || status.statusCause.reasons.length > 0) return yield* status;
41
+ })
42
+ };
43
+ });
44
+ export { connect };
45
+
46
+ //# sourceMappingURL=Local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Local.js","names":["FailureGroup.make","Port.make"],"sources":["../../../src/internal/runner/Local.ts"],"sourcesContent":["import { Cause, Effect, Fiber, Option } from \"effect\"\nimport type { Execution } from \"../directTransport\"\nimport * as FailureGroup from \"../FailureGroup\"\nimport {\n\tLocalTerminationTimeout,\n\tProcessExited,\n\tTransportError,\n} from \"../../Errors\"\nimport * as Port from \"../port\"\nimport { stdinExitTimeout } from \"./ProcessObservation\"\n\n/** Direct execution observers stay alive until exit, including forced cleanup. */\nexport const connect = Effect.fnUntraced(function* (\n\texecution: Execution,\n\toptions: Port.Options,\n) {\n\tconst failures = yield* FailureGroup.make<ProcessExited | TransportError>()\n\tconst exited = yield* execution.exited.pipe(Effect.forkScoped)\n\tconst peer = yield* Port.make(execution.channel, options)\n\tyield* failures.run(\n\t\tEffect.raceFirst(\n\t\t\tpeer.await,\n\t\t\tFiber.join(exited).pipe(Effect.flatMap(Effect.fail)),\n\t\t),\n\t)\n\tconst report = (cause: Cause.Cause<unknown>) =>\n\t\tCause.hasInterruptsOnly(cause)\n\t\t\t? Effect.void\n\t\t\t: failures\n\t\t\t\t\t.fail(TransportError.make({ cause }))\n\t\t\t\t\t.pipe(Effect.andThen(peer.fail(TransportError.make({ cause }))))\n\tyield* failures.run(execution.failure)\n\n\treturn {\n\t\t...peer,\n\t\tpid: execution.pid,\n\t\t...(execution.threadId === undefined\n\t\t\t? {}\n\t\t\t: { threadId: execution.threadId }),\n\t\texited,\n\t\tresources: yield* Effect.scope,\n\t\ttransport: { ...peer, failure: failures.await, report },\n\t\tdiagnostics: Fiber.await(exited).pipe(Effect.andThen(failures.cause)),\n\t\tterminate: (graceful: boolean) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Stop observation before intentionally ending stdin or killing the process.\n\t\t\t\tyield* failures.close\n\t\t\t\tif (!graceful) return\n\t\t\t\t// If this fails, the execution scope forces termination and waits for exit.\n\t\t\t\tconst status = yield* peer.end.pipe(\n\t\t\t\t\t// Peer EOF can interrupt the writer as its output ends. Still confirm the unit's exit.\n\t\t\t\t\tEffect.catchCauseIf(Cause.hasInterruptsOnly, () => Effect.void),\n\t\t\t\t\tEffect.andThen(Fiber.join(exited)),\n\t\t\t\t\tEffect.interruptible,\n\t\t\t\t\tEffect.timeoutOrElse({\n\t\t\t\t\t\tduration: stdinExitTimeout,\n\t\t\t\t\t\torElse: () =>\n\t\t\t\t\t\t\tLocalTerminationTimeout.make({\n\t\t\t\t\t\t\t\t...Option.match(execution.pid, {\n\t\t\t\t\t\t\t\t\tonNone: () => ({}),\n\t\t\t\t\t\t\t\t\tonSome: (pid) => ({ pid }),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t...(execution.threadId === undefined\n\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t: { threadId: execution.threadId }),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tif (status.exitCode !== 0 || status.statusCause.reasons.length > 0)\n\t\t\t\t\treturn yield* status\n\t\t\t}),\n\t}\n})\n"],"mappings":";;;;;;;AAYA,MAAa,UAAU,OAAO,WAAW,WACxC,WACA,SACC;CACD,MAAM,WAAW,OAAOA,KAAkD;CAC1E,MAAM,SAAS,OAAO,UAAU,OAAO,KAAK,OAAO,UAAU;CAC7D,MAAM,OAAO,OAAOC,OAAU,UAAU,SAAS,OAAO;CACxD,OAAO,SAAS,IACf,OAAO,UACN,KAAK,OACL,MAAM,KAAK,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,OAAO,IAAI,CAAC,CACpD,CACD;CACA,MAAM,UAAU,UACf,MAAM,kBAAkB,KAAK,IAC1B,OAAO,OACP,SACC,KAAK,eAAe,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CACpC,KAAK,OAAO,QAAQ,KAAK,KAAK,eAAe,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CACnE,OAAO,SAAS,IAAI,UAAU,OAAO;CAErC,OAAO;EACN,GAAG;EACH,KAAK,UAAU;EACf,GAAI,UAAU,aAAa,KAAA,IACxB,CAAC,IACD,EAAE,UAAU,UAAU,SAAS;EAClC;EACA,WAAW,OAAO,OAAO;EACzB,WAAW;GAAE,GAAG;GAAM,SAAS,SAAS;GAAO;EAAO;EACtD,aAAa,MAAM,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,KAAK,CAAC;EACpE,YAAY,aACX,OAAO,IAAI,aAAa;GAEvB,OAAO,SAAS;GAChB,IAAI,CAAC,UAAU;GAEf,MAAM,SAAS,OAAO,KAAK,IAAI,KAE9B,OAAO,aAAa,MAAM,yBAAyB,OAAO,IAAI,GAC9D,OAAO,QAAQ,MAAM,KAAK,MAAM,CAAC,GACjC,OAAO,eACP,OAAO,cAAc;IACpB,UAAU;IACV,cACC,wBAAwB,KAAK;KAC5B,GAAG,OAAO,MAAM,UAAU,KAAK;MAC9B,eAAe,CAAC;MAChB,SAAS,SAAS,EAAE,IAAI;KACzB,CAAC;KACD,GAAI,UAAU,aAAa,KAAA,IACxB,CAAC,IACD,EAAE,UAAU,UAAU,SAAS;IACnC,CAAC;GACH,CAAC,CACF;GACA,IAAI,OAAO,aAAa,KAAK,OAAO,YAAY,QAAQ,SAAS,GAChE,OAAO,OAAO;EAChB,CAAC;CACH;AACD,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { StateDirectoryLocked } from "./model.js";
2
+ import { Cause, Effect, FileSystem, Path } from "effect";
3
+ // src/internal/runner/Lock.ts
4
+ /** SQLite owns the local directory lock for the enclosing scope, including failed startup. */
5
+ const acquire = (directory) => Effect.gen(function* () {
6
+ const fs = yield* FileSystem.FileSystem;
7
+ const path = yield* Path.Path;
8
+ yield* fs.makeDirectory(directory, { recursive: true }).pipe(Effect.uninterruptible);
9
+ const { DatabaseSync } = yield* Effect.promise(() => import("node:sqlite")).pipe(Effect.uninterruptible);
10
+ const locked = (cause) => StateDirectoryLocked.make({
11
+ detail: "The runner state directory is already owned or cannot be locked",
12
+ cause: Cause.die(cause)
13
+ });
14
+ const db = yield* Effect.acquireRelease(Effect.try({
15
+ try: () => new DatabaseSync(path.join(directory, "owner.sqlite")),
16
+ catch: locked
17
+ }), (db) => Effect.sync(() => db.close()));
18
+ yield* Effect.try({
19
+ try: () => db.exec("BEGIN EXCLUSIVE"),
20
+ catch: locked
21
+ });
22
+ });
23
+ export { acquire };
24
+
25
+ //# sourceMappingURL=Lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lock.js","names":[],"sources":["../../../src/internal/runner/Lock.ts"],"sourcesContent":["import { Cause, Effect, FileSystem, Path } from \"effect\"\nimport { StateDirectoryLocked } from \"./model\"\n\n/** SQLite owns the local directory lock for the enclosing scope, including failed startup. */\nexport const acquire = (directory: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem\n\t\tconst path = yield* Path.Path\n\t\tyield* fs\n\t\t\t.makeDirectory(directory, { recursive: true })\n\t\t\t.pipe(Effect.uninterruptible)\n\t\tconst { DatabaseSync } = yield* Effect.promise(\n\t\t\t() => import(\"node:sqlite\"),\n\t\t).pipe(Effect.uninterruptible)\n\t\tconst locked = (cause: unknown) =>\n\t\t\tStateDirectoryLocked.make({\n\t\t\t\tdetail:\n\t\t\t\t\t\"The runner state directory is already owned or cannot be locked\",\n\t\t\t\tcause: Cause.die(cause),\n\t\t\t})\n\t\tconst db = yield* Effect.acquireRelease(\n\t\t\tEffect.try({\n\t\t\t\ttry: () => new DatabaseSync(path.join(directory, \"owner.sqlite\")),\n\t\t\t\tcatch: locked,\n\t\t\t}),\n\t\t\t(db) => Effect.sync(() => db.close()),\n\t\t)\n\t\tyield* Effect.try({ try: () => db.exec(\"BEGIN EXCLUSIVE\"), catch: locked })\n\t})\n"],"mappings":";;;;AAIA,MAAa,WAAW,cACvB,OAAO,IAAI,aAAa;CACvB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,OAAO,GACL,cAAc,WAAW,EAAE,WAAW,KAAK,CAAC,CAAC,CAC7C,KAAK,OAAO,eAAe;CAC7B,MAAM,EAAE,iBAAiB,OAAO,OAAO,cAChC,OAAO,cACd,CAAC,CAAC,KAAK,OAAO,eAAe;CAC7B,MAAM,UAAU,UACf,qBAAqB,KAAK;EACzB,QACC;EACD,OAAO,MAAM,IAAI,KAAK;CACvB,CAAC;CACF,MAAM,KAAK,OAAO,OAAO,eACxB,OAAO,IAAI;EACV,WAAW,IAAI,aAAa,KAAK,KAAK,WAAW,cAAc,CAAC;EAChE,OAAO;CACR,CAAC,IACA,OAAO,OAAO,WAAW,GAAG,MAAM,CAAC,CACrC;CACA,OAAO,OAAO,IAAI;EAAE,WAAW,GAAG,KAAK,iBAAiB;EAAG,OAAO;CAAO,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,5 @@
1
+ import "../../Errors.js";
2
+ import "../port.js";
3
+ import "./Framing.js";
4
+ import { Effect } from "effect";
5
+ import { Socket } from "effect/socket";
@@ -0,0 +1,49 @@
1
+ import { TransportError } from "../../Errors.js";
2
+ import { make as make$1 } from "../FailureGroup.js";
3
+ import { EndOfStream, decoder, encode } from "./Framing.js";
4
+ import { Cause, Effect, Fiber, Option, Queue, Sink, Stream, TxQueue } from "effect";
5
+ // src/internal/runner/Multiplex.ts
6
+ /** Ports own admission and ACK backpressure. This layer only frames and separates session/instance bytes. */
7
+ const make = Effect.fnUntraced(function* (channel) {
8
+ const group = yield* make$1();
9
+ const incoming = {
10
+ 0: yield* Queue.unbounded(),
11
+ 1: yield* Queue.unbounded()
12
+ };
13
+ const outgoing = {
14
+ 0: yield* TxQueue.unbounded(),
15
+ 1: yield* TxQueue.unbounded()
16
+ };
17
+ const next = Effect.tx(Effect.gen(function* () {
18
+ const session = yield* TxQueue.poll(outgoing[0]);
19
+ if (Option.isSome(session)) return session.value;
20
+ const instance = yield* TxQueue.poll(outgoing[1]);
21
+ if (Option.isSome(instance)) return instance.value;
22
+ if ((yield* TxQueue.isDone(outgoing[0])) && (yield* TxQueue.isDone(outgoing[1]))) return yield* Cause.done();
23
+ return yield* Effect.txRetry;
24
+ }));
25
+ const writing = yield* group.run(Stream.fromEffectRepeat(next).pipe(Stream.run(channel.output), Effect.asVoid));
26
+ const decoder$1 = decoder();
27
+ yield* group.run(channel.input.pipe(Stream.runForEach((bytes) => Effect.fromResult(decoder$1.decode(bytes)).pipe(Effect.flatMap((frames) => Effect.forEach(frames, (frame) => Queue.offer(incoming[frame.channel], frame.payload), { discard: true })))), Effect.andThen(decoder$1.finish), Effect.andThen(Effect.fail(EndOfStream.make({}))), Effect.mapError((error) => error._tag === "TransportError" ? error : TransportError.make({ cause: Cause.fail(error) }))));
28
+ return {
29
+ await: group.await,
30
+ fail: group.fail,
31
+ end: Effect.tx(TxQueue.end(outgoing[0]).pipe(Effect.andThen(TxQueue.end(outgoing[1])))).pipe(Effect.andThen(Fiber.join(writing))),
32
+ send: (id, payload) => group.race(encode({
33
+ channel: id,
34
+ payload
35
+ }).pipe(Effect.flatMap((bytes) => TxQueue.offer(outgoing[id], bytes)), Effect.asVoid)),
36
+ take: (id) => group.race(Queue.take(incoming[id]))
37
+ };
38
+ });
39
+ Effect.fnUntraced(function* (socket) {
40
+ const reader = yield* socket.reader;
41
+ const writer = yield* socket.writer;
42
+ return yield* make({
43
+ input: Stream.fromEffectRepeat(reader.pull).pipe(Stream.flattenIterable, Stream.map((bytes) => typeof bytes === "string" ? new TextEncoder().encode(bytes) : bytes), Stream.mapError((error) => TransportError.make({ cause: Cause.fail(error) }))),
44
+ output: Sink.forEach((bytes) => writer.write(bytes)).pipe(Sink.mapError((error) => TransportError.make({ cause: Cause.fail(error) })))
45
+ });
46
+ });
47
+ export { make };
48
+
49
+ //# sourceMappingURL=Multiplex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Multiplex.js","names":["FailureGroup.make","decoder","Framing.decoder","Framing.encode"],"sources":["../../../src/internal/runner/Multiplex.ts"],"sourcesContent":["import {\n\tCause,\n\tEffect,\n\tFiber,\n\tOption,\n\tQueue,\n\tSink,\n\tStream,\n\tTxQueue,\n} from \"effect\"\nimport type { Socket } from \"effect/socket\"\nimport { TransportError } from \"../../Errors\"\nimport type { Channel as ByteChannel } from \"../port\"\nimport * as FailureGroup from \"../FailureGroup\"\nimport * as Framing from \"./Framing\"\n\nexport interface Peer {\n\treadonly await: Effect.Effect<never, TransportError>\n\treadonly fail: (error: TransportError) => Effect.Effect<void>\n\treadonly end: Effect.Effect<void, TransportError>\n\treadonly send: (\n\t\tchannel: Framing.Channel,\n\t\tpayload: Uint8Array,\n\t) => Effect.Effect<void, TransportError | Framing.FrameError>\n\treadonly take: (\n\t\tchannel: Framing.Channel,\n\t) => Effect.Effect<Uint8Array, TransportError>\n}\n/** Ports own admission and ACK backpressure. This layer only frames and separates session/instance bytes. */\nexport const make = Effect.fnUntraced(function* (\n\tchannel: ByteChannel,\n): Effect.fn.Return<Peer, never, import(\"effect\").Scope.Scope> {\n\tconst group = yield* FailureGroup.make<TransportError>()\n\tconst incoming = {\n\t\t0: yield* Queue.unbounded<Uint8Array>(),\n\t\t1: yield* Queue.unbounded<Uint8Array>(),\n\t}\n\tconst outgoing = {\n\t\t0: yield* TxQueue.unbounded<Uint8Array, Cause.Done>(),\n\t\t1: yield* TxQueue.unbounded<Uint8Array, Cause.Done>(),\n\t}\n\tconst next = Effect.tx(\n\t\tEffect.gen(function* () {\n\t\t\tconst session = yield* TxQueue.poll(outgoing[0])\n\t\t\tif (Option.isSome(session)) return session.value\n\t\t\tconst instance = yield* TxQueue.poll(outgoing[1])\n\t\t\tif (Option.isSome(instance)) return instance.value\n\t\t\tif (\n\t\t\t\t(yield* TxQueue.isDone(outgoing[0])) &&\n\t\t\t\t(yield* TxQueue.isDone(outgoing[1]))\n\t\t\t)\n\t\t\t\treturn yield* Cause.done()\n\t\t\treturn yield* Effect.txRetry\n\t\t}),\n\t)\n\tconst writing = yield* group.run(\n\t\tStream.fromEffectRepeat(next).pipe(\n\t\t\tStream.run(channel.output),\n\t\t\tEffect.asVoid,\n\t\t),\n\t)\n\tconst decoder = Framing.decoder()\n\tyield* group.run(\n\t\tchannel.input.pipe(\n\t\t\tStream.runForEach((bytes) =>\n\t\t\t\tEffect.fromResult(decoder.decode(bytes)).pipe(\n\t\t\t\t\tEffect.flatMap((frames) =>\n\t\t\t\t\t\tEffect.forEach(\n\t\t\t\t\t\t\tframes,\n\t\t\t\t\t\t\t(frame) => Queue.offer(incoming[frame.channel], frame.payload),\n\t\t\t\t\t\t\t{ discard: true },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t\tEffect.andThen(decoder.finish),\n\t\t\tEffect.andThen(Effect.fail(Framing.EndOfStream.make({}))),\n\t\t\tEffect.mapError((error) =>\n\t\t\t\terror._tag === \"TransportError\"\n\t\t\t\t\t? error\n\t\t\t\t\t: TransportError.make({ cause: Cause.fail(error) }),\n\t\t\t),\n\t\t),\n\t)\n\treturn {\n\t\tawait: group.await,\n\t\tfail: group.fail,\n\t\tend: Effect.tx(\n\t\t\tTxQueue.end(outgoing[0]).pipe(Effect.andThen(TxQueue.end(outgoing[1]))),\n\t\t).pipe(Effect.andThen(Fiber.join(writing))),\n\t\tsend: (id, payload) =>\n\t\t\tgroup.race(\n\t\t\t\tFraming.encode({ channel: id, payload }).pipe(\n\t\t\t\t\tEffect.flatMap((bytes) => TxQueue.offer(outgoing[id], bytes)),\n\t\t\t\t\tEffect.asVoid,\n\t\t\t\t),\n\t\t\t),\n\t\ttake: (id) => group.race(Queue.take(incoming[id])),\n\t}\n})\nexport const fromSocket = Effect.fnUntraced(function* (socket: Socket.Socket) {\n\tconst reader = yield* socket.reader\n\tconst writer = yield* socket.writer\n\treturn yield* make({\n\t\tinput: Stream.fromEffectRepeat(reader.pull).pipe(\n\t\t\tStream.flattenIterable,\n\t\t\tStream.map((bytes) =>\n\t\t\t\ttypeof bytes === \"string\" ? new TextEncoder().encode(bytes) : bytes,\n\t\t\t),\n\t\t\tStream.mapError((error) =>\n\t\t\t\tTransportError.make({ cause: Cause.fail(error) }),\n\t\t\t),\n\t\t),\n\t\toutput: Sink.forEach((bytes: Uint8Array) => writer.write(bytes)).pipe(\n\t\t\tSink.mapError((error) =>\n\t\t\t\tTransportError.make({ cause: Cause.fail(error) }),\n\t\t\t),\n\t\t),\n\t})\n})\n"],"mappings":";;;;;;AA6BA,MAAa,OAAO,OAAO,WAAW,WACrC,SAC8D;CAC9D,MAAM,QAAQ,OAAOA,OAAkC;CACvD,MAAM,WAAW;EAChB,GAAG,OAAO,MAAM,UAAsB;EACtC,GAAG,OAAO,MAAM,UAAsB;CACvC;CACA,MAAM,WAAW;EAChB,GAAG,OAAO,QAAQ,UAAkC;EACpD,GAAG,OAAO,QAAQ,UAAkC;CACrD;CACA,MAAM,OAAO,OAAO,GACnB,OAAO,IAAI,aAAa;EACvB,MAAM,UAAU,OAAO,QAAQ,KAAK,SAAS,EAAE;EAC/C,IAAI,OAAO,OAAO,OAAO,GAAG,OAAO,QAAQ;EAC3C,MAAM,WAAW,OAAO,QAAQ,KAAK,SAAS,EAAE;EAChD,IAAI,OAAO,OAAO,QAAQ,GAAG,OAAO,SAAS;EAC7C,KACE,OAAO,QAAQ,OAAO,SAAS,EAAE,OACjC,OAAO,QAAQ,OAAO,SAAS,EAAE,IAElC,OAAO,OAAO,MAAM,KAAK;EAC1B,OAAO,OAAO,OAAO;CACtB,CAAC,CACF;CACA,MAAM,UAAU,OAAO,MAAM,IAC5B,OAAO,iBAAiB,IAAI,CAAC,CAAC,KAC7B,OAAO,IAAI,QAAQ,MAAM,GACzB,OAAO,MACR,CACD;CACA,MAAMC,YAAUC,QAAgB;CAChC,OAAO,MAAM,IACZ,QAAQ,MAAM,KACb,OAAO,YAAY,UAClB,OAAO,WAAWD,UAAQ,OAAO,KAAK,CAAC,CAAC,CAAC,KACxC,OAAO,SAAS,WACf,OAAO,QACN,SACC,UAAU,MAAM,MAAM,SAAS,MAAM,UAAU,MAAM,OAAO,GAC7D,EAAE,SAAS,KAAK,CACjB,CACD,CACD,CACD,GACA,OAAO,QAAQA,UAAQ,MAAM,GAC7B,OAAO,QAAQ,OAAO,KAAA,YAAyB,KAAK,CAAC,CAAC,CAAC,CAAC,GACxD,OAAO,UAAU,UAChB,MAAM,SAAS,mBACZ,QACA,eAAe,KAAK,EAAE,OAAO,MAAM,KAAK,KAAK,EAAE,CAAC,CACpD,CACD,CACD;CACA,OAAO;EACN,OAAO,MAAM;EACb,MAAM,MAAM;EACZ,KAAK,OAAO,GACX,QAAQ,IAAI,SAAS,EAAE,CAAC,CAAC,KAAK,OAAO,QAAQ,QAAQ,IAAI,SAAS,EAAE,CAAC,CAAC,CACvE,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,KAAK,OAAO,CAAC,CAAC;EAC1C,OAAO,IAAI,YACV,MAAM,KACLE,OAAe;GAAE,SAAS;GAAI;EAAQ,CAAC,CAAC,CAAC,KACxC,OAAO,SAAS,UAAU,QAAQ,MAAM,SAAS,KAAK,KAAK,CAAC,GAC5D,OAAO,MACR,CACD;EACD,OAAO,OAAO,MAAM,KAAK,MAAM,KAAK,SAAS,GAAG,CAAC;CAClD;AACD,CAAC;AACyB,OAAO,WAAW,WAAW,QAAuB;CAC7E,MAAM,SAAS,OAAO,OAAO;CAC7B,MAAM,SAAS,OAAO,OAAO;CAC7B,OAAO,OAAO,KAAK;EAClB,OAAO,OAAO,iBAAiB,OAAO,IAAI,CAAC,CAAC,KAC3C,OAAO,iBACP,OAAO,KAAK,UACX,OAAO,UAAU,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,IAAI,KAC/D,GACA,OAAO,UAAU,UAChB,eAAe,KAAK,EAAE,OAAO,MAAM,KAAK,KAAK,EAAE,CAAC,CACjD,CACD;EACA,QAAQ,KAAK,SAAS,UAAsB,OAAO,MAAM,KAAK,CAAC,CAAC,CAAC,KAChE,KAAK,UAAU,UACd,eAAe,KAAK,EAAE,OAAO,MAAM,KAAK,KAAK,EAAE,CAAC,CACjD,CACD;CACD,CAAC;AACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import "./model.js";
2
+ import { Effect, FileSystem, Path } from "effect";
3
+ import { ChildProcessSpawner } from "effect/process";
@@ -0,0 +1,108 @@
1
+ import { PackageError } from "./model.js";
2
+ import { Array, Cause, Effect, FileSystem, Order, Path, Schema, Stream, String } from "effect";
3
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
4
+ import { createHash } from "node:crypto";
5
+ import process from "node:process";
6
+ import { fileURLToPath } from "node:url";
7
+ // src/internal/runner/Packages.ts
8
+ const Manifest = Schema.Struct({
9
+ name: Schema.String,
10
+ version: Schema.String
11
+ });
12
+ const verify = (actual, expected = {}) => expected.version !== void 0 && actual.version !== expected.version ? Effect.fail(PackageError.make({ detail: `Package version mismatch: expected ${expected.version}, received ${actual.version}` })) : expected.digest !== void 0 && actual.digest !== expected.digest ? Effect.fail(PackageError.make({ detail: `Package digest mismatch: expected ${expected.digest}, received ${actual.digest}` })) : Effect.void;
13
+ /** A path-sensitive SHA-256 of sorted entries and bytes, excluding every node_modules subtree. */
14
+ const digest = Effect.fnUntraced(function* (directory) {
15
+ const fs = yield* FileSystem.FileSystem;
16
+ const path = yield* Path.Path;
17
+ const hash = yield* Effect.sync(() => createHash("sha256").update("graft-package-sha256-v1\0"));
18
+ const visit = (relative) => Effect.gen(function* () {
19
+ const filename = path.join(directory, relative);
20
+ const info = yield* fs.stat(filename);
21
+ if (info.type !== "File" && info.type !== "Directory") return yield* PackageError.make({ detail: `Unsupported package entry: ${relative}` });
22
+ const name = new TextEncoder().encode(relative);
23
+ yield* Effect.sync(() => {
24
+ hash.update(`${info.type}:${name.byteLength}:${info.type === "File" ? info.size : 0}:`);
25
+ hash.update(name);
26
+ });
27
+ if (info.type === "File") yield* fs.stream(filename).pipe(Stream.runForEach((bytes) => Effect.sync(() => {
28
+ hash.update(bytes);
29
+ })));
30
+ else {
31
+ const entries = yield* fs.readDirectory(filename);
32
+ for (const entry of Array.sort(entries, Order.String)) {
33
+ if (entry === "node_modules") continue;
34
+ yield* visit(relative === "" ? entry : `${relative}/${entry}`);
35
+ }
36
+ }
37
+ });
38
+ yield* visit("");
39
+ return yield* Effect.sync(() => hash.digest("hex"));
40
+ });
41
+ /**
42
+ * Resolve using Node's import conditions without importing executable package code.
43
+ * The helper's cwd is the installation root and it inherits no NODE_OPTIONS/loaders.
44
+ * The installation directory and its package exports are trusted.
45
+ */
46
+ const resolve = Effect.fnUntraced(function* (root, specifier, includeDigest = false) {
47
+ const segments = String.split(specifier, "/");
48
+ const scoped = String.startsWith("@")(specifier);
49
+ const name = Array.join(Array.take(segments, scoped ? 2 : 1), "/");
50
+ const fs = yield* FileSystem.FileSystem;
51
+ const path = yield* Path.Path;
52
+ const installation = yield* fs.realPath(root);
53
+ const directory = yield* fs.realPath(path.join(installation, "node_modules", name));
54
+ const manifest = yield* fs.readFileString(path.join(directory, "package.json")).pipe(Effect.flatMap(Schema.decodeEffect(Schema.fromJsonString(Manifest))));
55
+ const resolved = yield* resolveEntry(installation, specifier);
56
+ const filename = yield* Effect.try({
57
+ try: () => fileURLToPath(resolved),
58
+ catch: (error) => PackageError.make({
59
+ detail: "The package export is not a file URL",
60
+ cause: Cause.die(error)
61
+ })
62
+ });
63
+ return {
64
+ directory,
65
+ entry: yield* fs.realPath(filename),
66
+ identity: {
67
+ ...manifest,
68
+ ...includeDigest ? { digest: yield* digest(directory) } : {}
69
+ }
70
+ };
71
+ }, Effect.catchTags({
72
+ PlatformError: (error) => Effect.fail(PackageError.make({
73
+ detail: "Reading the installed package failed",
74
+ cause: Cause.fail(error)
75
+ })),
76
+ SchemaError: (error) => Effect.fail(PackageError.make({
77
+ detail: "Reading the package manifest failed",
78
+ cause: Cause.fail(error)
79
+ }))
80
+ }));
81
+ const resolveEntry = (installation, specifier) => Effect.gen(function* () {
82
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
83
+ return yield* Effect.scoped(Effect.gen(function* () {
84
+ const child = yield* spawner.spawn(ChildProcess.make(process.execPath, [
85
+ "--input-type=module",
86
+ "--eval",
87
+ "process.stdout.write(import.meta.resolve(process.argv[1]))",
88
+ "--",
89
+ specifier
90
+ ], {
91
+ cwd: installation,
92
+ env: {},
93
+ stdin: "ignore",
94
+ stdout: "pipe",
95
+ stderr: "pipe"
96
+ }));
97
+ const [code, stdout, stderr] = yield* Effect.all([
98
+ child.exitCode,
99
+ child.stdout.pipe(Stream.decodeText(), Stream.mkString),
100
+ child.stderr.pipe(Stream.decodeText(), Stream.mkString)
101
+ ], { concurrency: "unbounded" });
102
+ if (code !== 0) return yield* PackageError.make({ detail: `Package resolution failed: ${stderr}` });
103
+ return stdout;
104
+ }));
105
+ });
106
+ export { digest, resolve, resolveEntry, verify };
107
+
108
+ //# sourceMappingURL=Packages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Packages.js","names":[],"sources":["../../../src/internal/runner/Packages.ts"],"sourcesContent":["import {\n\tArray,\n\tCause,\n\tEffect,\n\tFileSystem,\n\tOrder,\n\tPath,\n\tSchema,\n\tStream,\n\tString,\n} from \"effect\"\nimport type { PlatformError } from \"effect\"\nimport { ChildProcess, ChildProcessSpawner } from \"effect/process\"\n// @effect-diagnostics-next-line nodeBuiltinImport:off -- WebCrypto has no incremental digest API; package files are hashed as streams without buffering the directory.\nimport { createHash } from \"node:crypto\"\nimport process from \"node:process\"\nimport { fileURLToPath } from \"node:url\"\nimport { PackageError, type CodeIdentity } from \"./model\"\n\nconst Manifest = Schema.Struct({ name: Schema.String, version: Schema.String })\nexport interface Expected {\n\treadonly version?: string\n\treadonly digest?: string\n}\nexport const verify = (actual: CodeIdentity, expected: Expected = {}) =>\n\texpected.version !== undefined && actual.version !== expected.version\n\t\t? Effect.fail(\n\t\t\t\tPackageError.make({\n\t\t\t\t\tdetail: `Package version mismatch: expected ${expected.version}, received ${actual.version}`,\n\t\t\t\t}),\n\t\t\t)\n\t\t: expected.digest !== undefined && actual.digest !== expected.digest\n\t\t\t? Effect.fail(\n\t\t\t\t\tPackageError.make({\n\t\t\t\t\t\tdetail: `Package digest mismatch: expected ${expected.digest}, received ${actual.digest}`,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t: Effect.void\n\n/** A path-sensitive SHA-256 of sorted entries and bytes, excluding every node_modules subtree. */\nexport const digest = Effect.fnUntraced(function* (directory: string) {\n\tconst fs = yield* FileSystem.FileSystem\n\tconst path = yield* Path.Path\n\tconst hash = yield* Effect.sync(() =>\n\t\tcreateHash(\"sha256\").update(\"graft-package-sha256-v1\\0\"),\n\t)\n\tconst visit = (\n\t\trelative: string,\n\t): Effect.Effect<void, PackageError | PlatformError.PlatformError> =>\n\t\tEffect.gen(function* () {\n\t\t\tconst filename = path.join(directory, relative)\n\t\t\tconst info = yield* fs.stat(filename)\n\t\t\tif (info.type !== \"File\" && info.type !== \"Directory\")\n\t\t\t\treturn yield* PackageError.make({\n\t\t\t\t\tdetail: `Unsupported package entry: ${relative}`,\n\t\t\t\t})\n\t\t\tconst name = new TextEncoder().encode(relative)\n\t\t\tyield* Effect.sync(() => {\n\t\t\t\thash.update(\n\t\t\t\t\t`${info.type}:${name.byteLength}:${info.type === \"File\" ? info.size : 0}:`,\n\t\t\t\t)\n\t\t\t\thash.update(name)\n\t\t\t})\n\t\t\tif (info.type === \"File\") {\n\t\t\t\tyield* fs.stream(filename).pipe(\n\t\t\t\t\tStream.runForEach((bytes) =>\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\thash.update(bytes)\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tconst entries = yield* fs.readDirectory(filename)\n\t\t\t\tfor (const entry of Array.sort(entries, Order.String)) {\n\t\t\t\t\tif (entry === \"node_modules\") continue\n\t\t\t\t\tyield* visit(relative === \"\" ? entry : `${relative}/${entry}`)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\tyield* visit(\"\")\n\treturn yield* Effect.sync(() => hash.digest(\"hex\"))\n})\n\n/**\n * Resolve using Node's import conditions without importing executable package code.\n * The helper's cwd is the installation root and it inherits no NODE_OPTIONS/loaders.\n * The installation directory and its package exports are trusted.\n */\nexport const resolve = Effect.fnUntraced(\n\tfunction* (root: string, specifier: string, includeDigest: boolean = false) {\n\t\tconst segments = String.split(specifier, \"/\")\n\t\tconst scoped = String.startsWith(\"@\")(specifier)\n\t\tconst name = Array.join(Array.take(segments, scoped ? 2 : 1), \"/\")\n\t\tconst fs = yield* FileSystem.FileSystem\n\t\tconst path = yield* Path.Path\n\t\tconst installation = yield* fs.realPath(root)\n\t\tconst directory = yield* fs.realPath(\n\t\t\tpath.join(installation, \"node_modules\", name),\n\t\t)\n\t\tconst manifest = yield* fs\n\t\t\t.readFileString(path.join(directory, \"package.json\"))\n\t\t\t.pipe(\n\t\t\t\tEffect.flatMap(Schema.decodeEffect(Schema.fromJsonString(Manifest))),\n\t\t\t)\n\t\tconst resolved = yield* resolveEntry(installation, specifier)\n\t\tconst filename = yield* Effect.try({\n\t\t\ttry: () => fileURLToPath(resolved),\n\t\t\tcatch: (error) =>\n\t\t\t\tPackageError.make({\n\t\t\t\t\tdetail: \"The package export is not a file URL\",\n\t\t\t\t\tcause: Cause.die(error),\n\t\t\t\t}),\n\t\t})\n\t\tconst entry = yield* fs.realPath(filename)\n\t\tconst identity: CodeIdentity = {\n\t\t\t...manifest,\n\t\t\t...(includeDigest ? { digest: yield* digest(directory) } : {}),\n\t\t}\n\t\treturn { directory, entry, identity }\n\t},\n\tEffect.catchTags({\n\t\tPlatformError: (error) =>\n\t\t\tEffect.fail(\n\t\t\t\tPackageError.make({\n\t\t\t\t\tdetail: \"Reading the installed package failed\",\n\t\t\t\t\tcause: Cause.fail(error),\n\t\t\t\t}),\n\t\t\t),\n\t\tSchemaError: (error) =>\n\t\t\tEffect.fail(\n\t\t\t\tPackageError.make({\n\t\t\t\t\tdetail: \"Reading the package manifest failed\",\n\t\t\t\t\tcause: Cause.fail(error),\n\t\t\t\t}),\n\t\t\t),\n\t}),\n)\n\nexport const resolveEntry = (installation: string, specifier: string) =>\n\tEffect.gen(function* () {\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner\n\t\treturn yield* Effect.scoped(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst child = yield* spawner.spawn(\n\t\t\t\t\tChildProcess.make(\n\t\t\t\t\t\tprocess.execPath,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\"--input-type=module\",\n\t\t\t\t\t\t\t\"--eval\",\n\t\t\t\t\t\t\t\"process.stdout.write(import.meta.resolve(process.argv[1]))\",\n\t\t\t\t\t\t\t\"--\",\n\t\t\t\t\t\t\tspecifier,\n\t\t\t\t\t\t],\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcwd: installation,\n\t\t\t\t\t\t\tenv: {},\n\t\t\t\t\t\t\tstdin: \"ignore\",\n\t\t\t\t\t\t\tstdout: \"pipe\",\n\t\t\t\t\t\t\tstderr: \"pipe\",\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tconst [code, stdout, stderr] = yield* Effect.all(\n\t\t\t\t\t[\n\t\t\t\t\t\tchild.exitCode,\n\t\t\t\t\t\tchild.stdout.pipe(Stream.decodeText(), Stream.mkString),\n\t\t\t\t\t\tchild.stderr.pipe(Stream.decodeText(), Stream.mkString),\n\t\t\t\t\t],\n\t\t\t\t\t{ concurrency: \"unbounded\" },\n\t\t\t\t)\n\t\t\t\tif (code !== 0)\n\t\t\t\t\treturn yield* PackageError.make({\n\t\t\t\t\t\tdetail: `Package resolution failed: ${stderr}`,\n\t\t\t\t\t})\n\t\t\t\treturn stdout\n\t\t\t}),\n\t\t)\n\t})\n"],"mappings":";;;;;;;AAmBA,MAAM,WAAW,OAAO,OAAO;CAAE,MAAM,OAAO;CAAQ,SAAS,OAAO;AAAO,CAAC;AAK9E,MAAa,UAAU,QAAsB,WAAqB,CAAC,MAClE,SAAS,YAAY,KAAA,KAAa,OAAO,YAAY,SAAS,UAC3D,OAAO,KACP,aAAa,KAAK,EACjB,QAAQ,sCAAsC,SAAS,QAAQ,aAAa,OAAO,UACpF,CAAC,CACF,IACC,SAAS,WAAW,KAAA,KAAa,OAAO,WAAW,SAAS,SAC3D,OAAO,KACP,aAAa,KAAK,EACjB,QAAQ,qCAAqC,SAAS,OAAO,aAAa,OAAO,SAClF,CAAC,CACF,IACC,OAAO;;AAGZ,MAAa,SAAS,OAAO,WAAW,WAAW,WAAmB;CACrE,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,OAAO,OAAO,OAAO,WAC1B,WAAW,QAAQ,CAAC,CAAC,OAAO,2BAA2B,CACxD;CACA,MAAM,SACL,aAEA,OAAO,IAAI,aAAa;EACvB,MAAM,WAAW,KAAK,KAAK,WAAW,QAAQ;EAC9C,MAAM,OAAO,OAAO,GAAG,KAAK,QAAQ;EACpC,IAAI,KAAK,SAAS,UAAU,KAAK,SAAS,aACzC,OAAO,OAAO,aAAa,KAAK,EAC/B,QAAQ,8BAA8B,WACvC,CAAC;EACF,MAAM,OAAO,IAAI,YAAY,CAAC,CAAC,OAAO,QAAQ;EAC9C,OAAO,OAAO,WAAW;GACxB,KAAK,OACJ,GAAG,KAAK,KAAK,GAAG,KAAK,WAAW,GAAG,KAAK,SAAS,SAAS,KAAK,OAAO,EAAE,EACzE;GACA,KAAK,OAAO,IAAI;EACjB,CAAC;EACD,IAAI,KAAK,SAAS,QACjB,OAAO,GAAG,OAAO,QAAQ,CAAC,CAAC,KAC1B,OAAO,YAAY,UAClB,OAAO,WAAW;GACjB,KAAK,OAAO,KAAK;EAClB,CAAC,CACF,CACD;OACM;GACN,MAAM,UAAU,OAAO,GAAG,cAAc,QAAQ;GAChD,KAAK,MAAM,SAAS,MAAM,KAAK,SAAS,MAAM,MAAM,GAAG;IACtD,IAAI,UAAU,gBAAgB;IAC9B,OAAO,MAAM,aAAa,KAAK,QAAQ,GAAG,SAAS,GAAG,OAAO;GAC9D;EACD;CACD,CAAC;CACF,OAAO,MAAM,EAAE;CACf,OAAO,OAAO,OAAO,WAAW,KAAK,OAAO,KAAK,CAAC;AACnD,CAAC;;;;;;AAOD,MAAa,UAAU,OAAO,WAC7B,WAAW,MAAc,WAAmB,gBAAyB,OAAO;CAC3E,MAAM,WAAW,OAAO,MAAM,WAAW,GAAG;CAC5C,MAAM,SAAS,OAAO,WAAW,GAAG,CAAC,CAAC,SAAS;CAC/C,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,GAAG,GAAG;CACjE,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,eAAe,OAAO,GAAG,SAAS,IAAI;CAC5C,MAAM,YAAY,OAAO,GAAG,SAC3B,KAAK,KAAK,cAAc,gBAAgB,IAAI,CAC7C;CACA,MAAM,WAAW,OAAO,GACtB,eAAe,KAAK,KAAK,WAAW,cAAc,CAAC,CAAC,CACpD,KACA,OAAO,QAAQ,OAAO,aAAa,OAAO,eAAe,QAAQ,CAAC,CAAC,CACpE;CACD,MAAM,WAAW,OAAO,aAAa,cAAc,SAAS;CAC5D,MAAM,WAAW,OAAO,OAAO,IAAI;EAClC,WAAW,cAAc,QAAQ;EACjC,QAAQ,UACP,aAAa,KAAK;GACjB,QAAQ;GACR,OAAO,MAAM,IAAI,KAAK;EACvB,CAAC;CACH,CAAC;CAMD,OAAO;EAAE;EAAW,OAAA,OALC,GAAG,SAAS,QAAQ;EAKd,UAAA;GAH1B,GAAG;GACH,GAAI,gBAAgB,EAAE,QAAQ,OAAO,OAAO,SAAS,EAAE,IAAI,CAAC;EAE3B;CAAE;AACrC,GACA,OAAO,UAAU;CAChB,gBAAgB,UACf,OAAO,KACN,aAAa,KAAK;EACjB,QAAQ;EACR,OAAO,MAAM,KAAK,KAAK;CACxB,CAAC,CACF;CACD,cAAc,UACb,OAAO,KACN,aAAa,KAAK;EACjB,QAAQ;EACR,OAAO,MAAM,KAAK,KAAK;CACxB,CAAC,CACF;AACF,CAAC,CACF;AAEA,MAAa,gBAAgB,cAAsB,cAClD,OAAO,IAAI,aAAa;CACvB,MAAM,UAAU,OAAO,oBAAoB;CAC3C,OAAO,OAAO,OAAO,OACpB,OAAO,IAAI,aAAa;EACvB,MAAM,QAAQ,OAAO,QAAQ,MAC5B,aAAa,KACZ,QAAQ,UACR;GACC;GACA;GACA;GACA;GACA;EACD,GACA;GACC,KAAK;GACL,KAAK,CAAC;GACN,OAAO;GACP,QAAQ;GACR,QAAQ;EACT,CACD,CACD;EACA,MAAM,CAAC,MAAM,QAAQ,UAAU,OAAO,OAAO,IAC5C;GACC,MAAM;GACN,MAAM,OAAO,KAAK,OAAO,WAAW,GAAG,OAAO,QAAQ;GACtD,MAAM,OAAO,KAAK,OAAO,WAAW,GAAG,OAAO,QAAQ;EACvD,GACA,EAAE,aAAa,YAAY,CAC5B;EACA,IAAI,SAAS,GACZ,OAAO,OAAO,aAAa,KAAK,EAC/B,QAAQ,8BAA8B,SACvC,CAAC;EACF,OAAO;CACR,CAAC,CACF;AACD,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { make } from "../FailureGroup.js";
2
+ import { Array, Cause, Effect, Exit, Fiber, Ref, Schedule, Stream, String } from "effect";
3
+ // src/internal/runner/ProcessObservation.ts
4
+ /** Time allowed for a direct execution unit or launcher to exit after input EOF. */
5
+ const stdinExitTimeout = "1 second";
6
+ /** Readers outlive the failure monitor so forced termination still captures its diagnostic tail. */
7
+ const observe = Effect.fnUntraced(function* (child, options = {}) {
8
+ const failures = yield* make();
9
+ const tail = yield* Ref.make("");
10
+ const stdout = yield* (options.drainStdout === false ? Effect.void : Stream.runDrain(child.stdout)).pipe(Effect.forkScoped);
11
+ const stderr = yield* child.stderr.pipe(Stream.decodeText(), Stream.runForEach((text) => Ref.update(tail, (old) => String.takeRight(old + text, 8192))), Effect.forkScoped);
12
+ yield* failures.run(Fiber.join(stdout));
13
+ yield* failures.run(Fiber.join(stderr));
14
+ const exited = yield* Effect.gen(function* () {
15
+ const result = yield* Effect.exit(child.exitCode);
16
+ yield* child.isRunning.pipe(Effect.repeat({
17
+ schedule: Schedule.spaced("25 millis"),
18
+ while: (running) => running
19
+ }));
20
+ const err = yield* Fiber.await(stderr);
21
+ const out = yield* Fiber.await(stdout);
22
+ return {
23
+ code: Exit.isSuccess(result) ? result.value : null,
24
+ signal: null,
25
+ stderr: yield* Ref.get(tail),
26
+ cause: Array.reduce([
27
+ Exit.asVoid(result),
28
+ err,
29
+ out
30
+ ], Cause.empty, (cause, exit) => Exit.isFailure(exit) ? Cause.combine(cause, exit.cause) : cause)
31
+ };
32
+ }).pipe(Effect.forkScoped);
33
+ return {
34
+ exited: Fiber.join(exited),
35
+ failure: failures.await
36
+ };
37
+ });
38
+ export { observe, stdinExitTimeout };
39
+
40
+ //# sourceMappingURL=ProcessObservation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessObservation.js","names":["FailureGroup.make"],"sources":["../../../src/internal/runner/ProcessObservation.ts"],"sourcesContent":["import {\n\tArray,\n\tCause,\n\tEffect,\n\tExit,\n\tFiber,\n\tRef,\n\tSchedule,\n\tStream,\n\tString,\n} from \"effect\"\nimport type { PlatformError } from \"effect\"\nimport type { ChildProcessSpawner } from \"effect/process\"\nimport * as FailureGroup from \"../FailureGroup\"\n\n/** Time allowed for a direct execution unit or launcher to exit after input EOF. */\nexport const stdinExitTimeout = \"1 second\"\n\n/** Readers outlive the failure monitor so forced termination still captures its diagnostic tail. */\nexport const observe = Effect.fnUntraced(function* (\n\tchild: ChildProcessSpawner.ChildProcessHandle,\n\toptions: { readonly drainStdout?: boolean } = {},\n) {\n\tconst failures = yield* FailureGroup.make<PlatformError.PlatformError>()\n\tconst tail = yield* Ref.make(\"\")\n\t// Command transports own stdout as a protocol stream.\n\tconst stdout = yield* (\n\t\toptions.drainStdout === false ? Effect.void : Stream.runDrain(child.stdout)\n\t).pipe(Effect.forkScoped)\n\tconst stderr = yield* child.stderr.pipe(\n\t\tStream.decodeText(),\n\t\tStream.runForEach((text) =>\n\t\t\tRef.update(tail, (old) => String.takeRight(old + text, 8192)),\n\t\t),\n\t\tEffect.forkScoped,\n\t)\n\tyield* failures.run(Fiber.join(stdout))\n\tyield* failures.run(Fiber.join(stderr))\n\tconst exited = yield* Effect.gen(function* () {\n\t\tconst result = yield* Effect.exit(child.exitCode)\n\t\t// exitCode can fail before exit on an input error; isRunning follows Node's exit event.\n\t\tyield* child.isRunning.pipe(\n\t\t\tEffect.repeat({\n\t\t\t\tschedule: Schedule.spaced(\"25 millis\"),\n\t\t\t\twhile: (running) => running,\n\t\t\t}),\n\t\t)\n\t\tconst err = yield* Fiber.await(stderr)\n\t\tconst out = yield* Fiber.await(stdout)\n\t\treturn {\n\t\t\tcode: Exit.isSuccess(result) ? result.value : null,\n\t\t\tsignal: null,\n\t\t\tstderr: yield* Ref.get(tail),\n\t\t\tcause: Array.reduce(\n\t\t\t\t[Exit.asVoid(result), err, out],\n\t\t\t\tCause.empty,\n\t\t\t\t(cause: Cause.Cause<PlatformError.PlatformError>, exit) =>\n\t\t\t\t\tExit.isFailure(exit) ? Cause.combine(cause, exit.cause) : cause,\n\t\t\t),\n\t\t}\n\t}).pipe(Effect.forkScoped)\n\treturn { exited: Fiber.join(exited), failure: failures.await }\n})\n"],"mappings":";;;;AAgBA,MAAa,mBAAmB;;AAGhC,MAAa,UAAU,OAAO,WAAW,WACxC,OACA,UAA8C,CAAC,GAC9C;CACD,MAAM,WAAW,OAAOA,KAA+C;CACvE,MAAM,OAAO,OAAO,IAAI,KAAK,EAAE;CAE/B,MAAM,SAAS,QACd,QAAQ,gBAAgB,QAAQ,OAAO,OAAO,OAAO,SAAS,MAAM,MAAM,EAAA,CACzE,KAAK,OAAO,UAAU;CACxB,MAAM,SAAS,OAAO,MAAM,OAAO,KAClC,OAAO,WAAW,GAClB,OAAO,YAAY,SAClB,IAAI,OAAO,OAAO,QAAQ,OAAO,UAAU,MAAM,MAAM,IAAI,CAAC,CAC7D,GACA,OAAO,UACR;CACA,OAAO,SAAS,IAAI,MAAM,KAAK,MAAM,CAAC;CACtC,OAAO,SAAS,IAAI,MAAM,KAAK,MAAM,CAAC;CACtC,MAAM,SAAS,OAAO,OAAO,IAAI,aAAa;EAC7C,MAAM,SAAS,OAAO,OAAO,KAAK,MAAM,QAAQ;EAEhD,OAAO,MAAM,UAAU,KACtB,OAAO,OAAO;GACb,UAAU,SAAS,OAAO,WAAW;GACrC,QAAQ,YAAY;EACrB,CAAC,CACF;EACA,MAAM,MAAM,OAAO,MAAM,MAAM,MAAM;EACrC,MAAM,MAAM,OAAO,MAAM,MAAM,MAAM;EACrC,OAAO;GACN,MAAM,KAAK,UAAU,MAAM,IAAI,OAAO,QAAQ;GAC9C,QAAQ;GACR,QAAQ,OAAO,IAAI,IAAI,IAAI;GAC3B,OAAO,MAAM,OACZ;IAAC,KAAK,OAAO,MAAM;IAAG;IAAK;GAAG,GAC9B,MAAM,QACL,OAAiD,SACjD,KAAK,UAAU,IAAI,IAAI,MAAM,QAAQ,OAAO,KAAK,KAAK,IAAI,KAC5D;EACD;CACD,CAAC,CAAC,CAAC,KAAK,OAAO,UAAU;CACzB,OAAO;EAAE,QAAQ,MAAM,KAAK,MAAM;EAAG,SAAS,SAAS;CAAM;AAC9D,CAAC"}
@@ -0,0 +1,83 @@
1
+ import { ExecutionError, TerminationUnconfirmed } from "./model.js";
2
+ import { Cause, Effect, Option, Schedule, Stream, String } from "effect";
3
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
4
+ import process from "node:process";
5
+ // src/internal/runner/Processes.ts
6
+ const inspect = (pid) => Effect.scoped(Effect.gen(function* () {
7
+ const child = yield* (yield* ChildProcessSpawner.ChildProcessSpawner).spawn(ChildProcess.make("ps", [
8
+ "-p",
9
+ `${pid}`,
10
+ "-o",
11
+ "lstart=",
12
+ "-o",
13
+ "stat="
14
+ ], {
15
+ env: {
16
+ ...process.env,
17
+ LC_ALL: "C"
18
+ },
19
+ stdin: "ignore"
20
+ }));
21
+ const [code, output, stderr] = yield* Effect.all([
22
+ child.exitCode,
23
+ child.stdout.pipe(Stream.decodeText(), Stream.mkString),
24
+ child.stderr.pipe(Stream.decodeText(), Stream.mkString)
25
+ ], { concurrency: "unbounded" });
26
+ if (code === 1 && String.trim(output) === "") return Option.none();
27
+ const [, born, status] = /^(.{24})\s+(\S+)$/m.exec(String.trim(output)) ?? [];
28
+ if (code !== 0 || born === void 0 || status === void 0) return yield* ExecutionError.make({ detail: "Cannot inspect process identity: " + stderr });
29
+ if (String.startsWith("Z")(status)) return Option.none();
30
+ return Option.some({ born });
31
+ })).pipe(Effect.mapError((error) => error._tag === "ExecutionError" ? error : ExecutionError.make({
32
+ detail: "Inspecting process identity failed",
33
+ cause: Cause.fail(error)
34
+ })));
35
+ const identity = (pid) => Effect.gen(function* () {
36
+ const current = yield* inspect(pid);
37
+ if (Option.isNone(current)) return yield* ExecutionError.make({ detail: "The child exited before its identity could be recorded" });
38
+ return {
39
+ pid,
40
+ start: current.value
41
+ };
42
+ });
43
+ const matches = (child) => Effect.gen(function* () {
44
+ const current = yield* inspect(child.pid);
45
+ if (Option.isNone(current) || current.value.born !== child.start.born) return false;
46
+ return true;
47
+ });
48
+ const recover = (child) => Effect.gen(function* () {
49
+ if (!(yield* matches(child))) return {
50
+ kind: "Exited",
51
+ exit: {
52
+ code: null,
53
+ signal: null
54
+ },
55
+ cause: Cause.empty
56
+ };
57
+ const sent = yield* Effect.exit(Effect.try({
58
+ try: () => process.kill(child.pid, "SIGKILL"),
59
+ catch: (cause) => ExecutionError.make({
60
+ detail: "Signaling the orphan failed",
61
+ cause: Cause.die(cause)
62
+ })
63
+ }));
64
+ const confirmed = yield* matches(child).pipe(Effect.repeat({
65
+ schedule: Schedule.spaced("50 millis"),
66
+ while: (value) => value
67
+ }), Effect.timeoutOption("10 seconds"));
68
+ if (Option.isNone(confirmed)) return yield* TerminationUnconfirmed.make({
69
+ detail: "The orphan did not exit after recovery",
70
+ cause: sent._tag === "Failure" ? sent.cause : Cause.empty
71
+ });
72
+ return {
73
+ kind: "Killed",
74
+ exit: {
75
+ code: null,
76
+ signal: "SIGKILL"
77
+ },
78
+ cause: sent._tag === "Failure" ? sent.cause : Cause.empty
79
+ };
80
+ });
81
+ export { identity, matches, recover };
82
+
83
+ //# sourceMappingURL=Processes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Processes.js","names":[],"sources":["../../../src/internal/runner/Processes.ts"],"sourcesContent":["import { Cause, Effect, Option, Schedule, Stream, String } from \"effect\"\nimport { ChildProcess, ChildProcessSpawner } from \"effect/process\"\nimport process from \"node:process\"\nimport {\n\tExecutionError,\n\tTerminationUnconfirmed,\n\ttype ProcessIdentity,\n\ttype Termination,\n} from \"./model\"\n\nconst inspect = (pid: number) =>\n\tEffect.scoped(\n\t\tEffect.gen(function* () {\n\t\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner\n\t\t\tconst child = yield* spawner.spawn(\n\t\t\t\tChildProcess.make(\n\t\t\t\t\t\"ps\",\n\t\t\t\t\t[\"-p\", `${pid}`, \"-o\", \"lstart=\", \"-o\", \"stat=\"],\n\t\t\t\t\t{\n\t\t\t\t\t\tenv: { ...process.env, LC_ALL: \"C\" },\n\t\t\t\t\t\tstdin: \"ignore\",\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t\tconst [code, output, stderr] = yield* Effect.all(\n\t\t\t\t[\n\t\t\t\t\tchild.exitCode,\n\t\t\t\t\tchild.stdout.pipe(Stream.decodeText(), Stream.mkString),\n\t\t\t\t\tchild.stderr.pipe(Stream.decodeText(), Stream.mkString),\n\t\t\t\t],\n\t\t\t\t{ concurrency: \"unbounded\" },\n\t\t\t)\n\t\t\tif (code === 1 && String.trim(output) === \"\") return Option.none()\n\t\t\tconst [, born, status] =\n\t\t\t\t/^(.{24})\\s+(\\S+)$/m.exec(String.trim(output)) ?? []\n\t\t\tif (code !== 0 || born === undefined || status === undefined)\n\t\t\t\treturn yield* ExecutionError.make({\n\t\t\t\t\tdetail: \"Cannot inspect process identity: \" + stderr,\n\t\t\t\t})\n\t\t\tif (String.startsWith(\"Z\")(status)) return Option.none()\n\t\t\treturn Option.some({ born })\n\t\t}),\n\t).pipe(\n\t\tEffect.mapError((error) =>\n\t\t\terror._tag === \"ExecutionError\"\n\t\t\t\t? error\n\t\t\t\t: ExecutionError.make({\n\t\t\t\t\t\tdetail: \"Inspecting process identity failed\",\n\t\t\t\t\t\tcause: Cause.fail(error),\n\t\t\t\t\t}),\n\t\t),\n\t)\n\nexport const identity = (pid: number) =>\n\tEffect.gen(function* () {\n\t\tconst current = yield* inspect(pid)\n\t\tif (Option.isNone(current))\n\t\t\treturn yield* ExecutionError.make({\n\t\t\t\tdetail: \"The child exited before its identity could be recorded\",\n\t\t\t})\n\t\treturn { pid, start: current.value }\n\t})\n\n// The OS may discard argv before reporting a zombie; PID and start time remain the identity.\nexport const matches = (child: ProcessIdentity) =>\n\tEffect.gen(function* () {\n\t\tconst current = yield* inspect(child.pid)\n\t\tif (Option.isNone(current) || current.value.born !== child.start.born)\n\t\t\treturn false\n\t\treturn true\n\t})\n\nexport const recover = (child: ProcessIdentity) =>\n\tEffect.gen(function* () {\n\t\tif (!(yield* matches(child)))\n\t\t\treturn {\n\t\t\t\tkind: \"Exited\",\n\t\t\t\texit: { code: null, signal: null },\n\t\t\t\tcause: Cause.empty,\n\t\t\t} satisfies Termination\n\t\t// The PID can still be reused between this final check and kill; an external supervisor covers descendants.\n\t\tconst sent = yield* Effect.exit(\n\t\t\tEffect.try({\n\t\t\t\ttry: () => process.kill(child.pid, \"SIGKILL\"),\n\t\t\t\tcatch: (cause) =>\n\t\t\t\t\tExecutionError.make({\n\t\t\t\t\t\tdetail: \"Signaling the orphan failed\",\n\t\t\t\t\t\tcause: Cause.die(cause),\n\t\t\t\t\t}),\n\t\t\t}),\n\t\t)\n\t\tconst confirmed = yield* matches(child).pipe(\n\t\t\tEffect.repeat({\n\t\t\t\tschedule: Schedule.spaced(\"50 millis\"),\n\t\t\t\twhile: (value) => value,\n\t\t\t}),\n\t\t\tEffect.timeoutOption(\"10 seconds\"),\n\t\t)\n\t\tif (Option.isNone(confirmed))\n\t\t\treturn yield* TerminationUnconfirmed.make({\n\t\t\t\tdetail: \"The orphan did not exit after recovery\",\n\t\t\t\tcause: sent._tag === \"Failure\" ? sent.cause : Cause.empty,\n\t\t\t})\n\t\treturn {\n\t\t\tkind: \"Killed\",\n\t\t\texit: { code: null, signal: \"SIGKILL\" },\n\t\t\tcause: sent._tag === \"Failure\" ? sent.cause : Cause.empty,\n\t\t} satisfies Termination\n\t})\n"],"mappings":";;;;;AAUA,MAAM,WAAW,QAChB,OAAO,OACN,OAAO,IAAI,aAAa;CAEvB,MAAM,QAAQ,QAAO,OADE,oBAAoB,oBAAA,CACd,MAC5B,aAAa,KACZ,MACA;EAAC;EAAM,GAAG;EAAO;EAAM;EAAW;EAAM;CAAO,GAC/C;EACC,KAAK;GAAE,GAAG,QAAQ;GAAK,QAAQ;EAAI;EACnC,OAAO;CACR,CACD,CACD;CACA,MAAM,CAAC,MAAM,QAAQ,UAAU,OAAO,OAAO,IAC5C;EACC,MAAM;EACN,MAAM,OAAO,KAAK,OAAO,WAAW,GAAG,OAAO,QAAQ;EACtD,MAAM,OAAO,KAAK,OAAO,WAAW,GAAG,OAAO,QAAQ;CACvD,GACA,EAAE,aAAa,YAAY,CAC5B;CACA,IAAI,SAAS,KAAK,OAAO,KAAK,MAAM,MAAM,IAAI,OAAO,OAAO,KAAK;CACjE,MAAM,GAAG,MAAM,UACd,qBAAqB,KAAK,OAAO,KAAK,MAAM,CAAC,KAAK,CAAC;CACpD,IAAI,SAAS,KAAK,SAAS,KAAA,KAAa,WAAW,KAAA,GAClD,OAAO,OAAO,eAAe,KAAK,EACjC,QAAQ,sCAAsC,OAC/C,CAAC;CACF,IAAI,OAAO,WAAW,GAAG,CAAC,CAAC,MAAM,GAAG,OAAO,OAAO,KAAK;CACvD,OAAO,OAAO,KAAK,EAAE,KAAK,CAAC;AAC5B,CAAC,CACF,CAAC,CAAC,KACD,OAAO,UAAU,UAChB,MAAM,SAAS,mBACZ,QACA,eAAe,KAAK;CACpB,QAAQ;CACR,OAAO,MAAM,KAAK,KAAK;AACxB,CAAC,CACJ,CACD;AAED,MAAa,YAAY,QACxB,OAAO,IAAI,aAAa;CACvB,MAAM,UAAU,OAAO,QAAQ,GAAG;CAClC,IAAI,OAAO,OAAO,OAAO,GACxB,OAAO,OAAO,eAAe,KAAK,EACjC,QAAQ,yDACT,CAAC;CACF,OAAO;EAAE;EAAK,OAAO,QAAQ;CAAM;AACpC,CAAC;AAGF,MAAa,WAAW,UACvB,OAAO,IAAI,aAAa;CACvB,MAAM,UAAU,OAAO,QAAQ,MAAM,GAAG;CACxC,IAAI,OAAO,OAAO,OAAO,KAAK,QAAQ,MAAM,SAAS,MAAM,MAAM,MAChE,OAAO;CACR,OAAO;AACR,CAAC;AAEF,MAAa,WAAW,UACvB,OAAO,IAAI,aAAa;CACvB,IAAI,EAAE,OAAO,QAAQ,KAAK,IACzB,OAAO;EACN,MAAM;EACN,MAAM;GAAE,MAAM;GAAM,QAAQ;EAAK;EACjC,OAAO,MAAM;CACd;CAED,MAAM,OAAO,OAAO,OAAO,KAC1B,OAAO,IAAI;EACV,WAAW,QAAQ,KAAK,MAAM,KAAK,SAAS;EAC5C,QAAQ,UACP,eAAe,KAAK;GACnB,QAAQ;GACR,OAAO,MAAM,IAAI,KAAK;EACvB,CAAC;CACH,CAAC,CACF;CACA,MAAM,YAAY,OAAO,QAAQ,KAAK,CAAC,CAAC,KACvC,OAAO,OAAO;EACb,UAAU,SAAS,OAAO,WAAW;EACrC,QAAQ,UAAU;CACnB,CAAC,GACD,OAAO,cAAc,YAAY,CAClC;CACA,IAAI,OAAO,OAAO,SAAS,GAC1B,OAAO,OAAO,uBAAuB,KAAK;EACzC,QAAQ;EACR,OAAO,KAAK,SAAS,YAAY,KAAK,QAAQ,MAAM;CACrD,CAAC;CACF,OAAO;EACN,MAAM;EACN,MAAM;GAAE,MAAM;GAAM,QAAQ;EAAU;EACtC,OAAO,KAAK,SAAS,YAAY,KAAK,QAAQ,MAAM;CACrD;AACD,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { keyOf } from "./model.js";
2
+ import { Array, HashMap, Option } from "effect";
3
+ // src/internal/runner/Retention.ts
4
+ /** A terminal high-water record fences every older Open, even after its request id is forgotten. */
5
+ const retain = (records) => {
6
+ const highWater = Array.reduce(records, HashMap.empty(), (water, record) => HashMap.set(water, keyOf(record.handle.key), Math.max(Option.getOrElse(HashMap.get(water, keyOf(record.handle.key)), () => 0), record.handle.generation)));
7
+ return Array.filter(records, (record) => record.phase !== "Stopped" || record.handle.generation === Option.getOrUndefined(HashMap.get(highWater, keyOf(record.handle.key))));
8
+ };
9
+ /** Apply the same retention rule to both in-memory stores. */
10
+ const save = (records, record) => HashMap.fromIterable(Array.map(retain(Array.fromIterable(HashMap.values(HashMap.set(records, record.handle.token, record)))), (record) => [record.handle.token, record]));
11
+ export { retain, save };
12
+
13
+ //# sourceMappingURL=Retention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Retention.js","names":[],"sources":["../../../src/internal/runner/Retention.ts"],"sourcesContent":["import { Array, HashMap, Option } from \"effect\"\nimport { keyOf, type SessionKey, type SessionRecord } from \"./model\"\n\n/** A terminal high-water record fences every older Open, even after its request id is forgotten. */\nexport const retain = (\n\trecords: ReadonlyArray<SessionRecord>,\n): ReadonlyArray<SessionRecord> => {\n\tconst highWater = Array.reduce(\n\t\trecords,\n\t\tHashMap.empty<SessionKey, number>(),\n\t\t(water, record) =>\n\t\t\tHashMap.set(\n\t\t\t\twater,\n\t\t\t\tkeyOf(record.handle.key),\n\t\t\t\tMath.max(\n\t\t\t\t\tOption.getOrElse(\n\t\t\t\t\t\tHashMap.get(water, keyOf(record.handle.key)),\n\t\t\t\t\t\t() => 0,\n\t\t\t\t\t),\n\t\t\t\t\trecord.handle.generation,\n\t\t\t\t),\n\t\t\t),\n\t)\n\treturn Array.filter(\n\t\trecords,\n\t\t(record) =>\n\t\t\trecord.phase !== \"Stopped\" ||\n\t\t\trecord.handle.generation ===\n\t\t\t\tOption.getOrUndefined(HashMap.get(highWater, keyOf(record.handle.key))),\n\t)\n}\n/** Apply the same retention rule to both in-memory stores. */\nexport const save = (\n\trecords: HashMap.HashMap<string, SessionRecord>,\n\trecord: SessionRecord,\n) =>\n\tHashMap.fromIterable(\n\t\tArray.map(\n\t\t\tretain(\n\t\t\t\tArray.fromIterable(\n\t\t\t\t\tHashMap.values(HashMap.set(records, record.handle.token, record)),\n\t\t\t\t),\n\t\t\t),\n\t\t\t(record): readonly [string, SessionRecord] => [\n\t\t\t\trecord.handle.token,\n\t\t\t\trecord,\n\t\t\t],\n\t\t),\n\t)\n"],"mappings":";;;;AAIA,MAAa,UACZ,YACkC;CAClC,MAAM,YAAY,MAAM,OACvB,SACA,QAAQ,MAA0B,IACjC,OAAO,WACP,QAAQ,IACP,OACA,MAAM,OAAO,OAAO,GAAG,GACvB,KAAK,IACJ,OAAO,UACN,QAAQ,IAAI,OAAO,MAAM,OAAO,OAAO,GAAG,CAAC,SACrC,CACP,GACA,OAAO,OAAO,UACf,CACD,CACF;CACA,OAAO,MAAM,OACZ,UACC,WACA,OAAO,UAAU,aACjB,OAAO,OAAO,eACb,OAAO,eAAe,QAAQ,IAAI,WAAW,MAAM,OAAO,OAAO,GAAG,CAAC,CAAC,CACzE;AACD;;AAEA,MAAa,QACZ,SACA,WAEA,QAAQ,aACP,MAAM,IACL,OACC,MAAM,aACL,QAAQ,OAAO,QAAQ,IAAI,SAAS,OAAO,OAAO,OAAO,MAAM,CAAC,CACjE,CACD,IACC,WAA6C,CAC7C,OAAO,OAAO,OACd,MACD,CACD,CACD"}