@astrale-os/cli 0.8.1-alpha.4 → 0.8.1-alpha.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/README.md +1 -1
- package/dist/astrale.js +827 -575
- package/dist/public/connect-core.js +22 -16
- package/dist/public/keys/index.js +3 -10
- package/dist/public/paths/index.js +3 -10
- package/dist/types/lib/instance-target.d.ts +2 -0
- package/dist/types/lib/invocation.d.ts +3 -0
- package/dist/types/lib/log.d.ts +6 -5
- package/dist/types/lib/output.d.ts +6 -2
- package/package.json +1 -1
- package/src/commands/__tests__/introspect-parse.test.ts +21 -0
- package/src/commands/__tests__/logs.test.ts +5 -0
- package/src/commands/__tests__/read-commands.test.ts +11 -1
- package/src/commands/__tests__/token-ttl.test.ts +21 -0
- package/src/commands/auth/token.ts +19 -7
- package/src/commands/call.ts +18 -43
- package/src/commands/get.ts +23 -5
- package/src/commands/identity/create.ts +11 -2
- package/src/commands/identity/delete.ts +8 -2
- package/src/commands/identity/export.ts +8 -2
- package/src/commands/identity/import.ts +11 -2
- package/src/commands/identity/sync.ts +8 -2
- package/src/commands/identity/unsync.ts +12 -2
- package/src/commands/identity/use.ts +8 -2
- package/src/commands/identity/whoami.ts +1 -1
- package/src/commands/introspect.ts +117 -0
- package/src/commands/logs.ts +50 -6
- package/src/commands/mutate.ts +2 -3
- package/src/commands/query.ts +3 -5
- package/src/commands/token.ts +35 -8
- package/src/commands/update.ts +30 -9
- package/src/commands/view.ts +5 -3
- package/src/connection/__tests__/credential.test.ts +10 -0
- package/src/connection/__tests__/errors.test.ts +20 -0
- package/src/connection/credential.ts +3 -0
- package/src/connection/errors.ts +74 -12
- package/src/connection/session.ts +9 -0
- package/src/connection/target.ts +1 -0
- package/src/graph/__tests__/mutation.test.ts +6 -0
- package/src/graph/mutation.ts +13 -0
- package/src/identity/__tests__/registry.test.ts +1 -1
- package/src/identity/registry.ts +12 -5
- package/src/lib/__tests__/command-dx.test.ts +47 -15
- package/src/lib/__tests__/instance-target.test.ts +17 -0
- package/src/lib/__tests__/output.test.ts +12 -0
- package/src/lib/command-dx.ts +41 -23
- package/src/lib/instance-target.ts +18 -2
- package/src/lib/invocation.ts +11 -0
- package/src/lib/log.ts +17 -9
- package/src/lib/output.ts +20 -4
- package/src/program/__tests__/program.test.ts +4 -2
- package/src/program/build.ts +3 -9
- package/src/program/options.ts +2 -1
- package/src/state/__tests__/identities.test.ts +2 -2
- package/src/state/identities.ts +3 -10
- package/src/commands/describe.ts +0 -86
|
@@ -138,7 +138,6 @@ describe('program composition', () => {
|
|
|
138
138
|
'auth token',
|
|
139
139
|
'browser',
|
|
140
140
|
'call',
|
|
141
|
-
'describe',
|
|
142
141
|
'domain',
|
|
143
142
|
'domain install',
|
|
144
143
|
'domain list',
|
|
@@ -170,6 +169,7 @@ describe('program composition', () => {
|
|
|
170
169
|
'instance list',
|
|
171
170
|
'instance status',
|
|
172
171
|
'instance use',
|
|
172
|
+
'introspect',
|
|
173
173
|
'logs',
|
|
174
174
|
'mutate',
|
|
175
175
|
'query',
|
|
@@ -186,7 +186,7 @@ describe('program composition', () => {
|
|
|
186
186
|
'whoami',
|
|
187
187
|
])
|
|
188
188
|
expect(createHash('sha256').update(JSON.stringify(surface)).digest('hex')).toBe(
|
|
189
|
-
'
|
|
189
|
+
'0f4739269db4c1dc8e1ba8cdf7840d7fbbe9c809234d2e21eef143a9de856382',
|
|
190
190
|
)
|
|
191
191
|
})
|
|
192
192
|
|
|
@@ -279,6 +279,7 @@ describe('help contract — connect-only command surface', () => {
|
|
|
279
279
|
'server',
|
|
280
280
|
'env',
|
|
281
281
|
'ls',
|
|
282
|
+
'describe',
|
|
282
283
|
]) {
|
|
283
284
|
expect(names).not.toContain(removed)
|
|
284
285
|
}
|
|
@@ -334,6 +335,7 @@ describe('help contract — payload sources', () => {
|
|
|
334
335
|
|
|
335
336
|
expect(callHelp).toContain('--data <json>')
|
|
336
337
|
expect(callHelp).not.toContain('--file <path>')
|
|
338
|
+
expect(callHelp).not.toContain('--describe')
|
|
337
339
|
expect(mutateHelp).toContain('--data <json>')
|
|
338
340
|
expect(mutateHelp).toContain('--file <path>')
|
|
339
341
|
})
|
package/src/program/build.ts
CHANGED
|
@@ -23,13 +23,6 @@ export async function buildProgram(): Promise<Command> {
|
|
|
23
23
|
.showSuggestionAfterError(true)
|
|
24
24
|
.addOption(new Option('--ci', 'Machine mode: no prompts, structured errors on stderr'))
|
|
25
25
|
.addOption(new Option('--no-prompt', 'Disable interactive prompts'))
|
|
26
|
-
.addOption(
|
|
27
|
-
new Option('--offline-ok', 'Tolerate offline state for commands that can operate locally'),
|
|
28
|
-
)
|
|
29
|
-
.addOption(
|
|
30
|
-
new Option('--log-level <level>', 'Log level').choices(['debug', 'info', 'warn', 'error']),
|
|
31
|
-
)
|
|
32
|
-
.addOption(new Option('--log-format <format>', 'Log output format').choices(['text', 'json']))
|
|
33
26
|
.action(async () => {
|
|
34
27
|
// Bare `astrale` in an interactive terminal with nothing connected yet →
|
|
35
28
|
// launch the guided setup. Otherwise (configured, piped, or CI) show help.
|
|
@@ -61,8 +54,8 @@ export async function buildProgram(): Promise<Command> {
|
|
|
61
54
|
registerCommand(program, withKernelOptions((await import('../commands/token')).default))
|
|
62
55
|
registerCommand(program, withKernelOptions((await import('../commands/get')).default))
|
|
63
56
|
registerCommand(program, withKernelOptions((await import('../commands/mutate')).default))
|
|
64
|
-
registerCommand(program, withKernelOptions((await import('../commands/describe')).default))
|
|
65
57
|
registerCommand(program, withKernelOptions((await import('../commands/query')).default))
|
|
58
|
+
registerCommand(program, withKernelOptions((await import('../commands/introspect')).default))
|
|
66
59
|
registerCommand(program, withKernelOptions((await import('../commands/logs')).default))
|
|
67
60
|
registerCommand(program, withKernelOptions((await import('../commands/view')).default))
|
|
68
61
|
registerCommand(program, (await import('../commands/status')).default)
|
|
@@ -158,7 +151,7 @@ export async function buildProgram(): Promise<Command> {
|
|
|
158
151
|
`
|
|
159
152
|
Command groups:
|
|
160
153
|
Getting started setup (sign in, pick an instance, equip your workspace)
|
|
161
|
-
Kernel get, mutate, call, query,
|
|
154
|
+
Kernel get, mutate, call, query, introspect, logs, view, token
|
|
162
155
|
Management admin, instance, domain, identity, auth, idp, update
|
|
163
156
|
Agent browser (drive the GUI via agent-browser)
|
|
164
157
|
Studio studio (launch the local Domain Studio GUI for a workspace)
|
|
@@ -180,6 +173,7 @@ Examples:
|
|
|
180
173
|
$ astrale instance status staging
|
|
181
174
|
$ astrale token --audience shell.astrale.ai --ttl 3600
|
|
182
175
|
$ astrale query /:notes.example.dev:class.Note --limit 50
|
|
176
|
+
$ astrale introspect /:host.astrale.ai:class.Manager:createInstance
|
|
183
177
|
$ astrale query --file query.v6.json --cursor "$CURSOR"
|
|
184
178
|
`,
|
|
185
179
|
)
|
package/src/program/options.ts
CHANGED
|
@@ -16,7 +16,8 @@ const KERNEL_PASSTHROUGH_OPTIONS: readonly CommandOption[] = Object.freeze([
|
|
|
16
16
|
{ flags: '--creds <token>', description: 'Use a pre-signed credential (e.g. delegation token)' },
|
|
17
17
|
{
|
|
18
18
|
flags: '--anonymous',
|
|
19
|
-
description:
|
|
19
|
+
description:
|
|
20
|
+
'Send no credential (cannot be combined with --as or --creds; --as and --creds are mutually exclusive)',
|
|
20
21
|
},
|
|
21
22
|
{ flags: '--debug', description: 'Print full error diagnostics on failure' },
|
|
22
23
|
])
|
|
@@ -46,7 +46,7 @@ describe('identity state', () => {
|
|
|
46
46
|
path,
|
|
47
47
|
now: () => new Date('2025-01-01T00:00:00.000Z'),
|
|
48
48
|
})
|
|
49
|
-
expect(missing
|
|
49
|
+
expect(missing).toEqual({ default: '', identities: {} })
|
|
50
50
|
await expect(readFile(path, 'utf-8')).rejects.toThrow()
|
|
51
51
|
|
|
52
52
|
await writeFile(path, legacy)
|
|
@@ -56,7 +56,7 @@ describe('identity state', () => {
|
|
|
56
56
|
|
|
57
57
|
const current = `${JSON.stringify({ version: IDENTITY_STORE_VERSION, ...missing })}\n`
|
|
58
58
|
await writeFile(path, current)
|
|
59
|
-
expect((await readIdentityStore({ path })).identities
|
|
59
|
+
expect((await readIdentityStore({ path })).identities).toEqual({})
|
|
60
60
|
expect(await readFile(path, 'utf-8')).toBe(current)
|
|
61
61
|
})
|
|
62
62
|
|
package/src/state/identities.ts
CHANGED
|
@@ -183,17 +183,10 @@ function hasVersion(input: unknown): input is { readonly version: unknown } {
|
|
|
183
183
|
return typeof input === 'object' && input !== null && Object.hasOwn(input, 'version')
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
function seed(
|
|
186
|
+
function seed(_now: Date): IdentityStore {
|
|
187
187
|
return {
|
|
188
|
-
default: '
|
|
189
|
-
identities: {
|
|
190
|
-
manager: {
|
|
191
|
-
subject: 'manager',
|
|
192
|
-
createdAt: now.toISOString(),
|
|
193
|
-
source: 'key',
|
|
194
|
-
mode: 'local',
|
|
195
|
-
},
|
|
196
|
-
},
|
|
188
|
+
default: '',
|
|
189
|
+
identities: {},
|
|
197
190
|
}
|
|
198
191
|
}
|
|
199
192
|
|
package/src/commands/describe.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { Node } from '@astrale-os/sdk/graph/node'
|
|
2
|
-
|
|
3
|
-
import { ClassPath } from '@astrale-os/sdk/graph/class'
|
|
4
|
-
import { Path } from '@astrale-os/sdk/graph/path'
|
|
5
|
-
import chalk from 'chalk'
|
|
6
|
-
|
|
7
|
-
import type { KernelCommandOpts } from '../connection'
|
|
8
|
-
import type { CommandDefinition } from '../program/index'
|
|
9
|
-
|
|
10
|
-
import { expandSelfInPath, runKernelCommand, withSelfHint } from '../connection'
|
|
11
|
-
import { unqualifyProperty } from '../graph/index'
|
|
12
|
-
import { log } from '../lib/log'
|
|
13
|
-
import { output } from '../lib/output'
|
|
14
|
-
|
|
15
|
-
type DescribeOpts = KernelCommandOpts & { schema?: boolean }
|
|
16
|
-
type DescribedNode = Omit<Node, 'props'> & { readonly props: Readonly<Record<string, unknown>> }
|
|
17
|
-
|
|
18
|
-
/** Describe only facts present on the canonical Node; no hierarchy is inferred from its Path. */
|
|
19
|
-
export async function describeCommand(target: string, opts: DescribeOpts): Promise<void> {
|
|
20
|
-
let path: string
|
|
21
|
-
let meta
|
|
22
|
-
try {
|
|
23
|
-
;({ path, meta } = await expandSelfInPath(target, opts))
|
|
24
|
-
} catch (error) {
|
|
25
|
-
log.error(error instanceof Error ? error.message : 'Invalid target')
|
|
26
|
-
process.exit(1)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
await runKernelCommand({
|
|
30
|
-
opts,
|
|
31
|
-
label: `Describe ${path}`,
|
|
32
|
-
fn: ({ graph }) => withSelfHint(() => graph.getOrThrow(Path.parse(path)), meta),
|
|
33
|
-
format: (node, format, machine) => {
|
|
34
|
-
const shown = opts.schema === false ? withoutSchema(node) : node
|
|
35
|
-
if (machine || format.format !== undefined) output(shown, format)
|
|
36
|
-
else printDescription(path, shown)
|
|
37
|
-
},
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function withoutSchema(node: Node): DescribedNode {
|
|
42
|
-
return {
|
|
43
|
-
...node,
|
|
44
|
-
props: Object.fromEntries(
|
|
45
|
-
Object.entries(node.props).filter(([key]) => unqualifyProperty(key) !== 'schema'),
|
|
46
|
-
),
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function printDescription(target: string, node: DescribedNode): void {
|
|
51
|
-
console.log(` ${chalk.bold.cyan(target)}`)
|
|
52
|
-
console.log(` ${chalk.dim('id')} ${node.id}`)
|
|
53
|
-
console.log(
|
|
54
|
-
` ${chalk.dim('class')} ${ClassPath.name(node.class)} ${chalk.dim(`(${node.class})`)}`,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
const properties = Object.entries(node.props)
|
|
58
|
-
if (properties.length === 0) return
|
|
59
|
-
console.log(`\n ${chalk.bold('Properties:')}`)
|
|
60
|
-
for (const [key, value] of properties) {
|
|
61
|
-
const rendered = typeof value === 'string' ? value : JSON.stringify(value)
|
|
62
|
-
console.log(` ${chalk.cyan(unqualifyProperty(key))}: ${chalk.dim(rendered)}`)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export default {
|
|
67
|
-
name: 'describe',
|
|
68
|
-
description: 'Describe the canonical facts of one node',
|
|
69
|
-
afterHelpText: `
|
|
70
|
-
Behavior:
|
|
71
|
-
Reads one canonical Node and presents its ID, Class, and properties.
|
|
72
|
-
It does not infer operations or children from path layout. --no-schema
|
|
73
|
-
omits schema-valued properties from Domain-sized results.
|
|
74
|
-
|
|
75
|
-
Examples:
|
|
76
|
-
$ astrale describe /:kernel.astrale.ai:class.Domain
|
|
77
|
-
$ astrale describe @self --no-schema
|
|
78
|
-
`,
|
|
79
|
-
arguments: [{ name: 'target', description: 'Canonical Node Path or @id' }],
|
|
80
|
-
options: [
|
|
81
|
-
{ flags: '--no-schema', description: 'Omit properties whose qualified leaf is schema' },
|
|
82
|
-
],
|
|
83
|
-
action: async (target, opts) => {
|
|
84
|
-
await describeCommand(target as string, opts as DescribeOpts)
|
|
85
|
-
},
|
|
86
|
-
} satisfies CommandDefinition
|