@smthrs/kernel 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 (267) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/LICENSE +21 -0
  3. package/README.md +154 -2
  4. package/dist/cjs/CapabilitySet.d.ts +6 -0
  5. package/dist/cjs/CapabilitySet.d.ts.map +1 -0
  6. package/dist/cjs/CapabilitySet.js +19 -0
  7. package/dist/cjs/CapabilitySet.js.map +7 -0
  8. package/dist/cjs/ChildProcessEnvironment.d.ts +60 -0
  9. package/dist/cjs/ChildProcessEnvironment.d.ts.map +1 -0
  10. package/dist/cjs/ChildProcessEnvironment.js +61 -0
  11. package/dist/cjs/ChildProcessEnvironment.js.map +7 -0
  12. package/dist/cjs/ChildProcessSpawner.d.ts +100 -0
  13. package/dist/cjs/ChildProcessSpawner.d.ts.map +1 -0
  14. package/dist/cjs/ChildProcessSpawner.js +291 -0
  15. package/dist/cjs/ChildProcessSpawner.js.map +7 -0
  16. package/dist/cjs/CommandLine.d.ts +173 -0
  17. package/dist/cjs/CommandLine.d.ts.map +1 -0
  18. package/dist/cjs/CommandLine.js +54 -0
  19. package/dist/cjs/CommandLine.js.map +7 -0
  20. package/dist/cjs/ContainedSpawner.d.ts +135 -0
  21. package/dist/cjs/ContainedSpawner.d.ts.map +1 -0
  22. package/dist/cjs/ContainedSpawner.js +141 -0
  23. package/dist/cjs/ContainedSpawner.js.map +7 -0
  24. package/dist/cjs/FileSystem.d.ts +452 -0
  25. package/dist/cjs/FileSystem.d.ts.map +1 -0
  26. package/dist/cjs/FileSystem.js +890 -0
  27. package/dist/cjs/FileSystem.js.map +7 -0
  28. package/dist/cjs/FileSystemBatch.d.ts +94 -0
  29. package/dist/cjs/FileSystemBatch.d.ts.map +1 -0
  30. package/dist/cjs/FileSystemBatch.js +31 -0
  31. package/dist/cjs/FileSystemBatch.js.map +7 -0
  32. package/dist/cjs/GrantEvent.d.ts +240 -0
  33. package/dist/cjs/GrantEvent.d.ts.map +1 -0
  34. package/dist/cjs/GrantEvent.js +115 -0
  35. package/dist/cjs/GrantEvent.js.map +7 -0
  36. package/dist/cjs/GrantStore.d.ts +270 -0
  37. package/dist/cjs/GrantStore.d.ts.map +1 -0
  38. package/dist/cjs/GrantStore.js +857 -0
  39. package/dist/cjs/GrantStore.js.map +7 -0
  40. package/dist/cjs/HostError.d.ts +36 -0
  41. package/dist/cjs/HostError.d.ts.map +1 -0
  42. package/dist/cjs/HostError.js +17 -0
  43. package/dist/cjs/HostError.js.map +7 -0
  44. package/dist/cjs/HostServices.d.ts +101 -0
  45. package/dist/cjs/HostServices.d.ts.map +1 -0
  46. package/dist/cjs/HostServices.js +66 -0
  47. package/dist/cjs/HostServices.js.map +7 -0
  48. package/dist/cjs/HttpClient.d.ts +177 -0
  49. package/dist/cjs/HttpClient.d.ts.map +1 -0
  50. package/dist/cjs/HttpClient.js +217 -0
  51. package/dist/cjs/HttpClient.js.map +7 -0
  52. package/dist/cjs/Jj.d.ts +67 -0
  53. package/dist/cjs/Jj.d.ts.map +1 -0
  54. package/dist/cjs/Jj.js +118 -0
  55. package/dist/cjs/Jj.js.map +7 -0
  56. package/dist/cjs/JournalGrantStore.d.ts +65 -0
  57. package/dist/cjs/JournalGrantStore.d.ts.map +1 -0
  58. package/dist/cjs/JournalGrantStore.js +354 -0
  59. package/dist/cjs/JournalGrantStore.js.map +7 -0
  60. package/dist/cjs/Path.d.ts +37 -0
  61. package/dist/cjs/Path.d.ts.map +1 -0
  62. package/dist/cjs/Path.js +46 -0
  63. package/dist/cjs/Path.js.map +7 -0
  64. package/dist/cjs/ProcessConfinement.d.ts +55 -0
  65. package/dist/cjs/ProcessConfinement.d.ts.map +1 -0
  66. package/dist/cjs/ProcessConfinement.js +94 -0
  67. package/dist/cjs/ProcessConfinement.js.map +7 -0
  68. package/dist/cjs/ProcessLedger.d.ts +260 -0
  69. package/dist/cjs/ProcessLedger.d.ts.map +1 -0
  70. package/dist/cjs/ProcessLedger.js +190 -0
  71. package/dist/cjs/ProcessLedger.js.map +7 -0
  72. package/dist/cjs/Rooted.d.ts +53 -0
  73. package/dist/cjs/Rooted.d.ts.map +1 -0
  74. package/dist/cjs/Rooted.js +101 -0
  75. package/dist/cjs/Rooted.js.map +7 -0
  76. package/dist/cjs/Unreachable.d.ts +27 -0
  77. package/dist/cjs/Unreachable.d.ts.map +1 -0
  78. package/dist/cjs/Unreachable.js +43 -0
  79. package/dist/cjs/Unreachable.js.map +7 -0
  80. package/dist/cjs/Workspace.d.ts +62 -0
  81. package/dist/cjs/Workspace.d.ts.map +1 -0
  82. package/dist/cjs/Workspace.js +35 -0
  83. package/dist/cjs/Workspace.js.map +7 -0
  84. package/dist/cjs/index.d.ts +161 -0
  85. package/dist/cjs/index.d.ts.map +1 -0
  86. package/dist/cjs/index.js +73 -0
  87. package/dist/cjs/index.js.map +7 -0
  88. package/dist/cjs/internal/Containment.d.ts +24 -0
  89. package/dist/cjs/internal/Containment.d.ts.map +1 -0
  90. package/dist/cjs/internal/Containment.js +30 -0
  91. package/dist/cjs/internal/Containment.js.map +7 -0
  92. package/dist/cjs/internal/Pipeline.d.ts +18 -0
  93. package/dist/cjs/internal/Pipeline.d.ts.map +1 -0
  94. package/dist/cjs/internal/Pipeline.js +90 -0
  95. package/dist/cjs/internal/Pipeline.js.map +7 -0
  96. package/dist/cjs/internal/makeCapability.d.ts +16 -0
  97. package/dist/cjs/internal/makeCapability.d.ts.map +1 -0
  98. package/dist/cjs/internal/makeCapability.js +44 -0
  99. package/dist/cjs/internal/makeCapability.js.map +7 -0
  100. package/dist/cjs/package.json +1 -0
  101. package/dist/cjs/test/FileSystemBatchContract.d.ts +15 -0
  102. package/dist/cjs/test/FileSystemBatchContract.d.ts.map +1 -0
  103. package/dist/cjs/test/FileSystemBatchContract.js +76 -0
  104. package/dist/cjs/test/FileSystemBatchContract.js.map +7 -0
  105. package/dist/cjs/test/HostContract.d.ts +225 -0
  106. package/dist/cjs/test/HostContract.d.ts.map +1 -0
  107. package/dist/cjs/test/HostContract.js +489 -0
  108. package/dist/cjs/test/HostContract.js.map +7 -0
  109. package/dist/cjs/test/TestGrantStore.d.ts +31 -0
  110. package/dist/cjs/test/TestGrantStore.d.ts.map +1 -0
  111. package/dist/cjs/test/TestGrantStore.js +65 -0
  112. package/dist/cjs/test/TestGrantStore.js.map +7 -0
  113. package/dist/esm/CapabilitySet.d.ts +6 -0
  114. package/dist/esm/CapabilitySet.d.ts.map +1 -0
  115. package/dist/esm/CapabilitySet.js +6 -0
  116. package/dist/esm/CapabilitySet.js.map +1 -0
  117. package/dist/esm/ChildProcessEnvironment.d.ts +60 -0
  118. package/dist/esm/ChildProcessEnvironment.d.ts.map +1 -0
  119. package/dist/esm/ChildProcessEnvironment.js +91 -0
  120. package/dist/esm/ChildProcessEnvironment.js.map +1 -0
  121. package/dist/esm/ChildProcessSpawner.d.ts +100 -0
  122. package/dist/esm/ChildProcessSpawner.d.ts.map +1 -0
  123. package/dist/esm/ChildProcessSpawner.js +342 -0
  124. package/dist/esm/ChildProcessSpawner.js.map +1 -0
  125. package/dist/esm/CommandLine.d.ts +173 -0
  126. package/dist/esm/CommandLine.d.ts.map +1 -0
  127. package/dist/esm/CommandLine.js +195 -0
  128. package/dist/esm/CommandLine.js.map +1 -0
  129. package/dist/esm/ContainedSpawner.d.ts +135 -0
  130. package/dist/esm/ContainedSpawner.d.ts.map +1 -0
  131. package/dist/esm/ContainedSpawner.js +180 -0
  132. package/dist/esm/ContainedSpawner.js.map +1 -0
  133. package/dist/esm/FileSystem.d.ts +452 -0
  134. package/dist/esm/FileSystem.d.ts.map +1 -0
  135. package/dist/esm/FileSystem.js +989 -0
  136. package/dist/esm/FileSystem.js.map +1 -0
  137. package/dist/esm/FileSystemBatch.d.ts +94 -0
  138. package/dist/esm/FileSystemBatch.d.ts.map +1 -0
  139. package/dist/esm/FileSystemBatch.js +26 -0
  140. package/dist/esm/FileSystemBatch.js.map +1 -0
  141. package/dist/esm/GrantEvent.d.ts +240 -0
  142. package/dist/esm/GrantEvent.d.ts.map +1 -0
  143. package/dist/esm/GrantEvent.js +155 -0
  144. package/dist/esm/GrantEvent.js.map +1 -0
  145. package/dist/esm/GrantStore.d.ts +270 -0
  146. package/dist/esm/GrantStore.d.ts.map +1 -0
  147. package/dist/esm/GrantStore.js +951 -0
  148. package/dist/esm/GrantStore.js.map +1 -0
  149. package/dist/esm/HostError.d.ts +36 -0
  150. package/dist/esm/HostError.d.ts.map +1 -0
  151. package/dist/esm/HostError.js +20 -0
  152. package/dist/esm/HostError.js.map +1 -0
  153. package/dist/esm/HostServices.d.ts +101 -0
  154. package/dist/esm/HostServices.d.ts.map +1 -0
  155. package/dist/esm/HostServices.js +76 -0
  156. package/dist/esm/HostServices.js.map +1 -0
  157. package/dist/esm/HttpClient.d.ts +177 -0
  158. package/dist/esm/HttpClient.d.ts.map +1 -0
  159. package/dist/esm/HttpClient.js +299 -0
  160. package/dist/esm/HttpClient.js.map +1 -0
  161. package/dist/esm/Jj.d.ts +67 -0
  162. package/dist/esm/Jj.d.ts.map +1 -0
  163. package/dist/esm/Jj.js +111 -0
  164. package/dist/esm/Jj.js.map +1 -0
  165. package/dist/esm/JournalGrantStore.d.ts +65 -0
  166. package/dist/esm/JournalGrantStore.d.ts.map +1 -0
  167. package/dist/esm/JournalGrantStore.js +350 -0
  168. package/dist/esm/JournalGrantStore.js.map +1 -0
  169. package/dist/esm/Path.d.ts +37 -0
  170. package/dist/esm/Path.d.ts.map +1 -0
  171. package/dist/esm/Path.js +34 -0
  172. package/dist/esm/Path.js.map +1 -0
  173. package/dist/esm/ProcessConfinement.d.ts +55 -0
  174. package/dist/esm/ProcessConfinement.d.ts.map +1 -0
  175. package/dist/esm/ProcessConfinement.js +106 -0
  176. package/dist/esm/ProcessConfinement.js.map +1 -0
  177. package/dist/esm/ProcessLedger.d.ts +260 -0
  178. package/dist/esm/ProcessLedger.d.ts.map +1 -0
  179. package/dist/esm/ProcessLedger.js +283 -0
  180. package/dist/esm/ProcessLedger.js.map +1 -0
  181. package/dist/esm/Rooted.d.ts +53 -0
  182. package/dist/esm/Rooted.d.ts.map +1 -0
  183. package/dist/esm/Rooted.js +104 -0
  184. package/dist/esm/Rooted.js.map +1 -0
  185. package/dist/esm/Unreachable.d.ts +27 -0
  186. package/dist/esm/Unreachable.d.ts.map +1 -0
  187. package/dist/esm/Unreachable.js +26 -0
  188. package/dist/esm/Unreachable.js.map +1 -0
  189. package/dist/esm/Workspace.d.ts +62 -0
  190. package/dist/esm/Workspace.d.ts.map +1 -0
  191. package/dist/esm/Workspace.js +51 -0
  192. package/dist/esm/Workspace.js.map +1 -0
  193. package/dist/esm/index.d.ts +161 -0
  194. package/dist/esm/index.d.ts.map +1 -0
  195. package/dist/esm/index.js +151 -0
  196. package/dist/esm/index.js.map +1 -0
  197. package/dist/esm/internal/Containment.d.ts +24 -0
  198. package/dist/esm/internal/Containment.d.ts.map +1 -0
  199. package/dist/esm/internal/Containment.js +27 -0
  200. package/dist/esm/internal/Containment.js.map +1 -0
  201. package/dist/esm/internal/Pipeline.d.ts +18 -0
  202. package/dist/esm/internal/Pipeline.d.ts.map +1 -0
  203. package/dist/esm/internal/Pipeline.js +68 -0
  204. package/dist/esm/internal/Pipeline.js.map +1 -0
  205. package/dist/esm/internal/makeCapability.d.ts +16 -0
  206. package/dist/esm/internal/makeCapability.d.ts.map +1 -0
  207. package/dist/esm/internal/makeCapability.js +22 -0
  208. package/dist/esm/internal/makeCapability.js.map +1 -0
  209. package/dist/esm/test/FileSystemBatchContract.d.ts +15 -0
  210. package/dist/esm/test/FileSystemBatchContract.d.ts.map +1 -0
  211. package/dist/esm/test/FileSystemBatchContract.js +57 -0
  212. package/dist/esm/test/FileSystemBatchContract.js.map +1 -0
  213. package/dist/esm/test/HostContract.d.ts +225 -0
  214. package/dist/esm/test/HostContract.d.ts.map +1 -0
  215. package/dist/esm/test/HostContract.js +460 -0
  216. package/dist/esm/test/HostContract.js.map +1 -0
  217. package/dist/esm/test/TestGrantStore.d.ts +31 -0
  218. package/dist/esm/test/TestGrantStore.d.ts.map +1 -0
  219. package/dist/esm/test/TestGrantStore.js +57 -0
  220. package/dist/esm/test/TestGrantStore.js.map +1 -0
  221. package/docs/README.md +162 -0
  222. package/docs/api.md +1532 -0
  223. package/docs/concepts/decoration-in-place.md +117 -0
  224. package/docs/concepts/filesystem-batches.md +58 -0
  225. package/docs/concepts/filesystem-confinement.md +168 -0
  226. package/docs/concepts/grant-decisions.md +181 -0
  227. package/docs/concepts/process-containment.md +155 -0
  228. package/docs/contract.md +14 -0
  229. package/docs/guides/adapt-a-new-host-platform.md +148 -0
  230. package/docs/guides/answer-permission-requests.md +151 -0
  231. package/docs/guides/authorize-network-and-model-calls.md +118 -0
  232. package/docs/guides/contain-spawned-processes.md +118 -0
  233. package/docs/guides/guard-a-host-bundle.md +109 -0
  234. package/docs/guides/persist-grants-across-restarts.md +135 -0
  235. package/docs/guides/write-a-capability-policy.md +159 -0
  236. package/docs/installation.md +115 -0
  237. package/docs/quickstart.md +182 -0
  238. package/docs/testing.md +108 -0
  239. package/docs/troubleshooting.md +281 -0
  240. package/package.json +344 -3
  241. package/src/CapabilitySet.ts +6 -0
  242. package/src/ChildProcessEnvironment.ts +98 -0
  243. package/src/ChildProcessSpawner.ts +414 -0
  244. package/src/CommandLine.ts +250 -0
  245. package/src/ContainedSpawner.ts +284 -0
  246. package/src/FileSystem.ts +1655 -0
  247. package/src/FileSystemBatch.ts +90 -0
  248. package/src/GrantEvent.ts +174 -0
  249. package/src/GrantStore.ts +1345 -0
  250. package/src/HostError.ts +37 -0
  251. package/src/HostServices.ts +133 -0
  252. package/src/HttpClient.ts +406 -0
  253. package/src/Jj.ts +159 -0
  254. package/src/JournalGrantStore.ts +461 -0
  255. package/src/Path.ts +47 -0
  256. package/src/ProcessConfinement.ts +156 -0
  257. package/src/ProcessLedger.ts +423 -0
  258. package/src/Rooted.ts +128 -0
  259. package/src/Unreachable.ts +30 -0
  260. package/src/Workspace.ts +65 -0
  261. package/src/index.ts +181 -0
  262. package/src/internal/Containment.ts +37 -0
  263. package/src/internal/Pipeline.ts +85 -0
  264. package/src/internal/makeCapability.ts +26 -0
  265. package/src/test/FileSystemBatchContract.ts +59 -0
  266. package/src/test/HostContract.ts +785 -0
  267. package/src/test/TestGrantStore.ts +73 -0
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Explicit kernel decision for the Effect path service.
3
+ *
4
+ * Governing design:
5
+ * `docs/specs/Concepts/Permission Kernel.md` and
6
+ * `docs/specs/Concepts/Host Adapters.md`.
7
+ *
8
+ * @since 1.0.0-rc.0
9
+ */
10
+ import { Layer, Path as EffectPath } from "effect";
11
+ import { Workspace } from "./Workspace.ts";
12
+ /**
13
+ * Effect's lexical path-service shape.
14
+ *
15
+ * @category models
16
+ * @since 1.0.0-rc.0
17
+ */
18
+ export type Path = EffectPath.Path;
19
+ /**
20
+ * The unchanged underlying path-service tag.
21
+ *
22
+ * @category services
23
+ * @since 1.0.0-rc.0
24
+ */
25
+ export declare const Path: import("effect/Context").Service<EffectPath.Path, EffectPath.Path>;
26
+ /**
27
+ * Re-provides Effect's path service with relative paths resolved against
28
+ * `Workspace.root`, the same root the kernel spawner runs commands in. Path
29
+ * manipulation is pure and lexical, so it requires no capability check. This
30
+ * explicit layer proves that every member of the Host services closed list has
31
+ * a kernel decision.
32
+ *
33
+ * @category layers
34
+ * @since 1.0.0-rc.0
35
+ */
36
+ export declare const layer: Layer.Layer<Path, never, Path | Workspace>;
37
+ //# sourceMappingURL=Path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Path.d.ts","sourceRoot":"","sources":["../../src/Path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAU,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAA;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAA;AAElC;;;;;GAKG;AACH,eAAO,MAAM,IAAI,oEAAkB,CAAA;AAEnC;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,SAAS,CAM5D,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Explicit kernel decision for the Effect path service.
3
+ *
4
+ * Governing design:
5
+ * `docs/specs/Concepts/Permission Kernel.md` and
6
+ * `docs/specs/Concepts/Host Adapters.md`.
7
+ *
8
+ * @since 1.0.0-rc.0
9
+ */
10
+ import { Effect, Layer, Path as EffectPath } from "effect";
11
+ import * as Rooted from "./Rooted.js";
12
+ import { Workspace } from "./Workspace.js";
13
+ /**
14
+ * The unchanged underlying path-service tag.
15
+ *
16
+ * @category services
17
+ * @since 1.0.0-rc.0
18
+ */
19
+ export const Path = EffectPath.Path;
20
+ /**
21
+ * Re-provides Effect's path service with relative paths resolved against
22
+ * `Workspace.root`, the same root the kernel spawner runs commands in. Path
23
+ * manipulation is pure and lexical, so it requires no capability check. This
24
+ * explicit layer proves that every member of the Host services closed list has
25
+ * a kernel decision.
26
+ *
27
+ * @category layers
28
+ * @since 1.0.0-rc.0
29
+ */
30
+ export const layer = Layer.effect(Path, Effect.gen(function* () {
31
+ const path = yield* Path;
32
+ return Rooted.path(path, path.resolve((yield* Workspace).root));
33
+ }));
34
+ //# sourceMappingURL=Path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Path.js","sourceRoot":"","sources":["../../src/Path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC1D,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAU1C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAA;AAEnC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,KAAK,GAA+C,KAAK,CAAC,MAAM,CAC3E,IAAI,EACJ,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAA;IACxB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;AACjE,CAAC,CAAC,CACH,CAAA","sourcesContent":["/**\n * Explicit kernel decision for the Effect path service.\n *\n * Governing design:\n * `docs/specs/Concepts/Permission Kernel.md` and\n * `docs/specs/Concepts/Host Adapters.md`.\n *\n * @since 1.0.0-rc.0\n */\n\nimport { Effect, Layer, Path as EffectPath } from \"effect\"\nimport * as Rooted from \"./Rooted.ts\"\nimport { Workspace } from \"./Workspace.ts\"\n\n/**\n * Effect's lexical path-service shape.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type Path = EffectPath.Path\n\n/**\n * The unchanged underlying path-service tag.\n *\n * @category services\n * @since 1.0.0-rc.0\n */\nexport const Path = EffectPath.Path\n\n/**\n * Re-provides Effect's path service with relative paths resolved against\n * `Workspace.root`, the same root the kernel spawner runs commands in. Path\n * manipulation is pure and lexical, so it requires no capability check. This\n * explicit layer proves that every member of the Host services closed list has\n * a kernel decision.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layer: Layer.Layer<Path, never, Path | Workspace> = Layer.effect(\n Path,\n Effect.gen(function*() {\n const path = yield* Path\n return Rooted.path(path, path.resolve((yield* Workspace).root))\n })\n)\n"]}
@@ -0,0 +1,55 @@
1
+ /** Operating-system confinement derived conservatively from effective grants.
2
+ * @since 1.0.0-rc.1
3
+ */
4
+ import type { GrantStoreError } from "@smthrs/capability/Permission";
5
+ import { Context, Effect, Layer, type Path, type Scope } from "effect";
6
+ import type { PlatformError } from "effect/PlatformError";
7
+ import type * as ChildProcess from "effect/unstable/process/ChildProcess";
8
+ import type { Service as GrantService } from "./GrantStore.ts";
9
+ /** Workspace-relative trees; `.` names the workspace. No path opens its parent.
10
+ * @category models
11
+ * @since 1.0.0-rc.1
12
+ */
13
+ export interface Profile {
14
+ readonly workspaceRoot: string;
15
+ readonly reads: ReadonlyArray<string>;
16
+ readonly writes: ReadonlyArray<string>;
17
+ readonly readOnly: ReadonlyArray<string>;
18
+ readonly network: "none" | "open";
19
+ }
20
+ /** Host wrapper for one process stage. Failure must occur before spawning.
21
+ * @category models
22
+ * @since 1.0.0-rc.1
23
+ */
24
+ export interface Service {
25
+ readonly confine: (command: ChildProcess.StandardCommand, profile: Profile) => Effect.Effect<ChildProcess.StandardCommand, PlatformError, Scope.Scope>;
26
+ }
27
+ declare const ProcessConfinement_base: Context.ServiceClass<ProcessConfinement, "@smthrs/kernel/ProcessConfinement", Service>;
28
+ /** Host confinement seam; missing service refuses spawning.
29
+ * @category services
30
+ * @since 1.0.0-rc.1
31
+ */
32
+ export declare class ProcessConfinement extends ProcessConfinement_base {
33
+ }
34
+ /** Explicit unconfined composition.
35
+ * @category constructors
36
+ * @since 1.0.0-rc.1
37
+ */
38
+ export declare const makeNoop: Service;
39
+ /** Explicit unconfined layer.
40
+ * @category layers
41
+ * @since 1.0.0-rc.1
42
+ */
43
+ export declare const layerNoop: Layer.Layer<ProcessConfinement>;
44
+ /** Derives a subset of authority, never a widening. Literal filesystem grants,
45
+ * complex globs and unrepresentable restrictions conservatively open nothing.
46
+ * Writable trees also require read authority and write authority over their
47
+ * exact directory root: native mounts permit reads and directory metadata
48
+ * changes. Only whole-tree grants prove filesystem trees; unrestricted
49
+ * authority for each of get/post/private is required to open network access.
50
+ * @category resolution
51
+ * @since 1.0.0-rc.1
52
+ */
53
+ export declare const profile: (grants: GrantService, workspaceRoot: string, path: Path.Path) => Effect.Effect<Profile, GrantStoreError>;
54
+ export {};
55
+ //# sourceMappingURL=ProcessConfinement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessConfinement.d.ts","sourceRoot":"","sources":["../../src/ProcessConfinement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,KAAK,YAAY,MAAM,sCAAsC,CAAA;AACzE,OAAO,KAAK,EAAsB,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAElF;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CAClC;AACD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,CAChB,OAAO,EAAE,YAAY,CAAC,eAAe,EACrC,OAAO,EAAE,OAAO,KACb,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;CAC7E;;AACD;;;GAGG;AACH,qBAAa,kBACX,SAAQ,uBAAmF;CAC3F;AACF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,OAAkF,CAAA;AACzG;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAA+C,CAAA;AAqCrG;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAClB,QAAQ,YAAY,EACpB,eAAe,MAAM,EACrB,MAAM,IAAI,CAAC,IAAI,KACd,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,eAAe,CAiDrC,CAAA"}
@@ -0,0 +1,106 @@
1
+ /** Operating-system confinement derived conservatively from effective grants.
2
+ * @since 1.0.0-rc.1
3
+ */
4
+ import { Capability, CapabilityPattern, matches, maxResourceLength, subsumes, withinMatchBudget } from "@smthrs/capability/Capability";
5
+ import { Context, Effect, Layer } from "effect";
6
+ /** Host confinement seam; missing service refuses spawning.
7
+ * @category services
8
+ * @since 1.0.0-rc.1
9
+ */
10
+ export class ProcessConfinement extends Context.Service()("@smthrs/kernel/ProcessConfinement") {
11
+ }
12
+ /** Explicit unconfined composition.
13
+ * @category constructors
14
+ * @since 1.0.0-rc.1
15
+ */
16
+ export const makeNoop = ProcessConfinement.of({ confine: (command) => Effect.succeed(command) });
17
+ /** Explicit unconfined layer.
18
+ * @category layers
19
+ * @since 1.0.0-rc.1
20
+ */
21
+ export const layerNoop = Layer.succeed(ProcessConfinement)(makeNoop);
22
+ const decidable = (pattern, action) => withinMatchBudget(pattern, new Capability({ action, resource: "x".repeat(maxResourceLength) }));
23
+ // The capability matcher permits a single star to cross separators. Only
24
+ // this universal spelling is equivalent to **; arbitrary globs stay closed.
25
+ const universal = (pattern) => pattern.resource === "*" ? new CapabilityPattern({ action: pattern.action, resource: "**" }) : pattern;
26
+ const coversCeiling = (ceiling, target) => ceiling.groups.every((group) => group.some((pattern) => decidable(pattern, target.action) && subsumes(universal(pattern), target)));
27
+ const actionRelevant = (pattern, action) => matches(new CapabilityPattern({ action: pattern.action, resource: "**" }), new Capability({ action, resource: "" }));
28
+ // A covering rule resolves the complete region. A narrower/conditional refusal
29
+ // makes it unknown until a later covering rule resolves it. Unknown configured
30
+ // denial vetoes all later grant groups, just as evaluate's configured veto does.
31
+ const prove = (policy, target) => {
32
+ if (!coversCeiling(policy.ceiling, target))
33
+ return false;
34
+ let decision = "ask";
35
+ let configured = "ask";
36
+ for (const [index, group] of policy.groups.entries()) {
37
+ for (const { rule, ceiling } of group) {
38
+ if (!decidable(rule.pattern, target.action))
39
+ return false;
40
+ if (!actionRelevant(rule.pattern, target.action))
41
+ continue;
42
+ if (target.action === "net:private" && rule.effect === "allow" && rule.pattern.action !== "net:private")
43
+ continue;
44
+ if (coversCeiling(ceiling, target) && subsumes(universal(rule.pattern), target))
45
+ decision = rule.effect;
46
+ else if (rule.effect !== "allow")
47
+ decision = "unknown";
48
+ if (index === 0)
49
+ configured = decision;
50
+ }
51
+ }
52
+ return configured !== "deny" && configured !== "unknown" && decision === "allow";
53
+ };
54
+ /** Derives a subset of authority, never a widening. Literal filesystem grants,
55
+ * complex globs and unrepresentable restrictions conservatively open nothing.
56
+ * Writable trees also require read authority and write authority over their
57
+ * exact directory root: native mounts permit reads and directory metadata
58
+ * changes. Only whole-tree grants prove filesystem trees; unrestricted
59
+ * authority for each of get/post/private is required to open network access.
60
+ * @category resolution
61
+ * @since 1.0.0-rc.1
62
+ */
63
+ export const profile = (grants, workspaceRoot, path) => Effect.gen(function* () {
64
+ const policy = yield* grants.policy;
65
+ const root = path.resolve(workspaceRoot);
66
+ const resources = [
67
+ ...policy.groups.flatMap((group) => group.flatMap(({ rule, ceiling }) => [rule.pattern, ...ceiling.groups.flat()])),
68
+ ...policy.ceiling.groups.flat()
69
+ ];
70
+ const candidates = new Set();
71
+ for (const { resource } of resources) {
72
+ if (resource === "**" || resource === "*") {
73
+ candidates.add(".");
74
+ continue;
75
+ }
76
+ if (!resource.endsWith("/**") || /[*?]/.test(resource.slice(0, -3)))
77
+ continue;
78
+ const base = resource.slice(0, -3);
79
+ // Relative policy resources do not authorize absolute kernel resources.
80
+ if (!path.isAbsolute(base) || path.normalize(base) !== base)
81
+ continue;
82
+ const relative = path.relative(root, base);
83
+ if (path.isAbsolute(relative) || relative.split(path.sep)[0] === "..")
84
+ continue;
85
+ candidates.add(relative === "" ? "." : relative.split(path.sep).join("/"));
86
+ }
87
+ const opened = (action) => [...candidates].filter((relative) => {
88
+ const directory = relative === "." ? root : path.resolve(root, relative);
89
+ const resource = `${directory}/**`;
90
+ return prove(policy, new CapabilityPattern({ action, resource })) &&
91
+ (action !== "fs:write" || (prove(policy, new CapabilityPattern({ action: "fs:read", resource })) &&
92
+ prove(policy, new CapabilityPattern({ action: "fs:write", resource: directory }))));
93
+ })
94
+ .filter((relative, _, all) => !all.some((parent) => parent !== relative && (parent === "." || relative.startsWith(`${parent}/`))))
95
+ .sort();
96
+ return Object.freeze({
97
+ workspaceRoot: root,
98
+ reads: Object.freeze(opened("fs:read")),
99
+ writes: Object.freeze(opened("fs:write")),
100
+ readOnly: Object.freeze([]),
101
+ network: ["net:get", "net:post", "net:private"].every((action) => prove(policy, new CapabilityPattern({ action, resource: "**" }))) ?
102
+ "open" :
103
+ "none"
104
+ });
105
+ });
106
+ //# sourceMappingURL=ProcessConfinement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessConfinement.js","sourceRoot":"","sources":["../../src/ProcessConfinement.ts"],"names":[],"mappings":"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","sourcesContent":["/** Operating-system confinement derived conservatively from effective grants.\n * @since 1.0.0-rc.1\n */\n\nimport {\n type Action,\n Capability,\n CapabilityPattern,\n matches,\n maxResourceLength,\n subsumes,\n withinMatchBudget\n} from \"@smthrs/capability/Capability\"\nimport type { GrantStoreError } from \"@smthrs/capability/Permission\"\nimport { Context, Effect, Layer, type Path, type Scope } from \"effect\"\nimport type { PlatformError } from \"effect/PlatformError\"\nimport type * as ChildProcess from \"effect/unstable/process/ChildProcess\"\nimport type { Policy, PolicyRule, Service as GrantService } from \"./GrantStore.ts\"\n\n/** Workspace-relative trees; `.` names the workspace. No path opens its parent.\n * @category models\n * @since 1.0.0-rc.1\n */\nexport interface Profile {\n readonly workspaceRoot: string\n readonly reads: ReadonlyArray<string>\n readonly writes: ReadonlyArray<string>\n readonly readOnly: ReadonlyArray<string>\n readonly network: \"none\" | \"open\"\n}\n/** Host wrapper for one process stage. Failure must occur before spawning.\n * @category models\n * @since 1.0.0-rc.1\n */\nexport interface Service {\n readonly confine: (\n command: ChildProcess.StandardCommand,\n profile: Profile\n ) => Effect.Effect<ChildProcess.StandardCommand, PlatformError, Scope.Scope>\n}\n/** Host confinement seam; missing service refuses spawning.\n * @category services\n * @since 1.0.0-rc.1\n */\nexport class ProcessConfinement\n extends Context.Service<ProcessConfinement, Service>()(\"@smthrs/kernel/ProcessConfinement\")\n{}\n/** Explicit unconfined composition.\n * @category constructors\n * @since 1.0.0-rc.1\n */\nexport const makeNoop: Service = ProcessConfinement.of({ confine: (command) => Effect.succeed(command) })\n/** Explicit unconfined layer.\n * @category layers\n * @since 1.0.0-rc.1\n */\nexport const layerNoop: Layer.Layer<ProcessConfinement> = Layer.succeed(ProcessConfinement)(makeNoop)\n\nconst decidable = (pattern: CapabilityPattern, action: Action) =>\n withinMatchBudget(pattern, new Capability({ action, resource: \"x\".repeat(maxResourceLength) }))\n\n// The capability matcher permits a single star to cross separators. Only\n// this universal spelling is equivalent to **; arbitrary globs stay closed.\nconst universal = (pattern: CapabilityPattern): CapabilityPattern =>\n pattern.resource === \"*\" ? new CapabilityPattern({ action: pattern.action, resource: \"**\" }) : pattern\n\nconst coversCeiling = (ceiling: PolicyRule[\"ceiling\"], target: CapabilityPattern): boolean =>\n ceiling.groups.every((group) =>\n group.some((pattern) => decidable(pattern, target.action as Action) && subsumes(universal(pattern), target))\n )\nconst actionRelevant = (pattern: CapabilityPattern, action: Action): boolean =>\n matches(new CapabilityPattern({ action: pattern.action, resource: \"**\" }), new Capability({ action, resource: \"\" }))\n\n// A covering rule resolves the complete region. A narrower/conditional refusal\n// makes it unknown until a later covering rule resolves it. Unknown configured\n// denial vetoes all later grant groups, just as evaluate's configured veto does.\nconst prove = (policy: Policy, target: CapabilityPattern): boolean => {\n if (!coversCeiling(policy.ceiling, target)) return false\n let decision: \"allow\" | \"deny\" | \"ask\" | \"unknown\" = \"ask\"\n let configured: \"allow\" | \"deny\" | \"ask\" | \"unknown\" = \"ask\"\n for (const [index, group] of policy.groups.entries()) {\n for (const { rule, ceiling } of group) {\n if (!decidable(rule.pattern, target.action as Action)) return false\n if (!actionRelevant(rule.pattern, target.action as Action)) continue\n if (target.action === \"net:private\" && rule.effect === \"allow\" && rule.pattern.action !== \"net:private\") continue\n if (coversCeiling(ceiling, target) && subsumes(universal(rule.pattern), target)) decision = rule.effect\n else if (rule.effect !== \"allow\") decision = \"unknown\"\n if (index === 0) configured = decision\n }\n }\n return configured !== \"deny\" && configured !== \"unknown\" && decision === \"allow\"\n}\n\n/** Derives a subset of authority, never a widening. Literal filesystem grants,\n * complex globs and unrepresentable restrictions conservatively open nothing.\n * Writable trees also require read authority and write authority over their\n * exact directory root: native mounts permit reads and directory metadata\n * changes. Only whole-tree grants prove filesystem trees; unrestricted\n * authority for each of get/post/private is required to open network access.\n * @category resolution\n * @since 1.0.0-rc.1\n */\nexport const profile = (\n grants: GrantService,\n workspaceRoot: string,\n path: Path.Path\n): Effect.Effect<Profile, GrantStoreError> =>\n Effect.gen(function*() {\n const policy = yield* grants.policy\n const root = path.resolve(workspaceRoot)\n const resources = [\n ...policy.groups.flatMap((group) =>\n group.flatMap(({ rule, ceiling }) => [rule.pattern, ...ceiling.groups.flat()])\n ),\n ...policy.ceiling.groups.flat()\n ]\n const candidates = new Set<string>()\n for (const { resource } of resources) {\n if (resource === \"**\" || resource === \"*\") {\n candidates.add(\".\")\n continue\n }\n if (!resource.endsWith(\"/**\") || /[*?]/.test(resource.slice(0, -3))) continue\n const base = resource.slice(0, -3)\n // Relative policy resources do not authorize absolute kernel resources.\n if (!path.isAbsolute(base) || path.normalize(base) !== base) continue\n const relative = path.relative(root, base)\n if (path.isAbsolute(relative) || relative.split(path.sep)[0] === \"..\") continue\n candidates.add(relative === \"\" ? \".\" : relative.split(path.sep).join(\"/\"))\n }\n const opened = (action: Action) =>\n [...candidates].filter((relative) => {\n const directory = relative === \".\" ? root : path.resolve(root, relative)\n const resource = `${directory}/**`\n return prove(policy, new CapabilityPattern({ action, resource })) &&\n (action !== \"fs:write\" || (\n prove(policy, new CapabilityPattern({ action: \"fs:read\", resource })) &&\n prove(policy, new CapabilityPattern({ action: \"fs:write\", resource: directory }))\n ))\n })\n .filter((relative, _, all) =>\n !all.some((parent) => parent !== relative && (parent === \".\" || relative.startsWith(`${parent}/`)))\n )\n .sort()\n return Object.freeze({\n workspaceRoot: root,\n reads: Object.freeze(opened(\"fs:read\")),\n writes: Object.freeze(opened(\"fs:write\")),\n readOnly: Object.freeze([]),\n network: ([\"net:get\", \"net:post\", \"net:private\"] as const).every((action) =>\n prove(policy, new CapabilityPattern({ action, resource: \"**\" }))\n ) ?\n \"open\" as const :\n \"none\" as const\n })\n })\n"]}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * The host's ledger of the processes it spawned.
3
+ *
4
+ * A cancelled run must not leave a child agent running, and the engine cannot
5
+ * do anything about that on its own: cancellation interrupts fibers, and a
6
+ * fiber closing its scope only reaches the processes THIS incarnation of the
7
+ * host still holds a handle for. A host that crashed left its children with no
8
+ * one holding anything.
9
+ *
10
+ * The ledger is the missing half. Every spawn is recorded here in memory and
11
+ * written to the journal as an ownerless durable record. It is ownerless
12
+ * because it describes the host rather than a run, and first-writer-wins is
13
+ * exactly the semantics a spawn record wants. The next incarnation of the same
14
+ * `hostId` replays those records, subtracts the ones that reported an exit,
15
+ * and is left with {@link Service.orphans}: the process groups a dead owner
16
+ * abandoned, which a platform reaper can then signal.
17
+ *
18
+ * The kernel stays BELOW the engine: this module records pids and process
19
+ * groups and knows nothing about runs, attempts, or ownership fences. It also
20
+ * stays platform-neutral, because signalling a process group is a platform
21
+ * concern and lives in `@smthrs/platform-node`.
22
+ *
23
+ * Governing design:
24
+ * `docs/specs/Concepts/Host Adapters.md` and
25
+ * `docs/specs/Concepts/Journal Queue.md`.
26
+ *
27
+ * @since 1.0.0-rc.0
28
+ */
29
+ import * as JournalModule from "@smthrs/journal/Journal";
30
+ import type { JournalError } from "@smthrs/journal/Journal";
31
+ import * as JournalEvent from "@smthrs/journal/JournalEvent";
32
+ import * as Context from "effect/Context";
33
+ import * as Effect from "effect/Effect";
34
+ import * as Layer from "effect/Layer";
35
+ import * as Schema from "effect/Schema";
36
+ /**
37
+ * The event type recording that a host started a process.
38
+ *
39
+ * @category models
40
+ * @since 1.0.0-rc.0
41
+ */
42
+ export declare const SpawnedEventType = "flows.host.process-spawned.v1";
43
+ /**
44
+ * The event type recording that a recorded process ended.
45
+ *
46
+ * @category models
47
+ * @since 1.0.0-rc.0
48
+ */
49
+ export declare const ExitedEventType = "flows.host.process-exited.v1";
50
+ /**
51
+ * The event type recording that a later incarnation killed an abandoned
52
+ * process group.
53
+ *
54
+ * @category models
55
+ * @since 1.0.0-rc.0
56
+ */
57
+ export declare const ReapedEventType = "flows.host.process-reaped.v1";
58
+ /**
59
+ * The event type recording that a later incarnation retired a record WITHOUT
60
+ * signalling anything.
61
+ *
62
+ * A stored pid outlives the process that wrote it, so a reaper that cannot
63
+ * prove the number still names the process the record describes must not
64
+ * signal it. Retiring the record is still correct: nothing will ever be able
65
+ * to prove it again, and leaving it would make every later incarnation
66
+ * re-examine a number the operating system has moved on from.
67
+ *
68
+ * @category models
69
+ * @since 1.0.0-rc.0
70
+ */
71
+ export declare const SkippedEventType = "flows.host.process-reap-skipped.v1";
72
+ /**
73
+ * The producer id every ledger record is written under.
74
+ *
75
+ * Replay checks it: a record forged by another producer cannot make a host
76
+ * signal a process group.
77
+ *
78
+ * @category models
79
+ * @since 1.0.0-rc.0
80
+ */
81
+ export declare const sourceId = "@smthrs/kernel/ProcessLedger";
82
+ /**
83
+ * The journal run a host's process records live on.
84
+ *
85
+ * Process records describe a host, not a run, so they get a run of their own,
86
+ * named after the host. Two incarnations of one `hostId` therefore share a
87
+ * history, which is what makes an abandoned process discoverable.
88
+ *
89
+ * @category constructors
90
+ * @since 1.0.0-rc.0
91
+ */
92
+ export declare const hostRunId: (hostId: string) => JournalEvent.RunId;
93
+ /**
94
+ * What the spawner knows about a process the moment it starts.
95
+ *
96
+ * `pgid` is `null` when the child shares the host's own process group. Such a
97
+ * process cannot be group-signalled — signalling that group would signal the
98
+ * host itself — so the ledger records the absence rather than a number a
99
+ * reaper could misread.
100
+ *
101
+ * `commandDigest` names the executable and nothing else, as
102
+ * `CommandLine.executable` renders it. Arguments carry credentials
103
+ * (`curl -u user:password`, `mysql -phunter2`) and these records are permanent
104
+ * journal entries, so the ledger never writes an argument down. A reader that
105
+ * has to act on a record matches it by pid and process group; the program name
106
+ * is there to make the row legible.
107
+ *
108
+ * @category models
109
+ * @since 1.0.0-rc.0
110
+ */
111
+ export interface Spawned {
112
+ readonly pid: number;
113
+ readonly pgid: number | null;
114
+ readonly commandDigest: string;
115
+ }
116
+ /**
117
+ * Schema for a recorded process, as it round-trips through the journal.
118
+ *
119
+ * @category schemas
120
+ * @since 1.0.0-rc.0
121
+ */
122
+ export declare const ProcessRecord: Schema.Struct<{
123
+ readonly pid: Schema.Int;
124
+ readonly pgid: Schema.NullOr<Schema.Int>;
125
+ readonly hostId: Schema.String;
126
+ readonly ownerPid: Schema.Int;
127
+ readonly startedAtMs: Schema.Int;
128
+ readonly commandDigest: Schema.String;
129
+ }>;
130
+ /**
131
+ * One process a host started, with the identity of the incarnation that
132
+ * started it.
133
+ *
134
+ * @category models
135
+ * @since 1.0.0-rc.0
136
+ */
137
+ export type ProcessRecord = typeof ProcessRecord.Type;
138
+ /**
139
+ * Why a ledger history could not be replayed.
140
+ *
141
+ * - `journal_unreadable`: a page of the host's history could not be read.
142
+ * - `cursor_stalled`: the journal reported more history but did not advance.
143
+ *
144
+ * @category models
145
+ * @since 1.0.0-rc.1
146
+ */
147
+ export declare const ProcessLedgerReplayErrorCode: Schema.Literals<readonly ["journal_unreadable", "cursor_stalled"]>;
148
+ declare const ProcessLedgerReplayError_base: Schema.Class<ProcessLedgerReplayError, Schema.TaggedStruct<"@smthrs/kernel/ProcessLedgerReplayError", {
149
+ readonly code: Schema.Literals<readonly ["journal_unreadable", "cursor_stalled"]>;
150
+ readonly message: Schema.String;
151
+ readonly cause: Schema.optional<Schema.Defect>;
152
+ }>, import("effect/Cause").YieldableError>;
153
+ /**
154
+ * The ledger could not read a previous incarnation's history to its end.
155
+ *
156
+ * An unread history is never reported as an empty one: a caller that treated
157
+ * it as empty would leave every abandoned child running with no owner.
158
+ *
159
+ * @category errors
160
+ * @since 1.0.0-rc.1
161
+ */
162
+ export declare class ProcessLedgerReplayError extends ProcessLedgerReplayError_base {
163
+ }
164
+ /**
165
+ * Ledger operations.
166
+ *
167
+ * Every write that has a durable half REPORTS whether that half committed.
168
+ * The in-memory set is still updated first, so a caller that decides to carry
169
+ * on has an accurate view of this incarnation, but the failure is not
170
+ * swallowed: a spawn whose record did not commit is a child that no later
171
+ * incarnation can discover, which is the exact hole this ledger exists to
172
+ * close. {@link ContainedSpawner} therefore refuses such a spawn, and the
173
+ * reaper leaves a record it could not retire in place so a later incarnation
174
+ * tries again.
175
+ *
176
+ * A ledger built with no journal ({@link makeMemory}) never fails: it promises
177
+ * nothing durable in the first place.
178
+ *
179
+ * @category services
180
+ * @since 1.0.0-rc.0
181
+ */
182
+ export interface Service {
183
+ /** Records a started process and returns the durable record written for it. */
184
+ readonly record: (spawned: Spawned) => Effect.Effect<ProcessRecord, JournalError>;
185
+ /** Records that a process ended, and drops it from {@link Service.live}. */
186
+ readonly release: (record: ProcessRecord) => Effect.Effect<void, JournalError>;
187
+ /** Records that an abandoned process group was signalled by this host. */
188
+ readonly reaped: (record: ProcessRecord) => Effect.Effect<void, JournalError>;
189
+ /**
190
+ * Retires a record this host refused to signal, naming why. The record
191
+ * leaves {@link Service.orphans} without anything having been killed.
192
+ */
193
+ readonly skipped: (record: ProcessRecord, reason: string) => Effect.Effect<void, JournalError>;
194
+ /** The processes this incarnation started and has not yet released. */
195
+ readonly live: Effect.Effect<ReadonlyArray<ProcessRecord>>;
196
+ /**
197
+ * The processes a previous incarnation of this host left running.
198
+ *
199
+ * Fails when that history cannot be read to its end, so an unreadable
200
+ * history is never mistaken for one with nothing left running.
201
+ */
202
+ readonly orphans: Effect.Effect<ReadonlyArray<ProcessRecord>, ProcessLedgerReplayError>;
203
+ }
204
+ declare const ProcessLedger_base: Context.ServiceClass<ProcessLedger, "@smthrs/kernel/ProcessLedger", Service>;
205
+ /**
206
+ * The process-ledger service tag.
207
+ *
208
+ * @category services
209
+ * @since 1.0.0-rc.0
210
+ */
211
+ export declare class ProcessLedger extends ProcessLedger_base {
212
+ }
213
+ /**
214
+ * Ledger configuration.
215
+ *
216
+ * `hostId` is the durable identity two incarnations share; `ownerPid` is the
217
+ * process id of THIS incarnation, which is how a replay tells its own live
218
+ * processes from an abandoned one's.
219
+ *
220
+ * @category models
221
+ * @since 1.0.0-rc.0
222
+ */
223
+ export interface Options {
224
+ readonly hostId: string;
225
+ readonly ownerPid: number;
226
+ }
227
+ /**
228
+ * Builds a journal-backed ledger.
229
+ *
230
+ * @category constructors
231
+ * @since 1.0.0-rc.0
232
+ */
233
+ export declare const make: (options: Options) => Effect.Effect<Service, never, JournalModule.Journal>;
234
+ /**
235
+ * Builds a ledger that records nothing durably.
236
+ *
237
+ * A host without a journal still contains the processes it holds handles for —
238
+ * scope closure does that — but it inherits nothing from a previous
239
+ * incarnation, so {@link Service.orphans} is always empty.
240
+ *
241
+ * @category constructors
242
+ * @since 1.0.0-rc.0
243
+ */
244
+ export declare const makeMemory: (options: Options) => Effect.Effect<Service>;
245
+ /**
246
+ * Provides a journal-backed ledger.
247
+ *
248
+ * @category layers
249
+ * @since 1.0.0-rc.0
250
+ */
251
+ export declare const layer: (options: Options) => Layer.Layer<ProcessLedger, never, JournalModule.Journal>;
252
+ /**
253
+ * Provides a ledger that records nothing durably.
254
+ *
255
+ * @category layers
256
+ * @since 1.0.0-rc.0
257
+ */
258
+ export declare const layerMemory: (options: Options) => Layer.Layer<ProcessLedger>;
259
+ export {};
260
+ //# sourceMappingURL=ProcessLedger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessLedger.d.ts","sourceRoot":"","sources":["../../src/ProcessLedger.ts"],"names":[],"mappings":"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"}