@astrale-os/cli 0.8.1-alpha.0 → 0.8.1-alpha.3
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 +63133 -41267
- package/dist/public/connect-core.js +55030 -0
- package/dist/public/keys/index.js +45631 -0
- package/dist/public/paths/index.js +43990 -0
- package/dist/types/admin/instance/model.d.ts +40 -0
- package/dist/types/connect-core.d.ts +22 -0
- package/dist/types/connection/auth.d.ts +33 -0
- package/dist/types/errors.d.ts +23 -0
- package/dist/types/identity/registry.d.ts +25 -0
- package/dist/types/keys/algorithm.d.ts +6 -0
- package/dist/types/keys/credential.d.ts +21 -0
- package/dist/types/keys/index.d.ts +4 -0
- package/dist/types/keys/pair.d.ts +34 -0
- package/dist/types/lib/admin-target.d.ts +74 -0
- package/dist/types/lib/ca-fetch.d.ts +2 -0
- package/dist/types/lib/config.d.ts +71 -0
- package/dist/types/lib/format.d.ts +1 -0
- package/dist/types/lib/idp-session.d.ts +33 -0
- package/dist/types/lib/idp.d.ts +397 -0
- package/dist/types/lib/instance-target.d.ts +36 -0
- package/dist/types/lib/instance.d.ts +186 -0
- package/dist/types/lib/log.d.ts +30 -0
- package/dist/types/lib/login-flow.d.ts +49 -0
- package/dist/types/lib/meta.d.ts +36 -0
- package/dist/types/lib/output.d.ts +83 -0
- package/dist/types/lib/table.d.ts +18 -0
- package/dist/types/lib/validation.d.ts +11 -0
- package/dist/types/paths/index.d.ts +2 -0
- package/dist/types/state/exchange-credentials.d.ts +25 -0
- package/dist/types/state/files.d.ts +9 -0
- package/dist/types/state/identities.d.ts +42 -0
- package/dist/types/state/index.d.ts +8 -0
- package/dist/types/state/paths.d.ts +32 -0
- package/package.json +22 -7
- package/src/admin/.spec/api.d.ts +3 -0
- package/src/admin/.spec/architecture.md +15 -0
- package/src/admin/.spec/icon.svg +3 -0
- package/src/admin/.spec/layout.ts +6 -0
- package/src/admin/catalog/.spec/api.d.ts +65 -0
- package/src/admin/catalog/.spec/architecture.md +6 -0
- package/src/admin/catalog/.spec/icon.svg +3 -0
- package/src/admin/catalog/.spec/layout.ts +6 -0
- package/src/admin/catalog/__tests__/client.test.ts +171 -0
- package/src/admin/catalog/client.ts +214 -0
- package/src/admin/catalog/index.ts +13 -0
- package/src/admin/catalog/model.ts +42 -0
- package/src/admin/catalog/tsconfig.json +8 -0
- package/src/admin/graph/.spec/api.d.ts +28 -0
- package/src/admin/graph/.spec/architecture.md +5 -0
- package/src/admin/graph/.spec/icon.svg +3 -0
- package/src/admin/graph/.spec/layout.ts +3 -0
- package/src/admin/graph/index.ts +6 -0
- package/src/admin/graph/nodes.ts +56 -0
- package/src/admin/index.ts +2 -0
- package/src/admin/instance/.spec/api.d.ts +66 -0
- package/src/admin/instance/.spec/architecture.md +10 -0
- package/src/admin/instance/.spec/icon.svg +3 -0
- package/src/admin/instance/.spec/layout.ts +6 -0
- package/src/admin/instance/__tests__/client.test.ts +289 -0
- package/src/admin/instance/client.ts +298 -0
- package/src/admin/instance/index.ts +16 -0
- package/src/admin/instance/model.ts +65 -0
- package/src/admin/instance/tsconfig.json +8 -0
- package/src/commands/__tests__/admin-instance.test.ts +3 -36
- package/src/commands/__tests__/call-describe.test.ts +67 -0
- package/src/commands/__tests__/call.test.ts +21 -68
- package/src/commands/__tests__/domain-install-owned.test.ts +26 -27
- package/src/commands/__tests__/domain-list.test.ts +2 -6
- package/src/commands/__tests__/install-direct.test.ts +20 -0
- package/src/commands/__tests__/instance-list-admin.test.ts +26 -0
- package/src/commands/__tests__/logs.test.ts +71 -96
- package/src/commands/__tests__/ls.test.ts +21 -17
- package/src/commands/__tests__/read-commands.test.ts +171 -101
- package/src/commands/__tests__/view.test.ts +100 -51
- package/src/commands/admin/status.ts +3 -3
- package/src/commands/admin/use.ts +29 -6
- package/src/commands/auth/login.ts +1 -1
- package/src/commands/auth/logout.ts +4 -2
- package/src/commands/auth/status.ts +2 -2
- package/src/commands/auth/token.ts +2 -2
- package/src/commands/browser.ts +1 -1
- package/src/commands/call-describe.ts +131 -0
- package/src/commands/call.ts +69 -109
- package/src/commands/describe.ts +52 -147
- package/src/commands/domain/install.ts +106 -49
- package/src/commands/domain/list.ts +4 -8
- package/src/commands/domain/publish.ts +9 -31
- package/src/commands/get.ts +33 -66
- package/src/commands/identity/__tests__/register.test.ts +93 -0
- package/src/commands/identity/create.ts +2 -2
- package/src/commands/identity/delete.ts +2 -2
- package/src/commands/identity/export.ts +7 -33
- package/src/commands/identity/import.ts +21 -70
- package/src/commands/identity/list.ts +2 -2
- package/src/commands/identity/register.ts +148 -117
- package/src/commands/identity/sync.ts +2 -2
- package/src/commands/identity/unsync.ts +2 -2
- package/src/commands/identity/use.ts +2 -2
- package/src/commands/identity/whoami.ts +2 -2
- package/src/commands/idp/add.ts +1 -1
- package/src/commands/idp/list.ts +1 -1
- package/src/commands/idp/refresh.ts +1 -1
- package/src/commands/idp/remove.ts +2 -2
- package/src/commands/idp/show.ts +1 -1
- package/src/commands/instance/active.ts +2 -2
- package/src/commands/instance/bookmark.ts +8 -2
- package/src/commands/instance/create.ts +1 -1
- package/src/commands/instance/delete.ts +4 -10
- package/src/commands/instance/forget.ts +1 -1
- package/src/commands/instance/list.ts +39 -6
- package/src/commands/instance/status.ts +5 -7
- package/src/commands/instance/use.ts +3 -3
- package/src/commands/logs.ts +171 -278
- package/src/commands/ls.ts +78 -204
- package/src/commands/mutate.ts +70 -139
- package/src/commands/query.ts +100 -278
- package/src/commands/session/analyze.ts +1 -1
- package/src/commands/session/list.ts +1 -1
- package/src/commands/setup.ts +1 -1
- package/src/commands/status.ts +1 -1
- package/src/commands/studio.ts +1 -1
- package/src/commands/token.ts +26 -21
- package/src/commands/update.ts +1 -1
- package/src/commands/use.ts +2 -3
- package/src/commands/view-serve.ts +1 -1
- package/src/commands/view.ts +67 -109
- package/src/connect-core.test.ts +38 -0
- package/src/connect-core.ts +42 -0
- package/src/connection/.spec/api.d.ts +111 -0
- package/src/connection/.spec/architecture.md +41 -0
- package/src/connection/.spec/capabilities/connection.ts +13 -0
- package/src/connection/.spec/examples/call.ts +7 -0
- package/src/connection/.spec/flows/command.ts +20 -0
- package/src/connection/.spec/flows/session.ts +61 -0
- package/src/connection/.spec/laws/connection.ts +181 -0
- package/src/connection/.spec/layout.ts +19 -0
- package/src/{kernel → connection}/__tests__/auth.test.ts +26 -2
- package/src/connection/__tests__/ca-fetch.test.ts +53 -0
- package/src/connection/__tests__/call.test.ts +17 -0
- package/src/connection/__tests__/credential.test.ts +109 -0
- package/src/connection/__tests__/errors.test.ts +96 -0
- package/src/connection/__tests__/exchange.test.ts +224 -0
- package/src/connection/__tests__/fixtures/localhost-cert.pem +19 -0
- package/src/connection/__tests__/fixtures/localhost-key.base64 +1 -0
- package/src/connection/__tests__/managed.test.ts +39 -0
- package/src/connection/__tests__/self.test.ts +51 -0
- package/src/connection/__tests__/session.test.ts +140 -0
- package/src/connection/__tests__/target.test.ts +93 -0
- package/src/{kernel → connection}/auth.ts +8 -8
- package/src/connection/call.ts +7 -0
- package/src/{kernel/run.ts → connection/command.ts} +22 -13
- package/src/connection/credential.ts +114 -0
- package/src/{kernel → connection}/errors.ts +32 -9
- package/src/connection/exchange.ts +274 -0
- package/src/connection/index.ts +8 -0
- package/src/connection/self.ts +120 -0
- package/src/connection/session.ts +176 -0
- package/src/connection/target.ts +111 -0
- package/src/connection/tsconfig.json +6 -0
- package/src/graph/.spec/api.d.ts +34 -0
- package/src/graph/.spec/laws/documents.ts +24 -0
- package/src/graph/.spec/laws/projection.ts +13 -0
- package/src/graph/.spec/layout.ts +6 -0
- package/src/graph/__tests__/mutation.test.ts +45 -0
- package/src/graph/__tests__/projection.test.ts +22 -0
- package/src/graph/__tests__/query.test.ts +154 -0
- package/src/graph/index.ts +3 -0
- package/src/graph/mutation.ts +33 -0
- package/src/graph/projection.ts +21 -0
- package/src/graph/query.ts +108 -0
- package/src/graph/tsconfig.json +6 -0
- package/src/identity/.history/ard/bootstrap-root-transfer.md +57 -0
- package/src/identity/.history/ard/domain-mediated-registration.md +36 -0
- package/src/identity/.spec/api.d.ts +124 -0
- package/src/identity/.spec/architecture.md +33 -0
- package/src/identity/.spec/capabilities/identity.ts +7 -0
- package/src/identity/.spec/flows/bootstrap-root.ts +79 -0
- package/src/identity/.spec/flows/domain-mediated-registration.ts +51 -0
- package/src/identity/.spec/flows/import.ts +29 -0
- package/src/identity/.spec/laws/identity.ts +56 -0
- package/src/identity/.spec/layout.ts +13 -0
- package/src/identity/.spec/schemas/identity-export-v1.schema.json +25 -0
- package/src/identity/__tests__/fixtures/registry-journey.ts +53 -0
- package/src/identity/__tests__/registration.test.ts +64 -0
- package/src/identity/__tests__/registry.test.ts +70 -0
- package/src/identity/__tests__/transfer.test.ts +198 -0
- package/src/identity/index.ts +23 -0
- package/src/identity/registration.ts +72 -0
- package/src/identity/registry.ts +172 -0
- package/src/identity/transfer.ts +187 -0
- package/src/identity/tsconfig.json +6 -0
- package/src/index.ts +1 -0
- package/src/keys/.spec/api.d.ts +74 -0
- package/src/keys/.spec/architecture.md +13 -0
- package/src/keys/.spec/laws/keys.ts +43 -0
- package/src/keys/.spec/layout.ts +6 -0
- package/src/keys/__tests__/algorithm.test.ts +39 -0
- package/src/keys/__tests__/keys.test.ts +168 -0
- package/src/keys/algorithm.ts +33 -0
- package/src/keys/credential.ts +112 -0
- package/src/keys/index.ts +14 -0
- package/src/keys/pair.ts +219 -0
- package/src/keys/tsconfig.json +6 -0
- package/src/lib/__tests__/admin-target.test.ts +67 -7
- package/src/lib/__tests__/binary.test.ts +2 -3
- package/src/lib/__tests__/command-dx.test.ts +2 -2
- package/src/lib/__tests__/config.test.ts +3 -2
- package/src/lib/__tests__/idp.test.ts +4 -6
- package/src/lib/__tests__/instance-target.test.ts +7 -4
- package/src/lib/__tests__/local-status.test.ts +1 -1
- package/src/lib/__tests__/log.test.ts +31 -0
- package/src/lib/__tests__/meta.test.ts +55 -0
- package/src/lib/__tests__/sdk-deps.test.ts +1 -1
- package/src/lib/__tests__/self.test.ts +8 -230
- package/src/lib/__tests__/use-target.test.ts +1 -1
- package/src/lib/__tests__/view-open-intent.test.ts +78 -104
- package/src/lib/__tests__/view-session.test.ts +99 -0
- package/src/lib/admin-domain.ts +39 -25
- package/src/lib/admin-instance.ts +38 -43
- package/src/lib/admin-target.ts +67 -13
- package/src/lib/binary.ts +13 -34
- package/src/lib/browser.ts +1 -1
- package/src/{kernel → lib}/ca-fetch.ts +35 -27
- package/src/lib/config.ts +1 -1
- package/src/lib/idp-session.ts +1 -1
- package/src/lib/idp.ts +3 -8
- package/src/lib/instance-target.ts +12 -8
- package/src/lib/instance.ts +34 -2
- package/src/lib/local-status.ts +2 -2
- package/src/lib/log.ts +3 -1
- package/src/lib/login-flow.ts +32 -5
- package/src/lib/meta.ts +15 -11
- package/src/lib/provision-instance.ts +4 -12
- package/src/lib/self.ts +5 -147
- package/src/lib/update.ts +1 -1
- package/src/lib/use-target.ts +1 -1
- package/src/lib/validation.ts +2 -2
- package/src/lib/view/open-intent.ts +7 -37
- package/src/lib/view/port-allocation.ts +1 -1
- package/src/lib/view/resolve.ts +52 -45
- package/src/lib/view/server.ts +16 -33
- package/src/lib/view/session.ts +51 -22
- package/src/paths/.spec/api.d.ts +13 -0
- package/src/paths/.spec/architecture.md +5 -0
- package/src/paths/.spec/layout.ts +3 -0
- package/src/paths/index.ts +13 -0
- package/src/program/.spec/api.d.ts +42 -0
- package/src/program/.spec/architecture.md +18 -0
- package/src/program/.spec/laws/program.ts +29 -0
- package/src/program/.spec/layout.ts +14 -0
- package/src/program/__tests__/program.test.ts +359 -0
- package/src/program/build.ts +190 -0
- package/src/program/command.ts +42 -0
- package/src/program/index.ts +2 -0
- package/src/program/options.ts +40 -0
- package/src/{registry.ts → program/registry.ts} +5 -1
- package/src/program/tsconfig.json +6 -0
- package/src/setup/steps/admin.ts +18 -3
- package/src/setup/steps/instance.ts +1 -1
- package/src/state/.spec/api.d.ts +133 -0
- package/src/state/.spec/architecture.md +31 -0
- package/src/state/.spec/capabilities/state.ts +7 -0
- package/src/state/.spec/flows/identity-update.ts +22 -0
- package/src/state/.spec/laws/state.ts +73 -0
- package/src/state/.spec/layout.ts +14 -0
- package/src/state/__tests__/exchange-credentials.test.ts +188 -0
- package/src/state/__tests__/files.test.ts +113 -0
- package/src/state/__tests__/fixtures/identity-transition.ts +37 -0
- package/src/state/__tests__/identities.test.ts +142 -0
- package/src/state/__tests__/paths.test.ts +27 -0
- package/src/state/exchange-credentials.ts +219 -0
- package/src/state/files.ts +129 -0
- package/src/state/identities.ts +236 -0
- package/src/state/index.ts +29 -0
- package/src/state/paths.ts +61 -0
- package/src/state/tsconfig.json +6 -0
- package/src/telemetry/__tests__/redact.test.ts +3 -3
- package/src/telemetry/__tests__/trigger.test.ts +1 -1
- package/src/telemetry/settings.ts +1 -1
- package/src/telemetry/store.ts +1 -1
- package/src/test-utils.ts +1 -1
- package/studio/client/dist/assets/{elk-api-DVw5WDTH.js → elk-api-D0cBetPW.js} +1 -1
- package/studio/client/dist/assets/index-Dspir4w7.js +81 -0
- package/studio/client/dist/assets/{index-Dl709Ra1.js → index-bVD2KJgz.js} +4 -4
- package/studio/client/dist/index.html +1 -1
- package/studio/package.json +10 -1
- package/studio/server/introspect/extractor.ts +1 -1
- package/studio/server/state/views.test.ts +3 -7
- package/studio/server/state/views.ts +23 -30
- package/tsconfig.json +1 -1
- package/viewer/dist/main.js +65 -39
- package/src/command.ts +0 -42
- package/src/commands/__tests__/help-contract.test.ts +0 -164
- package/src/kernel/__tests__/client-owned-lookup.test.ts +0 -51
- package/src/kernel/__tests__/errors.test.ts +0 -43
- package/src/kernel/__tests__/expand.test.ts +0 -123
- package/src/kernel/client.ts +0 -214
- package/src/kernel/expand.ts +0 -192
- package/src/kernel/graph.ts +0 -96
- package/src/kernel/index.ts +0 -29
- package/src/kernel/options.ts +0 -22
- package/src/kernel/types.ts +0 -14
- package/src/lib/__tests__/domain-identity.test.ts +0 -60
- package/src/lib/__tests__/fs-atomic.test.ts +0 -104
- package/src/lib/__tests__/identity.test.ts +0 -79
- package/src/lib/__tests__/keys.test.ts +0 -129
- package/src/lib/domain-identity.ts +0 -49
- package/src/lib/env.ts +0 -49
- package/src/lib/fs-atomic.ts +0 -126
- package/src/lib/identity.ts +0 -256
- package/src/lib/keys.ts +0 -294
- package/src/lib/paths.ts +0 -11
- package/src/program.ts +0 -213
- package/studio/client/dist/assets/index-CTbkDp3z.js +0 -81
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { CommandDefinition } from '../../
|
|
1
|
+
import type { CommandDefinition } from '../../program/index'
|
|
2
2
|
|
|
3
|
-
import { getDefault, readIdentities } from '../../
|
|
3
|
+
import { getDefault, readIdentities } from '../../identity/index'
|
|
4
4
|
import { deleteIdpSession, listIdpSessions } from '../../lib/idp'
|
|
5
5
|
import { log } from '../../lib/log'
|
|
6
6
|
import { output, RAW_OUTPUT_OPTIONS } from '../../lib/output'
|
|
7
|
+
import { ExchangeCredentialCache } from '../../state/index'
|
|
7
8
|
|
|
8
9
|
export default {
|
|
9
10
|
name: 'logout',
|
|
@@ -28,6 +29,7 @@ export default {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
for (const name of names) await deleteIdpSession(name)
|
|
32
|
+
await new ExchangeCredentialCache().clear()
|
|
31
33
|
|
|
32
34
|
if (opts.raw || opts.json) {
|
|
33
35
|
output({ cleared: names }, opts)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
2
|
|
|
3
|
-
import type { CommandDefinition } from '../../command'
|
|
4
3
|
import type { ListOpts, ListProjection } from '../../lib/output'
|
|
4
|
+
import type { CommandDefinition } from '../../program/index'
|
|
5
5
|
|
|
6
|
-
import { readIdentities } from '../../
|
|
6
|
+
import { readIdentities } from '../../identity/index'
|
|
7
7
|
import { isSessionExpired, listIdpSessions } from '../../lib/idp'
|
|
8
8
|
import { log } from '../../lib/log'
|
|
9
9
|
import { isMachine, presentList, RAW_OUTPUT_OPTIONS } from '../../lib/output'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { CommandDefinition } from '../../
|
|
1
|
+
import type { CommandDefinition } from '../../program/index'
|
|
2
2
|
|
|
3
|
-
import { getDefault, getIdentity, readIdentities } from '../../
|
|
3
|
+
import { getDefault, getIdentity, readIdentities } from '../../identity/index'
|
|
4
4
|
import { isSessionExpired, readIdpSession, type IdpSession } from '../../lib/idp'
|
|
5
5
|
import { ensureFreshSession } from '../../lib/idp-session'
|
|
6
6
|
import { log } from '../../lib/log'
|
package/src/commands/browser.ts
CHANGED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { Path } from '@astrale-os/sdk/graph/path'
|
|
2
|
+
|
|
3
|
+
import { AstraleError } from '../errors'
|
|
4
|
+
|
|
5
|
+
type JsonRecord = Record<string, unknown>
|
|
6
|
+
|
|
7
|
+
export interface CallableDescription {
|
|
8
|
+
readonly path: string
|
|
9
|
+
readonly origin: string
|
|
10
|
+
readonly method?: string
|
|
11
|
+
readonly function?: string
|
|
12
|
+
readonly class?: string
|
|
13
|
+
readonly dispatch?: 'static' | 'instance'
|
|
14
|
+
readonly description?: string
|
|
15
|
+
readonly auth?: unknown
|
|
16
|
+
readonly input?: unknown
|
|
17
|
+
readonly output?: unknown
|
|
18
|
+
readonly candidates?: readonly CallableDescription[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Resolve one callable's input/output from an installed Domain schema document. */
|
|
22
|
+
export function describeCallableFromSchema(
|
|
23
|
+
path: Path,
|
|
24
|
+
schema: unknown,
|
|
25
|
+
): CallableDescription | undefined {
|
|
26
|
+
if (path.ast.anchor.kind !== 'domain') return undefined
|
|
27
|
+
const origin = path.ast.anchor.origin
|
|
28
|
+
const last = path.ast.steps.at(-1)
|
|
29
|
+
const document = asRecord(schema)
|
|
30
|
+
if (document === undefined || last === undefined) return undefined
|
|
31
|
+
|
|
32
|
+
if (last.kind === 'method') {
|
|
33
|
+
const owner = path.ast.steps.at(-2)
|
|
34
|
+
if (
|
|
35
|
+
owner?.kind === 'projection' &&
|
|
36
|
+
(owner.projection.kind === 'class' || owner.projection.kind === 'interface')
|
|
37
|
+
) {
|
|
38
|
+
const bag = asRecord(
|
|
39
|
+
owner.projection.kind === 'class' ? document.classes : document.interfaces,
|
|
40
|
+
)
|
|
41
|
+
const definition = asRecord(bag?.[owner.projection.name])
|
|
42
|
+
const method = asRecord(asRecord(definition?.methods)?.[last.name])
|
|
43
|
+
if (method !== undefined) {
|
|
44
|
+
return Object.freeze({
|
|
45
|
+
path: path.raw,
|
|
46
|
+
origin,
|
|
47
|
+
class: owner.projection.name,
|
|
48
|
+
method: last.name,
|
|
49
|
+
dispatch: last.dispatch,
|
|
50
|
+
...callableFields(method),
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const matches = findNamedMethods(document, origin, path.raw, last.name, last.dispatch)
|
|
55
|
+
if (matches.length === 1) return matches[0]
|
|
56
|
+
if (matches.length > 1) {
|
|
57
|
+
return Object.freeze({
|
|
58
|
+
path: path.raw,
|
|
59
|
+
origin,
|
|
60
|
+
method: last.name,
|
|
61
|
+
dispatch: last.dispatch,
|
|
62
|
+
candidates: Object.freeze(matches),
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
return undefined
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (last.kind === 'projection' && last.projection.kind === 'function') {
|
|
69
|
+
const fn = asRecord(asRecord(document.functions)?.[last.projection.name])
|
|
70
|
+
if (fn === undefined) return undefined
|
|
71
|
+
return Object.freeze({
|
|
72
|
+
path: path.raw,
|
|
73
|
+
origin,
|
|
74
|
+
function: last.projection.name,
|
|
75
|
+
...callableFields(fn),
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
return undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function missingCallableDescription(path: string): AstraleError {
|
|
82
|
+
return new AstraleError(
|
|
83
|
+
'CALL_DESCRIBE_UNAVAILABLE',
|
|
84
|
+
`No callable schema is installed for ${path}.`,
|
|
85
|
+
'Use a Domain-rooted Path such as /:host.astrale.ai:class.Manager:createInstance. Method Paths are not Function nodes.',
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function findNamedMethods(
|
|
90
|
+
schema: JsonRecord,
|
|
91
|
+
origin: string,
|
|
92
|
+
path: string,
|
|
93
|
+
method: string,
|
|
94
|
+
dispatch: 'static' | 'instance',
|
|
95
|
+
): CallableDescription[] {
|
|
96
|
+
const matches: CallableDescription[] = []
|
|
97
|
+
for (const bag of [schema.classes, schema.interfaces]) {
|
|
98
|
+
const definitions = asRecord(bag)
|
|
99
|
+
if (definitions === undefined) continue
|
|
100
|
+
for (const [className, definition] of Object.entries(definitions)) {
|
|
101
|
+
const methodDef = asRecord(asRecord(asRecord(definition)?.methods)?.[method])
|
|
102
|
+
if (methodDef === undefined) continue
|
|
103
|
+
matches.push(
|
|
104
|
+
Object.freeze({
|
|
105
|
+
path,
|
|
106
|
+
origin,
|
|
107
|
+
class: className,
|
|
108
|
+
method,
|
|
109
|
+
dispatch,
|
|
110
|
+
...callableFields(methodDef),
|
|
111
|
+
}),
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return matches
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function callableFields(value: JsonRecord): Partial<CallableDescription> {
|
|
119
|
+
return {
|
|
120
|
+
...(typeof value.description === 'string' ? { description: value.description } : {}),
|
|
121
|
+
...(value.auth === undefined ? {} : { auth: value.auth }),
|
|
122
|
+
...(value.input === undefined ? {} : { input: value.input }),
|
|
123
|
+
...(value.output === undefined ? {} : { output: value.output }),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function asRecord(input: unknown): JsonRecord | undefined {
|
|
128
|
+
return input !== null && typeof input === 'object' && !Array.isArray(input)
|
|
129
|
+
? (input as JsonRecord)
|
|
130
|
+
: undefined
|
|
131
|
+
}
|
package/src/commands/call.ts
CHANGED
|
@@ -1,59 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Path } from '@astrale-os/sdk/graph/path'
|
|
2
2
|
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { ConnectionContext, KernelCommandOpts } from '../connection'
|
|
4
|
+
import type { CommandDefinition } from '../program/index'
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
nodeProp,
|
|
10
|
-
resolveSelfIdLazy,
|
|
11
|
-
runKernelCommand,
|
|
12
|
-
withSelfHint,
|
|
13
|
-
} from '../kernel'
|
|
14
|
-
import { presentBinary, type BinaryLike } from '../lib/binary'
|
|
6
|
+
import { createPathCall, expandSelfInCall, runKernelCommand, withSelfHint } from '../connection'
|
|
7
|
+
import { nodeProperty } from '../graph/index'
|
|
8
|
+
import { presentBinary } from '../lib/binary'
|
|
15
9
|
import { log } from '../lib/log'
|
|
16
10
|
import { output, present } from '../lib/output'
|
|
17
|
-
import {
|
|
11
|
+
import { describeCallableFromSchema, missingCallableDescription } from './call-describe'
|
|
18
12
|
|
|
19
|
-
type CallOpts =
|
|
13
|
+
type CallOpts = KernelCommandOpts & {
|
|
14
|
+
data?: string
|
|
15
|
+
describe?: boolean
|
|
16
|
+
dryRun?: boolean
|
|
17
|
+
output?: string
|
|
18
|
+
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
type
|
|
20
|
+
type CallResult = Awaited<ReturnType<ConnectionContext['session']['dispatch']>>
|
|
21
|
+
type MaterializedCallResult =
|
|
22
|
+
| Exclude<CallResult, { readonly kind: 'stream' }>
|
|
23
|
+
| { readonly kind: 'stream'; readonly values: readonly unknown[] }
|
|
23
24
|
|
|
24
25
|
export async function callCommand(
|
|
25
26
|
path: string,
|
|
26
27
|
rawParams: string[],
|
|
27
28
|
opts: CallOpts,
|
|
28
29
|
): Promise<void> {
|
|
29
|
-
// Expand @self before describe/execute
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
const selfCtx = await buildSelfContext(opts)
|
|
38
|
-
const selfId = await resolveSelfIdLazy(selfCtx, opts)
|
|
39
|
-
expandedPath = expandSelfReferences(path, selfId)
|
|
40
|
-
expandedRaw = rawParams.map((p) => expandSelfReferences(p, selfId))
|
|
41
|
-
// Stale-registration hints apply when @self appears in either path or params.
|
|
42
|
-
const rawMutated = expandedRaw.some((p, i) => p !== rawParams[i])
|
|
43
|
-
if (expandedPath !== path || rawMutated) {
|
|
44
|
-
selfMeta = {
|
|
45
|
-
original: path,
|
|
46
|
-
expanded: expandedPath,
|
|
47
|
-
selfId,
|
|
48
|
-
identity: selfCtx.identity?.name,
|
|
49
|
-
slug: selfCtx.instanceSlug,
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} catch (e) {
|
|
53
|
-
log.error(e instanceof Error ? e.message : 'Invalid @self expansion')
|
|
54
|
-
process.exit(1)
|
|
55
|
-
}
|
|
30
|
+
// Expand @self before describe/execute through authenticated Identity.whoami.
|
|
31
|
+
let expanded: Awaited<ReturnType<typeof expandSelfInCall>>
|
|
32
|
+
try {
|
|
33
|
+
expanded = await expandSelfInCall(path, rawParams, opts)
|
|
34
|
+
} catch (error) {
|
|
35
|
+
log.error(error instanceof Error ? error.message : 'Invalid @self expansion')
|
|
36
|
+
process.exit(1)
|
|
56
37
|
}
|
|
38
|
+
const expandedPath = expanded.path
|
|
57
39
|
|
|
58
40
|
// ── Describe mode: show schema without executing ────────
|
|
59
41
|
// Runs AFTER expansion so `astrale call @self::m --describe` works.
|
|
@@ -64,7 +46,7 @@ export async function callCommand(
|
|
|
64
46
|
// ── Parse params ────────────────────────────────────────
|
|
65
47
|
let params: Record<string, unknown>
|
|
66
48
|
try {
|
|
67
|
-
params = await parseParams(
|
|
49
|
+
params = await parseParams([...expanded.parameters], opts.data)
|
|
68
50
|
} catch (e) {
|
|
69
51
|
log.error(e instanceof Error ? e.message : 'Invalid params')
|
|
70
52
|
process.exit(1)
|
|
@@ -77,84 +59,59 @@ export async function callCommand(
|
|
|
77
59
|
}
|
|
78
60
|
|
|
79
61
|
// ── Execute ────────────────────────────────────────────
|
|
80
|
-
await runKernelCommand<
|
|
62
|
+
await runKernelCommand<MaterializedCallResult>({
|
|
81
63
|
opts,
|
|
82
64
|
label: expandedPath,
|
|
83
|
-
fn:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const value = await withSelfHint(() => ctx.client.call(expandedPath, params), selfMeta)
|
|
90
|
-
return { kind: 'value', value }
|
|
91
|
-
},
|
|
65
|
+
fn: (ctx) =>
|
|
66
|
+
withSelfHint(
|
|
67
|
+
async () =>
|
|
68
|
+
materializeCallResult(await ctx.session.dispatch(createPathCall(expandedPath, params))),
|
|
69
|
+
expanded.meta,
|
|
70
|
+
),
|
|
92
71
|
format: async (result, fmtOpts) => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
72
|
+
switch (result.kind) {
|
|
73
|
+
case 'value':
|
|
74
|
+
present(result.value, fmtOpts)
|
|
75
|
+
return
|
|
76
|
+
case 'binary':
|
|
77
|
+
await presentBinary(result.value, fmtOpts, { outFile: opts.output })
|
|
78
|
+
return
|
|
79
|
+
case 'stream':
|
|
80
|
+
output(result.values, fmtOpts)
|
|
81
|
+
return
|
|
82
|
+
case 'redirect':
|
|
83
|
+
throw new Error('Client Session returned an unresolved redirect.')
|
|
96
84
|
}
|
|
97
|
-
present(result.value, fmtOpts)
|
|
98
85
|
},
|
|
99
86
|
})
|
|
100
87
|
}
|
|
101
88
|
|
|
102
|
-
/**
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const target = path.includes('::') ? await instanceMethodNodePath(ctx, path) : path
|
|
109
|
-
if (!target) return false
|
|
110
|
-
const node = await bindGraph(ctx).get(target)
|
|
111
|
-
// Props travel under fully-qualified keys; `output.key` IS that key.
|
|
112
|
-
return node?.props?.[K.$.i('Function').output.key] === 'binary'
|
|
113
|
-
} catch {
|
|
114
|
-
return false
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** `<node>::method` → the method's Function-node MethodPath, via the node's class. */
|
|
119
|
-
async function instanceMethodNodePath(
|
|
120
|
-
ctx: ClientContext,
|
|
121
|
-
path: string,
|
|
122
|
-
): Promise<string | undefined> {
|
|
123
|
-
const sep = path.lastIndexOf('::')
|
|
124
|
-
const source = path.slice(0, sep)
|
|
125
|
-
const method = path.slice(sep + 2)
|
|
126
|
-
if (!source || !method) return undefined
|
|
127
|
-
const node = await bindGraph(ctx).get(source)
|
|
128
|
-
// ClassPath + method name forms the class-owned Function MethodPath.
|
|
129
|
-
return node?.class ? `${node.class.raw}:${method}` : undefined
|
|
89
|
+
/** Drain a session-backed stream before the command-scoped Client Session closes. */
|
|
90
|
+
export async function materializeCallResult(result: CallResult): Promise<MaterializedCallResult> {
|
|
91
|
+
if (result.kind !== 'stream') return result
|
|
92
|
+
const values: unknown[] = []
|
|
93
|
+
for await (const value of result.stream) values.push(value)
|
|
94
|
+
return Object.freeze({ kind: 'stream', values: Object.freeze(values) })
|
|
130
95
|
}
|
|
131
96
|
|
|
132
97
|
async function describeOperation(path: string, opts: CallOpts): Promise<void> {
|
|
133
98
|
await runKernelCommand({
|
|
134
99
|
opts,
|
|
135
100
|
label: `Schema for ${path}`,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
|
|
101
|
+
fn: async ({ graph }) => {
|
|
102
|
+
const parsed = Path.parse(path)
|
|
103
|
+
if (parsed.ast.anchor.kind !== 'domain') {
|
|
104
|
+
throw missingCallableDescription(path)
|
|
105
|
+
}
|
|
106
|
+
const domain = await graph.getOrThrow(Path.parse(`/:${parsed.ast.anchor.origin}`))
|
|
107
|
+
const described = describeCallableFromSchema(parsed, nodeProperty(domain, 'schema'))
|
|
108
|
+
if (described === undefined) throw missingCallableDescription(path)
|
|
109
|
+
return described
|
|
145
110
|
},
|
|
111
|
+
format: (schema, fmtOpts) => output(schema, fmtOpts),
|
|
146
112
|
})
|
|
147
113
|
}
|
|
148
114
|
|
|
149
|
-
function tryParseJson(value: unknown): unknown {
|
|
150
|
-
if (typeof value !== 'string') return value
|
|
151
|
-
try {
|
|
152
|
-
return JSON.parse(value)
|
|
153
|
-
} catch {
|
|
154
|
-
return value
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
115
|
// ── Param parsing ───────────────────────────────────────────
|
|
159
116
|
|
|
160
117
|
export async function parseParams(
|
|
@@ -254,20 +211,23 @@ Self-reference:
|
|
|
254
211
|
@self expands to your nodeId on the active instance (path head or
|
|
255
212
|
bare param value, e.g. node=@self). --data and stdin payloads are
|
|
256
213
|
sent verbatim — pre-resolve manually to a literal @<nodeId> there
|
|
257
|
-
(e.g. via 'astrale
|
|
258
|
-
registration
|
|
214
|
+
(e.g. via 'astrale get @self --json'). Resolution authenticates to
|
|
215
|
+
the selected Kernel and never trusts a local registration or JWT sub.
|
|
216
|
+
|
|
217
|
+
--describe reads the callable's input/output from the installed Domain
|
|
218
|
+
schema. Method Paths are not Function nodes.
|
|
259
219
|
|
|
260
220
|
Examples:
|
|
261
|
-
$ astrale call /:host.astrale.ai:class.
|
|
221
|
+
$ astrale call /:host.astrale.ai:class.Manager:createInstance --describe
|
|
262
222
|
$ astrale call /:blog.acme.com:class.Author:list limit=10
|
|
263
223
|
$ astrale call '@self::deactivate'
|
|
264
|
-
$ astrale call /:
|
|
224
|
+
$ astrale call /:kernel.astrale.ai:function.journal --data '{"limit":5}' --json
|
|
265
225
|
`,
|
|
266
226
|
arguments: [
|
|
267
227
|
{
|
|
268
228
|
name: 'path',
|
|
269
229
|
description:
|
|
270
|
-
'Operation path (e.g., /:host.astrale.ai:class.
|
|
230
|
+
'Operation path (e.g., /:host.astrale.ai:class.Manager:createInstance or /node::method)',
|
|
271
231
|
},
|
|
272
232
|
{ name: 'params...', description: 'Params as key=value pairs', required: false },
|
|
273
233
|
],
|
package/src/commands/describe.ts
CHANGED
|
@@ -1,181 +1,86 @@
|
|
|
1
|
-
import {
|
|
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'
|
|
2
5
|
import chalk from 'chalk'
|
|
3
6
|
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
7
|
+
import type { KernelCommandOpts } from '../connection'
|
|
8
|
+
import type { CommandDefinition } from '../program/index'
|
|
6
9
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
expandSelfInPath,
|
|
10
|
-
nodeProp,
|
|
11
|
-
runKernelCommand,
|
|
12
|
-
splitRoot,
|
|
13
|
-
unqualifyKey,
|
|
14
|
-
withSelfHint,
|
|
15
|
-
} from '../kernel'
|
|
10
|
+
import { expandSelfInPath, runKernelCommand, withSelfHint } from '../connection'
|
|
11
|
+
import { unqualifyProperty } from '../graph/index'
|
|
16
12
|
import { log } from '../lib/log'
|
|
17
13
|
import { output } from '../lib/output'
|
|
18
14
|
|
|
19
|
-
type DescribeResult = { node: GraphNode | undefined; children: GraphNode[] }
|
|
20
|
-
|
|
21
|
-
// Commander turns `--no-schema` into `schema: false`.
|
|
22
15
|
type DescribeOpts = KernelCommandOpts & { schema?: boolean }
|
|
16
|
+
type DescribedNode = Omit<Node, 'props'> & { readonly props: Readonly<Record<string, unknown>> }
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
26
21
|
let meta
|
|
27
22
|
try {
|
|
28
|
-
;({ path
|
|
29
|
-
} catch (
|
|
30
|
-
log.error(
|
|
23
|
+
;({ path, meta } = await expandSelfInPath(target, opts))
|
|
24
|
+
} catch (error) {
|
|
25
|
+
log.error(error instanceof Error ? error.message : 'Invalid target')
|
|
31
26
|
process.exit(1)
|
|
32
27
|
}
|
|
33
|
-
|
|
28
|
+
|
|
29
|
+
await runKernelCommand({
|
|
34
30
|
opts,
|
|
35
|
-
label:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
meta,
|
|
42
|
-
)
|
|
43
|
-
const { root, children } = splitRoot(result.wire.nodes, expandedPath)
|
|
44
|
-
return { node: root, children }
|
|
45
|
-
},
|
|
46
|
-
format: (result, fmtOpts, isRaw) => {
|
|
47
|
-
const shown = opts.schema === false ? stripSchema(result) : result
|
|
48
|
-
if (isRaw) {
|
|
49
|
-
output(shown, fmtOpts)
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
printDescribe(shown, expandedPath)
|
|
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)
|
|
53
37
|
},
|
|
54
38
|
})
|
|
55
39
|
}
|
|
56
40
|
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// ── Pretty-print ────────────────────────────────────────────
|
|
64
|
-
|
|
65
|
-
function printDescribe({ node, children }: DescribeResult, path: string): void {
|
|
66
|
-
const kind = classNameOf(node) ?? 'Node'
|
|
67
|
-
const name = basename(path) || path
|
|
68
|
-
console.log(` ${chalk.bold.cyan(name)} ${chalk.dim(`(${kind})`)}`)
|
|
69
|
-
|
|
70
|
-
const description = nodeProp(node, 'description')
|
|
71
|
-
if (description) console.log(` ${chalk.dim(String(description))}`)
|
|
72
|
-
console.log('')
|
|
73
|
-
|
|
74
|
-
const operations = children.filter(isFunction)
|
|
75
|
-
const otherChildren = children.filter((c) => !isFunction(c))
|
|
76
|
-
|
|
77
|
-
if (operations.length > 0) {
|
|
78
|
-
console.log(` ${chalk.bold('Operations:')}`)
|
|
79
|
-
const names = operations.map((o) => basename(o.path))
|
|
80
|
-
const slugW = Math.max(4, ...names.map((n) => n.length))
|
|
81
|
-
operations.forEach((op, i) => {
|
|
82
|
-
const opName = names[i].padEnd(slugW)
|
|
83
|
-
const schema = formatInputSchema(op)
|
|
84
|
-
console.log(` ${chalk.green(opName)} ${chalk.dim(schema)}`)
|
|
85
|
-
})
|
|
86
|
-
console.log('')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (otherChildren.length > 0) {
|
|
90
|
-
console.log(` ${chalk.bold('Children:')}`)
|
|
91
|
-
for (const child of otherChildren) {
|
|
92
|
-
const childKind = classNameOf(child) ?? '?'
|
|
93
|
-
console.log(` ${chalk.cyan(basename(child.path) || '?')} ${chalk.dim(childKind)}`)
|
|
94
|
-
}
|
|
95
|
-
console.log('')
|
|
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
|
+
),
|
|
96
47
|
}
|
|
97
|
-
|
|
98
|
-
if (children.length === 0) {
|
|
99
|
-
printProperties(node)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** `/a/b/c` → `c`; `/` → `/`. */
|
|
104
|
-
function basename(path?: string): string {
|
|
105
|
-
if (!path || path === '/') return path ?? ''
|
|
106
|
-
return path.slice(path.lastIndexOf('/') + 1)
|
|
107
48
|
}
|
|
108
49
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
.
|
|
122
|
-
.filter(([k]) => k !== '__labels' && k !== 'id')
|
|
123
|
-
if (entries.length === 0) return
|
|
124
|
-
|
|
125
|
-
console.log(` ${chalk.bold('Properties:')}`)
|
|
126
|
-
for (const [k, v] of entries) {
|
|
127
|
-
const val = typeof v === 'string' && v.length > 80 ? v.slice(0, 80) + '...' : String(v)
|
|
128
|
-
console.log(` ${chalk.cyan(k)}: ${chalk.dim(val)}`)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function formatInputSchema(node: GraphNode): string {
|
|
133
|
-
const raw = nodeProp(node, 'inputSchema')
|
|
134
|
-
if (!raw) return '{}'
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const schema = typeof raw === 'string' ? JSON.parse(raw) : raw
|
|
138
|
-
if (typeof schema !== 'object' || schema === null) return '{}'
|
|
139
|
-
|
|
140
|
-
const props = (schema as { properties?: Record<string, { type?: string }> }).properties
|
|
141
|
-
if (!props || Object.keys(props).length === 0) return '{}'
|
|
142
|
-
|
|
143
|
-
const required = new Set((schema as { required?: string[] }).required ?? [])
|
|
144
|
-
|
|
145
|
-
const fields = Object.entries(props).map(([name, def]) => {
|
|
146
|
-
const type = def?.type ?? '?'
|
|
147
|
-
return required.has(name) ? `${name}: ${type}` : `${name}?: ${type}`
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
return `{ ${fields.join(', ')} }`
|
|
151
|
-
} catch {
|
|
152
|
-
return '{...}'
|
|
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)}`)
|
|
153
63
|
}
|
|
154
64
|
}
|
|
155
65
|
|
|
156
66
|
export default {
|
|
157
67
|
name: 'describe',
|
|
158
|
-
description: 'Describe
|
|
68
|
+
description: 'Describe the canonical facts of one node',
|
|
159
69
|
afterHelpText: `
|
|
160
70
|
Behavior:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
use --no-schema, and pipe to jq rather than reading by eye.
|
|
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.
|
|
165
74
|
|
|
166
75
|
Examples:
|
|
167
|
-
$ astrale describe
|
|
168
|
-
$ astrale describe
|
|
76
|
+
$ astrale describe /:kernel.astrale.ai:class.Domain
|
|
77
|
+
$ astrale describe @self --no-schema
|
|
169
78
|
`,
|
|
170
|
-
arguments: [{ name: '
|
|
79
|
+
arguments: [{ name: 'target', description: 'Canonical Node Path or @id' }],
|
|
171
80
|
options: [
|
|
172
|
-
{
|
|
173
|
-
flags: '--no-schema',
|
|
174
|
-
description:
|
|
175
|
-
'Omit the serialized `schema` property (useful for Domain nodes, where it is multi-kB)',
|
|
176
|
-
},
|
|
81
|
+
{ flags: '--no-schema', description: 'Omit properties whose qualified leaf is schema' },
|
|
177
82
|
],
|
|
178
|
-
action: async (
|
|
179
|
-
await describeCommand(
|
|
83
|
+
action: async (target, opts) => {
|
|
84
|
+
await describeCommand(target as string, opts as DescribeOpts)
|
|
180
85
|
},
|
|
181
86
|
} satisfies CommandDefinition
|