@astrale-os/cli 1.0.0-beta.32 → 1.0.0-beta.43
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/CHANGELOG.md +928 -0
- package/README.md +53 -43
- package/THIRD-PARTY-NOTICES.md +37 -1
- package/dist/astrale.js +349631 -83669
- package/dist/public/connect-core.js +16 -47
- package/dist/public/keys/index.js +1 -1
- package/dist/types/admin/contract.d.ts +11 -0
- package/dist/types/admin/graph/index.d.ts +1 -0
- package/dist/types/admin/graph/nodes.d.ts +12 -0
- package/dist/types/admin/instance/client.d.ts +2 -0
- package/dist/types/connection/lifetime.d.ts +1 -1
- package/dist/types/errors.d.ts +3 -0
- package/dist/types/lib/proc.d.ts +1 -0
- package/dist/types/lib/update.d.ts +15 -7
- package/package.json +8 -6
- package/studio/client/dist/assets/index-5C1uT6ML.css +2 -0
- package/studio/client/dist/assets/index-C4kNlvwF.js +80 -0
- package/studio/client/dist/assets/schema-studio-BR9d0faB.js +8 -0
- package/studio/client/dist/index.html +13 -2
- package/studio/package.json +2 -1
- package/studio/server/agent/ask.test.ts +7 -1
- package/studio/server/agent/bridge/grant.ts +15 -3
- package/studio/server/agent/prompts/system.test.ts +5 -0
- package/studio/server/agent/prompts/system.ts +19 -4
- package/studio/server/agent/routes.test.ts +39 -1
- package/studio/server/agent/routes.ts +3 -0
- package/studio/server/agent/run/coordinator.test.ts +7 -1
- package/studio/server/agent/run/preparation.ts +1 -0
- package/studio/server/agent/run/transcript.test.ts +47 -2
- package/studio/server/agent/run/transcript.ts +32 -3
- package/studio/server/api/documents.test.ts +31 -0
- package/studio/server/api/documents.ts +35 -1
- package/studio/server/api-agent-loadout.test.ts +7 -1
- package/studio/server/api.test.ts +7 -1
- package/studio/server/cache.ts +4 -4
- package/studio/server/detect.ts +9 -12
- package/studio/server/domain.test.ts +83 -3
- package/studio/server/domain.ts +205 -27
- package/studio/server/handoff/service.ts +1 -1
- package/studio/server/index.ts +5 -8
- package/studio/server/introspect/extractor.ts +111 -17
- package/studio/server/introspect/overlay-tsmorph.test.ts +9 -9
- package/studio/server/introspect/overlay.ts +1 -1
- package/studio/server/introspect/runtime.ts +9 -1
- package/studio/server/introspect/source-overlay/spans.ts +2 -5
- package/studio/server/lifecycle.ts +1 -1
- package/studio/server/state/baseline.test.ts +14 -0
- package/studio/server/state/baseline.ts +16 -2
- package/studio/server/watch.test.ts +2 -1
- package/studio/server/watch.ts +5 -2
- package/studio/server/workspace/create.ts +9 -8
- package/studio/server/workspace-state.ts +4 -6
- package/studio/server/workspace-watch.ts +33 -22
- package/studio/shared/contracts/agent.ts +3 -0
- package/viewer/dist/main.js +12 -12
- package/src/__tests__/fixtures/publication.ts +0 -20
- package/src/admin/.spec/api.d.ts +0 -3
- package/src/admin/.spec/architecture.md +0 -22
- package/src/admin/.spec/icon.svg +0 -3
- package/src/admin/.spec/layout.ts +0 -6
- package/src/admin/__tests__/fixture.ts +0 -25
- package/src/admin/catalog/.spec/api.d.ts +0 -63
- package/src/admin/catalog/.spec/architecture.md +0 -7
- package/src/admin/catalog/.spec/icon.svg +0 -3
- package/src/admin/catalog/.spec/layout.ts +0 -6
- package/src/admin/catalog/__tests__/client.test.ts +0 -245
- package/src/admin/catalog/client.ts +0 -195
- package/src/admin/catalog/index.ts +0 -13
- package/src/admin/catalog/model.ts +0 -41
- package/src/admin/catalog/tsconfig.json +0 -8
- package/src/admin/contract.ts +0 -47
- package/src/admin/graph/.spec/api.d.ts +0 -22
- package/src/admin/graph/.spec/architecture.md +0 -5
- package/src/admin/graph/.spec/icon.svg +0 -3
- package/src/admin/graph/.spec/layout.ts +0 -3
- package/src/admin/graph/index.ts +0 -6
- package/src/admin/graph/nodes.ts +0 -56
- package/src/admin/index.ts +0 -2
- package/src/admin/instance/.spec/api.d.ts +0 -62
- package/src/admin/instance/.spec/architecture.md +0 -10
- package/src/admin/instance/.spec/icon.svg +0 -3
- package/src/admin/instance/.spec/layout.ts +0 -6
- package/src/admin/instance/__tests__/client.test.ts +0 -273
- package/src/admin/instance/client.ts +0 -191
- package/src/admin/instance/index.ts +0 -15
- package/src/admin/instance/model.ts +0 -59
- package/src/admin/instance/tsconfig.json +0 -8
- package/src/commands/__tests__/admin-instance.test.ts +0 -91
- package/src/commands/__tests__/auth-login.test.ts +0 -231
- package/src/commands/__tests__/auth-token.test.ts +0 -223
- package/src/commands/__tests__/call-describe.test.ts +0 -80
- package/src/commands/__tests__/call.test.ts +0 -63
- package/src/commands/__tests__/domain-install-operation.test.ts +0 -145
- package/src/commands/__tests__/domain-install-owned.test.ts +0 -191
- package/src/commands/__tests__/domain-list.test.ts +0 -133
- package/src/commands/__tests__/domain-uninstall.test.ts +0 -53
- package/src/commands/__tests__/install-direct.test.ts +0 -128
- package/src/commands/__tests__/install-identity-override.test.ts +0 -76
- package/src/commands/__tests__/instance-bookmark.test.ts +0 -166
- package/src/commands/__tests__/instance-list-admin.test.ts +0 -26
- package/src/commands/__tests__/instance-list-rows.test.ts +0 -64
- package/src/commands/__tests__/instance-status.test.ts +0 -139
- package/src/commands/__tests__/instance-use.test.ts +0 -67
- package/src/commands/__tests__/introspect-parse.test.ts +0 -100
- package/src/commands/__tests__/logs.test.ts +0 -345
- package/src/commands/__tests__/read-commands.test.ts +0 -377
- package/src/commands/__tests__/setup-plan.test.ts +0 -61
- package/src/commands/__tests__/studio-descriptor.test.ts +0 -22
- package/src/commands/__tests__/token-ttl.test.ts +0 -66
- package/src/commands/__tests__/update.test.ts +0 -95
- package/src/commands/__tests__/view-build.test.ts +0 -58
- package/src/commands/__tests__/view.test.ts +0 -197
- package/src/commands/admin/status.ts +0 -61
- package/src/commands/admin/use.ts +0 -100
- package/src/commands/auth/login.ts +0 -82
- package/src/commands/auth/logout.ts +0 -53
- package/src/commands/auth/status.ts +0 -86
- package/src/commands/auth/token.ts +0 -174
- package/src/commands/browser.ts +0 -236
- package/src/commands/call-describe.ts +0 -123
- package/src/commands/call.ts +0 -230
- package/src/commands/domain/install.ts +0 -575
- package/src/commands/domain/list.ts +0 -155
- package/src/commands/domain/publish.ts +0 -136
- package/src/commands/domain/uninstall.ts +0 -128
- package/src/commands/get.ts +0 -69
- package/src/commands/identity/__tests__/register.test.ts +0 -93
- package/src/commands/identity/create.ts +0 -35
- package/src/commands/identity/delete.ts +0 -24
- package/src/commands/identity/export.ts +0 -46
- package/src/commands/identity/import.ts +0 -61
- package/src/commands/identity/list.ts +0 -56
- package/src/commands/identity/register.ts +0 -195
- package/src/commands/identity/sync.ts +0 -38
- package/src/commands/identity/unsync.ts +0 -34
- package/src/commands/identity/use.ts +0 -24
- package/src/commands/identity/whoami.ts +0 -34
- package/src/commands/idp/add.ts +0 -150
- package/src/commands/idp/list.ts +0 -57
- package/src/commands/idp/refresh.ts +0 -38
- package/src/commands/idp/remove.ts +0 -36
- package/src/commands/idp/show.ts +0 -29
- package/src/commands/instance/active.ts +0 -73
- package/src/commands/instance/bookmark.ts +0 -101
- package/src/commands/instance/create.ts +0 -61
- package/src/commands/instance/delete.ts +0 -69
- package/src/commands/instance/forget.ts +0 -26
- package/src/commands/instance/list.ts +0 -197
- package/src/commands/instance/status.ts +0 -92
- package/src/commands/instance/use.ts +0 -263
- package/src/commands/introspect.ts +0 -129
- package/src/commands/logs.ts +0 -371
- package/src/commands/mutate.ts +0 -122
- package/src/commands/query.ts +0 -142
- package/src/commands/session/analyze.ts +0 -72
- package/src/commands/session/list.ts +0 -36
- package/src/commands/setup.ts +0 -54
- package/src/commands/status.ts +0 -60
- package/src/commands/studio.ts +0 -434
- package/src/commands/token.ts +0 -121
- package/src/commands/ui/__tests__/commands.test.ts +0 -152
- package/src/commands/ui/add.ts +0 -51
- package/src/commands/ui/doctor.ts +0 -21
- package/src/commands/ui/init.ts +0 -38
- package/src/commands/ui/list.ts +0 -26
- package/src/commands/ui/preset-apply.ts +0 -19
- package/src/commands/ui/preset-list.ts +0 -12
- package/src/commands/ui/shared.ts +0 -25
- package/src/commands/update.ts +0 -356
- package/src/commands/use.ts +0 -86
- package/src/commands/view-serve.ts +0 -26
- package/src/commands/view.ts +0 -658
- package/src/connect-core.test.ts +0 -38
- package/src/connect-core.ts +0 -42
- package/src/connection/.spec/api.d.ts +0 -110
- package/src/connection/.spec/architecture.md +0 -58
- package/src/connection/.spec/capabilities/connection.ts +0 -13
- package/src/connection/.spec/examples/call.ts +0 -7
- package/src/connection/.spec/flows/command.ts +0 -20
- package/src/connection/.spec/flows/session.ts +0 -62
- package/src/connection/.spec/laws/connection.ts +0 -213
- package/src/connection/.spec/layout.ts +0 -22
- package/src/connection/__tests__/auth.test.ts +0 -129
- package/src/connection/__tests__/ca-fetch.test.ts +0 -60
- package/src/connection/__tests__/call.test.ts +0 -17
- package/src/connection/__tests__/credential.test.ts +0 -254
- package/src/connection/__tests__/errors.test.ts +0 -577
- package/src/connection/__tests__/exchange.test.ts +0 -404
- package/src/connection/__tests__/failure-fixtures.ts +0 -39
- package/src/connection/__tests__/failure-safety.test.ts +0 -75
- package/src/connection/__tests__/fixtures/localhost-cert.pem +0 -19
- package/src/connection/__tests__/fixtures/localhost-key.base64 +0 -1
- package/src/connection/__tests__/managed.test.ts +0 -39
- package/src/connection/__tests__/reasons.test.ts +0 -78
- package/src/connection/__tests__/self.test.ts +0 -71
- package/src/connection/__tests__/session.test.ts +0 -144
- package/src/connection/__tests__/target.test.ts +0 -95
- package/src/connection/auth.ts +0 -265
- package/src/connection/call.ts +0 -7
- package/src/connection/command.ts +0 -67
- package/src/connection/credential.ts +0 -138
- package/src/connection/errors.ts +0 -1
- package/src/connection/exchange.ts +0 -394
- package/src/connection/failure/classify.ts +0 -110
- package/src/connection/failure/index.ts +0 -18
- package/src/connection/failure/model.ts +0 -28
- package/src/connection/failure/render.ts +0 -116
- package/src/connection/index.ts +0 -8
- package/src/connection/lifetime.ts +0 -25
- package/src/connection/reasons.ts +0 -209
- package/src/connection/self.ts +0 -138
- package/src/connection/session.ts +0 -203
- package/src/connection/target.ts +0 -112
- package/src/connection/tsconfig.json +0 -6
- package/src/errors.ts +0 -66
- package/src/graph/.spec/api.d.ts +0 -41
- package/src/graph/.spec/laws/documents.ts +0 -24
- package/src/graph/.spec/laws/projection.ts +0 -13
- package/src/graph/.spec/layout.ts +0 -14
- package/src/graph/__tests__/mutation.test.ts +0 -51
- package/src/graph/__tests__/projection.test.ts +0 -22
- package/src/graph/__tests__/query.test.ts +0 -180
- package/src/graph/class.ts +0 -30
- package/src/graph/index.ts +0 -4
- package/src/graph/mutation.ts +0 -46
- package/src/graph/projection.ts +0 -21
- package/src/graph/query.ts +0 -95
- package/src/graph/tsconfig.json +0 -6
- package/src/identity/.history/ard/bootstrap-root-transfer.md +0 -57
- package/src/identity/.history/ard/domain-mediated-registration.md +0 -36
- package/src/identity/.spec/api.d.ts +0 -124
- package/src/identity/.spec/architecture.md +0 -33
- package/src/identity/.spec/capabilities/identity.ts +0 -7
- package/src/identity/.spec/flows/bootstrap-root.ts +0 -79
- package/src/identity/.spec/flows/domain-mediated-registration.ts +0 -51
- package/src/identity/.spec/flows/import.ts +0 -29
- package/src/identity/.spec/laws/identity.ts +0 -56
- package/src/identity/.spec/layout.ts +0 -13
- package/src/identity/__tests__/fixtures/registry-journey.ts +0 -65
- package/src/identity/__tests__/registration.test.ts +0 -64
- package/src/identity/__tests__/registry.test.ts +0 -74
- package/src/identity/__tests__/transfer.test.ts +0 -198
- package/src/identity/index.ts +0 -23
- package/src/identity/registration.ts +0 -72
- package/src/identity/registry.ts +0 -181
- package/src/identity/transfer.ts +0 -187
- package/src/identity/tsconfig.json +0 -6
- package/src/index.ts +0 -1
- package/src/keys/.spec/api.d.ts +0 -74
- package/src/keys/.spec/architecture.md +0 -13
- package/src/keys/.spec/laws/keys.ts +0 -43
- package/src/keys/.spec/layout.ts +0 -6
- package/src/keys/__tests__/algorithm.test.ts +0 -39
- package/src/keys/__tests__/keys.test.ts +0 -172
- package/src/keys/algorithm.ts +0 -33
- package/src/keys/credential.ts +0 -113
- package/src/keys/index.ts +0 -14
- package/src/keys/pair.ts +0 -219
- package/src/keys/tsconfig.json +0 -6
- package/src/lib/__tests__/admin-target.test.ts +0 -184
- package/src/lib/__tests__/binary.test.ts +0 -70
- package/src/lib/__tests__/browser-retention.test.ts +0 -212
- package/src/lib/__tests__/command-dx.test.ts +0 -102
- package/src/lib/__tests__/concurrency.test.ts +0 -62
- package/src/lib/__tests__/config.test.ts +0 -81
- package/src/lib/__tests__/design.test.ts +0 -99
- package/src/lib/__tests__/domain-publication.test.ts +0 -138
- package/src/lib/__tests__/format.test.ts +0 -22
- package/src/lib/__tests__/idp-session.driver.ts +0 -60
- package/src/lib/__tests__/idp-session.test.ts +0 -404
- package/src/lib/__tests__/idp.test.ts +0 -415
- package/src/lib/__tests__/instance-candidates.test.ts +0 -146
- package/src/lib/__tests__/instance-target.test.ts +0 -213
- package/src/lib/__tests__/instance.test.ts +0 -192
- package/src/lib/__tests__/local-status.test.ts +0 -202
- package/src/lib/__tests__/log-errors.test.ts +0 -64
- package/src/lib/__tests__/log.test.ts +0 -31
- package/src/lib/__tests__/meta.test.ts +0 -55
- package/src/lib/__tests__/output.test.ts +0 -162
- package/src/lib/__tests__/panel.test.ts +0 -40
- package/src/lib/__tests__/port.test.ts +0 -44
- package/src/lib/__tests__/prompt.test.ts +0 -25
- package/src/lib/__tests__/sdk-deps.test.ts +0 -68
- package/src/lib/__tests__/self.test.ts +0 -50
- package/src/lib/__tests__/skills.test.ts +0 -834
- package/src/lib/__tests__/studio-server-deps.test.ts +0 -111
- package/src/lib/__tests__/table.test.ts +0 -53
- package/src/lib/__tests__/update.test.ts +0 -511
- package/src/lib/__tests__/use-target.test.ts +0 -56
- package/src/lib/__tests__/validation.test.ts +0 -34
- package/src/lib/__tests__/view-assets.test.ts +0 -171
- package/src/lib/__tests__/view-external-open-intent.test.ts +0 -150
- package/src/lib/__tests__/view-external-open-origins.test.ts +0 -27
- package/src/lib/__tests__/view-open-intent.test.ts +0 -280
- package/src/lib/__tests__/view-port-allocation.test.ts +0 -82
- package/src/lib/__tests__/view-server.test.ts +0 -91
- package/src/lib/__tests__/view-session.test.ts +0 -100
- package/src/lib/__tests__/view-snapshot.test.ts +0 -77
- package/src/lib/admin-domain.ts +0 -43
- package/src/lib/admin-instance.ts +0 -56
- package/src/lib/admin-target.ts +0 -290
- package/src/lib/binary.ts +0 -127
- package/src/lib/browser-retention.ts +0 -210
- package/src/lib/browser.ts +0 -150
- package/src/lib/ca-fetch.ts +0 -133
- package/src/lib/command-dx.ts +0 -191
- package/src/lib/concurrency.ts +0 -31
- package/src/lib/config.ts +0 -57
- package/src/lib/credential-lifetime.ts +0 -24
- package/src/lib/domain-publication.ts +0 -104
- package/src/lib/failure-debug.ts +0 -26
- package/src/lib/format.ts +0 -4
- package/src/lib/idp-session.ts +0 -156
- package/src/lib/idp.ts +0 -926
- package/src/lib/instance-candidates.ts +0 -49
- package/src/lib/instance-target.ts +0 -197
- package/src/lib/instance.ts +0 -468
- package/src/lib/invocation.ts +0 -11
- package/src/lib/local-status.ts +0 -152
- package/src/lib/log.ts +0 -143
- package/src/lib/login-flow.ts +0 -201
- package/src/lib/meta.ts +0 -90
- package/src/lib/output.ts +0 -238
- package/src/lib/panel.ts +0 -61
- package/src/lib/port.ts +0 -41
- package/src/lib/proc.ts +0 -87
- package/src/lib/prompt.ts +0 -136
- package/src/lib/provision-instance.ts +0 -139
- package/src/lib/sdk-deps.ts +0 -104
- package/src/lib/self.ts +0 -22
- package/src/lib/skills/lock.ts +0 -117
- package/src/lib/skills/sync.ts +0 -878
- package/src/lib/skills.ts +0 -120
- package/src/lib/table.ts +0 -62
- package/src/lib/update.ts +0 -568
- package/src/lib/use-target.ts +0 -24
- package/src/lib/validation.ts +0 -59
- package/src/lib/view/assets.ts +0 -87
- package/src/lib/view/external-open-intent.ts +0 -41
- package/src/lib/view/external-open-origins.ts +0 -37
- package/src/lib/view/host-capabilities.ts +0 -17
- package/src/lib/view/open-intent.ts +0 -67
- package/src/lib/view/port-allocation.ts +0 -19
- package/src/lib/view/resolve.ts +0 -111
- package/src/lib/view/server.ts +0 -259
- package/src/lib/view/session.ts +0 -154
- package/src/lib/view/snapshot.ts +0 -101
- package/src/paths/.spec/api.d.ts +0 -13
- package/src/paths/.spec/architecture.md +0 -5
- package/src/paths/.spec/layout.ts +0 -3
- package/src/paths/index.ts +0 -13
- package/src/program/.spec/api.d.ts +0 -43
- package/src/program/.spec/architecture.md +0 -18
- package/src/program/.spec/laws/program.ts +0 -29
- package/src/program/.spec/layout.ts +0 -14
- package/src/program/__tests__/program.test.ts +0 -556
- package/src/program/argv.ts +0 -14
- package/src/program/build.ts +0 -205
- package/src/program/command.ts +0 -43
- package/src/program/index.ts +0 -3
- package/src/program/options.ts +0 -41
- package/src/program/registry.ts +0 -64
- package/src/program/tsconfig.json +0 -6
- package/src/setup/__tests__/instance-step.test.ts +0 -256
- package/src/setup/__tests__/util.test.ts +0 -29
- package/src/setup/engine.ts +0 -83
- package/src/setup/render.ts +0 -107
- package/src/setup/steps/admin.ts +0 -93
- package/src/setup/steps/agent-browser.ts +0 -81
- package/src/setup/steps/auth.ts +0 -54
- package/src/setup/steps/domain.ts +0 -68
- package/src/setup/steps/index.ts +0 -18
- package/src/setup/steps/instance.ts +0 -206
- package/src/setup/steps/skills-bridge.ts +0 -70
- package/src/setup/steps/skills.ts +0 -61
- package/src/setup/types.ts +0 -61
- package/src/setup/util.ts +0 -34
- package/src/state/.spec/api.d.ts +0 -152
- package/src/state/.spec/architecture.md +0 -45
- package/src/state/.spec/capabilities/state.ts +0 -7
- package/src/state/.spec/flows/identity-update.ts +0 -22
- package/src/state/.spec/laws/state.ts +0 -73
- package/src/state/.spec/layout.ts +0 -15
- package/src/state/__tests__/exchange-credentials.test.ts +0 -341
- package/src/state/__tests__/files.test.ts +0 -136
- package/src/state/__tests__/fixtures/identity-transition.ts +0 -37
- package/src/state/__tests__/fixtures/session-route-process.ts +0 -93
- package/src/state/__tests__/identities.test.ts +0 -142
- package/src/state/__tests__/paths.test.ts +0 -28
- package/src/state/__tests__/session-routes.test.ts +0 -138
- package/src/state/exchange-credentials.ts +0 -250
- package/src/state/files.ts +0 -170
- package/src/state/identities.ts +0 -229
- package/src/state/index.ts +0 -31
- package/src/state/paths.ts +0 -64
- package/src/state/session-routes.ts +0 -34
- package/src/state/tsconfig.json +0 -6
- package/src/telemetry/__tests__/analyze-log.test.ts +0 -38
- package/src/telemetry/__tests__/gate.test.ts +0 -63
- package/src/telemetry/__tests__/recorder.test.ts +0 -111
- package/src/telemetry/__tests__/redact.test.ts +0 -79
- package/src/telemetry/__tests__/retention.test.ts +0 -267
- package/src/telemetry/__tests__/session.test.ts +0 -166
- package/src/telemetry/__tests__/settings.test.ts +0 -102
- package/src/telemetry/__tests__/store-scan.test.ts +0 -128
- package/src/telemetry/__tests__/trigger.test.ts +0 -78
- package/src/telemetry/adapters/__tests__/claude-code.test.ts +0 -89
- package/src/telemetry/adapters/__tests__/codex.test.ts +0 -138
- package/src/telemetry/adapters/__tests__/index.test.ts +0 -88
- package/src/telemetry/adapters/claude-code.ts +0 -90
- package/src/telemetry/adapters/codex.ts +0 -160
- package/src/telemetry/adapters/index.ts +0 -45
- package/src/telemetry/adapters/types.ts +0 -21
- package/src/telemetry/analyze.ts +0 -249
- package/src/telemetry/gate.ts +0 -79
- package/src/telemetry/recorder.ts +0 -68
- package/src/telemetry/redact.ts +0 -53
- package/src/telemetry/retention.ts +0 -176
- package/src/telemetry/session.ts +0 -94
- package/src/telemetry/settings.ts +0 -79
- package/src/telemetry/store.ts +0 -174
- package/src/telemetry/trigger.ts +0 -107
- package/src/telemetry/types.ts +0 -64
- package/src/test-utils.ts +0 -18
- package/src/ui/.spec/api.d.ts +0 -14
- package/src/ui/.spec/architecture.md +0 -14
- package/src/ui/.spec/laws.ts +0 -50
- package/src/ui/.spec/layout.ts +0 -16
- package/src/ui/__tests__/ui.test.ts +0 -1742
- package/src/ui/index.ts +0 -13
- package/src/ui/lock.ts +0 -89
- package/src/ui/model.ts +0 -83
- package/src/ui/operations.ts +0 -1044
- package/src/ui/project.ts +0 -333
- package/src/ui/release.ts +0 -398
- package/src/ui/runner.ts +0 -18
- package/studio/client/dist/assets/index-BFVFs_8x.js +0 -81
- package/studio/client/dist/assets/index-DuB9iUdu.css +0 -2
- package/studio/client/dist/assets/schema-studio-DH6oEWME.js +0 -8
- package/studio/tsconfig.json +0 -24
- package/viewer/tsconfig.json +0 -13
|
@@ -1,575 +0,0 @@
|
|
|
1
|
-
import type { InstallRequest, InstallResult, OperationId } from '@astrale-os/sdk/client/schema'
|
|
2
|
-
|
|
3
|
-
import chalk from 'chalk'
|
|
4
|
-
|
|
5
|
-
import type { KernelCommandOpts } from '../../connection'
|
|
6
|
-
import type { CommandDefinition } from '../../program/index'
|
|
7
|
-
|
|
8
|
-
import { runKernelCommand, withAdminClientSession } from '../../connection'
|
|
9
|
-
import { formatKernelError } from '../../connection/errors'
|
|
10
|
-
import { AstraleError } from '../../errors'
|
|
11
|
-
import {
|
|
12
|
-
installAdminDomainInContext,
|
|
13
|
-
listAdminDomainsInContext,
|
|
14
|
-
type DomainInfo,
|
|
15
|
-
} from '../../lib/admin-domain'
|
|
16
|
-
import { listOwnedInstancesInContext, type OwnedInstanceInfo } from '../../lib/admin-instance'
|
|
17
|
-
import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
|
|
18
|
-
import { fetchDomainPublication } from '../../lib/domain-publication'
|
|
19
|
-
import { getActive } from '../../lib/instance'
|
|
20
|
-
import { fatal, log, withSpinner } from '../../lib/log'
|
|
21
|
-
import { isMachine, output } from '../../lib/output'
|
|
22
|
-
import { confirmWithInput, promptText, selectFrom } from '../../lib/prompt'
|
|
23
|
-
import { isHttpUrl } from '../../lib/validation'
|
|
24
|
-
|
|
25
|
-
/** Public Kernel install syscall input for one remote URL. */
|
|
26
|
-
export function directInstallCallInput(
|
|
27
|
-
url: string,
|
|
28
|
-
operation: string,
|
|
29
|
-
token?: string,
|
|
30
|
-
): InstallRequest {
|
|
31
|
-
const domain = Object.freeze({
|
|
32
|
-
publication: Object.freeze({
|
|
33
|
-
url,
|
|
34
|
-
...(token === undefined ? {} : { token }),
|
|
35
|
-
}),
|
|
36
|
-
})
|
|
37
|
-
return Object.freeze({
|
|
38
|
-
operation: acceptOperationId(operation),
|
|
39
|
-
domains: Object.freeze([domain] as const),
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface DirectInstallPresentation {
|
|
44
|
-
readonly operation: string
|
|
45
|
-
readonly origin: string
|
|
46
|
-
readonly revision: string
|
|
47
|
-
readonly status: 'installed' | 'already current'
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Stable CLI presentation derived from the canonical binary install result. */
|
|
51
|
-
export function directInstallPresentation(
|
|
52
|
-
result: InstallResult,
|
|
53
|
-
requestedOperation: string,
|
|
54
|
-
): DirectInstallPresentation {
|
|
55
|
-
if (result.changed) {
|
|
56
|
-
const installed = result.receipt.transitions[0]?.intent
|
|
57
|
-
if (!installed) throw new Error('Kernel install returned no committed Domain transition.')
|
|
58
|
-
if (!installed.generation) {
|
|
59
|
-
throw new Error('Kernel install returned a committed transition without a Domain generation.')
|
|
60
|
-
}
|
|
61
|
-
return Object.freeze({
|
|
62
|
-
operation: result.receipt.operation,
|
|
63
|
-
origin: installed.origin,
|
|
64
|
-
revision: installed.generation.revision,
|
|
65
|
-
status: 'installed' as const,
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
const installed = result.domains[0]
|
|
69
|
-
return Object.freeze({
|
|
70
|
-
operation: requestedOperation,
|
|
71
|
-
origin: installed.origin,
|
|
72
|
-
revision: installed.revision,
|
|
73
|
-
status: 'already current' as const,
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const OPERATION_ID_PATTERN =
|
|
78
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u
|
|
79
|
-
|
|
80
|
-
function acceptOperationId(input: unknown): OperationId {
|
|
81
|
-
if (typeof input !== 'string' || !OPERATION_ID_PATTERN.test(input)) {
|
|
82
|
-
throw new AstraleError(
|
|
83
|
-
'INVALID_FLAG',
|
|
84
|
-
'--operation must be a canonical lowercase UUIDv4.',
|
|
85
|
-
'Omit --operation for a fresh install; use it only with the exact UUID printed for recovery.',
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
return input as OperationId
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function createOperationId(): OperationId {
|
|
92
|
-
return acceptOperationId(globalThis.crypto.randomUUID())
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
type InstallOpts = KernelCommandOpts &
|
|
96
|
-
AdminTargetCommandOpts & {
|
|
97
|
-
direct?: boolean
|
|
98
|
-
operation?: string
|
|
99
|
-
token?: string
|
|
100
|
-
allowIdentityOverride?: boolean
|
|
101
|
-
// Global flags (program.ts) that force non-interactive.
|
|
102
|
-
ci?: boolean
|
|
103
|
-
noPrompt?: boolean
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export default {
|
|
107
|
-
name: 'install',
|
|
108
|
-
description: 'Install a domain on an instance (via the admin catalog, or --direct from a url)',
|
|
109
|
-
afterHelpText: `
|
|
110
|
-
Behavior:
|
|
111
|
-
Default: installs a PUBLISHED domain through the admin control plane
|
|
112
|
-
(DomainEntry.install). Address it by its catalog \`origin\` (the unique
|
|
113
|
-
registry key) or by its \`url\`; run it bare to pick from the catalog
|
|
114
|
-
interactively. The target instance is the active one, or -i <slug>; it must be
|
|
115
|
-
admin-managed (otherwise the command fails loudly and points you at --direct).
|
|
116
|
-
|
|
117
|
-
--direct: installs a url through the public Kernel install syscall,
|
|
118
|
-
bypassing the admin catalog. Works on any instance you can authenticate to
|
|
119
|
-
(managed, bookmarked, or local), using your own authority. This is the only
|
|
120
|
-
mode that runs the identity-override consent gate: when the domain's declared
|
|
121
|
-
origin differs from its serving host, it requires explicit consent (an
|
|
122
|
-
interactive DANGER prompt, or --allow-identity-override in scripts).
|
|
123
|
-
|
|
124
|
-
A fresh, strong operation id is generated automatically. Use --operation
|
|
125
|
-
only to retry or recover the exact same direct install after an outcome-unknown
|
|
126
|
-
timeout or disconnect.
|
|
127
|
-
|
|
128
|
-
Examples:
|
|
129
|
-
$ astrale domain install crm.acme.dev -i staging # by origin, via admin
|
|
130
|
-
$ astrale domain install https://crm.acme.dev # by url, via admin
|
|
131
|
-
$ astrale domain install # interactive: pick domain + instance
|
|
132
|
-
$ astrale domain install https://crm.workers.dev --direct # straight to the instance kernel
|
|
133
|
-
$ astrale domain install http://localhost:8787 --direct --token "$INSTALL_TOKEN"
|
|
134
|
-
`,
|
|
135
|
-
arguments: [
|
|
136
|
-
{
|
|
137
|
-
name: 'target',
|
|
138
|
-
description: 'Domain origin or url (omit to pick from the catalog interactively)',
|
|
139
|
-
required: false,
|
|
140
|
-
},
|
|
141
|
-
],
|
|
142
|
-
options: [
|
|
143
|
-
...ADMIN_TARGET_OPTIONS,
|
|
144
|
-
{
|
|
145
|
-
flags: '--direct',
|
|
146
|
-
description:
|
|
147
|
-
'Install a url straight onto the instance kernel, bypassing the admin catalog (any instance; runs the identity-override gate)',
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
flags: '--token <token>',
|
|
151
|
-
description: 'Bearer token for private domain install endpoints (--direct only)',
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
flags: '--operation <uuid>',
|
|
155
|
-
description: 'Reuse an exact direct-install operation id for explicit retry/recovery',
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
flags: '--allow-identity-override',
|
|
159
|
-
description: 'Consent to a domain whose origin differs from its serving host (--direct only)',
|
|
160
|
-
},
|
|
161
|
-
],
|
|
162
|
-
action: async (target: string | undefined, opts: InstallOpts) => {
|
|
163
|
-
if (opts.operation !== undefined && !opts.direct) {
|
|
164
|
-
fatal(
|
|
165
|
-
new AstraleError(
|
|
166
|
-
'INVALID_FLAG',
|
|
167
|
-
'--operation is valid only with --direct.',
|
|
168
|
-
'Ordinary direct installs generate a fresh operation id automatically.',
|
|
169
|
-
),
|
|
170
|
-
opts,
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
if (opts.direct) {
|
|
174
|
-
await installDirect(target, opts)
|
|
175
|
-
return
|
|
176
|
-
}
|
|
177
|
-
await installViaAdmin(target, opts)
|
|
178
|
-
},
|
|
179
|
-
} satisfies CommandDefinition
|
|
180
|
-
|
|
181
|
-
// ── Admin path (default) ──────────────────────────────────────────────────────
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Install a published domain through the admin control plane. The domain is
|
|
185
|
-
* addressed by `origin` (catalog key) or `url`; the target instance is the
|
|
186
|
-
* active one or `-i <slug>` and must be admin-managed.
|
|
187
|
-
*
|
|
188
|
-
* `-i` here means the INSTALL TARGET, not the admin target — so it is stripped
|
|
189
|
-
* before resolving the admin client (which would otherwise read `-i`/`--url` as
|
|
190
|
-
* an admin-kernel override). The admin kernel is chosen via --admin/--admin-url
|
|
191
|
-
* or config, exactly like `domain publish`.
|
|
192
|
-
*/
|
|
193
|
-
export async function installViaAdmin(
|
|
194
|
-
target: string | undefined,
|
|
195
|
-
opts: InstallOpts,
|
|
196
|
-
dependencies: Partial<AdminInstallDependencies> = {},
|
|
197
|
-
): Promise<void> {
|
|
198
|
-
const admin = { ...defaultAdminInstallDependencies, ...dependencies }
|
|
199
|
-
const interactive = !!process.stdin.isTTY && !(opts.ci || opts.noPrompt || process.env.CI)
|
|
200
|
-
if (!target && !interactive) {
|
|
201
|
-
fatal(
|
|
202
|
-
new AstraleError(
|
|
203
|
-
'MISSING_ARG',
|
|
204
|
-
'No domain given and no TTY for interactive selection.',
|
|
205
|
-
'Pass an origin or url, e.g. astrale domain install crm.acme.dev — or use --direct <url>.',
|
|
206
|
-
),
|
|
207
|
-
)
|
|
208
|
-
}
|
|
209
|
-
// Strip the install-target selector so the admin client resolves only the
|
|
210
|
-
// admin kernel (via --admin/--admin-url/config), not the instance under `-i`.
|
|
211
|
-
const adminOpts = {
|
|
212
|
-
admin: opts.admin,
|
|
213
|
-
adminUrl: opts.adminUrl,
|
|
214
|
-
timeout: opts.timeout,
|
|
215
|
-
as: opts.as,
|
|
216
|
-
creds: opts.creds,
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
try {
|
|
220
|
-
await withAdminClientSession(adminOpts, async (ctx) => {
|
|
221
|
-
const instances = await admin.listInstances(ctx)
|
|
222
|
-
const slug = await resolveTargetSlug(opts, target, interactive, instances)
|
|
223
|
-
|
|
224
|
-
const match = instances.find((i) => i.slug === slug)
|
|
225
|
-
if (!match) {
|
|
226
|
-
const known = instances.map((i) => i.slug).join(', ') || '(none)'
|
|
227
|
-
throw new AstraleError(
|
|
228
|
-
'INSTANCE_NOT_MANAGED',
|
|
229
|
-
`Instance "${slug}" is not admin-managed (managed: ${known}).`,
|
|
230
|
-
`Install the url directly onto it instead: astrale domain install <url> --direct -i ${slug}`,
|
|
231
|
-
)
|
|
232
|
-
}
|
|
233
|
-
assertInstallTargetReady(match)
|
|
234
|
-
|
|
235
|
-
const domains = await admin.listDomains(ctx)
|
|
236
|
-
const domain = await resolveDomain(domains, target, interactive)
|
|
237
|
-
|
|
238
|
-
const label = domain.origin
|
|
239
|
-
const result = await withSpinner(
|
|
240
|
-
`Installing ${label} on ${match.slug}`,
|
|
241
|
-
!isMachine(opts),
|
|
242
|
-
() => admin.install(ctx, match, domain),
|
|
243
|
-
{ success: (r) => `Installed ${r.origin} on ${match.slug}` },
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
if (isMachine(opts)) {
|
|
247
|
-
output(result, opts)
|
|
248
|
-
return
|
|
249
|
-
}
|
|
250
|
-
// The admin returns install failures as `ok:false` (it never throws past
|
|
251
|
-
// the saga). Surface them loudly rather than printing a quiet success.
|
|
252
|
-
if (!result.ok) {
|
|
253
|
-
throw new AstraleError(
|
|
254
|
-
'INSTALL_FAILED',
|
|
255
|
-
`Install failed on ${match.slug}: ${result.error ?? 'unknown error'}`,
|
|
256
|
-
)
|
|
257
|
-
}
|
|
258
|
-
log.dim(` origin: ${result.origin}`)
|
|
259
|
-
log.dim(` url: ${result.url}`)
|
|
260
|
-
})
|
|
261
|
-
} catch (error) {
|
|
262
|
-
await formatKernelError(error, isMachine(opts), undefined, opts.debug)
|
|
263
|
-
process.exit(1)
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function assertInstallTargetReady(instance: OwnedInstanceInfo): void {
|
|
268
|
-
if (instance.state === 'ready') return
|
|
269
|
-
const detail = instance.phase && instance.phase !== instance.state ? ` (${instance.phase})` : ''
|
|
270
|
-
throw new AstraleError(
|
|
271
|
-
'INSTANCE_NOT_READY',
|
|
272
|
-
`Instance "${instance.slug}" is ${instance.state}${detail}; domains cannot be installed yet.`,
|
|
273
|
-
instance.error ?? `Run: astrale instance status ${instance.slug}`,
|
|
274
|
-
)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Classify the positional install target for the admin path: an http(s) URL
|
|
279
|
-
* installs by `url`, anything else is treated as a catalog `origin` (the unique
|
|
280
|
-
* registry key). The admin method accepts either.
|
|
281
|
-
*/
|
|
282
|
-
export function domainRefFromTarget(target: string): { origin?: string; url?: string } {
|
|
283
|
-
return isHttpUrl(target) ? { url: target } : { origin: target }
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/** Resolve the domain to install: the positional `target`, or an interactive pick. */
|
|
287
|
-
async function resolveDomain(
|
|
288
|
-
catalog: readonly DomainInfo[],
|
|
289
|
-
target: string | undefined,
|
|
290
|
-
interactive: boolean,
|
|
291
|
-
): Promise<DomainInfo> {
|
|
292
|
-
if (target) {
|
|
293
|
-
const ref = domainRefFromTarget(target)
|
|
294
|
-
const found = catalog.find((domain) =>
|
|
295
|
-
ref.origin === undefined ? domain.url === ref.url : domain.origin === ref.origin,
|
|
296
|
-
)
|
|
297
|
-
if (found !== undefined) return found
|
|
298
|
-
throw new AstraleError(
|
|
299
|
-
'DOMAIN_NOT_FOUND',
|
|
300
|
-
`No published domain matches "${target}".`,
|
|
301
|
-
'Run `astrale domain list` to see the Admin catalog.',
|
|
302
|
-
)
|
|
303
|
-
}
|
|
304
|
-
if (!interactive) throw new AstraleError('MISSING_ARG', 'No domain given.')
|
|
305
|
-
|
|
306
|
-
const installable = catalog.filter((d) => d.url)
|
|
307
|
-
if (installable.length === 0) {
|
|
308
|
-
throw new AstraleError(
|
|
309
|
-
'EMPTY_CATALOG',
|
|
310
|
-
'No published domains in the admin catalog.',
|
|
311
|
-
'Publish one first: astrale domain publish --origin … --name … --public-url …',
|
|
312
|
-
)
|
|
313
|
-
}
|
|
314
|
-
const origin = await selectFrom(
|
|
315
|
-
'Select a domain to install',
|
|
316
|
-
installable.map((d) => ({
|
|
317
|
-
label: `${d.name} ${chalk.dim(`${d.origin} → ${d.url}`)}`,
|
|
318
|
-
value: d.origin,
|
|
319
|
-
})),
|
|
320
|
-
)
|
|
321
|
-
if (!origin) throw new AstraleError('CANCELLED', 'No domain selected.')
|
|
322
|
-
return catalog.find((domain) => domain.origin === origin)!
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
interface AdminInstallDependencies {
|
|
326
|
-
readonly listInstances: typeof listOwnedInstancesInContext
|
|
327
|
-
readonly listDomains: typeof listAdminDomainsInContext
|
|
328
|
-
readonly install: typeof installAdminDomainInContext
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const defaultAdminInstallDependencies: AdminInstallDependencies = Object.freeze({
|
|
332
|
-
listInstances: listOwnedInstancesInContext,
|
|
333
|
-
listDomains: listAdminDomainsInContext,
|
|
334
|
-
install: installAdminDomainInContext,
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Resolve the target instance slug: `-i`, else the active instance. When run
|
|
339
|
-
* bare (no positional) in a TTY, prompt for it with the active instance
|
|
340
|
-
* pre-filled (Enter accepts) and validated against the managed list.
|
|
341
|
-
*/
|
|
342
|
-
async function resolveTargetSlug(
|
|
343
|
-
opts: InstallOpts,
|
|
344
|
-
target: string | undefined,
|
|
345
|
-
interactive: boolean,
|
|
346
|
-
instances: OwnedInstanceInfo[],
|
|
347
|
-
): Promise<string> {
|
|
348
|
-
if (opts.instance) return opts.instance
|
|
349
|
-
const active = await activeSlug()
|
|
350
|
-
|
|
351
|
-
if (target === undefined && interactive) {
|
|
352
|
-
const slugs = instances.map((i) => i.slug)
|
|
353
|
-
if (slugs.length > 0) log.dim(` managed instances: ${slugs.join(', ')}`)
|
|
354
|
-
const chosen = await promptText('Instance to install on', {
|
|
355
|
-
default: active && slugs.includes(active) ? active : undefined,
|
|
356
|
-
validate: (v) =>
|
|
357
|
-
slugs.includes(v) ||
|
|
358
|
-
`unknown managed instance "${v}" (one of: ${slugs.join(', ') || 'none'})`,
|
|
359
|
-
})
|
|
360
|
-
if (!chosen) throw new AstraleError('CANCELLED', 'No instance selected.')
|
|
361
|
-
return chosen
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (!active) {
|
|
365
|
-
throw new AstraleError(
|
|
366
|
-
'NO_TARGET_INSTANCE',
|
|
367
|
-
'No target instance: none active and no -i <slug> given.',
|
|
368
|
-
'Pass -i <slug>, or select one with astrale instance use <slug>.',
|
|
369
|
-
)
|
|
370
|
-
}
|
|
371
|
-
return active
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/** The active instance's slug (its admin-side id), or undefined when none. */
|
|
375
|
-
async function activeSlug(): Promise<string | undefined> {
|
|
376
|
-
try {
|
|
377
|
-
const a = await getActive()
|
|
378
|
-
return a.slug ?? a.name
|
|
379
|
-
} catch {
|
|
380
|
-
return undefined
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// ── Direct path (--direct) ────────────────────────────────────────────────────
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Install a url through the public Kernel install syscall,
|
|
388
|
-
* bypassing the admin catalog, with the identity-override
|
|
389
|
-
* consent gate. Works on any instance the caller can authenticate to.
|
|
390
|
-
*/
|
|
391
|
-
interface DirectInstallDependencies {
|
|
392
|
-
readonly acceptOperationId: (input: unknown) => string
|
|
393
|
-
readonly createOperationId: () => string
|
|
394
|
-
readonly runKernelCommand: typeof runKernelCommand
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const defaultDirectInstallDependencies: DirectInstallDependencies = Object.freeze({
|
|
398
|
-
acceptOperationId,
|
|
399
|
-
createOperationId,
|
|
400
|
-
runKernelCommand,
|
|
401
|
-
})
|
|
402
|
-
|
|
403
|
-
export async function installDirect(
|
|
404
|
-
target: string | undefined,
|
|
405
|
-
opts: InstallOpts,
|
|
406
|
-
dependencies: Partial<DirectInstallDependencies> = {},
|
|
407
|
-
): Promise<void> {
|
|
408
|
-
const direct = { ...defaultDirectInstallDependencies, ...dependencies }
|
|
409
|
-
let host = ''
|
|
410
|
-
let consentedOrigin: string | undefined
|
|
411
|
-
let operation: string
|
|
412
|
-
try {
|
|
413
|
-
if (!target) {
|
|
414
|
-
throw new AstraleError(
|
|
415
|
-
'MISSING_ARG',
|
|
416
|
-
'--direct requires a domain url.',
|
|
417
|
-
'e.g. astrale domain install https://crm.acme.dev --direct',
|
|
418
|
-
)
|
|
419
|
-
}
|
|
420
|
-
host = validateInstallUrl(target)
|
|
421
|
-
operation =
|
|
422
|
-
opts.operation === undefined
|
|
423
|
-
? direct.createOperationId()
|
|
424
|
-
: direct.acceptOperationId(opts.operation)
|
|
425
|
-
consentedOrigin = await ensureIdentityOverrideConsent(
|
|
426
|
-
target,
|
|
427
|
-
host,
|
|
428
|
-
opts.allowIdentityOverride ?? false,
|
|
429
|
-
isMachine(opts),
|
|
430
|
-
)
|
|
431
|
-
} catch (e) {
|
|
432
|
-
fatal(e, opts)
|
|
433
|
-
}
|
|
434
|
-
const url = target as string
|
|
435
|
-
const retry = directInstallRetry(url, operation, opts)
|
|
436
|
-
|
|
437
|
-
await direct.runKernelCommand<InstallResult>({
|
|
438
|
-
opts,
|
|
439
|
-
label: `Installing domain from ${url} (operation ${operation})`,
|
|
440
|
-
recovery: { operation, retry },
|
|
441
|
-
fn: async ({ session }) =>
|
|
442
|
-
session.schema.install(directInstallCallInput(url, operation, opts.token)),
|
|
443
|
-
format: (result, fmtOpts, isRaw) => {
|
|
444
|
-
if (isRaw) {
|
|
445
|
-
output(result, fmtOpts)
|
|
446
|
-
return
|
|
447
|
-
}
|
|
448
|
-
const installed = directInstallPresentation(result, operation)
|
|
449
|
-
log.success(`Domain ${installed.status}: ${installed.origin}@${installed.revision}`)
|
|
450
|
-
log.dim(` operation: ${installed.operation}`)
|
|
451
|
-
// Belt-and-braces: the kernel-confirmed origin is authoritative. If it
|
|
452
|
-
// aliases the host and the pre-install gate never consented to THAT
|
|
453
|
-
// origin (lying or unavailable Publication), say so loudly after the fact.
|
|
454
|
-
if (isIdentityOverride(installed.origin, host) && installed.origin !== consentedOrigin) {
|
|
455
|
-
if (!isMachine(fmtOpts)) {
|
|
456
|
-
log.warn(
|
|
457
|
-
`Installed origin "${installed.origin}" differs from the serving host "${host}" ` +
|
|
458
|
-
`and was not confirmed before install (the worker Publication was unavailable). ` +
|
|
459
|
-
`Every ${installed.origin}/* call on this instance now routes to ${host}.`,
|
|
460
|
-
)
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
},
|
|
464
|
-
})
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
function directInstallRetry(url: string, operation: string, opts: InstallOpts): string {
|
|
468
|
-
const instance = opts.instance === undefined ? '' : ` -i ${opts.instance}`
|
|
469
|
-
return `astrale domain install ${url} --direct --operation ${operation}${instance}`
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
function validateInstallUrl(value: string): string {
|
|
473
|
-
let url: URL
|
|
474
|
-
try {
|
|
475
|
-
url = new URL(value)
|
|
476
|
-
} catch {
|
|
477
|
-
throw new AstraleError(
|
|
478
|
-
'INVALID_DOMAIN_URL',
|
|
479
|
-
`Domain install source must be an http(s) URL, got "${value}".`,
|
|
480
|
-
'Run or deploy the domain service, then install its base URL, for example: astrale domain install https://contract.astrale.ai --direct',
|
|
481
|
-
)
|
|
482
|
-
}
|
|
483
|
-
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
484
|
-
throw new AstraleError(
|
|
485
|
-
'INVALID_DOMAIN_URL',
|
|
486
|
-
`Domain install URL must use http or https, got "${url.protocol}".`,
|
|
487
|
-
)
|
|
488
|
-
}
|
|
489
|
-
return url.hostname
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/** An override = the declared origin and the serving host name differ. */
|
|
493
|
-
export function isIdentityOverride(origin: string, host: string): boolean {
|
|
494
|
-
return origin.toLowerCase() !== host.toLowerCase()
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* The §5 identity-override gate (spec: CREATE_ASTRALE_DOMAIN_DX). A domain's
|
|
499
|
-
* `origin` is its addressing identity on the instance: every `<origin>/*` call
|
|
500
|
-
* — including other domains' `requires` — routes to the installed URL.
|
|
501
|
-
* Claiming an origin that differs from the serving host is an explicit actAs
|
|
502
|
-
* and needs typed consent (or `--allow-identity-override` in scripts).
|
|
503
|
-
*
|
|
504
|
-
* The pre-install check reads the worker's canonical Publication origin,
|
|
505
|
-
* so it is consent UX, not enforcement — a hostile worker can lie here, and
|
|
506
|
-
* the kernel anchors the cryptographic identity (`iss`) on the real URL
|
|
507
|
-
* regardless. When the Publication is unreachable or invalid, the gate
|
|
508
|
-
* degrades to a warning and the kernel-confirmed origin is re-checked after
|
|
509
|
-
* install (see `format` above).
|
|
510
|
-
*
|
|
511
|
-
* Returns the origin the user consented to (or `undefined` when no override
|
|
512
|
-
* was detected / verifiable pre-install).
|
|
513
|
-
*/
|
|
514
|
-
async function ensureIdentityOverrideConsent(
|
|
515
|
-
url: string,
|
|
516
|
-
host: string,
|
|
517
|
-
allow: boolean,
|
|
518
|
-
machine: boolean,
|
|
519
|
-
): Promise<string | undefined> {
|
|
520
|
-
const origin = await probeDeclaredOrigin(url)
|
|
521
|
-
if (origin === undefined) {
|
|
522
|
-
if (!machine) {
|
|
523
|
-
log.warn(
|
|
524
|
-
`Could not read a declared origin from ` +
|
|
525
|
-
`${new URL('/.well-known/astrale/domain.json', url).href} — ` +
|
|
526
|
-
`skipping the pre-install identity check (the installed origin is verified after install).`,
|
|
527
|
-
)
|
|
528
|
-
}
|
|
529
|
-
return undefined
|
|
530
|
-
}
|
|
531
|
-
if (!isIdentityOverride(origin, host)) return undefined
|
|
532
|
-
|
|
533
|
-
if (allow) {
|
|
534
|
-
if (!machine) {
|
|
535
|
-
log.warn(`Identity override consented via --allow-identity-override: ${origin} ← ${host}`)
|
|
536
|
-
}
|
|
537
|
-
return origin
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const banner =
|
|
541
|
-
chalk.red.bold('⚠ DANGER — IDENTITY OVERRIDE') +
|
|
542
|
-
'\n' +
|
|
543
|
-
chalk.dim('│') +
|
|
544
|
-
` deployed ${host}\n` +
|
|
545
|
-
chalk.dim('│') +
|
|
546
|
-
` origin ${chalk.bold(origin)} ${chalk.red('(≠)')}\n` +
|
|
547
|
-
chalk.dim('│') +
|
|
548
|
-
'\n' +
|
|
549
|
-
chalk.dim('│') +
|
|
550
|
-
` Every call to ${origin}/* on this instance —\n` +
|
|
551
|
-
chalk.dim('│') +
|
|
552
|
-
` including from other domains — will hit ${host}.\n` +
|
|
553
|
-
chalk.dim('│') +
|
|
554
|
-
` Only proceed if you trust ${host}.`
|
|
555
|
-
const confirmed = await confirmWithInput(banner, origin)
|
|
556
|
-
if (!confirmed) {
|
|
557
|
-
throw new AstraleError(
|
|
558
|
-
'IDENTITY_OVERRIDE_REJECTED',
|
|
559
|
-
`Install aborted: the domain at ${host} declares origin "${origin}" (identity override) and it was not confirmed.`,
|
|
560
|
-
'Re-run interactively and type the origin to confirm, or pass --allow-identity-override in scripts.',
|
|
561
|
-
)
|
|
562
|
-
}
|
|
563
|
-
return origin
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
/** Best-effort read of the worker's origin from its admitted canonical Publication. */
|
|
567
|
-
export async function probeDeclaredOrigin(url: string): Promise<string | undefined> {
|
|
568
|
-
try {
|
|
569
|
-
return (await fetchDomainPublication(url, AbortSignal.timeout(10_000))).origin
|
|
570
|
-
} catch {
|
|
571
|
-
// An unreachable or invalid Publication is not fatal here: the caller warns
|
|
572
|
-
// and the install itself will surface a dead worker with its own error.
|
|
573
|
-
return undefined
|
|
574
|
-
}
|
|
575
|
-
}
|