@mysten-incubation/devstack 0.1.1 → 0.2.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 (858) hide show
  1. package/README.md +6 -3
  2. package/dashboard-ui/assets/grpc-a4usE3Nk.js +3 -0
  3. package/dashboard-ui/assets/index-B82Bh84P.css +1 -0
  4. package/dashboard-ui/assets/index-CRYJ4pru.js +1277 -0
  5. package/dashboard-ui/index.html +2 -2
  6. package/dist/api/define-capabilities.d.mts +1 -20
  7. package/dist/api/define-capabilities.mjs +15 -22
  8. package/dist/api/define-capabilities.mjs.map +1 -1
  9. package/dist/api/define-devstack-with.d.mts +7 -1
  10. package/dist/api/define-devstack-with.mjs.map +1 -1
  11. package/dist/api/define-devstack.mjs.map +1 -1
  12. package/dist/api/define-plugin.d.mts +2 -1
  13. package/dist/api/inference-network.d.mts +31 -17
  14. package/dist/api/inference-network.mjs +40 -43
  15. package/dist/api/inference-network.mjs.map +1 -1
  16. package/dist/api/load-config.mjs +88 -0
  17. package/dist/api/load-config.mjs.map +1 -0
  18. package/dist/api/mode-narrowed-factory.d.mts +1 -1
  19. package/dist/api/mode-narrowed-factory.mjs.map +1 -1
  20. package/dist/api/run-stack-internal.mjs +202 -0
  21. package/dist/api/run-stack-internal.mjs.map +1 -0
  22. package/dist/api/run-stack.d.mts +82 -31
  23. package/dist/api/run-stack.mjs +22 -141
  24. package/dist/api/run-stack.mjs.map +1 -1
  25. package/dist/build-integrations/dapp-kit/index.d.mts +61 -0
  26. package/dist/build-integrations/dapp-kit/index.mjs +58 -0
  27. package/dist/build-integrations/dapp-kit/index.mjs.map +1 -0
  28. package/dist/build-integrations/playwright/config.d.mts +1 -30
  29. package/dist/build-integrations/playwright/config.mjs +1 -27
  30. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  31. package/dist/build-integrations/playwright/errors.d.mts +4 -7
  32. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  33. package/dist/build-integrations/playwright/global-setup.d.mts +42 -71
  34. package/dist/build-integrations/playwright/global-setup.mjs +142 -218
  35. package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
  36. package/dist/build-integrations/playwright/index.d.mts +2 -2
  37. package/dist/build-integrations/playwright/index.mjs +2 -2
  38. package/dist/build-integrations/playwright/stack-context.d.mts +3 -1
  39. package/dist/build-integrations/playwright/stack-context.mjs +4 -2
  40. package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
  41. package/dist/build-integrations/playwright/wallet-context.mjs +44 -19
  42. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  43. package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
  44. package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -1
  45. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  46. package/dist/build-integrations/runtime/discover.d.mts +6 -4
  47. package/dist/build-integrations/runtime/discover.mjs +15 -4
  48. package/dist/build-integrations/runtime/discover.mjs.map +1 -1
  49. package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
  50. package/dist/build-integrations/runtime/errors.mjs.map +1 -1
  51. package/dist/build-integrations/runtime/read-stack-context.mjs +3 -3
  52. package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
  53. package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +23 -7
  54. package/dist/build-integrations/runtime/resolve-discovery-env.mjs +25 -12
  55. package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -1
  56. package/dist/build-integrations/runtime/stack-context.d.mts +2 -2
  57. package/dist/build-integrations/vite/index.d.mts +84 -19
  58. package/dist/build-integrations/vite/index.mjs +203 -28
  59. package/dist/build-integrations/vite/index.mjs.map +1 -1
  60. package/dist/build-integrations/vitest/config.d.mts +20 -2
  61. package/dist/build-integrations/vitest/config.mjs +16 -4
  62. package/dist/build-integrations/vitest/config.mjs.map +1 -1
  63. package/dist/build-integrations/vitest/env.d.mts +18 -10
  64. package/dist/build-integrations/vitest/env.mjs +11 -10
  65. package/dist/build-integrations/vitest/env.mjs.map +1 -1
  66. package/dist/build-integrations/vitest/errors.d.mts +7 -11
  67. package/dist/build-integrations/vitest/errors.mjs +3 -4
  68. package/dist/build-integrations/vitest/errors.mjs.map +1 -1
  69. package/dist/build-integrations/vitest/global-setup.d.mts +35 -0
  70. package/dist/build-integrations/vitest/global-setup.mjs +156 -0
  71. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -0
  72. package/dist/build-integrations/vitest/index.d.mts +3 -2
  73. package/dist/build-integrations/vitest/index.mjs +3 -2
  74. package/dist/build-integrations/vitest/setup.mjs +2 -2
  75. package/dist/build-integrations/vitest/setup.mjs.map +1 -1
  76. package/dist/build-integrations/vitest/stack-context.d.mts +5 -3
  77. package/dist/build-integrations/vitest/stack-context.mjs +3 -2
  78. package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
  79. package/dist/cli/bail.mjs.map +1 -1
  80. package/dist/cli/doctor-probes.mjs +1 -3
  81. package/dist/cli/doctor-probes.mjs.map +1 -1
  82. package/dist/cli/main.d.mts +23 -1
  83. package/dist/cli/main.mjs +63 -8
  84. package/dist/cli/main.mjs.map +1 -1
  85. package/dist/cli/prune-direct.mjs.map +1 -1
  86. package/dist/cli/snapshot-reader.mjs.map +1 -1
  87. package/dist/cli/up-lifecycle.mjs.map +1 -1
  88. package/dist/cli/wirings/apply.mjs +28 -21
  89. package/dist/cli/wirings/apply.mjs.map +1 -1
  90. package/dist/cli/wirings/codegen.mjs +108 -0
  91. package/dist/cli/wirings/codegen.mjs.map +1 -0
  92. package/dist/cli/wirings/config-loader.mjs +12 -62
  93. package/dist/cli/wirings/config-loader.mjs.map +1 -1
  94. package/dist/cli/wirings/dump-ids.mjs +86 -0
  95. package/dist/cli/wirings/dump-ids.mjs.map +1 -0
  96. package/dist/cli/wirings/engine-command.mjs +1 -1
  97. package/dist/cli/wirings/engine-command.mjs.map +1 -1
  98. package/dist/cli/wirings/identity.mjs +2 -2
  99. package/dist/cli/wirings/identity.mjs.map +1 -1
  100. package/dist/cli/wirings/provide-file-system.mjs.map +1 -1
  101. package/dist/cli/wirings/read-devstack-version.mjs +17 -0
  102. package/dist/cli/wirings/read-devstack-version.mjs.map +1 -0
  103. package/dist/cli/wirings/snapshot.mjs +27 -34
  104. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  105. package/dist/cli/wirings/up-ipc.mjs +147 -0
  106. package/dist/cli/wirings/up-ipc.mjs.map +1 -0
  107. package/dist/cli/wirings/up.mjs +218 -198
  108. package/dist/cli/wirings/up.mjs.map +1 -1
  109. package/dist/cli/wirings/wipe.mjs +1 -1
  110. package/dist/cli/wirings/wipe.mjs.map +1 -1
  111. package/dist/contracts/chain-probe.d.mts +1 -1
  112. package/dist/contracts/chain-probe.mjs +1 -1
  113. package/dist/contracts/chain-probe.mjs.map +1 -1
  114. package/dist/contracts/codegenable.d.mts +60 -6
  115. package/dist/contracts/codegenable.mjs +28 -0
  116. package/dist/contracts/codegenable.mjs.map +1 -0
  117. package/dist/contracts/config-bindings.mjs +162 -0
  118. package/dist/contracts/config-bindings.mjs.map +1 -0
  119. package/dist/contracts/container-runtime.d.mts +23 -17
  120. package/dist/contracts/plugin-expander.mjs.map +1 -1
  121. package/dist/contracts/snapshotable.d.mts +5 -7
  122. package/dist/contracts/wallet-protocol.d.mts +2 -5
  123. package/dist/contracts/wallet-protocol.mjs +2 -5
  124. package/dist/contracts/wallet-protocol.mjs.map +1 -1
  125. package/dist/index.d.mts +21 -26
  126. package/dist/index.mjs +8 -9
  127. package/dist/orchestrators/boot.d.mts +28 -0
  128. package/dist/orchestrators/boot.mjs +440 -0
  129. package/dist/orchestrators/boot.mjs.map +1 -0
  130. package/dist/orchestrators/codegen/bindings.d.mts +13 -1
  131. package/dist/orchestrators/codegen/bindings.mjs +23 -9
  132. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  133. package/dist/orchestrators/codegen/config-runtime.mjs +208 -0
  134. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -0
  135. package/dist/orchestrators/codegen/emit.mjs +1 -1
  136. package/dist/orchestrators/codegen/emit.mjs.map +1 -1
  137. package/dist/orchestrators/codegen/errors.mjs +21 -1
  138. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  139. package/dist/orchestrators/codegen/format.mjs +2 -0
  140. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  141. package/dist/orchestrators/codegen/gitignore.mjs +30 -11
  142. package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
  143. package/dist/orchestrators/codegen/id-config.mjs +107 -0
  144. package/dist/orchestrators/codegen/id-config.mjs.map +1 -0
  145. package/dist/orchestrators/codegen/output-location.mjs +23 -32
  146. package/dist/orchestrators/codegen/output-location.mjs.map +1 -1
  147. package/dist/orchestrators/codegen/paths.mjs +8 -1
  148. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  149. package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
  150. package/dist/orchestrators/codegen/service.mjs +286 -58
  151. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  152. package/dist/orchestrators/layers.mjs +31 -0
  153. package/dist/orchestrators/layers.mjs.map +1 -0
  154. package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -1
  155. package/dist/orchestrators/lifecycle-prune/index.mjs +8 -10
  156. package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -1
  157. package/dist/orchestrators/network-options.d.mts +52 -0
  158. package/dist/orchestrators/network-options.mjs +43 -0
  159. package/dist/orchestrators/network-options.mjs.map +1 -0
  160. package/dist/orchestrators/router/cleanup.mjs.map +1 -1
  161. package/dist/orchestrators/router/cors.mjs.map +1 -1
  162. package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
  163. package/dist/orchestrators/router/errors.mjs.map +1 -1
  164. package/dist/orchestrators/router/file-provider.mjs.map +1 -1
  165. package/dist/orchestrators/router/hostname.mjs.map +1 -1
  166. package/dist/orchestrators/router/profile.mjs +1 -1
  167. package/dist/orchestrators/router/profile.mjs.map +1 -1
  168. package/dist/orchestrators/router/service.d.mts +2 -2
  169. package/dist/orchestrators/router/service.mjs +12 -27
  170. package/dist/orchestrators/router/service.mjs.map +1 -1
  171. package/dist/orchestrators/router/traefik-container.mjs +1 -1
  172. package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
  173. package/dist/orchestrators/snapshot/capture.mjs +171 -195
  174. package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
  175. package/dist/orchestrators/snapshot/descriptor.d.mts +1 -1
  176. package/dist/orchestrators/snapshot/descriptor.mjs +53 -11
  177. package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
  178. package/dist/orchestrators/snapshot/identity-guard.mjs +3 -5
  179. package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -1
  180. package/dist/orchestrators/snapshot/image-bundle-tags.mjs +32 -101
  181. package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -1
  182. package/dist/orchestrators/snapshot/index.mjs +1 -4
  183. package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
  184. package/dist/orchestrators/snapshot/interrupted-restore.mjs +116 -0
  185. package/dist/orchestrators/snapshot/interrupted-restore.mjs.map +1 -0
  186. package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -1
  187. package/dist/orchestrators/snapshot/prune.mjs +40 -31
  188. package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
  189. package/dist/orchestrators/snapshot/restore.mjs +221 -196
  190. package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
  191. package/dist/orchestrators/snapshot/service.mjs +72 -62
  192. package/dist/orchestrators/snapshot/service.mjs.map +1 -1
  193. package/dist/orchestrators/snapshot/wipe.mjs +67 -56
  194. package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
  195. package/dist/plugins/account/codegen.mjs +3 -0
  196. package/dist/plugins/account/codegen.mjs.map +1 -1
  197. package/dist/plugins/account/errors.d.mts +2 -2
  198. package/dist/plugins/account/errors.mjs +1 -4
  199. package/dist/plugins/account/errors.mjs.map +1 -1
  200. package/dist/plugins/account/funding.mjs +3 -27
  201. package/dist/plugins/account/funding.mjs.map +1 -1
  202. package/dist/plugins/account/index.d.mts +3 -8
  203. package/dist/plugins/account/index.mjs +71 -35
  204. package/dist/plugins/account/index.mjs.map +1 -1
  205. package/dist/plugins/account/keypair.d.mts +8 -7
  206. package/dist/plugins/account/keypair.mjs +5 -18
  207. package/dist/plugins/account/keypair.mjs.map +1 -1
  208. package/dist/plugins/account/lease.mjs.map +1 -1
  209. package/dist/plugins/account/registry.d.mts +1 -46
  210. package/dist/plugins/account/registry.mjs.map +1 -1
  211. package/dist/plugins/account/service.d.mts +43 -34
  212. package/dist/plugins/account/service.mjs +9 -54
  213. package/dist/plugins/account/service.mjs.map +1 -1
  214. package/dist/plugins/account/snapshot.mjs.map +1 -1
  215. package/dist/plugins/account/variants/ephemeral.mjs.map +1 -1
  216. package/dist/plugins/account/variants/impersonate.mjs.map +1 -1
  217. package/dist/plugins/account/variants/signer.mjs.map +1 -1
  218. package/dist/plugins/action/discriminator.mjs.map +1 -1
  219. package/dist/plugins/action/errors.mjs +1 -4
  220. package/dist/plugins/action/errors.mjs.map +1 -1
  221. package/dist/plugins/action/execute.mjs +3 -4
  222. package/dist/plugins/action/execute.mjs.map +1 -1
  223. package/dist/plugins/action/index.d.mts +2 -2
  224. package/dist/plugins/action/index.mjs +7 -11
  225. package/dist/plugins/action/index.mjs.map +1 -1
  226. package/dist/plugins/action/service.d.mts +5 -7
  227. package/dist/plugins/action/service.mjs +2 -16
  228. package/dist/plugins/action/service.mjs.map +1 -1
  229. package/dist/plugins/coin/address-resolution.mjs.map +1 -1
  230. package/dist/plugins/coin/codegen.mjs +97 -16
  231. package/dist/plugins/coin/codegen.mjs.map +1 -1
  232. package/dist/plugins/coin/discovery.mjs.map +1 -1
  233. package/dist/plugins/coin/errors.mjs +1 -4
  234. package/dist/plugins/coin/errors.mjs.map +1 -1
  235. package/dist/plugins/coin/index.d.mts +4 -34
  236. package/dist/plugins/coin/index.mjs +47 -28
  237. package/dist/plugins/coin/index.mjs.map +1 -1
  238. package/dist/plugins/coin/metadata.d.mts +1 -0
  239. package/dist/plugins/coin/metadata.mjs +8 -9
  240. package/dist/plugins/coin/metadata.mjs.map +1 -1
  241. package/dist/plugins/coin/mint.mjs +7 -21
  242. package/dist/plugins/coin/mint.mjs.map +1 -1
  243. package/dist/plugins/coin/registry.mjs +33 -20
  244. package/dist/plugins/coin/registry.mjs.map +1 -1
  245. package/dist/plugins/coin/service.d.mts +1 -1
  246. package/dist/plugins/coin/service.mjs +1 -8
  247. package/dist/plugins/coin/service.mjs.map +1 -1
  248. package/dist/plugins/coin/snapshot.mjs.map +1 -1
  249. package/dist/plugins/coin/type-strings.mjs.map +1 -1
  250. package/dist/plugins/dashboard/domain.mjs +106 -167
  251. package/dist/plugins/dashboard/domain.mjs.map +1 -1
  252. package/dist/plugins/dashboard/index.mjs +13 -13
  253. package/dist/plugins/dashboard/index.mjs.map +1 -1
  254. package/dist/plugins/dashboard/origin-policy.mjs +3 -3
  255. package/dist/plugins/dashboard/origin-policy.mjs.map +1 -1
  256. package/dist/plugins/dashboard/routable.mjs.map +1 -1
  257. package/dist/plugins/dashboard/schema/builder.mjs.map +1 -1
  258. package/dist/plugins/dashboard/schema/enums.mjs.map +1 -1
  259. package/dist/plugins/dashboard/schema/root.mjs +23 -44
  260. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  261. package/dist/plugins/dashboard/schema/types.mjs +37 -91
  262. package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
  263. package/dist/plugins/dashboard/schema.mjs.map +1 -1
  264. package/dist/plugins/dashboard/server.mjs.map +1 -1
  265. package/dist/plugins/deepbook/codegen.d.mts +12 -11
  266. package/dist/plugins/deepbook/codegen.mjs +108 -11
  267. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  268. package/dist/plugins/deepbook/deploy.mjs +7 -14
  269. package/dist/plugins/deepbook/deploy.mjs.map +1 -1
  270. package/dist/plugins/deepbook/errors.mjs +4 -2
  271. package/dist/plugins/deepbook/errors.mjs.map +1 -1
  272. package/dist/plugins/deepbook/faucet-strategy.mjs +4 -10
  273. package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
  274. package/dist/plugins/deepbook/hash.mjs.map +1 -1
  275. package/dist/plugins/deepbook/index.d.mts +38 -34
  276. package/dist/plugins/deepbook/index.mjs +133 -64
  277. package/dist/plugins/deepbook/index.mjs.map +1 -1
  278. package/dist/plugins/deepbook/plugin-key.mjs.map +1 -1
  279. package/dist/plugins/deepbook/pyth/index.mjs +4 -8
  280. package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
  281. package/dist/plugins/deepbook/snapshot.mjs +0 -1
  282. package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
  283. package/dist/plugins/deepbook/type-strings.mjs.map +1 -1
  284. package/dist/plugins/deepbook/types.d.mts +2 -1
  285. package/dist/plugins/deepbook/types.mjs.map +1 -1
  286. package/dist/plugins/faucet/dispatcher.d.mts +3 -3
  287. package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
  288. package/dist/plugins/faucet/errors.mjs.map +1 -1
  289. package/dist/plugins/faucet/http.mjs +2 -10
  290. package/dist/plugins/faucet/http.mjs.map +1 -1
  291. package/dist/plugins/faucet/index.mjs +0 -1
  292. package/dist/plugins/faucet/index.mjs.map +1 -1
  293. package/dist/plugins/host-service/errors.d.mts +1 -3
  294. package/dist/plugins/host-service/errors.mjs +1 -2
  295. package/dist/plugins/host-service/errors.mjs.map +1 -1
  296. package/dist/plugins/host-service/index.d.mts +1 -2
  297. package/dist/plugins/host-service/index.mjs +11 -11
  298. package/dist/plugins/host-service/index.mjs.map +1 -1
  299. package/dist/plugins/host-service/routable.mjs.map +1 -1
  300. package/dist/plugins/host-service/service.mjs +13 -13
  301. package/dist/plugins/host-service/service.mjs.map +1 -1
  302. package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -1
  303. package/dist/plugins/internal/codegen-helpers.mjs +2 -0
  304. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  305. package/dist/plugins/internal/funding-failure-error.mjs.map +1 -1
  306. package/dist/plugins/{postgres → internal/postgres-sidecar}/connection.mjs +1 -1
  307. package/dist/plugins/internal/postgres-sidecar/connection.mjs.map +1 -0
  308. package/dist/plugins/{postgres → internal/postgres-sidecar}/db-ensure.mjs +30 -16
  309. package/dist/plugins/internal/postgres-sidecar/db-ensure.mjs.map +1 -0
  310. package/dist/plugins/internal/postgres-sidecar/errors.mjs +21 -0
  311. package/dist/plugins/internal/postgres-sidecar/errors.mjs.map +1 -0
  312. package/dist/{substrate/runtime/scoped-multimap → plugins/internal/postgres-sidecar}/index.mjs +1 -0
  313. package/dist/plugins/internal/postgres-sidecar/service.mjs +121 -0
  314. package/dist/plugins/internal/postgres-sidecar/service.mjs.map +1 -0
  315. package/dist/plugins/package/build.mjs +2 -2
  316. package/dist/plugins/package/build.mjs.map +1 -1
  317. package/dist/plugins/package/codegen.d.mts +7 -14
  318. package/dist/plugins/package/codegen.mjs +187 -59
  319. package/dist/plugins/package/codegen.mjs.map +1 -1
  320. package/dist/plugins/package/dep-resolution.mjs +51 -3
  321. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  322. package/dist/plugins/package/errors.mjs +1 -4
  323. package/dist/plugins/package/errors.mjs.map +1 -1
  324. package/dist/plugins/package/git-source.d.mts +18 -0
  325. package/dist/plugins/package/git-source.mjs +119 -0
  326. package/dist/plugins/package/git-source.mjs.map +1 -0
  327. package/dist/plugins/package/index.d.mts +28 -19
  328. package/dist/plugins/package/index.mjs +107 -32
  329. package/dist/plugins/package/index.mjs.map +1 -1
  330. package/dist/plugins/package/mode-known.mjs +2 -2
  331. package/dist/plugins/package/mode-known.mjs.map +1 -1
  332. package/dist/plugins/package/mode-local.mjs +18 -35
  333. package/dist/plugins/package/mode-local.mjs.map +1 -1
  334. package/dist/plugins/package/publish-executor.mjs +13 -8
  335. package/dist/plugins/package/publish-executor.mjs.map +1 -1
  336. package/dist/plugins/package/publish-output.d.mts +1 -11
  337. package/dist/plugins/package/publish-output.mjs +1 -9
  338. package/dist/plugins/package/publish-output.mjs.map +1 -1
  339. package/dist/plugins/package/registry.d.mts +1 -1
  340. package/dist/plugins/package/registry.mjs +26 -14
  341. package/dist/plugins/package/registry.mjs.map +1 -1
  342. package/dist/plugins/package/service.mjs.map +1 -1
  343. package/dist/plugins/package/snapshot.mjs.map +1 -1
  344. package/dist/plugins/router-entrypoints.mjs +1 -3
  345. package/dist/plugins/router-entrypoints.mjs.map +1 -1
  346. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +1 -2
  347. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
  348. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +1 -6
  349. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
  350. package/dist/plugins/seal/codegen.d.mts +1 -5
  351. package/dist/plugins/seal/codegen.mjs +83 -12
  352. package/dist/plugins/seal/codegen.mjs.map +1 -1
  353. package/dist/plugins/seal/config-render.mjs +2 -6
  354. package/dist/plugins/seal/config-render.mjs.map +1 -1
  355. package/dist/plugins/seal/deploy.mjs +18 -29
  356. package/dist/plugins/seal/deploy.mjs.map +1 -1
  357. package/dist/plugins/seal/errors.d.mts +4 -5
  358. package/dist/plugins/seal/errors.mjs +1 -8
  359. package/dist/plugins/seal/errors.mjs.map +1 -1
  360. package/dist/plugins/seal/index.d.mts +7 -28
  361. package/dist/plugins/seal/index.mjs +69 -47
  362. package/dist/plugins/seal/index.mjs.map +1 -1
  363. package/dist/plugins/seal/key-manager.mjs.map +1 -1
  364. package/dist/plugins/seal/key-server.mjs +1 -6
  365. package/dist/plugins/seal/key-server.mjs.map +1 -1
  366. package/dist/plugins/seal/keygen.mjs +2 -3
  367. package/dist/plugins/seal/keygen.mjs.map +1 -1
  368. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
  369. package/dist/plugins/seal/mode/live.mjs +1 -1
  370. package/dist/plugins/seal/mode/live.mjs.map +1 -1
  371. package/dist/plugins/seal/mode/local-keygen.mjs +4 -10
  372. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
  373. package/dist/plugins/seal/plugin-key.mjs.map +1 -1
  374. package/dist/plugins/seal/registry-publish.mjs.map +1 -1
  375. package/dist/plugins/seal/routable.mjs.map +1 -1
  376. package/dist/plugins/seal/service.mjs.map +1 -1
  377. package/dist/plugins/seal/snapshot.mjs +1 -2
  378. package/dist/plugins/seal/snapshot.mjs.map +1 -1
  379. package/dist/plugins/sui/auto-tick.mjs +5 -5
  380. package/dist/plugins/sui/auto-tick.mjs.map +1 -1
  381. package/dist/plugins/sui/chain-build-container.mjs +2 -2
  382. package/dist/plugins/sui/chain-build-container.mjs.map +1 -1
  383. package/dist/plugins/sui/chain-probe.mjs +4 -4
  384. package/dist/plugins/sui/chain-probe.mjs.map +1 -1
  385. package/dist/plugins/sui/codegen.d.mts +9 -7
  386. package/dist/plugins/sui/codegen.mjs +49 -46
  387. package/dist/plugins/sui/codegen.mjs.map +1 -1
  388. package/dist/plugins/sui/errors.d.mts +1 -1
  389. package/dist/plugins/sui/errors.mjs +1 -9
  390. package/dist/plugins/sui/errors.mjs.map +1 -1
  391. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.d.mts +1 -1
  392. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.mjs +3 -7
  393. package/dist/plugins/sui/exec/index.mjs.map +1 -0
  394. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.mjs +1 -1
  395. package/dist/plugins/sui/exec/sign-and-dispatch.mjs.map +1 -0
  396. package/dist/plugins/sui/fork-faucet-strategy.mjs +2 -6
  397. package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -1
  398. package/dist/plugins/sui/fork-orchestration.mjs +13 -23
  399. package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
  400. package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
  401. package/dist/plugins/sui/index.d.mts +34 -83
  402. package/dist/plugins/sui/index.mjs +200 -68
  403. package/dist/plugins/sui/index.mjs.map +1 -1
  404. package/dist/{substrate/runtime/sui-ledger → plugins/sui/ledger}/object-ref.mjs +1 -1
  405. package/dist/plugins/sui/ledger/object-ref.mjs.map +1 -0
  406. package/dist/plugins/sui/local-faucet-strategy.mjs +1 -5
  407. package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -1
  408. package/dist/plugins/sui/log-attrs.mjs +11 -0
  409. package/dist/plugins/sui/log-attrs.mjs.map +1 -0
  410. package/dist/plugins/sui/mode/external.mjs +4 -12
  411. package/dist/plugins/sui/mode/external.mjs.map +1 -1
  412. package/dist/plugins/sui/mode/fork.mjs +19 -16
  413. package/dist/plugins/sui/mode/fork.mjs.map +1 -1
  414. package/dist/plugins/sui/mode/live.mjs +4 -17
  415. package/dist/plugins/sui/mode/live.mjs.map +1 -1
  416. package/dist/plugins/sui/mode/local.d.mts +1 -0
  417. package/dist/plugins/sui/mode/local.mjs +203 -61
  418. package/dist/plugins/sui/mode/local.mjs.map +1 -1
  419. package/dist/plugins/sui/mode/shared-boot.mjs +18 -23
  420. package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
  421. package/dist/plugins/sui/mode/shared.d.mts +6 -7
  422. package/dist/plugins/sui/mode/shared.mjs.map +1 -1
  423. package/dist/plugins/sui/mode/spec.d.mts +23 -6
  424. package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.mjs +28 -30
  425. package/dist/plugins/sui/move/index.mjs.map +1 -0
  426. package/dist/plugins/sui/move-summary-runner.mjs +8 -4
  427. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
  428. package/dist/{substrate/network.d.mts → plugins/sui/network-config.d.mts} +11 -10
  429. package/dist/plugins/sui/network-resolver.d.mts +6 -6
  430. package/dist/plugins/sui/routable.mjs.map +1 -1
  431. package/dist/plugins/sui/service.mjs +10 -6
  432. package/dist/plugins/sui/service.mjs.map +1 -1
  433. package/dist/plugins/sui/snapshot.mjs +10 -5
  434. package/dist/plugins/sui/snapshot.mjs.map +1 -1
  435. package/dist/plugins/wallet/codegen.d.mts +8 -6
  436. package/dist/plugins/wallet/codegen.mjs +4 -10
  437. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  438. package/dist/plugins/wallet/errors.mjs +1 -4
  439. package/dist/plugins/wallet/errors.mjs.map +1 -1
  440. package/dist/plugins/wallet/index.d.mts +3 -6
  441. package/dist/plugins/wallet/index.mjs +16 -21
  442. package/dist/plugins/wallet/index.mjs.map +1 -1
  443. package/dist/plugins/wallet/origin-policy.mjs +3 -3
  444. package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
  445. package/dist/plugins/wallet/pairing.mjs +6 -24
  446. package/dist/plugins/wallet/pairing.mjs.map +1 -1
  447. package/dist/plugins/wallet/protocol.mjs.map +1 -1
  448. package/dist/plugins/wallet/routable.mjs.map +1 -1
  449. package/dist/plugins/wallet/server.mjs +17 -24
  450. package/dist/plugins/wallet/server.mjs.map +1 -1
  451. package/dist/plugins/wallet/service.d.mts +2 -2
  452. package/dist/plugins/wallet/service.mjs +4 -15
  453. package/dist/plugins/wallet/service.mjs.map +1 -1
  454. package/dist/plugins/wallet/snapshot.mjs.map +1 -1
  455. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +1 -5
  456. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
  457. package/dist/plugins/walrus/codegen.d.mts +2 -13
  458. package/dist/plugins/walrus/codegen.mjs +93 -28
  459. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  460. package/dist/plugins/walrus/deploy-paths.mjs +2 -3
  461. package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
  462. package/dist/plugins/walrus/deploy.mjs +26 -19
  463. package/dist/plugins/walrus/deploy.mjs.map +1 -1
  464. package/dist/plugins/walrus/errors.mjs +1 -8
  465. package/dist/plugins/walrus/errors.mjs.map +1 -1
  466. package/dist/plugins/walrus/faucet-strategy.mjs +15 -1
  467. package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
  468. package/dist/plugins/walrus/index.d.mts +13 -44
  469. package/dist/plugins/walrus/index.mjs +119 -122
  470. package/dist/plugins/walrus/index.mjs.map +1 -1
  471. package/dist/plugins/walrus/mode/known-deploy.mjs +6 -6
  472. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
  473. package/dist/plugins/walrus/mode/local-cluster.d.mts +2 -2
  474. package/dist/plugins/walrus/mode/local-cluster.mjs +2 -10
  475. package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
  476. package/dist/plugins/walrus/plugin-key.mjs.map +1 -1
  477. package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
  478. package/dist/plugins/walrus/routable.mjs.map +1 -1
  479. package/dist/plugins/walrus/service.mjs.map +1 -1
  480. package/dist/plugins/walrus/snapshot.mjs +3 -3
  481. package/dist/plugins/walrus/snapshot.mjs.map +1 -1
  482. package/dist/plugins/walrus/storage-nodes.mjs +53 -14
  483. package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
  484. package/dist/plugins/walrus/wal-swap.mjs +4 -8
  485. package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
  486. package/dist/primitives/artifact-publisher.mjs.map +1 -1
  487. package/dist/primitives/cache.d.mts +1 -1
  488. package/dist/runtime/docker/client.mjs +47 -3
  489. package/dist/runtime/docker/client.mjs.map +1 -1
  490. package/dist/runtime/docker/container.mjs +37 -57
  491. package/dist/runtime/docker/container.mjs.map +1 -1
  492. package/dist/runtime/docker/errors.mjs.map +1 -1
  493. package/dist/runtime/docker/exec.mjs +2 -2
  494. package/dist/runtime/docker/exec.mjs.map +1 -1
  495. package/dist/runtime/docker/image.mjs +10 -11
  496. package/dist/runtime/docker/image.mjs.map +1 -1
  497. package/dist/runtime/docker/index.mjs +0 -1
  498. package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -1
  499. package/dist/runtime/docker/inventory.mjs +9 -9
  500. package/dist/runtime/docker/inventory.mjs.map +1 -1
  501. package/dist/runtime/docker/labels.mjs +12 -1
  502. package/dist/runtime/docker/labels.mjs.map +1 -1
  503. package/dist/runtime/docker/network.mjs +6 -6
  504. package/dist/runtime/docker/network.mjs.map +1 -1
  505. package/dist/runtime/docker/render-run-args.mjs.map +1 -1
  506. package/dist/runtime/docker/service.mjs +31 -45
  507. package/dist/runtime/docker/service.mjs.map +1 -1
  508. package/dist/runtime/docker/sweep.mjs +14 -64
  509. package/dist/runtime/docker/sweep.mjs.map +1 -1
  510. package/dist/runtime/docker/volume.mjs +1 -1
  511. package/dist/runtime/docker/volume.mjs.map +1 -1
  512. package/dist/runtime/docker/wrap.mjs +14 -2
  513. package/dist/runtime/docker/wrap.mjs.map +1 -1
  514. package/dist/substrate/brand.d.mts +2 -5
  515. package/dist/substrate/brand.mjs +3 -2
  516. package/dist/substrate/brand.mjs.map +1 -1
  517. package/dist/substrate/cross-process.mjs +2 -16
  518. package/dist/substrate/cross-process.mjs.map +1 -1
  519. package/dist/substrate/event-time.mjs +0 -2
  520. package/dist/substrate/event-time.mjs.map +1 -1
  521. package/dist/substrate/events.d.mts +46 -16
  522. package/dist/substrate/identity.d.mts +11 -5
  523. package/dist/substrate/manifest.d.mts +33 -26
  524. package/dist/substrate/manifest.mjs +8 -3
  525. package/dist/substrate/manifest.mjs.map +1 -1
  526. package/dist/substrate/options.d.mts +33 -4
  527. package/dist/substrate/plugin-ctx.d.mts +70 -0
  528. package/dist/substrate/plugin-ctx.mjs +66 -0
  529. package/dist/substrate/plugin-ctx.mjs.map +1 -0
  530. package/dist/substrate/plugin.d.mts +46 -38
  531. package/dist/substrate/plugin.mjs +13 -9
  532. package/dist/substrate/plugin.mjs.map +1 -1
  533. package/dist/substrate/projection.d.mts +1 -1
  534. package/dist/substrate/runtime/atomic-write.mjs +3 -4
  535. package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
  536. package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
  537. package/dist/substrate/runtime/cache/service.mjs +50 -20
  538. package/dist/substrate/runtime/cache/service.mjs.map +1 -1
  539. package/dist/substrate/runtime/config-validation.mjs.map +1 -1
  540. package/dist/substrate/runtime/control-plane/domain.mjs +34 -12
  541. package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -1
  542. package/dist/substrate/runtime/control-plane/service.mjs.map +1 -1
  543. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +14 -17
  544. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
  545. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
  546. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
  547. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -1
  548. package/dist/substrate/runtime/cross-process/index.mjs +0 -2
  549. package/dist/substrate/runtime/cross-process/live-clock.mjs +1 -1
  550. package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -1
  551. package/dist/substrate/runtime/cross-process/liveness.mjs +11 -18
  552. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  553. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +2 -2
  554. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -1
  555. package/dist/substrate/runtime/cross-process/roster.mjs +17 -127
  556. package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
  557. package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -1
  558. package/dist/substrate/runtime/cross-process/stack-lock.mjs +29 -28
  559. package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
  560. package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
  561. package/dist/substrate/runtime/errors.mjs +1 -13
  562. package/dist/substrate/runtime/errors.mjs.map +1 -1
  563. package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -1
  564. package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -1
  565. package/dist/substrate/runtime/host-gateway.mjs.map +1 -1
  566. package/dist/substrate/runtime/host-tree-tar/index.mjs +15 -163
  567. package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
  568. package/dist/substrate/runtime/http-probe.d.mts +1 -3
  569. package/dist/substrate/runtime/http-probe.mjs.map +1 -1
  570. package/dist/substrate/runtime/index.mjs +1 -6
  571. package/dist/substrate/runtime/lease-broker/service.mjs +5 -23
  572. package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
  573. package/dist/substrate/runtime/lifecycle/dep-graph.mjs +3 -3
  574. package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
  575. package/dist/substrate/runtime/lifecycle/graph-input-id.d.mts +1 -0
  576. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs +133 -0
  577. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs.map +1 -0
  578. package/dist/substrate/runtime/lifecycle/index.mjs +2 -2
  579. package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -1
  580. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +22 -1
  581. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
  582. package/dist/substrate/runtime/lifecycle/ready-gate.mjs +2 -15
  583. package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -1
  584. package/dist/substrate/runtime/lifecycle/selective-restart.mjs +29 -25
  585. package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -1
  586. package/dist/substrate/runtime/lifecycle/signals.mjs +1 -1
  587. package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
  588. package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -1
  589. package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -1
  590. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +0 -1
  591. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
  592. package/dist/substrate/runtime/managed-container.d.mts +5 -1
  593. package/dist/substrate/runtime/managed-container.mjs +8 -10
  594. package/dist/substrate/runtime/managed-container.mjs.map +1 -1
  595. package/dist/substrate/runtime/manifest/manifest.mjs +8 -30
  596. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  597. package/dist/substrate/runtime/mode-errors.d.mts +1 -2
  598. package/dist/substrate/runtime/mode-errors.mjs.map +1 -1
  599. package/dist/substrate/runtime/observability/cascade-formatter.mjs +1 -11
  600. package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
  601. package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -1
  602. package/dist/substrate/runtime/observability/index.d.mts +1 -1
  603. package/dist/substrate/runtime/observability/index.mjs +4 -6
  604. package/dist/substrate/runtime/observability/log-attrs.mjs +46 -0
  605. package/dist/substrate/runtime/observability/log-attrs.mjs.map +1 -0
  606. package/dist/substrate/runtime/observability/log-store.mjs.map +1 -1
  607. package/dist/substrate/runtime/observability/logger.mjs +3 -3
  608. package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
  609. package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -1
  610. package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
  611. package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -1
  612. package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
  613. package/dist/substrate/runtime/observability/subprocess-capture.mjs +2 -2
  614. package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -1
  615. package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -1
  616. package/dist/substrate/runtime/paths.mjs +27 -9
  617. package/dist/substrate/runtime/paths.mjs.map +1 -1
  618. package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -1
  619. package/dist/substrate/runtime/port-broker/service.mjs +10 -27
  620. package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
  621. package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
  622. package/dist/substrate/runtime/probes.d.mts +2 -3
  623. package/dist/substrate/runtime/probes.mjs.map +1 -1
  624. package/dist/substrate/runtime/process-supervisor.mjs.map +1 -1
  625. package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
  626. package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
  627. package/dist/substrate/runtime/projection/update.mjs +87 -11
  628. package/dist/substrate/runtime/projection/update.mjs.map +1 -1
  629. package/dist/substrate/runtime/random-suffix.mjs.map +1 -1
  630. package/dist/substrate/runtime/reconcile/fs-plan.mjs +146 -0
  631. package/dist/substrate/runtime/reconcile/fs-plan.mjs.map +1 -0
  632. package/dist/substrate/runtime/reconcile/graph.mjs +19 -0
  633. package/dist/substrate/runtime/reconcile/graph.mjs.map +1 -0
  634. package/dist/substrate/runtime/reconcile/index.mjs +5 -0
  635. package/dist/substrate/runtime/reconcile/label.mjs +41 -0
  636. package/dist/substrate/runtime/reconcile/label.mjs.map +1 -0
  637. package/dist/substrate/runtime/reconcile/spec.mjs +15 -0
  638. package/dist/substrate/runtime/reconcile/spec.mjs.map +1 -0
  639. package/dist/substrate/runtime/retry-policy.d.mts +2 -3
  640. package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
  641. package/dist/substrate/runtime/routed-url.mjs.map +1 -1
  642. package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
  643. package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
  644. package/dist/substrate/runtime/stage-and-swap/index.mjs +49 -12
  645. package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
  646. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -1
  647. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
  648. package/dist/substrate/runtime/strategy-registry/service.mjs +29 -17
  649. package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
  650. package/dist/substrate/runtime/subnet-broker.mjs.map +1 -1
  651. package/dist/substrate/runtime/supervisor/acquire-node.mjs +188 -56
  652. package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -1
  653. package/dist/substrate/runtime/supervisor/background-tasks.mjs +79 -65
  654. package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -1
  655. package/dist/substrate/runtime/supervisor/command-loop.mjs +82 -23
  656. package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -1
  657. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs +16 -0
  658. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs.map +1 -0
  659. package/dist/substrate/runtime/supervisor/errors.mjs +11 -2
  660. package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -1
  661. package/dist/substrate/runtime/supervisor/index.mjs +2 -0
  662. package/dist/substrate/runtime/supervisor/shutdown.mjs +6 -6
  663. package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -1
  664. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +60 -70
  665. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
  666. package/dist/substrate/runtime/supervisor/state.d.mts +1 -1
  667. package/dist/substrate/runtime/supervisor/state.mjs +1 -1
  668. package/dist/substrate/runtime/supervisor/state.mjs.map +1 -1
  669. package/dist/substrate/runtime/supervisor/teardown.mjs +10 -9
  670. package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -1
  671. package/dist/substrate/runtime/supervisor/wiring.mjs +6 -20
  672. package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -1
  673. package/dist/substrate/runtime/tar/reader.mjs +216 -0
  674. package/dist/substrate/runtime/tar/reader.mjs.map +1 -0
  675. package/dist/substrate/runtime/typed-env.mjs.map +1 -1
  676. package/dist/substrate/versioned-doc-schema.mjs.map +1 -1
  677. package/dist/substrate/versioned-doc-sync.mjs +5 -5
  678. package/dist/substrate/versioned-doc-sync.mjs.map +1 -1
  679. package/dist/surfaces/cli/command-tree.mjs +49 -7
  680. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  681. package/dist/surfaces/cli/commands/config.mjs +1 -1
  682. package/dist/surfaces/cli/commands/config.mjs.map +1 -1
  683. package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -1
  684. package/dist/surfaces/cli/commands/confirm.mjs.map +1 -1
  685. package/dist/surfaces/cli/commands/doctor.mjs +1 -1
  686. package/dist/surfaces/cli/commands/doctor.mjs.map +1 -1
  687. package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -1
  688. package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
  689. package/dist/surfaces/cli/commands/prune.mjs +1 -1
  690. package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
  691. package/dist/surfaces/cli/commands/snapshot.mjs +1 -1
  692. package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -1
  693. package/dist/surfaces/cli/commands/status.mjs +1 -1
  694. package/dist/surfaces/cli/commands/status.mjs.map +1 -1
  695. package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
  696. package/dist/surfaces/cli/commands/wipe.mjs +3 -4
  697. package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
  698. package/dist/surfaces/cli/envelope.mjs.map +1 -1
  699. package/dist/surfaces/cli/errors.mjs.map +1 -1
  700. package/dist/surfaces/cli/flags.mjs.map +1 -1
  701. package/dist/surfaces/cli/index.mjs +45 -14
  702. package/dist/surfaces/cli/index.mjs.map +1 -1
  703. package/dist/surfaces/cli/output.mjs.map +1 -1
  704. package/dist/surfaces/cli/sysexits.mjs.map +1 -1
  705. package/dist/surfaces/tui/app.mjs +0 -21
  706. package/dist/surfaces/tui/app.mjs.map +1 -1
  707. package/dist/surfaces/tui/dashboard.mjs +0 -48
  708. package/dist/surfaces/tui/dashboard.mjs.map +1 -1
  709. package/dist/surfaces/tui/display-derivation.mjs +80 -16
  710. package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
  711. package/dist/surfaces/tui/errors.mjs.map +1 -1
  712. package/dist/surfaces/tui/event-log.mjs +0 -9
  713. package/dist/surfaces/tui/event-log.mjs.map +1 -1
  714. package/dist/surfaces/tui/heartbeat.mjs.map +1 -1
  715. package/dist/surfaces/tui/index.mjs +2 -2
  716. package/dist/surfaces/tui/index.mjs.map +1 -1
  717. package/dist/surfaces/tui/input.mjs.map +1 -1
  718. package/dist/surfaces/tui/mode-detect.mjs.map +1 -1
  719. package/dist/surfaces/tui/mount-ink.mjs.map +1 -1
  720. package/dist/surfaces/tui/plain-renderer.mjs +26 -19
  721. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  722. package/dist/surfaces/tui/resource-table.mjs +8 -10
  723. package/dist/surfaces/tui/resource-table.mjs.map +1 -1
  724. package/images/postgres/Dockerfile +0 -1
  725. package/images/sui/Dockerfile +27 -54
  726. package/images/sui/entrypoint.sh +17 -179
  727. package/package.json +23 -15
  728. package/dashboard-ui/assets/index-Bmi1UtAg.js +0 -1356
  729. package/dashboard-ui/assets/index-D5EShVt4.js +0 -3
  730. package/dashboard-ui/assets/index-Deml9drg.css +0 -1
  731. package/dist/api/plugin-errors.d.mts +0 -7
  732. package/dist/api/plugin-errors.mjs +0 -10
  733. package/dist/api/plugin-errors.mjs.map +0 -1
  734. package/dist/cli/wirings/build-verb-layers.mjs +0 -42
  735. package/dist/cli/wirings/build-verb-layers.mjs.map +0 -1
  736. package/dist/contracts/capability-decl.d.mts +0 -40
  737. package/dist/orchestrators/built-in-plugin-layers.mjs +0 -54
  738. package/dist/orchestrators/built-in-plugin-layers.mjs.map +0 -1
  739. package/dist/orchestrators/run.mjs +0 -91
  740. package/dist/orchestrators/run.mjs.map +0 -1
  741. package/dist/orchestrators/runtime-composition.d.mts +0 -10
  742. package/dist/orchestrators/runtime-composition.mjs +0 -252
  743. package/dist/orchestrators/runtime-composition.mjs.map +0 -1
  744. package/dist/orchestrators/snapshot/capture-command.d.mts +0 -1
  745. package/dist/orchestrators/snapshot/capture-command.mjs +0 -25
  746. package/dist/orchestrators/snapshot/capture-command.mjs.map +0 -1
  747. package/dist/orchestrators/snapshot/pending-marker.mjs +0 -99
  748. package/dist/orchestrators/snapshot/pending-marker.mjs.map +0 -1
  749. package/dist/orchestrators/snapshot/recover-pending.mjs +0 -223
  750. package/dist/orchestrators/snapshot/recover-pending.mjs.map +0 -1
  751. package/dist/orchestrators/snapshot/state-document.d.mts +0 -1
  752. package/dist/orchestrators/snapshot/state-document.mjs +0 -58
  753. package/dist/orchestrators/snapshot/state-document.mjs.map +0 -1
  754. package/dist/plugins/account/spans.mjs +0 -16
  755. package/dist/plugins/account/spans.mjs.map +0 -1
  756. package/dist/plugins/account/variants/env.mjs +0 -24
  757. package/dist/plugins/account/variants/env.mjs.map +0 -1
  758. package/dist/plugins/account/variants/inline.mjs +0 -13
  759. package/dist/plugins/account/variants/inline.mjs.map +0 -1
  760. package/dist/plugins/account/variants/keystore.mjs +0 -91
  761. package/dist/plugins/account/variants/keystore.mjs.map +0 -1
  762. package/dist/plugins/action/spans.mjs +0 -11
  763. package/dist/plugins/action/spans.mjs.map +0 -1
  764. package/dist/plugins/coin/spans.mjs +0 -20
  765. package/dist/plugins/coin/spans.mjs.map +0 -1
  766. package/dist/plugins/deepbook/spans.mjs +0 -18
  767. package/dist/plugins/deepbook/spans.mjs.map +0 -1
  768. package/dist/plugins/faucet/spans.mjs +0 -12
  769. package/dist/plugins/faucet/spans.mjs.map +0 -1
  770. package/dist/plugins/package/spans.mjs +0 -14
  771. package/dist/plugins/package/spans.mjs.map +0 -1
  772. package/dist/plugins/postgres/codegen.mjs +0 -42
  773. package/dist/plugins/postgres/codegen.mjs.map +0 -1
  774. package/dist/plugins/postgres/connection.d.mts +0 -33
  775. package/dist/plugins/postgres/connection.mjs.map +0 -1
  776. package/dist/plugins/postgres/db-ensure.mjs.map +0 -1
  777. package/dist/plugins/postgres/errors.d.mts +0 -60
  778. package/dist/plugins/postgres/errors.mjs +0 -29
  779. package/dist/plugins/postgres/errors.mjs.map +0 -1
  780. package/dist/plugins/postgres/index.d.mts +0 -37
  781. package/dist/plugins/postgres/index.mjs +0 -68
  782. package/dist/plugins/postgres/index.mjs.map +0 -1
  783. package/dist/plugins/postgres/routable.mjs +0 -33
  784. package/dist/plugins/postgres/routable.mjs.map +0 -1
  785. package/dist/plugins/postgres/service.d.mts +0 -50
  786. package/dist/plugins/postgres/service.mjs +0 -179
  787. package/dist/plugins/postgres/service.mjs.map +0 -1
  788. package/dist/plugins/postgres/snapshot.mjs +0 -32
  789. package/dist/plugins/postgres/snapshot.mjs.map +0 -1
  790. package/dist/plugins/postgres/spans.mjs +0 -11
  791. package/dist/plugins/postgres/spans.mjs.map +0 -1
  792. package/dist/plugins/seal/spans.mjs +0 -18
  793. package/dist/plugins/seal/spans.mjs.map +0 -1
  794. package/dist/plugins/sui/spans.mjs +0 -17
  795. package/dist/plugins/sui/spans.mjs.map +0 -1
  796. package/dist/plugins/wallet/spans.mjs +0 -22
  797. package/dist/plugins/wallet/spans.mjs.map +0 -1
  798. package/dist/plugins/walrus/registry-publish.d.mts +0 -24
  799. package/dist/plugins/walrus/spans.mjs +0 -18
  800. package/dist/plugins/walrus/spans.mjs.map +0 -1
  801. package/dist/runtime/docker/logs.d.mts +0 -1
  802. package/dist/runtime/docker/logs.mjs +0 -34
  803. package/dist/runtime/docker/logs.mjs.map +0 -1
  804. package/dist/substrate/runtime/artifact-publisher/index.mjs +0 -86
  805. package/dist/substrate/runtime/artifact-publisher/index.mjs.map +0 -1
  806. package/dist/substrate/runtime/capability-sinks/index.d.mts +0 -1
  807. package/dist/substrate/runtime/capability-sinks/index.mjs +0 -3
  808. package/dist/substrate/runtime/capability-sinks/layer.d.mts +0 -1
  809. package/dist/substrate/runtime/capability-sinks/layer.mjs +0 -31
  810. package/dist/substrate/runtime/capability-sinks/layer.mjs.map +0 -1
  811. package/dist/substrate/runtime/capability-sinks/service.d.mts +0 -95
  812. package/dist/substrate/runtime/capability-sinks/service.mjs +0 -69
  813. package/dist/substrate/runtime/capability-sinks/service.mjs.map +0 -1
  814. package/dist/substrate/runtime/cross-process/lock.d.mts +0 -1
  815. package/dist/substrate/runtime/cross-process/lock.mjs +0 -23
  816. package/dist/substrate/runtime/cross-process/lock.mjs.map +0 -1
  817. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +0 -113
  818. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +0 -1
  819. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +0 -31
  820. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +0 -1
  821. package/dist/substrate/runtime/observability/formatter-registry.d.mts +0 -1
  822. package/dist/substrate/runtime/observability/formatter-registry.mjs +0 -48
  823. package/dist/substrate/runtime/observability/formatter-registry.mjs.map +0 -1
  824. package/dist/substrate/runtime/observability/span-store.d.mts +0 -1
  825. package/dist/substrate/runtime/observability/span-store.mjs +0 -110
  826. package/dist/substrate/runtime/observability/span-store.mjs.map +0 -1
  827. package/dist/substrate/runtime/observability/spans.d.mts +0 -1
  828. package/dist/substrate/runtime/observability/spans.mjs +0 -87
  829. package/dist/substrate/runtime/observability/spans.mjs.map +0 -1
  830. package/dist/substrate/runtime/projection/index.mjs +0 -4
  831. package/dist/substrate/runtime/projection/persisted.mjs +0 -213
  832. package/dist/substrate/runtime/projection/persisted.mjs.map +0 -1
  833. package/dist/substrate/runtime/scoped-multimap/service.mjs +0 -52
  834. package/dist/substrate/runtime/scoped-multimap/service.mjs.map +0 -1
  835. package/dist/substrate/runtime/scoped-ref-map/index.mjs +0 -2
  836. package/dist/substrate/runtime/scoped-ref-map/service.mjs +0 -83
  837. package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +0 -1
  838. package/dist/substrate/runtime/state-store/index.mjs +0 -3
  839. package/dist/substrate/runtime/state-store/schema.d.mts +0 -1
  840. package/dist/substrate/runtime/state-store/schema.mjs +0 -41
  841. package/dist/substrate/runtime/state-store/schema.mjs.map +0 -1
  842. package/dist/substrate/runtime/state-store/service.d.mts +0 -1
  843. package/dist/substrate/runtime/state-store/service.mjs +0 -145
  844. package/dist/substrate/runtime/state-store/service.mjs.map +0 -1
  845. package/dist/substrate/runtime/sui-execute/index.mjs.map +0 -1
  846. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +0 -1
  847. package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +0 -1
  848. package/dist/substrate/runtime/sui-move-build/index.mjs.map +0 -1
  849. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +0 -151
  850. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +0 -1
  851. package/dist/substrate/state-store.d.mts +0 -1
  852. /package/dist/orchestrators/{snapshot/pending-marker.d.mts → codegen/id-config.d.mts} +0 -0
  853. /package/dist/orchestrators/snapshot/{recover-pending.d.mts → interrupted-restore.d.mts} +0 -0
  854. /package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.d.mts +0 -0
  855. /package/dist/plugins/{postgres/snapshot.d.mts → sui/ledger/object-ref.d.mts} +0 -0
  856. /package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.d.mts +0 -0
  857. /package/dist/substrate/runtime/{state-store/index.d.mts → reconcile/graph.d.mts} +0 -0
  858. /package/dist/substrate/runtime/{cross-process/snapshot-reservation.d.mts → supervisor/contribution-dispatcher.d.mts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"prune-picker.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/prune-picker.tsx"],"sourcesContent":["import { Box, Text, render, useApp, useInput } from 'ink';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { Effect } from 'effect';\n\nimport {\n\tappsWithLiveSiblings,\n\tdefaultPruneSelection,\n\tgroupResourceCountForResources,\n\thasPruneResources,\n\tsummarizePruneGroups,\n\tsummarizePruneGroupsForResources,\n\ttype PruneGroup,\n\ttype PruneInventory,\n\ttype PruneResourceScope,\n\ttype PruneTargetSelection,\n} from './prune.ts';\n\nexport const selectPruneTargets = (\n\tinventory: PruneInventory,\n\tresources: PruneResourceScope,\n): Effect.Effect<PruneTargetSelection> => {\n\tif (inventory.groups.length === 0) return Effect.succeed({ groupKeys: [], resources });\n\treturn Effect.callback<PruneTargetSelection>((resume) => {\n\t\tconst instance = renderPrunePicker({\n\t\t\tinventory,\n\t\t\tresources,\n\t\t\tonSubmit: (selection) => {\n\t\t\t\tinstance.unmount();\n\t\t\t\tresume(Effect.succeed(selection));\n\t\t\t},\n\t\t\tonQuit: () => {\n\t\t\t\tinstance.unmount();\n\t\t\t\tresume(Effect.succeed({ groupKeys: [], resources }));\n\t\t\t},\n\t\t});\n\t});\n};\n\nconst renderPrunePicker = (props: PrunePickerProps) => {\n\treturn render(React.createElement(PrunePicker, props), { exitOnCtrlC: false });\n};\n\ninterface PrunePickerProps {\n\treadonly inventory: PruneInventory;\n\treadonly resources: PruneResourceScope;\n\treadonly onSubmit: (selection: PruneTargetSelection) => void;\n\treadonly onQuit: () => void;\n}\n\nconst PrunePicker = ({\n\tinventory,\n\tresources: initialResources,\n\tonSubmit,\n\tonQuit,\n}: PrunePickerProps): React.JSX.Element => {\n\tconst app = useApp();\n\tconst rows = inventory.groups;\n\tconst [cursor, setCursor] = useState(0);\n\tconst [resources, setResources] = useState<PruneResourceScope>(initialResources);\n\tconst [selected, setSelected] = useState<ReadonlySet<string>>(\n\t\t() => new Set(defaultPruneSelection(inventory, initialResources)),\n\t);\n\tconst [confirming, setConfirming] = useState(false);\n\n\tuseEffect(() => {\n\t\tconst first = rows.findIndex((row) => !row.live);\n\t\tsetCursor(first >= 0 ? first : 0);\n\t\tsetResources(initialResources);\n\t\tsetSelected(new Set(defaultPruneSelection(inventory, initialResources)));\n\t}, [initialResources, inventory, rows]);\n\n\t// Apps with a live non-shared sibling pin their `per-app-shared`\n\t// group (shared chain-build cache &c.). The default `selected` set\n\t// already excludes these via `defaultPruneSelection`; mirroring the\n\t// predicate here keeps manual toggle / select-all from re-adding a\n\t// pinned shared group, matching the orchestrator's enforcement.\n\tconst pinned = useMemo(() => appsWithLiveSiblings(inventory), [inventory]);\n\n\tconst selectable = (row: PruneGroup): boolean =>\n\t\t!row.live && !(row.sharedKind === 'per-app-shared' && pinned.has(row.app));\n\n\tconst move = (dir: 1 | -1): void => {\n\t\tif (rows.length === 0) return;\n\t\tlet next = cursor;\n\t\tfor (let i = 0; i < rows.length; i += 1) {\n\t\t\tnext = (next + dir + rows.length) % rows.length;\n\t\t\tconst row = rows[next];\n\t\t\tif (row !== undefined && selectable(row)) {\n\t\t\t\tsetCursor(next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconst toggle = (): void => {\n\t\tconst row = rows[cursor];\n\t\tif (row === undefined || !selectable(row)) return;\n\t\tconst next = new Set(selected);\n\t\tif (next.has(row.key)) next.delete(row.key);\n\t\telse next.add(row.key);\n\t\tsetSelected(next);\n\t};\n\n\tconst selectAll = (): void => {\n\t\tsetSelected(\n\t\t\tnew Set(\n\t\t\t\trows\n\t\t\t\t\t.filter((row) => selectable(row) && groupResourceCountForResources(row, resources) > 0)\n\t\t\t\t\t.map((row) => row.key),\n\t\t\t),\n\t\t);\n\t};\n\n\tconst toggleResource = (name: keyof PruneResourceScope): void => {\n\t\tsetResources((current) => ({ ...current, [name]: !current[name] }));\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (confirming) {\n\t\t\tif (input === 'y' || input === 'Y') {\n\t\t\t\tapp.exit();\n\t\t\t\tonSubmit({ groupKeys: [...selected], resources });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (input === 'n' || input === 'N' || key.escape || key.return) {\n\t\t\t\tsetConfirming(false);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (input === 'q' || input === 'Q' || (key.ctrl && input === 'c')) {\n\t\t\tapp.exit();\n\t\t\tonQuit();\n\t\t\treturn;\n\t\t}\n\t\tif (key.upArrow || input === 'k') {\n\t\t\tmove(-1);\n\t\t\treturn;\n\t\t}\n\t\tif (key.downArrow || input === 'j') {\n\t\t\tmove(1);\n\t\t\treturn;\n\t\t}\n\t\tif (input === ' ') {\n\t\t\ttoggle();\n\t\t\treturn;\n\t\t}\n\t\tif (input === '1') {\n\t\t\ttoggleResource('containers');\n\t\t\treturn;\n\t\t}\n\t\tif (input === '2') {\n\t\t\ttoggleResource('networks');\n\t\t\treturn;\n\t\t}\n\t\tif (input === '3') {\n\t\t\ttoggleResource('volumes');\n\t\t\treturn;\n\t\t}\n\t\tif (input === '4' || input === 'i' || input === 'I') {\n\t\t\ttoggleResource('images');\n\t\t\treturn;\n\t\t}\n\t\tif (input === 'a' || input === 'A') {\n\t\t\tselectAll();\n\t\t\treturn;\n\t\t}\n\t\tif (input === 'n' || input === 'N') {\n\t\t\tsetSelected(new Set());\n\t\t\treturn;\n\t\t}\n\t\tif (\n\t\t\tkey.return &&\n\t\t\tselected.size > 0 &&\n\t\t\thasPruneResources(resources) &&\n\t\t\tselectedResourceCount(rows, selected, resources) > 0\n\t\t) {\n\t\t\tsetConfirming(true);\n\t\t}\n\t});\n\n\tconst selectedRows = useMemo(() => rows.filter((row) => selected.has(row.key)), [rows, selected]);\n\tconst selectedTotals = useMemo(\n\t\t() => summarizePruneGroupsForResources(selectedRows, resources),\n\t\t[selectedRows, resources],\n\t);\n\tconst idleTotals = summarizePruneGroupsForResources(\n\t\trows.filter((row) => !row.live),\n\t\tresources,\n\t);\n\tconst allIdleTotals = summarizePruneGroups(rows.filter((row) => !row.live));\n\tconst effectiveSelectedCount =\n\t\tselectedTotals.containers +\n\t\tselectedTotals.networks +\n\t\tselectedTotals.volumes +\n\t\tselectedTotals.images;\n\n\treturn (\n\t\t<Box flexDirection=\"column\">\n\t\t\t<Box paddingX={1} borderStyle=\"round\" borderColor=\"gray\">\n\t\t\t\t<Text bold>devstack prune</Text>\n\t\t\t\t<Text dimColor>\n\t\t\t\t\t{' '}\n\t\t\t\t\t{rows.length} group(s), {idleTotals.containers} container(s), {idleTotals.networks}{' '}\n\t\t\t\t\tnetwork(s), {idleTotals.volumes} volume(s), {idleTotals.images} image(s)\n\t\t\t\t</Text>\n\t\t\t</Box>\n\t\t\t<ResourceScopeRow resources={resources} totals={allIdleTotals} />\n\t\t\t<Box flexDirection=\"column\" paddingX={1}>\n\t\t\t\t{rows.map((row, index) => (\n\t\t\t\t\t<PruneRow\n\t\t\t\t\t\tkey={row.key}\n\t\t\t\t\t\trow={row}\n\t\t\t\t\t\tresources={resources}\n\t\t\t\t\t\tfocused={index === cursor}\n\t\t\t\t\t\tchecked={selected.has(row.key)}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</Box>\n\t\t\t{confirming ? (\n\t\t\t\t<Box paddingX={1} marginTop={1} flexDirection=\"column\">\n\t\t\t\t\t<Text>\n\t\t\t\t\t\tWill remove {selectedRows.length} group(s): {selectedTotals.containers} container(s),{' '}\n\t\t\t\t\t\t{selectedTotals.networks} network(s), {selectedTotals.volumes} volume(s),{' '}\n\t\t\t\t\t\t{selectedTotals.images} image(s).\n\t\t\t\t\t</Text>\n\t\t\t\t\t<Text color=\"yellow\">Proceed? [y/N]</Text>\n\t\t\t\t</Box>\n\t\t\t) : (\n\t\t\t\t<Box paddingX={1} marginTop={1} flexDirection=\"column\">\n\t\t\t\t\t{!hasPruneResources(resources) ? (\n\t\t\t\t\t\t<Text color=\"yellow\">Enable at least one resource type.</Text>\n\t\t\t\t\t) : selected.size > 0 && effectiveSelectedCount === 0 ? (\n\t\t\t\t\t\t<Text color=\"yellow\">Selected groups have no enabled resource types.</Text>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<Text dimColor>\n\t\t\t\t\t\t[space] toggle row [1-4] resources [a] all [n] none [enter] prune selected [q]uit\n\t\t\t\t\t</Text>\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t</Box>\n\t);\n};\n\nconst selectedResourceCount = (\n\trows: ReadonlyArray<PruneGroup>,\n\tselected: ReadonlySet<string>,\n\tresources: PruneResourceScope,\n): number =>\n\trows\n\t\t.filter((row) => selected.has(row.key))\n\t\t.reduce((total, row) => total + groupResourceCountForResources(row, resources), 0);\n\nconst ResourceScopeRow = ({\n\tresources,\n\ttotals,\n}: {\n\treadonly resources: PruneResourceScope;\n\treadonly totals: ReturnType<typeof summarizePruneGroups>;\n}): React.JSX.Element => (\n\t<Box paddingX={1}>\n\t\t<Text dimColor>resources </Text>\n\t\t<ResourceToggle\n\t\t\tactive={resources.containers}\n\t\t\tindex=\"1\"\n\t\t\tlabel=\"containers\"\n\t\t\tcount={totals.containers}\n\t\t/>\n\t\t<Text> </Text>\n\t\t<ResourceToggle\n\t\t\tactive={resources.networks}\n\t\t\tindex=\"2\"\n\t\t\tlabel=\"networks\"\n\t\t\tcount={totals.networks}\n\t\t/>\n\t\t<Text> </Text>\n\t\t<ResourceToggle active={resources.volumes} index=\"3\" label=\"volumes\" count={totals.volumes} />\n\t\t<Text> </Text>\n\t\t<ResourceToggle active={resources.images} index=\"4\" label=\"images\" count={totals.images} />\n\t</Box>\n);\n\nconst ResourceToggle = ({\n\tactive,\n\tindex,\n\tlabel,\n\tcount,\n}: {\n\treadonly active: boolean;\n\treadonly index: string;\n\treadonly label: string;\n\treadonly count: number;\n}): React.JSX.Element => (\n\t<Text color={active ? 'green' : 'gray'}>\n\t\t{index}:{active ? '[x]' : '[ ]'} {label}({count})\n\t</Text>\n);\n\nconst PruneRow = ({\n\trow,\n\tresources,\n\tfocused,\n\tchecked,\n}: {\n\treadonly row: PruneGroup;\n\treadonly resources: PruneResourceScope;\n\treadonly focused: boolean;\n\treadonly checked: boolean;\n}): React.JSX.Element => {\n\tconst cursor = focused ? '>' : ' ';\n\tconst box = row.live ? '[-]' : checked ? '[x]' : '[ ]';\n\tconst state = row.live ? `live pid ${row.livePids.join(',')}` : row.shared ? 'shared' : 'idle';\n\tconst color = row.live ? 'red' : focused ? 'cyan' : row.shared ? 'yellow' : undefined;\n\tconst running = row.runningContainers > 0 ? `, ${row.runningContainers} running` : '';\n\treturn (\n\t\t<Box>\n\t\t\t<Text color={color} bold={focused || row.shared}>\n\t\t\t\t{cursor} {box} {row.app}/{row.stack}{' '}\n\t\t\t</Text>\n\t\t\t<Text dimColor>\n\t\t\t\t{state}\n\t\t\t\t{running}{' '}\n\t\t\t</Text>\n\t\t\t<ResourceCount active={resources.containers} count={row.containers} label=\"ctr\" />\n\t\t\t<Text dimColor>, </Text>\n\t\t\t<ResourceCount active={resources.networks} count={row.networks} label=\"net\" />\n\t\t\t<Text dimColor>, </Text>\n\t\t\t<ResourceCount active={resources.volumes} count={row.volumes} label=\"vol\" />\n\t\t\t<Text dimColor>, </Text>\n\t\t\t<ResourceCount active={resources.images} count={row.images} label=\"img\" />\n\t\t</Box>\n\t);\n};\n\nconst ResourceCount = ({\n\tactive,\n\tcount,\n\tlabel,\n}: {\n\treadonly active: boolean;\n\treadonly count: number;\n\treadonly label: string;\n}): React.JSX.Element => (\n\t<Text color={active ? undefined : 'gray'}>\n\t\t{count} {label}\n\t</Text>\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"prune-picker.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/prune-picker.tsx"],"sourcesContent":["import { Box, Text, render, useApp, useInput } from 'ink';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport { Effect } from 'effect';\n\nimport {\n\tappsWithLiveSiblings,\n\tdefaultPruneSelection,\n\tgroupResourceCountForResources,\n\thasPruneResources,\n\tsummarizePruneGroups,\n\tsummarizePruneGroupsForResources,\n\ttype PruneGroup,\n\ttype PruneInventory,\n\ttype PruneResourceScope,\n\ttype PruneTargetSelection,\n} from './prune.ts';\n\nexport const selectPruneTargets = (\n\tinventory: PruneInventory,\n\tresources: PruneResourceScope,\n): Effect.Effect<PruneTargetSelection> => {\n\tif (inventory.groups.length === 0) return Effect.succeed({ groupKeys: [], resources });\n\treturn Effect.callback<PruneTargetSelection>((resume) => {\n\t\tconst instance = renderPrunePicker({\n\t\t\tinventory,\n\t\t\tresources,\n\t\t\tonSubmit: (selection) => {\n\t\t\t\tinstance.unmount();\n\t\t\t\tresume(Effect.succeed(selection));\n\t\t\t},\n\t\t\tonQuit: () => {\n\t\t\t\tinstance.unmount();\n\t\t\t\tresume(Effect.succeed({ groupKeys: [], resources }));\n\t\t\t},\n\t\t});\n\t});\n};\n\nconst renderPrunePicker = (props: PrunePickerProps) => {\n\treturn render(React.createElement(PrunePicker, props), { exitOnCtrlC: false });\n};\n\ninterface PrunePickerProps {\n\treadonly inventory: PruneInventory;\n\treadonly resources: PruneResourceScope;\n\treadonly onSubmit: (selection: PruneTargetSelection) => void;\n\treadonly onQuit: () => void;\n}\n\nconst PrunePicker = ({\n\tinventory,\n\tresources: initialResources,\n\tonSubmit,\n\tonQuit,\n}: PrunePickerProps): React.JSX.Element => {\n\tconst app = useApp();\n\tconst rows = inventory.groups;\n\tconst [cursor, setCursor] = useState(0);\n\tconst [resources, setResources] = useState<PruneResourceScope>(initialResources);\n\tconst [selected, setSelected] = useState<ReadonlySet<string>>(\n\t\t() => new Set(defaultPruneSelection(inventory, initialResources)),\n\t);\n\tconst [confirming, setConfirming] = useState(false);\n\n\tuseEffect(() => {\n\t\tconst first = rows.findIndex((row) => !row.live);\n\t\tsetCursor(first >= 0 ? first : 0);\n\t\tsetResources(initialResources);\n\t\tsetSelected(new Set(defaultPruneSelection(inventory, initialResources)));\n\t}, [initialResources, inventory, rows]);\n\n\t// Apps with a live non-shared sibling pin their `per-app-shared`\n\t// group (shared chain-build cache &c.). The default `selected` set\n\t// already excludes these via `defaultPruneSelection`; mirroring the\n\t// predicate here keeps manual toggle / select-all from re-adding a\n\t// pinned shared group, matching the orchestrator's enforcement.\n\tconst pinned = useMemo(() => appsWithLiveSiblings(inventory), [inventory]);\n\n\tconst selectable = (row: PruneGroup): boolean =>\n\t\t!row.live && !(row.sharedKind === 'per-app-shared' && pinned.has(row.app));\n\n\tconst move = (dir: 1 | -1): void => {\n\t\tif (rows.length === 0) return;\n\t\tlet next = cursor;\n\t\tfor (let i = 0; i < rows.length; i += 1) {\n\t\t\tnext = (next + dir + rows.length) % rows.length;\n\t\t\tconst row = rows[next];\n\t\t\tif (row !== undefined && selectable(row)) {\n\t\t\t\tsetCursor(next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconst toggle = (): void => {\n\t\tconst row = rows[cursor];\n\t\tif (row === undefined || !selectable(row)) return;\n\t\tconst next = new Set(selected);\n\t\tif (next.has(row.key)) next.delete(row.key);\n\t\telse next.add(row.key);\n\t\tsetSelected(next);\n\t};\n\n\tconst selectAll = (): void => {\n\t\tsetSelected(\n\t\t\tnew Set(\n\t\t\t\trows\n\t\t\t\t\t.filter((row) => selectable(row) && groupResourceCountForResources(row, resources) > 0)\n\t\t\t\t\t.map((row) => row.key),\n\t\t\t),\n\t\t);\n\t};\n\n\tconst toggleResource = (name: keyof PruneResourceScope): void => {\n\t\tsetResources((current) => ({ ...current, [name]: !current[name] }));\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (confirming) {\n\t\t\tif (input === 'y' || input === 'Y') {\n\t\t\t\tapp.exit();\n\t\t\t\tonSubmit({ groupKeys: [...selected], resources });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (input === 'n' || input === 'N' || key.escape || key.return) {\n\t\t\t\tsetConfirming(false);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (input === 'q' || input === 'Q' || (key.ctrl && input === 'c')) {\n\t\t\tapp.exit();\n\t\t\tonQuit();\n\t\t\treturn;\n\t\t}\n\t\tif (key.upArrow || input === 'k') {\n\t\t\tmove(-1);\n\t\t\treturn;\n\t\t}\n\t\tif (key.downArrow || input === 'j') {\n\t\t\tmove(1);\n\t\t\treturn;\n\t\t}\n\t\tif (input === ' ') {\n\t\t\ttoggle();\n\t\t\treturn;\n\t\t}\n\t\tif (input === '1') {\n\t\t\ttoggleResource('containers');\n\t\t\treturn;\n\t\t}\n\t\tif (input === '2') {\n\t\t\ttoggleResource('networks');\n\t\t\treturn;\n\t\t}\n\t\tif (input === '3') {\n\t\t\ttoggleResource('volumes');\n\t\t\treturn;\n\t\t}\n\t\tif (input === '4' || input === 'i' || input === 'I') {\n\t\t\ttoggleResource('images');\n\t\t\treturn;\n\t\t}\n\t\tif (input === 'a' || input === 'A') {\n\t\t\tselectAll();\n\t\t\treturn;\n\t\t}\n\t\tif (input === 'n' || input === 'N') {\n\t\t\tsetSelected(new Set());\n\t\t\treturn;\n\t\t}\n\t\tif (\n\t\t\tkey.return &&\n\t\t\tselected.size > 0 &&\n\t\t\thasPruneResources(resources) &&\n\t\t\tselectedResourceCount(rows, selected, resources) > 0\n\t\t) {\n\t\t\tsetConfirming(true);\n\t\t}\n\t});\n\n\tconst selectedRows = useMemo(() => rows.filter((row) => selected.has(row.key)), [rows, selected]);\n\tconst selectedTotals = useMemo(\n\t\t() => summarizePruneGroupsForResources(selectedRows, resources),\n\t\t[selectedRows, resources],\n\t);\n\tconst idleTotals = summarizePruneGroupsForResources(\n\t\trows.filter((row) => !row.live),\n\t\tresources,\n\t);\n\tconst allIdleTotals = summarizePruneGroups(rows.filter((row) => !row.live));\n\tconst effectiveSelectedCount =\n\t\tselectedTotals.containers +\n\t\tselectedTotals.networks +\n\t\tselectedTotals.volumes +\n\t\tselectedTotals.images;\n\n\treturn (\n\t\t<Box flexDirection=\"column\">\n\t\t\t<Box paddingX={1} borderStyle=\"round\" borderColor=\"gray\">\n\t\t\t\t<Text bold>devstack prune</Text>\n\t\t\t\t<Text dimColor>\n\t\t\t\t\t{' '}\n\t\t\t\t\t{rows.length} group(s), {idleTotals.containers} container(s), {idleTotals.networks}{' '}\n\t\t\t\t\tnetwork(s), {idleTotals.volumes} volume(s), {idleTotals.images} image(s)\n\t\t\t\t</Text>\n\t\t\t</Box>\n\t\t\t<ResourceScopeRow resources={resources} totals={allIdleTotals} />\n\t\t\t<Box flexDirection=\"column\" paddingX={1}>\n\t\t\t\t{rows.map((row, index) => (\n\t\t\t\t\t<PruneRow\n\t\t\t\t\t\tkey={row.key}\n\t\t\t\t\t\trow={row}\n\t\t\t\t\t\tresources={resources}\n\t\t\t\t\t\tfocused={index === cursor}\n\t\t\t\t\t\tchecked={selected.has(row.key)}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</Box>\n\t\t\t{confirming ? (\n\t\t\t\t<Box paddingX={1} marginTop={1} flexDirection=\"column\">\n\t\t\t\t\t<Text>\n\t\t\t\t\t\tWill remove {selectedRows.length} group(s): {selectedTotals.containers} container(s),{' '}\n\t\t\t\t\t\t{selectedTotals.networks} network(s), {selectedTotals.volumes} volume(s),{' '}\n\t\t\t\t\t\t{selectedTotals.images} image(s).\n\t\t\t\t\t</Text>\n\t\t\t\t\t<Text color=\"yellow\">Proceed? [y/N]</Text>\n\t\t\t\t</Box>\n\t\t\t) : (\n\t\t\t\t<Box paddingX={1} marginTop={1} flexDirection=\"column\">\n\t\t\t\t\t{!hasPruneResources(resources) ? (\n\t\t\t\t\t\t<Text color=\"yellow\">Enable at least one resource type.</Text>\n\t\t\t\t\t) : selected.size > 0 && effectiveSelectedCount === 0 ? (\n\t\t\t\t\t\t<Text color=\"yellow\">Selected groups have no enabled resource types.</Text>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<Text dimColor>\n\t\t\t\t\t\t[space] toggle row [1-4] resources [a] all [n] none [enter] prune selected [q]uit\n\t\t\t\t\t</Text>\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t</Box>\n\t);\n};\n\nconst selectedResourceCount = (\n\trows: ReadonlyArray<PruneGroup>,\n\tselected: ReadonlySet<string>,\n\tresources: PruneResourceScope,\n): number =>\n\trows\n\t\t.filter((row) => selected.has(row.key))\n\t\t.reduce((total, row) => total + groupResourceCountForResources(row, resources), 0);\n\nconst ResourceScopeRow = ({\n\tresources,\n\ttotals,\n}: {\n\treadonly resources: PruneResourceScope;\n\treadonly totals: ReturnType<typeof summarizePruneGroups>;\n}): React.JSX.Element => (\n\t<Box paddingX={1}>\n\t\t<Text dimColor>resources </Text>\n\t\t<ResourceToggle\n\t\t\tactive={resources.containers}\n\t\t\tindex=\"1\"\n\t\t\tlabel=\"containers\"\n\t\t\tcount={totals.containers}\n\t\t/>\n\t\t<Text> </Text>\n\t\t<ResourceToggle\n\t\t\tactive={resources.networks}\n\t\t\tindex=\"2\"\n\t\t\tlabel=\"networks\"\n\t\t\tcount={totals.networks}\n\t\t/>\n\t\t<Text> </Text>\n\t\t<ResourceToggle active={resources.volumes} index=\"3\" label=\"volumes\" count={totals.volumes} />\n\t\t<Text> </Text>\n\t\t<ResourceToggle active={resources.images} index=\"4\" label=\"images\" count={totals.images} />\n\t</Box>\n);\n\nconst ResourceToggle = ({\n\tactive,\n\tindex,\n\tlabel,\n\tcount,\n}: {\n\treadonly active: boolean;\n\treadonly index: string;\n\treadonly label: string;\n\treadonly count: number;\n}): React.JSX.Element => (\n\t<Text color={active ? 'green' : 'gray'}>\n\t\t{index}:{active ? '[x]' : '[ ]'} {label}({count})\n\t</Text>\n);\n\nconst PruneRow = ({\n\trow,\n\tresources,\n\tfocused,\n\tchecked,\n}: {\n\treadonly row: PruneGroup;\n\treadonly resources: PruneResourceScope;\n\treadonly focused: boolean;\n\treadonly checked: boolean;\n}): React.JSX.Element => {\n\tconst cursor = focused ? '>' : ' ';\n\tconst box = row.live ? '[-]' : checked ? '[x]' : '[ ]';\n\tconst state = row.live ? `live pid ${row.livePids.join(',')}` : row.shared ? 'shared' : 'idle';\n\tconst color = row.live ? 'red' : focused ? 'cyan' : row.shared ? 'yellow' : undefined;\n\tconst running = row.runningContainers > 0 ? `, ${row.runningContainers} running` : '';\n\treturn (\n\t\t<Box>\n\t\t\t<Text color={color} bold={focused || row.shared}>\n\t\t\t\t{cursor} {box} {row.app}/{row.stack}{' '}\n\t\t\t</Text>\n\t\t\t<Text dimColor>\n\t\t\t\t{state}\n\t\t\t\t{running}{' '}\n\t\t\t</Text>\n\t\t\t<ResourceCount active={resources.containers} count={row.containers} label=\"ctr\" />\n\t\t\t<Text dimColor>, </Text>\n\t\t\t<ResourceCount active={resources.networks} count={row.networks} label=\"net\" />\n\t\t\t<Text dimColor>, </Text>\n\t\t\t<ResourceCount active={resources.volumes} count={row.volumes} label=\"vol\" />\n\t\t\t<Text dimColor>, </Text>\n\t\t\t<ResourceCount active={resources.images} count={row.images} label=\"img\" />\n\t\t</Box>\n\t);\n};\n\nconst ResourceCount = ({\n\tactive,\n\tcount,\n\tlabel,\n}: {\n\treadonly active: boolean;\n\treadonly count: number;\n\treadonly label: string;\n}): React.JSX.Element => (\n\t<Text color={active ? undefined : 'gray'}>\n\t\t{count} {label}\n\t</Text>\n);\n"],"mappings":"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"}
@@ -188,7 +188,7 @@ const runPrune = (deps, ctx, options = {
188
188
  humanLines: completedLines(outcome.summary, ctx.flags.dryRun)
189
189
  });
190
190
  return { exitCode: 0 };
191
- }).pipe(Effect.withSpan("cli.prune"));
191
+ });
192
192
  //#endregion
