@astrale-os/cli 1.0.0-beta.4 → 1.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/astrale.js +55649 -59388
- package/dist/public/connect-core.js +1972 -26831
- package/dist/public/keys/index.js +1754 -40686
- package/dist/public/paths/index.js +859 -39511
- package/dist/types/admin/instance/model.d.ts +3 -4
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/lib/idp.d.ts +1 -0
- package/dist/types/lib/instance-target.d.ts +1 -1
- package/dist/types/lib/log.d.ts +2 -2
- package/dist/types/lib/update.d.ts +30 -0
- package/package.json +4 -6
- package/src/__tests__/fixtures/publication.ts +20 -0
- package/src/admin/__tests__/binding.test.ts +14 -21
- package/src/admin/__tests__/fixture.ts +101 -0
- package/src/admin/binding.ts +86 -6
- package/src/admin/catalog/.spec/api.d.ts +2 -2
- package/src/admin/catalog/__tests__/client.test.ts +20 -49
- package/src/admin/catalog/client.ts +35 -26
- package/src/admin/catalog/model.ts +3 -4
- package/src/admin/graph/.spec/api.d.ts +4 -10
- package/src/admin/graph/nodes.ts +1 -1
- package/src/admin/instance/.spec/api.d.ts +2 -2
- package/src/admin/instance/__tests__/client.test.ts +58 -83
- package/src/admin/instance/client.ts +49 -39
- package/src/admin/instance/model.ts +9 -8
- package/src/commands/__tests__/call-describe.test.ts +46 -33
- package/src/commands/__tests__/domain-install-operation.test.ts +3 -14
- package/src/commands/__tests__/domain-install-owned.test.ts +1 -1
- package/src/commands/__tests__/domain-list.test.ts +5 -25
- package/src/commands/__tests__/install-identity-override.test.ts +3 -14
- package/src/commands/__tests__/read-commands.test.ts +35 -10
- package/src/commands/__tests__/update.test.ts +25 -3
- package/src/commands/call-describe.ts +59 -67
- package/src/commands/call.ts +41 -54
- package/src/commands/domain/install.ts +2 -2
- package/src/commands/domain/uninstall.ts +2 -2
- package/src/commands/get.ts +13 -14
- package/src/commands/identity/__tests__/register.test.ts +3 -3
- package/src/commands/identity/register.ts +5 -4
- package/src/commands/instance/delete.ts +5 -3
- package/src/commands/instance/status.ts +1 -9
- package/src/commands/introspect.ts +4 -11
- package/src/commands/logs.ts +24 -25
- package/src/commands/mutate.ts +6 -5
- package/src/commands/query.ts +27 -30
- package/src/commands/token.ts +8 -7
- package/src/commands/update.ts +31 -11
- package/src/commands/view.ts +4 -3
- package/src/connection/.spec/api.d.ts +7 -8
- package/src/connection/.spec/architecture.md +5 -4
- package/src/connection/.spec/flows/session.ts +2 -2
- package/src/connection/.spec/laws/connection.ts +6 -2
- package/src/connection/.spec/layout.ts +1 -0
- package/src/connection/__tests__/credential.test.ts +1 -1
- package/src/connection/__tests__/errors.test.ts +27 -20
- package/src/connection/__tests__/exchange.test.ts +30 -1
- package/src/connection/__tests__/failure-fixtures.ts +39 -0
- package/src/connection/__tests__/failure-safety.test.ts +75 -0
- package/src/connection/__tests__/self.test.ts +31 -11
- package/src/connection/__tests__/session.test.ts +3 -3
- package/src/connection/call.ts +1 -1
- package/src/connection/credential.ts +2 -2
- package/src/connection/errors.ts +1 -355
- package/src/connection/exchange.ts +47 -23
- package/src/connection/failure/classify.ts +110 -0
- package/src/connection/failure/debug.ts +26 -0
- package/src/connection/failure/index.ts +18 -0
- package/src/connection/failure/model.ts +28 -0
- package/src/connection/failure/render.ts +116 -0
- package/src/connection/reasons.ts +16 -0
- package/src/connection/self.ts +39 -21
- package/src/connection/session.ts +8 -8
- package/src/errors.ts +3 -2
- package/src/graph/.spec/api.d.ts +12 -5
- package/src/graph/.spec/layout.ts +9 -1
- package/src/graph/__tests__/mutation.test.ts +2 -2
- package/src/graph/__tests__/query.test.ts +25 -6
- package/src/graph/class.ts +30 -0
- package/src/graph/index.ts +1 -0
- package/src/graph/query.ts +21 -32
- package/src/identity/.spec/api.d.ts +2 -2
- package/src/identity/__tests__/registration.test.ts +1 -1
- package/src/identity/registration.ts +3 -3
- package/src/lib/__tests__/domain-publication.test.ts +4 -15
- package/src/lib/__tests__/idp.test.ts +25 -0
- package/src/lib/__tests__/instance-target.test.ts +6 -39
- package/src/lib/__tests__/log-errors.test.ts +53 -0
- package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
- package/src/lib/__tests__/update.test.ts +101 -8
- package/src/lib/__tests__/view-open-intent.test.ts +0 -2
- package/src/lib/__tests__/view-server.test.ts +1 -1
- package/src/lib/__tests__/view-session.test.ts +1 -1
- package/src/lib/command-dx.ts +1 -4
- package/src/lib/domain-publication.ts +1 -1
- package/src/lib/idp.ts +29 -1
- package/src/lib/instance-target.ts +3 -14
- package/src/lib/log.ts +11 -6
- package/src/lib/update.ts +120 -26
- package/src/lib/validation.ts +2 -2
- package/src/lib/view/resolve.ts +1 -1
- package/src/program/__tests__/program.test.ts +1 -1
- package/studio/client/dist/assets/{elk-api-lwhFo7vB.js → elk-api-Di4OXGNH.js} +1 -1
- package/studio/client/dist/assets/index-BLm6J11H.js +81 -0
- package/studio/client/dist/assets/index-BiGR8Oo9.css +1 -0
- package/studio/client/dist/assets/index-DTjvkOUX.js +8 -0
- package/studio/client/dist/index.html +2 -2
- package/studio/package.json +2 -9
- package/studio/server/agent/ask.test.ts +1 -1
- package/studio/server/agent/bridge/grant.test.ts +1 -1
- package/studio/server/agent/bridge/routes.test.ts +1 -1
- package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
- package/studio/server/agent/prompts/anchors.test.ts +32 -36
- package/studio/server/agent/prompts/anchors.ts +20 -49
- package/studio/server/agent/prompts/system.test.ts +3 -2
- package/studio/server/agent/prompts/system.ts +3 -3
- package/studio/server/agent/routes.test.ts +1 -1
- package/studio/server/agent/run/coordinator.test.ts +1 -1
- package/studio/server/api/canvas.ts +0 -1
- package/studio/server/api-agent-loadout.test.ts +1 -1
- package/studio/server/api.test.ts +1 -1
- package/studio/server/cache.test.ts +23 -12
- package/studio/server/cache.ts +12 -15
- package/studio/server/domain.test.ts +50 -68
- package/studio/server/domain.ts +82 -63
- package/studio/server/handoff/copy.ts +1 -1
- package/studio/server/index.ts +1 -1
- package/studio/server/instances/probe.test.ts +1 -1
- package/studio/server/introspect/anatomy/views/routes.ts +46 -37
- package/studio/server/introspect/anatomy/views.ts +9 -14
- package/studio/server/introspect/anatomy-extras.test.ts +26 -42
- package/studio/server/introspect/anatomy.test.ts +22 -14
- package/studio/server/introspect/anatomy.ts +6 -9
- package/studio/server/introspect/bundle.ts +0 -3
- package/studio/server/introspect/canonical-schema.test.ts +94 -389
- package/studio/server/introspect/canonical-schema.ts +227 -457
- package/studio/server/introspect/core-extractor.ts +18 -127
- package/studio/server/introspect/core.ts +1 -2
- package/studio/server/introspect/diff.test.ts +11 -7
- package/studio/server/introspect/diff.ts +18 -55
- package/studio/server/introspect/extractor.ts +22 -117
- package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
- package/studio/server/introspect/overlay.test.ts +26 -54
- package/studio/server/introspect/overlay.ts +10 -37
- package/studio/server/introspect/revision.test.ts +1 -1
- package/studio/server/introspect/revision.ts +1 -1
- package/studio/server/introspect/runtime.test.ts +65 -183
- package/studio/server/introspect/runtime.ts +8 -25
- package/studio/server/introspect/schema-ir-json.test.ts +70 -0
- package/studio/server/introspect/schema-ir-json.ts +38 -68
- package/studio/server/introspect/schema-refs.test.ts +43 -88
- package/studio/server/introspect/schema-refs.ts +14 -49
- package/studio/server/introspect/source-overlay/handlers.ts +116 -636
- package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -3
- package/studio/server/introspect/source-overlay/spans.ts +15 -45
- package/studio/server/state/baseline.test.ts +14 -9
- package/studio/server/state/baseline.ts +3 -5
- package/studio/server/state/visibility.ts +1 -5
- package/studio/server/views/model.ts +3 -3
- package/studio/server/views/target.test.ts +17 -74
- package/studio/server/views/target.ts +24 -50
- package/studio/server/watch.test.ts +11 -11
- package/studio/server/watch.ts +8 -4
- package/studio/server/workspace-watch.ts +2 -2
- package/studio/shared/contracts/schema.ts +38 -107
- package/studio/shared/contracts/surface.test.ts +13 -15
- package/studio/shared/contracts/workspace.ts +2 -11
- package/studio/shared/schema/identity.test.ts +20 -44
- package/studio/shared/schema/identity.ts +9 -23
- package/viewer/dist/main.js +40 -61
- package/studio/client/dist/assets/index-B-c-smo9.js +0 -8
- package/studio/client/dist/assets/index-BckHuAWk.js +0 -81
- package/studio/client/dist/assets/index-C4aNQ6dz.css +0 -1
- package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
|
@@ -1,139 +1,30 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* core-extractor.ts — the Bun-executed island for a domain's CORE (genesis) data.
|
|
3
|
-
* Spawned as a short-lived subprocess by runtime.ts (cwd = domain dir, so the
|
|
4
|
-
* domain's own node_modules resolve @astrale-os/*). It imports the pure schema
|
|
5
|
-
* entry and reads canonical V1 `schema.core` directly. Importing the composition
|
|
6
|
-
* entry and discovering legacy `defineCore(...)` output is retained only as a
|
|
7
|
-
* fallback.
|
|
8
|
-
*
|
|
9
|
-
* bun core-extractor.ts <schemaIndexPath> <domainFile> <domainDir>
|
|
10
|
-
*
|
|
11
|
-
* Contract mirrors extractor.ts exactly: NEVER crash. A thrown error prints
|
|
12
|
-
* { ok:false } and exits 0 — the driver treats it as a render state. A domain
|
|
13
|
-
* with no core prints { ok:true, core:null }.
|
|
14
|
-
*
|
|
15
|
-
* NOTE: the `export {}` below marks this as a module so its top-level `domainDir`/
|
|
16
|
-
* `main` are module-scoped (extractor.ts is a sibling script with the same names).
|
|
17
|
-
*
|
|
18
|
-
* className resolution: a core node's `def` is the runtime class-definition
|
|
19
|
-
* object (shape `{ __kind, config }` — it carries NO name field). We resolve the
|
|
20
|
-
* name by identity-matching `def` against the core's own `schema.classes` /
|
|
21
|
-
* `schema.interfaces`, AND every `schema.imports[*]` group — imported kernel
|
|
22
|
-
* classes like `Folder` ONLY resolve via the imports walk. `data` is passed
|
|
23
|
-
* through as the author wrote it in `node(Class, {...})` (most readable form).
|
|
24
|
-
*/
|
|
25
|
-
export {} // module marker — see header note
|
|
1
|
+
/** Bun subprocess that projects canonical Core directly from the pure Schema entry. */
|
|
26
2
|
import { isAbsolute, resolve } from 'node:path'
|
|
27
3
|
|
|
28
4
|
import { findCanonicalDomainSchemaExport, projectCanonicalCore } from './canonical-schema'
|
|
29
5
|
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const schemaFile = resolveInput(process.argv[2])
|
|
34
|
-
const domainFile = resolveInput(process.argv[3])
|
|
6
|
+
const projectRoot = process.argv[3] ?? process.cwd()
|
|
7
|
+
const input = process.argv[2]
|
|
8
|
+
const schemaFile = input && !isAbsolute(input) ? resolve(projectRoot, input) : input
|
|
35
9
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
10
|
+
async function main(): Promise<void> {
|
|
11
|
+
if (!schemaFile) throw new Error('core-extractor: missing <schemaPath>')
|
|
12
|
+
const exports = (await import(schemaFile)) as Record<string, unknown>
|
|
13
|
+
const schema = findCanonicalDomainSchemaExport(exports)
|
|
14
|
+
if (schema === null) throw new Error('Schema entry exports no canonical V1 DomainSchema.')
|
|
15
|
+
const core = projectCanonicalCore(schema)
|
|
16
|
+
process.stdout.write(
|
|
17
|
+
JSON.stringify({
|
|
18
|
+
ok: true,
|
|
19
|
+
core: core.nodes.length === 0 && core.edges.length === 0 ? null : core,
|
|
20
|
+
}),
|
|
47
21
|
)
|
|
48
22
|
}
|
|
49
23
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const wired = mod?.domain?.core ?? mod?.default?.core ?? mod?.core
|
|
53
|
-
if (looksLikeCore(wired)) return wired
|
|
54
|
-
// export name varies per domain (GatewayCore / IntegrationCore / …) — scan by shape
|
|
55
|
-
for (const v of Object.values(mod ?? {})) {
|
|
56
|
-
if (looksLikeCore(v)) return v
|
|
57
|
-
if (v && typeof v === 'object' && looksLikeCore((v as AnyRec).core)) return (v as AnyRec).core
|
|
58
|
-
}
|
|
59
|
-
return null
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** Build def→className from the schema's own classes/interfaces + imported schemas. */
|
|
63
|
-
function classNameMap(schema: AnyRec): Map<any, string> {
|
|
64
|
-
const m = new Map<any, string>()
|
|
65
|
-
const add = (group?: AnyRec) => {
|
|
66
|
-
for (const [name, def] of Object.entries(group ?? {})) if (def && !m.has(def)) m.set(def, name)
|
|
67
|
-
}
|
|
68
|
-
add(schema?.interfaces)
|
|
69
|
-
add(schema?.classes)
|
|
70
|
-
for (const imp of schema?.imports ?? []) {
|
|
71
|
-
add(imp?.interfaces)
|
|
72
|
-
add(imp?.classes)
|
|
73
|
-
}
|
|
74
|
-
return m
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async function main() {
|
|
78
|
-
if (!schemaFile) throw new Error('core-extractor: missing <schemaIndexPath>')
|
|
79
|
-
|
|
80
|
-
// Current SDK roots embed genesis data in the canonical, portable schema.
|
|
81
|
-
// Do not import implementation.ts/domain.ts when that source of truth exists.
|
|
82
|
-
try {
|
|
83
|
-
const schemaModule: AnyRec = await import(schemaFile)
|
|
84
|
-
const canonical = findCanonicalDomainSchemaExport(schemaModule)
|
|
85
|
-
if (canonical) {
|
|
86
|
-
const core = projectCanonicalCore(canonical)
|
|
87
|
-
const empty = core.nodes.length === 0 && core.edges.length === 0
|
|
88
|
-
process.stdout.write(JSON.stringify({ ok: true, core: empty ? null : core }))
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
} catch {
|
|
92
|
-
// A legacy composition entry may still expose a valid defineCore result.
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (!domainFile) throw new Error('core-extractor: missing <domainFile> legacy fallback')
|
|
96
|
-
const mod: AnyRec = await import(domainFile)
|
|
97
|
-
const core = findCore(mod)
|
|
98
|
-
if (!core) {
|
|
99
|
-
process.stdout.write(JSON.stringify({ ok: true, core: null }))
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const names = classNameMap(core.schema)
|
|
104
|
-
const nameOf = (def: any): string => names.get(def) ?? def?.config?.name ?? def?.name ?? '?'
|
|
105
|
-
// CorePath is a branded string; nested parents are objects with toString/valueOf,
|
|
106
|
-
// so String() is the correct universal coercion (never JSON.stringify a path).
|
|
107
|
-
const pathStr = (p: any): string => (p == null ? '' : String(p))
|
|
108
|
-
// An edge endpoint is a CorePath OR a SelfMarker ({ type:'core-self', __def }).
|
|
109
|
-
const endpoint = (e: any): string =>
|
|
110
|
-
e && typeof e === 'object' && (e.type === 'core-self' || e.__def)
|
|
111
|
-
? `self(${nameOf(e.__def)})`
|
|
112
|
-
: pathStr(e)
|
|
113
|
-
|
|
114
|
-
const nodes = (core.__nodes ?? []).map((n: AnyRec) => ({
|
|
115
|
-
path: pathStr(n.path),
|
|
116
|
-
className: nameOf(n.def),
|
|
117
|
-
data: n.data ?? {},
|
|
118
|
-
...(n.parent != null ? { parent: pathStr(n.parent) } : {}),
|
|
119
|
-
}))
|
|
120
|
-
|
|
121
|
-
const edges = (core.__edges ?? []).map((e: AnyRec) => ({
|
|
122
|
-
from: endpoint(e.from),
|
|
123
|
-
to: endpoint(e.to),
|
|
124
|
-
edgeName: nameOf(e.edge),
|
|
125
|
-
...(e.data != null ? { data: e.data } : {}),
|
|
126
|
-
}))
|
|
127
|
-
|
|
128
|
-
process.stdout.write(JSON.stringify({ ok: true, core: { domain: core.domain, nodes, edges } }))
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
main().catch((err: any) => {
|
|
24
|
+
main().catch((cause: unknown) => {
|
|
25
|
+
const error = cause instanceof Error ? cause : new Error(String(cause))
|
|
132
26
|
process.stdout.write(
|
|
133
|
-
JSON.stringify({
|
|
134
|
-
ok: false,
|
|
135
|
-
error: { message: String(err?.message ?? err), stack: String(err?.stack ?? '') },
|
|
136
|
-
}),
|
|
27
|
+
JSON.stringify({ ok: false, error: { message: error.message, stack: error.stack ?? '' } }),
|
|
137
28
|
)
|
|
138
29
|
process.exit(0)
|
|
139
30
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* core.ts — assembles a domain's StudioCore: the genesis node/edge graph
|
|
3
|
-
* extracted from canonical `schema.core
|
|
3
|
+
* extracted from canonical `schema.core`, gated
|
|
4
4
|
* on installed deps. Never throws; a failed import or a domain with no core both
|
|
5
5
|
* become a well-formed (empty) render state.
|
|
6
6
|
*/
|
|
@@ -28,7 +28,6 @@ export async function buildCore(handle: DomainHandle): Promise<StudioCore> {
|
|
|
28
28
|
|
|
29
29
|
const r = await coreExtract(
|
|
30
30
|
handle.schemaIndex,
|
|
31
|
-
handle.domainFile,
|
|
32
31
|
handle.root,
|
|
33
32
|
readSettings(handle.root).introspectTimeoutMs,
|
|
34
33
|
)
|
|
@@ -7,22 +7,22 @@ import { diffSchemas, structuralStatusOf } from './diff'
|
|
|
7
7
|
const callable = (returnsType = 'string'): IrFunction => ({
|
|
8
8
|
name: 'inspect',
|
|
9
9
|
input: { type: 'object', properties: {}, additionalProperties: false },
|
|
10
|
-
params: {},
|
|
11
10
|
output: { mode: 'value', schema: { type: returnsType } },
|
|
12
|
-
returns: { type: returnsType },
|
|
13
|
-
static: true,
|
|
14
|
-
inheritance: 'default',
|
|
15
11
|
auth: 'authenticated',
|
|
16
12
|
})
|
|
17
13
|
|
|
18
14
|
const schema = (functions: SchemaIR['functions']): SchemaIR => ({
|
|
19
15
|
version: 'v1',
|
|
16
|
+
format: 'astrale.dsl',
|
|
20
17
|
domain: 'example.test',
|
|
21
|
-
types: {},
|
|
22
|
-
interfaces: {},
|
|
23
18
|
classes: {},
|
|
24
|
-
|
|
19
|
+
importsByKey: {},
|
|
20
|
+
importedClassesByKey: {},
|
|
25
21
|
functions,
|
|
22
|
+
views: {},
|
|
23
|
+
policies: {},
|
|
24
|
+
dependencies: [],
|
|
25
|
+
core: {},
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
const withClass = (member: IrClass): SchemaIR => ({
|
|
@@ -63,6 +63,8 @@ describe('canonical standalone Function diffs', () => {
|
|
|
63
63
|
const member = (required: string[], minLength: number): IrClass => ({
|
|
64
64
|
type: 'node',
|
|
65
65
|
name: 'Person',
|
|
66
|
+
origin: 'example.test',
|
|
67
|
+
ref: { origin: 'example.test', kind: 'class', name: 'Person' },
|
|
66
68
|
properties: { name: { type: 'string', minLength } },
|
|
67
69
|
required,
|
|
68
70
|
methods: {},
|
|
@@ -87,6 +89,8 @@ describe('canonical standalone Function diffs', () => {
|
|
|
87
89
|
...withClass({
|
|
88
90
|
type: 'edge',
|
|
89
91
|
name: 'owns',
|
|
92
|
+
origin: 'example.test',
|
|
93
|
+
ref: { origin: 'example.test', kind: 'class', name: 'owns' },
|
|
90
94
|
properties: {},
|
|
91
95
|
required: [],
|
|
92
96
|
methods: {},
|
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
* diff.ts — indicative structural diff of two Studio render IRs. Pure.
|
|
3
3
|
*
|
|
4
4
|
* Canonical V1 keeps optionality in the owning `required` arrays and nullability
|
|
5
|
-
* in each value schema.
|
|
6
|
-
* inventory deliberately makes no installation or data-migration claim;
|
|
5
|
+
* in each value schema. This inventory makes no installation or data-migration claim;
|
|
7
6
|
* only the Kernel Runtime can assess those transitions against installed data.
|
|
8
7
|
*/
|
|
9
8
|
import type {
|
|
10
9
|
IrClass,
|
|
11
10
|
IrFunction,
|
|
12
|
-
IrInterface,
|
|
13
11
|
IrMethod,
|
|
14
12
|
JsonSchema,
|
|
15
13
|
SchemaChange,
|
|
@@ -32,28 +30,11 @@ export function baseType(s: JsonSchema | undefined): string {
|
|
|
32
30
|
return s.enum ? `enum(${s.enum.join(',')})` : 'unknown'
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
function requiredParams(m: IrMethod | IrFunction): string[] {
|
|
36
|
-
return (
|
|
37
|
-
m.requiredParams ??
|
|
38
|
-
Object.entries(m.params ?? {}).flatMap(([name, schema]) => (isOptional(schema) ? [] : [name]))
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
33
|
function callableContract(m: IrMethod | IrFunction): unknown {
|
|
43
|
-
const required = requiredParams(m)
|
|
44
34
|
return {
|
|
45
|
-
input:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
type: 'object',
|
|
49
|
-
properties: m.params ?? {},
|
|
50
|
-
required,
|
|
51
|
-
additionalProperties: false,
|
|
52
|
-
} satisfies JsonSchema),
|
|
53
|
-
required,
|
|
54
|
-
output: m.output ?? { mode: 'value', schema: m.returns },
|
|
55
|
-
static: m.static,
|
|
56
|
-
inheritance: m.inheritance,
|
|
35
|
+
input: m.input,
|
|
36
|
+
output: m.output,
|
|
37
|
+
...('static' in m ? { static: m.static, inheritance: m.inheritance } : {}),
|
|
57
38
|
auth: m.auth,
|
|
58
39
|
policy: m.policy,
|
|
59
40
|
}
|
|
@@ -76,15 +57,8 @@ export function diffSchemas(prev: SchemaIR | null, next: SchemaIR | null): Schem
|
|
|
76
57
|
changes.push({ kind: 'schema-metadata-changed', target: next.domain })
|
|
77
58
|
}
|
|
78
59
|
|
|
79
|
-
diffValueRecord(prev.
|
|
80
|
-
|
|
81
|
-
prev.importsByKey ?? prev.imports ?? {},
|
|
82
|
-
next.importsByKey ?? next.imports ?? {},
|
|
83
|
-
'import',
|
|
84
|
-
changes,
|
|
85
|
-
)
|
|
86
|
-
diffMembers(prev.interfaces ?? {}, next.interfaces ?? {}, 'interface', changes)
|
|
87
|
-
diffMembers(prev.classes ?? {}, next.classes ?? {}, 'class', changes)
|
|
60
|
+
diffValueRecord(prev.importsByKey, next.importsByKey, 'import', changes)
|
|
61
|
+
diffMembers(prev.classes, next.classes, changes)
|
|
88
62
|
diffFunctions(prev.functions ?? {}, next.functions ?? {}, changes)
|
|
89
63
|
diffViews(prev.views ?? {}, next.views ?? {}, changes)
|
|
90
64
|
diffValueRecord(prev.policies ?? {}, next.policies ?? {}, 'policy', changes)
|
|
@@ -98,7 +72,7 @@ export function diffSchemas(prev: SchemaIR | null, next: SchemaIR | null): Schem
|
|
|
98
72
|
function diffValueRecord(
|
|
99
73
|
prev: Record<string, unknown>,
|
|
100
74
|
next: Record<string, unknown>,
|
|
101
|
-
scope: '
|
|
75
|
+
scope: 'import' | 'policy',
|
|
102
76
|
out: SchemaChange[],
|
|
103
77
|
): void {
|
|
104
78
|
for (const name of sortedKeys(next)) {
|
|
@@ -196,15 +170,13 @@ function diffDependencies(
|
|
|
196
170
|
}
|
|
197
171
|
}
|
|
198
172
|
|
|
199
|
-
function memberKind(
|
|
200
|
-
|
|
201
|
-
return (m as IrClass).type === 'edge' ? 'edge' : 'class'
|
|
173
|
+
function memberKind(member: IrClass): 'class' | 'edge' {
|
|
174
|
+
return member.type === 'edge' ? 'edge' : 'class'
|
|
202
175
|
}
|
|
203
176
|
|
|
204
177
|
function diffMembers(
|
|
205
|
-
prev: Record<string, IrClass
|
|
206
|
-
next: Record<string, IrClass
|
|
207
|
-
_scope: 'class' | 'interface',
|
|
178
|
+
prev: Record<string, IrClass>,
|
|
179
|
+
next: Record<string, IrClass>,
|
|
208
180
|
out: SchemaChange[],
|
|
209
181
|
): void {
|
|
210
182
|
for (const name of sortedKeys(next)) {
|
|
@@ -223,12 +195,7 @@ function diffMembers(
|
|
|
223
195
|
}
|
|
224
196
|
}
|
|
225
197
|
|
|
226
|
-
function diffMemberBody(
|
|
227
|
-
name: string,
|
|
228
|
-
a: IrClass | IrInterface,
|
|
229
|
-
b: IrClass | IrInterface,
|
|
230
|
-
out: SchemaChange[],
|
|
231
|
-
): void {
|
|
198
|
+
function diffMemberBody(name: string, a: IrClass, b: IrClass, out: SchemaChange[]): void {
|
|
232
199
|
const pa = a.properties ?? {}
|
|
233
200
|
const pb = b.properties ?? {}
|
|
234
201
|
for (const p of sortedKeys(pb)) {
|
|
@@ -302,31 +269,27 @@ function diffMemberBody(
|
|
|
302
269
|
}
|
|
303
270
|
}
|
|
304
271
|
|
|
305
|
-
function propertyRequired(member: IrClass
|
|
272
|
+
function propertyRequired(member: IrClass, name: string): boolean {
|
|
306
273
|
return member.required ? member.required.includes(name) : !isOptional(member.properties?.[name])
|
|
307
274
|
}
|
|
308
275
|
|
|
309
|
-
function memberContract(member: IrClass
|
|
310
|
-
const cls = member as IrClass
|
|
311
|
-
const iface = member as IrInterface
|
|
276
|
+
function memberContract(member: IrClass): unknown {
|
|
312
277
|
return {
|
|
313
278
|
type: member.type,
|
|
314
279
|
origin: member.origin,
|
|
315
280
|
ref: member.ref,
|
|
316
|
-
|
|
317
|
-
extends: iface.extendsRefs ?? iface.extends,
|
|
318
|
-
implements: cls.implementsRefs ?? cls.implements,
|
|
281
|
+
extends: member.extendsRefs ?? member.extends,
|
|
319
282
|
endpoints: member.endpoints,
|
|
320
283
|
orientation: member.orientation,
|
|
321
284
|
constraints: member.constraints,
|
|
322
285
|
propertyMetadata: member.propertyMetadata,
|
|
323
286
|
data: member.data,
|
|
324
|
-
policies:
|
|
287
|
+
policies: member.policies,
|
|
325
288
|
}
|
|
326
289
|
}
|
|
327
290
|
|
|
328
|
-
function memberMetadata(member: IrClass
|
|
329
|
-
return { description: member.description, icon:
|
|
291
|
+
function memberMetadata(member: IrClass): unknown {
|
|
292
|
+
return { description: member.description, icon: member.icon }
|
|
330
293
|
}
|
|
331
294
|
|
|
332
295
|
function sortedKeys(value: Record<string, unknown>): string[] {
|
|
@@ -1,136 +1,41 @@
|
|
|
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 the composition entry → integrations). Canonical
|
|
5
|
-
* DomainSchema V1 roots are projected directly; legacy `D.$.ir` / serialize
|
|
6
|
-
* domains retain their existing fallback.
|
|
7
|
-
*
|
|
8
|
-
* bun extractor.ts <schemaIndexPath> <domainDir>
|
|
9
|
-
*
|
|
10
|
-
* A thrown error prints { ok:false } and exits 0 — the driver treats it as a
|
|
11
|
-
* render state, never a crash.
|
|
12
|
-
*/
|
|
1
|
+
/** Bun subprocess that imports only the authored Schema entry and its installed SDK. */
|
|
13
2
|
import {
|
|
14
3
|
admitCanonicalSchemaFromSdk,
|
|
15
4
|
findCanonicalDomainSchemaExport,
|
|
16
|
-
normalizeLegacySchemaIR,
|
|
17
5
|
projectCanonicalSchema,
|
|
18
6
|
} from './canonical-schema'
|
|
19
7
|
|
|
20
8
|
const schemaPath = process.argv[2]
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
async function main() {
|
|
24
|
-
if (!schemaPath) throw new Error('extractor: missing <
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
let sdk: Record<string, any> | null = null
|
|
30
|
-
const loadSdkSchema = async (): Promise<Record<string, any>> => {
|
|
31
|
-
if (sdk) return sdk
|
|
32
|
-
const loaded: Record<string, any> = await import(
|
|
33
|
-
Bun.resolveSync('@astrale-os/sdk/schema', domainDir)
|
|
34
|
-
)
|
|
35
|
-
sdk = loaded
|
|
36
|
-
return loaded
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const canonicalRoot = findCanonicalDomainSchemaExport(mod)
|
|
40
|
-
if (canonicalRoot) {
|
|
41
|
-
const domainSdk = await loadSdkSchema()
|
|
42
|
-
const admission = admitCanonicalSchemaFromSdk(domainSdk, canonicalRoot)
|
|
43
|
-
const projected = projectCanonicalSchema(admission.root, admission.closure)
|
|
44
|
-
process.stdout.write(
|
|
45
|
-
JSON.stringify({
|
|
46
|
-
ok: true,
|
|
47
|
-
ir: projected.ir,
|
|
48
|
-
root: admission.root,
|
|
49
|
-
schemaMode: admission.status === 'admitted' ? 'canonical-admitted' : 'canonical-preview',
|
|
50
|
-
revision: admission.revision,
|
|
51
|
-
importedInterfaces: projected.importedInterfaces,
|
|
52
|
-
}),
|
|
53
|
-
)
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Prefer the conventional `D` (compiled), but accept a compiled domain exported
|
|
58
|
-
// under ANY name — e.g. ai-gateway exports its `compileDomain(...)` result as
|
|
59
|
-
// `Gateway`, not `D`. A compiled domain is recognized by shape (`.$.ir`).
|
|
60
|
-
let ir: unknown = mod?.D?.$?.ir
|
|
61
|
-
if (!ir) {
|
|
62
|
-
for (const v of Object.values(mod)) {
|
|
63
|
-
const candidate = (v as any)?.$?.ir
|
|
64
|
-
if (candidate) {
|
|
65
|
-
ir = candidate
|
|
66
|
-
break
|
|
67
|
-
}
|
|
68
|
-
}
|
|
9
|
+
const projectRoot = process.argv[3] ?? process.cwd()
|
|
10
|
+
|
|
11
|
+
async function main(): Promise<void> {
|
|
12
|
+
if (!schemaPath) throw new Error('extractor: missing <schemaPath>')
|
|
13
|
+
const exports = (await import(schemaPath)) as Record<string, unknown>
|
|
14
|
+
const candidate = findCanonicalDomainSchemaExport(exports)
|
|
15
|
+
if (candidate === null) {
|
|
16
|
+
throw new Error('Schema entry exports no canonical V1 DomainSchema.')
|
|
69
17
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
(v) =>
|
|
77
|
-
typeof (v as any)?.domain === 'string' && !!(v as any)?.classes && !!(v as any)?.imports,
|
|
78
|
-
)
|
|
79
|
-
if (!schema) {
|
|
80
|
-
throw new Error(
|
|
81
|
-
'schema entry exports no compiled domain (a `compileDomain(...)` value with `.$.ir`, e.g. `D`) nor a raw `schema`',
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
const d = await loadSdkSchema()
|
|
85
|
-
if (typeof d.serialize !== 'function') throw new Error('kernel-dsl.serialize unavailable')
|
|
86
|
-
ir = d.serialize(schema)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Recover member bodies of IMPORTED interfaces (kernel mixins + cross-domain
|
|
90
|
-
// interfaces). `serialize()` emits them in `ir.imports` as name-only
|
|
91
|
-
// descriptors, so re-serialize each imported schema (KernelSchema, other
|
|
92
|
-
// domains) and collect its interface definitions. Best-effort: a single import
|
|
93
|
-
// failing to serialize must never break extraction of the primary IR.
|
|
94
|
-
const importedInterfaces: Record<string, unknown> = {}
|
|
95
|
-
const importSchemas: any[] = Array.isArray(mod?.schema?.imports) ? mod.schema.imports : []
|
|
96
|
-
if (importSchemas.length > 0) {
|
|
97
|
-
try {
|
|
98
|
-
const d = await loadSdkSchema()
|
|
99
|
-
if (typeof d.serialize === 'function') {
|
|
100
|
-
for (const imp of importSchemas) {
|
|
101
|
-
try {
|
|
102
|
-
const sub = d.serialize(imp)
|
|
103
|
-
for (const [name, def] of Object.entries(sub?.interfaces ?? {})) {
|
|
104
|
-
if (!(name in importedInterfaces)) importedInterfaces[name] = def
|
|
105
|
-
}
|
|
106
|
-
} catch {
|
|
107
|
-
/* skip this import — keep going */
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
} catch {
|
|
112
|
-
/* dsl unavailable — degrade gracefully (no imported-interface bodies) */
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
18
|
+
const sdk = (await import(Bun.resolveSync('@astrale-os/sdk/schema', projectRoot))) as Record<
|
|
19
|
+
string,
|
|
20
|
+
unknown
|
|
21
|
+
>
|
|
22
|
+
const admission = admitCanonicalSchemaFromSdk(sdk, candidate)
|
|
23
|
+
const projected = projectCanonicalSchema(admission.root, admission.closure)
|
|
116
24
|
process.stdout.write(
|
|
117
25
|
JSON.stringify({
|
|
118
26
|
ok: true,
|
|
119
|
-
ir:
|
|
120
|
-
root:
|
|
121
|
-
schemaMode: '
|
|
122
|
-
revision:
|
|
123
|
-
importedInterfaces,
|
|
27
|
+
ir: projected.ir,
|
|
28
|
+
root: admission.root,
|
|
29
|
+
schemaMode: admission.status === 'admitted' ? 'canonical-admitted' : 'canonical-preview',
|
|
30
|
+
revision: admission.revision,
|
|
124
31
|
}),
|
|
125
32
|
)
|
|
126
33
|
}
|
|
127
34
|
|
|
128
|
-
main().catch((
|
|
35
|
+
main().catch((cause: unknown) => {
|
|
36
|
+
const error = cause instanceof Error ? cause : new Error(String(cause))
|
|
129
37
|
process.stdout.write(
|
|
130
|
-
JSON.stringify({
|
|
131
|
-
ok: false,
|
|
132
|
-
error: { message: String(err?.message ?? err), stack: String(err?.stack ?? '') },
|
|
133
|
-
}),
|
|
38
|
+
JSON.stringify({ ok: false, error: { message: error.message, stack: error.stack ?? '' } }),
|
|
134
39
|
)
|
|
135
40
|
process.exit(0)
|
|
136
41
|
})
|