@mysten-incubation/devstack 0.0.1 → 0.1.0

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 (838) hide show
  1. package/README.md +7 -3
  2. package/dashboard-ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  3. package/dashboard-ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  4. package/dashboard-ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  5. package/dashboard-ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  6. package/dashboard-ui/assets/geist-mono-cyrillic-ext-wght-normal-I4S5GZfc.woff2 +0 -0
  7. package/dashboard-ui/assets/geist-mono-cyrillic-wght-normal-BmXc_FBt.woff2 +0 -0
  8. package/dashboard-ui/assets/geist-mono-latin-ext-wght-normal-DrnZ1wKl.woff2 +0 -0
  9. package/dashboard-ui/assets/geist-mono-latin-wght-normal-B_7UjwxQ.woff2 +0 -0
  10. package/dashboard-ui/assets/geist-mono-symbols2-wght-normal-GZpp1pK2.woff2 +0 -0
  11. package/dashboard-ui/assets/geist-mono-vietnamese-wght-normal-D8KDMBhC.woff2 +0 -0
  12. package/dashboard-ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  13. package/dashboard-ui/assets/index-Bmi1UtAg.js +1356 -0
  14. package/dashboard-ui/assets/index-D5EShVt4.js +3 -0
  15. package/dashboard-ui/assets/index-Deml9drg.css +1 -0
  16. package/dashboard-ui/index.html +13 -0
  17. package/dist/api/define-capabilities.d.mts +14 -3
  18. package/dist/api/define-capabilities.mjs +18 -1
  19. package/dist/api/define-capabilities.mjs.map +1 -1
  20. package/dist/api/define-devstack.d.mts +1 -1
  21. package/dist/api/define-devstack.mjs +6 -26
  22. package/dist/api/define-devstack.mjs.map +1 -1
  23. package/dist/api/define-plugin.d.mts +1 -0
  24. package/dist/api/define-plugin.mjs +2 -0
  25. package/dist/api/inference-network.d.mts +132 -0
  26. package/dist/api/inference-network.mjs +105 -16
  27. package/dist/api/inference-network.mjs.map +1 -1
  28. package/dist/api/plugin-errors.d.mts +7 -0
  29. package/dist/api/run-stack.d.mts +20 -9
  30. package/dist/api/run-stack.mjs +56 -29
  31. package/dist/api/run-stack.mjs.map +1 -1
  32. package/dist/build-integrations/playwright/config.d.mts +6 -4
  33. package/dist/build-integrations/playwright/config.mjs +5 -3
  34. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  35. package/dist/build-integrations/playwright/errors.d.mts +1 -1
  36. package/dist/build-integrations/playwright/global-setup.d.mts +43 -17
  37. package/dist/build-integrations/playwright/global-setup.mjs +250 -13
  38. package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
  39. package/dist/build-integrations/playwright/index.d.mts +5 -3
  40. package/dist/build-integrations/playwright/index.mjs +4 -2
  41. package/dist/build-integrations/playwright/stack-context.d.mts +0 -1
  42. package/dist/build-integrations/playwright/stack-context.mjs +24 -63
  43. package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
  44. package/dist/build-integrations/playwright/wallet-context.d.mts +7 -10
  45. package/dist/build-integrations/playwright/wallet-context.mjs +8 -13
  46. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  47. package/dist/build-integrations/runtime/cold-start-url.d.mts +5 -0
  48. package/dist/build-integrations/runtime/cold-start-url.mjs +4 -3
  49. package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
  50. package/dist/build-integrations/runtime/conventional-routes.d.mts +51 -0
  51. package/dist/build-integrations/runtime/conventional-routes.mjs +92 -0
  52. package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -0
  53. package/dist/build-integrations/runtime/discover.d.mts +38 -30
  54. package/dist/build-integrations/runtime/discover.mjs +73 -70
  55. package/dist/build-integrations/runtime/discover.mjs.map +1 -1
  56. package/dist/build-integrations/runtime/endpoint-registry.d.mts +3 -1
  57. package/dist/build-integrations/runtime/endpoint-registry.mjs +3 -1
  58. package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
  59. package/dist/build-integrations/runtime/index.d.mts +7 -2
  60. package/dist/build-integrations/runtime/index.mjs +9 -2
  61. package/dist/build-integrations/runtime/manifest-types.d.mts +2 -0
  62. package/dist/build-integrations/runtime/manifest-types.mjs +3 -0
  63. package/dist/build-integrations/runtime/playwright-stack-context-slot.d.mts +29 -0
  64. package/dist/build-integrations/runtime/playwright-stack-context-slot.mjs +10 -0
  65. package/dist/build-integrations/runtime/playwright-stack-context-slot.mjs.map +1 -0
  66. package/dist/build-integrations/runtime/read-stack-context.d.mts +1 -1
  67. package/dist/build-integrations/runtime/read-stack-context.mjs +10 -4
  68. package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
  69. package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +48 -0
  70. package/dist/build-integrations/runtime/resolve-discovery-env.mjs +42 -0
  71. package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -0
  72. package/dist/build-integrations/runtime/stack-context.d.mts +1 -1
  73. package/dist/build-integrations/runtime/wallet-paths.mjs +2 -0
  74. package/dist/build-integrations/vite/index.d.mts +51 -0
  75. package/dist/build-integrations/vite/index.mjs +73 -0
  76. package/dist/build-integrations/vite/index.mjs.map +1 -0
  77. package/dist/build-integrations/vitest/env.d.mts +4 -3
  78. package/dist/build-integrations/vitest/env.mjs +6 -4
  79. package/dist/build-integrations/vitest/env.mjs.map +1 -1
  80. package/dist/build-integrations/vitest/errors.d.mts +25 -4
  81. package/dist/build-integrations/vitest/errors.mjs +15 -2
  82. package/dist/build-integrations/vitest/errors.mjs.map +1 -1
  83. package/dist/build-integrations/vitest/index.d.mts +2 -2
  84. package/dist/build-integrations/vitest/index.mjs +3 -3
  85. package/dist/build-integrations/vitest/setup.d.mts +4 -2
  86. package/dist/build-integrations/vitest/setup.mjs +2 -2
  87. package/dist/build-integrations/vitest/setup.mjs.map +1 -1
  88. package/dist/build-integrations/vitest/stack-context.d.mts +0 -1
  89. package/dist/build-integrations/vitest/stack-context.mjs +33 -13
  90. package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
  91. package/dist/cli/bail.mjs +23 -0
  92. package/dist/cli/bail.mjs.map +1 -0
  93. package/dist/{surfaces/cli/commands → cli}/doctor-probes.mjs +26 -16
  94. package/dist/cli/doctor-probes.mjs.map +1 -0
  95. package/dist/cli/main.d.mts +15 -1
  96. package/dist/cli/main.mjs +166 -482
  97. package/dist/cli/main.mjs.map +1 -1
  98. package/dist/cli/prune-direct.mjs +31 -201
  99. package/dist/cli/prune-direct.mjs.map +1 -1
  100. package/dist/cli/snapshot-reader.mjs +14 -11
  101. package/dist/cli/snapshot-reader.mjs.map +1 -1
  102. package/dist/cli/up-lifecycle.mjs +4 -1
  103. package/dist/cli/up-lifecycle.mjs.map +1 -1
  104. package/dist/cli/wirings/apply.mjs +95 -0
  105. package/dist/cli/wirings/apply.mjs.map +1 -0
  106. package/dist/cli/wirings/build-verb-layers.mjs +42 -0
  107. package/dist/cli/wirings/build-verb-layers.mjs.map +1 -0
  108. package/dist/cli/wirings/config-loader.mjs +69 -0
  109. package/dist/cli/wirings/config-loader.mjs.map +1 -0
  110. package/dist/cli/wirings/engine-command.mjs +30 -0
  111. package/dist/cli/wirings/engine-command.mjs.map +1 -0
  112. package/dist/cli/wirings/identity.mjs +72 -0
  113. package/dist/cli/wirings/identity.mjs.map +1 -0
  114. package/dist/cli/wirings/provide-file-system.mjs +7 -0
  115. package/dist/cli/wirings/provide-file-system.mjs.map +1 -0
  116. package/dist/cli/wirings/snapshot.mjs +177 -0
  117. package/dist/cli/wirings/snapshot.mjs.map +1 -0
  118. package/dist/cli/wirings/up.mjs +287 -0
  119. package/dist/cli/wirings/up.mjs.map +1 -0
  120. package/dist/cli/wirings/wipe.mjs +40 -0
  121. package/dist/cli/wirings/wipe.mjs.map +1 -0
  122. package/dist/contracts/capability-decl.d.mts +0 -2
  123. package/dist/contracts/codegenable.d.mts +43 -0
  124. package/dist/contracts/container-runtime.d.mts +26 -1
  125. package/dist/contracts/faucet-strategy.d.mts +25 -0
  126. package/dist/contracts/funding-strategy.d.mts +42 -0
  127. package/dist/contracts/plugin-expander.mjs +60 -0
  128. package/dist/contracts/plugin-expander.mjs.map +1 -0
  129. package/dist/contracts/projection.d.mts +5 -3
  130. package/dist/contracts/renderer.d.mts +23 -0
  131. package/dist/contracts/routable.d.mts +14 -1
  132. package/dist/contracts/snapshotable.d.mts +25 -3
  133. package/dist/contracts/wallet-protocol.d.mts +52 -0
  134. package/dist/contracts/wallet-protocol.mjs +52 -0
  135. package/dist/contracts/wallet-protocol.mjs.map +1 -0
  136. package/dist/index.d.mts +26 -25
  137. package/dist/index.mjs +20 -13
  138. package/dist/{runtime → orchestrators}/built-in-plugin-layers.mjs +10 -5
  139. package/dist/orchestrators/built-in-plugin-layers.mjs.map +1 -0
  140. package/dist/orchestrators/codegen/bindings.d.mts +1 -2
  141. package/dist/orchestrators/codegen/bindings.mjs +52 -186
  142. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  143. package/dist/orchestrators/codegen/emit.mjs +19 -1
  144. package/dist/orchestrators/codegen/emit.mjs.map +1 -1
  145. package/dist/orchestrators/codegen/errors.mjs +8 -3
  146. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  147. package/dist/orchestrators/codegen/format.mjs +47 -39
  148. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  149. package/dist/orchestrators/codegen/gitignore.mjs +3 -1
  150. package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
  151. package/dist/orchestrators/codegen/output-location.mjs +40 -0
  152. package/dist/orchestrators/codegen/output-location.mjs.map +1 -0
  153. package/dist/orchestrators/codegen/paths.d.mts +1 -1
  154. package/dist/orchestrators/codegen/paths.mjs +40 -14
  155. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  156. package/dist/orchestrators/codegen/permissions.mjs +3 -1
  157. package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
  158. package/dist/orchestrators/codegen/service.mjs +157 -105
  159. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  160. package/dist/orchestrators/lifecycle-prune/errors.mjs +31 -0
  161. package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -0
  162. package/dist/orchestrators/lifecycle-prune/index.mjs +350 -0
  163. package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -0
  164. package/dist/orchestrators/router/cleanup.mjs +26 -27
  165. package/dist/orchestrators/router/cleanup.mjs.map +1 -1
  166. package/dist/orchestrators/router/entrypoints.mjs +2 -2
  167. package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
  168. package/dist/orchestrators/router/file-provider.mjs +14 -5
  169. package/dist/orchestrators/router/file-provider.mjs.map +1 -1
  170. package/dist/orchestrators/router/hostname.mjs +19 -55
  171. package/dist/orchestrators/router/hostname.mjs.map +1 -1
  172. package/dist/orchestrators/router/index.mjs +11 -0
  173. package/dist/orchestrators/router/profile.mjs +2 -2
  174. package/dist/orchestrators/router/sentinels.mjs +26 -0
  175. package/dist/orchestrators/router/sentinels.mjs.map +1 -0
  176. package/dist/orchestrators/router/service.mjs +40 -37
  177. package/dist/orchestrators/router/service.mjs.map +1 -1
  178. package/dist/orchestrators/router/traefik-container.mjs +27 -16
  179. package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
  180. package/dist/{substrate/runtime → orchestrators}/run.mjs +26 -21
  181. package/dist/orchestrators/run.mjs.map +1 -0
  182. package/dist/orchestrators/runtime-composition.d.mts +1 -1
  183. package/dist/orchestrators/runtime-composition.mjs +123 -39
  184. package/dist/orchestrators/runtime-composition.mjs.map +1 -1
  185. package/dist/orchestrators/snapshot/capture-command.d.mts +1 -0
  186. package/dist/orchestrators/snapshot/capture-command.mjs +25 -0
  187. package/dist/orchestrators/snapshot/capture-command.mjs.map +1 -0
  188. package/dist/orchestrators/snapshot/capture.mjs +42 -28
  189. package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
  190. package/dist/orchestrators/snapshot/descriptor.mjs +35 -10
  191. package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
  192. package/dist/orchestrators/snapshot/identity-guard.mjs +1 -1
  193. package/dist/orchestrators/snapshot/index.mjs +13 -0
  194. package/dist/orchestrators/snapshot/integrity.d.mts +1 -1
  195. package/dist/orchestrators/snapshot/integrity.mjs +73 -17
  196. package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
  197. package/dist/orchestrators/snapshot/pending-marker.d.mts +1 -0
  198. package/dist/orchestrators/snapshot/pending-marker.mjs +99 -0
  199. package/dist/orchestrators/snapshot/pending-marker.mjs.map +1 -0
  200. package/dist/orchestrators/snapshot/phase-error.mjs +23 -0
  201. package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -0
  202. package/dist/orchestrators/snapshot/prune.mjs +20 -55
  203. package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
  204. package/dist/orchestrators/snapshot/recover-pending.d.mts +1 -0
  205. package/dist/orchestrators/snapshot/recover-pending.mjs +223 -0
  206. package/dist/orchestrators/snapshot/recover-pending.mjs.map +1 -0
  207. package/dist/orchestrators/snapshot/restore.mjs +118 -84
  208. package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
  209. package/dist/orchestrators/snapshot/service.mjs +53 -56
  210. package/dist/orchestrators/snapshot/service.mjs.map +1 -1
  211. package/dist/orchestrators/snapshot/state-document.d.mts +1 -0
  212. package/dist/orchestrators/snapshot/state-document.mjs +47 -7
  213. package/dist/orchestrators/snapshot/state-document.mjs.map +1 -1
  214. package/dist/orchestrators/snapshot/wipe.mjs +67 -10
  215. package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
  216. package/dist/plugins/account/codegen.mjs +9 -8
  217. package/dist/plugins/account/codegen.mjs.map +1 -1
  218. package/dist/plugins/account/errors.d.mts +33 -6
  219. package/dist/plugins/account/errors.mjs.map +1 -1
  220. package/dist/plugins/account/funding.d.mts +29 -19
  221. package/dist/plugins/account/funding.mjs +84 -66
  222. package/dist/plugins/account/funding.mjs.map +1 -1
  223. package/dist/plugins/account/index.d.mts +2 -4
  224. package/dist/plugins/account/index.mjs +64 -31
  225. package/dist/plugins/account/index.mjs.map +1 -1
  226. package/dist/plugins/account/keypair.mjs +6 -9
  227. package/dist/plugins/account/keypair.mjs.map +1 -1
  228. package/dist/plugins/account/lease.mjs +1 -0
  229. package/dist/plugins/account/lease.mjs.map +1 -1
  230. package/dist/plugins/account/registry.d.mts +14 -1
  231. package/dist/plugins/account/registry.mjs +18 -18
  232. package/dist/plugins/account/registry.mjs.map +1 -1
  233. package/dist/plugins/account/service.d.mts +23 -4
  234. package/dist/plugins/account/service.mjs +83 -45
  235. package/dist/plugins/account/service.mjs.map +1 -1
  236. package/dist/plugins/account/snapshot.mjs +2 -5
  237. package/dist/plugins/account/snapshot.mjs.map +1 -1
  238. package/dist/plugins/account/spans.mjs +16 -0
  239. package/dist/plugins/account/spans.mjs.map +1 -0
  240. package/dist/plugins/account/variants/keystore.mjs +6 -8
  241. package/dist/plugins/account/variants/keystore.mjs.map +1 -1
  242. package/dist/plugins/action/build-context.d.mts +3 -2
  243. package/dist/plugins/action/errors.d.mts +16 -12
  244. package/dist/plugins/action/errors.mjs.map +1 -1
  245. package/dist/plugins/action/execute.mjs +65 -103
  246. package/dist/plugins/action/execute.mjs.map +1 -1
  247. package/dist/plugins/action/index.d.mts +0 -2
  248. package/dist/plugins/action/index.mjs +17 -13
  249. package/dist/plugins/action/index.mjs.map +1 -1
  250. package/dist/plugins/action/service.mjs +38 -35
  251. package/dist/plugins/action/service.mjs.map +1 -1
  252. package/dist/plugins/action/spans.mjs +11 -0
  253. package/dist/plugins/action/spans.mjs.map +1 -0
  254. package/dist/plugins/coin/codegen.mjs +9 -8
  255. package/dist/plugins/coin/codegen.mjs.map +1 -1
  256. package/dist/plugins/coin/discovery.mjs +8 -4
  257. package/dist/plugins/coin/discovery.mjs.map +1 -1
  258. package/dist/plugins/coin/index.d.mts +11 -29
  259. package/dist/plugins/coin/index.mjs +56 -27
  260. package/dist/plugins/coin/index.mjs.map +1 -1
  261. package/dist/plugins/coin/metadata.mjs +8 -15
  262. package/dist/plugins/coin/metadata.mjs.map +1 -1
  263. package/dist/plugins/coin/mint.d.mts +30 -11
  264. package/dist/plugins/coin/mint.mjs +78 -74
  265. package/dist/plugins/coin/mint.mjs.map +1 -1
  266. package/dist/plugins/coin/registry.mjs +4 -7
  267. package/dist/plugins/coin/registry.mjs.map +1 -1
  268. package/dist/plugins/coin/service.d.mts +39 -1
  269. package/dist/plugins/coin/service.mjs +11 -4
  270. package/dist/plugins/coin/service.mjs.map +1 -1
  271. package/dist/plugins/coin/spans.mjs +20 -0
  272. package/dist/plugins/coin/spans.mjs.map +1 -0
  273. package/dist/plugins/dashboard/domain.mjs +402 -0
  274. package/dist/plugins/dashboard/domain.mjs.map +1 -0
  275. package/dist/plugins/dashboard/index.d.mts +29 -0
  276. package/dist/plugins/dashboard/index.mjs +91 -0
  277. package/dist/plugins/dashboard/index.mjs.map +1 -0
  278. package/dist/plugins/dashboard/origin-policy.mjs +36 -0
  279. package/dist/plugins/dashboard/origin-policy.mjs.map +1 -0
  280. package/dist/plugins/dashboard/routable.mjs +27 -0
  281. package/dist/plugins/dashboard/routable.mjs.map +1 -0
  282. package/dist/plugins/dashboard/schema/builder.mjs +21 -0
  283. package/dist/plugins/dashboard/schema/builder.mjs.map +1 -0
  284. package/dist/plugins/dashboard/schema/enums.mjs +72 -0
  285. package/dist/plugins/dashboard/schema/enums.mjs.map +1 -0
  286. package/dist/plugins/dashboard/schema/root.mjs +351 -0
  287. package/dist/plugins/dashboard/schema/root.mjs.map +1 -0
  288. package/dist/plugins/dashboard/schema/types.mjs +508 -0
  289. package/dist/plugins/dashboard/schema/types.mjs.map +1 -0
  290. package/dist/plugins/dashboard/schema.mjs +11 -0
  291. package/dist/plugins/dashboard/schema.mjs.map +1 -0
  292. package/dist/plugins/dashboard/server.mjs +166 -0
  293. package/dist/plugins/dashboard/server.mjs.map +1 -0
  294. package/dist/plugins/deepbook/deploy.mjs +53 -115
  295. package/dist/plugins/deepbook/deploy.mjs.map +1 -1
  296. package/dist/plugins/deepbook/errors.mjs +1 -0
  297. package/dist/plugins/deepbook/errors.mjs.map +1 -1
  298. package/dist/plugins/deepbook/faucet-strategy.mjs +47 -34
  299. package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
  300. package/dist/plugins/deepbook/hash.mjs +9 -0
  301. package/dist/plugins/deepbook/hash.mjs.map +1 -0
  302. package/dist/plugins/deepbook/index.d.mts +1 -10
  303. package/dist/plugins/deepbook/index.mjs +25 -22
  304. package/dist/plugins/deepbook/index.mjs.map +1 -1
  305. package/dist/plugins/deepbook/pyth/index.mjs +26 -55
  306. package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
  307. package/dist/plugins/deepbook/snapshot.mjs +17 -29
  308. package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
  309. package/dist/plugins/deepbook/spans.mjs +18 -0
  310. package/dist/plugins/deepbook/spans.mjs.map +1 -0
  311. package/dist/plugins/deepbook/type-strings.mjs +65 -0
  312. package/dist/plugins/deepbook/type-strings.mjs.map +1 -0
  313. package/dist/plugins/deepbook/types.d.mts +2 -3
  314. package/dist/plugins/deepbook/types.mjs.map +1 -1
  315. package/dist/plugins/faucet/dispatcher.d.mts +21 -2
  316. package/dist/plugins/faucet/dispatcher.mjs +1 -2
  317. package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
  318. package/dist/plugins/faucet/errors.d.mts +11 -24
  319. package/dist/plugins/faucet/errors.mjs.map +1 -1
  320. package/dist/plugins/faucet/http.mjs +33 -14
  321. package/dist/plugins/faucet/http.mjs.map +1 -1
  322. package/dist/plugins/faucet/index.d.mts +15 -5
  323. package/dist/plugins/faucet/index.mjs +3 -0
  324. package/dist/plugins/faucet/index.mjs.map +1 -1
  325. package/dist/plugins/faucet/spans.mjs +12 -0
  326. package/dist/plugins/faucet/spans.mjs.map +1 -0
  327. package/dist/plugins/host-service/errors.d.mts +1 -1
  328. package/dist/plugins/host-service/index.mjs +34 -8
  329. package/dist/plugins/host-service/index.mjs.map +1 -1
  330. package/dist/plugins/host-service/routable.mjs +2 -1
  331. package/dist/plugins/host-service/routable.mjs.map +1 -1
  332. package/dist/plugins/host-service/service.d.mts +21 -0
  333. package/dist/plugins/host-service/service.mjs +136 -81
  334. package/dist/plugins/host-service/service.mjs.map +1 -1
  335. package/dist/plugins/internal/acquire-on-chain-artifact.mjs +23 -0
  336. package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -0
  337. package/dist/plugins/internal/codegen-helpers.mjs +18 -0
  338. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -0
  339. package/dist/plugins/internal/funding-failure-error.mjs +32 -0
  340. package/dist/plugins/internal/funding-failure-error.mjs.map +1 -0
  341. package/dist/plugins/package/build.mjs +1 -1
  342. package/dist/plugins/package/build.mjs.map +1 -1
  343. package/dist/plugins/package/codegen.mjs +26 -0
  344. package/dist/plugins/package/codegen.mjs.map +1 -1
  345. package/dist/plugins/package/errors.d.mts +16 -6
  346. package/dist/plugins/package/errors.mjs.map +1 -1
  347. package/dist/plugins/package/index.d.mts +0 -4
  348. package/dist/plugins/package/index.mjs +27 -21
  349. package/dist/plugins/package/index.mjs.map +1 -1
  350. package/dist/plugins/package/mode-known.mjs +26 -12
  351. package/dist/plugins/package/mode-known.mjs.map +1 -1
  352. package/dist/plugins/package/mode-local.mjs +47 -41
  353. package/dist/plugins/package/mode-local.mjs.map +1 -1
  354. package/dist/plugins/package/publish-executor.mjs +55 -114
  355. package/dist/plugins/package/publish-executor.mjs.map +1 -1
  356. package/dist/plugins/package/registry.mjs +2 -1
  357. package/dist/plugins/package/registry.mjs.map +1 -1
  358. package/dist/plugins/package/service.mjs.map +1 -1
  359. package/dist/plugins/package/spans.mjs +14 -0
  360. package/dist/plugins/package/spans.mjs.map +1 -0
  361. package/dist/plugins/postgres/db-ensure.mjs +19 -12
  362. package/dist/plugins/postgres/db-ensure.mjs.map +1 -1
  363. package/dist/plugins/postgres/errors.d.mts +5 -0
  364. package/dist/plugins/postgres/errors.mjs.map +1 -1
  365. package/dist/plugins/postgres/index.mjs +10 -17
  366. package/dist/plugins/postgres/index.mjs.map +1 -1
  367. package/dist/plugins/postgres/service.mjs +58 -24
  368. package/dist/plugins/postgres/service.mjs.map +1 -1
  369. package/dist/plugins/postgres/snapshot.mjs.map +1 -1
  370. package/dist/plugins/postgres/spans.mjs +11 -0
  371. package/dist/plugins/postgres/spans.mjs.map +1 -0
  372. package/dist/plugins/router-entrypoints.mjs +4 -4
  373. package/dist/plugins/router-entrypoints.mjs.map +1 -1
  374. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +15 -13
  375. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
  376. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +15 -19
  377. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
  378. package/dist/plugins/seal/codegen.d.mts +2 -3
  379. package/dist/plugins/seal/codegen.mjs.map +1 -1
  380. package/dist/plugins/seal/config-render.mjs +35 -8
  381. package/dist/plugins/seal/config-render.mjs.map +1 -1
  382. package/dist/plugins/seal/deploy.mjs +31 -39
  383. package/dist/plugins/seal/deploy.mjs.map +1 -1
  384. package/dist/plugins/seal/errors.d.mts +1 -3
  385. package/dist/plugins/seal/errors.mjs +7 -1
  386. package/dist/plugins/seal/errors.mjs.map +1 -1
  387. package/dist/plugins/seal/index.d.mts +1 -6
  388. package/dist/plugins/seal/index.mjs +40 -14
  389. package/dist/plugins/seal/index.mjs.map +1 -1
  390. package/dist/plugins/seal/key-manager.d.mts +1 -9
  391. package/dist/plugins/seal/key-manager.mjs +2 -18
  392. package/dist/plugins/seal/key-manager.mjs.map +1 -1
  393. package/dist/plugins/seal/key-server.mjs +37 -36
  394. package/dist/plugins/seal/key-server.mjs.map +1 -1
  395. package/dist/plugins/seal/keygen.mjs +16 -17
  396. package/dist/plugins/seal/keygen.mjs.map +1 -1
  397. package/dist/plugins/seal/mode/fork-known.mjs +36 -14
  398. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
  399. package/dist/plugins/seal/mode/live.d.mts +6 -4
  400. package/dist/plugins/seal/mode/live.mjs +14 -21
  401. package/dist/plugins/seal/mode/live.mjs.map +1 -1
  402. package/dist/plugins/seal/mode/local-keygen.mjs +57 -21
  403. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
  404. package/dist/plugins/seal/registry-publish.mjs +1 -0
  405. package/dist/plugins/seal/registry-publish.mjs.map +1 -1
  406. package/dist/plugins/seal/routable.mjs.map +1 -1
  407. package/dist/plugins/seal/service.mjs.map +1 -1
  408. package/dist/plugins/seal/spans.mjs +18 -0
  409. package/dist/plugins/seal/spans.mjs.map +1 -0
  410. package/dist/plugins/sui/auto-tick.mjs +17 -23
  411. package/dist/plugins/sui/auto-tick.mjs.map +1 -1
  412. package/dist/plugins/sui/chain-build-container.mjs +18 -0
  413. package/dist/plugins/sui/chain-build-container.mjs.map +1 -0
  414. package/dist/plugins/sui/chain-probe.d.mts +5 -5
  415. package/dist/plugins/sui/chain-probe.mjs +28 -58
  416. package/dist/plugins/sui/chain-probe.mjs.map +1 -1
  417. package/dist/plugins/sui/codegen.mjs +26 -0
  418. package/dist/plugins/sui/codegen.mjs.map +1 -1
  419. package/dist/plugins/sui/errors.d.mts +2 -29
  420. package/dist/plugins/sui/errors.mjs +1 -3
  421. package/dist/plugins/sui/errors.mjs.map +1 -1
  422. package/dist/plugins/sui/fork-faucet-strategy.d.mts +1 -0
  423. package/dist/plugins/sui/fork-faucet-strategy.mjs +55 -0
  424. package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -0
  425. package/dist/plugins/sui/fork-orchestration.d.mts +1 -0
  426. package/dist/plugins/sui/fork-orchestration.mjs +170 -2
  427. package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
  428. package/dist/plugins/sui/fork-transaction.d.mts +2 -0
  429. package/dist/plugins/sui/fork-transaction.mjs +92 -28
  430. package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
  431. package/dist/plugins/sui/index.d.mts +33 -70
  432. package/dist/plugins/sui/index.mjs +58 -35
  433. package/dist/plugins/sui/index.mjs.map +1 -1
  434. package/dist/plugins/{faucet/strategies/sui-local.mjs → sui/local-faucet-strategy.mjs} +10 -7
  435. package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -0
  436. package/dist/plugins/sui/mode/external.mjs +7 -13
  437. package/dist/plugins/sui/mode/external.mjs.map +1 -1
  438. package/dist/plugins/sui/mode/fork.mjs +136 -59
  439. package/dist/plugins/sui/mode/fork.mjs.map +1 -1
  440. package/dist/plugins/sui/mode/live.mjs +10 -16
  441. package/dist/plugins/sui/mode/live.mjs.map +1 -1
  442. package/dist/plugins/sui/mode/local.mjs +37 -36
  443. package/dist/plugins/sui/mode/local.mjs.map +1 -1
  444. package/dist/plugins/sui/mode/shared-boot.mjs +38 -115
  445. package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
  446. package/dist/plugins/sui/mode/shared.d.mts +1 -5
  447. package/dist/plugins/sui/mode/shared.mjs.map +1 -1
  448. package/dist/plugins/sui/mode/spec.d.mts +18 -0
  449. package/dist/plugins/sui/move-summary-runner.mjs +207 -0
  450. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -0
  451. package/dist/plugins/sui/network-resolver.d.mts +4 -3
  452. package/dist/plugins/sui/service.mjs.map +1 -1
  453. package/dist/plugins/sui/snapshot.mjs +3 -0
  454. package/dist/plugins/sui/snapshot.mjs.map +1 -1
  455. package/dist/plugins/sui/spans.mjs +17 -0
  456. package/dist/plugins/sui/spans.mjs.map +1 -0
  457. package/dist/plugins/wallet/codegen.d.mts +0 -1
  458. package/dist/plugins/wallet/codegen.mjs +8 -9
  459. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  460. package/dist/plugins/wallet/index.d.mts +6 -8
  461. package/dist/plugins/wallet/index.mjs +46 -35
  462. package/dist/plugins/wallet/index.mjs.map +1 -1
  463. package/dist/plugins/wallet/origin-policy.mjs +12 -28
  464. package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
  465. package/dist/plugins/wallet/pairing.mjs +6 -4
  466. package/dist/plugins/wallet/pairing.mjs.map +1 -1
  467. package/dist/plugins/wallet/protocol.d.mts +1 -0
  468. package/dist/plugins/wallet/protocol.mjs +5 -44
  469. package/dist/plugins/wallet/protocol.mjs.map +1 -1
  470. package/dist/plugins/wallet/routable.mjs +2 -8
  471. package/dist/plugins/wallet/routable.mjs.map +1 -1
  472. package/dist/plugins/wallet/server.mjs +36 -44
  473. package/dist/plugins/wallet/server.mjs.map +1 -1
  474. package/dist/plugins/wallet/service.d.mts +1 -5
  475. package/dist/plugins/wallet/service.mjs +22 -18
  476. package/dist/plugins/wallet/service.mjs.map +1 -1
  477. package/dist/plugins/wallet/spans.mjs +22 -0
  478. package/dist/plugins/wallet/spans.mjs.map +1 -0
  479. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +33 -8
  480. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
  481. package/dist/plugins/walrus/codegen.d.mts +3 -3
  482. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  483. package/dist/plugins/walrus/deploy-paths.mjs +21 -5
  484. package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
  485. package/dist/plugins/walrus/deploy.mjs +67 -69
  486. package/dist/plugins/walrus/deploy.mjs.map +1 -1
  487. package/dist/plugins/walrus/errors.mjs +1 -0
  488. package/dist/plugins/walrus/errors.mjs.map +1 -1
  489. package/dist/plugins/walrus/faucet-strategy.mjs +12 -7
  490. package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
  491. package/dist/plugins/walrus/index.d.mts +2 -13
  492. package/dist/plugins/walrus/index.mjs +18 -23
  493. package/dist/plugins/walrus/index.mjs.map +1 -1
  494. package/dist/plugins/walrus/mode/known-deploy.mjs +7 -5
  495. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
  496. package/dist/plugins/walrus/mode/local-cluster.mjs +26 -7
  497. package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
  498. package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
  499. package/dist/plugins/walrus/routable.mjs +7 -23
  500. package/dist/plugins/walrus/routable.mjs.map +1 -1
  501. package/dist/plugins/walrus/service.mjs.map +1 -1
  502. package/dist/plugins/walrus/spans.mjs +18 -0
  503. package/dist/plugins/walrus/spans.mjs.map +1 -0
  504. package/dist/plugins/walrus/storage-nodes.d.mts +6 -2
  505. package/dist/plugins/walrus/storage-nodes.mjs +15 -8
  506. package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
  507. package/dist/plugins/walrus/wal-swap.mjs +58 -15
  508. package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
  509. package/dist/primitives/artifact-publisher.d.mts +1 -1
  510. package/dist/primitives/artifact-publisher.mjs +15 -0
  511. package/dist/primitives/artifact-publisher.mjs.map +1 -0
  512. package/dist/runtime/docker/client.mjs +17 -4
  513. package/dist/runtime/docker/client.mjs.map +1 -1
  514. package/dist/runtime/docker/container.mjs +219 -132
  515. package/dist/runtime/docker/container.mjs.map +1 -1
  516. package/dist/runtime/docker/errors.mjs +0 -6
  517. package/dist/runtime/docker/errors.mjs.map +1 -1
  518. package/dist/runtime/docker/exec.mjs +21 -18
  519. package/dist/runtime/docker/exec.mjs.map +1 -1
  520. package/dist/runtime/docker/image.mjs +36 -13
  521. package/dist/runtime/docker/image.mjs.map +1 -1
  522. package/dist/runtime/docker/index.mjs +14 -0
  523. package/dist/runtime/docker/inspect-and-decode.mjs +51 -0
  524. package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -0
  525. package/dist/runtime/docker/inventory.mjs +14 -11
  526. package/dist/runtime/docker/inventory.mjs.map +1 -1
  527. package/dist/runtime/docker/labels.mjs +38 -5
  528. package/dist/runtime/docker/labels.mjs.map +1 -1
  529. package/dist/runtime/docker/logs.d.mts +1 -1
  530. package/dist/runtime/docker/logs.mjs.map +1 -1
  531. package/dist/runtime/docker/network.mjs +83 -47
  532. package/dist/runtime/docker/network.mjs.map +1 -1
  533. package/dist/runtime/docker/render-run-args.mjs +82 -0
  534. package/dist/runtime/docker/render-run-args.mjs.map +1 -0
  535. package/dist/runtime/docker/service.d.mts +1 -1
  536. package/dist/runtime/docker/service.mjs +12 -7
  537. package/dist/runtime/docker/service.mjs.map +1 -1
  538. package/dist/runtime/docker/sweep.mjs +118 -43
  539. package/dist/runtime/docker/sweep.mjs.map +1 -1
  540. package/dist/runtime/docker/volume.mjs +2 -0
  541. package/dist/runtime/docker/volume.mjs.map +1 -1
  542. package/dist/runtime/docker/wrap.mjs +30 -1
  543. package/dist/runtime/docker/wrap.mjs.map +1 -1
  544. package/dist/substrate/cross-process.mjs +14 -8
  545. package/dist/substrate/cross-process.mjs.map +1 -1
  546. package/dist/substrate/event-time.mjs +33 -0
  547. package/dist/substrate/event-time.mjs.map +1 -0
  548. package/dist/substrate/events.d.mts +28 -8
  549. package/dist/substrate/identity.d.mts +2 -1
  550. package/dist/substrate/manifest.d.mts +68 -5
  551. package/dist/substrate/manifest.mjs +34 -5
  552. package/dist/substrate/manifest.mjs.map +1 -1
  553. package/dist/substrate/network.d.mts +3 -5
  554. package/dist/substrate/options.d.mts +0 -2
  555. package/dist/substrate/plugin.d.mts +13 -0
  556. package/dist/substrate/plugin.mjs +4 -2
  557. package/dist/substrate/plugin.mjs.map +1 -1
  558. package/dist/substrate/projection.d.mts +35 -3
  559. package/dist/substrate/runtime/artifact-publisher/index.mjs +19 -9
  560. package/dist/substrate/runtime/artifact-publisher/index.mjs.map +1 -1
  561. package/dist/substrate/runtime/atomic-write.mjs +97 -32
  562. package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
  563. package/dist/substrate/runtime/cache/index.mjs +3 -0
  564. package/dist/substrate/runtime/cache/schema.mjs +2 -2
  565. package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
  566. package/dist/substrate/runtime/cache/service.mjs +9 -7
  567. package/dist/substrate/runtime/cache/service.mjs.map +1 -1
  568. package/dist/substrate/runtime/capability-sinks/index.d.mts +1 -1
  569. package/dist/substrate/runtime/capability-sinks/index.mjs +3 -0
  570. package/dist/substrate/runtime/capability-sinks/layer.mjs +1 -1
  571. package/dist/substrate/runtime/capability-sinks/service.d.mts +61 -2
  572. package/dist/substrate/runtime/capability-sinks/service.mjs +21 -26
  573. package/dist/substrate/runtime/capability-sinks/service.mjs.map +1 -1
  574. package/dist/substrate/runtime/config-validation.d.mts +1 -13
  575. package/dist/substrate/runtime/config-validation.mjs +2 -91
  576. package/dist/substrate/runtime/config-validation.mjs.map +1 -1
  577. package/dist/substrate/runtime/container-runtime.d.mts +1 -0
  578. package/dist/substrate/runtime/container-runtime.mjs +2 -0
  579. package/dist/substrate/runtime/control-plane/domain.mjs +101 -0
  580. package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -0
  581. package/dist/substrate/runtime/control-plane/service.mjs +7 -0
  582. package/dist/substrate/runtime/control-plane/service.mjs.map +1 -0
  583. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +46 -19
  584. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
  585. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs +30 -12
  586. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
  587. package/dist/substrate/runtime/cross-process/command-channel/index.mjs +5 -0
  588. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs +11 -2
  589. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
  590. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs +1 -1
  591. package/dist/substrate/runtime/cross-process/index.mjs +11 -0
  592. package/dist/substrate/runtime/cross-process/live-clock.mjs +34 -0
  593. package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -0
  594. package/dist/substrate/runtime/cross-process/liveness.mjs +52 -10
  595. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  596. package/dist/substrate/runtime/cross-process/lock.d.mts +1 -0
  597. package/dist/substrate/runtime/cross-process/lock.mjs +23 -0
  598. package/dist/substrate/runtime/cross-process/lock.mjs.map +1 -0
  599. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +64 -0
  600. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -0
  601. package/dist/substrate/runtime/cross-process/roster.mjs +97 -83
  602. package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
  603. package/dist/substrate/runtime/cross-process/self-pid.mjs +8 -0
  604. package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -0
  605. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +24 -28
  606. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +1 -1
  607. package/dist/substrate/runtime/cross-process/stack-lock.mjs +41 -20
  608. package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
  609. package/dist/substrate/runtime/current-plugin.mjs +2 -2
  610. package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
  611. package/dist/substrate/runtime/errors.mjs +12 -6
  612. package/dist/substrate/runtime/errors.mjs.map +1 -1
  613. package/dist/substrate/runtime/format-unknown-error.mjs +30 -0
  614. package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -0
  615. package/dist/substrate/runtime/host-bind-mount-owner.mjs +10 -0
  616. package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -0
  617. package/dist/substrate/runtime/host-gateway.mjs +20 -0
  618. package/dist/substrate/runtime/host-gateway.mjs.map +1 -0
  619. package/dist/substrate/runtime/host-tree-tar/index.mjs +61 -50
  620. package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
  621. package/dist/substrate/runtime/http-probe.d.mts +1 -1
  622. package/dist/substrate/runtime/index.mjs +14 -0
  623. package/dist/substrate/runtime/lease-broker/index.d.mts +1 -1
  624. package/dist/substrate/runtime/lease-broker/index.mjs +2 -0
  625. package/dist/substrate/runtime/lease-broker/service.d.mts +1 -64
  626. package/dist/substrate/runtime/lease-broker/service.mjs +1 -1
  627. package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
  628. package/dist/substrate/runtime/lifecycle/dep-graph.mjs +22 -3
  629. package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
  630. package/dist/substrate/runtime/lifecycle/index.mjs +9 -0
  631. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +1 -1
  632. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +20 -3
  633. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
  634. package/dist/substrate/runtime/lifecycle/selective-restart.mjs +1 -1
  635. package/dist/substrate/runtime/lifecycle/signals.mjs +5 -5
  636. package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
  637. package/dist/substrate/runtime/lifecycle/state-machine.mjs +1 -1
  638. package/dist/substrate/runtime/managed-container.d.mts +19 -1
  639. package/dist/substrate/runtime/managed-container.mjs +20 -1
  640. package/dist/substrate/runtime/managed-container.mjs.map +1 -1
  641. package/dist/substrate/runtime/manifest/index.mjs +3 -0
  642. package/dist/substrate/runtime/manifest/manifest.mjs +15 -11
  643. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  644. package/dist/substrate/runtime/mode-errors.mjs +20 -0
  645. package/dist/substrate/runtime/mode-errors.mjs.map +1 -0
  646. package/dist/substrate/runtime/observability/cascade-formatter.mjs +9 -13
  647. package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
  648. package/dist/substrate/runtime/observability/formatter-registry.mjs +19 -36
  649. package/dist/substrate/runtime/observability/formatter-registry.mjs.map +1 -1
  650. package/dist/substrate/runtime/observability/ignore-with-log.d.mts +1 -0
  651. package/dist/substrate/runtime/observability/ignore-with-log.mjs +17 -0
  652. package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -0
  653. package/dist/substrate/runtime/observability/index.d.mts +1 -1
  654. package/dist/substrate/runtime/observability/index.mjs +13 -0
  655. package/dist/substrate/runtime/observability/log-store.d.mts +1 -0
  656. package/dist/substrate/runtime/observability/log-store.mjs +175 -0
  657. package/dist/substrate/runtime/observability/log-store.mjs.map +1 -0
  658. package/dist/substrate/runtime/observability/logger.d.mts +2 -1
  659. package/dist/substrate/runtime/observability/logger.mjs +5 -9
  660. package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
  661. package/dist/substrate/runtime/observability/output-truncate.mjs +35 -0
  662. package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -0
  663. package/dist/substrate/runtime/observability/pretty-error.mjs +9 -12
  664. package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
  665. package/dist/substrate/runtime/observability/redaction.d.mts +2 -13
  666. package/dist/substrate/runtime/observability/redaction.mjs +8 -14
  667. package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
  668. package/dist/substrate/runtime/observability/span-store.d.mts +1 -0
  669. package/dist/substrate/runtime/observability/span-store.mjs +110 -0
  670. package/dist/substrate/runtime/observability/span-store.mjs.map +1 -0
  671. package/dist/substrate/runtime/observability/spans.mjs +14 -14
  672. package/dist/substrate/runtime/observability/spans.mjs.map +1 -1
  673. package/dist/substrate/runtime/observability/subprocess-capture.mjs +1 -1
  674. package/dist/substrate/runtime/passthrough-or-wrap.mjs +33 -0
  675. package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -0
  676. package/dist/substrate/runtime/paths.d.mts +1 -1
  677. package/dist/substrate/runtime/paths.mjs +4 -3
  678. package/dist/substrate/runtime/paths.mjs.map +1 -1
  679. package/dist/substrate/runtime/phase-preserving-produce.mjs +40 -0
  680. package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -0
  681. package/dist/substrate/runtime/port-broker/index.mjs +3 -0
  682. package/dist/substrate/runtime/port-broker/service.mjs +170 -126
  683. package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
  684. package/dist/substrate/runtime/post-acquire-tasks.mjs +1 -1
  685. package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
  686. package/dist/substrate/runtime/probes.d.mts +7 -5
  687. package/dist/substrate/runtime/probes.mjs +3 -1
  688. package/dist/substrate/runtime/probes.mjs.map +1 -1
  689. package/dist/substrate/runtime/projection/index.mjs +4 -0
  690. package/dist/substrate/runtime/projection/operational-endpoints.mjs +1 -2
  691. package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
  692. package/dist/substrate/runtime/projection/persisted.mjs +33 -15
  693. package/dist/substrate/runtime/projection/persisted.mjs.map +1 -1
  694. package/dist/substrate/runtime/projection/state-ref.mjs +26 -2
  695. package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
  696. package/dist/substrate/runtime/projection/update.mjs +88 -24
  697. package/dist/substrate/runtime/projection/update.mjs.map +1 -1
  698. package/dist/substrate/runtime/random-suffix.mjs +11 -0
  699. package/dist/substrate/runtime/random-suffix.mjs.map +1 -0
  700. package/dist/substrate/runtime/retry-policy.d.mts +59 -1
  701. package/dist/substrate/runtime/retry-policy.mjs +66 -1
  702. package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
  703. package/dist/substrate/runtime/routed-url.d.mts +1 -0
  704. package/dist/substrate/runtime/routed-url.mjs +79 -0
  705. package/dist/substrate/runtime/routed-url.mjs.map +1 -0
  706. package/dist/substrate/runtime/runtime-decode.d.mts +1 -1
  707. package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
  708. package/dist/substrate/runtime/scoped-http-server.mjs +2 -3
  709. package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
  710. package/dist/substrate/runtime/scoped-multimap/index.mjs +2 -0
  711. package/dist/substrate/runtime/scoped-multimap/service.mjs +52 -0
  712. package/dist/substrate/runtime/scoped-multimap/service.mjs.map +1 -0
  713. package/dist/substrate/runtime/scoped-ref-map/index.mjs +2 -0
  714. package/dist/substrate/runtime/scoped-ref-map/service.mjs +2 -2
  715. package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +1 -1
  716. package/dist/substrate/runtime/stage-and-swap/index.mjs +72 -4
  717. package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
  718. package/dist/substrate/runtime/state-store/index.d.mts +1 -0
  719. package/dist/substrate/runtime/state-store/index.mjs +3 -0
  720. package/dist/substrate/runtime/state-store/schema.d.mts +1 -0
  721. package/dist/substrate/runtime/state-store/schema.mjs +19 -14
  722. package/dist/substrate/runtime/state-store/schema.mjs.map +1 -1
  723. package/dist/substrate/runtime/state-store/service.d.mts +1 -0
  724. package/dist/substrate/runtime/state-store/service.mjs +145 -0
  725. package/dist/substrate/runtime/state-store/service.mjs.map +1 -0
  726. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.d.mts +1 -0
  727. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs +33 -0
  728. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -0
  729. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs +1 -1
  730. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
  731. package/dist/substrate/runtime/strategy-registry/index.mjs +4 -0
  732. package/dist/substrate/runtime/strategy-registry/service.mjs +19 -33
  733. package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
  734. package/dist/substrate/runtime/subnet-broker.mjs +60 -0
  735. package/dist/substrate/runtime/subnet-broker.mjs.map +1 -0
  736. package/dist/substrate/runtime/sui-execute/index.d.mts +21 -1
  737. package/dist/substrate/runtime/sui-execute/index.mjs +84 -20
  738. package/dist/substrate/runtime/sui-execute/index.mjs.map +1 -1
  739. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.d.mts +1 -0
  740. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs +32 -0
  741. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +1 -0
  742. package/dist/substrate/runtime/sui-ledger/object-ref.mjs +32 -0
  743. package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +1 -0
  744. package/dist/substrate/runtime/sui-move-build/index.mjs +93 -19
  745. package/dist/substrate/runtime/sui-move-build/index.mjs.map +1 -1
  746. package/dist/substrate/runtime/supervisor/acquire-node.mjs +181 -0
  747. package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -0
  748. package/dist/substrate/runtime/supervisor/background-tasks.mjs +144 -0
  749. package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -0
  750. package/dist/substrate/runtime/supervisor/command-loop.mjs +68 -0
  751. package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -0
  752. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +151 -0
  753. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +1 -0
  754. package/dist/substrate/runtime/supervisor/errors.d.mts +1 -0
  755. package/dist/substrate/runtime/supervisor/errors.mjs +9 -0
  756. package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -0
  757. package/dist/substrate/runtime/supervisor/index.d.mts +1 -0
  758. package/dist/substrate/runtime/supervisor/index.mjs +3 -0
  759. package/dist/substrate/runtime/supervisor/shutdown.mjs +51 -0
  760. package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -0
  761. package/dist/substrate/runtime/supervisor/start-supervisor.d.mts +1 -0
  762. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +250 -0
  763. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -0
  764. package/dist/substrate/runtime/supervisor/state.d.mts +1 -0
  765. package/dist/substrate/runtime/supervisor/state.mjs +22 -0
  766. package/dist/substrate/runtime/supervisor/state.mjs.map +1 -0
  767. package/dist/substrate/runtime/supervisor/teardown.mjs +57 -0
  768. package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -0
  769. package/dist/substrate/runtime/supervisor/types.d.mts +1 -0
  770. package/dist/substrate/runtime/supervisor/wiring.mjs +133 -0
  771. package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -0
  772. package/dist/substrate/runtime/typed-env.mjs +8 -0
  773. package/dist/substrate/runtime/typed-env.mjs.map +1 -0
  774. package/dist/substrate/state-store.d.mts +1 -0
  775. package/dist/substrate/versioned-doc-schema.mjs +17 -0
  776. package/dist/substrate/versioned-doc-schema.mjs.map +1 -0
  777. package/dist/substrate/versioned-doc-sync.mjs +94 -0
  778. package/dist/substrate/versioned-doc-sync.mjs.map +1 -0
  779. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  780. package/dist/surfaces/cli/commands/index.mjs +9 -0
  781. package/dist/surfaces/cli/commands/prune-picker-entry.mjs +13 -0
  782. package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -0
  783. package/dist/surfaces/cli/commands/prune-picker.mjs +3 -2
  784. package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
  785. package/dist/surfaces/cli/commands/prune.mjs +34 -17
  786. package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
  787. package/dist/surfaces/cli/commands/status.mjs +2 -2
  788. package/dist/surfaces/cli/commands/status.mjs.map +1 -1
  789. package/dist/surfaces/cli/commands/supervisor-presence.mjs +5 -3
  790. package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
  791. package/dist/surfaces/cli/commands/wipe.mjs +38 -4
  792. package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
  793. package/dist/surfaces/cli/errors.mjs +1 -1
  794. package/dist/surfaces/cli/errors.mjs.map +1 -1
  795. package/dist/surfaces/cli/flags.mjs +0 -1
  796. package/dist/surfaces/cli/flags.mjs.map +1 -1
  797. package/dist/surfaces/cli/index.mjs +98 -18
  798. package/dist/surfaces/cli/index.mjs.map +1 -1
  799. package/dist/surfaces/cli/output.mjs +1 -0
  800. package/dist/surfaces/cli/output.mjs.map +1 -1
  801. package/dist/surfaces/cli/sysexits.mjs +2 -1
  802. package/dist/surfaces/cli/sysexits.mjs.map +1 -1
  803. package/dist/surfaces/tui/app.mjs +25 -3
  804. package/dist/surfaces/tui/app.mjs.map +1 -1
  805. package/dist/surfaces/tui/display-derivation.mjs +23 -74
  806. package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
  807. package/dist/surfaces/tui/event-log.mjs +35 -23
  808. package/dist/surfaces/tui/event-log.mjs.map +1 -1
  809. package/dist/surfaces/tui/input.mjs +5 -1
  810. package/dist/surfaces/tui/input.mjs.map +1 -1
  811. package/dist/surfaces/tui/plain-renderer.mjs +70 -34
  812. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  813. package/package.json +24 -4
  814. package/dist/contracts/liveness-classifier.d.mts +0 -19
  815. package/dist/contracts/network-resolver.d.mts +0 -15
  816. package/dist/contracts/network-resolver.mjs +0 -7
  817. package/dist/contracts/network-resolver.mjs.map +0 -1
  818. package/dist/orchestrators/codegen/extras.mjs +0 -16
  819. package/dist/orchestrators/codegen/extras.mjs.map +0 -1
  820. package/dist/plugins/deepbook/routable.mjs +0 -21
  821. package/dist/plugins/deepbook/routable.mjs.map +0 -1
  822. package/dist/plugins/faucet/service.d.mts +0 -20
  823. package/dist/plugins/faucet/strategies/sui-local.d.mts +0 -23
  824. package/dist/plugins/faucet/strategies/sui-local.mjs.map +0 -1
  825. package/dist/plugins/sui/seed-objects.d.mts +0 -18
  826. package/dist/plugins/sui/seed-objects.mjs +0 -25
  827. package/dist/plugins/sui/seed-objects.mjs.map +0 -1
  828. package/dist/runtime/built-in-plugin-layers.mjs.map +0 -1
  829. package/dist/substrate/runtime/context-helpers.mjs +0 -32
  830. package/dist/substrate/runtime/context-helpers.mjs.map +0 -1
  831. package/dist/substrate/runtime/run.mjs.map +0 -1
  832. package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs +0 -30
  833. package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs.map +0 -1
  834. package/dist/substrate/runtime/supervisor.d.mts +0 -1
  835. package/dist/substrate/runtime/supervisor.mjs +0 -831
  836. package/dist/substrate/runtime/supervisor.mjs.map +0 -1
  837. package/dist/surfaces/cli/commands/doctor-probes.mjs.map +0 -1
  838. /package/dist/{substrate/runtime/strategy-registry/faucet-capability-for.d.mts → plugins/faucet/http.d.mts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-registry.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/plugin-registry.ts"],"sourcesContent":["// Per-plugin lifecycle bookkeeping.\n//\n// One `PluginEntry` per node in the resolved dep-graph. The entry\n// holds:\n// - the live `LifecycleStatus` (Ref, single-fiber linearizable),\n// - the resolved value (set when status transitions to `ready`),\n// - the scope owning the plugin's `start` finalizers,\n// - a `Deferred` that downstream consumers await for the ready gate.\n//\n// The registry tracks per-key lifecycle only; projection concerns stay\n// in the supervisor and reducer.\n\nimport { Data, Deferred, Effect, Ref, Scope } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { LifecycleStatus } from '../../lifecycle.ts';\nimport type { DepNode } from './dep-graph.ts';\nimport { assertTransition } from './state-machine.ts';\n\n/** Per-registry side channel: synchronously-readable resolved values.\n * Keyed by plugin key. Populated by `markReady`; consulted by the\n * synchronous dependency reader. We can't put the value on the\n * `Deferred` itself in a publicly-supported way, and plugin start\n * receives dependency values synchronously; this is the safe escape hatch.\n *\n * Module-private; only `makeRegistry` writes into the map it\n * allocates. */\ntype ResolvedMap = Map<PluginKey, ResolvedValue>;\n\n// -----------------------------------------------------------------------------\n// Resolved-value shape\n// -----------------------------------------------------------------------------\n\n/** Erased resolved value held in the registry. The supervisor casts\n * back to the concrete type at the boundary where it threads the\n * value into a downstream plugin's resolved dependency object. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ResolvedValue = any;\n\n// -----------------------------------------------------------------------------\n// Per-plugin entry\n// -----------------------------------------------------------------------------\n\n/** Mutable lifecycle state for one plugin instance. */\nexport interface PluginEntry {\n\treadonly node: DepNode;\n\treadonly statusRef: Ref.Ref<LifecycleStatus>;\n\t/** Resolved when the plugin reaches `ready`. Downstream consumers\n\t * await this in the ready-gate. Failure is propagated by interruption\n\t * via `Deferred.fail` to keep the error chain in the cause walker. */\n\treadonly readyGate: Deferred.Deferred<ResolvedValue, PluginAcquireFailed>;\n\t/** Per-plugin Scope. Closing it runs the `start` finalizers. */\n\treadonly scope: Scope.Closeable;\n}\n\n/** Tagged failure: a plugin's `start` rejected. Carries the cause and\n * the failing plugin's key so the cause walker / cascade formatter can\n * attribute it. */\nexport class PluginAcquireFailed extends Data.TaggedError('PluginAcquireFailed')<{\n\treadonly pluginKey: PluginKey;\n\treadonly cause: unknown;\n}> {}\n\n/** Tagged failure: a downstream plugin tried to read a resolved value\n * whose entry isn't registered or hasn't reached `ready`. Programmer-\n * level error class — the dep-graph guarantees this can't happen on\n * the supervisor's own scheduling path. Surfaced when a plugin author\n * reaches outside their declared dependencies. */\nexport class UnknownDependency extends Data.TaggedError('UnknownDependency')<{\n\treadonly pluginKey: PluginKey;\n\treadonly requestedResourceId: string;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Registry\n// -----------------------------------------------------------------------------\n\n/** Build a fresh entry for `node`. Caller still owns the entry — the\n * registry below holds a `ReadonlyMap` of these. */\nexport const makeEntry = (\n\tnode: DepNode,\n\tparentScope: Scope.Scope,\n): Effect.Effect<PluginEntry, never, never> =>\n\tEffect.gen(function* () {\n\t\tconst statusRef = yield* Ref.make<LifecycleStatus>('pending');\n\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\tconst scope = yield* Scope.fork(parentScope);\n\t\treturn { node, statusRef, readyGate, scope } satisfies PluginEntry;\n\t});\n\n/** The lifecycle registry. Holds one entry per dep-graph node. */\nexport interface PluginRegistry {\n\treadonly entries: ReadonlyMap<PluginKey, PluginEntry>;\n\t/** Read a plugin's current status. */\n\treadonly getStatus: (key: PluginKey) => Effect.Effect<LifecycleStatus, UnknownDependency>;\n\t/** Transition a plugin to a new status. Validates against the\n\t * transition table; emits via `onTransition`. */\n\treadonly transition: (\n\t\tkey: PluginKey,\n\t\tto: LifecycleStatus,\n\t) => Effect.Effect<\n\t\t{ readonly from: LifecycleStatus; readonly to: LifecycleStatus },\n\t\tUnknownDependency\n\t>;\n\t/** Mark a plugin ready with its resolved value. */\n\treadonly markReady: (\n\t\tkey: PluginKey,\n\t\tvalue: ResolvedValue,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Mark a plugin failed. */\n\treadonly markFailed: (key: PluginKey, cause: unknown) => Effect.Effect<void, UnknownDependency>;\n\t/** Prepare a previously torn-down entry for hot restart. Plugin\n\t * scopes and ready gates are single-use: once a scope has been closed,\n\t * any finalizer registered during a later acquire would run\n\t * immediately, and an already-resolved ready gate would leak the old\n\t * value to downstream consumers. */\n\treadonly resetForRestart: (\n\t\tkey: PluginKey,\n\t\tparentScope: Scope.Scope,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Await `ready` for `key`. Suspends until the plugin's `readyGate`\n\t * resolves. The deferred's failure channel propagates a\n\t * `PluginAcquireFailed` so the supervisor's outer error path picks\n\t * it up. */\n\treadonly awaitReady: (\n\t\tkey: PluginKey,\n\t) => Effect.Effect<ResolvedValue, PluginAcquireFailed | UnknownDependency>;\n}\n\n/** Build a registry from a map of entries. The `onTransition` callback\n * is the supervisor's published event sink — every status change\n * flows through here. */\nexport const makeRegistry = (\n\tentries: ReadonlyMap<PluginKey, PluginEntry>,\n\tonTransition: (key: PluginKey, from: LifecycleStatus, to: LifecycleStatus) => Effect.Effect<void>,\n): PluginRegistry => {\n\tconst mutableEntries = new Map(entries);\n\tconst resolved: ResolvedMap = new Map();\n\n\tconst getEntry = (key: PluginKey): Effect.Effect<PluginEntry, UnknownDependency> => {\n\t\tconst entry = mutableEntries.get(key);\n\t\tif (entry === undefined) {\n\t\t\treturn Effect.fail(new UnknownDependency({ pluginKey: key, requestedResourceId: '' }));\n\t\t}\n\t\treturn Effect.succeed(entry);\n\t};\n\n\tconst reg: PluginRegistry & { __resolved: ResolvedMap } = {\n\t\tentries: mutableEntries,\n\t\t__resolved: resolved,\n\t\tgetStatus: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Ref.get(entry.statusRef);\n\t\t\t}),\n\t\ttransition: (key, to) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tyield* assertTransition(from, to);\n\t\t\t\tyield* Ref.set(entry.statusRef, to);\n\t\t\t\tyield* onTransition(key, from, to);\n\t\t\t\treturn { from, to };\n\t\t\t}),\n\t\tmarkReady: (key, value) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.set(key, value);\n\t\t\t\tif (from !== 'ready') {\n\t\t\t\t\t// `pending → ready` is off-table — the state machine\n\t\t\t\t\t// requires the intermediate `acquiring` hop. Bridge it\n\t\t\t\t\t// here so callers reaching `markReady` from a `pending`\n\t\t\t\t\t// entry (test fixtures, callers that mark a synthetic\n\t\t\t\t\t// already-resolved value) don't have to pre-walk the\n\t\t\t\t\t// machine. Both transitions still emit through\n\t\t\t\t\t// `onTransition` so subscribers see the full path.\n\t\t\t\t\tif (from === 'pending') {\n\t\t\t\t\t\tyield* assertTransition(from, 'acquiring');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'acquiring');\n\t\t\t\t\t\tyield* onTransition(key, from, 'acquiring');\n\t\t\t\t\t\tyield* assertTransition('acquiring', 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, 'acquiring', 'ready');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tyield* assertTransition(from, 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, from, 'ready');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tyield* Deferred.succeed(entry.readyGate, value);\n\t\t\t}),\n\t\tmarkFailed: (key, cause) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.delete(key);\n\t\t\t\tyield* assertTransition(from, 'failed');\n\t\t\t\tyield* Ref.set(entry.statusRef, 'failed');\n\t\t\t\tyield* onTransition(key, from, 'failed');\n\t\t\t\tyield* Deferred.fail(entry.readyGate, new PluginAcquireFailed({ pluginKey: key, cause }));\n\t\t\t}),\n\t\tresetForRestart: (key, parentScope) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tresolved.delete(key);\n\t\t\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\t\t\tconst scope = yield* Scope.fork(parentScope);\n\t\t\t\tmutableEntries.set(key, {\n\t\t\t\t\tnode: entry.node,\n\t\t\t\t\tstatusRef: entry.statusRef,\n\t\t\t\t\treadyGate,\n\t\t\t\t\tscope,\n\t\t\t\t});\n\t\t\t}),\n\t\tawaitReady: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Deferred.await(entry.readyGate);\n\t\t\t}),\n\t};\n\treturn reg;\n};\n\n/** Synchronous accessor: snapshot the resolved value for `key`.\n * Returns `undefined` if the plugin isn't ready yet OR isn't\n * registered. The supervisor guarantees readiness before any\n * consumer calls this; it's the ONLY synchronous path. */\nexport const readResolvedSync = (\n\tregistry: PluginRegistry,\n\tkey: PluginKey,\n): ResolvedValue | undefined => {\n\tconst resolved = (registry as PluginRegistry & { __resolved?: ResolvedMap }).__resolved;\n\treturn resolved?.get(key);\n};\n\n// -----------------------------------------------------------------------------\n// Dependency reader over the registry\n// -----------------------------------------------------------------------------\n\n/**\n * Build a synchronous dependency reader over the registry for one\n * plugin. The upstream key must already be `ready`; the supervisor\n * ensures this by awaiting upstream ready-gates before invoking start.\n */\nexport const buildDependencyReaderFor = (\n\tregistry: PluginRegistry,\n\tnode: DepNode,\n): ((resource: { readonly id: string }) => unknown) => {\n\t// Pre-build a resource-id → upstream-key index for this node so the\n\t// lookups are O(1) instead of scanning dependencies.\n\tconst resourceIdToKey = new Map<string, PluginKey>();\n\tnode.upstreamResources.forEach((resource, i) => {\n\t\tconst upstream = node.upstreamKeys[i];\n\t\tif (upstream !== undefined) resourceIdToKey.set(resource.id, upstream);\n\t});\n\treturn (resource): unknown => {\n\t\tconst key = resourceIdToKey.get(resource.id);\n\t\tif (key === undefined) {\n\t\t\t// Programmer error: the plugin reached outside its declared\n\t\t\t// dependencies. The type system normally rules this out — defending\n\t\t\t// here keeps the runtime honest in the face of cast escapes.\n\t\t\tthrow new Error(\n\t\t\t\t`DependencyReader: resource '${resource.id}' not in this plugin's declared dependencies`,\n\t\t\t);\n\t\t}\n\t\tconst value = readResolvedSync(registry, key);\n\t\tif (value === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`DependencyReader: upstream '${key}' has no resolved value yet — ` +\n\t\t\t\t\t'supervisor must mark the entry ready before downstream acquire.',\n\t\t\t);\n\t\t}\n\t\treturn value;\n\t};\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugin-registry.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/plugin-registry.ts"],"sourcesContent":["// Per-plugin lifecycle bookkeeping.\n//\n// One `PluginEntry` per node in the resolved dep-graph. The entry\n// holds:\n// - the live `LifecycleStatus` (Ref, single-fiber linearizable),\n// - the resolved value (set when status transitions to `ready`),\n// - the scope owning the plugin's `start` finalizers,\n// - a `Deferred` that downstream consumers await for the ready gate.\n//\n// The registry tracks per-key lifecycle only; projection concerns stay\n// in the supervisor and reducer.\n\nimport { Data, Deferred, Effect, Ref, Scope } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { LifecycleStatus } from '../../lifecycle.ts';\nimport type { DepNode } from './dep-graph.ts';\nimport { assertTransition } from './state-machine.ts';\n\n/** Per-registry side channel: synchronously-readable resolved values.\n * Keyed by plugin key. Populated by `markReady`; consulted by the\n * synchronous dependency reader. We can't put the value on the\n * `Deferred` itself in a publicly-supported way, and plugin start\n * receives dependency values synchronously; this is the safe escape hatch.\n *\n * Module-private; only `makeRegistry` writes into the map it\n * allocates. */\ntype ResolvedMap = Map<PluginKey, ResolvedValue>;\n\n// -----------------------------------------------------------------------------\n// Resolved-value shape\n// -----------------------------------------------------------------------------\n\n/** Erased resolved value held in the registry. The supervisor casts\n * back to the concrete type at the boundary where it threads the\n * value into a downstream plugin's resolved dependency object. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ResolvedValue = any;\n\n// -----------------------------------------------------------------------------\n// Per-plugin entry\n// -----------------------------------------------------------------------------\n\n/** Mutable lifecycle state for one plugin instance. */\nexport interface PluginEntry {\n\treadonly node: DepNode;\n\treadonly statusRef: Ref.Ref<LifecycleStatus>;\n\t/** Resolved when the plugin reaches `ready`. Downstream consumers\n\t * await this in the ready-gate. Failure is propagated by interruption\n\t * via `Deferred.fail` to keep the error chain in the cause walker. */\n\treadonly readyGate: Deferred.Deferred<ResolvedValue, PluginAcquireFailed>;\n\t/** Per-plugin Scope. Closing it runs the `start` finalizers. */\n\treadonly scope: Scope.Closeable;\n}\n\n/** Tagged failure: a plugin's `start` rejected. Carries the cause and\n * the failing plugin's key so the cause walker / cascade formatter can\n * attribute it. */\nexport class PluginAcquireFailed extends Data.TaggedError('PluginAcquireFailed')<{\n\treadonly pluginKey: PluginKey;\n\treadonly cause: unknown;\n}> {}\n\n/** Tagged failure: a downstream plugin tried to read a resolved value\n * whose entry isn't registered or hasn't reached `ready`. Programmer-\n * level error class — the dep-graph guarantees this can't happen on\n * the supervisor's own scheduling path. Surfaced when a plugin author\n * reaches outside their declared dependencies. */\nexport class UnknownDependency extends Data.TaggedError('UnknownDependency')<{\n\treadonly pluginKey: PluginKey;\n\treadonly requestedResourceId: string;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Registry\n// -----------------------------------------------------------------------------\n\n/** Build a fresh entry for `node`. Caller still owns the entry — the\n * registry below holds a `ReadonlyMap` of these. */\nexport const makeEntry = (\n\tnode: DepNode,\n\tparentScope: Scope.Scope,\n): Effect.Effect<PluginEntry, never, never> =>\n\tEffect.gen(function* () {\n\t\tconst statusRef = yield* Ref.make<LifecycleStatus>('pending');\n\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\tconst scope = yield* Scope.fork(parentScope);\n\t\treturn { node, statusRef, readyGate, scope } satisfies PluginEntry;\n\t});\n\n/** The lifecycle registry. Holds one entry per dep-graph node. */\nexport interface PluginRegistry {\n\treadonly entries: ReadonlyMap<PluginKey, PluginEntry>;\n\t/** Read a plugin's current status. */\n\treadonly getStatus: (key: PluginKey) => Effect.Effect<LifecycleStatus, UnknownDependency>;\n\t/** Transition a plugin to a new status. Validates against the\n\t * transition table; emits via `onTransition`. */\n\treadonly transition: (\n\t\tkey: PluginKey,\n\t\tto: LifecycleStatus,\n\t) => Effect.Effect<\n\t\t{ readonly from: LifecycleStatus; readonly to: LifecycleStatus },\n\t\tUnknownDependency\n\t>;\n\t/** Mark a plugin ready with its resolved value. */\n\treadonly markReady: (\n\t\tkey: PluginKey,\n\t\tvalue: ResolvedValue,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Mark a plugin failed. */\n\treadonly markFailed: (key: PluginKey, cause: unknown) => Effect.Effect<void, UnknownDependency>;\n\t/** Prepare a previously torn-down entry for hot restart. Plugin\n\t * scopes and ready gates are single-use: once a scope has been closed,\n\t * any finalizer registered during a later acquire would run\n\t * immediately, and an already-resolved ready gate would leak the old\n\t * value to downstream consumers. */\n\treadonly resetForRestart: (\n\t\tkey: PluginKey,\n\t\tparentScope: Scope.Scope,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Await `ready` for `key`. Suspends until the plugin's `readyGate`\n\t * resolves. The deferred's failure channel propagates a\n\t * `PluginAcquireFailed` so the supervisor's outer error path picks\n\t * it up. */\n\treadonly awaitReady: (\n\t\tkey: PluginKey,\n\t) => Effect.Effect<ResolvedValue, PluginAcquireFailed | UnknownDependency>;\n}\n\n/** Build a registry from a map of entries. The `onTransition` callback\n * is the supervisor's published event sink — every status change\n * flows through here. */\nexport const makeRegistry = (\n\tentries: ReadonlyMap<PluginKey, PluginEntry>,\n\tonTransition: (key: PluginKey, from: LifecycleStatus, to: LifecycleStatus) => Effect.Effect<void>,\n): PluginRegistry => {\n\tconst mutableEntries = new Map(entries);\n\tconst resolved: ResolvedMap = new Map();\n\n\tconst getEntry = (key: PluginKey): Effect.Effect<PluginEntry, UnknownDependency> => {\n\t\tconst entry = mutableEntries.get(key);\n\t\tif (entry === undefined) {\n\t\t\treturn Effect.fail(new UnknownDependency({ pluginKey: key, requestedResourceId: '' }));\n\t\t}\n\t\treturn Effect.succeed(entry);\n\t};\n\n\tconst reg: PluginRegistry & { __resolved: ResolvedMap } = {\n\t\tentries: mutableEntries,\n\t\t__resolved: resolved,\n\t\tgetStatus: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Ref.get(entry.statusRef);\n\t\t\t}),\n\t\ttransition: (key, to) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tyield* assertTransition(from, to);\n\t\t\t\tyield* Ref.set(entry.statusRef, to);\n\t\t\t\tyield* onTransition(key, from, to);\n\t\t\t\treturn { from, to };\n\t\t\t}),\n\t\tmarkReady: (key, value) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.set(key, value);\n\t\t\t\tif (from !== 'ready') {\n\t\t\t\t\t// `pending → ready` is off-table — the state machine\n\t\t\t\t\t// requires the intermediate `acquiring` hop. Bridge it\n\t\t\t\t\t// here so callers reaching `markReady` from a `pending`\n\t\t\t\t\t// entry (test fixtures, callers that mark a synthetic\n\t\t\t\t\t// already-resolved value) don't have to pre-walk the\n\t\t\t\t\t// machine. Both transitions still emit through\n\t\t\t\t\t// `onTransition` so subscribers see the full path.\n\t\t\t\t\tif (from === 'pending') {\n\t\t\t\t\t\tyield* assertTransition(from, 'acquiring');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'acquiring');\n\t\t\t\t\t\tyield* onTransition(key, from, 'acquiring');\n\t\t\t\t\t\tyield* assertTransition('acquiring', 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, 'acquiring', 'ready');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tyield* assertTransition(from, 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, from, 'ready');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tyield* Deferred.succeed(entry.readyGate, value);\n\t\t\t}),\n\t\tmarkFailed: (key, cause) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.delete(key);\n\t\t\t\tyield* assertTransition(from, 'failed');\n\t\t\t\tyield* Ref.set(entry.statusRef, 'failed');\n\t\t\t\tyield* onTransition(key, from, 'failed');\n\t\t\t\tyield* Deferred.fail(entry.readyGate, new PluginAcquireFailed({ pluginKey: key, cause }));\n\t\t\t}),\n\t\tresetForRestart: (key, parentScope) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tresolved.delete(key);\n\t\t\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\t\t\tconst scope = yield* Scope.fork(parentScope);\n\t\t\t\t// Authoritatively reset the status to `pending`. The\n\t\t\t\t// transition table only admits `→ pending` from terminal\n\t\t\t\t// states (`failed` / `stopped` / `done`), but a selective\n\t\t\t\t// restart can reset a node that is still `acquiring` or\n\t\t\t\t// `pending` (its scope close interrupted an in-flight\n\t\t\t\t// acquire). Routing that through `transition` would die on\n\t\t\t\t// the off-table move — a defect the supervisor's command\n\t\t\t\t// loop can't catch — so we set the Ref directly and emit\n\t\t\t\t// the `statusChanged` event ourselves to keep the\n\t\t\t\t// projection's restart blip and the \"every status change\n\t\t\t\t// flows through `onTransition`\" contract intact. `acquire`\n\t\t\t\t// then performs a clean `pending → acquiring` for every\n\t\t\t\t// prior node state.\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tyield* Ref.set(entry.statusRef, 'pending');\n\t\t\t\tif (from !== 'pending') yield* onTransition(key, from, 'pending');\n\t\t\t\tmutableEntries.set(key, {\n\t\t\t\t\tnode: entry.node,\n\t\t\t\t\tstatusRef: entry.statusRef,\n\t\t\t\t\treadyGate,\n\t\t\t\t\tscope,\n\t\t\t\t});\n\t\t\t}),\n\t\tawaitReady: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Deferred.await(entry.readyGate);\n\t\t\t}),\n\t};\n\treturn reg;\n};\n\n/** Synchronous accessor: snapshot the resolved value for `key`.\n * Returns `undefined` if the plugin isn't ready yet OR isn't\n * registered. The supervisor guarantees readiness before any\n * consumer calls this; it's the ONLY synchronous path. */\nexport const readResolvedSync = (\n\tregistry: PluginRegistry,\n\tkey: PluginKey,\n): ResolvedValue | undefined => {\n\tconst resolved = (registry as PluginRegistry & { __resolved?: ResolvedMap }).__resolved;\n\treturn resolved?.get(key);\n};\n\n// -----------------------------------------------------------------------------\n// Dependency reader over the registry\n// -----------------------------------------------------------------------------\n\n/**\n * Build a synchronous dependency reader over the registry for one\n * plugin. The upstream key must already be `ready`; the supervisor\n * ensures this by awaiting upstream ready-gates before invoking start.\n */\nexport const buildDependencyReaderFor = (\n\tregistry: PluginRegistry,\n\tnode: DepNode,\n): ((resource: { readonly id: string }) => unknown) => {\n\t// Pre-build a resource-id → upstream-key index for this node so the\n\t// lookups are O(1) instead of scanning dependencies.\n\tconst resourceIdToKey = new Map<string, PluginKey>();\n\tnode.upstreamResources.forEach((resource, i) => {\n\t\tconst upstream = node.upstreamKeys[i];\n\t\tif (upstream !== undefined) resourceIdToKey.set(resource.id, upstream);\n\t});\n\treturn (resource): unknown => {\n\t\tconst key = resourceIdToKey.get(resource.id);\n\t\tif (key === undefined) {\n\t\t\t// Programmer error: the plugin reached outside its declared\n\t\t\t// dependencies. The type system normally rules this out — defending\n\t\t\t// here keeps the runtime honest in the face of cast escapes.\n\t\t\tthrow new DependencyReaderViolation({\n\t\t\t\tkind: 'undeclared-dependency',\n\t\t\t\ttarget: resource.id,\n\t\t\t});\n\t\t}\n\t\tconst value = readResolvedSync(registry, key);\n\t\tif (value === undefined) {\n\t\t\tthrow new DependencyReaderViolation({\n\t\t\t\tkind: 'unresolved-upstream',\n\t\t\t\ttarget: key,\n\t\t\t});\n\t\t}\n\t\treturn value;\n\t};\n};\n\n/** Tagged defect surfaced when a plugin's `start` callback reads a\n * dependency outside its declared `dependsOn` set, or an upstream\n * that hasn't been marked ready yet. Throws synchronously inside the\n * dependency-reader closure; the Effect runtime captures it as a\n * defect the cascade-formatter projects via `_tag`. The `kind`\n * discriminator and `target` carry the offending name; consumers\n * read both. */\nexport class DependencyReaderViolation extends Data.TaggedError('DependencyReaderViolation')<{\n\treadonly kind: 'undeclared-dependency' | 'unresolved-upstream';\n\treadonly target: string;\n}> {}\n"],"mappings":";;;;;;AA0DA,IAAa,sBAAb,cAAyC,KAAK,YAAY,sBAAsB,CAG7E;;;;;;AAOH,IAAa,oBAAb,cAAuC,KAAK,YAAY,oBAAoB,CAGzE;;;AAQH,MAAa,aACZ,MACA,gBAEA,OAAO,IAAI,aAAa;AAIvB,QAAO;EAAE;EAAM,WAAA,OAHU,IAAI,KAAsB,UAAU;EAGnC,WAAA,OAFD,SAAS,MAA0C;EAEvC,OAAA,OADhB,MAAM,KAAK,YAAY;EACA;EAC3C;;;;AA4CH,MAAa,gBACZ,SACA,iBACoB;CACpB,MAAM,iBAAiB,IAAI,IAAI,QAAQ;CACvC,MAAM,2BAAwB,IAAI,KAAK;CAEvC,MAAM,YAAY,QAAkE;EACnF,MAAM,QAAQ,eAAe,IAAI,IAAI;AACrC,MAAI,UAAU,KAAA,EACb,QAAO,OAAO,KAAK,IAAI,kBAAkB;GAAE,WAAW;GAAK,qBAAqB;GAAI,CAAC,CAAC;AAEvF,SAAO,OAAO,QAAQ,MAAM;;AA6F7B,QAAO;EAzFN,SAAS;EACT,YAAY;EACZ,YAAY,QACX,OAAO,IAAI,aAAa;GACvB,MAAM,QAAQ,OAAO,SAAS,IAAI;AAClC,UAAO,OAAO,IAAI,IAAI,MAAM,UAAU;IACrC;EACH,aAAa,KAAK,OACjB,OAAO,IAAI,aAAa;GACvB,MAAM,QAAQ,OAAO,SAAS,IAAI;GAClC,MAAM,OAAO,OAAO,IAAI,IAAI,MAAM,UAAU;AAC5C,UAAO,iBAAiB,MAAM,GAAG;AACjC,UAAO,IAAI,IAAI,MAAM,WAAW,GAAG;AACnC,UAAO,aAAa,KAAK,MAAM,GAAG;AAClC,UAAO;IAAE;IAAM;IAAI;IAClB;EACH,YAAY,KAAK,UAChB,OAAO,IAAI,aAAa;GACvB,MAAM,QAAQ,OAAO,SAAS,IAAI;GAClC,MAAM,OAAO,OAAO,IAAI,IAAI,MAAM,UAAU;AAC5C,YAAS,IAAI,KAAK,MAAM;AACxB,OAAI,SAAS,QAQZ,KAAI,SAAS,WAAW;AACvB,WAAO,iBAAiB,MAAM,YAAY;AAC1C,WAAO,IAAI,IAAI,MAAM,WAAW,YAAY;AAC5C,WAAO,aAAa,KAAK,MAAM,YAAY;AAC3C,WAAO,iBAAiB,aAAa,QAAQ;AAC7C,WAAO,IAAI,IAAI,MAAM,WAAW,QAAQ;AACxC,WAAO,aAAa,KAAK,aAAa,QAAQ;UACxC;AACN,WAAO,iBAAiB,MAAM,QAAQ;AACtC,WAAO,IAAI,IAAI,MAAM,WAAW,QAAQ;AACxC,WAAO,aAAa,KAAK,MAAM,QAAQ;;AAGzC,UAAO,SAAS,QAAQ,MAAM,WAAW,MAAM;IAC9C;EACH,aAAa,KAAK,UACjB,OAAO,IAAI,aAAa;GACvB,MAAM,QAAQ,OAAO,SAAS,IAAI;GAClC,MAAM,OAAO,OAAO,IAAI,IAAI,MAAM,UAAU;AAC5C,YAAS,OAAO,IAAI;AACpB,UAAO,iBAAiB,MAAM,SAAS;AACvC,UAAO,IAAI,IAAI,MAAM,WAAW,SAAS;AACzC,UAAO,aAAa,KAAK,MAAM,SAAS;AACxC,UAAO,SAAS,KAAK,MAAM,WAAW,IAAI,oBAAoB;IAAE,WAAW;IAAK;IAAO,CAAC,CAAC;IACxF;EACH,kBAAkB,KAAK,gBACtB,OAAO,IAAI,aAAa;GACvB,MAAM,QAAQ,OAAO,SAAS,IAAI;AAClC,YAAS,OAAO,IAAI;GACpB,MAAM,YAAY,OAAO,SAAS,MAA0C;GAC5E,MAAM,QAAQ,OAAO,MAAM,KAAK,YAAY;GAc5C,MAAM,OAAO,OAAO,IAAI,IAAI,MAAM,UAAU;AAC5C,UAAO,IAAI,IAAI,MAAM,WAAW,UAAU;AAC1C,OAAI,SAAS,UAAW,QAAO,aAAa,KAAK,MAAM,UAAU;AACjE,kBAAe,IAAI,KAAK;IACvB,MAAM,MAAM;IACZ,WAAW,MAAM;IACjB;IACA;IACA,CAAC;IACD;EACH,aAAa,QACZ,OAAO,IAAI,aAAa;GACvB,MAAM,QAAQ,OAAO,SAAS,IAAI;AAClC,UAAO,OAAO,SAAS,MAAM,MAAM,UAAU;IAC5C;EAEM;;;;;;AAOX,MAAa,oBACZ,UACA,QAC+B;AAE/B,QADkB,SAA2D,YAC5D,IAAI,IAAI;;;;;;;AAY1B,MAAa,4BACZ,UACA,SACsD;CAGtD,MAAM,kCAAkB,IAAI,KAAwB;AACpD,MAAK,kBAAkB,SAAS,UAAU,MAAM;EAC/C,MAAM,WAAW,KAAK,aAAa;AACnC,MAAI,aAAa,KAAA,EAAW,iBAAgB,IAAI,SAAS,IAAI,SAAS;GACrE;AACF,SAAQ,aAAsB;EAC7B,MAAM,MAAM,gBAAgB,IAAI,SAAS,GAAG;AAC5C,MAAI,QAAQ,KAAA,EAIX,OAAM,IAAI,0BAA0B;GACnC,MAAM;GACN,QAAQ,SAAS;GACjB,CAAC;EAEH,MAAM,QAAQ,iBAAiB,UAAU,IAAI;AAC7C,MAAI,UAAU,KAAA,EACb,OAAM,IAAI,0BAA0B;GACnC,MAAM;GACN,QAAQ;GACR,CAAC;AAEH,SAAO;;;;;;;;;;AAWT,IAAa,4BAAb,cAA+C,KAAK,YAAY,4BAA4B,CAGzF"}
@@ -38,6 +38,6 @@ const planFullDrain = (graph) => {
38
38
  };
39
39
  };