193
193
  export { DEFAULT_PRUNE_RESOURCES, appsWithLiveSiblings, defaultPruneSelection, groupResourceCountForResources, hasPruneResources, runPrune, summarizePruneGroups, summarizePruneGroupsForResources };
194
194
 
@@ -1 +1 @@
1
- {"version":3,"file":"prune.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/prune.ts"],"sourcesContent":["// CLI verb: `devstack prune` — cross-stack Docker cleanup.\n//\n// The rewrite initially wired this command to snapshot-catalog prune\n// only. That path can report success while leaving ordinary stale\n// containers, networks, and volumes untouched. This command owns the\n// operator surface; production injects a Docker-label inventory and\n// remover that understand both current labels and pre-rewrite labels.\n\nimport { Effect } from 'effect';\n\nimport {\n\tdefaultLifecyclePruneSelection,\n\tDEFAULT_LIFECYCLE_PRUNE_RESOURCES,\n\tlifecyclePruneAppsWithLiveSiblings,\n\ttype SharedGroupKind,\n} from '../../../orchestrators/lifecycle-prune/index.ts';\nimport {\n\ttype CliError,\n\tCliConfirmRequiredError,\n\tCliInternalError,\n\tCliUsageError,\n\tisCliError,\n} from '../errors.ts';\nimport { emitSuccess } from '../output.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\nexport interface PruneGroup {\n\treadonly key: string;\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly live: boolean;\n\treadonly livePids: ReadonlyArray<number>;\n\treadonly shared: boolean;\n\t/** Discriminator for shared groups — mirrored from the L3 orchestrator\n\t * shape so surfaces never re-derive the `_per-app_` / router-singleton\n\t * predicate. `null` for normal groups. */\n\treadonly sharedKind: SharedGroupKind | null;\n\t/** True when the group represents a router-shared resource set that\n\t * is auto-prunable in non-interactive flows (`devstack prune --all`).\n\t * Computed by the lifecycle-prune orchestrator; surfaces never\n\t * recompute the router-stack naming predicate. */\n\treadonly autoPrunable: boolean;\n\treadonly containers: number;\n\treadonly runningContainers: number;\n\treadonly networks: number;\n\treadonly volumes: number;\n\treadonly images: number;\n}\n\nexport interface PruneTotals {\n\treadonly groups: number;\n\treadonly liveGroups: number;\n\treadonly sharedGroups: number;\n\treadonly containers: number;\n\treadonly runningContainers: number;\n\treadonly networks: number;\n\treadonly volumes: number;\n\treadonly images: number;\n}\n\nexport interface PruneInventory {\n\treadonly groups: ReadonlyArray<PruneGroup>;\n\treadonly totals: PruneTotals;\n}\n\nexport interface PruneResourceScope {\n\treadonly containers: boolean;\n\treadonly networks: boolean;\n\treadonly volumes: boolean;\n\treadonly images: boolean;\n}\n\nexport interface PruneTargetSelection {\n\treadonly groupKeys: ReadonlyArray<string>;\n\treadonly resources: PruneResourceScope;\n}\n\nexport interface PruneSelection extends PruneTargetSelection {\n\treadonly dryRun: boolean;\n}\n\n/** One non-devstack container still holding a network that prune\n * could not remove. Surfaced so the operator can investigate the\n * external holder (typically a test fixture, a sibling project's\n * container, or a manually-attached debugging container). */\nexport interface PruneForeignNetworkHolder {\n\treadonly network: string;\n\treadonly container: { readonly id: string; readonly name: string };\n}\n\n/** Endpoint Docker still tracks on a network even though the owning\n * container is gone and no CLI/API path can remove it. Docker engine\n * bug — only a daemon restart reclaims the network. */\nexport interface PruneStaleNetworkEndpoint {\n\treadonly network: string;\n\treadonly name: string;\n\treadonly id: string;\n}\n\nexport interface PruneSummary {\n\treadonly inspectedGroups: number;\n\treadonly selectedGroups: number;\n\treadonly skippedLiveGroups: number;\n\treadonly containersRemoved: number;\n\treadonly networksRemoved: number;\n\treadonly networksSkipped: number;\n\treadonly volumesRemoved: number;\n\treadonly imagesRemoved: number;\n\t/** Foreign holders surviving network removal. Empty when every\n\t * network came down cleanly or no network removal was attempted. */\n\treadonly foreignNetworkHolders: ReadonlyArray<PruneForeignNetworkHolder>;\n\t/** Stale phantom endpoints requiring a Docker daemon restart to\n\t * reclaim. Empty in the happy path. */\n\treadonly staleNetworkEndpoints: ReadonlyArray<PruneStaleNetworkEndpoint>;\n}\n\nexport type PruneOutcome = { readonly kind: 'completed'; readonly summary: PruneSummary };\n\nexport interface PruneDeps {\n\treadonly inventory: () => Effect.Effect<PruneInventory, unknown>;\n\treadonly prune: (selection: PruneSelection) => Effect.Effect<PruneOutcome, unknown>;\n\treadonly select: (\n\t\tinventory: PruneInventory,\n\t\tresources: PruneResourceScope,\n\t) => Effect.Effect<PruneTargetSelection, unknown>;\n}\n\nexport interface PruneRunOptions {\n\treadonly mode: 'auto' | 'list' | 'all';\n\treadonly resources: PruneResourceScope;\n}\n\n/** L4 mirror of the orchestrator's default resource scope. Re-export\n * rather than redefine so the default never drifts between layers. */\nexport const DEFAULT_PRUNE_RESOURCES: PruneResourceScope = DEFAULT_LIFECYCLE_PRUNE_RESOURCES;\n\nexport const summarizePruneGroups = (groups: ReadonlyArray<PruneGroup>): PruneTotals => {\n\tlet liveGroups = 0;\n\tlet sharedGroups = 0;\n\tlet containers = 0;\n\tlet runningContainers = 0;\n\tlet networks = 0;\n\tlet volumes = 0;\n\tlet images = 0;\n\tfor (const group of groups) {\n\t\tif (group.live) liveGroups += 1;\n\t\tif (group.shared) sharedGroups += 1;\n\t\tcontainers += group.containers;\n\t\trunningContainers += group.runningContainers;\n\t\tnetworks += group.networks;\n\t\tvolumes += group.volumes;\n\t\timages += group.images;\n\t}\n\treturn {\n\t\tgroups: groups.length,\n\t\tliveGroups,\n\t\tsharedGroups,\n\t\tcontainers,\n\t\trunningContainers,\n\t\tnetworks,\n\t\tvolumes,\n\t\timages,\n\t};\n};\n\nexport const summarizePruneGroupsForResources = (\n\tgroups: ReadonlyArray<PruneGroup>,\n\tresources: PruneResourceScope,\n): PruneTotals => {\n\tconst totals = summarizePruneGroups(groups);\n\treturn {\n\t\t...totals,\n\t\tcontainers: resources.containers ? totals.containers : 0,\n\t\trunningContainers: resources.containers ? totals.runningContainers : 0,\n\t\tnetworks: resources.networks ? totals.networks : 0,\n\t\tvolumes: resources.volumes ? totals.volumes : 0,\n\t\timages: resources.images ? totals.images : 0,\n\t};\n};\n\nexport const hasPruneResources = (resources: PruneResourceScope): boolean =>\n\tresources.containers || resources.networks || resources.volumes || resources.images;\n\nexport const groupResourceCountForResources = (\n\tgroup: PruneGroup,\n\tresources: PruneResourceScope,\n): number =>\n\t(resources.containers ? group.containers : 0) +\n\t(resources.networks ? group.networks : 0) +\n\t(resources.volumes ? group.volumes : 0) +\n\t(resources.images ? group.images : 0);\n\n/** L4 mirror — defers to the orchestrator's pinning predicate so the\n * shared-resource rule lives in exactly one place. Exported so the\n * interactive picker enforces the same per-app-shared pinning rule\n * the default selection already obeys (manual toggle / select-all must\n * not add a `per-app-shared` group pinned by a live sibling). */\nexport const appsWithLiveSiblings = (inventory: PruneInventory): ReadonlySet<string> =>\n\tlifecyclePruneAppsWithLiveSiblings(inventory);\n\n/** Delegates to the orchestrator's `defaultLifecyclePruneSelection`.\n * The L4 shape mirrors the L3 shape field-for-field; the surface\n * never reimplements the shared/per-app/router policy. */\nexport const defaultPruneSelection = (\n\tinventory: PruneInventory,\n\tresources: PruneResourceScope = DEFAULT_PRUNE_RESOURCES,\n): ReadonlyArray<string> => defaultLifecyclePruneSelection(inventory, resources);\n\nconst requireBulkConfirm = (verb: string, ctx: CommandContext): Effect.Effect<void, CliError> => {\n\tif (ctx.flags.dryRun) return Effect.void;\n\tif (ctx.flags.confirm.assumeYes) return Effect.void;\n\treturn Effect.fail(\n\t\tnew CliConfirmRequiredError({\n\t\t\tverb,\n\t\t\thint: 'rerun with --yes for non-interactive bulk prune, or omit --all in a TTY to pick rows interactively',\n\t\t}),\n\t);\n};\n\nconst requireInteractive = (ctx: CommandContext): Effect.Effect<void, CliError> => {\n\tif (ctx.flags.confirm.stdinIsTty && !ctx.flags.confirm.forbidPrompt) return Effect.void;\n\treturn Effect.fail(\n\t\tnew CliConfirmRequiredError({\n\t\t\tverb: 'prune',\n\t\t\thint: 'use --list, --dry-run, or --all --yes in non-interactive shells',\n\t\t}),\n\t);\n};\n\nconst formatGroupLine = (group: PruneGroup, pinnedApps: ReadonlySet<string>): string => {\n\tconst state =\n\t\tgroup.live && group.livePids.length > 0\n\t\t\t? `live pid ${group.livePids.join(',')}`\n\t\t\t: group.live\n\t\t\t\t? 'live'\n\t\t\t\t: group.sharedKind === 'per-app-shared'\n\t\t\t\t\t? pinnedApps.has(group.app)\n\t\t\t\t\t\t? 'shared (pinned by live sibling)'\n\t\t\t\t\t\t: 'shared (auto)'\n\t\t\t\t\t: group.shared\n\t\t\t\t\t\t? group.autoPrunable\n\t\t\t\t\t\t\t? 'shared (auto)'\n\t\t\t\t\t\t\t: 'shared'\n\t\t\t\t\t\t: 'idle';\n\tconst running = group.runningContainers > 0 ? `, ${group.runningContainers} running` : '';\n\tconst images = group.images > 0 ? `, ${group.images} image(s)` : '';\n\treturn ` ${group.app}/${group.stack} ${state} ${group.containers} container(s)${running}, ${group.networks} network(s), ${group.volumes} volume(s)${images}`;\n};\n\nconst inventoryLines = (inventory: PruneInventory): ReadonlyArray<string> => {\n\tif (inventory.groups.length === 0) return ['(no devstack-labelled Docker resources)'];\n\tconst pinned = appsWithLiveSiblings(inventory);\n\treturn [\n\t\t`devstack prune inventory: ${inventory.totals.groups} group(s), ${inventory.totals.containers} container(s), ${inventory.totals.networks} network(s), ${inventory.totals.volumes} volume(s), ${inventory.totals.images} image(s)`,\n\t\t...inventory.groups.map((g) => formatGroupLine(g, pinned)),\n\t];\n};\n\nconst completedLines = (summary: PruneSummary, dryRun: boolean): ReadonlyArray<string> => {\n\tconst prefix = dryRun ? '[dry-run] would prune' : 'prune completed';\n\tconst skippedNetworks =\n\t\tsummary.networksSkipped > 0 ? `, ${summary.networksSkipped} network(s) still in use` : '';\n\tconst head = `${prefix}: ${summary.selectedGroups} group(s), ${summary.containersRemoved} container(s), ${summary.networksRemoved} network(s), ${summary.volumesRemoved} volume(s), ${summary.imagesRemoved} image(s), ${summary.skippedLiveGroups} live group(s) skipped${skippedNetworks}`;\n\tconst lines: Array<string> = [head];\n\tif (summary.foreignNetworkHolders.length > 0) {\n\t\tlines.push('foreign network holders:');\n\t\tfor (const h of summary.foreignNetworkHolders) {\n\t\t\tlines.push(` ${h.network} held by ${h.container.name} (${h.container.id.slice(0, 12)})`);\n\t\t}\n\t}\n\tif (summary.staleNetworkEndpoints.length > 0) {\n\t\tlines.push(\n\t\t\t'stale endpoints (Docker engine bug — restart Docker Desktop to reclaim these networks):',\n\t\t);\n\t\tfor (const ep of summary.staleNetworkEndpoints) {\n\t\t\tlines.push(` ${ep.network}: phantom endpoint \"${ep.name}\" (${ep.id.slice(0, 12)})`);\n\t\t}\n\t}\n\treturn lines;\n};\n\nconst mapUnknownPruneError = (cause: unknown): Effect.Effect<never, CliError> =>\n\tisCliError(cause)\n\t\t? Effect.fail(cause)\n\t\t: Effect.fail(new CliInternalError({ message: 'prune failed', cause }));\n\nexport const runPrune = (\n\tdeps: PruneDeps,\n\tctx: CommandContext,\n\toptions: PruneRunOptions = { mode: 'auto', resources: DEFAULT_PRUNE_RESOURCES },\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst inventory = yield* deps.inventory().pipe(Effect.catch(mapUnknownPruneError));\n\n\t\tif (options.mode === 'list') {\n\t\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\t\tcommand: 'prune',\n\t\t\t\telapsedMs: Date.now() - started,\n\t\t\t\tdryRun: true,\n\t\t\t\tdata: { mode: 'list' as const, inventory },\n\t\t\t\thumanLines: inventoryLines(inventory),\n\t\t\t});\n\t\t\treturn { exitCode: 0 } as CommandResult;\n\t\t}\n\n\t\tif (!hasPruneResources(options.resources)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'prune requires at least one resource type',\n\t\t\t\t\thint: 'enable containers, networks, volumes, or images',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tlet selected: PruneTargetSelection;\n\t\tif (ctx.flags.dryRun || options.mode === 'all' || ctx.flags.confirm.assumeYes) {\n\t\t\tyield* requireBulkConfirm('prune', ctx);\n\t\t\tselected = {\n\t\t\t\tgroupKeys: defaultPruneSelection(inventory, options.resources),\n\t\t\t\tresources: options.resources,\n\t\t\t};\n\t\t} else {\n\t\t\tyield* requireInteractive(ctx);\n\t\t\tselected = yield* deps\n\t\t\t\t.select(inventory, options.resources)\n\t\t\t\t.pipe(Effect.catch(mapUnknownPruneError));\n\t\t}\n\n\t\tif (!hasPruneResources(selected.resources)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'prune requires at least one selected resource type',\n\t\t\t\t\thint: 'toggle at least one resource type before confirming',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tif (selected.groupKeys.length === 0) {\n\t\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\t\tcommand: 'prune',\n\t\t\t\telapsedMs: Date.now() - started,\n\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t\tdata: {\n\t\t\t\t\tmode: options.mode,\n\t\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t\t\tinventory,\n\t\t\t\t\tselection: selected,\n\t\t\t\t\toutcome: {\n\t\t\t\t\t\tkind: 'completed' as const,\n\t\t\t\t\t\tsummary: {\n\t\t\t\t\t\t\tinspectedGroups: inventory.groups.length,\n\t\t\t\t\t\t\tselectedGroups: 0,\n\t\t\t\t\t\t\tskippedLiveGroups: inventory.totals.liveGroups,\n\t\t\t\t\t\t\tcontainersRemoved: 0,\n\t\t\t\t\t\t\tnetworksRemoved: 0,\n\t\t\t\t\t\t\tnetworksSkipped: 0,\n\t\t\t\t\t\t\tvolumesRemoved: 0,\n\t\t\t\t\t\t\timagesRemoved: 0,\n\t\t\t\t\t\t\tforeignNetworkHolders: [],\n\t\t\t\t\t\t\tstaleNetworkEndpoints: [],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\thumanLines: ['prune: no idle resource groups selected'],\n\t\t\t});\n\t\t\treturn { exitCode: 0 } as CommandResult;\n\t\t}\n\n\t\tconst outcome = yield* deps\n\t\t\t.prune({\n\t\t\t\tgroupKeys: selected.groupKeys,\n\t\t\t\tresources: selected.resources,\n\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t})\n\t\t\t.pipe(Effect.catch(mapUnknownPruneError));\n\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'prune',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\tdata: {\n\t\t\t\tmode: options.mode,\n\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t\tinventory,\n\t\t\t\tselection: selected,\n\t\t\t\toutcome,\n\t\t\t},\n\t\t\thumanLines: completedLines(outcome.summary, ctx.flags.dryRun),\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t}).pipe(Effect.withSpan('cli.prune'));\n"],"mappings":"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"}
1
+ {"version":3,"file":"prune.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/prune.ts"],"sourcesContent":["// CLI verb: `devstack prune` — cross-stack Docker cleanup.\n//\n// The rewrite initially wired this command to snapshot-catalog prune\n// only. That path can report success while leaving ordinary stale\n// containers, networks, and volumes untouched. This command owns the\n// operator surface; production injects a Docker-label inventory and\n// remover that understand both current labels and pre-rewrite labels.\n\nimport { Effect } from 'effect';\n\nimport {\n\tdefaultLifecyclePruneSelection,\n\tDEFAULT_LIFECYCLE_PRUNE_RESOURCES,\n\tlifecyclePruneAppsWithLiveSiblings,\n\ttype SharedGroupKind,\n} from '../../../orchestrators/lifecycle-prune/index.ts';\nimport {\n\ttype CliError,\n\tCliConfirmRequiredError,\n\tCliInternalError,\n\tCliUsageError,\n\tisCliError,\n} from '../errors.ts';\nimport { emitSuccess } from '../output.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\nexport interface PruneGroup {\n\treadonly key: string;\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly live: boolean;\n\treadonly livePids: ReadonlyArray<number>;\n\treadonly shared: boolean;\n\t/** Discriminator for shared groups — mirrored from the L3 orchestrator\n\t * shape so surfaces never re-derive the `_per-app_` / router-singleton\n\t * predicate. `null` for normal groups. */\n\treadonly sharedKind: SharedGroupKind | null;\n\t/** True when the group represents a router-shared resource set that\n\t * is auto-prunable in non-interactive flows (`devstack prune --all`).\n\t * Computed by the lifecycle-prune orchestrator; surfaces never\n\t * recompute the router-stack naming predicate. */\n\treadonly autoPrunable: boolean;\n\treadonly containers: number;\n\treadonly runningContainers: number;\n\treadonly networks: number;\n\treadonly volumes: number;\n\treadonly images: number;\n}\n\nexport interface PruneTotals {\n\treadonly groups: number;\n\treadonly liveGroups: number;\n\treadonly sharedGroups: number;\n\treadonly containers: number;\n\treadonly runningContainers: number;\n\treadonly networks: number;\n\treadonly volumes: number;\n\treadonly images: number;\n}\n\nexport interface PruneInventory {\n\treadonly groups: ReadonlyArray<PruneGroup>;\n\treadonly totals: PruneTotals;\n}\n\nexport interface PruneResourceScope {\n\treadonly containers: boolean;\n\treadonly networks: boolean;\n\treadonly volumes: boolean;\n\treadonly images: boolean;\n}\n\nexport interface PruneTargetSelection {\n\treadonly groupKeys: ReadonlyArray<string>;\n\treadonly resources: PruneResourceScope;\n}\n\nexport interface PruneSelection extends PruneTargetSelection {\n\treadonly dryRun: boolean;\n}\n\n/** One non-devstack container still holding a network that prune\n * could not remove. Surfaced so the operator can investigate the\n * external holder (typically a test fixture, a sibling project's\n * container, or a manually-attached debugging container). */\nexport interface PruneForeignNetworkHolder {\n\treadonly network: string;\n\treadonly container: { readonly id: string; readonly name: string };\n}\n\n/** Endpoint Docker still tracks on a network even though the owning\n * container is gone and no CLI/API path can remove it. Docker engine\n * bug — only a daemon restart reclaims the network. */\nexport interface PruneStaleNetworkEndpoint {\n\treadonly network: string;\n\treadonly name: string;\n\treadonly id: string;\n}\n\nexport interface PruneSummary {\n\treadonly inspectedGroups: number;\n\treadonly selectedGroups: number;\n\treadonly skippedLiveGroups: number;\n\treadonly containersRemoved: number;\n\treadonly networksRemoved: number;\n\treadonly networksSkipped: number;\n\treadonly volumesRemoved: number;\n\treadonly imagesRemoved: number;\n\t/** Foreign holders surviving network removal. Empty when every\n\t * network came down cleanly or no network removal was attempted. */\n\treadonly foreignNetworkHolders: ReadonlyArray<PruneForeignNetworkHolder>;\n\t/** Stale phantom endpoints requiring a Docker daemon restart to\n\t * reclaim. Empty in the happy path. */\n\treadonly staleNetworkEndpoints: ReadonlyArray<PruneStaleNetworkEndpoint>;\n}\n\nexport type PruneOutcome = { readonly kind: 'completed'; readonly summary: PruneSummary };\n\nexport interface PruneDeps {\n\treadonly inventory: () => Effect.Effect<PruneInventory, unknown>;\n\treadonly prune: (selection: PruneSelection) => Effect.Effect<PruneOutcome, unknown>;\n\treadonly select: (\n\t\tinventory: PruneInventory,\n\t\tresources: PruneResourceScope,\n\t) => Effect.Effect<PruneTargetSelection, unknown>;\n}\n\nexport interface PruneRunOptions {\n\treadonly mode: 'auto' | 'list' | 'all';\n\treadonly resources: PruneResourceScope;\n}\n\n/** L4 mirror of the orchestrator's default resource scope. Re-export\n * rather than redefine so the default never drifts between layers. */\nexport const DEFAULT_PRUNE_RESOURCES: PruneResourceScope = DEFAULT_LIFECYCLE_PRUNE_RESOURCES;\n\nexport const summarizePruneGroups = (groups: ReadonlyArray<PruneGroup>): PruneTotals => {\n\tlet liveGroups = 0;\n\tlet sharedGroups = 0;\n\tlet containers = 0;\n\tlet runningContainers = 0;\n\tlet networks = 0;\n\tlet volumes = 0;\n\tlet images = 0;\n\tfor (const group of groups) {\n\t\tif (group.live) liveGroups += 1;\n\t\tif (group.shared) sharedGroups += 1;\n\t\tcontainers += group.containers;\n\t\trunningContainers += group.runningContainers;\n\t\tnetworks += group.networks;\n\t\tvolumes += group.volumes;\n\t\timages += group.images;\n\t}\n\treturn {\n\t\tgroups: groups.length,\n\t\tliveGroups,\n\t\tsharedGroups,\n\t\tcontainers,\n\t\trunningContainers,\n\t\tnetworks,\n\t\tvolumes,\n\t\timages,\n\t};\n};\n\nexport const summarizePruneGroupsForResources = (\n\tgroups: ReadonlyArray<PruneGroup>,\n\tresources: PruneResourceScope,\n): PruneTotals => {\n\tconst totals = summarizePruneGroups(groups);\n\treturn {\n\t\t...totals,\n\t\tcontainers: resources.containers ? totals.containers : 0,\n\t\trunningContainers: resources.containers ? totals.runningContainers : 0,\n\t\tnetworks: resources.networks ? totals.networks : 0,\n\t\tvolumes: resources.volumes ? totals.volumes : 0,\n\t\timages: resources.images ? totals.images : 0,\n\t};\n};\n\nexport const hasPruneResources = (resources: PruneResourceScope): boolean =>\n\tresources.containers || resources.networks || resources.volumes || resources.images;\n\nexport const groupResourceCountForResources = (\n\tgroup: PruneGroup,\n\tresources: PruneResourceScope,\n): number =>\n\t(resources.containers ? group.containers : 0) +\n\t(resources.networks ? group.networks : 0) +\n\t(resources.volumes ? group.volumes : 0) +\n\t(resources.images ? group.images : 0);\n\n/** L4 mirror — defers to the orchestrator's pinning predicate so the\n * shared-resource rule lives in exactly one place. Exported so the\n * interactive picker enforces the same per-app-shared pinning rule\n * the default selection already obeys (manual toggle / select-all must\n * not add a `per-app-shared` group pinned by a live sibling). */\nexport const appsWithLiveSiblings = (inventory: PruneInventory): ReadonlySet<string> =>\n\tlifecyclePruneAppsWithLiveSiblings(inventory);\n\n/** Delegates to the orchestrator's `defaultLifecyclePruneSelection`.\n * The L4 shape mirrors the L3 shape field-for-field; the surface\n * never reimplements the shared/per-app/router policy. */\nexport const defaultPruneSelection = (\n\tinventory: PruneInventory,\n\tresources: PruneResourceScope = DEFAULT_PRUNE_RESOURCES,\n): ReadonlyArray<string> => defaultLifecyclePruneSelection(inventory, resources);\n\nconst requireBulkConfirm = (verb: string, ctx: CommandContext): Effect.Effect<void, CliError> => {\n\tif (ctx.flags.dryRun) return Effect.void;\n\tif (ctx.flags.confirm.assumeYes) return Effect.void;\n\treturn Effect.fail(\n\t\tnew CliConfirmRequiredError({\n\t\t\tverb,\n\t\t\thint: 'rerun with --yes for non-interactive bulk prune, or omit --all in a TTY to pick rows interactively',\n\t\t}),\n\t);\n};\n\nconst requireInteractive = (ctx: CommandContext): Effect.Effect<void, CliError> => {\n\tif (ctx.flags.confirm.stdinIsTty && !ctx.flags.confirm.forbidPrompt) return Effect.void;\n\treturn Effect.fail(\n\t\tnew CliConfirmRequiredError({\n\t\t\tverb: 'prune',\n\t\t\thint: 'use --list, --dry-run, or --all --yes in non-interactive shells',\n\t\t}),\n\t);\n};\n\nconst formatGroupLine = (group: PruneGroup, pinnedApps: ReadonlySet<string>): string => {\n\tconst state =\n\t\tgroup.live && group.livePids.length > 0\n\t\t\t? `live pid ${group.livePids.join(',')}`\n\t\t\t: group.live\n\t\t\t\t? 'live'\n\t\t\t\t: group.sharedKind === 'per-app-shared'\n\t\t\t\t\t? pinnedApps.has(group.app)\n\t\t\t\t\t\t? 'shared (pinned by live sibling)'\n\t\t\t\t\t\t: 'shared (auto)'\n\t\t\t\t\t: group.shared\n\t\t\t\t\t\t? group.autoPrunable\n\t\t\t\t\t\t\t? 'shared (auto)'\n\t\t\t\t\t\t\t: 'shared'\n\t\t\t\t\t\t: 'idle';\n\tconst running = group.runningContainers > 0 ? `, ${group.runningContainers} running` : '';\n\tconst images = group.images > 0 ? `, ${group.images} image(s)` : '';\n\treturn ` ${group.app}/${group.stack} ${state} ${group.containers} container(s)${running}, ${group.networks} network(s), ${group.volumes} volume(s)${images}`;\n};\n\nconst inventoryLines = (inventory: PruneInventory): ReadonlyArray<string> => {\n\tif (inventory.groups.length === 0) return ['(no devstack-labelled Docker resources)'];\n\tconst pinned = appsWithLiveSiblings(inventory);\n\treturn [\n\t\t`devstack prune inventory: ${inventory.totals.groups} group(s), ${inventory.totals.containers} container(s), ${inventory.totals.networks} network(s), ${inventory.totals.volumes} volume(s), ${inventory.totals.images} image(s)`,\n\t\t...inventory.groups.map((g) => formatGroupLine(g, pinned)),\n\t];\n};\n\nconst completedLines = (summary: PruneSummary, dryRun: boolean): ReadonlyArray<string> => {\n\tconst prefix = dryRun ? '[dry-run] would prune' : 'prune completed';\n\tconst skippedNetworks =\n\t\tsummary.networksSkipped > 0 ? `, ${summary.networksSkipped} network(s) still in use` : '';\n\tconst head = `${prefix}: ${summary.selectedGroups} group(s), ${summary.containersRemoved} container(s), ${summary.networksRemoved} network(s), ${summary.volumesRemoved} volume(s), ${summary.imagesRemoved} image(s), ${summary.skippedLiveGroups} live group(s) skipped${skippedNetworks}`;\n\tconst lines: Array<string> = [head];\n\tif (summary.foreignNetworkHolders.length > 0) {\n\t\tlines.push('foreign network holders:');\n\t\tfor (const h of summary.foreignNetworkHolders) {\n\t\t\tlines.push(` ${h.network} held by ${h.container.name} (${h.container.id.slice(0, 12)})`);\n\t\t}\n\t}\n\tif (summary.staleNetworkEndpoints.length > 0) {\n\t\tlines.push(\n\t\t\t'stale endpoints (Docker engine bug — restart Docker Desktop to reclaim these networks):',\n\t\t);\n\t\tfor (const ep of summary.staleNetworkEndpoints) {\n\t\t\tlines.push(` ${ep.network}: phantom endpoint \"${ep.name}\" (${ep.id.slice(0, 12)})`);\n\t\t}\n\t}\n\treturn lines;\n};\n\nconst mapUnknownPruneError = (cause: unknown): Effect.Effect<never, CliError> =>\n\tisCliError(cause)\n\t\t? Effect.fail(cause)\n\t\t: Effect.fail(new CliInternalError({ message: 'prune failed', cause }));\n\nexport const runPrune = (\n\tdeps: PruneDeps,\n\tctx: CommandContext,\n\toptions: PruneRunOptions = { mode: 'auto', resources: DEFAULT_PRUNE_RESOURCES },\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst inventory = yield* deps.inventory().pipe(Effect.catch(mapUnknownPruneError));\n\n\t\tif (options.mode === 'list') {\n\t\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\t\tcommand: 'prune',\n\t\t\t\telapsedMs: Date.now() - started,\n\t\t\t\tdryRun: true,\n\t\t\t\tdata: { mode: 'list' as const, inventory },\n\t\t\t\thumanLines: inventoryLines(inventory),\n\t\t\t});\n\t\t\treturn { exitCode: 0 } as CommandResult;\n\t\t}\n\n\t\tif (!hasPruneResources(options.resources)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'prune requires at least one resource type',\n\t\t\t\t\thint: 'enable containers, networks, volumes, or images',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tlet selected: PruneTargetSelection;\n\t\tif (ctx.flags.dryRun || options.mode === 'all' || ctx.flags.confirm.assumeYes) {\n\t\t\tyield* requireBulkConfirm('prune', ctx);\n\t\t\tselected = {\n\t\t\t\tgroupKeys: defaultPruneSelection(inventory, options.resources),\n\t\t\t\tresources: options.resources,\n\t\t\t};\n\t\t} else {\n\t\t\tyield* requireInteractive(ctx);\n\t\t\tselected = yield* deps\n\t\t\t\t.select(inventory, options.resources)\n\t\t\t\t.pipe(Effect.catch(mapUnknownPruneError));\n\t\t}\n\n\t\tif (!hasPruneResources(selected.resources)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'prune requires at least one selected resource type',\n\t\t\t\t\thint: 'toggle at least one resource type before confirming',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tif (selected.groupKeys.length === 0) {\n\t\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\t\tcommand: 'prune',\n\t\t\t\telapsedMs: Date.now() - started,\n\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t\tdata: {\n\t\t\t\t\tmode: options.mode,\n\t\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t\t\tinventory,\n\t\t\t\t\tselection: selected,\n\t\t\t\t\toutcome: {\n\t\t\t\t\t\tkind: 'completed' as const,\n\t\t\t\t\t\tsummary: {\n\t\t\t\t\t\t\tinspectedGroups: inventory.groups.length,\n\t\t\t\t\t\t\tselectedGroups: 0,\n\t\t\t\t\t\t\tskippedLiveGroups: inventory.totals.liveGroups,\n\t\t\t\t\t\t\tcontainersRemoved: 0,\n\t\t\t\t\t\t\tnetworksRemoved: 0,\n\t\t\t\t\t\t\tnetworksSkipped: 0,\n\t\t\t\t\t\t\tvolumesRemoved: 0,\n\t\t\t\t\t\t\timagesRemoved: 0,\n\t\t\t\t\t\t\tforeignNetworkHolders: [],\n\t\t\t\t\t\t\tstaleNetworkEndpoints: [],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\thumanLines: ['prune: no idle resource groups selected'],\n\t\t\t});\n\t\t\treturn { exitCode: 0 } as CommandResult;\n\t\t}\n\n\t\tconst outcome = yield* deps\n\t\t\t.prune({\n\t\t\t\tgroupKeys: selected.groupKeys,\n\t\t\t\tresources: selected.resources,\n\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t})\n\t\t\t.pipe(Effect.catch(mapUnknownPruneError));\n\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'prune',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\tdata: {\n\t\t\t\tmode: options.mode,\n\t\t\t\tdryRun: ctx.flags.dryRun,\n\t\t\t\tinventory,\n\t\t\t\tselection: selected,\n\t\t\t\toutcome,\n\t\t\t},\n\t\t\thumanLines: completedLines(outcome.summary, ctx.flags.dryRun),\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n"],"mappings":"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"}
@@ -18,7 +18,7 @@ const runSnapshot = (deps, ctx) => Effect.gen(function* () {
18
18
  hint: "try: snapshot save [name] | restore <name-or-id> | list | delete <name-or-id>"
19
19
  }));
