@astrale-os/cli 1.0.0-beta.0 → 1.0.0-beta.10

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.
Files changed (322) hide show
  1. package/README.md +23 -12
  2. package/dist/astrale.js +51494 -56307
  3. package/dist/public/connect-core.js +2028 -26846
  4. package/dist/public/keys/index.js +1755 -40694
  5. package/dist/public/paths/index.js +859 -39518
  6. package/dist/types/admin/binding.d.ts +19 -0
  7. package/dist/types/admin/instance/client.d.ts +22 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +5 -12
  10. package/dist/types/connection/auth.d.ts +3 -0
  11. package/dist/types/connection/call.d.ts +3 -0
  12. package/dist/types/connection/command.d.ts +27 -0
  13. package/dist/types/connection/credential.d.ts +14 -0
  14. package/dist/types/connection/errors.d.ts +1 -0
  15. package/dist/types/connection/exchange.d.ts +9 -0
  16. package/dist/types/connection/failure/classify.d.ts +2 -0
  17. package/dist/types/connection/failure/index.d.ts +5 -0
  18. package/dist/types/connection/failure/model.d.ts +25 -0
  19. package/dist/types/connection/failure/render.d.ts +3 -0
  20. package/dist/types/connection/index.d.ts +8 -0
  21. package/dist/types/connection/reasons.d.ts +37 -0
  22. package/dist/types/connection/self.d.ts +37 -0
  23. package/dist/types/connection/session.d.ts +31 -0
  24. package/dist/types/connection/target.d.ts +38 -0
  25. package/dist/types/errors.d.ts +1 -1
  26. package/dist/types/lib/admin-instance.d.ts +17 -0
  27. package/dist/types/lib/admin-target.d.ts +6 -2
  28. package/dist/types/lib/failure-debug.d.ts +1 -0
  29. package/dist/types/lib/idp.d.ts +7 -0
  30. package/dist/types/lib/instance-target.d.ts +1 -1
  31. package/dist/types/lib/instance.d.ts +10 -2
  32. package/dist/types/lib/log.d.ts +5 -3
  33. package/dist/types/lib/meta.d.ts +2 -2
  34. package/dist/types/lib/proc.d.ts +43 -0
  35. package/dist/types/lib/self.d.ts +9 -0
  36. package/dist/types/lib/update.d.ts +131 -0
  37. package/package.json +8 -10
  38. package/src/__tests__/fixtures/publication.ts +20 -0
  39. package/src/admin/__tests__/binding.test.ts +31 -0
  40. package/src/admin/__tests__/fixture.ts +101 -0
  41. package/src/admin/binding.ts +98 -0
  42. package/src/admin/catalog/.spec/api.d.ts +2 -2
  43. package/src/admin/catalog/__tests__/client.test.ts +20 -49
  44. package/src/admin/catalog/client.ts +36 -32
  45. package/src/admin/catalog/model.ts +3 -4
  46. package/src/admin/graph/.spec/api.d.ts +4 -10
  47. package/src/admin/graph/nodes.ts +1 -1
  48. package/src/admin/instance/.spec/api.d.ts +2 -2
  49. package/src/admin/instance/__tests__/client.test.ts +40 -163
  50. package/src/admin/instance/client.ts +35 -137
  51. package/src/admin/instance/index.ts +1 -2
  52. package/src/admin/instance/model.ts +11 -20
  53. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  54. package/src/commands/__tests__/auth-login.test.ts +54 -1
  55. package/src/commands/__tests__/call-describe.test.ts +46 -33
  56. package/src/commands/__tests__/call.test.ts +5 -1
  57. package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
  58. package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
  59. package/src/commands/__tests__/domain-list.test.ts +63 -4
  60. package/src/commands/__tests__/install-identity-override.test.ts +19 -19
  61. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  62. package/src/commands/__tests__/instance-status.test.ts +139 -0
  63. package/src/commands/__tests__/read-commands.test.ts +35 -10
  64. package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
  65. package/src/commands/__tests__/update.test.ts +95 -0
  66. package/src/commands/call-describe.ts +60 -68
  67. package/src/commands/call.ts +43 -56
  68. package/src/commands/domain/install.ts +13 -17
  69. package/src/commands/domain/list.ts +18 -13
  70. package/src/commands/domain/publish.ts +14 -11
  71. package/src/commands/domain/uninstall.ts +2 -2
  72. package/src/commands/get.ts +14 -15
  73. package/src/commands/identity/__tests__/register.test.ts +3 -3
  74. package/src/commands/identity/register.ts +5 -4
  75. package/src/commands/instance/create.ts +8 -16
  76. package/src/commands/instance/delete.ts +12 -9
  77. package/src/commands/instance/list.ts +2 -2
  78. package/src/commands/instance/status.ts +66 -20
  79. package/src/commands/instance/use.ts +16 -12
  80. package/src/commands/introspect.ts +9 -16
  81. package/src/commands/logs.ts +24 -25
  82. package/src/commands/mutate.ts +6 -5
  83. package/src/commands/query.ts +27 -30
  84. package/src/commands/studio.ts +20 -0
  85. package/src/commands/token.ts +8 -7
  86. package/src/commands/update.ts +68 -22
  87. package/src/commands/view.ts +7 -6
  88. package/src/connection/.spec/api.d.ts +7 -8
  89. package/src/connection/.spec/architecture.md +5 -4
  90. package/src/connection/.spec/flows/session.ts +2 -2
  91. package/src/connection/.spec/laws/connection.ts +6 -2
  92. package/src/connection/.spec/layout.ts +1 -0
  93. package/src/connection/__tests__/credential.test.ts +20 -1
  94. package/src/connection/__tests__/errors.test.ts +43 -32
  95. package/src/connection/__tests__/exchange.test.ts +36 -6
  96. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  97. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  98. package/src/connection/__tests__/self.test.ts +31 -11
  99. package/src/connection/__tests__/session.test.ts +3 -3
  100. package/src/connection/__tests__/target.test.ts +1 -0
  101. package/src/connection/auth.ts +13 -0
  102. package/src/connection/call.ts +1 -1
  103. package/src/connection/credential.ts +2 -2
  104. package/src/connection/errors.ts +1 -355
  105. package/src/connection/exchange.ts +52 -27
  106. package/src/connection/failure/classify.ts +110 -0
  107. package/src/connection/failure/index.ts +18 -0
  108. package/src/connection/failure/model.ts +28 -0
  109. package/src/connection/failure/render.ts +116 -0
  110. package/src/connection/reasons.ts +16 -0
  111. package/src/connection/self.ts +39 -21
  112. package/src/connection/session.ts +19 -8
  113. package/src/errors.ts +3 -2
  114. package/src/graph/.spec/api.d.ts +12 -5
  115. package/src/graph/.spec/layout.ts +9 -1
  116. package/src/graph/__tests__/mutation.test.ts +2 -2
  117. package/src/graph/__tests__/query.test.ts +25 -6
  118. package/src/graph/class.ts +30 -0
  119. package/src/graph/index.ts +1 -0
  120. package/src/graph/query.ts +21 -32
  121. package/src/identity/.spec/api.d.ts +2 -2
  122. package/src/identity/__tests__/registration.test.ts +1 -1
  123. package/src/identity/registration.ts +3 -3
  124. package/src/keys/__tests__/keys.test.ts +4 -0
  125. package/src/keys/credential.ts +1 -0
  126. package/src/lib/__tests__/admin-target.test.ts +12 -0
  127. package/src/lib/__tests__/command-dx.test.ts +1 -1
  128. package/src/lib/__tests__/domain-publication.test.ts +138 -0
  129. package/src/lib/__tests__/idp-session.test.ts +22 -0
  130. package/src/lib/__tests__/idp.test.ts +36 -4
  131. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  132. package/src/lib/__tests__/instance-target.test.ts +7 -39
  133. package/src/lib/__tests__/instance.test.ts +6 -0
  134. package/src/lib/__tests__/log-errors.test.ts +64 -0
  135. package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
  136. package/src/lib/__tests__/update.test.ts +113 -8
  137. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  138. package/src/lib/__tests__/view-server.test.ts +1 -1
  139. package/src/lib/__tests__/view-session.test.ts +1 -1
  140. package/src/lib/admin-instance.ts +14 -8
  141. package/src/lib/admin-target.ts +21 -2
  142. package/src/lib/command-dx.ts +9 -9
  143. package/src/lib/domain-publication.ts +104 -0
  144. package/src/lib/failure-debug.ts +26 -0
  145. package/src/lib/idp.ts +39 -4
  146. package/src/lib/instance-candidates.ts +2 -2
  147. package/src/lib/instance-target.ts +3 -14
  148. package/src/lib/instance.ts +22 -12
  149. package/src/lib/log.ts +16 -9
  150. package/src/lib/login-flow.ts +13 -3
  151. package/src/lib/meta.ts +2 -2
  152. package/src/lib/provision-instance.ts +34 -57
  153. package/src/lib/update.ts +124 -30
  154. package/src/lib/validation.ts +2 -2
  155. package/src/lib/view/resolve.ts +1 -1
  156. package/src/program/__tests__/program.test.ts +20 -4
  157. package/src/program/build.ts +2 -2
  158. package/src/setup/__tests__/instance-step.test.ts +27 -10
  159. package/src/setup/steps/instance.ts +22 -15
  160. package/studio/client/dist/assets/{elk-api-D2xgMJvi.js → elk-api-ByzoDZWH.js} +1 -1
  161. package/studio/client/dist/assets/index-B0RCgUOT.js +8 -0
  162. package/studio/client/dist/assets/index-BiGR8Oo9.css +1 -0
  163. package/studio/client/dist/assets/index-N8J8EKlB.js +81 -0
  164. package/studio/client/dist/index.html +2 -2
  165. package/studio/package.json +5 -10
  166. package/studio/server/agent/ask.test.ts +1 -1
  167. package/studio/server/agent/bridge/grant.test.ts +1 -1
  168. package/studio/server/agent/bridge/routes.test.ts +1 -1
  169. package/studio/server/agent/bridge/stdio.ts +8 -1
  170. package/studio/server/agent/conversation.test.ts +10 -5
  171. package/studio/server/agent/conversation.ts +56 -8
  172. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  173. package/studio/server/agent/harness/codex/loadout.ts +18 -21
  174. package/studio/server/agent/harness/gateway/config.ts +20 -18
  175. package/studio/server/agent/harness/selection.ts +9 -1
  176. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  177. package/studio/server/agent/prompts/anchors.ts +20 -49
  178. package/studio/server/agent/prompts/system.test.ts +3 -2
  179. package/studio/server/agent/prompts/system.ts +6 -5
  180. package/studio/server/agent/prompts/turn.ts +13 -4
  181. package/studio/server/agent/routes.test.ts +1 -1
  182. package/studio/server/agent/run/completion.ts +2 -2
  183. package/studio/server/agent/run/coordinator.test.ts +1 -1
  184. package/studio/server/agent/run/preparation.ts +6 -5
  185. package/studio/server/agent/run/transcript.test.ts +35 -1
  186. package/studio/server/agent/run/transcript.ts +169 -3
  187. package/studio/server/agent/run/usage.test.ts +24 -0
  188. package/studio/server/agent/run/usage.ts +26 -1
  189. package/studio/server/api/canvas.ts +43 -0
  190. package/studio/server/api/comments.ts +85 -0
  191. package/studio/server/api/context.ts +61 -0
  192. package/studio/server/api/deployment.ts +39 -0
  193. package/studio/server/api/documents.ts +55 -0
  194. package/studio/server/api/domain.ts +59 -0
  195. package/studio/server/api/http.ts +45 -0
  196. package/studio/server/api/project.ts +57 -0
  197. package/studio/server/api/schema.ts +12 -0
  198. package/studio/server/api/views.ts +57 -0
  199. package/studio/server/api/workspace.ts +60 -0
  200. package/studio/server/api-agent-loadout.test.ts +1 -1
  201. package/studio/server/api.test.ts +147 -0
  202. package/studio/server/api.ts +20 -422
  203. package/studio/server/cache.test.ts +122 -0
  204. package/studio/server/cache.ts +162 -11
  205. package/studio/server/cli-consumers.test.ts +494 -0
  206. package/studio/server/cli.test.ts +88 -0
  207. package/studio/server/cli.ts +240 -0
  208. package/studio/server/client-package.ts +25 -1
  209. package/studio/server/domain.test.ts +50 -40
  210. package/studio/server/domain.ts +83 -52
  211. package/studio/server/environment/dotenv-preview.test.ts +39 -0
  212. package/studio/server/environment/dotenv-preview.ts +27 -0
  213. package/studio/server/environment/files.test.ts +53 -0
  214. package/studio/server/{state/env.ts → environment/files.ts} +7 -48
  215. package/studio/server/{state → handoff}/copy.ts +21 -6
  216. package/studio/server/handoff/service.test.ts +22 -0
  217. package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
  218. package/studio/server/index.ts +1 -1
  219. package/studio/server/instances/active.ts +72 -0
  220. package/studio/server/instances/deploy-record.test.ts +31 -0
  221. package/studio/server/instances/deploy-record.ts +37 -0
  222. package/studio/server/instances/deploy.ts +56 -0
  223. package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
  224. package/studio/server/instances/probe.ts +67 -0
  225. package/studio/server/instances/status.test.ts +12 -0
  226. package/studio/server/instances/status.ts +49 -0
  227. package/studio/server/introspect/anatomy/client-tree.ts +57 -0
  228. package/studio/server/introspect/anatomy/env-fields.ts +66 -0
  229. package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
  230. package/studio/server/introspect/anatomy/source.ts +181 -0
  231. package/studio/server/introspect/anatomy/views/routes.ts +114 -0
  232. package/studio/server/introspect/anatomy/views.ts +53 -0
  233. package/studio/server/introspect/anatomy-extras.test.ts +106 -35
  234. package/studio/server/introspect/anatomy-extras.ts +7 -726
  235. package/studio/server/introspect/anatomy.test.ts +22 -14
  236. package/studio/server/introspect/anatomy.ts +52 -28
  237. package/studio/server/introspect/bundle.ts +15 -9
  238. package/studio/server/introspect/canonical-schema.test.ts +93 -309
  239. package/studio/server/introspect/canonical-schema.ts +257 -425
  240. package/studio/server/introspect/config-preview.test.ts +32 -0
  241. package/studio/server/introspect/config-preview.ts +119 -0
  242. package/studio/server/introspect/core-extractor.ts +18 -127
  243. package/studio/server/introspect/core.ts +1 -2
  244. package/studio/server/introspect/diff.test.ts +18 -18
  245. package/studio/server/introspect/diff.ts +44 -90
  246. package/studio/server/introspect/extractor.ts +23 -116
  247. package/studio/server/introspect/hash.ts +5 -2
  248. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  249. package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
  250. package/studio/server/introspect/overlay.test.ts +26 -54
  251. package/studio/server/introspect/overlay.ts +10 -37
  252. package/studio/server/introspect/revision.test.ts +54 -0
  253. package/studio/server/introspect/revision.ts +49 -0
  254. package/studio/server/introspect/runtime.test.ts +83 -143
  255. package/studio/server/introspect/runtime.ts +40 -11
  256. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  257. package/studio/server/introspect/schema-ir-json.ts +151 -0
  258. package/studio/server/introspect/schema-refs.test.ts +43 -88
  259. package/studio/server/introspect/schema-refs.ts +14 -49
  260. package/studio/server/introspect/source-overlay/annotations.ts +14 -0
  261. package/studio/server/introspect/source-overlay/handlers.ts +161 -0
  262. package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
  263. package/studio/server/introspect/source-overlay/project.ts +248 -0
  264. package/studio/server/introspect/source-overlay/spans.ts +330 -0
  265. package/studio/server/json.ts +46 -0
  266. package/studio/server/lifecycle.ts +5 -1
  267. package/studio/server/sse.test.ts +26 -0
  268. package/studio/server/sse.ts +4 -1
  269. package/studio/server/state/baseline.test.ts +223 -7
  270. package/studio/server/state/baseline.ts +148 -34
  271. package/studio/server/state/comments.test.ts +66 -1
  272. package/studio/server/state/comments.ts +173 -10
  273. package/studio/server/state/context.ts +34 -2
  274. package/studio/server/state/documents.ts +42 -1
  275. package/studio/server/state/integrations.ts +27 -1
  276. package/studio/server/state/layout.test.ts +34 -0
  277. package/studio/server/state/layout.ts +44 -17
  278. package/studio/server/state/settings.ts +29 -22
  279. package/studio/server/state/store.test.ts +122 -0
  280. package/studio/server/state/store.ts +66 -17
  281. package/studio/server/state/visibility.ts +22 -11
  282. package/studio/server/views/model.test.ts +57 -0
  283. package/studio/server/views/model.ts +66 -0
  284. package/studio/server/views/runtime.ts +40 -0
  285. package/studio/server/views/selection-repository.test.ts +31 -0
  286. package/studio/server/views/selection-repository.ts +60 -0
  287. package/studio/server/views/session.test.ts +73 -0
  288. package/studio/server/views/session.ts +166 -0
  289. package/studio/server/views/target.test.ts +78 -0
  290. package/studio/server/views/target.ts +222 -0
  291. package/studio/server/watch.test.ts +11 -11
  292. package/studio/server/watch.ts +9 -5
  293. package/studio/server/workspace/catalog.test.ts +17 -0
  294. package/studio/server/workspace/catalog.ts +43 -0
  295. package/studio/server/{state → workspace}/create.test.ts +1 -1
  296. package/studio/server/{state → workspace}/create.ts +1 -1
  297. package/studio/server/{state → workspace}/git.ts +1 -1
  298. package/studio/server/workspace/updates.ts +83 -0
  299. package/studio/server/workspace-state.ts +1 -1
  300. package/studio/server/workspace-watch.ts +2 -2
  301. package/studio/shared/contracts/README.md +16 -0
  302. package/studio/shared/contracts/agent.ts +270 -0
  303. package/studio/shared/contracts/runtime.ts +50 -0
  304. package/studio/shared/contracts/schema.ts +393 -0
  305. package/studio/shared/contracts/surface.test.ts +317 -0
  306. package/studio/shared/contracts/workspace.ts +265 -0
  307. package/studio/shared/layout.test.ts +116 -0
  308. package/studio/shared/schema/identity.test.ts +34 -0
  309. package/studio/shared/schema/identity.ts +68 -0
  310. package/studio/shared/types.ts +11 -1099
  311. package/studio/tsconfig.json +1 -1
  312. package/viewer/dist/main.js +40 -61
  313. package/.check-workspace.cjs +0 -40
  314. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  315. package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
  316. package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
  317. package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
  318. package/studio/server/state/catalog.ts +0 -117
  319. package/studio/server/state/instance.ts +0 -280
  320. package/studio/server/state/updates.ts +0 -63
  321. package/studio/server/state/views.test.ts +0 -286
  322. package/studio/server/state/views.ts +0 -535
