@astrale-os/cli 1.0.0-beta.4 → 1.0.0-beta.6
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/dist/astrale.js +55649 -59388
- package/dist/public/connect-core.js +1972 -26831
- package/dist/public/keys/index.js +1754 -40686
- package/dist/public/paths/index.js +859 -39511
- package/dist/types/admin/instance/model.d.ts +3 -4
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/lib/idp.d.ts +1 -0
- package/dist/types/lib/instance-target.d.ts +1 -1
- package/dist/types/lib/log.d.ts +2 -2
- package/dist/types/lib/update.d.ts +30 -0
- package/package.json +4 -6
- package/src/__tests__/fixtures/publication.ts +20 -0
- package/src/admin/__tests__/binding.test.ts +14 -21
- package/src/admin/__tests__/fixture.ts +101 -0
- package/src/admin/binding.ts +86 -6
- 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 +35 -26
- 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 +58 -83
- package/src/admin/instance/client.ts +49 -39
- package/src/admin/instance/model.ts +9 -8
- package/src/commands/__tests__/call-describe.test.ts +46 -33
- package/src/commands/__tests__/domain-install-operation.test.ts +3 -14
- package/src/commands/__tests__/domain-install-owned.test.ts +1 -1
- package/src/commands/__tests__/domain-list.test.ts +5 -25
- package/src/commands/__tests__/install-identity-override.test.ts +3 -14
- package/src/commands/__tests__/read-commands.test.ts +35 -10
- package/src/commands/__tests__/update.test.ts +25 -3
- package/src/commands/call-describe.ts +59 -67
- package/src/commands/call.ts +41 -54
- package/src/commands/domain/install.ts +2 -2
- package/src/commands/domain/uninstall.ts +2 -2
- package/src/commands/get.ts +13 -14
- package/src/commands/identity/__tests__/register.test.ts +3 -3
- package/src/commands/identity/register.ts +5 -4
- package/src/commands/instance/delete.ts +5 -3
- package/src/commands/instance/status.ts +1 -9
- package/src/commands/introspect.ts +4 -11
- package/src/commands/logs.ts +24 -25
- package/src/commands/mutate.ts +6 -5
- package/src/commands/query.ts +27 -30
- package/src/commands/token.ts +8 -7
- package/src/commands/update.ts +31 -11
- package/src/commands/view.ts +4 -3
- 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 +1 -1
- package/src/connection/__tests__/errors.test.ts +27 -20
- package/src/connection/__tests__/exchange.test.ts +30 -1
- 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/call.ts +1 -1
- package/src/connection/credential.ts +2 -2
- package/src/connection/errors.ts +1 -355
- package/src/connection/exchange.ts +47 -23
- package/src/connection/failure/classify.ts +110 -0
- package/src/connection/failure/debug.ts +26 -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 +8 -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/lib/__tests__/domain-publication.test.ts +4 -15
- package/src/lib/__tests__/idp.test.ts +25 -0
- package/src/lib/__tests__/instance-target.test.ts +6 -39
- package/src/lib/__tests__/log-errors.test.ts +53 -0
- package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
- package/src/lib/__tests__/update.test.ts +101 -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/command-dx.ts +1 -4
- package/src/lib/domain-publication.ts +1 -1
- package/src/lib/idp.ts +29 -1
- package/src/lib/instance-target.ts +3 -14
- package/src/lib/log.ts +11 -6
- package/src/lib/update.ts +120 -26
- package/src/lib/validation.ts +2 -2
- package/src/lib/view/resolve.ts +1 -1
- package/src/program/__tests__/program.test.ts +1 -1
- package/studio/client/dist/assets/{elk-api-lwhFo7vB.js → elk-api-Di4OXGNH.js} +1 -1
- package/studio/client/dist/assets/index-BLm6J11H.js +81 -0
- package/studio/client/dist/assets/index-BiGR8Oo9.css +1 -0
- package/studio/client/dist/assets/index-DTjvkOUX.js +8 -0
- package/studio/client/dist/index.html +2 -2
- package/studio/package.json +2 -9
- 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/harness/claude/adapter.test.ts +15 -5
- 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 +3 -3
- package/studio/server/agent/routes.test.ts +1 -1
- package/studio/server/agent/run/coordinator.test.ts +1 -1
- package/studio/server/api/canvas.ts +0 -1
- package/studio/server/api-agent-loadout.test.ts +1 -1
- package/studio/server/api.test.ts +1 -1
- package/studio/server/cache.test.ts +23 -12
- package/studio/server/cache.ts +12 -15
- package/studio/server/domain.test.ts +50 -68
- package/studio/server/domain.ts +82 -63
- package/studio/server/handoff/copy.ts +1 -1
- package/studio/server/index.ts +1 -1
- package/studio/server/instances/probe.test.ts +1 -1
- package/studio/server/introspect/anatomy/views/routes.ts +46 -37
- package/studio/server/introspect/anatomy/views.ts +9 -14
- package/studio/server/introspect/anatomy-extras.test.ts +26 -42
- package/studio/server/introspect/anatomy.test.ts +22 -14
- package/studio/server/introspect/anatomy.ts +6 -9
- package/studio/server/introspect/bundle.ts +0 -3
- package/studio/server/introspect/canonical-schema.test.ts +94 -389
- package/studio/server/introspect/canonical-schema.ts +227 -457
- package/studio/server/introspect/core-extractor.ts +18 -127
- package/studio/server/introspect/core.ts +1 -2
- package/studio/server/introspect/diff.test.ts +11 -7
- package/studio/server/introspect/diff.ts +18 -55
- package/studio/server/introspect/extractor.ts +22 -117
- package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
- package/studio/server/introspect/overlay.test.ts +26 -54
- package/studio/server/introspect/overlay.ts +10 -37
- package/studio/server/introspect/revision.test.ts +1 -1
- package/studio/server/introspect/revision.ts +1 -1
- package/studio/server/introspect/runtime.test.ts +65 -183
- package/studio/server/introspect/runtime.ts +8 -25
- package/studio/server/introspect/schema-ir-json.test.ts +70 -0
- package/studio/server/introspect/schema-ir-json.ts +38 -68
- 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/handlers.ts +116 -636
- package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -3
- package/studio/server/introspect/source-overlay/spans.ts +15 -45
- package/studio/server/state/baseline.test.ts +14 -9
- package/studio/server/state/baseline.ts +3 -5
- package/studio/server/state/visibility.ts +1 -5
- package/studio/server/views/model.ts +3 -3
- package/studio/server/views/target.test.ts +17 -74
- package/studio/server/views/target.ts +24 -50
- package/studio/server/watch.test.ts +11 -11
- package/studio/server/watch.ts +8 -4
- package/studio/server/workspace-watch.ts +2 -2
- package/studio/shared/contracts/schema.ts +38 -107
- package/studio/shared/contracts/surface.test.ts +13 -15
- package/studio/shared/contracts/workspace.ts +2 -11
- package/studio/shared/schema/identity.test.ts +20 -44
- package/studio/shared/schema/identity.ts +9 -23
- package/viewer/dist/main.js +40 -61
- package/studio/client/dist/assets/index-B-c-smo9.js +0 -8
- package/studio/client/dist/assets/index-BckHuAWk.js +0 -81
- package/studio/client/dist/assets/index-C4aNQ6dz.css +0 -1
- package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
package/src/commands/call.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { CommandDefinition } from '../program/index'
|
|
|
5
5
|
|
|
6
6
|
import { createPathCall, expandSelfInCall, runKernelCommand, withSelfHint } from '../connection'
|
|
7
7
|
import { presentBinary } from '../lib/binary'
|
|
8
|
-
import {
|
|
8
|
+
import { failInput, log } from '../lib/log'
|
|
9
9
|
import { output, present } from '../lib/output'
|
|
10
10
|
|
|
11
11
|
type CallOpts = KernelCommandOpts & {
|
|
@@ -24,60 +24,47 @@ export async function callCommand(
|
|
|
24
24
|
rawParams: string[],
|
|
25
25
|
opts: CallOpts,
|
|
26
26
|
): Promise<void> {
|
|
27
|
-
// Expand @self before describe/execute through authenticated Identity.whoami.
|
|
28
|
-
let expanded: Awaited<ReturnType<typeof expandSelfInCall>>
|
|
29
|
-
try {
|
|
30
|
-
expanded = await expandSelfInCall(path, rawParams, opts)
|
|
31
|
-
} catch (error) {
|
|
32
|
-
failClosed(error, opts)
|
|
33
|
-
}
|
|
34
|
-
const expandedPath = expanded.path
|
|
35
|
-
try {
|
|
36
|
-
Path.parse(expandedPath)
|
|
37
|
-
} catch (error) {
|
|
38
|
-
failClosed(error, opts)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ── Parse params ────────────────────────────────────────
|
|
42
27
|
let params: Record<string, unknown>
|
|
43
28
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// ── Dry-run: show what would be sent ─────────────────────
|
|
50
|
-
if (opts.dryRun) {
|
|
51
|
-
output({ method: expandedPath, params }, opts)
|
|
52
|
-
return
|
|
29
|
+
Path.parse(path)
|
|
30
|
+
params = await parseParams(rawParams, opts.data)
|
|
31
|
+
} catch (error) {
|
|
32
|
+
failInput(error, opts)
|
|
53
33
|
}
|
|
54
34
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
35
|
+
await runKernelCommand<MaterializedCallResult | { readonly kind: 'dry'; readonly call: unknown }>(
|
|
36
|
+
{
|
|
37
|
+
opts,
|
|
38
|
+
label: path,
|
|
39
|
+
fn: async (ctx) => {
|
|
40
|
+
const expanded = await expandSelfInCall(path, params, ctx)
|
|
41
|
+
const request = createPathCall(expanded.path, expanded.parameters)
|
|
42
|
+
if (opts.dryRun) return { kind: 'dry', call: request }
|
|
43
|
+
return withSelfHint(
|
|
44
|
+
async () => materializeCallResult(await ctx.session.dispatch(request)),
|
|
45
|
+
expanded.meta,
|
|
46
|
+
)
|
|
47
|
+
},
|
|
48
|
+
format: async (result, fmtOpts) => {
|
|
49
|
+
switch (result.kind) {
|
|
50
|
+
case 'dry':
|
|
51
|
+
output(result.call, fmtOpts)
|
|
52
|
+
return
|
|
53
|
+
case 'value':
|
|
54
|
+
present(result.value, fmtOpts)
|
|
55
|
+
return
|
|
56
|
+
case 'binary':
|
|
57
|
+
await presentBinary(result.value, fmtOpts, { outFile: opts.output })
|
|
58
|
+
return
|
|
59
|
+
case 'stream':
|
|
60
|
+
output(result.values, fmtOpts)
|
|
61
|
+
return
|
|
62
|
+
case 'redirect':
|
|
63
|
+
throw new Error('Client Session returned an unresolved redirect.')
|
|
64
|
+
}
|
|
65
|
+
},
|
|
79
66
|
},
|
|
80
|
-
|
|
67
|
+
)
|
|
81
68
|
}
|
|
82
69
|
|
|
83
70
|
/** Drain a session-backed stream before the command-scoped Client Session closes. */
|
|
@@ -101,7 +88,7 @@ export async function parseParams(
|
|
|
101
88
|
try {
|
|
102
89
|
return JSON.parse(dataFlag)
|
|
103
90
|
} catch {
|
|
104
|
-
throw new
|
|
91
|
+
throw new TypeError(`Invalid JSON in --data: ${dataFlag}`)
|
|
105
92
|
}
|
|
106
93
|
}
|
|
107
94
|
|
|
@@ -114,7 +101,7 @@ export async function parseParams(
|
|
|
114
101
|
try {
|
|
115
102
|
return JSON.parse(stdin)
|
|
116
103
|
} catch {
|
|
117
|
-
throw new
|
|
104
|
+
throw new TypeError('Invalid JSON from stdin')
|
|
118
105
|
}
|
|
119
106
|
}
|
|
120
107
|
|
|
@@ -142,7 +129,7 @@ export function parseKeyValue(pairs: string[]): Record<string, unknown> {
|
|
|
142
129
|
for (const pair of pairs) {
|
|
143
130
|
const eqIdx = pair.indexOf('=')
|
|
144
131
|
if (eqIdx === -1) {
|
|
145
|
-
throw new
|
|
132
|
+
throw new TypeError(`Invalid param "${pair}" — expected key=value format`)
|
|
146
133
|
}
|
|
147
134
|
const key = pair.slice(0, eqIdx)
|
|
148
135
|
const raw = pair.slice(eqIdx + 1)
|
|
@@ -150,7 +137,7 @@ export function parseKeyValue(pairs: string[]): Record<string, unknown> {
|
|
|
150
137
|
const hint = key.endsWith(':')
|
|
151
138
|
? ` (looks like httpie's "key:=value" syntax — Astrale CLI doesn't support it; use --data '{"${key.slice(0, -1)}":<value>}' for nested values)`
|
|
152
139
|
: ` (keys must be identifier-shaped: letters, digits, underscore, hyphen)`
|
|
153
|
-
throw new
|
|
140
|
+
throw new TypeError(`Invalid param key "${key}" in "${pair}"${hint}`)
|
|
154
141
|
}
|
|
155
142
|
result[key] = coerceValue(raw)
|
|
156
143
|
}
|
|
@@ -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'
|
|
@@ -414,7 +414,7 @@ export async function installDirect(
|
|
|
414
414
|
fn: async ({ session }) =>
|
|
415
415
|
(await session.call(
|
|
416
416
|
createPathCall(
|
|
417
|
-
Path.project(
|
|
417
|
+
Path.project(K.functions.install.ref).raw,
|
|
418
418
|
directInstallCallInput(url, operation, opts.token),
|
|
419
419
|
),
|
|
420
420
|
)) as DirectInstallResult,
|
|
@@ -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
|
}
|
|
@@ -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,6 +1,7 @@
|
|
|
1
1
|
import type { KernelCommandOpts } from '../../connection'
|
|
2
2
|
import type { CommandDefinition } from '../../program/index'
|
|
3
3
|
|
|
4
|
+
import { AdminInstanceNotFoundError } from '../../admin/instance'
|
|
4
5
|
import { deleteOwnedInstance } from '../../lib/admin-instance'
|
|
5
6
|
import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
|
|
6
7
|
import { clearActive, readInstances, removeInstance, resolveInstanceKey } from '../../lib/instance'
|
|
@@ -53,9 +54,10 @@ 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)
|
|
@@ -3,7 +3,6 @@ import chalk from 'chalk'
|
|
|
3
3
|
import type { KernelCommandOpts } from '../../connection'
|
|
4
4
|
import type { CommandDefinition } from '../../program/index'
|
|
5
5
|
|
|
6
|
-
import { AstraleError } from '../../errors'
|
|
7
6
|
import { statusOwnedInstance } from '../../lib/admin-instance'
|
|
8
7
|
import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
|
|
9
8
|
import { fatal, log, withSpinner } from '../../lib/log'
|
|
@@ -19,14 +18,7 @@ export default {
|
|
|
19
18
|
action: async (id: string, opts: StatusOpts) => {
|
|
20
19
|
try {
|
|
21
20
|
const result = await withSpinner(`Fetching instance ${id}`, !isMachine(opts), () =>
|
|
22
|
-
statusOwnedInstance(opts, id)
|
|
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
|
-
}),
|
|
21
|
+
statusOwnedInstance(opts, id),
|
|
30
22
|
)
|
|
31
23
|
if (isMachine(opts)) {
|
|
32
24
|
output(result, opts)
|
|
@@ -5,9 +5,9 @@ import type { CommandDefinition } from '../program/index'
|
|
|
5
5
|
|
|
6
6
|
import { runKernelCommand } from '../connection'
|
|
7
7
|
import { AstraleError } from '../errors'
|
|
8
|
-
import {
|
|
8
|
+
import { failInput } from '../lib/log'
|
|
9
9
|
import { output } from '../lib/output'
|
|
10
|
-
import {
|
|
10
|
+
import { describeCallableFromBundle, missingCallableDescription } from './call-describe'
|
|
11
11
|
|
|
12
12
|
type IntrospectOpts = KernelCommandOpts & { bundle?: boolean }
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ export async function introspectCommand(target: string, opts: IntrospectOpts): P
|
|
|
17
17
|
try {
|
|
18
18
|
;({ origin, path } = parseIntrospectTarget(target))
|
|
19
19
|
} catch (error) {
|
|
20
|
-
|
|
20
|
+
failInput(error, opts)
|
|
21
21
|
}
|
|
22
22
|
const wantsCallable = isCallablePath(path)
|
|
23
23
|
|
|
@@ -44,7 +44,7 @@ export async function introspectCommand(target: string, opts: IntrospectOpts): P
|
|
|
44
44
|
)
|
|
45
45
|
}
|
|
46
46
|
if (wantsCallable) {
|
|
47
|
-
const described =
|
|
47
|
+
const described = describeCallableFromBundle(path, result.bundle)
|
|
48
48
|
if (described === undefined) throw missingCallableDescription(path.raw)
|
|
49
49
|
return described
|
|
50
50
|
}
|
|
@@ -85,13 +85,6 @@ function isCallablePath(path: Path): boolean {
|
|
|
85
85
|
return last.kind === 'projection' && last.projection.kind === 'function'
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function bundleRoot(bundle: unknown): unknown {
|
|
89
|
-
if (bundle !== null && typeof bundle === 'object' && 'root' in bundle) {
|
|
90
|
-
return (bundle as { root: unknown }).root
|
|
91
|
-
}
|
|
92
|
-
return bundle
|
|
93
|
-
}
|
|
94
|
-
|
|
95
88
|
export default {
|
|
96
89
|
name: 'introspect',
|
|
97
90
|
description: 'Read installed Domain schema from the Kernel Schema syscall',
|
package/src/commands/logs.ts
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
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 { ConnectionContext, KernelCommandOpts } from '../connection'
|
|
6
6
|
import type { Column, ListProjection } from '../lib/output'
|
|
7
7
|
import type { CommandDefinition } from '../program/index'
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
expandSelfInPath,
|
|
12
|
-
runKernelCommand,
|
|
13
|
-
withClientSession,
|
|
14
|
-
} from '../connection'
|
|
15
|
-
import { failClosed } from '../lib/log'
|
|
9
|
+
import { createPathCall, expandSelfInPath, runKernelCommand } from '../connection'
|
|
10
|
+
import { failInput } from '../lib/log'
|
|
16
11
|
import { isMachine, output, presentList } from '../lib/output'
|
|
17
12
|
|
|
18
|
-
const JOURNAL_PATH = Path.project(
|
|
13
|
+
const JOURNAL_PATH = Path.project(K.functions.journal.ref).raw
|
|
19
14
|
const DEFAULT_LIMIT = 200
|
|
20
15
|
const FOLLOW_INTERVAL_MS = 2_000
|
|
21
16
|
|
|
@@ -127,7 +122,7 @@ async function runOnce(opts: LogsOpts): Promise<void> {
|
|
|
127
122
|
await runKernelCommand({
|
|
128
123
|
opts,
|
|
129
124
|
label: 'Kernel journal',
|
|
130
|
-
fn: (context) => fetchPage(context, opts),
|
|
125
|
+
fn: async (context) => fetchPage(context, await resolveLogsOpts(opts, context)),
|
|
131
126
|
format: (page, format) => {
|
|
132
127
|
if (isMachine(format) || format.format !== undefined) output(page, format)
|
|
133
128
|
else {
|
|
@@ -139,14 +134,19 @@ async function runOnce(opts: LogsOpts): Promise<void> {
|
|
|
139
134
|
}
|
|
140
135
|
|
|
141
136
|
async function follow(opts: LogsOpts): Promise<void> {
|
|
142
|
-
await
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
cursor =
|
|
148
|
-
|
|
149
|
-
|
|
137
|
+
await runKernelCommand({
|
|
138
|
+
opts,
|
|
139
|
+
label: 'Kernel journal',
|
|
140
|
+
fn: async (context): Promise<never> => {
|
|
141
|
+
const resolved = await resolveLogsOpts(opts, context)
|
|
142
|
+
let cursor = resolved.cursor
|
|
143
|
+
for (;;) {
|
|
144
|
+
const page = await fetchPage(context, { ...resolved, cursor })
|
|
145
|
+
for (const record of page.records) printRecord(record)
|
|
146
|
+
cursor = page.cursor ?? cursor
|
|
147
|
+
await new Promise((resolve) => setTimeout(resolve, FOLLOW_INTERVAL_MS))
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
150
|
})
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -227,11 +227,10 @@ function positiveInteger(flag: string, raw: string): number {
|
|
|
227
227
|
return value
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
async function
|
|
231
|
-
buildJournalInput(opts)
|
|
230
|
+
async function resolveLogsOpts(opts: LogsOpts, context: ConnectionContext): Promise<LogsOpts> {
|
|
232
231
|
const principal = nonEmpty(opts.principal)
|
|
233
232
|
if (principal !== '@self') return opts
|
|
234
|
-
const { path } = await expandSelfInPath('@self',
|
|
233
|
+
const { path } = await expandSelfInPath('@self', context)
|
|
235
234
|
return { ...opts, principal: path.startsWith('@') ? path.slice(1) : path }
|
|
236
235
|
}
|
|
237
236
|
|
|
@@ -274,11 +273,11 @@ Examples:
|
|
|
274
273
|
],
|
|
275
274
|
action: async (opts: LogsOpts) => {
|
|
276
275
|
try {
|
|
277
|
-
|
|
278
|
-
if (prepared.follow) await follow(prepared)
|
|
279
|
-
else await runOnce(prepared)
|
|
276
|
+
buildJournalInput(opts)
|
|
280
277
|
} catch (error) {
|
|
281
|
-
|
|
278
|
+
failInput(error, opts)
|
|
282
279
|
}
|
|
280
|
+
if (opts.follow) await follow(opts)
|
|
281
|
+
else await runOnce(opts)
|
|
283
282
|
},
|
|
284
283
|
} satisfies CommandDefinition
|
package/src/commands/mutate.ts
CHANGED
|
@@ -7,8 +7,9 @@ import type { KernelCommandOpts } from '../connection'
|
|
|
7
7
|
import type { CommandDefinition } from '../program/index'
|
|
8
8
|
|
|
9
9
|
import { runKernelCommand } from '../connection'
|
|
10
|
+
import { AstraleError } from '../errors'
|
|
10
11
|
import { prepareMutation } from '../graph/index'
|
|
11
|
-
import {
|
|
12
|
+
import { failInput } from '../lib/log'
|
|
12
13
|
import { output } from '../lib/output'
|
|
13
14
|
import { renderTable } from '../lib/table'
|
|
14
15
|
|
|
@@ -23,7 +24,7 @@ export async function mutateCommand(opts: MutateOpts): Promise<void> {
|
|
|
23
24
|
try {
|
|
24
25
|
mutation = prepareMutation(await readDocument(opts))
|
|
25
26
|
} catch (error) {
|
|
26
|
-
|
|
27
|
+
failInput(error, opts)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
if (opts.dry) {
|
|
@@ -51,9 +52,9 @@ async function readDocument(opts: MutateOpts): Promise<unknown> {
|
|
|
51
52
|
try {
|
|
52
53
|
raw = await readFile(opts.file, 'utf8')
|
|
53
54
|
} catch (error) {
|
|
54
|
-
throw new
|
|
55
|
-
|
|
56
|
-
)
|
|
55
|
+
throw new AstraleError('FILE_READ_FAILED', `Cannot read --file ${opts.file}.`, undefined, {
|
|
56
|
+
cause: error,
|
|
57
|
+
})
|
|
57
58
|
}
|
|
58
59
|
return parseJson(raw, opts.file)
|
|
59
60
|
}
|
package/src/commands/query.ts
CHANGED
|
@@ -6,8 +6,9 @@ import type { KernelCommandOpts, SelfExpansionMeta } from '../connection'
|
|
|
6
6
|
import type { CommandDefinition } from '../program/index'
|
|
7
7
|
|
|
8
8
|
import { expandSelfInPath, runKernelCommand, withSelfHint } from '../connection'
|
|
9
|
+
import { AstraleError } from '../errors'
|
|
9
10
|
import { prepareQuery, type QueryCommandInput } from '../graph/index'
|
|
10
|
-
import {
|
|
11
|
+
import { failInput } from '../lib/log'
|
|
11
12
|
import { isMachine, output } from '../lib/output'
|
|
12
13
|
|
|
13
14
|
type QueryOpts = KernelCommandOpts & {
|
|
@@ -22,46 +23,42 @@ type QueryOpts = KernelCommandOpts & {
|
|
|
22
23
|
|
|
23
24
|
export async function queryCommand(sources: string[], opts: QueryOpts): Promise<void> {
|
|
24
25
|
let input: QueryCommandInput
|
|
25
|
-
let meta: SelfExpansionMeta | undefined
|
|
26
26
|
try {
|
|
27
27
|
const ast = await readAst(opts)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
cursor: opts.cursor,
|
|
37
|
-
}
|
|
38
|
-
meta = expanded.find((entry) => entry.meta !== undefined)?.meta
|
|
39
|
-
} else {
|
|
40
|
-
input = {
|
|
41
|
-
sources,
|
|
42
|
-
ast,
|
|
43
|
-
definition: opts.definition,
|
|
44
|
-
edge: opts.edge,
|
|
45
|
-
direction: opts.direction,
|
|
46
|
-
limit: opts.limit,
|
|
47
|
-
cursor: opts.cursor,
|
|
48
|
-
}
|
|
28
|
+
input = {
|
|
29
|
+
sources,
|
|
30
|
+
...(ast === undefined ? {} : { ast }),
|
|
31
|
+
definition: opts.definition,
|
|
32
|
+
edge: opts.edge,
|
|
33
|
+
direction: opts.direction,
|
|
34
|
+
limit: opts.limit,
|
|
35
|
+
cursor: opts.cursor,
|
|
49
36
|
}
|
|
50
37
|
} catch (error) {
|
|
51
|
-
|
|
38
|
+
failInput(error, opts)
|
|
52
39
|
}
|
|
53
40
|
|
|
54
41
|
let prepared
|
|
55
42
|
try {
|
|
56
43
|
prepared = prepareQuery(input)
|
|
57
44
|
} catch (error) {
|
|
58
|
-
|
|
45
|
+
failInput(error, opts)
|
|
59
46
|
}
|
|
60
47
|
|
|
61
48
|
await runKernelCommand({
|
|
62
49
|
opts,
|
|
63
50
|
label: 'Query',
|
|
64
|
-
fn:
|
|
51
|
+
fn: async (context) => {
|
|
52
|
+
const expanded = await Promise.all(sources.map((source) => expandSelfInPath(source, context)))
|
|
53
|
+
const meta: SelfExpansionMeta | undefined = expanded.find(
|
|
54
|
+
(entry) => entry.meta !== undefined,
|
|
55
|
+
)?.meta
|
|
56
|
+
const resolved =
|
|
57
|
+
meta === undefined
|
|
58
|
+
? prepared
|
|
59
|
+
: prepareQuery({ ...input, sources: expanded.map(({ path }) => path) })
|
|
60
|
+
return withSelfHint(() => context.graph.query(resolved.ast, { page: resolved.page }), meta)
|
|
61
|
+
},
|
|
65
62
|
format: (response, format) => {
|
|
66
63
|
output(response.result, format)
|
|
67
64
|
if (response.page.next && !isMachine(format)) {
|
|
@@ -81,9 +78,9 @@ async function readAst(opts: QueryOpts): Promise<unknown | undefined> {
|
|
|
81
78
|
try {
|
|
82
79
|
raw = await readFile(opts.file, 'utf8')
|
|
83
80
|
} catch (error) {
|
|
84
|
-
throw new
|
|
85
|
-
|
|
86
|
-
)
|
|
81
|
+
throw new AstraleError('FILE_READ_FAILED', `Cannot read --file ${opts.file}.`, undefined, {
|
|
82
|
+
cause: error,
|
|
83
|
+
})
|
|
87
84
|
}
|
|
88
85
|
return parseJson(raw, opts.file)
|
|
89
86
|
}
|
|
@@ -122,7 +119,7 @@ Examples:
|
|
|
122
119
|
{ flags: '-f, --file <path>', description: 'Read a canonical Query V6 document from a file' },
|
|
123
120
|
{
|
|
124
121
|
flags: '--definition <path>',
|
|
125
|
-
description: 'Select Nodes
|
|
122
|
+
description: 'Select Nodes satisfying one exact Class',
|
|
126
123
|
},
|
|
127
124
|
{ flags: '--edge <class>', description: 'Expand one exact Edge Class' },
|
|
128
125
|
{
|
package/src/commands/token.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { CommandDefinition } from '../program/index'
|
|
|
6
6
|
import { runKernelCommand } from '../connection'
|
|
7
7
|
import { AstraleError } from '../errors'
|
|
8
8
|
import { decodeJwtExpiration } from '../lib/local-status'
|
|
9
|
-
import {
|
|
9
|
+
import { failInput, log } from '../lib/log'
|
|
10
10
|
import { output } from '../lib/output'
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -23,7 +23,12 @@ export type TokenOpts = KernelCommandOpts & {
|
|
|
23
23
|
|
|
24
24
|
export async function tokenCommand(opts: TokenOpts): Promise<void> {
|
|
25
25
|
const commandOpts: TokenOpts = opts.for && !opts.as ? { ...opts, as: opts.for } : opts
|
|
26
|
-
|
|
26
|
+
let ttl: number
|
|
27
|
+
try {
|
|
28
|
+
ttl = parseTtl(commandOpts.ttl)
|
|
29
|
+
} catch (error) {
|
|
30
|
+
failInput(error, opts)
|
|
31
|
+
}
|
|
27
32
|
await runKernelCommand<string>({
|
|
28
33
|
opts: commandOpts,
|
|
29
34
|
label: 'Minting delegation token',
|
|
@@ -97,10 +102,6 @@ Examples:
|
|
|
97
102
|
{ flags: '--for <identity>', description: 'Mint the token for this identity (alias of --as)' },
|
|
98
103
|
],
|
|
99
104
|
action: async (opts) => {
|
|
100
|
-
|
|
101
|
-
await tokenCommand(opts as Parameters<typeof tokenCommand>[0])
|
|
102
|
-
} catch (error) {
|
|
103
|
-
failClosed(error, opts as TokenOpts)
|
|
104
|
-
}
|
|
105
|
+
await tokenCommand(opts as Parameters<typeof tokenCommand>[0])
|
|
105
106
|
},
|
|
106
107
|
} satisfies CommandDefinition
|