20
20
  }
21
- }).pipe(Effect.withSpan("cli.snapshot"));
21
+ });
22
22
  const runSnapshotSave = (deps, ctx, rest) => Effect.gen(function* () {
23
23
  const started = Date.now();
24
24
  const { value: flagName, tail: afterName } = takeValueFlag(rest, "name");
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/snapshot.ts"],"sourcesContent":["// CLI verb: `devstack snapshot {save|restore|list|delete}`.\n//\n// Architecture (distilled/20-cli.md § Subcommands § Persistence):\n// \"snapshot save / restore / list / delete — capture, rehydrate,\n// enumerate, remove point-in-time captures of a stack.\"\n//\n// Surface-equality: snapshot is a peer command on the typed command\n// channel (`snapshot.capture` / `restore` / `list` / `delete`). The\n// CLI publishes; the L3 snapshot orchestrator (architecture § L3)\n// consumes — same code path for TUI / programmable API.\n\nimport { Effect } from 'effect';\n\nimport {\n\ttype CliError,\n\tCliSnapshotAmbiguousError,\n\tCliInternalError,\n\tCliSnapshotNotFoundError,\n\tCliUsageError,\n\tisCliError,\n} from '../errors.ts';\nimport { takePositional, takeValueFlag } from '../flags.ts';\nimport { emitSuccess } from '../output.ts';\nimport { confirmDestructive, type ConfirmPrompt } from './confirm.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\n/** Snapshot read seam. The list verb reads the catalog without going\n * through the command channel — same observation discipline as\n * `status`: read-only views are equal across surfaces. */\nexport interface SnapshotReader {\n\treadonly list: () => Effect.Effect<ReadonlyArray<SnapshotEntry>>;\n\treadonly resolve: (snapshotRef: string) => Effect.Effect<SnapshotResolveResult>;\n}\n\nexport interface SnapshotEntry {\n\treadonly snapshotId: string;\n\treadonly name: string | null;\n\treadonly createdAt: number;\n\treadonly size: number | null;\n}\n\nexport type SnapshotResolveResult =\n\t| { readonly tag: 'found'; readonly entry: SnapshotEntry }\n\t| { readonly tag: 'not-found' }\n\t| {\n\t\t\treadonly tag: 'ambiguous';\n\t\t\treadonly snapshotRef: string;\n\t\t\treadonly matches: ReadonlyArray<SnapshotEntry>;\n\t };\n\nexport interface SnapshotCaptureResult {\n\treadonly snapshotId: string;\n\treadonly name: string;\n}\n\nexport interface SnapshotDeps {\n\treadonly reader: SnapshotReader;\n\treadonly capture: (args: {\n\t\treadonly snapshotId?: string;\n\t\treadonly name?: string;\n\t\treadonly configPath?: string;\n\t}) => Effect.Effect<SnapshotCaptureResult, unknown>;\n\treadonly restore: (snapshotId: string) => Effect.Effect<void, unknown>;\n\treadonly delete: (snapshotId: string) => Effect.Effect<void, unknown>;\n\treadonly confirm: ConfirmPrompt;\n}\n\n/** Snapshot subcommand dispatcher. `ctx.flags.rest` holds the\n * sub-verb + verb-local arguments. */\nexport const runSnapshot = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst [sub, ...rest] = ctx.flags.rest;\n\t\tswitch (sub) {\n\t\t\tcase 'save':\n\t\t\t\treturn yield* runSnapshotSave(deps, ctx, rest);\n\t\t\tcase 'restore':\n\t\t\t\treturn yield* runSnapshotRestore(deps, ctx, rest);\n\t\t\tcase 'list':\n\t\t\t\treturn yield* runSnapshotList(deps, ctx);\n\t\t\tcase 'delete':\n\t\t\t\treturn yield* runSnapshotDelete(deps, ctx, rest);\n\t\t\tdefault:\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CliUsageError({\n\t\t\t\t\t\tmessage: `unknown snapshot subcommand: ${sub ?? '(missing)'}`,\n\t\t\t\t\t\thint: 'try: snapshot save [name] | restore <name-or-id> | list | delete <name-or-id>',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t}\n\t}).pipe(Effect.withSpan('cli.snapshot'));\n\nconst runSnapshotSave = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n\trest: ReadonlyArray<string>,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst { value: flagName, tail: afterName } = takeValueFlag(rest, 'name');\n\t\tconst { head: positionalName, tail: afterSnapshotName } = takePositional(afterName);\n\t\tconst extra = afterSnapshotName.find((tok) => !tok.startsWith('-'));\n\t\tif (extra !== undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: `unexpected snapshot save argument: ${extra}`,\n\t\t\t\t\thint: 'try: snapshot save [name]',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (flagName !== undefined && positionalName !== undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'snapshot save accepts a name either positionally or with --name, not both',\n\t\t\t\t\thint: 'try: snapshot save [name]',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst name = flagName ?? positionalName;\n\t\tconst captured = yield* deps\n\t\t\t.capture({\n\t\t\t\t...(name === undefined ? {} : { name }),\n\t\t\t\t...(ctx.flags.configPath === undefined ? {} : { configPath: ctx.flags.configPath }),\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\t\tisCliError(cause)\n\t\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t\t: isSnapshotInputError(cause)\n\t\t\t\t\t\t\t? Effect.fail(snapshotInputCliError(cause))\n\t\t\t\t\t\t\t: Effect.fail(new CliInternalError({ message: 'snapshot capture failed', cause })),\n\t\t\t\t),\n\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot save',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: {\n\t\t\t\tsnapshotId: captured.snapshotId,\n\t\t\t\tname: captured.name,\n\t\t\t},\n\t\t\thumanLines: [`snapshot saved ${captured.name} (${captured.snapshotId})`],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\nconst runSnapshotRestore = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n\trest: ReadonlyArray<string>,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst snapshotRef = rest.find((tok) => !tok.startsWith('-'));\n\t\tif (snapshotRef === undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'snapshot restore requires a snapshot name or id',\n\t\t\t\t\thint: 'snapshot list to enumerate available names and ids',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst resolved = yield* deps.reader.resolve(snapshotRef);\n\t\tif (resolved.tag === 'not-found') {\n\t\t\treturn yield* Effect.fail(new CliSnapshotNotFoundError({ snapshotRef }));\n\t\t}\n\t\tif (resolved.tag === 'ambiguous') {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliSnapshotAmbiguousError({\n\t\t\t\t\tsnapshotRef,\n\t\t\t\t\tmatches: resolved.matches.map((entry) => entry.snapshotId),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst entry = resolved.entry;\n\t\tconst snapshotId = entry.snapshotId;\n\t\tyield* confirmDestructive(deps.confirm, ctx, {\n\t\t\tverb: 'snapshot restore',\n\t\t\tprompt:\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `Restore snapshot ${snapshotId} and replace current stack state?`\n\t\t\t\t\t: `Restore snapshot ${entry.name} (${snapshotId}) and replace current stack state?`,\n\t\t\tskipWhenDryRun: false,\n\t\t});\n\t\tyield* deps\n\t\t\t.restore(snapshotId)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\t\tisCliError(cause)\n\t\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t\t: Effect.fail(new CliInternalError({ message: 'snapshot restore failed', cause })),\n\t\t\t\t),\n\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot restore',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: { snapshotId, name: entry.name },\n\t\t\thumanLines: [\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `snapshot restored ${snapshotId}`\n\t\t\t\t\t: `snapshot restored ${entry.name} (${snapshotId})`,\n\t\t\t],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\nconst runSnapshotList = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst entries = yield* deps.reader.list();\n\t\tconst humanLines =\n\t\t\tentries.length === 0\n\t\t\t\t? ['(no snapshots)']\n\t\t\t\t: entries.map(\n\t\t\t\t\t\t(e) =>\n\t\t\t\t\t\t\t`${e.name ?? '(unnamed)'} ${e.snapshotId} ${new Date(e.createdAt).toISOString()}`,\n\t\t\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot list',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: { entries },\n\t\t\thumanLines,\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\nconst runSnapshotDelete = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n\trest: ReadonlyArray<string>,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst snapshotRef = rest.find((tok) => !tok.startsWith('-'));\n\t\tif (snapshotRef === undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({ message: 'snapshot delete requires a snapshot name or id' }),\n\t\t\t);\n\t\t}\n\t\tconst resolved = yield* deps.reader.resolve(snapshotRef);\n\t\tif (resolved.tag === 'not-found') {\n\t\t\treturn yield* Effect.fail(new CliSnapshotNotFoundError({ snapshotRef }));\n\t\t}\n\t\tif (resolved.tag === 'ambiguous') {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliSnapshotAmbiguousError({\n\t\t\t\t\tsnapshotRef,\n\t\t\t\t\tmatches: resolved.matches.map((entry) => entry.snapshotId),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst entry = resolved.entry;\n\t\tconst snapshotId = entry.snapshotId;\n\t\tyield* confirmDestructive(deps.confirm, ctx, {\n\t\t\tverb: 'snapshot delete',\n\t\t\tprompt:\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `Delete snapshot ${snapshotId}?`\n\t\t\t\t\t: `Delete snapshot ${entry.name} (${snapshotId})?`,\n\t\t\tskipWhenDryRun: false,\n\t\t});\n\t\tyield* deps\n\t\t\t.delete(snapshotId)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\t\tisCliError(cause)\n\t\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t\t: Effect.fail(new CliInternalError({ message: 'snapshot delete failed', cause })),\n\t\t\t\t),\n\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot delete',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: { snapshotId, name: entry.name },\n\t\t\thumanLines: [\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `snapshot deleted ${snapshotId}`\n\t\t\t\t\t: `snapshot deleted ${entry.name} (${snapshotId})`,\n\t\t\t],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\ninterface SnapshotInputErrorShape {\n\treadonly _tag: 'SnapshotIdError';\n\treadonly operation: string;\n\treadonly field: string;\n\treadonly value: string;\n\treadonly detail: string;\n}\n\nconst isSnapshotInputError = (value: unknown): value is SnapshotInputErrorShape =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\t(value as { readonly _tag?: unknown })._tag === 'SnapshotIdError';\n\nconst snapshotInputCliError = (error: SnapshotInputErrorShape): CliUsageError =>\n\tnew CliUsageError({\n\t\tmessage: `invalid snapshot ${error.field} for ${error.operation}: ${error.value}`,\n\t\thint: error.detail,\n\t});\n"],"mappings":"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"}
1
+ {"version":3,"file":"snapshot.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/snapshot.ts"],"sourcesContent":["// CLI verb: `devstack snapshot {save|restore|list|delete}`.\n//\n// Architecture (distilled/20-cli.md § Subcommands § Persistence):\n// \"snapshot save / restore / list / delete — capture, rehydrate,\n// enumerate, remove point-in-time captures of a stack.\"\n//\n// Surface-equality: snapshot is a peer command on the typed command\n// channel (`snapshot.capture` / `restore` / `list` / `delete`). The\n// CLI publishes; the L3 snapshot orchestrator (architecture § L3)\n// consumes — same code path for TUI / programmable API.\n\nimport { Effect } from 'effect';\n\nimport {\n\ttype CliError,\n\tCliSnapshotAmbiguousError,\n\tCliInternalError,\n\tCliSnapshotNotFoundError,\n\tCliUsageError,\n\tisCliError,\n} from '../errors.ts';\nimport { takePositional, takeValueFlag } from '../flags.ts';\nimport { emitSuccess } from '../output.ts';\nimport { confirmDestructive, type ConfirmPrompt } from './confirm.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\n/** Snapshot read seam. The list verb reads the catalog without going\n * through the command channel — same observation discipline as\n * `status`: read-only views are equal across surfaces. */\nexport interface SnapshotReader {\n\treadonly list: () => Effect.Effect<ReadonlyArray<SnapshotEntry>>;\n\treadonly resolve: (snapshotRef: string) => Effect.Effect<SnapshotResolveResult>;\n}\n\nexport interface SnapshotEntry {\n\treadonly snapshotId: string;\n\treadonly name: string | null;\n\treadonly createdAt: number;\n\treadonly size: number | null;\n}\n\nexport type SnapshotResolveResult =\n\t| { readonly tag: 'found'; readonly entry: SnapshotEntry }\n\t| { readonly tag: 'not-found' }\n\t| {\n\t\t\treadonly tag: 'ambiguous';\n\t\t\treadonly snapshotRef: string;\n\t\t\treadonly matches: ReadonlyArray<SnapshotEntry>;\n\t };\n\nexport interface SnapshotCaptureResult {\n\treadonly snapshotId: string;\n\treadonly name: string;\n}\n\nexport interface SnapshotDeps {\n\treadonly reader: SnapshotReader;\n\treadonly capture: (args: {\n\t\treadonly snapshotId?: string;\n\t\treadonly name?: string;\n\t\treadonly configPath?: string;\n\t}) => Effect.Effect<SnapshotCaptureResult, unknown>;\n\treadonly restore: (snapshotId: string) => Effect.Effect<void, unknown>;\n\treadonly delete: (snapshotId: string) => Effect.Effect<void, unknown>;\n\treadonly confirm: ConfirmPrompt;\n}\n\n/** Snapshot subcommand dispatcher. `ctx.flags.rest` holds the\n * sub-verb + verb-local arguments. */\nexport const runSnapshot = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst [sub, ...rest] = ctx.flags.rest;\n\t\tswitch (sub) {\n\t\t\tcase 'save':\n\t\t\t\treturn yield* runSnapshotSave(deps, ctx, rest);\n\t\t\tcase 'restore':\n\t\t\t\treturn yield* runSnapshotRestore(deps, ctx, rest);\n\t\t\tcase 'list':\n\t\t\t\treturn yield* runSnapshotList(deps, ctx);\n\t\t\tcase 'delete':\n\t\t\t\treturn yield* runSnapshotDelete(deps, ctx, rest);\n\t\t\tdefault:\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CliUsageError({\n\t\t\t\t\t\tmessage: `unknown snapshot subcommand: ${sub ?? '(missing)'}`,\n\t\t\t\t\t\thint: 'try: snapshot save [name] | restore <name-or-id> | list | delete <name-or-id>',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t}\n\t});\n\nconst runSnapshotSave = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n\trest: ReadonlyArray<string>,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst { value: flagName, tail: afterName } = takeValueFlag(rest, 'name');\n\t\tconst { head: positionalName, tail: afterSnapshotName } = takePositional(afterName);\n\t\tconst extra = afterSnapshotName.find((tok) => !tok.startsWith('-'));\n\t\tif (extra !== undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: `unexpected snapshot save argument: ${extra}`,\n\t\t\t\t\thint: 'try: snapshot save [name]',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (flagName !== undefined && positionalName !== undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'snapshot save accepts a name either positionally or with --name, not both',\n\t\t\t\t\thint: 'try: snapshot save [name]',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst name = flagName ?? positionalName;\n\t\tconst captured = yield* deps\n\t\t\t.capture({\n\t\t\t\t...(name === undefined ? {} : { name }),\n\t\t\t\t...(ctx.flags.configPath === undefined ? {} : { configPath: ctx.flags.configPath }),\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\t\tisCliError(cause)\n\t\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t\t: isSnapshotInputError(cause)\n\t\t\t\t\t\t\t? Effect.fail(snapshotInputCliError(cause))\n\t\t\t\t\t\t\t: Effect.fail(new CliInternalError({ message: 'snapshot capture failed', cause })),\n\t\t\t\t),\n\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot save',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: {\n\t\t\t\tsnapshotId: captured.snapshotId,\n\t\t\t\tname: captured.name,\n\t\t\t},\n\t\t\thumanLines: [`snapshot saved ${captured.name} (${captured.snapshotId})`],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\nconst runSnapshotRestore = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n\trest: ReadonlyArray<string>,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst snapshotRef = rest.find((tok) => !tok.startsWith('-'));\n\t\tif (snapshotRef === undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({\n\t\t\t\t\tmessage: 'snapshot restore requires a snapshot name or id',\n\t\t\t\t\thint: 'snapshot list to enumerate available names and ids',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst resolved = yield* deps.reader.resolve(snapshotRef);\n\t\tif (resolved.tag === 'not-found') {\n\t\t\treturn yield* Effect.fail(new CliSnapshotNotFoundError({ snapshotRef }));\n\t\t}\n\t\tif (resolved.tag === 'ambiguous') {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliSnapshotAmbiguousError({\n\t\t\t\t\tsnapshotRef,\n\t\t\t\t\tmatches: resolved.matches.map((entry) => entry.snapshotId),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst entry = resolved.entry;\n\t\tconst snapshotId = entry.snapshotId;\n\t\tyield* confirmDestructive(deps.confirm, ctx, {\n\t\t\tverb: 'snapshot restore',\n\t\t\tprompt:\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `Restore snapshot ${snapshotId} and replace current stack state?`\n\t\t\t\t\t: `Restore snapshot ${entry.name} (${snapshotId}) and replace current stack state?`,\n\t\t\tskipWhenDryRun: false,\n\t\t});\n\t\tyield* deps\n\t\t\t.restore(snapshotId)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\t\tisCliError(cause)\n\t\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t\t: Effect.fail(new CliInternalError({ message: 'snapshot restore failed', cause })),\n\t\t\t\t),\n\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot restore',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: { snapshotId, name: entry.name },\n\t\t\thumanLines: [\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `snapshot restored ${snapshotId}`\n\t\t\t\t\t: `snapshot restored ${entry.name} (${snapshotId})`,\n\t\t\t],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\nconst runSnapshotList = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst entries = yield* deps.reader.list();\n\t\tconst humanLines =\n\t\t\tentries.length === 0\n\t\t\t\t? ['(no snapshots)']\n\t\t\t\t: entries.map(\n\t\t\t\t\t\t(e) =>\n\t\t\t\t\t\t\t`${e.name ?? '(unnamed)'} ${e.snapshotId} ${new Date(e.createdAt).toISOString()}`,\n\t\t\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot list',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: { entries },\n\t\t\thumanLines,\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\nconst runSnapshotDelete = (\n\tdeps: SnapshotDeps,\n\tctx: CommandContext,\n\trest: ReadonlyArray<string>,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tconst snapshotRef = rest.find((tok) => !tok.startsWith('-'));\n\t\tif (snapshotRef === undefined) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliUsageError({ message: 'snapshot delete requires a snapshot name or id' }),\n\t\t\t);\n\t\t}\n\t\tconst resolved = yield* deps.reader.resolve(snapshotRef);\n\t\tif (resolved.tag === 'not-found') {\n\t\t\treturn yield* Effect.fail(new CliSnapshotNotFoundError({ snapshotRef }));\n\t\t}\n\t\tif (resolved.tag === 'ambiguous') {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CliSnapshotAmbiguousError({\n\t\t\t\t\tsnapshotRef,\n\t\t\t\t\tmatches: resolved.matches.map((entry) => entry.snapshotId),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst entry = resolved.entry;\n\t\tconst snapshotId = entry.snapshotId;\n\t\tyield* confirmDestructive(deps.confirm, ctx, {\n\t\t\tverb: 'snapshot delete',\n\t\t\tprompt:\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `Delete snapshot ${snapshotId}?`\n\t\t\t\t\t: `Delete snapshot ${entry.name} (${snapshotId})?`,\n\t\t\tskipWhenDryRun: false,\n\t\t});\n\t\tyield* deps\n\t\t\t.delete(snapshotId)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\t\tisCliError(cause)\n\t\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t\t: Effect.fail(new CliInternalError({ message: 'snapshot delete failed', cause })),\n\t\t\t\t),\n\t\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'snapshot delete',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdata: { snapshotId, name: entry.name },\n\t\t\thumanLines: [\n\t\t\t\tentry.name === null\n\t\t\t\t\t? `snapshot deleted ${snapshotId}`\n\t\t\t\t\t: `snapshot deleted ${entry.name} (${snapshotId})`,\n\t\t\t],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n\ninterface SnapshotInputErrorShape {\n\treadonly _tag: 'SnapshotIdError';\n\treadonly operation: string;\n\treadonly field: string;\n\treadonly value: string;\n\treadonly detail: string;\n}\n\nconst isSnapshotInputError = (value: unknown): value is SnapshotInputErrorShape =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\t(value as { readonly _tag?: unknown })._tag === 'SnapshotIdError';\n\nconst snapshotInputCliError = (error: SnapshotInputErrorShape): CliUsageError =>\n\tnew CliUsageError({\n\t\tmessage: `invalid snapshot ${error.field} for ${error.operation}: ${error.value}`,\n\t\thint: error.detail,\n\t});\n"],"mappings":"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"}
@@ -88,7 +88,7 @@ const runStatus = (deps, ctx) => Effect.gen(function* () {
88
88
  humanLines
89
89
  });
90
90
  return { exitCode: 0 };
91
- }).pipe(Effect.withSpan("cli.status"));
91
+ });
92
92
  //#endregion
