@astrale-os/cli 1.0.0-beta.1 → 1.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -12
- package/dist/astrale.js +48048 -56798
- package/dist/public/connect-core.js +2011 -30765
- package/dist/public/keys/index.js +884 -29483
- package/dist/public/paths/index.js +13101 -41459
- package/dist/types/admin/binding.d.ts +19 -0
- package/dist/types/admin/instance/client.d.ts +22 -0
- package/dist/types/admin/instance/index.d.ts +2 -0
- package/dist/types/admin/instance/model.d.ts +5 -12
- package/dist/types/connection/auth.d.ts +3 -0
- package/dist/types/connection/call.d.ts +3 -0
- package/dist/types/connection/command.d.ts +27 -0
- package/dist/types/connection/credential.d.ts +14 -0
- package/dist/types/connection/errors.d.ts +1 -0
- package/dist/types/connection/exchange.d.ts +9 -0
- package/dist/types/connection/failure/classify.d.ts +2 -0
- package/dist/types/connection/failure/index.d.ts +5 -0
- package/dist/types/connection/failure/model.d.ts +25 -0
- package/dist/types/connection/failure/render.d.ts +3 -0
- package/dist/types/connection/index.d.ts +8 -0
- package/dist/types/connection/reasons.d.ts +37 -0
- package/dist/types/connection/self.d.ts +37 -0
- package/dist/types/connection/session.d.ts +31 -0
- package/dist/types/connection/target.d.ts +38 -0
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/lib/admin-instance.d.ts +17 -0
- package/dist/types/lib/admin-target.d.ts +11 -36
- package/dist/types/lib/config.d.ts +7 -59
- package/dist/types/lib/failure-debug.d.ts +1 -0
- package/dist/types/lib/idp.d.ts +26 -168
- package/dist/types/lib/instance-target.d.ts +1 -1
- package/dist/types/lib/instance.d.ts +30 -88
- package/dist/types/lib/log.d.ts +5 -3
- package/dist/types/lib/meta.d.ts +2 -2
- package/dist/types/lib/proc.d.ts +43 -0
- package/dist/types/lib/self.d.ts +9 -0
- package/dist/types/lib/update.d.ts +91 -0
- package/dist/types/lib/validation.d.ts +4 -1
- package/package.json +16 -19
- package/src/__tests__/fixtures/publication.ts +20 -0
- package/src/admin/__tests__/binding.test.ts +31 -0
- package/src/admin/__tests__/fixture.ts +101 -0
- package/src/admin/binding.ts +98 -0
- package/src/admin/catalog/.spec/api.d.ts +2 -2
- package/src/admin/catalog/__tests__/client.test.ts +20 -49
- package/src/admin/catalog/client.ts +36 -32
- package/src/admin/catalog/model.ts +3 -4
- package/src/admin/graph/.spec/api.d.ts +4 -10
- package/src/admin/graph/nodes.ts +1 -1
- package/src/admin/instance/.spec/api.d.ts +2 -2
- package/src/admin/instance/__tests__/client.test.ts +39 -164
- package/src/admin/instance/client.ts +35 -124
- package/src/admin/instance/index.ts +1 -2
- package/src/admin/instance/model.ts +11 -20
- package/src/commands/__tests__/admin-instance.test.ts +11 -8
- package/src/commands/__tests__/auth-login.test.ts +54 -1
- package/src/commands/__tests__/call-describe.test.ts +46 -33
- package/src/commands/__tests__/call.test.ts +5 -1
- package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
- package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
- package/src/commands/__tests__/domain-list.test.ts +63 -4
- package/src/commands/__tests__/install-identity-override.test.ts +19 -19
- package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
- package/src/commands/__tests__/instance-status.test.ts +139 -0
- package/src/commands/__tests__/read-commands.test.ts +35 -10
- package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
- package/src/commands/__tests__/update.test.ts +48 -19
- package/src/commands/call-describe.ts +60 -68
- package/src/commands/call.ts +43 -56
- package/src/commands/domain/install.ts +13 -17
- package/src/commands/domain/list.ts +18 -13
- package/src/commands/domain/publish.ts +14 -11
- package/src/commands/domain/uninstall.ts +2 -2
- package/src/commands/get.ts +14 -15
- package/src/commands/identity/__tests__/register.test.ts +3 -3
- package/src/commands/identity/register.ts +5 -4
- package/src/commands/instance/create.ts +8 -16
- package/src/commands/instance/delete.ts +12 -9
- package/src/commands/instance/list.ts +2 -2
- package/src/commands/instance/status.ts +66 -20
- package/src/commands/instance/use.ts +16 -12
- package/src/commands/introspect.ts +9 -16
- package/src/commands/logs.ts +24 -25
- package/src/commands/mutate.ts +6 -5
- package/src/commands/query.ts +27 -30
- package/src/commands/studio.ts +20 -0
- package/src/commands/token.ts +8 -7
- package/src/commands/update.ts +38 -14
- package/src/commands/view.ts +7 -6
- package/src/connection/.spec/api.d.ts +7 -8
- package/src/connection/.spec/architecture.md +5 -4
- package/src/connection/.spec/flows/session.ts +2 -2
- package/src/connection/.spec/laws/connection.ts +6 -2
- package/src/connection/.spec/layout.ts +1 -0
- package/src/connection/__tests__/credential.test.ts +20 -1
- package/src/connection/__tests__/errors.test.ts +43 -32
- package/src/connection/__tests__/exchange.test.ts +36 -6
- package/src/connection/__tests__/failure-fixtures.ts +39 -0
- package/src/connection/__tests__/failure-safety.test.ts +75 -0
- package/src/connection/__tests__/self.test.ts +31 -11
- package/src/connection/__tests__/session.test.ts +3 -3
- package/src/connection/__tests__/target.test.ts +1 -0
- package/src/connection/auth.ts +13 -0
- package/src/connection/call.ts +1 -1
- package/src/connection/credential.ts +2 -2
- package/src/connection/errors.ts +1 -355
- package/src/connection/exchange.ts +52 -27
- package/src/connection/failure/classify.ts +110 -0
- package/src/connection/failure/index.ts +18 -0
- package/src/connection/failure/model.ts +28 -0
- package/src/connection/failure/render.ts +116 -0
- package/src/connection/reasons.ts +16 -0
- package/src/connection/self.ts +39 -21
- package/src/connection/session.ts +19 -8
- package/src/errors.ts +3 -2
- package/src/graph/.spec/api.d.ts +12 -5
- package/src/graph/.spec/layout.ts +9 -1
- package/src/graph/__tests__/mutation.test.ts +2 -2
- package/src/graph/__tests__/query.test.ts +25 -6
- package/src/graph/class.ts +30 -0
- package/src/graph/index.ts +1 -0
- package/src/graph/query.ts +21 -32
- package/src/identity/.spec/api.d.ts +2 -2
- package/src/identity/__tests__/registration.test.ts +1 -1
- package/src/identity/registration.ts +3 -3
- package/src/keys/__tests__/keys.test.ts +4 -0
- package/src/keys/credential.ts +1 -0
- package/src/lib/__tests__/admin-target.test.ts +12 -0
- package/src/lib/__tests__/command-dx.test.ts +1 -1
- package/src/lib/__tests__/domain-publication.test.ts +138 -0
- package/src/lib/__tests__/idp-session.test.ts +22 -0
- package/src/lib/__tests__/idp.test.ts +36 -4
- package/src/lib/__tests__/instance-candidates.test.ts +1 -3
- package/src/lib/__tests__/instance-target.test.ts +7 -39
- package/src/lib/__tests__/instance.test.ts +6 -0
- package/src/lib/__tests__/log-errors.test.ts +64 -0
- package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
- package/src/lib/__tests__/update.test.ts +113 -8
- package/src/lib/__tests__/view-open-intent.test.ts +0 -2
- package/src/lib/__tests__/view-server.test.ts +18 -3
- package/src/lib/__tests__/view-session.test.ts +1 -1
- package/src/lib/admin-instance.ts +14 -8
- package/src/lib/admin-target.ts +21 -2
- package/src/lib/command-dx.ts +9 -9
- package/src/lib/domain-publication.ts +104 -0
- package/src/lib/failure-debug.ts +26 -0
- package/src/lib/idp.ts +39 -4
- package/src/lib/instance-candidates.ts +2 -2
- package/src/lib/instance-target.ts +3 -14
- package/src/lib/instance.ts +22 -12
- package/src/lib/log.ts +16 -9
- package/src/lib/login-flow.ts +13 -3
- package/src/lib/meta.ts +2 -2
- package/src/lib/provision-instance.ts +34 -57
- package/src/lib/update.ts +124 -30
- package/src/lib/validation.ts +2 -2
- package/src/lib/view/resolve.ts +1 -1
- package/src/lib/view/server.ts +17 -3
- package/src/program/__tests__/program.test.ts +20 -4
- package/src/program/build.ts +2 -2
- package/src/setup/__tests__/instance-step.test.ts +27 -10
- package/src/setup/steps/instance.ts +22 -15
- package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
- package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
- package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
- package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
- package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
- package/studio/client/dist/index.html +3 -2
- package/studio/package.json +10 -14
- package/studio/server/agent/ask.test.ts +1 -1
- package/studio/server/agent/bridge/grant.test.ts +1 -1
- package/studio/server/agent/bridge/routes.test.ts +1 -1
- package/studio/server/agent/bridge/stdio.ts +8 -1
- package/studio/server/agent/conversation.test.ts +10 -5
- package/studio/server/agent/conversation.ts +56 -8
- package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
- package/studio/server/agent/harness/codex/loadout.ts +18 -21
- package/studio/server/agent/harness/gateway/config.ts +20 -18
- package/studio/server/agent/harness/selection.ts +9 -1
- package/studio/server/agent/prompts/anchors.test.ts +32 -36
- package/studio/server/agent/prompts/anchors.ts +20 -49
- package/studio/server/agent/prompts/system.test.ts +3 -2
- package/studio/server/agent/prompts/system.ts +6 -5
- package/studio/server/agent/prompts/turn.ts +13 -4
- package/studio/server/agent/routes.test.ts +1 -1
- package/studio/server/agent/run/completion.ts +2 -2
- package/studio/server/agent/run/coordinator.test.ts +1 -1
- package/studio/server/agent/run/preparation.ts +6 -5
- package/studio/server/agent/run/transcript.test.ts +35 -1
- package/studio/server/agent/run/transcript.ts +169 -3
- package/studio/server/agent/run/usage.test.ts +24 -0
- package/studio/server/agent/run/usage.ts +26 -1
- package/studio/server/api/canvas.ts +43 -0
- package/studio/server/api/comments.ts +85 -0
- package/studio/server/api/context.ts +61 -0
- package/studio/server/api/deployment.ts +39 -0
- package/studio/server/api/documents.ts +55 -0
- package/studio/server/api/domain.ts +59 -0
- package/studio/server/api/http.ts +45 -0
- package/studio/server/api/project.ts +57 -0
- package/studio/server/api/schema.ts +12 -0
- package/studio/server/api/views.ts +57 -0
- package/studio/server/api/workspace.ts +60 -0
- package/studio/server/api-agent-loadout.test.ts +1 -1
- package/studio/server/api.test.ts +147 -0
- package/studio/server/api.ts +20 -422
- package/studio/server/cache.test.ts +122 -0
- package/studio/server/cache.ts +162 -11
- package/studio/server/cli-consumers.test.ts +494 -0
- package/studio/server/cli.test.ts +88 -0
- package/studio/server/cli.ts +240 -0
- package/studio/server/client-package.ts +25 -1
- package/studio/server/domain.test.ts +50 -40
- package/studio/server/domain.ts +83 -52
- package/studio/server/environment/dotenv-preview.test.ts +39 -0
- package/studio/server/environment/dotenv-preview.ts +27 -0
- package/studio/server/environment/files.test.ts +53 -0
- package/studio/server/{state/env.ts → environment/files.ts} +7 -48
- package/studio/server/{state → handoff}/copy.ts +21 -6
- package/studio/server/handoff/service.test.ts +22 -0
- package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
- package/studio/server/index.ts +1 -1
- package/studio/server/instances/active.ts +72 -0
- package/studio/server/instances/deploy-record.test.ts +31 -0
- package/studio/server/instances/deploy-record.ts +37 -0
- package/studio/server/instances/deploy.ts +56 -0
- package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
- package/studio/server/instances/probe.ts +67 -0
- package/studio/server/instances/status.test.ts +12 -0
- package/studio/server/instances/status.ts +49 -0
- package/studio/server/introspect/anatomy/client-tree.ts +57 -0
- package/studio/server/introspect/anatomy/env-fields.ts +66 -0
- package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
- package/studio/server/introspect/anatomy/source.ts +181 -0
- package/studio/server/introspect/anatomy/views/routes.ts +114 -0
- package/studio/server/introspect/anatomy/views.ts +53 -0
- package/studio/server/introspect/anatomy-extras.test.ts +106 -35
- package/studio/server/introspect/anatomy-extras.ts +7 -726
- package/studio/server/introspect/anatomy.test.ts +22 -14
- package/studio/server/introspect/anatomy.ts +52 -28
- package/studio/server/introspect/bundle.ts +15 -9
- package/studio/server/introspect/canonical-schema.test.ts +93 -309
- package/studio/server/introspect/canonical-schema.ts +257 -425
- package/studio/server/introspect/config-preview.test.ts +32 -0
- package/studio/server/introspect/config-preview.ts +119 -0
- package/studio/server/introspect/core-extractor.ts +18 -127
- package/studio/server/introspect/core.ts +1 -2
- package/studio/server/introspect/diff.test.ts +18 -18
- package/studio/server/introspect/diff.ts +44 -90
- package/studio/server/introspect/extractor.ts +23 -116
- package/studio/server/introspect/hash.ts +5 -2
- package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
- package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
- package/studio/server/introspect/overlay.test.ts +26 -54
- package/studio/server/introspect/overlay.ts +10 -37
- package/studio/server/introspect/revision.test.ts +54 -0
- package/studio/server/introspect/revision.ts +49 -0
- package/studio/server/introspect/runtime.test.ts +83 -143
- package/studio/server/introspect/runtime.ts +40 -11
- package/studio/server/introspect/schema-ir-json.test.ts +70 -0
- package/studio/server/introspect/schema-ir-json.ts +151 -0
- package/studio/server/introspect/schema-refs.test.ts +43 -88
- package/studio/server/introspect/schema-refs.ts +14 -49
- package/studio/server/introspect/source-overlay/annotations.ts +14 -0
- package/studio/server/introspect/source-overlay/handlers.ts +161 -0
- package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
- package/studio/server/introspect/source-overlay/project.ts +248 -0
- package/studio/server/introspect/source-overlay/spans.ts +330 -0
- package/studio/server/json.ts +46 -0
- package/studio/server/lifecycle.ts +5 -1
- package/studio/server/sse.test.ts +26 -0
- package/studio/server/sse.ts +4 -1
- package/studio/server/state/baseline.test.ts +223 -7
- package/studio/server/state/baseline.ts +148 -34
- package/studio/server/state/comments.test.ts +66 -1
- package/studio/server/state/comments.ts +173 -10
- package/studio/server/state/context.ts +34 -2
- package/studio/server/state/documents.ts +42 -1
- package/studio/server/state/integrations.ts +27 -1
- package/studio/server/state/layout.test.ts +34 -0
- package/studio/server/state/layout.ts +44 -17
- package/studio/server/state/settings.ts +29 -22
- package/studio/server/state/store.test.ts +122 -0
- package/studio/server/state/store.ts +66 -17
- package/studio/server/state/visibility.ts +22 -11
- package/studio/server/views/model.test.ts +57 -0
- package/studio/server/views/model.ts +66 -0
- package/studio/server/views/runtime.ts +40 -0
- package/studio/server/views/selection-repository.test.ts +31 -0
- package/studio/server/views/selection-repository.ts +60 -0
- package/studio/server/views/session.test.ts +73 -0
- package/studio/server/views/session.ts +166 -0
- package/studio/server/views/target.test.ts +78 -0
- package/studio/server/views/target.ts +222 -0
- package/studio/server/watch.test.ts +11 -11
- package/studio/server/watch.ts +9 -5
- package/studio/server/workspace/catalog.test.ts +17 -0
- package/studio/server/workspace/catalog.ts +43 -0
- package/studio/server/{state → workspace}/create.test.ts +1 -1
- package/studio/server/{state → workspace}/create.ts +1 -1
- package/studio/server/{state → workspace}/git.ts +1 -1
- package/studio/server/workspace/updates.ts +83 -0
- package/studio/server/workspace-state.ts +1 -1
- package/studio/server/workspace-watch.ts +2 -2
- package/studio/shared/contracts/README.md +16 -0
- package/studio/shared/contracts/agent.ts +270 -0
- package/studio/shared/contracts/runtime.ts +50 -0
- package/studio/shared/contracts/schema.ts +393 -0
- package/studio/shared/contracts/surface.test.ts +317 -0
- package/studio/shared/contracts/workspace.ts +265 -0
- package/studio/shared/layout.test.ts +116 -0
- package/studio/shared/schema/identity.test.ts +34 -0
- package/studio/shared/schema/identity.ts +68 -0
- package/studio/shared/types.ts +11 -1099
- package/studio/tsconfig.json +1 -1
- package/viewer/dist/main.js +40 -61
- package/.check-workspace.cjs +0 -40
- package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
- package/studio/client/dist/assets/elk-api-D2xgMJvi.js +0 -1
- package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
- package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
- package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
- package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
- package/studio/server/state/catalog.ts +0 -117
- package/studio/server/state/instance.ts +0 -280
- package/studio/server/state/updates.ts +0 -63
- package/studio/server/state/views.test.ts +0 -286
- package/studio/server/state/views.ts +0 -535
|
@@ -6,6 +6,7 @@ import type { CommandDefinition } from '../../program/index'
|
|
|
6
6
|
|
|
7
7
|
import { listAdminDomains, type DomainInfo } from '../../lib/admin-domain'
|
|
8
8
|
import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
|
|
9
|
+
import { fetchDomainPublication } from '../../lib/domain-publication'
|
|
9
10
|
import { fatal, withSpinner } from '../../lib/log'
|
|
10
11
|
import { isMachine, presentList } from '../../lib/output'
|
|
11
12
|
|
|
@@ -23,7 +24,7 @@ type ListOpts = KernelCommandOpts &
|
|
|
23
24
|
/** A catalog entry, optionally enriched with a live `--check` probe. */
|
|
24
25
|
export type DomainRow = DomainInfo & {
|
|
25
26
|
reachable?: boolean
|
|
26
|
-
|
|
27
|
+
schemaRevision?: string
|
|
27
28
|
checkError?: string | null
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -72,9 +73,9 @@ Behavior:
|
|
|
72
73
|
or with --json/--raw (agent-friendly — full DomainInfo objects). -q prints
|
|
73
74
|
one install URL per line (pipeable into \`domain install\`); --count prints
|
|
74
75
|
only the number. --default-only keeps the install-by-default entries (what
|
|
75
|
-
every new instance
|
|
76
|
-
|
|
77
|
-
machine output).
|
|
76
|
+
every new instance receives during Admin-managed provisioning). --check probes each published URL's
|
|
77
|
+
canonical Publication and adds a live/unreachable STATUS column
|
|
78
|
+
(+ reachable/schemaRevision in machine output).
|
|
78
79
|
|
|
79
80
|
The admin kernel is selected like every admin op — the configured default,
|
|
80
81
|
or --admin <bookmark> / --admin-url <url>.
|
|
@@ -87,7 +88,10 @@ Examples:
|
|
|
87
88
|
`,
|
|
88
89
|
options: [
|
|
89
90
|
...ADMIN_TARGET_OPTIONS,
|
|
90
|
-
{
|
|
91
|
+
{
|
|
92
|
+
flags: '--check',
|
|
93
|
+
description: "Probe each domain's canonical Publication + schema revision",
|
|
94
|
+
},
|
|
91
95
|
{ flags: '--default-only', description: 'Only show install-by-default domains' },
|
|
92
96
|
{ flags: '-q, --quiet', description: 'One install URL per line (unix-pipeable)' },
|
|
93
97
|
{ flags: '--count', description: 'Print only the number of published domains' },
|
|
@@ -103,7 +107,7 @@ Examples:
|
|
|
103
107
|
const filtered = opts.defaultOnly ? list.filter((d) => d.installByDefault) : list
|
|
104
108
|
filtered.sort(byDefaultThenName)
|
|
105
109
|
if (!opts.check) return filtered as DomainRow[]
|
|
106
|
-
// Reachability is a direct client-side
|
|
110
|
+
// Reachability is a direct client-side Publication fetch per entry, in
|
|
107
111
|
// parallel — no admin round-trip, and version-independent of the
|
|
108
112
|
// admin worker (mirrors `domain install`'s probeDeclaredOrigin).
|
|
109
113
|
return Promise.all(filtered.map(probe))
|
|
@@ -129,19 +133,20 @@ export function byDefaultThenName(a: DomainInfo, b: DomainInfo): number {
|
|
|
129
133
|
|
|
130
134
|
/**
|
|
131
135
|
* Enrich one entry with a reachability probe: fetch the published worker's
|
|
132
|
-
*
|
|
133
|
-
*
|
|
136
|
+
* canonical Publication and read its schema revision. A dead or missing URL is
|
|
137
|
+
* itself a result, not a throw.
|
|
134
138
|
*/
|
|
135
|
-
async function probe(d: DomainInfo): Promise<DomainRow> {
|
|
139
|
+
export async function probe(d: DomainInfo): Promise<DomainRow> {
|
|
136
140
|
if (!d.url) return { ...d, reachable: false, checkError: 'no url published' }
|
|
137
141
|
try {
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
|
|
142
|
+
const deployed = await fetchDomainPublication(d.url, AbortSignal.timeout(10_000))
|
|
143
|
+
if (deployed.origin !== d.origin) {
|
|
144
|
+
throw new Error(`Domain origin mismatch: deployed=${deployed.origin} expected=${d.origin}`)
|
|
145
|
+
}
|
|
141
146
|
return {
|
|
142
147
|
...d,
|
|
143
148
|
reachable: true,
|
|
144
|
-
|
|
149
|
+
schemaRevision: deployed.schema.revision,
|
|
145
150
|
checkError: null,
|
|
146
151
|
}
|
|
147
152
|
} catch (err) {
|
|
@@ -3,9 +3,11 @@ import chalk from 'chalk'
|
|
|
3
3
|
import type { KernelCommandOpts } from '../../connection'
|
|
4
4
|
import type { CommandDefinition } from '../../program/index'
|
|
5
5
|
|
|
6
|
+
import { formatKernelError } from '../../connection/errors'
|
|
6
7
|
import { publishAdminDomain } from '../../lib/admin-domain'
|
|
7
8
|
import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
|
|
8
|
-
import {
|
|
9
|
+
import { domainPublicationUrl } from '../../lib/domain-publication'
|
|
10
|
+
import { withSpinner } from '../../lib/log'
|
|
9
11
|
import { isMachine, output } from '../../lib/output'
|
|
10
12
|
import { promptText } from '../../lib/prompt'
|
|
11
13
|
import { isHttpUrl, validateName, validateUrl } from '../../lib/validation'
|
|
@@ -48,9 +50,9 @@ Behavior:
|
|
|
48
50
|
|
|
49
51
|
Publishing only makes the domain INSTALLABLE. Mount it on an instance with
|
|
50
52
|
\`astrale domain install <url>\` (or rely on the admin's install-by-default
|
|
51
|
-
policy).
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
policy). Deployment and catalog publication are separate owners: run the
|
|
54
|
+
project's \`astrale-domain deploy <environment>\`, then publish its observed
|
|
55
|
+
public URL with this command.
|
|
54
56
|
|
|
55
57
|
Run in a terminal with flags omitted and it PROMPTS for origin / name /
|
|
56
58
|
public-url (origin defaults to the URL host, name to the origin's first
|
|
@@ -68,17 +70,16 @@ Examples:
|
|
|
68
70
|
{ flags: '--description <text>', description: 'Optional human description for the catalog' },
|
|
69
71
|
{
|
|
70
72
|
flags: '--install-by-default',
|
|
71
|
-
description: 'Mark the domain for install on every new instance
|
|
73
|
+
description: 'Mark the domain for install on every new instance',
|
|
72
74
|
},
|
|
73
75
|
],
|
|
74
76
|
// No positional arguments → Commander passes (opts, command); `opts` is first.
|
|
75
77
|
action: async (opts: PublishOpts) => {
|
|
76
78
|
try {
|
|
77
79
|
// Interactive fill (TTY only): a human running this by hand is prompted for
|
|
78
|
-
// any missing field.
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
// so a piped / agent / LLM run fails fast instead of hanging on a read.
|
|
80
|
+
// any missing field. Automation passes every flag. No TTY / --ci /
|
|
81
|
+
// --no-prompt / CI env means no prompt: fall straight through to the
|
|
82
|
+
// required-flag error below so a piped or agent run fails fast.
|
|
82
83
|
const interactive = !!process.stdin.isTTY && !(opts.ci || opts.noPrompt || process.env.CI)
|
|
83
84
|
let { origin, name, publicUrl } = opts
|
|
84
85
|
if (interactive) {
|
|
@@ -102,6 +103,7 @@ Examples:
|
|
|
102
103
|
validateName(origin, 'origin')
|
|
103
104
|
validateName(name, 'domain')
|
|
104
105
|
validateUrl(publicUrl)
|
|
106
|
+
const discoveryUrl = domainPublicationUrl(publicUrl).href
|
|
105
107
|
|
|
106
108
|
const result = await withSpinner(
|
|
107
109
|
`Publishing ${name} → ${publicUrl}`,
|
|
@@ -110,7 +112,7 @@ Examples:
|
|
|
110
112
|
publishAdminDomain(opts, {
|
|
111
113
|
origin,
|
|
112
114
|
name,
|
|
113
|
-
url:
|
|
115
|
+
url: discoveryUrl,
|
|
114
116
|
...(opts.description ? { description: opts.description } : {}),
|
|
115
117
|
...(opts.installByDefault ? { installByDefault: true } : {}),
|
|
116
118
|
}),
|
|
@@ -127,7 +129,8 @@ Examples:
|
|
|
127
129
|
return
|
|
128
130
|
}
|
|
129
131
|
} catch (e) {
|
|
130
|
-
|
|
132
|
+
await formatKernelError(e, isMachine(opts), undefined, opts.debug)
|
|
133
|
+
process.exit(1)
|
|
131
134
|
}
|
|
132
135
|
},
|
|
133
136
|
} satisfies CommandDefinition
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Path } from '@astrale-os/sdk/graph/path'
|
|
2
|
-
import {
|
|
2
|
+
import { K } from '@astrale-os/sdk/schema'
|
|
3
3
|
import chalk from 'chalk'
|
|
4
4
|
|
|
5
5
|
import type { KernelCommandOpts } from '../../connection'
|
|
@@ -77,7 +77,7 @@ Examples:
|
|
|
77
77
|
label: `Uninstalling domain ${origin}`,
|
|
78
78
|
fn: async ({ session }) =>
|
|
79
79
|
(await session.call(
|
|
80
|
-
createPathCall(Path.project(
|
|
80
|
+
createPathCall(Path.project(K.functions.uninstall.ref).raw, uninstallCallInput(origin)),
|
|
81
81
|
)) as UninstallResult,
|
|
82
82
|
format: (result, formatOpts, machine) => {
|
|
83
83
|
if (machine) {
|
package/src/commands/get.ts
CHANGED
|
@@ -4,40 +4,39 @@ import type { KernelCommandOpts } from '../connection'
|
|
|
4
4
|
import type { CommandDefinition } from '../program/index'
|
|
5
5
|
|
|
6
6
|
import { expandSelfInPath, runKernelCommand, withSelfHint } from '../connection'
|
|
7
|
-
import { formatKernelError } from '../connection/errors'
|
|
8
7
|
import { AstraleError } from '../errors'
|
|
9
|
-
import {
|
|
8
|
+
import { failInput, fatal } from '../lib/log'
|
|
9
|
+
import { denoise, output } from '../lib/output'
|
|
10
10
|
|
|
11
11
|
type GetOpts = KernelCommandOpts & { schema?: boolean }
|
|
12
12
|
|
|
13
13
|
/** Read one exact canonical Node. The caller's Path is not fabricated into the Node value. */
|
|
14
14
|
export async function getCommand(target: string, opts: GetOpts): Promise<void> {
|
|
15
|
-
let path: string
|
|
16
|
-
let meta
|
|
17
15
|
let parsed
|
|
18
16
|
try {
|
|
19
|
-
|
|
20
|
-
parsed = Path.parse(path)
|
|
17
|
+
parsed = Path.parse(target)
|
|
21
18
|
} catch (error) {
|
|
22
|
-
|
|
23
|
-
process.exit(1)
|
|
19
|
+
failInput(error, opts)
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
const last = parsed.ast.steps.at(-1)
|
|
27
23
|
if (last?.kind === 'method') {
|
|
28
24
|
const error = new AstraleError(
|
|
29
25
|
'NOT_A_NODE',
|
|
30
|
-
`${
|
|
31
|
-
`Use \`astrale call ${
|
|
26
|
+
`${target} is a callable Path, not a Node.`,
|
|
27
|
+
`Use \`astrale call ${target}\` or \`astrale introspect ${target}\`.`,
|
|
32
28
|
)
|
|
33
|
-
|
|
34
|
-
process.exit(1)
|
|
29
|
+
fatal(error, opts)
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
await runKernelCommand({
|
|
38
33
|
opts,
|
|
39
|
-
label: `Node ${
|
|
40
|
-
fn:
|
|
34
|
+
label: `Node ${target}`,
|
|
35
|
+
fn: async (context) => {
|
|
36
|
+
const { path, meta } = await expandSelfInPath(target, context)
|
|
37
|
+
const resolved = meta === undefined ? parsed : Path.parse(path)
|
|
38
|
+
return withSelfHint(() => context.graph.getOrThrow(resolved), meta)
|
|
39
|
+
},
|
|
41
40
|
format: (node, format) => output(opts.schema === true ? node : denoise(node), format),
|
|
42
41
|
})
|
|
43
42
|
}
|
|
@@ -60,7 +59,7 @@ Examples:
|
|
|
60
59
|
$ astrale get /:notes.example.dev:class.Note
|
|
61
60
|
$ astrale get @abc123 --json
|
|
62
61
|
$ astrale get @self
|
|
63
|
-
$ astrale get /:
|
|
62
|
+
$ astrale get /:kernel.astrale.ai --schema
|
|
64
63
|
`,
|
|
65
64
|
arguments: [{ name: 'target', description: 'Canonical Node Path or @id' }],
|
|
66
65
|
options: [{ flags: '--schema', description: 'Include schema-valued properties' }],
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { issuer, jwk, provision } from '@astrale-os/sdk/auth'
|
|
2
|
-
import { ClassPath } from '@astrale-os/sdk/graph/class'
|
|
3
2
|
import { normalizeProperties } from '@astrale-os/sdk/graph/properties'
|
|
4
3
|
import { expect, mock, test } from 'bun:test'
|
|
5
4
|
import { exportJWK, generateKeyPair, jwtVerify } from 'jose'
|
|
6
5
|
|
|
6
|
+
import { classKey } from '../../../graph'
|
|
7
7
|
import { formatIdentityRegistration, prepareIdentityProvision } from '../register'
|
|
8
8
|
|
|
9
9
|
/** @evidence TEST-CLI-IDENTITY-REGISTER-JSON-EXACT */
|
|
@@ -46,7 +46,7 @@ test('builds one exact Mutation V3 identity birth bound to a self proof', async
|
|
|
46
46
|
kid: 'alice-key',
|
|
47
47
|
})
|
|
48
48
|
const kernelIssuer = issuer.accept('https://kernel.example')
|
|
49
|
-
const classPath =
|
|
49
|
+
const classPath = classKey('/:accounts.example:class.User', '--class')
|
|
50
50
|
const properties = normalizeProperties({
|
|
51
51
|
'accounts.example:class.User.property.name': 'Alice',
|
|
52
52
|
})
|
|
@@ -70,7 +70,7 @@ test('builds one exact Mutation V3 identity birth bound to a self proof', async
|
|
|
70
70
|
{
|
|
71
71
|
op: 'node.create',
|
|
72
72
|
as: 'identity',
|
|
73
|
-
class: '
|
|
73
|
+
class: 'accounts.example:class.User',
|
|
74
74
|
props: { 'accounts.example:class.User.property.name': 'Alice' },
|
|
75
75
|
},
|
|
76
76
|
],
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { IssuerId, JsonWebKey, ProvisionRequest } from '@astrale-os/sdk/auth'
|
|
2
|
+
import type { ClassKey as ClassKeyValue } from '@astrale-os/sdk/graph/class'
|
|
2
3
|
import type { JWK } from 'jose'
|
|
3
4
|
|
|
4
5
|
import { provision, jwk } from '@astrale-os/sdk/auth'
|
|
5
|
-
import {
|
|
6
|
-
import { LocalBinding } from '@astrale-os/sdk/graph/model'
|
|
6
|
+
import { LocalBinding } from '@astrale-os/sdk/graph'
|
|
7
7
|
import { normalizeProperties } from '@astrale-os/sdk/graph/properties'
|
|
8
8
|
import { MutationAST } from '@astrale-os/sdk/mutation'
|
|
9
9
|
import { importJWK, SignJWT } from 'jose'
|
|
@@ -14,6 +14,7 @@ import type { IdentityRegistrationResult } from '../../identity/index'
|
|
|
14
14
|
import type { CommandDefinition } from '../../program/index'
|
|
15
15
|
|
|
16
16
|
import { registrationKeyForTarget, runKernelCommand } from '../../connection'
|
|
17
|
+
import { classKey } from '../../graph'
|
|
17
18
|
import { getIdentity, setRegistration, submitIdentityProvision } from '../../identity/index'
|
|
18
19
|
import { fileExists, keypairPaths } from '../../keys/index'
|
|
19
20
|
import { fatal, log } from '../../lib/log'
|
|
@@ -83,7 +84,7 @@ Example:
|
|
|
83
84
|
|
|
84
85
|
const privateKey = await readJwk(privatePath)
|
|
85
86
|
const publicKey = jwk.acceptPublic(await readJwk(publicPath))
|
|
86
|
-
const classPath =
|
|
87
|
+
const classPath = classKey(opts.class, '--class')
|
|
87
88
|
const properties = normalizeProperties(opts.props ? JSON.parse(opts.props) : {})
|
|
88
89
|
|
|
89
90
|
await runKernelCommand<IdentityRegistrationResult>({
|
|
@@ -142,7 +143,7 @@ export function formatIdentityRegistration(
|
|
|
142
143
|
/** Build and self-prove one exact canonical provision request for the target Kernel. */
|
|
143
144
|
export async function prepareIdentityProvision(input: {
|
|
144
145
|
readonly name: string
|
|
145
|
-
readonly classPath:
|
|
146
|
+
readonly classPath: ClassKeyValue
|
|
146
147
|
readonly properties: ReturnType<typeof normalizeProperties>
|
|
147
148
|
readonly privateKey: JWK
|
|
148
149
|
readonly publicKey: JsonWebKey
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import type { CommandDefinition } from '../../program/index'
|
|
2
2
|
|
|
3
|
+
import { formatKernelError } from '../../connection/errors'
|
|
3
4
|
import { ADMIN_TARGET_OPTIONS } from '../../lib/admin-target'
|
|
4
|
-
import { fatal } from '../../lib/log'
|
|
5
5
|
import { isMachine, output } from '../../lib/output'
|
|
6
6
|
import { promptText } from '../../lib/prompt'
|
|
7
7
|
import { provisionInstance, type ProvisionOpts } from '../../lib/provision-instance'
|
|
8
8
|
import { validateSlug } from '../../lib/validation'
|
|
9
9
|
|
|
10
|
-
// Re-exported for tests + `astrale setup`, which share the provisioning saga.
|
|
11
|
-
export { assertAlphaCreateIdentity, parseEligibleHostIds } from '../../lib/provision-instance'
|
|
12
|
-
|
|
13
10
|
/** inquirer `validate` for a slug: true when valid, else the human message. */
|
|
14
11
|
function slugError(value: string): true | string {
|
|
15
12
|
try {
|
|
@@ -22,12 +19,12 @@ function slugError(value: string): true | string {
|
|
|
22
19
|
|
|
23
20
|
export default {
|
|
24
21
|
name: 'create',
|
|
25
|
-
description: 'Provision an
|
|
22
|
+
description: 'Provision an instance through the Admin control plane',
|
|
26
23
|
afterHelpText: `
|
|
27
24
|
Behavior:
|
|
28
|
-
|
|
29
|
-
logged in with WorkOS.
|
|
30
|
-
|
|
25
|
+
Requests a new Instance from the configured Admin Domain. The caller must be
|
|
26
|
+
logged in with WorkOS. Admin owns infrastructure placement. The new instance
|
|
27
|
+
becomes the active instance.
|
|
31
28
|
|
|
32
29
|
Run with no slug in a terminal and it prompts for one (validated live). With
|
|
33
30
|
no TTY — or --ci / --no-prompt — the slug argument is required up front, so
|
|
@@ -38,13 +35,7 @@ Examples:
|
|
|
38
35
|
$ astrale instance create demo
|
|
39
36
|
`,
|
|
40
37
|
arguments: [{ name: 'id', description: 'Instance slug', required: false }],
|
|
41
|
-
options: [
|
|
42
|
-
...ADMIN_TARGET_OPTIONS,
|
|
43
|
-
{
|
|
44
|
-
flags: '--host-id <id>',
|
|
45
|
-
description: 'Advanced: host node id to provision on when multiple hosts are available',
|
|
46
|
-
},
|
|
47
|
-
],
|
|
38
|
+
options: [...ADMIN_TARGET_OPTIONS],
|
|
48
39
|
action: async (id: string | undefined, opts: ProvisionOpts) => {
|
|
49
40
|
try {
|
|
50
41
|
// Interactive (TTY only): prompt for the slug when omitted, with live
|
|
@@ -63,7 +54,8 @@ Examples:
|
|
|
63
54
|
return
|
|
64
55
|
}
|
|
65
56
|
} catch (e) {
|
|
66
|
-
|
|
57
|
+
await formatKernelError(e, isMachine(opts), undefined, opts.debug)
|
|
58
|
+
process.exit(1)
|
|
67
59
|
}
|
|
68
60
|
},
|
|
69
61
|
} satisfies CommandDefinition
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { KernelCommandOpts } from '../../connection'
|
|
2
2
|
import type { CommandDefinition } from '../../program/index'
|
|
3
3
|
|
|
4
|
+
import { AdminInstanceNotFoundError } from '../../admin/instance'
|
|
5
|
+
import { formatKernelError } from '../../connection/errors'
|
|
4
6
|
import { deleteOwnedInstance } from '../../lib/admin-instance'
|
|
5
7
|
import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
|
|
6
8
|
import { clearActive, readInstances, removeInstance, resolveInstanceKey } from '../../lib/instance'
|
|
7
|
-
import {
|
|
9
|
+
import { log, withSpinner } from '../../lib/log'
|
|
8
10
|
import { isMachine, output } from '../../lib/output'
|
|
9
11
|
|
|
10
12
|
type DeleteOpts = KernelCommandOpts &
|
|
@@ -18,10 +20,9 @@ export default {
|
|
|
18
20
|
afterHelpText: `
|
|
19
21
|
Behavior:
|
|
20
22
|
Calls Instance.delete on the configured admin kernel: best-effort decommission
|
|
21
|
-
of the instance's
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
after the delete succeeds unless --keep-bookmark is passed.
|
|
23
|
+
of the instance's route and tenant reservation, then removes the Instance
|
|
24
|
+
projection. A same-name local bookmark is removed after the delete succeeds
|
|
25
|
+
unless --keep-bookmark is passed.
|
|
25
26
|
`,
|
|
26
27
|
arguments: [{ name: 'id', description: 'Instance slug', required: true }],
|
|
27
28
|
options: [
|
|
@@ -53,14 +54,16 @@ Behavior:
|
|
|
53
54
|
} catch (e) {
|
|
54
55
|
// Bookmark-only id → no admin Instance → kernel NOT_FOUND. Point to
|
|
55
56
|
// `forget` (local drop) instead of surfacing the raw path error.
|
|
56
|
-
|
|
57
|
-
e instanceof
|
|
58
|
-
|
|
57
|
+
if (
|
|
58
|
+
e instanceof AdminInstanceNotFoundError &&
|
|
59
|
+
resolveInstanceKey(await readInstances(), id)
|
|
60
|
+
) {
|
|
59
61
|
log.error(`No admin-managed instance "${id}".`)
|
|
60
62
|
log.dim(` hint: it's a local bookmark — drop it with: astrale instance forget ${id}`)
|
|
61
63
|
process.exit(1)
|
|
62
64
|
}
|
|
63
|
-
|
|
65
|
+
await formatKernelError(e, isMachine(opts), undefined, opts.debug)
|
|
66
|
+
process.exit(1)
|
|
64
67
|
}
|
|
65
68
|
},
|
|
66
69
|
} satisfies CommandDefinition
|
|
@@ -7,7 +7,7 @@ import type { CommandDefinition } from '../../program/index'
|
|
|
7
7
|
import { AstraleError } from '../../errors'
|
|
8
8
|
import { listOwnedInstances } from '../../lib/admin-instance'
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
formatInstanceState,
|
|
11
11
|
type InstanceInfo,
|
|
12
12
|
type OwnedInstanceInfo,
|
|
13
13
|
} from '../../lib/admin-instance'
|
|
@@ -136,7 +136,7 @@ export function buildInstanceRows(
|
|
|
136
136
|
name: twin?.active ? `${item.slug} ${chalk.green('*')}` : item.slug,
|
|
137
137
|
kind: 'managed',
|
|
138
138
|
url: item.url ?? '',
|
|
139
|
-
extra: [
|
|
139
|
+
extra: [formatInstanceState(item), twin ? formatBookmarkConnection(twin) : '']
|
|
140
140
|
.filter(Boolean)
|
|
141
141
|
.join(' · '),
|
|
142
142
|
})
|
|
@@ -3,44 +3,90 @@ import chalk from 'chalk'
|
|
|
3
3
|
import type { KernelCommandOpts } from '../../connection'
|
|
4
4
|
import type { CommandDefinition } from '../../program/index'
|
|
5
5
|
|
|
6
|
+
import { formatKernelError } from '../../connection/errors'
|
|
6
7
|
import { AstraleError } from '../../errors'
|
|
7
|
-
import { statusOwnedInstance } from '../../lib/admin-instance'
|
|
8
|
+
import { statusOwnedInstance, type InstanceInfo } from '../../lib/admin-instance'
|
|
8
9
|
import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
|
|
9
|
-
import {
|
|
10
|
+
import { resolveInstance } from '../../lib/instance'
|
|
11
|
+
import { log, withSpinner } from '../../lib/log'
|
|
10
12
|
import { isMachine, output, type RawOutputOpts } from '../../lib/output'
|
|
13
|
+
import { probeBookmark } from './use'
|
|
11
14
|
|
|
12
|
-
type StatusOpts = KernelCommandOpts &
|
|
15
|
+
type StatusOpts = KernelCommandOpts &
|
|
16
|
+
AdminTargetCommandOpts &
|
|
17
|
+
RawOutputOpts & { bookmarked?: boolean }
|
|
18
|
+
|
|
19
|
+
interface BookmarkStatus {
|
|
20
|
+
readonly slug: string
|
|
21
|
+
readonly url: string
|
|
22
|
+
readonly issuer: string
|
|
23
|
+
readonly kind: 'bookmark'
|
|
24
|
+
readonly state: 'ready'
|
|
25
|
+
}
|
|
13
26
|
|
|
14
27
|
export default {
|
|
15
28
|
name: 'status',
|
|
16
|
-
description: 'Show
|
|
29
|
+
description: 'Show managed instance status or probe a bookmark',
|
|
17
30
|
arguments: [{ name: 'id', description: 'Instance slug', required: true }],
|
|
18
|
-
options: [
|
|
31
|
+
options: [
|
|
32
|
+
...ADMIN_TARGET_OPTIONS,
|
|
33
|
+
{ flags: '--bookmarked', description: 'Probe a locally bookmarked kernel connection' },
|
|
34
|
+
],
|
|
19
35
|
action: async (id: string, opts: StatusOpts) => {
|
|
20
36
|
try {
|
|
21
37
|
const result = await withSpinner(`Fetching instance ${id}`, !isMachine(opts), () =>
|
|
22
|
-
|
|
23
|
-
if (!(error instanceof Error) || error.name !== 'NotFoundError') throw error
|
|
24
|
-
throw new AstraleError(
|
|
25
|
-
'INSTANCE_NOT_FOUND',
|
|
26
|
-
`No owned instance matches "${id}".`,
|
|
27
|
-
'Run `astrale instance list` to see your instances.',
|
|
28
|
-
)
|
|
29
|
-
}),
|
|
38
|
+
resolveStatus(id, opts),
|
|
30
39
|
)
|
|
31
40
|
if (isMachine(opts)) {
|
|
32
41
|
output(result, opts)
|
|
33
42
|
return
|
|
34
43
|
}
|
|
35
44
|
console.log(`${chalk.bold(result.slug)} ${chalk.dim(result.url)}`)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (result.
|
|
39
|
-
if (result
|
|
40
|
-
|
|
41
|
-
if (result.createdAt) log.dim(` created: ${result.createdAt}`)
|
|
45
|
+
const phase = 'phase' in result ? result.phase : undefined
|
|
46
|
+
log.dim(` state: ${result.state}${phase ? ` (${phase})` : ''}`)
|
|
47
|
+
if ('error' in result && result.error) log.dim(` error: ${result.error}`)
|
|
48
|
+
if ('organizationId' in result && result.organizationId)
|
|
49
|
+
log.dim(` organization: ${result.organizationId}`)
|
|
50
|
+
if ('createdAt' in result && result.createdAt) log.dim(` created: ${result.createdAt}`)
|
|
42
51
|
} catch (e) {
|
|
43
|
-
|
|
52
|
+
await formatKernelError(e, isMachine(opts), undefined, opts.debug)
|
|
53
|
+
process.exit(1)
|
|
44
54
|
}
|
|
45
55
|
},
|
|
46
56
|
} satisfies CommandDefinition
|
|
57
|
+
|
|
58
|
+
export interface StatusDependencies {
|
|
59
|
+
readonly statusOwnedInstance: typeof statusOwnedInstance
|
|
60
|
+
readonly resolveInstance: typeof resolveInstance
|
|
61
|
+
readonly probeBookmark: typeof probeBookmark
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const defaultStatusDependencies: StatusDependencies = Object.freeze({
|
|
65
|
+
statusOwnedInstance,
|
|
66
|
+
resolveInstance,
|
|
67
|
+
probeBookmark,
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
export async function resolveStatus(
|
|
71
|
+
id: string,
|
|
72
|
+
opts: StatusOpts,
|
|
73
|
+
dependencies: StatusDependencies = defaultStatusDependencies,
|
|
74
|
+
): Promise<InstanceInfo | BookmarkStatus> {
|
|
75
|
+
if (!opts.bookmarked) return dependencies.statusOwnedInstance(opts, id)
|
|
76
|
+
if (opts.admin !== undefined || opts.adminUrl !== undefined || opts.domainIssuer !== undefined) {
|
|
77
|
+
throw new AstraleError(
|
|
78
|
+
'INVALID_FLAG',
|
|
79
|
+
'--bookmarked cannot be combined with Admin target options.',
|
|
80
|
+
'Remove --bookmarked to inspect managed lifecycle, or remove the Admin options to probe a local bookmark.',
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
const bookmark = await dependencies.resolveInstance(id, undefined, { persist: false })
|
|
84
|
+
await dependencies.probeBookmark(bookmark)
|
|
85
|
+
return Object.freeze({
|
|
86
|
+
slug: bookmark.name,
|
|
87
|
+
url: bookmark.url,
|
|
88
|
+
issuer: bookmark.issuer ?? bookmark.url,
|
|
89
|
+
kind: 'bookmark',
|
|
90
|
+
state: 'ready',
|
|
91
|
+
})
|
|
92
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { CommandDefinition } from '../../program/index'
|
|
|
3
3
|
|
|
4
4
|
import { AstraleError } from '../../errors'
|
|
5
5
|
import { getDefault, setDefault } from '../../identity/index'
|
|
6
|
-
import {
|
|
6
|
+
import { listOwnedInstancesWithIdentity } from '../../lib/admin-instance'
|
|
7
7
|
import { ADMIN_TARGET_OPTIONS } from '../../lib/admin-target'
|
|
8
8
|
import { fetchWithCaFile } from '../../lib/ca-fetch'
|
|
9
9
|
import {
|
|
@@ -143,7 +143,7 @@ const defaultBookmarkProbeDependencies: BookmarkProbeDependencies = Object.freez
|
|
|
143
143
|
|
|
144
144
|
async function resolveUseTarget(name: string, opts: UseOpts): Promise<ResolvedInstance> {
|
|
145
145
|
const [store, managed] = await Promise.all([readInstances(), fetchManagedInstances(name, opts)])
|
|
146
|
-
const candidates = collectInstanceCandidates(name, store, managed)
|
|
146
|
+
const candidates = collectInstanceCandidates(name, store, managed.instances)
|
|
147
147
|
|
|
148
148
|
if (candidates.length === 0) {
|
|
149
149
|
throw new AstraleError(
|
|
@@ -168,12 +168,13 @@ async function resolveUseTarget(name: string, opts: UseOpts): Promise<ResolvedIn
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
assertManagedReady(chosen.info)
|
|
171
|
-
const { repointedFrom } = await upsertManagedBookmark(
|
|
172
|
-
chosen.key,
|
|
173
|
-
chosen.info.slug,
|
|
174
|
-
chosen.url,
|
|
175
|
-
chosen.info.organizationId,
|
|
176
|
-
|
|
171
|
+
const { repointedFrom } = await upsertManagedBookmark({
|
|
172
|
+
key: chosen.key,
|
|
173
|
+
slug: chosen.info.slug,
|
|
174
|
+
url: chosen.url,
|
|
175
|
+
...(chosen.info.organizationId ? { organizationId: chosen.info.organizationId } : {}),
|
|
176
|
+
...(managed.identity ? { defaultIdentity: managed.identity } : {}),
|
|
177
|
+
})
|
|
177
178
|
if (repointedFrom) {
|
|
178
179
|
log.warn(`Bookmark "${chosen.key}" repointed: ${repointedFrom} → ${chosen.url}`)
|
|
179
180
|
}
|
|
@@ -185,16 +186,19 @@ async function resolveUseTarget(name: string, opts: UseOpts): Promise<ResolvedIn
|
|
|
185
186
|
* Best-effort: an unreachable or unauthenticated admin kernel degrades to
|
|
186
187
|
* bookmark-only resolution.
|
|
187
188
|
*/
|
|
188
|
-
async function fetchManagedInstances(
|
|
189
|
+
async function fetchManagedInstances(
|
|
190
|
+
name: string,
|
|
191
|
+
opts: UseOpts,
|
|
192
|
+
): Promise<{ readonly instances: OwnedInstanceInfo[]; readonly identity?: string }> {
|
|
189
193
|
try {
|
|
190
194
|
validateSlug(name)
|
|
191
195
|
} catch {
|
|
192
|
-
return []
|
|
196
|
+
return { instances: [] }
|
|
193
197
|
}
|
|
194
198
|
try {
|
|
195
|
-
return await
|
|
199
|
+
return await listOwnedInstancesWithIdentity(opts)
|
|
196
200
|
} catch {
|
|
197
|
-
return []
|
|
201
|
+
return { instances: [] }
|
|
198
202
|
}
|
|
199
203
|
}
|
|
200
204
|
|