@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.
Files changed (345) hide show
  1. package/README.md +84 -6
  2. package/dist/astrale.js +57586 -60753
  3. package/dist/public/connect-core.js +2158 -30706
  4. package/dist/public/keys/index.js +1016 -29541
  5. package/dist/public/paths/index.js +370 -28654
  6. package/dist/types/admin/contract.d.ts +26 -0
  7. package/dist/types/admin/instance/client.d.ts +20 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +6 -10
  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 +11 -36
  28. package/dist/types/lib/config.d.ts +13 -59
  29. package/dist/types/lib/failure-debug.d.ts +1 -0
  30. package/dist/types/lib/idp.d.ts +25 -173
  31. package/dist/types/lib/instance-target.d.ts +1 -1
  32. package/dist/types/lib/instance.d.ts +30 -88
  33. package/dist/types/lib/log.d.ts +5 -3
  34. package/dist/types/lib/output.d.ts +1 -1
  35. package/dist/types/lib/proc.d.ts +43 -0
  36. package/dist/types/lib/self.d.ts +9 -0
  37. package/dist/types/lib/update.d.ts +109 -0
  38. package/dist/types/lib/validation.d.ts +4 -1
  39. package/dist/types/state/exchange-credentials.d.ts +6 -2
  40. package/dist/types/state/files.d.ts +2 -0
  41. package/dist/types/state/index.d.ts +3 -2
  42. package/dist/types/state/paths.d.ts +2 -0
  43. package/dist/types/state/session-routes.d.ts +10 -0
  44. package/package.json +16 -19
  45. package/src/__tests__/fixtures/publication.ts +20 -0
  46. package/src/admin/.spec/architecture.md +12 -5
  47. package/src/admin/__tests__/fixture.ts +25 -0
  48. package/src/admin/catalog/.spec/api.d.ts +1 -3
  49. package/src/admin/catalog/.spec/architecture.md +5 -4
  50. package/src/admin/catalog/__tests__/client.test.ts +143 -69
  51. package/src/admin/catalog/client.ts +40 -54
  52. package/src/admin/catalog/model.ts +3 -4
  53. package/src/admin/contract.ts +47 -0
  54. package/src/admin/graph/.spec/api.d.ts +4 -10
  55. package/src/admin/graph/nodes.ts +1 -1
  56. package/src/admin/instance/.spec/api.d.ts +5 -9
  57. package/src/admin/instance/.spec/architecture.md +7 -7
  58. package/src/admin/instance/__tests__/client.test.ts +157 -175
  59. package/src/admin/instance/client.ts +39 -128
  60. package/src/admin/instance/index.ts +1 -2
  61. package/src/admin/instance/model.ts +12 -18
  62. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  63. package/src/commands/__tests__/call-describe.test.ts +46 -33
  64. package/src/commands/__tests__/call.test.ts +34 -0
  65. package/src/commands/__tests__/domain-install-operation.test.ts +30 -22
  66. package/src/commands/__tests__/domain-install-owned.test.ts +1 -1
  67. package/src/commands/__tests__/domain-list.test.ts +5 -25
  68. package/src/commands/__tests__/install-direct.test.ts +115 -8
  69. package/src/commands/__tests__/install-identity-override.test.ts +6 -17
  70. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  71. package/src/commands/__tests__/instance-status.test.ts +139 -0
  72. package/src/commands/__tests__/introspect-parse.test.ts +80 -1
  73. package/src/commands/__tests__/logs.test.ts +250 -2
  74. package/src/commands/__tests__/read-commands.test.ts +119 -11
  75. package/src/commands/__tests__/token-ttl.test.ts +49 -4
  76. package/src/commands/__tests__/update.test.ts +25 -3
  77. package/src/commands/__tests__/view.test.ts +50 -2
  78. package/src/commands/auth/logout.ts +2 -1
  79. package/src/commands/browser.ts +29 -0
  80. package/src/commands/call-describe.ts +60 -68
  81. package/src/commands/call.ts +71 -59
  82. package/src/commands/domain/install.ts +73 -46
  83. package/src/commands/domain/list.ts +1 -1
  84. package/src/commands/domain/publish.ts +14 -11
  85. package/src/commands/domain/uninstall.ts +2 -2
  86. package/src/commands/get.ts +15 -16
  87. package/src/commands/identity/__tests__/register.test.ts +3 -3
  88. package/src/commands/identity/register.ts +8 -8
  89. package/src/commands/instance/create.ts +8 -16
  90. package/src/commands/instance/delete.ts +12 -9
  91. package/src/commands/instance/list.ts +2 -2
  92. package/src/commands/instance/status.ts +66 -20
  93. package/src/commands/instance/use.ts +16 -12
  94. package/src/commands/introspect.ts +53 -41
  95. package/src/commands/logs.ts +123 -36
  96. package/src/commands/mutate.ts +6 -5
  97. package/src/commands/query.ts +39 -36
  98. package/src/commands/session/analyze.ts +26 -4
  99. package/src/commands/token.ts +42 -27
  100. package/src/commands/ui/__tests__/commands.test.ts +152 -0
  101. package/src/commands/ui/add.ts +51 -0
  102. package/src/commands/ui/doctor.ts +21 -0
  103. package/src/commands/ui/init.ts +38 -0
  104. package/src/commands/ui/list.ts +26 -0
  105. package/src/commands/ui/preset-apply.ts +19 -0
  106. package/src/commands/ui/preset-list.ts +12 -0
  107. package/src/commands/ui/shared.ts +25 -0
  108. package/src/commands/update.ts +90 -48
  109. package/src/commands/view.ts +82 -37
  110. package/src/connection/.spec/api.d.ts +7 -8
  111. package/src/connection/.spec/architecture.md +14 -5
  112. package/src/connection/.spec/flows/session.ts +2 -2
  113. package/src/connection/.spec/laws/connection.ts +6 -2
  114. package/src/connection/.spec/layout.ts +1 -0
  115. package/src/connection/__tests__/auth.test.ts +1 -0
  116. package/src/connection/__tests__/credential.test.ts +21 -1
  117. package/src/connection/__tests__/errors.test.ts +27 -20
  118. package/src/connection/__tests__/exchange.test.ts +64 -11
  119. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  120. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  121. package/src/connection/__tests__/self.test.ts +31 -11
  122. package/src/connection/__tests__/session.test.ts +8 -4
  123. package/src/connection/__tests__/target.test.ts +2 -0
  124. package/src/connection/auth.ts +13 -0
  125. package/src/connection/call.ts +1 -1
  126. package/src/connection/credential.ts +2 -2
  127. package/src/connection/errors.ts +1 -355
  128. package/src/connection/exchange.ts +110 -61
  129. package/src/connection/failure/classify.ts +110 -0
  130. package/src/connection/failure/index.ts +18 -0
  131. package/src/connection/failure/model.ts +28 -0
  132. package/src/connection/failure/render.ts +116 -0
  133. package/src/connection/reasons.ts +16 -0
  134. package/src/connection/self.ts +39 -21
  135. package/src/connection/session.ts +27 -9
  136. package/src/errors.ts +3 -2
  137. package/src/graph/.spec/api.d.ts +13 -6
  138. package/src/graph/.spec/laws/documents.ts +7 -7
  139. package/src/graph/.spec/layout.ts +9 -1
  140. package/src/graph/__tests__/mutation.test.ts +2 -2
  141. package/src/graph/__tests__/query.test.ts +35 -9
  142. package/src/graph/class.ts +30 -0
  143. package/src/graph/index.ts +1 -0
  144. package/src/graph/query.ts +27 -40
  145. package/src/identity/.spec/api.d.ts +2 -2
  146. package/src/identity/__tests__/fixtures/registry-journey.ts +13 -1
  147. package/src/identity/__tests__/registration.test.ts +1 -1
  148. package/src/identity/__tests__/registry.test.ts +4 -0
  149. package/src/identity/registration.ts +3 -3
  150. package/src/identity/registry.ts +2 -0
  151. package/src/keys/__tests__/keys.test.ts +4 -0
  152. package/src/keys/credential.ts +1 -0
  153. package/src/lib/__tests__/admin-target.test.ts +12 -0
  154. package/src/lib/__tests__/binary.test.ts +16 -1
  155. package/src/lib/__tests__/browser-retention.test.ts +212 -0
  156. package/src/lib/__tests__/command-dx.test.ts +1 -1
  157. package/src/lib/__tests__/config.test.ts +27 -0
  158. package/src/lib/__tests__/domain-publication.test.ts +10 -16
  159. package/src/lib/__tests__/idp.test.ts +34 -4
  160. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  161. package/src/lib/__tests__/instance-target.test.ts +7 -39
  162. package/src/lib/__tests__/log-errors.test.ts +64 -0
  163. package/src/lib/__tests__/skills.test.ts +834 -0
  164. package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
  165. package/src/lib/__tests__/update.test.ts +264 -11
  166. package/src/lib/__tests__/view-assets.test.ts +25 -0
  167. package/src/lib/__tests__/view-external-open-intent.test.ts +150 -0
  168. package/src/lib/__tests__/view-external-open-origins.test.ts +27 -0
  169. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  170. package/src/lib/__tests__/view-server.test.ts +26 -3
  171. package/src/lib/__tests__/view-session.test.ts +2 -1
  172. package/src/lib/admin-instance.ts +14 -8
  173. package/src/lib/admin-target.ts +21 -2
  174. package/src/lib/binary.ts +22 -5
  175. package/src/lib/browser-retention.ts +210 -0
  176. package/src/lib/command-dx.ts +9 -9
  177. package/src/lib/config.ts +12 -1
  178. package/src/lib/domain-publication.ts +9 -7
  179. package/src/lib/failure-debug.ts +26 -0
  180. package/src/lib/idp.ts +34 -3
  181. package/src/lib/instance-candidates.ts +2 -2
  182. package/src/lib/instance-target.ts +3 -14
  183. package/src/lib/instance.ts +16 -11
  184. package/src/lib/log.ts +16 -9
  185. package/src/lib/output.ts +1 -1
  186. package/src/lib/proc.ts +7 -2
  187. package/src/lib/provision-instance.ts +34 -57
  188. package/src/lib/skills/lock.ts +117 -0
  189. package/src/lib/skills/sync.ts +878 -0
  190. package/src/lib/skills.ts +1 -52
  191. package/src/lib/update.ts +298 -45
  192. package/src/lib/validation.ts +2 -2
  193. package/src/lib/view/assets.ts +11 -2
  194. package/src/lib/view/external-open-intent.ts +41 -0
  195. package/src/lib/view/external-open-origins.ts +37 -0
  196. package/src/lib/view/host-capabilities.ts +17 -0
  197. package/src/lib/view/resolve.ts +1 -1
  198. package/src/lib/view/server.ts +18 -3
  199. package/src/lib/view/session.ts +2 -0
  200. package/src/program/.spec/api.d.ts +1 -0
  201. package/src/program/__tests__/program.test.ts +201 -7
  202. package/src/program/argv.ts +14 -0
  203. package/src/program/build.ts +26 -4
  204. package/src/program/command.ts +1 -0
  205. package/src/program/index.ts +1 -0
  206. package/src/program/registry.ts +2 -1
  207. package/src/setup/__tests__/instance-step.test.ts +27 -10
  208. package/src/setup/steps/instance.ts +22 -15
  209. package/src/setup/steps/skills.ts +40 -38
  210. package/src/state/.spec/api.d.ts +21 -2
  211. package/src/state/.spec/architecture.md +18 -4
  212. package/src/state/.spec/layout.ts +1 -0
  213. package/src/state/__tests__/exchange-credentials.test.ts +88 -42
  214. package/src/state/__tests__/files.test.ts +24 -1
  215. package/src/state/__tests__/fixtures/session-route-process.ts +93 -0
  216. package/src/state/__tests__/paths.test.ts +1 -0
  217. package/src/state/__tests__/session-routes.test.ts +138 -0
  218. package/src/state/exchange-credentials.ts +22 -9
  219. package/src/state/files.ts +41 -0
  220. package/src/state/index.ts +3 -1
  221. package/src/state/paths.ts +3 -0
  222. package/src/state/session-routes.ts +34 -0
  223. package/src/telemetry/__tests__/analyze-log.test.ts +38 -0
  224. package/src/telemetry/__tests__/recorder.test.ts +1 -0
  225. package/src/telemetry/__tests__/retention.test.ts +267 -0
  226. package/src/telemetry/__tests__/settings.test.ts +102 -0
  227. package/src/telemetry/__tests__/store-scan.test.ts +128 -0
  228. package/src/telemetry/__tests__/trigger.test.ts +33 -4
  229. package/src/telemetry/analyze.ts +24 -2
  230. package/src/telemetry/recorder.ts +15 -4
  231. package/src/telemetry/retention.ts +176 -0
  232. package/src/telemetry/session.ts +18 -12
  233. package/src/telemetry/settings.ts +64 -11
  234. package/src/telemetry/store.ts +92 -9
  235. package/src/telemetry/trigger.ts +16 -28
  236. package/src/ui/.spec/api.d.ts +14 -0
  237. package/src/ui/.spec/architecture.md +14 -0
  238. package/src/ui/.spec/laws.ts +50 -0
  239. package/src/ui/.spec/layout.ts +16 -0
  240. package/src/ui/__tests__/ui.test.ts +1742 -0
  241. package/src/ui/index.ts +13 -0
  242. package/src/ui/lock.ts +89 -0
  243. package/src/ui/model.ts +83 -0
  244. package/src/ui/operations.ts +1044 -0
  245. package/src/ui/project.ts +333 -0
  246. package/src/ui/release.ts +398 -0
  247. package/src/ui/runner.ts +18 -0
  248. package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
  249. package/studio/client/dist/assets/index-BFVFs_8x.js +81 -0
  250. package/studio/client/dist/assets/index-DuB9iUdu.css +2 -0
  251. package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  252. package/studio/client/dist/assets/schema-studio--a0kX3QU.css +1 -0
  253. package/studio/client/dist/assets/schema-studio-DH6oEWME.js +8 -0
  254. package/studio/client/dist/index.html +4 -3
  255. package/studio/package.json +8 -14
  256. package/studio/server/agent/ask.test.ts +1 -1
  257. package/studio/server/agent/bridge/grant.test.ts +1 -1
  258. package/studio/server/agent/bridge/routes.test.ts +1 -1
  259. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  260. package/studio/server/agent/harness/gateway/token.test.ts +1 -1
  261. package/studio/server/agent/harness/gateway/token.ts +3 -3
  262. package/studio/server/agent/prompts/anchors.test.ts +41 -32
  263. package/studio/server/agent/prompts/anchors.ts +23 -51
  264. package/studio/server/agent/prompts/system.test.ts +4 -4
  265. package/studio/server/agent/prompts/system.ts +5 -5
  266. package/studio/server/agent/routes.test.ts +1 -1
  267. package/studio/server/agent/run/coordinator.test.ts +1 -1
  268. package/studio/server/agent/run/preparation.ts +1 -1
  269. package/studio/server/api/canvas.ts +0 -1
  270. package/studio/server/api/context.ts +1 -1
  271. package/studio/server/api/deployment.ts +1 -1
  272. package/studio/server/api/views.ts +2 -2
  273. package/studio/server/api/workspace.ts +1 -1
  274. package/studio/server/api-agent-loadout.test.ts +1 -1
  275. package/studio/server/api.test.ts +1 -1
  276. package/studio/server/cache.test.ts +24 -18
  277. package/studio/server/cache.ts +10 -54
  278. package/studio/server/cli-consumers.test.ts +32 -4
  279. package/studio/server/cli.test.ts +2 -2
  280. package/studio/server/domain.test.ts +50 -68
  281. package/studio/server/domain.ts +82 -63
  282. package/studio/server/handoff/copy.ts +2 -2
  283. package/studio/server/index.ts +1 -1
  284. package/studio/server/instances/probe.test.ts +1 -1
  285. package/studio/server/introspect/anatomy/views/routes.ts +46 -37
  286. package/studio/server/introspect/anatomy/views.ts +10 -16
  287. package/studio/server/introspect/anatomy-extras.test.ts +29 -56
  288. package/studio/server/introspect/anatomy.test.ts +22 -14
  289. package/studio/server/introspect/anatomy.ts +6 -9
  290. package/studio/server/introspect/bundle.ts +0 -3
  291. package/studio/server/introspect/canonical-schema.test.ts +155 -424
  292. package/studio/server/introspect/canonical-schema.ts +248 -601
  293. package/studio/server/introspect/core.ts +14 -22
  294. package/studio/server/introspect/diff.test.ts +21 -9
  295. package/studio/server/introspect/diff.ts +19 -64
  296. package/studio/server/introspect/extractor.ts +23 -122
  297. package/studio/server/introspect/overlay-tsmorph.test.ts +116 -241
  298. package/studio/server/introspect/overlay-tsmorph.ts +0 -1
  299. package/studio/server/introspect/overlay.ts +3 -51
  300. package/studio/server/introspect/revision.test.ts +24 -28
  301. package/studio/server/introspect/revision.ts +11 -22
  302. package/studio/server/introspect/runtime.test.ts +77 -195
  303. package/studio/server/introspect/runtime.ts +5 -67
  304. package/studio/server/introspect/schema-ir-json.test.ts +81 -0
  305. package/studio/server/introspect/schema-ir-json.ts +39 -69
  306. package/studio/server/introspect/schema-refs.test.ts +43 -88
  307. package/studio/server/introspect/schema-refs.ts +14 -49
  308. package/studio/server/introspect/source-overlay/handlers.ts +116 -636
  309. package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -3
  310. package/studio/server/introspect/source-overlay/spans.ts +15 -45
  311. package/studio/server/lifecycle.ts +4 -1
  312. package/studio/server/state/baseline.test.ts +14 -9
  313. package/studio/server/state/baseline.ts +3 -5
  314. package/studio/server/state/documents.test.ts +69 -0
  315. package/studio/server/state/documents.ts +57 -10
  316. package/studio/server/state/visibility.ts +1 -5
  317. package/studio/server/views/model.ts +3 -3
  318. package/studio/server/views/target.test.ts +18 -76
  319. package/studio/server/views/target.ts +25 -51
  320. package/studio/server/watch.test.ts +11 -11
  321. package/studio/server/watch.ts +8 -4
  322. package/studio/server/workspace/updates.ts +23 -1
  323. package/studio/server/workspace-watch.ts +2 -2
  324. package/studio/shared/contracts/runtime.ts +4 -0
  325. package/studio/shared/contracts/schema.ts +44 -131
  326. package/studio/shared/contracts/surface.test.ts +15 -17
  327. package/studio/shared/contracts/workspace.ts +5 -11
  328. package/studio/shared/schema/identity.test.ts +20 -44
  329. package/studio/shared/schema/identity.ts +9 -24
  330. package/studio/tsconfig.json +2 -1
  331. package/tsconfig.json +1 -1
  332. package/viewer/dist/index.html +21 -0
  333. package/viewer/dist/main.js +41 -62
  334. package/.check-workspace.cjs +0 -40
  335. package/src/admin/binding.ts +0 -168
  336. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  337. package/studio/client/dist/assets/elk-api-lwhFo7vB.js +0 -1
  338. package/studio/client/dist/assets/index-B-c-smo9.js +0 -8
  339. package/studio/client/dist/assets/index-BckHuAWk.js +0 -81
  340. package/studio/client/dist/assets/index-C4aNQ6dz.css +0 -1
  341. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  342. package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
  343. package/studio/server/introspect/core-extractor.ts +0 -139
  344. package/studio/server/introspect/overlay.test.ts +0 -72
  345. 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' | 'interface' | 'edge' | 'function'> = {
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 both legacy `edgeClass(...)` and current
69
- * `edgeClass.directed/undirected({...})` authoring forms. */
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
- * The declaration helpers (nodeClass/nodeInterface/edgeClass) carry no name a
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: 'interface' | 'class' | 'function' // the `classes` map also holds edge classes
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
- /** Legacy fallback when a symbol cannot be resolved. */
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: 'interfaces' | 'classes' | 'functions',
149
- section: 'interface' | 'class' | 'function',
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 ('class' | 'interface' | 'edge') for a declared member.
167
- * The `defineSchema` SECTION is authoritative for interface-vs-class — a
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: 'interface' | 'class' | 'function' | undefined,
177
- helperKind: 'node' | 'interface' | 'edge' | 'function',
178
- ): 'class' | 'interface' | 'edge' | 'function' {
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 domain's `defineSchema` map is authoritative for each member's name +
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 `edge.<Name>.endpoint.<role>` from the two args. */
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?.overlay.origin ?? handle.id,
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 implementation and semantic layer files alongside legacy anatomy', () => {
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
- 'handlers/risk',
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
- 'implementation.ts',
39
+ 'application.ts',
40
+ 'runtime.ts',
40
41
  'actions/risk/index.ts',
41
- 'handlers/risk/index.ts',
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
- 'handlers/risk/index.ts',
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
- imports: {},
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
- 'implementation.ts',
68
- 'domain.ts',
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 are
3
- * stored under `.domain-studio/context/documents/` (allow-listed) and tracked in
4
- * an index. They travel with the domain and are part of the agent handoff context.
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 storedPath = (id: string, name: string) => `context/documents/${id}${extname(name)}`
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('context/documents/') ||
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 id = randomUUID()
64
- const stored = storedPath(id, name)
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, and materialized-interface set). Sibling of
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:interface.Named.property.name'
8
- const DESCRIPTABLE_DESCRIPTION = 'kernel.astrale.ai:interface.Descriptable.property.description'
9
- const STATUSED_STATUS = 'kernel.astrale.ai:interface.Statused.property.status'
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('view target definitions', () => {
8
- test('preserves canonical interface View target coordinates', () => {
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: 'WrongLegacyTarget',
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: 'interface', name: 'Named' },
49
- { origin: 'people.example.dev', kind: 'interface', name: 'Named' },
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: 'interface' },
60
- { className: 'Named', classOrigin: 'people.example.dev', kind: 'interface' },
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 an exact Domain target as authoritative over legacy viewFor', () => {
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', auth: 'required', target: { kind: 'domain' } } } },
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('uses every exact fallback candidate across origin and definition-kind collisions', () => {
74
- const view = { slug: 'legacy-named', kind: 'unknown', viewFor: 'Named' } satisfies ViewInfo
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
- ref: { origin: 'shell.astrale.ai', kind: 'class', name: 'Named' },
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
- definition: 'class',
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('uses the short-name import only for legacy bundles without an exact index', () => {
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
  })