93
93
  export { buildStatusPayload, runStatus };
94
94
 
@@ -1 +1 @@
1
- {"version":3,"file":"status.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/status.ts"],"sourcesContent":["// CLI verb: `devstack status` — observational read of stack state.\n//\n// Architecture (distilled/20-cli.md § Subcommands § Lifecycle):\n// \"status — observational read of stack state, manifest, and (if\n// present) fork meta.\"\n//\n// Surface invariant: status MUST tolerate missing/malformed state\n// files. It describes what IS, not what should be. The architecture\n// explicitly calls this out — throwing on a stack that hasn't been\n// brought up would be a regression.\n\nimport { Effect } from 'effect';\n\nimport type { SubscribableState } from '../../../substrate/projection.ts';\nimport type { CliError } from '../errors.ts';\nimport { emitSuccess } from '../output.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\n/** Pure projection: `SubscribableState` → JSON-safe status blob.\n * Never leaks substrate types. */\nexport const buildStatusPayload = (state: SubscribableState | null) => {\n\tif (state === null) {\n\t\treturn {\n\t\t\tpresent: false as const,\n\t\t\tidentity: null,\n\t\t\tcycle: null,\n\t\t\trowCount: 0,\n\t\t\tendpointCount: 0,\n\t\t\taccountCount: 0,\n\t\t\tpackageCount: 0,\n\t\t\terrorCount: 0,\n\t\t};\n\t}\n\treturn {\n\t\tpresent: true as const,\n\t\tidentity: { ...state.identity },\n\t\tcycle: { ...state.cycle },\n\t\trowCount: state.rows.length,\n\t\tendpointCount: state.endpoints.length,\n\t\taccountCount: state.accounts.length,\n\t\tpackageCount: state.packages.length,\n\t\terrorCount: state.errors.length,\n\t\trows: state.rows.map((r) => ({\n\t\t\tkey: r.key as string,\n\t\t\trole: r.role,\n\t\t\tstatus: r.status,\n\t\t\tphase: r.phase,\n\t\t\tlastErrorTag: r.lastError?.tag ?? null,\n\t\t})),\n\t\tendpoints: state.endpoints.map((e) => ({\n\t\t\tendpointKey: e.endpointKey as string,\n\t\t\tname: e.name,\n\t\t\turl: e.displayUrl ?? e.url,\n\t\t})),\n\t\taccounts: state.accounts.map((account) => ({\n\t\t\tkey: account.key,\n\t\t\trowKey: account.rowKey,\n\t\t\tname: account.name,\n\t\t\taddress: account.address,\n\t\t\tscheme: account.scheme,\n\t\t\tsource: account.source,\n\t\t\tfunding: { ...account.funding },\n\t\t\twalletVisible: account.walletVisible,\n\t\t})),\n\t\tpackages: state.packages.map((pkg) => ({\n\t\t\tkey: pkg.key,\n\t\t\trowKey: pkg.rowKey,\n\t\t\tname: pkg.name,\n\t\t\tkind: pkg.kind,\n\t\t\tpackageId: pkg.packageId,\n\t\t\tupgradeCapId: pkg.upgradeCapId,\n\t\t\tmvrPlaceholder: pkg.mvrPlaceholder,\n\t\t\tsourcePath: pkg.sourcePath,\n\t\t})),\n\t};\n};\n\n/**\n * Status reader interface. The dispatcher wires this to the\n * substrate's projection ref via a thin reader; tests pass a stub.\n * The CLI never calls engine methods directly — it reads the same\n * projection any peer surface (TUI, programmable API) sees.\n */\nexport interface StatusReader {\n\t/** Resolve the current projection. Identity is resolved from argv\n\t * upstream and baked into the reader at wiring time, so this takes no\n\t * `(app, stack)` params. Returns `null` if no state has been written\n\t * yet — a normal, tolerated state for a freshly-defined stack. */\n\treadonly readState: () => Effect.Effect<SubscribableState | null>;\n}\n\nexport interface StatusDeps {\n\treadonly reader: StatusReader;\n}\n\n/**\n * Run `devstack status`. Tolerant of missing state. Always succeeds\n * (returns ok=true) unless the projection read itself raises (which\n * the reader contractually swallows for missing files).\n */\nexport const runStatus = (\n\tdeps: StatusDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\t// `(app, stack)` are read ONLY for the human-readable status line\n\t\t// label below. The reader's identity is resolved from argv upstream\n\t\t// and baked in at wiring time, so it takes no params.\n\t\tconst app = ctx.flags.app ?? '';\n\t\tconst stack = ctx.flags.stack ?? '';\n\t\tconst state = yield* deps.reader.readState();\n\t\tconst data = buildStatusPayload(state);\n\t\tconst elapsedMs = Date.now() - started;\n\n\t\tconst humanLines: Array<string> = [];\n\t\tif (!data.present) {\n\t\t\thumanLines.push(\n\t\t\t\t`status: no state present for ${app || '(no app)'} / ${stack || '(no stack)'}`,\n\t\t\t);\n\t\t} else {\n\t\t\thumanLines.push(`app: ${data.identity!.app}`);\n\t\t\thumanLines.push(`stack: ${data.identity!.stack}`);\n\t\t\thumanLines.push(`network: ${data.identity!.network}`);\n\t\t\thumanLines.push(`cycle: #${data.cycle!.id} ${data.cycle!.phase}`);\n\t\t\thumanLines.push(`rows: ${data.rowCount}`);\n\t\t\thumanLines.push(`endpoints: ${data.endpointCount}`);\n\t\t\thumanLines.push(`accounts: ${data.accountCount}`);\n\t\t\thumanLines.push(`packages: ${data.packageCount}`);\n\t\t\thumanLines.push(`errors: ${data.errorCount}`);\n\t\t}\n\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'status',\n\t\t\telapsedMs,\n\t\t\tdata,\n\t\t\thumanLines,\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t}).pipe(Effect.withSpan('cli.status'));\n"],"mappings":";;;;;AAoBA,MAAa,sBAAsB,UAAoC;AACtE,KAAI,UAAU,KACb,QAAO;EACN,SAAS;EACT,UAAU;EACV,OAAO;EACP,UAAU;EACV,eAAe;EACf,cAAc;EACd,cAAc;EACd,YAAY;EACZ;AAEF,QAAO;EACN,SAAS;EACT,UAAU,EAAE,GAAG,MAAM,UAAU;EAC/B,OAAO,EAAE,GAAG,MAAM,OAAO;EACzB,UAAU,MAAM,KAAK;EACrB,eAAe,MAAM,UAAU;EAC/B,cAAc,MAAM,SAAS;EAC7B,cAAc,MAAM,SAAS;EAC7B,YAAY,MAAM,OAAO;EACzB,MAAM,MAAM,KAAK,KAAK,OAAO;GAC5B,KAAK,EAAE;GACP,MAAM,EAAE;GACR,QAAQ,EAAE;GACV,OAAO,EAAE;GACT,cAAc,EAAE,WAAW,OAAO;GAClC,EAAE;EACH,WAAW,MAAM,UAAU,KAAK,OAAO;GACtC,aAAa,EAAE;GACf,MAAM,EAAE;GACR,KAAK,EAAE,cAAc,EAAE;GACvB,EAAE;EACH,UAAU,MAAM,SAAS,KAAK,aAAa;GAC1C,KAAK,QAAQ;GACb,QAAQ,QAAQ;GAChB,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,SAAS,EAAE,GAAG,QAAQ,SAAS;GAC/B,eAAe,QAAQ;GACvB,EAAE;EACH,UAAU,MAAM,SAAS,KAAK,SAAS;GACtC,KAAK,IAAI;GACT,QAAQ,IAAI;GACZ,MAAM,IAAI;GACV,MAAM,IAAI;GACV,WAAW,IAAI;GACf,cAAc,IAAI;GAClB,gBAAgB,IAAI;GACpB,YAAY,IAAI;GAChB,EAAE;EACH;;;;;;;AA0BF,MAAa,aACZ,MACA,QAEA,OAAO,IAAI,aAAa;CACvB,MAAM,UAAU,KAAK,KAAK;CAI1B,MAAM,MAAM,IAAI,MAAM,OAAO;CAC7B,MAAM,QAAQ,IAAI,MAAM,SAAS;CAEjC,MAAM,OAAO,mBAAmB,OADX,KAAK,OAAO,WAAW,CACN;CACtC,MAAM,YAAY,KAAK,KAAK,GAAG;CAE/B,MAAM,aAA4B,EAAE;AACpC,KAAI,CAAC,KAAK,QACT,YAAW,KACV,gCAAgC,OAAO,WAAW,KAAK,SAAS,eAChE;MACK;AACN,aAAW,KAAK,YAAY,KAAK,SAAU,MAAM;AACjD,aAAW,KAAK,YAAY,KAAK,SAAU,QAAQ;AACnD,aAAW,KAAK,YAAY,KAAK,SAAU,UAAU;AACrD,aAAW,KAAK,aAAa,KAAK,MAAO,GAAG,GAAG,KAAK,MAAO,QAAQ;AACnE,aAAW,KAAK,YAAY,KAAK,WAAW;AAC5C,aAAW,KAAK,cAAc,KAAK,gBAAgB;AACnD,aAAW,KAAK,aAAa,KAAK,eAAe;AACjD,aAAW,KAAK,aAAa,KAAK,eAAe;AACjD,aAAW,KAAK,YAAY,KAAK,aAAa;;AAG/C,QAAO,YAAY,IAAI,IAAI,IAAI,MAAM,YAAY;EAChD,SAAS;EACT;EACA;EACA;EACA,CAAC;AACF,QAAO,EAAE,UAAU,GAAG;EACrB,CAAC,KAAK,OAAO,SAAS,aAAa,CAAC"}
1
+ {"version":3,"file":"status.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/status.ts"],"sourcesContent":["// CLI verb: `devstack status` — observational read of stack state.\n//\n// Architecture (distilled/20-cli.md § Subcommands § Lifecycle):\n// \"status — observational read of stack state, manifest, and (if\n// present) fork meta.\"\n//\n// Surface invariant: status MUST tolerate missing/malformed state\n// files. It describes what IS, not what should be. The architecture\n// explicitly calls this out — throwing on a stack that hasn't been\n// brought up would be a regression.\n\nimport { Effect } from 'effect';\n\nimport type { SubscribableState } from '../../../substrate/projection.ts';\nimport type { CliError } from '../errors.ts';\nimport { emitSuccess } from '../output.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\n/** Pure projection: `SubscribableState` → JSON-safe status blob.\n * Never leaks substrate types. */\nexport const buildStatusPayload = (state: SubscribableState | null) => {\n\tif (state === null) {\n\t\treturn {\n\t\t\tpresent: false as const,\n\t\t\tidentity: null,\n\t\t\tcycle: null,\n\t\t\trowCount: 0,\n\t\t\tendpointCount: 0,\n\t\t\taccountCount: 0,\n\t\t\tpackageCount: 0,\n\t\t\terrorCount: 0,\n\t\t};\n\t}\n\treturn {\n\t\tpresent: true as const,\n\t\tidentity: { ...state.identity },\n\t\tcycle: { ...state.cycle },\n\t\trowCount: state.rows.length,\n\t\tendpointCount: state.endpoints.length,\n\t\taccountCount: state.accounts.length,\n\t\tpackageCount: state.packages.length,\n\t\terrorCount: state.errors.length,\n\t\trows: state.rows.map((r) => ({\n\t\t\tkey: r.key as string,\n\t\t\trole: r.role,\n\t\t\tstatus: r.status,\n\t\t\tphase: r.phase,\n\t\t\tlastErrorTag: r.lastError?.tag ?? null,\n\t\t})),\n\t\tendpoints: state.endpoints.map((e) => ({\n\t\t\tendpointKey: e.endpointKey as string,\n\t\t\tname: e.name,\n\t\t\turl: e.displayUrl ?? e.url,\n\t\t})),\n\t\taccounts: state.accounts.map((account) => ({\n\t\t\tkey: account.key,\n\t\t\trowKey: account.rowKey,\n\t\t\tname: account.name,\n\t\t\taddress: account.address,\n\t\t\tscheme: account.scheme,\n\t\t\tsource: account.source,\n\t\t\tfunding: { ...account.funding },\n\t\t\twalletVisible: account.walletVisible,\n\t\t})),\n\t\tpackages: state.packages.map((pkg) => ({\n\t\t\tkey: pkg.key,\n\t\t\trowKey: pkg.rowKey,\n\t\t\tname: pkg.name,\n\t\t\tkind: pkg.kind,\n\t\t\tpackageId: pkg.packageId,\n\t\t\tupgradeCapId: pkg.upgradeCapId,\n\t\t\tmvrPlaceholder: pkg.mvrPlaceholder,\n\t\t\tsourcePath: pkg.sourcePath,\n\t\t})),\n\t};\n};\n\n/**\n * Status reader interface. The dispatcher wires this to the\n * substrate's projection ref via a thin reader; tests pass a stub.\n * The CLI never calls engine methods directly — it reads the same\n * projection any peer surface (TUI, programmable API) sees.\n */\nexport interface StatusReader {\n\t/** Resolve the current projection. Identity is resolved from argv\n\t * upstream and baked into the reader at wiring time, so this takes no\n\t * `(app, stack)` params. Returns `null` if no state has been written\n\t * yet — a normal, tolerated state for a freshly-defined stack. */\n\treadonly readState: () => Effect.Effect<SubscribableState | null>;\n}\n\nexport interface StatusDeps {\n\treadonly reader: StatusReader;\n}\n\n/**\n * Run `devstack status`. Tolerant of missing state. Always succeeds\n * (returns ok=true) unless the projection read itself raises (which\n * the reader contractually swallows for missing files).\n */\nexport const runStatus = (\n\tdeps: StatusDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\t// `(app, stack)` are read ONLY for the human-readable status line\n\t\t// label below. The reader's identity is resolved from argv upstream\n\t\t// and baked in at wiring time, so it takes no params.\n\t\tconst app = ctx.flags.app ?? '';\n\t\tconst stack = ctx.flags.stack ?? '';\n\t\tconst state = yield* deps.reader.readState();\n\t\tconst data = buildStatusPayload(state);\n\t\tconst elapsedMs = Date.now() - started;\n\n\t\tconst humanLines: Array<string> = [];\n\t\tif (!data.present) {\n\t\t\thumanLines.push(\n\t\t\t\t`status: no state present for ${app || '(no app)'} / ${stack || '(no stack)'}`,\n\t\t\t);\n\t\t} else {\n\t\t\thumanLines.push(`app: ${data.identity!.app}`);\n\t\t\thumanLines.push(`stack: ${data.identity!.stack}`);\n\t\t\thumanLines.push(`network: ${data.identity!.network}`);\n\t\t\thumanLines.push(`cycle: #${data.cycle!.id} ${data.cycle!.phase}`);\n\t\t\thumanLines.push(`rows: ${data.rowCount}`);\n\t\t\thumanLines.push(`endpoints: ${data.endpointCount}`);\n\t\t\thumanLines.push(`accounts: ${data.accountCount}`);\n\t\t\thumanLines.push(`packages: ${data.packageCount}`);\n\t\t\thumanLines.push(`errors: ${data.errorCount}`);\n\t\t}\n\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'status',\n\t\t\telapsedMs,\n\t\t\tdata,\n\t\t\thumanLines,\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n"],"mappings":";;;;;AAoBA,MAAa,sBAAsB,UAAoC;CACtE,IAAI,UAAU,MACb,OAAO;EACN,SAAS;EACT,UAAU;EACV,OAAO;EACP,UAAU;EACV,eAAe;EACf,cAAc;EACd,cAAc;EACd,YAAY;CACb;CAED,OAAO;EACN,SAAS;EACT,UAAU,EAAE,GAAG,MAAM,SAAS;EAC9B,OAAO,EAAE,GAAG,MAAM,MAAM;EACxB,UAAU,MAAM,KAAK;EACrB,eAAe,MAAM,UAAU;EAC/B,cAAc,MAAM,SAAS;EAC7B,cAAc,MAAM,SAAS;EAC7B,YAAY,MAAM,OAAO;EACzB,MAAM,MAAM,KAAK,KAAK,OAAO;GAC5B,KAAK,EAAE;GACP,MAAM,EAAE;GACR,QAAQ,EAAE;GACV,OAAO,EAAE;GACT,cAAc,EAAE,WAAW,OAAO;EACnC,EAAE;EACF,WAAW,MAAM,UAAU,KAAK,OAAO;GACtC,aAAa,EAAE;GACf,MAAM,EAAE;GACR,KAAK,EAAE,cAAc,EAAE;EACxB,EAAE;EACF,UAAU,MAAM,SAAS,KAAK,aAAa;GAC1C,KAAK,QAAQ;GACb,QAAQ,QAAQ;GAChB,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,SAAS,EAAE,GAAG,QAAQ,QAAQ;GAC9B,eAAe,QAAQ;EACxB,EAAE;EACF,UAAU,MAAM,SAAS,KAAK,SAAS;GACtC,KAAK,IAAI;GACT,QAAQ,IAAI;GACZ,MAAM,IAAI;GACV,MAAM,IAAI;GACV,WAAW,IAAI;GACf,cAAc,IAAI;GAClB,gBAAgB,IAAI;GACpB,YAAY,IAAI;EACjB,EAAE;CACH;AACD;;;;;;AAyBA,MAAa,aACZ,MACA,QAEA,OAAO,IAAI,aAAa;CACvB,MAAM,UAAU,KAAK,IAAI;CAIzB,MAAM,MAAM,IAAI,MAAM,OAAO;CAC7B,MAAM,QAAQ,IAAI,MAAM,SAAS;CAEjC,MAAM,OAAO,mBAAmB,OADX,KAAK,OAAO,UAAU,CACN;CACrC,MAAM,YAAY,KAAK,IAAI,IAAI;CAE/B,MAAM,aAA4B,CAAC;CACnC,IAAI,CAAC,KAAK,SACT,WAAW,KACV,gCAAgC,OAAO,WAAW,KAAK,SAAS,cACjE;MACM;EACN,WAAW,KAAK,YAAY,KAAK,SAAU,KAAK;EAChD,WAAW,KAAK,YAAY,KAAK,SAAU,OAAO;EAClD,WAAW,KAAK,YAAY,KAAK,SAAU,SAAS;EACpD,WAAW,KAAK,aAAa,KAAK,MAAO,GAAG,GAAG,KAAK,MAAO,OAAO;EAClE,WAAW,KAAK,YAAY,KAAK,UAAU;EAC3C,WAAW,KAAK,cAAc,KAAK,eAAe;EAClD,WAAW,KAAK,aAAa,KAAK,cAAc;EAChD,WAAW,KAAK,aAAa,KAAK,cAAc;EAChD,WAAW,KAAK,YAAY,KAAK,YAAY;CAC9C;CAEA,OAAO,YAAY,IAAI,IAAI,IAAI,MAAM,YAAY;EAChD,SAAS;EACT;EACA;EACA;CACD,CAAC;CACD,OAAO,EAAE,UAAU,EAAE;AACtB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"supervisor-presence.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/supervisor-presence.ts"],"sourcesContent":["// Detect whether a supervisor is currently live for a given stack.\n//\n// The CLI uses this to decide whether a verb should publish via the\n// cross-process command channel (live supervisor: publish + await ack)\n// or use its direct/offline fallback.\n//\n// Detection reads the existing `roster.json` (architecture § Cross-\n// process safety protocol § Roster) and walks holders. A same-host\n// holder with a live PID + matching start-time → supervisor live.\n// Foreign-host holders are conservatively treated as live (NFS-safe\n// default; matches `liveness.ts` discipline).\n\nimport { Effect } from 'effect';\n\nimport {\n\tlayerLivenessProbeScope,\n\tLivenessProbeScope,\n\treadRoster,\n\ttype RosterError,\n} from '../../../substrate/runtime/cross-process/index.ts';\n\nexport interface SupervisorPresence {\n\treadonly live: boolean;\n\treadonly pid: number | null;\n\treadonly hostname: string | null;\n}\n\n/**\n * Read `rosterFile` and report whether at least one live holder\n * remains. Returns `{ live: false, pid: null }` when the roster is\n * missing OR all holders are dead-by-liveness-check.\n *\n * Tolerates corrupt rosters: a malformed file is treated as \"no\n * live supervisor\" — the worst case is the CLI refusing a publish\n * the user could have buffered.\n */\nexport const probeSupervisorPresence = (\n\trosterFile: string,\n): Effect.Effect<SupervisorPresence, RosterError> =>\n\t// Yield a fresh `LivenessProbeScope` so a corrupted-roster edge case\n\t// with multiple holders sharing one pid forks `ps`/`tasklist` once.\n\tEffect.gen(function* () {\n\t\tconst doc = yield* readRoster(rosterFile).pipe(\n\t\t\tEffect.catchTag('RosterCorruptError', () =>\n\t\t\t\tEffect.succeed({ version: 1 as const, holders: [] }),\n\t\t\t),\n\t\t);\n\t\tconst probe = yield* LivenessProbeScope;\n\t\tfor (const holder of doc.holders) {\n\t\t\tconst liveness = yield* probe\n\t\t\t\t.probeHolderLiveness(holder)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed('alive' as const)));\n\t\t\tif (liveness === 'alive') {\n\t\t\t\treturn { live: true, pid: holder.pid, hostname: holder.hostname };\n\t\t\t}\n\t\t}\n\t\treturn { live: false, pid: null, hostname: null };\n\t}).pipe(Effect.provide(layerLivenessProbeScope));\n"],"mappings":";;;;;;;;;;;;;;AAoCA,MAAa,2BACZ,eAIA,OAAO,IAAI,aAAa;CACvB,MAAM,MAAM,OAAO,WAAW,WAAW,CAAC,KACzC,OAAO,SAAS,4BACf,OAAO,QAAQ;EAAE,SAAS;EAAY,SAAS,EAAE;EAAE,CAAC,CACpD,CACD;CACD,MAAM,QAAQ,OAAO;AACrB,MAAK,MAAM,UAAU,IAAI,QAIxB,MAAI,OAHoB,MACtB,oBAAoB,OAAO,CAC3B,KAAK,OAAO,YAAY,OAAO,QAAQ,QAAiB,CAAC,CAAC,MAC3C,QAChB,QAAO;EAAE,MAAM;EAAM,KAAK,OAAO;EAAK,UAAU,OAAO;EAAU;AAGnE,QAAO;EAAE,MAAM;EAAO,KAAK;EAAM,UAAU;EAAM;EAChD,CAAC,KAAK,OAAO,QAAQ,wBAAwB,CAAC"}
1
+ {"version":3,"file":"supervisor-presence.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/supervisor-presence.ts"],"sourcesContent":["// Detect whether a supervisor is currently live for a given stack.\n//\n// The CLI uses this to decide whether a verb should publish via the\n// cross-process command channel (live supervisor: publish + await ack)\n// or use its direct/offline fallback.\n//\n// Detection reads the existing `roster.json` (architecture § Cross-\n// process safety protocol § Roster) and walks holders. A holder with a\n// live PID + matching start-time → supervisor live (matches\n// `liveness.ts` discipline; devstack is single-host).\n\nimport { Effect } from 'effect';\n\nimport {\n\tlayerLivenessProbeScope,\n\tLivenessProbeScope,\n\treadRoster,\n\ttype RosterError,\n} from '../../../substrate/runtime/cross-process/index.ts';\n\nexport interface SupervisorPresence {\n\treadonly live: boolean;\n\treadonly pid: number | null;\n\treadonly hostname: string | null;\n}\n\n/**\n * Read `rosterFile` and report whether at least one live holder\n * remains. Returns `{ live: false, pid: null }` when the roster is\n * missing OR all holders are dead-by-liveness-check.\n *\n * Tolerates corrupt rosters: a malformed file is treated as \"no\n * live supervisor\" — the worst case is the CLI refusing a publish\n * the user could have buffered.\n */\nexport const probeSupervisorPresence = (\n\trosterFile: string,\n): Effect.Effect<SupervisorPresence, RosterError> =>\n\t// Yield a fresh `LivenessProbeScope` so a corrupted-roster edge case\n\t// with multiple holders sharing one pid forks `ps`/`tasklist` once.\n\tEffect.gen(function* () {\n\t\tconst doc = yield* readRoster(rosterFile).pipe(\n\t\t\tEffect.catchTag('RosterCorruptError', () =>\n\t\t\t\tEffect.succeed({ version: 1 as const, holders: [] }),\n\t\t\t),\n\t\t);\n\t\tconst probe = yield* LivenessProbeScope;\n\t\tfor (const holder of doc.holders) {\n\t\t\tconst liveness = yield* probe\n\t\t\t\t.probeHolderLiveness(holder)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed('alive' as const)));\n\t\t\tif (liveness === 'alive') {\n\t\t\t\treturn { live: true, pid: holder.pid, hostname: holder.hostname };\n\t\t\t}\n\t\t}\n\t\treturn { live: false, pid: null, hostname: null };\n\t}).pipe(Effect.provide(layerLivenessProbeScope));\n"],"mappings":";;;;;;;;;;;;;;AAmCA,MAAa,2BACZ,eAIA,OAAO,IAAI,aAAa;CACvB,MAAM,MAAM,OAAO,WAAW,UAAU,CAAC,CAAC,KACzC,OAAO,SAAS,4BACf,OAAO,QAAQ;EAAE,SAAS;EAAY,SAAS,CAAC;CAAE,CAAC,CACpD,CACD;CACA,MAAM,QAAQ,OAAO;CACrB,KAAK,MAAM,UAAU,IAAI,SAIxB,KAAI,OAHoB,MACtB,oBAAoB,MAAM,CAAC,CAC3B,KAAK,OAAO,YAAY,OAAO,QAAQ,OAAgB,CAAC,CAAC,OAC1C,SAChB,OAAO;EAAE,MAAM;EAAM,KAAK,OAAO;EAAK,UAAU,OAAO;CAAS;CAGlE,OAAO;EAAE,MAAM;EAAO,KAAK;EAAM,UAAU;CAAK;AACjD,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,uBAAuB,CAAC"}
@@ -5,8 +5,8 @@ import { Effect } from "effect";
5
5
  //#region src/surfaces/cli/commands/wipe.ts
