@astrale-os/cli 1.0.0-beta.3 → 1.0.0-beta.31
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 +84 -6
- package/dist/astrale.js +57586 -60753
- package/dist/public/connect-core.js +2158 -30706
- package/dist/public/keys/index.js +1016 -29541
- package/dist/public/paths/index.js +370 -28654
- package/dist/types/admin/contract.d.ts +26 -0
- package/dist/types/admin/instance/client.d.ts +20 -0
- package/dist/types/admin/instance/index.d.ts +2 -0
- package/dist/types/admin/instance/model.d.ts +6 -10
- package/dist/types/connection/auth.d.ts +3 -0
- package/dist/types/connection/call.d.ts +3 -0
- package/dist/types/connection/command.d.ts +27 -0
- package/dist/types/connection/credential.d.ts +14 -0
- package/dist/types/connection/errors.d.ts +1 -0
- package/dist/types/connection/exchange.d.ts +9 -0
- package/dist/types/connection/failure/classify.d.ts +2 -0
- package/dist/types/connection/failure/index.d.ts +5 -0
- package/dist/types/connection/failure/model.d.ts +25 -0
- package/dist/types/connection/failure/render.d.ts +3 -0
- package/dist/types/connection/index.d.ts +8 -0
- package/dist/types/connection/reasons.d.ts +37 -0
- package/dist/types/connection/self.d.ts +37 -0
- package/dist/types/connection/session.d.ts +31 -0
- package/dist/types/connection/target.d.ts +38 -0
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/lib/admin-instance.d.ts +17 -0
- package/dist/types/lib/admin-target.d.ts +11 -36
- package/dist/types/lib/config.d.ts +13 -59
- package/dist/types/lib/failure-debug.d.ts +1 -0
- package/dist/types/lib/idp.d.ts +25 -173
- package/dist/types/lib/instance-target.d.ts +1 -1
- package/dist/types/lib/instance.d.ts +30 -88
- package/dist/types/lib/log.d.ts +5 -3
- package/dist/types/lib/output.d.ts +1 -1
- package/dist/types/lib/proc.d.ts +43 -0
- package/dist/types/lib/self.d.ts +9 -0
- package/dist/types/lib/update.d.ts +109 -0
- package/dist/types/lib/validation.d.ts +4 -1
- package/dist/types/state/exchange-credentials.d.ts +6 -2
- package/dist/types/state/files.d.ts +2 -0
- package/dist/types/state/index.d.ts +3 -2
- package/dist/types/state/paths.d.ts +2 -0
- package/dist/types/state/session-routes.d.ts +10 -0
- package/package.json +16 -19
- package/src/__tests__/fixtures/publication.ts +20 -0
- package/src/admin/.spec/architecture.md +12 -5
- package/src/admin/__tests__/fixture.ts +25 -0
- package/src/admin/catalog/.spec/api.d.ts +1 -3
- package/src/admin/catalog/.spec/architecture.md +5 -4
- package/src/admin/catalog/__tests__/client.test.ts +143 -69
- package/src/admin/catalog/client.ts +40 -54
- package/src/admin/catalog/model.ts +3 -4
- package/src/admin/contract.ts +47 -0
- 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 +5 -9
- package/src/admin/instance/.spec/architecture.md +7 -7
- package/src/admin/instance/__tests__/client.test.ts +157 -175
- package/src/admin/instance/client.ts +39 -128
- package/src/admin/instance/index.ts +1 -2
- package/src/admin/instance/model.ts +12 -18
- package/src/commands/__tests__/admin-instance.test.ts +11 -8
- package/src/commands/__tests__/call-describe.test.ts +46 -33
- package/src/commands/__tests__/call.test.ts +34 -0
- package/src/commands/__tests__/domain-install-operation.test.ts +30 -22
- 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-direct.test.ts +115 -8
- package/src/commands/__tests__/install-identity-override.test.ts +6 -17
- package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
- package/src/commands/__tests__/instance-status.test.ts +139 -0
- package/src/commands/__tests__/introspect-parse.test.ts +80 -1
- package/src/commands/__tests__/logs.test.ts +250 -2
- package/src/commands/__tests__/read-commands.test.ts +119 -11
- package/src/commands/__tests__/token-ttl.test.ts +49 -4
- package/src/commands/__tests__/update.test.ts +25 -3
- package/src/commands/__tests__/view.test.ts +50 -2
- package/src/commands/auth/logout.ts +2 -1
- package/src/commands/browser.ts +29 -0
- package/src/commands/call-describe.ts +60 -68
- package/src/commands/call.ts +71 -59
- package/src/commands/domain/install.ts +73 -46
- package/src/commands/domain/list.ts +1 -1
- package/src/commands/domain/publish.ts +14 -11
- package/src/commands/domain/uninstall.ts +2 -2
- package/src/commands/get.ts +15 -16
- package/src/commands/identity/__tests__/register.test.ts +3 -3
- package/src/commands/identity/register.ts +8 -8
- package/src/commands/instance/create.ts +8 -16
- package/src/commands/instance/delete.ts +12 -9
- package/src/commands/instance/list.ts +2 -2
- package/src/commands/instance/status.ts +66 -20
- package/src/commands/instance/use.ts +16 -12
- package/src/commands/introspect.ts +53 -41
- package/src/commands/logs.ts +123 -36
- package/src/commands/mutate.ts +6 -5
- package/src/commands/query.ts +39 -36
- package/src/commands/session/analyze.ts +26 -4
- package/src/commands/token.ts +42 -27
- package/src/commands/ui/__tests__/commands.test.ts +152 -0
- package/src/commands/ui/add.ts +51 -0
- package/src/commands/ui/doctor.ts +21 -0
- package/src/commands/ui/init.ts +38 -0
- package/src/commands/ui/list.ts +26 -0
- package/src/commands/ui/preset-apply.ts +19 -0
- package/src/commands/ui/preset-list.ts +12 -0
- package/src/commands/ui/shared.ts +25 -0
- package/src/commands/update.ts +90 -48
- package/src/commands/view.ts +82 -37
- package/src/connection/.spec/api.d.ts +7 -8
- package/src/connection/.spec/architecture.md +14 -5
- 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__/auth.test.ts +1 -0
- package/src/connection/__tests__/credential.test.ts +21 -1
- package/src/connection/__tests__/errors.test.ts +27 -20
- package/src/connection/__tests__/exchange.test.ts +64 -11
- 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 +8 -4
- package/src/connection/__tests__/target.test.ts +2 -0
- package/src/connection/auth.ts +13 -0
- 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 +110 -61
- package/src/connection/failure/classify.ts +110 -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 +27 -9
- package/src/errors.ts +3 -2
- package/src/graph/.spec/api.d.ts +13 -6
- package/src/graph/.spec/laws/documents.ts +7 -7
- package/src/graph/.spec/layout.ts +9 -1
- package/src/graph/__tests__/mutation.test.ts +2 -2
- package/src/graph/__tests__/query.test.ts +35 -9
- package/src/graph/class.ts +30 -0
- package/src/graph/index.ts +1 -0
- package/src/graph/query.ts +27 -40
- package/src/identity/.spec/api.d.ts +2 -2
- package/src/identity/__tests__/fixtures/registry-journey.ts +13 -1
- package/src/identity/__tests__/registration.test.ts +1 -1
- package/src/identity/__tests__/registry.test.ts +4 -0
- package/src/identity/registration.ts +3 -3
- package/src/identity/registry.ts +2 -0
- package/src/keys/__tests__/keys.test.ts +4 -0
- package/src/keys/credential.ts +1 -0
- package/src/lib/__tests__/admin-target.test.ts +12 -0
- package/src/lib/__tests__/binary.test.ts +16 -1
- package/src/lib/__tests__/browser-retention.test.ts +212 -0
- package/src/lib/__tests__/command-dx.test.ts +1 -1
- package/src/lib/__tests__/config.test.ts +27 -0
- package/src/lib/__tests__/domain-publication.test.ts +10 -16
- package/src/lib/__tests__/idp.test.ts +34 -4
- package/src/lib/__tests__/instance-candidates.test.ts +1 -3
- package/src/lib/__tests__/instance-target.test.ts +7 -39
- package/src/lib/__tests__/log-errors.test.ts +64 -0
- package/src/lib/__tests__/skills.test.ts +834 -0
- package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
- package/src/lib/__tests__/update.test.ts +264 -11
- package/src/lib/__tests__/view-assets.test.ts +25 -0
- package/src/lib/__tests__/view-external-open-intent.test.ts +150 -0
- package/src/lib/__tests__/view-external-open-origins.test.ts +27 -0
- package/src/lib/__tests__/view-open-intent.test.ts +0 -2
- package/src/lib/__tests__/view-server.test.ts +26 -3
- package/src/lib/__tests__/view-session.test.ts +2 -1
- package/src/lib/admin-instance.ts +14 -8
- package/src/lib/admin-target.ts +21 -2
- package/src/lib/binary.ts +22 -5
- package/src/lib/browser-retention.ts +210 -0
- package/src/lib/command-dx.ts +9 -9
- package/src/lib/config.ts +12 -1
- package/src/lib/domain-publication.ts +9 -7
- package/src/lib/failure-debug.ts +26 -0
- package/src/lib/idp.ts +34 -3
- package/src/lib/instance-candidates.ts +2 -2
- package/src/lib/instance-target.ts +3 -14
- package/src/lib/instance.ts +16 -11
- package/src/lib/log.ts +16 -9
- package/src/lib/output.ts +1 -1
- package/src/lib/proc.ts +7 -2
- package/src/lib/provision-instance.ts +34 -57
- package/src/lib/skills/lock.ts +117 -0
- package/src/lib/skills/sync.ts +878 -0
- package/src/lib/skills.ts +1 -52
- package/src/lib/update.ts +298 -45
- package/src/lib/validation.ts +2 -2
- package/src/lib/view/assets.ts +11 -2
- package/src/lib/view/external-open-intent.ts +41 -0
- package/src/lib/view/external-open-origins.ts +37 -0
- package/src/lib/view/host-capabilities.ts +17 -0
- package/src/lib/view/resolve.ts +1 -1
- package/src/lib/view/server.ts +18 -3
- package/src/lib/view/session.ts +2 -0
- package/src/program/.spec/api.d.ts +1 -0
- package/src/program/__tests__/program.test.ts +201 -7
- package/src/program/argv.ts +14 -0
- package/src/program/build.ts +26 -4
- package/src/program/command.ts +1 -0
- package/src/program/index.ts +1 -0
- package/src/program/registry.ts +2 -1
- package/src/setup/__tests__/instance-step.test.ts +27 -10
- package/src/setup/steps/instance.ts +22 -15
- package/src/setup/steps/skills.ts +40 -38
- package/src/state/.spec/api.d.ts +21 -2
- package/src/state/.spec/architecture.md +18 -4
- package/src/state/.spec/layout.ts +1 -0
- package/src/state/__tests__/exchange-credentials.test.ts +88 -42
- package/src/state/__tests__/files.test.ts +24 -1
- package/src/state/__tests__/fixtures/session-route-process.ts +93 -0
- package/src/state/__tests__/paths.test.ts +1 -0
- package/src/state/__tests__/session-routes.test.ts +138 -0
- package/src/state/exchange-credentials.ts +22 -9
- package/src/state/files.ts +41 -0
- package/src/state/index.ts +3 -1
- package/src/state/paths.ts +3 -0
- package/src/state/session-routes.ts +34 -0
- package/src/telemetry/__tests__/analyze-log.test.ts +38 -0
- package/src/telemetry/__tests__/recorder.test.ts +1 -0
- package/src/telemetry/__tests__/retention.test.ts +267 -0
- package/src/telemetry/__tests__/settings.test.ts +102 -0
- package/src/telemetry/__tests__/store-scan.test.ts +128 -0
- package/src/telemetry/__tests__/trigger.test.ts +33 -4
- package/src/telemetry/analyze.ts +24 -2
- package/src/telemetry/recorder.ts +15 -4
- package/src/telemetry/retention.ts +176 -0
- package/src/telemetry/session.ts +18 -12
- package/src/telemetry/settings.ts +64 -11
- package/src/telemetry/store.ts +92 -9
- package/src/telemetry/trigger.ts +16 -28
- package/src/ui/.spec/api.d.ts +14 -0
- package/src/ui/.spec/architecture.md +14 -0
- package/src/ui/.spec/laws.ts +50 -0
- package/src/ui/.spec/layout.ts +16 -0
- package/src/ui/__tests__/ui.test.ts +1742 -0
- package/src/ui/index.ts +13 -0
- package/src/ui/lock.ts +89 -0
- package/src/ui/model.ts +83 -0
- package/src/ui/operations.ts +1044 -0
- package/src/ui/project.ts +333 -0
- package/src/ui/release.ts +398 -0
- package/src/ui/runner.ts +18 -0
- package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
- package/studio/client/dist/assets/index-BFVFs_8x.js +81 -0
- package/studio/client/dist/assets/index-DuB9iUdu.css +2 -0
- package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/studio/client/dist/assets/schema-studio--a0kX3QU.css +1 -0
- package/studio/client/dist/assets/schema-studio-DH6oEWME.js +8 -0
- package/studio/client/dist/index.html +4 -3
- package/studio/package.json +8 -14
- 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/harness/gateway/token.test.ts +1 -1
- package/studio/server/agent/harness/gateway/token.ts +3 -3
- package/studio/server/agent/prompts/anchors.test.ts +41 -32
- package/studio/server/agent/prompts/anchors.ts +23 -51
- package/studio/server/agent/prompts/system.test.ts +4 -4
- package/studio/server/agent/prompts/system.ts +5 -5
- package/studio/server/agent/routes.test.ts +1 -1
- package/studio/server/agent/run/coordinator.test.ts +1 -1
- package/studio/server/agent/run/preparation.ts +1 -1
- package/studio/server/api/canvas.ts +0 -1
- package/studio/server/api/context.ts +1 -1
- package/studio/server/api/deployment.ts +1 -1
- package/studio/server/api/views.ts +2 -2
- package/studio/server/api/workspace.ts +1 -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 +24 -18
- package/studio/server/cache.ts +10 -54
- package/studio/server/cli-consumers.test.ts +32 -4
- package/studio/server/cli.test.ts +2 -2
- package/studio/server/domain.test.ts +50 -68
- package/studio/server/domain.ts +82 -63
- package/studio/server/handoff/copy.ts +2 -2
- 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 +10 -16
- package/studio/server/introspect/anatomy-extras.test.ts +29 -56
- 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 +155 -424
- package/studio/server/introspect/canonical-schema.ts +248 -601
- package/studio/server/introspect/core.ts +14 -22
- package/studio/server/introspect/diff.test.ts +21 -9
- package/studio/server/introspect/diff.ts +19 -64
- package/studio/server/introspect/extractor.ts +23 -122
- package/studio/server/introspect/overlay-tsmorph.test.ts +116 -241
- package/studio/server/introspect/overlay-tsmorph.ts +0 -1
- package/studio/server/introspect/overlay.ts +3 -51
- package/studio/server/introspect/revision.test.ts +24 -28
- package/studio/server/introspect/revision.ts +11 -22
- package/studio/server/introspect/runtime.test.ts +77 -195
- package/studio/server/introspect/runtime.ts +5 -67
- package/studio/server/introspect/schema-ir-json.test.ts +81 -0
- package/studio/server/introspect/schema-ir-json.ts +39 -69
- 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/lifecycle.ts +4 -1
- package/studio/server/state/baseline.test.ts +14 -9
- package/studio/server/state/baseline.ts +3 -5
- package/studio/server/state/documents.test.ts +69 -0
- package/studio/server/state/documents.ts +57 -10
- package/studio/server/state/visibility.ts +1 -5
- package/studio/server/views/model.ts +3 -3
- package/studio/server/views/target.test.ts +18 -76
- package/studio/server/views/target.ts +25 -51
- package/studio/server/watch.test.ts +11 -11
- package/studio/server/watch.ts +8 -4
- package/studio/server/workspace/updates.ts +23 -1
- package/studio/server/workspace-watch.ts +2 -2
- package/studio/shared/contracts/runtime.ts +4 -0
- package/studio/shared/contracts/schema.ts +44 -131
- package/studio/shared/contracts/surface.test.ts +15 -17
- package/studio/shared/contracts/workspace.ts +5 -11
- package/studio/shared/schema/identity.test.ts +20 -44
- package/studio/shared/schema/identity.ts +9 -24
- package/studio/tsconfig.json +2 -1
- package/tsconfig.json +1 -1
- package/viewer/dist/index.html +21 -0
- package/viewer/dist/main.js +41 -62
- package/.check-workspace.cjs +0 -40
- package/src/admin/binding.ts +0 -168
- package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
- package/studio/client/dist/assets/elk-api-lwhFo7vB.js +0 -1
- 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/client/dist/assets/index-ChOr3yP0.css +0 -1
- package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
- package/studio/server/introspect/core-extractor.ts +0 -139
- package/studio/server/introspect/overlay.test.ts +0 -72
- package/studio/server/introspect/source-overlay/annotations.ts +0 -14
|
@@ -22,10 +22,7 @@ const KERNEL_TOKENS: KernelToken[] = [
|
|
|
22
22
|
{ token: 'auth.check' },
|
|
23
23
|
{ token: 'graph.tree' },
|
|
24
24
|
{ token: 'graph.node' },
|
|
25
|
-
{ token: 'revokePerm', label: 'revokePerm (legacy)' },
|
|
26
|
-
{ token: 'checkPerm', label: 'checkPerm (legacy)' },
|
|
27
25
|
{ token: 'graph.get' },
|
|
28
|
-
{ token: 'grantPerm', label: 'grantPerm (legacy)' },
|
|
29
26
|
]
|
|
30
27
|
|
|
31
28
|
/** Scan handler file text for kernel-op tokens. */
|
|
@@ -58,18 +58,14 @@ function cleanComment(raw: string): string {
|
|
|
58
58
|
return lines.join(' ').replace(/\s+/g, ' ').trim()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const DECL_HELPERS: Record<string, 'node' | '
|
|
61
|
+
const DECL_HELPERS: Record<string, 'node' | 'edge' | 'function'> = {
|
|
62
62
|
nodeClass: 'node',
|
|
63
|
-
nodeInterface: 'interface',
|
|
64
63
|
edgeClass: 'edge',
|
|
65
64
|
fn: 'function',
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
/** Recognize
|
|
69
|
-
|
|
70
|
-
function declarationHelper(
|
|
71
|
-
call: CallExpression,
|
|
72
|
-
): 'node' | 'interface' | 'edge' | 'function' | undefined {
|
|
67
|
+
/** Recognize current Class and Function declaration helpers. */
|
|
68
|
+
function declarationHelper(call: CallExpression): 'node' | 'edge' | 'function' | undefined {
|
|
73
69
|
const direct = calleeName(call)
|
|
74
70
|
if (direct && direct in DECL_HELPERS) return DECL_HELPERS[direct]
|
|
75
71
|
const expression = call.getExpression()
|
|
@@ -85,22 +81,17 @@ function declarationHelper(
|
|
|
85
81
|
|
|
86
82
|
/**
|
|
87
83
|
* A schema member's true NAME + section, resolved from the `defineSchema` map.
|
|
88
|
-
*
|
|
89
|
-
* member is named by the KEY it is registered under, not by its variable — and a
|
|
90
|
-
* domain may register a class and an interface under the SAME name (the
|
|
91
|
-
* intentional same-name pattern: the `iUser` interface alongside the `User`
|
|
92
|
-
* class). So the map is the sole authority for both the anchor name and the
|
|
93
|
-
* interface-vs-class distinction; the variable identifier alone tells us neither.
|
|
84
|
+
* Declaration helpers carry no name: the `defineSchema` key is authoritative.
|
|
94
85
|
*/
|
|
95
86
|
interface MemberName {
|
|
96
87
|
schemaName: string
|
|
97
|
-
section: '
|
|
88
|
+
section: 'class' | 'function'
|
|
98
89
|
}
|
|
99
90
|
|
|
100
91
|
interface MemberNameMap {
|
|
101
92
|
/** Exact declaration initializer, robust to imported/local aliases. */
|
|
102
93
|
byValue: Map<string, MemberName>
|
|
103
|
-
/**
|
|
94
|
+
/** Fallback when a symbol cannot be resolved. */
|
|
104
95
|
byIdentifier: Map<string, MemberName>
|
|
105
96
|
}
|
|
106
97
|
|
|
@@ -132,7 +123,6 @@ function buildMemberNameMap(files: SourceFile[]): MemberNameMap {
|
|
|
132
123
|
const input = call.getArguments()[1]
|
|
133
124
|
const cfg = input ? resolveObjectLiteral(input) : undefined
|
|
134
125
|
if (!cfg) continue
|
|
135
|
-
collectSchemaSection(map, cfg, 'interfaces', 'interface')
|
|
136
126
|
collectSchemaSection(map, cfg, 'classes', 'class')
|
|
137
127
|
collectSchemaSection(map, cfg, 'functions', 'function')
|
|
138
128
|
}
|
|
@@ -145,8 +135,8 @@ function buildMemberNameMap(files: SourceFile[]): MemberNameMap {
|
|
|
145
135
|
function collectSchemaSection(
|
|
146
136
|
map: MemberNameMap,
|
|
147
137
|
cfg: Node,
|
|
148
|
-
prop: '
|
|
149
|
-
section: '
|
|
138
|
+
prop: 'classes' | 'functions',
|
|
139
|
+
section: 'class' | 'function',
|
|
150
140
|
): void {
|
|
151
141
|
const obj = getObjectProp(cfg, prop)
|
|
152
142
|
if (!obj) return
|
|
@@ -163,24 +153,18 @@ function collectSchemaSection(
|
|
|
163
153
|
}
|
|
164
154
|
|
|
165
155
|
/**
|
|
166
|
-
* The anchor namespace
|
|
167
|
-
*
|
|
168
|
-
* `nodeClass` whose name collides with a same-named interface must still anchor
|
|
169
|
-
* as a class. Within the class section, an `edgeClass` (or an IR edge type)
|
|
170
|
-
* anchors as 'edge'. Falls back to the declaration helper when the member isn't
|
|
171
|
-
* in a parseable `defineSchema` map (e.g. an imported kernel member).
|
|
156
|
+
* The anchor namespace for a declared member. The Class section plus helper/IR
|
|
157
|
+
* kind distinguishes Node and Edge Classes.
|
|
172
158
|
*/
|
|
173
159
|
function resolveMemberKind(
|
|
174
160
|
ir: SchemaIR | null,
|
|
175
161
|
name: string,
|
|
176
|
-
section: '
|
|
177
|
-
helperKind: 'node' | '
|
|
178
|
-
): 'class' | '
|
|
162
|
+
section: 'class' | 'function' | undefined,
|
|
163
|
+
helperKind: 'node' | 'edge' | 'function',
|
|
164
|
+
): 'class' | 'edge' | 'function' {
|
|
179
165
|
if (section === 'function' || helperKind === 'function') return 'function'
|
|
180
|
-
if (section === 'interface') return 'interface'
|
|
181
166
|
const isEdge = helperKind === 'edge' || ir?.classes?.[name]?.type === 'edge'
|
|
182
167
|
if (section === 'class') return isEdge ? 'edge' : 'class'
|
|
183
|
-
if (helperKind === 'interface') return 'interface'
|
|
184
168
|
return isEdge ? 'edge' : 'class'
|
|
185
169
|
}
|
|
186
170
|
|
|
@@ -206,9 +190,7 @@ export function buildSourceSpans(args: {
|
|
|
206
190
|
const spans: Record<string, SourceSpan> = {}
|
|
207
191
|
|
|
208
192
|
const sourceFiles = files.map((f) => project.getSourceFile(f)).filter((f): f is SourceFile => !!f)
|
|
209
|
-
// The
|
|
210
|
-
// interface-vs-class kind, so an aliased interface (`iUser`→`User`) and a class
|
|
211
|
-
// sharing its name (`User`) each anchor correctly instead of colliding.
|
|
193
|
+
// The Domain's `defineSchema` map is authoritative for each member's name.
|
|
212
194
|
const memberNames = buildMemberNameMap(sourceFiles)
|
|
213
195
|
|
|
214
196
|
for (const sf of sourceFiles) {
|
|
@@ -287,7 +269,7 @@ function collectPropsAndMethods(
|
|
|
287
269
|
}
|
|
288
270
|
}
|
|
289
271
|
|
|
290
|
-
/** Record edge endpoint spans
|
|
272
|
+
/** Record edge endpoint and property spans from current directed/undirected forms. */
|
|
291
273
|
function collectEdge(
|
|
292
274
|
spans: Record<string, SourceSpan>,
|
|
293
275
|
name: string,
|
|
@@ -331,18 +313,6 @@ function collectEdge(
|
|
|
331
313
|
if (!role) continue
|
|
332
314
|
spans[`edge.${name}.endpoint.${role}`] = makeSpan(domainRoot, fileRel, ep, ep)
|
|
333
315
|
}
|
|
334
|
-
// Legacy edge props live in the third (config) arg.
|
|
335
|
-
const cfgArg = argsList[2]
|
|
336
|
-
if (cfgArg && Node.isObjectLiteralExpression(cfgArg)) {
|
|
337
|
-
const propsObj = getObjectProp(cfgArg, 'properties') ?? getObjectProp(cfgArg, 'props')
|
|
338
|
-
if (propsObj) {
|
|
339
|
-
for (const p of propsObj.getProperties()) {
|
|
340
|
-
const pName = propertyKey(p)
|
|
341
|
-
if (!pName) continue
|
|
342
|
-
spans[`edge.${name}.property.${pName}`] = makeSpan(domainRoot, fileRel, p, p)
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
316
|
}
|
|
347
317
|
|
|
348
318
|
/** The object-literal value of a named property, if it is itself an object. */
|
|
@@ -9,6 +9,7 @@ import type { DomainHandle } from './domain'
|
|
|
9
9
|
*/
|
|
10
10
|
import { getBundle } from './cache'
|
|
11
11
|
import { captureBaseline, hashAnatomyFiles, loadBaseline } from './state/baseline'
|
|
12
|
+
import { migrateDocuments } from './state/documents'
|
|
12
13
|
import { initDotDir } from './state/store'
|
|
13
14
|
import { watchDomain } from './watch'
|
|
14
15
|
|
|
@@ -22,6 +23,8 @@ export interface BootedDomain {
|
|
|
22
23
|
/** Initialize + start watching one domain. Returns its origin + a stop handle. */
|
|
23
24
|
export async function bootDomain(handle: DomainHandle): Promise<BootedDomain> {
|
|
24
25
|
initDotDir(handle.root)
|
|
26
|
+
// one-shot: uuid-named documents become readable file names under context/docs
|
|
27
|
+
migrateDocuments(handle.root)
|
|
25
28
|
const bundle = await getBundle(handle.id)
|
|
26
29
|
if (!loadBaseline(handle.root))
|
|
27
30
|
captureBaseline(
|
|
@@ -35,7 +38,7 @@ export async function bootDomain(handle: DomainHandle): Promise<BootedDomain> {
|
|
|
35
38
|
)
|
|
36
39
|
const stop = watchDomain(handle)
|
|
37
40
|
return {
|
|
38
|
-
origin: bundle?.
|
|
41
|
+
origin: bundle?.ir?.domain ?? handle.origin ?? handle.id,
|
|
39
42
|
depsInstalled: !!bundle?.depsInstalled,
|
|
40
43
|
stop,
|
|
41
44
|
}
|
|
@@ -21,13 +21,13 @@ afterEach(() => {
|
|
|
21
21
|
while (roots.length) rmSync(roots.pop()!, { recursive: true, force: true })
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
-
test('hashes current
|
|
24
|
+
test('hashes current Application and vertical authoring files', () => {
|
|
25
25
|
const root = mkdtempSync(join(tmpdir(), 'studio-current-baseline-'))
|
|
26
26
|
roots.push(root)
|
|
27
27
|
for (const dir of [
|
|
28
28
|
'schema',
|
|
29
29
|
'actions/risk',
|
|
30
|
-
'
|
|
30
|
+
'providers/mail',
|
|
31
31
|
'queries/risk',
|
|
32
32
|
'ui/risk',
|
|
33
33
|
'views/risk',
|
|
@@ -36,9 +36,10 @@ test('hashes current implementation and semantic layer files alongside legacy an
|
|
|
36
36
|
}
|
|
37
37
|
for (const file of [
|
|
38
38
|
'schema/index.ts',
|
|
39
|
-
'
|
|
39
|
+
'application.ts',
|
|
40
|
+
'runtime.ts',
|
|
40
41
|
'actions/risk/index.ts',
|
|
41
|
-
'
|
|
42
|
+
'providers/mail/index.ts',
|
|
42
43
|
'queries/risk/index.ts',
|
|
43
44
|
'ui/risk/screen.tsx',
|
|
44
45
|
'views/risk/index.ts',
|
|
@@ -50,10 +51,11 @@ test('hashes current implementation and semantic layer files alongside legacy an
|
|
|
50
51
|
|
|
51
52
|
expect(Object.keys(hashAnatomyFiles(root, 'schema')).sort()).toEqual([
|
|
52
53
|
'actions/risk/index.ts',
|
|
53
|
-
'
|
|
54
|
-
'implementation.ts',
|
|
54
|
+
'application.ts',
|
|
55
55
|
'package.json',
|
|
56
|
+
'providers/mail/index.ts',
|
|
56
57
|
'queries/risk/index.ts',
|
|
58
|
+
'runtime.ts',
|
|
57
59
|
'schema/index.ts',
|
|
58
60
|
'ui/risk/screen.tsx',
|
|
59
61
|
'views/risk/index.ts',
|
|
@@ -64,11 +66,14 @@ const schema = (domain: string): SchemaIR => ({
|
|
|
64
66
|
format: 'astrale.dsl',
|
|
65
67
|
version: 'v1',
|
|
66
68
|
domain,
|
|
67
|
-
types: {},
|
|
68
|
-
interfaces: {},
|
|
69
69
|
classes: {},
|
|
70
|
-
|
|
70
|
+
importsByKey: {},
|
|
71
|
+
importedClassesByKey: {},
|
|
71
72
|
functions: {},
|
|
73
|
+
views: {},
|
|
74
|
+
policies: {},
|
|
75
|
+
dependencies: [],
|
|
76
|
+
core: {},
|
|
72
77
|
})
|
|
73
78
|
|
|
74
79
|
const canonicalRoot = {
|
|
@@ -45,12 +45,10 @@ const SKIP_DIRS = new Set(['node_modules', '.dist', 'dist', '.domain-studio', '.
|
|
|
45
45
|
export const ANATOMY_GLOBS = {
|
|
46
46
|
dirs: [
|
|
47
47
|
'actions',
|
|
48
|
-
'capabilities',
|
|
49
48
|
'core',
|
|
49
|
+
'providers',
|
|
50
50
|
'runtime',
|
|
51
51
|
'views',
|
|
52
|
-
'functions',
|
|
53
|
-
'handlers',
|
|
54
52
|
'integrations',
|
|
55
53
|
'migrations',
|
|
56
54
|
'mutations',
|
|
@@ -64,8 +62,8 @@ export const ANATOMY_GLOBS = {
|
|
|
64
62
|
'client/src',
|
|
65
63
|
],
|
|
66
64
|
files: [
|
|
67
|
-
'
|
|
68
|
-
'
|
|
65
|
+
'application.ts',
|
|
66
|
+
'runtime.ts',
|
|
69
67
|
'index.ts',
|
|
70
68
|
'core.ts',
|
|
71
69
|
'deps.ts',
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { afterEach, expect, test } from 'bun:test'
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
import { addDocument, listDocuments, migrateDocuments, readDocument } from './documents'
|
|
7
|
+
import { statePath, writeJson, writeStateBuffer } from './store'
|
|
8
|
+
|
|
9
|
+
const roots: string[] = []
|
|
10
|
+
|
|
11
|
+
function root(): string {
|
|
12
|
+
const created = mkdtempSync(join(tmpdir(), 'studio-documents-'))
|
|
13
|
+
roots.push(created)
|
|
14
|
+
return created
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
while (roots.length) rmSync(roots.pop()!, { recursive: true, force: true })
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const bytes = (text: string) => new TextEncoder().encode(text)
|
|
22
|
+
|
|
23
|
+
test('a document is stored under a readable name, not its id', () => {
|
|
24
|
+
const domain = root()
|
|
25
|
+
const meta = addDocument(domain, 'Pricing Decisions.MD', 'text/markdown', bytes('# pricing'))
|
|
26
|
+
|
|
27
|
+
expect(meta.stored).toBe('context/docs/pricing-decisions.md')
|
|
28
|
+
expect(readFileSync(statePath(domain, meta.stored), 'utf8')).toBe('# pricing')
|
|
29
|
+
expect(readDocument(domain, meta.id)?.meta.name).toBe('Pricing Decisions.MD')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('same-named documents never overwrite each other', () => {
|
|
33
|
+
const domain = root()
|
|
34
|
+
const first = addDocument(domain, 'notes.md', 'text/markdown', bytes('first'))
|
|
35
|
+
const second = addDocument(domain, 'notes.md', 'text/markdown', bytes('second'))
|
|
36
|
+
|
|
37
|
+
expect([first.stored, second.stored]).toEqual([
|
|
38
|
+
'context/docs/notes.md',
|
|
39
|
+
'context/docs/notes-2.md',
|
|
40
|
+
])
|
|
41
|
+
expect(readFileSync(statePath(domain, first.stored), 'utf8')).toBe('first')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('uuid-named documents are migrated in place, once', () => {
|
|
45
|
+
const domain = root()
|
|
46
|
+
const legacy = 'context/documents/2b0d9d7e-1f2a-4a10-9f0c-1a2b3c4d5e6f.md'
|
|
47
|
+
writeStateBuffer(domain, legacy, bytes('legacy body'))
|
|
48
|
+
writeJson(domain, 'context/documents/index.json', [
|
|
49
|
+
{
|
|
50
|
+
id: '2b0d9d7e-1f2a-4a10-9f0c-1a2b3c4d5e6f',
|
|
51
|
+
name: 'Meeting notes.md',
|
|
52
|
+
type: 'text/markdown',
|
|
53
|
+
size: 11,
|
|
54
|
+
addedAt: new Date(0).toISOString(),
|
|
55
|
+
stored: legacy,
|
|
56
|
+
},
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
migrateDocuments(domain)
|
|
60
|
+
const [migrated] = listDocuments(domain)
|
|
61
|
+
|
|
62
|
+
expect(migrated?.stored).toBe('context/docs/meeting-notes.md')
|
|
63
|
+
expect(readFileSync(statePath(domain, migrated!.stored), 'utf8')).toBe('legacy body')
|
|
64
|
+
expect(existsSync(statePath(domain, legacy))).toBe(false)
|
|
65
|
+
|
|
66
|
+
// idempotent: a second boot leaves the already-migrated store alone
|
|
67
|
+
migrateDocuments(domain)
|
|
68
|
+
expect(listDocuments(domain)[0]?.stored).toBe('context/docs/meeting-notes.md')
|
|
69
|
+
})
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* documents.ts — context DOCUMENTS the user drops in for the AI agent. Files
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* documents.ts — context DOCUMENTS the user drops in for the AI agent. Files live
|
|
3
|
+
* under `.domain-studio/context/docs/`, named after the document (not its id), so
|
|
4
|
+
* the folder is readable by a human and by the agent that is handed its path.
|
|
5
|
+
* They travel with the domain and are part of the agent handoff context.
|
|
5
6
|
*/
|
|
6
7
|
import { randomUUID } from 'node:crypto'
|
|
7
|
-
import { existsSync } from 'node:fs'
|
|
8
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
8
9
|
import { extname } from 'node:path'
|
|
9
10
|
|
|
10
11
|
import type { DocMeta } from '../../shared/types'
|
|
@@ -13,7 +14,54 @@ import { asFiniteNumber, asJsonRecord, asString } from '../json'
|
|
|
13
14
|
import { readJson, removeState, statePath, writeJson, writeStateBuffer } from './store'
|
|
14
15
|
|
|
15
16
|
const INDEX = 'context/documents/index.json'
|
|
16
|
-
const
|
|
17
|
+
const DIR = 'context/docs'
|
|
18
|
+
/** Where documents lived before they were named: `context/documents/<uuid>.<ext>`. */
|
|
19
|
+
const LEGACY_DIR = 'context/documents'
|
|
20
|
+
|
|
21
|
+
/** `Pricing decisions.md` → `pricing-decisions` — a file name you can read. */
|
|
22
|
+
function slugify(name: string): string {
|
|
23
|
+
const base = name.replace(/\.[^.]+$/, '')
|
|
24
|
+
const slug = base
|
|
25
|
+
.normalize('NFKD')
|
|
26
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
27
|
+
.toLowerCase()
|
|
28
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
29
|
+
.replace(/^-+|-+$/g, '')
|
|
30
|
+
.slice(0, 60)
|
|
31
|
+
return slug || 'document'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A stored path no other document (and no file on disk) already claims. */
|
|
35
|
+
function uniqueStoredPath(root: string, docs: DocMeta[], name: string): string {
|
|
36
|
+
const extension = extname(name).toLowerCase()
|
|
37
|
+
const slug = slugify(name)
|
|
38
|
+
const taken = new Set(docs.map((doc) => doc.stored))
|
|
39
|
+
for (let attempt = 0; ; attempt++) {
|
|
40
|
+
const candidate = `${DIR}/${slug}${attempt === 0 ? '' : `-${attempt + 1}`}${extension}`
|
|
41
|
+
if (!taken.has(candidate) && !existsSync(statePath(root, candidate))) return candidate
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Move documents written under the old uuid-named layout into `context/docs/`.
|
|
47
|
+
* Idempotent and only ever renames inside the studio's own state directory.
|
|
48
|
+
*/
|
|
49
|
+
export function migrateDocuments(root: string): void {
|
|
50
|
+
const docs = listDocuments(root)
|
|
51
|
+
if (!docs.some((doc) => doc.stored.startsWith(`${LEGACY_DIR}/`))) return
|
|
52
|
+
let moved = false
|
|
53
|
+
for (const doc of docs) {
|
|
54
|
+
if (!doc.stored.startsWith(`${LEGACY_DIR}/`)) continue
|
|
55
|
+
const from = statePath(root, doc.stored)
|
|
56
|
+
if (!existsSync(from)) continue
|
|
57
|
+
const next = uniqueStoredPath(root, docs, doc.name)
|
|
58
|
+
writeStateBuffer(root, next, readFileSync(from))
|
|
59
|
+
removeState(root, doc.stored)
|
|
60
|
+
doc.stored = next
|
|
61
|
+
moved = true
|
|
62
|
+
}
|
|
63
|
+
if (moved) writeJson(root, INDEX, docs)
|
|
64
|
+
}
|
|
17
65
|
|
|
18
66
|
function decodeDocument(value: unknown): DocMeta | undefined {
|
|
19
67
|
const record = asJsonRecord(value)
|
|
@@ -30,7 +78,7 @@ function decodeDocument(value: unknown): DocMeta | undefined {
|
|
|
30
78
|
size === undefined ||
|
|
31
79
|
size < 0 ||
|
|
32
80
|
!addedAt ||
|
|
33
|
-
!stored?.startsWith(
|
|
81
|
+
!(stored?.startsWith(`${DIR}/`) || stored?.startsWith(`${LEGACY_DIR}/`)) ||
|
|
34
82
|
stored.split('/').includes('..')
|
|
35
83
|
) {
|
|
36
84
|
return undefined
|
|
@@ -60,18 +108,17 @@ export function listDocuments(root: string): DocMeta[] {
|
|
|
60
108
|
}
|
|
61
109
|
|
|
62
110
|
export function addDocument(root: string, name: string, type: string, data: Uint8Array): DocMeta {
|
|
63
|
-
const
|
|
64
|
-
const stored =
|
|
111
|
+
const docs = listDocuments(root)
|
|
112
|
+
const stored = uniqueStoredPath(root, docs, name || 'untitled')
|
|
65
113
|
writeStateBuffer(root, stored, data)
|
|
66
114
|
const meta: DocMeta = {
|
|
67
|
-
id,
|
|
115
|
+
id: randomUUID(),
|
|
68
116
|
name: name || 'untitled',
|
|
69
117
|
type: type || 'application/octet-stream',
|
|
70
118
|
size: data.byteLength,
|
|
71
119
|
addedAt: new Date().toISOString(),
|
|
72
120
|
stored,
|
|
73
121
|
}
|
|
74
|
-
const docs = listDocuments(root)
|
|
75
122
|
docs.unshift(meta)
|
|
76
123
|
writeJson(root, INDEX, docs)
|
|
77
124
|
return meta
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* visibility.ts — persisted per-domain canvas visibility (the manual hide-set,
|
|
3
|
-
* inherited-edge category toggle
|
|
3
|
+
* and inherited-edge category toggle). Sibling of
|
|
4
4
|
* layout.ts: layout owns node POSITIONS, this owns what's SHOWN. All entries use
|
|
5
5
|
* stable refs, so they survive schema edits (a removed ref is harmless).
|
|
6
6
|
* Persisted via the allow-listed store (visibility.json).
|
|
@@ -14,7 +14,6 @@ const FILE = 'visibility.json'
|
|
|
14
14
|
const DEFAULT: VisibilityState = {
|
|
15
15
|
hidden: {},
|
|
16
16
|
showInheritedEdges: true,
|
|
17
|
-
materializedInterfaces: {},
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
function trueSet(value: unknown): Record<string, true> {
|
|
@@ -31,13 +30,10 @@ function decodeVisibility(value: unknown): VisibilityState | undefined {
|
|
|
31
30
|
return {
|
|
32
31
|
hidden: trueSet(record.hidden),
|
|
33
32
|
showInheritedEdges: asBoolean(record.showInheritedEdges) ?? DEFAULT.showInheritedEdges,
|
|
34
|
-
materializedInterfaces: trueSet(record.materializedInterfaces),
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
export function readVisibility(root: string): VisibilityState {
|
|
39
|
-
// merge over DEFAULT so a file written before a field existed (e.g. pre-materialize)
|
|
40
|
-
// still returns the complete shape — the client reads every field unconditionally.
|
|
41
37
|
return readJson(root, FILE, decodeVisibility, { ...DEFAULT })
|
|
42
38
|
}
|
|
43
39
|
|
|
@@ -4,9 +4,9 @@ import type {
|
|
|
4
4
|
ViewTargetResult,
|
|
5
5
|
} from '../../shared/types'
|
|
6
6
|
|
|
7
|
-
const NAMED_NAME = 'kernel.astrale.ai:
|
|
8
|
-
const DESCRIPTABLE_DESCRIPTION = 'kernel.astrale.ai:
|
|
9
|
-
const STATUSED_STATUS = 'kernel.astrale.ai:
|
|
7
|
+
const NAMED_NAME = 'kernel.astrale.ai:class.Named.property.name'
|
|
8
|
+
const DESCRIPTABLE_DESCRIPTION = 'kernel.astrale.ai:class.Descriptable.property.description'
|
|
9
|
+
const STATUSED_STATUS = 'kernel.astrale.ai:class.Statused.property.status'
|
|
10
10
|
|
|
11
11
|
export interface RawTargetRow {
|
|
12
12
|
id?: unknown
|
|
@@ -4,132 +4,74 @@ import type { StudioSchemaBundle, ViewInfo } from '../../shared/types'
|
|
|
4
4
|
|
|
5
5
|
import { targetDefinition, viewDefinitionBindings } from './target'
|
|
6
6
|
|
|
7
|
-
describe('
|
|
8
|
-
test('preserves canonical
|
|
9
|
-
const view = { slug: 'users', kind: 'unknown' } satisfies ViewInfo
|
|
10
|
-
const bundle = {
|
|
11
|
-
ir: {
|
|
12
|
-
views: {
|
|
13
|
-
users: {
|
|
14
|
-
name: 'users',
|
|
15
|
-
auth: 'required',
|
|
16
|
-
target: {
|
|
17
|
-
kind: 'definition',
|
|
18
|
-
definitions: [{ origin: 'kernel.astrale.ai', kind: 'interface', name: 'Identity' }],
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
} as unknown as StudioSchemaBundle
|
|
24
|
-
|
|
25
|
-
expect(viewDefinitionBindings('shell.astrale.ai', view, bundle)).toEqual([
|
|
26
|
-
{ className: 'Identity', classOrigin: 'kernel.astrale.ai', kind: 'interface' },
|
|
27
|
-
])
|
|
28
|
-
expect(targetDefinition('Identity', 'kernel.astrale.ai', 'interface')).toBe(
|
|
29
|
-
'/:kernel.astrale.ai:interface.Identity',
|
|
30
|
-
)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('preserves every exact canonical homonym and ignores short-name metadata', () => {
|
|
7
|
+
describe('View target definitions', () => {
|
|
8
|
+
test('preserves every exact canonical Class target and ignores short-name metadata', () => {
|
|
34
9
|
const view = {
|
|
35
10
|
slug: 'named',
|
|
36
11
|
kind: 'unknown',
|
|
37
|
-
viewFor: '
|
|
12
|
+
viewFor: 'WrongFallback',
|
|
38
13
|
} satisfies ViewInfo
|
|
39
14
|
const bundle = {
|
|
40
15
|
ir: {
|
|
41
16
|
views: {
|
|
42
17
|
named: {
|
|
43
18
|
name: 'named',
|
|
44
|
-
auth: 'required',
|
|
45
19
|
target: {
|
|
46
20
|
kind: 'definition',
|
|
47
21
|
definitions: [
|
|
48
|
-
{ origin: 'directory.example.dev', kind: '
|
|
49
|
-
{ origin: 'people.example.dev', kind: '
|
|
50
|
-
{ origin: 'catalog.example.dev', kind: 'class', name: 'Named' },
|
|
22
|
+
{ origin: 'directory.example.dev', kind: 'class', name: 'Named' },
|
|
23
|
+
{ origin: 'people.example.dev', kind: 'class', name: 'Named' },
|
|
51
24
|
],
|
|
52
25
|
},
|
|
53
26
|
},
|
|
54
27
|
},
|
|
55
28
|
},
|
|
56
29
|
} as unknown as StudioSchemaBundle
|
|
57
|
-
|
|
58
30
|
expect(viewDefinitionBindings('shell.astrale.ai', view, bundle)).toEqual([
|
|
59
|
-
{ className: 'Named', classOrigin: 'directory.example.dev', kind: '
|
|
60
|
-
{ className: 'Named', classOrigin: 'people.example.dev', kind: '
|
|
61
|
-
{ className: 'Named', classOrigin: 'catalog.example.dev', kind: 'class' },
|
|
31
|
+
{ className: 'Named', classOrigin: 'directory.example.dev', kind: 'class' },
|
|
32
|
+
{ className: 'Named', classOrigin: 'people.example.dev', kind: 'class' },
|
|
62
33
|
])
|
|
63
34
|
})
|
|
64
35
|
|
|
65
|
-
test('treats
|
|
36
|
+
test('treats a canonical Domain target as authoritative', () => {
|
|
66
37
|
const view = { slug: 'home', kind: 'unknown', viewFor: 'User' } satisfies ViewInfo
|
|
67
38
|
const bundle = {
|
|
68
|
-
ir: { views: { home: { name: 'home',
|
|
39
|
+
ir: { views: { home: { name: 'home', target: { kind: 'domain' } } } },
|
|
69
40
|
} as unknown as StudioSchemaBundle
|
|
70
41
|
expect(viewDefinitionBindings('shell.astrale.ai', view, bundle)).toEqual([])
|
|
71
42
|
})
|
|
72
43
|
|
|
73
|
-
test('
|
|
74
|
-
const view = { slug: '
|
|
44
|
+
test('resolves fallback targets through local and exact imported Classes', () => {
|
|
45
|
+
const view = { slug: 'named', kind: 'unknown', viewFor: 'Named' } satisfies ViewInfo
|
|
75
46
|
const bundle = {
|
|
76
47
|
ir: {
|
|
77
48
|
domain: 'shell.astrale.ai',
|
|
78
49
|
views: {},
|
|
79
50
|
classes: {
|
|
80
51
|
Named: {
|
|
52
|
+
type: 'node',
|
|
53
|
+
name: 'Named',
|
|
81
54
|
origin: 'shell.astrale.ai',
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
},
|
|
85
|
-
interfaces: {
|
|
86
|
-
Named: {
|
|
87
|
-
origin: 'shell.astrale.ai',
|
|
88
|
-
ref: { origin: 'shell.astrale.ai', kind: 'interface', name: 'Named' },
|
|
55
|
+
properties: {},
|
|
56
|
+
methods: {},
|
|
89
57
|
},
|
|
90
58
|
},
|
|
91
|
-
imports: { Named: { origin: 'legacy.invalid', definition: 'class' } },
|
|
92
59
|
importsByKey: {
|
|
93
|
-
'directory.example.dev:interface.Named': {
|
|
94
|
-
origin: 'directory.example.dev',
|
|
95
|
-
definition: 'interface',
|
|
96
|
-
},
|
|
97
60
|
'catalog.example.dev:class.Named': {
|
|
98
61
|
origin: 'catalog.example.dev',
|
|
99
|
-
|
|
62
|
+
ref: { origin: 'catalog.example.dev', kind: 'class', name: 'Named' },
|
|
63
|
+
key: 'catalog.example.dev:class.Named',
|
|
100
64
|
},
|
|
101
65
|
},
|
|
102
66
|
},
|
|
103
67
|
} as unknown as StudioSchemaBundle
|
|
104
|
-
|
|
105
68
|
expect(viewDefinitionBindings('shell.astrale.ai', view, bundle)).toEqual([
|
|
106
69
|
{ className: 'Named', classOrigin: 'shell.astrale.ai', kind: 'class' },
|
|
107
|
-
{ className: 'Named', classOrigin: 'shell.astrale.ai', kind: 'interface' },
|
|
108
|
-
{ className: 'Named', classOrigin: 'directory.example.dev', kind: 'interface' },
|
|
109
70
|
{ className: 'Named', classOrigin: 'catalog.example.dev', kind: 'class' },
|
|
110
71
|
])
|
|
111
72
|
})
|
|
112
73
|
|
|
113
|
-
test('
|
|
114
|
-
const view = { slug: 'legacy-users', kind: 'unknown', viewFor: 'User' } satisfies ViewInfo
|
|
115
|
-
const legacy = {
|
|
116
|
-
ir: {
|
|
117
|
-
domain: 'shell.astrale.ai',
|
|
118
|
-
views: {},
|
|
119
|
-
classes: {},
|
|
120
|
-
interfaces: {},
|
|
121
|
-
imports: { User: { origin: 'accounts.example.dev', definition: 'interface' } },
|
|
122
|
-
},
|
|
123
|
-
} as unknown as StudioSchemaBundle
|
|
124
|
-
const exact = { ir: { ...legacy.ir, importsByKey: {} } } as unknown as StudioSchemaBundle
|
|
125
|
-
|
|
126
|
-
expect(viewDefinitionBindings('shell.astrale.ai', view, legacy)).toEqual([
|
|
127
|
-
{ className: 'User', classOrigin: 'accounts.example.dev', kind: 'interface' },
|
|
128
|
-
])
|
|
129
|
-
expect(viewDefinitionBindings('shell.astrale.ai', view, exact)).toEqual([])
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
test('addresses exact class instances through a canonical Definition source', () => {
|
|
74
|
+
test('addresses exact Class instances through a canonical Definition source', () => {
|
|
133
75
|
expect(targetDefinition('Issue', 'issues.astrale.ai')).toBe('/:issues.astrale.ai:class.Issue')
|
|
134
76
|
})
|
|
135
77
|
})
|