@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.
Files changed (56) hide show
  1. package/README.md +1 -1
  2. package/dist/astrale.js +827 -575
  3. package/dist/public/connect-core.js +22 -16
  4. package/dist/public/keys/index.js +3 -10
  5. package/dist/public/paths/index.js +3 -10
  6. package/dist/types/lib/instance-target.d.ts +2 -0
  7. package/dist/types/lib/invocation.d.ts +3 -0
  8. package/dist/types/lib/log.d.ts +6 -5
  9. package/dist/types/lib/output.d.ts +6 -2
  10. package/package.json +1 -1
  11. package/src/commands/__tests__/introspect-parse.test.ts +21 -0
  12. package/src/commands/__tests__/logs.test.ts +5 -0
  13. package/src/commands/__tests__/read-commands.test.ts +11 -1
  14. package/src/commands/__tests__/token-ttl.test.ts +21 -0
  15. package/src/commands/auth/token.ts +19 -7
  16. package/src/commands/call.ts +18 -43
  17. package/src/commands/get.ts +23 -5
  18. package/src/commands/identity/create.ts +11 -2
  19. package/src/commands/identity/delete.ts +8 -2
  20. package/src/commands/identity/export.ts +8 -2
  21. package/src/commands/identity/import.ts +11 -2
  22. package/src/commands/identity/sync.ts +8 -2
  23. package/src/commands/identity/unsync.ts +12 -2
  24. package/src/commands/identity/use.ts +8 -2
  25. package/src/commands/identity/whoami.ts +1 -1
  26. package/src/commands/introspect.ts +117 -0
  27. package/src/commands/logs.ts +50 -6
  28. package/src/commands/mutate.ts +2 -3
  29. package/src/commands/query.ts +3 -5
  30. package/src/commands/token.ts +35 -8
  31. package/src/commands/update.ts +30 -9
  32. package/src/commands/view.ts +5 -3
  33. package/src/connection/__tests__/credential.test.ts +10 -0
  34. package/src/connection/__tests__/errors.test.ts +20 -0
  35. package/src/connection/credential.ts +3 -0
  36. package/src/connection/errors.ts +74 -12
  37. package/src/connection/session.ts +9 -0
  38. package/src/connection/target.ts +1 -0
  39. package/src/graph/__tests__/mutation.test.ts +6 -0
  40. package/src/graph/mutation.ts +13 -0
  41. package/src/identity/__tests__/registry.test.ts +1 -1
  42. package/src/identity/registry.ts +12 -5
  43. package/src/lib/__tests__/command-dx.test.ts +47 -15
  44. package/src/lib/__tests__/instance-target.test.ts +17 -0
  45. package/src/lib/__tests__/output.test.ts +12 -0
  46. package/src/lib/command-dx.ts +41 -23
  47. package/src/lib/instance-target.ts +18 -2
  48. package/src/lib/invocation.ts +11 -0
  49. package/src/lib/log.ts +17 -9
  50. package/src/lib/output.ts +20 -4
  51. package/src/program/__tests__/program.test.ts +4 -2
  52. package/src/program/build.ts +3 -9
  53. package/src/program/options.ts +2 -1
  54. package/src/state/__tests__/identities.test.ts +2 -2
  55. package/src/state/identities.ts +3 -10
  56. 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
- '4b053fe80827aeb40aecc13cd17c293b8701e59cb04f5ccb8185e9e255376dd1',
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
  })
@@ -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, describe, token
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
  )
@@ -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: 'Send no credential (cannot be combined with --as or --creds)',
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.identities.manager.createdAt).toBe('2025-01-01T00:00:00.000Z')
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.manager.subject).toBe('manager')
59
+ expect((await readIdentityStore({ path })).identities).toEqual({})
60
60
  expect(await readFile(path, 'utf-8')).toBe(current)
61
61
  })
62
62
 
@@ -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(now: Date): IdentityStore {
186
+ function seed(_now: Date): IdentityStore {
187
187
  return {
188
- default: 'manager',
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
 
@@ -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