6
6
  /** Human-readable preview of what a real wipe would delete. Mirrors the
7
7
  * orchestrator's teardown order (containers → networks/volumes →
8
- * state.json → runtime tree) so the operator reads the plan in the same
9
- * sequence the wipe executes. */
8
+ * runtime tree) so the operator reads the plan in the same sequence the
9
+ * wipe executes. */
10
10
  const dryRunLines = (targets) => {
11
11
  const lines = [`[dry-run] would wipe ${targets.app}/${targets.stack}:`];
12
12
  if (targets.containers.length > 0) {
@@ -15,7 +15,6 @@ const dryRunLines = (targets) => {
15
15
  } else lines.push(" containers: (none running/created)");
16
16
  lines.push(` networks: all managed (label devstack.app=${targets.networkLabelMatch.app},devstack.stack=${targets.networkLabelMatch.stack})`);
17
17
  lines.push(` volumes: all managed (label devstack.app=${targets.volumeLabelMatch.app},devstack.stack=${targets.volumeLabelMatch.stack})`);
18
- lines.push(` state file: ${targets.stateFile}`);
19
18
  if (targets.onDiskPaths.length > 0) {
20
19
  lines.push(` on-disk (${targets.onDiskPaths.length}):`);
21
20
  for (const path of targets.onDiskPaths) lines.push(` - ${path}`);
@@ -55,7 +54,7 @@ const runWipe = (deps, ctx) => Effect.gen(function* () {
55
54
  humanLines: ["stack state wiped"]
56
55
  });
57
56
  return { exitCode: 0 };
58
- }).pipe(Effect.withSpan("cli.wipe"));
57
+ });
59
58
  //#endregion
