@astrale-os/cli 1.0.0-beta.2 → 1.0.0-beta.20
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 +16 -1
- package/dist/astrale.js +51105 -58057
- package/dist/public/connect-core.js +2085 -30702
- package/dist/public/keys/index.js +884 -29476
- package/dist/public/paths/index.js +13101 -41452
- 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 +7 -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/package.json +15 -20
- 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 +46 -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 +7 -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 +3 -14
- 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 +62 -10
- 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 +49 -0
- package/src/commands/call-describe.ts +60 -68
- package/src/commands/call.ts +71 -59
- package/src/commands/domain/install.ts +54 -35
- 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 +14 -15
- package/src/commands/identity/__tests__/register.test.ts +3 -3
- package/src/commands/identity/register.ts +5 -4
- 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 +48 -35
- package/src/commands/logs.ts +123 -33
- package/src/commands/mutate.ts +6 -5
- package/src/commands/query.ts +35 -32
- 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 +13 -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 +31 -11
- package/src/commands/view.ts +82 -37
- 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 +20 -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/__tests__/target.test.ts +1 -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 +47 -23
- 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 +19 -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/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__/command-dx.test.ts +1 -1
- 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__/studio-server-deps.test.ts +1 -1
- package/src/lib/__tests__/update.test.ts +264 -11
- package/src/lib/__tests__/view-assets.test.ts +14 -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/command-dx.ts +9 -9
- 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/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 +163 -6
- 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/telemetry/__tests__/recorder.test.ts +1 -0
- package/src/telemetry/recorder.ts +9 -1
- package/src/ui/.spec/api.d.ts +14 -0
- package/src/ui/.spec/architecture.md +10 -0
- package/src/ui/.spec/laws.ts +36 -0
- package/src/ui/.spec/layout.ts +16 -0
- package/src/ui/__tests__/ui.test.ts +981 -0
- package/src/ui/index.ts +13 -0
- package/src/ui/lock.ts +87 -0
- package/src/ui/model.ts +83 -0
- package/src/ui/operations.ts +710 -0
- package/src/ui/project.ts +219 -0
- package/src/ui/release.ts +321 -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-7YHdeCxp.js +81 -0
- package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
- package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
- package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
- package/studio/client/dist/index.html +3 -2
- package/studio/package.json +7 -13
- 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 +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 +30 -51
- 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
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { afterEach, expect, test } from 'bun:test'
|
|
1
|
+
import { afterEach, describe, expect, test } from 'bun:test'
|
|
2
2
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
3
|
import { tmpdir } from 'node:os'
|
|
4
4
|
import { basename, join } from 'node:path'
|
|
5
5
|
|
|
6
|
-
import { resolveTarget } from './detect'
|
|
7
6
|
import {
|
|
8
7
|
depsInstalled,
|
|
9
8
|
isDomainDir,
|
|
10
9
|
registerDomain,
|
|
11
|
-
|
|
10
|
+
resolveApplicationEntry,
|
|
11
|
+
resolveSchemaEntry,
|
|
12
12
|
unregisterDomain,
|
|
13
13
|
} from './domain'
|
|
14
14
|
|
|
@@ -20,76 +20,58 @@ afterEach(() => {
|
|
|
20
20
|
while (roots.length) rmSync(roots.pop()!, { recursive: true, force: true })
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
function fixture(
|
|
24
|
-
const root = mkdtempSync(join(
|
|
23
|
+
function fixture(nested = false): string {
|
|
24
|
+
const root = mkdtempSync(join(tmpdir(), 'studio-application-layout-'))
|
|
25
25
|
roots.push(root)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
writeFileSync(
|
|
29
|
-
|
|
26
|
+
const owner = nested ? join(root, 'domain') : root
|
|
27
|
+
mkdirSync(join(owner, 'schema'), { recursive: true })
|
|
28
|
+
writeFileSync(
|
|
29
|
+
join(root, 'astrale.config.ts'),
|
|
30
|
+
nested
|
|
31
|
+
? "import application from './domain/application.js'\nexport default { application }\n"
|
|
32
|
+
: 'export default {}\n',
|
|
33
|
+
)
|
|
34
|
+
writeFileSync(join(owner, 'application.ts'), 'export default {}\n')
|
|
35
|
+
writeFileSync(join(owner, 'schema/index.ts'), 'export const schema = {}\n')
|
|
30
36
|
return root
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const handle = registerDomain(root)!
|
|
46
|
-
domainIds.push(handle.id)
|
|
47
|
-
expect(basename(handle.domainFile)).toBe('implementation.ts')
|
|
48
|
-
expect(resolveTarget(root).map((domain) => domain.root)).toEqual([root])
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('preserves domain.ts and kernel-core as the legacy fallback', () => {
|
|
52
|
-
const root = fixture('domain.ts')
|
|
53
|
-
mkdirSync(join(root, 'node_modules', '@astrale-os', 'kernel-core'), { recursive: true })
|
|
54
|
-
|
|
55
|
-
expect(isDomainDir(root)).toBe(true)
|
|
56
|
-
expect(depsInstalled(root)).toBe(true)
|
|
57
|
-
const handle = registerDomain(root)!
|
|
58
|
-
domainIds.push(handle.id)
|
|
59
|
-
expect(basename(handle.domainFile)).toBe('domain.ts')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('prefers implementation.ts when both composition entries exist', () => {
|
|
63
|
-
const root = fixture('domain.ts')
|
|
64
|
-
writeFileSync(join(root, 'implementation.ts'), 'export const domain = {}\n')
|
|
65
|
-
|
|
66
|
-
expect(basename(resolveDomainEntry(root)!)).toBe('implementation.ts')
|
|
67
|
-
})
|
|
39
|
+
describe('SDK V1 project discovery', () => {
|
|
40
|
+
test('discovers conventional root Application and Schema entries', () => {
|
|
41
|
+
const root = fixture()
|
|
42
|
+
expect(isDomainDir(root)).toBe(true)
|
|
43
|
+
expect(basename(resolveApplicationEntry(root)!)).toBe('application.ts')
|
|
44
|
+
expect(basename(resolveSchemaEntry(root, resolveApplicationEntry(root)!)!)).toBe('index.ts')
|
|
45
|
+
const handle = registerDomain(root)!
|
|
46
|
+
domainIds.push(handle.id)
|
|
47
|
+
expect(basename(handle.applicationFile)).toBe('application.ts')
|
|
48
|
+
expect(handle.schemaDirName).toBe('schema')
|
|
49
|
+
})
|
|
68
50
|
|
|
69
|
-
test('
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
51
|
+
test('follows a config-imported nested Application and adjacent Schema', () => {
|
|
52
|
+
const root = fixture(true)
|
|
53
|
+
const application = resolveApplicationEntry(root)!
|
|
54
|
+
expect(application).toBe(join(root, 'domain/application.ts'))
|
|
55
|
+
expect(resolveSchemaEntry(root, application)).toBe(join(root, 'domain/schema/index.ts'))
|
|
56
|
+
})
|
|
75
57
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
join(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
type: 'module',
|
|
85
|
-
exports: { './schema': './schema.js' },
|
|
86
|
-
}),
|
|
87
|
-
)
|
|
88
|
-
writeFileSync(
|
|
89
|
-
join(hoistedWorkspace, 'node_modules', '@astrale-os', 'sdk', 'schema.js'),
|
|
90
|
-
'export const schema = {}\n',
|
|
91
|
-
)
|
|
92
|
-
const hoistedRoot = fixture('implementation.ts', join(hoistedWorkspace, 'packages'))
|
|
58
|
+
test('requires the semantic SDK dependency, not Kernel implementation packages', () => {
|
|
59
|
+
const root = fixture()
|
|
60
|
+
expect(depsInstalled(root)).toBe(false)
|
|
61
|
+
mkdirSync(join(root, 'node_modules', '@astrale-os', 'kernel-core'), { recursive: true })
|
|
62
|
+
expect(depsInstalled(root)).toBe(false)
|
|
63
|
+
mkdirSync(join(root, 'node_modules', '@astrale-os', 'sdk'), { recursive: true })
|
|
64
|
+
expect(depsInstalled(root)).toBe(true)
|
|
65
|
+
})
|
|
93
66
|
|
|
94
|
-
|
|
67
|
+
test('rejects implementation.ts and domain.ts compatibility layouts', () => {
|
|
68
|
+
const root = mkdtempSync(join(tmpdir(), 'studio-legacy-layout-'))
|
|
69
|
+
roots.push(root)
|
|
70
|
+
mkdirSync(join(root, 'schema'))
|
|
71
|
+
writeFileSync(join(root, 'astrale.config.ts'), 'export default {}\n')
|
|
72
|
+
writeFileSync(join(root, 'implementation.ts'), 'export default {}\n')
|
|
73
|
+
writeFileSync(join(root, 'domain.ts'), 'export default {}\n')
|
|
74
|
+
writeFileSync(join(root, 'schema/index.ts'), 'export const schema = {}\n')
|
|
75
|
+
expect(isDomainDir(root)).toBe(false)
|
|
76
|
+
})
|
|
95
77
|
})
|
package/studio/server/domain.ts
CHANGED
|
@@ -1,74 +1,95 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Current SDK projects use implementation.ts; domain.ts remains the legacy
|
|
5
|
-
* fallback. The schema dir is configurable (default 'schema') and threaded
|
|
6
|
-
* everywhere.
|
|
7
|
-
*/
|
|
8
|
-
import { existsSync } from 'node:fs'
|
|
9
|
-
import { basename, join, resolve } from 'node:path'
|
|
1
|
+
/** SDK V1 project discovery and the in-process Studio registry. */
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
3
|
+
import { basename, dirname, extname, join, relative, resolve } from 'node:path'
|
|
10
4
|
|
|
11
5
|
export interface DomainHandle {
|
|
12
|
-
id: string
|
|
13
|
-
root: string
|
|
14
|
-
configFile: string
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
schemaIndex: string
|
|
6
|
+
readonly id: string
|
|
7
|
+
readonly root: string
|
|
8
|
+
readonly configFile: string
|
|
9
|
+
readonly applicationFile: string
|
|
10
|
+
readonly schemaDirName: string
|
|
11
|
+
readonly schemaDir: string
|
|
12
|
+
readonly schemaIndex: string
|
|
20
13
|
origin?: string
|
|
21
14
|
}
|
|
22
15
|
|
|
23
16
|
const registry = new Map<string, DomainHandle>()
|
|
24
17
|
|
|
25
|
-
export const DOMAIN_ENTRY_FILES = ['implementation.ts', 'domain.ts'] as const
|
|
26
|
-
|
|
27
18
|
export function makeId(root: string): string {
|
|
28
19
|
return basename(resolve(root)).replace(/[^a-zA-Z0-9_-]/g, '-') || 'domain'
|
|
29
20
|
}
|
|
30
21
|
|
|
31
|
-
/** Resolve the
|
|
32
|
-
export function
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
/** Resolve the Application imported by config, with root application.ts as convention. */
|
|
23
|
+
export function resolveApplicationEntry(root: string): string | null {
|
|
24
|
+
const project = resolve(root)
|
|
25
|
+
const conventional = join(project, 'application.ts')
|
|
26
|
+
if (existsSync(conventional)) return conventional
|
|
27
|
+
const config = join(project, 'astrale.config.ts')
|
|
28
|
+
if (!existsSync(config)) return null
|
|
29
|
+
let source: string
|
|
30
|
+
try {
|
|
31
|
+
source = readFileSync(config, 'utf8')
|
|
32
|
+
} catch {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
for (const match of source.matchAll(/\bfrom\s+['"]([^'"]+)['"]/gu)) {
|
|
36
|
+
const specifier = match[1]
|
|
37
|
+
if (
|
|
38
|
+
!specifier?.startsWith('.') ||
|
|
39
|
+
basename(specifier).replace(/\.[^.]+$/u, '') !== 'application'
|
|
40
|
+
) {
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
const selected = resolveSourceFile(project, specifier)
|
|
44
|
+
if (selected !== null) return selected
|
|
37
45
|
}
|
|
38
46
|
return null
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
/**
|
|
49
|
+
/** Resolve schema.ts or schema/index.ts beside the Application, then at project root. */
|
|
50
|
+
export function resolveSchemaEntry(
|
|
51
|
+
root: string,
|
|
52
|
+
applicationFile: string,
|
|
53
|
+
schemaDirName = 'schema',
|
|
54
|
+
): string | null {
|
|
55
|
+
const project = resolve(root)
|
|
56
|
+
const applicationDir = dirname(applicationFile)
|
|
57
|
+
const candidates = [
|
|
58
|
+
join(applicationDir, 'schema.ts'),
|
|
59
|
+
join(applicationDir, schemaDirName, 'index.ts'),
|
|
60
|
+
join(project, 'schema.ts'),
|
|
61
|
+
join(project, schemaDirName, 'index.ts'),
|
|
62
|
+
]
|
|
63
|
+
return [...new Set(candidates)].find(existsSync) ?? null
|
|
64
|
+
}
|
|
65
|
+
|
|
42
66
|
export function isDomainDir(root: string, schemaDirName = 'schema'): boolean {
|
|
43
|
-
const
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
existsSync(join(r, schemaDirName, 'index.ts'))
|
|
48
|
-
)
|
|
67
|
+
const project = resolve(root)
|
|
68
|
+
if (!existsSync(join(project, 'astrale.config.ts'))) return false
|
|
69
|
+
const application = resolveApplicationEntry(project)
|
|
70
|
+
return application !== null && resolveSchemaEntry(project, application, schemaDirName) !== null
|
|
49
71
|
}
|
|
50
72
|
|
|
51
|
-
/** Confirm + register a domain rooted at `root`. Returns null if the triple is incomplete. */
|
|
52
73
|
export function registerDomain(root: string, schemaDirName = 'schema'): DomainHandle | null {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
const project = resolve(root)
|
|
75
|
+
const applicationFile = resolveApplicationEntry(project)
|
|
76
|
+
if (applicationFile === null || !existsSync(join(project, 'astrale.config.ts'))) return null
|
|
77
|
+
const schemaIndex = resolveSchemaEntry(project, applicationFile, schemaDirName)
|
|
78
|
+
if (schemaIndex === null) return null
|
|
79
|
+
const schemaDir = dirname(schemaIndex)
|
|
58
80
|
const handle: DomainHandle = {
|
|
59
|
-
id: makeId(
|
|
60
|
-
root:
|
|
61
|
-
configFile: join(
|
|
62
|
-
|
|
63
|
-
schemaDirName,
|
|
81
|
+
id: makeId(project),
|
|
82
|
+
root: project,
|
|
83
|
+
configFile: join(project, 'astrale.config.ts'),
|
|
84
|
+
applicationFile,
|
|
85
|
+
schemaDirName: relative(project, schemaDir).replaceAll('\\', '/') || '.',
|
|
64
86
|
schemaDir,
|
|
65
|
-
schemaIndex
|
|
87
|
+
schemaIndex,
|
|
66
88
|
}
|
|
67
89
|
registry.set(handle.id, handle)
|
|
68
90
|
return handle
|
|
69
91
|
}
|
|
70
92
|
|
|
71
|
-
/** Drop a domain from the registry (its dir/triple is gone). */
|
|
72
93
|
export function unregisterDomain(id: string): void {
|
|
73
94
|
registry.delete(id)
|
|
74
95
|
}
|
|
@@ -81,25 +102,23 @@ export function allDomains(): DomainHandle[] {
|
|
|
81
102
|
return [...registry.values()]
|
|
82
103
|
}
|
|
83
104
|
|
|
84
|
-
/**
|
|
105
|
+
/** Studio's current project model always requires the semantic SDK Schema facade. */
|
|
85
106
|
export function depsInstalled(root: string): boolean {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return false
|
|
93
|
-
}
|
|
107
|
+
if (existsSync(join(root, 'node_modules', '@astrale-os', 'sdk'))) return true
|
|
108
|
+
try {
|
|
109
|
+
Bun.resolveSync('@astrale-os/sdk/schema', root)
|
|
110
|
+
return true
|
|
111
|
+
} catch {
|
|
112
|
+
return false
|
|
94
113
|
}
|
|
114
|
+
}
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return sdk || installed('kernel-core', '@astrale-os/kernel-core')
|
|
116
|
+
function resolveSourceFile(root: string, specifier: string): string | null {
|
|
117
|
+
const absolute = resolve(root, specifier)
|
|
118
|
+
const extension = extname(absolute)
|
|
119
|
+
const candidates =
|
|
120
|
+
extension === ''
|
|
121
|
+
? [`${absolute}.ts`, join(absolute, 'index.ts')]
|
|
122
|
+
: [absolute, `${absolute.slice(0, -extension.length)}.ts`]
|
|
123
|
+
return candidates.find(existsSync) ?? null
|
|
105
124
|
}
|
|
@@ -10,7 +10,7 @@ import type { Comment, ContextItem, DocMeta, SchemaRevision, ThreadEntry } from
|
|
|
10
10
|
interface CopyParts {
|
|
11
11
|
origin: string
|
|
12
12
|
root: string
|
|
13
|
-
/** Studio render fingerprint retained by the
|
|
13
|
+
/** Studio render fingerprint retained by the handoff machine-state. */
|
|
14
14
|
renderFingerprint: string
|
|
15
15
|
schemaRevision?: SchemaRevision
|
|
16
16
|
openComments: Comment[]
|
package/studio/server/index.ts
CHANGED
|
@@ -42,7 +42,7 @@ const domains = resolveTarget(target, schemaDir)
|
|
|
42
42
|
if (!domains.length) {
|
|
43
43
|
console.error(`\n ✗ No Astrale domains found at ${target}`)
|
|
44
44
|
console.error(
|
|
45
|
-
` (looking for: astrale.config.ts +
|
|
45
|
+
` (looking for: astrale.config.ts + application.ts + schema.ts or ${schemaDir}/index.ts)\n`,
|
|
46
46
|
)
|
|
47
47
|
process.exit(1)
|
|
48
48
|
}
|
|
@@ -21,7 +21,7 @@ describe('installed Domain introspection', () => {
|
|
|
21
21
|
])
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
-
test('retains the complete installed Bundle for
|
|
24
|
+
test('retains the complete installed Bundle for installed SDK admission', () => {
|
|
25
25
|
const root = {
|
|
26
26
|
version: 'v1',
|
|
27
27
|
domain: 'issues.astrale.ai',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs'
|
|
2
1
|
import { join, relative } from 'node:path'
|
|
3
2
|
import { Node, type SourceFile, SyntaxKind } from 'ts-morph'
|
|
4
3
|
|
|
5
4
|
import type { ViewInfo } from '../../../../shared/types'
|
|
6
5
|
|
|
6
|
+
import { resolveApplicationEntry } from '../../../domain'
|
|
7
7
|
import { defineSchemaCalls, schemaProject } from '../schema-definition'
|
|
8
8
|
import {
|
|
9
9
|
addSource,
|
|
@@ -44,27 +44,29 @@ export function buildSchemaViewSources(root: string, schemaDirName: string): Map
|
|
|
44
44
|
return sources
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return {
|
|
47
|
+
function defaultRoute(name: string): string {
|
|
48
|
+
return `/${name
|
|
49
|
+
.replace(/([a-z0-9])([A-Z])/gu, '$1-$2')
|
|
50
|
+
.replace(/[_\s]+/gu, '-')
|
|
51
|
+
.toLowerCase()}`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function frontendSource(input: Node, source: SourceFile): { externalOrigin?: string } {
|
|
55
|
+
const value = objectProperty(input, 'source', source)
|
|
56
|
+
if (!value || !Node.isCallExpression(value)) return {}
|
|
57
|
+
if (callName(value) !== 'external') return {}
|
|
58
|
+
const origin = literalString(value.getArguments()[0], source)
|
|
59
|
+
return origin === undefined ? {} : { externalOrigin: origin }
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
export function buildFrontendViews(
|
|
62
|
+
export function buildFrontendViews(
|
|
63
|
+
root: string,
|
|
64
|
+
canonicalViewNames: readonly string[],
|
|
65
|
+
): ViewInfo[] {
|
|
63
66
|
const project = makeProject()
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const sources = [...new Set([...listSourceFiles(join(root, 'views')), ...compositionFiles])]
|
|
67
|
+
const application = resolveApplicationEntry(root)
|
|
68
|
+
const applicationFiles = application === null ? [] : [application]
|
|
69
|
+
const sources = [...new Set([...listSourceFiles(join(root, 'views')), ...applicationFiles])]
|
|
68
70
|
.map((file) => addSource(project, file))
|
|
69
71
|
.filter((source): source is SourceFile => source !== null)
|
|
70
72
|
const views: ViewInfo[] = []
|
|
@@ -72,30 +74,37 @@ export function buildFrontendViews(root: string): ViewInfo[] {
|
|
|
72
74
|
for (const source of sources) {
|
|
73
75
|
for (const call of source.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
74
76
|
const frontendName = callName(call)
|
|
75
|
-
if (frontendName !== '
|
|
77
|
+
if (frontendName !== 'defineFrontend') continue
|
|
76
78
|
const input = objectValue(call.getArguments()[0], source)
|
|
77
79
|
if (!input) continue
|
|
78
80
|
const routes = objectValue(objectProperty(input, 'routes', source) ?? undefined, source)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
const declared = new Map<string, string>()
|
|
82
|
+
if (routes && Node.isObjectLiteralExpression(routes)) {
|
|
83
|
+
for (const property of routes.getProperties()) {
|
|
84
|
+
const slug = propertySlug(property)
|
|
85
|
+
const routeValue = propertyValue(property, source)
|
|
86
|
+
if (!slug || !routeValue) continue
|
|
87
|
+
const direct = literalString(routeValue, source)
|
|
88
|
+
const routeInput = objectValue(routeValue, source)
|
|
89
|
+
const path =
|
|
90
|
+
direct ??
|
|
91
|
+
(routeInput
|
|
92
|
+
? literalString(objectProperty(routeInput, 'path', source) ?? undefined, source)
|
|
93
|
+
: undefined)
|
|
94
|
+
if (path) declared.set(slug, path)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const frontend = frontendSource(input, source)
|
|
91
98
|
|
|
92
|
-
|
|
93
|
-
const
|
|
99
|
+
for (const slug of canonicalViewNames) {
|
|
100
|
+
const path = declared.get(slug) ?? defaultRoute(slug)
|
|
101
|
+
const url = frontend.externalOrigin
|
|
102
|
+
? new URL(path, `${frontend.externalOrigin}/`).toString()
|
|
103
|
+
: undefined
|
|
94
104
|
views.push({
|
|
95
105
|
slug,
|
|
96
|
-
kind:
|
|
97
|
-
...(
|
|
98
|
-
...(!href && (path || !artifact.external) ? { mount: path ?? `/ui/${slug}` } : {}),
|
|
106
|
+
kind: 'spa',
|
|
107
|
+
...(url ? { url } : { mount: path }),
|
|
99
108
|
file: relative(root, source.getFilePath()).replaceAll('\\', '/'),
|
|
100
109
|
})
|
|
101
110
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { SchemaIR, ViewInfo } from '../../../shared/types'
|
|
2
2
|
|
|
3
|
-
import { buildLegacyViews } from './views/legacy'
|
|
4
3
|
import { buildFrontendViews, buildSchemaViewSources } from './views/routes'
|
|
5
4
|
|
|
6
5
|
function mergeRoute(target: ViewInfo, incoming: ViewInfo): void {
|
|
@@ -30,7 +29,7 @@ function canonicalViewInfo(slug: string, view: NonNullable<SchemaIR['views']>[st
|
|
|
30
29
|
* Join canonical View definitions with route/source metadata. Passing a
|
|
31
30
|
* canonical map (including an empty map) makes it authoritative: static routes
|
|
32
31
|
* cannot invent Views or override identity, target, auth, or description.
|
|
33
|
-
* Without
|
|
32
|
+
* Without admitted canonical Views, Studio does not invent authoring semantics.
|
|
34
33
|
*/
|
|
35
34
|
export function buildViews(
|
|
36
35
|
root: string,
|
|
@@ -38,21 +37,17 @@ export function buildViews(
|
|
|
38
37
|
canonicalViews?: NonNullable<SchemaIR['views']>,
|
|
39
38
|
): ViewInfo[] {
|
|
40
39
|
const merged = new Map<string, ViewInfo>()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
for (const [slug, file] of buildSchemaViewSources(root, _schemaDirName)) {
|
|
46
|
-
const current = merged.get(slug)
|
|
47
|
-
if (current) current.file = file
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
for (const view of buildLegacyViews(root)) merged.set(view.slug, view)
|
|
40
|
+
const admittedViews = canonicalViews ?? {}
|
|
41
|
+
for (const [slug, view] of Object.entries(admittedViews)) {
|
|
42
|
+
merged.set(slug, canonicalViewInfo(slug, view))
|
|
51
43
|
}
|
|
52
|
-
for (const
|
|
44
|
+
for (const [slug, file] of buildSchemaViewSources(root, _schemaDirName)) {
|
|
45
|
+
const current = merged.get(slug)
|
|
46
|
+
if (current) current.file = file
|
|
47
|
+
}
|
|
48
|
+
for (const view of buildFrontendViews(root, Object.keys(admittedViews))) {
|
|
53
49
|
const current = merged.get(view.slug)
|
|
54
50
|
if (current) mergeRoute(current, view)
|
|
55
|
-
else if (canonicalViews === undefined) merged.set(view.slug, view)
|
|
56
51
|
}
|
|
57
52
|
return [...merged.values()]
|
|
58
53
|
}
|