@@ -1,72 +1,44 @@
1
1
  import { expect, test } from 'bun:test'
2
2
 
3
- import type { SchemaIR } from '../../shared/types'
3
+ import type { IrClassKey, SchemaIR } from '../../shared/types'
4
4
 
5
5
  import { buildOverlay } from './overlay'
6
6
 
7
- test('preserves homonymous and cross-kind imports from the exact index', () => {
7
+ function descriptor(origin: string, name: string) {
8
+ const key = `${origin}:class.${name}` as IrClassKey
9
+ return { origin, ref: { origin, kind: 'class' as const, name }, key }
10
+ }
11
+
12
+ test('preserves homonymous Classes through exact import identity', () => {
13
+ const first = descriptor('a.example', 'Shared')
14
+ const second = descriptor('b.example', 'Shared')
15
+ const kernel = descriptor('kernel.astrale.ai', 'Identity')
8
16
  const ir = {
9
17
  version: 'v1',
18
+ format: 'astrale.dsl',
10
19
  domain: 'app.example',
11
- types: {},
12
- interfaces: {},
13
20
  classes: {},
14
21
  functions: {},
15
- imports: {},
16
22
  importsByKey: {
17
- 'a.example:interface.Shared': {
18
- origin: 'a.example',
19
- definition: 'interface',
20
- ref: { origin: 'a.example', kind: 'interface', name: 'Shared' },
21
- key: 'a.example:interface.Shared',
22
- },
23
- 'b.example:interface.Shared': {
24
- origin: 'b.example',
25
- definition: 'interface',
26
- ref: { origin: 'b.example', kind: 'interface', name: 'Shared' },
27
- key: 'b.example:interface.Shared',
28
- },
29
- 'a.example:class.Shared': {
30
- origin: 'a.example',
31
- definition: 'class',
32
- ref: { origin: 'a.example', kind: 'class', name: 'Shared' },
33
- key: 'a.example:class.Shared',
34
- },
35
- 'kernel.astrale.ai:interface.Identity': {
36
- origin: 'kernel.astrale.ai',
37
- definition: 'interface',
38
- ref: { origin: 'kernel.astrale.ai', kind: 'interface', name: 'Identity' },
39
- key: 'kernel.astrale.ai:interface.Identity',
40
- },
23
+ [first.key]: first,
24
+ [second.key]: second,
25
+ [kernel.key]: kernel,
41
26
  },
27
+ importedClassesByKey: {},
28
+ views: {},
29
+ policies: {},
30
+ dependencies: [
31
+ { origin: first.origin, revision: `sha256:${'a'.repeat(64)}` },
32
+ { origin: second.origin, revision: `sha256:${'b'.repeat(64)}` },
33
+ ],
34
+ core: {},
42
35
  } satisfies SchemaIR
43
36
 
44
37
  const overlay = buildOverlay({ ir, domainRoot: '', schemaDir: '' })
45
-
46
38
  expect(overlay.crossDomainImports).toEqual([
47
- { name: 'Shared', origin: 'a.example', definition: 'interface' },
48
- { name: 'Shared', origin: 'b.example', definition: 'interface' },
49
- { name: 'Shared', origin: 'a.example', definition: 'class' },
50
- ])
51
- expect(overlay.mixins).toEqual([
52
- { name: 'Identity', origin: 'kernel.astrale.ai', definition: 'interface' },
53
- ])
54
- })
55
-
56
- test('retains the legacy short-name import fallback', () => {
57
- const ir = {
58
- version: 'legacy',
59
- domain: 'app.example',
60
- types: {},
61
- interfaces: {},
62
- classes: {},
63
- functions: {},
64
- imports: {
65
- Identity: { origin: 'kernel.astrale.ai', definition: 'interface' },
66
- },
67
- } satisfies SchemaIR
68
-
69
- expect(buildOverlay({ ir, domainRoot: '', schemaDir: '' }).mixins).toEqual([
70
- { name: 'Identity', origin: 'kernel.astrale.ai', definition: 'interface' },
39
+ { name: 'Shared', origin: first.origin, ref: first.ref },
40
+ { name: 'Shared', origin: second.origin, ref: second.ref },
71
41
  ])
42
+ expect(overlay.mixins).toEqual([{ name: 'Identity', origin: kernel.origin, ref: kernel.ref }])
43
+ expect(overlay.requires).toEqual(['a.example', 'b.example'])
72
44
  })
@@ -1,13 +1,9 @@
1
1
  /**
2
2
  * overlay.ts — the Studio overlay over the DSL IR. Computes what the IR cannot
3
- * carry. The imports split + requires/postInstall are done here (pure / light
3
+ * carry. The import split and dependency list are computed here; handlerLinks,
4
4
  * static parse). handlerLinks, sourceSpans (+JSDoc) and annotations are filled
5
- * by a ts-morph pass over the current implementation/schema files, with legacy
6
- * domain.ts and runtime/index.ts support retained.
5
+ * by a ts-morph pass over current Schema, Runtime, Action, and Workflow files.
7
6
  */
8
- import { existsSync, readFileSync } from 'node:fs'
9
- import { join } from 'node:path'
10
-
11
7
  import type { CrossDomainImport, SchemaIR, SchemaOverlay } from '../../shared/types'
12
8
 
13
9
  import { buildHandlerLinks, buildSchemaAnnotations, buildSourceSpans } from './overlay-tsmorph'
@@ -22,46 +18,23 @@ export function buildOverlay({ ir, domainRoot, schemaDir }: OverlayArgs): Schema
22
18
  const origin = ir?.domain ?? ''
23
19
  const mixins: CrossDomainImport[] = []
24
20
  const crossDomainImports: CrossDomainImport[] = []
25
- const imports =
26
- ir?.importsByKey !== undefined
27
- ? Object.values(ir.importsByKey).flatMap((descriptor) =>
28
- descriptor.ref ? [[descriptor.ref.name, descriptor] as const] : [],
29
- )
30
- : Object.entries(ir?.imports ?? {})
31
- for (const [name, d] of imports) {
32
- const entry: CrossDomainImport = { name, origin: d.origin, definition: d.definition }
33
- if (d.origin === 'kernel.astrale.ai') mixins.push(entry)
21
+ for (const descriptor of Object.values(ir?.importsByKey ?? {})) {
22
+ const entry: CrossDomainImport = {
23
+ name: descriptor.ref.name,
24
+ origin: descriptor.origin,
25
+ ref: descriptor.ref,
26
+ }
27
+ if (descriptor.origin === 'kernel.astrale.ai') mixins.push(entry)
34
28
  else crossDomainImports.push(entry)
35
29
  }
36
30
 
37
- const { requires, postInstall } = parseCompositionEntry(domainRoot, origin)
38
-
39
31
  return {
40
32
  origin,
41
- requires,
33
+ requires: (ir?.dependencies ?? []).map(({ origin }) => origin),
42
34
  crossDomainImports,
43
35
  mixins,
44
- postInstall,
45
36
  handlerLinks: buildHandlerLinks({ ir, domainRoot }),
46
37
  sourceSpans: buildSourceSpans({ ir, schemaDir }),
47
38
  annotations: buildSchemaAnnotations({ ir }),
48
39
  }
49
40
  }
50
-
51
- function parseCompositionEntry(
52
- root: string,
53
- origin: string,
54
- ): { requires: string[]; postInstall?: string } {
55
- const f = ['implementation.ts', 'domain.ts'].map((file) => join(root, file)).find(existsSync)
56
- let requires: string[] = []
57
- let postInstall: string | undefined
58
- if (f) {
59
- const src = readFileSync(f, 'utf8')
60
- const rm = src.match(/requires\s*:\s*\[([^\]]*)\]/)
61
- if (rm) requires = [...rm[1].matchAll(/['"`]([^'"`]+)['"`]/g)].map((x) => x[1])
62
- const pm = src.match(/postInstall\s*:\s*[`'"]([^`'"]+)[`'"]/)
63
- if (pm)
64
- postInstall = pm[1].replace(/\$\{schema\.domain\}/g, origin).replace(/\$\{[^}]+\}/g, origin)
65
- }
66
- return { requires, postInstall }
67
- }
@@ -0,0 +1,54 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+
3
+ import { admittedBundleRevisionFromSdk } from './revision'
4
+
5
+ const REVISION = `sha256:${'a'.repeat(64)}` as const
6
+
7
+ describe('installed Bundle revision', () => {
8
+ test('uses bundle admission before asking the installed schema owner for its revision', () => {
9
+ const calls: string[] = []
10
+ const root = { format: 'astrale.dsl', version: 'v1', origin: 'notes.example.dev' }
11
+ const input = { wire: true }
12
+ const sdk = {
13
+ bundle: {
14
+ accept(value: unknown) {
15
+ calls.push('bundle.accept')
16
+ expect(value).toBe(input)
17
+ return { root, closure: [] }
18
+ },
19
+ },
20
+ schema: {
21
+ revision(value: unknown) {
22
+ calls.push('schema.revision')
23
+ expect(value).toBe(root)
24
+ return REVISION
25
+ },
26
+ },
27
+ }
28
+
29
+ expect(admittedBundleRevisionFromSdk(sdk, input)).toBe(REVISION)
30
+ expect(calls).toEqual(['bundle.accept', 'schema.revision'])
31
+ })
32
+
33
+ test('fails closed when bundle admission or the returned revision is invalid', () => {
34
+ expect(
35
+ admittedBundleRevisionFromSdk(
36
+ { bundle: { accept: () => ({ root: {} }) }, schema: { revision: () => 'sha-short' } },
37
+ {},
38
+ ),
39
+ ).toBeNull()
40
+ expect(
41
+ admittedBundleRevisionFromSdk(
42
+ {
43
+ bundle: {
44
+ accept: () => {
45
+ throw new Error('invalid bundle')
46
+ },
47
+ },
48
+ schema: { revision: () => REVISION },
49
+ },
50
+ {},
51
+ ),
52
+ ).toBeNull()
53
+ })
54
+ })
@@ -0,0 +1,49 @@
1
+ import type { SchemaRevision } from '../../shared/types'
2
+
3
+ import { isSchemaRevision } from '../../shared/types'
4
+
5
+ type AnyRecord = Record<string, unknown>
6
+
7
+ /**
8
+ * Cross the installed-bundle JSON boundary through the Domain's installed SDK, then
9
+ * ask the DSL owner for the root revision. Invalid/unavailable bundles return
10
+ * null so Studio reports unknown drift instead of inventing an identity.
11
+ */
12
+ export function admittedBundleRevisionFromSdk(
13
+ sdkModule: Record<string, unknown>,
14
+ input: unknown,
15
+ ): SchemaRevision | null {
16
+ const bundleApi = asRecord(sdkModule.bundle)
17
+ const schemaApi = asRecord(sdkModule.schema)
18
+ if (typeof bundleApi?.accept !== 'function' || typeof schemaApi?.revision !== 'function') {
19
+ return null
20
+ }
21
+ try {
22
+ const accepted = asRecord(Reflect.apply(bundleApi.accept, bundleApi, [input]))
23
+ if (!accepted || !Object.prototype.hasOwnProperty.call(accepted, 'root')) return null
24
+ const revision = Reflect.apply(schemaApi.revision, schemaApi, [accepted.root])
25
+ return isSchemaRevision(revision) ? revision : null
26
+ } catch {
27
+ return null
28
+ }
29
+ }
30
+
31
+ export async function admittedBundleRevision(
32
+ domainRoot: string,
33
+ input: unknown,
34
+ ): Promise<SchemaRevision | null> {
35
+ try {
36
+ const sdkModule: Record<string, unknown> = await import(
37
+ Bun.resolveSync('@astrale-os/sdk/schema', domainRoot)
38
+ )
39
+ return admittedBundleRevisionFromSdk(sdkModule, input)
40
+ } catch {
41
+ return null
42
+ }
43
+ }
44
+
45
+ function asRecord(value: unknown): AnyRecord | null {
46
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
47
+ ? (value as AnyRecord)
48
+ : null
49
+ }
@@ -6,11 +6,11 @@ import { join } from 'node:path'
6
6
  import type { DomainHandle } from '../domain'
7
7
 
8
8
  import { buildBundle } from './bundle'
9
- import { schemaHashOf } from './hash'
9
+ import { renderFingerprintOf } from './hash'
10
+ import { admittedBundleRevision } from './revision'
10
11
  import { coreExtract, runtimeExtract } from './runtime'
11
12
 
12
13
  const roots: string[] = []
13
-
14
14
  afterEach(() => {
15
15
  while (roots.length > 0) rmSync(roots.pop()!, { recursive: true, force: true })
16
16
  })
@@ -21,134 +21,114 @@ function fixtureRoot(label: string): string {
21
21
  mkdirSync(join(root, 'schema'), { recursive: true })
22
22
  writeFileSync(join(root, 'package.json'), '{"type":"module"}\n')
23
23
  writeFileSync(join(root, 'astrale.config.ts'), 'export default {}\n')
24
- return root
25
- }
26
-
27
- function linkCurrentSdk(root: string): void {
28
24
  const sdk = realpathSync(join(import.meta.dir, '../../../node_modules/@astrale-os/sdk'))
29
25
  const scope = join(root, 'node_modules', '@astrale-os')
30
26
  mkdirSync(scope, { recursive: true })
31
27
  symlinkSync(sdk, join(scope, 'sdk'), 'dir')
28
+ return root
32
29
  }
33
30
 
34
31
  function currentFixture(): DomainHandle {
35
32
  const root = fixtureRoot('canonical-runtime')
36
- linkCurrentSdk(root)
37
- const schemaIndex = join(root, 'schema', 'index.ts')
38
- const domainFile = join(root, 'implementation.ts')
33
+ const schemaIndex = join(root, 'schema/index.ts')
34
+ const applicationFile = join(root, 'application.ts')
39
35
  writeFileSync(
40
36
  schemaIndex,
41
37
  `
42
- import {
43
- defineSchema, domain, edge, edgeClass, fn, node, nodeClass,
44
- nodeInterface, output, property, view,
45
- } from '@astrale-os/sdk/schema'
46
-
47
- const Named = nodeInterface()
48
- export const Directory = defineSchema('directory.runtime.test', {
49
- interfaces: { Named },
50
- })
51
-
52
- const rename = fn({
53
- input: {
54
- type: 'object', properties: { title: { type: 'string' } },
55
- required: ['title'], additionalProperties: false,
56
- },
57
- output: { type: 'boolean' },
58
- auth: 'authenticated',
59
- })
60
- const Document = nodeClass({
61
- implements: [Named],
62
- properties: { title: property({ type: 'string' }, { required: true }) },
63
- methods: { rename },
64
- })
65
- const owned_by = edgeClass.directed({
66
- source: { as: 'document', accepts: [Document], outgoing: '0..*' },
67
- target: { as: 'owner', accepts: [Document], incoming: '0..*' },
68
- })
69
- const welcome = node(Document, { title: 'Welcome' })
70
-
71
- export const schema = defineSchema('documents.runtime.test', {
72
- dependencies: [Directory],
73
- classes: { Document, owned_by },
74
- functions: {
75
- exportAll: fn({
76
- input: { type: 'object', properties: {}, required: [], additionalProperties: false },
77
- output: output.binary(),
78
- auth: 'authenticated',
79
- }),
80
- },
81
- views: { editor: view({ target: Document, auth: 'optional' }) },
82
- core: {
83
- nodes: { welcome },
84
- edges: [edge(welcome, owned_by, domain(), {})],
85
- },
86
- })
87
- `,
38
+ import { bundle, core, defineSchema, nodeClass, view } from '@astrale-os/sdk/schema'
39
+ const Named = nodeClass({ properties: {} })
40
+ export const DirectorySchema = defineSchema('directory.runtime.test', {
41
+ classes: { Named },
42
+ })
43
+ const Document = nodeClass({ extends: [Named], properties: {} })
44
+ const welcome = core.node(Document, {})
45
+ export const schema = defineSchema('documents.runtime.test', {
46
+ dependencies: { directory: DirectorySchema },
47
+ classes: { Document },
48
+ views: { editor: view({ target: Document }) },
49
+ core: { nodes: { welcome } },
50
+ })
51
+ export const installedBundle = bundle.create(schema)
52
+ `,
88
53
  )
89
- // Canonical core extraction must not import the effectful composition entry.
90
- writeFileSync(domainFile, `throw new Error('composition entry was imported')\n`)
54
+ writeFileSync(applicationFile, `throw new Error('Application entry was imported')\n`)
91
55
  return {
92
56
  id: 'documents-runtime-test',
93
57
  root,
94
58
  configFile: join(root, 'astrale.config.ts'),
95
- domainFile,
59
+ applicationFile,
96
60
  schemaDirName: 'schema',
97
61
  schemaDir: join(root, 'schema'),
98
62
  schemaIndex,
99
63
  }
100
64
  }
101
65
 
102
- describe('current SDK schema extractor', () => {
103
- test('resolves the domain SDK, returns its raw root, and projects current members', async () => {
66
+ describe('SDK V1 schema extractor', () => {
67
+ test('uses the authored SDK for admission and projects exact imported Classes', async () => {
104
68
  const handle = currentFixture()
105
69
  const result = await runtimeExtract(handle.schemaIndex, handle.root)
106
-
107
- expect(result.ok).toBe(true)
108
- expect(result.root).toMatchObject({
109
- format: 'astrale.dsl',
110
- version: 'v1',
111
- origin: 'documents.runtime.test',
112
- })
113
- expect(result.ir).toMatchObject({
114
- format: 'astrale.dsl',
115
- domain: 'documents.runtime.test',
116
- functions: {
117
- exportAll: {
118
- static: true,
119
- inheritance: 'default',
120
- output: { mode: 'binary' },
121
- },
70
+ expect(result).toMatchObject({
71
+ ok: true,
72
+ schemaMode: 'canonical-admitted',
73
+ root: {
74
+ format: 'astrale.dsl',
75
+ version: 'v1',
76
+ origin: 'documents.runtime.test',
122
77
  },
123
- views: {
124
- editor: {
125
- auth: 'optional',
126
- target: { kind: 'definition' },
78
+ ir: {
79
+ domain: 'documents.runtime.test',
80
+ views: { editor: { auth: 'required', target: { kind: 'definition' } } },
81
+ importsByKey: {
82
+ 'directory.runtime.test:class.Named': {
83
+ ref: { origin: 'directory.runtime.test', kind: 'class', name: 'Named' },
84
+ },
127
85
  },
128
86
  },
129
87
  })
130
- expect(result.importedInterfaces?.Named).toMatchObject({
131
- name: 'Named',
132
- origin: 'directory.runtime.test',
133
- })
88
+ expect(result.revision).toMatch(/^sha256:[0-9a-f]{64}$/)
134
89
  })
135
90
 
136
- test('hashes the raw canonical root instead of the render projection', async () => {
91
+ test('transports the DSL revision while keeping render identity separate', async () => {
137
92
  const handle = currentFixture()
138
93
  const extracted = await runtimeExtract(handle.schemaIndex, handle.root)
139
- expect(extracted.ok).toBe(true)
140
-
141
- const bundle = await buildBundle(handle)
142
- expect(bundle.schemaRoot).toEqual(extracted.root)
143
- expect(bundle.schemaHash).toBe(schemaHashOf(extracted.root))
144
- expect(bundle.schemaHash).not.toBe(schemaHashOf(extracted.ir))
94
+ if (extracted.revision === null) throw new Error('expected an admitted Schema revision')
95
+ const built = await buildBundle(handle)
96
+ expect(built.schemaRoot).toEqual(extracted.root)
97
+ expect(built.schemaRevision).toBe(extracted.revision)
98
+ expect(built.renderFingerprint).toBe(renderFingerprintOf(extracted.root))
99
+ expect(built.renderFingerprint).not.toBe(renderFingerprintOf(extracted.ir))
145
100
  })
146
101
 
147
- test('extracts canonical core without importing implementation.ts', async () => {
102
+ test('re-admits installed Bundle JSON before comparing its revision', async () => {
148
103
  const handle = currentFixture()
149
- const result = await coreExtract(handle.schemaIndex, handle.domainFile, handle.root)
104
+ const extracted = await runtimeExtract(handle.schemaIndex, handle.root)
105
+ if (extracted.revision === null) throw new Error('expected an admitted Schema revision')
106
+ const fixture = (await import(handle.schemaIndex)) as { installedBundle: unknown }
107
+ const installedWire = JSON.parse(JSON.stringify(fixture.installedBundle))
108
+ expect(await admittedBundleRevision(handle.root, installedWire)).toBe(extracted.revision)
109
+ })
150
110
 
151
- expect(result).toEqual({
111
+ test('renders a V1-shaped root as preview when SDK admission fails', async () => {
112
+ const root = fixtureRoot('canonical-preview')
113
+ const schemaIndex = join(root, 'schema/index.ts')
114
+ writeFileSync(
115
+ schemaIndex,
116
+ `export const schema = {
117
+ format: 'astrale.dsl', version: 'v1', origin: 'not an origin',
118
+ dependencies: {}, classes: {}, functions: {}, policies: {}, views: {},
119
+ core: { nodes: {}, edges: [] },
120
+ }\n`,
121
+ )
122
+ expect(await runtimeExtract(schemaIndex, root)).toMatchObject({
123
+ ok: true,
124
+ schemaMode: 'canonical-preview',
125
+ revision: null,
126
+ })
127
+ })
128
+
129
+ test('extracts Core through the pure Schema entry without importing Application', async () => {
130
+ const handle = currentFixture()
131
+ expect(await coreExtract(handle.schemaIndex, handle.root)).toEqual({
152
132
  ok: true,
153
133
  core: {
154
134
  domain: 'documents.runtime.test',
@@ -156,62 +136,22 @@ describe('current SDK schema extractor', () => {
156
136
  {
157
137
  path: '/:documents.runtime.test:core.welcome',
158
138
  className: 'Document',
159
- data: { 'documents.runtime.test:class.Document.property.title': 'Welcome' },
160
- },
161
- ],
162
- edges: [
163
- {
164
- from: '/:documents.runtime.test:core.welcome',
165
- to: '/:documents.runtime.test',
166
- edgeName: 'owned_by',
167
139
  data: {},
168
140
  },
169
141
  ],
142
+ edges: [],
170
143
  },
171
144
  })
172
145
  })
173
146
  })
174
147
 
175
- test('core extractor preserves the legacy defineCore fallback', async () => {
176
- const root = fixtureRoot('legacy-core')
177
- const schemaIndex = join(root, 'schema', 'index.ts')
178
- const domainFile = join(root, 'domain.ts')
179
- writeFileSync(schemaIndex, `export const schema = { domain: 'legacy.runtime.test' }\n`)
180
- writeFileSync(
181
- domainFile,
182
- `
183
- const Item = { config: { name: 'Item' } }
184
- const linked = { config: { name: 'linked' } }
185
- const schema = { interfaces: {}, classes: { Item, linked }, imports: [] }
186
- export const core = {
187
- domain: 'legacy.runtime.test', schema,
188
- __nodes: [
189
- { path: '/legacy/left', def: Item, data: { name: 'Left' } },
190
- { path: '/legacy/right', def: Item, data: { name: 'Right' } },
191
- ],
192
- __edges: [
193
- { from: '/legacy/left', to: '/legacy/right', edge: linked, data: { order: 1 } },
194
- ],
195
- }
196
- `,
197
- )
198
-
199
- expect(await coreExtract(schemaIndex, domainFile, root)).toEqual({
200
- ok: true,
201
- core: {
202
- domain: 'legacy.runtime.test',
203
- nodes: [
204
- { path: '/legacy/left', className: 'Item', data: { name: 'Left' } },
205
- { path: '/legacy/right', className: 'Item', data: { name: 'Right' } },
206
- ],
207
- edges: [
208
- {
209
- from: '/legacy/left',
210
- to: '/legacy/right',
211
- edgeName: 'linked',
212
- data: { order: 1 },
213
- },
214
- ],
215
- },
148
+ test('rejects the removed compiled-IR compatibility envelope', async () => {
149
+ const root = fixtureRoot('removed-runtime')
150
+ const schemaIndex = join(root, 'schema/index.ts')
151
+ writeFileSync(schemaIndex, `export const D = { $: { ir: { domain: 'legacy' } } }\n`)
152
+ expect(await runtimeExtract(schemaIndex, root)).toMatchObject({
153
+ ok: false,
154
+ schemaMode: 'unavailable',
155
+ revision: null,
216
156
  })
217
157
  })
@@ -5,7 +5,9 @@
5
5
  * render IR plus the raw canonical root (when present), or an error render-state
6
6
  * — never throws.
7
7
  */
8
- import type { IrInterface, SchemaIR, StudioCore } from '../../shared/types'
8
+ import type { SchemaIR, SchemaRevision, StudioCore, StudioSchemaBundle } from '../../shared/types'
9
+
10
+ import { isSchemaRevision } from '../../shared/types'
9
11
 
10
12
  const EXTRACTOR = new URL('./extractor.ts', import.meta.url).pathname
11
13
  const CORE_EXTRACTOR = new URL('./core-extractor.ts', import.meta.url).pathname
@@ -13,10 +15,11 @@ const CORE_EXTRACTOR = new URL('./core-extractor.ts', import.meta.url).pathname
13
15
  export interface RuntimeExtractResult {
14
16
  ok: boolean
15
17
  ir: SchemaIR | null
16
- /** Exact canonical V1 root. Null for legacy `D.$.ir` domains and failures. */
18
+ /** Portable canonical V1 document. Null only for failures. */
17
19
  root: unknown | null
18
- /** member bodies of imported (kernel + cross-domain) interfaces, by name */
19
- importedInterfaces?: Record<string, IrInterface>
20
+ schemaMode: StudioSchemaBundle['schemaMode']
21
+ /** Present only when the Domain's installed SDK admitted `root`. */
22
+ revision: SchemaRevision | null
20
23
  error?: { message: string }
21
24
  }
22
25
 
@@ -42,6 +45,8 @@ export async function runtimeExtract(
42
45
  ok: false,
43
46
  ir: null,
44
47
  root: null,
48
+ schemaMode: 'unavailable',
49
+ revision: null,
45
50
  error: { message: err.trim() || 'extractor produced no output' },
46
51
  }
47
52
  }
@@ -51,16 +56,42 @@ export async function runtimeExtract(
51
56
  ok: false,
52
57
  ir: null,
53
58
  root: null,
59
+ schemaMode: 'unavailable',
60
+ revision: null,
54
61
  error: parsed.error ?? { message: 'extraction failed' },
55
62
  }
63
+ const schemaMode = parsed.schemaMode
64
+ const revision = parsed.revision
65
+ const validMode = schemaMode === 'canonical-admitted' || schemaMode === 'canonical-preview'
66
+ const validRevision =
67
+ schemaMode === 'canonical-admitted' ? isSchemaRevision(revision) : revision == null
68
+ const validRoot = parsed.root !== null && parsed.root !== undefined
69
+ if (!validMode || !validRevision || !validRoot) {
70
+ return {
71
+ ok: false,
72
+ ir: null,
73
+ root: null,
74
+ schemaMode: 'unavailable',
75
+ revision: null,
76
+ error: { message: 'extractor produced an invalid schema admission envelope' },
77
+ }
78
+ }
56
79
  return {
57
80
  ok: true,
58
81
  ir: parsed.ir as SchemaIR,
59
82
  root: parsed.root ?? null,
60
- importedInterfaces: (parsed.importedInterfaces ?? {}) as Record<string, IrInterface>,
83
+ schemaMode,
84
+ revision: revision ?? null,
61
85
  }
62
86
  } catch (e: any) {
63
- return { ok: false, ir: null, root: null, error: { message: String(e?.message ?? e) } }
87
+ return {
88
+ ok: false,
89
+ ir: null,
90
+ root: null,
91
+ schemaMode: 'unavailable',
92
+ revision: null,
93
+ error: { message: String(e?.message ?? e) },
94
+ }
64
95
  }
65
96
  }
66
97
 
@@ -72,18 +103,16 @@ export interface CoreExtractResult {
72
103
  }
73
104
 
74
105
  /**
75
- * Spawn the core-extractor island over the pure schema entry first, retaining the
76
- * composition entry only as the legacy `defineCore` fallback. Returns the
77
- * resolved core graph or an error — never throws.
106
+ * Spawn the Core extractor over the pure Schema entry. Returns the projected
107
+ * graph or an error and never imports Application or Runtime modules.
78
108
  */
79
109
  export async function coreExtract(
80
110
  schemaIndexPath: string,
81
- domainFile: string,
82
111
  domainDir: string,
83
112
  timeoutMs = 20000,
84
113
  ): Promise<CoreExtractResult> {
85
114
  try {
86
- const proc = Bun.spawn(['bun', 'run', CORE_EXTRACTOR, schemaIndexPath, domainFile, domainDir], {
115
+ const proc = Bun.spawn(['bun', 'run', CORE_EXTRACTOR, schemaIndexPath, domainDir], {
87
116
  cwd: domainDir,
88
117
  stdout: 'pipe',
89
118
  stderr: 'pipe',