40
40
  //#endregion
41
- export { planFullDrain, planRestart };
41
+ export { RestartTargetMissing, planFullDrain, planRestart };
42
42
 
43
43
  //# sourceMappingURL=selective-restart.mjs.map
@@ -27,25 +27,25 @@ const scheduleProcessExit = (exitCode) => {
27
27
  */
28
28
  const installSignalHandler = (commands, options = {}) => Effect.gen(function* () {
29
29
  const scheduleExit = options.scheduleExit ?? scheduleProcessExit;
30
+ const supervisorContext = yield* Effect.context();
31
+ const runForkInherited = Effect.runForkWith(supervisorContext);
30
32
  let shutdownRequested = false;
31
33
  const handlers = [];
32
34
  for (const signal of HANDLED_SIGNALS) {
33
35
  const listener = () => {
34
36
  const exitCode = exitCodeForSignal(signal);
35
37
  if (shutdownRequested) {
36
- const offerEffect = Queue.offer(commands, {
38
+ runForkInherited(Queue.offer(commands, {
37
39
  tag: "shutdown.hardKillRequested",
38
40
  signal,
39
41
  exitCode,
40
42
  at: Date.now()
41
- }).pipe(Effect.andThen(Effect.sync(() => scheduleExit(exitCode))));
42
- Effect.runFork(offerEffect);
43
+ }).pipe(Effect.andThen(Effect.sync(() => scheduleExit(exitCode)))));
43
44
  return;
44
45
  }
45
46
  shutdownRequested = true;
46
47
  process.exitCode ??= exitCode;
47
- const offerEffect = Queue.offer(commands, { tag: "shutdown.requested" });
48
- Effect.runFork(offerEffect);
48
+ runForkInherited(Queue.offer(commands, { tag: "shutdown.requested" }));
49
49
  };
50
50
  process.on(signal, listener);
51
51
  handlers.push({
@@ -1 +1 @@
1
- {"version":3,"file":"signals.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/signals.ts"],"sourcesContent":["// POSIX signal handling.\n//\n// Architecture § Engine / supervisor split:\n// \"signals → L0 (one POSIX signal handler at process boot), routed\n// via the command channel.\"\n//\n// Discipline:\n// - ONE handler per process. Registering twice is a programmer\n// error.\n// - Signals translate to `EngineCommand`s on the typed command stream\n// (`shutdown.requested` for graceful, `shutdown.hardKillRequested`\n// for hard).\n// - Second SIGINT/SIGTERM escalates to abort: the hard-kill command\n// is offered first, then `process.exit(130)` (or 143 for SIGTERM)\n// is scheduled.\n//\n// The supervisor wires this fiber once at boot via `Effect.forkScoped`;\n// its scope is the supervisor's outer scope, so the handler unregisters\n// when the supervisor tears down (test environments that boot multiple\n// supervisors must close them before booting the next).\n\nimport { Effect, Queue, Scope } from 'effect';\n\nimport type { EngineCommand, ShutdownSignal } from '../../events.ts';\n\n/** Signals the supervisor handles. SIGHUP intentionally omitted —\n * reconfigure is a command-channel concern, not a signal one. */\nconst HANDLED_SIGNALS = ['SIGINT', 'SIGTERM'] as const satisfies ReadonlyArray<ShutdownSignal>;\ntype HandledSignal = (typeof HANDLED_SIGNALS)[number];\n\n/** Map a signal to the exit code POSIX clients expect — 128 + N. */\nconst exitCodeForSignal = (signal: HandledSignal): number => {\n\tswitch (signal) {\n\t\tcase 'SIGINT':\n\t\t\treturn 130;\n\t\tcase 'SIGTERM':\n\t\t\treturn 143;\n\t}\n};\n\nexport interface SignalHandlerOptions {\n\treadonly scheduleExit?: (exitCode: number) => void;\n}\n\nconst scheduleProcessExit = (exitCode: number): void => {\n\tsetImmediate(() => {\n\t\tprocess.exit(exitCode);\n\t});\n};\n\n/**\n * Install signal handlers that publish `shutdown.requested` (first\n * signal) and `shutdown.hardKillRequested` before scheduling process\n * exit (second handled signal).\n *\n * Returns an Effect that runs forever in its Scope; the supervisor\n * forks it via `Effect.forkScoped`. Scope close unregisters the\n * listeners — Node's `process` listeners persist past the scope\n * otherwise, leading to \"ghost\" handlers from prior test boots.\n */\nexport const installSignalHandler = (\n\tcommands: Queue.Enqueue<EngineCommand>,\n\toptions: SignalHandlerOptions = {},\n): Effect.Effect<never, never, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst scheduleExit = options.scheduleExit ?? scheduleProcessExit;\n\t\tlet shutdownRequested = false;\n\n\t\tconst handlers: Array<{\n\t\t\treadonly signal: HandledSignal;\n\t\t\treadonly listener: NodeJS.SignalsListener;\n\t\t}> = [];\n\n\t\tfor (const signal of HANDLED_SIGNALS) {\n\t\t\tconst listener: NodeJS.SignalsListener = () => {\n\t\t\t\tconst exitCode = exitCodeForSignal(signal);\n\t\t\t\tif (shutdownRequested) {\n\t\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\t\ttag: 'shutdown.hardKillRequested',\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tat: Date.now(),\n\t\t\t\t\t} satisfies EngineCommand).pipe(\n\t\t\t\t\t\tEffect.andThen(Effect.sync(() => scheduleExit(exitCode))),\n\t\t\t\t\t);\n\t\t\t\t\tEffect.runFork(offerEffect);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tshutdownRequested = true;\n\t\t\t\tprocess.exitCode ??= exitCode;\n\t\t\t\t// Publish `shutdown.requested` — same shape regardless of\n\t\t\t\t// which signal fired. The supervisor decides drain vs abort\n\t\t\t\t// on its own loop.\n\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\ttag: 'shutdown.requested',\n\t\t\t\t} satisfies EngineCommand);\n\t\t\t\t// We're inside a Node listener; bridge into Effect via the\n\t\t\t\t// process's default runtime. `runFork` returns a fiber but we\n\t\t\t\t// don't track it — the queue is bounded by the supervisor's\n\t\t\t\t// lifetime.\n\t\t\t\tEffect.runFork(offerEffect);\n\t\t\t};\n\t\t\tprocess.on(signal, listener);\n\t\t\thandlers.push({ signal, listener });\n\t\t}\n\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tfor (const { signal, listener } of handlers) {\n\t\t\t\t\tprocess.removeListener(signal, listener);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\t// Park forever; the listeners themselves run synchronously in\n\t\t// Node's event loop, not in this fiber.\n\t\treturn yield* Effect.never;\n\t}).pipe(Effect.withSpan('lifecycle.signals.installSignalHandler'));\n\n/** Re-export the handled-signal list so tests / docs can enumerate. */\nexport const handledSignals: ReadonlyArray<HandledSignal> = HANDLED_SIGNALS;\n"],"mappings":";;;;AA2BA,MAAM,kBAAkB,CAAC,UAAU,UAAU;;AAI7C,MAAM,qBAAqB,WAAkC;AAC5D,SAAQ,QAAR;EACC,KAAK,SACJ,QAAO;EACR,KAAK,UACJ,QAAO;;;AAQV,MAAM,uBAAuB,aAA2B;AACvD,oBAAmB;AAClB,UAAQ,KAAK,SAAS;GACrB;;;;;;;;;;;;AAaH,MAAa,wBACZ,UACA,UAAgC,EAAE,KAElC,OAAO,IAAI,aAAa;CACvB,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,IAAI,oBAAoB;CAExB,MAAM,WAGD,EAAE;AAEP,MAAK,MAAM,UAAU,iBAAiB;EACrC,MAAM,iBAAyC;GAC9C,MAAM,WAAW,kBAAkB,OAAO;AAC1C,OAAI,mBAAmB;IACtB,MAAM,cAAc,MAAM,MAAM,UAAU;KACzC,KAAK;KACL;KACA;KACA,IAAI,KAAK,KAAK;KACd,CAAyB,CAAC,KAC1B,OAAO,QAAQ,OAAO,WAAW,aAAa,SAAS,CAAC,CAAC,CACzD;AACD,WAAO,QAAQ,YAAY;AAC3B;;AAED,uBAAoB;AACpB,WAAQ,aAAa;GAIrB,MAAM,cAAc,MAAM,MAAM,UAAU,EACzC,KAAK,sBACL,CAAyB;AAK1B,UAAO,QAAQ,YAAY;;AAE5B,UAAQ,GAAG,QAAQ,SAAS;AAC5B,WAAS,KAAK;GAAE;GAAQ;GAAU,CAAC;;AAGpC,QAAO,OAAO,mBACb,OAAO,WAAW;AACjB,OAAK,MAAM,EAAE,QAAQ,cAAc,SAClC,SAAQ,eAAe,QAAQ,SAAS;GAExC,CACF;AAID,QAAO,OAAO,OAAO;EACpB,CAAC,KAAK,OAAO,SAAS,yCAAyC,CAAC"}
1
+ {"version":3,"file":"signals.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/signals.ts"],"sourcesContent":["// POSIX signal handling.\n//\n// Architecture § Engine / supervisor split:\n// \"signals → L0 (one POSIX signal handler at process boot), routed\n// via the command channel.\"\n//\n// Discipline:\n// - ONE handler per process. Registering twice is a programmer\n// error.\n// - Signals translate to `EngineCommand`s on the typed command stream\n// (`shutdown.requested` for graceful, `shutdown.hardKillRequested`\n// for hard).\n// - Second SIGINT/SIGTERM escalates to abort: the hard-kill command\n// is offered first, then `process.exit(130)` (or 143 for SIGTERM)\n// is scheduled.\n//\n// The supervisor wires this fiber once at boot via `Effect.forkScoped`;\n// its scope is the supervisor's outer scope, so the handler unregisters\n// when the supervisor tears down (test environments that boot multiple\n// supervisors must close them before booting the next).\n\nimport { Effect, Queue, Scope } from 'effect';\n\nimport type { EngineCommand, ShutdownSignal } from '../../events.ts';\n\n/** Signals the supervisor handles. SIGHUP intentionally omitted —\n * reconfigure is a command-channel concern, not a signal one. */\nconst HANDLED_SIGNALS = ['SIGINT', 'SIGTERM'] as const satisfies ReadonlyArray<ShutdownSignal>;\ntype HandledSignal = (typeof HANDLED_SIGNALS)[number];\n\n/** Map a signal to the exit code POSIX clients expect — 128 + N. */\nconst exitCodeForSignal = (signal: HandledSignal): number => {\n\tswitch (signal) {\n\t\tcase 'SIGINT':\n\t\t\treturn 130;\n\t\tcase 'SIGTERM':\n\t\t\treturn 143;\n\t}\n};\n\nexport interface SignalHandlerOptions {\n\treadonly scheduleExit?: (exitCode: number) => void;\n}\n\nconst scheduleProcessExit = (exitCode: number): void => {\n\tsetImmediate(() => {\n\t\tprocess.exit(exitCode);\n\t});\n};\n\n/**\n * Install signal handlers that publish `shutdown.requested` (first\n * signal) and `shutdown.hardKillRequested` before scheduling process\n * exit (second handled signal).\n *\n * Returns an Effect that runs forever in its Scope; the supervisor\n * forks it via `Effect.forkScoped`. Scope close unregisters the\n * listeners — Node's `process` listeners persist past the scope\n * otherwise, leading to \"ghost\" handlers from prior test boots.\n */\nexport const installSignalHandler = (\n\tcommands: Queue.Enqueue<EngineCommand>,\n\toptions: SignalHandlerOptions = {},\n): Effect.Effect<never, never, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst scheduleExit = options.scheduleExit ?? scheduleProcessExit;\n\t\t// Capture the surrounding fiber's Context so the signal-listener\n\t\t// fork inherits the supervisor's logger Layer, fiber-refs, and\n\t\t// span context. Bare `Effect.runFork` evaluates against an empty\n\t\t// context — warnings/spans from the offered command would\n\t\t// otherwise bypass redaction rules and supervisor instrumentation.\n\t\tconst supervisorContext = yield* Effect.context<never>();\n\t\tconst runForkInherited = Effect.runForkWith(supervisorContext);\n\t\tlet shutdownRequested = false;\n\n\t\tconst handlers: Array<{\n\t\t\treadonly signal: HandledSignal;\n\t\t\treadonly listener: NodeJS.SignalsListener;\n\t\t}> = [];\n\n\t\tfor (const signal of HANDLED_SIGNALS) {\n\t\t\tconst listener: NodeJS.SignalsListener = () => {\n\t\t\t\tconst exitCode = exitCodeForSignal(signal);\n\t\t\t\tif (shutdownRequested) {\n\t\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\t\ttag: 'shutdown.hardKillRequested',\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tat: Date.now(),\n\t\t\t\t\t} satisfies EngineCommand).pipe(\n\t\t\t\t\t\tEffect.andThen(Effect.sync(() => scheduleExit(exitCode))),\n\t\t\t\t\t);\n\t\t\t\t\trunForkInherited(offerEffect);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tshutdownRequested = true;\n\t\t\t\tprocess.exitCode ??= exitCode;\n\t\t\t\t// Publish `shutdown.requested` — same shape regardless of\n\t\t\t\t// which signal fired. The supervisor decides drain vs abort\n\t\t\t\t// on its own loop.\n\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\ttag: 'shutdown.requested',\n\t\t\t\t} satisfies EngineCommand);\n\t\t\t\t// We're inside a Node listener; bridge into Effect via the\n\t\t\t\t// captured supervisor Context so the offered command\n\t\t\t\t// inherits logger/fiber-refs/spans. `runFork` returns a\n\t\t\t\t// fiber but we don't track it — the queue is bounded by\n\t\t\t\t// the supervisor's lifetime.\n\t\t\t\trunForkInherited(offerEffect);\n\t\t\t};\n\t\t\tprocess.on(signal, listener);\n\t\t\thandlers.push({ signal, listener });\n\t\t}\n\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tfor (const { signal, listener } of handlers) {\n\t\t\t\t\tprocess.removeListener(signal, listener);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\t// Park forever; the listeners themselves run synchronously in\n\t\t// Node's event loop, not in this fiber.\n\t\treturn yield* Effect.never;\n\t}).pipe(Effect.withSpan('lifecycle.signals.installSignalHandler'));\n\n/** Re-export the handled-signal list so tests / docs can enumerate. */\nexport const handledSignals: ReadonlyArray<HandledSignal> = HANDLED_SIGNALS;\n"],"mappings":";;;;AA2BA,MAAM,kBAAkB,CAAC,UAAU,UAAU;;AAI7C,MAAM,qBAAqB,WAAkC;AAC5D,SAAQ,QAAR;EACC,KAAK,SACJ,QAAO;EACR,KAAK,UACJ,QAAO;;;AAQV,MAAM,uBAAuB,aAA2B;AACvD,oBAAmB;AAClB,UAAQ,KAAK,SAAS;GACrB;;;;;;;;;;;;AAaH,MAAa,wBACZ,UACA,UAAgC,EAAE,KAElC,OAAO,IAAI,aAAa;CACvB,MAAM,eAAe,QAAQ,gBAAgB;CAM7C,MAAM,oBAAoB,OAAO,OAAO,SAAgB;CACxD,MAAM,mBAAmB,OAAO,YAAY,kBAAkB;CAC9D,IAAI,oBAAoB;CAExB,MAAM,WAGD,EAAE;AAEP,MAAK,MAAM,UAAU,iBAAiB;EACrC,MAAM,iBAAyC;GAC9C,MAAM,WAAW,kBAAkB,OAAO;AAC1C,OAAI,mBAAmB;AAStB,qBARoB,MAAM,MAAM,UAAU;KACzC,KAAK;KACL;KACA;KACA,IAAI,KAAK,KAAK;KACd,CAAyB,CAAC,KAC1B,OAAO,QAAQ,OAAO,WAAW,aAAa,SAAS,CAAC,CAAC,CAE9B,CAAC;AAC7B;;AAED,uBAAoB;AACpB,WAAQ,aAAa;AAYrB,oBARoB,MAAM,MAAM,UAAU,EACzC,KAAK,sBACL,CAM2B,CAAC;;AAE9B,UAAQ,GAAG,QAAQ,SAAS;AAC5B,WAAS,KAAK;GAAE;GAAQ;GAAU,CAAC;;AAGpC,QAAO,OAAO,mBACb,OAAO,WAAW;AACjB,OAAK,MAAM,EAAE,QAAQ,cAAc,SAClC,SAAQ,eAAe,QAAQ,SAAS;GAExC,CACF;AAID,QAAO,OAAO,OAAO;EACpB,CAAC,KAAK,OAAO,SAAS,yCAAyC,CAAC"}
@@ -33,6 +33,6 @@ const assertTransition = (from, to) => isAllowedTransition(from, to) ? Effect.su
33
33
  * in one of these for the stack to surface `running`. */
34
34
  const isReadyOrTerminal = (status) => status === "ready" || status === "done";
35
35
  //#endregion
36
- export { assertTransition, isReadyOrTerminal };
36
+ export { InvalidLifecycleTransition, assertTransition, isAllowedTransition, isReadyOrTerminal };
37
37
 
38
38
  //# sourceMappingURL=state-machine.mjs.map
@@ -4,8 +4,26 @@ import { Effect, Scope } from "effect";
4
4
 
5
5
  //#region src/substrate/runtime/managed-container.d.ts
6
6
  declare namespace managed_container_d_exports {
7
- export { EnsureManagedContainerOptions, ManagedContainerIdentity, ManagedContainerLabelOptions, ensureManagedContainer, managedContainerLabels };
7
+ export { EnsureManagedContainerOptions, ManagedContainerIdentity, ManagedContainerLabelOptions, PER_APP_SHARED_STACK, ensureManagedContainer, managedContainerLabels };
8
8
  }
9
+ /** Sentinel `stack` value for containers / volumes / networks that are
10
+ * shared across a single app's stacks but isolated PER APP — the
11
+ * resource lives at app-scope, not stack-scope.
12
+ *
13
+ * Current producer: the per-app sui chain-build container
14
+ * (`plugins/sui/chain-build-container.ts`) reuses one container
15
+ * across multiple stacks of the same app to keep the bind-mounted
16
+ * Move dep cache warm.
17
+ *
18
+ * Lifecycle-prune + the prune CLI compare against this sentinel to
19
+ * decide whether a resource group is shared (pinned while any
20
+ * sibling stack under the same app is live) vs per-stack (pruned
21
+ * with its stack).
22
+ *
23
+ * The vocabulary lives here alongside the `{ app, stack, plugin,
24
+ * role }` label tuple — managed-container.ts is the canonical
25
+ * owner. */
26
+ declare const PER_APP_SHARED_STACK: "_per-app_";
9
27
  interface ManagedContainerIdentity {
10
28
  readonly app: string;
11
29
  readonly stack: string;
@@ -3,9 +3,28 @@ import { SpanAttr } from "./observability/spans.mjs";
3
3
  import { Effect } from "effect";
4
4
  //#region src/substrate/runtime/managed-container.ts
5
5
  var managed_container_exports = /* @__PURE__ */ __exportAll({
6
+ PER_APP_SHARED_STACK: () => PER_APP_SHARED_STACK,
6
7
  ensureManagedContainer: () => ensureManagedContainer,
7
8
  managedContainerLabels: () => managedContainerLabels
8
9
  });
10
+ /** Sentinel `stack` value for containers / volumes / networks that are
11
+ * shared across a single app's stacks but isolated PER APP — the
12
+ * resource lives at app-scope, not stack-scope.
13
+ *
14
+ * Current producer: the per-app sui chain-build container
15
+ * (`plugins/sui/chain-build-container.ts`) reuses one container
16
+ * across multiple stacks of the same app to keep the bind-mounted
17
+ * Move dep cache warm.
18
+ *
19
+ * Lifecycle-prune + the prune CLI compare against this sentinel to
20
+ * decide whether a resource group is shared (pinned while any
21
+ * sibling stack under the same app is live) vs per-stack (pruned
22
+ * with its stack).
23
+ *
24
+ * The vocabulary lives here alongside the `{ app, stack, plugin,
25
+ * role }` label tuple — managed-container.ts is the canonical
26
+ * owner. */
27
+ const PER_APP_SHARED_STACK = "_per-app_";
9
28
  const managedContainerLabels = (options) => ({
10
29
  app: options.identity.app,
11
30
  stack: options.identity.stack,
@@ -27,6 +46,6 @@ const ensureManagedContainer = (options) => {
27
46
  } }));
28
47
  };
29
48
  //#endregion
30
- export { ensureManagedContainer, managed_container_exports };
49
+ export { PER_APP_SHARED_STACK, ensureManagedContainer, managed_container_exports };
31
50
 
32
51
  //# sourceMappingURL=managed-container.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"managed-container.mjs","names":[],"sources":["../../../src/substrate/runtime/managed-container.ts"],"sourcesContent":["import { Effect, type Scope } from 'effect';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tContainerRuntimeError,\n\tEnsureContainerSpec,\n} from '../../contracts/container-runtime.ts';\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport { SpanAttr } from './observability/spans.ts';\n\nexport interface ManagedContainerIdentity {\n\treadonly app: string;\n\treadonly stack: string;\n}\n\nexport interface ManagedContainerLabelOptions {\n\treadonly identity: ManagedContainerIdentity;\n\treadonly plugin: string;\n\treadonly role: string;\n}\n\nexport const managedContainerLabels = (\n\toptions: ManagedContainerLabelOptions,\n): ContainerLabelTuple => ({\n\tapp: options.identity.app,\n\tstack: options.identity.stack,\n\tplugin: options.plugin,\n\trole: options.role,\n});\n\ntype ManagedContainerLabelInput =\n\t| { readonly labels: ContainerLabelTuple }\n\t| ManagedContainerLabelOptions;\n\nexport type EnsureManagedContainerOptions<E> = ManagedContainerLabelInput & {\n\treadonly runtime: ContainerRuntime;\n\treadonly spec: Omit<EnsureContainerSpec, 'labels'>;\n\treadonly mapError: (cause: ContainerRuntimeError) => E;\n};\n\nconst labelsFrom = (input: ManagedContainerLabelInput): ContainerLabelTuple =>\n\t'labels' in input ? input.labels : managedContainerLabels(input);\n\nexport const ensureManagedContainer = <E>(\n\toptions: EnsureManagedContainerOptions<E>,\n): Effect.Effect<ContainerHandle, E, Scope.Scope> => {\n\tconst labels = labelsFrom(options);\n\treturn options.runtime\n\t\t.ensureContainer({\n\t\t\t...options.spec,\n\t\t\tlabels,\n\t\t})\n\t\t.pipe(\n\t\t\tEffect.mapError(options.mapError),\n\t\t\tEffect.withSpan('substrate.managedContainer.ensure', {\n\t\t\t\tattributes: {\n\t\t\t\t\t[SpanAttr.app]: labels.app,\n\t\t\t\t\t[SpanAttr.stack]: labels.stack,\n\t\t\t\t\t[SpanAttr.plugin]: labels.plugin,\n\t\t\t\t\t[SpanAttr.containerRole]: labels.role,\n\t\t\t\t\t[SpanAttr.containerName]: options.spec.name,\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n};\n"],"mappings":";;;;;;;;AAsBA,MAAa,0BACZ,aAC0B;CAC1B,KAAK,QAAQ,SAAS;CACtB,OAAO,QAAQ,SAAS;CACxB,QAAQ,QAAQ;CAChB,MAAM,QAAQ;CACd;AAYD,MAAM,cAAc,UACnB,YAAY,QAAQ,MAAM,SAAS,uBAAuB,MAAM;AAEjE,MAAa,0BACZ,YACoD;CACpD,MAAM,SAAS,WAAW,QAAQ;AAClC,QAAO,QAAQ,QACb,gBAAgB;EAChB,GAAG,QAAQ;EACX;EACA,CAAC,CACD,KACA,OAAO,SAAS,QAAQ,SAAS,EACjC,OAAO,SAAS,qCAAqC,EACpD,YAAY;GACV,SAAS,MAAM,OAAO;GACtB,SAAS,QAAQ,OAAO;GACxB,SAAS,SAAS,OAAO;GACzB,SAAS,gBAAgB,OAAO;GAChC,SAAS,gBAAgB,QAAQ,KAAK;EACvC,EACD,CAAC,CACF"}
1
+ {"version":3,"file":"managed-container.mjs","names":[],"sources":["../../../src/substrate/runtime/managed-container.ts"],"sourcesContent":["import { Effect, type Scope } from 'effect';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tContainerRuntimeError,\n\tEnsureContainerSpec,\n} from '../../contracts/container-runtime.ts';\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport { SpanAttr } from './observability/spans.ts';\n\n/** Sentinel `stack` value for containers / volumes / networks that are\n * shared across a single app's stacks but isolated PER APP — the\n * resource lives at app-scope, not stack-scope.\n *\n * Current producer: the per-app sui chain-build container\n * (`plugins/sui/chain-build-container.ts`) reuses one container\n * across multiple stacks of the same app to keep the bind-mounted\n * Move dep cache warm.\n *\n * Lifecycle-prune + the prune CLI compare against this sentinel to\n * decide whether a resource group is shared (pinned while any\n * sibling stack under the same app is live) vs per-stack (pruned\n * with its stack).\n *\n * The vocabulary lives here alongside the `{ app, stack, plugin,\n * role }` label tuple — managed-container.ts is the canonical\n * owner. */\nexport const PER_APP_SHARED_STACK = '_per-app_' as const;\n\nexport interface ManagedContainerIdentity {\n\treadonly app: string;\n\treadonly stack: string;\n}\n\nexport interface ManagedContainerLabelOptions {\n\treadonly identity: ManagedContainerIdentity;\n\treadonly plugin: string;\n\treadonly role: string;\n}\n\nexport const managedContainerLabels = (\n\toptions: ManagedContainerLabelOptions,\n): ContainerLabelTuple => ({\n\tapp: options.identity.app,\n\tstack: options.identity.stack,\n\tplugin: options.plugin,\n\trole: options.role,\n});\n\ntype ManagedContainerLabelInput =\n\t| { readonly labels: ContainerLabelTuple }\n\t| ManagedContainerLabelOptions;\n\nexport type EnsureManagedContainerOptions<E> = ManagedContainerLabelInput & {\n\treadonly runtime: ContainerRuntime;\n\treadonly spec: Omit<EnsureContainerSpec, 'labels'>;\n\treadonly mapError: (cause: ContainerRuntimeError) => E;\n};\n\nconst labelsFrom = (input: ManagedContainerLabelInput): ContainerLabelTuple =>\n\t'labels' in input ? input.labels : managedContainerLabels(input);\n\nexport const ensureManagedContainer = <E>(\n\toptions: EnsureManagedContainerOptions<E>,\n): Effect.Effect<ContainerHandle, E, Scope.Scope> => {\n\tconst labels = labelsFrom(options);\n\treturn options.runtime\n\t\t.ensureContainer({\n\t\t\t...options.spec,\n\t\t\tlabels,\n\t\t})\n\t\t.pipe(\n\t\t\tEffect.mapError(options.mapError),\n\t\t\tEffect.withSpan('substrate.managedContainer.ensure', {\n\t\t\t\tattributes: {\n\t\t\t\t\t[SpanAttr.app]: labels.app,\n\t\t\t\t\t[SpanAttr.stack]: labels.stack,\n\t\t\t\t\t[SpanAttr.plugin]: labels.plugin,\n\t\t\t\t\t[SpanAttr.containerRole]: labels.role,\n\t\t\t\t\t[SpanAttr.containerName]: options.spec.name,\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAa,uBAAuB;AAapC,MAAa,0BACZ,aAC0B;CAC1B,KAAK,QAAQ,SAAS;CACtB,OAAO,QAAQ,SAAS;CACxB,QAAQ,QAAQ;CAChB,MAAM,QAAQ;CACd;AAYD,MAAM,cAAc,UACnB,YAAY,QAAQ,MAAM,SAAS,uBAAuB,MAAM;AAEjE,MAAa,0BACZ,YACoD;CACpD,MAAM,SAAS,WAAW,QAAQ;AAClC,QAAO,QAAQ,QACb,gBAAgB;EAChB,GAAG,QAAQ;EACX;EACA,CAAC,CACD,KACA,OAAO,SAAS,QAAQ,SAAS,EACjC,OAAO,SAAS,qCAAqC,EACpD,YAAY;GACV,SAAS,MAAM,OAAO;GACtB,SAAS,QAAQ,OAAO;GACxB,SAAS,SAAS,OAAO;GACzB,SAAS,gBAAgB,OAAO;GAChC,SAAS,gBAAgB,QAAQ,KAAK;EACvC,EACD,CAAC,CACF"}
@@ -0,0 +1,3 @@
1
+ import "../../manifest.mjs";
2
+ import "./manifest.mjs";
3
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { atomicWriteFile } from "../atomic-write.mjs";
2
+ import "../runtime-decode.mjs";
2
3
  import "../../manifest.mjs";
3
4
  import { Data, Effect } from "effect";
4
5
  /** One error class for every manifest IO failure. */
@@ -16,6 +17,15 @@ const buildEnvelope = (input) => Effect.gen(function* () {
16
17
  const services = {};
17
18
  const endpoints = {};
18
19
  const extras = { ...input.extras };
20
+ const addEndpoint = (ep) => Effect.gen(function* () {
21
+ const ek = ep.endpointKey;
22
+ if (ek in endpoints) return yield* Effect.fail(new ManifestError({
23
+ reason: "duplicate-contribution",
24
+ path: "(in-memory envelope)",
25
+ detail: `endpointKey ${ek} contributed twice`
26
+ }));
27
+ endpoints[ek] = ep;
28
+ });
19
29
  for (const contribution of input.contributions) {
20
30
  const key = contribution.pluginKey;
21
31
  if (key in services) return yield* Effect.fail(new ManifestError({
@@ -32,22 +42,16 @@ const buildEnvelope = (input) => Effect.gen(function* () {
32
42
  }));
33
43
  extras[extraKey] = extraValue;
34
44
  }
35
- for (const ep of contribution.endpoints) {
36
- const ek = ep.endpointKey;
37
- if (ek in endpoints) return yield* Effect.fail(new ManifestError({
38
- reason: "duplicate-contribution",
39
- path: "(in-memory envelope)",
40
- detail: `endpointKey ${ek} contributed twice`
41
- }));
42
- endpoints[ek] = ep;
43
- }
45
+ for (const ep of contribution.endpoints) yield* addEndpoint(ep);
44
46
  }
47
+ for (const ep of input.endpoints ?? []) yield* addEndpoint(ep);
45
48
  return {
46
49
  identity: input.identity,
47
50
  manifestVersion: 1,
48
51
  services,
49
52
  endpoints,
50
- extras
53
+ extras,
54
+ ...input.codegen !== void 0 ? { codegen: input.codegen } : {}
51
55
  };
52
56
  });
53
57
  /**
@@ -68,6 +72,6 @@ const writeManifest = (envelope, path) => Effect.gen(function* () {
68
72
  }).pipe(Effect.withSpan("Manifest.writeManifest", { attributes: { "devstack.manifest.path": path } }));
69
73
  const serializeEnvelope = (envelope) => JSON.stringify(envelope, null, 2);
70
74
  //#endregion
71
- export { buildEnvelope, writeManifest };
75
+ export { ManifestError, buildEnvelope, writeManifest };
72
76
 
73
77
  //# sourceMappingURL=manifest.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.mjs","names":[],"sources":["../../../../src/substrate/runtime/manifest/manifest.ts"],"sourcesContent":["// Manifest emitter — endpoint-keyed envelope, atomic write.\n//\n// Architecture § Manifest data model. The envelope is L0 (`identity`\n// tuple, `manifestVersion`, `services` slot, `endpoints` lookup,\n// `extras`). The per-service projection lives in each plugin's\n// Codegenable contribution and is consumed by codegen output, not by\n// the manifest envelope itself.\n//\n// The emitter:\n// - Accepts per-plugin contributions through a `contribute` Effect.\n// - Walks endpoint contributions to build the flat `endpoints`\n// lookup keyed by `endpointKey`. Entries still carry the declared\n// endpoint `name` for build-integration lookup.\n// - Writes atomically via tempfile + fsync + rename. The atomic-\n// write primitive lives in L0 (per architecture § Collapsed:\n// \"Three tempfile+rename impls → one atomic-write primitive\").\n// - Validates the envelope against `ManifestEnvelopeSchema` on read.\n// - Pins `manifestVersion` so future-proofing migrations have a\n// compatibility seam. The pinned version is `1` for the post-\n// rewrite envelope. (The old devstack used unversioned manifests\n// plus a hash field; the rewrite's clean break is `version 1`.)\n//\n// Discipline: zero service names. The writer iterates `pluginKey`-\n// indexed contributions and copies the bytes through. The schema\n// validates the envelope shape, not the per-plugin contents (which\n// are `Schema.Unknown`).\n\nimport { Effect } from 'effect';\nimport { Data } from 'effect';\nimport { FileSystem } from 'effect';\n\nimport type { EndpointKey, PluginKey } from '../../brand.ts';\nimport {\n\ttype EndpointEntry,\n\ttype ManifestExtras,\n\ttype ManifestEnvelope,\n\tManifestEnvelopeSchema,\n} from '../../manifest.ts';\nimport { atomicWriteFile } from '../atomic-write.ts';\nimport { decodeJsonText } from '../runtime-decode.ts';\n\n// -----------------------------------------------------------------------------\n// Pinned schema version\n// -----------------------------------------------------------------------------\n\n/**\n * Schema version pinned at the envelope level. Bump only on a\n * breaking shape change to the envelope (NOT to a per-plugin service\n * slice — those carry their own version via Codegenable contribution).\n *\n * Reader policy:\n * - Equal version: accept.\n * - Older version: refuse (advise user to re-run `up`).\n * - Newer version: refuse (build integration is out of date).\n */\nexport const CURRENT_MANIFEST_VERSION = 1 as const;\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** One error class for every manifest IO failure. */\nexport class ManifestError extends Data.TaggedError('ManifestError')<{\n\treadonly reason:\n\t\t| 'write-failed'\n\t\t| 'read-failed'\n\t\t| 'decode-failed'\n\t\t| 'version-mismatch'\n\t\t| 'duplicate-contribution';\n\treadonly path: string;\n\treadonly detail?: string;\n\treadonly cause?: unknown;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Contribution shape\n// -----------------------------------------------------------------------------\n\n/**\n * One plugin's contribution to the manifest. Keyed by `pluginKey`\n * (branded), opaque `services` blob, plus a flat list of endpoint\n * entries the plugin owns.\n *\n * The writer copies `services` through to\n * `envelope.services[pluginKey]`. The renderer of the typed shape\n * lives in the plugin's Codegenable contribution — the manifest\n * doesn't decode it.\n */\nexport interface PluginManifestContribution {\n\treadonly pluginKey: PluginKey;\n\t/** Plugin's structured slice — opaque to the writer. */\n\treadonly services: unknown;\n\t/** Endpoints owned by this plugin. The writer indexes these by\n\t * `endpointKey` into the flat top-level lookup. */\n\treadonly endpoints: ReadonlyArray<EndpointEntry>;\n\t/** Optional app-facing extras merged into the top-level extras slot. */\n\treadonly extras?: ManifestExtras;\n}\n\n// -----------------------------------------------------------------------------\n// Public writer interface\n// -----------------------------------------------------------------------------\n\nexport interface WriteManifestInput {\n\treadonly identity: ManifestEnvelope['identity'];\n\treadonly contributions: ReadonlyArray<PluginManifestContribution>;\n\treadonly extras?: ManifestExtras;\n}\n\n/**\n * Build the envelope from per-plugin contributions. Pure; the writer\n * calls this and then atomically writes the JSON.\n *\n * `pluginKey` collisions are an error — two contributions for the\n * same plugin would silently overwrite. Endpoint-key collisions also\n * error: every endpoint has a unique `(pluginKey, dispatchId)` digest\n * by construction; a duplicate means a substrate bug.\n */\nexport const buildEnvelope = (\n\tinput: WriteManifestInput,\n): Effect.Effect<ManifestEnvelope, ManifestError> =>\n\tEffect.gen(function* () {\n\t\tconst services: Record<string, unknown> = {};\n\t\tconst endpoints: Record<string, EndpointEntry> = {};\n\t\tconst extras: Record<string, unknown> = { ...input.extras };\n\n\t\tfor (const contribution of input.contributions) {\n\t\t\tconst key = contribution.pluginKey as string;\n\t\t\tif (key in services) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\treason: 'duplicate-contribution',\n\t\t\t\t\t\tpath: '(in-memory envelope)',\n\t\t\t\t\t\tdetail: `pluginKey ${key} contributed twice`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tservices[key] = contribution.services;\n\t\t\tif (contribution.extras !== undefined) {\n\t\t\t\tfor (const [extraKey, extraValue] of Object.entries(contribution.extras)) {\n\t\t\t\t\tif (extraKey in extras) {\n\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\t\t\treason: 'duplicate-contribution',\n\t\t\t\t\t\t\t\tpath: '(in-memory envelope)',\n\t\t\t\t\t\t\t\tdetail: `extras key ${extraKey} contributed twice`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\textras[extraKey] = extraValue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const ep of contribution.endpoints) {\n\t\t\t\tconst ek = ep.endpointKey as string;\n\t\t\t\tif (ek in endpoints) {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\t\treason: 'duplicate-contribution',\n\t\t\t\t\t\t\tpath: '(in-memory envelope)',\n\t\t\t\t\t\t\tdetail: `endpointKey ${ek} contributed twice`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tendpoints[ek] = ep;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tidentity: input.identity,\n\t\t\tmanifestVersion: CURRENT_MANIFEST_VERSION,\n\t\t\tservices,\n\t\t\tendpoints,\n\t\t\textras,\n\t\t};\n\t});\n\n// -----------------------------------------------------------------------------\n// Atomic write — delegates to the canonical primitive.\n// -----------------------------------------------------------------------------\n\n/**\n * Serialize and write the envelope at `path` atomically. Routes\n * through the canonical `atomicWriteFile` primitive (mkdir-parent →\n * O_EXCL temp → write → fsync → rename), so the manifest writer\n * shares ONE owner of the tempfile dance with the state-store and\n * cache.\n */\nexport const writeManifest = (\n\tenvelope: ManifestEnvelope,\n\tpath: string,\n): Effect.Effect<void, ManifestError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst json = serializeEnvelope(envelope);\n\t\tconst bytes = new TextEncoder().encode(json);\n\t\tyield* atomicWriteFile(path, bytes).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\treason: 'write-failed',\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tdetail: `atomic write failed at stage ${cause.stage}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t}).pipe(\n\t\tEffect.withSpan('Manifest.writeManifest', { attributes: { 'devstack.manifest.path': path } }),\n\t);\n\nconst serializeEnvelope = (envelope: ManifestEnvelope): string =>\n\t// Stable key ordering, deterministic re-emit. `JSON.stringify` with\n\t// 2-space indent is reproducible byte-for-byte given the same\n\t// input object.\n\tJSON.stringify(envelope, null, 2);\n\n// -----------------------------------------------------------------------------\n// Read + decode\n// -----------------------------------------------------------------------------\n\n/**\n * Read and decode the manifest at `path`. Validates against\n * `ManifestEnvelopeSchema` and the pinned `CURRENT_MANIFEST_VERSION`.\n *\n * Used by:\n * - Codegen (architecture §6) — consumes plugin slices off\n * `envelope.services[pluginKey]`.\n * - Build integrations (Vitest, Playwright, generated app code) — consumes\n * `envelope.endpoints` lookup.\n *\n * The reader is read-only; no mutation, no IO beyond the single read.\n */\nexport const readManifest = (\n\tpath: string,\n): Effect.Effect<ManifestEnvelope, ManifestError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(Effect.mapError((cause) => new ManifestError({ reason: 'read-failed', path, cause })));\n\t\tconst decoded = yield* decodeJsonText(ManifestEnvelopeSchema, text, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew ManifestError({ reason: 'decode-failed', path, cause: issue.cause ?? issue }),\n\t\t});\n\t\tif (decoded.manifestVersion !== CURRENT_MANIFEST_VERSION) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew ManifestError({\n\t\t\t\t\treason: 'version-mismatch',\n\t\t\t\t\tpath,\n\t\t\t\t\tdetail: `expected ${CURRENT_MANIFEST_VERSION}, got ${decoded.manifestVersion}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn decoded as ManifestEnvelope;\n\t}).pipe(\n\t\tEffect.withSpan('Manifest.readManifest', { attributes: { 'devstack.manifest.path': path } }),\n\t);\n\n// -----------------------------------------------------------------------------\n// Re-export the envelope + endpoint types so downstream substrate\n// modules (codegen, build integrations) don't reach into substrate/\n// directly.\n// -----------------------------------------------------------------------------\n\nexport type { EndpointEntry, EndpointKey, ManifestEnvelope, PluginKey };\nexport { ManifestEnvelopeSchema };\n"],"mappings":";;;;AA8DA,IAAa,gBAAb,cAAmC,KAAK,YAAY,gBAAgB,CAUjE;;;;;;;;;;AA8CH,MAAa,iBACZ,UAEA,OAAO,IAAI,aAAa;CACvB,MAAM,WAAoC,EAAE;CAC5C,MAAM,YAA2C,EAAE;CACnD,MAAM,SAAkC,EAAE,GAAG,MAAM,QAAQ;AAE3D,MAAK,MAAM,gBAAgB,MAAM,eAAe;EAC/C,MAAM,MAAM,aAAa;AACzB,MAAI,OAAO,SACV,QAAO,OAAO,OAAO,KACpB,IAAI,cAAc;GACjB,QAAQ;GACR,MAAM;GACN,QAAQ,aAAa,IAAI;GACzB,CAAC,CACF;AAEF,WAAS,OAAO,aAAa;AAC7B,MAAI,aAAa,WAAW,KAAA,EAC3B,MAAK,MAAM,CAAC,UAAU,eAAe,OAAO,QAAQ,aAAa,OAAO,EAAE;AACzE,OAAI,YAAY,OACf,QAAO,OAAO,OAAO,KACpB,IAAI,cAAc;IACjB,QAAQ;IACR,MAAM;IACN,QAAQ,cAAc,SAAS;IAC/B,CAAC,CACF;AAEF,UAAO,YAAY;;AAGrB,OAAK,MAAM,MAAM,aAAa,WAAW;GACxC,MAAM,KAAK,GAAG;AACd,OAAI,MAAM,UACT,QAAO,OAAO,OAAO,KACpB,IAAI,cAAc;IACjB,QAAQ;IACR,MAAM;IACN,QAAQ,eAAe,GAAG;IAC1B,CAAC,CACF;AAEF,aAAU,MAAM;;;AAIlB,QAAO;EACN,UAAU,MAAM;EAChB,iBAAA;EACA;EACA;EACA;EACA;EACA;;;;;;;;AAaH,MAAa,iBACZ,UACA,SAEA,OAAO,IAAI,aAAa;CACvB,MAAM,OAAO,kBAAkB,SAAS;AAExC,QAAO,gBAAgB,MADT,IAAI,aAAa,CAAC,OAAO,KACL,CAAC,CAAC,KACnC,OAAO,UACL,UACA,IAAI,cAAc;EACjB,QAAQ;EACR;EACA,QAAQ,gCAAgC,MAAM;EAC9C;EACA,CAAC,CACH,CACD;EACA,CAAC,KACF,OAAO,SAAS,0BAA0B,EAAE,YAAY,EAAE,0BAA0B,MAAM,EAAE,CAAC,CAC7F;AAEF,MAAM,qBAAqB,aAI1B,KAAK,UAAU,UAAU,MAAM,EAAE"}
1
+ {"version":3,"file":"manifest.mjs","names":[],"sources":["../../../../src/substrate/runtime/manifest/manifest.ts"],"sourcesContent":["// Manifest emitter — endpoint-keyed envelope, atomic write.\n//\n// Architecture § Manifest data model. The envelope is L0 (`identity`\n// tuple, `manifestVersion`, `services` slot, `endpoints` lookup,\n// `extras`). The per-service projection lives in each plugin's\n// Codegenable contribution and is consumed by codegen output, not by\n// the manifest envelope itself.\n//\n// The emitter:\n// - Accepts per-plugin contributions through a `contribute` Effect.\n// - Walks endpoint contributions to build the flat `endpoints`\n// lookup keyed by `endpointKey`. Entries still carry the declared\n// endpoint `name` for build-integration lookup.\n// - Writes atomically via tempfile + fsync + rename. The atomic-\n// write primitive lives in L0 (per architecture § Collapsed:\n// \"Three tempfile+rename impls → one atomic-write primitive\").\n// - Validates the envelope against `ManifestEnvelopeSchema` on read.\n// - Pins `manifestVersion` so future-proofing migrations have a\n// compatibility seam. The pinned version is `1` for the post-\n// rewrite envelope. (The old devstack used unversioned manifests\n// plus a hash field; the rewrite's clean break is `version 1`.)\n//\n// Discipline: zero service names. The writer iterates `pluginKey`-\n// indexed contributions and copies the bytes through. The schema\n// validates the envelope shape, not the per-plugin contents (which\n// are `Schema.Unknown`).\n\nimport { Effect } from 'effect';\nimport { Data } from 'effect';\nimport { FileSystem } from 'effect';\n\nimport type { EndpointKey, PluginKey } from '../../brand.ts';\nimport {\n\ttype EndpointEntry,\n\ttype ManifestCodegen,\n\ttype ManifestExtras,\n\ttype ManifestEnvelope,\n\tManifestEnvelopeSchema,\n} from '../../manifest.ts';\nimport { atomicWriteFile } from '../atomic-write.ts';\nimport { decodeJsonText } from '../runtime-decode.ts';\n\n// -----------------------------------------------------------------------------\n// Pinned schema version\n// -----------------------------------------------------------------------------\n\n/**\n * Schema version pinned at the envelope level. Bump only on a\n * breaking shape change to the envelope (NOT to a per-plugin service\n * slice — those carry their own version via Codegenable contribution).\n *\n * Reader policy:\n * - Equal version: accept.\n * - Older version: refuse (advise user to re-run `up`).\n * - Newer version: refuse (build integration is out of date).\n */\nexport const CURRENT_MANIFEST_VERSION = 1 as const;\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** One error class for every manifest IO failure. */\nexport class ManifestError extends Data.TaggedError('ManifestError')<{\n\treadonly reason:\n\t\t| 'write-failed'\n\t\t| 'read-failed'\n\t\t| 'decode-failed'\n\t\t| 'version-mismatch'\n\t\t| 'duplicate-contribution';\n\treadonly path: string;\n\treadonly detail?: string;\n\treadonly cause?: unknown;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Contribution shape\n// -----------------------------------------------------------------------------\n\n/**\n * One plugin's contribution to the manifest. Keyed by `pluginKey`\n * (branded), opaque `services` blob, plus a flat list of endpoint\n * entries the plugin owns.\n *\n * The writer copies `services` through to\n * `envelope.services[pluginKey]`. The renderer of the typed shape\n * lives in the plugin's Codegenable contribution — the manifest\n * doesn't decode it.\n */\nexport interface PluginManifestContribution {\n\treadonly pluginKey: PluginKey;\n\t/** Plugin's structured slice — opaque to the writer. */\n\treadonly services: unknown;\n\t/** Endpoints owned by this plugin. The writer indexes these by\n\t * `endpointKey` into the flat top-level lookup. */\n\treadonly endpoints: ReadonlyArray<EndpointEntry>;\n\t/** Optional app-facing extras merged into the top-level extras slot. */\n\treadonly extras?: ManifestExtras;\n}\n\n// -----------------------------------------------------------------------------\n// Public writer interface\n// -----------------------------------------------------------------------------\n\nexport interface WriteManifestInput {\n\treadonly identity: ManifestEnvelope['identity'];\n\treadonly contributions: ReadonlyArray<PluginManifestContribution>;\n\treadonly endpoints?: ReadonlyArray<EndpointEntry>;\n\treadonly extras?: ManifestExtras;\n\t/** Per-stack codegen metadata (the resolved absolute `generatedDir`).\n\t * Optional + additive — omitting it produces an envelope without the\n\t * `codegen` key, identical to a pre-field manifest. */\n\treadonly codegen?: ManifestCodegen;\n}\n\n/**\n * Build the envelope from per-plugin contributions. Pure; the writer\n * calls this and then atomically writes the JSON.\n *\n * `pluginKey` collisions are an error — two contributions for the\n * same plugin would silently overwrite. Endpoint-key collisions also\n * error: every endpoint has a unique `(pluginKey, dispatchId)` digest\n * by construction; a duplicate means a substrate bug.\n */\nexport const buildEnvelope = (\n\tinput: WriteManifestInput,\n): Effect.Effect<ManifestEnvelope, ManifestError> =>\n\tEffect.gen(function* () {\n\t\tconst services: Record<string, unknown> = {};\n\t\tconst endpoints: Record<string, EndpointEntry> = {};\n\t\tconst extras: Record<string, unknown> = { ...input.extras };\n\n\t\tconst addEndpoint = (ep: EndpointEntry): Effect.Effect<void, ManifestError> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ek = ep.endpointKey as string;\n\t\t\t\tif (ek in endpoints) {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\t\treason: 'duplicate-contribution',\n\t\t\t\t\t\t\tpath: '(in-memory envelope)',\n\t\t\t\t\t\t\tdetail: `endpointKey ${ek} contributed twice`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tendpoints[ek] = ep;\n\t\t\t});\n\n\t\tfor (const contribution of input.contributions) {\n\t\t\tconst key = contribution.pluginKey as string;\n\t\t\tif (key in services) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\treason: 'duplicate-contribution',\n\t\t\t\t\t\tpath: '(in-memory envelope)',\n\t\t\t\t\t\tdetail: `pluginKey ${key} contributed twice`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tservices[key] = contribution.services;\n\t\t\tif (contribution.extras !== undefined) {\n\t\t\t\tfor (const [extraKey, extraValue] of Object.entries(contribution.extras)) {\n\t\t\t\t\tif (extraKey in extras) {\n\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\t\t\treason: 'duplicate-contribution',\n\t\t\t\t\t\t\t\tpath: '(in-memory envelope)',\n\t\t\t\t\t\t\t\tdetail: `extras key ${extraKey} contributed twice`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\textras[extraKey] = extraValue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const ep of contribution.endpoints) {\n\t\t\t\tyield* addEndpoint(ep);\n\t\t\t}\n\t\t}\n\t\tfor (const ep of input.endpoints ?? []) {\n\t\t\tyield* addEndpoint(ep);\n\t\t}\n\n\t\treturn {\n\t\t\tidentity: input.identity,\n\t\t\tmanifestVersion: CURRENT_MANIFEST_VERSION,\n\t\t\tservices,\n\t\t\tendpoints,\n\t\t\textras,\n\t\t\t// Spread only when present so an omitted `codegen` yields the\n\t\t\t// exact same envelope (and serialized bytes) as a pre-field\n\t\t\t// manifest — additive, no churn for stacks that don't record it.\n\t\t\t...(input.codegen !== undefined ? { codegen: input.codegen } : {}),\n\t\t};\n\t});\n\n// -----------------------------------------------------------------------------\n// Atomic write — delegates to the canonical primitive.\n// -----------------------------------------------------------------------------\n\n/**\n * Serialize and write the envelope at `path` atomically. Routes\n * through the canonical `atomicWriteFile` primitive (mkdir-parent →\n * O_EXCL temp → write → fsync → rename), so the manifest writer\n * shares ONE owner of the tempfile dance with the state-store and\n * cache.\n */\nexport const writeManifest = (\n\tenvelope: ManifestEnvelope,\n\tpath: string,\n): Effect.Effect<void, ManifestError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst json = serializeEnvelope(envelope);\n\t\tconst bytes = new TextEncoder().encode(json);\n\t\tyield* atomicWriteFile(path, bytes).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew ManifestError({\n\t\t\t\t\t\treason: 'write-failed',\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tdetail: `atomic write failed at stage ${cause.stage}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t}).pipe(\n\t\tEffect.withSpan('Manifest.writeManifest', { attributes: { 'devstack.manifest.path': path } }),\n\t);\n\nconst serializeEnvelope = (envelope: ManifestEnvelope): string =>\n\t// Stable key ordering, deterministic re-emit. `JSON.stringify` with\n\t// 2-space indent is reproducible byte-for-byte given the same\n\t// input object.\n\tJSON.stringify(envelope, null, 2);\n\n// -----------------------------------------------------------------------------\n// Read + decode\n// -----------------------------------------------------------------------------\n\n/**\n * Read and decode the manifest at `path`. Validates against\n * `ManifestEnvelopeSchema` and the pinned `CURRENT_MANIFEST_VERSION`.\n *\n * Used by:\n * - Codegen (architecture §6) — consumes plugin slices off\n * `envelope.services[pluginKey]`.\n * - Build integrations (Vitest, Playwright, generated app code) — consumes\n * `envelope.endpoints` lookup.\n *\n * The reader is read-only; no mutation, no IO beyond the single read.\n */\nexport const readManifest = (\n\tpath: string,\n): Effect.Effect<ManifestEnvelope, ManifestError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(Effect.mapError((cause) => new ManifestError({ reason: 'read-failed', path, cause })));\n\t\tconst decoded = yield* decodeJsonText(ManifestEnvelopeSchema, text, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew ManifestError({ reason: 'decode-failed', path, cause: issue.cause ?? issue }),\n\t\t});\n\t\tif (decoded.manifestVersion !== CURRENT_MANIFEST_VERSION) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew ManifestError({\n\t\t\t\t\treason: 'version-mismatch',\n\t\t\t\t\tpath,\n\t\t\t\t\tdetail: `expected ${CURRENT_MANIFEST_VERSION}, got ${decoded.manifestVersion}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn decoded as ManifestEnvelope;\n\t}).pipe(\n\t\tEffect.withSpan('Manifest.readManifest', { attributes: { 'devstack.manifest.path': path } }),\n\t);\n\n// -----------------------------------------------------------------------------\n// Re-export the envelope + endpoint types so downstream substrate\n// modules (codegen, build integrations) don't reach into substrate/\n// directly.\n// -----------------------------------------------------------------------------\n\nexport type { EndpointEntry, EndpointKey, ManifestCodegen, ManifestEnvelope, PluginKey };\nexport { ManifestEnvelopeSchema };\n"],"mappings":";;;;;AA+DA,IAAa,gBAAb,cAAmC,KAAK,YAAY,gBAAgB,CAUjE;;;;;;;;;;AAmDH,MAAa,iBACZ,UAEA,OAAO,IAAI,aAAa;CACvB,MAAM,WAAoC,EAAE;CAC5C,MAAM,YAA2C,EAAE;CACnD,MAAM,SAAkC,EAAE,GAAG,MAAM,QAAQ;CAE3D,MAAM,eAAe,OACpB,OAAO,IAAI,aAAa;EACvB,MAAM,KAAK,GAAG;AACd,MAAI,MAAM,UACT,QAAO,OAAO,OAAO,KACpB,IAAI,cAAc;GACjB,QAAQ;GACR,MAAM;GACN,QAAQ,eAAe,GAAG;GAC1B,CAAC,CACF;AAEF,YAAU,MAAM;GACf;AAEH,MAAK,MAAM,gBAAgB,MAAM,eAAe;EAC/C,MAAM,MAAM,aAAa;AACzB,MAAI,OAAO,SACV,QAAO,OAAO,OAAO,KACpB,IAAI,cAAc;GACjB,QAAQ;GACR,MAAM;GACN,QAAQ,aAAa,IAAI;GACzB,CAAC,CACF;AAEF,WAAS,OAAO,aAAa;AAC7B,MAAI,aAAa,WAAW,KAAA,EAC3B,MAAK,MAAM,CAAC,UAAU,eAAe,OAAO,QAAQ,aAAa,OAAO,EAAE;AACzE,OAAI,YAAY,OACf,QAAO,OAAO,OAAO,KACpB,IAAI,cAAc;IACjB,QAAQ;IACR,MAAM;IACN,QAAQ,cAAc,SAAS;IAC/B,CAAC,CACF;AAEF,UAAO,YAAY;;AAGrB,OAAK,MAAM,MAAM,aAAa,UAC7B,QAAO,YAAY,GAAG;;AAGxB,MAAK,MAAM,MAAM,MAAM,aAAa,EAAE,CACrC,QAAO,YAAY,GAAG;AAGvB,QAAO;EACN,UAAU,MAAM;EAChB,iBAAA;EACA;EACA;EACA;EAIA,GAAI,MAAM,YAAY,KAAA,IAAY,EAAE,SAAS,MAAM,SAAS,GAAG,EAAE;EACjE;EACA;;;;;;;;AAaH,MAAa,iBACZ,UACA,SAEA,OAAO,IAAI,aAAa;CACvB,MAAM,OAAO,kBAAkB,SAAS;AAExC,QAAO,gBAAgB,MADT,IAAI,aAAa,CAAC,OAAO,KACL,CAAC,CAAC,KACnC,OAAO,UACL,UACA,IAAI,cAAc;EACjB,QAAQ;EACR;EACA,QAAQ,gCAAgC,MAAM;EAC9C;EACA,CAAC,CACH,CACD;EACA,CAAC,KACF,OAAO,SAAS,0BAA0B,EAAE,YAAY,EAAE,0BAA0B,MAAM,EAAE,CAAC,CAC7F;AAEF,MAAM,qBAAqB,aAI1B,KAAK,UAAU,UAAU,MAAM,EAAE"}
@@ -0,0 +1,20 @@
1
+ import { Schema } from "effect";
2
+ Schema.TaggedErrorClass()("ForkIncompatibleError", {
3
+ /** Refusing factory variant — e.g. `'walrusLocalCluster'`,
4
+ * `'sealLocalKeygen'`. Lets multiple plugin factories share
5
+ * this shape without losing the call-site distinction. */
6
+ variant: Schema.String,
7
+ /** Resolved network the composition refused under. */
8
+ network: Schema.String,
9
+ /** Imperative one-liner suitable for stderr. */
10
+ message: Schema.String,
11
+ /** Actionable next step (the known-deployment alternative). */
12
+ hint: Schema.optional(Schema.String),
13
+ /** Optional original cause when the refusal wraps an underlying
14
+ * fault (rare — typical use is a pure factory-time refusal). */
15
+ cause: Schema.optional(Schema.Defect)
16
+ });
17
+ //#endregion
18
+ export {};
19
+
20
+ //# sourceMappingURL=mode-errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode-errors.mjs","names":[],"sources":["../../../src/substrate/runtime/mode-errors.ts"],"sourcesContent":["// Cross-cutting mode-refusal errors.\n//\n// Reviews finding (cross-cutting.md §\"Error model\"): the\n// `ForkIncompatibleError` tag is defined twice today — once in\n// `plugins/walrus/errors.ts`, once in `plugins/seal/errors.ts` — with\n// conflicting field shapes. Two `_tag` literals with the same name\n// but different shapes violate STYLE_GUIDE §2 (\"One `_tag` literal\n// per logical error type across the whole package\").\n//\n// Lift the canonical shape here. Both plugins import from substrate\n// in PR3; this PR does NOT modify the plugin-side error files (per\n// PR1 scope).\n//\n// Shape decision:\n// - `variant` carries the refusing factory name (e.g.\n// `'walrusLocalCluster'`, `'sealLocalKeygen'`). Lets walrus and\n// seal share the shape without losing the call-site distinction.\n// - `network` carries the resolved `*-fork` network string the\n// user passed.\n// - `message` is the imperative one-liner suitable for stderr.\n// - `hint` is the actionable next step (the known-deployment\n// alternative).\n//\n// Substrate is name-blind on the plugin level — these fields are\n// generic (\"which factory variant refused\" + \"which network it\n// refused under\") and do NOT name walrus / seal.\n\nimport { Schema } from 'effect';\n\n/**\n * Synchronous factory-time refusal raised by a plugin factory\n * variant when composed against a network the variant cannot serve\n * (canonically: a `*-fork` chain that doesn't expose the fullnode\n * surface the variant requires).\n *\n * Architecture (Tension 11): primary refusal is TYPE-LEVEL via\n * mode-narrowed factory namespaces — `walrusFor(forkNet).<mode>` only\n * exposes `.known`. This runtime shape is defense-in-depth for\n * callers that bypass the type-level narrowing (env-driven factories,\n * plugin composition through resolved values).\n *\n * Used by walrus (`local-cluster` variant) and seal (`local-keygen`\n * variant) today; future plugin factories refusing on a network\n * predicate share this single shape.\n */\nexport class ForkIncompatibleError extends Schema.TaggedErrorClass<ForkIncompatibleError>()(\n\t'ForkIncompatibleError',\n\t{\n\t\t/** Refusing factory variant — e.g. `'walrusLocalCluster'`,\n\t\t * `'sealLocalKeygen'`. Lets multiple plugin factories share\n\t\t * this shape without losing the call-site distinction. */\n\t\tvariant: Schema.String,\n\t\t/** Resolved network the composition refused under. */\n\t\tnetwork: Schema.String,\n\t\t/** Imperative one-liner suitable for stderr. */\n\t\tmessage: Schema.String,\n\t\t/** Actionable next step (the known-deployment alternative). */\n\t\thint: Schema.optional(Schema.String),\n\t\t/** Optional original cause when the refusal wraps an underlying\n\t\t * fault (rare — typical use is a pure factory-time refusal). */\n\t\tcause: Schema.optional(Schema.Defect),\n\t},\n) {}\n"],"mappings":";AA6C2C,OAAO,kBAAyC,CAC1F,yBACA;;;;CAIC,SAAS,OAAO;;CAEhB,SAAS,OAAO;;CAEhB,SAAS,OAAO;;CAEhB,MAAM,OAAO,SAAS,OAAO,OAAO;;;CAGpC,OAAO,OAAO,SAAS,OAAO,OAAO;CACrC,CACD"}
@@ -1,4 +1,5 @@
1
1
  import { redactText, redactValue } from "./redaction.mjs";
2
+ import { Cause } from "effect";
2
3
  //#region src/substrate/runtime/observability/cascade-formatter.ts
3
4
  /** Empty registry — the formatter falls back to the default
4
5
  * rendering for every value. */
@@ -6,7 +7,6 @@ const emptyFormatterRegistry = /* @__PURE__ */ new Map();
6
7
  const DEFAULT_FIELD_TRUNCATE = 8192;
7
8
  const DEFAULT_MAX_DEPTH = 12;
8
9
  const isTaggedError = (value) => typeof value === "object" && value !== null && typeof value._tag === "string";
9
- const isCauseLike = (value) => typeof value === "object" && value !== null && Array.isArray(value.reasons);
10
10
  /**
11
11
  * Format an Effect `Cause<E>` as a multi-line cascade string. Pure.
12
12
  *
@@ -24,9 +24,8 @@ const formatCause = (cause, options) => {
24
24
  redactions: options?.redactions ?? []
25
25
  };
26
26
  const visited = /* @__PURE__ */ new WeakSet();
27
- const reasons = cause.reasons;
28
- if (reasons.length === 0) return "(empty cause)";
29
- return reasons.map((reason) => formatReason(reason, opts, visited, 0)).join("\n--- (also)\n");
27
+ if (cause.reasons.length === 0) return "(empty cause)";
28
+ return cause.reasons.map((reason) => formatReason(reason, opts, visited, 0)).join("\n--- (also)\n");
30
29
  };
31
30
  /**
32
31
  * Format an arbitrary value (a `Cause`, a tagged error, a plain
@@ -50,11 +49,9 @@ const truncate = (s, limit, redactions) => {
50
49
  };
51
50
  const indent = (s, prefix) => s.split("\n").map((line) => `${prefix}${line}`).join("\n");
52
51
  const formatReason = (reason, opts, visited, depth) => {
53
- switch (reason._tag) {
54
- case "Fail": return formatAny(reason.error, opts, visited, depth);
55
- case "Die": return `DEFECT:\n${indent(formatAny(reason.defect, opts, visited, depth), " ")}`;
56
- case "Interrupt": return `INTERRUPT[${reason.fiberId ?? "unknown"}]`;
57
- }
52
+ if (Cause.isFailReason(reason)) return formatAny(reason.error, opts, visited, depth);
53
+ if (Cause.isDieReason(reason)) return `DEFECT:\n${indent(formatAny(reason.defect, opts, visited, depth), " ")}`;
54
+ return `INTERRUPT[${reason.fiberId ?? "unknown"}]`;
58
55
  };
59
56
  const formatAny = (value, opts, visited, depth) => {
60
57
  if (value === void 0 || value === null) return "";
@@ -63,10 +60,9 @@ const formatAny = (value, opts, visited, depth) => {
63
60
  if (visited.has(value)) return "…[cycle]";
64
61
  visited.add(value);
65
62
  }
66
- if (isCauseLike(value)) {
67
- const rs = value.reasons;
68
- if (rs.length === 0) return "(empty cause)";
69
- return rs.map((r) => formatReason(r, opts, visited, depth)).join("\n--- (also)\n");
63
+ if (Cause.isCause(value)) {
64
+ if (value.reasons.length === 0) return "(empty cause)";
65
+ return value.reasons.map((r) => formatReason(r, opts, visited, depth)).join("\n--- (also)\n");
70
66
  }
71
67
  if (isTaggedError(value)) return formatTagged(value, opts, visited, depth);
72
68
  if (value instanceof Error) {
@@ -1 +1 @@
1
- {"version":3,"file":"cascade-formatter.mjs","names":[],"sources":["../../../../src/substrate/runtime/observability/cascade-formatter.ts"],"sourcesContent":["// L0 cascade formatter.\n//\n// Architecture § Substrate violations § \"C2 — relocate cause walker\n// from the renderer\". The cascade formatter walks an Effect `Cause`\n// and returns a stringified cascade of taxonomy-aware lines. Called\n// from CLI, TUI, prune — anywhere a failure surfaces.\n//\n// Hard rules:\n// - PURE. No IO, no Effect, no clocks. Input → string.\n// - No service names: the formatter inspects `_tag` strings and\n// structured fields verbatim, never branches on a specific\n// concrete plugin error class.\n// - Pluggable per-error-class formatters via a `formatters` map\n// keyed by `_tag`. The default formatter handles tagged errors,\n// plain `Error`, defects, and Interrupts.\n//\n// Output shape:\n//\n// <Tag> (<phase?>): <message>\n// exitCode: <n>\n// stderr: <text…[truncated]>\n// <field>: <value>\n// caused by:\n// <recursive render, indented by 2 spaces>\n//\n// Multi-`Fail` causes (parallel failures) render with a `--- (also)`\n// separator. Defects (`Die`) render with `DEFECT (<tag>?)` prefix so\n// the operator can tell programmer errors from typed failures at a\n// glance. Interrupts render as `INTERRUPT[<fiberId>]`.\n\nimport type { Cause } from 'effect';\n\nimport { redactText, redactValue, type RedactionRule } from './redaction.ts';\n\n// `Cause` is a namespace in effect v4; the actual cause type is\n// `Cause.Cause<E>`. We re-alias here so call sites read naturally.\ntype CauseT<E> = Cause.Cause<E>;\n\n// -----------------------------------------------------------------------------\n// Plug-in formatter API\n// -----------------------------------------------------------------------------\n\n/**\n * Per-tag formatter override. Receives the tagged-error-like value\n * and the default formatter (so a plugin formatter can recurse on a\n * nested `cause` field without re-implementing the walk).\n *\n * Return `null` to fall back to the default rendering.\n *\n * Architecture: the formatter registry is keyed by `_tag` string —\n * the substrate never imports a concrete plugin error class. Plugins\n * register their custom renderer via the supervisor harvest loop over\n * `errorContributions` (see `substrate/plugin.ts:PluginErrorContribution`).\n */\nexport type TagFormatter = (\n\tvalue: TaggedErrorLike,\n\trecurse: (inner: unknown) => string,\n) => string | null;\n\n/** Per-tag formatter map. */\nexport type FormatterRegistry = ReadonlyMap<string, TagFormatter>;\n\n/** Empty registry — the formatter falls back to the default\n * rendering for every value. */\nexport const emptyFormatterRegistry: FormatterRegistry = new Map();\n\n// -----------------------------------------------------------------------------\n// Render budget\n// -----------------------------------------------------------------------------\n\nconst DEFAULT_FIELD_TRUNCATE = 8192;\nconst DEFAULT_MAX_DEPTH = 12;\n\nexport interface FormatOptions {\n\t/** Per-tag override registry. Defaults to the empty registry. */\n\treadonly formatters?: FormatterRegistry;\n\t/** Truncate individual fields (stderr/stdout/detail) past this\n\t * length. Default 8 KiB. */\n\treadonly fieldTruncate?: number;\n\t/** Hard recursion cap. Cyclic graphs are detected separately by\n\t * visit-set; this guards against pathological cause chains.\n\t * Default 12. */\n\treadonly maxDepth?: number;\n\t/** Optional redaction rules applied before rendering string fields. */\n\treadonly redactions?: ReadonlyArray<RedactionRule>;\n}\n\n// -----------------------------------------------------------------------------\n// Type guards (structural — no imports of concrete classes)\n// -----------------------------------------------------------------------------\n\n/** Shape of a `Schema.TaggedError` / `Data.TaggedError` instance.\n * The cascade formatter never imports a concrete class — it dispatches\n * on `_tag`. */\nexport interface TaggedErrorLike {\n\treadonly _tag: string;\n\treadonly message?: unknown;\n\treadonly cause?: unknown;\n\treadonly phase?: unknown;\n\treadonly stderr?: unknown;\n\treadonly stdout?: unknown;\n\treadonly exitCode?: unknown;\n\treadonly [key: string]: unknown;\n\treadonly detail?: unknown;\n\treadonly op?: unknown;\n}\n\nexport const isTaggedError = (value: unknown): value is TaggedErrorLike =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\ttypeof (value as { _tag?: unknown })._tag === 'string';\n\ninterface CauseLike {\n\treadonly reasons: ReadonlyArray<ReasonLike>;\n}\n\ninterface FailReasonLike {\n\treadonly _tag: 'Fail';\n\treadonly error: unknown;\n}\ninterface DieReasonLike {\n\treadonly _tag: 'Die';\n\treadonly defect: unknown;\n}\ninterface InterruptReasonLike {\n\treadonly _tag: 'Interrupt';\n\treadonly fiberId: number | undefined;\n}\ntype ReasonLike = FailReasonLike | DieReasonLike | InterruptReasonLike;\n\nconst isCauseLike = (value: unknown): value is CauseLike =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\tArray.isArray((value as { reasons?: unknown }).reasons);\n\n// -----------------------------------------------------------------------------\n// Public entry points\n// -----------------------------------------------------------------------------\n\n/**\n * Format an Effect `Cause<E>` as a multi-line cascade string. Pure.\n *\n * Multiple `Fail` reasons render as separate blocks joined by\n * `--- (also)` so parallel failures are visible. Defects render with\n * a `DEFECT` prefix. Interrupts render with `INTERRUPT[<fiberId>]`.\n *\n * Cyclic `cause` chains are broken with `…[cycle]`.\n */\nexport const formatCause = <E>(cause: CauseT<E>, options?: FormatOptions): string => {\n\tconst opts: Required<FormatOptions> = {\n\t\tformatters: options?.formatters ?? emptyFormatterRegistry,\n\t\tfieldTruncate: options?.fieldTruncate ?? DEFAULT_FIELD_TRUNCATE,\n\t\tmaxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n\t\tredactions: options?.redactions ?? [],\n\t};\n\tconst visited = new WeakSet<object>();\n\tconst reasons = (cause as unknown as CauseLike).reasons;\n\tif (reasons.length === 0) return '(empty cause)';\n\tconst rendered = reasons.map((reason) => formatReason(reason, opts, visited, 0));\n\treturn rendered.join('\\n--- (also)\\n');\n};\n\n/**\n * Format an arbitrary value (a `Cause`, a tagged error, a plain\n * `Error`, or anything else) using the cascade rules. Pure.\n *\n * The pretty-error renderer (`pretty-error.ts`) is a thin wrapper\n * over this — it just sets the IO conventions (where to write,\n * what to truncate per-context). The formatting logic lives here.\n */\nexport const formatValue = (value: unknown, options?: FormatOptions): string => {\n\tconst opts: Required<FormatOptions> = {\n\t\tformatters: options?.formatters ?? emptyFormatterRegistry,\n\t\tfieldTruncate: options?.fieldTruncate ?? DEFAULT_FIELD_TRUNCATE,\n\t\tmaxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n\t\tredactions: options?.redactions ?? [],\n\t};\n\treturn formatAny(value, opts, new WeakSet(), 0);\n};\n\n// -----------------------------------------------------------------------------\n// Internals\n// -----------------------------------------------------------------------------\n\nconst truncate = (s: string, limit: number, redactions: ReadonlyArray<RedactionRule>): string => {\n\tconst redacted = redactText(s, redactions);\n\treturn redacted.length > limit ? `${redacted.slice(0, limit)}…[truncated]` : redacted;\n};\n\nconst indent = (s: string, prefix: string): string =>\n\ts\n\t\t.split('\\n')\n\t\t.map((line) => `${prefix}${line}`)\n\t\t.join('\\n');\n\nconst formatReason = (\n\treason: ReasonLike,\n\topts: Required<FormatOptions>,\n\tvisited: WeakSet<object>,\n\tdepth: number,\n): string => {\n\tswitch (reason._tag) {\n\t\tcase 'Fail':\n\t\t\treturn formatAny(reason.error, opts, visited, depth);\n\t\tcase 'Die': {\n\t\t\tconst inner = formatAny(reason.defect, opts, visited, depth);\n\t\t\treturn `DEFECT:\\n${indent(inner, ' ')}`;\n\t\t}\n\t\tcase 'Interrupt':\n\t\t\treturn `INTERRUPT[${reason.fiberId ?? 'unknown'}]`;\n\t}\n};\n\nconst formatAny = (\n\tvalue: unknown,\n\topts: Required<FormatOptions>,\n\tvisited: WeakSet<object>,\n\tdepth: number,\n): string => {\n\tif (value === undefined || value === null) return '';\n\tif (depth > opts.maxDepth) return '…[max depth]';\n\tif (typeof value === 'object') {\n\t\tif (visited.has(value as object)) return '…[cycle]';\n\t\tvisited.add(value as object);\n\t}\n\tif (isCauseLike(value)) {\n\t\tconst rs = value.reasons;\n\t\tif (rs.length === 0) return '(empty cause)';\n\t\treturn rs.map((r) => formatReason(r, opts, visited, depth)).join('\\n--- (also)\\n');\n\t}\n\tif (isTaggedError(value)) {\n\t\treturn formatTagged(value, opts, visited, depth);\n\t}\n\tif (value instanceof Error) {\n\t\tconst header = `${value.name}: ${value.message}`;\n\t\tif (value.stack && value.stack !== header) return value.stack;\n\t\treturn header;\n\t}\n\tif (typeof value === 'string') return redactText(value, opts.redactions);\n\ttry {\n\t\treturn JSON.stringify(redactValue(value, opts.redactions));\n\t} catch {\n\t\treturn String(value);\n\t}\n};\n\nconst formatTagged = (\n\tvalue: TaggedErrorLike,\n\topts: Required<FormatOptions>,\n\tvisited: WeakSet<object>,\n\tdepth: number,\n): string => {\n\tconst override = opts.formatters.get(value._tag);\n\tif (override) {\n\t\tconst result = override(value, (inner) => formatAny(inner, opts, visited, depth + 1));\n\t\tif (result !== null) return result;\n\t}\n\n\tconst qualifier =\n\t\ttypeof value.phase === 'string'\n\t\t\t? `(${value.phase})`\n\t\t\t: typeof value.op === 'string'\n\t\t\t\t? `(${value.op})`\n\t\t\t\t: '';\n\tconst message =\n\t\ttypeof value.message === 'string' ? redactText(value.message, opts.redactions) : '';\n\tconst header = qualifier ? `${value._tag} ${qualifier}: ${message}` : `${value._tag}: ${message}`;\n\n\tconst lines: Array<string> = [header];\n\tif (typeof value.exitCode === 'number') lines.push(` exitCode: ${value.exitCode}`);\n\tif (typeof value.stderr === 'string' && value.stderr.trim().length > 0) {\n\t\tlines.push(` stderr: ${truncate(value.stderr.trim(), opts.fieldTruncate, opts.redactions)}`);\n\t}\n\tif (typeof value.stdout === 'string' && value.stdout.trim().length > 0) {\n\t\tlines.push(` stdout: ${truncate(value.stdout.trim(), opts.fieldTruncate, opts.redactions)}`);\n\t}\n\tif (typeof value.detail === 'string' && value.detail.trim().length > 0) {\n\t\tlines.push(` detail: ${truncate(value.detail.trim(), opts.fieldTruncate, opts.redactions)}`);\n\t}\n\n\t// Surface any extra plain-data fields the tagged error carries.\n\t// We skip the conventional ones already rendered above plus `_tag`,\n\t// `cause`. This makes the formatter discover-by-shape: a plugin\n\t// adding `path` or `kind` to its error gets it rendered for free.\n\tconst conventional = new Set([\n\t\t'_tag',\n\t\t'message',\n\t\t'cause',\n\t\t'phase',\n\t\t'stderr',\n\t\t'stdout',\n\t\t'exitCode',\n\t\t'detail',\n\t\t'op',\n\t]);\n\tfor (const key of Object.keys(value)) {\n\t\tif (conventional.has(key)) continue;\n\t\tconst v = (value as unknown as Record<string, unknown>)[key];\n\t\tif (v === undefined || v === null) continue;\n\t\tconst rendered =\n\t\t\ttypeof v === 'string'\n\t\t\t\t? truncate(v, opts.fieldTruncate, opts.redactions)\n\t\t\t\t: typeof v === 'number' || typeof v === 'boolean'\n\t\t\t\t\t? String(v)\n\t\t\t\t\t: safeJson(v, opts.fieldTruncate, opts.redactions);\n\t\tlines.push(` ${key}: ${rendered}`);\n\t}\n\n\tif (value.cause !== undefined && value.cause !== null) {\n\t\tconst rendered = formatAny(value.cause, opts, visited, depth + 1);\n\t\tif (rendered.trim().length > 0 && rendered.trim() !== header.trim()) {\n\t\t\tlines.push(' caused by:');\n\t\t\tlines.push(indent(rendered, ' '));\n\t\t}\n\t}\n\treturn lines.join('\\n');\n};\n\nconst safeJson = (\n\tvalue: unknown,\n\tlimit: number,\n\tredactions: ReadonlyArray<RedactionRule>,\n): string => {\n\ttry {\n\t\treturn truncate(JSON.stringify(redactValue(value, redactions)), limit, redactions);\n\t} catch {\n\t\treturn '[unserializable]';\n\t}\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cascade-formatter.mjs","names":[],"sources":["../../../../src/substrate/runtime/observability/cascade-formatter.ts"],"sourcesContent":["// L0 cascade formatter.\n//\n// Architecture § Substrate violations § \"C2 — relocate cause walker\n// from the renderer\". The cascade formatter walks an Effect `Cause`\n// and returns a stringified cascade of taxonomy-aware lines. Called\n// from CLI, TUI, prune — anywhere a failure surfaces.\n//\n// Hard rules:\n// - PURE. No IO, no Effect, no clocks. Input → string.\n// - No service names: the formatter inspects `_tag` strings and\n// structured fields verbatim, never branches on a specific\n// concrete plugin error class.\n// - Pluggable per-error-class formatters via a `formatters` map\n// keyed by `_tag`. The default formatter handles tagged errors,\n// plain `Error`, defects, and Interrupts.\n//\n// Output shape:\n//\n// <Tag> (<phase?>): <message>\n// exitCode: <n>\n// stderr: <text…[truncated]>\n// <field>: <value>\n// caused by:\n// <recursive render, indented by 2 spaces>\n//\n// Multi-`Fail` causes (parallel failures) render with a `--- (also)`\n// separator. Defects (`Die`) render with `DEFECT (<tag>?)` prefix so\n// the operator can tell programmer errors from typed failures at a\n// glance. Interrupts render as `INTERRUPT[<fiberId>]`.\n\nimport { Cause } from 'effect';\n\nimport { redactText, redactValue, type RedactionRule } from './redaction.ts';\n\n// -----------------------------------------------------------------------------\n// Plug-in formatter API\n// -----------------------------------------------------------------------------\n\n/**\n * Per-tag formatter override. Receives the tagged-error-like value\n * and the default formatter (so a plugin formatter can recurse on a\n * nested `cause` field without re-implementing the walk).\n *\n * Return `null` to fall back to the default rendering.\n *\n * Architecture: the formatter registry is keyed by `_tag` string —\n * the substrate never imports a concrete plugin error class. Plugins\n * register their custom renderer via the supervisor harvest loop over\n * `errorContributions` (see `substrate/plugin.ts:PluginErrorContribution`).\n */\nexport type TagFormatter = (\n\tvalue: TaggedErrorLike,\n\trecurse: (inner: unknown) => string,\n) => string | null;\n\n/** Per-tag formatter map. */\nexport type FormatterRegistry = ReadonlyMap<string, TagFormatter>;\n\n/** Empty registry — the formatter falls back to the default\n * rendering for every value. */\nexport const emptyFormatterRegistry: FormatterRegistry = new Map();\n\n// -----------------------------------------------------------------------------\n// Render budget\n// -----------------------------------------------------------------------------\n\nconst DEFAULT_FIELD_TRUNCATE = 8192;\nconst DEFAULT_MAX_DEPTH = 12;\n\nexport interface FormatOptions {\n\t/** Per-tag override registry. Defaults to the empty registry. */\n\treadonly formatters?: FormatterRegistry;\n\t/** Truncate individual fields (stderr/stdout/detail) past this\n\t * length. Default 8 KiB. */\n\treadonly fieldTruncate?: number;\n\t/** Hard recursion cap. Cyclic graphs are detected separately by\n\t * visit-set; this guards against pathological cause chains.\n\t * Default 12. */\n\treadonly maxDepth?: number;\n\t/** Optional redaction rules applied before rendering string fields. */\n\treadonly redactions?: ReadonlyArray<RedactionRule>;\n}\n\n// -----------------------------------------------------------------------------\n// Type guards (structural — no imports of concrete classes)\n// -----------------------------------------------------------------------------\n\n/** Shape of a `Schema.TaggedError` / `Data.TaggedError` instance.\n * The cascade formatter never imports a concrete class — it dispatches\n * on `_tag`. */\nexport interface TaggedErrorLike {\n\treadonly _tag: string;\n\treadonly message?: unknown;\n\treadonly cause?: unknown;\n\treadonly phase?: unknown;\n\treadonly stderr?: unknown;\n\treadonly stdout?: unknown;\n\treadonly exitCode?: unknown;\n\treadonly [key: string]: unknown;\n\treadonly detail?: unknown;\n\treadonly op?: unknown;\n}\n\nexport const isTaggedError = (value: unknown): value is TaggedErrorLike =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\ttypeof (value as { _tag?: unknown })._tag === 'string';\n\n// -----------------------------------------------------------------------------\n// Public entry points\n// -----------------------------------------------------------------------------\n\n/**\n * Format an Effect `Cause<E>` as a multi-line cascade string. Pure.\n *\n * Multiple `Fail` reasons render as separate blocks joined by\n * `--- (also)` so parallel failures are visible. Defects render with\n * a `DEFECT` prefix. Interrupts render with `INTERRUPT[<fiberId>]`.\n *\n * Cyclic `cause` chains are broken with `…[cycle]`.\n */\nexport const formatCause = <E>(cause: Cause.Cause<E>, options?: FormatOptions): string => {\n\tconst opts: Required<FormatOptions> = {\n\t\tformatters: options?.formatters ?? emptyFormatterRegistry,\n\t\tfieldTruncate: options?.fieldTruncate ?? DEFAULT_FIELD_TRUNCATE,\n\t\tmaxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n\t\tredactions: options?.redactions ?? [],\n\t};\n\tconst visited = new WeakSet<object>();\n\tif (cause.reasons.length === 0) return '(empty cause)';\n\tconst rendered = cause.reasons.map((reason) => formatReason(reason, opts, visited, 0));\n\treturn rendered.join('\\n--- (also)\\n');\n};\n\n/**\n * Format an arbitrary value (a `Cause`, a tagged error, a plain\n * `Error`, or anything else) using the cascade rules. Pure.\n *\n * The pretty-error renderer (`pretty-error.ts`) is a thin wrapper\n * over this — it just sets the IO conventions (where to write,\n * what to truncate per-context). The formatting logic lives here.\n */\nexport const formatValue = (value: unknown, options?: FormatOptions): string => {\n\tconst opts: Required<FormatOptions> = {\n\t\tformatters: options?.formatters ?? emptyFormatterRegistry,\n\t\tfieldTruncate: options?.fieldTruncate ?? DEFAULT_FIELD_TRUNCATE,\n\t\tmaxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n\t\tredactions: options?.redactions ?? [],\n\t};\n\treturn formatAny(value, opts, new WeakSet(), 0);\n};\n\n// -----------------------------------------------------------------------------\n// Internals\n// -----------------------------------------------------------------------------\n\nconst truncate = (s: string, limit: number, redactions: ReadonlyArray<RedactionRule>): string => {\n\tconst redacted = redactText(s, redactions);\n\treturn redacted.length > limit ? `${redacted.slice(0, limit)}…[truncated]` : redacted;\n};\n\nconst indent = (s: string, prefix: string): string =>\n\ts\n\t\t.split('\\n')\n\t\t.map((line) => `${prefix}${line}`)\n\t\t.join('\\n');\n\nconst formatReason = (\n\treason: Cause.Reason<unknown>,\n\topts: Required<FormatOptions>,\n\tvisited: WeakSet<object>,\n\tdepth: number,\n): string => {\n\tif (Cause.isFailReason(reason)) {\n\t\treturn formatAny(reason.error, opts, visited, depth);\n\t}\n\tif (Cause.isDieReason(reason)) {\n\t\tconst inner = formatAny(reason.defect, opts, visited, depth);\n\t\treturn `DEFECT:\\n${indent(inner, ' ')}`;\n\t}\n\t// Cause.isInterruptReason(reason)\n\treturn `INTERRUPT[${reason.fiberId ?? 'unknown'}]`;\n};\n\nconst formatAny = (\n\tvalue: unknown,\n\topts: Required<FormatOptions>,\n\tvisited: WeakSet<object>,\n\tdepth: number,\n): string => {\n\tif (value === undefined || value === null) return '';\n\tif (depth > opts.maxDepth) return '…[max depth]';\n\tif (typeof value === 'object') {\n\t\tif (visited.has(value as object)) return '…[cycle]';\n\t\tvisited.add(value as object);\n\t}\n\tif (Cause.isCause(value)) {\n\t\tif (value.reasons.length === 0) return '(empty cause)';\n\t\treturn value.reasons.map((r) => formatReason(r, opts, visited, depth)).join('\\n--- (also)\\n');\n\t}\n\tif (isTaggedError(value)) {\n\t\treturn formatTagged(value, opts, visited, depth);\n\t}\n\tif (value instanceof Error) {\n\t\tconst header = `${value.name}: ${value.message}`;\n\t\tif (value.stack && value.stack !== header) return value.stack;\n\t\treturn header;\n\t}\n\tif (typeof value === 'string') return redactText(value, opts.redactions);\n\ttry {\n\t\treturn JSON.stringify(redactValue(value, opts.redactions));\n\t} catch {\n\t\treturn String(value);\n\t}\n};\n\nconst formatTagged = (\n\tvalue: TaggedErrorLike,\n\topts: Required<FormatOptions>,\n\tvisited: WeakSet<object>,\n\tdepth: number,\n): string => {\n\tconst override = opts.formatters.get(value._tag);\n\tif (override) {\n\t\tconst result = override(value, (inner) => formatAny(inner, opts, visited, depth + 1));\n\t\tif (result !== null) return result;\n\t}\n\n\tconst qualifier =\n\t\ttypeof value.phase === 'string'\n\t\t\t? `(${value.phase})`\n\t\t\t: typeof value.op === 'string'\n\t\t\t\t? `(${value.op})`\n\t\t\t\t: '';\n\tconst message =\n\t\ttypeof value.message === 'string' ? redactText(value.message, opts.redactions) : '';\n\tconst header = qualifier ? `${value._tag} ${qualifier}: ${message}` : `${value._tag}: ${message}`;\n\n\tconst lines: Array<string> = [header];\n\tif (typeof value.exitCode === 'number') lines.push(` exitCode: ${value.exitCode}`);\n\tif (typeof value.stderr === 'string' && value.stderr.trim().length > 0) {\n\t\tlines.push(` stderr: ${truncate(value.stderr.trim(), opts.fieldTruncate, opts.redactions)}`);\n\t}\n\tif (typeof value.stdout === 'string' && value.stdout.trim().length > 0) {\n\t\tlines.push(` stdout: ${truncate(value.stdout.trim(), opts.fieldTruncate, opts.redactions)}`);\n\t}\n\tif (typeof value.detail === 'string' && value.detail.trim().length > 0) {\n\t\tlines.push(` detail: ${truncate(value.detail.trim(), opts.fieldTruncate, opts.redactions)}`);\n\t}\n\n\t// Surface any extra plain-data fields the tagged error carries.\n\t// We skip the conventional ones already rendered above plus `_tag`,\n\t// `cause`. This makes the formatter discover-by-shape: a plugin\n\t// adding `path` or `kind` to its error gets it rendered for free.\n\tconst conventional = new Set([\n\t\t'_tag',\n\t\t'message',\n\t\t'cause',\n\t\t'phase',\n\t\t'stderr',\n\t\t'stdout',\n\t\t'exitCode',\n\t\t'detail',\n\t\t'op',\n\t]);\n\tfor (const key of Object.keys(value)) {\n\t\tif (conventional.has(key)) continue;\n\t\tconst v = (value as unknown as Record<string, unknown>)[key];\n\t\tif (v === undefined || v === null) continue;\n\t\tconst rendered =\n\t\t\ttypeof v === 'string'\n\t\t\t\t? truncate(v, opts.fieldTruncate, opts.redactions)\n\t\t\t\t: typeof v === 'number' || typeof v === 'boolean'\n\t\t\t\t\t? String(v)\n\t\t\t\t\t: safeJson(v, opts.fieldTruncate, opts.redactions);\n\t\tlines.push(` ${key}: ${rendered}`);\n\t}\n\n\tif (value.cause !== undefined && value.cause !== null) {\n\t\tconst rendered = formatAny(value.cause, opts, visited, depth + 1);\n\t\tif (rendered.trim().length > 0 && rendered.trim() !== header.trim()) {\n\t\t\tlines.push(' caused by:');\n\t\t\tlines.push(indent(rendered, ' '));\n\t\t}\n\t}\n\treturn lines.join('\\n');\n};\n\nconst safeJson = (\n\tvalue: unknown,\n\tlimit: number,\n\tredactions: ReadonlyArray<RedactionRule>,\n): string => {\n\ttry {\n\t\treturn truncate(JSON.stringify(redactValue(value, redactions)), limit, redactions);\n\t} catch {\n\t\treturn '[unserializable]';\n\t}\n};\n"],"mappings":"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"}
@@ -1,58 +1,41 @@
1
+ import { makeScopedMultimap } from "../scoped-multimap/service.mjs";
2
+ import "../scoped-multimap/index.mjs";
1
3
  import { emptyFormatterRegistry } from "./cascade-formatter.mjs";
2
- import { Context, Effect, Layer, Ref } from "effect";
4
+ import { Context, Effect, Layer } from "effect";
3
5
  //#region src/substrate/runtime/observability/formatter-registry.ts
4
- var FormatterRegistryService = class extends Context.Service()("@devstack-rewrite/substrate/FormatterRegistry") {};
6
+ var FormatterRegistryService = class extends Context.Service()("@devstack/substrate/FormatterRegistry") {};
5
7
  /** Layer constructing the per-stack formatter registry. Stateful;
6
- * the substrate provides one per supervisor scope. */
8
+ * the substrate provides one per supervisor scope.
9
+ *
10
+ * Storage is the shared scoped-multimap keyed by tag. The per-entry
11
+ * value is the (optional) formatter — the registry may track a tag
12
+ * with NO formatter (default rendering is enough), so `null` is a
13
+ * legitimate value and the seq still tracks the registration. */
7
14
  const layerFormatterRegistry = Layer.effect(FormatterRegistryService, Effect.gen(function* () {
8
- const state = yield* Ref.make(/* @__PURE__ */ new Map());
9
- const seqRef = yield* Ref.make(0);
15
+ const store = yield* makeScopedMultimap();
10
16
  const register = (contribution) => Effect.gen(function* () {
11
- const baseSeq = yield* Ref.updateAndGet(seqRef, (n) => n + 1);
12
17
  const fmt = contribution.formatter !== void 0 ? (value, recurse) => contribution.formatter(value, recurse) : null;
13
- const newEntries = contribution.errorTags.map((tag) => ({
14
- tag,
15
- formatter: fmt,
16
- seq: baseSeq
17
- }));
18
- yield* Ref.update(state, (current) => {
19
- const next = new Map(current);
20
- for (const e of newEntries) {
21
- const existing = next.get(e.tag) ?? [];
22
- next.set(e.tag, [...existing, e]);
23
- }
24
- return next;
25
- });
26
- yield* Effect.addFinalizer((_exit) => Ref.update(state, (current) => {
27
- const next = new Map(current);
28
- for (const e of newEntries) {
29
- const existing = next.get(e.tag);
30
- if (!existing) continue;
31
- const filtered = existing.filter((x) => x.seq !== e.seq);
32
- if (filtered.length === 0) next.delete(e.tag);
33
- else next.set(e.tag, filtered);
34
- }
35
- return next;
36
- }));
18
+ yield* store.register(contribution.errorTags.map((tag) => ({
19
+ key: tag,
20
+ value: fmt
21
+ })));
37
22
  }).pipe(Effect.withSpan("substrate.formatterRegistry.register"));
38
23
  const snapshot = Effect.gen(function* () {
39
- const current = yield* Ref.get(state);
24
+ const current = yield* store.snapshot;
40
25
  if (current.size === 0) return emptyFormatterRegistry;
41
26
  const out = /* @__PURE__ */ new Map();
42
27
  for (const [tag, entries] of current) {
43
28
  let chosen = null;
44
29
  let chosenSeq = -1;
45
- for (const e of entries) if (e.formatter !== null && e.seq > chosenSeq) {
46
- chosen = e.formatter;
30
+ for (const e of entries) if (e.value !== null && e.seq > chosenSeq) {
31
+ chosen = e.value;
47
32
  chosenSeq = e.seq;
48
33
  }
49
34
  if (chosen !== null) out.set(tag, chosen);
50
35
  }
51
36
  return out;
52
37
  });
53
- const tags = Effect.gen(function* () {
54
- return [...(yield* Ref.get(state)).keys()];
55
- });
38
+ const tags = store.keys;
56
39
  return FormatterRegistryService.of({
57
40
  register,
58
41
  snapshot,