@astrale-os/cli 0.4.0-alpha.13
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/.check-workspace.cjs +40 -0
- package/README.md +151 -0
- package/dist/astrale.js +59749 -0
- package/package.json +90 -0
- package/src/command.ts +40 -0
- package/src/commands/__tests__/admin-instance.test.ts +73 -0
- package/src/commands/__tests__/auth-login.test.ts +178 -0
- package/src/commands/__tests__/auth-token.test.ts +223 -0
- package/src/commands/__tests__/call.test.ts +72 -0
- package/src/commands/__tests__/domain-list.test.ts +74 -0
- package/src/commands/__tests__/help-contract.test.ts +136 -0
- package/src/commands/__tests__/install-identity-override.test.ts +65 -0
- package/src/commands/__tests__/instance-bookmark.test.ts +101 -0
- package/src/commands/__tests__/instance-create-hosts.test.ts +29 -0
- package/src/commands/__tests__/instance-list-rows.test.ts +63 -0
- package/src/commands/__tests__/logs.test.ts +117 -0
- package/src/commands/__tests__/ls.test.ts +25 -0
- package/src/commands/__tests__/setup-plan.test.ts +61 -0
- package/src/commands/admin/status.ts +61 -0
- package/src/commands/admin/use.ts +77 -0
- package/src/commands/auth/login.ts +82 -0
- package/src/commands/auth/logout.ts +50 -0
- package/src/commands/auth/status.ts +86 -0
- package/src/commands/auth/token.ts +162 -0
- package/src/commands/browser.ts +207 -0
- package/src/commands/call.ts +300 -0
- package/src/commands/describe.ts +182 -0
- package/src/commands/domain/install.ts +420 -0
- package/src/commands/domain/list.ts +154 -0
- package/src/commands/domain/publish.ts +155 -0
- package/src/commands/get.ts +60 -0
- package/src/commands/identity/create.ts +26 -0
- package/src/commands/identity/delete.ts +18 -0
- package/src/commands/identity/export.ts +66 -0
- package/src/commands/identity/import.ts +101 -0
- package/src/commands/identity/list.ts +56 -0
- package/src/commands/identity/register.ts +170 -0
- package/src/commands/identity/sync.ts +32 -0
- package/src/commands/identity/unsync.ts +24 -0
- package/src/commands/identity/use.ts +18 -0
- package/src/commands/identity/whoami.ts +34 -0
- package/src/commands/idp/add.ts +150 -0
- package/src/commands/idp/list.ts +57 -0
- package/src/commands/idp/refresh.ts +38 -0
- package/src/commands/idp/remove.ts +36 -0
- package/src/commands/idp/show.ts +29 -0
- package/src/commands/instance/active.ts +64 -0
- package/src/commands/instance/bookmark.ts +72 -0
- package/src/commands/instance/create.ts +69 -0
- package/src/commands/instance/delete.ts +72 -0
- package/src/commands/instance/forget.ts +26 -0
- package/src/commands/instance/list.ts +149 -0
- package/src/commands/instance/status.ts +42 -0
- package/src/commands/instance/use.ts +210 -0
- package/src/commands/logs.ts +347 -0
- package/src/commands/ls.ts +229 -0
- package/src/commands/query.ts +32 -0
- package/src/commands/setup.ts +54 -0
- package/src/commands/status.ts +60 -0
- package/src/commands/studio.ts +401 -0
- package/src/commands/token.ts +77 -0
- package/src/commands/update.ts +267 -0
- package/src/commands/use.ts +87 -0
- package/src/errors.ts +65 -0
- package/src/kernel/__tests__/auth.test.ts +77 -0
- package/src/kernel/__tests__/errors.test.ts +43 -0
- package/src/kernel/__tests__/remote-routing.test.ts +70 -0
- package/src/kernel/auth.ts +234 -0
- package/src/kernel/ca-fetch.ts +119 -0
- package/src/kernel/client.ts +191 -0
- package/src/kernel/errors.ts +280 -0
- package/src/kernel/expand.ts +217 -0
- package/src/kernel/index.ts +14 -0
- package/src/kernel/options.ts +22 -0
- package/src/kernel/remote-routing.ts +88 -0
- package/src/kernel/run.ts +63 -0
- package/src/kernel/types.ts +14 -0
- package/src/lib/__tests__/admin-target.test.ts +112 -0
- package/src/lib/__tests__/binary.test.ts +56 -0
- package/src/lib/__tests__/command-dx.test.ts +58 -0
- package/src/lib/__tests__/concurrency.test.ts +62 -0
- package/src/lib/__tests__/config.test.ts +53 -0
- package/src/lib/__tests__/design.test.ts +99 -0
- package/src/lib/__tests__/domain-identity.test.ts +60 -0
- package/src/lib/__tests__/format.test.ts +22 -0
- package/src/lib/__tests__/fs-atomic.test.ts +104 -0
- package/src/lib/__tests__/identity.test.ts +79 -0
- package/src/lib/__tests__/idp-session.driver.ts +53 -0
- package/src/lib/__tests__/idp-session.test.ts +357 -0
- package/src/lib/__tests__/idp.test.ts +385 -0
- package/src/lib/__tests__/instance-candidates.test.ts +73 -0
- package/src/lib/__tests__/instance-target.test.ts +183 -0
- package/src/lib/__tests__/instance.test.ts +136 -0
- package/src/lib/__tests__/keys.test.ts +129 -0
- package/src/lib/__tests__/local-status.test.ts +202 -0
- package/src/lib/__tests__/output.test.ts +150 -0
- package/src/lib/__tests__/panel.test.ts +40 -0
- package/src/lib/__tests__/port.test.ts +44 -0
- package/src/lib/__tests__/prompt.test.ts +25 -0
- package/src/lib/__tests__/sdk-deps.test.ts +68 -0
- package/src/lib/__tests__/self.test.ts +272 -0
- package/src/lib/__tests__/studio-server-deps.test.ts +74 -0
- package/src/lib/__tests__/table.test.ts +53 -0
- package/src/lib/__tests__/update.test.ts +246 -0
- package/src/lib/__tests__/use-target.test.ts +56 -0
- package/src/lib/__tests__/validation.test.ts +34 -0
- package/src/lib/admin-domain.ts +25 -0
- package/src/lib/admin-instance.ts +26 -0
- package/src/lib/admin-target.ts +217 -0
- package/src/lib/binary.ts +131 -0
- package/src/lib/browser.ts +150 -0
- package/src/lib/command-dx.ts +161 -0
- package/src/lib/concurrency.ts +31 -0
- package/src/lib/config.ts +45 -0
- package/src/lib/domain-identity.ts +49 -0
- package/src/lib/env.ts +49 -0
- package/src/lib/format.ts +4 -0
- package/src/lib/fs-atomic.ts +126 -0
- package/src/lib/identity.ts +256 -0
- package/src/lib/idp-session.ts +134 -0
- package/src/lib/idp.ts +876 -0
- package/src/lib/instance-candidates.ts +49 -0
- package/src/lib/instance-target.ts +182 -0
- package/src/lib/instance.ts +395 -0
- package/src/lib/keys.ts +294 -0
- package/src/lib/local-status.ts +152 -0
- package/src/lib/log.ts +116 -0
- package/src/lib/login-flow.ts +164 -0
- package/src/lib/meta.ts +86 -0
- package/src/lib/output.ts +222 -0
- package/src/lib/panel.ts +61 -0
- package/src/lib/paths.ts +11 -0
- package/src/lib/port.ts +41 -0
- package/src/lib/proc.ts +82 -0
- package/src/lib/prompt.ts +136 -0
- package/src/lib/provision-instance.ts +170 -0
- package/src/lib/sdk-deps.ts +104 -0
- package/src/lib/self.ts +166 -0
- package/src/lib/skills.ts +171 -0
- package/src/lib/table.ts +62 -0
- package/src/lib/update.ts +315 -0
- package/src/lib/use-target.ts +24 -0
- package/src/lib/validation.ts +59 -0
- package/src/program.ts +200 -0
- package/src/registry.ts +59 -0
- package/src/setup/__tests__/util.test.ts +29 -0
- package/src/setup/engine.ts +83 -0
- package/src/setup/render.ts +109 -0
- package/src/setup/steps/admin.ts +78 -0
- package/src/setup/steps/agent-browser.ts +81 -0
- package/src/setup/steps/auth.ts +54 -0
- package/src/setup/steps/domain.ts +68 -0
- package/src/setup/steps/index.ts +18 -0
- package/src/setup/steps/instance.ts +119 -0
- package/src/setup/steps/skills-bridge.ts +70 -0
- package/src/setup/steps/skills.ts +59 -0
- package/src/setup/types.ts +61 -0
- package/src/setup/util.ts +34 -0
- package/src/test-utils.ts +18 -0
- package/studio/client/dist/assets/index-DOwzZAEK.css +1 -0
- package/studio/client/dist/assets/index-wtU0Zxhy.js +183 -0
- package/studio/client/dist/index.html +13 -0
- package/studio/package.json +62 -0
- package/studio/server/agent/ask.ts +68 -0
- package/studio/server/agent/bridge-mcp.ts +182 -0
- package/studio/server/agent/bridge.ts +188 -0
- package/studio/server/agent/claude.ts +666 -0
- package/studio/server/agent/mock.ts +186 -0
- package/studio/server/agent/prompt.ts +202 -0
- package/studio/server/agent/registry.ts +29 -0
- package/studio/server/agent/runner.ts +484 -0
- package/studio/server/agent/schema-map.ts +112 -0
- package/studio/server/agent/types.ts +120 -0
- package/studio/server/api.ts +574 -0
- package/studio/server/cache.ts +138 -0
- package/studio/server/detect.ts +81 -0
- package/studio/server/domain.ts +70 -0
- package/studio/server/index.ts +136 -0
- package/studio/server/introspect/anatomy-extras.ts +398 -0
- package/studio/server/introspect/anatomy.ts +108 -0
- package/studio/server/introspect/bundle.ts +57 -0
- package/studio/server/introspect/core-extractor.ts +119 -0
- package/studio/server/introspect/core.ts +44 -0
- package/studio/server/introspect/diff.ts +133 -0
- package/studio/server/introspect/extractor.ts +102 -0
- package/studio/server/introspect/hash.ts +21 -0
- package/studio/server/introspect/overlay-tsmorph.ts +874 -0
- package/studio/server/introspect/overlay.ts +57 -0
- package/studio/server/introspect/runtime.ts +99 -0
- package/studio/server/introspect/schema-refs.ts +46 -0
- package/studio/server/lifecycle.ts +38 -0
- package/studio/server/sse.ts +57 -0
- package/studio/server/state/baseline.ts +211 -0
- package/studio/server/state/catalog.ts +117 -0
- package/studio/server/state/comments.ts +321 -0
- package/studio/server/state/context.ts +167 -0
- package/studio/server/state/copy.ts +156 -0
- package/studio/server/state/create.ts +156 -0
- package/studio/server/state/documents.ts +70 -0
- package/studio/server/state/env.ts +161 -0
- package/studio/server/state/git.ts +75 -0
- package/studio/server/state/handoff.ts +55 -0
- package/studio/server/state/harness-gateway.ts +181 -0
- package/studio/server/state/harness-token.ts +0 -0
- package/studio/server/state/instance.ts +244 -0
- package/studio/server/state/integrations.ts +55 -0
- package/studio/server/state/layout.ts +55 -0
- package/studio/server/state/settings.ts +39 -0
- package/studio/server/state/store.ts +97 -0
- package/studio/server/state/updates.ts +63 -0
- package/studio/server/state/usage.ts +37 -0
- package/studio/server/state/views.ts +138 -0
- package/studio/server/state/visibility.ts +33 -0
- package/studio/server/watch.ts +81 -0
- package/studio/server/workspace-state.ts +26 -0
- package/studio/server/workspace-watch.ts +101 -0
- package/studio/shared/types.ts +873 -0
- package/studio/tsconfig.json +23 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core.ts — assembles a domain's StudioCore: the genesis node/edge graph
|
|
3
|
+
* extracted from `defineCore`, gated on installed deps. Never throws; a failed
|
|
4
|
+
* import or a domain with no core both become a well-formed (empty) render state.
|
|
5
|
+
*/
|
|
6
|
+
import type { StudioCore } from '../../shared/types'
|
|
7
|
+
|
|
8
|
+
import { type DomainHandle, depsInstalled } from '../domain'
|
|
9
|
+
import { readSettings } from '../state/settings'
|
|
10
|
+
import { coreExtract } from './runtime'
|
|
11
|
+
|
|
12
|
+
export async function buildCore(handle: DomainHandle): Promise<StudioCore> {
|
|
13
|
+
const at = new Date().toISOString()
|
|
14
|
+
const empty = (error: StudioCore['error']): StudioCore => ({
|
|
15
|
+
domain: handle.origin ?? handle.id,
|
|
16
|
+
nodes: [],
|
|
17
|
+
edges: [],
|
|
18
|
+
error,
|
|
19
|
+
extractedAt: at,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
if (!depsInstalled(handle.root)) {
|
|
23
|
+
return empty({
|
|
24
|
+
message: 'dependencies not installed — run `pnpm install` in the domain for core extraction',
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const r = await coreExtract(
|
|
29
|
+
handle.domainFile,
|
|
30
|
+
handle.root,
|
|
31
|
+
readSettings(handle.root).introspectTimeoutMs,
|
|
32
|
+
)
|
|
33
|
+
// r.ok && r.core===null → the domain simply defines no core (not an error).
|
|
34
|
+
if (!r.ok) return empty(r.error ?? { message: 'core extraction failed' })
|
|
35
|
+
if (!r.core) return empty(null)
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
domain: r.core.domain,
|
|
39
|
+
nodes: r.core.nodes,
|
|
40
|
+
edges: r.core.edges,
|
|
41
|
+
error: null,
|
|
42
|
+
extractedAt: at,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* diff.ts — structural diff of two Schema IRs + breaking/additive classification.
|
|
3
|
+
* Shared by change tracking (baseline) and data versioning. Pure.
|
|
4
|
+
*
|
|
5
|
+
* Optionality is encoded in JSON Schema as a `type` array containing 'null'.
|
|
6
|
+
* BREAKING: any removal/rename, prop type change, optional→required, method
|
|
7
|
+
* signature change. ADDITIVE: only additions, or required→optional.
|
|
8
|
+
*/
|
|
9
|
+
import type {
|
|
10
|
+
IrClass,
|
|
11
|
+
IrInterface,
|
|
12
|
+
IrMethod,
|
|
13
|
+
JsonSchema,
|
|
14
|
+
SchemaChange,
|
|
15
|
+
SchemaIR,
|
|
16
|
+
} from '../../shared/types'
|
|
17
|
+
|
|
18
|
+
export function isOptional(s: JsonSchema | undefined): boolean {
|
|
19
|
+
if (!s) return false
|
|
20
|
+
return Array.isArray(s.type) ? s.type.includes('null') : false
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function baseType(s: JsonSchema | undefined): string {
|
|
24
|
+
if (!s) return 'unknown'
|
|
25
|
+
const t = s.type
|
|
26
|
+
if (Array.isArray(t)) {
|
|
27
|
+
const base = t.filter((x) => x !== 'null')
|
|
28
|
+
return (base.length ? base.join('|') : 'null') + (s.enum ? `(${s.enum.join(',')})` : '')
|
|
29
|
+
}
|
|
30
|
+
if (typeof t === 'string') return t + (s.enum ? `(${s.enum.join(',')})` : '')
|
|
31
|
+
return s.enum ? `enum(${s.enum.join(',')})` : 'unknown'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function methodSig(m: IrMethod): string {
|
|
35
|
+
const params = Object.entries(m.params ?? {})
|
|
36
|
+
.map(([k, v]) => `${k}:${baseType(v)}${isOptional(v) ? '?' : ''}`)
|
|
37
|
+
.sort()
|
|
38
|
+
.join(',')
|
|
39
|
+
return `static=${m.static};in=${params};out=${baseType(m.returns)};inh=${m.inheritance}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function diffSchemas(prev: SchemaIR | null, next: SchemaIR | null): SchemaChange[] {
|
|
43
|
+
const changes: SchemaChange[] = []
|
|
44
|
+
if (!prev || !next) return changes
|
|
45
|
+
|
|
46
|
+
diffMembers(prev.interfaces ?? {}, next.interfaces ?? {}, 'interface', changes)
|
|
47
|
+
diffMembers(prev.classes ?? {}, next.classes ?? {}, 'class', changes)
|
|
48
|
+
return changes
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function memberKind(m: IrClass | IrInterface): 'class' | 'edge' | 'interface' {
|
|
52
|
+
if ((m as IrInterface).type === 'interface') return 'interface'
|
|
53
|
+
return (m as IrClass).type === 'edge' ? 'edge' : 'class'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function diffMembers(
|
|
57
|
+
prev: Record<string, IrClass | IrInterface>,
|
|
58
|
+
next: Record<string, IrClass | IrInterface>,
|
|
59
|
+
_scope: 'class' | 'interface',
|
|
60
|
+
out: SchemaChange[],
|
|
61
|
+
): void {
|
|
62
|
+
for (const name of Object.keys(next)) {
|
|
63
|
+
if (!prev[name]) {
|
|
64
|
+
const k = memberKind(next[name])
|
|
65
|
+
out.push({ kind: `${k}-added` as SchemaChange['kind'], target: name, breaking: false })
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const name of Object.keys(prev)) {
|
|
69
|
+
if (!next[name]) {
|
|
70
|
+
const k = memberKind(prev[name])
|
|
71
|
+
out.push({ kind: `${k}-removed` as SchemaChange['kind'], target: name, breaking: true })
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
diffMemberBody(name, prev[name], next[name], out)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function diffMemberBody(
|
|
79
|
+
name: string,
|
|
80
|
+
a: IrClass | IrInterface,
|
|
81
|
+
b: IrClass | IrInterface,
|
|
82
|
+
out: SchemaChange[],
|
|
83
|
+
): void {
|
|
84
|
+
const pa = a.properties ?? {}
|
|
85
|
+
const pb = b.properties ?? {}
|
|
86
|
+
for (const p of Object.keys(pb)) {
|
|
87
|
+
if (!pa[p]) out.push({ kind: 'prop-added', target: `${name}.${p}`, breaking: false })
|
|
88
|
+
}
|
|
89
|
+
for (const p of Object.keys(pa)) {
|
|
90
|
+
if (!pb[p]) {
|
|
91
|
+
out.push({ kind: 'prop-removed', target: `${name}.${p}`, breaking: true })
|
|
92
|
+
continue
|
|
93
|
+
}
|
|
94
|
+
if (baseType(pa[p]) !== baseType(pb[p])) {
|
|
95
|
+
out.push({
|
|
96
|
+
kind: 'prop-type-changed',
|
|
97
|
+
target: `${name}.${p}`,
|
|
98
|
+
detail: `${baseType(pa[p])} → ${baseType(pb[p])}`,
|
|
99
|
+
breaking: true,
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
const wasOpt = isOptional(pa[p])
|
|
103
|
+
const nowOpt = isOptional(pb[p])
|
|
104
|
+
if (wasOpt !== nowOpt) {
|
|
105
|
+
out.push({
|
|
106
|
+
kind: 'prop-required-changed',
|
|
107
|
+
target: `${name}.${p}`,
|
|
108
|
+
detail: wasOpt ? 'optional → required' : 'required → optional',
|
|
109
|
+
breaking: wasOpt && !nowOpt, // optional→required is breaking
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const ma = a.methods ?? {}
|
|
115
|
+
const mb = b.methods ?? {}
|
|
116
|
+
for (const m of Object.keys(mb)) {
|
|
117
|
+
if (!ma[m]) out.push({ kind: 'method-added', target: `${name}.${m}`, breaking: false })
|
|
118
|
+
}
|
|
119
|
+
for (const m of Object.keys(ma)) {
|
|
120
|
+
if (!mb[m]) {
|
|
121
|
+
out.push({ kind: 'method-removed', target: `${name}.${m}`, breaking: true })
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
if (methodSig(ma[m]) !== methodSig(mb[m])) {
|
|
125
|
+
out.push({ kind: 'method-signature-changed', target: `${name}.${m}`, breaking: true })
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function classify(changes: SchemaChange[]): 'none' | 'additive' | 'breaking' {
|
|
131
|
+
if (changes.length === 0) return 'none'
|
|
132
|
+
return changes.some((c) => c.breaking) ? 'breaking' : 'additive'
|
|
133
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extractor.ts — the Bun-executed island. Spawned as a short-lived subprocess by
|
|
3
|
+
* runtime.ts. It imports ONLY the domain's pure `schema/index.ts` module graph
|
|
4
|
+
* (never astrale.config.ts or domain.ts → deps → integrations), reads the
|
|
5
|
+
* compiled `D.$.ir`, and prints the SchemaIR as JSON to stdout.
|
|
6
|
+
*
|
|
7
|
+
* bun extractor.ts <schemaIndexPath> <domainDir>
|
|
8
|
+
*
|
|
9
|
+
* `compileDomain`/`serialize` are PURE (no IO, no env), so importing the schema
|
|
10
|
+
* is side-effect-free. A thrown error prints { ok:false } and exits 0 — the
|
|
11
|
+
* driver treats it as a render state, never a crash.
|
|
12
|
+
*/
|
|
13
|
+
const schemaPath = process.argv[2]
|
|
14
|
+
const domainDir = process.argv[3] ?? process.cwd()
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
if (!schemaPath) throw new Error('extractor: missing <schemaIndexPath>')
|
|
18
|
+
const mod: Record<string, any> = await import(schemaPath)
|
|
19
|
+
|
|
20
|
+
// Lazily resolve the domain's own kernel-dsl serializer (used by the fallback
|
|
21
|
+
// path AND to recover imported-interface bodies). Cached after first load.
|
|
22
|
+
let dsl: Record<string, any> | null = null
|
|
23
|
+
const loadDsl = async (): Promise<Record<string, any>> => {
|
|
24
|
+
if (dsl) return dsl
|
|
25
|
+
const loaded: Record<string, any> = await import(
|
|
26
|
+
Bun.resolveSync('@astrale-os/kernel-dsl', domainDir)
|
|
27
|
+
)
|
|
28
|
+
dsl = loaded
|
|
29
|
+
return loaded
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Prefer the conventional `D` (compiled), but accept a compiled domain exported
|
|
33
|
+
// under ANY name — e.g. ai-gateway exports its `compileDomain(...)` result as
|
|
34
|
+
// `Gateway`, not `D`. A compiled domain is recognized by shape (`.$.ir`).
|
|
35
|
+
let ir: unknown = mod?.D?.$?.ir
|
|
36
|
+
if (!ir) {
|
|
37
|
+
for (const v of Object.values(mod)) {
|
|
38
|
+
const candidate = (v as any)?.$?.ir
|
|
39
|
+
if (candidate) {
|
|
40
|
+
ir = candidate
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!ir) {
|
|
46
|
+
// Fallback: serialize a raw schema — the conventional `schema`, else any
|
|
47
|
+
// exported `defineSchema(...)` result (recognized by its `kind === 'schema'`).
|
|
48
|
+
const schema =
|
|
49
|
+
mod?.schema ??
|
|
50
|
+
Object.values(mod).find(
|
|
51
|
+
(v) =>
|
|
52
|
+
typeof (v as any)?.domain === 'string' && !!(v as any)?.classes && !!(v as any)?.imports,
|
|
53
|
+
)
|
|
54
|
+
if (!schema) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
'schema entry exports no compiled domain (a `compileDomain(...)` value with `.$.ir`, e.g. `D`) nor a raw `schema`',
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
const d = await loadDsl()
|
|
60
|
+
if (typeof d.serialize !== 'function') throw new Error('kernel-dsl.serialize unavailable')
|
|
61
|
+
ir = d.serialize(schema)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Recover member bodies of IMPORTED interfaces (kernel mixins + cross-domain
|
|
65
|
+
// interfaces). `serialize()` emits them in `ir.imports` as name-only
|
|
66
|
+
// descriptors, so re-serialize each imported schema (KernelSchema, other
|
|
67
|
+
// domains) and collect its interface definitions. Best-effort: a single import
|
|
68
|
+
// failing to serialize must never break extraction of the primary IR.
|
|
69
|
+
const importedInterfaces: Record<string, unknown> = {}
|
|
70
|
+
const importSchemas: any[] = Array.isArray(mod?.schema?.imports) ? mod.schema.imports : []
|
|
71
|
+
if (importSchemas.length > 0) {
|
|
72
|
+
try {
|
|
73
|
+
const d = await loadDsl()
|
|
74
|
+
if (typeof d.serialize === 'function') {
|
|
75
|
+
for (const imp of importSchemas) {
|
|
76
|
+
try {
|
|
77
|
+
const sub = d.serialize(imp)
|
|
78
|
+
for (const [name, def] of Object.entries(sub?.interfaces ?? {})) {
|
|
79
|
+
if (!(name in importedInterfaces)) importedInterfaces[name] = def
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
/* skip this import — keep going */
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
/* dsl unavailable — degrade gracefully (no imported-interface bodies) */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
process.stdout.write(JSON.stringify({ ok: true, ir, importedInterfaces }))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
main().catch((err: any) => {
|
|
95
|
+
process.stdout.write(
|
|
96
|
+
JSON.stringify({
|
|
97
|
+
ok: false,
|
|
98
|
+
error: { message: String(err?.message ?? err), stack: String(err?.stack ?? '') },
|
|
99
|
+
}),
|
|
100
|
+
)
|
|
101
|
+
process.exit(0)
|
|
102
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
|
|
3
|
+
/** Deterministic JSON with stable key order — so cosmetic edits/reordering don't churn the hash. */
|
|
4
|
+
export function canonicalJSON(value: unknown): string {
|
|
5
|
+
return JSON.stringify(sortKeys(value))
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function sortKeys(v: any): any {
|
|
9
|
+
if (Array.isArray(v)) return v.map(sortKeys)
|
|
10
|
+
if (v && typeof v === 'object') {
|
|
11
|
+
const out: Record<string, any> = {}
|
|
12
|
+
for (const k of Object.keys(v).sort()) out[k] = sortKeys(v[k])
|
|
13
|
+
return out
|
|
14
|
+
}
|
|
15
|
+
return v
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** sha256 over canonical JSON, short-prefixed — the schemaHash (identifies a schema version). */
|
|
19
|
+
export function schemaHashOf(value: unknown): string {
|
|
20
|
+
return 'sha-' + createHash('sha256').update(canonicalJSON(value)).digest('hex').slice(0, 12)
|
|
21
|
+
}
|