@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
package/src/lib/update.ts
DELETED
|
@@ -1,568 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto'
|
|
2
|
-
import {
|
|
3
|
-
chmod,
|
|
4
|
-
copyFile,
|
|
5
|
-
mkdir,
|
|
6
|
-
mkdtemp,
|
|
7
|
-
readFile,
|
|
8
|
-
realpath,
|
|
9
|
-
rename,
|
|
10
|
-
rm,
|
|
11
|
-
writeFile,
|
|
12
|
-
} from 'node:fs/promises'
|
|
13
|
-
import { tmpdir } from 'node:os'
|
|
14
|
-
import { dirname, join } from 'node:path'
|
|
15
|
-
import { z } from 'zod'
|
|
16
|
-
|
|
17
|
-
import { AstraleError } from '../errors'
|
|
18
|
-
import { INSTALL_PATH } from '../state/index'
|
|
19
|
-
import { run } from './proc'
|
|
20
|
-
|
|
21
|
-
const DEFAULT_REPO = 'astrale-os/cli'
|
|
22
|
-
export const DEFAULT_UPDATE_CHANNEL = 'beta'
|
|
23
|
-
|
|
24
|
-
export const InstallMetadataSchema = z.object({
|
|
25
|
-
method: z.literal('script'),
|
|
26
|
-
channel: z.string().min(1).default(DEFAULT_UPDATE_CHANNEL),
|
|
27
|
-
version: z.string().min(1).optional(),
|
|
28
|
-
repo: z.string().min(1).default(DEFAULT_REPO),
|
|
29
|
-
bin: z.string().min(1),
|
|
30
|
-
installedAt: z.string().optional(),
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
export type InstallMetadata = z.infer<typeof InstallMetadataSchema>
|
|
34
|
-
|
|
35
|
-
const ManifestAssetSchema = z.object({
|
|
36
|
-
name: z.string().min(1),
|
|
37
|
-
sha256: z
|
|
38
|
-
.string()
|
|
39
|
-
.regex(/^[a-fA-F0-9]{64}$/)
|
|
40
|
-
.optional(),
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
export const UpdateManifestSchema = z.object({
|
|
44
|
-
version: z.string().min(1),
|
|
45
|
-
binaryVersion: z.string().min(1).optional(),
|
|
46
|
-
channel: z.string().min(1),
|
|
47
|
-
repo: z.string().min(1).optional(),
|
|
48
|
-
assets: z.record(
|
|
49
|
-
z.string(),
|
|
50
|
-
z.union([
|
|
51
|
-
ManifestAssetSchema,
|
|
52
|
-
z
|
|
53
|
-
.string()
|
|
54
|
-
.min(1)
|
|
55
|
-
.transform((name) => ({ name })),
|
|
56
|
-
]),
|
|
57
|
-
),
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
export type UpdateManifest = z.infer<typeof UpdateManifestSchema>
|
|
61
|
-
|
|
62
|
-
export type Platform = {
|
|
63
|
-
os: 'darwin' | 'linux'
|
|
64
|
-
arch: 'arm64' | 'x64'
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export type UpdateRequest = {
|
|
68
|
-
check?: boolean
|
|
69
|
-
channel?: string
|
|
70
|
-
version?: string
|
|
71
|
-
currentVersion: string
|
|
72
|
-
platform?: Platform
|
|
73
|
-
installPath?: string
|
|
74
|
-
execution?: UpdateExecution
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export type UpdateExecution =
|
|
78
|
-
| { kind: 'standalone'; executable: string }
|
|
79
|
-
| { kind: 'package-managed'; executable: string }
|
|
80
|
-
|
|
81
|
-
const admittedScriptInstall = Symbol('admittedScriptInstall')
|
|
82
|
-
export type AdmittedScriptInstall = Readonly<{
|
|
83
|
-
metadata: InstallMetadata
|
|
84
|
-
executable: string
|
|
85
|
-
[admittedScriptInstall]: true
|
|
86
|
-
}>
|
|
87
|
-
|
|
88
|
-
export type UpdateResult =
|
|
89
|
-
| {
|
|
90
|
-
status: 'managed'
|
|
91
|
-
currentVersion: string
|
|
92
|
-
executable: string
|
|
93
|
-
}
|
|
94
|
-
| {
|
|
95
|
-
status: 'up-to-date'
|
|
96
|
-
currentVersion: string
|
|
97
|
-
latestVersion: string
|
|
98
|
-
channel: string
|
|
99
|
-
}
|
|
100
|
-
| {
|
|
101
|
-
status: 'available'
|
|
102
|
-
currentVersion: string
|
|
103
|
-
latestVersion: string
|
|
104
|
-
channel: string
|
|
105
|
-
}
|
|
106
|
-
| {
|
|
107
|
-
status: 'updated'
|
|
108
|
-
previousVersion: string
|
|
109
|
-
currentVersion: string
|
|
110
|
-
channel: string
|
|
111
|
-
bin: string
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function detectPlatform(): Platform {
|
|
115
|
-
const os = process.platform
|
|
116
|
-
const arch = process.arch
|
|
117
|
-
if (os !== 'darwin' && os !== 'linux') {
|
|
118
|
-
throw new AstraleError(
|
|
119
|
-
'UNSUPPORTED_PLATFORM',
|
|
120
|
-
`Unsupported OS "${os}" — Astrale update supports macOS and Linux.`,
|
|
121
|
-
)
|
|
122
|
-
}
|
|
123
|
-
if (arch !== 'arm64' && arch !== 'x64') {
|
|
124
|
-
throw new AstraleError(
|
|
125
|
-
'UNSUPPORTED_PLATFORM',
|
|
126
|
-
`Unsupported CPU architecture "${arch}" — Astrale update supports arm64 and x64.`,
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
return { os, arch }
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function platformKey(platform: Platform): string {
|
|
133
|
-
return `${platform.os}-${platform.arch}`
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function classifyUpdateExecution(input: {
|
|
137
|
-
bunVersion?: string
|
|
138
|
-
executable: string
|
|
139
|
-
entry?: string
|
|
140
|
-
}): UpdateExecution {
|
|
141
|
-
return input.bunVersion && input.entry?.startsWith('/$bunfs/')
|
|
142
|
-
? { kind: 'standalone', executable: input.executable }
|
|
143
|
-
: { kind: 'package-managed', executable: input.executable }
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export function detectUpdateExecution(): UpdateExecution {
|
|
147
|
-
return classifyUpdateExecution({
|
|
148
|
-
bunVersion: (process.versions as { bun?: string }).bun,
|
|
149
|
-
executable: process.execPath,
|
|
150
|
-
entry: process.argv[1],
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function packageManagedUpdateError(executable: string): AstraleError {
|
|
155
|
-
return new AstraleError(
|
|
156
|
-
'UPDATE_PACKAGE_MANAGED',
|
|
157
|
-
'This Astrale build is managed by your package manager.',
|
|
158
|
-
`Active binary: ${executable}. Update it with npm, pnpm, or bun; or put the official script installation first on PATH.`,
|
|
159
|
-
)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export async function readInstallMetadata(path = INSTALL_PATH): Promise<InstallMetadata> {
|
|
163
|
-
let raw: string
|
|
164
|
-
try {
|
|
165
|
-
raw = await readFile(path, 'utf8')
|
|
166
|
-
} catch (error) {
|
|
167
|
-
if (!isMissingFile(error)) throw error
|
|
168
|
-
throw new AstraleError(
|
|
169
|
-
'UPDATE_NOT_SCRIPT_INSTALLED',
|
|
170
|
-
'Astrale was not installed by the official install script.',
|
|
171
|
-
'Reinstall with: curl -fsSL https://raw.githubusercontent.com/astrale-os/cli/main/install.sh | sh',
|
|
172
|
-
)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
let decoded: unknown
|
|
176
|
-
try {
|
|
177
|
-
decoded = JSON.parse(raw)
|
|
178
|
-
} catch {
|
|
179
|
-
throw badInstallMetadata(path)
|
|
180
|
-
}
|
|
181
|
-
const parsed = InstallMetadataSchema.safeParse(decoded)
|
|
182
|
-
if (!parsed.success) {
|
|
183
|
-
throw badInstallMetadata(path)
|
|
184
|
-
}
|
|
185
|
-
return parsed.data
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function isMissingFile(error: unknown): error is NodeJS.ErrnoException {
|
|
189
|
-
return error instanceof Error && 'code' in error && error.code === 'ENOENT'
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function badInstallMetadata(path: string): AstraleError {
|
|
193
|
-
return new AstraleError(
|
|
194
|
-
'UPDATE_BAD_INSTALL_METADATA',
|
|
195
|
-
`Invalid install metadata at ${path}.`,
|
|
196
|
-
'Reinstall with: curl -fsSL https://raw.githubusercontent.com/astrale-os/cli/main/install.sh | sh',
|
|
197
|
-
)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export async function admitScriptInstall(
|
|
201
|
-
meta: InstallMetadata,
|
|
202
|
-
execution: Extract<UpdateExecution, { kind: 'standalone' }>,
|
|
203
|
-
): Promise<AdmittedScriptInstall> {
|
|
204
|
-
const [running, recorded] = await Promise.all([
|
|
205
|
-
realpathIfExists(execution.executable),
|
|
206
|
-
realpathIfExists(meta.bin),
|
|
207
|
-
])
|
|
208
|
-
if (running === undefined || recorded === undefined || running !== recorded) {
|
|
209
|
-
throw new AstraleError(
|
|
210
|
-
'UPDATE_INSTALL_MISMATCH',
|
|
211
|
-
'The running Astrale binary does not own the recorded script installation.',
|
|
212
|
-
`Running binary: ${execution.executable}; recorded binary: ${meta.bin}. Refusing to replace a different installation.`,
|
|
213
|
-
)
|
|
214
|
-
}
|
|
215
|
-
return Object.freeze({
|
|
216
|
-
metadata: meta,
|
|
217
|
-
executable: running,
|
|
218
|
-
[admittedScriptInstall]: true as const,
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async function realpathIfExists(path: string): Promise<string | undefined> {
|
|
223
|
-
try {
|
|
224
|
-
return await realpath(path)
|
|
225
|
-
} catch (error) {
|
|
226
|
-
if (isMissingFile(error)) return undefined
|
|
227
|
-
throw error
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export async function writeInstallMetadata(
|
|
232
|
-
meta: InstallMetadata,
|
|
233
|
-
path = INSTALL_PATH,
|
|
234
|
-
filesystem: Pick<CohortFilesystem, 'mkdir' | 'rename' | 'rm'> &
|
|
235
|
-
Pick<typeof import('node:fs/promises'), 'writeFile'> = { mkdir, rename, rm, writeFile },
|
|
236
|
-
): Promise<void> {
|
|
237
|
-
const staged = `${path}.next`
|
|
238
|
-
const previous = `${path}.previous`
|
|
239
|
-
await filesystem.mkdir(dirname(path), { recursive: true })
|
|
240
|
-
await filesystem.rm(staged, { force: true })
|
|
241
|
-
await filesystem.rm(previous, { force: true })
|
|
242
|
-
await filesystem.writeFile(staged, JSON.stringify(meta, null, 2) + '\n')
|
|
243
|
-
|
|
244
|
-
let backedUp = false
|
|
245
|
-
try {
|
|
246
|
-
try {
|
|
247
|
-
await filesystem.rename(path, previous)
|
|
248
|
-
backedUp = true
|
|
249
|
-
} catch (error) {
|
|
250
|
-
if (!isMissingFile(error)) throw error
|
|
251
|
-
}
|
|
252
|
-
await filesystem.rename(staged, path)
|
|
253
|
-
await filesystem.rm(previous, { force: true })
|
|
254
|
-
} catch (error) {
|
|
255
|
-
const rollback: unknown[] = []
|
|
256
|
-
if (backedUp) {
|
|
257
|
-
await filesystem.rename(previous, path).catch((failure) => rollback.push(failure))
|
|
258
|
-
}
|
|
259
|
-
await filesystem.rm(staged, { force: true }).catch((failure) => rollback.push(failure))
|
|
260
|
-
if (rollback.length > 0) {
|
|
261
|
-
throw new AggregateError(
|
|
262
|
-
[error, ...rollback],
|
|
263
|
-
'Install metadata update and rollback both failed.',
|
|
264
|
-
)
|
|
265
|
-
}
|
|
266
|
-
throw error
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function releaseBase(
|
|
271
|
-
meta: InstallMetadata,
|
|
272
|
-
req: Pick<UpdateRequest, 'channel' | 'version'>,
|
|
273
|
-
): string {
|
|
274
|
-
if (process.env.ASTRALE_UPDATE_BASE) return process.env.ASTRALE_UPDATE_BASE.replace(/\/+$/, '')
|
|
275
|
-
const repo = meta.repo || DEFAULT_REPO
|
|
276
|
-
if (req.version) {
|
|
277
|
-
const version = req.version.replace(/^cli\/v/, '').replace(/^v/, '')
|
|
278
|
-
return `https://github.com/${repo}/releases/download/cli/v${version}`
|
|
279
|
-
}
|
|
280
|
-
return `https://github.com/${repo}/releases/download/${req.channel ?? meta.channel ?? DEFAULT_UPDATE_CHANNEL}`
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export async function fetchManifest(base: string): Promise<UpdateManifest> {
|
|
284
|
-
const raw = await readUrlText(`${base}/manifest.json`)
|
|
285
|
-
return UpdateManifestSchema.parse(JSON.parse(raw))
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
export function shouldUpdate(currentVersion: string, manifestVersion: string): boolean {
|
|
289
|
-
return currentVersion !== manifestVersion
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
interface CohortFilesystem {
|
|
293
|
-
readonly chmod: typeof chmod
|
|
294
|
-
readonly copyFile: typeof copyFile
|
|
295
|
-
readonly mkdir: typeof mkdir
|
|
296
|
-
readonly rename: typeof rename
|
|
297
|
-
readonly rm: typeof rm
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const defaultCohortFilesystem: CohortFilesystem = { chmod, copyFile, mkdir, rename, rm }
|
|
301
|
-
|
|
302
|
-
export interface StandaloneCohortReplacement {
|
|
303
|
-
readonly finalize: () => Promise<void>
|
|
304
|
-
readonly rollback: () => Promise<void>
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/** Replace the standalone executable and its Viewer as one rollback-safe cohort. */
|
|
308
|
-
export async function replaceStandaloneCohort(
|
|
309
|
-
installedBinary: string,
|
|
310
|
-
nextBinary: string,
|
|
311
|
-
nextViewerDist: string,
|
|
312
|
-
filesystem: Partial<CohortFilesystem> = {},
|
|
313
|
-
): Promise<StandaloneCohortReplacement> {
|
|
314
|
-
const fs = { ...defaultCohortFilesystem, ...filesystem }
|
|
315
|
-
const binDirectory = dirname(installedBinary)
|
|
316
|
-
const previousBinary = `${installedBinary}.previous`
|
|
317
|
-
const stagedBinary = `${installedBinary}.next`
|
|
318
|
-
const viewer = join(binDirectory, 'viewer')
|
|
319
|
-
const previousViewer = join(binDirectory, 'viewer.previous')
|
|
320
|
-
const stagedViewer = join(binDirectory, 'viewer.next')
|
|
321
|
-
const stagedViewerDist = join(stagedViewer, 'dist')
|
|
322
|
-
|
|
323
|
-
try {
|
|
324
|
-
await fs.rm(stagedViewer, { recursive: true, force: true })
|
|
325
|
-
await fs.mkdir(stagedViewerDist, { recursive: true })
|
|
326
|
-
await fs.copyFile(join(nextViewerDist, 'main.js'), join(stagedViewerDist, 'main.js'))
|
|
327
|
-
await fs.copyFile(join(nextViewerDist, 'index.html'), join(stagedViewerDist, 'index.html'))
|
|
328
|
-
await fs.copyFile(installedBinary, previousBinary)
|
|
329
|
-
await fs.copyFile(nextBinary, stagedBinary)
|
|
330
|
-
await fs.chmod(stagedBinary, 0o755)
|
|
331
|
-
} catch (error) {
|
|
332
|
-
await fs.rm(stagedViewer, { recursive: true, force: true }).catch(() => undefined)
|
|
333
|
-
await fs.rm(stagedBinary, { force: true }).catch(() => undefined)
|
|
334
|
-
throw error
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
await fs.rm(previousViewer, { recursive: true, force: true })
|
|
338
|
-
let viewerBackedUp = false
|
|
339
|
-
let viewerCommitted = false
|
|
340
|
-
let binaryCommitted = false
|
|
341
|
-
try {
|
|
342
|
-
try {
|
|
343
|
-
await fs.rename(viewer, previousViewer)
|
|
344
|
-
viewerBackedUp = true
|
|
345
|
-
} catch (error) {
|
|
346
|
-
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
|
|
347
|
-
}
|
|
348
|
-
await fs.rename(stagedViewer, viewer)
|
|
349
|
-
viewerCommitted = true
|
|
350
|
-
await fs.rename(stagedBinary, installedBinary)
|
|
351
|
-
binaryCommitted = true
|
|
352
|
-
} catch (error) {
|
|
353
|
-
const rollback: unknown[] = []
|
|
354
|
-
if (binaryCommitted) {
|
|
355
|
-
await fs.copyFile(previousBinary, installedBinary).catch((failure) => rollback.push(failure))
|
|
356
|
-
await fs.chmod(installedBinary, 0o755).catch((failure) => rollback.push(failure))
|
|
357
|
-
}
|
|
358
|
-
if (viewerCommitted) {
|
|
359
|
-
await fs
|
|
360
|
-
.rm(viewer, { recursive: true, force: true })
|
|
361
|
-
.catch((failure) => rollback.push(failure))
|
|
362
|
-
}
|
|
363
|
-
if (viewerBackedUp) {
|
|
364
|
-
await fs.rename(previousViewer, viewer).catch((failure) => rollback.push(failure))
|
|
365
|
-
}
|
|
366
|
-
if (rollback.length > 0) {
|
|
367
|
-
throw new AggregateError([error, ...rollback], 'Standalone update and rollback both failed.')
|
|
368
|
-
}
|
|
369
|
-
throw error
|
|
370
|
-
} finally {
|
|
371
|
-
await fs.rm(stagedViewer, { recursive: true, force: true }).catch(() => undefined)
|
|
372
|
-
await fs.rm(stagedBinary, { force: true }).catch(() => undefined)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
let settled = false
|
|
376
|
-
return Object.freeze({
|
|
377
|
-
finalize: async () => {
|
|
378
|
-
if (settled) return
|
|
379
|
-
settled = true
|
|
380
|
-
await fs.rm(previousViewer, { recursive: true, force: true }).catch(() => undefined)
|
|
381
|
-
},
|
|
382
|
-
rollback: async () => {
|
|
383
|
-
if (settled) return
|
|
384
|
-
settled = true
|
|
385
|
-
const rollback: unknown[] = []
|
|
386
|
-
await fs.copyFile(previousBinary, installedBinary).catch((failure) => rollback.push(failure))
|
|
387
|
-
await fs.chmod(installedBinary, 0o755).catch((failure) => rollback.push(failure))
|
|
388
|
-
await fs
|
|
389
|
-
.rm(viewer, { recursive: true, force: true })
|
|
390
|
-
.catch((failure) => rollback.push(failure))
|
|
391
|
-
if (viewerBackedUp) {
|
|
392
|
-
await fs.rename(previousViewer, viewer).catch((failure) => rollback.push(failure))
|
|
393
|
-
}
|
|
394
|
-
if (rollback.length > 0) {
|
|
395
|
-
throw new AggregateError(rollback, 'Standalone update rollback failed.')
|
|
396
|
-
}
|
|
397
|
-
},
|
|
398
|
-
})
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
interface UpdateDependencies {
|
|
402
|
-
readonly replaceStandaloneCohort: typeof replaceStandaloneCohort
|
|
403
|
-
readonly writeInstallMetadata: typeof writeInstallMetadata
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const defaultUpdateDependencies = Object.freeze({ replaceStandaloneCohort, writeInstallMetadata })
|
|
407
|
-
|
|
408
|
-
export async function updateAstrale(
|
|
409
|
-
req: UpdateRequest,
|
|
410
|
-
dependencies: Partial<UpdateDependencies> = {},
|
|
411
|
-
): Promise<UpdateResult> {
|
|
412
|
-
const update = { ...defaultUpdateDependencies, ...dependencies }
|
|
413
|
-
const execution = req.execution ?? detectUpdateExecution()
|
|
414
|
-
if (execution.kind === 'package-managed') {
|
|
415
|
-
return {
|
|
416
|
-
status: 'managed',
|
|
417
|
-
currentVersion: req.currentVersion,
|
|
418
|
-
executable: execution.executable,
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
const install = await admitScriptInstall(await readInstallMetadata(req.installPath), execution)
|
|
423
|
-
const meta = install.metadata
|
|
424
|
-
const currentVersion = meta.version ?? req.currentVersion
|
|
425
|
-
const channel = req.channel ?? meta.channel ?? DEFAULT_UPDATE_CHANNEL
|
|
426
|
-
const platform = req.platform ?? detectPlatform()
|
|
427
|
-
const key = platformKey(platform)
|
|
428
|
-
const base = releaseBase(meta, { channel, version: req.version })
|
|
429
|
-
const manifest = await fetchManifest(base)
|
|
430
|
-
const asset = manifest.assets[key]
|
|
431
|
-
if (!asset) {
|
|
432
|
-
throw new AstraleError(
|
|
433
|
-
'UPDATE_ASSET_NOT_FOUND',
|
|
434
|
-
`No Astrale CLI release asset for ${key}.`,
|
|
435
|
-
`Available platforms: ${Object.keys(manifest.assets).join(', ')}`,
|
|
436
|
-
)
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (!shouldUpdate(currentVersion, manifest.version)) {
|
|
440
|
-
return {
|
|
441
|
-
status: 'up-to-date',
|
|
442
|
-
currentVersion,
|
|
443
|
-
latestVersion: manifest.version,
|
|
444
|
-
channel: manifest.channel,
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (req.check) {
|
|
449
|
-
return {
|
|
450
|
-
status: 'available',
|
|
451
|
-
currentVersion,
|
|
452
|
-
latestVersion: manifest.version,
|
|
453
|
-
channel: manifest.channel,
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const tmp = await mkdtemp(join(tmpdir(), 'astrale-update-'))
|
|
458
|
-
try {
|
|
459
|
-
const archive = join(tmp, asset.name)
|
|
460
|
-
await downloadToFile(`${base}/${asset.name}`, archive)
|
|
461
|
-
const manifestChecksum = 'sha256' in asset ? asset.sha256 : undefined
|
|
462
|
-
const expected = manifestChecksum ?? (await fetchChecksum(base, asset.name))
|
|
463
|
-
const actual = await sha256File(archive)
|
|
464
|
-
if (actual !== expected.toLowerCase()) {
|
|
465
|
-
throw new AstraleError(
|
|
466
|
-
'UPDATE_CHECKSUM_MISMATCH',
|
|
467
|
-
`Checksum mismatch for ${asset.name}.`,
|
|
468
|
-
`Expected ${expected}; got ${actual}.`,
|
|
469
|
-
)
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
await extractTarGz(archive, tmp)
|
|
473
|
-
const nextBin = join(tmp, 'astrale')
|
|
474
|
-
const nextViewer = join(tmp, 'viewer', 'dist')
|
|
475
|
-
await chmod(nextBin, 0o755)
|
|
476
|
-
await smokeVersion(nextBin, manifest.binaryVersion ?? manifest.version)
|
|
477
|
-
|
|
478
|
-
const replacement = await update.replaceStandaloneCohort(meta.bin, nextBin, nextViewer)
|
|
479
|
-
try {
|
|
480
|
-
await update.writeInstallMetadata(
|
|
481
|
-
{
|
|
482
|
-
...meta,
|
|
483
|
-
channel: manifest.channel,
|
|
484
|
-
version: manifest.version,
|
|
485
|
-
installedAt: new Date().toISOString(),
|
|
486
|
-
},
|
|
487
|
-
req.installPath,
|
|
488
|
-
)
|
|
489
|
-
} catch (error) {
|
|
490
|
-
try {
|
|
491
|
-
await replacement.rollback()
|
|
492
|
-
} catch (rollbackError) {
|
|
493
|
-
throw new AggregateError(
|
|
494
|
-
[error, rollbackError],
|
|
495
|
-
'Standalone update metadata commit and cohort rollback both failed.',
|
|
496
|
-
)
|
|
497
|
-
}
|
|
498
|
-
throw error
|
|
499
|
-
}
|
|
500
|
-
await replacement.finalize()
|
|
501
|
-
|
|
502
|
-
return {
|
|
503
|
-
status: 'updated',
|
|
504
|
-
previousVersion: currentVersion,
|
|
505
|
-
currentVersion: manifest.version,
|
|
506
|
-
channel: manifest.channel,
|
|
507
|
-
bin: meta.bin,
|
|
508
|
-
}
|
|
509
|
-
} finally {
|
|
510
|
-
await rm(tmp, { recursive: true, force: true })
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
async function readUrlText(url: string): Promise<string> {
|
|
515
|
-
if (url.startsWith('file://')) {
|
|
516
|
-
return readFile(new URL(url), 'utf8')
|
|
517
|
-
}
|
|
518
|
-
const res = await fetch(url)
|
|
519
|
-
if (!res.ok) throw new Error(`GET ${url} failed: HTTP ${res.status}`)
|
|
520
|
-
return res.text()
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
async function downloadToFile(url: string, path: string): Promise<void> {
|
|
524
|
-
if (url.startsWith('file://')) {
|
|
525
|
-
await copyFile(new URL(url), path)
|
|
526
|
-
return
|
|
527
|
-
}
|
|
528
|
-
const res = await fetch(url)
|
|
529
|
-
if (!res.ok) throw new Error(`GET ${url} failed: HTTP ${res.status}`)
|
|
530
|
-
const bytes = new Uint8Array(await res.arrayBuffer())
|
|
531
|
-
await writeFile(path, bytes)
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
async function fetchChecksum(base: string, assetName: string): Promise<string> {
|
|
535
|
-
const raw = await readUrlText(`${base}/sha256sums.txt`)
|
|
536
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
537
|
-
const [sha, file] = line.trim().split(/\s+/, 2)
|
|
538
|
-
if (!sha || !file) continue
|
|
539
|
-
if (file.replace(/^\*/, '') === assetName && /^[a-fA-F0-9]{64}$/.test(sha)) return sha
|
|
540
|
-
}
|
|
541
|
-
throw new AstraleError(
|
|
542
|
-
'UPDATE_CHECKSUM_NOT_FOUND',
|
|
543
|
-
`Checksum entry not found for ${assetName}.`,
|
|
544
|
-
`Release base: ${base}`,
|
|
545
|
-
)
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
async function sha256File(path: string): Promise<string> {
|
|
549
|
-
const hash = createHash('sha256')
|
|
550
|
-
hash.update(await readFile(path))
|
|
551
|
-
return hash.digest('hex')
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
async function extractTarGz(archive: string, cwd: string): Promise<void> {
|
|
555
|
-
const { code, stderr } = await run('tar', ['-xzf', archive, '-C', cwd])
|
|
556
|
-
if (code !== 0) {
|
|
557
|
-
throw new Error(`Could not extract update archive: ${stderr.trim()}`)
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
async function smokeVersion(bin: string, expectedVersion: string): Promise<void> {
|
|
562
|
-
const { code, stdout, stderr } = await run(bin, ['--version'])
|
|
563
|
-
if (code !== 0) throw new Error(`Updated binary failed --version: ${stderr.trim()}`)
|
|
564
|
-
const actual = stdout.trim()
|
|
565
|
-
if (actual !== expectedVersion) {
|
|
566
|
-
throw new Error(`Updated binary reported version ${actual}, expected ${expectedVersion}`)
|
|
567
|
-
}
|
|
568
|
-
}
|
package/src/lib/use-target.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { IdentityStore } from '../identity/index'
|
|
2
|
-
import type { InstanceStore } from './instance'
|
|
3
|
-
|
|
4
|
-
import { resolveInstanceKey } from './instance'
|
|
5
|
-
|
|
6
|
-
export type UseTarget =
|
|
7
|
-
| { kind: 'identity'; name: string }
|
|
8
|
-
| { kind: 'instance'; name: string }
|
|
9
|
-
| { kind: 'ambiguous'; name: string }
|
|
10
|
-
| { kind: 'missing'; name: string }
|
|
11
|
-
|
|
12
|
-
export function resolveUseTarget(
|
|
13
|
-
name: string,
|
|
14
|
-
instances: InstanceStore,
|
|
15
|
-
identities: IdentityStore,
|
|
16
|
-
): UseTarget {
|
|
17
|
-
const identityExists = !!identities.identities[name]
|
|
18
|
-
const instanceKey = resolveInstanceKey(instances, name)
|
|
19
|
-
|
|
20
|
-
if (identityExists && instanceKey) return { kind: 'ambiguous', name }
|
|
21
|
-
if (identityExists) return { kind: 'identity', name }
|
|
22
|
-
if (instanceKey) return { kind: 'instance', name: instanceKey }
|
|
23
|
-
return { kind: 'missing', name }
|
|
24
|
-
}
|
package/src/lib/validation.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { isDnsLabel } from '@astrale-os/sdk/value'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
|
|
4
|
-
import { ReservedSlugError } from '../errors'
|
|
5
|
-
|
|
6
|
-
// Shared validators + schema fragments used by both instance and identity
|
|
7
|
-
// registries — kept in a leaf module to avoid circular imports.
|
|
8
|
-
|
|
9
|
-
const NAME_RE = /^[a-zA-Z0-9_.-]+$/
|
|
10
|
-
// `host` is the reserved slug of the host/manager kernel (SPEC §5.2); `manager` is the legacy name.
|
|
11
|
-
const RESERVED_SLUGS = new Set(['manager', 'host'])
|
|
12
|
-
|
|
13
|
-
export { RESERVED_SLUGS }
|
|
14
|
-
|
|
15
|
-
export function validateName(name: string, entity: string): void {
|
|
16
|
-
if (!name || !NAME_RE.test(name)) {
|
|
17
|
-
throw new Error(
|
|
18
|
-
`Invalid ${entity.toLowerCase()} name "${name}" — must be non-empty and contain only letters, digits, hyphens, underscores, and dots`,
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function validateSlug(slug: string): void {
|
|
24
|
-
// Canonical Core DNS-label rule: a slug becomes a
|
|
25
|
-
// hostname label, so reject anything not DNS-safe (§4.7).
|
|
26
|
-
if (!slug || !isDnsLabel(slug)) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
`Invalid slug "${slug}" — must be a lowercase DNS label [a-z0-9-], ≤63 chars, no leading/trailing hyphen (§4.7)`,
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
if (RESERVED_SLUGS.has(slug)) {
|
|
32
|
-
throw new ReservedSlugError(slug)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function validateUrl(url: string): void {
|
|
37
|
-
try {
|
|
38
|
-
const parsed = new URL(url)
|
|
39
|
-
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
40
|
-
throw new Error('not http(s)')
|
|
41
|
-
}
|
|
42
|
-
} catch {
|
|
43
|
-
throw new Error(`Invalid URL "${url}" — expected a valid http:// or https:// URL`)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Non-throwing predicate form of `validateUrl`. */
|
|
48
|
-
export function isHttpUrl(url: string): boolean {
|
|
49
|
-
try {
|
|
50
|
-
validateUrl(url)
|
|
51
|
-
return true
|
|
52
|
-
} catch {
|
|
53
|
-
return false
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** `local` = only this machine. `remote` = mirrored via astrale cloud (§2.7). */
|
|
58
|
-
export const RegistryModeSchema = z.enum(['local', 'remote'])
|
|
59
|
-
export type RegistryMode = z.infer<typeof RegistryModeSchema>
|