@astrale-os/cli 1.0.0-beta.1 → 1.0.0-beta.10
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 +51471 -56290
- package/dist/public/connect-core.js +2028 -26846
- package/dist/public/keys/index.js +1755 -40694
- package/dist/public/paths/index.js +859 -39518
- 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 +6 -2
- package/dist/types/lib/failure-debug.d.ts +1 -0
- package/dist/types/lib/idp.d.ts +7 -0
- package/dist/types/lib/instance-target.d.ts +1 -1
- package/dist/types/lib/instance.d.ts +10 -2
- 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 +131 -0
- package/package.json +8 -10
- 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 +1 -1
- 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/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-D2xgMJvi.js → elk-api-ByzoDZWH.js} +1 -1
- package/studio/client/dist/assets/index-B0RCgUOT.js +8 -0
- package/studio/client/dist/assets/index-BiGR8Oo9.css +1 -0
- package/studio/client/dist/assets/index-N8J8EKlB.js +81 -0
- package/studio/client/dist/index.html +2 -2
- package/studio/package.json +5 -10
- 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/index-BMdnsIJA.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
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineSchema, schema as schemaApi } from '@astrale-os/sdk/schema'
|
|
2
|
+
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
3
|
|
|
3
4
|
import type { DomainInfo } from '../../lib/admin-domain'
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
+
import { releaseFor } from '../../__tests__/fixtures/publication'
|
|
7
|
+
import { byDefaultThenName, domainProjection, probe, type DomainRow } from '../domain/list'
|
|
6
8
|
|
|
7
9
|
const strip = (s: string): string => s.replace(/\[[0-9;]*m/g, '')
|
|
8
10
|
|
|
@@ -68,7 +70,64 @@ describe('domain list — projection', () => {
|
|
|
68
70
|
const live: DomainRow = { ...base, reachable: true, checkError: null }
|
|
69
71
|
expect(strip(domainProjection([live]).rows[0].status)).toBe('● live')
|
|
70
72
|
|
|
71
|
-
const down: DomainRow = { ...base, reachable: false, checkError: '
|
|
72
|
-
expect(strip(domainProjection([down]).rows[0].status)).toBe('○
|
|
73
|
+
const down: DomainRow = { ...base, reachable: false, checkError: 'Publication HTTP 502' }
|
|
74
|
+
expect(strip(domainProjection([down]).rows[0].status)).toBe('○ Publication HTTP 502')
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('domain list — canonical Publication check', () => {
|
|
79
|
+
const servers: { stop(): void }[] = []
|
|
80
|
+
afterAll(() => {
|
|
81
|
+
for (const server of servers) server.stop()
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test('reports the admitted schema revision in machine data', async () => {
|
|
85
|
+
const schema = defineSchema('catalog-check.example.dev', {})
|
|
86
|
+
const deployed = releaseFor(schema, 'https://catalog-check.example.dev').publication
|
|
87
|
+
const server = Bun.serve({
|
|
88
|
+
port: 0,
|
|
89
|
+
fetch(request) {
|
|
90
|
+
return new URL(request.url).pathname === '/.well-known/astrale/domain.json'
|
|
91
|
+
? Response.json(deployed)
|
|
92
|
+
: new Response('not found', { status: 404 })
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
servers.push(server)
|
|
96
|
+
|
|
97
|
+
await expect(
|
|
98
|
+
probe(
|
|
99
|
+
entry({
|
|
100
|
+
origin: schema.origin,
|
|
101
|
+
url: `http://localhost:${server.port}`,
|
|
102
|
+
}),
|
|
103
|
+
),
|
|
104
|
+
).resolves.toMatchObject({
|
|
105
|
+
reachable: true,
|
|
106
|
+
schemaRevision: schemaApi.revision(schema),
|
|
107
|
+
checkError: null,
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('rejects a Publication whose origin differs from the catalog entry', async () => {
|
|
112
|
+
const schema = defineSchema('deployed.example.dev', {})
|
|
113
|
+
const deployed = releaseFor(schema, 'https://deployed.example.dev').publication
|
|
114
|
+
const server = Bun.serve({
|
|
115
|
+
port: 0,
|
|
116
|
+
fetch: () => Response.json(deployed),
|
|
117
|
+
})
|
|
118
|
+
servers.push(server)
|
|
119
|
+
|
|
120
|
+
await expect(
|
|
121
|
+
probe(
|
|
122
|
+
entry({
|
|
123
|
+
origin: 'catalog.example.dev',
|
|
124
|
+
url: `http://localhost:${server.port}`,
|
|
125
|
+
}),
|
|
126
|
+
),
|
|
127
|
+
).resolves.toMatchObject({
|
|
128
|
+
reachable: false,
|
|
129
|
+
checkError:
|
|
130
|
+
'Domain origin mismatch: deployed=deployed.example.dev expected=catalog.example.dev',
|
|
131
|
+
})
|
|
73
132
|
})
|
|
74
133
|
})
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { defineSchema } from '@astrale-os/sdk/schema'
|
|
1
2
|
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
3
|
|
|
4
|
+
import { releaseFor } from '../../__tests__/fixtures/publication'
|
|
3
5
|
import { domainRefFromTarget, isIdentityOverride, probeDeclaredOrigin } from '../domain/install'
|
|
4
6
|
|
|
5
7
|
describe('admin-path target classification', () => {
|
|
@@ -29,46 +31,44 @@ describe('identity-override detection', () => {
|
|
|
29
31
|
})
|
|
30
32
|
})
|
|
31
33
|
|
|
32
|
-
describe('declared-origin probe
|
|
34
|
+
describe('declared-origin Publication probe', () => {
|
|
33
35
|
const servers: { stop(): void }[] = []
|
|
34
36
|
afterAll(() => {
|
|
35
37
|
for (const s of servers) s.stop()
|
|
36
38
|
})
|
|
37
39
|
|
|
38
|
-
function
|
|
40
|
+
function servePublication(handler: (req: Request) => Response): string {
|
|
39
41
|
const server = Bun.serve({ port: 0, fetch: handler })
|
|
40
42
|
servers.push(server)
|
|
41
43
|
return `http://localhost:${server.port}`
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
test('reads origin from a well-formed
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
issuer: 'https://crm.acme.dev',
|
|
51
|
-
schemaRevision: 'sha256:abc',
|
|
52
|
-
deploymentVersion: 'v1',
|
|
53
|
-
})
|
|
46
|
+
test('reads origin from a well-formed canonical Publication', async () => {
|
|
47
|
+
const schema = defineSchema('crm.acme.dev', {})
|
|
48
|
+
const deployed = releaseFor(schema, 'https://crm.acme.dev').publication
|
|
49
|
+
const url = servePublication((req) =>
|
|
50
|
+
new URL(req.url).pathname === '/.well-known/astrale/domain.json'
|
|
51
|
+
? Response.json(deployed)
|
|
54
52
|
: new Response('nope', { status: 404 }),
|
|
55
53
|
)
|
|
56
54
|
expect(await probeDeclaredOrigin(url)).toBe('crm.acme.dev')
|
|
57
55
|
})
|
|
58
56
|
|
|
59
|
-
test('
|
|
60
|
-
const legacy =
|
|
61
|
-
|
|
57
|
+
test('does not accept the removed pre-Kernel-V2 domainName shape', async () => {
|
|
58
|
+
const legacy = servePublication(() =>
|
|
59
|
+
Response.json({ iss: 'https://x', domainName: 'crm.acme.dev' }),
|
|
60
|
+
)
|
|
61
|
+
expect(await probeDeclaredOrigin(legacy)).toBeUndefined()
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
test('degrades to undefined on
|
|
65
|
-
const noName =
|
|
64
|
+
test('degrades to undefined on invalid Publication, non-200, bad JSON, or dead host', async () => {
|
|
65
|
+
const noName = servePublication(() => Response.json({ iss: 'https://x' }))
|
|
66
66
|
expect(await probeDeclaredOrigin(noName)).toBeUndefined()
|
|
67
67
|
|
|
68
|
-
const error =
|
|
68
|
+
const error = servePublication(() => new Response('boom', { status: 500 }))
|
|
69
69
|
expect(await probeDeclaredOrigin(error)).toBeUndefined()
|
|
70
70
|
|
|
71
|
-
const badJson =
|
|
71
|
+
const badJson = servePublication(() => new Response('<html>', { status: 200 }))
|
|
72
72
|
expect(await probeDeclaredOrigin(badJson)).toBeUndefined()
|
|
73
73
|
|
|
74
74
|
expect(await probeDeclaredOrigin('http://127.0.0.1:1')).toBeUndefined()
|
|
@@ -5,7 +5,7 @@ import type { InstanceInfo } from '../../lib/admin-instance'
|
|
|
5
5
|
import { buildInstanceRows, type Bookmark } from '../instance/list'
|
|
6
6
|
|
|
7
7
|
const managed: InstanceInfo[] = [
|
|
8
|
-
{ id: 'demo', slug: 'demo', url: 'https://demo.eu.astrale.ai',
|
|
8
|
+
{ id: 'demo', slug: 'demo', url: 'https://demo.eu.astrale.ai', state: 'ready' },
|
|
9
9
|
]
|
|
10
10
|
|
|
11
11
|
function bookmark(overrides: Partial<Bookmark> = {}): Bookmark {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
|
|
2
|
+
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
import type { InstanceInfo } from '../../lib/admin-instance'
|
|
7
|
+
import type { ResolvedInstance } from '../../lib/instance'
|
|
8
|
+
|
|
9
|
+
import { resolveStatus, type StatusDependencies } from '../instance/status'
|
|
10
|
+
|
|
11
|
+
const cliRoot = join(import.meta.dir, '../../..')
|
|
12
|
+
|
|
13
|
+
let home: string
|
|
14
|
+
let server: ReturnType<typeof Bun.serve>
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
home = await mkdtemp(join(tmpdir(), 'astrale-instance-status-'))
|
|
18
|
+
server = Bun.serve({
|
|
19
|
+
port: 0,
|
|
20
|
+
fetch(request) {
|
|
21
|
+
const url = new URL(request.url)
|
|
22
|
+
const issuer = `http://127.0.0.1:${server.port}`
|
|
23
|
+
if (url.pathname === '/.well-known/openid-configuration') {
|
|
24
|
+
return Response.json({ issuer, jwks_uri: `${issuer}/.well-known/jwks.json` })
|
|
25
|
+
}
|
|
26
|
+
if (url.pathname === '/.well-known/jwks.json') {
|
|
27
|
+
return Response.json({ keys: [{ kid: 'status-test' }] })
|
|
28
|
+
}
|
|
29
|
+
return new Response('Not found', { status: 404 })
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
afterEach(async () => {
|
|
35
|
+
server.stop(true)
|
|
36
|
+
await rm(home, { recursive: true, force: true })
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
describe('instance status', () => {
|
|
40
|
+
test('keeps managed lifecycle authoritative when the slug is also bookmarked', async () => {
|
|
41
|
+
const managed: InstanceInfo = {
|
|
42
|
+
id: '@managed',
|
|
43
|
+
slug: 'shared',
|
|
44
|
+
url: 'https://managed.example.com',
|
|
45
|
+
state: 'provisioning',
|
|
46
|
+
phase: 'bootstrap',
|
|
47
|
+
}
|
|
48
|
+
const statusOwnedInstance: StatusDependencies['statusOwnedInstance'] = mock(async () => managed)
|
|
49
|
+
const resolveInstance: StatusDependencies['resolveInstance'] = mock(async () => {
|
|
50
|
+
throw new Error('bookmark resolution must not run')
|
|
51
|
+
})
|
|
52
|
+
const probeBookmark: StatusDependencies['probeBookmark'] = mock(async () => {
|
|
53
|
+
throw new Error('bookmark probe must not run')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
await expect(
|
|
57
|
+
resolveStatus('shared', {}, { statusOwnedInstance, resolveInstance, probeBookmark }),
|
|
58
|
+
).resolves.toEqual(managed)
|
|
59
|
+
expect(statusOwnedInstance).toHaveBeenCalledWith({}, 'shared')
|
|
60
|
+
expect(resolveInstance).not.toHaveBeenCalled()
|
|
61
|
+
expect(probeBookmark).not.toHaveBeenCalled()
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('probes only an explicitly selected bookmark and rejects mixed source flags', async () => {
|
|
65
|
+
const bookmark: ResolvedInstance = {
|
|
66
|
+
name: 'local',
|
|
67
|
+
kind: 'bookmark',
|
|
68
|
+
url: 'https://local.example.com',
|
|
69
|
+
issuer: 'https://issuer.example.com',
|
|
70
|
+
}
|
|
71
|
+
const statusOwnedInstance: StatusDependencies['statusOwnedInstance'] = mock(async () => {
|
|
72
|
+
throw new Error('managed status must not run')
|
|
73
|
+
})
|
|
74
|
+
const resolveInstance: StatusDependencies['resolveInstance'] = mock(async () => bookmark)
|
|
75
|
+
const probeBookmark: StatusDependencies['probeBookmark'] = mock(async () => undefined)
|
|
76
|
+
const dependencies = { statusOwnedInstance, resolveInstance, probeBookmark }
|
|
77
|
+
|
|
78
|
+
await expect(resolveStatus('local', { bookmarked: true }, dependencies)).resolves.toEqual({
|
|
79
|
+
slug: 'local',
|
|
80
|
+
url: bookmark.url,
|
|
81
|
+
issuer: 'https://issuer.example.com',
|
|
82
|
+
kind: 'bookmark',
|
|
83
|
+
state: 'ready',
|
|
84
|
+
})
|
|
85
|
+
expect(resolveInstance).toHaveBeenCalledWith('local', undefined, { persist: false })
|
|
86
|
+
expect(probeBookmark).toHaveBeenCalledWith(bookmark)
|
|
87
|
+
expect(statusOwnedInstance).not.toHaveBeenCalled()
|
|
88
|
+
|
|
89
|
+
await expect(
|
|
90
|
+
resolveStatus('local', { bookmarked: true, admin: 'admin' }, dependencies),
|
|
91
|
+
).rejects.toMatchObject({ code: 'INVALID_FLAG' })
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('probes an explicit local bookmark without rewriting its registry', async () => {
|
|
95
|
+
const issuer = `http://127.0.0.1:${server.port}`
|
|
96
|
+
const registry = `${JSON.stringify({
|
|
97
|
+
active: 'local',
|
|
98
|
+
instances: {
|
|
99
|
+
local: {
|
|
100
|
+
url: issuer,
|
|
101
|
+
issuer,
|
|
102
|
+
mode: 'remote',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
})}\n`
|
|
106
|
+
const path = join(home, 'instances.json')
|
|
107
|
+
await writeFile(path, registry)
|
|
108
|
+
|
|
109
|
+
const process = Bun.spawn({
|
|
110
|
+
cmd: [
|
|
111
|
+
'bun',
|
|
112
|
+
join(cliRoot, 'bin/astrale.ts'),
|
|
113
|
+
'instance',
|
|
114
|
+
'status',
|
|
115
|
+
'local',
|
|
116
|
+
'--bookmarked',
|
|
117
|
+
'--json',
|
|
118
|
+
],
|
|
119
|
+
env: { ...Bun.env, ASTRALE_HOME: home },
|
|
120
|
+
stdout: 'pipe',
|
|
121
|
+
stderr: 'pipe',
|
|
122
|
+
})
|
|
123
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
124
|
+
new Response(process.stdout).text(),
|
|
125
|
+
new Response(process.stderr).text(),
|
|
126
|
+
process.exited,
|
|
127
|
+
])
|
|
128
|
+
|
|
129
|
+
expect(exitCode, stderr).toBe(0)
|
|
130
|
+
expect(JSON.parse(stdout)).toEqual({
|
|
131
|
+
slug: 'local',
|
|
132
|
+
url: issuer,
|
|
133
|
+
issuer,
|
|
134
|
+
kind: 'bookmark',
|
|
135
|
+
state: 'ready',
|
|
136
|
+
})
|
|
137
|
+
expect(await readFile(path, 'utf8')).toBe(registry)
|
|
138
|
+
})
|
|
139
|
+
})
|
|
@@ -36,6 +36,8 @@ let mutations: unknown[] = []
|
|
|
36
36
|
let queryResult: unknown
|
|
37
37
|
let getResult: unknown
|
|
38
38
|
let mutationResult: unknown
|
|
39
|
+
let selfFailure: unknown
|
|
40
|
+
let selfContexts: unknown[] = []
|
|
39
41
|
|
|
40
42
|
const queryMock = mock(async (ast: unknown, options?: unknown) => {
|
|
41
43
|
queryCalls.push({ ast, options })
|
|
@@ -49,7 +51,9 @@ const mutateMock = mock(async (mutation: unknown) => {
|
|
|
49
51
|
mutations.push(mutation)
|
|
50
52
|
return mutationResult
|
|
51
53
|
})
|
|
52
|
-
const expandSelfInPathMock = mock(async (path: string) => {
|
|
54
|
+
const expandSelfInPathMock = mock(async (path: string, context: unknown) => {
|
|
55
|
+
selfContexts.push(context)
|
|
56
|
+
if (selfFailure !== undefined) throw selfFailure
|
|
53
57
|
if (path === '@self') {
|
|
54
58
|
return {
|
|
55
59
|
path: '@expanded-self',
|
|
@@ -59,10 +63,11 @@ const expandSelfInPathMock = mock(async (path: string) => {
|
|
|
59
63
|
return { path, meta: undefined }
|
|
60
64
|
})
|
|
61
65
|
const withSelfHintMock = mock(async (action: () => Promise<unknown>) => action())
|
|
66
|
+
const commandContext = {
|
|
67
|
+
graph: { query: queryMock, getOrThrow: getOrThrowMock, mutate: mutateMock },
|
|
68
|
+
}
|
|
62
69
|
const runKernelCommandMock = mock(async (run: RunOpts) => {
|
|
63
|
-
const result = await run.fn(
|
|
64
|
-
graph: { query: queryMock, getOrThrow: getOrThrowMock, mutate: mutateMock },
|
|
65
|
-
})
|
|
70
|
+
const result = await run.fn(commandContext)
|
|
66
71
|
await run.format?.(result, run.opts, true)
|
|
67
72
|
})
|
|
68
73
|
|
|
@@ -88,6 +93,8 @@ beforeEach(() => {
|
|
|
88
93
|
}
|
|
89
94
|
getResult = undefined
|
|
90
95
|
mutationResult = { createdNodes: {} }
|
|
96
|
+
selfFailure = undefined
|
|
97
|
+
selfContexts = []
|
|
91
98
|
queryMock.mockClear()
|
|
92
99
|
getOrThrowMock.mockClear()
|
|
93
100
|
mutateMock.mockClear()
|
|
@@ -161,7 +168,7 @@ describe('query command', () => {
|
|
|
161
168
|
])
|
|
162
169
|
})
|
|
163
170
|
|
|
164
|
-
test('authors a
|
|
171
|
+
test('authors a Class source through the same canonical Query V6 call', async () => {
|
|
165
172
|
const { queryCommand } = await import('../query')
|
|
166
173
|
|
|
167
174
|
await queryCommand([], {
|
|
@@ -179,8 +186,8 @@ describe('query command', () => {
|
|
|
179
186
|
kind: 'node',
|
|
180
187
|
terms: [
|
|
181
188
|
{
|
|
182
|
-
kind: '
|
|
183
|
-
|
|
189
|
+
kind: 'class',
|
|
190
|
+
class: { origin: 'issues.astrale.ai', kind: 'class', name: 'Issue' },
|
|
184
191
|
},
|
|
185
192
|
],
|
|
186
193
|
binding: 'n0',
|
|
@@ -193,6 +200,17 @@ describe('query command', () => {
|
|
|
193
200
|
])
|
|
194
201
|
})
|
|
195
202
|
|
|
203
|
+
test('resolves @self inside the command session and never relabels transport failure as input', async () => {
|
|
204
|
+
const { queryCommand } = await import('../query')
|
|
205
|
+
await queryCommand(['@self'], { json: true, limit: '2' })
|
|
206
|
+
expect(selfContexts).toEqual([commandContext])
|
|
207
|
+
|
|
208
|
+
const aggregate = new AggregateError([], '')
|
|
209
|
+
selfFailure = aggregate
|
|
210
|
+
await expect(queryCommand(['@self'], { json: true, limit: '2' })).rejects.toBe(aggregate)
|
|
211
|
+
expect(errors.join('\n')).not.toContain('INVALID_INPUT')
|
|
212
|
+
})
|
|
213
|
+
|
|
196
214
|
/** @evidence TEST-CLI-QUERY-REJECTS-V1-BEFORE-CONNECTION */
|
|
197
215
|
test('rejects a legacy AST before opening the command connection', async () => {
|
|
198
216
|
const { queryCommand } = await import('../query')
|
|
@@ -215,7 +233,7 @@ describe('get command', () => {
|
|
|
215
233
|
const { getCommand } = await import('../get')
|
|
216
234
|
getResult = {
|
|
217
235
|
id: 'note-1',
|
|
218
|
-
class: '
|
|
236
|
+
class: 'notes.example.dev:class.Note',
|
|
219
237
|
props: { 'notes.example.dev:class.Note.property.title': 'Hello' },
|
|
220
238
|
}
|
|
221
239
|
|
|
@@ -226,6 +244,13 @@ describe('get command', () => {
|
|
|
226
244
|
expect(stdout).not.toContain('__labels')
|
|
227
245
|
expect(stdout).not.toContain('classId')
|
|
228
246
|
})
|
|
247
|
+
|
|
248
|
+
test('resolves @self through the same point-read command context', async () => {
|
|
249
|
+
const { getCommand } = await import('../get')
|
|
250
|
+
await getCommand('@self', { json: true })
|
|
251
|
+
expect(selfContexts).toEqual([commandContext])
|
|
252
|
+
expect(getTargets).toEqual(['@expanded-self'])
|
|
253
|
+
})
|
|
229
254
|
})
|
|
230
255
|
|
|
231
256
|
describe('mutate command', () => {
|
|
@@ -242,7 +267,7 @@ describe('mutate command', () => {
|
|
|
242
267
|
{
|
|
243
268
|
op: 'node.create',
|
|
244
269
|
as: 'note',
|
|
245
|
-
class: '
|
|
270
|
+
class: 'notes.example.dev:class.Note',
|
|
246
271
|
props: {},
|
|
247
272
|
},
|
|
248
273
|
],
|
|
@@ -258,7 +283,7 @@ describe('mutate command', () => {
|
|
|
258
283
|
{
|
|
259
284
|
op: 'node.create',
|
|
260
285
|
as: 'note',
|
|
261
|
-
class: '
|
|
286
|
+
class: 'notes.example.dev:class.Note',
|
|
262
287
|
props: {},
|
|
263
288
|
},
|
|
264
289
|
],
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
import { realpathSync } from 'node:fs'
|
|
3
|
+
|
|
4
|
+
import { encodeStudioCliDescriptor } from '../studio'
|
|
5
|
+
|
|
6
|
+
test('Studio descriptor preserves the exact runtime and script entrypoint', () => {
|
|
7
|
+
expect(JSON.parse(encodeStudioCliDescriptor(process.execPath, import.meta.path))).toEqual({
|
|
8
|
+
version: 1,
|
|
9
|
+
executable: process.execPath,
|
|
10
|
+
args: [realpathSync(import.meta.path)],
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('Studio descriptor reinvokes a compiled executable without its virtual bunfs entry', () => {
|
|
15
|
+
expect(JSON.parse(encodeStudioCliDescriptor('/opt/bin/astrale', '/$bunfs/root/astrale'))).toEqual(
|
|
16
|
+
{
|
|
17
|
+
version: 1,
|
|
18
|
+
executable: '/opt/bin/astrale',
|
|
19
|
+
args: [],
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
})
|
|
@@ -6,14 +6,17 @@ describe('CLI update staleness', () => {
|
|
|
6
6
|
test('trusts the release manifest for a script install without consulting npm latest', async () => {
|
|
7
7
|
const fetchPackageVersion = mock(async () => '0.8.1-alpha.7')
|
|
8
8
|
const result = await cliStale(
|
|
9
|
-
{
|
|
9
|
+
{},
|
|
10
10
|
{
|
|
11
|
-
update: async () =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
update: async ({ channel }) => {
|
|
12
|
+
expect(channel).toBe('beta')
|
|
13
|
+
return {
|
|
14
|
+
status: 'up-to-date',
|
|
15
|
+
currentVersion: '1.0.0-beta.0',
|
|
16
|
+
latestVersion: '1.0.0-beta.0',
|
|
17
|
+
channel: 'beta',
|
|
18
|
+
}
|
|
19
|
+
},
|
|
17
20
|
fetchPackageVersion,
|
|
18
21
|
},
|
|
19
22
|
)
|
|
@@ -28,37 +31,63 @@ describe('CLI update staleness', () => {
|
|
|
28
31
|
expect(fetchPackageVersion).not.toHaveBeenCalled()
|
|
29
32
|
})
|
|
30
33
|
|
|
31
|
-
test('uses
|
|
34
|
+
test('uses an explicit npm dist-tag only for package-managed installs', async () => {
|
|
32
35
|
const result = await cliStale(
|
|
33
|
-
{ channel: '
|
|
36
|
+
{ channel: 'canary' },
|
|
34
37
|
{
|
|
35
|
-
update: async () => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
update: async () => ({
|
|
39
|
+
status: 'managed',
|
|
40
|
+
currentVersion: '1.0.0-beta.0',
|
|
41
|
+
executable: '/opt/homebrew/bin/node',
|
|
42
|
+
}),
|
|
38
43
|
fetchPackageVersion: async ({ channel }) => {
|
|
39
|
-
expect(channel).toBe('
|
|
40
|
-
return '1.0.0-
|
|
44
|
+
expect(channel).toBe('canary')
|
|
45
|
+
return '1.0.0-canary.0'
|
|
41
46
|
},
|
|
42
47
|
},
|
|
43
48
|
)
|
|
44
49
|
|
|
45
50
|
expect(result).toMatchObject({
|
|
46
51
|
managed: true,
|
|
47
|
-
latest: '1.0.0-
|
|
52
|
+
latest: '1.0.0-canary.0',
|
|
48
53
|
channel: 'npm',
|
|
49
54
|
})
|
|
50
55
|
})
|
|
51
56
|
|
|
52
|
-
test('
|
|
57
|
+
test('does not misclassify a script update failure as package-managed', async () => {
|
|
58
|
+
const fetchPackageVersion = mock(async () => '9.9.9')
|
|
59
|
+
const result = await cliStale(
|
|
60
|
+
{},
|
|
61
|
+
{
|
|
62
|
+
update: async () => {
|
|
63
|
+
throw new Error('release endpoint unavailable')
|
|
64
|
+
},
|
|
65
|
+
fetchPackageVersion,
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
expect(result).toMatchObject({
|
|
70
|
+
stale: false,
|
|
71
|
+
managed: false,
|
|
72
|
+
error: 'release endpoint unavailable',
|
|
73
|
+
})
|
|
74
|
+
expect(fetchPackageVersion).not.toHaveBeenCalled()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('maps the default to beta and the stable channel to npm latest', async () => {
|
|
53
78
|
const originalFetch = globalThis.fetch
|
|
54
79
|
const fetchMock = mock(async (input: RequestInfo | URL) => {
|
|
55
|
-
|
|
56
|
-
return Response.json({ version: '1.0.0' })
|
|
80
|
+
const target = String(input).split('/').at(-1)
|
|
81
|
+
return Response.json({ version: target === 'beta' ? '1.0.0-beta.0' : '1.0.0' })
|
|
57
82
|
})
|
|
58
83
|
globalThis.fetch = fetchMock as unknown as typeof fetch
|
|
59
84
|
try {
|
|
85
|
+
expect(await fetchNpmTargetVersion({})).toBe('1.0.0-beta.0')
|
|
60
86
|
expect(await fetchNpmTargetVersion({ channel: 'stable' })).toBe('1.0.0')
|
|
61
|
-
expect(fetchMock).
|
|
87
|
+
expect(fetchMock.mock.calls.map(([input]) => String(input))).toEqual([
|
|
88
|
+
'https://registry.npmjs.org/@astrale-os/cli/beta',
|
|
89
|
+
'https://registry.npmjs.org/@astrale-os/cli/latest',
|
|
90
|
+
])
|
|
62
91
|
} finally {
|
|
63
92
|
globalThis.fetch = originalFetch
|
|
64
93
|
}
|