@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
@@ -0,0 +1,393 @@
1
+ /**
2
+ * Shared schema and introspection contracts.
3
+ *
4
+ * Studio's IR remains a lossy render projection. Canonical reference identity
5
+ * is owned by `../schema/identity`; SDK admission owns schema semantics.
6
+ */
7
+
8
+ import type { IrClassKey, IrClassRef, IrSchemaRef } from '../schema/identity'
9
+
10
+ export interface JsonSchema {
11
+ type?: string | string[]
12
+ enum?: (string | number | boolean | null)[]
13
+ properties?: Record<string, JsonSchema>
14
+ required?: string[]
15
+ items?: JsonSchema
16
+ additionalProperties?: boolean
17
+ minimum?: number
18
+ maximum?: number
19
+ format?: string
20
+ description?: string
21
+ $nodeRef?: unknown
22
+ $dataRef?: unknown
23
+ [k: string]: unknown
24
+ }
25
+
26
+ export type MethodInheritance = 'default' | 'abstract' | 'sealed'
27
+
28
+ /** Portable form of the DSL-owned canonical schema revision. */
29
+ export type SchemaRevision = `sha256:${string}`
30
+
31
+ /** Wire-format check only; SDK admission remains the semantic proof. */
32
+ export function isSchemaRevision(value: unknown): value is SchemaRevision {
33
+ return typeof value === 'string' && /^sha256:[0-9a-f]{64}$/.test(value)
34
+ }
35
+
36
+ /**
37
+ * Version of Studio's lossy canonical-schema -> render-IR projection. Persisted
38
+ * baselines must match this value before their IR can be compared.
39
+ */
40
+ export const STUDIO_SCHEMA_PROJECTION_VERSION = 1
41
+
42
+ export type IrCallableAuth = 'anonymous' | 'authenticated' | 'authorized'
43
+
44
+ export type IrCallableOutput =
45
+ | { mode: 'value'; schema: JsonSchema }
46
+ | { mode: 'stream'; item: JsonSchema }
47
+ | { mode: 'binary' }
48
+
49
+ export interface IrCallable {
50
+ name: string
51
+ input: JsonSchema
52
+ output: IrCallableOutput
53
+ description?: string
54
+ auth?: IrCallableAuth
55
+ policy?: unknown
56
+ }
57
+
58
+ export interface IrMethod extends IrCallable {
59
+ static: boolean
60
+ inheritance: MethodInheritance
61
+ }
62
+
63
+ /** Standalone DSL callable projected without inventing a receiver. */
64
+ export interface IrFunction extends IrCallable {}
65
+
66
+ export interface IrEndpoint {
67
+ name: string
68
+ types: string[]
69
+ /** Exact accepted Definition coordinates. `types` is the local display projection. */
70
+ refs?: IrSchemaRef[]
71
+ /** declared multiplicity for this end; max:null = unbounded ("many"). Absent ⇒ unconstrained. */
72
+ cardinality?: { min: number; max: number | null }
73
+ }
74
+
75
+ export interface IrClass {
76
+ type: 'node' | 'edge'
77
+ name: string
78
+ origin: string
79
+ ref: IrClassRef
80
+ extends?: string[]
81
+ extendsRefs?: IrClassRef[]
82
+ /** edges only: the two (source,target) endpoints with role names + allowed types */
83
+ endpoints?: IrEndpoint[]
84
+ orientation?: 'directed' | 'undirected'
85
+ constraints?: { noSelf?: true; acyclic?: true }
86
+ properties: Record<string, JsonSchema>
87
+ /** Canonical `properties.required`; absence, unlike null, encodes optionality. */
88
+ required?: string[]
89
+ methods: Record<string, IrMethod>
90
+ /** class-level icon: raw (lucide-style) SVG markup, `stroke="currentColor"` */
91
+ icon?: string
92
+ description?: string
93
+ propertyMetadata?: Record<string, unknown>
94
+ /** Canonical data declaration; `mediaType` is required and extensions stay lossless. */
95
+ data?: { mediaType: string; [key: string]: unknown }
96
+ policies?: Record<string, IrSchemaRef>
97
+ }
98
+
99
+ export interface IrImportDescriptor {
100
+ origin: string
101
+ ref: IrClassRef
102
+ key: IrClassKey
103
+ }
104
+
105
+ export type IrViewTarget = { kind: 'domain' } | { kind: 'definition'; definitions: IrSchemaRef[] }
106
+
107
+ export interface IrView {
108
+ name: string
109
+ target: IrViewTarget
110
+ auth: 'required' | 'optional' | 'public'
111
+ description?: string
112
+ }
113
+
114
+ export interface SchemaIR {
115
+ format: 'astrale.dsl'
116
+ version: string
117
+ domain: string
118
+ classes: Record<string, IrClass>
119
+ importsByKey: Record<IrClassKey, IrImportDescriptor>
120
+ importedClassesByKey: Record<IrClassKey, IrClass>
121
+ functions: Record<string, IrFunction>
122
+ views: Record<string, IrView>
123
+ policies: Record<string, unknown>
124
+ dependencies: Array<{ origin: string; revision: string }>
125
+ core: unknown
126
+ }
127
+
128
+ export interface HandlerLink {
129
+ owner: string
130
+ ownerKind: 'class' | 'function'
131
+ kind: 'action' | 'workflow'
132
+ method: string
133
+ static: boolean
134
+ /** The Runtime registry or one modular Action/Workflow file. */
135
+ wiringFile?: string
136
+ wiringLine?: number
137
+ /** the resolved handler file (followed from the `execute` import) */
138
+ handlerFile?: string
139
+ handlerLine?: number
140
+ /** kernel ops detected in the handler (::update, ::link, createNode, …) */
141
+ kernelCalls?: string[]
142
+ /** false ⇒ a todo()/NotImplemented stub → "contract-only" badge */
143
+ implemented: boolean
144
+ /** true ⇒ resolver could not link a file → "unlinked" badge */
145
+ unlinked?: boolean
146
+ }
147
+
148
+ export interface SourceSpan {
149
+ file: string
150
+ startLine: number
151
+ endLine: number
152
+ doc?: string
153
+ }
154
+
155
+ export interface SchemaAnnotation {
156
+ /** anchor ref key, e.g. 'class.Monitor.property.status' */
157
+ target: string
158
+ severity: 'warn' | 'info'
159
+ code: 'COMPILE_ERROR' | 'EDGE_PROP_TYPE_MISSING'
160
+ message: string
161
+ }
162
+
163
+ export interface CrossDomainImport {
164
+ name: string
165
+ origin: string
166
+ ref: IrClassRef
167
+ }
168
+
169
+ export interface SchemaOverlay {
170
+ origin: string
171
+ /** Exact declared Domain dependencies. */
172
+ requires: string[]
173
+ /** Non-Kernel imported Classes. */
174
+ crossDomainImports: CrossDomainImport[]
175
+ /** Kernel base Classes rendered as inherited platform facts. */
176
+ mixins: CrossDomainImport[]
177
+ handlerLinks: HandlerLink[]
178
+ /** Keyed by Class, Property, Method, Function, Policy, View, or Core anchor. */
179
+ sourceSpans: Record<string, SourceSpan>
180
+ annotations: SchemaAnnotation[]
181
+ }
182
+
183
+ export interface BundleError {
184
+ message: string
185
+ file?: string
186
+ }
187
+
188
+ export interface StudioSchemaBundle {
189
+ domainId: string
190
+ /** UI/cache identity only. This is not the DSL schema revision. */
191
+ renderFingerprint: string
192
+ schemaMode: 'canonical-admitted' | 'canonical-preview' | 'unavailable'
193
+ /** DSL-owned revision, present only after installed SDK admission. */
194
+ schemaRevision?: SchemaRevision
195
+ extractedBy: 'runtime-bun' | 'static-tsmorph-fallback'
196
+ depsInstalled: boolean
197
+ ir: SchemaIR | null
198
+ /**
199
+ * Portable canonical V1 document emitted by the domain. `schemaMode` records
200
+ * whether the installed SDK admitted it or Studio is rendering it as a structural
201
+ * preview. Kept separate from the lossy render IR.
202
+ */
203
+ schemaRoot?: unknown
204
+ overlay: SchemaOverlay
205
+ /** present when the runtime import failed to compile (render state, not a crash) */
206
+ error?: BundleError | null
207
+ extractedAt: string
208
+ }
209
+
210
+ export interface DomainOverview {
211
+ origin: string
212
+ /** Active SDK Application entry relative to the project root. */
213
+ applicationFile?: string
214
+ adapter: 'astrale' | 'cloudflare' | 'unknown'
215
+ prodTarget?: string
216
+ devSecrets?: string
217
+ requires: string[]
218
+ packageName?: string
219
+ packageVersion?: string
220
+ astraleDeps: Record<string, string>
221
+ schemaDir: string
222
+ client?: string
223
+ }
224
+
225
+ export interface ViewInfo {
226
+ slug: string
227
+ kind: 'inline-html' | 'spa' | 'unknown'
228
+ auth?: string
229
+ mount?: string
230
+ url?: string
231
+ /** the class(es) this view binds to via `viewFor: selfOf(Class)` (DSL allows an array);
232
+ * absent ⇒ unbound/global */
233
+ viewFor?: string | string[]
234
+ file?: string
235
+ description?: string
236
+ }
237
+
238
+ /** One node that can be supplied as a targeted view's `targetNodeId`. */
239
+ export interface ViewTargetCandidate {
240
+ id: string
241
+ ref: string
242
+ className: string
243
+ classOrigin: string
244
+ label: string
245
+ description?: string
246
+ status?: string
247
+ }
248
+
249
+ /** Small durable snapshot retained when a previously selected node disappears. */
250
+ export interface RememberedViewTarget {
251
+ id: string
252
+ className: string
253
+ classOrigin: string
254
+ label: string
255
+ }
256
+
257
+ export interface ViewTargetResult {
258
+ status: 'available' | 'unavailable'
259
+ items: ViewTargetCandidate[]
260
+ selected: ViewTargetCandidate | null
261
+ stale: RememberedViewTarget | null
262
+ truncated: boolean
263
+ reason?: string
264
+ }
265
+
266
+ /** Full launch context shown before Studio asks `astrale view` to resolve and open the View. */
267
+ export interface ViewRuntime {
268
+ slug: string
269
+ instance: string | null
270
+ targetRequired: boolean
271
+ targets: ViewTargetResult
272
+ }
273
+
274
+ export type ViewSessionResult =
275
+ | {
276
+ status: 'ready'
277
+ sessionId: string
278
+ pageUrl: string
279
+ viewUrl: string
280
+ target: ViewTargetCandidate | null
281
+ }
282
+ | { status: 'unavailable'; reason: string }
283
+
284
+ export interface ClientFeature {
285
+ name: string
286
+ files: string[]
287
+ }
288
+
289
+ export interface ClientTree {
290
+ shell: string[]
291
+ features: ClientFeature[]
292
+ routes: Record<string, string>
293
+ present: boolean
294
+ }
295
+
296
+ export interface EnvField {
297
+ name: string
298
+ optional: boolean
299
+ doc?: string
300
+ secret?: boolean
301
+ }
302
+
303
+ export type EnvName = 'dev' | 'prod'
304
+
305
+ /** One env var in the editor: the env.ts contract side (declared/optional/doc)
306
+ * merged with the `.env.<env>` file side (value). A row may be declared-only
307
+ * (in env.ts, not yet in the file), set, or an orphan (in the file, not env.ts). */
308
+ export interface EnvVarRow {
309
+ name: string
310
+ /** current value from `.env.<env>` ('' when unset or empty) */
311
+ value: string
312
+ /** declared as a fillable (non-binding) field in env.ts's Env interface */
313
+ declared: boolean
314
+ /** env.ts marks it optional (`?`). Only required (!optional) + empty raises the signal. */
315
+ optional: boolean
316
+ /** JSDoc on the env.ts field — the inline hint */
317
+ doc?: string
318
+ }
319
+
320
+ /** The editable env for one env name (dev|prod): the `.env.<env>` file reconciled
321
+ * against env.ts. The GUI is the read-only studio's one sanctioned writer of a
322
+ * domain file (the explicit exception). */
323
+ export interface EnvFileModel {
324
+ env: EnvName
325
+ /** the secrets file, relative to the domain root (e.g. '.env.dev') */
326
+ file: string
327
+ /** wired via `astrale.config.ts` (`secrets: '.env.<env>'`)? false ⇒ the file is used
328
+ * by convention but the adapter isn't pointed at it (e.g. managed prod). */
329
+ configured: boolean
330
+ exists: boolean
331
+ adapter: DomainOverview['adapter']
332
+ rows: EnvVarRow[]
333
+ /** declared && required && empty — the count the "needs values" signal shows */
334
+ requiredMissing: number
335
+ }
336
+
337
+ export interface DomainAnatomy {
338
+ overview: DomainOverview
339
+ views: ViewInfo[]
340
+ client: ClientTree
341
+ env: EnvField[]
342
+ depsContainer?: string
343
+ /** shallow readdir of integrations/ top-level dir names — a hint, NOT a parse */
344
+ detectedIntegrations: string[]
345
+ }
346
+
347
+ /** One materialized node instance in a domain's core graph. */
348
+ export interface StudioCoreNode {
349
+ /** canonical CoreRef identity, e.g. `/:big-shop.example.dev:core.acme` */
350
+ path: string
351
+ /** the IR class this node instantiates (keys into StudioSchemaBundle.ir.classes) */
352
+ className: string
353
+ /** the node's property values, keyed by (possibly owner-qualified) property name */
354
+ data: Record<string, unknown>
355
+ /** parent node's `path`, when nested under another node (absent for roots) */
356
+ parent?: string
357
+ }
358
+
359
+ /** One materialized edge instance wiring two core nodes. */
360
+ export interface StudioCoreEdge {
361
+ /** source Core path or owning Domain path */
362
+ from: string
363
+ /** target Core path or owning Domain path */
364
+ to: string
365
+ /** the IR edge class name (keys into StudioSchemaBundle.ir.classes, type:'edge') */
366
+ edgeName: string
367
+ /** edge property values, when the edge class carries data */
368
+ data?: Record<string, unknown>
369
+ }
370
+
371
+ /** A domain's core data: the concrete genesis node/edge instance graph. */
372
+ export interface StudioCore {
373
+ /** the domain origin this core graph belongs to (mirrors SchemaIR.domain) */
374
+ domain: string
375
+ nodes: StudioCoreNode[]
376
+ edges: StudioCoreEdge[]
377
+ /** set when extraction failed; null when extraction succeeded (including "no core defined") */
378
+ error?: { message: string } | null
379
+ extractedAt: string
380
+ }
381
+
382
+ /** Client-side rendering description derived from a JSON value schema. */
383
+ export type TypeDescriptor =
384
+ | { kind: 'string' | 'number' | 'integer' | 'boolean' | 'null' | 'unknown'; optional: boolean }
385
+ | { kind: 'enum'; values: (string | number | boolean | null)[]; optional: boolean }
386
+ | { kind: 'array'; items: TypeDescriptor; optional: boolean }
387
+ | {
388
+ kind: 'object'
389
+ fields: Record<string, TypeDescriptor>
390
+ required: string[]
391
+ optional: boolean
392
+ }
393
+ | { kind: 'ref'; target: string; refKind: 'node' | 'data'; optional: boolean }
@@ -0,0 +1,317 @@
1
+ import { expect, test } from 'bun:test'
2
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
3
+ import { dirname, join, relative, resolve } from 'node:path'
4
+ import ts from 'typescript'
5
+
6
+ const SHARED_ROOT = resolve(import.meta.dir, '..')
7
+ const STUDIO_ROOT = resolve(SHARED_ROOT, '..')
8
+
9
+ // Closed Studio V1 shared surface. Keeping this manifest independent of Git
10
+ // catches accidental aliases and shadow contracts.
11
+ const TARGET_BARREL_EXPORTS = [
12
+ 'AGENT_ACCESS_LEVELS',
13
+ 'AGENT_EFFORT_LEVELS',
14
+ 'AgentAccess',
15
+ 'AgentEffort',
16
+ 'AgentEvent',
17
+ 'AgentEventKind',
18
+ 'AgentPromptSnapshot',
19
+ 'AgentRun',
20
+ 'AgentRunSnapshot',
21
+ 'AgentRunStatus',
22
+ 'AgentSessionInfo',
23
+ 'AgentSystemPromptInfo',
24
+ 'AnchorKind',
25
+ 'AnchorRef',
26
+ 'BundleError',
27
+ 'ChangeSet',
28
+ 'ClientFeature',
29
+ 'ClientTree',
30
+ 'Comment',
31
+ 'CommentStore',
32
+ 'ContextItem',
33
+ 'ContextStore',
34
+ 'ConversationInfo',
35
+ 'CopyPayload',
36
+ 'CrossDomainImport',
37
+ 'DeployRecord',
38
+ 'DeployResult',
39
+ 'DocMeta',
40
+ 'DomainAnatomy',
41
+ 'DomainCatalogEntry',
42
+ 'DomainOverview',
43
+ 'DomainSummary',
44
+ 'DomainUsage',
45
+ 'EnvField',
46
+ 'EnvFileModel',
47
+ 'EnvName',
48
+ 'EnvVarRow',
49
+ 'FileChange',
50
+ 'HandlerLink',
51
+ 'HarnessCapabilities',
52
+ 'HarnessGatewayAuth',
53
+ 'HarnessGatewayConfig',
54
+ 'HarnessGatewayState',
55
+ 'HarnessLoadout',
56
+ 'HarnessModelOption',
57
+ 'HarnessStatus',
58
+ 'InstanceInfo',
59
+ 'InstanceStatus',
60
+ 'InstancesState',
61
+ 'Integration',
62
+ 'IntegrationsState',
63
+ 'IrCallable',
64
+ 'IrCallableAuth',
65
+ 'IrCallableOutput',
66
+ 'IrClass',
67
+ 'IrClassKey',
68
+ 'IrClassRef',
69
+ 'IrEndpoint',
70
+ 'IrFunction',
71
+ 'IrImportDescriptor',
72
+ 'IrMethod',
73
+ 'IrSchemaKey',
74
+ 'IrSchemaRef',
75
+ 'IrView',
76
+ 'IrViewTarget',
77
+ 'JsonSchema',
78
+ 'LayoutState',
79
+ 'LoadoutSkill',
80
+ 'McpServerInfo',
81
+ 'MergeResult',
82
+ 'MethodInheritance',
83
+ 'NodePosition',
84
+ 'RememberedViewTarget',
85
+ 'SchemaAnnotation',
86
+ 'SchemaChange',
87
+ 'SchemaChangeKind',
88
+ 'SchemaIR',
89
+ 'SchemaOverlay',
90
+ 'SourceSpan',
91
+ 'StaleReport',
92
+ 'StudioCore',
93
+ 'StudioCoreEdge',
94
+ 'StudioCoreNode',
95
+ 'StudioEvent',
96
+ 'StudioSchemaBundle',
97
+ 'StudioSettings',
98
+ 'ThreadEntry',
99
+ 'ThreadEntryType',
100
+ 'ThreadRole',
101
+ 'TypeDescriptor',
102
+ 'ViewInfo',
103
+ 'ViewRuntime',
104
+ 'ViewSessionResult',
105
+ 'ViewTargetCandidate',
106
+ 'ViewTargetResult',
107
+ 'VisibilityState',
108
+ ] as const
109
+
110
+ const TARGET_BARREL_HELPERS = [
111
+ 'IR_SCHEMA_REF_KINDS',
112
+ 'IrSchemaRefKind',
113
+ 'STUDIO_SCHEMA_PROJECTION_VERSION',
114
+ 'SchemaRevision',
115
+ 'classRefKey',
116
+ 'isIrClassRef',
117
+ 'isIrSchemaRef',
118
+ 'isSchemaRevision',
119
+ 'parseClassRefKey',
120
+ 'parseSchemaRefKey',
121
+ 'schemaRefKey',
122
+ ] as const
123
+
124
+ function productionFiles(dir: string): string[] {
125
+ return readdirSync(dir).flatMap((entry) => {
126
+ if (entry === 'node_modules') return []
127
+ const path = join(dir, entry)
128
+ if (statSync(path).isDirectory()) return productionFiles(path)
129
+ return /\.(?:ts|tsx)$/.test(path) && !/\.test\.(?:ts|tsx)$/.test(path) ? [path] : []
130
+ })
131
+ }
132
+
133
+ function parseTypeScript(file: string): ts.SourceFile {
134
+ return ts.createSourceFile(
135
+ file,
136
+ readFileSync(file, 'utf8'),
137
+ ts.ScriptTarget.Latest,
138
+ false,
139
+ file.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
140
+ )
141
+ }
142
+
143
+ function hasExportModifier(node: ts.Node): boolean {
144
+ return Boolean(
145
+ ts.canHaveModifiers(node) &&
146
+ ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword),
147
+ )
148
+ }
149
+
150
+ function bindingNames(name: ts.BindingName): string[] {
151
+ if (ts.isIdentifier(name)) return [name.text]
152
+ return name.elements.flatMap((element) =>
153
+ ts.isOmittedExpression(element) ? [] : bindingNames(element.name),
154
+ )
155
+ }
156
+
157
+ function resolveTypeScriptModule(file: string, specifier: string): string {
158
+ const target = resolve(dirname(file), specifier)
159
+ const candidate = [target, `${target}.ts`, `${target}.tsx`, join(target, 'index.ts')].find(
160
+ existsSync,
161
+ )
162
+ if (!candidate) throw new Error(`Cannot resolve ${specifier} from ${file}`)
163
+ return candidate
164
+ }
165
+
166
+ function namedExports(file: string, seen = new Set<string>()): string[] {
167
+ if (seen.has(file)) return []
168
+ seen.add(file)
169
+ const names: string[] = []
170
+
171
+ for (const statement of parseTypeScript(file).statements) {
172
+ if (ts.isExportDeclaration(statement)) {
173
+ if (statement.exportClause && ts.isNamedExports(statement.exportClause)) {
174
+ names.push(...statement.exportClause.elements.map((element) => element.name.text))
175
+ } else if (statement.exportClause && ts.isNamespaceExport(statement.exportClause)) {
176
+ names.push(statement.exportClause.name.text)
177
+ } else if (
178
+ statement.moduleSpecifier &&
179
+ ts.isStringLiteral(statement.moduleSpecifier) &&
180
+ statement.moduleSpecifier.text.startsWith('.')
181
+ ) {
182
+ names.push(
183
+ ...namedExports(resolveTypeScriptModule(file, statement.moduleSpecifier.text), seen),
184
+ )
185
+ }
186
+ continue
187
+ }
188
+ if (!hasExportModifier(statement)) continue
189
+ if (ts.isVariableStatement(statement)) {
190
+ names.push(
191
+ ...statement.declarationList.declarations.flatMap(({ name }) => bindingNames(name)),
192
+ )
193
+ } else if (
194
+ (ts.isClassDeclaration(statement) ||
195
+ ts.isEnumDeclaration(statement) ||
196
+ ts.isFunctionDeclaration(statement) ||
197
+ ts.isInterfaceDeclaration(statement) ||
198
+ ts.isTypeAliasDeclaration(statement)) &&
199
+ statement.name
200
+ ) {
201
+ names.push(statement.name.text)
202
+ }
203
+ }
204
+ return names
205
+ }
206
+
207
+ function moduleSpecifiers(file: string): string[] {
208
+ const found: string[] = []
209
+ const visit = (node: ts.Node): void => {
210
+ if (
211
+ (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
212
+ node.moduleSpecifier &&
213
+ ts.isStringLiteralLike(node.moduleSpecifier)
214
+ ) {
215
+ found.push(node.moduleSpecifier.text)
216
+ } else if (
217
+ ts.isImportEqualsDeclaration(node) &&
218
+ ts.isExternalModuleReference(node.moduleReference) &&
219
+ node.moduleReference.expression &&
220
+ ts.isStringLiteralLike(node.moduleReference.expression)
221
+ ) {
222
+ found.push(node.moduleReference.expression.text)
223
+ } else if (
224
+ ts.isCallExpression(node) &&
225
+ node.arguments.length === 1 &&
226
+ ts.isStringLiteralLike(node.arguments[0]!) &&
227
+ (node.expression.kind === ts.SyntaxKind.ImportKeyword ||
228
+ (ts.isIdentifier(node.expression) && node.expression.text === 'require'))
229
+ ) {
230
+ found.push(node.arguments[0]!.text)
231
+ }
232
+ ts.forEachChild(node, visit)
233
+ }
234
+ visit(parseTypeScript(file))
235
+ return found
236
+ }
237
+
238
+ function declaredTypes(file: string, candidates: ReadonlySet<string>): string[] {
239
+ const text = readFileSync(file, 'utf8')
240
+ if (![...candidates].some((name) => text.includes(name))) return []
241
+ return parseTypeScript(file).statements.flatMap((statement) => {
242
+ if (
243
+ !ts.isInterfaceDeclaration(statement) &&
244
+ !ts.isTypeAliasDeclaration(statement) &&
245
+ !ts.isClassDeclaration(statement) &&
246
+ !ts.isEnumDeclaration(statement)
247
+ ) {
248
+ return []
249
+ }
250
+ const name = statement.name?.text
251
+ return name && candidates.has(name) ? [name] : []
252
+ })
253
+ }
254
+
255
+ test('types.ts remains a re-export-only compatibility facade', () => {
256
+ const source = parseTypeScript(join(SHARED_ROOT, 'types.ts'))
257
+ const exports = source.statements.flatMap((statement) => {
258
+ if (
259
+ !ts.isExportDeclaration(statement) ||
260
+ statement.exportClause ||
261
+ !statement.moduleSpecifier ||
262
+ !ts.isStringLiteral(statement.moduleSpecifier)
263
+ ) {
264
+ return []
265
+ }
266
+ return [statement.moduleSpecifier.text]
267
+ })
268
+ expect(exports).toEqual([
269
+ './schema/identity',
270
+ './contracts/schema',
271
+ './contracts/workspace',
272
+ './contracts/agent',
273
+ './contracts/runtime',
274
+ ])
275
+ expect(source.statements.every(ts.isExportDeclaration)).toBe(true)
276
+ })
277
+
278
+ test('types.ts exposes exactly the Studio V1 shared surface', () => {
279
+ const exports = namedExports(join(SHARED_ROOT, 'types.ts'))
280
+ const duplicates = exports.filter((name, index) => exports.indexOf(name) !== index)
281
+ const expected = [...TARGET_BARREL_EXPORTS, ...TARGET_BARREL_HELPERS].sort()
282
+
283
+ expect(duplicates).toEqual([])
284
+ expect(exports.sort()).toEqual(expected)
285
+ })
286
+
287
+ test('persisted layout and visibility shapes each have one semantic owner', () => {
288
+ const files = productionFiles(STUDIO_ROOT)
289
+ const names = new Set(['LayoutState', 'VisibilityState'])
290
+ const owners = new Map([...names].map((name) => [name, [] as string[]]))
291
+ for (const file of files) {
292
+ for (const name of declaredTypes(file, names)) {
293
+ owners.get(name)!.push(relative(STUDIO_ROOT, file).replaceAll('\\', '/'))
294
+ }
295
+ }
296
+ expect(Object.fromEntries(owners)).toEqual({
297
+ LayoutState: ['shared/contracts/workspace.ts'],
298
+ VisibilityState: ['shared/contracts/workspace.ts'],
299
+ })
300
+ })
301
+
302
+ test('contract modules follow the documented dependency direction', () => {
303
+ const expectedImports = new Map([
304
+ ['schema/identity.ts', []],
305
+ ['contracts/schema.ts', ['../schema/identity']],
306
+ ['contracts/workspace.ts', ['./schema']],
307
+ ['contracts/agent.ts', ['./workspace']],
308
+ ['contracts/runtime.ts', ['./agent']],
309
+ ])
310
+
311
+ for (const [file, expected] of expectedImports) {
312
+ const imports = moduleSpecifiers(join(SHARED_ROOT, file)).filter((specifier) =>
313
+ specifier.startsWith('.'),
314
+ )
315
+ expect(imports).toEqual(expected)
316
+ }
317
+ })