@mysten-incubation/devstack 0.1.0 → 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.
- package/README.md +7 -4
- package/dashboard-ui/assets/grpc-a4usE3Nk.js +3 -0
- package/dashboard-ui/assets/index-B82Bh84P.css +1 -0
- package/dashboard-ui/assets/index-CRYJ4pru.js +1277 -0
- package/dashboard-ui/index.html +2 -2
- package/dist/api/define-capabilities.d.mts +1 -20
- package/dist/api/define-capabilities.mjs +15 -22
- package/dist/api/define-capabilities.mjs.map +1 -1
- package/dist/api/define-devstack-with.d.mts +7 -1
- package/dist/api/define-devstack-with.mjs.map +1 -1
- package/dist/api/define-devstack.mjs.map +1 -1
- package/dist/api/define-plugin.d.mts +2 -1
- package/dist/api/inference-network.d.mts +31 -17
- package/dist/api/inference-network.mjs +40 -43
- package/dist/api/inference-network.mjs.map +1 -1
- package/dist/api/load-config.mjs +88 -0
- package/dist/api/load-config.mjs.map +1 -0
- package/dist/api/mode-narrowed-factory.d.mts +1 -1
- package/dist/api/mode-narrowed-factory.mjs.map +1 -1
- package/dist/api/run-stack-internal.mjs +202 -0
- package/dist/api/run-stack-internal.mjs.map +1 -0
- package/dist/api/run-stack.d.mts +82 -31
- package/dist/api/run-stack.mjs +22 -141
- package/dist/api/run-stack.mjs.map +1 -1
- package/dist/build-integrations/dapp-kit/index.d.mts +61 -0
- package/dist/build-integrations/dapp-kit/index.mjs +58 -0
- package/dist/build-integrations/dapp-kit/index.mjs.map +1 -0
- package/dist/build-integrations/playwright/config.d.mts +1 -30
- package/dist/build-integrations/playwright/config.mjs +1 -27
- package/dist/build-integrations/playwright/config.mjs.map +1 -1
- package/dist/build-integrations/playwright/errors.d.mts +4 -7
- package/dist/build-integrations/playwright/errors.mjs.map +1 -1
- package/dist/build-integrations/playwright/global-setup.d.mts +42 -71
- package/dist/build-integrations/playwright/global-setup.mjs +142 -218
- package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
- package/dist/build-integrations/playwright/index.d.mts +2 -2
- package/dist/build-integrations/playwright/index.mjs +2 -2
- package/dist/build-integrations/playwright/stack-context.d.mts +3 -1
- package/dist/build-integrations/playwright/stack-context.mjs +4 -2
- package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
- package/dist/build-integrations/playwright/wallet-context.mjs +44 -19
- package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
- package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -1
- package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
- package/dist/build-integrations/runtime/discover.d.mts +6 -4
- package/dist/build-integrations/runtime/discover.mjs +15 -4
- package/dist/build-integrations/runtime/discover.mjs.map +1 -1
- package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
- package/dist/build-integrations/runtime/errors.mjs.map +1 -1
- package/dist/build-integrations/runtime/read-stack-context.mjs +3 -3
- package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +23 -7
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs +25 -12
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -1
- package/dist/build-integrations/runtime/stack-context.d.mts +2 -2
- package/dist/build-integrations/vite/index.d.mts +84 -19
- package/dist/build-integrations/vite/index.mjs +203 -28
- package/dist/build-integrations/vite/index.mjs.map +1 -1
- package/dist/build-integrations/vitest/config.d.mts +20 -2
- package/dist/build-integrations/vitest/config.mjs +16 -4
- package/dist/build-integrations/vitest/config.mjs.map +1 -1
- package/dist/build-integrations/vitest/env.d.mts +18 -10
- package/dist/build-integrations/vitest/env.mjs +11 -10
- package/dist/build-integrations/vitest/env.mjs.map +1 -1
- package/dist/build-integrations/vitest/errors.d.mts +7 -11
- package/dist/build-integrations/vitest/errors.mjs +3 -4
- package/dist/build-integrations/vitest/errors.mjs.map +1 -1
- package/dist/build-integrations/vitest/global-setup.d.mts +35 -0
- package/dist/build-integrations/vitest/global-setup.mjs +156 -0
- package/dist/build-integrations/vitest/global-setup.mjs.map +1 -0
- package/dist/build-integrations/vitest/index.d.mts +3 -2
- package/dist/build-integrations/vitest/index.mjs +3 -2
- package/dist/build-integrations/vitest/setup.mjs +2 -2
- package/dist/build-integrations/vitest/setup.mjs.map +1 -1
- package/dist/build-integrations/vitest/stack-context.d.mts +5 -3
- package/dist/build-integrations/vitest/stack-context.mjs +3 -2
- package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
- package/dist/cli/bail.mjs.map +1 -1
- package/dist/cli/doctor-probes.mjs +1 -3
- package/dist/cli/doctor-probes.mjs.map +1 -1
- package/dist/cli/main.d.mts +23 -1
- package/dist/cli/main.mjs +63 -8
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/prune-direct.mjs.map +1 -1
- package/dist/cli/snapshot-reader.mjs.map +1 -1
- package/dist/cli/up-lifecycle.mjs.map +1 -1
- package/dist/cli/wirings/apply.mjs +28 -21
- package/dist/cli/wirings/apply.mjs.map +1 -1
- package/dist/cli/wirings/codegen.mjs +108 -0
- package/dist/cli/wirings/codegen.mjs.map +1 -0
- package/dist/cli/wirings/config-loader.mjs +12 -62
- package/dist/cli/wirings/config-loader.mjs.map +1 -1
- package/dist/cli/wirings/dump-ids.mjs +86 -0
- package/dist/cli/wirings/dump-ids.mjs.map +1 -0
- package/dist/cli/wirings/engine-command.mjs +1 -1
- package/dist/cli/wirings/engine-command.mjs.map +1 -1
- package/dist/cli/wirings/identity.mjs +2 -2
- package/dist/cli/wirings/identity.mjs.map +1 -1
- package/dist/cli/wirings/provide-file-system.mjs.map +1 -1
- package/dist/cli/wirings/read-devstack-version.mjs +17 -0
- package/dist/cli/wirings/read-devstack-version.mjs.map +1 -0
- package/dist/cli/wirings/snapshot.mjs +27 -34
- package/dist/cli/wirings/snapshot.mjs.map +1 -1
- package/dist/cli/wirings/up-ipc.mjs +147 -0
- package/dist/cli/wirings/up-ipc.mjs.map +1 -0
- package/dist/cli/wirings/up.mjs +218 -198
- package/dist/cli/wirings/up.mjs.map +1 -1
- package/dist/cli/wirings/wipe.mjs +1 -1
- package/dist/cli/wirings/wipe.mjs.map +1 -1
- package/dist/contracts/chain-probe.d.mts +1 -1
- package/dist/contracts/chain-probe.mjs +1 -1
- package/dist/contracts/chain-probe.mjs.map +1 -1
- package/dist/contracts/codegenable.d.mts +60 -6
- package/dist/contracts/codegenable.mjs +28 -0
- package/dist/contracts/codegenable.mjs.map +1 -0
- package/dist/contracts/config-bindings.mjs +162 -0
- package/dist/contracts/config-bindings.mjs.map +1 -0
- package/dist/contracts/container-runtime.d.mts +23 -17
- package/dist/contracts/plugin-expander.mjs.map +1 -1
- package/dist/contracts/snapshotable.d.mts +5 -7
- package/dist/contracts/wallet-protocol.d.mts +2 -5
- package/dist/contracts/wallet-protocol.mjs +2 -5
- package/dist/contracts/wallet-protocol.mjs.map +1 -1
- package/dist/index.d.mts +21 -26
- package/dist/index.mjs +8 -9
- package/dist/orchestrators/boot.d.mts +28 -0
- package/dist/orchestrators/boot.mjs +440 -0
- package/dist/orchestrators/boot.mjs.map +1 -0
- package/dist/orchestrators/codegen/bindings.d.mts +13 -1
- package/dist/orchestrators/codegen/bindings.mjs +23 -9
- package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
- package/dist/orchestrators/codegen/config-runtime.mjs +208 -0
- package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -0
- package/dist/orchestrators/codegen/emit.mjs +1 -1
- package/dist/orchestrators/codegen/emit.mjs.map +1 -1
- package/dist/orchestrators/codegen/errors.mjs +21 -1
- package/dist/orchestrators/codegen/errors.mjs.map +1 -1
- package/dist/orchestrators/codegen/format.mjs +2 -0
- package/dist/orchestrators/codegen/format.mjs.map +1 -1
- package/dist/orchestrators/codegen/gitignore.mjs +30 -11
- package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
- package/dist/orchestrators/codegen/id-config.mjs +107 -0
- package/dist/orchestrators/codegen/id-config.mjs.map +1 -0
- package/dist/orchestrators/codegen/output-location.mjs +23 -31
- package/dist/orchestrators/codegen/output-location.mjs.map +1 -1
- package/dist/orchestrators/codegen/paths.mjs +8 -1
- package/dist/orchestrators/codegen/paths.mjs.map +1 -1
- package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
- package/dist/orchestrators/codegen/service.mjs +286 -58
- package/dist/orchestrators/codegen/service.mjs.map +1 -1
- package/dist/orchestrators/layers.mjs +31 -0
- package/dist/orchestrators/layers.mjs.map +1 -0
- package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -1
- package/dist/orchestrators/lifecycle-prune/index.mjs +8 -10
- package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -1
- package/dist/orchestrators/network-options.d.mts +52 -0
- package/dist/orchestrators/network-options.mjs +43 -0
- package/dist/orchestrators/network-options.mjs.map +1 -0
- package/dist/orchestrators/router/cleanup.mjs.map +1 -1
- package/dist/orchestrators/router/cors.mjs.map +1 -1
- package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
- package/dist/orchestrators/router/errors.mjs.map +1 -1
- package/dist/orchestrators/router/file-provider.mjs.map +1 -1
- package/dist/orchestrators/router/hostname.mjs.map +1 -1
- package/dist/orchestrators/router/profile.mjs +1 -1
- package/dist/orchestrators/router/profile.mjs.map +1 -1
- package/dist/orchestrators/router/service.d.mts +2 -2
- package/dist/orchestrators/router/service.mjs +12 -27
- package/dist/orchestrators/router/service.mjs.map +1 -1
- package/dist/orchestrators/router/traefik-container.mjs +1 -1
- package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
- package/dist/orchestrators/snapshot/capture.mjs +171 -195
- package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
- package/dist/orchestrators/snapshot/descriptor.d.mts +1 -1
- package/dist/orchestrators/snapshot/descriptor.mjs +53 -11
- package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
- package/dist/orchestrators/snapshot/identity-guard.mjs +3 -5
- package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -1
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs +32 -101
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -1
- package/dist/orchestrators/snapshot/index.mjs +1 -4
- package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
- package/dist/orchestrators/snapshot/interrupted-restore.mjs +116 -0
- package/dist/orchestrators/snapshot/interrupted-restore.mjs.map +1 -0
- package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -1
- package/dist/orchestrators/snapshot/prune.mjs +40 -31
- package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
- package/dist/orchestrators/snapshot/restore.mjs +221 -196
- package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
- package/dist/orchestrators/snapshot/service.mjs +72 -62
- package/dist/orchestrators/snapshot/service.mjs.map +1 -1
- package/dist/orchestrators/snapshot/wipe.mjs +67 -56
- package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
- package/dist/plugins/account/codegen.mjs +3 -0
- package/dist/plugins/account/codegen.mjs.map +1 -1
- package/dist/plugins/account/errors.d.mts +2 -2
- package/dist/plugins/account/errors.mjs +1 -4
- package/dist/plugins/account/errors.mjs.map +1 -1
- package/dist/plugins/account/funding.mjs +3 -27
- package/dist/plugins/account/funding.mjs.map +1 -1
- package/dist/plugins/account/index.d.mts +3 -8
- package/dist/plugins/account/index.mjs +71 -35
- package/dist/plugins/account/index.mjs.map +1 -1
- package/dist/plugins/account/keypair.d.mts +8 -7
- package/dist/plugins/account/keypair.mjs +5 -18
- package/dist/plugins/account/keypair.mjs.map +1 -1
- package/dist/plugins/account/lease.mjs.map +1 -1
- package/dist/plugins/account/registry.d.mts +1 -46
- package/dist/plugins/account/registry.mjs.map +1 -1
- package/dist/plugins/account/service.d.mts +43 -34
- package/dist/plugins/account/service.mjs +9 -54
- package/dist/plugins/account/service.mjs.map +1 -1
- package/dist/plugins/account/snapshot.mjs.map +1 -1
- package/dist/plugins/account/variants/ephemeral.mjs.map +1 -1
- package/dist/plugins/account/variants/impersonate.mjs.map +1 -1
- package/dist/plugins/account/variants/signer.mjs.map +1 -1
- package/dist/plugins/action/discriminator.mjs.map +1 -1
- package/dist/plugins/action/errors.mjs +1 -4
- package/dist/plugins/action/errors.mjs.map +1 -1
- package/dist/plugins/action/execute.mjs +3 -4
- package/dist/plugins/action/execute.mjs.map +1 -1
- package/dist/plugins/action/index.d.mts +2 -2
- package/dist/plugins/action/index.mjs +7 -11
- package/dist/plugins/action/index.mjs.map +1 -1
- package/dist/plugins/action/service.d.mts +5 -7
- package/dist/plugins/action/service.mjs +2 -16
- package/dist/plugins/action/service.mjs.map +1 -1
- package/dist/plugins/coin/address-resolution.mjs.map +1 -1
- package/dist/plugins/coin/codegen.mjs +97 -16
- package/dist/plugins/coin/codegen.mjs.map +1 -1
- package/dist/plugins/coin/discovery.mjs.map +1 -1
- package/dist/plugins/coin/errors.mjs +1 -4
- package/dist/plugins/coin/errors.mjs.map +1 -1
- package/dist/plugins/coin/index.d.mts +4 -34
- package/dist/plugins/coin/index.mjs +47 -28
- package/dist/plugins/coin/index.mjs.map +1 -1
- package/dist/plugins/coin/metadata.d.mts +1 -0
- package/dist/plugins/coin/metadata.mjs +8 -9
- package/dist/plugins/coin/metadata.mjs.map +1 -1
- package/dist/plugins/coin/mint.mjs +7 -21
- package/dist/plugins/coin/mint.mjs.map +1 -1
- package/dist/plugins/coin/registry.mjs +33 -20
- package/dist/plugins/coin/registry.mjs.map +1 -1
- package/dist/plugins/coin/service.d.mts +1 -1
- package/dist/plugins/coin/service.mjs +1 -8
- package/dist/plugins/coin/service.mjs.map +1 -1
- package/dist/plugins/coin/snapshot.mjs.map +1 -1
- package/dist/plugins/coin/type-strings.mjs.map +1 -1
- package/dist/plugins/dashboard/domain.mjs +106 -167
- package/dist/plugins/dashboard/domain.mjs.map +1 -1
- package/dist/plugins/dashboard/index.mjs +13 -13
- package/dist/plugins/dashboard/index.mjs.map +1 -1
- package/dist/plugins/dashboard/origin-policy.mjs +3 -3
- package/dist/plugins/dashboard/origin-policy.mjs.map +1 -1
- package/dist/plugins/dashboard/routable.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/builder.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/enums.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/root.mjs +23 -44
- package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/types.mjs +37 -91
- package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
- package/dist/plugins/dashboard/schema.mjs.map +1 -1
- package/dist/plugins/dashboard/server.mjs.map +1 -1
- package/dist/plugins/deepbook/codegen.d.mts +12 -11
- package/dist/plugins/deepbook/codegen.mjs +108 -11
- package/dist/plugins/deepbook/codegen.mjs.map +1 -1
- package/dist/plugins/deepbook/deploy.mjs +7 -14
- package/dist/plugins/deepbook/deploy.mjs.map +1 -1
- package/dist/plugins/deepbook/errors.mjs +4 -2
- package/dist/plugins/deepbook/errors.mjs.map +1 -1
- package/dist/plugins/deepbook/faucet-strategy.mjs +4 -10
- package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/deepbook/hash.mjs.map +1 -1
- package/dist/plugins/deepbook/index.d.mts +38 -34
- package/dist/plugins/deepbook/index.mjs +133 -64
- package/dist/plugins/deepbook/index.mjs.map +1 -1
- package/dist/plugins/deepbook/plugin-key.mjs.map +1 -1
- package/dist/plugins/deepbook/pyth/index.mjs +4 -8
- package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
- package/dist/plugins/deepbook/snapshot.mjs +0 -1
- package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
- package/dist/plugins/deepbook/type-strings.mjs.map +1 -1
- package/dist/plugins/deepbook/types.d.mts +2 -1
- package/dist/plugins/deepbook/types.mjs.map +1 -1
- package/dist/plugins/faucet/dispatcher.d.mts +3 -3
- package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
- package/dist/plugins/faucet/errors.mjs.map +1 -1
- package/dist/plugins/faucet/http.mjs +2 -10
- package/dist/plugins/faucet/http.mjs.map +1 -1
- package/dist/plugins/faucet/index.mjs +0 -1
- package/dist/plugins/faucet/index.mjs.map +1 -1
- package/dist/plugins/host-service/errors.d.mts +1 -3
- package/dist/plugins/host-service/errors.mjs +1 -2
- package/dist/plugins/host-service/errors.mjs.map +1 -1
- package/dist/plugins/host-service/index.d.mts +1 -2
- package/dist/plugins/host-service/index.mjs +11 -11
- package/dist/plugins/host-service/index.mjs.map +1 -1
- package/dist/plugins/host-service/routable.mjs.map +1 -1
- package/dist/plugins/host-service/service.mjs +13 -13
- package/dist/plugins/host-service/service.mjs.map +1 -1
- package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -1
- package/dist/plugins/internal/codegen-helpers.mjs +2 -0
- package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
- package/dist/plugins/internal/funding-failure-error.mjs.map +1 -1
- package/dist/plugins/{postgres → internal/postgres-sidecar}/connection.mjs +1 -1
- package/dist/plugins/internal/postgres-sidecar/connection.mjs.map +1 -0
- package/dist/plugins/{postgres → internal/postgres-sidecar}/db-ensure.mjs +30 -16
- package/dist/plugins/internal/postgres-sidecar/db-ensure.mjs.map +1 -0
- package/dist/plugins/internal/postgres-sidecar/errors.mjs +21 -0
- package/dist/plugins/internal/postgres-sidecar/errors.mjs.map +1 -0
- package/dist/{substrate/runtime/scoped-multimap → plugins/internal/postgres-sidecar}/index.mjs +1 -0
- package/dist/plugins/internal/postgres-sidecar/service.mjs +121 -0
- package/dist/plugins/internal/postgres-sidecar/service.mjs.map +1 -0
- package/dist/plugins/package/build.mjs +2 -2
- package/dist/plugins/package/build.mjs.map +1 -1
- package/dist/plugins/package/codegen.d.mts +7 -14
- package/dist/plugins/package/codegen.mjs +187 -59
- package/dist/plugins/package/codegen.mjs.map +1 -1
- package/dist/plugins/package/dep-resolution.mjs +51 -3
- package/dist/plugins/package/dep-resolution.mjs.map +1 -1
- package/dist/plugins/package/errors.mjs +1 -4
- package/dist/plugins/package/errors.mjs.map +1 -1
- package/dist/plugins/package/git-source.d.mts +18 -0
- package/dist/plugins/package/git-source.mjs +119 -0
- package/dist/plugins/package/git-source.mjs.map +1 -0
- package/dist/plugins/package/index.d.mts +28 -19
- package/dist/plugins/package/index.mjs +107 -32
- package/dist/plugins/package/index.mjs.map +1 -1
- package/dist/plugins/package/mode-known.mjs +2 -2
- package/dist/plugins/package/mode-known.mjs.map +1 -1
- package/dist/plugins/package/mode-local.mjs +18 -35
- package/dist/plugins/package/mode-local.mjs.map +1 -1
- package/dist/plugins/package/publish-executor.mjs +13 -8
- package/dist/plugins/package/publish-executor.mjs.map +1 -1
- package/dist/plugins/package/publish-output.d.mts +1 -11
- package/dist/plugins/package/publish-output.mjs +1 -9
- package/dist/plugins/package/publish-output.mjs.map +1 -1
- package/dist/plugins/package/registry.d.mts +1 -1
- package/dist/plugins/package/registry.mjs +26 -14
- package/dist/plugins/package/registry.mjs.map +1 -1
- package/dist/plugins/package/service.mjs.map +1 -1
- package/dist/plugins/package/snapshot.mjs.map +1 -1
- package/dist/plugins/router-entrypoints.mjs +1 -3
- package/dist/plugins/router-entrypoints.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +1 -2
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +1 -6
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
- package/dist/plugins/seal/codegen.d.mts +1 -5
- package/dist/plugins/seal/codegen.mjs +83 -12
- package/dist/plugins/seal/codegen.mjs.map +1 -1
- package/dist/plugins/seal/config-render.mjs +2 -6
- package/dist/plugins/seal/config-render.mjs.map +1 -1
- package/dist/plugins/seal/deploy.mjs +18 -29
- package/dist/plugins/seal/deploy.mjs.map +1 -1
- package/dist/plugins/seal/errors.d.mts +4 -5
- package/dist/plugins/seal/errors.mjs +1 -8
- package/dist/plugins/seal/errors.mjs.map +1 -1
- package/dist/plugins/seal/index.d.mts +7 -28
- package/dist/plugins/seal/index.mjs +69 -47
- package/dist/plugins/seal/index.mjs.map +1 -1
- package/dist/plugins/seal/key-manager.mjs.map +1 -1
- package/dist/plugins/seal/key-server.mjs +1 -6
- package/dist/plugins/seal/key-server.mjs.map +1 -1
- package/dist/plugins/seal/keygen.mjs +2 -3
- package/dist/plugins/seal/keygen.mjs.map +1 -1
- package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
- package/dist/plugins/seal/mode/live.mjs +1 -1
- package/dist/plugins/seal/mode/live.mjs.map +1 -1
- package/dist/plugins/seal/mode/local-keygen.mjs +4 -10
- package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
- package/dist/plugins/seal/plugin-key.mjs.map +1 -1
- package/dist/plugins/seal/registry-publish.mjs.map +1 -1
- package/dist/plugins/seal/routable.mjs.map +1 -1
- package/dist/plugins/seal/service.mjs.map +1 -1
- package/dist/plugins/seal/snapshot.mjs +1 -2
- package/dist/plugins/seal/snapshot.mjs.map +1 -1
- package/dist/plugins/sui/auto-tick.mjs +5 -5
- package/dist/plugins/sui/auto-tick.mjs.map +1 -1
- package/dist/plugins/sui/chain-build-container.mjs +2 -2
- package/dist/plugins/sui/chain-build-container.mjs.map +1 -1
- package/dist/plugins/sui/chain-probe.mjs +4 -4
- package/dist/plugins/sui/chain-probe.mjs.map +1 -1
- package/dist/plugins/sui/codegen.d.mts +9 -7
- package/dist/plugins/sui/codegen.mjs +49 -46
- package/dist/plugins/sui/codegen.mjs.map +1 -1
- package/dist/plugins/sui/errors.d.mts +1 -1
- package/dist/plugins/sui/errors.mjs +1 -9
- package/dist/plugins/sui/errors.mjs.map +1 -1
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.d.mts +1 -1
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.mjs +3 -7
- package/dist/plugins/sui/exec/index.mjs.map +1 -0
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.mjs +1 -1
- package/dist/plugins/sui/exec/sign-and-dispatch.mjs.map +1 -0
- package/dist/plugins/sui/fork-faucet-strategy.mjs +2 -6
- package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -1
- package/dist/plugins/sui/fork-orchestration.mjs +13 -23
- package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
- package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
- package/dist/plugins/sui/index.d.mts +34 -83
- package/dist/plugins/sui/index.mjs +200 -68
- package/dist/plugins/sui/index.mjs.map +1 -1
- package/dist/{substrate/runtime/sui-ledger → plugins/sui/ledger}/object-ref.mjs +1 -1
- package/dist/plugins/sui/ledger/object-ref.mjs.map +1 -0
- package/dist/plugins/sui/local-faucet-strategy.mjs +1 -5
- package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -1
- package/dist/plugins/sui/log-attrs.mjs +11 -0
- package/dist/plugins/sui/log-attrs.mjs.map +1 -0
- package/dist/plugins/sui/mode/external.mjs +4 -12
- package/dist/plugins/sui/mode/external.mjs.map +1 -1
- package/dist/plugins/sui/mode/fork.mjs +19 -16
- package/dist/plugins/sui/mode/fork.mjs.map +1 -1
- package/dist/plugins/sui/mode/live.mjs +4 -17
- package/dist/plugins/sui/mode/live.mjs.map +1 -1
- package/dist/plugins/sui/mode/local.d.mts +1 -0
- package/dist/plugins/sui/mode/local.mjs +203 -61
- package/dist/plugins/sui/mode/local.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared-boot.mjs +18 -23
- package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared.d.mts +6 -7
- package/dist/plugins/sui/mode/shared.mjs.map +1 -1
- package/dist/plugins/sui/mode/spec.d.mts +23 -6
- package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.mjs +28 -30
- package/dist/plugins/sui/move/index.mjs.map +1 -0
- package/dist/plugins/sui/move-summary-runner.mjs +8 -4
- package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
- package/dist/{substrate/network.d.mts → plugins/sui/network-config.d.mts} +11 -10
- package/dist/plugins/sui/network-resolver.d.mts +6 -6
- package/dist/plugins/sui/routable.mjs.map +1 -1
- package/dist/plugins/sui/service.mjs +10 -6
- package/dist/plugins/sui/service.mjs.map +1 -1
- package/dist/plugins/sui/snapshot.mjs +10 -5
- package/dist/plugins/sui/snapshot.mjs.map +1 -1
- package/dist/plugins/wallet/codegen.d.mts +8 -6
- package/dist/plugins/wallet/codegen.mjs +4 -10
- package/dist/plugins/wallet/codegen.mjs.map +1 -1
- package/dist/plugins/wallet/errors.mjs +1 -4
- package/dist/plugins/wallet/errors.mjs.map +1 -1
- package/dist/plugins/wallet/index.d.mts +3 -6
- package/dist/plugins/wallet/index.mjs +16 -21
- package/dist/plugins/wallet/index.mjs.map +1 -1
- package/dist/plugins/wallet/origin-policy.mjs +3 -3
- package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
- package/dist/plugins/wallet/pairing.mjs +6 -24
- package/dist/plugins/wallet/pairing.mjs.map +1 -1
- package/dist/plugins/wallet/protocol.mjs.map +1 -1
- package/dist/plugins/wallet/routable.mjs.map +1 -1
- package/dist/plugins/wallet/server.mjs +17 -24
- package/dist/plugins/wallet/server.mjs.map +1 -1
- package/dist/plugins/wallet/service.d.mts +2 -2
- package/dist/plugins/wallet/service.mjs +4 -15
- package/dist/plugins/wallet/service.mjs.map +1 -1
- package/dist/plugins/wallet/snapshot.mjs.map +1 -1
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +1 -5
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/walrus/codegen.d.mts +2 -13
- package/dist/plugins/walrus/codegen.mjs +93 -28
- package/dist/plugins/walrus/codegen.mjs.map +1 -1
- package/dist/plugins/walrus/deploy-paths.mjs +2 -3
- package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
- package/dist/plugins/walrus/deploy.mjs +26 -19
- package/dist/plugins/walrus/deploy.mjs.map +1 -1
- package/dist/plugins/walrus/errors.mjs +1 -8
- package/dist/plugins/walrus/errors.mjs.map +1 -1
- package/dist/plugins/walrus/faucet-strategy.mjs +15 -1
- package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/walrus/index.d.mts +13 -44
- package/dist/plugins/walrus/index.mjs +119 -122
- package/dist/plugins/walrus/index.mjs.map +1 -1
- package/dist/plugins/walrus/mode/known-deploy.mjs +6 -6
- package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
- package/dist/plugins/walrus/mode/local-cluster.d.mts +2 -2
- package/dist/plugins/walrus/mode/local-cluster.mjs +2 -10
- package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
- package/dist/plugins/walrus/plugin-key.mjs.map +1 -1
- package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
- package/dist/plugins/walrus/routable.mjs.map +1 -1
- package/dist/plugins/walrus/service.mjs.map +1 -1
- package/dist/plugins/walrus/snapshot.mjs +3 -3
- package/dist/plugins/walrus/snapshot.mjs.map +1 -1
- package/dist/plugins/walrus/storage-nodes.mjs +53 -14
- package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
- package/dist/plugins/walrus/wal-swap.mjs +4 -8
- package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
- package/dist/primitives/artifact-publisher.mjs.map +1 -1
- package/dist/primitives/cache.d.mts +1 -1
- package/dist/runtime/docker/client.mjs +47 -3
- package/dist/runtime/docker/client.mjs.map +1 -1
- package/dist/runtime/docker/container.mjs +37 -57
- package/dist/runtime/docker/container.mjs.map +1 -1
- package/dist/runtime/docker/errors.mjs.map +1 -1
- package/dist/runtime/docker/exec.mjs +2 -2
- package/dist/runtime/docker/exec.mjs.map +1 -1
- package/dist/runtime/docker/image.mjs +10 -11
- package/dist/runtime/docker/image.mjs.map +1 -1
- package/dist/runtime/docker/index.mjs +0 -1
- package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -1
- package/dist/runtime/docker/inventory.mjs +9 -9
- package/dist/runtime/docker/inventory.mjs.map +1 -1
- package/dist/runtime/docker/labels.mjs +12 -1
- package/dist/runtime/docker/labels.mjs.map +1 -1
- package/dist/runtime/docker/network.mjs +6 -6
- package/dist/runtime/docker/network.mjs.map +1 -1
- package/dist/runtime/docker/render-run-args.mjs.map +1 -1
- package/dist/runtime/docker/service.mjs +31 -45
- package/dist/runtime/docker/service.mjs.map +1 -1
- package/dist/runtime/docker/sweep.mjs +14 -64
- package/dist/runtime/docker/sweep.mjs.map +1 -1
- package/dist/runtime/docker/volume.mjs +1 -1
- package/dist/runtime/docker/volume.mjs.map +1 -1
- package/dist/runtime/docker/wrap.mjs +14 -2
- package/dist/runtime/docker/wrap.mjs.map +1 -1
- package/dist/substrate/brand.d.mts +2 -5
- package/dist/substrate/brand.mjs +3 -2
- package/dist/substrate/brand.mjs.map +1 -1
- package/dist/substrate/cross-process.mjs +2 -16
- package/dist/substrate/cross-process.mjs.map +1 -1
- package/dist/substrate/event-time.mjs +0 -2
- package/dist/substrate/event-time.mjs.map +1 -1
- package/dist/substrate/events.d.mts +46 -16
- package/dist/substrate/identity.d.mts +11 -5
- package/dist/substrate/manifest.d.mts +33 -26
- package/dist/substrate/manifest.mjs +8 -3
- package/dist/substrate/manifest.mjs.map +1 -1
- package/dist/substrate/options.d.mts +33 -4
- package/dist/substrate/plugin-ctx.d.mts +70 -0
- package/dist/substrate/plugin-ctx.mjs +66 -0
- package/dist/substrate/plugin-ctx.mjs.map +1 -0
- package/dist/substrate/plugin.d.mts +46 -38
- package/dist/substrate/plugin.mjs +13 -9
- package/dist/substrate/plugin.mjs.map +1 -1
- package/dist/substrate/projection.d.mts +1 -1
- package/dist/substrate/runtime/atomic-write.mjs +3 -4
- package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
- package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
- package/dist/substrate/runtime/cache/service.mjs +50 -20
- package/dist/substrate/runtime/cache/service.mjs.map +1 -1
- package/dist/substrate/runtime/config-validation.mjs.map +1 -1
- package/dist/substrate/runtime/control-plane/domain.mjs +34 -12
- package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -1
- package/dist/substrate/runtime/control-plane/service.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +14 -17
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/index.mjs +0 -2
- package/dist/substrate/runtime/cross-process/live-clock.mjs +1 -1
- package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/liveness.mjs +11 -18
- package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +2 -2
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/roster.mjs +17 -127
- package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/stack-lock.mjs +29 -28
- package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
- package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
- package/dist/substrate/runtime/errors.mjs +1 -13
- package/dist/substrate/runtime/errors.mjs.map +1 -1
- package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -1
- package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -1
- package/dist/substrate/runtime/host-gateway.mjs.map +1 -1
- package/dist/substrate/runtime/host-tree-tar/index.mjs +15 -163
- package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
- package/dist/substrate/runtime/http-probe.d.mts +1 -3
- package/dist/substrate/runtime/http-probe.mjs.map +1 -1
- package/dist/substrate/runtime/index.mjs +1 -6
- package/dist/substrate/runtime/lease-broker/service.mjs +5 -23
- package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs +3 -3
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/graph-input-id.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/graph-input-id.mjs +133 -0
- package/dist/substrate/runtime/lifecycle/graph-input-id.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/index.mjs +2 -2
- package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -1
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +22 -1
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs +2 -15
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs +29 -25
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/signals.mjs +1 -1
- package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +0 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
- package/dist/substrate/runtime/managed-container.d.mts +5 -1
- package/dist/substrate/runtime/managed-container.mjs +8 -10
- package/dist/substrate/runtime/managed-container.mjs.map +1 -1
- package/dist/substrate/runtime/manifest/manifest.mjs +8 -30
- package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
- package/dist/substrate/runtime/mode-errors.d.mts +1 -2
- package/dist/substrate/runtime/mode-errors.mjs.map +1 -1
- package/dist/substrate/runtime/observability/cascade-formatter.mjs +1 -11
- package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
- package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -1
- package/dist/substrate/runtime/observability/index.d.mts +1 -1
- package/dist/substrate/runtime/observability/index.mjs +4 -6
- package/dist/substrate/runtime/observability/log-attrs.mjs +46 -0
- package/dist/substrate/runtime/observability/log-attrs.mjs.map +1 -0
- package/dist/substrate/runtime/observability/log-store.mjs.map +1 -1
- package/dist/substrate/runtime/observability/logger.mjs +3 -3
- package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
- package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -1
- package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
- package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -1
- package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
- package/dist/substrate/runtime/observability/subprocess-capture.mjs +2 -2
- package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -1
- package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -1
- package/dist/substrate/runtime/paths.mjs +27 -9
- package/dist/substrate/runtime/paths.mjs.map +1 -1
- package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -1
- package/dist/substrate/runtime/port-broker/service.mjs +10 -27
- package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
- package/dist/substrate/runtime/probes.d.mts +2 -3
- package/dist/substrate/runtime/probes.mjs.map +1 -1
- package/dist/substrate/runtime/process-supervisor.mjs.map +1 -1
- package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
- package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
- package/dist/substrate/runtime/projection/update.mjs +87 -11
- package/dist/substrate/runtime/projection/update.mjs.map +1 -1
- package/dist/substrate/runtime/random-suffix.mjs.map +1 -1
- package/dist/substrate/runtime/reconcile/fs-plan.mjs +146 -0
- package/dist/substrate/runtime/reconcile/fs-plan.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/graph.mjs +19 -0
- package/dist/substrate/runtime/reconcile/graph.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/index.mjs +5 -0
- package/dist/substrate/runtime/reconcile/label.mjs +41 -0
- package/dist/substrate/runtime/reconcile/label.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/spec.mjs +15 -0
- package/dist/substrate/runtime/reconcile/spec.mjs.map +1 -0
- package/dist/substrate/runtime/retry-policy.d.mts +2 -3
- package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
- package/dist/substrate/runtime/routed-url.mjs.map +1 -1
- package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
- package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
- package/dist/substrate/runtime/stage-and-swap/index.mjs +49 -12
- package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/service.mjs +29 -17
- package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
- package/dist/substrate/runtime/subnet-broker.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/acquire-node.mjs +188 -56
- package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/background-tasks.mjs +79 -65
- package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/command-loop.mjs +82 -23
- package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs +16 -0
- package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/errors.mjs +11 -2
- package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/index.mjs +2 -0
- package/dist/substrate/runtime/supervisor/shutdown.mjs +6 -6
- package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs +60 -70
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/state.d.mts +1 -1
- package/dist/substrate/runtime/supervisor/state.mjs +1 -1
- package/dist/substrate/runtime/supervisor/state.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/teardown.mjs +10 -9
- package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/wiring.mjs +6 -20
- package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -1
- package/dist/substrate/runtime/tar/reader.mjs +216 -0
- package/dist/substrate/runtime/tar/reader.mjs.map +1 -0
- package/dist/substrate/runtime/typed-env.mjs.map +1 -1
- package/dist/substrate/versioned-doc-schema.mjs.map +1 -1
- package/dist/substrate/versioned-doc-sync.mjs +5 -5
- package/dist/substrate/versioned-doc-sync.mjs.map +1 -1
- package/dist/surfaces/cli/command-tree.mjs +49 -7
- package/dist/surfaces/cli/command-tree.mjs.map +1 -1
- package/dist/surfaces/cli/commands/config.mjs +1 -1
- package/dist/surfaces/cli/commands/config.mjs.map +1 -1
- package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -1
- package/dist/surfaces/cli/commands/confirm.mjs.map +1 -1
- package/dist/surfaces/cli/commands/doctor.mjs +1 -1
- package/dist/surfaces/cli/commands/doctor.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune.mjs +1 -1
- package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
- package/dist/surfaces/cli/commands/snapshot.mjs +1 -1
- package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -1
- package/dist/surfaces/cli/commands/status.mjs +1 -1
- package/dist/surfaces/cli/commands/status.mjs.map +1 -1
- package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
- package/dist/surfaces/cli/commands/wipe.mjs +3 -4
- package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
- package/dist/surfaces/cli/envelope.mjs.map +1 -1
- package/dist/surfaces/cli/errors.mjs.map +1 -1
- package/dist/surfaces/cli/flags.mjs.map +1 -1
- package/dist/surfaces/cli/index.mjs +45 -14
- package/dist/surfaces/cli/index.mjs.map +1 -1
- package/dist/surfaces/cli/output.mjs.map +1 -1
- package/dist/surfaces/cli/sysexits.mjs.map +1 -1
- package/dist/surfaces/tui/app.mjs +0 -21
- package/dist/surfaces/tui/app.mjs.map +1 -1
- package/dist/surfaces/tui/dashboard.mjs +0 -48
- package/dist/surfaces/tui/dashboard.mjs.map +1 -1
- package/dist/surfaces/tui/display-derivation.mjs +80 -16
- package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
- package/dist/surfaces/tui/errors.mjs.map +1 -1
- package/dist/surfaces/tui/event-log.mjs +0 -9
- package/dist/surfaces/tui/event-log.mjs.map +1 -1
- package/dist/surfaces/tui/heartbeat.mjs.map +1 -1
- package/dist/surfaces/tui/index.mjs +2 -2
- package/dist/surfaces/tui/index.mjs.map +1 -1
- package/dist/surfaces/tui/input.mjs.map +1 -1
- package/dist/surfaces/tui/mode-detect.mjs.map +1 -1
- package/dist/surfaces/tui/mount-ink.mjs.map +1 -1
- package/dist/surfaces/tui/plain-renderer.mjs +26 -19
- package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
- package/dist/surfaces/tui/resource-table.mjs +8 -10
- package/dist/surfaces/tui/resource-table.mjs.map +1 -1
- package/images/postgres/Dockerfile +0 -1
- package/images/sui/Dockerfile +27 -54
- package/images/sui/entrypoint.sh +17 -179
- package/package.json +23 -15
- package/dashboard-ui/assets/index-Bmi1UtAg.js +0 -1356
- package/dashboard-ui/assets/index-D5EShVt4.js +0 -3
- package/dashboard-ui/assets/index-Deml9drg.css +0 -1
- package/dist/api/plugin-errors.d.mts +0 -7
- package/dist/api/plugin-errors.mjs +0 -10
- package/dist/api/plugin-errors.mjs.map +0 -1
- package/dist/cli/wirings/build-verb-layers.mjs +0 -42
- package/dist/cli/wirings/build-verb-layers.mjs.map +0 -1
- package/dist/contracts/capability-decl.d.mts +0 -40
- package/dist/orchestrators/built-in-plugin-layers.mjs +0 -54
- package/dist/orchestrators/built-in-plugin-layers.mjs.map +0 -1
- package/dist/orchestrators/run.mjs +0 -91
- package/dist/orchestrators/run.mjs.map +0 -1
- package/dist/orchestrators/runtime-composition.d.mts +0 -10
- package/dist/orchestrators/runtime-composition.mjs +0 -252
- package/dist/orchestrators/runtime-composition.mjs.map +0 -1
- package/dist/orchestrators/snapshot/capture-command.d.mts +0 -1
- package/dist/orchestrators/snapshot/capture-command.mjs +0 -25
- package/dist/orchestrators/snapshot/capture-command.mjs.map +0 -1
- package/dist/orchestrators/snapshot/pending-marker.mjs +0 -99
- package/dist/orchestrators/snapshot/pending-marker.mjs.map +0 -1
- package/dist/orchestrators/snapshot/recover-pending.mjs +0 -223
- package/dist/orchestrators/snapshot/recover-pending.mjs.map +0 -1
- package/dist/orchestrators/snapshot/state-document.d.mts +0 -1
- package/dist/orchestrators/snapshot/state-document.mjs +0 -58
- package/dist/orchestrators/snapshot/state-document.mjs.map +0 -1
- package/dist/plugins/account/spans.mjs +0 -16
- package/dist/plugins/account/spans.mjs.map +0 -1
- package/dist/plugins/account/variants/env.mjs +0 -24
- package/dist/plugins/account/variants/env.mjs.map +0 -1
- package/dist/plugins/account/variants/inline.mjs +0 -13
- package/dist/plugins/account/variants/inline.mjs.map +0 -1
- package/dist/plugins/account/variants/keystore.mjs +0 -91
- package/dist/plugins/account/variants/keystore.mjs.map +0 -1
- package/dist/plugins/action/spans.mjs +0 -11
- package/dist/plugins/action/spans.mjs.map +0 -1
- package/dist/plugins/coin/spans.mjs +0 -20
- package/dist/plugins/coin/spans.mjs.map +0 -1
- package/dist/plugins/deepbook/spans.mjs +0 -18
- package/dist/plugins/deepbook/spans.mjs.map +0 -1
- package/dist/plugins/faucet/spans.mjs +0 -12
- package/dist/plugins/faucet/spans.mjs.map +0 -1
- package/dist/plugins/package/spans.mjs +0 -14
- package/dist/plugins/package/spans.mjs.map +0 -1
- package/dist/plugins/postgres/codegen.mjs +0 -42
- package/dist/plugins/postgres/codegen.mjs.map +0 -1
- package/dist/plugins/postgres/connection.d.mts +0 -33
- package/dist/plugins/postgres/connection.mjs.map +0 -1
- package/dist/plugins/postgres/db-ensure.mjs.map +0 -1
- package/dist/plugins/postgres/errors.d.mts +0 -60
- package/dist/plugins/postgres/errors.mjs +0 -29
- package/dist/plugins/postgres/errors.mjs.map +0 -1
- package/dist/plugins/postgres/index.d.mts +0 -37
- package/dist/plugins/postgres/index.mjs +0 -68
- package/dist/plugins/postgres/index.mjs.map +0 -1
- package/dist/plugins/postgres/routable.mjs +0 -33
- package/dist/plugins/postgres/routable.mjs.map +0 -1
- package/dist/plugins/postgres/service.d.mts +0 -50
- package/dist/plugins/postgres/service.mjs +0 -179
- package/dist/plugins/postgres/service.mjs.map +0 -1
- package/dist/plugins/postgres/snapshot.mjs +0 -32
- package/dist/plugins/postgres/snapshot.mjs.map +0 -1
- package/dist/plugins/postgres/spans.mjs +0 -11
- package/dist/plugins/postgres/spans.mjs.map +0 -1
- package/dist/plugins/seal/spans.mjs +0 -18
- package/dist/plugins/seal/spans.mjs.map +0 -1
- package/dist/plugins/sui/spans.mjs +0 -17
- package/dist/plugins/sui/spans.mjs.map +0 -1
- package/dist/plugins/wallet/spans.mjs +0 -22
- package/dist/plugins/wallet/spans.mjs.map +0 -1
- package/dist/plugins/walrus/registry-publish.d.mts +0 -24
- package/dist/plugins/walrus/spans.mjs +0 -18
- package/dist/plugins/walrus/spans.mjs.map +0 -1
- package/dist/runtime/docker/logs.d.mts +0 -1
- package/dist/runtime/docker/logs.mjs +0 -34
- package/dist/runtime/docker/logs.mjs.map +0 -1
- package/dist/substrate/runtime/artifact-publisher/index.mjs +0 -86
- package/dist/substrate/runtime/artifact-publisher/index.mjs.map +0 -1
- package/dist/substrate/runtime/capability-sinks/index.d.mts +0 -1
- package/dist/substrate/runtime/capability-sinks/index.mjs +0 -3
- package/dist/substrate/runtime/capability-sinks/layer.d.mts +0 -1
- package/dist/substrate/runtime/capability-sinks/layer.mjs +0 -31
- package/dist/substrate/runtime/capability-sinks/layer.mjs.map +0 -1
- package/dist/substrate/runtime/capability-sinks/service.d.mts +0 -95
- package/dist/substrate/runtime/capability-sinks/service.mjs +0 -69
- package/dist/substrate/runtime/capability-sinks/service.mjs.map +0 -1
- package/dist/substrate/runtime/cross-process/lock.d.mts +0 -1
- package/dist/substrate/runtime/cross-process/lock.mjs +0 -23
- package/dist/substrate/runtime/cross-process/lock.mjs.map +0 -1
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +0 -113
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +0 -1
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +0 -31
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +0 -1
- package/dist/substrate/runtime/observability/formatter-registry.d.mts +0 -1
- package/dist/substrate/runtime/observability/formatter-registry.mjs +0 -48
- package/dist/substrate/runtime/observability/formatter-registry.mjs.map +0 -1
- package/dist/substrate/runtime/observability/span-store.d.mts +0 -1
- package/dist/substrate/runtime/observability/span-store.mjs +0 -110
- package/dist/substrate/runtime/observability/span-store.mjs.map +0 -1
- package/dist/substrate/runtime/observability/spans.d.mts +0 -1
- package/dist/substrate/runtime/observability/spans.mjs +0 -87
- package/dist/substrate/runtime/observability/spans.mjs.map +0 -1
- package/dist/substrate/runtime/projection/index.mjs +0 -4
- package/dist/substrate/runtime/projection/persisted.mjs +0 -213
- package/dist/substrate/runtime/projection/persisted.mjs.map +0 -1
- package/dist/substrate/runtime/scoped-multimap/service.mjs +0 -52
- package/dist/substrate/runtime/scoped-multimap/service.mjs.map +0 -1
- package/dist/substrate/runtime/scoped-ref-map/index.mjs +0 -2
- package/dist/substrate/runtime/scoped-ref-map/service.mjs +0 -83
- package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +0 -1
- package/dist/substrate/runtime/state-store/index.mjs +0 -3
- package/dist/substrate/runtime/state-store/schema.d.mts +0 -1
- package/dist/substrate/runtime/state-store/schema.mjs +0 -41
- package/dist/substrate/runtime/state-store/schema.mjs.map +0 -1
- package/dist/substrate/runtime/state-store/service.d.mts +0 -1
- package/dist/substrate/runtime/state-store/service.mjs +0 -145
- package/dist/substrate/runtime/state-store/service.mjs.map +0 -1
- package/dist/substrate/runtime/sui-execute/index.mjs.map +0 -1
- package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +0 -1
- package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +0 -1
- package/dist/substrate/runtime/sui-move-build/index.mjs.map +0 -1
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +0 -151
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +0 -1
- package/dist/substrate/state-store.d.mts +0 -1
- /package/dist/orchestrators/{snapshot/pending-marker.d.mts → codegen/id-config.d.mts} +0 -0
- /package/dist/orchestrators/snapshot/{recover-pending.d.mts → interrupted-restore.d.mts} +0 -0
- /package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.d.mts +0 -0
- /package/dist/plugins/{postgres/snapshot.d.mts → sui/ledger/object-ref.d.mts} +0 -0
- /package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.d.mts +0 -0
- /package/dist/substrate/runtime/{state-store/index.d.mts → reconcile/graph.d.mts} +0 -0
- /package/dist/substrate/runtime/{cross-process/snapshot-reservation.d.mts → supervisor/contribution-dispatcher.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-probes.mjs","names":["nodeHostname"],"sources":["../../src/cli/doctor-probes.ts"],"sourcesContent":["// L4-adjacent CLI infrastructure: doctor probe definitions.\n//\n// Per STYLE_GUIDE §7: `cli/*.ts` modules sit alongside the bin entry\n// (`cli/main.ts`) and may import L3 orchestrator + L2 plugin barrels —\n// they are NOT L4 surfaces proper. The router-profile probe needs\n// both the L3 router orchestrator helpers (parsing dispatch files,\n// matching profile labels, sorting entrypoint ports) and the built-in\n// L2 router entrypoint composition; that wiring lives here.\n//\n// The probes themselves are read-only diagnostics: Docker reachable,\n// `sui` CLI on PATH, state-dir writable, router profile state +\n// dispatch leases + entrypoint listeners, orphan cross-process locks,\n// fork-cache health. Each returns a typed `ProbeOutcome` and never\n// throws. `required: true` means a `fail | unavailable` projects to\n// `CliUnavailableError` and exits 69; non-required probes are\n// informational.\n\nimport { execFileSync } from 'node:child_process';\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { hostname as nodeHostname } from 'node:os';\nimport { createConnection } from 'node:net';\nimport { join } from 'node:path';\n\nimport { Effect } from 'effect';\n\nimport {\n\tdispatchFileIdFromFilename,\n\tmakeDefaultRouterProfile,\n\tparseDispatchRouteFile,\n\trouterProfileLabelsMatch,\n\tuniqueSortedEntrypointPorts,\n\ttype Entrypoint,\n\ttype RouterProfile,\n} from '../orchestrators/router/index.ts';\nimport { BUILT_IN_ENTRYPOINTS } from '../plugins/router-entrypoints.ts';\nimport { parseJsonTextSync } from '../substrate/runtime/runtime-decode.ts';\nimport {\n\tlayerLivenessProbeScope,\n\tLivenessProbeScope,\n\treadRoster,\n} from '../substrate/runtime/cross-process/index.ts';\nimport type { RosterHolder } from '../substrate/cross-process.ts';\nimport type { Probe, ProbeOutcome } from '../surfaces/cli/commands/doctor.ts';\n\nconst okOutcome = (detail?: string): ProbeOutcome =>\n\tdetail !== undefined ? { status: 'ok', detail } : { status: 'ok' };\n\ntype CommandResult = { ok: true; out: string } | { ok: false; err: string };\n\nconst captureCommand = (\n\tcmd: string,\n\targs: ReadonlyArray<string>,\n\ttimeoutMs = 3000,\n): CommandResult => {\n\ttry {\n\t\tconst out = execFileSync(cmd, args as string[], {\n\t\t\tencoding: 'utf8',\n\t\t\ttimeout: timeoutMs,\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t});\n\t\treturn { ok: true, out: out.trim() };\n\t} catch (err) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terr: err instanceof Error ? err.message : String(err),\n\t\t};\n\t}\n};\n\n/** Probe: `docker version` resolves. */\nexport const dockerProbe: Probe = {\n\tname: 'docker',\n\tdescription: 'Docker daemon reachable',\n\trequired: true,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tconst result = captureCommand('docker', ['version', '--format', '{{.Server.Version}}']);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\tdetail: `docker version failed: ${result.err}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn okOutcome(`server ${result.out}`);\n\t\t}),\n};\n\n/** Probe: required CLIs on PATH (just sui-cli for fork-aware flows). */\nexport const suiCliProbe: Probe = {\n\tname: 'sui-cli',\n\tdescription: '`sui` CLI on PATH',\n\trequired: false,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tconst result = captureCommand('sui', ['--version']);\n\t\t\treturn result.ok\n\t\t\t\t? okOutcome(result.out)\n\t\t\t\t: {\n\t\t\t\t\t\tstatus: 'warn',\n\t\t\t\t\t\tdetail: 'sui CLI not on PATH (only needed for live/fork modes)',\n\t\t\t\t\t};\n\t\t}),\n};\n\n/** Probe: a TCP port is FREE on localhost (resolves `true` when nothing\n * is listening — connection refused/timeout — and `false` when a\n * listener answers). Backs `routerProfileProbe`'s entrypoint-listener\n * check. */\nconst probePortFree = (port: number, timeoutMs = 500): Promise<boolean> =>\n\tnew Promise((resolve) => {\n\t\tconst socket = createConnection({ host: '127.0.0.1', port });\n\t\tconst finish = (free: boolean): void => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(free);\n\t\t};\n\t\tconst timer = setTimeout(() => finish(true), timeoutMs);\n\t\tsocket.on('connect', () => {\n\t\t\tclearTimeout(timer);\n\t\t\tfinish(false);\n\t\t});\n\t\tsocket.on('error', () => {\n\t\t\tclearTimeout(timer);\n\t\t\tfinish(true);\n\t\t});\n\t});\n\nexport type DoctorCommandRunner = typeof captureCommand;\nexport type PortAvailabilityProbe = typeof probePortFree;\n\nexport interface RouterProfileProbeOptions {\n\treadonly profile?: RouterProfile;\n\treadonly entrypoints?: ReadonlyArray<Entrypoint>;\n\treadonly command?: DoctorCommandRunner;\n\treadonly probePort?: PortAvailabilityProbe;\n}\n\ninterface RouterDispatchScan {\n\treadonly status: 'absent' | 'ok' | 'not-directory' | 'unreadable';\n\treadonly files: number;\n\treadonly liveRoutes: number;\n\treadonly staleRoutes: number;\n\treadonly unknownOwnerRoutes: number;\n\treadonly corruptRouteFiles: number;\n\treadonly diagnostics: number;\n\treadonly safeToPrune: boolean;\n}\n\ninterface RouterContainerStatus {\n\treadonly status: 'absent' | 'present' | 'invalid' | 'unavailable';\n\treadonly detail?: string;\n\treadonly running?: boolean;\n\treadonly labelsMatch?: boolean;\n\treadonly attachedToNetwork?: boolean;\n\treadonly publishedPorts?: ReadonlyArray<number>;\n}\n\ninterface RouterNetworkStatus {\n\treadonly status: 'absent' | 'present' | 'invalid' | 'unavailable';\n\treadonly detail?: string;\n\treadonly id?: string;\n}\n\nconst unknownRecord = (value: unknown): Record<string, unknown> | null =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: null;\n\nconst stringRecord = (value: unknown): Record<string, string> => {\n\tconst rec = unknownRecord(value);\n\tif (rec === null) return {};\n\tconst out: Record<string, string> = {};\n\tfor (const [key, raw] of Object.entries(rec)) {\n\t\tif (typeof raw === 'string') out[key] = raw;\n\t}\n\treturn out;\n};\n\nconst fieldRecord = (\n\trecord: Record<string, unknown>,\n\tkey: string,\n): Record<string, unknown> | null => unknownRecord(record[key]);\n\nconst fieldString = (record: Record<string, unknown>, key: string): string | null =>\n\ttypeof record[key] === 'string' ? (record[key] as string) : null;\n\nconst fieldBoolean = (record: Record<string, unknown>, key: string): boolean | null =>\n\ttypeof record[key] === 'boolean' ? (record[key] as boolean) : null;\n\nconst parseDockerInspectFirst = (out: string): Record<string, unknown> | null => {\n\ttry {\n\t\tconst parsed = parseJsonTextSync(out, {\n\t\t\tsource: 'docker inspect',\n\t\t\tmkError: (issue) => issue,\n\t\t});\n\t\tif (Array.isArray(parsed)) return unknownRecord(parsed[0]);\n\t\treturn unknownRecord(parsed);\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst dockerObjectIsAbsent = (err: string): boolean =>\n\t/No such (object|container|network)|not found|No such/i.test(err);\n\nconst uniqueNumbers = (values: ReadonlyArray<number>): ReadonlyArray<number> =>\n\t[...new Set(values)].sort((a, b) => a - b);\n\nconst inspectRouterContainer = (\n\tprofile: RouterProfile,\n\tcommand: DoctorCommandRunner,\n): RouterContainerStatus => {\n\tconst result = command('docker', ['container', 'inspect', profile.containerName]);\n\tif (!result.ok) {\n\t\treturn dockerObjectIsAbsent(result.err)\n\t\t\t? { status: 'absent' }\n\t\t\t: { status: 'unavailable', detail: result.err };\n\t}\n\tconst doc = parseDockerInspectFirst(result.out);\n\tif (doc === null) return { status: 'invalid', detail: 'container inspect JSON was invalid' };\n\tconst state = fieldRecord(doc, 'State') ?? {};\n\tconst config = fieldRecord(doc, 'Config') ?? {};\n\tconst networkSettings = fieldRecord(doc, 'NetworkSettings') ?? {};\n\tconst networks = fieldRecord(networkSettings, 'Networks') ?? {};\n\tconst ports = fieldRecord(networkSettings, 'Ports') ?? {};\n\tconst publishedPorts: Array<number> = [];\n\tfor (const bindings of Object.values(ports)) {\n\t\tif (!Array.isArray(bindings)) continue;\n\t\tfor (const binding of bindings) {\n\t\t\tconst rec = unknownRecord(binding);\n\t\t\tif (rec === null) continue;\n\t\t\tconst rawPort = fieldString(rec, 'HostPort');\n\t\t\tif (rawPort !== null && /^\\d+$/.test(rawPort)) {\n\t\t\t\tpublishedPorts.push(Number.parseInt(rawPort, 10));\n\t\t\t}\n\t\t}\n\t}\n\tconst labels = stringRecord(config.Labels);\n\treturn {\n\t\tstatus: 'present',\n\t\trunning: fieldBoolean(state, 'Running') === true,\n\t\tlabelsMatch: routerProfileLabelsMatch(labels, profile),\n\t\tattachedToNetwork: Object.keys(networks).includes(profile.networkName),\n\t\tpublishedPorts: uniqueNumbers(publishedPorts),\n\t};\n};\n\nconst inspectRouterNetwork = (\n\tprofile: RouterProfile,\n\tcommand: DoctorCommandRunner,\n): RouterNetworkStatus => {\n\tconst result = command('docker', ['network', 'inspect', profile.networkName]);\n\tif (!result.ok) {\n\t\treturn dockerObjectIsAbsent(result.err)\n\t\t\t? { status: 'absent' }\n\t\t\t: { status: 'unavailable', detail: result.err };\n\t}\n\tconst doc = parseDockerInspectFirst(result.out);\n\tif (doc === null) return { status: 'invalid', detail: 'network inspect JSON was invalid' };\n\tconst id = fieldString(doc, 'Id');\n\treturn id === null ? { status: 'present' } : { status: 'present', id };\n};\n\nconst inspectRouterDispatch = (profile: RouterProfile): Effect.Effect<RouterDispatchScan> =>\n\t// Yield a fresh `LivenessProbeScope` so repeated lease owners across\n\t// many dispatch route files fork the OS probe once per pid.\n\tEffect.gen(function* () {\n\t\tif (!existsSync(profile.dispatchDir)) {\n\t\t\treturn {\n\t\t\t\tstatus: 'absent' as const,\n\t\t\t\tfiles: 0,\n\t\t\t\tliveRoutes: 0,\n\t\t\t\tstaleRoutes: 0,\n\t\t\t\tunknownOwnerRoutes: 0,\n\t\t\t\tcorruptRouteFiles: 0,\n\t\t\t\tdiagnostics: 0,\n\t\t\t\tsafeToPrune: true,\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\tif (!statSync(profile.dispatchDir).isDirectory()) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'not-directory' as const,\n\t\t\t\t\tfiles: 0,\n\t\t\t\t\tliveRoutes: 0,\n\t\t\t\t\tstaleRoutes: 0,\n\t\t\t\t\tunknownOwnerRoutes: 1,\n\t\t\t\t\tcorruptRouteFiles: 1,\n\t\t\t\t\tdiagnostics: 1,\n\t\t\t\t\tsafeToPrune: false,\n\t\t\t\t};\n\t\t\t}\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tstatus: 'unreadable' as const,\n\t\t\t\tfiles: 0,\n\t\t\t\tliveRoutes: 0,\n\t\t\t\tstaleRoutes: 0,\n\t\t\t\tunknownOwnerRoutes: 1,\n\t\t\t\tcorruptRouteFiles: 1,\n\t\t\t\tdiagnostics: 1,\n\t\t\t\tsafeToPrune: false,\n\t\t\t};\n\t\t}\n\t\tlet files: ReadonlyArray<string>;\n\t\ttry {\n\t\t\tfiles = readdirSync(profile.dispatchDir);\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tstatus: 'unreadable' as const,\n\t\t\t\tfiles: 0,\n\t\t\t\tliveRoutes: 0,\n\t\t\t\tstaleRoutes: 0,\n\t\t\t\tunknownOwnerRoutes: 1,\n\t\t\t\tcorruptRouteFiles: 1,\n\t\t\t\tdiagnostics: 1,\n\t\t\t\tsafeToPrune: false,\n\t\t\t};\n\t\t}\n\t\tconst probe = yield* LivenessProbeScope;\n\t\tlet routeFiles = 0;\n\t\tlet liveRoutes = 0;\n\t\tlet staleRoutes = 0;\n\t\tlet unknownOwnerRoutes = 0;\n\t\tlet corruptRouteFiles = 0;\n\t\tlet diagnostics = 0;\n\t\tfor (const filename of files) {\n\t\t\tconst dispatchFileId = dispatchFileIdFromFilename(filename);\n\t\t\tif (dispatchFileId === null) continue;\n\t\t\trouteFiles += 1;\n\t\t\tlet body: string;\n\t\t\ttry {\n\t\t\t\tbody = readFileSync(join(profile.dispatchDir, filename), 'utf8');\n\t\t\t} catch {\n\t\t\t\tcorruptRouteFiles += 1;\n\t\t\t\tunknownOwnerRoutes += 1;\n\t\t\t\tdiagnostics += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst parsed = parseDispatchRouteFile(body, dispatchFileId);\n\t\t\tdiagnostics += parsed.diagnostics.length;\n\t\t\tif (parsed._tag === 'invalid') {\n\t\t\t\tcorruptRouteFiles += 1;\n\t\t\t\tunknownOwnerRoutes += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (parsed.route.lease === null) {\n\t\t\t\tunknownOwnerRoutes += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst leaseStatus = yield* probe\n\t\t\t\t.probeHolderLiveness(parsed.route.lease.owner)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed('alive' as const)));\n\t\t\tif (leaseStatus === 'dead') staleRoutes += 1;\n\t\t\telse liveRoutes += 1;\n\t\t}\n\t\tconst safeToPrune = liveRoutes === 0 && unknownOwnerRoutes === 0 && corruptRouteFiles === 0;\n\t\treturn {\n\t\t\tstatus: 'ok' as const,\n\t\t\tfiles: routeFiles,\n\t\t\tliveRoutes,\n\t\t\tstaleRoutes,\n\t\t\tunknownOwnerRoutes,\n\t\t\tcorruptRouteFiles,\n\t\t\tdiagnostics,\n\t\t\tsafeToPrune,\n\t\t};\n\t}).pipe(Effect.provide(layerLivenessProbeScope));\n\nconst inspectRouterStateDir = (profile: RouterProfile): 'absent' | 'present' | 'not-directory' => {\n\tif (!existsSync(profile.stateDir)) return 'absent';\n\ttry {\n\t\treturn statSync(profile.stateDir).isDirectory() ? 'present' : 'not-directory';\n\t} catch {\n\t\treturn 'not-directory';\n\t}\n};\n\nconst summarizeRouterContainer = (container: RouterContainerStatus): string => {\n\tif (container.status !== 'present') return container.status;\n\treturn [\n\t\tcontainer.running === true ? 'running' : 'stopped',\n\t\t`labels=${container.labelsMatch === true ? 'ok' : 'mismatch'}`,\n\t\t`network=${container.attachedToNetwork === true ? 'attached' : 'missing'}`,\n\t\t`ports=${(container.publishedPorts ?? []).join(',') || 'none'}`,\n\t].join('/');\n};\n\nexport const routerProfileProbe = (options: RouterProfileProbeOptions = {}): Probe => ({\n\tname: 'router-profile',\n\tdescription: 'router profile state, dispatch leases, and entrypoint listeners',\n\trequired: false,\n\trun: () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst profile = options.profile ?? makeDefaultRouterProfile();\n\t\t\tconst entrypoints = options.entrypoints ?? BUILT_IN_ENTRYPOINTS;\n\t\t\tconst command = options.command ?? captureCommand;\n\t\t\tconst probePort = options.probePort ?? probePortFree;\n\t\t\tconst ports = uniqueSortedEntrypointPorts(entrypoints);\n\t\t\tconst stateDirStatus = inspectRouterStateDir(profile);\n\t\t\tconst dispatch = yield* inspectRouterDispatch(profile);\n\t\t\tconst container = inspectRouterContainer(profile, command);\n\t\t\tconst network = inspectRouterNetwork(profile, command);\n\t\t\tconst listenerResults = yield* Effect.tryPromise({\n\t\t\t\ttry: () =>\n\t\t\t\t\tPromise.all(\n\t\t\t\t\t\tports.map(async (port) => ({\n\t\t\t\t\t\t\tport,\n\t\t\t\t\t\t\tfree: await probePort(port),\n\t\t\t\t\t\t})),\n\t\t\t\t\t),\n\t\t\t\tcatch: () => 'router entrypoint listener probe failed',\n\t\t\t}).pipe(Effect.catch(() => Effect.succeed(ports.map((port) => ({ port, free: true })))));\n\t\t\tconst freePorts = listenerResults.filter((r) => r.free).map((r) => r.port);\n\t\t\tconst occupiedPorts = listenerResults.filter((r) => !r.free).map((r) => r.port);\n\t\t\tconst protectedRoutes =\n\t\t\t\tdispatch.liveRoutes + dispatch.unknownOwnerRoutes + dispatch.corruptRouteFiles;\n\t\t\tconst problems: string[] = [];\n\t\t\tif (stateDirStatus === 'not-directory')\n\t\t\t\tproblems.push(`${profile.stateDir} is not a directory`);\n\t\t\tif (dispatch.status === 'not-directory' || dispatch.status === 'unreadable') {\n\t\t\t\tproblems.push(`dispatch dir is ${dispatch.status}`);\n\t\t\t}\n\t\t\tif (dispatch.unknownOwnerRoutes > 0 || dispatch.corruptRouteFiles > 0) {\n\t\t\t\tproblems.push(\n\t\t\t\t\t`unknown/corrupt dispatch leases=${dispatch.unknownOwnerRoutes + dispatch.corruptRouteFiles}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (dispatch.staleRoutes > 0) problems.push(`stale dispatch leases=${dispatch.staleRoutes}`);\n\t\t\tif (protectedRoutes > 0 && (container.status !== 'present' || container.running !== true)) {\n\t\t\t\tproblems.push('protected dispatch leases exist without a running router container');\n\t\t\t}\n\t\t\tif (container.status === 'invalid' || container.status === 'unavailable') {\n\t\t\t\tproblems.push(\n\t\t\t\t\t`router container inspect ${container.status}: ${container.detail ?? 'unknown'}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (container.status === 'present') {\n\t\t\t\tif (container.labelsMatch !== true)\n\t\t\t\t\tproblems.push('router container labels do not match profile');\n\t\t\t\tif (container.attachedToNetwork !== true) {\n\t\t\t\t\tproblems.push('router container is not attached to profile network');\n\t\t\t\t}\n\t\t\t\tif (container.running === true && freePorts.length > 0) {\n\t\t\t\t\tproblems.push(`router entrypoint listeners missing: ${freePorts.join(', ')}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (container.status !== 'present' && occupiedPorts.length > 0) {\n\t\t\t\tproblems.push(\n\t\t\t\t\t`router entrypoint ports already in use without profile container: ${occupiedPorts.join(', ')}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (network.status === 'invalid' || network.status === 'unavailable') {\n\t\t\t\tproblems.push(`router network inspect ${network.status}: ${network.detail ?? 'unknown'}`);\n\t\t\t}\n\t\t\tconst detail = [\n\t\t\t\t`profile=${profile.id}`,\n\t\t\t\t`state=${stateDirStatus}`,\n\t\t\t\t`dispatch=${dispatch.status}:files=${dispatch.files},live=${dispatch.liveRoutes},stale=${dispatch.staleRoutes},unknown=${dispatch.unknownOwnerRoutes},corrupt=${dispatch.corruptRouteFiles},diagnostics=${dispatch.diagnostics},pruneSafe=${dispatch.safeToPrune ? 'yes' : 'no'}`,\n\t\t\t\t`container=${summarizeRouterContainer(container)}`,\n\t\t\t\t`network=${network.status}`,\n\t\t\t\t`entrypoints=${ports.join(', ') || 'none'}`,\n\t\t\t].join('; ');\n\t\t\tif (problems.length === 0) return okOutcome(detail);\n\t\t\treturn {\n\t\t\t\tstatus: 'warn' as const,\n\t\t\t\tdetail: `${detail}; ${problems.join('; ')}`,\n\t\t\t};\n\t\t}),\n});\n\n/** Probe: list orphaned stack locks under `<runtimeRoot>/<app>/`. A\n * stack lock whose owner PID is dead is a stale-lock candidate that\n * `--clean-locks` would reclaim. */\nexport const locksProbe = (appRoot: string): Probe => ({\n\tname: 'locks',\n\tdescription: 'stale cross-process locks',\n\trequired: false,\n\trun: () =>\n\t\tEffect.gen(function* () {\n\t\t\tif (!existsSync(appRoot)) return okOutcome('(no app root yet)');\n\t\t\tconst ownHost = nodeHostname();\n\t\t\t// Yield a fresh `LivenessProbeScope` so a single pid that\n\t\t\t// shows up in multiple stack rosters under this app root is\n\t\t\t// probed AT MOST once across the full lock scan.\n\t\t\tconst probe = yield* LivenessProbeScope;\n\t\t\tlet orphans = 0;\n\t\t\tlet totalLive = 0;\n\t\t\ttry {\n\t\t\t\tfor (const entry of readdirSync(appRoot)) {\n\t\t\t\t\tif (entry.startsWith('.')) continue;\n\t\t\t\t\tconst stackRoot = join(appRoot, entry);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!statSync(stackRoot).isDirectory()) continue;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst rosterFile = join(stackRoot, 'roster.json');\n\t\t\t\t\tif (!existsSync(rosterFile)) continue;\n\t\t\t\t\tconst doc = yield* readRoster(rosterFile).pipe(\n\t\t\t\t\t\tEffect.catch(() =>\n\t\t\t\t\t\t\tEffect.succeed({ version: 1 as const, holders: [] as RosterHolder[] }),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tfor (const holder of doc.holders) {\n\t\t\t\t\t\tconst liveness = yield* probe\n\t\t\t\t\t\t\t.probeHolderLiveness(holder, ownHost)\n\t\t\t\t\t\t\t.pipe(Effect.catch(() => Effect.succeed('alive' as const)));\n\t\t\t\t\t\tif (liveness === 'alive') totalLive += 1;\n\t\t\t\t\t\telse orphans += 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (cause) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'warn' as const,\n\t\t\t\t\tdetail: `lock scan failed: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (orphans === 0) {\n\t\t\t\treturn okOutcome(`${totalLive} live, 0 orphan`);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: 'warn' as const,\n\t\t\t\tdetail: `${orphans} orphan holder(s); rerun with --clean-locks`,\n\t\t\t};\n\t\t}).pipe(Effect.provide(layerLivenessProbeScope)),\n});\n\n/** Probe: state-dir is writable. Validates DEVSTACK_STATE_DIR resolves\n * to a usable path (or the default ~/.devstack does). */\nexport const stateDirProbe = (stateDir: string): Probe => ({\n\tname: 'state-dir',\n\tdescription: 'state directory',\n\trequired: true,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tif (!existsSync(stateDir)) {\n\t\t\t\treturn okOutcome(`${stateDir} (will be created)`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst s = statSync(stateDir);\n\t\t\t\tif (!s.isDirectory()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\t\tdetail: `${stateDir} is not a directory`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn okOutcome(stateDir);\n\t\t\t} catch (cause) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\tdetail: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t};\n\t\t\t}\n\t\t}),\n});\n\n/** Probe: optional fork-cache directory inspection. Returns the size\n * of the cache (informational). */\nexport const forkCacheProbe = (appRoot: string): Probe => ({\n\tname: 'fork-cache',\n\tdescription: 'sui-fork cache',\n\trequired: false,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tconst cacheDir = join(appRoot, '.fork-cache');\n\t\t\tif (!existsSync(cacheDir)) return okOutcome('(absent)');\n\t\t\ttry {\n\t\t\t\tconst size = countTreeSize(cacheDir);\n\t\t\t\treturn okOutcome(`${size} entries`);\n\t\t\t} catch {\n\t\t\t\treturn { status: 'warn', detail: 'fork cache scan failed' };\n\t\t\t}\n\t\t}),\n});\n\nconst countTreeSize = (dir: string, depth = 0): number => {\n\tif (depth > 3) return 0;\n\tlet n = 0;\n\tfor (const entry of readdirSync(dir)) {\n\t\tconst p = join(dir, entry);\n\t\ttry {\n\t\t\tconst s = statSync(p);\n\t\t\tif (s.isFile()) n += 1;\n\t\t\telse if (s.isDirectory()) n += countTreeSize(p, depth + 1);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\treturn n;\n};\n\n/** Default probe set. `cli/main.ts` composes this with the resolved\n * app root, runtime state dir, router profile, and router entrypoints. */\nexport const defaultProbes = (params: {\n\treadonly stateDir: string;\n\treadonly appRoot: string;\n\treadonly routerProfile?: RouterProfile;\n\treadonly routerEntrypoints?: ReadonlyArray<Entrypoint>;\n}): ReadonlyArray<Probe> => [\n\tdockerProbe,\n\tsuiCliProbe,\n\tstateDirProbe(params.stateDir),\n\trouterProfileProbe({\n\t\t...(params.routerProfile === undefined ? {} : { profile: params.routerProfile }),\n\t\t...(params.routerEntrypoints === undefined ? {} : { entrypoints: params.routerEntrypoints }),\n\t}),\n\tlocksProbe(params.appRoot),\n\tforkCacheProbe(params.appRoot),\n];\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"doctor-probes.mjs","names":[],"sources":["../../src/cli/doctor-probes.ts"],"sourcesContent":["// L4-adjacent CLI infrastructure: doctor probe definitions.\n//\n// Per STYLE_GUIDE §7: `cli/*.ts` modules sit alongside the bin entry\n// (`cli/main.ts`) and may import L3 orchestrator + L2 plugin barrels —\n// they are NOT L4 surfaces proper. The router-profile probe needs\n// both the L3 router orchestrator helpers (parsing dispatch files,\n// matching profile labels, sorting entrypoint ports) and the built-in\n// L2 router entrypoint composition; that wiring lives here.\n//\n// The probes themselves are read-only diagnostics: Docker reachable,\n// `sui` CLI on PATH, state-dir writable, router profile state +\n// dispatch leases + entrypoint listeners, orphan cross-process locks,\n// fork-cache health. Each returns a typed `ProbeOutcome` and never\n// throws. `required: true` means a `fail | unavailable` projects to\n// `CliUnavailableError` and exits 69; non-required probes are\n// informational.\n\nimport { execFileSync } from 'node:child_process';\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { createConnection } from 'node:net';\nimport { join } from 'node:path';\n\nimport { Effect } from 'effect';\n\nimport {\n\tdispatchFileIdFromFilename,\n\tmakeDefaultRouterProfile,\n\tparseDispatchRouteFile,\n\trouterProfileLabelsMatch,\n\tuniqueSortedEntrypointPorts,\n\ttype Entrypoint,\n\ttype RouterProfile,\n} from '../orchestrators/router/index.ts';\nimport { BUILT_IN_ENTRYPOINTS } from '../plugins/router-entrypoints.ts';\nimport { parseJsonTextSync } from '../substrate/runtime/runtime-decode.ts';\nimport {\n\tlayerLivenessProbeScope,\n\tLivenessProbeScope,\n\treadRoster,\n} from '../substrate/runtime/cross-process/index.ts';\nimport type { RosterHolder } from '../substrate/cross-process.ts';\nimport type { Probe, ProbeOutcome } from '../surfaces/cli/commands/doctor.ts';\n\nconst okOutcome = (detail?: string): ProbeOutcome =>\n\tdetail !== undefined ? { status: 'ok', detail } : { status: 'ok' };\n\ntype CommandResult = { ok: true; out: string } | { ok: false; err: string };\n\nconst captureCommand = (\n\tcmd: string,\n\targs: ReadonlyArray<string>,\n\ttimeoutMs = 3000,\n): CommandResult => {\n\ttry {\n\t\tconst out = execFileSync(cmd, args as string[], {\n\t\t\tencoding: 'utf8',\n\t\t\ttimeout: timeoutMs,\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t});\n\t\treturn { ok: true, out: out.trim() };\n\t} catch (err) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terr: err instanceof Error ? err.message : String(err),\n\t\t};\n\t}\n};\n\n/** Probe: `docker version` resolves. */\nexport const dockerProbe: Probe = {\n\tname: 'docker',\n\tdescription: 'Docker daemon reachable',\n\trequired: true,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tconst result = captureCommand('docker', ['version', '--format', '{{.Server.Version}}']);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\tdetail: `docker version failed: ${result.err}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn okOutcome(`server ${result.out}`);\n\t\t}),\n};\n\n/** Probe: required CLIs on PATH (just sui-cli for fork-aware flows). */\nexport const suiCliProbe: Probe = {\n\tname: 'sui-cli',\n\tdescription: '`sui` CLI on PATH',\n\trequired: false,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tconst result = captureCommand('sui', ['--version']);\n\t\t\treturn result.ok\n\t\t\t\t? okOutcome(result.out)\n\t\t\t\t: {\n\t\t\t\t\t\tstatus: 'warn',\n\t\t\t\t\t\tdetail: 'sui CLI not on PATH (only needed for live/fork modes)',\n\t\t\t\t\t};\n\t\t}),\n};\n\n/** Probe: a TCP port is FREE on localhost (resolves `true` when nothing\n * is listening — connection refused/timeout — and `false` when a\n * listener answers). Backs `routerProfileProbe`'s entrypoint-listener\n * check. */\nconst probePortFree = (port: number, timeoutMs = 500): Promise<boolean> =>\n\tnew Promise((resolve) => {\n\t\tconst socket = createConnection({ host: '127.0.0.1', port });\n\t\tconst finish = (free: boolean): void => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(free);\n\t\t};\n\t\tconst timer = setTimeout(() => finish(true), timeoutMs);\n\t\tsocket.on('connect', () => {\n\t\t\tclearTimeout(timer);\n\t\t\tfinish(false);\n\t\t});\n\t\tsocket.on('error', () => {\n\t\t\tclearTimeout(timer);\n\t\t\tfinish(true);\n\t\t});\n\t});\n\nexport type DoctorCommandRunner = typeof captureCommand;\nexport type PortAvailabilityProbe = typeof probePortFree;\n\nexport interface RouterProfileProbeOptions {\n\treadonly profile?: RouterProfile;\n\treadonly entrypoints?: ReadonlyArray<Entrypoint>;\n\treadonly command?: DoctorCommandRunner;\n\treadonly probePort?: PortAvailabilityProbe;\n}\n\ninterface RouterDispatchScan {\n\treadonly status: 'absent' | 'ok' | 'not-directory' | 'unreadable';\n\treadonly files: number;\n\treadonly liveRoutes: number;\n\treadonly staleRoutes: number;\n\treadonly unknownOwnerRoutes: number;\n\treadonly corruptRouteFiles: number;\n\treadonly diagnostics: number;\n\treadonly safeToPrune: boolean;\n}\n\ninterface RouterContainerStatus {\n\treadonly status: 'absent' | 'present' | 'invalid' | 'unavailable';\n\treadonly detail?: string;\n\treadonly running?: boolean;\n\treadonly labelsMatch?: boolean;\n\treadonly attachedToNetwork?: boolean;\n\treadonly publishedPorts?: ReadonlyArray<number>;\n}\n\ninterface RouterNetworkStatus {\n\treadonly status: 'absent' | 'present' | 'invalid' | 'unavailable';\n\treadonly detail?: string;\n\treadonly id?: string;\n}\n\nconst unknownRecord = (value: unknown): Record<string, unknown> | null =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: null;\n\nconst stringRecord = (value: unknown): Record<string, string> => {\n\tconst rec = unknownRecord(value);\n\tif (rec === null) return {};\n\tconst out: Record<string, string> = {};\n\tfor (const [key, raw] of Object.entries(rec)) {\n\t\tif (typeof raw === 'string') out[key] = raw;\n\t}\n\treturn out;\n};\n\nconst fieldRecord = (\n\trecord: Record<string, unknown>,\n\tkey: string,\n): Record<string, unknown> | null => unknownRecord(record[key]);\n\nconst fieldString = (record: Record<string, unknown>, key: string): string | null =>\n\ttypeof record[key] === 'string' ? (record[key] as string) : null;\n\nconst fieldBoolean = (record: Record<string, unknown>, key: string): boolean | null =>\n\ttypeof record[key] === 'boolean' ? (record[key] as boolean) : null;\n\nconst parseDockerInspectFirst = (out: string): Record<string, unknown> | null => {\n\ttry {\n\t\tconst parsed = parseJsonTextSync(out, {\n\t\t\tsource: 'docker inspect',\n\t\t\tmkError: (issue) => issue,\n\t\t});\n\t\tif (Array.isArray(parsed)) return unknownRecord(parsed[0]);\n\t\treturn unknownRecord(parsed);\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst dockerObjectIsAbsent = (err: string): boolean =>\n\t/No such (object|container|network)|not found|No such/i.test(err);\n\nconst uniqueNumbers = (values: ReadonlyArray<number>): ReadonlyArray<number> =>\n\t[...new Set(values)].sort((a, b) => a - b);\n\nconst inspectRouterContainer = (\n\tprofile: RouterProfile,\n\tcommand: DoctorCommandRunner,\n): RouterContainerStatus => {\n\tconst result = command('docker', ['container', 'inspect', profile.containerName]);\n\tif (!result.ok) {\n\t\treturn dockerObjectIsAbsent(result.err)\n\t\t\t? { status: 'absent' }\n\t\t\t: { status: 'unavailable', detail: result.err };\n\t}\n\tconst doc = parseDockerInspectFirst(result.out);\n\tif (doc === null) return { status: 'invalid', detail: 'container inspect JSON was invalid' };\n\tconst state = fieldRecord(doc, 'State') ?? {};\n\tconst config = fieldRecord(doc, 'Config') ?? {};\n\tconst networkSettings = fieldRecord(doc, 'NetworkSettings') ?? {};\n\tconst networks = fieldRecord(networkSettings, 'Networks') ?? {};\n\tconst ports = fieldRecord(networkSettings, 'Ports') ?? {};\n\tconst publishedPorts: Array<number> = [];\n\tfor (const bindings of Object.values(ports)) {\n\t\tif (!Array.isArray(bindings)) continue;\n\t\tfor (const binding of bindings) {\n\t\t\tconst rec = unknownRecord(binding);\n\t\t\tif (rec === null) continue;\n\t\t\tconst rawPort = fieldString(rec, 'HostPort');\n\t\t\tif (rawPort !== null && /^\\d+$/.test(rawPort)) {\n\t\t\t\tpublishedPorts.push(Number.parseInt(rawPort, 10));\n\t\t\t}\n\t\t}\n\t}\n\tconst labels = stringRecord(config.Labels);\n\treturn {\n\t\tstatus: 'present',\n\t\trunning: fieldBoolean(state, 'Running') === true,\n\t\tlabelsMatch: routerProfileLabelsMatch(labels, profile),\n\t\tattachedToNetwork: Object.keys(networks).includes(profile.networkName),\n\t\tpublishedPorts: uniqueNumbers(publishedPorts),\n\t};\n};\n\nconst inspectRouterNetwork = (\n\tprofile: RouterProfile,\n\tcommand: DoctorCommandRunner,\n): RouterNetworkStatus => {\n\tconst result = command('docker', ['network', 'inspect', profile.networkName]);\n\tif (!result.ok) {\n\t\treturn dockerObjectIsAbsent(result.err)\n\t\t\t? { status: 'absent' }\n\t\t\t: { status: 'unavailable', detail: result.err };\n\t}\n\tconst doc = parseDockerInspectFirst(result.out);\n\tif (doc === null) return { status: 'invalid', detail: 'network inspect JSON was invalid' };\n\tconst id = fieldString(doc, 'Id');\n\treturn id === null ? { status: 'present' } : { status: 'present', id };\n};\n\nconst inspectRouterDispatch = (profile: RouterProfile): Effect.Effect<RouterDispatchScan> =>\n\t// Yield a fresh `LivenessProbeScope` so repeated lease owners across\n\t// many dispatch route files fork the OS probe once per pid.\n\tEffect.gen(function* () {\n\t\tif (!existsSync(profile.dispatchDir)) {\n\t\t\treturn {\n\t\t\t\tstatus: 'absent' as const,\n\t\t\t\tfiles: 0,\n\t\t\t\tliveRoutes: 0,\n\t\t\t\tstaleRoutes: 0,\n\t\t\t\tunknownOwnerRoutes: 0,\n\t\t\t\tcorruptRouteFiles: 0,\n\t\t\t\tdiagnostics: 0,\n\t\t\t\tsafeToPrune: true,\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\tif (!statSync(profile.dispatchDir).isDirectory()) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'not-directory' as const,\n\t\t\t\t\tfiles: 0,\n\t\t\t\t\tliveRoutes: 0,\n\t\t\t\t\tstaleRoutes: 0,\n\t\t\t\t\tunknownOwnerRoutes: 1,\n\t\t\t\t\tcorruptRouteFiles: 1,\n\t\t\t\t\tdiagnostics: 1,\n\t\t\t\t\tsafeToPrune: false,\n\t\t\t\t};\n\t\t\t}\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tstatus: 'unreadable' as const,\n\t\t\t\tfiles: 0,\n\t\t\t\tliveRoutes: 0,\n\t\t\t\tstaleRoutes: 0,\n\t\t\t\tunknownOwnerRoutes: 1,\n\t\t\t\tcorruptRouteFiles: 1,\n\t\t\t\tdiagnostics: 1,\n\t\t\t\tsafeToPrune: false,\n\t\t\t};\n\t\t}\n\t\tlet files: ReadonlyArray<string>;\n\t\ttry {\n\t\t\tfiles = readdirSync(profile.dispatchDir);\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tstatus: 'unreadable' as const,\n\t\t\t\tfiles: 0,\n\t\t\t\tliveRoutes: 0,\n\t\t\t\tstaleRoutes: 0,\n\t\t\t\tunknownOwnerRoutes: 1,\n\t\t\t\tcorruptRouteFiles: 1,\n\t\t\t\tdiagnostics: 1,\n\t\t\t\tsafeToPrune: false,\n\t\t\t};\n\t\t}\n\t\tconst probe = yield* LivenessProbeScope;\n\t\tlet routeFiles = 0;\n\t\tlet liveRoutes = 0;\n\t\tlet staleRoutes = 0;\n\t\tlet unknownOwnerRoutes = 0;\n\t\tlet corruptRouteFiles = 0;\n\t\tlet diagnostics = 0;\n\t\tfor (const filename of files) {\n\t\t\tconst dispatchFileId = dispatchFileIdFromFilename(filename);\n\t\t\tif (dispatchFileId === null) continue;\n\t\t\trouteFiles += 1;\n\t\t\tlet body: string;\n\t\t\ttry {\n\t\t\t\tbody = readFileSync(join(profile.dispatchDir, filename), 'utf8');\n\t\t\t} catch {\n\t\t\t\tcorruptRouteFiles += 1;\n\t\t\t\tunknownOwnerRoutes += 1;\n\t\t\t\tdiagnostics += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst parsed = parseDispatchRouteFile(body, dispatchFileId);\n\t\t\tdiagnostics += parsed.diagnostics.length;\n\t\t\tif (parsed._tag === 'invalid') {\n\t\t\t\tcorruptRouteFiles += 1;\n\t\t\t\tunknownOwnerRoutes += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (parsed.route.lease === null) {\n\t\t\t\tunknownOwnerRoutes += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst leaseStatus = yield* probe\n\t\t\t\t.probeHolderLiveness(parsed.route.lease.owner)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed('alive' as const)));\n\t\t\tif (leaseStatus === 'dead') staleRoutes += 1;\n\t\t\telse liveRoutes += 1;\n\t\t}\n\t\tconst safeToPrune = liveRoutes === 0 && unknownOwnerRoutes === 0 && corruptRouteFiles === 0;\n\t\treturn {\n\t\t\tstatus: 'ok' as const,\n\t\t\tfiles: routeFiles,\n\t\t\tliveRoutes,\n\t\t\tstaleRoutes,\n\t\t\tunknownOwnerRoutes,\n\t\t\tcorruptRouteFiles,\n\t\t\tdiagnostics,\n\t\t\tsafeToPrune,\n\t\t};\n\t}).pipe(Effect.provide(layerLivenessProbeScope));\n\nconst inspectRouterStateDir = (profile: RouterProfile): 'absent' | 'present' | 'not-directory' => {\n\tif (!existsSync(profile.stateDir)) return 'absent';\n\ttry {\n\t\treturn statSync(profile.stateDir).isDirectory() ? 'present' : 'not-directory';\n\t} catch {\n\t\treturn 'not-directory';\n\t}\n};\n\nconst summarizeRouterContainer = (container: RouterContainerStatus): string => {\n\tif (container.status !== 'present') return container.status;\n\treturn [\n\t\tcontainer.running === true ? 'running' : 'stopped',\n\t\t`labels=${container.labelsMatch === true ? 'ok' : 'mismatch'}`,\n\t\t`network=${container.attachedToNetwork === true ? 'attached' : 'missing'}`,\n\t\t`ports=${(container.publishedPorts ?? []).join(',') || 'none'}`,\n\t].join('/');\n};\n\nexport const routerProfileProbe = (options: RouterProfileProbeOptions = {}): Probe => ({\n\tname: 'router-profile',\n\tdescription: 'router profile state, dispatch leases, and entrypoint listeners',\n\trequired: false,\n\trun: () =>\n\t\tEffect.gen(function* () {\n\t\t\tconst profile = options.profile ?? makeDefaultRouterProfile();\n\t\t\tconst entrypoints = options.entrypoints ?? BUILT_IN_ENTRYPOINTS;\n\t\t\tconst command = options.command ?? captureCommand;\n\t\t\tconst probePort = options.probePort ?? probePortFree;\n\t\t\tconst ports = uniqueSortedEntrypointPorts(entrypoints);\n\t\t\tconst stateDirStatus = inspectRouterStateDir(profile);\n\t\t\tconst dispatch = yield* inspectRouterDispatch(profile);\n\t\t\tconst container = inspectRouterContainer(profile, command);\n\t\t\tconst network = inspectRouterNetwork(profile, command);\n\t\t\tconst listenerResults = yield* Effect.tryPromise({\n\t\t\t\ttry: () =>\n\t\t\t\t\tPromise.all(\n\t\t\t\t\t\tports.map(async (port) => ({\n\t\t\t\t\t\t\tport,\n\t\t\t\t\t\t\tfree: await probePort(port),\n\t\t\t\t\t\t})),\n\t\t\t\t\t),\n\t\t\t\tcatch: () => 'router entrypoint listener probe failed',\n\t\t\t}).pipe(Effect.catch(() => Effect.succeed(ports.map((port) => ({ port, free: true })))));\n\t\t\tconst freePorts = listenerResults.filter((r) => r.free).map((r) => r.port);\n\t\t\tconst occupiedPorts = listenerResults.filter((r) => !r.free).map((r) => r.port);\n\t\t\tconst protectedRoutes =\n\t\t\t\tdispatch.liveRoutes + dispatch.unknownOwnerRoutes + dispatch.corruptRouteFiles;\n\t\t\tconst problems: string[] = [];\n\t\t\tif (stateDirStatus === 'not-directory')\n\t\t\t\tproblems.push(`${profile.stateDir} is not a directory`);\n\t\t\tif (dispatch.status === 'not-directory' || dispatch.status === 'unreadable') {\n\t\t\t\tproblems.push(`dispatch dir is ${dispatch.status}`);\n\t\t\t}\n\t\t\tif (dispatch.unknownOwnerRoutes > 0 || dispatch.corruptRouteFiles > 0) {\n\t\t\t\tproblems.push(\n\t\t\t\t\t`unknown/corrupt dispatch leases=${dispatch.unknownOwnerRoutes + dispatch.corruptRouteFiles}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (dispatch.staleRoutes > 0) problems.push(`stale dispatch leases=${dispatch.staleRoutes}`);\n\t\t\tif (protectedRoutes > 0 && (container.status !== 'present' || container.running !== true)) {\n\t\t\t\tproblems.push('protected dispatch leases exist without a running router container');\n\t\t\t}\n\t\t\tif (container.status === 'invalid' || container.status === 'unavailable') {\n\t\t\t\tproblems.push(\n\t\t\t\t\t`router container inspect ${container.status}: ${container.detail ?? 'unknown'}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (container.status === 'present') {\n\t\t\t\tif (container.labelsMatch !== true)\n\t\t\t\t\tproblems.push('router container labels do not match profile');\n\t\t\t\tif (container.attachedToNetwork !== true) {\n\t\t\t\t\tproblems.push('router container is not attached to profile network');\n\t\t\t\t}\n\t\t\t\tif (container.running === true && freePorts.length > 0) {\n\t\t\t\t\tproblems.push(`router entrypoint listeners missing: ${freePorts.join(', ')}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (container.status !== 'present' && occupiedPorts.length > 0) {\n\t\t\t\tproblems.push(\n\t\t\t\t\t`router entrypoint ports already in use without profile container: ${occupiedPorts.join(', ')}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (network.status === 'invalid' || network.status === 'unavailable') {\n\t\t\t\tproblems.push(`router network inspect ${network.status}: ${network.detail ?? 'unknown'}`);\n\t\t\t}\n\t\t\tconst detail = [\n\t\t\t\t`profile=${profile.id}`,\n\t\t\t\t`state=${stateDirStatus}`,\n\t\t\t\t`dispatch=${dispatch.status}:files=${dispatch.files},live=${dispatch.liveRoutes},stale=${dispatch.staleRoutes},unknown=${dispatch.unknownOwnerRoutes},corrupt=${dispatch.corruptRouteFiles},diagnostics=${dispatch.diagnostics},pruneSafe=${dispatch.safeToPrune ? 'yes' : 'no'}`,\n\t\t\t\t`container=${summarizeRouterContainer(container)}`,\n\t\t\t\t`network=${network.status}`,\n\t\t\t\t`entrypoints=${ports.join(', ') || 'none'}`,\n\t\t\t].join('; ');\n\t\t\tif (problems.length === 0) return okOutcome(detail);\n\t\t\treturn {\n\t\t\t\tstatus: 'warn' as const,\n\t\t\t\tdetail: `${detail}; ${problems.join('; ')}`,\n\t\t\t};\n\t\t}),\n});\n\n/** Probe: list orphaned stack locks under `<runtimeRoot>/<app>/`. A\n * stack lock whose owner PID is dead is a stale-lock candidate that\n * `--clean-locks` would reclaim. */\nexport const locksProbe = (appRoot: string): Probe => ({\n\tname: 'locks',\n\tdescription: 'stale cross-process locks',\n\trequired: false,\n\trun: () =>\n\t\tEffect.gen(function* () {\n\t\t\tif (!existsSync(appRoot)) return okOutcome('(no app root yet)');\n\t\t\t// Yield a fresh `LivenessProbeScope` so a single pid that\n\t\t\t// shows up in multiple stack rosters under this app root is\n\t\t\t// probed AT MOST once across the full lock scan.\n\t\t\tconst probe = yield* LivenessProbeScope;\n\t\t\tlet orphans = 0;\n\t\t\tlet totalLive = 0;\n\t\t\ttry {\n\t\t\t\tfor (const entry of readdirSync(appRoot)) {\n\t\t\t\t\tif (entry.startsWith('.')) continue;\n\t\t\t\t\tconst stackRoot = join(appRoot, entry);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!statSync(stackRoot).isDirectory()) continue;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst rosterFile = join(stackRoot, 'roster.json');\n\t\t\t\t\tif (!existsSync(rosterFile)) continue;\n\t\t\t\t\tconst doc = yield* readRoster(rosterFile).pipe(\n\t\t\t\t\t\tEffect.catch(() =>\n\t\t\t\t\t\t\tEffect.succeed({ version: 1 as const, holders: [] as RosterHolder[] }),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tfor (const holder of doc.holders) {\n\t\t\t\t\t\tconst liveness = yield* probe\n\t\t\t\t\t\t\t.probeHolderLiveness(holder)\n\t\t\t\t\t\t\t.pipe(Effect.catch(() => Effect.succeed('alive' as const)));\n\t\t\t\t\t\tif (liveness === 'alive') totalLive += 1;\n\t\t\t\t\t\telse orphans += 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (cause) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'warn' as const,\n\t\t\t\t\tdetail: `lock scan failed: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (orphans === 0) {\n\t\t\t\treturn okOutcome(`${totalLive} live, 0 orphan`);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: 'warn' as const,\n\t\t\t\tdetail: `${orphans} orphan holder(s); rerun with --clean-locks`,\n\t\t\t};\n\t\t}).pipe(Effect.provide(layerLivenessProbeScope)),\n});\n\n/** Probe: state-dir is writable. Validates DEVSTACK_STATE_DIR resolves\n * to a usable path (or the default ~/.devstack does). */\nexport const stateDirProbe = (stateDir: string): Probe => ({\n\tname: 'state-dir',\n\tdescription: 'state directory',\n\trequired: true,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tif (!existsSync(stateDir)) {\n\t\t\t\treturn okOutcome(`${stateDir} (will be created)`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst s = statSync(stateDir);\n\t\t\t\tif (!s.isDirectory()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\t\tdetail: `${stateDir} is not a directory`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn okOutcome(stateDir);\n\t\t\t} catch (cause) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\tdetail: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t};\n\t\t\t}\n\t\t}),\n});\n\n/** Probe: optional fork-cache directory inspection. Returns the size\n * of the cache (informational). */\nexport const forkCacheProbe = (appRoot: string): Probe => ({\n\tname: 'fork-cache',\n\tdescription: 'sui-fork cache',\n\trequired: false,\n\trun: () =>\n\t\tEffect.sync(() => {\n\t\t\tconst cacheDir = join(appRoot, '.fork-cache');\n\t\t\tif (!existsSync(cacheDir)) return okOutcome('(absent)');\n\t\t\ttry {\n\t\t\t\tconst size = countTreeSize(cacheDir);\n\t\t\t\treturn okOutcome(`${size} entries`);\n\t\t\t} catch {\n\t\t\t\treturn { status: 'warn', detail: 'fork cache scan failed' };\n\t\t\t}\n\t\t}),\n});\n\nconst countTreeSize = (dir: string, depth = 0): number => {\n\tif (depth > 3) return 0;\n\tlet n = 0;\n\tfor (const entry of readdirSync(dir)) {\n\t\tconst p = join(dir, entry);\n\t\ttry {\n\t\t\tconst s = statSync(p);\n\t\t\tif (s.isFile()) n += 1;\n\t\t\telse if (s.isDirectory()) n += countTreeSize(p, depth + 1);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\treturn n;\n};\n\n/** Default probe set. `cli/main.ts` composes this with the resolved\n * app root, runtime state dir, router profile, and router entrypoints. */\nexport const defaultProbes = (params: {\n\treadonly stateDir: string;\n\treadonly appRoot: string;\n\treadonly routerProfile?: RouterProfile;\n\treadonly routerEntrypoints?: ReadonlyArray<Entrypoint>;\n}): ReadonlyArray<Probe> => [\n\tdockerProbe,\n\tsuiCliProbe,\n\tstateDirProbe(params.stateDir),\n\trouterProfileProbe({\n\t\t...(params.routerProfile === undefined ? {} : { profile: params.routerProfile }),\n\t\t...(params.routerEntrypoints === undefined ? {} : { entrypoints: params.routerEntrypoints }),\n\t}),\n\tlocksProbe(params.appRoot),\n\tforkCacheProbe(params.appRoot),\n];\n"],"mappings":";;;;;;;;;;;;;;;AA2CA,MAAM,aAAa,WAClB,WAAW,KAAA,IAAY;CAAE,QAAQ;CAAM;AAAO,IAAI,EAAE,QAAQ,KAAK;AAIlE,MAAM,kBACL,KACA,MACA,YAAY,QACO;CACnB,IAAI;EAMH,OAAO;GAAE,IAAI;GAAM,KALP,aAAa,KAAK,MAAkB;IAC/C,UAAU;IACV,SAAS;IACT,OAAO;KAAC;KAAU;KAAQ;IAAM;GACjC,CAC0B,CAAC,CAAC,KAAK;EAAE;CACpC,SAAS,KAAK;EACb,OAAO;GACN,IAAI;GACJ,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EACrD;CACD;AACD;;AAGA,MAAa,cAAqB;CACjC,MAAM;CACN,aAAa;CACb,UAAU;CACV,WACC,OAAO,WAAW;EACjB,MAAM,SAAS,eAAe,UAAU;GAAC;GAAW;GAAY;EAAqB,CAAC;EACtF,IAAI,CAAC,OAAO,IACX,OAAO;GACN,QAAQ;GACR,QAAQ,0BAA0B,OAAO;EAC1C;EAED,OAAO,UAAU,UAAU,OAAO,KAAK;CACxC,CAAC;AACH;;AAGA,MAAa,cAAqB;CACjC,MAAM;CACN,aAAa;CACb,UAAU;CACV,WACC,OAAO,WAAW;EACjB,MAAM,SAAS,eAAe,OAAO,CAAC,WAAW,CAAC;EAClD,OAAO,OAAO,KACX,UAAU,OAAO,GAAG,IACpB;GACA,QAAQ;GACR,QAAQ;EACT;CACH,CAAC;AACH;;;;;AAMA,MAAM,iBAAiB,MAAc,YAAY,QAChD,IAAI,SAAS,YAAY;CACxB,MAAM,SAAS,iBAAiB;EAAE,MAAM;EAAa;CAAK,CAAC;CAC3D,MAAM,UAAU,SAAwB;EACvC,OAAO,QAAQ;EACf,QAAQ,IAAI;CACb;CACA,MAAM,QAAQ,iBAAiB,OAAO,IAAI,GAAG,SAAS;CACtD,OAAO,GAAG,iBAAiB;EAC1B,aAAa,KAAK;EAClB,OAAO,KAAK;CACb,CAAC;CACD,OAAO,GAAG,eAAe;EACxB,aAAa,KAAK;EAClB,OAAO,IAAI;CACZ,CAAC;AACF,CAAC;AAsCF,MAAM,iBAAiB,UACtB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAC/D,QACD;AAEJ,MAAM,gBAAgB,UAA2C;CAChE,MAAM,MAAM,cAAc,KAAK;CAC/B,IAAI,QAAQ,MAAM,OAAO,CAAC;CAC1B,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,GAAG,GAC1C,IAAI,OAAO,QAAQ,UAAU,IAAI,OAAO;CAEzC,OAAO;AACR;AAEA,MAAM,eACL,QACA,QACoC,cAAc,OAAO,IAAI;AAE9D,MAAM,eAAe,QAAiC,QACrD,OAAO,OAAO,SAAS,WAAY,OAAO,OAAkB;AAE7D,MAAM,gBAAgB,QAAiC,QACtD,OAAO,OAAO,SAAS,YAAa,OAAO,OAAmB;AAE/D,MAAM,2BAA2B,QAAgD;CAChF,IAAI;EACH,MAAM,SAAS,kBAAkB,KAAK;GACrC,QAAQ;GACR,UAAU,UAAU;EACrB,CAAC;EACD,IAAI,MAAM,QAAQ,MAAM,GAAG,OAAO,cAAc,OAAO,EAAE;EACzD,OAAO,cAAc,MAAM;CAC5B,QAAQ;EACP,OAAO;CACR;AACD;AAEA,MAAM,wBAAwB,QAC7B,wDAAwD,KAAK,GAAG;AAEjE,MAAM,iBAAiB,WACtB,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;AAE1C,MAAM,0BACL,SACA,YAC2B;CAC3B,MAAM,SAAS,QAAQ,UAAU;EAAC;EAAa;EAAW,QAAQ;CAAa,CAAC;CAChF,IAAI,CAAC,OAAO,IACX,OAAO,qBAAqB,OAAO,GAAG,IACnC,EAAE,QAAQ,SAAS,IACnB;EAAE,QAAQ;EAAe,QAAQ,OAAO;CAAI;CAEhD,MAAM,MAAM,wBAAwB,OAAO,GAAG;CAC9C,IAAI,QAAQ,MAAM,OAAO;EAAE,QAAQ;EAAW,QAAQ;CAAqC;CAC3F,MAAM,QAAQ,YAAY,KAAK,OAAO,KAAK,CAAC;CAC5C,MAAM,SAAS,YAAY,KAAK,QAAQ,KAAK,CAAC;CAC9C,MAAM,kBAAkB,YAAY,KAAK,iBAAiB,KAAK,CAAC;CAChE,MAAM,WAAW,YAAY,iBAAiB,UAAU,KAAK,CAAC;CAC9D,MAAM,QAAQ,YAAY,iBAAiB,OAAO,KAAK,CAAC;CACxD,MAAM,iBAAgC,CAAC;CACvC,KAAK,MAAM,YAAY,OAAO,OAAO,KAAK,GAAG;EAC5C,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;EAC9B,KAAK,MAAM,WAAW,UAAU;GAC/B,MAAM,MAAM,cAAc,OAAO;GACjC,IAAI,QAAQ,MAAM;GAClB,MAAM,UAAU,YAAY,KAAK,UAAU;GAC3C,IAAI,YAAY,QAAQ,QAAQ,KAAK,OAAO,GAC3C,eAAe,KAAK,OAAO,SAAS,SAAS,EAAE,CAAC;EAElD;CACD;CACA,MAAM,SAAS,aAAa,OAAO,MAAM;CACzC,OAAO;EACN,QAAQ;EACR,SAAS,aAAa,OAAO,SAAS,MAAM;EAC5C,aAAa,yBAAyB,QAAQ,OAAO;EACrD,mBAAmB,OAAO,KAAK,QAAQ,CAAC,CAAC,SAAS,QAAQ,WAAW;EACrE,gBAAgB,cAAc,cAAc;CAC7C;AACD;AAEA,MAAM,wBACL,SACA,YACyB;CACzB,MAAM,SAAS,QAAQ,UAAU;EAAC;EAAW;EAAW,QAAQ;CAAW,CAAC;CAC5E,IAAI,CAAC,OAAO,IACX,OAAO,qBAAqB,OAAO,GAAG,IACnC,EAAE,QAAQ,SAAS,IACnB;EAAE,QAAQ;EAAe,QAAQ,OAAO;CAAI;CAEhD,MAAM,MAAM,wBAAwB,OAAO,GAAG;CAC9C,IAAI,QAAQ,MAAM,OAAO;EAAE,QAAQ;EAAW,QAAQ;CAAmC;CACzF,MAAM,KAAK,YAAY,KAAK,IAAI;CAChC,OAAO,OAAO,OAAO,EAAE,QAAQ,UAAU,IAAI;EAAE,QAAQ;EAAW;CAAG;AACtE;AAEA,MAAM,yBAAyB,YAG9B,OAAO,IAAI,aAAa;CACvB,IAAI,CAAC,WAAW,QAAQ,WAAW,GAClC,OAAO;EACN,QAAQ;EACR,OAAO;EACP,YAAY;EACZ,aAAa;EACb,oBAAoB;EACpB,mBAAmB;EACnB,aAAa;EACb,aAAa;CACd;CAED,IAAI;EACH,IAAI,CAAC,SAAS,QAAQ,WAAW,CAAC,CAAC,YAAY,GAC9C,OAAO;GACN,QAAQ;GACR,OAAO;GACP,YAAY;GACZ,aAAa;GACb,oBAAoB;GACpB,mBAAmB;GACnB,aAAa;GACb,aAAa;EACd;CAEF,QAAQ;EACP,OAAO;GACN,QAAQ;GACR,OAAO;GACP,YAAY;GACZ,aAAa;GACb,oBAAoB;GACpB,mBAAmB;GACnB,aAAa;GACb,aAAa;EACd;CACD;CACA,IAAI;CACJ,IAAI;EACH,QAAQ,YAAY,QAAQ,WAAW;CACxC,QAAQ;EACP,OAAO;GACN,QAAQ;GACR,OAAO;GACP,YAAY;GACZ,aAAa;GACb,oBAAoB;GACpB,mBAAmB;GACnB,aAAa;GACb,aAAa;EACd;CACD;CACA,MAAM,QAAQ,OAAO;CACrB,IAAI,aAAa;CACjB,IAAI,aAAa;CACjB,IAAI,cAAc;CAClB,IAAI,qBAAqB;CACzB,IAAI,oBAAoB;CACxB,IAAI,cAAc;CAClB,KAAK,MAAM,YAAY,OAAO;EAC7B,MAAM,iBAAiB,2BAA2B,QAAQ;EAC1D,IAAI,mBAAmB,MAAM;EAC7B,cAAc;EACd,IAAI;EACJ,IAAI;GACH,OAAO,aAAa,KAAK,QAAQ,aAAa,QAAQ,GAAG,MAAM;EAChE,QAAQ;GACP,qBAAqB;GACrB,sBAAsB;GACtB,eAAe;GACf;EACD;EACA,MAAM,SAAS,uBAAuB,MAAM,cAAc;EAC1D,eAAe,OAAO,YAAY;EAClC,IAAI,OAAO,SAAS,WAAW;GAC9B,qBAAqB;GACrB,sBAAsB;GACtB;EACD;EACA,IAAI,OAAO,MAAM,UAAU,MAAM;GAChC,sBAAsB;GACtB;EACD;EAIA,KAAI,OAHuB,MACzB,oBAAoB,OAAO,MAAM,MAAM,KAAK,CAAC,CAC7C,KAAK,OAAO,YAAY,OAAO,QAAQ,OAAgB,CAAC,CAAC,OACvC,QAAQ,eAAe;OACtC,cAAc;CACpB;CAEA,OAAO;EACN,QAAQ;EACR,OAAO;EACP;EACA;EACA;EACA;EACA;EACA,aATmB,eAAe,KAAK,uBAAuB,KAAK,sBAAsB;CAU1F;AACD,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,uBAAuB,CAAC;AAEhD,MAAM,yBAAyB,YAAmE;CACjG,IAAI,CAAC,WAAW,QAAQ,QAAQ,GAAG,OAAO;CAC1C,IAAI;EACH,OAAO,SAAS,QAAQ,QAAQ,CAAC,CAAC,YAAY,IAAI,YAAY;CAC/D,QAAQ;EACP,OAAO;CACR;AACD;AAEA,MAAM,4BAA4B,cAA6C;CAC9E,IAAI,UAAU,WAAW,WAAW,OAAO,UAAU;CACrD,OAAO;EACN,UAAU,YAAY,OAAO,YAAY;EACzC,UAAU,UAAU,gBAAgB,OAAO,OAAO;EAClD,WAAW,UAAU,sBAAsB,OAAO,aAAa;EAC/D,UAAU,UAAU,kBAAkB,CAAC,EAAA,CAAG,KAAK,GAAG,KAAK;CACxD,CAAC,CAAC,KAAK,GAAG;AACX;AAEA,MAAa,sBAAsB,UAAqC,CAAC,OAAc;CACtF,MAAM;CACN,aAAa;CACb,UAAU;CACV,WACC,OAAO,IAAI,aAAa;EACvB,MAAM,UAAU,QAAQ,WAAW,yBAAyB;EAC5D,MAAM,cAAc,QAAQ,eAAe;EAC3C,MAAM,UAAU,QAAQ,WAAW;EACnC,MAAM,YAAY,QAAQ,aAAa;EACvC,MAAM,QAAQ,4BAA4B,WAAW;EACrD,MAAM,iBAAiB,sBAAsB,OAAO;EACpD,MAAM,WAAW,OAAO,sBAAsB,OAAO;EACrD,MAAM,YAAY,uBAAuB,SAAS,OAAO;EACzD,MAAM,UAAU,qBAAqB,SAAS,OAAO;EACrD,MAAM,kBAAkB,OAAO,OAAO,WAAW;GAChD,WACC,QAAQ,IACP,MAAM,IAAI,OAAO,UAAU;IAC1B;IACA,MAAM,MAAM,UAAU,IAAI;GAC3B,EAAE,CACH;GACD,aAAa;EACd,CAAC,CAAC,CAAC,KAAK,OAAO,YAAY,OAAO,QAAQ,MAAM,KAAK,UAAU;GAAE;GAAM,MAAM;EAAK,EAAE,CAAC,CAAC,CAAC;EACvF,MAAM,YAAY,gBAAgB,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;EACzE,MAAM,gBAAgB,gBAAgB,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;EAC9E,MAAM,kBACL,SAAS,aAAa,SAAS,qBAAqB,SAAS;EAC9D,MAAM,WAAqB,CAAC;EAC5B,IAAI,mBAAmB,iBACtB,SAAS,KAAK,GAAG,QAAQ,SAAS,oBAAoB;EACvD,IAAI,SAAS,WAAW,mBAAmB,SAAS,WAAW,cAC9D,SAAS,KAAK,mBAAmB,SAAS,QAAQ;EAEnD,IAAI,SAAS,qBAAqB,KAAK,SAAS,oBAAoB,GACnE,SAAS,KACR,mCAAmC,SAAS,qBAAqB,SAAS,mBAC3E;EAED,IAAI,SAAS,cAAc,GAAG,SAAS,KAAK,yBAAyB,SAAS,aAAa;EAC3F,IAAI,kBAAkB,MAAM,UAAU,WAAW,aAAa,UAAU,YAAY,OACnF,SAAS,KAAK,oEAAoE;EAEnF,IAAI,UAAU,WAAW,aAAa,UAAU,WAAW,eAC1D,SAAS,KACR,4BAA4B,UAAU,OAAO,IAAI,UAAU,UAAU,WACtE;EAED,IAAI,UAAU,WAAW,WAAW;GACnC,IAAI,UAAU,gBAAgB,MAC7B,SAAS,KAAK,8CAA8C;GAC7D,IAAI,UAAU,sBAAsB,MACnC,SAAS,KAAK,qDAAqD;GAEpE,IAAI,UAAU,YAAY,QAAQ,UAAU,SAAS,GACpD,SAAS,KAAK,wCAAwC,UAAU,KAAK,IAAI,GAAG;EAE9E;EACA,IAAI,UAAU,WAAW,aAAa,cAAc,SAAS,GAC5D,SAAS,KACR,qEAAqE,cAAc,KAAK,IAAI,GAC7F;EAED,IAAI,QAAQ,WAAW,aAAa,QAAQ,WAAW,eACtD,SAAS,KAAK,0BAA0B,QAAQ,OAAO,IAAI,QAAQ,UAAU,WAAW;EAEzF,MAAM,SAAS;GACd,WAAW,QAAQ;GACnB,SAAS;GACT,YAAY,SAAS,OAAO,SAAS,SAAS,MAAM,QAAQ,SAAS,WAAW,SAAS,SAAS,YAAY,WAAW,SAAS,mBAAmB,WAAW,SAAS,kBAAkB,eAAe,SAAS,YAAY,aAAa,SAAS,cAAc,QAAQ;GAC3Q,aAAa,yBAAyB,SAAS;GAC/C,WAAW,QAAQ;GACnB,eAAe,MAAM,KAAK,IAAI,KAAK;EACpC,CAAC,CAAC,KAAK,IAAI;EACX,IAAI,SAAS,WAAW,GAAG,OAAO,UAAU,MAAM;EAClD,OAAO;GACN,QAAQ;GACR,QAAQ,GAAG,OAAO,IAAI,SAAS,KAAK,IAAI;EACzC;CACD,CAAC;AACH;;;;AAKA,MAAa,cAAc,aAA4B;CACtD,MAAM;CACN,aAAa;CACb,UAAU;CACV,WACC,OAAO,IAAI,aAAa;EACvB,IAAI,CAAC,WAAW,OAAO,GAAG,OAAO,UAAU,mBAAmB;EAI9D,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU;EACd,IAAI,YAAY;EAChB,IAAI;GACH,KAAK,MAAM,SAAS,YAAY,OAAO,GAAG;IACzC,IAAI,MAAM,WAAW,GAAG,GAAG;IAC3B,MAAM,YAAY,KAAK,SAAS,KAAK;IACrC,IAAI;KACH,IAAI,CAAC,SAAS,SAAS,CAAC,CAAC,YAAY,GAAG;IACzC,QAAQ;KACP;IACD;IACA,MAAM,aAAa,KAAK,WAAW,aAAa;IAChD,IAAI,CAAC,WAAW,UAAU,GAAG;IAC7B,MAAM,MAAM,OAAO,WAAW,UAAU,CAAC,CAAC,KACzC,OAAO,YACN,OAAO,QAAQ;KAAE,SAAS;KAAY,SAAS,CAAC;IAAoB,CAAC,CACtE,CACD;IACA,KAAK,MAAM,UAAU,IAAI,SAIxB,KAAI,OAHoB,MACtB,oBAAoB,MAAM,CAAC,CAC3B,KAAK,OAAO,YAAY,OAAO,QAAQ,OAAgB,CAAC,CAAC,OAC1C,SAAS,aAAa;SAClC,WAAW;GAElB;EACD,SAAS,OAAO;GACf,OAAO;IACN,QAAQ;IACR,QAAQ,qBAAqB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GACnF;EACD;EACA,IAAI,YAAY,GACf,OAAO,UAAU,GAAG,UAAU,gBAAgB;EAE/C,OAAO;GACN,QAAQ;GACR,QAAQ,GAAG,QAAQ;EACpB;CACD,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,uBAAuB,CAAC;AACjD;;;AAIA,MAAa,iBAAiB,cAA6B;CAC1D,MAAM;CACN,aAAa;CACb,UAAU;CACV,WACC,OAAO,WAAW;EACjB,IAAI,CAAC,WAAW,QAAQ,GACvB,OAAO,UAAU,GAAG,SAAS,mBAAmB;EAEjD,IAAI;GAEH,IAAI,CADM,SAAS,QACd,CAAC,CAAC,YAAY,GAClB,OAAO;IACN,QAAQ;IACR,QAAQ,GAAG,SAAS;GACrB;GAED,OAAO,UAAU,QAAQ;EAC1B,SAAS,OAAO;GACf,OAAO;IACN,QAAQ;IACR,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAC9D;EACD;CACD,CAAC;AACH;;;AAIA,MAAa,kBAAkB,aAA4B;CAC1D,MAAM;CACN,aAAa;CACb,UAAU;CACV,WACC,OAAO,WAAW;EACjB,MAAM,WAAW,KAAK,SAAS,aAAa;EAC5C,IAAI,CAAC,WAAW,QAAQ,GAAG,OAAO,UAAU,UAAU;EACtD,IAAI;GAEH,OAAO,UAAU,GADJ,cAAc,QACJ,EAAE,SAAS;EACnC,QAAQ;GACP,OAAO;IAAE,QAAQ;IAAQ,QAAQ;GAAyB;EAC3D;CACD,CAAC;AACH;AAEA,MAAM,iBAAiB,KAAa,QAAQ,MAAc;CACzD,IAAI,QAAQ,GAAG,OAAO;CACtB,IAAI,IAAI;CACR,KAAK,MAAM,SAAS,YAAY,GAAG,GAAG;EACrC,MAAM,IAAI,KAAK,KAAK,KAAK;EACzB,IAAI;GACH,MAAM,IAAI,SAAS,CAAC;GACpB,IAAI,EAAE,OAAO,GAAG,KAAK;QAChB,IAAI,EAAE,YAAY,GAAG,KAAK,cAAc,GAAG,QAAQ,CAAC;EAC1D,QAAQ,CAER;CACD;CACA,OAAO;AACR;;;AAIA,MAAa,iBAAiB,WAKF;CAC3B;CACA;CACA,cAAc,OAAO,QAAQ;CAC7B,mBAAmB;EAClB,GAAI,OAAO,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,OAAO,cAAc;EAC9E,GAAI,OAAO,sBAAsB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,OAAO,kBAAkB;CAC3F,CAAC;CACD,WAAW,OAAO,OAAO;CACzB,eAAe,OAAO,OAAO;AAC9B"}
|
package/dist/cli/main.d.mts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
+
import { StackContext } from "../build-integrations/runtime/stack-context.mjs";
|
|
2
|
+
import { SubscribableState } from "../substrate/projection.mjs";
|
|
3
|
+
|
|
1
4
|
//#region src/cli/main.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Degraded offline-status projection — built from the on-disk manifest,
|
|
7
|
+
* NOT from a persisted projection twin (the projection snapshot file no
|
|
8
|
+
* longer exists). When the stack is DOWN, the manifest is the only
|
|
9
|
+
* durable record of the boot; `status` surfaces identity + endpoints
|
|
10
|
+
* from it and leaves the live-only slices (`rows` / `accounts` /
|
|
11
|
+
* `packages` / `errors`) empty. A freshly-booted stack also has empty
|
|
12
|
+
* `rows`, so the status renderer already tolerates this shape.
|
|
13
|
+
*
|
|
14
|
+
* Pure projector — exported for the focused unit test. Starts from
|
|
15
|
+
* `emptyProjection()` (the closed-vocabulary baseline) and fills only
|
|
16
|
+
* the two manifest-backed slices, so no display vocabulary can leak in.
|
|
17
|
+
* The manifest identity tuple is `{ app, stack, network }`, matching
|
|
18
|
+
* the projection's identity shape directly. Endpoints get re-branded
|
|
19
|
+
* (`endpointKey` / `pluginKey`)
|
|
20
|
+
* to the projection's branded shape; `registeredAt` is unknown offline,
|
|
21
|
+
* so it defaults to `0`.
|
|
22
|
+
*/
|
|
23
|
+
declare const degradedStatusFromContext: (ctx: StackContext) => SubscribableState;
|
|
2
24
|
/** @internal Exported for tests. Resolves identity flag inputs from a
|
|
3
25
|
* `--app <x>` / `--stack <x>` / `--network <x>` / `--state-dir <x>` /
|
|
4
26
|
* `--config <x>` argv, falling back to `DEVSTACK_*` env vars. Throws
|
|
@@ -15,5 +37,5 @@ declare const identityInputsFromArgv: (argv: ReadonlyArray<string>, env: Readonl
|
|
|
15
37
|
};
|
|
16
38
|
declare const runCli: (argv?: ReadonlyArray<string>) => Promise<void>;
|
|
17
39
|
//#endregion
|
|
18
|
-
export { identityInputsFromArgv, runCli };
|
|
40
|
+
export { degradedStatusFromContext, identityInputsFromArgv, runCli };
|
|
19
41
|
//# sourceMappingURL=main.d.mts.map
|
package/dist/cli/main.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import "../substrate/runtime/
|
|
2
|
+
import { endpointKey, pluginKey } from "../substrate/brand.mjs";
|
|
3
|
+
import { emptyProjection } from "../substrate/runtime/projection/state-ref.mjs";
|
|
4
4
|
import { DevstackNetworkParseError, resolveAppName, resolveNetworkSync, resolveStackName, resolveStateDir } from "../api/inference-network.mjs";
|
|
5
|
+
import { resolveConfigPath } from "../api/load-config.mjs";
|
|
6
|
+
import { readStackContext } from "../build-integrations/runtime/read-stack-context.mjs";
|
|
5
7
|
import { ExitCode } from "../surfaces/cli/sysexits.mjs";
|
|
6
8
|
import { CliUsageError } from "../surfaces/cli/errors.mjs";
|
|
7
9
|
import { ENV_VARS } from "../surfaces/cli/flags.mjs";
|
|
@@ -11,14 +13,16 @@ import { defaultProbes } from "./doctor-probes.mjs";
|
|
|
11
13
|
import { nodeConfirmPrompt } from "../surfaces/cli/commands/confirm-node.mjs";
|
|
12
14
|
import { makeSnapshotReader } from "./snapshot-reader.mjs";
|
|
13
15
|
import { makeDirectPruneDeps } from "./prune-direct.mjs";
|
|
14
|
-
import { makeConfigLoader
|
|
16
|
+
import { makeConfigLoader } from "./wirings/config-loader.mjs";
|
|
15
17
|
import { runUpLive } from "./wirings/up.mjs";
|
|
16
18
|
import { runApplyLive } from "./wirings/apply.mjs";
|
|
19
|
+
import { runCodegen } from "./wirings/codegen.mjs";
|
|
20
|
+
import { runDumpIds } from "./wirings/dump-ids.mjs";
|
|
17
21
|
import { runSnapshotCaptureLiveAware, runSnapshotDeleteDirect, runSnapshotRestoreDirect } from "./wirings/snapshot.mjs";
|
|
18
22
|
import { runWipeDirect, runWipePlanDirect } from "./wirings/wipe.mjs";
|
|
19
23
|
import { Effect } from "effect";
|
|
20
24
|
import { realpathSync } from "node:fs";
|
|
21
|
-
import { dirname, resolve } from "node:path";
|
|
25
|
+
import { dirname, join, resolve } from "node:path";
|
|
22
26
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
23
27
|
//#region src/cli/main.ts
|
|
24
28
|
/** Resolve identity from flags + env. App and stack fall through the
|
|
@@ -66,7 +70,7 @@ const resolveIdentity = (params) => {
|
|
|
66
70
|
explicit: params.network,
|
|
67
71
|
env: process.env.DEVSTACK_NETWORK,
|
|
68
72
|
explicitSource: "--network"
|
|
69
|
-
}).
|
|
73
|
+
}).parsed.name;
|
|
70
74
|
const stackRoot = resolve(stacksRoot, stack);
|
|
71
75
|
return {
|
|
72
76
|
app,
|
|
@@ -79,14 +83,65 @@ const resolveIdentity = (params) => {
|
|
|
79
83
|
explicitStack
|
|
80
84
|
};
|
|
81
85
|
};
|
|
82
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Degraded offline-status projection — built from the on-disk manifest,
|
|
88
|
+
* NOT from a persisted projection twin (the projection snapshot file no
|
|
89
|
+
* longer exists). When the stack is DOWN, the manifest is the only
|
|
90
|
+
* durable record of the boot; `status` surfaces identity + endpoints
|
|
91
|
+
* from it and leaves the live-only slices (`rows` / `accounts` /
|
|
92
|
+
* `packages` / `errors`) empty. A freshly-booted stack also has empty
|
|
93
|
+
* `rows`, so the status renderer already tolerates this shape.
|
|
94
|
+
*
|
|
95
|
+
* Pure projector — exported for the focused unit test. Starts from
|
|
96
|
+
* `emptyProjection()` (the closed-vocabulary baseline) and fills only
|
|
97
|
+
* the two manifest-backed slices, so no display vocabulary can leak in.
|
|
98
|
+
* The manifest identity tuple is `{ app, stack, network }`, matching
|
|
99
|
+
* the projection's identity shape directly. Endpoints get re-branded
|
|
100
|
+
* (`endpointKey` / `pluginKey`)
|
|
101
|
+
* to the projection's branded shape; `registeredAt` is unknown offline,
|
|
102
|
+
* so it defaults to `0`.
|
|
103
|
+
*/
|
|
104
|
+
const degradedStatusFromContext = (ctx) => ({
|
|
105
|
+
...emptyProjection(),
|
|
106
|
+
identity: {
|
|
107
|
+
app: ctx.identity.app,
|
|
108
|
+
stack: ctx.identity.stack,
|
|
109
|
+
network: ctx.identity.network
|
|
110
|
+
},
|
|
111
|
+
endpoints: ctx.endpoints.all().map((endpoint) => ({
|
|
112
|
+
endpointKey: endpointKey(endpoint.endpointKey),
|
|
113
|
+
pluginKey: pluginKey(endpoint.pluginKey),
|
|
114
|
+
name: endpoint.name,
|
|
115
|
+
url: endpoint.url,
|
|
116
|
+
displayUrl: endpoint.displayUrl,
|
|
117
|
+
wireProtocol: endpoint.wireProtocol,
|
|
118
|
+
registeredAt: 0
|
|
119
|
+
}))
|
|
120
|
+
});
|
|
121
|
+
const projectionStatusReader = (identity) => ({ readState: () => Effect.sync(() => {
|
|
122
|
+
try {
|
|
123
|
+
return degradedStatusFromContext(readStackContext({ manifestPath: join(identity.stackRoot, "manifest.json") }));
|
|
124
|
+
} catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}) });
|
|
83
128
|
const buildDirectDeps = (identity) => {
|
|
84
129
|
return {
|
|
85
130
|
up: { run: (flags) => runUpLive(flags.configPath, identity, {
|
|
86
131
|
renderer: flags.renderer,
|
|
87
|
-
stdoutIsTty: Boolean(process.stdout.isTTY)
|
|
132
|
+
stdoutIsTty: Boolean(process.stdout.isTTY),
|
|
133
|
+
fromSnapshot: flags.fromSnapshot,
|
|
134
|
+
snapshotCache: flags.snapshotCache,
|
|
135
|
+
snapshotStalePolicy: flags.snapshotStalePolicy
|
|
88
136
|
}) },
|
|
89
137
|
apply: { run: (flags) => runApplyLive(flags.configPath, identity) },
|
|
138
|
+
codegen: { run: (flags) => runCodegen(flags.configPath, identity) },
|
|
139
|
+
dumpIds: { run: (flags) => runDumpIds(identity, {
|
|
140
|
+
configPath: flags.configPath,
|
|
141
|
+
out: flags.out,
|
|
142
|
+
io: flags.io,
|
|
143
|
+
outputMode: flags.outputMode
|
|
144
|
+
}) },
|
|
90
145
|
status: { reader: projectionStatusReader(identity) },
|
|
91
146
|
snapshot: {
|
|
92
147
|
reader: makeSnapshotReader(identity),
|
|
@@ -265,6 +320,6 @@ if (isMainEntrypoint()) runCli().catch((err) => {
|
|
|
265
320
|
process.exitCode = ExitCode.GENERIC;
|
|
266
321
|
});
|
|
267
322
|
//#endregion
|
|
268
|
-
export { identityInputsFromArgv, runCli };
|
|
323
|
+
export { degradedStatusFromContext, identityInputsFromArgv, runCli };
|
|
269
324
|
|
|
270
325
|
//# sourceMappingURL=main.mjs.map
|
package/dist/cli/main.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.mjs","names":["resolvePath"],"sources":["../../src/cli/main.ts"],"sourcesContent":["// devstack CLI bin entry — argv → identity → deps → dispatch → exit.\n//\n// This file is the executable entry the `bin: { devstack: ... }`\n// package.json field points at. Build output: `dist/cli/main.mjs`.\n//\n// Architecture invariant (surfaces/cli/index.ts header):\n// \"`up` must hand its long-running effect to the outer Node runtime\n// directly, not nest a runtime — otherwise SIGINT cannot reach\n// scope finalizers and container teardown leaks.\"\n//\n// Shape:\n// 1. Pre-parse identity inputs from argv + env (see\n// `identityInputsFromArgv`).\n// 2. Resolve identity (app / stack / network / runtime root) via the\n// shared `api/inference-network` helpers.\n// 3. Build the dispatcher's `CliDeps` bundle from each verb's wiring\n// module in `cli/wirings/`.\n// 4. Hand control to the Stricli-backed dispatcher, which routes to\n// the verb-scoped wiring function.\n\nimport { realpathSync } from 'node:fs';\nimport { dirname, resolve as resolvePath } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\n\nimport { Effect } from 'effect';\n\nimport { readProjectionSnapshot } from '../substrate/runtime/index.ts';\nimport type { SubscribableState } from '../substrate/projection.ts';\nimport { dispatch, type CliDeps, CliUsageError } from '../surfaces/cli/index.ts';\nimport { emitFailure, nodeProcessIO } from '../surfaces/cli/output.ts';\nimport { ENV_VARS } from '../surfaces/cli/flags.ts';\nimport { defaultProbes } from './doctor-probes.ts';\nimport { nodeConfirmPrompt } from '../surfaces/cli/commands/confirm-node.ts';\nimport type { StatusReader } from '../surfaces/cli/commands/status.ts';\nimport { ExitCode } from '../surfaces/cli/sysexits.ts';\nimport { makeSnapshotReader } from './snapshot-reader.ts';\nimport {\n\tDevstackNetworkParseError,\n\tresolveAppName,\n\tresolveNetworkSync,\n\tresolveStackName,\n\tresolveStateDir,\n} from '../api/inference-network.ts';\nimport { makeDirectPruneDeps } from './prune-direct.ts';\nimport { runUpLive } from './wirings/up.ts';\nimport { runApplyLive } from './wirings/apply.ts';\nimport {\n\trunSnapshotCaptureLiveAware,\n\trunSnapshotDeleteDirect,\n\trunSnapshotRestoreDirect,\n} from './wirings/snapshot.ts';\nimport { runWipeDirect, runWipePlanDirect } from './wirings/wipe.ts';\nimport { makeConfigLoader, resolveConfigPath } from './wirings/config-loader.ts';\nimport type { ResolvedIdentity } from './wirings/identity.ts';\n\n// -----------------------------------------------------------------------------\n// Identity resolution\n// -----------------------------------------------------------------------------\n\n/** Resolve identity from flags + env. App and stack fall through the\n * shared cwd/package metadata resolver before their defaults.\n *\n * State-dir precedence ladder:\n * `--state-dir` flag (`stateDir`) > `config.options.stateDir`\n * (`configStateDir`) > `$DEVSTACK_STATE_DIR` > `<cwd>/.devstack`.\n * The flag maps to `resolveStateDir`'s top `runtimeRoot` rung and the\n * config value to its `stateDir` rung so the flag always wins over a\n * config-declared `defineDevstack({ stateDir })`.\n *\n * Stack-name precedence ladder (the SAME flag-beats-config shape as\n * state-dir, so the two are consistent and reviewable side-by-side):\n * `--stack` flag / `$DEVSTACK_STACK` (`params.stack`)\n * > config's `defineDevstack({ stackName })`\n * > cwd/package inference (default `'main'`).\n * Config-vs-explicit resolution can't happen here (the config isn't\n * loaded yet for the no-config verbs), so we record the explicit value\n * on `ResolvedIdentity.explicitStack` and let the verb wirings apply\n * `config.stackName` ONLY when no explicit stack was given — see\n * `effectiveStackName` in `cli/wirings/identity.ts`. `params.stack` is\n * exactly the explicit `--stack`-or-`$DEVSTACK_STACK` value (the argv\n * pre-parser seeds it from env, then lets the flag overwrite it), and\n * is `undefined` when neither was provided. */\nconst resolveIdentity = (params: {\n\treadonly app: string | undefined;\n\treadonly stack: string | undefined;\n\treadonly network: string | undefined;\n\treadonly stateDir: string | undefined;\n\treadonly configStateDir?: string | undefined;\n\treadonly cwd?: string;\n}): ResolvedIdentity => {\n\tconst cwd = params.cwd ?? process.cwd();\n\tconst app = resolveAppName({\n\t\texplicit: params.app,\n\t\tcwd,\n\t});\n\tconst runtimeRoot = resolveStateDir({\n\t\truntimeRoot: params.stateDir,\n\t\tstateDir: params.configStateDir,\n\t\tenv: process.env.DEVSTACK_STATE_DIR,\n\t\tcwd,\n\t});\n\tconst stacksRoot = resolvePath(runtimeRoot, 'stacks');\n\t// `resolveStackName` here folds explicit (flag/env) > inferred >\n\t// default. Crucially it does NOT see `config.stackName`: a non-empty\n\t// `params.stack` means the operator was explicit, so `stack` already\n\t// equals the explicit value and `config.stackName` must not override\n\t// it downstream. An empty `params.stack` falls through to the\n\t// inferred/default name, which a verb's `config.stackName` may then\n\t// supersede via `effectiveStackName`.\n\tconst explicitStack =\n\t\tparams.stack !== undefined && params.stack.length > 0 ? params.stack : undefined;\n\tconst stack = resolveStackName({\n\t\texplicit: params.stack,\n\t\tcwd,\n\t});\n\t// Centralized explicit > env > default ladder. Throws\n\t// `DevstackNetworkParseError` on a malformed value so the CLI fails\n\t// fast with a structured error instead of a downstream cryptic\n\t// chain-probe failure. The raw input is preserved (not the\n\t// canonical name) so chain-keyed cache namespaces stay stable.\n\tconst network = resolveNetworkSync({\n\t\texplicit: params.network,\n\t\tenv: process.env.DEVSTACK_NETWORK,\n\t\texplicitSource: '--network',\n\t}).raw;\n\tconst stackRoot = resolvePath(stacksRoot, stack);\n\treturn {\n\t\tapp,\n\t\tstack,\n\t\tnetwork,\n\t\truntimeRoot,\n\t\tstacksRoot,\n\t\tstackRoot,\n\t\trosterFile: resolvePath(stackRoot, 'roster.json'),\n\t\texplicitStack,\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Verb deps composition\n// -----------------------------------------------------------------------------\n\nconst projectionStatusReader = (identity: ResolvedIdentity): StatusReader => ({\n\treadState: () =>\n\t\tEffect.sync(() => readProjectionSnapshot(identity.stackRoot) as SubscribableState | null),\n});\n\nconst buildDirectDeps = (identity: ResolvedIdentity): CliDeps => {\n\treturn {\n\t\tup: {\n\t\t\trun: (flags) =>\n\t\t\t\trunUpLive(flags.configPath, identity, {\n\t\t\t\t\trenderer: flags.renderer,\n\t\t\t\t\tstdoutIsTty: Boolean((process.stdout as { isTTY?: boolean }).isTTY),\n\t\t\t\t}),\n\t\t},\n\t\tapply: {\n\t\t\trun: (flags) => runApplyLive(flags.configPath, identity),\n\t\t},\n\t\tstatus: { reader: projectionStatusReader(identity) },\n\t\tsnapshot: {\n\t\t\treader: makeSnapshotReader(identity),\n\t\t\tcapture: (args) => runSnapshotCaptureLiveAware(identity, args),\n\t\t\trestore: (snapshotId) => runSnapshotRestoreDirect(identity, snapshotId),\n\t\t\tdelete: (snapshotId) => runSnapshotDeleteDirect(identity, snapshotId),\n\t\t\tconfirm: nodeConfirmPrompt,\n\t\t},\n\t\tprune: makeDirectPruneDeps({ runtimeRoot: identity.runtimeRoot }),\n\t\tdoctor: {\n\t\t\tprobes: defaultProbes({\n\t\t\t\tstateDir: identity.runtimeRoot,\n\t\t\t\tappRoot: identity.stacksRoot,\n\t\t\t}),\n\t\t},\n\t\tconfig: { loader: makeConfigLoader() },\n\t\twipe: {\n\t\t\twipe: () => runWipeDirect(identity),\n\t\t\tplan: () => runWipePlanDirect(identity),\n\t\t\tconfirm: nodeConfirmPrompt,\n\t\t},\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Argv pre-parser\n// -----------------------------------------------------------------------------\n\n/** @internal Exported for tests. Resolves identity flag inputs from a\n * `--app <x>` / `--stack <x>` / `--network <x>` / `--state-dir <x>` /\n * `--config <x>` argv, falling back to `DEVSTACK_*` env vars. Throws\n * on a missing or flag-shaped value so a typo doesn't silently demote\n * a downstream flag, and on a duplicate flag (`--app a --app b`) so\n * the pre-parser does not silently last-write-wins a value that\n * Stricli will later reject outright. */\nexport const identityInputsFromArgv = (\n\targv: ReadonlyArray<string>,\n\tenv: Readonly<Record<string, string | undefined>>,\n) => {\n\tlet app = env.DEVSTACK_APP;\n\tlet stack = env.DEVSTACK_STACK;\n\tlet network = env.DEVSTACK_NETWORK;\n\t// `stateDir` intentionally captures the `--state-dir` flag ONLY. The\n\t// full ladder — `--state-dir` flag > `config.options.stateDir`\n\t// (`defineDevstack({ stateDir })`) > `$DEVSTACK_STATE_DIR` >\n\t// `<cwd>/.devstack` — is assembled at the `resolveStateDir(...)`\n\t// call-site in `resolveIdentity`: the flag wins (top `runtimeRoot`\n\t// rung), the best-effort config value sits below it (`stateDir`\n\t// rung), then env, then the cwd default. Keeping the pre-parser a\n\t// thin flag-extractor means config + env precedence live in one place.\n\tlet stateDir: string | undefined;\n\tlet configPath = env.DEVSTACK_CONFIG;\n\t// Tracks which flags have been seen on the argv side so a second\n\t// occurrence trips a usage error before the value silently overwrites\n\t// the first. Env-sourced defaults are NOT counted (they are not user\n\t// argv).\n\tconst seenArgvFlags = new Set<string>();\n\tfor (let i = 0; i < argv.length; i += 1) {\n\t\tconst token = argv[i]!;\n\t\tconst readValue = (name: string): string | undefined => {\n\t\t\tlet value: string | undefined;\n\t\t\t// `--name=value` form: trust the literal between `=` and end.\n\t\t\tif (token.startsWith(`--${name}=`)) {\n\t\t\t\tvalue = token.slice(name.length + 3);\n\t\t\t}\n\t\t\t// `--name value` form: peek the next token. Reject another\n\t\t\t// flag token (`--foo`) as the value — it almost certainly\n\t\t\t// means the user meant `--name <empty>` (typo / forgotten\n\t\t\t// argument) and quietly absorbing `--foo` as the value\n\t\t\t// silently demotes a downstream flag.\n\t\t\telse if (token === `--${name}`) {\n\t\t\t\tconst next = argv[i + 1];\n\t\t\t\tif (next === undefined) {\n\t\t\t\t\tthrow new CliUsageError({ message: `flag --${name} requires a value` });\n\t\t\t\t}\n\t\t\t\tif (next.startsWith('--')) {\n\t\t\t\t\tthrow new CliUsageError({\n\t\t\t\t\t\tmessage: `flag --${name} requires a value; got \"${next}\" which looks like a flag`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tvalue = next;\n\t\t\t}\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (seenArgvFlags.has(name)) {\n\t\t\t\tthrow new CliUsageError({ message: `flag --${name} given more than once` });\n\t\t\t}\n\t\t\tseenArgvFlags.add(name);\n\t\t\treturn value;\n\t\t};\n\t\tapp = readValue('app') ?? app;\n\t\tstack = readValue('stack') ?? stack;\n\t\tnetwork = readValue('network') ?? network;\n\t\tstateDir = readValue('state-dir') ?? stateDir;\n\t\tconfigPath = readValue('config') ?? configPath;\n\t}\n\treturn { app, stack, network, stateDir, configPath };\n};\n\nconst identityCwdFromConfig = (configPath: string | undefined): string => {\n\tconst resolved = resolveConfigPath(configPath);\n\treturn resolved === null ? process.cwd() : dirname(resolved);\n};\n\n/** Whether the resolved argv is a purely-informational invocation that\n * never consumes `identity.runtimeRoot` (the only value the config\n * pre-load feeds). For these we SKIP `configStateDirBestEffort` so we\n * don't dynamic-import (and run the top-level side effects of) the\n * user's `devstack.config.ts` — plus walk parent dirs — for commands\n * the file header itself says must stay cheap:\n *\n * - empty argv → Stricli prints root help\n * - `--help`/`-h` or `--version`/`-v` anywhere → Stricli short-circuits\n * - first token `schema` → emits the static CLI schema (no state dir)\n *\n * An unknown verb also never reaches a state-dir consumer (Stricli\n * fails the parse), but we keep pre-loading on the general path: the\n * pre-parser already accepted the identity flags, and gating on a\n * closed verb set here would duplicate the dispatcher's route table.\n * The two flagged-as-wasteful informational paths (help/version/schema)\n * are the ones with a registered short-circuit, so skipping exactly\n * those removes the eager-import surprise without re-deriving routes. */\nconst argvSkipsConfigPreload = (argv: ReadonlyArray<string>): boolean => {\n\tif (argv.length === 0) return true;\n\tfor (const token of argv) {\n\t\tif (token === '--help' || token === '-h' || token === '--version' || token === '-v') {\n\t\t\treturn true;\n\t\t}\n\t}\n\tconst firstVerb = argv.find((token) => !token.startsWith('-'));\n\treturn firstVerb === 'schema';\n};\n\n/** Best-effort read of `config.options.stateDir` (the value a program\n * sets via `defineDevstack({ stateDir })`) for the state-dir precedence\n * ladder in `resolveIdentity`. Swallows EVERY config-loader failure\n * (not-found AND evaluation errors) and returns `undefined`:\n *\n * - No-config verbs (`prune`, `wipe`) MUST keep resolving identity\n * without a config, so a missing config silently falls through to\n * the flag > env > cwd ladder.\n * - A genuinely malformed config is NOT surfaced here — the verbs that\n * actually consume config (`up` / `apply` via `makeConfigLoader`)\n * re-load it and surface the typed `CliConfig*` error through the\n * normal envelope path, so behavior for those verbs is unchanged.\n *\n * This is one redundant config evaluation for `up` / `apply` (the verb\n * wiring re-loads via its own loader); threading the loaded value into\n * the verb dispatch would require touching the off-limits `wirings/up.ts`\n * signature, so the duplicate import is accepted deliberately. */\nconst configStateDirBestEffort = async (\n\tconfigPath: string | undefined,\n): Promise<string | undefined> => {\n\tconst loaded = await Effect.runPromise(makeConfigLoader().load(configPath).pipe(Effect.option));\n\tif (loaded._tag === 'None') return undefined;\n\tconst options = (loaded.value.stack as { readonly options?: { readonly stateDir?: string } })\n\t\t.options;\n\tconst stateDir = options?.stateDir;\n\treturn stateDir !== undefined && stateDir.length > 0 ? stateDir : undefined;\n};\n\n// -----------------------------------------------------------------------------\n// Bin entry\n// -----------------------------------------------------------------------------\n\nexport const runCli = async (\n\targv: ReadonlyArray<string> = process.argv.slice(2),\n): Promise<void> => {\n\tconst stdinIsTty = Boolean((process.stdin as { isTTY?: boolean }).isTTY);\n\tconst env: Record<string, string | undefined> = { ...process.env };\n\tlet identityInputs: ReturnType<typeof identityInputsFromArgv>;\n\ttry {\n\t\tidentityInputs = identityInputsFromArgv(argv, env);\n\t} catch (cause) {\n\t\tconst error =\n\t\t\tcause instanceof CliUsageError\n\t\t\t\t? cause\n\t\t\t\t: new CliUsageError({\n\t\t\t\t\t\tmessage: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t\t});\n\t\tconst jsonMode = env[ENV_VARS.JSON] === '1' || argv.includes('--json');\n\t\tawait Effect.runPromise(\n\t\t\temitFailure(nodeProcessIO, jsonMode ? 'json' : 'human', {\n\t\t\t\tcommand: '(parse-argv)',\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\t// Best-effort config pre-load for the state-dir ladder. Swallows\n\t// not-found / malformed configs so no-config verbs (prune/wipe) keep\n\t// working; the `--state-dir` flag still wins over the config value.\n\t// Skipped for informational invocations (help/version/schema/empty)\n\t// that never read `identity.runtimeRoot`, so those commands don't\n\t// dynamic-import the user's config (and run its top-level side\n\t// effects) just to print help.\n\tconst configStateDir = argvSkipsConfigPreload(argv)\n\t\t? undefined\n\t\t: await configStateDirBestEffort(identityInputs.configPath);\n\tlet identity: ResolvedIdentity;\n\ttry {\n\t\tidentity = resolveIdentity({\n\t\t\tapp: identityInputs.app,\n\t\t\tstack: identityInputs.stack,\n\t\t\tnetwork: identityInputs.network,\n\t\t\tstateDir: identityInputs.stateDir,\n\t\t\tconfigStateDir,\n\t\t\tcwd: identityCwdFromConfig(identityInputs.configPath),\n\t\t});\n\t} catch (cause) {\n\t\t// `resolveIdentity` -> `resolveNetworkSync` throws\n\t\t// `DevstackNetworkParseError` (a plain Error, NOT a CliError) on a\n\t\t// malformed `--network`/`$DEVSTACK_NETWORK` value. This runs OUTSIDE\n\t\t// the argv pre-parse try/catch above and BEFORE dispatch, so without\n\t\t// this guard the throw escapes to the bin entry's generic `.catch`\n\t\t// (exit 1, no envelope). Convert to `CliUsageError` and route through\n\t\t// the same envelope path the parse-argv block uses so a bad value\n\t\t// exits USAGE (64) with a JSON envelope in `--json` mode — never the\n\t\t// disallowed generic exit 1.\n\t\tconst error =\n\t\t\tcause instanceof DevstackNetworkParseError\n\t\t\t\t? new CliUsageError({ message: cause.message })\n\t\t\t\t: cause instanceof CliUsageError\n\t\t\t\t\t? cause\n\t\t\t\t\t: new CliUsageError({\n\t\t\t\t\t\t\tmessage: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t\t\t});\n\t\tconst jsonMode = env[ENV_VARS.JSON] === '1' || argv.includes('--json');\n\t\tawait Effect.runPromise(\n\t\t\temitFailure(nodeProcessIO, jsonMode ? 'json' : 'human', {\n\t\t\t\tcommand: '(resolve-identity)',\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\tconst deps = buildDirectDeps(identity);\n\tawait Effect.runPromise(\n\t\tdispatch(deps, {\n\t\t\targv,\n\t\t\tenv: {\n\t\t\t\t...env,\n\t\t\t\tDEVSTACK_APP: identity.app,\n\t\t\t\tDEVSTACK_STACK: identity.stack,\n\t\t\t\tDEVSTACK_STATE_DIR: identity.runtimeRoot,\n\t\t\t},\n\t\t\tstdinIsTty,\n\t\t}),\n\t);\n};\n\nconst isMainEntrypoint = (): boolean => {\n\tconst argvPath = process.argv[1];\n\tif (argvPath === undefined) return false;\n\ttry {\n\t\treturn realpathSync(argvPath) === realpathSync(fileURLToPath(import.meta.url));\n\t} catch {\n\t\treturn import.meta.url === pathToFileURL(argvPath).href;\n\t}\n};\n\nif (isMainEntrypoint()) {\n\t// Intentionally do NOT call `process.exit(...)` after `runCli`:\n\t// `process.exit` synchronously terminates the event loop before any\n\t// pending `setImmediate` work flushes. The `up` lifecycle's hard-kill\n\t// path schedules its escalation via `setImmediate(process.exit)` in\n\t// `up-lifecycle.ts:scheduleProcessExit` (the file-header invariant for\n\t// SIGINT → finalizers requires the outer Node fiber to drain\n\t// naturally). Letting Node's natural exit handle the shutdown\n\t// preserves that invariant. We only set `process.exitCode` so the\n\t// final OS exit code reflects the verb's outcome.\n\trunCli().catch((err) => {\n\t\tprocess.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\\n`);\n\t\tprocess.exitCode = ExitCode.GENERIC;\n\t});\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main.mjs","names":["resolvePath"],"sources":["../../src/cli/main.ts"],"sourcesContent":["// devstack CLI bin entry — argv → identity → deps → dispatch → exit.\n//\n// This file is the executable entry the `bin: { devstack: ... }`\n// package.json field points at. Build output: `dist/cli/main.mjs`.\n//\n// Architecture invariant (surfaces/cli/index.ts header):\n// \"`up` must hand its long-running effect to the outer Node runtime\n// directly, not nest a runtime — otherwise SIGINT cannot reach\n// scope finalizers and container teardown leaks.\"\n//\n// Shape:\n// 1. Pre-parse identity inputs from argv + env (see\n// `identityInputsFromArgv`).\n// 2. Resolve identity (app / stack / network / runtime root) via the\n// shared `api/inference-network` helpers.\n// 3. Build the dispatcher's `CliDeps` bundle from each verb's wiring\n// module in `cli/wirings/`.\n// 4. Hand control to the Stricli-backed dispatcher, which routes to\n// the verb-scoped wiring function.\n\nimport { realpathSync } from 'node:fs';\nimport { dirname, join, resolve as resolvePath } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\n\nimport { Effect } from 'effect';\n\nimport { endpointKey, pluginKey } from '../substrate/brand.ts';\nimport { emptyProjection } from '../substrate/runtime/projection/state-ref.ts';\nimport type { SubscribableState } from '../substrate/projection.ts';\nimport { readStackContext } from '../build-integrations/runtime/read-stack-context.ts';\nimport type { StackContext } from '../build-integrations/runtime/stack-context.ts';\nimport { dispatch, type CliDeps, CliUsageError } from '../surfaces/cli/index.ts';\nimport { emitFailure, nodeProcessIO } from '../surfaces/cli/output.ts';\nimport { ENV_VARS } from '../surfaces/cli/flags.ts';\nimport { defaultProbes } from './doctor-probes.ts';\nimport { nodeConfirmPrompt } from '../surfaces/cli/commands/confirm-node.ts';\nimport type { StatusReader } from '../surfaces/cli/commands/status.ts';\nimport { ExitCode } from '../surfaces/cli/sysexits.ts';\nimport { makeSnapshotReader } from './snapshot-reader.ts';\nimport {\n\tDevstackNetworkParseError,\n\tresolveAppName,\n\tresolveNetworkSync,\n\tresolveStackName,\n\tresolveStateDir,\n} from '../api/inference-network.ts';\nimport { makeDirectPruneDeps } from './prune-direct.ts';\nimport { runUpLive } from './wirings/up.ts';\nimport { runApplyLive } from './wirings/apply.ts';\nimport { runCodegen } from './wirings/codegen.ts';\nimport { runDumpIds } from './wirings/dump-ids.ts';\nimport {\n\trunSnapshotCaptureLiveAware,\n\trunSnapshotDeleteDirect,\n\trunSnapshotRestoreDirect,\n} from './wirings/snapshot.ts';\nimport { runWipeDirect, runWipePlanDirect } from './wirings/wipe.ts';\nimport { makeConfigLoader, resolveConfigPath } from './wirings/config-loader.ts';\nimport type { ResolvedIdentity } from './wirings/identity.ts';\n\n// -----------------------------------------------------------------------------\n// Identity resolution\n// -----------------------------------------------------------------------------\n\n/** Resolve identity from flags + env. App and stack fall through the\n * shared cwd/package metadata resolver before their defaults.\n *\n * State-dir precedence ladder:\n * `--state-dir` flag (`stateDir`) > `config.options.stateDir`\n * (`configStateDir`) > `$DEVSTACK_STATE_DIR` > `<cwd>/.devstack`.\n * The flag maps to `resolveStateDir`'s top `runtimeRoot` rung and the\n * config value to its `stateDir` rung so the flag always wins over a\n * config-declared `defineDevstack({ stateDir })`.\n *\n * Stack-name precedence ladder (the SAME flag-beats-config shape as\n * state-dir, so the two are consistent and reviewable side-by-side):\n * `--stack` flag / `$DEVSTACK_STACK` (`params.stack`)\n * > config's `defineDevstack({ stackName })`\n * > cwd/package inference (default `'main'`).\n * Config-vs-explicit resolution can't happen here (the config isn't\n * loaded yet for the no-config verbs), so we record the explicit value\n * on `ResolvedIdentity.explicitStack` and let the verb wirings apply\n * `config.stackName` ONLY when no explicit stack was given — see\n * `effectiveStackName` in `cli/wirings/identity.ts`. `params.stack` is\n * exactly the explicit `--stack`-or-`$DEVSTACK_STACK` value (the argv\n * pre-parser seeds it from env, then lets the flag overwrite it), and\n * is `undefined` when neither was provided. */\nconst resolveIdentity = (params: {\n\treadonly app: string | undefined;\n\treadonly stack: string | undefined;\n\treadonly network: string | undefined;\n\treadonly stateDir: string | undefined;\n\treadonly configStateDir?: string | undefined;\n\treadonly cwd?: string;\n}): ResolvedIdentity => {\n\tconst cwd = params.cwd ?? process.cwd();\n\tconst app = resolveAppName({\n\t\texplicit: params.app,\n\t\tcwd,\n\t});\n\tconst runtimeRoot = resolveStateDir({\n\t\truntimeRoot: params.stateDir,\n\t\tstateDir: params.configStateDir,\n\t\tenv: process.env.DEVSTACK_STATE_DIR,\n\t\tcwd,\n\t});\n\tconst stacksRoot = resolvePath(runtimeRoot, 'stacks');\n\t// `resolveStackName` here folds explicit (flag/env) > inferred >\n\t// default. Crucially it does NOT see `config.stackName`: a non-empty\n\t// `params.stack` means the operator was explicit, so `stack` already\n\t// equals the explicit value and `config.stackName` must not override\n\t// it downstream. An empty `params.stack` falls through to the\n\t// inferred/default name, which a verb's `config.stackName` may then\n\t// supersede via `effectiveStackName`.\n\tconst explicitStack =\n\t\tparams.stack !== undefined && params.stack.length > 0 ? params.stack : undefined;\n\tconst stack = resolveStackName({\n\t\texplicit: params.stack,\n\t\tcwd,\n\t});\n\t// Centralized explicit > env > default ladder. Throws\n\t// `DevstackNetworkParseError` on a malformed value so the CLI fails\n\t// fast with a structured error instead of a downstream cryptic\n\t// network-probe failure. The identity's network is the canonical name\n\t// (`localnet`, `testnet`, …), independent of how it was spelled.\n\tconst network = resolveNetworkSync({\n\t\texplicit: params.network,\n\t\tenv: process.env.DEVSTACK_NETWORK,\n\t\texplicitSource: '--network',\n\t}).parsed.name;\n\tconst stackRoot = resolvePath(stacksRoot, stack);\n\treturn {\n\t\tapp,\n\t\tstack,\n\t\tnetwork,\n\t\truntimeRoot,\n\t\tstacksRoot,\n\t\tstackRoot,\n\t\trosterFile: resolvePath(stackRoot, 'roster.json'),\n\t\texplicitStack,\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Verb deps composition\n// -----------------------------------------------------------------------------\n\n/**\n * Degraded offline-status projection — built from the on-disk manifest,\n * NOT from a persisted projection twin (the projection snapshot file no\n * longer exists). When the stack is DOWN, the manifest is the only\n * durable record of the boot; `status` surfaces identity + endpoints\n * from it and leaves the live-only slices (`rows` / `accounts` /\n * `packages` / `errors`) empty. A freshly-booted stack also has empty\n * `rows`, so the status renderer already tolerates this shape.\n *\n * Pure projector — exported for the focused unit test. Starts from\n * `emptyProjection()` (the closed-vocabulary baseline) and fills only\n * the two manifest-backed slices, so no display vocabulary can leak in.\n * The manifest identity tuple is `{ app, stack, network }`, matching\n * the projection's identity shape directly. Endpoints get re-branded\n * (`endpointKey` / `pluginKey`)\n * to the projection's branded shape; `registeredAt` is unknown offline,\n * so it defaults to `0`.\n */\nexport const degradedStatusFromContext = (ctx: StackContext): SubscribableState => ({\n\t...emptyProjection(),\n\tidentity: {\n\t\tapp: ctx.identity.app,\n\t\tstack: ctx.identity.stack,\n\t\tnetwork: ctx.identity.network,\n\t},\n\tendpoints: ctx.endpoints.all().map((endpoint) => ({\n\t\tendpointKey: endpointKey(endpoint.endpointKey),\n\t\tpluginKey: pluginKey(endpoint.pluginKey),\n\t\tname: endpoint.name,\n\t\turl: endpoint.url,\n\t\tdisplayUrl: endpoint.displayUrl,\n\t\twireProtocol: endpoint.wireProtocol,\n\t\tregisteredAt: 0,\n\t})),\n});\n\nconst projectionStatusReader = (identity: ResolvedIdentity): StatusReader => ({\n\treadState: () =>\n\t\tEffect.sync(() => {\n\t\t\t// Offline read: project the on-disk manifest for THIS stack root.\n\t\t\t// A missing / malformed manifest (no `up` yet, or a hand-edit)\n\t\t\t// is a tolerated \"no state present\" — `readStackContext` throws\n\t\t\t// in that case, so swallow the throw and report `null` (the\n\t\t\t// status command's contract for an absent stack).\n\t\t\ttry {\n\t\t\t\tconst ctx = readStackContext({ manifestPath: join(identity.stackRoot, 'manifest.json') });\n\t\t\t\treturn degradedStatusFromContext(ctx);\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}),\n});\n\nconst buildDirectDeps = (identity: ResolvedIdentity): CliDeps => {\n\treturn {\n\t\tup: {\n\t\t\trun: (flags) =>\n\t\t\t\trunUpLive(flags.configPath, identity, {\n\t\t\t\t\trenderer: flags.renderer,\n\t\t\t\t\tstdoutIsTty: Boolean((process.stdout as { isTTY?: boolean }).isTTY),\n\t\t\t\t\tfromSnapshot: flags.fromSnapshot,\n\t\t\t\t\tsnapshotCache: flags.snapshotCache,\n\t\t\t\t\tsnapshotStalePolicy: flags.snapshotStalePolicy,\n\t\t\t\t}),\n\t\t},\n\t\tapply: {\n\t\t\trun: (flags) => runApplyLive(flags.configPath, identity),\n\t\t},\n\t\tcodegen: {\n\t\t\trun: (flags) => runCodegen(flags.configPath, identity),\n\t\t},\n\t\tdumpIds: {\n\t\t\trun: (flags) =>\n\t\t\t\trunDumpIds(identity, {\n\t\t\t\t\tconfigPath: flags.configPath,\n\t\t\t\t\tout: flags.out,\n\t\t\t\t\tio: flags.io,\n\t\t\t\t\toutputMode: flags.outputMode,\n\t\t\t\t}),\n\t\t},\n\t\tstatus: { reader: projectionStatusReader(identity) },\n\t\tsnapshot: {\n\t\t\treader: makeSnapshotReader(identity),\n\t\t\tcapture: (args) => runSnapshotCaptureLiveAware(identity, args),\n\t\t\trestore: (snapshotId) => runSnapshotRestoreDirect(identity, snapshotId),\n\t\t\tdelete: (snapshotId) => runSnapshotDeleteDirect(identity, snapshotId),\n\t\t\tconfirm: nodeConfirmPrompt,\n\t\t},\n\t\tprune: makeDirectPruneDeps({ runtimeRoot: identity.runtimeRoot }),\n\t\tdoctor: {\n\t\t\tprobes: defaultProbes({\n\t\t\t\tstateDir: identity.runtimeRoot,\n\t\t\t\tappRoot: identity.stacksRoot,\n\t\t\t}),\n\t\t},\n\t\tconfig: { loader: makeConfigLoader() },\n\t\twipe: {\n\t\t\twipe: () => runWipeDirect(identity),\n\t\t\tplan: () => runWipePlanDirect(identity),\n\t\t\tconfirm: nodeConfirmPrompt,\n\t\t},\n\t};\n};\n\n// -----------------------------------------------------------------------------\n// Argv pre-parser\n// -----------------------------------------------------------------------------\n\n/** @internal Exported for tests. Resolves identity flag inputs from a\n * `--app <x>` / `--stack <x>` / `--network <x>` / `--state-dir <x>` /\n * `--config <x>` argv, falling back to `DEVSTACK_*` env vars. Throws\n * on a missing or flag-shaped value so a typo doesn't silently demote\n * a downstream flag, and on a duplicate flag (`--app a --app b`) so\n * the pre-parser does not silently last-write-wins a value that\n * Stricli will later reject outright. */\nexport const identityInputsFromArgv = (\n\targv: ReadonlyArray<string>,\n\tenv: Readonly<Record<string, string | undefined>>,\n) => {\n\tlet app = env.DEVSTACK_APP;\n\tlet stack = env.DEVSTACK_STACK;\n\tlet network = env.DEVSTACK_NETWORK;\n\t// `stateDir` intentionally captures the `--state-dir` flag ONLY. The\n\t// full ladder — `--state-dir` flag > `config.options.stateDir`\n\t// (`defineDevstack({ stateDir })`) > `$DEVSTACK_STATE_DIR` >\n\t// `<cwd>/.devstack` — is assembled at the `resolveStateDir(...)`\n\t// call-site in `resolveIdentity`: the flag wins (top `runtimeRoot`\n\t// rung), the best-effort config value sits below it (`stateDir`\n\t// rung), then env, then the cwd default. Keeping the pre-parser a\n\t// thin flag-extractor means config + env precedence live in one place.\n\tlet stateDir: string | undefined;\n\tlet configPath = env.DEVSTACK_CONFIG;\n\t// Tracks which flags have been seen on the argv side so a second\n\t// occurrence trips a usage error before the value silently overwrites\n\t// the first. Env-sourced defaults are NOT counted (they are not user\n\t// argv).\n\tconst seenArgvFlags = new Set<string>();\n\tfor (let i = 0; i < argv.length; i += 1) {\n\t\tconst token = argv[i]!;\n\t\tconst readValue = (name: string): string | undefined => {\n\t\t\tlet value: string | undefined;\n\t\t\t// `--name=value` form: trust the literal between `=` and end.\n\t\t\tif (token.startsWith(`--${name}=`)) {\n\t\t\t\tvalue = token.slice(name.length + 3);\n\t\t\t}\n\t\t\t// `--name value` form: peek the next token. Reject another\n\t\t\t// flag token (`--foo`) as the value — it almost certainly\n\t\t\t// means the user meant `--name <empty>` (typo / forgotten\n\t\t\t// argument) and quietly absorbing `--foo` as the value\n\t\t\t// silently demotes a downstream flag.\n\t\t\telse if (token === `--${name}`) {\n\t\t\t\tconst next = argv[i + 1];\n\t\t\t\tif (next === undefined) {\n\t\t\t\t\tthrow new CliUsageError({ message: `flag --${name} requires a value` });\n\t\t\t\t}\n\t\t\t\tif (next.startsWith('--')) {\n\t\t\t\t\tthrow new CliUsageError({\n\t\t\t\t\t\tmessage: `flag --${name} requires a value; got \"${next}\" which looks like a flag`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tvalue = next;\n\t\t\t}\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (seenArgvFlags.has(name)) {\n\t\t\t\tthrow new CliUsageError({ message: `flag --${name} given more than once` });\n\t\t\t}\n\t\t\tseenArgvFlags.add(name);\n\t\t\treturn value;\n\t\t};\n\t\tapp = readValue('app') ?? app;\n\t\tstack = readValue('stack') ?? stack;\n\t\tnetwork = readValue('network') ?? network;\n\t\tstateDir = readValue('state-dir') ?? stateDir;\n\t\tconfigPath = readValue('config') ?? configPath;\n\t}\n\treturn { app, stack, network, stateDir, configPath };\n};\n\nconst identityCwdFromConfig = (configPath: string | undefined): string => {\n\tconst resolved = resolveConfigPath(configPath);\n\treturn resolved === null ? process.cwd() : dirname(resolved);\n};\n\n/** Whether the resolved argv is a purely-informational invocation that\n * never consumes `identity.runtimeRoot` (the only value the config\n * pre-load feeds). For these we SKIP `configStateDirBestEffort` so we\n * don't dynamic-import (and run the top-level side effects of) the\n * user's `devstack.config.ts` — plus walk parent dirs — for commands\n * the file header itself says must stay cheap:\n *\n * - empty argv → Stricli prints root help\n * - `--help`/`-h` or `--version`/`-v` anywhere → Stricli short-circuits\n * - first token `schema` → emits the static CLI schema (no state dir)\n *\n * An unknown verb also never reaches a state-dir consumer (Stricli\n * fails the parse), but we keep pre-loading on the general path: the\n * pre-parser already accepted the identity flags, and gating on a\n * closed verb set here would duplicate the dispatcher's route table.\n * The two flagged-as-wasteful informational paths (help/version/schema)\n * are the ones with a registered short-circuit, so skipping exactly\n * those removes the eager-import surprise without re-deriving routes. */\nconst argvSkipsConfigPreload = (argv: ReadonlyArray<string>): boolean => {\n\tif (argv.length === 0) return true;\n\tfor (const token of argv) {\n\t\tif (token === '--help' || token === '-h' || token === '--version' || token === '-v') {\n\t\t\treturn true;\n\t\t}\n\t}\n\tconst firstVerb = argv.find((token) => !token.startsWith('-'));\n\treturn firstVerb === 'schema';\n};\n\n/** Best-effort read of `config.options.stateDir` (the value a program\n * sets via `defineDevstack({ stateDir })`) for the state-dir precedence\n * ladder in `resolveIdentity`. Swallows EVERY config-loader failure\n * (not-found AND evaluation errors) and returns `undefined`:\n *\n * - No-config verbs (`prune`, `wipe`) MUST keep resolving identity\n * without a config, so a missing config silently falls through to\n * the flag > env > cwd ladder.\n * - A genuinely malformed config is NOT surfaced here — the verbs that\n * actually consume config (`up` / `apply` via `makeConfigLoader`)\n * re-load it and surface the typed `CliConfig*` error through the\n * normal envelope path, so behavior for those verbs is unchanged.\n *\n * This is one redundant config evaluation for `up` / `apply` (the verb\n * wiring re-loads via its own loader); threading the loaded value into\n * the verb dispatch would require touching the off-limits `wirings/up.ts`\n * signature, so the duplicate import is accepted deliberately. */\nconst configStateDirBestEffort = async (\n\tconfigPath: string | undefined,\n): Promise<string | undefined> => {\n\tconst loaded = await Effect.runPromise(makeConfigLoader().load(configPath).pipe(Effect.option));\n\tif (loaded._tag === 'None') return undefined;\n\tconst options = (loaded.value.stack as { readonly options?: { readonly stateDir?: string } })\n\t\t.options;\n\tconst stateDir = options?.stateDir;\n\treturn stateDir !== undefined && stateDir.length > 0 ? stateDir : undefined;\n};\n\n// -----------------------------------------------------------------------------\n// Bin entry\n// -----------------------------------------------------------------------------\n\nexport const runCli = async (\n\targv: ReadonlyArray<string> = process.argv.slice(2),\n): Promise<void> => {\n\tconst stdinIsTty = Boolean((process.stdin as { isTTY?: boolean }).isTTY);\n\tconst env: Record<string, string | undefined> = { ...process.env };\n\tlet identityInputs: ReturnType<typeof identityInputsFromArgv>;\n\ttry {\n\t\tidentityInputs = identityInputsFromArgv(argv, env);\n\t} catch (cause) {\n\t\tconst error =\n\t\t\tcause instanceof CliUsageError\n\t\t\t\t? cause\n\t\t\t\t: new CliUsageError({\n\t\t\t\t\t\tmessage: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t\t});\n\t\tconst jsonMode = env[ENV_VARS.JSON] === '1' || argv.includes('--json');\n\t\tawait Effect.runPromise(\n\t\t\temitFailure(nodeProcessIO, jsonMode ? 'json' : 'human', {\n\t\t\t\tcommand: '(parse-argv)',\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\t// Best-effort config pre-load for the state-dir ladder. Swallows\n\t// not-found / malformed configs so no-config verbs (prune/wipe) keep\n\t// working; the `--state-dir` flag still wins over the config value.\n\t// Skipped for informational invocations (help/version/schema/empty)\n\t// that never read `identity.runtimeRoot`, so those commands don't\n\t// dynamic-import the user's config (and run its top-level side\n\t// effects) just to print help.\n\tconst configStateDir = argvSkipsConfigPreload(argv)\n\t\t? undefined\n\t\t: await configStateDirBestEffort(identityInputs.configPath);\n\tlet identity: ResolvedIdentity;\n\ttry {\n\t\tidentity = resolveIdentity({\n\t\t\tapp: identityInputs.app,\n\t\t\tstack: identityInputs.stack,\n\t\t\tnetwork: identityInputs.network,\n\t\t\tstateDir: identityInputs.stateDir,\n\t\t\tconfigStateDir,\n\t\t\tcwd: identityCwdFromConfig(identityInputs.configPath),\n\t\t});\n\t} catch (cause) {\n\t\t// `resolveIdentity` -> `resolveNetworkSync` throws\n\t\t// `DevstackNetworkParseError` (a plain Error, NOT a CliError) on a\n\t\t// malformed `--network`/`$DEVSTACK_NETWORK` value. This runs OUTSIDE\n\t\t// the argv pre-parse try/catch above and BEFORE dispatch, so without\n\t\t// this guard the throw escapes to the bin entry's generic `.catch`\n\t\t// (exit 1, no envelope). Convert to `CliUsageError` and route through\n\t\t// the same envelope path the parse-argv block uses so a bad value\n\t\t// exits USAGE (64) with a JSON envelope in `--json` mode — never the\n\t\t// disallowed generic exit 1.\n\t\tconst error =\n\t\t\tcause instanceof DevstackNetworkParseError\n\t\t\t\t? new CliUsageError({ message: cause.message })\n\t\t\t\t: cause instanceof CliUsageError\n\t\t\t\t\t? cause\n\t\t\t\t\t: new CliUsageError({\n\t\t\t\t\t\t\tmessage: cause instanceof Error ? cause.message : String(cause),\n\t\t\t\t\t\t});\n\t\tconst jsonMode = env[ENV_VARS.JSON] === '1' || argv.includes('--json');\n\t\tawait Effect.runPromise(\n\t\t\temitFailure(nodeProcessIO, jsonMode ? 'json' : 'human', {\n\t\t\t\tcommand: '(resolve-identity)',\n\t\t\t\telapsedMs: 0,\n\t\t\t\terror,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\tconst deps = buildDirectDeps(identity);\n\tawait Effect.runPromise(\n\t\tdispatch(deps, {\n\t\t\targv,\n\t\t\tenv: {\n\t\t\t\t...env,\n\t\t\t\tDEVSTACK_APP: identity.app,\n\t\t\t\tDEVSTACK_STACK: identity.stack,\n\t\t\t\tDEVSTACK_STATE_DIR: identity.runtimeRoot,\n\t\t\t},\n\t\t\tstdinIsTty,\n\t\t}),\n\t);\n};\n\nconst isMainEntrypoint = (): boolean => {\n\tconst argvPath = process.argv[1];\n\tif (argvPath === undefined) return false;\n\ttry {\n\t\treturn realpathSync(argvPath) === realpathSync(fileURLToPath(import.meta.url));\n\t} catch {\n\t\treturn import.meta.url === pathToFileURL(argvPath).href;\n\t}\n};\n\nif (isMainEntrypoint()) {\n\t// Intentionally do NOT call `process.exit(...)` after `runCli`:\n\t// `process.exit` synchronously terminates the event loop before any\n\t// pending `setImmediate` work flushes. The `up` lifecycle's hard-kill\n\t// path schedules its escalation via `setImmediate(process.exit)` in\n\t// `up-lifecycle.ts:scheduleProcessExit` (the file-header invariant for\n\t// SIGINT → finalizers requires the outer Node fiber to drain\n\t// naturally). Letting Node's natural exit handle the shutdown\n\t// preserves that invariant. We only set `process.exitCode` so the\n\t// final OS exit code reflects the verb's outcome.\n\trunCli().catch((err) => {\n\t\tprocess.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\\n`);\n\t\tprocess.exitCode = ExitCode.GENERIC;\n\t});\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prune-direct.mjs","names":[],"sources":["../../src/cli/prune-direct.ts"],"sourcesContent":["// L4-adjacent CLI infrastructure for `devstack prune`.\n//\n// Per STYLE_GUIDE §7: `cli/*.ts` modules sit alongside the bin entry\n// (`cli/main.ts`) and may import L3 orchestrator/substrate barrels —\n// they are NOT L4 surfaces proper. The actual cross-stack Docker\n// orchestration lives at `orchestrators/lifecycle-prune/`; this file\n// is the deps-builder the bin entry hands to the `prune` verb runner.\n\nimport { Effect } from 'effect';\n\nimport {\n\tcollectLifecyclePruneInventory,\n\ttype LifecyclePruneError,\n\ttype LifecyclePruneGroup,\n\ttype LifecyclePruneInventory,\n\ttype LifecyclePruneOptions,\n\trunLifecyclePrune,\n} from '../orchestrators/lifecycle-prune/index.ts';\nimport {\n\tsummarizePruneGroups,\n\ttype PruneDeps,\n\ttype PruneGroup,\n\ttype PruneInventory,\n\ttype PruneOutcome,\n\ttype PruneSelection,\n} from '../surfaces/cli/commands/index.ts';\nimport { selectPruneTargets } from '../surfaces/cli/commands/prune-picker-entry.ts';\n\nconst adaptGroup = (group: LifecyclePruneGroup): PruneGroup => ({\n\tkey: group.key,\n\tapp: group.app,\n\tstack: group.stack,\n\tlive: group.live,\n\tlivePids: group.livePids,\n\tshared: group.shared,\n\tsharedKind: group.sharedKind,\n\tautoPrunable: group.autoPrunable,\n\tcontainers: group.containers,\n\trunningContainers: group.runningContainers,\n\tnetworks: group.networks,\n\tvolumes: group.volumes,\n\timages: group.images,\n});\n\nconst adaptInventory = (inventory: LifecyclePruneInventory): PruneInventory => {\n\tconst groups = inventory.groups.map(adaptGroup);\n\treturn { groups, totals: summarizePruneGroups(groups) };\n};\n\n// Internal helpers preserve the orchestrator's typed `LifecyclePruneError`\n// channel. The `PruneDeps` surface contract still accepts `unknown` for\n// the E channel (the surface module owns its own CliError projection via\n// `mapUnknownPruneError`); Effect's covariant E channel means\n// `LifecyclePruneError` flows up cleanly without erasing the type here.\n\nconst collectInventory = (\n\toptions: LifecyclePruneOptions,\n): Effect.Effect<PruneInventory, LifecyclePruneError> =>\n\tcollectLifecyclePruneInventory(options).pipe(Effect.map(adaptInventory));\n\nconst pruneSelection = (\n\toptions: LifecyclePruneOptions,\n\tselection: PruneSelection,\n): Effect.Effect<PruneOutcome, LifecyclePruneError> =>\n\trunLifecyclePrune(options, {\n\t\tgroupKeys: selection.groupKeys,\n\t\tresources: selection.resources,\n\t\tdryRun: selection.dryRun,\n\t}).pipe(Effect.map((summary) => ({ kind: 'completed' as const, summary })));\n\nexport const makeDirectPruneDeps = (options: LifecyclePruneOptions): PruneDeps => ({\n\tinventory: () => collectInventory(options),\n\tprune: (selection) => pruneSelection(options, selection),\n\tselect: (inventory, resources) => selectPruneTargets(inventory, resources),\n});\n"],"mappings":";;;;;;AA4BA,MAAM,cAAc,WAA4C;CAC/D,KAAK,MAAM;CACX,KAAK,MAAM;CACX,OAAO,MAAM;CACb,MAAM,MAAM;CACZ,UAAU,MAAM;CAChB,QAAQ,MAAM;CACd,YAAY,MAAM;CAClB,cAAc,MAAM;CACpB,YAAY,MAAM;CAClB,mBAAmB,MAAM;CACzB,UAAU,MAAM;CAChB,SAAS,MAAM;CACf,QAAQ,MAAM;
|
|
1
|
+
{"version":3,"file":"prune-direct.mjs","names":[],"sources":["../../src/cli/prune-direct.ts"],"sourcesContent":["// L4-adjacent CLI infrastructure for `devstack prune`.\n//\n// Per STYLE_GUIDE §7: `cli/*.ts` modules sit alongside the bin entry\n// (`cli/main.ts`) and may import L3 orchestrator/substrate barrels —\n// they are NOT L4 surfaces proper. The actual cross-stack Docker\n// orchestration lives at `orchestrators/lifecycle-prune/`; this file\n// is the deps-builder the bin entry hands to the `prune` verb runner.\n\nimport { Effect } from 'effect';\n\nimport {\n\tcollectLifecyclePruneInventory,\n\ttype LifecyclePruneError,\n\ttype LifecyclePruneGroup,\n\ttype LifecyclePruneInventory,\n\ttype LifecyclePruneOptions,\n\trunLifecyclePrune,\n} from '../orchestrators/lifecycle-prune/index.ts';\nimport {\n\tsummarizePruneGroups,\n\ttype PruneDeps,\n\ttype PruneGroup,\n\ttype PruneInventory,\n\ttype PruneOutcome,\n\ttype PruneSelection,\n} from '../surfaces/cli/commands/index.ts';\nimport { selectPruneTargets } from '../surfaces/cli/commands/prune-picker-entry.ts';\n\nconst adaptGroup = (group: LifecyclePruneGroup): PruneGroup => ({\n\tkey: group.key,\n\tapp: group.app,\n\tstack: group.stack,\n\tlive: group.live,\n\tlivePids: group.livePids,\n\tshared: group.shared,\n\tsharedKind: group.sharedKind,\n\tautoPrunable: group.autoPrunable,\n\tcontainers: group.containers,\n\trunningContainers: group.runningContainers,\n\tnetworks: group.networks,\n\tvolumes: group.volumes,\n\timages: group.images,\n});\n\nconst adaptInventory = (inventory: LifecyclePruneInventory): PruneInventory => {\n\tconst groups = inventory.groups.map(adaptGroup);\n\treturn { groups, totals: summarizePruneGroups(groups) };\n};\n\n// Internal helpers preserve the orchestrator's typed `LifecyclePruneError`\n// channel. The `PruneDeps` surface contract still accepts `unknown` for\n// the E channel (the surface module owns its own CliError projection via\n// `mapUnknownPruneError`); Effect's covariant E channel means\n// `LifecyclePruneError` flows up cleanly without erasing the type here.\n\nconst collectInventory = (\n\toptions: LifecyclePruneOptions,\n): Effect.Effect<PruneInventory, LifecyclePruneError> =>\n\tcollectLifecyclePruneInventory(options).pipe(Effect.map(adaptInventory));\n\nconst pruneSelection = (\n\toptions: LifecyclePruneOptions,\n\tselection: PruneSelection,\n): Effect.Effect<PruneOutcome, LifecyclePruneError> =>\n\trunLifecyclePrune(options, {\n\t\tgroupKeys: selection.groupKeys,\n\t\tresources: selection.resources,\n\t\tdryRun: selection.dryRun,\n\t}).pipe(Effect.map((summary) => ({ kind: 'completed' as const, summary })));\n\nexport const makeDirectPruneDeps = (options: LifecyclePruneOptions): PruneDeps => ({\n\tinventory: () => collectInventory(options),\n\tprune: (selection) => pruneSelection(options, selection),\n\tselect: (inventory, resources) => selectPruneTargets(inventory, resources),\n});\n"],"mappings":";;;;;;AA4BA,MAAM,cAAc,WAA4C;CAC/D,KAAK,MAAM;CACX,KAAK,MAAM;CACX,OAAO,MAAM;CACb,MAAM,MAAM;CACZ,UAAU,MAAM;CAChB,QAAQ,MAAM;CACd,YAAY,MAAM;CAClB,cAAc,MAAM;CACpB,YAAY,MAAM;CAClB,mBAAmB,MAAM;CACzB,UAAU,MAAM;CAChB,SAAS,MAAM;CACf,QAAQ,MAAM;AACf;AAEA,MAAM,kBAAkB,cAAuD;CAC9E,MAAM,SAAS,UAAU,OAAO,IAAI,UAAU;CAC9C,OAAO;EAAE;EAAQ,QAAQ,qBAAqB,MAAM;CAAE;AACvD;AAQA,MAAM,oBACL,YAEA,+BAA+B,OAAO,CAAC,CAAC,KAAK,OAAO,IAAI,cAAc,CAAC;AAExE,MAAM,kBACL,SACA,cAEA,kBAAkB,SAAS;CAC1B,WAAW,UAAU;CACrB,WAAW,UAAU;CACrB,QAAQ,UAAU;AACnB,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK,aAAa;CAAE,MAAM;CAAsB;AAAQ,EAAE,CAAC;AAE3E,MAAa,uBAAuB,aAA+C;CAClF,iBAAiB,iBAAiB,OAAO;CACzC,QAAQ,cAAc,eAAe,SAAS,SAAS;CACvD,SAAS,WAAW,cAAc,mBAAmB,WAAW,SAAS;AAC1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-reader.mjs","names":["resolvePath"],"sources":["../../src/cli/snapshot-reader.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { resolve as resolvePath } from 'node:path';\n\nimport { Effect } from 'effect';\n\nimport {\n\tSnapshotLayout,\n\tSnapshotMetadataSchema,\n\tparseSnapshotId,\n} from '../orchestrators/snapshot/index.ts';\nimport { decodeJsonTextSync } from '../substrate/runtime/runtime-decode.ts';\nimport type {\n\tSnapshotEntry,\n\tSnapshotReader,\n\tSnapshotResolveResult,\n} from '../surfaces/cli/commands/snapshot.ts';\n\nexport interface SnapshotReaderIdentity {\n\treadonly stackRoot: string;\n}\n\nexport const makeSnapshotReader = (identity: SnapshotReaderIdentity): SnapshotReader => {\n\tconst readEntries = (): ReadonlyArray<SnapshotEntry> => {\n\t\tconst snapshotDir = resolvePath(identity.stackRoot, 'snapshots');\n\t\tif (!existsSync(snapshotDir)) return [];\n\t\treturn readdirSync(snapshotDir, { withFileTypes: true })\n\t\t\t.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))\n\t\t\t.flatMap((entry) => {\n\t\t\t\tconst parsedEntryId = parseSnapshotId(entry.name);\n\t\t\t\tif (parsedEntryId === null) return [];\n\t\t\t\tconst dir = resolvePath(snapshotDir, entry.name);\n\t\t\t\tconst fallbackCreatedAt = statSync(dir).mtimeMs;\n\t\t\t\tconst metaPath = resolvePath(dir, SnapshotLayout.metaFile);\n\t\t\t\tif (!existsSync(metaPath)) {\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsnapshotId: parsedEntryId,\n\t\t\t\t\t\t\tname: null,\n\t\t\t\t\t\t\tcreatedAt: fallbackCreatedAt,\n\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t} satisfies SnapshotEntry,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst meta = decodeJsonTextSync(SnapshotMetadataSchema, readFileSync(metaPath, 'utf8'), {\n\t\t\t\t\t\tsource: metaPath,\n\t\t\t\t\t\tmkError: (issue) => issue,\n\t\t\t\t\t});\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsnapshotId: parsedEntryId,\n\t\t\t\t\t\t\tname: meta.label,\n\t\t\t\t\t\t\tcreatedAt: meta.createdAt,\n\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t} satisfies SnapshotEntry,\n\t\t\t\t\t];\n\t\t\t\t} catch {\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsnapshotId: parsedEntryId,\n\t\t\t\t\t\t\tname: null,\n\t\t\t\t\t\t\tcreatedAt: fallbackCreatedAt,\n\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t} satisfies SnapshotEntry,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t});\n\t};\n\treturn {\n\t\tlist: () =>\n\t\t\tEffect.try({\n\t\t\t\ttry: readEntries,\n\t\t\t\tcatch: (cause) => cause,\n\t\t\t}).pipe(Effect.orElseSucceed(() => [])),\n\t\tresolve: (snapshotRef) =>\n\t\t\tEffect.try({\n\t\t\t\ttry: (): SnapshotResolveResult => {\n\t\t\t\t\tconst entries = readEntries();\n\t\t\t\t\t// Resolve id-vs-name in a single pass so a ref that matches\n\t\t\t\t\t// BOTH an id AND a name (different entries) surfaces as\n\t\t\t\t\t// ambiguous instead of silently shadowing the name match\n\t\t\t\t\t// with the id match. The auto-mint format\n\t\t\t\t\t// (`snap-<ts>-<uuid>`) satisfies the same grammar as a\n\t\t\t\t\t// user-supplied name, so id-first fall-through was a real\n\t\t\t\t\t// foot-gun: a user typing a label that happened to equal\n\t\t\t\t\t// an existing snapshot id would restore the wrong artifact.\n\t\t\t\t\tconst byId = entries.find((entry) => entry.snapshotId === snapshotRef);\n\t\t\t\t\tconst byName = entries.filter((entry) => entry.name === snapshotRef);\n\n\t\t\t\t\t// Same entry matched by both axes (unusual but well-defined):\n\t\t\t\t\t// caller's intent is unambiguous because there is exactly\n\t\t\t\t\t// one matching artifact.\n\t\t\t\t\tconst distinct = new Map<string, SnapshotEntry>();\n\t\t\t\t\tif (byId !== undefined) distinct.set(byId.snapshotId, byId);\n\t\t\t\t\tfor (const entry of byName) distinct.set(entry.snapshotId, entry);\n\n\t\t\t\t\tif (distinct.size === 0) return { tag: 'not-found' };\n\t\t\t\t\tif (distinct.size === 1) {\n\t\t\t\t\t\tconst only = distinct.values().next().value as SnapshotEntry;\n\t\t\t\t\t\treturn { tag: 'found', entry: only };\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttag: 'ambiguous',\n\t\t\t\t\t\tsnapshotRef,\n\t\t\t\t\t\tmatches: Array.from(distinct.values()),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tcatch: (cause) => cause,\n\t\t\t}).pipe(Effect.orElseSucceed((): SnapshotResolveResult => ({ tag: 'not-found' }))),\n\t};\n};\n"],"mappings":";;;;;;;AAqBA,MAAa,sBAAsB,aAAqD;CACvF,MAAM,oBAAkD;EACvD,MAAM,cAAcA,QAAY,SAAS,WAAW,
|
|
1
|
+
{"version":3,"file":"snapshot-reader.mjs","names":["resolvePath"],"sources":["../../src/cli/snapshot-reader.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { resolve as resolvePath } from 'node:path';\n\nimport { Effect } from 'effect';\n\nimport {\n\tSnapshotLayout,\n\tSnapshotMetadataSchema,\n\tparseSnapshotId,\n} from '../orchestrators/snapshot/index.ts';\nimport { decodeJsonTextSync } from '../substrate/runtime/runtime-decode.ts';\nimport type {\n\tSnapshotEntry,\n\tSnapshotReader,\n\tSnapshotResolveResult,\n} from '../surfaces/cli/commands/snapshot.ts';\n\nexport interface SnapshotReaderIdentity {\n\treadonly stackRoot: string;\n}\n\nexport const makeSnapshotReader = (identity: SnapshotReaderIdentity): SnapshotReader => {\n\tconst readEntries = (): ReadonlyArray<SnapshotEntry> => {\n\t\tconst snapshotDir = resolvePath(identity.stackRoot, 'snapshots');\n\t\tif (!existsSync(snapshotDir)) return [];\n\t\treturn readdirSync(snapshotDir, { withFileTypes: true })\n\t\t\t.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))\n\t\t\t.flatMap((entry) => {\n\t\t\t\tconst parsedEntryId = parseSnapshotId(entry.name);\n\t\t\t\tif (parsedEntryId === null) return [];\n\t\t\t\tconst dir = resolvePath(snapshotDir, entry.name);\n\t\t\t\tconst fallbackCreatedAt = statSync(dir).mtimeMs;\n\t\t\t\tconst metaPath = resolvePath(dir, SnapshotLayout.metaFile);\n\t\t\t\tif (!existsSync(metaPath)) {\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsnapshotId: parsedEntryId,\n\t\t\t\t\t\t\tname: null,\n\t\t\t\t\t\t\tcreatedAt: fallbackCreatedAt,\n\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t} satisfies SnapshotEntry,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst meta = decodeJsonTextSync(SnapshotMetadataSchema, readFileSync(metaPath, 'utf8'), {\n\t\t\t\t\t\tsource: metaPath,\n\t\t\t\t\t\tmkError: (issue) => issue,\n\t\t\t\t\t});\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsnapshotId: parsedEntryId,\n\t\t\t\t\t\t\tname: meta.label,\n\t\t\t\t\t\t\tcreatedAt: meta.createdAt,\n\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t} satisfies SnapshotEntry,\n\t\t\t\t\t];\n\t\t\t\t} catch {\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsnapshotId: parsedEntryId,\n\t\t\t\t\t\t\tname: null,\n\t\t\t\t\t\t\tcreatedAt: fallbackCreatedAt,\n\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t} satisfies SnapshotEntry,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t});\n\t};\n\treturn {\n\t\tlist: () =>\n\t\t\tEffect.try({\n\t\t\t\ttry: readEntries,\n\t\t\t\tcatch: (cause) => cause,\n\t\t\t}).pipe(Effect.orElseSucceed(() => [])),\n\t\tresolve: (snapshotRef) =>\n\t\t\tEffect.try({\n\t\t\t\ttry: (): SnapshotResolveResult => {\n\t\t\t\t\tconst entries = readEntries();\n\t\t\t\t\t// Resolve id-vs-name in a single pass so a ref that matches\n\t\t\t\t\t// BOTH an id AND a name (different entries) surfaces as\n\t\t\t\t\t// ambiguous instead of silently shadowing the name match\n\t\t\t\t\t// with the id match. The auto-mint format\n\t\t\t\t\t// (`snap-<ts>-<uuid>`) satisfies the same grammar as a\n\t\t\t\t\t// user-supplied name, so id-first fall-through was a real\n\t\t\t\t\t// foot-gun: a user typing a label that happened to equal\n\t\t\t\t\t// an existing snapshot id would restore the wrong artifact.\n\t\t\t\t\tconst byId = entries.find((entry) => entry.snapshotId === snapshotRef);\n\t\t\t\t\tconst byName = entries.filter((entry) => entry.name === snapshotRef);\n\n\t\t\t\t\t// Same entry matched by both axes (unusual but well-defined):\n\t\t\t\t\t// caller's intent is unambiguous because there is exactly\n\t\t\t\t\t// one matching artifact.\n\t\t\t\t\tconst distinct = new Map<string, SnapshotEntry>();\n\t\t\t\t\tif (byId !== undefined) distinct.set(byId.snapshotId, byId);\n\t\t\t\t\tfor (const entry of byName) distinct.set(entry.snapshotId, entry);\n\n\t\t\t\t\tif (distinct.size === 0) return { tag: 'not-found' };\n\t\t\t\t\tif (distinct.size === 1) {\n\t\t\t\t\t\tconst only = distinct.values().next().value as SnapshotEntry;\n\t\t\t\t\t\treturn { tag: 'found', entry: only };\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttag: 'ambiguous',\n\t\t\t\t\t\tsnapshotRef,\n\t\t\t\t\t\tmatches: Array.from(distinct.values()),\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tcatch: (cause) => cause,\n\t\t\t}).pipe(Effect.orElseSucceed((): SnapshotResolveResult => ({ tag: 'not-found' }))),\n\t};\n};\n"],"mappings":";;;;;;;AAqBA,MAAa,sBAAsB,aAAqD;CACvF,MAAM,oBAAkD;EACvD,MAAM,cAAcA,QAAY,SAAS,WAAW,WAAW;EAC/D,IAAI,CAAC,WAAW,WAAW,GAAG,OAAO,CAAC;EACtC,OAAO,YAAY,aAAa,EAAE,eAAe,KAAK,CAAC,CAAC,CACtD,QAAQ,UAAU,MAAM,YAAY,KAAK,CAAC,MAAM,KAAK,WAAW,GAAG,CAAC,CAAC,CACrE,SAAS,UAAU;GACnB,MAAM,gBAAgB,gBAAgB,MAAM,IAAI;GAChD,IAAI,kBAAkB,MAAM,OAAO,CAAC;GACpC,MAAM,MAAMA,QAAY,aAAa,MAAM,IAAI;GAC/C,MAAM,oBAAoB,SAAS,GAAG,CAAC,CAAC;GACxC,MAAM,WAAWA,QAAY,KAAK,eAAe,QAAQ;GACzD,IAAI,CAAC,WAAW,QAAQ,GACvB,OAAO,CACN;IACC,YAAY;IACZ,MAAM;IACN,WAAW;IACX,MAAM;GACP,CACD;GAED,IAAI;IACH,MAAM,OAAO,mBAAmB,wBAAwB,aAAa,UAAU,MAAM,GAAG;KACvF,QAAQ;KACR,UAAU,UAAU;IACrB,CAAC;IACD,OAAO,CACN;KACC,YAAY;KACZ,MAAM,KAAK;KACX,WAAW,KAAK;KAChB,MAAM;IACP,CACD;GACD,QAAQ;IACP,OAAO,CACN;KACC,YAAY;KACZ,MAAM;KACN,WAAW;KACX,MAAM;IACP,CACD;GACD;EACD,CAAC;CACH;CACA,OAAO;EACN,YACC,OAAO,IAAI;GACV,KAAK;GACL,QAAQ,UAAU;EACnB,CAAC,CAAC,CAAC,KAAK,OAAO,oBAAoB,CAAC,CAAC,CAAC;EACvC,UAAU,gBACT,OAAO,IAAI;GACV,WAAkC;IACjC,MAAM,UAAU,YAAY;IAS5B,MAAM,OAAO,QAAQ,MAAM,UAAU,MAAM,eAAe,WAAW;IACrE,MAAM,SAAS,QAAQ,QAAQ,UAAU,MAAM,SAAS,WAAW;IAKnE,MAAM,2BAAW,IAAI,IAA2B;IAChD,IAAI,SAAS,KAAA,GAAW,SAAS,IAAI,KAAK,YAAY,IAAI;IAC1D,KAAK,MAAM,SAAS,QAAQ,SAAS,IAAI,MAAM,YAAY,KAAK;IAEhE,IAAI,SAAS,SAAS,GAAG,OAAO,EAAE,KAAK,YAAY;IACnD,IAAI,SAAS,SAAS,GAErB,OAAO;KAAE,KAAK;KAAS,OADV,SAAS,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;IACH;IAEpC,OAAO;KACN,KAAK;KACL;KACA,SAAS,MAAM,KAAK,SAAS,OAAO,CAAC;IACtC;GACD;GACA,QAAQ,UAAU;EACnB,CAAC,CAAC,CAAC,KAAK,OAAO,qBAA4C,EAAE,KAAK,YAAY,EAAE,CAAC;CACnF;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"up-lifecycle.mjs","names":[],"sources":["../../src/cli/up-lifecycle.ts"],"sourcesContent":["import { Effect, Queue } from 'effect';\n\nimport type { EngineCommand } from '../substrate/events.ts';\nimport { resolveMode, type RendererMode } from '../surfaces/tui/mode-detect.ts';\nimport type { CliRendererMode } from '../surfaces/cli/flags.ts';\n\nexport interface ResolveUpRendererModeInput {\n\treadonly cliRenderer: CliRendererMode | undefined;\n\treadonly stackRenderer: 'tui' | 'plain' | 'silent' | undefined;\n\treadonly stdoutIsTty: boolean;\n}\n\nconst toRendererMode = (\n\tmode: CliRendererMode | 'tui' | 'plain' | 'silent' | undefined,\n): RendererMode | undefined => {\n\tswitch (mode) {\n\t\tcase undefined:\n\t\t\treturn undefined;\n\t\tcase 'tui':\n\t\t\treturn 'ink';\n\t\tcase 'plain':\n\t\tcase 'silent':\n\t\t\treturn mode;\n\t}\n};\n\nexport const resolveUpRendererMode = (input: ResolveUpRendererModeInput): RendererMode =>\n\tresolveMode({\n\t\trequested: toRendererMode(input.cliRenderer ?? input.stackRenderer),\n\t\tstdoutIsTty: input.stdoutIsTty,\n\t});\n\nexport interface QueueCommandPublisherOptions {\n\treadonly scheduleHardExit?: (exitCode: number) => void;\n}\n\nconst scheduleProcessExit = (exitCode: number): void => {\n\tsetImmediate(() => {\n\t\tprocess.exit(exitCode);\n\t});\n};\n\nexport const makeQueueCommandPublisher =\n\t(\n\t\tcommands: Queue.Enqueue<EngineCommand>,\n\t\toptions: QueueCommandPublisherOptions = {},\n\t): ((command: EngineCommand) => void) =>\n\t(command) => {\n\t\t// `hardKillRequested` escalates directly via `process.exit` —\n\t\t// `setImmediate(process.exit)` fires before the supervisor's\n\t\t// command loop can dequeue in the same tick, so any queue offer\n\t\t// here would be dead code. The supervisor still observes the\n\t\t// hard-kill through the signal handler chain\n\t\t// (`substrate/runtime/lifecycle/signals.ts`); this publisher\n\t\t// only handles the TUI keypress path and the platform exit is\n\t\t// authoritative for it.\n\t\tif (command.tag === 'shutdown.hardKillRequested') {\n\t\t\t(options.scheduleHardExit ?? scheduleProcessExit)(command.exitCode);\n\t\t\treturn;\n\t\t}\n\t\tEffect.runFork(Queue.offer(commands, command));\n\t};\n"],"mappings":";;;AAYA,MAAM,kBACL,SAC8B;
|
|
1
|
+
{"version":3,"file":"up-lifecycle.mjs","names":[],"sources":["../../src/cli/up-lifecycle.ts"],"sourcesContent":["import { Effect, Queue } from 'effect';\n\nimport type { EngineCommand } from '../substrate/events.ts';\nimport { resolveMode, type RendererMode } from '../surfaces/tui/mode-detect.ts';\nimport type { CliRendererMode } from '../surfaces/cli/flags.ts';\n\nexport interface ResolveUpRendererModeInput {\n\treadonly cliRenderer: CliRendererMode | undefined;\n\treadonly stackRenderer: 'tui' | 'plain' | 'silent' | undefined;\n\treadonly stdoutIsTty: boolean;\n}\n\nconst toRendererMode = (\n\tmode: CliRendererMode | 'tui' | 'plain' | 'silent' | undefined,\n): RendererMode | undefined => {\n\tswitch (mode) {\n\t\tcase undefined:\n\t\t\treturn undefined;\n\t\tcase 'tui':\n\t\t\treturn 'ink';\n\t\tcase 'plain':\n\t\tcase 'silent':\n\t\t\treturn mode;\n\t}\n};\n\nexport const resolveUpRendererMode = (input: ResolveUpRendererModeInput): RendererMode =>\n\tresolveMode({\n\t\trequested: toRendererMode(input.cliRenderer ?? input.stackRenderer),\n\t\tstdoutIsTty: input.stdoutIsTty,\n\t});\n\nexport interface QueueCommandPublisherOptions {\n\treadonly scheduleHardExit?: (exitCode: number) => void;\n}\n\nconst scheduleProcessExit = (exitCode: number): void => {\n\tsetImmediate(() => {\n\t\tprocess.exit(exitCode);\n\t});\n};\n\nexport const makeQueueCommandPublisher =\n\t(\n\t\tcommands: Queue.Enqueue<EngineCommand>,\n\t\toptions: QueueCommandPublisherOptions = {},\n\t): ((command: EngineCommand) => void) =>\n\t(command) => {\n\t\t// `hardKillRequested` escalates directly via `process.exit` —\n\t\t// `setImmediate(process.exit)` fires before the supervisor's\n\t\t// command loop can dequeue in the same tick, so any queue offer\n\t\t// here would be dead code. The supervisor still observes the\n\t\t// hard-kill through the signal handler chain\n\t\t// (`substrate/runtime/lifecycle/signals.ts`); this publisher\n\t\t// only handles the TUI keypress path and the platform exit is\n\t\t// authoritative for it.\n\t\tif (command.tag === 'shutdown.hardKillRequested') {\n\t\t\t(options.scheduleHardExit ?? scheduleProcessExit)(command.exitCode);\n\t\t\treturn;\n\t\t}\n\t\tEffect.runFork(Queue.offer(commands, command));\n\t};\n"],"mappings":";;;AAYA,MAAM,kBACL,SAC8B;CAC9B,QAAQ,MAAR;EACC,KAAK,KAAA,GACJ;EACD,KAAK,OACJ,OAAO;EACR,KAAK;EACL,KAAK,UACJ,OAAO;CACT;AACD;AAEA,MAAa,yBAAyB,UACrC,YAAY;CACX,WAAW,eAAe,MAAM,eAAe,MAAM,aAAa;CAClE,aAAa,MAAM;AACpB,CAAC;AAMF,MAAM,uBAAuB,aAA2B;CACvD,mBAAmB;EAClB,QAAQ,KAAK,QAAQ;CACtB,CAAC;AACF;AAEA,MAAa,6BAEX,UACA,UAAwC,CAAC,OAEzC,YAAY;CASZ,IAAI,QAAQ,QAAQ,8BAA8B;EACjD,CAAC,QAAQ,oBAAoB,oBAAA,CAAqB,QAAQ,QAAQ;EAClE;CACD;CACA,OAAO,QAAQ,MAAM,MAAM,UAAU,OAAO,CAAC;AAC9C"}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { StackPathsService } from "../../substrate/runtime/paths.mjs";
|
|
2
1
|
import { makeProjectionRef } from "../../substrate/runtime/projection/state-ref.mjs";
|
|
3
|
-
import { writeProjectionSnapshot } from "../../substrate/runtime/projection/persisted.mjs";
|
|
4
2
|
import { commandChannelPaths, makeCommandChannelPublisher } from "../../substrate/runtime/cross-process/command-channel/channel.mjs";
|
|
3
|
+
import { StackPathsService } from "../../substrate/runtime/paths.mjs";
|
|
4
|
+
import { computeSnapshotGraphInputFromStack } from "../../orchestrators/snapshot/descriptor.mjs";
|
|
5
|
+
import { recoverInterruptedRestore } from "../../orchestrators/snapshot/interrupted-restore.mjs";
|
|
5
6
|
import { SnapshotOrchestratorService } from "../../orchestrators/snapshot/service.mjs";
|
|
6
|
-
import "../../substrate/runtime/index.mjs";
|
|
7
|
-
import { superviseStackEffect } from "../../orchestrators/run.mjs";
|
|
8
7
|
import "../../orchestrators/snapshot/index.mjs";
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
8
|
+
import "../../substrate/runtime/index.mjs";
|
|
9
|
+
import { superviseStackWithProductionBoot } from "../../orchestrators/boot.mjs";
|
|
11
10
|
import { ExitCode } from "../../surfaces/cli/sysexits.mjs";
|
|
12
11
|
import { CliInternalError } from "../../surfaces/cli/errors.mjs";
|
|
13
12
|
import { probeSupervisorPresence } from "../../surfaces/cli/commands/supervisor-presence.mjs";
|
|
14
13
|
import "../../surfaces/cli/commands/index.mjs";
|
|
14
|
+
import { readDevstackVersion } from "./read-devstack-version.mjs";
|
|
15
15
|
import { cliErrorFromConfigExit } from "../bail.mjs";
|
|
16
16
|
import { makeConfigLoader } from "./config-loader.mjs";
|
|
17
17
|
import { identityValueFor, resolvedIdentityForStack, stackRootFor } from "./identity.mjs";
|
|
18
|
-
import { buildVerbLayers } from "
|
|
19
|
-
import { Cause, Effect, Exit, Logger
|
|
18
|
+
import { buildVerbLayers } from "../../orchestrators/layers.mjs";
|
|
19
|
+
import { Cause, Effect, Exit, Logger } from "effect";
|
|
20
20
|
import { dirname, resolve } from "node:path";
|
|
21
21
|
//#region src/cli/wirings/apply.ts
|
|
22
22
|
const LIVE_APPLY_ACK_TIMEOUT_MILLIS = 600 * 1e3;
|
|
@@ -50,7 +50,7 @@ const runApplyLive = (configPath, identity) => {
|
|
|
50
50
|
const loadExit = yield* Effect.exit(loader.load(configPath));
|
|
51
51
|
if (Exit.isFailure(loadExit)) return yield* Effect.fail(cliErrorFromConfigExit(loadExit));
|
|
52
52
|
const loaded = loadExit.value;
|
|
53
|
-
const stack = loaded.
|
|
53
|
+
const stack = loaded.engine;
|
|
54
54
|
const effectiveIdentity = resolvedIdentityForStack(identity, stack);
|
|
55
55
|
const identityValue = identityValueFor(effectiveIdentity);
|
|
56
56
|
const dispatch = yield* runApplyAgainstLiveSupervisor(effectiveIdentity, identityValue);
|
|
@@ -64,22 +64,29 @@ const runApplyLive = (configPath, identity) => {
|
|
|
64
64
|
});
|
|
65
65
|
return yield* Effect.gen(function* () {
|
|
66
66
|
const state = yield* makeProjectionRef();
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
})
|
|
72
|
-
yield*
|
|
67
|
+
const stackPaths = yield* StackPathsService;
|
|
68
|
+
const computeGraphInput = computeSnapshotGraphInputFromStack({
|
|
69
|
+
stack,
|
|
70
|
+
devstackVersion: readDevstackVersion({ fallback: "0.0.0" })
|
|
71
|
+
});
|
|
72
|
+
const snapshot = yield* SnapshotOrchestratorService;
|
|
73
|
+
yield* recoverInterruptedRestore({
|
|
74
|
+
liveRoot: stackPaths.stackRoot,
|
|
75
|
+
restoreSnapshot: (id) => computeGraphInput.pipe(Effect.flatMap((currentGraphInput) => snapshot.restore({
|
|
76
|
+
id,
|
|
77
|
+
currentGraphInput,
|
|
78
|
+
graphInputMismatchPolicy: "warn"
|
|
79
|
+
})))
|
|
80
|
+
});
|
|
81
|
+
yield* superviseStackWithProductionBoot({
|
|
73
82
|
_tag: "Stack",
|
|
74
83
|
members: stack.members,
|
|
75
84
|
options: stack.options
|
|
76
85
|
}, identityValue, state, {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
lifetime: "one-shot"
|
|
80
|
-
|
|
81
|
-
}).pipe(Effect.provide(layerBuiltInPluginRuntime(orchestratorSinks)));
|
|
82
|
-
yield* writeProjectionSnapshot((yield* StackPathsService).stackRoot, yield* SubscriptionRef.get(state));
|
|
86
|
+
extras: stack.options.extras,
|
|
87
|
+
networkOptions: stack.options.networkOptions,
|
|
88
|
+
lifetime: "one-shot"
|
|
89
|
+
});
|
|
83
90
|
}).pipe(Effect.provide(substrateLayers), Effect.provide(Logger.layer([Logger.consolePretty()])), Effect.matchCauseEffect({
|
|
84
91
|
onFailure: (cause) => Effect.fail(new CliInternalError({
|
|
85
92
|
message: "stack apply failed",
|