@mysten-incubation/devstack 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- 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 -32
- 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":"sweep.mjs","names":[],"sources":["../../../src/runtime/docker/sweep.ts"],"sourcesContent":["// Orphan sweep.\n//\n// Architecture § Container runtime § Sweep timing:\n// The supervisor invokes `sweepOrphans` AT BOOT, BEFORE any plugin\n// acquire fires. Sweep finds containers stamped with the engine's\n// label tuple but with no live process holder, and reclaims them\n// (force-remove) under `stack.lock`.\n//\n// Orphan = labelled with `(app, stack)` AND NOT in the active\n// container-claim ledger AND NOT held by any live peer.\n//\n// \"Live peer\" = roster holder whose PID+startTime liveness check\n// succeeds. The cross-process roster + claim-ledger is the authority;\n// we never use docker labels alone (a peer's container counts as\n// claimed even if our claim ledger is empty for it).\n\nimport { Effect } from 'effect';\n\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport { readClaims, type ContainerClaim } from '../../substrate/runtime/cross-process/roster.ts';\nimport { acquireStackLock } from '../../substrate/runtime/cross-process/stack-lock.ts';\nimport { StackPathsService } from '../../substrate/runtime/paths.ts';\nimport {\n\tmakeSpacedRetrySchedule,\n\tNETWORK_REMOVE_RETRY_PROFILE,\n} from '../../substrate/runtime/retry-policy.ts';\nimport { DockerHost, DockerSpawner, dockerRunOk } from './client.ts';\nimport {\n\tContainerRemoveFailed,\n\tDaemonUnreachable,\n\tImageRemoveFailed,\n\tNetworkOperationFailed,\n\ttype DockerRuntimeError,\n} from './errors.ts';\nimport {\n\tlistContainers,\n\tlistDevstackContainers,\n\tlistDevstackContainersByKind,\n\tlistDevstackImages,\n\tlistDevstackNetworks,\n\tlistDevstackVolumes,\n\tlistImages,\n\tlistNetworks,\n\tlistVolumes,\n} from './inventory.ts';\nimport { LabelKey } from './labels.ts';\nimport {\n\tforceDisconnect,\n\tlistAttachedContainers,\n\ttype NetworkAttachedEndpoint,\n} from './network.ts';\nimport { removeVolume } from './volume.ts';\nimport {\n\tisMissingImageStderr,\n\tisMissingNetworkStderr,\n\tisNetworkInUseStderr,\n\tisNoSuchContainerStderr,\n\twrapGeneric,\n} from './wrap.ts';\n\nconst removeManagedContainer = (\n\tname: string,\n): Effect.Effect<boolean, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('rm', ['-f', name]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return true;\n\t\tif (isNoSuchContainerStderr(res.stderr)) return false;\n\t\treturn yield* Effect.fail(\n\t\t\tnew ContainerRemoveFailed({\n\t\t\t\tname,\n\t\t\t\tstderr: res.stderr,\n\t\t\t\texitCode: res.exitCode,\n\t\t\t}),\n\t\t);\n\t});\n\n/** Sweep orphan containers matching the partial label tuple. Returns\n * the number of containers removed.\n *\n * The sweep:\n *\n * 1. Lists all containers with the canonical `devstack.managed=true`\n * + caller-supplied partial tuple (typically `{app, stack}`).\n * 2. Reads the container-claim ledger (the file held alongside\n * roster.json; mutated only under stack.lock).\n * 3. Under stack.lock, removes any container whose name is NOT in\n * the ledger.\n *\n * Concurrent sweepers are serialized by stack.lock. The architecture\n * says briefly here — we hold the lock only across the read + the\n * remove decision; we DON'T hold it across the individual `docker\n * rm` calls (which can be slow). The cost: a peer that registered a\n * claim between our decision and our rm gets its container rm'd\n * anyway. The mitigation: this only fires on the BOOT path before\n * any plugin acquires, so the steady-state \"peer just claimed\" race\n * is not in the picture. */\nexport const sweepOrphans = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner | StackPathsService> =>\n\tEffect.gen(function* () {\n\t\tconst paths = yield* StackPathsService;\n\t\tconst containers = yield* listContainers(labelMatch);\n\t\tif (containers.length === 0) return 0;\n\n\t\t// Under stack.lock, snapshot the claim ledger. The decision\n\t\t// (which to remove) happens here; the rm calls happen outside\n\t\t// the lock.\n\t\tconst mapSubstrateError = (cause: unknown): DockerRuntimeError =>\n\t\t\tnew DaemonUnreachable({\n\t\t\t\top: 'cross-process.sweep',\n\t\t\t\tdetail: `sweep substrate read failed: ${String(cause)}`,\n\t\t\t\tcause,\n\t\t\t});\n\t\tconst claimNames = yield* Effect.scoped(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tyield* acquireStackLock(paths.stackLockFile).pipe(Effect.mapError(mapSubstrateError));\n\t\t\t\tconst doc = yield* readClaims({\n\t\t\t\t\tstackLockFile: paths.stackLockFile,\n\t\t\t\t\trosterFile: paths.rosterFile,\n\t\t\t\t\tcontainerClaimsFile: paths.containerClaimsFile,\n\t\t\t\t}).pipe(Effect.mapError(mapSubstrateError));\n\t\t\t\treturn new Set(doc.claims.map((c: ContainerClaim) => c.containerKey));\n\t\t\t}),\n\t\t);\n\n\t\t// Sweep — best-effort per container. Individual rm failures\n\t\t// don't poison the whole sweep, but they DO need operator\n\t\t// visibility: a broken docker socket would otherwise silently\n\t\t// swallow every entry. Surface the cause via `logWarning` so the\n\t\t// supervisor's cascade and structured-log consumers can investigate.\n\t\t// We reuse `removeManagedContainer` so the idempotent \"no such\n\t\t// container\" path (a container reaped between list+rm) doesn't\n\t\t// trip the warning logger.\n\t\tlet removed = 0;\n\t\tfor (const c of containers) {\n\t\t\tif (claimNames.has(c.name)) continue;\n\t\t\tconst didRemove = yield* removeManagedContainer(c.name).pipe(\n\t\t\t\tEffect.tapCause((cause) =>\n\t\t\t\t\tEffect.logWarning('sweep: docker rm -f failed', { name: c.name, cause }),\n\t\t\t\t),\n\t\t\t\tEffect.catch(() => Effect.succeed(false)),\n\t\t\t);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.sweep'));\n\n/** Explicit teardown. Unlike `sweepOrphans`, this does not consult the\n * claim ledger; wipe/restore are intentional destructive operations. */\nexport const removeManagedContainers = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst containers = yield* listContainers(labelMatch);\n\t\tlet removed = 0;\n\t\tfor (const c of containers) {\n\t\t\tconst didRemove = yield* removeManagedContainer(c.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeManagedContainers'));\n\nconst labelsMatchAppStack = (\n\tlabels: Readonly<Record<string, string>>,\n\tmatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): boolean => labels[LabelKey.app] === match.app && labels[LabelKey.stack] === match.stack;\n\nexport const removeDevstackContainers = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst containers = yield* listDevstackContainers();\n\t\tlet removed = 0;\n\t\tfor (const c of containers) {\n\t\t\tif (!labelsMatchAppStack(c.labels, labelMatch)) continue;\n\t\t\tconst didRemove = yield* removeManagedContainer(c.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeDevstackContainers'));\n\n/** Remove devstack-managed containers whose generic `kind` label matches\n * AND whose name matches. The L1 helper is plugin-blind: orchestrators\n * pass the kind value they themselves stamp at create time. */\nexport const removeDevstackContainersByKindAndName = (\n\tkind: string,\n\tcontainerName: string,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst containers = yield* listDevstackContainersByKind(kind);\n\t\tlet removed = 0;\n\t\tfor (const c of containers) {\n\t\t\tif (c.name !== containerName) continue;\n\t\t\tconst didRemove = yield* removeManagedContainer(c.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeDevstackContainersByKindAndName'));\n\nconst removeManagedImage = (\n\tref: string,\n): Effect.Effect<boolean, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('image', ['rm', '-f', ref]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.image.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return true;\n\t\tif (isMissingImageStderr(res.stderr)) return false;\n\t\treturn yield* Effect.fail(\n\t\t\tnew ImageRemoveFailed({\n\t\t\t\tref,\n\t\t\t\tstderr: res.stderr,\n\t\t\t\texitCode: res.exitCode,\n\t\t\t}),\n\t\t);\n\t});\n\nexport const removeManagedImages = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst images = yield* listImages(labelMatch);\n\t\tlet removed = 0;\n\t\tconst seen = new Set<string>();\n\t\tfor (const image of images) {\n\t\t\tconst ref = image.tag;\n\t\t\tif (ref.endsWith(':<none>')) continue;\n\t\t\tif (seen.has(ref)) continue;\n\t\t\tseen.add(ref);\n\t\t\tconst didRemove = yield* removeManagedImage(ref);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeManagedImages'));\n\nexport const removeDevstackImages = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst images = yield* listDevstackImages();\n\t\tlet removed = 0;\n\t\tconst seen = new Set<string>();\n\t\tfor (const image of images) {\n\t\t\tif (!labelsMatchAppStack(image.labels, labelMatch)) continue;\n\t\t\tconst ref = image.tag;\n\t\t\tif (ref.endsWith(':<none>')) continue;\n\t\t\tif (seen.has(ref)) continue;\n\t\t\tseen.add(ref);\n\t\t\tconst didRemove = yield* removeManagedImage(ref);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeDevstackImages'));\n\nconst removeManagedNetwork = (\n\tname: string,\n): Effect.Effect<boolean, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('network', ['rm', name]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.network.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return true;\n\t\tif (isMissingNetworkStderr(res.stderr)) return false;\n\t\treturn yield* Effect.fail(\n\t\t\tnew NetworkOperationFailed({ op: 'remove', network: name, stderr: res.stderr }),\n\t\t);\n\t});\n\nexport const removeManagedNetworks = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst networks = yield* listNetworks(labelMatch);\n\t\tlet removed = 0;\n\t\tfor (const network of networks) {\n\t\t\tif (network.labels[LabelKey.networkMarker] !== 'true') continue;\n\t\t\tconst didRemove = yield* removeManagedNetwork(network.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeManagedNetworks'));\n\n/** Parse `network X has active endpoints (name:\"A\" id:\"B\")` stderr —\n * Docker enumerates each blocking endpoint as a `(name:\"…\" id:\"…\")`\n * tuple. Returns an empty array on non-matching stderr. */\nconst parseActiveEndpointsFromStderr = (\n\tstderr: string,\n): ReadonlyArray<{ readonly name: string; readonly id: string }> => {\n\tconst out: Array<{ name: string; id: string }> = [];\n\tconst re = /\\(name:\"([^\"]+)\"\\s+id:\"([^\"]+)\"\\)/g;\n\tlet m: RegExpExecArray | null;\n\twhile ((m = re.exec(stderr)) !== null) {\n\t\tout.push({ name: m[1]!, id: m[2]! });\n\t}\n\treturn out;\n};\n\n/** One foreign endpoint preventing a network from being removed —\n * surfaced in the prune summary so the operator can investigate. */\nexport interface ForeignNetworkHolder {\n\treadonly network: string;\n\treadonly container: NetworkAttachedEndpoint;\n}\n\n/** A `(name, id)` reference that appears in Docker's `network rm`\n * \"active endpoints\" error but is NOT addressable via `network\n * disconnect -f` and does NOT appear in `network inspect`'s\n * Containers map. Symptom of a Docker engine bug where the bridge\n * driver leaks endpoint metadata for a container that no longer\n * exists. Only a Docker daemon restart reclaims these. */\nexport interface StaleNetworkEndpoint {\n\treadonly network: string;\n\treadonly name: string;\n\treadonly id: string;\n}\n\ntype NetworkRemoveStep =\n\t| { readonly kind: 'removed' }\n\t| { readonly kind: 'missing' }\n\t| { readonly kind: 'in-use'; readonly stderr: string };\n\ntype NetworkRemoveOutcome =\n\t| { readonly kind: 'removed' }\n\t| { readonly kind: 'missing' }\n\t| {\n\t\t\treadonly kind: 'in-use';\n\t\t\treadonly foreignHolders: ReadonlyArray<NetworkAttachedEndpoint>;\n\t\t\treadonly staleEndpoints: ReadonlyArray<{ readonly name: string; readonly id: string }>;\n\t };\n\nexport interface DevstackNetworkRemovalSummary {\n\treadonly removed: number;\n\treadonly skippedInUse: number;\n\treadonly foreignHolders: ReadonlyArray<ForeignNetworkHolder>;\n\treadonly staleEndpoints: ReadonlyArray<StaleNetworkEndpoint>;\n}\n\ninterface DevstackNetworkRemovalOptions {\n\treadonly retryAttempts?: number;\n\treadonly retryDelayMillis?: number;\n}\n\nconst removeManagedNetworkOnce = (\n\tname: string,\n): Effect.Effect<NetworkRemoveStep, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('network', ['rm', name]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.network.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return { kind: 'removed' as const };\n\t\tif (isMissingNetworkStderr(res.stderr)) return { kind: 'missing' as const };\n\t\tif (isNetworkInUseStderr(res.stderr)) {\n\t\t\treturn { kind: 'in-use' as const, stderr: res.stderr };\n\t\t}\n\t\treturn yield* Effect.fail(\n\t\t\tnew NetworkOperationFailed({ op: 'remove', network: name, stderr: res.stderr }),\n\t\t);\n\t});\n\n/** Best-effort network removal that actively evicts our own endpoints\n * before declaring \"in-use\". Strategy on first in-use response:\n * 1. inspect the network for attached endpoints\n * 2. for each endpoint we own (`devstack.managed=true`), force-\n * disconnect it\n * 3. retry `network rm`\n * Anything still holding the network after that is reported as a\n * foreign holder — typically a non-devstack container, a test fixture,\n * or a sibling stack we deliberately left alone. */\nconst removeManagedNetworkBestEffort = (\n\tname: string,\n\toptions: Required<DevstackNetworkRemovalOptions>,\n): Effect.Effect<NetworkRemoveOutcome, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst first = yield* removeManagedNetworkOnce(name);\n\t\tif (first.kind !== 'in-use') return first;\n\t\t// Investigate, evict our own endpoints, retry.\n\t\tconst attachments = yield* listAttachedContainers(name).pipe(\n\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<NetworkAttachedEndpoint>)),\n\t\t);\n\t\tif (attachments.length > 0) {\n\t\t\tconst ownedNames = new Set<string>();\n\t\t\tconst all = yield* listDevstackContainers().pipe(\n\t\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<{ readonly name: string }>)),\n\t\t\t);\n\t\t\tfor (const c of all) ownedNames.add(c.name);\n\t\t\tfor (const attached of attachments) {\n\t\t\t\tif (!ownedNames.has(attached.name)) continue;\n\t\t\t\tyield* forceDisconnect(attached.name, name).pipe(\n\t\t\t\t\tEffect.tapCause((cause) =>\n\t\t\t\t\t\tEffect.logDebug('prune: force-disconnect failed; will retry rm anyway', {\n\t\t\t\t\t\t\tnetwork: name,\n\t\t\t\t\t\t\tcontainer: attached.name,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.catch(() => Effect.void),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Retry `network rm` after eviction — Effect.repeat with a\n\t\t// spaced schedule per §16 \"Balance / poll loop\" canonical\n\t\t// helper (substrate `NETWORK_REMOVE_RETRY_PROFILE`). User-\n\t\t// supplied `options.retryAttempts` / `retryDelayMillis`\n\t\t// override the profile defaults. `Schedule.recurs(N)` allows\n\t\t// N additional recurrences, so this retry block makes\n\t\t// `1 + retryAttempts` rm calls when persistently in-use. Counting\n\t\t// the pre-eviction `first` probe above, the worst-case in-use\n\t\t// total for this function is `2 + retryAttempts` rm invocations.\n\t\tconst lastStep: NetworkRemoveStep = yield* removeManagedNetworkOnce(name).pipe(\n\t\t\tEffect.repeat({\n\t\t\t\tschedule: makeSpacedRetrySchedule(options.retryDelayMillis, options.retryAttempts),\n\t\t\t\tuntil: (step): boolean => step.kind !== 'in-use',\n\t\t\t}),\n\t\t);\n\t\tif (lastStep.kind === 'removed') return { kind: 'removed' as const };\n\t\tif (lastStep.kind === 'missing') return { kind: 'missing' as const };\n\t\tconst lastStderr = lastStep.stderr;\n\t\t// Still in-use after our best effort — diagnose what's holding it.\n\t\tconst finalAttachments = yield* listAttachedContainers(name).pipe(\n\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<NetworkAttachedEndpoint>)),\n\t\t);\n\t\tconst ownedNames = new Set<string>();\n\t\tconst all = yield* listDevstackContainers().pipe(\n\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<{ readonly name: string }>)),\n\t\t);\n\t\tfor (const c of all) ownedNames.add(c.name);\n\t\tconst foreign = finalAttachments.filter((a) => !ownedNames.has(a.name));\n\t\t// Endpoints Docker mentions in the rm error but which DON'T\n\t\t// appear in inspect → stale metadata. The bridge driver kept\n\t\t// the endpoint record around after the container was reaped;\n\t\t// no CLI/API path can remove it. Operator must restart Docker.\n\t\tconst attachedNames = new Set(finalAttachments.map((a) => a.name));\n\t\tconst stale = parseActiveEndpointsFromStderr(lastStderr).filter(\n\t\t\t(ep) => !attachedNames.has(ep.name),\n\t\t);\n\t\treturn {\n\t\t\tkind: 'in-use' as const,\n\t\t\tforeignHolders: foreign,\n\t\t\tstaleEndpoints: stale,\n\t\t};\n\t});\n\nexport const removeDevstackNetworks = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst networks = yield* listDevstackNetworks();\n\t\tlet removed = 0;\n\t\tfor (const network of networks) {\n\t\t\tif (!labelsMatchAppStack(network.labels, labelMatch)) continue;\n\t\t\tconst didRemove = yield* removeManagedNetwork(network.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeDevstackNetworks'));\n\nexport const removeDevstackNetworksBestEffort = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n\toptions: DevstackNetworkRemovalOptions = {},\n): Effect.Effect<DevstackNetworkRemovalSummary, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst networks = yield* listDevstackNetworks();\n\t\tconst retryOptions = {\n\t\t\tretryAttempts: options.retryAttempts ?? NETWORK_REMOVE_RETRY_PROFILE.attempts,\n\t\t\tretryDelayMillis: options.retryDelayMillis ?? NETWORK_REMOVE_RETRY_PROFILE.delayMs,\n\t\t};\n\t\tlet removed = 0;\n\t\tlet skippedInUse = 0;\n\t\tconst foreignHolders: Array<ForeignNetworkHolder> = [];\n\t\tconst staleEndpoints: Array<StaleNetworkEndpoint> = [];\n\t\tfor (const network of networks) {\n\t\t\tif (!labelsMatchAppStack(network.labels, labelMatch)) continue;\n\t\t\tconst outcome = yield* removeManagedNetworkBestEffort(network.name, retryOptions);\n\t\t\tif (outcome.kind === 'removed') removed += 1;\n\t\t\telse if (outcome.kind === 'in-use') {\n\t\t\t\tskippedInUse += 1;\n\t\t\t\tfor (const container of outcome.foreignHolders) {\n\t\t\t\t\tforeignHolders.push({ network: network.name, container });\n\t\t\t\t}\n\t\t\t\tfor (const ep of outcome.staleEndpoints) {\n\t\t\t\t\tstaleEndpoints.push({ network: network.name, name: ep.name, id: ep.id });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn { removed, skippedInUse, foreignHolders, staleEndpoints };\n\t}).pipe(Effect.withSpan('runtime.docker.removeDevstackNetworksBestEffort'));\n\nexport const removeManagedVolumes = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst volumes = yield* listVolumes(labelMatch);\n\t\tlet removed = 0;\n\t\tfor (const volume of volumes) {\n\t\t\tif (volume.labels[LabelKey.volumeMarker] !== 'true') continue;\n\t\t\t// Best-effort per volume: an in-use/locked volume must not poison\n\t\t\t// the loop and strand later volumes. Surface the cause via\n\t\t\t// `logWarning` for operator visibility, then continue.\n\t\t\tconst didRemove = yield* removeVolume(volume.name).pipe(\n\t\t\t\tEffect.tapCause((cause) =>\n\t\t\t\t\tEffect.logWarning('sweep: docker volume rm failed', { name: volume.name, cause }),\n\t\t\t\t),\n\t\t\t\tEffect.as(true),\n\t\t\t\tEffect.catch(() => Effect.succeed(false)),\n\t\t\t);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeManagedVolumes'));\n\nexport const removeDevstackVolumes = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst volumes = yield* listDevstackVolumes();\n\t\tlet removed = 0;\n\t\tfor (const volume of volumes) {\n\t\t\tif (!labelsMatchAppStack(volume.labels, labelMatch)) continue;\n\t\t\t// Best-effort per volume: an in-use/locked volume must not poison\n\t\t\t// the loop and strand later volumes. Surface the cause via\n\t\t\t// `logWarning` for operator visibility, then continue.\n\t\t\tconst didRemove = yield* removeVolume(volume.name).pipe(\n\t\t\t\tEffect.tapCause((cause) =>\n\t\t\t\t\tEffect.logWarning('sweep: docker volume rm failed', { name: volume.name, cause }),\n\t\t\t\t),\n\t\t\t\tEffect.as(true),\n\t\t\t\tEffect.catch(() => Effect.succeed(false)),\n\t\t\t);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t}).pipe(Effect.withSpan('runtime.docker.removeDevstackVolumes'));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sweep.mjs","names":[],"sources":["../../../src/runtime/docker/sweep.ts"],"sourcesContent":["// Managed-resource teardown.\n//\n// Explicit, label-scoped removal of devstack-managed containers, images,\n// networks, and volumes. These are the intentional destructive paths\n// (wipe / restore / cross-stack prune) — they match on the engine's\n// label tuple and force-remove, without consulting the cross-process\n// claim ledger.\n\nimport { Effect } from 'effect';\n\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport {\n\tmakeSpacedRetrySchedule,\n\tNETWORK_REMOVE_RETRY_PROFILE,\n} from '../../substrate/runtime/retry-policy.ts';\nimport { DockerHost, DockerSpawner, dockerRunOk } from './client.ts';\nimport {\n\tContainerRemoveFailed,\n\tImageRemoveFailed,\n\tNetworkOperationFailed,\n\ttype DockerRuntimeError,\n} from './errors.ts';\nimport {\n\tlistContainers,\n\tlistDevstackContainers,\n\tlistDevstackContainersByKind,\n\tlistDevstackImages,\n\tlistDevstackNetworks,\n\tlistDevstackVolumes,\n\tlistImages,\n\tlistNetworks,\n\tlistVolumes,\n} from './inventory.ts';\nimport { LabelKey } from './labels.ts';\nimport {\n\tforceDisconnect,\n\tlistAttachedContainers,\n\ttype NetworkAttachedEndpoint,\n} from './network.ts';\nimport { removeVolume } from './volume.ts';\nimport {\n\tisMissingImageStderr,\n\tisMissingNetworkStderr,\n\tisNetworkInUseStderr,\n\tisNoSuchContainerStderr,\n\twrapGeneric,\n} from './wrap.ts';\n\nconst removeManagedContainer = (\n\tname: string,\n): Effect.Effect<boolean, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('rm', ['-f', name]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return true;\n\t\tif (isNoSuchContainerStderr(res.stderr)) return false;\n\t\treturn yield* Effect.fail(\n\t\t\tnew ContainerRemoveFailed({\n\t\t\t\tname,\n\t\t\t\tstderr: res.stderr,\n\t\t\t\texitCode: res.exitCode,\n\t\t\t}),\n\t\t);\n\t});\n\n/** Explicit teardown — force-removes managed containers matching the\n * partial label tuple, regardless of claim-ledger entries. Wipe/restore\n * are intentional destructive operations. */\nexport const removeManagedContainers = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst containers = yield* listContainers(labelMatch);\n\t\tlet removed = 0;\n\t\tfor (const c of containers) {\n\t\t\tconst didRemove = yield* removeManagedContainer(c.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\nconst labelsMatchAppStack = (\n\tlabels: Readonly<Record<string, string>>,\n\tmatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): boolean => labels[LabelKey.app] === match.app && labels[LabelKey.stack] === match.stack;\n\nexport const removeDevstackContainers = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst containers = yield* listDevstackContainers();\n\t\tlet removed = 0;\n\t\tfor (const c of containers) {\n\t\t\tif (!labelsMatchAppStack(c.labels, labelMatch)) continue;\n\t\t\tconst didRemove = yield* removeManagedContainer(c.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\n/** Remove devstack-managed containers whose generic `kind` label matches\n * AND whose name matches. The L1 helper is plugin-blind: orchestrators\n * pass the kind value they themselves stamp at create time. */\nexport const removeDevstackContainersByKindAndName = (\n\tkind: string,\n\tcontainerName: string,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst containers = yield* listDevstackContainersByKind(kind);\n\t\tlet removed = 0;\n\t\tfor (const c of containers) {\n\t\t\tif (c.name !== containerName) continue;\n\t\t\tconst didRemove = yield* removeManagedContainer(c.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\nconst removeManagedImage = (\n\tref: string,\n): Effect.Effect<boolean, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('image', ['rm', '-f', ref]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.image.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return true;\n\t\tif (isMissingImageStderr(res.stderr)) return false;\n\t\treturn yield* Effect.fail(\n\t\t\tnew ImageRemoveFailed({\n\t\t\t\tref,\n\t\t\t\tstderr: res.stderr,\n\t\t\t\texitCode: res.exitCode,\n\t\t\t}),\n\t\t);\n\t});\n\nexport const removeManagedImages = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst images = yield* listImages(labelMatch);\n\t\tlet removed = 0;\n\t\tconst seen = new Set<string>();\n\t\tfor (const image of images) {\n\t\t\tconst ref = image.tag;\n\t\t\tif (ref.endsWith(':<none>')) continue;\n\t\t\tif (seen.has(ref)) continue;\n\t\t\tseen.add(ref);\n\t\t\tconst didRemove = yield* removeManagedImage(ref);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\nexport const removeDevstackImages = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst images = yield* listDevstackImages();\n\t\tlet removed = 0;\n\t\tconst seen = new Set<string>();\n\t\tfor (const image of images) {\n\t\t\tif (!labelsMatchAppStack(image.labels, labelMatch)) continue;\n\t\t\tconst ref = image.tag;\n\t\t\tif (ref.endsWith(':<none>')) continue;\n\t\t\tif (seen.has(ref)) continue;\n\t\t\tseen.add(ref);\n\t\t\tconst didRemove = yield* removeManagedImage(ref);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\nconst removeManagedNetwork = (\n\tname: string,\n): Effect.Effect<boolean, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('network', ['rm', name]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.network.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return true;\n\t\tif (isMissingNetworkStderr(res.stderr)) return false;\n\t\treturn yield* Effect.fail(\n\t\t\tnew NetworkOperationFailed({ op: 'remove', network: name, stderr: res.stderr }),\n\t\t);\n\t});\n\nexport const removeManagedNetworks = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst networks = yield* listNetworks(labelMatch);\n\t\tlet removed = 0;\n\t\tfor (const network of networks) {\n\t\t\tif (network.labels[LabelKey.networkMarker] !== 'true') continue;\n\t\t\tconst didRemove = yield* removeManagedNetwork(network.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\n/** Parse `network X has active endpoints (name:\"A\" id:\"B\")` stderr —\n * Docker enumerates each blocking endpoint as a `(name:\"…\" id:\"…\")`\n * tuple. Returns an empty array on non-matching stderr. */\nconst parseActiveEndpointsFromStderr = (\n\tstderr: string,\n): ReadonlyArray<{ readonly name: string; readonly id: string }> => {\n\tconst out: Array<{ name: string; id: string }> = [];\n\tconst re = /\\(name:\"([^\"]+)\"\\s+id:\"([^\"]+)\"\\)/g;\n\tlet m: RegExpExecArray | null;\n\twhile ((m = re.exec(stderr)) !== null) {\n\t\tout.push({ name: m[1]!, id: m[2]! });\n\t}\n\treturn out;\n};\n\n/** One foreign endpoint preventing a network from being removed —\n * surfaced in the prune summary so the operator can investigate. */\nexport interface ForeignNetworkHolder {\n\treadonly network: string;\n\treadonly container: NetworkAttachedEndpoint;\n}\n\n/** A `(name, id)` reference that appears in Docker's `network rm`\n * \"active endpoints\" error but is NOT addressable via `network\n * disconnect -f` and does NOT appear in `network inspect`'s\n * Containers map. Symptom of a Docker engine bug where the bridge\n * driver leaks endpoint metadata for a container that no longer\n * exists. Only a Docker daemon restart reclaims these. */\nexport interface StaleNetworkEndpoint {\n\treadonly network: string;\n\treadonly name: string;\n\treadonly id: string;\n}\n\ntype NetworkRemoveStep =\n\t| { readonly kind: 'removed' }\n\t| { readonly kind: 'missing' }\n\t| { readonly kind: 'in-use'; readonly stderr: string };\n\ntype NetworkRemoveOutcome =\n\t| { readonly kind: 'removed' }\n\t| { readonly kind: 'missing' }\n\t| {\n\t\t\treadonly kind: 'in-use';\n\t\t\treadonly foreignHolders: ReadonlyArray<NetworkAttachedEndpoint>;\n\t\t\treadonly staleEndpoints: ReadonlyArray<{ readonly name: string; readonly id: string }>;\n\t };\n\nexport interface DevstackNetworkRemovalSummary {\n\treadonly removed: number;\n\treadonly skippedInUse: number;\n\treadonly foreignHolders: ReadonlyArray<ForeignNetworkHolder>;\n\treadonly staleEndpoints: ReadonlyArray<StaleNetworkEndpoint>;\n}\n\ninterface DevstackNetworkRemovalOptions {\n\treadonly retryAttempts?: number;\n\treadonly retryDelayMillis?: number;\n}\n\nconst removeManagedNetworkOnce = (\n\tname: string,\n): Effect.Effect<NetworkRemoveStep, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('network', ['rm', name]).pipe(\n\t\t\tEffect.mapError(wrapGeneric('docker.network.rm')),\n\t\t);\n\t\tif (res.exitCode === 0) return { kind: 'removed' as const };\n\t\tif (isMissingNetworkStderr(res.stderr)) return { kind: 'missing' as const };\n\t\tif (isNetworkInUseStderr(res.stderr)) {\n\t\t\treturn { kind: 'in-use' as const, stderr: res.stderr };\n\t\t}\n\t\treturn yield* Effect.fail(\n\t\t\tnew NetworkOperationFailed({ op: 'remove', network: name, stderr: res.stderr }),\n\t\t);\n\t});\n\n/** Best-effort network removal that actively evicts our own endpoints\n * before declaring \"in-use\". Strategy on first in-use response:\n * 1. inspect the network for attached endpoints\n * 2. for each endpoint we own (`devstack.managed=true`), force-\n * disconnect it\n * 3. retry `network rm`\n * Anything still holding the network after that is reported as a\n * foreign holder — typically a non-devstack container, a test fixture,\n * or a sibling stack we deliberately left alone. */\nconst removeManagedNetworkBestEffort = (\n\tname: string,\n\toptions: Required<DevstackNetworkRemovalOptions>,\n): Effect.Effect<NetworkRemoveOutcome, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst first = yield* removeManagedNetworkOnce(name);\n\t\tif (first.kind !== 'in-use') return first;\n\t\t// Investigate, evict our own endpoints, retry.\n\t\tconst attachments = yield* listAttachedContainers(name).pipe(\n\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<NetworkAttachedEndpoint>)),\n\t\t);\n\t\tif (attachments.length > 0) {\n\t\t\tconst ownedNames = new Set<string>();\n\t\t\tconst all = yield* listDevstackContainers().pipe(\n\t\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<{ readonly name: string }>)),\n\t\t\t);\n\t\t\tfor (const c of all) ownedNames.add(c.name);\n\t\t\tfor (const attached of attachments) {\n\t\t\t\tif (!ownedNames.has(attached.name)) continue;\n\t\t\t\tyield* forceDisconnect(attached.name, name).pipe(\n\t\t\t\t\tEffect.tapCause((cause) =>\n\t\t\t\t\t\tEffect.logDebug('prune: force-disconnect failed; will retry rm anyway', {\n\t\t\t\t\t\t\tnetwork: name,\n\t\t\t\t\t\t\tcontainer: attached.name,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.catch(() => Effect.void),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Retry `network rm` after eviction — Effect.repeat with a\n\t\t// spaced schedule per §16 \"Balance / poll loop\" canonical\n\t\t// helper (substrate `NETWORK_REMOVE_RETRY_PROFILE`). User-\n\t\t// supplied `options.retryAttempts` / `retryDelayMillis`\n\t\t// override the profile defaults. `Schedule.recurs(N)` allows\n\t\t// N additional recurrences, so this retry block makes\n\t\t// `1 + retryAttempts` rm calls when persistently in-use. Counting\n\t\t// the pre-eviction `first` probe above, the worst-case in-use\n\t\t// total for this function is `2 + retryAttempts` rm invocations.\n\t\tconst lastStep: NetworkRemoveStep = yield* removeManagedNetworkOnce(name).pipe(\n\t\t\tEffect.repeat({\n\t\t\t\tschedule: makeSpacedRetrySchedule(options.retryDelayMillis, options.retryAttempts),\n\t\t\t\tuntil: (step): boolean => step.kind !== 'in-use',\n\t\t\t}),\n\t\t);\n\t\tif (lastStep.kind === 'removed') return { kind: 'removed' as const };\n\t\tif (lastStep.kind === 'missing') return { kind: 'missing' as const };\n\t\tconst lastStderr = lastStep.stderr;\n\t\t// Still in-use after our best effort — diagnose what's holding it.\n\t\tconst finalAttachments = yield* listAttachedContainers(name).pipe(\n\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<NetworkAttachedEndpoint>)),\n\t\t);\n\t\tconst ownedNames = new Set<string>();\n\t\tconst all = yield* listDevstackContainers().pipe(\n\t\t\tEffect.catch(() => Effect.succeed([] as ReadonlyArray<{ readonly name: string }>)),\n\t\t);\n\t\tfor (const c of all) ownedNames.add(c.name);\n\t\tconst foreign = finalAttachments.filter((a) => !ownedNames.has(a.name));\n\t\t// Endpoints Docker mentions in the rm error but which DON'T\n\t\t// appear in inspect → stale metadata. The bridge driver kept\n\t\t// the endpoint record around after the container was reaped;\n\t\t// no CLI/API path can remove it. Operator must restart Docker.\n\t\tconst attachedNames = new Set(finalAttachments.map((a) => a.name));\n\t\tconst stale = parseActiveEndpointsFromStderr(lastStderr).filter(\n\t\t\t(ep) => !attachedNames.has(ep.name),\n\t\t);\n\t\treturn {\n\t\t\tkind: 'in-use' as const,\n\t\t\tforeignHolders: foreign,\n\t\t\tstaleEndpoints: stale,\n\t\t};\n\t});\n\nexport const removeDevstackNetworks = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst networks = yield* listDevstackNetworks();\n\t\tlet removed = 0;\n\t\tfor (const network of networks) {\n\t\t\tif (!labelsMatchAppStack(network.labels, labelMatch)) continue;\n\t\t\tconst didRemove = yield* removeManagedNetwork(network.name);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\nexport const removeDevstackNetworksBestEffort = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n\toptions: DevstackNetworkRemovalOptions = {},\n): Effect.Effect<DevstackNetworkRemovalSummary, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst networks = yield* listDevstackNetworks();\n\t\tconst retryOptions = {\n\t\t\tretryAttempts: options.retryAttempts ?? NETWORK_REMOVE_RETRY_PROFILE.attempts,\n\t\t\tretryDelayMillis: options.retryDelayMillis ?? NETWORK_REMOVE_RETRY_PROFILE.delayMs,\n\t\t};\n\t\tlet removed = 0;\n\t\tlet skippedInUse = 0;\n\t\tconst foreignHolders: Array<ForeignNetworkHolder> = [];\n\t\tconst staleEndpoints: Array<StaleNetworkEndpoint> = [];\n\t\tfor (const network of networks) {\n\t\t\tif (!labelsMatchAppStack(network.labels, labelMatch)) continue;\n\t\t\tconst outcome = yield* removeManagedNetworkBestEffort(network.name, retryOptions);\n\t\t\tif (outcome.kind === 'removed') removed += 1;\n\t\t\telse if (outcome.kind === 'in-use') {\n\t\t\t\tskippedInUse += 1;\n\t\t\t\tfor (const container of outcome.foreignHolders) {\n\t\t\t\t\tforeignHolders.push({ network: network.name, container });\n\t\t\t\t}\n\t\t\t\tfor (const ep of outcome.staleEndpoints) {\n\t\t\t\t\tstaleEndpoints.push({ network: network.name, name: ep.name, id: ep.id });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn { removed, skippedInUse, foreignHolders, staleEndpoints };\n\t});\n\nexport const removeManagedVolumes = (\n\tlabelMatch: Partial<ContainerLabelTuple>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst volumes = yield* listVolumes(labelMatch);\n\t\tlet removed = 0;\n\t\tfor (const volume of volumes) {\n\t\t\tif (volume.labels[LabelKey.volumeMarker] !== 'true') continue;\n\t\t\t// Best-effort per volume: an in-use/locked volume must not poison\n\t\t\t// the loop and strand later volumes. Surface the cause via\n\t\t\t// `logWarning` for operator visibility, then continue.\n\t\t\tconst didRemove = yield* removeVolume(volume.name).pipe(\n\t\t\t\tEffect.tapCause((cause) =>\n\t\t\t\t\tEffect.logWarning('sweep: docker volume rm failed', { name: volume.name, cause }),\n\t\t\t\t),\n\t\t\t\tEffect.as(true),\n\t\t\t\tEffect.catch(() => Effect.succeed(false)),\n\t\t\t);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n\nexport const removeDevstackVolumes = (\n\tlabelMatch: Pick<ContainerLabelTuple, 'app' | 'stack'>,\n): Effect.Effect<number, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst volumes = yield* listDevstackVolumes();\n\t\tlet removed = 0;\n\t\tfor (const volume of volumes) {\n\t\t\tif (!labelsMatchAppStack(volume.labels, labelMatch)) continue;\n\t\t\t// Best-effort per volume: an in-use/locked volume must not poison\n\t\t\t// the loop and strand later volumes. Surface the cause via\n\t\t\t// `logWarning` for operator visibility, then continue.\n\t\t\tconst didRemove = yield* removeVolume(volume.name).pipe(\n\t\t\t\tEffect.tapCause((cause) =>\n\t\t\t\t\tEffect.logWarning('sweep: docker volume rm failed', { name: volume.name, cause }),\n\t\t\t\t),\n\t\t\t\tEffect.as(true),\n\t\t\t\tEffect.catch(() => Effect.succeed(false)),\n\t\t\t);\n\t\t\tif (didRemove) removed += 1;\n\t\t}\n\t\treturn removed;\n\t});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"volume.mjs","names":[],"sources":["../../../src/runtime/docker/volume.ts"],"sourcesContent":["// Docker volume lifecycle.\n//\n// Architecture invariant: PRE-CREATE labelled volumes BEFORE the run\n// argv fires. Docker's lazy `-v <name>:<path>` produces UNLABELLED\n// volumes that no inventory enumeration can find. Bind mounts pass\n// through unchanged (host-owned paths).\n\nimport { Effect, Schema } from 'effect';\n\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport { DockerHost, DockerSpawner, dockerRun, dockerRunOk } from './client.ts';\nimport {
|
|
1
|
+
{"version":3,"file":"volume.mjs","names":[],"sources":["../../../src/runtime/docker/volume.ts"],"sourcesContent":["// Docker volume lifecycle.\n//\n// Architecture invariant: PRE-CREATE labelled volumes BEFORE the run\n// argv fires. Docker's lazy `-v <name>:<path>` produces UNLABELLED\n// volumes that no inventory enumeration can find. Bind mounts pass\n// through unchanged (host-owned paths).\n\nimport { Effect, Schema } from 'effect';\n\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport { DockerHost, DockerSpawner, dockerRun, dockerRunOk } from './client.ts';\nimport { type DockerRuntimeError, ForeignDockerResource, VolumeOperationFailed } from './errors.ts';\nimport { dockerInspectAndDecode } from './inspect-and-decode.ts';\nimport {\n\texpectedVolumeOwnershipLabels,\n\townershipMismatchDetail,\n\treadLabels,\n\trenderVolumeLabels,\n} from './labels.ts';\nimport { wrapVolumeError } from './wrap.ts';\n\ninterface VolumeInspectFacts {\n\treadonly name: string;\n\treadonly labels: Readonly<Record<string, string>>;\n}\n\nconst VolumeInspectSchema = Schema.Struct({\n\tName: Schema.String,\n\tLabels: Schema.optional(Schema.Unknown),\n});\n\nconst isNoSuchVolumeStderr = (stderr: string): boolean => /no such volume/i.test(stderr);\n\nconst inspectVolume = (\n\tname: string,\n): Effect.Effect<VolumeInspectFacts | null, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst decoded = yield* dockerInspectAndDecode({\n\t\t\tresourceKind: 'volume',\n\t\t\tname,\n\t\t\top: 'docker.volume.inspect',\n\t\t\tinspectCommand: dockerRunOk('volume', ['inspect', name]).pipe(\n\t\t\t\tEffect.mapError(wrapVolumeError('inspect', name)),\n\t\t\t),\n\t\t\tschema: VolumeInspectSchema,\n\t\t\tisMissingStderr: isNoSuchVolumeStderr,\n\t\t});\n\t\tif (decoded === null) return null;\n\t\treturn { name: decoded.Name, labels: readLabels(decoded.Labels) };\n\t});\n\nconst assertVolumeOwned = (\n\tname: string,\n\tfacts: VolumeInspectFacts,\n\ttuple: ContainerLabelTuple,\n): Effect.Effect<void, DockerRuntimeError> =>\n\tEffect.gen(function* () {\n\t\tconst expected = expectedVolumeOwnershipLabels(tuple);\n\t\tconst mismatch = ownershipMismatchDetail(expected, facts.labels);\n\t\tif (mismatch !== null) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew ForeignDockerResource({\n\t\t\t\t\tresource: 'volume',\n\t\t\t\t\tname,\n\t\t\t\t\texpected,\n\t\t\t\t\tactual: facts.labels,\n\t\t\t\t\tdetail: mismatch,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t});\n\n/** Idempotent `docker volume create`. Stamps the canonical label set.\n * Returns the volume name on success. */\nexport const ensureVolume = (\n\tname: string,\n\ttuple: ContainerLabelTuple,\n): Effect.Effect<string, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst probe = yield* inspectVolume(name);\n\t\tif (probe !== null) {\n\t\t\tyield* assertVolumeOwned(name, probe, tuple);\n\t\t\treturn probe.name;\n\t\t}\n\t\tconst labelArgs = renderVolumeLabels(name, tuple).flatMap((l) => ['--label', l]);\n\t\tyield* dockerRun('volume', ['create', ...labelArgs, name]).pipe(\n\t\t\tEffect.mapError(wrapVolumeError('create', name)),\n\t\t);\n\t\treturn name;\n\t});\n\nexport const removeVolume = (\n\tname: string,\n): Effect.Effect<void, DockerRuntimeError, DockerHost | DockerSpawner> =>\n\tEffect.gen(function* () {\n\t\tconst res = yield* dockerRunOk('volume', ['rm', '--force', name]).pipe(\n\t\t\tEffect.mapError(wrapVolumeError('remove', name)),\n\t\t);\n\t\t// \"no such volume\" is idempotent success.\n\t\tif (res.exitCode !== 0 && !/no such volume/i.test(res.stderr)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew VolumeOperationFailed({ op: 'remove', volume: name, stderr: res.stderr }),\n\t\t\t);\n\t\t}\n\t});\n"],"mappings":";;;;;;AA0B4B,OAAO,OAAO;CACzC,MAAM,OAAO;CACb,QAAQ,OAAO,SAAS,OAAO,OAAO;AACvC,CAAC;AA8DD,MAAa,gBACZ,SAEA,OAAO,IAAI,aAAa;CACvB,MAAM,MAAM,OAAO,YAAY,UAAU;EAAC;EAAM;EAAW;CAAI,CAAC,CAAC,CAAC,KACjE,OAAO,SAAS,gBAAgB,UAAU,IAAI,CAAC,CAChD;CAEA,IAAI,IAAI,aAAa,KAAK,CAAC,kBAAkB,KAAK,IAAI,MAAM,GAC3D,OAAO,OAAO,OAAO,KACpB,IAAI,sBAAsB;EAAE,IAAI;EAAU,QAAQ;EAAM,QAAQ,IAAI;CAAO,CAAC,CAC7E;AAEF,CAAC"}
|
|
@@ -26,8 +26,16 @@ const isNetworkAlreadyExistsStderr = (stderr) => /network with name \S+ already
|
|
|
26
26
|
/** Docker bridge IPAM exhaustion. This is a stale-network / missing
|
|
27
27
|
* explicit-subnet policy failure, not a daemon reachability failure. */
|
|
28
28
|
const isNetworkAddressPoolExhaustedStderr = (stderr) => /all predefined address pools have been fully subnetted/i.test(stderr);
|
|
29
|
-
/** Image not found — pull or inspect against an unknown ref.
|
|
30
|
-
|
|
29
|
+
/** Image not found — pull or inspect against an unknown ref. Also
|
|
30
|
+
* covers the implicit-pull-on-create case: `docker run` against a
|
|
31
|
+
* local-only image name that isn't present (an interrupted restore
|
|
32
|
+
* left the target image un-promoted, or a locally-built image was
|
|
33
|
+
* GC'd) tries an implicit registry pull and fails with `Unable to
|
|
34
|
+
* find image '<ref>' locally` followed by a `manifest unknown` /
|
|
35
|
+
* `pull access denied` line. Matching these here lets `wrapCreateError`
|
|
36
|
+
* surface a typed, recoverable `ImageNotFound` instead of an opaque
|
|
37
|
+
* fatal `ContainerCreateFailed`. */
|
|
38
|
+
const isImageNotFoundStderr = (stderr) => /pull access denied/i.test(stderr) || /manifest .* not found/i.test(stderr) || /manifest unknown/i.test(stderr) || /repository .* not found/i.test(stderr) || /Unable to find image/i.test(stderr) || /No such image/i.test(stderr);
|
|
31
39
|
/** Image missing — classifier for `docker image rm` / `docker tag`
|
|
32
40
|
* flows. Matches the daemon's canonical wording only — a bare
|
|
33
41
|
* `/not found/` alternation would misclassify permission-denied and
|
|
@@ -98,6 +106,10 @@ const wrapCreateError = (name) => (err) => {
|
|
|
98
106
|
stderr: err.stderr,
|
|
99
107
|
exitCode: err.exitCode
|
|
100
108
|
});
|
|
109
|
+
if (isImageNotFoundStderr(err.stderr)) return new ImageNotFound({
|
|
110
|
+
ref: name,
|
|
111
|
+
detail: "create target image not present locally"
|
|
112
|
+
});
|
|
101
113
|
return new ContainerCreateFailed({
|
|
102
114
|
name,
|
|
103
115
|
stderr: err.stderr,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap.mjs","names":[],"sources":["../../../src/runtime/docker/wrap.ts"],"sourcesContent":["// Subprocess-capture → typed docker-error translation.\n//\n// Architecture inverts the legacy \"stderr-pattern wording\" coupling:\n// instead of every plugin staring at stderr substrings, we classify\n// in ONE place and surface typed errors. Plugins consume typed errors\n// (`ImageNotFound`, `BuildFailed`, …) and never see raw stderr text\n// outside the error envelope's `detail` field.\n//\n// Stderr classifiers are kept here, not scattered. New runtime\n// backends (podman / finch) ship their own dialect of the classifier\n// set; the typed-error surface is the same.\n\nimport type {\n\tCaptureError,\n\tCaptureResult,\n} from '../../substrate/runtime/observability/subprocess-capture.ts';\nimport {\n\tBuildFailed,\n\tContainerCreateFailed,\n\tContainerNameCollisionUnrecoverable,\n\tContainerPortPublishConflict,\n\tDaemonUnreachable,\n\ttype DockerRuntimeError,\n\tImageNotFound,\n\tImagePullFailed,\n\tNetworkAddressPoolExhausted,\n\tNetworkOperationFailed,\n\tVolumeOperationFailed,\n} from './errors.ts';\n\n// -----------------------------------------------------------------------------\n// Classifiers\n// -----------------------------------------------------------------------------\n\n/** Daemon unreachable — the connection itself failed. Highest-priority\n * classifier; if this is true, no further classification is meaningful. */\nexport const isDaemonUnreachableStderr = (stderr: string): boolean =>\n\t/Cannot connect to the Docker daemon/i.test(stderr) ||\n\t/Is the docker daemon running\\?/i.test(stderr) ||\n\t/ENOENT.*docker/i.test(stderr);\n\n/** Name collision — `docker create` / `run -d` returns exit 125 with\n * \"name is already in use\" wording. Architecture §1 — name-atomic create. */\nexport const isNameCollisionStderr = (stderr: string): boolean =>\n\t/is already in use by container/i.test(stderr) || /Conflict.*The container name/i.test(stderr);\n\n/** Port conflict — used by container resume-fallback path. */\nexport const isPortConflictStderr = (stderr: string): boolean =>\n\t/port is already allocated/i.test(stderr) || /bind.*address already in use/i.test(stderr);\n\n/** \"No such container\" — TOCTOU recovery signal. */\nexport const isNoSuchContainerStderr = (stderr: string): boolean =>\n\t/No such container/i.test(stderr) ||\n\t/Error response from daemon: No such container/i.test(stderr) ||\n\t/no such object/i.test(stderr);\n\n/** Network attach idempotency — \"already exists in network\" is success. */\nexport const isAlreadyInNetworkStderr = (stderr: string): boolean =>\n\t/already exists in network/i.test(stderr) || /endpoint with name .* already exists/i.test(stderr);\n\n/** Network-create collision — `docker network create` is NOT name-atomic\n * and there is no per-name lock for networks, so two processes booting\n * against the shared `devstack` bridge can both pass the inspect-miss and\n * both run `create`; the loser sees this stderr. Matches the daemon's\n * canonical wording `network with name <name> already exists` plus the\n * `Conflict` (409) envelope libnetwork returns for the same condition.\n * Distinct from `isAlreadyInNetworkStderr` (the connect-side\n * endpoint-already-attached case) — this is the network object itself\n * already existing, the signal for `ensureNetwork`'s adopt-on-collision\n * re-inspect. */\nexport const isNetworkAlreadyExistsStderr = (stderr: string): boolean =>\n\t/network with name \\S+ already exists/i.test(stderr) ||\n\t/Conflict.*network/i.test(stderr) ||\n\t/network \\S+ already exists/i.test(stderr);\n\n/** Docker bridge IPAM exhaustion. This is a stale-network / missing\n * explicit-subnet policy failure, not a daemon reachability failure. */\nexport const isNetworkAddressPoolExhaustedStderr = (stderr: string): boolean =>\n\t/all predefined address pools have been fully subnetted/i.test(stderr);\n\n/** Image not found — pull or inspect against an unknown ref. */\nexport const isImageNotFoundStderr = (stderr: string): boolean =>\n\t/pull access denied/i.test(stderr) ||\n\t/manifest .* not found/i.test(stderr) ||\n\t/repository .* not found/i.test(stderr) ||\n\t/No such image/i.test(stderr);\n\n/** Image missing — classifier for `docker image rm` / `docker tag`\n * flows. Matches the daemon's canonical wording only — a bare\n * `/not found/` alternation would misclassify permission-denied and\n * registry-auth errors (e.g. `pull access denied … repository does\n * not exist`) as \"missing\" and let sweep silently skip them. Distinct\n * from `isImageNotFoundStderr` (pull-flow-specific) — this one is the\n * union used by idempotent remove/tag paths. */\nexport const isMissingImageStderr = (stderr: string): boolean =>\n\t/no such image|reference does not exist/i.test(stderr);\n\n/** Network missing — idempotent classifier for `docker network rm` /\n * `docker network inspect`. Matches the daemon's canonical wordings:\n * `No such network: <name>` and `network <name> not found`. A bare\n * `/not found/` alternation would misclassify auth / permission errors\n * on shared docker hosts. */\nexport const isMissingNetworkStderr = (stderr: string): boolean =>\n\t/no such network|network \\S+ not found/i.test(stderr);\n\n/** Network in-use — `docker network rm` failed because endpoints are\n * still attached. Inverse predicate of `isMissingNetworkStderr`; lives\n * next to its siblings so the two evolve together. */\nexport const isNetworkInUseStderr = (stderr: string): boolean =>\n\t/active endpoints|has active endpoint|network .* is in use/i.test(stderr);\n\n// -----------------------------------------------------------------------------\n// Wrappers — translate CaptureError → typed DockerRuntimeError\n// -----------------------------------------------------------------------------\n\n/** Daemon-unreachable check is the universal short-circuit. Every\n * wrapper runs this first. */\nconst checkDaemon = (err: CaptureError): DaemonUnreachable | null => {\n\tif (isDaemonUnreachableStderr(err.stderr)) {\n\t\treturn new DaemonUnreachable({\n\t\t\top: err.op,\n\t\t\tdetail: 'docker daemon unreachable',\n\t\t\tcause: err.cause,\n\t\t});\n\t}\n\tif (err.cause !== undefined && err.exitCode === undefined) {\n\t\treturn new DaemonUnreachable({\n\t\t\top: err.op,\n\t\t\tdetail: 'docker CLI spawn failed (binary missing or fork failure)',\n\t\t\tcause: err.cause,\n\t\t});\n\t}\n\treturn null;\n};\n\nexport const wrapPullError =\n\t(ref: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\tif (isImageNotFoundStderr(err.stderr)) {\n\t\t\treturn new ImageNotFound({ ref, detail: 'pull target not found' });\n\t\t}\n\t\treturn new ImagePullFailed({ ref, stderr: err.stderr, exitCode: err.exitCode });\n\t};\n\nexport const wrapBuildError =\n\t(contextPath: string, dockerfile: string | undefined) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\t// STUB: best-effort parse of `Step <n>/<m> : <line>` from a\n\t\t// buildkit / classic builder log. The architecture allows this\n\t\t// to be empty — the raw stderr is still surfaced in `detail`.\n\t\t// Follow-up: extract from buildkit's `#<n> ERROR: …` envelope.\n\t\tconst parsedStep = parseFailingBuildStep(err.stdout, err.stderr);\n\t\treturn new BuildFailed({\n\t\t\tcontextPath,\n\t\t\tdockerfile,\n\t\t\tstderr: err.stderr,\n\t\t\tparsedStep,\n\t\t\texitCode: err.exitCode,\n\t\t});\n\t};\n\nexport const wrapCreateError =\n\t(name: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\tif (isNameCollisionStderr(err.stderr)) {\n\t\t\t// Architecture §1: surface the collision typed so the\n\t\t\t// state machine can decide adopt vs typed-failure. The\n\t\t\t// `Unrecoverable` variant fires only AFTER the start-and-\n\t\t\t// adopt fallback has exhausted; here we signal the collision\n\t\t\t// for the caller to handle.\n\t\t\treturn new ContainerNameCollisionUnrecoverable({\n\t\t\t\tname,\n\t\t\t\tdetail: 'name collision; caller should attempt adopt fallback',\n\t\t\t});\n\t\t}\n\t\tif (isPortConflictStderr(err.stderr)) {\n\t\t\treturn new ContainerPortPublishConflict({\n\t\t\t\tname,\n\t\t\t\tstderr: err.stderr,\n\t\t\t\texitCode: err.exitCode,\n\t\t\t});\n\t\t}\n\t\treturn new ContainerCreateFailed({ name, stderr: err.stderr, exitCode: err.exitCode });\n\t};\n\nexport const wrapNetworkError =\n\t(op: 'create' | 'connect' | 'disconnect' | 'inspect' | 'remove', network: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\tif (op === 'create' && isNetworkAddressPoolExhaustedStderr(err.stderr)) {\n\t\t\treturn new NetworkAddressPoolExhausted({\n\t\t\t\tnetwork,\n\t\t\t\tstderr: err.stderr,\n\t\t\t\thint: 'Docker exhausted its predefined bridge address pools. Remove stale devstack networks with wipe/prune (for example `docker network prune`) or request an explicit non-overlapping subnet/gateway.',\n\t\t\t});\n\t\t}\n\t\treturn new NetworkOperationFailed({ op, network, stderr: err.stderr });\n\t};\n\nexport const wrapVolumeError =\n\t(op: 'create' | 'inspect' | 'remove', volume: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\treturn new VolumeOperationFailed({ op, volume, stderr: err.stderr });\n\t};\n\n/** Generic wrapper for op surfaces (`docker logs`, `docker inspect`,\n * etc.) where the only distinct failure mode is daemon down. */\nexport const wrapGeneric =\n\t(op: string) =>\n\t(err: CaptureError): DockerRuntimeError =>\n\t\tcheckDaemon(err) ??\n\t\tnew DaemonUnreachable({\n\t\t\top,\n\t\t\tdetail: err.stderr || `${op} failed (exit ${err.exitCode ?? '?'})`,\n\t\t\tcause: err.cause,\n\t\t});\n\n// -----------------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------------\n\n/** STUB: extract a \"failing step\" line from build output. The\n * buildkit envelope shape is documented; classic builder shape is\n * `Step N/M : <directive>`. Returning `undefined` is fine — the raw\n * stderr is still in the BuildFailed envelope. */\nconst parseFailingBuildStep = (stdout: string, stderr: string): string | undefined => {\n\tconst combined = `${stderr}\\n${stdout}`;\n\tconst classic = combined.match(/Step (\\d+)\\/(\\d+)\\s*:\\s*([^\\n]+)/);\n\tif (classic) return `Step ${classic[1]}/${classic[2]} ${classic[3]}`;\n\tconst buildkit = combined.match(/#(\\d+)\\s+ERROR\\s*:\\s*([^\\n]+)/);\n\tif (buildkit) return `#${buildkit[1]} ${buildkit[2]}`;\n\treturn undefined;\n};\n\n/** Inspect a `CaptureResult`'s exit code; if non-zero return null\n * (caller decides what to do). Used by the lifecycle state machine\n * to classify stderr patterns WITHOUT promoting non-zero to failure\n * via `nonZeroIsFailure`. */\nexport const classifyExit = (\n\tres: CaptureResult,\n): { readonly ok: boolean; readonly exitCode: number; readonly stderr: string } => ({\n\tok: res.exitCode === 0,\n\texitCode: res.exitCode,\n\tstderr: res.stderr,\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wrap.mjs","names":[],"sources":["../../../src/runtime/docker/wrap.ts"],"sourcesContent":["// Subprocess-capture → typed docker-error translation.\n//\n// Instead of every plugin staring at stderr substrings, classification\n// happens in ONE place and surfaces typed errors. Plugins consume typed errors\n// (`ImageNotFound`, `BuildFailed`, …) and never see raw stderr text\n// outside the error envelope's `detail` field.\n//\n// Stderr classifiers are kept here, not scattered. New runtime\n// backends (podman / finch) ship their own dialect of the classifier\n// set; the typed-error surface is the same.\n\nimport type {\n\tCaptureError,\n\tCaptureResult,\n} from '../../substrate/runtime/observability/subprocess-capture.ts';\nimport {\n\tBuildFailed,\n\tContainerCreateFailed,\n\tContainerNameCollisionUnrecoverable,\n\tContainerPortPublishConflict,\n\tDaemonUnreachable,\n\ttype DockerRuntimeError,\n\tImageNotFound,\n\tImagePullFailed,\n\tNetworkAddressPoolExhausted,\n\tNetworkOperationFailed,\n\tVolumeOperationFailed,\n} from './errors.ts';\n\n// -----------------------------------------------------------------------------\n// Classifiers\n// -----------------------------------------------------------------------------\n\n/** Daemon unreachable — the connection itself failed. Highest-priority\n * classifier; if this is true, no further classification is meaningful. */\nexport const isDaemonUnreachableStderr = (stderr: string): boolean =>\n\t/Cannot connect to the Docker daemon/i.test(stderr) ||\n\t/Is the docker daemon running\\?/i.test(stderr) ||\n\t/ENOENT.*docker/i.test(stderr);\n\n/** Name collision — `docker create` / `run -d` returns exit 125 with\n * \"name is already in use\" wording. Architecture §1 — name-atomic create. */\nexport const isNameCollisionStderr = (stderr: string): boolean =>\n\t/is already in use by container/i.test(stderr) || /Conflict.*The container name/i.test(stderr);\n\n/** Port conflict — used by container resume-fallback path. */\nexport const isPortConflictStderr = (stderr: string): boolean =>\n\t/port is already allocated/i.test(stderr) || /bind.*address already in use/i.test(stderr);\n\n/** \"No such container\" — TOCTOU recovery signal. */\nexport const isNoSuchContainerStderr = (stderr: string): boolean =>\n\t/No such container/i.test(stderr) ||\n\t/Error response from daemon: No such container/i.test(stderr) ||\n\t/no such object/i.test(stderr);\n\n/** Network attach idempotency — \"already exists in network\" is success. */\nexport const isAlreadyInNetworkStderr = (stderr: string): boolean =>\n\t/already exists in network/i.test(stderr) || /endpoint with name .* already exists/i.test(stderr);\n\n/** Network-create collision — `docker network create` is NOT name-atomic\n * and there is no per-name lock for networks, so two processes booting\n * against the shared `devstack` bridge can both pass the inspect-miss and\n * both run `create`; the loser sees this stderr. Matches the daemon's\n * canonical wording `network with name <name> already exists` plus the\n * `Conflict` (409) envelope libnetwork returns for the same condition.\n * Distinct from `isAlreadyInNetworkStderr` (the connect-side\n * endpoint-already-attached case) — this is the network object itself\n * already existing, the signal for `ensureNetwork`'s adopt-on-collision\n * re-inspect. */\nexport const isNetworkAlreadyExistsStderr = (stderr: string): boolean =>\n\t/network with name \\S+ already exists/i.test(stderr) ||\n\t/Conflict.*network/i.test(stderr) ||\n\t/network \\S+ already exists/i.test(stderr);\n\n/** Docker bridge IPAM exhaustion. This is a stale-network / missing\n * explicit-subnet policy failure, not a daemon reachability failure. */\nexport const isNetworkAddressPoolExhaustedStderr = (stderr: string): boolean =>\n\t/all predefined address pools have been fully subnetted/i.test(stderr);\n\n/** Image not found — pull or inspect against an unknown ref. Also\n * covers the implicit-pull-on-create case: `docker run` against a\n * local-only image name that isn't present (an interrupted restore\n * left the target image un-promoted, or a locally-built image was\n * GC'd) tries an implicit registry pull and fails with `Unable to\n * find image '<ref>' locally` followed by a `manifest unknown` /\n * `pull access denied` line. Matching these here lets `wrapCreateError`\n * surface a typed, recoverable `ImageNotFound` instead of an opaque\n * fatal `ContainerCreateFailed`. */\nexport const isImageNotFoundStderr = (stderr: string): boolean =>\n\t/pull access denied/i.test(stderr) ||\n\t/manifest .* not found/i.test(stderr) ||\n\t/manifest unknown/i.test(stderr) ||\n\t/repository .* not found/i.test(stderr) ||\n\t/Unable to find image/i.test(stderr) ||\n\t/No such image/i.test(stderr);\n\n/** Image missing — classifier for `docker image rm` / `docker tag`\n * flows. Matches the daemon's canonical wording only — a bare\n * `/not found/` alternation would misclassify permission-denied and\n * registry-auth errors (e.g. `pull access denied … repository does\n * not exist`) as \"missing\" and let sweep silently skip them. Distinct\n * from `isImageNotFoundStderr` (pull-flow-specific) — this one is the\n * union used by idempotent remove/tag paths. */\nexport const isMissingImageStderr = (stderr: string): boolean =>\n\t/no such image|reference does not exist/i.test(stderr);\n\n/** Network missing — idempotent classifier for `docker network rm` /\n * `docker network inspect`. Matches the daemon's canonical wordings:\n * `No such network: <name>` and `network <name> not found`. A bare\n * `/not found/` alternation would misclassify auth / permission errors\n * on shared docker hosts. */\nexport const isMissingNetworkStderr = (stderr: string): boolean =>\n\t/no such network|network \\S+ not found/i.test(stderr);\n\n/** Network in-use — `docker network rm` failed because endpoints are\n * still attached. Inverse predicate of `isMissingNetworkStderr`; lives\n * next to its siblings so the two evolve together. */\nexport const isNetworkInUseStderr = (stderr: string): boolean =>\n\t/active endpoints|has active endpoint|network .* is in use/i.test(stderr);\n\n// -----------------------------------------------------------------------------\n// Wrappers — translate CaptureError → typed DockerRuntimeError\n// -----------------------------------------------------------------------------\n\n/** Daemon-unreachable check is the universal short-circuit. Every\n * wrapper runs this first. */\nconst checkDaemon = (err: CaptureError): DaemonUnreachable | null => {\n\tif (isDaemonUnreachableStderr(err.stderr)) {\n\t\treturn new DaemonUnreachable({\n\t\t\top: err.op,\n\t\t\tdetail: 'docker daemon unreachable',\n\t\t\tcause: err.cause,\n\t\t});\n\t}\n\tif (err.cause !== undefined && err.exitCode === undefined) {\n\t\treturn new DaemonUnreachable({\n\t\t\top: err.op,\n\t\t\tdetail: 'docker CLI spawn failed (binary missing or fork failure)',\n\t\t\tcause: err.cause,\n\t\t});\n\t}\n\treturn null;\n};\n\nexport const wrapPullError =\n\t(ref: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\tif (isImageNotFoundStderr(err.stderr)) {\n\t\t\treturn new ImageNotFound({ ref, detail: 'pull target not found' });\n\t\t}\n\t\treturn new ImagePullFailed({ ref, stderr: err.stderr, exitCode: err.exitCode });\n\t};\n\nexport const wrapBuildError =\n\t(contextPath: string, dockerfile: string | undefined) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\t// STUB: best-effort parse of `Step <n>/<m> : <line>` from a\n\t\t// buildkit / classic builder log. The architecture allows this\n\t\t// to be empty — the raw stderr is still surfaced in `detail`.\n\t\t// Follow-up: extract from buildkit's `#<n> ERROR: …` envelope.\n\t\tconst parsedStep = parseFailingBuildStep(err.stdout, err.stderr);\n\t\treturn new BuildFailed({\n\t\t\tcontextPath,\n\t\t\tdockerfile,\n\t\t\tstderr: err.stderr,\n\t\t\tparsedStep,\n\t\t\texitCode: err.exitCode,\n\t\t});\n\t};\n\nexport const wrapCreateError =\n\t(name: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\tif (isNameCollisionStderr(err.stderr)) {\n\t\t\t// Architecture §1: surface the collision typed so the\n\t\t\t// state machine can decide adopt vs typed-failure. The\n\t\t\t// `Unrecoverable` variant fires only AFTER the start-and-\n\t\t\t// adopt fallback has exhausted; here we signal the collision\n\t\t\t// for the caller to handle.\n\t\t\treturn new ContainerNameCollisionUnrecoverable({\n\t\t\t\tname,\n\t\t\t\tdetail: 'name collision; caller should attempt adopt fallback',\n\t\t\t});\n\t\t}\n\t\tif (isPortConflictStderr(err.stderr)) {\n\t\t\treturn new ContainerPortPublishConflict({\n\t\t\t\tname,\n\t\t\t\tstderr: err.stderr,\n\t\t\t\texitCode: err.exitCode,\n\t\t\t});\n\t\t}\n\t\tif (isImageNotFoundStderr(err.stderr)) {\n\t\t\t// `docker run` against a local-only image name that isn't\n\t\t\t// present tries an implicit registry pull and fails. This is\n\t\t\t// RECOVERABLE (the dangling restored image still resolves by\n\t\t\t// digest, or restore can be re-run) — surface it typed so the\n\t\t\t// create path can try the digest fallback instead of a fatal\n\t\t\t// `ContainerCreateFailed`. `ref` carries the create name as the\n\t\t\t// best available identifier; the create caller knows the\n\t\t\t// concrete tag/digest it attempted.\n\t\t\treturn new ImageNotFound({ ref: name, detail: 'create target image not present locally' });\n\t\t}\n\t\treturn new ContainerCreateFailed({ name, stderr: err.stderr, exitCode: err.exitCode });\n\t};\n\nexport const wrapNetworkError =\n\t(op: 'create' | 'connect' | 'disconnect' | 'inspect' | 'remove', network: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\tif (op === 'create' && isNetworkAddressPoolExhaustedStderr(err.stderr)) {\n\t\t\treturn new NetworkAddressPoolExhausted({\n\t\t\t\tnetwork,\n\t\t\t\tstderr: err.stderr,\n\t\t\t\thint: 'Docker exhausted its predefined bridge address pools. Remove stale devstack networks with wipe/prune (for example `docker network prune`) or request an explicit non-overlapping subnet/gateway.',\n\t\t\t});\n\t\t}\n\t\treturn new NetworkOperationFailed({ op, network, stderr: err.stderr });\n\t};\n\nexport const wrapVolumeError =\n\t(op: 'create' | 'inspect' | 'remove', volume: string) =>\n\t(err: CaptureError): DockerRuntimeError => {\n\t\tconst d = checkDaemon(err);\n\t\tif (d) return d;\n\t\treturn new VolumeOperationFailed({ op, volume, stderr: err.stderr });\n\t};\n\n/** Generic wrapper for op surfaces (`docker logs`, `docker inspect`,\n * etc.) where the only distinct failure mode is daemon down. */\nexport const wrapGeneric =\n\t(op: string) =>\n\t(err: CaptureError): DockerRuntimeError =>\n\t\tcheckDaemon(err) ??\n\t\tnew DaemonUnreachable({\n\t\t\top,\n\t\t\tdetail: err.stderr || `${op} failed (exit ${err.exitCode ?? '?'})`,\n\t\t\tcause: err.cause,\n\t\t});\n\n// -----------------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------------\n\n/** STUB: extract a \"failing step\" line from build output. The\n * buildkit envelope shape is documented; classic builder shape is\n * `Step N/M : <directive>`. Returning `undefined` is fine — the raw\n * stderr is still in the BuildFailed envelope. */\nconst parseFailingBuildStep = (stdout: string, stderr: string): string | undefined => {\n\tconst combined = `${stderr}\\n${stdout}`;\n\tconst classic = combined.match(/Step (\\d+)\\/(\\d+)\\s*:\\s*([^\\n]+)/);\n\tif (classic) return `Step ${classic[1]}/${classic[2]} ${classic[3]}`;\n\tconst buildkit = combined.match(/#(\\d+)\\s+ERROR\\s*:\\s*([^\\n]+)/);\n\tif (buildkit) return `#${buildkit[1]} ${buildkit[2]}`;\n\treturn undefined;\n};\n\n/** Inspect a `CaptureResult`'s exit code; if non-zero return null\n * (caller decides what to do). Used by the lifecycle state machine\n * to classify stderr patterns WITHOUT promoting non-zero to failure\n * via `nonZeroIsFailure`. */\nexport const classifyExit = (\n\tres: CaptureResult,\n): { readonly ok: boolean; readonly exitCode: number; readonly stderr: string } => ({\n\tok: res.exitCode === 0,\n\texitCode: res.exitCode,\n\tstderr: res.stderr,\n});\n"],"mappings":"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"}
|
|
@@ -7,18 +7,15 @@ type Brand<T, B extends string> = T & {
|
|
|
7
7
|
type PluginKey = Brand<string, 'PluginKey'>;
|
|
8
8
|
/** Opaque endpoint key — `(pluginKey, dispatchId)` digest, branded. */
|
|
9
9
|
type EndpointKey = Brand<string, 'EndpointKey'>;
|
|
10
|
-
/** Content-hash brand. Substrate folds
|
|
10
|
+
/** Content-hash brand. Substrate folds the chain string into the final cache key. */
|
|
11
11
|
type ContentHash = Brand<string, 'ContentHash'>;
|
|
12
|
-
/** Chain identity brand (e.g. `sui:mainnet`, `sui:fork@<height>`). */
|
|
13
|
-
type ChainId = Brand<string, 'ChainId'>;
|
|
14
12
|
/** Stack identity triple components. Validated once at boot. */
|
|
15
13
|
type AppName = Brand<string, 'AppName'>;
|
|
16
14
|
type StackName = Brand<string, 'StackName'>;
|
|
17
15
|
declare const endpointKey: (s: string) => EndpointKey;
|
|
18
16
|
declare const contentHash: (s: string) => ContentHash;
|
|
19
|
-
declare const chainId: (s: string) => ChainId;
|
|
20
17
|
declare const appName: (s: string) => AppName;
|
|
21
18
|
declare const stackName: (s: string) => StackName;
|
|
22
19
|
//#endregion
|
|
23
|
-
export { AppName, Brand,
|
|
20
|
+
export { AppName, Brand, ContentHash, EndpointKey, PluginKey, StackName, appName, contentHash, endpointKey, stackName };
|
|
24
21
|
//# sourceMappingURL=brand.d.mts.map
|
package/dist/substrate/brand.mjs
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
const pluginKey = (s) => s;
|
|
6
6
|
const endpointKey = (s) => s;
|
|
7
7
|
const contentHash = (s) => s;
|
|
8
|
-
const
|
|
8
|
+
const nodeInputId = (s) => s;
|
|
9
|
+
const graphInputId = (s) => s;
|
|
9
10
|
const appName = (s) => s;
|
|
10
11
|
const stackName = (s) => s;
|
|
11
12
|
//#endregion
|
|
12
|
-
export { appName,
|
|
13
|
+
export { appName, contentHash, endpointKey, graphInputId, nodeInputId, pluginKey, stackName };
|
|
13
14
|
|
|
14
15
|
//# sourceMappingURL=brand.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brand.mjs","names":[],"sources":["../../src/substrate/brand.ts"],"sourcesContent":["// Branded primitives.\n//\n// One file owns the brand symbol so every primitive in this package\n// brands through the same shape. `Brand<T, B>` adds a unique-symbol\n// phantom so two strings with different brand tags are not\n// interchangeable.\n\ndeclare const _brand: unique symbol;\n\nexport type Brand<T, B extends string> = T & { readonly [_brand]: B };\n\n/** Opaque per-plugin-instance identity key. Substrate-blind. */\nexport type PluginKey = Brand<string, 'PluginKey'>;\n\n/** Opaque endpoint key — `(pluginKey, dispatchId)` digest, branded. */\nexport type EndpointKey = Brand<string, 'EndpointKey'>;\n\n/** Content-hash brand. Substrate folds
|
|
1
|
+
{"version":3,"file":"brand.mjs","names":[],"sources":["../../src/substrate/brand.ts"],"sourcesContent":["// Branded primitives.\n//\n// One file owns the brand symbol so every primitive in this package\n// brands through the same shape. `Brand<T, B>` adds a unique-symbol\n// phantom so two strings with different brand tags are not\n// interchangeable.\n\ndeclare const _brand: unique symbol;\n\nexport type Brand<T, B extends string> = T & { readonly [_brand]: B };\n\n/** Opaque per-plugin-instance identity key. Substrate-blind. */\nexport type PluginKey = Brand<string, 'PluginKey'>;\n\n/** Opaque endpoint key — `(pluginKey, dispatchId)` digest, branded. */\nexport type EndpointKey = Brand<string, 'EndpointKey'>;\n\n/** Content-hash brand. Substrate folds the chain string into the final cache key. */\nexport type ContentHash = Brand<string, 'ContentHash'>;\n\n/** Per-node input identity hash, computed from declared desired-state inputs. */\nexport type NodeInputId = Brand<string, 'NodeInputId'>;\n\n/** Aggregate graph input identity hash, computed from graph shape + node input ids. */\nexport type GraphInputId = Brand<string, 'GraphInputId'>;\n\n/** Stack identity triple components. Validated once at boot. */\nexport type AppName = Brand<string, 'AppName'>;\nexport type StackName = Brand<string, 'StackName'>;\n\n/** Constructor helpers. These are the boundary where unbranded strings\n * become branded; outside this file, callers should only see branded\n * values. */\nexport const pluginKey = (s: string): PluginKey => s as PluginKey;\nexport const endpointKey = (s: string): EndpointKey => s as EndpointKey;\nexport const contentHash = (s: string): ContentHash => s as ContentHash;\nexport const nodeInputId = (s: string): NodeInputId => s as NodeInputId;\nexport const graphInputId = (s: string): GraphInputId => s as GraphInputId;\nexport const appName = (s: string): AppName => s as AppName;\nexport const stackName = (s: string): StackName => s as StackName;\n"],"mappings":";;;;AAiCA,MAAa,aAAa,MAAyB;AACnD,MAAa,eAAe,MAA2B;AACvD,MAAa,eAAe,MAA2B;AACvD,MAAa,eAAe,MAA2B;AACvD,MAAa,gBAAgB,MAA4B;AACzD,MAAa,WAAW,MAAuB;AAC/C,MAAa,aAAa,MAAyB"}
|
|
@@ -12,23 +12,9 @@ const RosterHolderSchema = Schema.Struct({
|
|
|
12
12
|
const RosterDocumentSchema = versionedDocSchema(1, { holders: Schema.Array(RosterHolderSchema) });
|
|
13
13
|
const DEFAULT_SWEEP_POLICY = {
|
|
14
14
|
heartbeatIntervalMillis: 1e4,
|
|
15
|
-
staleAfterMillis: 3e4
|
|
16
|
-
trustForeignHosts: true
|
|
15
|
+
staleAfterMillis: 3e4
|
|
17
16
|
};
|
|
18
|
-
/** Versioned schema — routed through `versionedDocSchema` so a v2
|
|
19
|
-
* migration can add a literal-tagged `Schema.Union` at one call site
|
|
20
|
-
* rather than hand-rolling a discriminator. `creatorStartTime` mirrors
|
|
21
|
-
* `RosterHolderSchema.startTime` (`NullOr(Number)`): when the creator
|
|
22
|
-
* couldn't probe its own startTime, write null and the sweep's
|
|
23
|
-
* liveness check short-circuits to "alive" rather than evicting on a
|
|
24
|
-
* literal `0` mismatch. */
|
|
25
|
-
const SnapshotReservationSchema = versionedDocSchema(1, {
|
|
26
|
-
creatorPid: Schema.Number,
|
|
27
|
-
creatorStartTime: Schema.NullOr(Schema.Number),
|
|
28
|
-
createdAt: Schema.Number,
|
|
29
|
-
hostname: Schema.String
|
|
30
|
-
});
|
|
31
17
|
//#endregion
|
|
32
|
-
export { DEFAULT_SWEEP_POLICY, RosterDocumentSchema, RosterHolderSchema
|
|
18
|
+
export { DEFAULT_SWEEP_POLICY, RosterDocumentSchema, RosterHolderSchema };
|
|
33
19
|
|
|
34
20
|
//# sourceMappingURL=cross-process.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-process.mjs","names":[],"sources":["../../src/substrate/cross-process.ts"],"sourcesContent":["// Cross-process safety protocol.\n//\n// Architecture § Cross-process safety protocol. Core artifacts per\n// stack on disk under `<runtime-root>/stacks/<stack>/`:\n//\n// - `stack.lock` — OS-advisory exclusive lock; short critical\n// sections only.\n// - `roster.json` — authoritative cross-process record of holders;\n// mutated only under the lock.\n// - `commands.ndjson` / `events.ndjson` — filesystem command\n// channel between peer CLI commands and the live supervisor.\n//
|
|
1
|
+
{"version":3,"file":"cross-process.mjs","names":[],"sources":["../../src/substrate/cross-process.ts"],"sourcesContent":["// Cross-process safety protocol.\n//\n// Architecture § Cross-process safety protocol. Core artifacts per\n// stack on disk under `<runtime-root>/stacks/<stack>/`:\n//\n// - `stack.lock` — OS-advisory exclusive lock; short critical\n// sections only.\n// - `roster.json` — authoritative cross-process record of holders;\n// mutated only under the lock.\n// - `commands.ndjson` / `events.ndjson` — filesystem command\n// channel between peer CLI commands and the live supervisor.\n//\n// The snapshot bounce holds `stack.lock` for the (bounded, whole-stack-\n// stopped) snapshot window — there is no separate snapshot-reservation file\n// (the lock subsumes the concurrency guard).\n\nimport { Schema } from 'effect';\n\nimport { versionedDocSchema } from './versioned-doc-schema.ts';\n\n/** Holder intent — `normal` for ordinary peers; `snapshot` while\n * the holder is mid-capture (peers' commands defer). */\nexport type HolderIntent = 'normal' | 'snapshot';\n\n/** One holder entry in `roster.json`. PID + startTime distinguish live\n * processes from PID reuse.\n *\n * `startTime` is `number | null` — `null` means \"the platform could\n * not probe a start-time stamp for this process at write time\" (an\n * exotic platform, or `ps`/`tasklist` failed). Readers MUST treat\n * `null` as the conservative branch (see `isOwnEntry` in `roster.ts`\n * and `checkHolderLiveness` in `liveness.ts`): on a null recorded\n * stamp the start-time comparison is skipped and the (pid, hostname)\n * pair carries the identity. */\nexport interface RosterHolder {\n\treadonly pid: number;\n\t/** Process start-time, used for PID-reuse-safe liveness. `null`\n\t * means \"unprobable\" — see the interface doc above. */\n\treadonly startTime: number | null;\n\treadonly hostname: string;\n\treadonly claimedAt: number;\n\treadonly heartbeatAt: number;\n\treadonly intent: HolderIntent;\n}\n\n/** Roster document schema — versioned for schema validation. */\nexport interface RosterDocument {\n\treadonly version: 1;\n\treadonly holders: ReadonlyArray<RosterHolder>;\n}\n\nexport const RosterHolderSchema = Schema.Struct({\n\tpid: Schema.Number,\n\tstartTime: Schema.NullOr(Schema.Number),\n\thostname: Schema.String,\n\tclaimedAt: Schema.Number,\n\theartbeatAt: Schema.Number,\n\tintent: Schema.Literals(['normal', 'snapshot']),\n});\n\nexport const RosterDocumentSchema = versionedDocSchema(1, {\n\tholders: Schema.Array(RosterHolderSchema),\n});\n\n/** Sweep policy — peers older than `staleAfterMillis` AND failing\n * the PID liveness check are evicted on the next claim under the\n * exclusive lock. */\nexport interface RosterSweepPolicy {\n\treadonly heartbeatIntervalMillis: number;\n\treadonly staleAfterMillis: number;\n}\n\nexport const DEFAULT_SWEEP_POLICY: RosterSweepPolicy = {\n\theartbeatIntervalMillis: 10_000,\n\tstaleAfterMillis: 30_000,\n};\n"],"mappings":";;;AAmDA,MAAa,qBAAqB,OAAO,OAAO;CAC/C,KAAK,OAAO;CACZ,WAAW,OAAO,OAAO,OAAO,MAAM;CACtC,UAAU,OAAO;CACjB,WAAW,OAAO;CAClB,aAAa,OAAO;CACpB,QAAQ,OAAO,SAAS,CAAC,UAAU,UAAU,CAAC;AAC/C,CAAC;AAED,MAAa,uBAAuB,mBAAmB,GAAG,EACzD,SAAS,OAAO,MAAM,kBAAkB,EACzC,CAAC;AAUD,MAAa,uBAA0C;CACtD,yBAAyB;CACzB,kBAAkB;AACnB"}
|
|
@@ -16,8 +16,6 @@ const eventAtOrNull = (event) => {
|
|
|
16
16
|
case "restart.requested":
|
|
17
17
|
case "restart.completed":
|
|
18
18
|
case "shutdown.escalated":
|
|
19
|
-
case "snapshot.captureStarted":
|
|
20
|
-
case "snapshot.captureProgress":
|
|
21
19
|
case "snapshot.captureSkipped":
|
|
22
20
|
case "snapshot.captureFailed":
|
|
23
21
|
case "snapshot.captured":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-time.mjs","names":[],"sources":["../../src/substrate/event-time.ts"],"sourcesContent":["// Producer-time projection for `EngineEvent`.\n//\n// Every event variant carries an authoritative timestamp either at the\n// top level (`event.at`) or in a domain-specific nested field\n// (`endpoint.registered.endpoint.registeredAt`, `error.reported.error.at`,\n// `build.statusChanged.entry.startedAt`). The switch is intentionally\n// exhaustive so a newly-added variant must declare where its timestamp\n// lives — the compiler enforces it via the `never`-assignment default.\n//\n// Two shapes:\n// - `eventAtOrNull` (substrate-layer consumers): returns `null` when\n// the variant has no inherent timestamp, letting the caller fall\n// back to whatever stale value preserves invariants (e.g. the\n// projection update reducer keeps `state.lastEvent.at` on miss).\n// - `eventAt` (UI consumers): wraps `eventAtOrNull` with a `Date.now()`\n// fallback so log rendering always gets a number.
|
|
1
|
+
{"version":3,"file":"event-time.mjs","names":[],"sources":["../../src/substrate/event-time.ts"],"sourcesContent":["// Producer-time projection for `EngineEvent`.\n//\n// Every event variant carries an authoritative timestamp either at the\n// top level (`event.at`) or in a domain-specific nested field\n// (`endpoint.registered.endpoint.registeredAt`, `error.reported.error.at`,\n// `build.statusChanged.entry.startedAt`). The switch is intentionally\n// exhaustive so a newly-added variant must declare where its timestamp\n// lives — the compiler enforces it via the `never`-assignment default.\n//\n// Two shapes:\n// - `eventAtOrNull` (substrate-layer consumers): returns `null` when\n// the variant has no inherent timestamp, letting the caller fall\n// back to whatever stale value preserves invariants (e.g. the\n// projection update reducer keeps `state.lastEvent.at` on miss).\n// - `eventAt` (UI consumers): wraps `eventAtOrNull` with a `Date.now()`\n// fallback so log rendering always gets a number. It pins to the\n// producer's record rather than a dequeue-time stamp: under back-\n// pressure (a queued event flushed late from the dispatcher) a\n// dequeue-time stamp would back-date or forward-date the log entry,\n// producing apparent event-time reordering in the rendered log.\n// Pinning to the producer's record preserves the ordering tests\n// assert.\n\nimport type { EngineEvent } from './events.ts';\n\nexport const eventAtOrNull = (event: EngineEvent): number | null => {\n\tswitch (event.tag) {\n\t\tcase 'endpoint.registered':\n\t\t\treturn event.endpoint.registeredAt;\n\t\tcase 'error.reported':\n\t\t\treturn event.error.at;\n\t\tcase 'build.statusChanged':\n\t\t\treturn event.entry.startedAt;\n\t\tcase 'lifecycle.statusChanged':\n\t\tcase 'lifecycle.phaseSet':\n\t\tcase 'log.appended':\n\t\tcase 'projection.updated':\n\t\tcase 'endpoint.released':\n\t\tcase 'strategy.registered':\n\t\tcase 'strategy.unregistered':\n\t\tcase 'manifest.flushed':\n\t\tcase 'codegen.emitted':\n\t\tcase 'restart.requested':\n\t\tcase 'restart.completed':\n\t\tcase 'shutdown.escalated':\n\t\tcase 'snapshot.captureSkipped':\n\t\tcase 'snapshot.captureFailed':\n\t\tcase 'snapshot.captured':\n\t\tcase 'snapshot.restored':\n\t\tcase 'engine.orchestrator.dispatchFailed':\n\t\t\treturn event.at;\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = event;\n\t\t\tvoid _exhaustive;\n\t\t\treturn null;\n\t\t}\n\t}\n};\n\nexport const eventAt = (event: EngineEvent): number => eventAtOrNull(event) ?? Date.now();\n"],"mappings":";AAyBA,MAAa,iBAAiB,UAAsC;CACnE,QAAQ,MAAM,KAAd;EACC,KAAK,uBACJ,OAAO,MAAM,SAAS;EACvB,KAAK,kBACJ,OAAO,MAAM,MAAM;EACpB,KAAK,uBACJ,OAAO,MAAM,MAAM;EACpB,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,sCACJ,OAAO,MAAM;EACd,SAGC,OAAO;CAET;AACD;AAEA,MAAa,WAAW,UAA+B,cAAc,KAAK,KAAK,KAAK,IAAI"}
|
|
@@ -4,7 +4,6 @@ import { BuildEntry, Endpoint, StructuredError } from "./projection.mjs";
|
|
|
4
4
|
|
|
5
5
|
//#region src/substrate/events.d.ts
|
|
6
6
|
type ShutdownSignal = 'SIGINT' | 'SIGTERM';
|
|
7
|
-
type SnapshotCaptureProgressPhase = 'quiescing' | 'pausing' | 'paused' | 'capturing-containers' | 'saving-images' | 'capturing-host-tree' | 'saving-state' | 'saving-contributions' | 'writing-metadata' | 'resuming';
|
|
8
7
|
/** Typed lifecycle event stream. Architecture-enumerated categories. */
|
|
9
8
|
type EngineEvent = {
|
|
10
9
|
readonly tag: 'lifecycle.statusChanged';
|
|
@@ -82,20 +81,6 @@ type EngineEvent = {
|
|
|
82
81
|
readonly signal: ShutdownSignal;
|
|
83
82
|
readonly exitCode: number;
|
|
84
83
|
readonly at: number;
|
|
85
|
-
} | {
|
|
86
|
-
readonly tag: 'snapshot.captureStarted';
|
|
87
|
-
readonly snapshotId?: string;
|
|
88
|
-
readonly name?: string;
|
|
89
|
-
readonly at: number;
|
|
90
|
-
} | {
|
|
91
|
-
readonly tag: 'snapshot.captureProgress';
|
|
92
|
-
readonly snapshotId?: string;
|
|
93
|
-
readonly name?: string;
|
|
94
|
-
readonly phase: SnapshotCaptureProgressPhase;
|
|
95
|
-
readonly detail?: string;
|
|
96
|
-
readonly pausedContainers?: number;
|
|
97
|
-
readonly totalContainers?: number;
|
|
98
|
-
readonly at: number;
|
|
99
84
|
} | {
|
|
100
85
|
readonly tag: 'snapshot.captureSkipped';
|
|
101
86
|
readonly reason: 'already-running';
|
|
@@ -132,6 +117,51 @@ type EngineEvent = {
|
|
|
132
117
|
readonly causeType?: string;
|
|
133
118
|
readonly at: number;
|
|
134
119
|
};
|
|
120
|
+
/** Typed command channel. Surfaces publish; the engine consumes.
|
|
121
|
+
* Same shape regardless of producer (CLI argv / TUI keypress /
|
|
122
|
+
* programmable API). */
|
|
123
|
+
type EngineCommand = {
|
|
124
|
+
readonly tag: 'stack.start';
|
|
125
|
+
} | {
|
|
126
|
+
readonly tag: 'stack.stop';
|
|
127
|
+
} | {
|
|
128
|
+
readonly tag: 'stack.restart';
|
|
129
|
+
} | {
|
|
130
|
+
readonly tag: 'apply.requested';
|
|
131
|
+
readonly pluginKey?: PluginKey;
|
|
132
|
+
} | {
|
|
133
|
+
readonly tag: 'codegen.requested';
|
|
134
|
+
} | {
|
|
135
|
+
readonly tag: 'snapshot.capture';
|
|
136
|
+
readonly snapshotId?: string;
|
|
137
|
+
readonly name?: string;
|
|
138
|
+
readonly replaceExisting?: boolean;
|
|
139
|
+
} | {
|
|
140
|
+
readonly tag: 'snapshot.restore';
|
|
141
|
+
readonly snapshotId: string;
|
|
142
|
+
} | {
|
|
143
|
+
readonly tag: 'snapshot.list';
|
|
144
|
+
} | {
|
|
145
|
+
readonly tag: 'snapshot.delete';
|
|
146
|
+
readonly snapshotId: string;
|
|
147
|
+
} | {
|
|
148
|
+
readonly tag: 'wipe.requested';
|
|
149
|
+
} | {
|
|
150
|
+
readonly tag: 'prune.requested';
|
|
151
|
+
} | {
|
|
152
|
+
readonly tag: 'advance-clock.requested';
|
|
153
|
+
readonly toMillis: number;
|
|
154
|
+
} | {
|
|
155
|
+
readonly tag: 'shutdown.requested';
|
|
156
|
+
} | {
|
|
157
|
+
readonly tag: 'shutdown.hardKillRequested';
|
|
158
|
+
readonly signal: ShutdownSignal;
|
|
159
|
+
readonly exitCode: number;
|
|
160
|
+
readonly at: number;
|
|
161
|
+
} | {
|
|
162
|
+
readonly tag: 'selective-restart.requested';
|
|
163
|
+
readonly pluginKey: PluginKey;
|
|
164
|
+
};
|
|
135
165
|
//#endregion
|
|
136
|
-
export { EngineEvent };
|
|
166
|
+
export { EngineCommand, EngineEvent };
|
|
137
167
|
//# sourceMappingURL=events.d.mts.map
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { AppName,
|
|
1
|
+
import { AppName, StackName } from "./brand.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/substrate/identity.d.ts
|
|
4
|
-
/** Closed identity
|
|
4
|
+
/** Closed identity tuple. Architecture § Stack data model. The substrate
|
|
5
|
+
* is name-blind: it knows nothing about networks or modes. */
|
|
5
6
|
interface Identity {
|
|
6
7
|
readonly app: AppName;
|
|
7
8
|
readonly stack: StackName;
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
|
|
9
|
+
/** Opaque identity label — a substrate-blind plain string the caller
|
|
10
|
+
* supplies once at boot, threaded through Context as a generic
|
|
11
|
+
* correlation/display label (supervisor labels, span attributes,
|
|
12
|
+
* snapshot provenance meta). The substrate NEVER parses it or branches
|
|
13
|
+
* on its value; it carries no network/mode semantics here. Callers
|
|
14
|
+
* (CLI / `runStack`) happen to set it to a resolved network name, but
|
|
15
|
+
* that is a producer concern, not a substrate primitive. */
|
|
16
|
+
readonly network: string;
|
|
11
17
|
}
|
|
12
18
|
//#endregion
|
|
13
19
|
export { Identity };
|