@astrale-os/cli 0.8.0-alpha.0 → 0.8.1-alpha.2
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 +4 -1
- package/dist/astrale.js +62968 -41240
- 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 +30 -8
- 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.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__/logs.test.ts +50 -98
- 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.ts +55 -91
- package/src/commands/describe.ts +52 -147
- package/src/commands/domain/install.ts +81 -50
- package/src/commands/domain/list.ts +4 -8
- package/src/commands/domain/publish.ts +9 -31
- package/src/commands/get.ts +32 -65
- 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 +3 -3
- package/src/commands/instance/status.ts +5 -7
- package/src/commands/instance/use.ts +3 -3
- package/src/commands/logs.ts +152 -279
- 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 +43 -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 +18 -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-D0cBetPW.js +1 -0
- package/studio/client/dist/assets/elk-worker.min-C9JGDOE-.js +6312 -0
- package/studio/client/dist/assets/index-BQnJ5sgd.css +1 -0
- package/studio/client/dist/assets/index-ChOr3yP0.css +1 -0
- package/studio/client/dist/assets/index-Dspir4w7.js +81 -0
- package/studio/client/dist/assets/index-bVD2KJgz.js +8 -0
- package/studio/client/dist/index.html +2 -2
- 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/studio/tsconfig.json +23 -0
- package/tsconfig.json +1 -1
- package/viewer/dist/main.js +65 -39
- package/viewer/tsconfig.json +13 -0
- 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-BaqEuIQJ.js +0 -109
- package/studio/client/dist/assets/index-jRdExahh.css +0 -1
package/src/commands/ls.ts
CHANGED
|
@@ -1,251 +1,125 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Node } from '@astrale-os/sdk/graph/node'
|
|
2
|
+
import type { QueryDirection, QueryResult } from '@astrale-os/sdk/query'
|
|
3
|
+
|
|
4
|
+
import { ClassPath } from '@astrale-os/sdk/graph/class'
|
|
2
5
|
import chalk from 'chalk'
|
|
3
6
|
|
|
4
|
-
import type {
|
|
5
|
-
import type { GraphNode, KernelCommandOpts, SelfExpansionMeta } from '../kernel'
|
|
7
|
+
import type { KernelCommandOpts } from '../connection'
|
|
6
8
|
import type { ListProjection } from '../lib/output'
|
|
9
|
+
import type { CommandDefinition } from '../program/index'
|
|
7
10
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
formatKernelError,
|
|
13
|
-
runKernelCommand,
|
|
14
|
-
splitRoot,
|
|
15
|
-
withKernelClient,
|
|
16
|
-
withSelfHint,
|
|
17
|
-
} from '../kernel'
|
|
18
|
-
import { spinner } from '../lib/log'
|
|
19
|
-
import { isMachine, output, presentList } from '../lib/output'
|
|
11
|
+
import { expandSelfInPath, runKernelCommand, withSelfHint } from '../connection'
|
|
12
|
+
import { nodeProperty, prepareQuery } from '../graph/index'
|
|
13
|
+
import { log } from '../lib/log'
|
|
14
|
+
import { isMachine, presentList } from '../lib/output'
|
|
20
15
|
|
|
21
16
|
type LsOpts = KernelCommandOpts & {
|
|
17
|
+
edge?: string
|
|
18
|
+
direction?: QueryDirection
|
|
19
|
+
limit?: string
|
|
20
|
+
cursor?: string
|
|
22
21
|
long?: boolean
|
|
23
22
|
quiet?: boolean
|
|
24
|
-
recursive?: boolean
|
|
25
23
|
count?: boolean
|
|
26
|
-
filter?: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** A child node row — the shared `function.get` node shape. */
|
|
30
|
-
type Item = GraphNode
|
|
31
|
-
|
|
32
|
-
// ── Display projection ──────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
/** `/example.astrale.ai` → `example.astrale.ai`; `/` stays `/`. */
|
|
35
|
-
export function basename(path?: string): string {
|
|
36
|
-
if (!path || path === '/') return path ?? ''
|
|
37
|
-
return path.slice(path.lastIndexOf('/') + 1)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** `/:kernel.astrale.ai:class.Domain` → `Domain`; falls back to the most specific label. */
|
|
41
|
-
export function classNameOf(item: { class?: string; __labels?: string[] }): string {
|
|
42
|
-
const tail = item.class?.split(/[/:.]/).pop()
|
|
43
|
-
return tail || item.__labels?.[item.__labels.length - 1] || '?'
|
|
44
24
|
}
|
|
45
25
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
function lsProjection(items: Item[]): ListProjection {
|
|
52
|
-
return {
|
|
53
|
-
columns: [
|
|
54
|
-
{ key: 'name', header: 'NAME', color: chalk.cyan },
|
|
55
|
-
{ key: 'kind', header: 'KIND', color: chalk.dim },
|
|
56
|
-
{ key: 'id', header: 'ID', color: chalk.dim },
|
|
57
|
-
],
|
|
58
|
-
rows: items.map((i) => ({ name: basename(i.path), kind: classNameOf(i), id: i.id ?? '' })),
|
|
59
|
-
paths: items.map(itemPath),
|
|
26
|
+
export async function lsCommand(source: string, opts: LsOpts): Promise<void> {
|
|
27
|
+
if (opts.edge === undefined) {
|
|
28
|
+
log.error('ls requires --edge <class>; Kernel V2 has no universal child relation')
|
|
29
|
+
process.exit(1)
|
|
60
30
|
}
|
|
61
|
-
}
|
|
62
31
|
|
|
63
|
-
|
|
64
|
-
if (!filter) return items
|
|
65
|
-
const f = filter.toLowerCase()
|
|
66
|
-
return items.filter((i) => {
|
|
67
|
-
const kindMatch = classNameOf(i).toLowerCase() === f
|
|
68
|
-
const labelMatch = i.__labels?.some((l) => l.toLowerCase() === f) ?? false
|
|
69
|
-
return kindMatch || labelMatch
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ── Command ─────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
export async function lsCommand(path: string, opts: LsOpts): Promise<void> {
|
|
76
|
-
let expandedPath: string
|
|
32
|
+
let path: string
|
|
77
33
|
let meta
|
|
34
|
+
let prepared
|
|
78
35
|
try {
|
|
79
|
-
;({ path
|
|
80
|
-
|
|
81
|
-
|
|
36
|
+
;({ path, meta } = await expandSelfInPath(source, opts))
|
|
37
|
+
prepared = prepareQuery({
|
|
38
|
+
sources: [path],
|
|
39
|
+
edge: opts.edge,
|
|
40
|
+
direction: opts.direction,
|
|
41
|
+
limit: opts.limit,
|
|
42
|
+
cursor: opts.cursor,
|
|
43
|
+
})
|
|
44
|
+
} catch (error) {
|
|
45
|
+
log.error(error instanceof Error ? error.message : 'Invalid edge neighborhood')
|
|
82
46
|
process.exit(1)
|
|
83
47
|
}
|
|
84
48
|
|
|
85
|
-
if (opts.recursive) {
|
|
86
|
-
return recursiveLs(expandedPath, opts, meta)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
49
|
await runKernelCommand({
|
|
90
50
|
opts,
|
|
91
|
-
label: `
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const result = await withSelfHint(
|
|
96
|
-
() => bindGraph(ctx).query((q) => q.from(expandedPath).children()),
|
|
97
|
-
meta,
|
|
98
|
-
)
|
|
99
|
-
return {
|
|
100
|
-
children: splitRoot(result.wire.nodes, expandedPath).children,
|
|
101
|
-
next: childrenCursor(result.wire),
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
format: ({ children, next }, fmtOpts) => {
|
|
105
|
-
const items = applyFilter(children, opts.filter)
|
|
51
|
+
label: `Neighbors of ${path}`,
|
|
52
|
+
fn: ({ graph }) => withSelfHint(() => graph.query(prepared.ast, { page: prepared.page }), meta),
|
|
53
|
+
format: (response, format) => {
|
|
54
|
+
const graph = completeGraph(response.result)
|
|
106
55
|
presentList(
|
|
107
|
-
|
|
108
|
-
{ ...
|
|
109
|
-
|
|
56
|
+
[...graph.nodes],
|
|
57
|
+
{ ...format, long: opts.long, quiet: opts.quiet, count: opts.count },
|
|
58
|
+
listProjection,
|
|
110
59
|
)
|
|
111
|
-
if (next && !isMachine(
|
|
112
|
-
process.
|
|
113
|
-
chalk.dim(
|
|
114
|
-
' more children truncated - page with `query ' +
|
|
115
|
-
expandedPath +
|
|
116
|
-
' --depth 1 --children \'{"cursor":"' +
|
|
117
|
-
next +
|
|
118
|
-
'"}\'`\n',
|
|
119
|
-
),
|
|
120
|
-
)
|
|
60
|
+
if (response.page.next && !isMachine(format) && !opts.quiet && !opts.count) {
|
|
61
|
+
process.stderr.write(` cursor: ${response.page.next}\n`)
|
|
121
62
|
}
|
|
122
63
|
},
|
|
123
64
|
})
|
|
124
65
|
}
|
|
125
66
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
type TreeNode = Item & { children: TreeNode[] }
|
|
131
|
-
|
|
132
|
-
async function recursiveLs(
|
|
133
|
-
path: string,
|
|
134
|
-
opts: LsOpts,
|
|
135
|
-
meta: SelfExpansionMeta | undefined,
|
|
136
|
-
): Promise<void> {
|
|
137
|
-
const machine = isMachine(opts)
|
|
138
|
-
const spin = !machine ? spinner(`Listing ${path} recursively...`) : null
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
await withKernelClient(opts, async (ctx) => {
|
|
142
|
-
// The recursive walk is now ONE function.get to the depth cap; the tree is
|
|
143
|
-
// reassembled client-side from the flat node page (was an N+1 buildTree).
|
|
144
|
-
const result = await withSelfHint(
|
|
145
|
-
() => bindGraph(ctx).query((q) => q.from(path).descend(MAX_DEPTH)),
|
|
146
|
-
meta,
|
|
147
|
-
)
|
|
148
|
-
const tree = buildTree(result.wire.nodes, path)
|
|
149
|
-
spin?.succeed(`Tree of ${path}`)
|
|
150
|
-
if (!machine) console.log('')
|
|
151
|
-
|
|
152
|
-
if (machine || opts.format) {
|
|
153
|
-
output(tree, opts)
|
|
154
|
-
} else if (opts.quiet) {
|
|
155
|
-
printTreeQuiet(tree)
|
|
156
|
-
} else {
|
|
157
|
-
printTree(tree, '')
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
} catch (error) {
|
|
161
|
-
if (!machine && spin) spin.fail('Failed')
|
|
162
|
-
await formatKernelError(error, machine, undefined, opts.debug, { credential: opts.creds })
|
|
163
|
-
process.exit(1)
|
|
164
|
-
}
|
|
67
|
+
function completeGraph(result: QueryResult) {
|
|
68
|
+
if (result.kind !== 'graph') throw new TypeError('ls expected one complete graph Query result')
|
|
69
|
+
return result.graph
|
|
165
70
|
}
|
|
166
71
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
byPath.set(raw, { ...n, children: [] })
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const roots: TreeNode[] = []
|
|
184
|
-
for (const [raw, node] of byPath) {
|
|
185
|
-
const parent = parentPathOf(raw)
|
|
186
|
-
const parentNode = parent === rootRaw ? undefined : byPath.get(parent)
|
|
187
|
-
if (parentNode) parentNode.children.push(node)
|
|
188
|
-
else roots.push(node)
|
|
189
|
-
}
|
|
190
|
-
return roots
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function printTree(nodes: TreeNode[], prefix: string): void {
|
|
194
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
195
|
-
const node = nodes[i]
|
|
196
|
-
const isLast = i === nodes.length - 1
|
|
197
|
-
const connector = isLast ? '└── ' : '├── '
|
|
198
|
-
const childPrefix = isLast ? ' ' : '│ '
|
|
199
|
-
|
|
200
|
-
const name = basename(node.path) || node.id || '?'
|
|
201
|
-
console.log(`${prefix}${connector}${chalk.cyan(name)} ${chalk.dim(classNameOf(node))}`)
|
|
202
|
-
|
|
203
|
-
if (node.children.length > 0) {
|
|
204
|
-
printTree(node.children, prefix + childPrefix)
|
|
205
|
-
}
|
|
72
|
+
export function listProjection(nodes: Node[]): ListProjection {
|
|
73
|
+
return {
|
|
74
|
+
columns: [
|
|
75
|
+
{ key: 'name', header: 'NAME', color: chalk.cyan },
|
|
76
|
+
{ key: 'class', header: 'CLASS', color: chalk.dim },
|
|
77
|
+
{ key: 'id', header: 'ID', color: chalk.dim },
|
|
78
|
+
],
|
|
79
|
+
rows: nodes.map((node) => ({
|
|
80
|
+
name: displayName(node),
|
|
81
|
+
class: ClassPath.name(node.class),
|
|
82
|
+
id: node.id,
|
|
83
|
+
})),
|
|
84
|
+
paths: nodes.map((node) => `@${node.id}`),
|
|
206
85
|
}
|
|
207
86
|
}
|
|
208
87
|
|
|
209
|
-
function
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
88
|
+
export function displayName(node: Node): string {
|
|
89
|
+
const value =
|
|
90
|
+
nodeProperty(node, 'name') ?? nodeProperty(node, 'title') ?? nodeProperty(node, 'slug')
|
|
91
|
+
return typeof value === 'string' && value.length > 0 ? value : `@${node.id}`
|
|
214
92
|
}
|
|
215
93
|
|
|
216
94
|
export default {
|
|
217
95
|
name: 'ls',
|
|
218
|
-
description: 'List
|
|
96
|
+
description: 'List one finite exact edge neighborhood',
|
|
219
97
|
afterHelpText: `
|
|
220
98
|
Behavior:
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
Domain. At a domain's tree position the children are Folder nodes
|
|
226
|
-
(class.X), not Class — so --filter Class returns nothing; use --filter
|
|
227
|
-
Folder, or descend into class.<X>. -q prints one absolute path per line
|
|
228
|
-
(pipeable).
|
|
99
|
+
Lists Nodes reached from one source through one exact Edge Class. Kernel V2
|
|
100
|
+
has no universal parent/child relation, so --edge is required and recursive
|
|
101
|
+
tree walking is intentionally absent. Direction defaults to outgoing and the
|
|
102
|
+
finite default limit is 100. -q emits one @id per line.
|
|
229
103
|
|
|
230
104
|
Examples:
|
|
231
|
-
$ astrale ls
|
|
232
|
-
$ astrale ls
|
|
233
|
-
$ astrale ls / -q | xargs -I{} astrale describe {}
|
|
105
|
+
$ astrale ls @note --edge /:notes.example.dev:class.references
|
|
106
|
+
$ astrale ls @note --edge /:notes.example.dev:class.references --direction incoming --limit 25
|
|
234
107
|
`,
|
|
235
|
-
arguments: [
|
|
236
|
-
{ name: 'path', description: 'Node path (/domain/Class) or ID (@nodeId)', required: false },
|
|
237
|
-
],
|
|
108
|
+
arguments: [{ name: 'source', description: 'Canonical source Path or @id' }],
|
|
238
109
|
options: [
|
|
239
|
-
{ flags: '
|
|
240
|
-
{ flags: '-q, --quiet', description: 'One path per line (unix-pipeable)' },
|
|
241
|
-
{ flags: '-R, --recursive', description: 'List recursively (tree view)' },
|
|
242
|
-
{ flags: '--count', description: 'Print only the number of children' },
|
|
110
|
+
{ flags: '--edge <class>', description: 'Exact Edge Class to traverse' },
|
|
243
111
|
{
|
|
244
|
-
flags: '--
|
|
245
|
-
description: '
|
|
112
|
+
flags: '--direction <direction>',
|
|
113
|
+
description: 'Traversal direction (default: outgoing)',
|
|
114
|
+
choices: ['outgoing', 'incoming', 'incident'],
|
|
246
115
|
},
|
|
116
|
+
{ flags: '--limit <n>', description: 'Finite selected Node limit (default: 100)' },
|
|
117
|
+
{ flags: '--cursor <token>', description: 'Resume one live query scope' },
|
|
118
|
+
{ flags: '-l, --long', description: 'Print complete canonical Nodes' },
|
|
119
|
+
{ flags: '-q, --quiet', description: 'Print one @id per line' },
|
|
120
|
+
{ flags: '--count', description: 'Print only the number of returned Nodes' },
|
|
247
121
|
],
|
|
248
|
-
action: async (
|
|
249
|
-
await lsCommand(
|
|
122
|
+
action: async (source, opts) => {
|
|
123
|
+
await lsCommand(source as string, opts as LsOpts)
|
|
250
124
|
},
|
|
251
125
|
} satisfies CommandDefinition
|
package/src/commands/mutate.ts
CHANGED
|
@@ -1,189 +1,120 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MutationResult } from '@astrale-os/sdk/mutation'
|
|
2
2
|
|
|
3
|
-
import { patchDataSchema } from '@astrale-os/kernel-core'
|
|
4
3
|
import chalk from 'chalk'
|
|
5
4
|
import { readFile } from 'node:fs/promises'
|
|
6
5
|
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
9
|
-
import type { MutationResultWire } from '../kernel'
|
|
6
|
+
import type { KernelCommandOpts } from '../connection'
|
|
7
|
+
import type { CommandDefinition } from '../program/index'
|
|
10
8
|
|
|
11
|
-
import {
|
|
9
|
+
import { runKernelCommand } from '../connection'
|
|
10
|
+
import { prepareMutation } from '../graph/index'
|
|
12
11
|
import { log } from '../lib/log'
|
|
13
12
|
import { output } from '../lib/output'
|
|
14
13
|
import { renderTable } from '../lib/table'
|
|
15
14
|
|
|
16
|
-
type MutateOpts = KernelCommandOpts & {
|
|
15
|
+
type MutateOpts = KernelCommandOpts & {
|
|
16
|
+
data?: string
|
|
17
|
+
file?: string
|
|
18
|
+
dry?: boolean
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
export async function mutateCommand(opts: MutateOpts): Promise<void> {
|
|
19
|
-
let
|
|
22
|
+
let mutation
|
|
20
23
|
try {
|
|
21
|
-
|
|
22
|
-
} catch (
|
|
23
|
-
log.error(
|
|
24
|
+
mutation = prepareMutation(await readDocument(opts))
|
|
25
|
+
} catch (error) {
|
|
26
|
+
log.error(error instanceof Error ? error.message : 'Invalid Mutation V3 document')
|
|
24
27
|
process.exit(1)
|
|
25
|
-
return
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
// --dry: validate the patch locally against the kernel's own schema and print
|
|
29
|
-
// the normalized form (every arm defaulted to []). No kernel round-trip.
|
|
30
30
|
if (opts.dry) {
|
|
31
|
-
|
|
32
|
-
if (!parsed.success) {
|
|
33
|
-
log.error('Patch failed local validation:')
|
|
34
|
-
for (const issue of parsed.error.issues) {
|
|
35
|
-
log.dim(` ${issue.path.join('.') || '(root)'}: ${issue.message}`)
|
|
36
|
-
}
|
|
37
|
-
process.exit(1)
|
|
38
|
-
}
|
|
39
|
-
output(parsed.data, opts)
|
|
31
|
+
output(mutation, opts)
|
|
40
32
|
return
|
|
41
33
|
}
|
|
42
34
|
|
|
43
|
-
await runKernelCommand<
|
|
35
|
+
await runKernelCommand<MutationResult>({
|
|
44
36
|
opts,
|
|
45
37
|
label: 'Mutate',
|
|
46
|
-
fn: (
|
|
47
|
-
format: (result,
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
printResult(result)
|
|
38
|
+
fn: ({ graph }) => graph.mutate(mutation),
|
|
39
|
+
format: (result, format, machine) => {
|
|
40
|
+
if (machine || format.format !== undefined) output(result, format)
|
|
41
|
+
else printResult(result)
|
|
53
42
|
},
|
|
54
43
|
})
|
|
55
44
|
}
|
|
56
45
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
46
|
+
async function readDocument(opts: MutateOpts): Promise<unknown> {
|
|
47
|
+
const authored = [opts.data !== undefined, opts.file !== undefined].filter(Boolean).length
|
|
48
|
+
if (authored > 1) throw new TypeError('--data and --file are mutually exclusive')
|
|
49
|
+
if (opts.data !== undefined) return parseJson(opts.data, '--data')
|
|
50
|
+
if (opts.file !== undefined) {
|
|
51
|
+
let raw: string
|
|
60
52
|
try {
|
|
61
|
-
|
|
62
|
-
} catch {
|
|
63
|
-
throw new Error(
|
|
53
|
+
raw = await readFile(opts.file, 'utf8')
|
|
54
|
+
} catch (error) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`Cannot read --file ${opts.file}: ${error instanceof Error ? error.message : error}`,
|
|
57
|
+
)
|
|
64
58
|
}
|
|
59
|
+
return parseJson(raw, opts.file)
|
|
65
60
|
}
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
text = await readFile(opts.file, 'utf-8')
|
|
70
|
-
} catch (e) {
|
|
71
|
-
throw new Error(`Cannot read --file ${opts.file}: ${e instanceof Error ? e.message : e}`)
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
return JSON.parse(text)
|
|
75
|
-
} catch {
|
|
76
|
-
throw new Error(`Invalid JSON in ${opts.file}`)
|
|
77
|
-
}
|
|
61
|
+
if (process.stdin.isTTY) {
|
|
62
|
+
throw new TypeError('No mutation provided; use --data, --file, or stdin')
|
|
78
63
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
throw new Error('Invalid JSON from stdin')
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
throw new Error(
|
|
88
|
-
'No patch provided — pass --data <json>, --file <path>, or pipe a PatchData JSON on stdin',
|
|
89
|
-
)
|
|
64
|
+
const chunks: Buffer[] = []
|
|
65
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk))
|
|
66
|
+
const raw = Buffer.concat(chunks).toString('utf8').trim()
|
|
67
|
+
if (raw.length === 0) throw new TypeError('No mutation provided on stdin')
|
|
68
|
+
return parseJson(raw, 'stdin')
|
|
90
69
|
}
|
|
91
70
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
71
|
+
function parseJson(raw: string, source: string): unknown {
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(raw)
|
|
74
|
+
} catch {
|
|
75
|
+
throw new TypeError(`${source} must contain valid JSON`)
|
|
97
76
|
}
|
|
98
|
-
const text = Buffer.concat(chunks).toString('utf-8').trim()
|
|
99
|
-
return text || null
|
|
100
77
|
}
|
|
101
78
|
|
|
102
|
-
function printResult(result:
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (nodeRows.length === 0 && edgeRows.length === 0) {
|
|
107
|
-
console.log(chalk.dim(' applied — no nodes or edges minted (updates/deletes only)'))
|
|
79
|
+
function printResult(result: MutationResult): void {
|
|
80
|
+
const rows = Object.entries(result.createdNodes).map(([binding, id]) => ({ binding, id }))
|
|
81
|
+
if (rows.length === 0) {
|
|
82
|
+
console.log(chalk.dim(' applied — no Nodes created'))
|
|
108
83
|
return
|
|
109
84
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
],
|
|
121
|
-
showHeader: true,
|
|
122
|
-
},
|
|
123
|
-
),
|
|
124
|
-
)
|
|
125
|
-
console.log('')
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (edgeRows.length > 0) {
|
|
129
|
-
console.log(` ${chalk.bold('Created edges:')}`)
|
|
130
|
-
console.log(
|
|
131
|
-
renderTable(
|
|
132
|
-
edgeRows.map(([tuple, id]) => ({ tuple, id })),
|
|
133
|
-
{
|
|
134
|
-
columns: [
|
|
135
|
-
{ key: 'tuple', header: 'CLASS|SOURCE|SLUG|TARGET', color: chalk.cyan },
|
|
136
|
-
{ key: 'id', header: 'ID', color: chalk.dim },
|
|
137
|
-
],
|
|
138
|
-
showHeader: true,
|
|
139
|
-
},
|
|
140
|
-
),
|
|
141
|
-
)
|
|
142
|
-
console.log('')
|
|
143
|
-
}
|
|
85
|
+
console.log(` ${chalk.bold('Created nodes:')}`)
|
|
86
|
+
console.log(
|
|
87
|
+
renderTable(rows, {
|
|
88
|
+
columns: [
|
|
89
|
+
{ key: 'binding', header: 'BINDING', color: chalk.cyan },
|
|
90
|
+
{ key: 'id', header: 'ID', color: chalk.dim },
|
|
91
|
+
],
|
|
92
|
+
showHeader: true,
|
|
93
|
+
}),
|
|
94
|
+
)
|
|
144
95
|
}
|
|
145
96
|
|
|
146
97
|
export default {
|
|
147
98
|
name: 'mutate',
|
|
148
|
-
description: 'Apply
|
|
99
|
+
description: 'Apply one atomic Mutation V3 graph transition',
|
|
149
100
|
afterHelpText: `
|
|
150
101
|
Behavior:
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
Authorization is per-arm: a create needs USE on the class and EDIT on the
|
|
157
|
-
parent, an update/delete needs EDIT on the target. A denied arm fails the
|
|
158
|
-
whole patch. --dry validates the patch locally (kernel patchDataSchema) and
|
|
159
|
-
prints the normalized form without touching the kernel.
|
|
102
|
+
Accepts a canonical astrale.graph.mutation/v3 document or its exact
|
|
103
|
+
{ preconditions, operations } authoring input. Source is --data, --file,
|
|
104
|
+
or stdin. --dry admits and prints the canonical document without opening a
|
|
105
|
+
Kernel connection. The result contains the real createdNodes binding map.
|
|
160
106
|
|
|
161
|
-
PatchData
|
|
162
|
-
|
|
163
|
-
"nodes": {
|
|
164
|
-
"create": [{ "class": "/:d:class.X", "at": "/d/x", "props": {} }],
|
|
165
|
-
"update": [{ "class": "/:d:class.X", "path": "/d/x", "props": {} }],
|
|
166
|
-
"delete": [{ "class": "/:d:class.X", "path": "/d/x" }]
|
|
167
|
-
},
|
|
168
|
-
"edges": {
|
|
169
|
-
"create": [{ "class": "/:d:class.e", "source": "/a", "target": "/b", "props": {} }],
|
|
170
|
-
"delete": [{ "class": "/:d:class.e", "source": "/a", "target": "/b" }]
|
|
171
|
-
}
|
|
172
|
-
}
|
|
107
|
+
Legacy PatchData nodes/edges arms and createdEdges IDs are not part of
|
|
108
|
+
Mutation V3 and are rejected rather than approximated.
|
|
173
109
|
|
|
174
110
|
Examples:
|
|
175
|
-
$ astrale mutate --
|
|
176
|
-
$ astrale mutate --
|
|
177
|
-
$ echo '{"nodes":{"delete":[{"class":"/:d:class.X","path":"/d/x"}]}}' | astrale mutate
|
|
178
|
-
$ astrale mutate --file patch.json --dry
|
|
111
|
+
$ astrale mutate --file mutation.v3.json
|
|
112
|
+
$ astrale mutate --data '{"preconditions":[],"operations":[]}' --dry
|
|
179
113
|
`,
|
|
180
114
|
options: [
|
|
181
|
-
{ flags: '-d, --data <json>', description: '
|
|
182
|
-
{ flags: '-f, --file <path>', description: 'Read
|
|
183
|
-
{
|
|
184
|
-
flags: '--dry',
|
|
185
|
-
description: 'Validate locally (no kernel call) and print the normalized patch',
|
|
186
|
-
},
|
|
115
|
+
{ flags: '-d, --data <json>', description: 'Mutation V3 JSON document' },
|
|
116
|
+
{ flags: '-f, --file <path>', description: 'Read a Mutation V3 document from a file' },
|
|
117
|
+
{ flags: '--dry', description: 'Admit and print canonical Mutation V3 without dispatch' },
|
|
187
118
|
],
|
|
188
119
|
action: async (opts) => {
|
|
189
120
|
await mutateCommand(opts as MutateOpts)
|