60
59
  export { runWipe };
61
60
 
@@ -1 +1 @@
1
- {"version":3,"file":"wipe.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/wipe.ts"],"sourcesContent":["// CLI verb: `devstack wipe` — destroy all state for a stack.\n//\n// Architecture (distilled/20-cli.md § Subcommands § Teardown):\n// \"wipe — destroy all state for a stack.\"\n//\n// `wipe` is the recovery flow `apply` points users at when stale\n// on-disk state needs a clean reset. It is tier-2 destructive (requires\n// `--yes` or an interactive TTY confirmation) and refuses to run while\n// a supervisor is live for the target stack (writes to disk while\n// a peer is acquiring a container would race).\n//\n// Surface-equality: `wipe` publishes `wipe.requested`; the L3 snapshot\n// orchestrator consumes (it owns the `wipe.ts` body that rmdir's the\n// stack root + container labels).\n\nimport { Effect } from 'effect';\n\nimport type { WipeTargets } from '../../../orchestrators/snapshot/index.ts';\nimport { type CliError, CliInternalError, isCliError } from '../errors.ts';\nimport { emitSuccess } from '../output.ts';\nimport { confirmDestructive, type ConfirmPrompt } from './confirm.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\nexport type { WipeTargets } from '../../../orchestrators/snapshot/index.ts';\n\nexport interface WipeDeps {\n\treadonly wipe: () => Effect.Effect<void, unknown>;\n\t/** Read-only enumeration of the concrete targets a real wipe would\n\t * remove (containers, network/volume label scope, state file, the\n\t * on-disk stack tree). Drives `--dry-run`. Optional so a deps\n\t * builder that cannot enumerate (or a test fixture) still works —\n\t * the dry-run then falls back to a generic preview line. */\n\treadonly plan?: () => Effect.Effect<WipeTargets, unknown>;\n\treadonly confirm: ConfirmPrompt;\n}\n\n/** Human-readable preview of what a real wipe would delete. Mirrors the\n * orchestrator's teardown order (containers → networks/volumes →\n * state.json → runtime tree) so the operator reads the plan in the same\n * sequence the wipe executes. */\nconst dryRunLines = (targets: WipeTargets): ReadonlyArray<string> => {\n\tconst lines: Array<string> = [`[dry-run] would wipe ${targets.app}/${targets.stack}:`];\n\tif (targets.containers.length > 0) {\n\t\tlines.push(` containers (${targets.containers.length}):`);\n\t\tfor (const name of targets.containers) lines.push(` - ${name}`);\n\t} else {\n\t\tlines.push(' containers: (none running/created)');\n\t}\n\tlines.push(\n\t\t` networks: all managed (label devstack.app=${targets.networkLabelMatch.app},devstack.stack=${targets.networkLabelMatch.stack})`,\n\t);\n\tlines.push(\n\t\t` volumes: all managed (label devstack.app=${targets.volumeLabelMatch.app},devstack.stack=${targets.volumeLabelMatch.stack})`,\n\t);\n\tlines.push(` state file: ${targets.stateFile}`);\n\tif (targets.onDiskPaths.length > 0) {\n\t\tlines.push(` on-disk (${targets.onDiskPaths.length}):`);\n\t\tfor (const path of targets.onDiskPaths) lines.push(` - ${path}`);\n\t} else {\n\t\tlines.push(` on-disk: (stack root ${targets.stackRoot} has no removable state)`);\n\t}\n\tif (targets.preserved.length > 0) {\n\t\tlines.push(` preserved: ${targets.preserved.join(', ')}`);\n\t}\n\treturn lines;\n};\n\nexport const runWipe = (\n\tdeps: WipeDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tyield* confirmDestructive(deps.confirm, ctx, {\n\t\t\tverb: 'wipe',\n\t\t\tprompt: 'Wipe all devstack state for the selected stack?',\n\t\t});\n\n\t\tif (ctx.flags.dryRun) {\n\t\t\t// Enumerate (read-only) so the preview lists the concrete\n\t\t\t// containers / networks / volumes / on-disk state a real wipe\n\t\t\t// would remove. A plan failure is non-fatal for a dry-run — the\n\t\t\t// worst case is a less-detailed preview — so it degrades to the\n\t\t\t// generic line rather than failing the command.\n\t\t\tconst targets =\n\t\t\t\tdeps.plan === undefined\n\t\t\t\t\t? null\n\t\t\t\t\t: yield* deps.plan().pipe(Effect.catch(() => Effect.succeed(null)));\n\t\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\t\tcommand: 'wipe',\n\t\t\t\telapsedMs: Date.now() - started,\n\t\t\t\tdryRun: true,\n\t\t\t\tdata: {\n\t\t\t\t\tdryRun: true,\n\t\t\t\t\t...(targets === null ? {} : { targets }),\n\t\t\t\t},\n\t\t\t\thumanLines:\n\t\t\t\t\ttargets === null ? ['[dry-run] would wipe selected stack state'] : dryRunLines(targets),\n\t\t\t});\n\t\t\treturn { exitCode: 0 } as CommandResult;\n\t\t}\n\n\t\tyield* deps.wipe().pipe(\n\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\tisCliError(cause)\n\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t: Effect.fail(\n\t\t\t\t\t\t\tnew CliInternalError({\n\t\t\t\t\t\t\t\tmessage: 'wipe failed',\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'wipe',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdryRun: false,\n\t\t\tdata: {\n\t\t\t\tdryRun: false,\n\t\t\t},\n\t\t\thumanLines: ['stack state wiped'],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t}).pipe(Effect.withSpan('cli.wipe'));\n"],"mappings":";;;;;;;;;AAwCA,MAAM,eAAe,YAAgD;CACpE,MAAM,QAAuB,CAAC,wBAAwB,QAAQ,IAAI,GAAG,QAAQ,MAAM,GAAG;AACtF,KAAI,QAAQ,WAAW,SAAS,GAAG;AAClC,QAAM,KAAK,iBAAiB,QAAQ,WAAW,OAAO,IAAI;AAC1D,OAAK,MAAM,QAAQ,QAAQ,WAAY,OAAM,KAAK,SAAS,OAAO;OAElE,OAAM,KAAK,uCAAuC;AAEnD,OAAM,KACL,+CAA+C,QAAQ,kBAAkB,IAAI,kBAAkB,QAAQ,kBAAkB,MAAM,GAC/H;AACD,OAAM,KACL,8CAA8C,QAAQ,iBAAiB,IAAI,kBAAkB,QAAQ,iBAAiB,MAAM,GAC5H;AACD,OAAM,KAAK,iBAAiB,QAAQ,YAAY;AAChD,KAAI,QAAQ,YAAY,SAAS,GAAG;AACnC,QAAM,KAAK,cAAc,QAAQ,YAAY,OAAO,IAAI;AACxD,OAAK,MAAM,QAAQ,QAAQ,YAAa,OAAM,KAAK,SAAS,OAAO;OAEnE,OAAM,KAAK,0BAA0B,QAAQ,UAAU,0BAA0B;AAElF,KAAI,QAAQ,UAAU,SAAS,EAC9B,OAAM,KAAK,gBAAgB,QAAQ,UAAU,KAAK,KAAK,GAAG;AAE3D,QAAO;;AAGR,MAAa,WACZ,MACA,QAEA,OAAO,IAAI,aAAa;CACvB,MAAM,UAAU,KAAK,KAAK;AAC1B,QAAO,mBAAmB,KAAK,SAAS,KAAK;EAC5C,MAAM;EACN,QAAQ;EACR,CAAC;AAEF,KAAI,IAAI,MAAM,QAAQ;EAMrB,MAAM,UACL,KAAK,SAAS,KAAA,IACX,OACA,OAAO,KAAK,MAAM,CAAC,KAAK,OAAO,YAAY,OAAO,QAAQ,KAAK,CAAC,CAAC;AACrE,SAAO,YAAY,IAAI,IAAI,IAAI,MAAM,YAAY;GAChD,SAAS;GACT,WAAW,KAAK,KAAK,GAAG;GACxB,QAAQ;GACR,MAAM;IACL,QAAQ;IACR,GAAI,YAAY,OAAO,EAAE,GAAG,EAAE,SAAS;IACvC;GACD,YACC,YAAY,OAAO,CAAC,4CAA4C,GAAG,YAAY,QAAQ;GACxF,CAAC;AACF,SAAO,EAAE,UAAU,GAAG;;AAGvB,QAAO,KAAK,MAAM,CAAC,KAClB,OAAO,OAAO,UACb,WAAW,MAAM,GACd,OAAO,KAAK,MAAM,GAClB,OAAO,KACP,IAAI,iBAAiB;EACpB,SAAS;EACT;EACA,CAAC,CACF,CACH,CACD;AACD,QAAO,YAAY,IAAI,IAAI,IAAI,MAAM,YAAY;EAChD,SAAS;EACT,WAAW,KAAK,KAAK,GAAG;EACxB,QAAQ;EACR,MAAM,EACL,QAAQ,OACR;EACD,YAAY,CAAC,oBAAoB;EACjC,CAAC;AACF,QAAO,EAAE,UAAU,GAAG;EACrB,CAAC,KAAK,OAAO,SAAS,WAAW,CAAC"}
1
+ {"version":3,"file":"wipe.mjs","names":[],"sources":["../../../../src/surfaces/cli/commands/wipe.ts"],"sourcesContent":["// CLI verb: `devstack wipe` — destroy all state for a stack.\n//\n// Architecture (distilled/20-cli.md § Subcommands § Teardown):\n// \"wipe — destroy all state for a stack.\"\n//\n// `wipe` is the recovery flow `apply` points users at when stale\n// on-disk state needs a clean reset. It is tier-2 destructive (requires\n// `--yes` or an interactive TTY confirmation) and refuses to run while\n// a supervisor is live for the target stack (writes to disk while\n// a peer is acquiring a container would race).\n//\n// Surface-equality: `wipe` publishes `wipe.requested`; the L3 snapshot\n// orchestrator consumes (it owns the `wipe.ts` body that rmdir's the\n// stack root + container labels).\n\nimport { Effect } from 'effect';\n\nimport type { WipeTargets } from '../../../orchestrators/snapshot/index.ts';\nimport { type CliError, CliInternalError, isCliError } from '../errors.ts';\nimport { emitSuccess } from '../output.ts';\nimport { confirmDestructive, type ConfirmPrompt } from './confirm.ts';\nimport type { CommandContext, CommandResult } from './index.ts';\n\nexport type { WipeTargets } from '../../../orchestrators/snapshot/index.ts';\n\nexport interface WipeDeps {\n\treadonly wipe: () => Effect.Effect<void, unknown>;\n\t/** Read-only enumeration of the concrete targets a real wipe would\n\t * remove (containers, network/volume label scope, the on-disk stack\n\t * tree). Drives `--dry-run`. Optional so a deps\n\t * builder that cannot enumerate (or a test fixture) still works —\n\t * the dry-run then falls back to a generic preview line. */\n\treadonly plan?: () => Effect.Effect<WipeTargets, unknown>;\n\treadonly confirm: ConfirmPrompt;\n}\n\n/** Human-readable preview of what a real wipe would delete. Mirrors the\n * orchestrator's teardown order (containers → networks/volumes →\n * runtime tree) so the operator reads the plan in the same sequence the\n * wipe executes. */\nconst dryRunLines = (targets: WipeTargets): ReadonlyArray<string> => {\n\tconst lines: Array<string> = [`[dry-run] would wipe ${targets.app}/${targets.stack}:`];\n\tif (targets.containers.length > 0) {\n\t\tlines.push(` containers (${targets.containers.length}):`);\n\t\tfor (const name of targets.containers) lines.push(` - ${name}`);\n\t} else {\n\t\tlines.push(' containers: (none running/created)');\n\t}\n\tlines.push(\n\t\t` networks: all managed (label devstack.app=${targets.networkLabelMatch.app},devstack.stack=${targets.networkLabelMatch.stack})`,\n\t);\n\tlines.push(\n\t\t` volumes: all managed (label devstack.app=${targets.volumeLabelMatch.app},devstack.stack=${targets.volumeLabelMatch.stack})`,\n\t);\n\tif (targets.onDiskPaths.length > 0) {\n\t\tlines.push(` on-disk (${targets.onDiskPaths.length}):`);\n\t\tfor (const path of targets.onDiskPaths) lines.push(` - ${path}`);\n\t} else {\n\t\tlines.push(` on-disk: (stack root ${targets.stackRoot} has no removable state)`);\n\t}\n\tif (targets.preserved.length > 0) {\n\t\tlines.push(` preserved: ${targets.preserved.join(', ')}`);\n\t}\n\treturn lines;\n};\n\nexport const runWipe = (\n\tdeps: WipeDeps,\n\tctx: CommandContext,\n): Effect.Effect<CommandResult, CliError> =>\n\tEffect.gen(function* () {\n\t\tconst started = Date.now();\n\t\tyield* confirmDestructive(deps.confirm, ctx, {\n\t\t\tverb: 'wipe',\n\t\t\tprompt: 'Wipe all devstack state for the selected stack?',\n\t\t});\n\n\t\tif (ctx.flags.dryRun) {\n\t\t\t// Enumerate (read-only) so the preview lists the concrete\n\t\t\t// containers / networks / volumes / on-disk state a real wipe\n\t\t\t// would remove. A plan failure is non-fatal for a dry-run — the\n\t\t\t// worst case is a less-detailed preview — so it degrades to the\n\t\t\t// generic line rather than failing the command.\n\t\t\tconst targets =\n\t\t\t\tdeps.plan === undefined\n\t\t\t\t\t? null\n\t\t\t\t\t: yield* deps.plan().pipe(Effect.catch(() => Effect.succeed(null)));\n\t\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\t\tcommand: 'wipe',\n\t\t\t\telapsedMs: Date.now() - started,\n\t\t\t\tdryRun: true,\n\t\t\t\tdata: {\n\t\t\t\t\tdryRun: true,\n\t\t\t\t\t...(targets === null ? {} : { targets }),\n\t\t\t\t},\n\t\t\t\thumanLines:\n\t\t\t\t\ttargets === null ? ['[dry-run] would wipe selected stack state'] : dryRunLines(targets),\n\t\t\t});\n\t\t\treturn { exitCode: 0 } as CommandResult;\n\t\t}\n\n\t\tyield* deps.wipe().pipe(\n\t\t\tEffect.catch((cause: unknown) =>\n\t\t\t\tisCliError(cause)\n\t\t\t\t\t? Effect.fail(cause)\n\t\t\t\t\t: Effect.fail(\n\t\t\t\t\t\t\tnew CliInternalError({\n\t\t\t\t\t\t\t\tmessage: 'wipe failed',\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tyield* emitSuccess(ctx.io, ctx.flags.outputMode, {\n\t\t\tcommand: 'wipe',\n\t\t\telapsedMs: Date.now() - started,\n\t\t\tdryRun: false,\n\t\t\tdata: {\n\t\t\t\tdryRun: false,\n\t\t\t},\n\t\t\thumanLines: ['stack state wiped'],\n\t\t});\n\t\treturn { exitCode: 0 } as CommandResult;\n\t});\n"],"mappings":";;;;;;;;;AAwCA,MAAM,eAAe,YAAgD;CACpE,MAAM,QAAuB,CAAC,wBAAwB,QAAQ,IAAI,GAAG,QAAQ,MAAM,EAAE;CACrF,IAAI,QAAQ,WAAW,SAAS,GAAG;EAClC,MAAM,KAAK,iBAAiB,QAAQ,WAAW,OAAO,GAAG;EACzD,KAAK,MAAM,QAAQ,QAAQ,YAAY,MAAM,KAAK,SAAS,MAAM;CAClE,OACC,MAAM,KAAK,sCAAsC;CAElD,MAAM,KACL,+CAA+C,QAAQ,kBAAkB,IAAI,kBAAkB,QAAQ,kBAAkB,MAAM,EAChI;CACA,MAAM,KACL,8CAA8C,QAAQ,iBAAiB,IAAI,kBAAkB,QAAQ,iBAAiB,MAAM,EAC7H;CACA,IAAI,QAAQ,YAAY,SAAS,GAAG;EACnC,MAAM,KAAK,cAAc,QAAQ,YAAY,OAAO,GAAG;EACvD,KAAK,MAAM,QAAQ,QAAQ,aAAa,MAAM,KAAK,SAAS,MAAM;CACnE,OACC,MAAM,KAAK,0BAA0B,QAAQ,UAAU,yBAAyB;CAEjF,IAAI,QAAQ,UAAU,SAAS,GAC9B,MAAM,KAAK,gBAAgB,QAAQ,UAAU,KAAK,IAAI,GAAG;CAE1D,OAAO;AACR;AAEA,MAAa,WACZ,MACA,QAEA,OAAO,IAAI,aAAa;CACvB,MAAM,UAAU,KAAK,IAAI;CACzB,OAAO,mBAAmB,KAAK,SAAS,KAAK;EAC5C,MAAM;EACN,QAAQ;CACT,CAAC;CAED,IAAI,IAAI,MAAM,QAAQ;EAMrB,MAAM,UACL,KAAK,SAAS,KAAA,IACX,OACA,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,OAAO,YAAY,OAAO,QAAQ,IAAI,CAAC,CAAC;EACpE,OAAO,YAAY,IAAI,IAAI,IAAI,MAAM,YAAY;GAChD,SAAS;GACT,WAAW,KAAK,IAAI,IAAI;GACxB,QAAQ;GACR,MAAM;IACL,QAAQ;IACR,GAAI,YAAY,OAAO,CAAC,IAAI,EAAE,QAAQ;GACvC;GACA,YACC,YAAY,OAAO,CAAC,2CAA2C,IAAI,YAAY,OAAO;EACxF,CAAC;EACD,OAAO,EAAE,UAAU,EAAE;CACtB;CAEA,OAAO,KAAK,KAAK,CAAC,CAAC,KAClB,OAAO,OAAO,UACb,WAAW,KAAK,IACb,OAAO,KAAK,KAAK,IACjB,OAAO,KACP,IAAI,iBAAiB;EACpB,SAAS;EACT;CACD,CAAC,CACF,CACH,CACD;CACA,OAAO,YAAY,IAAI,IAAI,IAAI,MAAM,YAAY;EAChD,SAAS;EACT,WAAW,KAAK,IAAI,IAAI;EACxB,QAAQ;EACR,MAAM,EACL,QAAQ,MACT;EACA,YAAY,CAAC,mBAAmB;CACjC,CAAC;CACD,OAAO,EAAE,UAAU,EAAE;AACtB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.mjs","names":[],"sources":["../../../src/surfaces/cli/envelope.ts"],"sourcesContent":["// CLI surface — stable JSON envelope.\n//\n// Architecture (distilled/20-cli.md § Output formats / Invariants):\n// - Exactly one envelope per command on stdout in `--json` mode.\n// - Schema version pinned; bumped intentionally on breaking changes.\n// - Absent fields are OMITTED from serialized output (no\n// `undefined`).\n// - Envelope must never carry devstack-internal types — no engine\n// class instances, no raw Effect Causes, no plugin error objects.\n// The cascade formatter projects causes into the flat error block;\n// `data` is a JSON-safe blob.\n//\n// The envelope is the CLI's contract with downstream automation\n// (CI, agents, examples). Treat it as a public schema: ANY field-name\n// change is a major version bump.\n\nimport { ExitCode, exitCodeName } from './sysexits.ts';\n\n/**\n * Current envelope schema version. Bump on any incompatible field\n * rename / shape change. Additive fields (omitted-when-absent) do NOT\n * require a bump.\n *\n * Semantic: integer, monotonically increasing. Consumers MAY refuse to\n * parse an envelope whose `schemaVersion` exceeds their pinned\n * maximum.\n */\nexport const ENVELOPE_SCHEMA_VERSION = 1 as const;\n\n/** Flat error block carried inside the envelope. NEVER a raw Effect\n * Cause — the cascade formatter projects causes into `chain[]`. */\nexport interface EnvelopeError {\n\t/** Sysexits name, e.g. `'CONFIG'`. */\n\treadonly code: string;\n\t/** Sysexits numeric, e.g. 78. Mirrors the OS exit code. */\n\treadonly exitCode: number;\n\t/** Single-line summary fit for a TTY one-liner. */\n\treadonly summary: string;\n\t/** Optional remediation hint (\"run `devstack doctor` to verify\n\t * Docker is reachable\"). */\n\treadonly hint?: string;\n\t/** Optional copy-pasteable recipe block (multi-line). */\n\treadonly recipe?: string;\n\t/** Cascade lines, deepest-first. Each entry is a rendered line\n\t * from the cause walker; consumers never see Effect internals. */\n\treadonly chain?: ReadonlyArray<string>;\n\t/** Optional structured context (string-keyed primitives only). */\n\treadonly context?: Readonly<Record<string, string | number | boolean | null>>;\n}\n\n/** The envelope shape itself. Required fields surface always. Optional\n * fields are omitted when not relevant (the builder enforces this).\n *\n * Streaming verbs (`logs`) use `StreamingEvent` for each tick; the\n * closing envelope is one final `Envelope`. The `kind` discriminator\n * on the streaming shape lets `jq` distinguish per-event records\n * from the closing summary (surfaces review §1). */\nexport interface Envelope<Data = unknown> {\n\treadonly schemaVersion: typeof ENVELOPE_SCHEMA_VERSION;\n\treadonly ok: boolean;\n\treadonly command: string;\n\treadonly elapsedMs: number;\n\treadonly data?: Data;\n\treadonly hints?: ReadonlyArray<string>;\n\treadonly error?: EnvelopeError;\n\treadonly dryRun?: true;\n}\n\n/** Per-event streaming record. Carries `kind: 'event'` so a consumer\n * piping through `jq` can filter event records from the closing\n * `Envelope` by `.kind`. Streaming verbs emit zero-or-more\n * `StreamingEvent` records followed by exactly one closing `Envelope`. */\nexport interface StreamingEvent<Data = unknown> {\n\treadonly schemaVersion: typeof ENVELOPE_SCHEMA_VERSION;\n\treadonly kind: 'event';\n\treadonly command: string;\n\treadonly at: string;\n\treadonly data: Data;\n}\n\n/** Build a streaming-event record. The closing envelope is produced via\n * `successEnvelope` as usual. */\nexport const streamingEvent = <Data>(params: {\n\treadonly command: string;\n\treadonly at: number;\n\treadonly data: Data;\n}): StreamingEvent<Data> => ({\n\tschemaVersion: ENVELOPE_SCHEMA_VERSION,\n\tkind: 'event',\n\tcommand: params.command,\n\tat: new Date(params.at).toISOString(),\n\tdata: params.data,\n});\n\n// -----------------------------------------------------------------------------\n// Builders\n// -----------------------------------------------------------------------------\n\nexport interface SuccessParams<Data = unknown> {\n\treadonly command: string;\n\treadonly elapsedMs: number;\n\treadonly data?: Data;\n\treadonly hints?: ReadonlyArray<string>;\n\treadonly dryRun?: boolean;\n}\n\n/** Build a success envelope. Optional fields collapse cleanly when\n * absent — the JSON serializer in `output.ts` strips them. */\nexport const successEnvelope = <Data>(params: SuccessParams<Data>): Envelope<Data> => {\n\tconst env: Mutable<Envelope<Data>> = {\n\t\tschemaVersion: ENVELOPE_SCHEMA_VERSION,\n\t\tok: true,\n\t\tcommand: params.command,\n\t\telapsedMs: params.elapsedMs,\n\t};\n\tif (params.data !== undefined) env.data = params.data;\n\tif (params.hints !== undefined && params.hints.length > 0) env.hints = params.hints;\n\tif (params.dryRun === true) env.dryRun = true;\n\treturn env as Envelope<Data>;\n};\n\nexport interface FailureParams {\n\treadonly command: string;\n\treadonly elapsedMs: number;\n\treadonly exitCode: ExitCode;\n\treadonly summary: string;\n\treadonly hint?: string;\n\treadonly recipe?: string;\n\treadonly chain?: ReadonlyArray<string>;\n\treadonly context?: EnvelopeError['context'];\n\treadonly hints?: ReadonlyArray<string>;\n\treadonly dryRun?: boolean;\n}\n\n/** Build a failure envelope. The numeric `exitCode` is BOTH the\n * envelope's `error.exitCode` AND the OS exit code the CLI propagates\n * via `process.exitCode`. */\nexport const failureEnvelope = (params: FailureParams): Envelope<never> => {\n\tconst error: Mutable<EnvelopeError> = {\n\t\tcode: exitCodeName(params.exitCode),\n\t\texitCode: params.exitCode,\n\t\tsummary: params.summary,\n\t};\n\tif (params.hint !== undefined) error.hint = params.hint;\n\tif (params.recipe !== undefined) error.recipe = params.recipe;\n\tif (params.chain !== undefined && params.chain.length > 0) error.chain = params.chain;\n\tif (params.context !== undefined) error.context = params.context;\n\n\tconst env: Mutable<Envelope<never>> = {\n\t\tschemaVersion: ENVELOPE_SCHEMA_VERSION,\n\t\tok: false,\n\t\tcommand: params.command,\n\t\telapsedMs: params.elapsedMs,\n\t\terror: error as EnvelopeError,\n\t};\n\tif (params.hints !== undefined && params.hints.length > 0) env.hints = params.hints;\n\tif (params.dryRun === true) env.dryRun = true;\n\treturn env as Envelope<never>;\n};\n\n// -----------------------------------------------------------------------------\n// Internal helpers\n// -----------------------------------------------------------------------------\n\n/** Local `Mutable<T>` — the envelope is built mutably, then frozen by\n * the caller via `as`. We don't mutate after publish. */\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n"],"mappings":";;;AA4GA,MAAa,mBAAyB,WAAgD;CACrF,MAAM,MAA+B;EACpC,eAAA;EACA,IAAI;EACJ,SAAS,OAAO;EAChB,WAAW,OAAO;EAClB;AACD,KAAI,OAAO,SAAS,KAAA,EAAW,KAAI,OAAO,OAAO;AACjD,KAAI,OAAO,UAAU,KAAA,KAAa,OAAO,MAAM,SAAS,EAAG,KAAI,QAAQ,OAAO;AAC9E,KAAI,OAAO,WAAW,KAAM,KAAI,SAAS;AACzC,QAAO;;;;;AAmBR,MAAa,mBAAmB,WAA2C;CAC1E,MAAM,QAAgC;EACrC,MAAM,aAAa,OAAO,SAAS;EACnC,UAAU,OAAO;EACjB,SAAS,OAAO;EAChB;AACD,KAAI,OAAO,SAAS,KAAA,EAAW,OAAM,OAAO,OAAO;AACnD,KAAI,OAAO,WAAW,KAAA,EAAW,OAAM,SAAS,OAAO;AACvD,KAAI,OAAO,UAAU,KAAA,KAAa,OAAO,MAAM,SAAS,EAAG,OAAM,QAAQ,OAAO;AAChF,KAAI,OAAO,YAAY,KAAA,EAAW,OAAM,UAAU,OAAO;CAEzD,MAAM,MAAgC;EACrC,eAAA;EACA,IAAI;EACJ,SAAS,OAAO;EAChB,WAAW,OAAO;EACX;EACP;AACD,KAAI,OAAO,UAAU,KAAA,KAAa,OAAO,MAAM,SAAS,EAAG,KAAI,QAAQ,OAAO;AAC9E,KAAI,OAAO,WAAW,KAAM,KAAI,SAAS;AACzC,QAAO"}
1
+ {"version":3,"file":"envelope.mjs","names":[],"sources":["../../../src/surfaces/cli/envelope.ts"],"sourcesContent":["// CLI surface — stable JSON envelope.\n//\n// Architecture (distilled/20-cli.md § Output formats / Invariants):\n// - Exactly one envelope per command on stdout in `--json` mode.\n// - Schema version pinned; bumped intentionally on breaking changes.\n// - Absent fields are OMITTED from serialized output (no\n// `undefined`).\n// - Envelope must never carry devstack-internal types — no engine\n// class instances, no raw Effect Causes, no plugin error objects.\n// The cascade formatter projects causes into the flat error block;\n// `data` is a JSON-safe blob.\n//\n// The envelope is the CLI's contract with downstream automation\n// (CI, agents, examples). Treat it as a public schema: ANY field-name\n// change is a major version bump.\n\nimport { ExitCode, exitCodeName } from './sysexits.ts';\n\n/**\n * Current envelope schema version. Bump on any incompatible field\n * rename / shape change. Additive fields (omitted-when-absent) do NOT\n * require a bump.\n *\n * Semantic: integer, monotonically increasing. Consumers MAY refuse to\n * parse an envelope whose `schemaVersion` exceeds their pinned\n * maximum.\n */\nexport const ENVELOPE_SCHEMA_VERSION = 1 as const;\n\n/** Flat error block carried inside the envelope. NEVER a raw Effect\n * Cause — the cascade formatter projects causes into `chain[]`. */\nexport interface EnvelopeError {\n\t/** Sysexits name, e.g. `'CONFIG'`. */\n\treadonly code: string;\n\t/** Sysexits numeric, e.g. 78. Mirrors the OS exit code. */\n\treadonly exitCode: number;\n\t/** Single-line summary fit for a TTY one-liner. */\n\treadonly summary: string;\n\t/** Optional remediation hint (\"run `devstack doctor` to verify\n\t * Docker is reachable\"). */\n\treadonly hint?: string;\n\t/** Optional copy-pasteable recipe block (multi-line). */\n\treadonly recipe?: string;\n\t/** Cascade lines, deepest-first. Each entry is a rendered line\n\t * from the cause walker; consumers never see Effect internals. */\n\treadonly chain?: ReadonlyArray<string>;\n\t/** Optional structured context (string-keyed primitives only). */\n\treadonly context?: Readonly<Record<string, string | number | boolean | null>>;\n}\n\n/** The envelope shape itself. Required fields surface always. Optional\n * fields are omitted when not relevant (the builder enforces this).\n *\n * Streaming verbs (`logs`) use `StreamingEvent` for each tick; the\n * closing envelope is one final `Envelope`. The `kind` discriminator\n * on the streaming shape lets `jq` distinguish per-event records\n * from the closing summary (surfaces review §1). */\nexport interface Envelope<Data = unknown> {\n\treadonly schemaVersion: typeof ENVELOPE_SCHEMA_VERSION;\n\treadonly ok: boolean;\n\treadonly command: string;\n\treadonly elapsedMs: number;\n\treadonly data?: Data;\n\treadonly hints?: ReadonlyArray<string>;\n\treadonly error?: EnvelopeError;\n\treadonly dryRun?: true;\n}\n\n/** Per-event streaming record. Carries `kind: 'event'` so a consumer\n * piping through `jq` can filter event records from the closing\n * `Envelope` by `.kind`. Streaming verbs emit zero-or-more\n * `StreamingEvent` records followed by exactly one closing `Envelope`. */\nexport interface StreamingEvent<Data = unknown> {\n\treadonly schemaVersion: typeof ENVELOPE_SCHEMA_VERSION;\n\treadonly kind: 'event';\n\treadonly command: string;\n\treadonly at: string;\n\treadonly data: Data;\n}\n\n/** Build a streaming-event record. The closing envelope is produced via\n * `successEnvelope` as usual. */\nexport const streamingEvent = <Data>(params: {\n\treadonly command: string;\n\treadonly at: number;\n\treadonly data: Data;\n}): StreamingEvent<Data> => ({\n\tschemaVersion: ENVELOPE_SCHEMA_VERSION,\n\tkind: 'event',\n\tcommand: params.command,\n\tat: new Date(params.at).toISOString(),\n\tdata: params.data,\n});\n\n// -----------------------------------------------------------------------------\n// Builders\n// -----------------------------------------------------------------------------\n\nexport interface SuccessParams<Data = unknown> {\n\treadonly command: string;\n\treadonly elapsedMs: number;\n\treadonly data?: Data;\n\treadonly hints?: ReadonlyArray<string>;\n\treadonly dryRun?: boolean;\n}\n\n/** Build a success envelope. Optional fields collapse cleanly when\n * absent — the JSON serializer in `output.ts` strips them. */\nexport const successEnvelope = <Data>(params: SuccessParams<Data>): Envelope<Data> => {\n\tconst env: Mutable<Envelope<Data>> = {\n\t\tschemaVersion: ENVELOPE_SCHEMA_VERSION,\n\t\tok: true,\n\t\tcommand: params.command,\n\t\telapsedMs: params.elapsedMs,\n\t};\n\tif (params.data !== undefined) env.data = params.data;\n\tif (params.hints !== undefined && params.hints.length > 0) env.hints = params.hints;\n\tif (params.dryRun === true) env.dryRun = true;\n\treturn env as Envelope<Data>;\n};\n\nexport interface FailureParams {\n\treadonly command: string;\n\treadonly elapsedMs: number;\n\treadonly exitCode: ExitCode;\n\treadonly summary: string;\n\treadonly hint?: string;\n\treadonly recipe?: string;\n\treadonly chain?: ReadonlyArray<string>;\n\treadonly context?: EnvelopeError['context'];\n\treadonly hints?: ReadonlyArray<string>;\n\treadonly dryRun?: boolean;\n}\n\n/** Build a failure envelope. The numeric `exitCode` is BOTH the\n * envelope's `error.exitCode` AND the OS exit code the CLI propagates\n * via `process.exitCode`. */\nexport const failureEnvelope = (params: FailureParams): Envelope<never> => {\n\tconst error: Mutable<EnvelopeError> = {\n\t\tcode: exitCodeName(params.exitCode),\n\t\texitCode: params.exitCode,\n\t\tsummary: params.summary,\n\t};\n\tif (params.hint !== undefined) error.hint = params.hint;\n\tif (params.recipe !== undefined) error.recipe = params.recipe;\n\tif (params.chain !== undefined && params.chain.length > 0) error.chain = params.chain;\n\tif (params.context !== undefined) error.context = params.context;\n\n\tconst env: Mutable<Envelope<never>> = {\n\t\tschemaVersion: ENVELOPE_SCHEMA_VERSION,\n\t\tok: false,\n\t\tcommand: params.command,\n\t\telapsedMs: params.elapsedMs,\n\t\terror: error as EnvelopeError,\n\t};\n\tif (params.hints !== undefined && params.hints.length > 0) env.hints = params.hints;\n\tif (params.dryRun === true) env.dryRun = true;\n\treturn env as Envelope<never>;\n};\n\n// -----------------------------------------------------------------------------\n// Internal helpers\n// -----------------------------------------------------------------------------\n\n/** Local `Mutable<T>` — the envelope is built mutably, then frozen by\n * the caller via `as`. We don't mutate after publish. */\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n"],"mappings":";;;AA4GA,MAAa,mBAAyB,WAAgD;CACrF,MAAM,MAA+B;EACpC,eAAA;EACA,IAAI;EACJ,SAAS,OAAO;EAChB,WAAW,OAAO;CACnB;CACA,IAAI,OAAO,SAAS,KAAA,GAAW,IAAI,OAAO,OAAO;CACjD,IAAI,OAAO,UAAU,KAAA,KAAa,OAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,OAAO;CAC9E,IAAI,OAAO,WAAW,MAAM,IAAI,SAAS;CACzC,OAAO;AACR;;;;AAkBA,MAAa,mBAAmB,WAA2C;CAC1E,MAAM,QAAgC;EACrC,MAAM,aAAa,OAAO,QAAQ;EAClC,UAAU,OAAO;EACjB,SAAS,OAAO;CACjB;CACA,IAAI,OAAO,SAAS,KAAA,GAAW,MAAM,OAAO,OAAO;CACnD,IAAI,OAAO,WAAW,KAAA,GAAW,MAAM,SAAS,OAAO;CACvD,IAAI,OAAO,UAAU,KAAA,KAAa,OAAO,MAAM,SAAS,GAAG,MAAM,QAAQ,OAAO;CAChF,IAAI,OAAO,YAAY,KAAA,GAAW,MAAM,UAAU,OAAO;CAEzD,MAAM,MAAgC;EACrC,eAAA;EACA,IAAI;EACJ,SAAS,OAAO;EAChB,WAAW,OAAO;EACX;CACR;CACA,IAAI,OAAO,UAAU,KAAA,KAAa,OAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,OAAO;CAC9E,IAAI,OAAO,WAAW,MAAM,IAAI,SAAS;CACzC,OAAO;AACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.mjs","names":["XC"],"sources":["../../../src/surfaces/cli/errors.ts"],"sourcesContent":["// CLI surface — typed errors carried up to the top-level renderer.\n//\n// Architecture (distilled/20-cli.md § Edge cases) enumerates the\n// surface's failure modes. Each one MUST resolve to a stable sysexit\n// code; the error tag here carries that mapping so the dispatcher\n// doesn't sprinkle exit codes through every command.\n//\n// Why tagged errors and not plain `Effect.fail(string)`?\n// - `catchTag` in commands can pick out the precise tag without\n// stringly matching.\n// - The cascade formatter (substrate/runtime/observability/\n// cascade-formatter.ts) renders these natively via their `_tag`.\n// - The `schema --json` command enumerates the tag table.\n\nimport { Data } from 'effect';\n\nimport { type ExitCode, ExitCode as XC } from './sysexits.ts';\n\n// -----------------------------------------------------------------------------\n// Tagged errors\n// -----------------------------------------------------------------------------\n\n/** Argv parsing produced an error — unknown subcommand, malformed\n * flag value, missing required positional. */\nexport class CliUsageError extends Data.TaggedError('CliUsageError')<{\n\treadonly message: string;\n\treadonly hint?: string;\n}> {}\n\n/** The user's `devstack.config.ts` could not be located (path probe\n * exhausted) or could not be imported. */\nexport class CliConfigNotFoundError extends Data.TaggedError('CliConfigNotFoundError')<{\n\treadonly message: string;\n\treadonly searchedPaths?: ReadonlyArray<string>;\n}> {}\n\n/** The config imported successfully but its default export is not a\n * `Stack` value (failed brand check, missing required field). */\nexport class CliConfigInvalidError extends Data.TaggedError('CliConfigInvalidError')<{\n\treadonly message: string;\n\treadonly cause?: unknown;\n}> {}\n\n/** A required service (Docker daemon, network) is unavailable. */\nexport class CliUnavailableError extends Data.TaggedError('CliUnavailableError')<{\n\treadonly message: string;\n\treadonly service: string;\n\treadonly hint?: string;\n}> {}\n\n/** Snapshot name/id not found. Carries the reference the caller\n * used so the failure renderer can echo it back. */\nexport class CliSnapshotNotFoundError extends Data.TaggedError('CliSnapshotNotFoundError')<{\n\treadonly snapshotRef: string;\n}> {}\n\nexport class CliSnapshotAmbiguousError extends Data.TaggedError('CliSnapshotAmbiguousError')<{\n\treadonly snapshotRef: string;\n\treadonly matches: ReadonlyArray<string>;\n}> {}\n\n/** Destructive verb refused because `--yes` was absent and prompting\n * was forbidden (non-TTY stdin or `--no-input`). */\nexport class CliConfirmRequiredError extends Data.TaggedError('CliConfirmRequiredError')<{\n\treadonly verb: string;\n\treadonly hint?: string;\n}> {}\n\n/** Destructive verb was prompted interactively and the user declined. */\nexport class CliConfirmDeclinedError extends Data.TaggedError('CliConfirmDeclinedError')<{\n\treadonly verb: string;\n\treadonly hint?: string;\n}> {}\n\n/** Engine reports a live supervisor for the target stack; the verb\n * refused to mutate shared state. */\nexport class CliSupervisorLiveError extends Data.TaggedError('CliSupervisorLiveError')<{\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly hint?: string;\n}> {}\n\n/** The verb requires a live supervisor (a stack must be `up`) but\n * none is running for `(app, stack)`. Distinguished from\n * `CliSupervisorLiveError` (the inverse case where the verb refused\n * because one IS live). */\nexport class CliNoSupervisorError extends Data.TaggedError('CliNoSupervisorError')<{\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly hint?: string;\n}> {}\n\n/** Internal/unexpected failure. Wraps an arbitrary cause; the cascade\n * formatter renders the inner. */\nexport class CliInternalError extends Data.TaggedError('CliInternalError')<{\n\treadonly message: string;\n\treadonly cause?: unknown;\n}> {}\n\n/** Sentinel: subcommand already pretty-rendered its failure. The\n * top-level renderer recognizes this tag and skips re-rendering, but\n * still propagates `exitCode` to the OS exit code.\n *\n * Architecture § Learnings: \"Already-reported sentinel pattern\" — the\n * marker traverses the cause structure used by the Effect runtime, so\n * the top-level `Effect.catch` sees it. */\nexport class CliAlreadyReportedError extends Data.TaggedError('CliAlreadyReportedError')<{\n\treadonly exitCode: ExitCode;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Union + sysexit projection\n// -----------------------------------------------------------------------------\n\nexport type CliError =\n\t| CliUsageError\n\t| CliConfigNotFoundError\n\t| CliConfigInvalidError\n\t| CliUnavailableError\n\t| CliSnapshotNotFoundError\n\t| CliSnapshotAmbiguousError\n\t| CliConfirmRequiredError\n\t| CliConfirmDeclinedError\n\t| CliSupervisorLiveError\n\t| CliNoSupervisorError\n\t| CliInternalError\n\t| CliAlreadyReportedError;\n\nexport const isCliError = (value: unknown): value is CliError => {\n\tif (typeof value !== 'object' || value === null) return false;\n\tconst tag = (value as { readonly _tag?: unknown })._tag;\n\tswitch (tag) {\n\t\tcase 'CliUsageError':\n\t\tcase 'CliConfigNotFoundError':\n\t\tcase 'CliConfigInvalidError':\n\t\tcase 'CliUnavailableError':\n\t\tcase 'CliSnapshotNotFoundError':\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\tcase 'CliConfirmRequiredError':\n\t\tcase 'CliConfirmDeclinedError':\n\t\tcase 'CliSupervisorLiveError':\n\t\tcase 'CliNoSupervisorError':\n\t\tcase 'CliInternalError':\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n};\n\n/** Project a tagged error to its sysexit code. The dispatcher reads\n * this to set `process.exitCode` — there is exactly one place in the\n * surface where tag → numeric mapping happens. */\nexport const exitCodeFor = (error: CliError): ExitCode => {\n\tswitch (error._tag) {\n\t\tcase 'CliUsageError':\n\t\t\treturn XC.USAGE;\n\t\tcase 'CliConfigNotFoundError':\n\t\t\treturn XC.NO_INPUT;\n\t\tcase 'CliConfigInvalidError':\n\t\t\treturn XC.CONFIG;\n\t\tcase 'CliUnavailableError':\n\t\t\treturn XC.UNAVAILABLE;\n\t\tcase 'CliSnapshotNotFoundError':\n\t\t\treturn XC.SNAPSHOT_NOT_FOUND;\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\t\treturn XC.USAGE;\n\t\tcase 'CliConfirmRequiredError':\n\t\tcase 'CliConfirmDeclinedError':\n\t\t\treturn XC.CONFIRM_REQUIRED;\n\t\tcase 'CliSupervisorLiveError':\n\t\t\treturn XC.SUPERVISOR_LIVE;\n\t\tcase 'CliNoSupervisorError':\n\t\t\treturn XC.UNAVAILABLE;\n\t\tcase 'CliInternalError':\n\t\t\treturn XC.SOFTWARE;\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn error.exitCode;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = error;\n\t\t\tvoid _exhaustive;\n\t\t\treturn XC.SOFTWARE;\n\t\t}\n\t}\n};\n\n/** Short single-line summary for the envelope's `error.summary`\n * field. Cascade detail lives in `error.chain[]`. */\nexport const summaryFor = (error: CliError): string => {\n\tswitch (error._tag) {\n\t\tcase 'CliUsageError':\n\t\t\treturn error.message;\n\t\tcase 'CliConfigNotFoundError':\n\t\t\treturn error.message;\n\t\tcase 'CliConfigInvalidError':\n\t\t\treturn error.message;\n\t\tcase 'CliUnavailableError':\n\t\t\treturn `${error.service} unavailable: ${error.message}`;\n\t\tcase 'CliSnapshotNotFoundError':\n\t\t\treturn `snapshot not found: ${error.snapshotRef}`;\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\t\treturn `snapshot reference is ambiguous: ${error.snapshotRef}`;\n\t\tcase 'CliConfirmRequiredError':\n\t\t\treturn `${error.verb} requires confirmation`;\n\t\tcase 'CliConfirmDeclinedError':\n\t\t\treturn `${error.verb} confirmation declined`;\n\t\tcase 'CliSupervisorLiveError':\n\t\t\treturn `supervisor live for ${error.app}/${error.stack}`;\n\t\tcase 'CliNoSupervisorError':\n\t\t\treturn `no supervisor running for ${error.app}/${error.stack}`;\n\t\tcase 'CliInternalError':\n\t\t\treturn error.message;\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn '(already reported)';\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = error;\n\t\t\tvoid _exhaustive;\n\t\t\treturn '(unknown error)';\n\t\t}\n\t}\n};\n\n/** Optional hint for the envelope's `error.hint` field. */\nexport const hintFor = (error: CliError): string | undefined => {\n\tswitch (error._tag) {\n\t\tcase 'CliUsageError':\n\t\t\treturn error.hint;\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\t\treturn `use one of these ids instead: ${error.matches.join(', ')}`;\n\t\tcase 'CliUnavailableError':\n\t\tcase 'CliConfirmRequiredError':\n\t\tcase 'CliConfirmDeclinedError':\n\t\tcase 'CliSupervisorLiveError':\n\t\tcase 'CliNoSupervisorError':\n\t\t\treturn error.hint;\n\t\tcase 'CliConfigNotFoundError':\n\t\t\t// Operator-facing hint: the most common cause is running a\n\t\t\t// devstack verb in a directory whose ancestors don't contain a\n\t\t\t// `devstack.config.ts`. Two actions resolve it — either\n\t\t\t// initialize one in the current tree, or point the loader at\n\t\t\t// an explicit path. We surface both so the envelope renderer\n\t\t\t// (JSON `error.hint`, human stderr line) can render one short\n\t\t\t// line instead of forcing the caller to remember the recipe.\n\t\t\treturn 'config file not found; run `devstack init` or pass `--config <path>`';\n\t\tcase 'CliConfigInvalidError':\n\t\tcase 'CliSnapshotNotFoundError':\n\t\tcase 'CliInternalError':\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn undefined;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = error;\n\t\t\tvoid _exhaustive;\n\t\t\treturn undefined;\n\t\t}\n\t}\n};\n"],"mappings":";;;;;AAwBA,IAAa,gBAAb,cAAmC,KAAK,YAAY,gBAAgB,CAGjE;;;AAIH,IAAa,yBAAb,cAA4C,KAAK,YAAY,yBAAyB,CAGnF;;;AAIH,IAAa,wBAAb,cAA2C,KAAK,YAAY,wBAAwB,CAGjF;;AAGH,IAAa,sBAAb,cAAyC,KAAK,YAAY,sBAAsB,CAI7E;;;AAIH,IAAa,2BAAb,cAA8C,KAAK,YAAY,2BAA2B,CAEvF;AAEH,IAAa,4BAAb,cAA+C,KAAK,YAAY,4BAA4B,CAGzF;;;AAIH,IAAa,0BAAb,cAA6C,KAAK,YAAY,0BAA0B,CAGrF;;AAGH,IAAa,0BAAb,cAA6C,KAAK,YAAY,0BAA0B,CAGrF;;;AAIH,IAAa,yBAAb,cAA4C,KAAK,YAAY,yBAAyB,CAInF;AAMuC,KAAK,YAAY,uBAAuB;;;AAQlF,IAAa,mBAAb,cAAsC,KAAK,YAAY,mBAAmB,CAGvE;AAS0C,KAAK,YAAY,0BAA0B;AAsBxF,MAAa,cAAc,UAAsC;AAChE,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AAExD,SADa,MAAsC,MACnD;EACC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,0BACJ,QAAO;EACR,QACC,QAAO;;;;;;AAOV,MAAa,eAAe,UAA8B;AACzD,SAAQ,MAAM,MAAd;EACC,KAAK,gBACJ,QAAOA,SAAG;EACX,KAAK,yBACJ,QAAOA,SAAG;EACX,KAAK,wBACJ,QAAOA,SAAG;EACX,KAAK,sBACJ,QAAOA,SAAG;EACX,KAAK,2BACJ,QAAOA,SAAG;EACX,KAAK,4BACJ,QAAOA,SAAG;EACX,KAAK;EACL,KAAK,0BACJ,QAAOA,SAAG;EACX,KAAK,yBACJ,QAAOA,SAAG;EACX,KAAK,uBACJ,QAAOA,SAAG;EACX,KAAK,mBACJ,QAAOA,SAAG;EACX,KAAK,0BACJ,QAAO,MAAM;EACd,QAGC,QAAOA,SAAG;;;;;AAOb,MAAa,cAAc,UAA4B;AACtD,SAAQ,MAAM,MAAd;EACC,KAAK,gBACJ,QAAO,MAAM;EACd,KAAK,yBACJ,QAAO,MAAM;EACd,KAAK,wBACJ,QAAO,MAAM;EACd,KAAK,sBACJ,QAAO,GAAG,MAAM,QAAQ,gBAAgB,MAAM;EAC/C,KAAK,2BACJ,QAAO,uBAAuB,MAAM;EACrC,KAAK,4BACJ,QAAO,oCAAoC,MAAM;EAClD,KAAK,0BACJ,QAAO,GAAG,MAAM,KAAK;EACtB,KAAK,0BACJ,QAAO,GAAG,MAAM,KAAK;EACtB,KAAK,yBACJ,QAAO,uBAAuB,MAAM,IAAI,GAAG,MAAM;EAClD,KAAK,uBACJ,QAAO,6BAA6B,MAAM,IAAI,GAAG,MAAM;EACxD,KAAK,mBACJ,QAAO,MAAM;EACd,KAAK,0BACJ,QAAO;EACR,QAGC,QAAO;;;;AAMV,MAAa,WAAW,UAAwC;AAC/D,SAAQ,MAAM,MAAd;EACC,KAAK,gBACJ,QAAO,MAAM;EACd,KAAK,4BACJ,QAAO,iCAAiC,MAAM,QAAQ,KAAK,KAAK;EACjE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,uBACJ,QAAO,MAAM;EACd,KAAK,yBAQJ,QAAO;EACR,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,0BACJ;EACD,QAGC"}
1
+ {"version":3,"file":"errors.mjs","names":["XC"],"sources":["../../../src/surfaces/cli/errors.ts"],"sourcesContent":["// CLI surface — typed errors carried up to the top-level renderer.\n//\n// Architecture (distilled/20-cli.md § Edge cases) enumerates the\n// surface's failure modes. Each one MUST resolve to a stable sysexit\n// code; the error tag here carries that mapping so the dispatcher\n// doesn't sprinkle exit codes through every command.\n//\n// Why tagged errors and not plain `Effect.fail(string)`?\n// - `catchTag` in commands can pick out the precise tag without\n// stringly matching.\n// - The cascade formatter (substrate/runtime/observability/\n// cascade-formatter.ts) renders these natively via their `_tag`.\n// - The `schema --json` command enumerates the tag table.\n\nimport { Data } from 'effect';\n\nimport { type ExitCode, ExitCode as XC } from './sysexits.ts';\n\n// -----------------------------------------------------------------------------\n// Tagged errors\n// -----------------------------------------------------------------------------\n\n/** Argv parsing produced an error — unknown subcommand, malformed\n * flag value, missing required positional. */\nexport class CliUsageError extends Data.TaggedError('CliUsageError')<{\n\treadonly message: string;\n\treadonly hint?: string;\n}> {}\n\n/** The user's `devstack.config.ts` could not be located (path probe\n * exhausted) or could not be imported. */\nexport class CliConfigNotFoundError extends Data.TaggedError('CliConfigNotFoundError')<{\n\treadonly message: string;\n\treadonly searchedPaths?: ReadonlyArray<string>;\n}> {}\n\n/** The config imported successfully but its default export is not a\n * `Stack` value (failed brand check, missing required field). */\nexport class CliConfigInvalidError extends Data.TaggedError('CliConfigInvalidError')<{\n\treadonly message: string;\n\treadonly cause?: unknown;\n}> {}\n\n/** A required service (Docker daemon, network) is unavailable. */\nexport class CliUnavailableError extends Data.TaggedError('CliUnavailableError')<{\n\treadonly message: string;\n\treadonly service: string;\n\treadonly hint?: string;\n}> {}\n\n/** Snapshot name/id not found. Carries the reference the caller\n * used so the failure renderer can echo it back. */\nexport class CliSnapshotNotFoundError extends Data.TaggedError('CliSnapshotNotFoundError')<{\n\treadonly snapshotRef: string;\n}> {}\n\nexport class CliSnapshotAmbiguousError extends Data.TaggedError('CliSnapshotAmbiguousError')<{\n\treadonly snapshotRef: string;\n\treadonly matches: ReadonlyArray<string>;\n}> {}\n\n/** Destructive verb refused because `--yes` was absent and prompting\n * was forbidden (non-TTY stdin or `--no-input`). */\nexport class CliConfirmRequiredError extends Data.TaggedError('CliConfirmRequiredError')<{\n\treadonly verb: string;\n\treadonly hint?: string;\n}> {}\n\n/** Destructive verb was prompted interactively and the user declined. */\nexport class CliConfirmDeclinedError extends Data.TaggedError('CliConfirmDeclinedError')<{\n\treadonly verb: string;\n\treadonly hint?: string;\n}> {}\n\n/** Engine reports a live supervisor for the target stack; the verb\n * refused to mutate shared state. */\nexport class CliSupervisorLiveError extends Data.TaggedError('CliSupervisorLiveError')<{\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly hint?: string;\n}> {}\n\n/** The verb requires a live supervisor (a stack must be `up`) but\n * none is running for `(app, stack)`. Distinguished from\n * `CliSupervisorLiveError` (the inverse case where the verb refused\n * because one IS live). */\nexport class CliNoSupervisorError extends Data.TaggedError('CliNoSupervisorError')<{\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly hint?: string;\n}> {}\n\n/** Internal/unexpected failure. Wraps an arbitrary cause; the cascade\n * formatter renders the inner. */\nexport class CliInternalError extends Data.TaggedError('CliInternalError')<{\n\treadonly message: string;\n\treadonly cause?: unknown;\n}> {}\n\n/** Sentinel: subcommand already pretty-rendered its failure. The\n * top-level renderer recognizes this tag and skips re-rendering, but\n * still propagates `exitCode` to the OS exit code.\n *\n * Architecture § Learnings: \"Already-reported sentinel pattern\" — the\n * marker traverses the cause structure used by the Effect runtime, so\n * the top-level `Effect.catch` sees it. */\nexport class CliAlreadyReportedError extends Data.TaggedError('CliAlreadyReportedError')<{\n\treadonly exitCode: ExitCode;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Union + sysexit projection\n// -----------------------------------------------------------------------------\n\nexport type CliError =\n\t| CliUsageError\n\t| CliConfigNotFoundError\n\t| CliConfigInvalidError\n\t| CliUnavailableError\n\t| CliSnapshotNotFoundError\n\t| CliSnapshotAmbiguousError\n\t| CliConfirmRequiredError\n\t| CliConfirmDeclinedError\n\t| CliSupervisorLiveError\n\t| CliNoSupervisorError\n\t| CliInternalError\n\t| CliAlreadyReportedError;\n\nexport const isCliError = (value: unknown): value is CliError => {\n\tif (typeof value !== 'object' || value === null) return false;\n\tconst tag = (value as { readonly _tag?: unknown })._tag;\n\tswitch (tag) {\n\t\tcase 'CliUsageError':\n\t\tcase 'CliConfigNotFoundError':\n\t\tcase 'CliConfigInvalidError':\n\t\tcase 'CliUnavailableError':\n\t\tcase 'CliSnapshotNotFoundError':\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\tcase 'CliConfirmRequiredError':\n\t\tcase 'CliConfirmDeclinedError':\n\t\tcase 'CliSupervisorLiveError':\n\t\tcase 'CliNoSupervisorError':\n\t\tcase 'CliInternalError':\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n};\n\n/** Project a tagged error to its sysexit code. The dispatcher reads\n * this to set `process.exitCode` — there is exactly one place in the\n * surface where tag → numeric mapping happens. */\nexport const exitCodeFor = (error: CliError): ExitCode => {\n\tswitch (error._tag) {\n\t\tcase 'CliUsageError':\n\t\t\treturn XC.USAGE;\n\t\tcase 'CliConfigNotFoundError':\n\t\t\treturn XC.NO_INPUT;\n\t\tcase 'CliConfigInvalidError':\n\t\t\treturn XC.CONFIG;\n\t\tcase 'CliUnavailableError':\n\t\t\treturn XC.UNAVAILABLE;\n\t\tcase 'CliSnapshotNotFoundError':\n\t\t\treturn XC.SNAPSHOT_NOT_FOUND;\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\t\treturn XC.USAGE;\n\t\tcase 'CliConfirmRequiredError':\n\t\tcase 'CliConfirmDeclinedError':\n\t\t\treturn XC.CONFIRM_REQUIRED;\n\t\tcase 'CliSupervisorLiveError':\n\t\t\treturn XC.SUPERVISOR_LIVE;\n\t\tcase 'CliNoSupervisorError':\n\t\t\treturn XC.UNAVAILABLE;\n\t\tcase 'CliInternalError':\n\t\t\treturn XC.SOFTWARE;\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn error.exitCode;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = error;\n\t\t\tvoid _exhaustive;\n\t\t\treturn XC.SOFTWARE;\n\t\t}\n\t}\n};\n\n/** Short single-line summary for the envelope's `error.summary`\n * field. Cascade detail lives in `error.chain[]`. */\nexport const summaryFor = (error: CliError): string => {\n\tswitch (error._tag) {\n\t\tcase 'CliUsageError':\n\t\t\treturn error.message;\n\t\tcase 'CliConfigNotFoundError':\n\t\t\treturn error.message;\n\t\tcase 'CliConfigInvalidError':\n\t\t\treturn error.message;\n\t\tcase 'CliUnavailableError':\n\t\t\treturn `${error.service} unavailable: ${error.message}`;\n\t\tcase 'CliSnapshotNotFoundError':\n\t\t\treturn `snapshot not found: ${error.snapshotRef}`;\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\t\treturn `snapshot reference is ambiguous: ${error.snapshotRef}`;\n\t\tcase 'CliConfirmRequiredError':\n\t\t\treturn `${error.verb} requires confirmation`;\n\t\tcase 'CliConfirmDeclinedError':\n\t\t\treturn `${error.verb} confirmation declined`;\n\t\tcase 'CliSupervisorLiveError':\n\t\t\treturn `supervisor live for ${error.app}/${error.stack}`;\n\t\tcase 'CliNoSupervisorError':\n\t\t\treturn `no supervisor running for ${error.app}/${error.stack}`;\n\t\tcase 'CliInternalError':\n\t\t\treturn error.message;\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn '(already reported)';\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = error;\n\t\t\tvoid _exhaustive;\n\t\t\treturn '(unknown error)';\n\t\t}\n\t}\n};\n\n/** Optional hint for the envelope's `error.hint` field. */\nexport const hintFor = (error: CliError): string | undefined => {\n\tswitch (error._tag) {\n\t\tcase 'CliUsageError':\n\t\t\treturn error.hint;\n\t\tcase 'CliSnapshotAmbiguousError':\n\t\t\treturn `use one of these ids instead: ${error.matches.join(', ')}`;\n\t\tcase 'CliUnavailableError':\n\t\tcase 'CliConfirmRequiredError':\n\t\tcase 'CliConfirmDeclinedError':\n\t\tcase 'CliSupervisorLiveError':\n\t\tcase 'CliNoSupervisorError':\n\t\t\treturn error.hint;\n\t\tcase 'CliConfigNotFoundError':\n\t\t\t// Operator-facing hint: the most common cause is running a\n\t\t\t// devstack verb in a directory whose ancestors don't contain a\n\t\t\t// `devstack.config.ts`. Two actions resolve it — either\n\t\t\t// initialize one in the current tree, or point the loader at\n\t\t\t// an explicit path. We surface both so the envelope renderer\n\t\t\t// (JSON `error.hint`, human stderr line) can render one short\n\t\t\t// line instead of forcing the caller to remember the recipe.\n\t\t\treturn 'config file not found; run `devstack init` or pass `--config <path>`';\n\t\tcase 'CliConfigInvalidError':\n\t\tcase 'CliSnapshotNotFoundError':\n\t\tcase 'CliInternalError':\n\t\tcase 'CliAlreadyReportedError':\n\t\t\treturn undefined;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = error;\n\t\t\tvoid _exhaustive;\n\t\t\treturn undefined;\n\t\t}\n\t}\n};\n"],"mappings":";;;;;AAwBA,IAAa,gBAAb,cAAmC,KAAK,YAAY,eAAe,CAAC,CAGjE,CAAC;;;AAIJ,IAAa,yBAAb,cAA4C,KAAK,YAAY,wBAAwB,CAAC,CAGnF,CAAC;;;AAIJ,IAAa,wBAAb,cAA2C,KAAK,YAAY,uBAAuB,CAAC,CAGjF,CAAC;;AAGJ,IAAa,sBAAb,cAAyC,KAAK,YAAY,qBAAqB,CAAC,CAI7E,CAAC;;;AAIJ,IAAa,2BAAb,cAA8C,KAAK,YAAY,0BAA0B,CAAC,CAEvF,CAAC;AAEJ,IAAa,4BAAb,cAA+C,KAAK,YAAY,2BAA2B,CAAC,CAGzF,CAAC;;;AAIJ,IAAa,0BAAb,cAA6C,KAAK,YAAY,yBAAyB,CAAC,CAGrF,CAAC;;AAGJ,IAAa,0BAAb,cAA6C,KAAK,YAAY,yBAAyB,CAAC,CAGrF,CAAC;;;AAIJ,IAAa,yBAAb,cAA4C,KAAK,YAAY,wBAAwB,CAAC,CAInF,CAAC;AAMsC,KAAK,YAAY,sBAAsB;;;AAQjF,IAAa,mBAAb,cAAsC,KAAK,YAAY,kBAAkB,CAAC,CAGvE,CAAC;AASyC,KAAK,YAAY,yBAAyB;AAsBvF,MAAa,cAAc,UAAsC;CAChE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CAExD,QADa,MAAsC,MACnD;EACC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,2BACJ,OAAO;EACR,SACC,OAAO;CACT;AACD;;;;AAKA,MAAa,eAAe,UAA8B;CACzD,QAAQ,MAAM,MAAd;EACC,KAAK,iBACJ,OAAOA,SAAG;EACX,KAAK,0BACJ,OAAOA,SAAG;EACX,KAAK,yBACJ,OAAOA,SAAG;EACX,KAAK,uBACJ,OAAOA,SAAG;EACX,KAAK,4BACJ,OAAOA,SAAG;EACX,KAAK,6BACJ,OAAOA,SAAG;EACX,KAAK;EACL,KAAK,2BACJ,OAAOA,SAAG;EACX,KAAK,0BACJ,OAAOA,SAAG;EACX,KAAK,wBACJ,OAAOA,SAAG;EACX,KAAK,oBACJ,OAAOA,SAAG;EACX,KAAK,2BACJ,OAAO,MAAM;EACd,SAGC,OAAOA,SAAG;CAEZ;AACD;;;AAIA,MAAa,cAAc,UAA4B;CACtD,QAAQ,MAAM,MAAd;EACC,KAAK,iBACJ,OAAO,MAAM;EACd,KAAK,0BACJ,OAAO,MAAM;EACd,KAAK,yBACJ,OAAO,MAAM;EACd,KAAK,uBACJ,OAAO,GAAG,MAAM,QAAQ,gBAAgB,MAAM;EAC/C,KAAK,4BACJ,OAAO,uBAAuB,MAAM;EACrC,KAAK,6BACJ,OAAO,oCAAoC,MAAM;EAClD,KAAK,2BACJ,OAAO,GAAG,MAAM,KAAK;EACtB,KAAK,2BACJ,OAAO,GAAG,MAAM,KAAK;EACtB,KAAK,0BACJ,OAAO,uBAAuB,MAAM,IAAI,GAAG,MAAM;EAClD,KAAK,wBACJ,OAAO,6BAA6B,MAAM,IAAI,GAAG,MAAM;EACxD,KAAK,oBACJ,OAAO,MAAM;EACd,KAAK,2BACJ,OAAO;EACR,SAGC,OAAO;CAET;AACD;;AAGA,MAAa,WAAW,UAAwC;CAC/D,QAAQ,MAAM,MAAd;EACC,KAAK,iBACJ,OAAO,MAAM;EACd,KAAK,6BACJ,OAAO,iCAAiC,MAAM,QAAQ,KAAK,IAAI;EAChE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,wBACJ,OAAO,MAAM;EACd,KAAK,0BAQJ,OAAO;EACR,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,2BACJ;EACD,SAGC;CAEF;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"flags.mjs","names":[],"sources":["../../../src/surfaces/cli/flags.ts"],"sourcesContent":["// CLI surface — shared flag types and subcommand helpers.\n//\n// Stricli owns argv parsing in `surfaces/cli/index.ts`. This file\n// keeps the resolved flag shape and the tiny helpers used by nested\n// command implementations that still receive a typed `rest` tail\n// (currently snapshot subcommands).\n\nimport { CliUsageError } from './errors.ts';\n\n// -----------------------------------------------------------------------------\n// Global flag definitions (shared across every verb)\n// -----------------------------------------------------------------------------\n\n/** Output mode resolved from `--json` (or `DEVSTACK_JSON=1`). */\nexport type OutputMode = 'human' | 'json';\n\n/** Renderer selected by the CLI. `tui` maps to the Ink-backed live\n * dashboard; `plain` is line-oriented stderr output; `silent` mounts no\n * visible renderer. */\nexport type CliRendererMode = 'tui' | 'plain' | 'silent';\n\n/** Confirmation policy resolved from `--yes` + `--no-input` + TTY\n * state of stdin. */\nexport interface ConfirmPolicy {\n\treadonly assumeYes: boolean;\n\treadonly forbidPrompt: boolean;\n\treadonly stdinIsTty: boolean;\n}\n\n/** Bundle of command-scoped flags after Stricli parsing plus env\n * fallback resolution. */\nexport interface GlobalFlags {\n\treadonly outputMode: OutputMode;\n\treadonly app: string | undefined;\n\treadonly stack: string | undefined;\n\treadonly stateDir: string | undefined;\n\treadonly configPath: string | undefined;\n\treadonly network: string | undefined;\n\treadonly renderer: CliRendererMode | undefined;\n\treadonly dryRun: boolean;\n\treadonly confirm: ConfirmPolicy;\n\t/** Verbosity bump; primarily affects logger filter. */\n\treadonly verbose: boolean;\n\t/** Argv tail after the global-flag pass; subcommand parsers slice\n\t * positional arguments and verb-specific flags out of this. */\n\treadonly rest: ReadonlyArray<string>;\n}\n\n/** Environment-variable names the CLI consults. Centralized so the\n * `schema --json` command can enumerate them. */\nexport const ENV_VARS = {\n\tJSON: 'DEVSTACK_JSON',\n\tNO_INPUT: 'DEVSTACK_NO_INPUT',\n\tAPP: 'DEVSTACK_APP',\n\tSTACK: 'DEVSTACK_STACK',\n\tSTATE_DIR: 'DEVSTACK_STATE_DIR',\n\tCONFIG_PATH: 'DEVSTACK_CONFIG',\n\tNETWORK: 'DEVSTACK_NETWORK',\n\tNO_COLOR: 'NO_COLOR',\n} as const;\n\nexport type EnvVarName = (typeof ENV_VARS)[keyof typeof ENV_VARS];\n\n// -----------------------------------------------------------------------------\n// Subcommand-flag helpers\n// -----------------------------------------------------------------------------\n\n/** Pop the next positional argument from `rest`. Returns undefined if\n * none remain. */\nexport const takePositional = (\n\trest: ReadonlyArray<string>,\n): { readonly head: string | undefined; readonly tail: ReadonlyArray<string> } => {\n\tconst idx = rest.findIndex((tok) => !tok.startsWith('-'));\n\tif (idx === -1) return { head: undefined, tail: rest };\n\tconst tail = [...rest.slice(0, idx), ...rest.slice(idx + 1)];\n\treturn { head: rest[idx], tail };\n};\n\n/** Look up a value flag (`--name=val` or `--name val`). */\nexport const takeValueFlag = (\n\trest: ReadonlyArray<string>,\n\tname: string,\n): { readonly value: string | undefined; readonly tail: ReadonlyArray<string> } => {\n\tconst prefix = `--${name}=`;\n\tfor (let i = 0; i < rest.length; i++) {\n\t\tconst tok = rest[i]!;\n\t\tif (tok.startsWith(prefix)) {\n\t\t\treturn {\n\t\t\t\tvalue: tok.slice(prefix.length),\n\t\t\t\ttail: [...rest.slice(0, i), ...rest.slice(i + 1)],\n\t\t\t};\n\t\t}\n\t\tif (tok === `--${name}`) {\n\t\t\tconst next = rest[i + 1];\n\t\t\tif (next === undefined || next.startsWith('-')) {\n\t\t\t\tthrow new CliUsageError({ message: `flag --${name} requires a value` });\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tvalue: next,\n\t\t\t\ttail: [...rest.slice(0, i), ...rest.slice(i + 2)],\n\t\t\t};\n\t\t}\n\t}\n\treturn { value: undefined, tail: rest };\n};\n"],"mappings":";;;;AAkDA,MAAa,WAAW;CACvB,MAAM;CACN,UAAU;CACV,KAAK;CACL,OAAO;CACP,WAAW;CACX,aAAa;CACb,SAAS;CACT,UAAU;CACV;;;AAUD,MAAa,kBACZ,SACiF;CACjF,MAAM,MAAM,KAAK,WAAW,QAAQ,CAAC,IAAI,WAAW,IAAI,CAAC;AACzD,KAAI,QAAQ,GAAI,QAAO;EAAE,MAAM,KAAA;EAAW,MAAM;EAAM;CACtD,MAAM,OAAO,CAAC,GAAG,KAAK,MAAM,GAAG,IAAI,EAAE,GAAG,KAAK,MAAM,MAAM,EAAE,CAAC;AAC5D,QAAO;EAAE,MAAM,KAAK;EAAM;EAAM;;;AAIjC,MAAa,iBACZ,MACA,SACkF;CAClF,MAAM,SAAS,KAAK,KAAK;AACzB,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACrC,MAAM,MAAM,KAAK;AACjB,MAAI,IAAI,WAAW,OAAO,CACzB,QAAO;GACN,OAAO,IAAI,MAAM,OAAO,OAAO;GAC/B,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,EAAE,EAAE,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC;GACjD;AAEF,MAAI,QAAQ,KAAK,QAAQ;GACxB,MAAM,OAAO,KAAK,IAAI;AACtB,OAAI,SAAS,KAAA,KAAa,KAAK,WAAW,IAAI,CAC7C,OAAM,IAAI,cAAc,EAAE,SAAS,UAAU,KAAK,oBAAoB,CAAC;AAExE,UAAO;IACN,OAAO;IACP,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,EAAE,EAAE,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC;IACjD;;;AAGH,QAAO;EAAE,OAAO,KAAA;EAAW,MAAM;EAAM"}
1
+ {"version":3,"file":"flags.mjs","names":[],"sources":["../../../src/surfaces/cli/flags.ts"],"sourcesContent":["// CLI surface — shared flag types and subcommand helpers.\n//\n// Stricli owns argv parsing in `surfaces/cli/index.ts`. This file\n// keeps the resolved flag shape and the tiny helpers used by nested\n// command implementations that still receive a typed `rest` tail\n// (currently snapshot subcommands).\n\nimport { CliUsageError } from './errors.ts';\n\n// -----------------------------------------------------------------------------\n// Global flag definitions (shared across every verb)\n// -----------------------------------------------------------------------------\n\n/** Output mode resolved from `--json` (or `DEVSTACK_JSON=1`). */\nexport type OutputMode = 'human' | 'json';\n\n/** Renderer selected by the CLI. `tui` maps to the Ink-backed live\n * dashboard; `plain` is line-oriented stderr output; `silent` mounts no\n * visible renderer. */\nexport type CliRendererMode = 'tui' | 'plain' | 'silent';\n\nexport type SnapshotStalePolicy = 'warn' | 'block' | 'clean-start';\n\n/** Confirmation policy resolved from `--yes` + `--no-input` + TTY\n * state of stdin. */\nexport interface ConfirmPolicy {\n\treadonly assumeYes: boolean;\n\treadonly forbidPrompt: boolean;\n\treadonly stdinIsTty: boolean;\n}\n\n/** Bundle of command-scoped flags after Stricli parsing plus env\n * fallback resolution. */\nexport interface GlobalFlags {\n\treadonly outputMode: OutputMode;\n\treadonly app: string | undefined;\n\treadonly stack: string | undefined;\n\treadonly stateDir: string | undefined;\n\treadonly configPath: string | undefined;\n\treadonly network: string | undefined;\n\treadonly renderer: CliRendererMode | undefined;\n\treadonly fromSnapshot?: string;\n\treadonly snapshotCache?: string;\n\treadonly snapshotStalePolicy?: SnapshotStalePolicy;\n\treadonly dryRun: boolean;\n\treadonly confirm: ConfirmPolicy;\n\t/** Verbosity bump; primarily affects logger filter. */\n\treadonly verbose: boolean;\n\t/** Argv tail after the global-flag pass; subcommand parsers slice\n\t * positional arguments and verb-specific flags out of this. */\n\treadonly rest: ReadonlyArray<string>;\n}\n\n/** Environment-variable names the CLI consults. Centralized so the\n * `schema --json` command can enumerate them. */\nexport const ENV_VARS = {\n\tJSON: 'DEVSTACK_JSON',\n\tNO_INPUT: 'DEVSTACK_NO_INPUT',\n\tAPP: 'DEVSTACK_APP',\n\tSTACK: 'DEVSTACK_STACK',\n\tSTATE_DIR: 'DEVSTACK_STATE_DIR',\n\tCONFIG_PATH: 'DEVSTACK_CONFIG',\n\tNETWORK: 'DEVSTACK_NETWORK',\n\tNO_COLOR: 'NO_COLOR',\n} as const;\n\n// -----------------------------------------------------------------------------\n// Subcommand-flag helpers\n// -----------------------------------------------------------------------------\n\n/** Pop the next positional argument from `rest`. Returns undefined if\n * none remain. */\nexport const takePositional = (\n\trest: ReadonlyArray<string>,\n): { readonly head: string | undefined; readonly tail: ReadonlyArray<string> } => {\n\tconst idx = rest.findIndex((tok) => !tok.startsWith('-'));\n\tif (idx === -1) return { head: undefined, tail: rest };\n\tconst tail = [...rest.slice(0, idx), ...rest.slice(idx + 1)];\n\treturn { head: rest[idx], tail };\n};\n\n/** Look up a value flag (`--name=val` or `--name val`). */\nexport const takeValueFlag = (\n\trest: ReadonlyArray<string>,\n\tname: string,\n): { readonly value: string | undefined; readonly tail: ReadonlyArray<string> } => {\n\tconst prefix = `--${name}=`;\n\tfor (let i = 0; i < rest.length; i++) {\n\t\tconst tok = rest[i]!;\n\t\tif (tok.startsWith(prefix)) {\n\t\t\treturn {\n\t\t\t\tvalue: tok.slice(prefix.length),\n\t\t\t\ttail: [...rest.slice(0, i), ...rest.slice(i + 1)],\n\t\t\t};\n\t\t}\n\t\tif (tok === `--${name}`) {\n\t\t\tconst next = rest[i + 1];\n\t\t\tif (next === undefined || next.startsWith('-')) {\n\t\t\t\tthrow new CliUsageError({ message: `flag --${name} requires a value` });\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tvalue: next,\n\t\t\t\ttail: [...rest.slice(0, i), ...rest.slice(i + 2)],\n\t\t\t};\n\t\t}\n\t}\n\treturn { value: undefined, tail: rest };\n};\n"],"mappings":";;;;AAuDA,MAAa,WAAW;CACvB,MAAM;CACN,UAAU;CACV,KAAK;CACL,OAAO;CACP,WAAW;CACX,aAAa;CACb,SAAS;CACT,UAAU;AACX;;;AAQA,MAAa,kBACZ,SACiF;CACjF,MAAM,MAAM,KAAK,WAAW,QAAQ,CAAC,IAAI,WAAW,GAAG,CAAC;CACxD,IAAI,QAAQ,IAAI,OAAO;EAAE,MAAM,KAAA;EAAW,MAAM;CAAK;CACrD,MAAM,OAAO,CAAC,GAAG,KAAK,MAAM,GAAG,GAAG,GAAG,GAAG,KAAK,MAAM,MAAM,CAAC,CAAC;CAC3D,OAAO;EAAE,MAAM,KAAK;EAAM;CAAK;AAChC;;AAGA,MAAa,iBACZ,MACA,SACkF;CAClF,MAAM,SAAS,KAAK,KAAK;CACzB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACrC,MAAM,MAAM,KAAK;EACjB,IAAI,IAAI,WAAW,MAAM,GACxB,OAAO;GACN,OAAO,IAAI,MAAM,OAAO,MAAM;GAC9B,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,CAAC,GAAG,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC;EACjD;EAED,IAAI,QAAQ,KAAK,QAAQ;GACxB,MAAM,OAAO,KAAK,IAAI;GACtB,IAAI,SAAS,KAAA,KAAa,KAAK,WAAW,GAAG,GAC5C,MAAM,IAAI,cAAc,EAAE,SAAS,UAAU,KAAK,mBAAmB,CAAC;GAEvE,OAAO;IACN,OAAO;IACP,MAAM,CAAC,GAAG,KAAK,MAAM,GAAG,CAAC,GAAG,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC;GACjD;EACD;CACD;CACA,OAAO;EAAE,OAAO,KAAA;EAAW,MAAM;CAAK;AACvC"}