@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/browser.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import { paths } from '../state/index'
|
|
5
|
-
import { run } from './proc'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* `astrale browser` is a thin orchestrator over `agent-browser`
|
|
9
|
-
* (https://github.com/vercel-labs/agent-browser) — the Rust browser-automation
|
|
10
|
-
* CLI that AI agents drive. We own only the *session*: resolve the active
|
|
11
|
-
* instance's GUI origin, pin a persistent per-instance profile so the WorkOS
|
|
12
|
-
* login cookie survives across runs, and verify auth. Driving (snapshot/click/
|
|
13
|
-
* eval/…) is agent-browser's job, invoked directly by the agent afterward.
|
|
14
|
-
*
|
|
15
|
-
* Why a profile and not an injected token: the GUI session is an httpOnly
|
|
16
|
-
* sealed cookie (`astrale_router_session`) with no token-injection path, so the
|
|
17
|
-
* only way to "use my session" is to drive a browser whose profile already
|
|
18
|
-
* holds the cookie — minted once via interactive login, reused thereafter.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
export const BROWSER_DIR = join(paths.home, 'browser')
|
|
22
|
-
export const BROWSER_SESSION_PATH = join(paths.home, 'browser.json')
|
|
23
|
-
export const AGENT_BROWSER_REPO = 'vercel-labs/agent-browser'
|
|
24
|
-
|
|
25
|
-
/** Per-instance persistent profile dir handed to `agent-browser --profile`. */
|
|
26
|
-
export function profileDirFor(host: string): string {
|
|
27
|
-
return join(BROWSER_DIR, host)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** The last-connected browser session, read by agents to know how to drive. */
|
|
31
|
-
export type BrowserSession = {
|
|
32
|
-
/** GUI origin, e.g. `https://alpha1.eu.astrale.ai`. */
|
|
33
|
-
url: string
|
|
34
|
-
host: string
|
|
35
|
-
/** Profile dir, or null when attached to an external Chrome over CDP. */
|
|
36
|
-
profile: string | null
|
|
37
|
-
/** CDP endpoint (`9222` or a ws URL) when in attach mode. */
|
|
38
|
-
cdp: string | null
|
|
39
|
-
email?: string
|
|
40
|
-
updatedAt: string
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export async function readSession(): Promise<BrowserSession | null> {
|
|
44
|
-
try {
|
|
45
|
-
return JSON.parse(await readFile(BROWSER_SESSION_PATH, 'utf8')) as BrowserSession
|
|
46
|
-
} catch {
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export async function saveSession(session: BrowserSession): Promise<void> {
|
|
52
|
-
await mkdir(paths.home, { recursive: true })
|
|
53
|
-
await writeFile(BROWSER_SESSION_PATH, `${JSON.stringify(session, null, 2)}\n`)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Resolve `agent-browser` on PATH; null when not installed. */
|
|
57
|
-
export async function findAgentBrowser(): Promise<string | null> {
|
|
58
|
-
// `command -v` is a POSIX shell builtin (no `command` executable exists on
|
|
59
|
-
// Windows), so resolve via `where` on Windows and a shell on Unix.
|
|
60
|
-
const lookup =
|
|
61
|
-
process.platform === 'win32'
|
|
62
|
-
? run('where', ['agent-browser'])
|
|
63
|
-
: run('sh', ['-c', 'command -v agent-browser'])
|
|
64
|
-
const res = await lookup.catch(() => null)
|
|
65
|
-
if (!res || res.code !== 0) return null
|
|
66
|
-
const path = res.stdout.split(/\r?\n/)[0]?.trim()
|
|
67
|
-
return path || null
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export type AbResult = {
|
|
71
|
-
ok: boolean
|
|
72
|
-
data: unknown
|
|
73
|
-
error: string | null
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Connection target for an agent-browser invocation: either a persistent
|
|
78
|
-
* profile dir or a CDP endpoint (mutually exclusive).
|
|
79
|
-
*/
|
|
80
|
-
export type AbTarget = { profile?: string; cdp?: string }
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Run an `agent-browser` command with `--json` and parse its envelope
|
|
84
|
-
* (`{success, data, error}`). Global flags (`--profile`/`--cdp`/`--headed`)
|
|
85
|
-
* precede the subcommand; `--json` trails the args, matching the CLI's parser.
|
|
86
|
-
*/
|
|
87
|
-
export async function ab(
|
|
88
|
-
args: string[],
|
|
89
|
-
opts: AbTarget & { headed?: boolean } = {},
|
|
90
|
-
): Promise<AbResult> {
|
|
91
|
-
const argv = ['agent-browser']
|
|
92
|
-
if (opts.profile) argv.push('--profile', opts.profile)
|
|
93
|
-
if (opts.cdp) argv.push('--cdp', opts.cdp)
|
|
94
|
-
if (opts.headed) argv.push('--headed')
|
|
95
|
-
argv.push(...args, '--json')
|
|
96
|
-
|
|
97
|
-
const { code, stdout, stderr } = await run(argv[0], argv.slice(1))
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
const parsed = JSON.parse(stdout) as { success?: boolean; data?: unknown; error?: string }
|
|
101
|
-
if (parsed && typeof parsed === 'object' && 'success' in parsed) {
|
|
102
|
-
return { ok: !!parsed.success, data: parsed.data ?? null, error: parsed.error ?? null }
|
|
103
|
-
}
|
|
104
|
-
} catch {
|
|
105
|
-
// fall through to exit-code interpretation
|
|
106
|
-
}
|
|
107
|
-
return { ok: code === 0, data: null, error: stderr.trim() || null }
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Reads the GUI session from whatever origin the page currently sits on. During
|
|
111
|
-
// an interactive login the page is on the IdP origin, where `/auth/me` 404s and
|
|
112
|
-
// the fetch rejects → {authed:false}; once the router redirects back to the GUI
|
|
113
|
-
// it resolves to the authenticated user. Returned as a value (not top-level
|
|
114
|
-
// await — agent-browser's `eval` forbids it) so page.evaluate auto-resolves it.
|
|
115
|
-
const AUTH_EVAL =
|
|
116
|
-
"fetch('/auth/me',{credentials:'include'})" +
|
|
117
|
-
'.then(r=>r.json())' +
|
|
118
|
-
'.then(j=>({authed:!!j.authenticated,email:j.user&&j.user.email}))' +
|
|
119
|
-
'.catch(()=>({authed:false}))'
|
|
120
|
-
|
|
121
|
-
export type AuthState = { authed: boolean; email?: string }
|
|
122
|
-
|
|
123
|
-
function readAuthResult(res: AbResult): AuthState {
|
|
124
|
-
const result = (res.data as { result?: unknown } | null)?.result
|
|
125
|
-
if (result && typeof result === 'object') {
|
|
126
|
-
const r = result as { authed?: boolean; email?: string }
|
|
127
|
-
return { authed: !!r.authed, email: r.email }
|
|
128
|
-
}
|
|
129
|
-
return { authed: false }
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Poll auth on the current page (no navigation — safe during login redirects).
|
|
134
|
-
* Pass `headed:true` while a sign-in window is open: agent-browser defaults to
|
|
135
|
-
* headless, so an unflagged command flips the live window back to headless and
|
|
136
|
-
* closes it.
|
|
137
|
-
*/
|
|
138
|
-
export async function pollAuth(target: AbTarget & { headed?: boolean }): Promise<AuthState> {
|
|
139
|
-
return readAuthResult(await ab(['eval', AUTH_EVAL], target))
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/** Navigate to the GUI, then read auth (used for the silent reuse check). */
|
|
143
|
-
export async function navigateAndCheck(
|
|
144
|
-
url: string,
|
|
145
|
-
target: AbTarget & { headed?: boolean },
|
|
146
|
-
): Promise<AuthState> {
|
|
147
|
-
const opened = await ab(['open', url], target)
|
|
148
|
-
if (!opened.ok) return { authed: false }
|
|
149
|
-
return pollAuth(target)
|
|
150
|
-
}
|
package/src/lib/ca-fetch.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import type { IncomingHttpHeaders, request as httpRequest } from 'node:http'
|
|
2
|
-
|
|
3
|
-
import { Buffer } from 'node:buffer'
|
|
4
|
-
import { readFileSync } from 'node:fs'
|
|
5
|
-
import { request as httpsRequest } from 'node:https'
|
|
6
|
-
import { rootCertificates } from 'node:tls'
|
|
7
|
-
|
|
8
|
-
/** Create a Fetch capability whose HTTPS requests trust one CLI-selected CA file. */
|
|
9
|
-
export function fetchWithCaFile(
|
|
10
|
-
caFile: string,
|
|
11
|
-
fallback: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response> = globalThis.fetch,
|
|
12
|
-
): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response> {
|
|
13
|
-
const ca = readFileSync(caFile)
|
|
14
|
-
const fallbackFetch = fallback.bind(globalThis)
|
|
15
|
-
|
|
16
|
-
return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
|
|
17
|
-
const url = requestUrl(input)
|
|
18
|
-
if (url.protocol !== 'https:') return fallbackFetch(input, init)
|
|
19
|
-
return fetchWithNode(url, init, ca)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function requestUrl(input: RequestInfo | URL): URL {
|
|
24
|
-
if (input instanceof URL) return input
|
|
25
|
-
if (typeof input === 'string') return new URL(input)
|
|
26
|
-
return new URL(input.url)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function fetchWithNode(url: URL, init: RequestInit | undefined, ca: Buffer): Promise<Response> {
|
|
30
|
-
return new Promise((resolve, reject) => {
|
|
31
|
-
const request = httpsRequest(
|
|
32
|
-
url,
|
|
33
|
-
{
|
|
34
|
-
method: init?.method ?? 'GET',
|
|
35
|
-
headers: headersInitToRecord(init?.headers),
|
|
36
|
-
// `ca` replaces Node's default trust set. Retain public roots because one
|
|
37
|
-
// Client Session may reach both a private Kernel and a public Domain issuer.
|
|
38
|
-
ca: [...rootCertificates, ca],
|
|
39
|
-
},
|
|
40
|
-
(response) => {
|
|
41
|
-
const chunks: Buffer[] = []
|
|
42
|
-
response.on('data', (chunk) =>
|
|
43
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)),
|
|
44
|
-
)
|
|
45
|
-
response.on('end', () => {
|
|
46
|
-
const status = response.statusCode ?? 0
|
|
47
|
-
const body =
|
|
48
|
-
status === 204 || status === 205 || status === 304 ? null : Buffer.concat(chunks)
|
|
49
|
-
const result = new Response(body, {
|
|
50
|
-
status,
|
|
51
|
-
statusText: response.statusMessage,
|
|
52
|
-
headers: responseHeaders(response.headers),
|
|
53
|
-
})
|
|
54
|
-
// Synthetic Responses have no URL list. This transport does not follow
|
|
55
|
-
// redirects, so the exact request URL is also the final response URL.
|
|
56
|
-
Object.defineProperty(result, 'url', { value: url.toString() })
|
|
57
|
-
resolve(result)
|
|
58
|
-
})
|
|
59
|
-
},
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
request.on('error', reject)
|
|
63
|
-
if (init?.signal) {
|
|
64
|
-
if (init.signal.aborted) {
|
|
65
|
-
request.destroy(abortError(init.signal.reason))
|
|
66
|
-
} else {
|
|
67
|
-
init.signal.addEventListener(
|
|
68
|
-
'abort',
|
|
69
|
-
() => request.destroy(abortError(init.signal?.reason)),
|
|
70
|
-
{
|
|
71
|
-
once: true,
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
writeBody(request, init?.body)
|
|
78
|
-
.then(() => request.end())
|
|
79
|
-
.catch((error) => request.destroy(error))
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function abortError(reason: unknown): Error {
|
|
84
|
-
return reason instanceof Error
|
|
85
|
-
? reason
|
|
86
|
-
: new DOMException('The operation was aborted.', 'AbortError')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async function writeBody(
|
|
90
|
-
request: ReturnType<typeof httpRequest>,
|
|
91
|
-
body: BodyInit | null | undefined,
|
|
92
|
-
): Promise<void> {
|
|
93
|
-
if (body === undefined || body === null) return
|
|
94
|
-
if (typeof body === 'string' || body instanceof Uint8Array) {
|
|
95
|
-
request.write(body)
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
if (body instanceof ArrayBuffer) {
|
|
99
|
-
request.write(Buffer.from(body))
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
if (body instanceof Blob) {
|
|
103
|
-
request.write(Buffer.from(await body.arrayBuffer()))
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
throw new Error('Unsupported request body type for CA-backed fetch')
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function headersInitToRecord(headers: HeadersInit | undefined): Record<string, string> {
|
|
110
|
-
if (!headers) return {}
|
|
111
|
-
if (headers instanceof Headers) {
|
|
112
|
-
const out: Record<string, string> = {}
|
|
113
|
-
headers.forEach((value, key) => {
|
|
114
|
-
out[key] = value
|
|
115
|
-
})
|
|
116
|
-
return out
|
|
117
|
-
}
|
|
118
|
-
if (Array.isArray(headers)) return Object.fromEntries(headers)
|
|
119
|
-
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, String(value)]))
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function responseHeaders(headers: IncomingHttpHeaders): Headers {
|
|
123
|
-
const out = new Headers()
|
|
124
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
125
|
-
if (value === undefined) continue
|
|
126
|
-
if (Array.isArray(value)) {
|
|
127
|
-
for (const entry of value) out.append(key, entry)
|
|
128
|
-
} else {
|
|
129
|
-
out.set(key, value)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return out
|
|
133
|
-
}
|
package/src/lib/command-dx.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import type { Command, CommanderError } from 'commander'
|
|
2
|
-
|
|
3
|
-
import chalk from 'chalk'
|
|
4
|
-
|
|
5
|
-
export type CommandCatalogEntry = {
|
|
6
|
-
path: string[]
|
|
7
|
-
usage: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function collectCommandCatalog(program: Command): CommandCatalogEntry[] {
|
|
11
|
-
const out: CommandCatalogEntry[] = []
|
|
12
|
-
|
|
13
|
-
function walk(command: Command, path: string[]): void {
|
|
14
|
-
for (const child of command.commands) {
|
|
15
|
-
const childPath = [...path, child.name()]
|
|
16
|
-
if (child.commands.length === 0) {
|
|
17
|
-
out.push({ path: childPath, usage: usageFor(childPath, child) })
|
|
18
|
-
}
|
|
19
|
-
walk(child, childPath)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
walk(program, [])
|
|
24
|
-
return out
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function renderCommanderError(
|
|
28
|
-
program: Command,
|
|
29
|
-
error: CommanderError,
|
|
30
|
-
argv = process.argv.slice(2),
|
|
31
|
-
machine = argv.some((token) => token === '--ci' || token === '--json' || token === '--raw') ||
|
|
32
|
-
!(process.stdout.isTTY ?? false),
|
|
33
|
-
): string {
|
|
34
|
-
const tokens = stripOptions(argv)
|
|
35
|
-
const catalog = collectCommandCatalog(program)
|
|
36
|
-
const matched = matchRegisteredPrefix(program, tokens)
|
|
37
|
-
|
|
38
|
-
if (matched.path.length === 0 && tokens.length > 0) {
|
|
39
|
-
return maybeMachine(renderUnknownCommand(tokens, catalog), machine)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (error.code === 'commander.missingArgument') {
|
|
43
|
-
const usage = usageFor(matched.path, matched.command)
|
|
44
|
-
return maybeMachine(
|
|
45
|
-
[
|
|
46
|
-
`Missing required argument for ${chalk.bold(`astrale ${matched.path.join(' ')}`)}`,
|
|
47
|
-
'',
|
|
48
|
-
'Usage:',
|
|
49
|
-
` astrale ${usage}`,
|
|
50
|
-
].join('\n'),
|
|
51
|
-
machine,
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (error.code === 'commander.excessArguments') {
|
|
56
|
-
const usage = usageFor(matched.path, matched.command)
|
|
57
|
-
const extra = tokens.slice(matched.path.length).join(' ')
|
|
58
|
-
return maybeMachine(
|
|
59
|
-
[
|
|
60
|
-
`Unexpected argument${extra.includes(' ') ? 's' : ''} for ${chalk.bold(
|
|
61
|
-
`astrale ${matched.path.join(' ')}`,
|
|
62
|
-
)}${extra ? `: ${extra}` : ''}`,
|
|
63
|
-
'',
|
|
64
|
-
'Usage:',
|
|
65
|
-
` astrale ${usage}`,
|
|
66
|
-
].join('\n'),
|
|
67
|
-
machine,
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const suggestions = nearestCommands(tokens.join(' '), catalog)
|
|
72
|
-
return maybeMachine(
|
|
73
|
-
[
|
|
74
|
-
error.message,
|
|
75
|
-
...(suggestions.length > 0
|
|
76
|
-
? ['', 'Did you mean:', ...suggestions.map((s) => ` astrale ${s}`)]
|
|
77
|
-
: []),
|
|
78
|
-
].join('\n'),
|
|
79
|
-
machine,
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const RETIRED_COMMANDS: Record<string, string> = {
|
|
84
|
-
ls: 'astrale query <source> --edge <class>',
|
|
85
|
-
describe: 'astrale get <target>',
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function renderUnknownCommand(tokens: string[], catalog: CommandCatalogEntry[]): string {
|
|
89
|
-
const command = tokens.join(' ')
|
|
90
|
-
const first = tokens[0]
|
|
91
|
-
const retired = first === undefined ? undefined : RETIRED_COMMANDS[first]
|
|
92
|
-
if (retired !== undefined) {
|
|
93
|
-
return [
|
|
94
|
-
`Unknown command: ${chalk.bold(`astrale ${command}`)}`,
|
|
95
|
-
'',
|
|
96
|
-
`\`astrale ${first}\` was removed. Use ${chalk.bold(retired)} instead.`,
|
|
97
|
-
].join('\n')
|
|
98
|
-
}
|
|
99
|
-
const namespaceMatches = catalog.filter((entry) => entry.path.at(-1) === first)
|
|
100
|
-
if (namespaceMatches.length > 0) {
|
|
101
|
-
return [
|
|
102
|
-
`Unknown command: ${chalk.bold(`astrale ${command}`)}`,
|
|
103
|
-
'',
|
|
104
|
-
`"${first}" is available under:`,
|
|
105
|
-
...namespaceMatches.map((entry) => ` astrale ${entry.usage}`),
|
|
106
|
-
].join('\n')
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const suggestions = nearestCommands(command, catalog)
|
|
110
|
-
return [
|
|
111
|
-
`Unknown command: ${chalk.bold(`astrale ${command}`)}`,
|
|
112
|
-
...(suggestions.length > 0
|
|
113
|
-
? ['', 'Did you mean:', ...suggestions.map((s) => ` astrale ${s}`)]
|
|
114
|
-
: []),
|
|
115
|
-
].join('\n')
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function matchRegisteredPrefix(
|
|
119
|
-
program: Command,
|
|
120
|
-
tokens: string[],
|
|
121
|
-
): { command: Command; path: string[] } {
|
|
122
|
-
let current = program
|
|
123
|
-
const path: string[] = []
|
|
124
|
-
for (const token of tokens) {
|
|
125
|
-
const next = current.commands.find(
|
|
126
|
-
(cmd) => cmd.name() === token || cmd.aliases().includes(token),
|
|
127
|
-
)
|
|
128
|
-
if (!next) break
|
|
129
|
-
current = next
|
|
130
|
-
path.push(current.name())
|
|
131
|
-
}
|
|
132
|
-
return { command: current, path }
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function usageFor(path: string[], command: Command): string {
|
|
136
|
-
const suffix = command
|
|
137
|
-
.usage()
|
|
138
|
-
.replace(/\[options\]\s*/g, '')
|
|
139
|
-
.replace(/\s+/g, ' ')
|
|
140
|
-
.trim()
|
|
141
|
-
return [path.join(' '), suffix].filter(Boolean).join(' ')
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const ANSI_RE = new RegExp(String.fromCharCode(27) + '\\[[0-9;]*m', 'g')
|
|
145
|
-
|
|
146
|
-
function maybeMachine(text: string, machine: boolean): string {
|
|
147
|
-
if (!machine) return text
|
|
148
|
-
const plain = text.replace(ANSI_RE, '')
|
|
149
|
-
const first = plain.split('\n').find((line) => line.trim().length > 0) ?? plain
|
|
150
|
-
return JSON.stringify({ error: 'USAGE_ERROR', message: first, detail: plain })
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function stripOptions(argv: string[]): string[] {
|
|
154
|
-
const out: string[] = []
|
|
155
|
-
for (const token of argv) {
|
|
156
|
-
if (token === '--') break
|
|
157
|
-
if (token.startsWith('-')) continue
|
|
158
|
-
out.push(token)
|
|
159
|
-
}
|
|
160
|
-
return out
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function nearestCommands(input: string, catalog: CommandCatalogEntry[]): string[] {
|
|
164
|
-
if (!input) return []
|
|
165
|
-
return catalog
|
|
166
|
-
.map((entry) => ({ usage: entry.usage, score: similarity(input, entry.path.join(' ')) }))
|
|
167
|
-
.filter((entry) => entry.score >= 0.45)
|
|
168
|
-
.sort((a, b) => b.score - a.score || a.usage.localeCompare(b.usage))
|
|
169
|
-
.slice(0, 3)
|
|
170
|
-
.map((entry) => entry.usage)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function similarity(a: string, b: string): number {
|
|
174
|
-
const max = Math.max(a.length, b.length)
|
|
175
|
-
if (max === 0) return 1
|
|
176
|
-
return 1 - levenshtein(a, b) / max
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function levenshtein(a: string, b: string): number {
|
|
180
|
-
const prev = Array.from({ length: b.length + 1 }, (_, i) => i)
|
|
181
|
-
const curr = Array.from({ length: b.length + 1 }, () => 0)
|
|
182
|
-
for (let i = 1; i <= a.length; i += 1) {
|
|
183
|
-
curr[0] = i
|
|
184
|
-
for (let j = 1; j <= b.length; j += 1) {
|
|
185
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1
|
|
186
|
-
curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost)
|
|
187
|
-
}
|
|
188
|
-
prev.splice(0, prev.length, ...curr)
|
|
189
|
-
}
|
|
190
|
-
return prev[b.length] ?? 0
|
|
191
|
-
}
|
package/src/lib/concurrency.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal bounded-concurrency map. No external dependency (the repo
|
|
3
|
-
* hand-rolls with `Promise.all`); a tiny worker pool is enough for the
|
|
4
|
-
* `domain dev up` fan-out.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Run `fn` over `items` with at most `limit` in flight at once. Results
|
|
9
|
-
* are returned in input order regardless of completion order. The first
|
|
10
|
-
* rejection rejects the returned promise (in-flight work still settles).
|
|
11
|
-
*/
|
|
12
|
-
export async function mapBounded<T, R>(
|
|
13
|
-
items: readonly T[],
|
|
14
|
-
limit: number,
|
|
15
|
-
fn: (item: T, index: number) => Promise<R>,
|
|
16
|
-
): Promise<R[]> {
|
|
17
|
-
const results: R[] = []
|
|
18
|
-
const bound = Math.max(1, Math.min(limit, items.length))
|
|
19
|
-
let next = 0
|
|
20
|
-
|
|
21
|
-
async function worker(): Promise<void> {
|
|
22
|
-
while (true) {
|
|
23
|
-
const i = next++
|
|
24
|
-
if (i >= items.length) return
|
|
25
|
-
results[i] = await fn(items[i] as T, i)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
await Promise.all(Array.from({ length: bound }, () => worker()))
|
|
30
|
-
return results
|
|
31
|
-
}
|
package/src/lib/config.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises'
|
|
2
|
-
import { dirname } from 'node:path'
|
|
3
|
-
import { z } from 'zod'
|
|
4
|
-
|
|
5
|
-
import { CONFIG_PATH } from '../state/index'
|
|
6
|
-
import { AdminTargetConfigSchema, DEFAULT_ADMIN_TARGET_CONFIG } from './admin-target'
|
|
7
|
-
import { log } from './log'
|
|
8
|
-
|
|
9
|
-
/** A retention bound, or undefined when absent or nonsensical. A bad value must
|
|
10
|
-
* fall back to the default rather than take the whole config down with it —
|
|
11
|
-
* and must never read as "no limit". */
|
|
12
|
-
const bound = z.number().positive().finite().optional().catch(undefined)
|
|
13
|
-
|
|
14
|
-
export const AstraleConfigSchema = z.object({
|
|
15
|
-
issuer: z.string().url().default('https://unregistered.invalid'),
|
|
16
|
-
admin: AdminTargetConfigSchema.default(DEFAULT_ADMIN_TARGET_CONFIG),
|
|
17
|
-
// The retention bounds live in the schema, not just in the readers that
|
|
18
|
-
// consume them: zod strips unknown keys, so a config the CLI rewrites (see
|
|
19
|
-
// setup/steps/admin.ts) would silently drop anything declared elsewhere.
|
|
20
|
-
telemetry: z
|
|
21
|
-
.object({ enabled: z.boolean().default(true), maxAgeDays: bound, maxBytes: bound })
|
|
22
|
-
.default({ enabled: true }),
|
|
23
|
-
browser: z.object({ maxCacheBytes: bound, maxProfileAgeDays: bound }).default({}),
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
export type AstraleConfig = z.infer<typeof AstraleConfigSchema>
|
|
27
|
-
|
|
28
|
-
export const DEFAULT_CONFIG: AstraleConfig = AstraleConfigSchema.parse({})
|
|
29
|
-
|
|
30
|
-
export async function readConfig(): Promise<AstraleConfig> {
|
|
31
|
-
try {
|
|
32
|
-
const raw = await readFile(CONFIG_PATH, 'utf-8')
|
|
33
|
-
return AstraleConfigSchema.parse(JSON.parse(raw))
|
|
34
|
-
} catch (e) {
|
|
35
|
-
// A present-but-broken config (invalid JSON or failed validation) should
|
|
36
|
-
// surface; a missing file (readFile ENOENT) stays silent — that's the
|
|
37
|
-
// normal first-run case and defaults are expected.
|
|
38
|
-
if (e instanceof z.ZodError || e instanceof SyntaxError) {
|
|
39
|
-
log.warn(`Invalid config at ${CONFIG_PATH} — using defaults`)
|
|
40
|
-
}
|
|
41
|
-
return DEFAULT_CONFIG
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export async function writeConfig(config: AstraleConfig): Promise<void> {
|
|
46
|
-
await mkdir(dirname(CONFIG_PATH), { recursive: true })
|
|
47
|
-
await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n')
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export async function configExists(): Promise<boolean> {
|
|
51
|
-
try {
|
|
52
|
-
await readFile(CONFIG_PATH)
|
|
53
|
-
return true
|
|
54
|
-
} catch {
|
|
55
|
-
return false
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/** Whole seconds safely available after second-boundary rounding and carrier handoff. */
|
|
2
|
-
export function remainingCredentialLifetimeSeconds(
|
|
3
|
-
expiresAtEpochSeconds: number,
|
|
4
|
-
nowEpochSeconds = Math.ceil(Date.now() / 1_000),
|
|
5
|
-
): number {
|
|
6
|
-
if (!Number.isSafeInteger(expiresAtEpochSeconds) || !Number.isSafeInteger(nowEpochSeconds)) {
|
|
7
|
-
throw new TypeError('Credential expiration and current time must be safe epoch seconds.')
|
|
8
|
-
}
|
|
9
|
-
return expiresAtEpochSeconds - nowEpochSeconds - 1
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function credentialLifetimeCovers(
|
|
13
|
-
expiresAtEpochSeconds: number,
|
|
14
|
-
minimumRemainingSeconds: number,
|
|
15
|
-
nowEpochSeconds?: number,
|
|
16
|
-
): boolean {
|
|
17
|
-
if (!Number.isSafeInteger(minimumRemainingSeconds) || minimumRemainingSeconds < 1) {
|
|
18
|
-
throw new TypeError('Credential minimum lifetime must be a positive safe integer.')
|
|
19
|
-
}
|
|
20
|
-
return (
|
|
21
|
-
remainingCredentialLifetimeSeconds(expiresAtEpochSeconds, nowEpochSeconds) >=
|
|
22
|
-
minimumRemainingSeconds
|
|
23
|
-
)
|
|
24
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { publication } from '@astrale-os/sdk/publication'
|
|
2
|
-
|
|
3
|
-
const MAXIMUM_PUBLICATION_BYTES = 1024 * 1024
|
|
4
|
-
type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>
|
|
5
|
-
|
|
6
|
-
/** Fetch and admit one canonical Domain Publication without following its bundle. */
|
|
7
|
-
export async function fetchDomainPublication(
|
|
8
|
-
input: string,
|
|
9
|
-
signal?: AbortSignal,
|
|
10
|
-
fetchImpl: FetchLike = globalThis.fetch,
|
|
11
|
-
): Promise<publication.Publication> {
|
|
12
|
-
const url = domainPublicationUrl(input)
|
|
13
|
-
const response = await fetchImpl(url, {
|
|
14
|
-
redirect: 'error',
|
|
15
|
-
...(signal === undefined ? {} : { signal }),
|
|
16
|
-
})
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
await cancel(response.body)
|
|
19
|
-
throw new Error(`GET ${url.href} → ${response.status}`)
|
|
20
|
-
}
|
|
21
|
-
const bytes = await readBounded(response, url)
|
|
22
|
-
try {
|
|
23
|
-
const source = new TextDecoder('utf-8', { fatal: true }).decode(bytes)
|
|
24
|
-
return publication.accept(JSON.parse(source) as unknown)
|
|
25
|
-
} catch (cause) {
|
|
26
|
-
throw new Error(`GET ${url.href} returned an invalid Domain Publication`, { cause })
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function readBounded(response: Response, url: URL): Promise<Uint8Array> {
|
|
31
|
-
const declared = response.headers.get('content-length')
|
|
32
|
-
if (
|
|
33
|
-
declared !== null &&
|
|
34
|
-
(!/^\d+$/u.test(declared) ||
|
|
35
|
-
!Number.isSafeInteger(Number(declared)) ||
|
|
36
|
-
Number(declared) > MAXIMUM_PUBLICATION_BYTES)
|
|
37
|
-
) {
|
|
38
|
-
await cancel(response.body)
|
|
39
|
-
throw sizeError(url)
|
|
40
|
-
}
|
|
41
|
-
if (response.body === null) return new Uint8Array()
|
|
42
|
-
|
|
43
|
-
const reader = response.body.getReader()
|
|
44
|
-
const chunks: Uint8Array[] = []
|
|
45
|
-
let size = 0
|
|
46
|
-
let complete = false
|
|
47
|
-
try {
|
|
48
|
-
for (;;) {
|
|
49
|
-
const next = await reader.read()
|
|
50
|
-
if (next.done) {
|
|
51
|
-
complete = true
|
|
52
|
-
break
|
|
53
|
-
}
|
|
54
|
-
if (next.value.byteLength === 0) continue
|
|
55
|
-
if (next.value.byteLength > MAXIMUM_PUBLICATION_BYTES - size) {
|
|
56
|
-
throw sizeError(url)
|
|
57
|
-
}
|
|
58
|
-
chunks.push(next.value)
|
|
59
|
-
size += next.value.byteLength
|
|
60
|
-
}
|
|
61
|
-
} finally {
|
|
62
|
-
if (!complete) await reader.cancel().catch(() => undefined)
|
|
63
|
-
reader.releaseLock()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const bytes = new Uint8Array(size)
|
|
67
|
-
let offset = 0
|
|
68
|
-
for (const chunk of chunks) {
|
|
69
|
-
bytes.set(chunk, offset)
|
|
70
|
-
offset += chunk.byteLength
|
|
71
|
-
}
|
|
72
|
-
return bytes
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function sizeError(url: URL): Error {
|
|
76
|
-
return new Error(`GET ${url.href} exceeded ${MAXIMUM_PUBLICATION_BYTES} bytes`)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function cancel(body: ReadableStream<Uint8Array> | null): Promise<void> {
|
|
80
|
-
if (body !== null) await body.cancel().catch(() => undefined)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Canonical discovery document for a Domain origin or exact Publication URL. */
|
|
84
|
-
export function domainPublicationUrl(input: string): URL {
|
|
85
|
-
let url: URL
|
|
86
|
-
try {
|
|
87
|
-
url = new URL(input)
|
|
88
|
-
} catch {
|
|
89
|
-
throw new TypeError(`Domain deployment URL is invalid: ${input}`)
|
|
90
|
-
}
|
|
91
|
-
if (
|
|
92
|
-
!['http:', 'https:'].includes(url.protocol) ||
|
|
93
|
-
url.username !== '' ||
|
|
94
|
-
url.password !== '' ||
|
|
95
|
-
url.search !== '' ||
|
|
96
|
-
url.hash !== '' ||
|
|
97
|
-
!['', '/', publication.PATH].includes(url.pathname)
|
|
98
|
-
) {
|
|
99
|
-
throw new TypeError(
|
|
100
|
-
`Domain deployment URL must be an HTTP(S) origin or canonical Publication URL: ${input}`,
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
return new URL(publication.PATH, url.origin)
|
|
104
|
-
}
|