@astrale-os/cli 1.0.0-beta.1 → 1.0.0-beta.11

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 (329) hide show
  1. package/README.md +23 -12
  2. package/dist/astrale.js +48048 -56798
  3. package/dist/public/connect-core.js +2011 -30765
  4. package/dist/public/keys/index.js +884 -29483
  5. package/dist/public/paths/index.js +13101 -41459
  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 +11 -36
  28. package/dist/types/lib/config.d.ts +7 -59
  29. package/dist/types/lib/failure-debug.d.ts +1 -0
  30. package/dist/types/lib/idp.d.ts +26 -168
  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/meta.d.ts +2 -2
  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 +91 -0
  38. package/dist/types/lib/validation.d.ts +4 -1
  39. package/package.json +16 -19
  40. package/src/__tests__/fixtures/publication.ts +20 -0
  41. package/src/admin/__tests__/binding.test.ts +31 -0
  42. package/src/admin/__tests__/fixture.ts +101 -0
  43. package/src/admin/binding.ts +98 -0
  44. package/src/admin/catalog/.spec/api.d.ts +2 -2
  45. package/src/admin/catalog/__tests__/client.test.ts +20 -49
  46. package/src/admin/catalog/client.ts +36 -32
  47. package/src/admin/catalog/model.ts +3 -4
  48. package/src/admin/graph/.spec/api.d.ts +4 -10
  49. package/src/admin/graph/nodes.ts +1 -1
  50. package/src/admin/instance/.spec/api.d.ts +2 -2
  51. package/src/admin/instance/__tests__/client.test.ts +39 -164
  52. package/src/admin/instance/client.ts +35 -124
  53. package/src/admin/instance/index.ts +1 -2
  54. package/src/admin/instance/model.ts +11 -20
  55. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  56. package/src/commands/__tests__/auth-login.test.ts +54 -1
  57. package/src/commands/__tests__/call-describe.test.ts +46 -33
  58. package/src/commands/__tests__/call.test.ts +5 -1
  59. package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
  60. package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
  61. package/src/commands/__tests__/domain-list.test.ts +63 -4
  62. package/src/commands/__tests__/install-identity-override.test.ts +19 -19
  63. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  64. package/src/commands/__tests__/instance-status.test.ts +139 -0
  65. package/src/commands/__tests__/read-commands.test.ts +35 -10
  66. package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
  67. package/src/commands/__tests__/update.test.ts +48 -19
  68. package/src/commands/call-describe.ts +60 -68
  69. package/src/commands/call.ts +43 -56
  70. package/src/commands/domain/install.ts +13 -17
  71. package/src/commands/domain/list.ts +18 -13
  72. package/src/commands/domain/publish.ts +14 -11
  73. package/src/commands/domain/uninstall.ts +2 -2
  74. package/src/commands/get.ts +14 -15
  75. package/src/commands/identity/__tests__/register.test.ts +3 -3
  76. package/src/commands/identity/register.ts +5 -4
  77. package/src/commands/instance/create.ts +8 -16
  78. package/src/commands/instance/delete.ts +12 -9
  79. package/src/commands/instance/list.ts +2 -2
  80. package/src/commands/instance/status.ts +66 -20
  81. package/src/commands/instance/use.ts +16 -12
  82. package/src/commands/introspect.ts +9 -16
  83. package/src/commands/logs.ts +24 -25
  84. package/src/commands/mutate.ts +6 -5
  85. package/src/commands/query.ts +27 -30
  86. package/src/commands/studio.ts +20 -0
  87. package/src/commands/token.ts +8 -7
  88. package/src/commands/update.ts +38 -14
  89. package/src/commands/view.ts +7 -6
  90. package/src/connection/.spec/api.d.ts +7 -8
  91. package/src/connection/.spec/architecture.md +5 -4
  92. package/src/connection/.spec/flows/session.ts +2 -2
  93. package/src/connection/.spec/laws/connection.ts +6 -2
  94. package/src/connection/.spec/layout.ts +1 -0
  95. package/src/connection/__tests__/credential.test.ts +20 -1
  96. package/src/connection/__tests__/errors.test.ts +43 -32
  97. package/src/connection/__tests__/exchange.test.ts +36 -6
  98. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  99. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  100. package/src/connection/__tests__/self.test.ts +31 -11
  101. package/src/connection/__tests__/session.test.ts +3 -3
  102. package/src/connection/__tests__/target.test.ts +1 -0
  103. package/src/connection/auth.ts +13 -0
  104. package/src/connection/call.ts +1 -1
  105. package/src/connection/credential.ts +2 -2
  106. package/src/connection/errors.ts +1 -355
  107. package/src/connection/exchange.ts +52 -27
  108. package/src/connection/failure/classify.ts +110 -0
  109. package/src/connection/failure/index.ts +18 -0
  110. package/src/connection/failure/model.ts +28 -0
  111. package/src/connection/failure/render.ts +116 -0
  112. package/src/connection/reasons.ts +16 -0
  113. package/src/connection/self.ts +39 -21
  114. package/src/connection/session.ts +19 -8
  115. package/src/errors.ts +3 -2
  116. package/src/graph/.spec/api.d.ts +12 -5
  117. package/src/graph/.spec/layout.ts +9 -1
  118. package/src/graph/__tests__/mutation.test.ts +2 -2
  119. package/src/graph/__tests__/query.test.ts +25 -6
  120. package/src/graph/class.ts +30 -0
  121. package/src/graph/index.ts +1 -0
  122. package/src/graph/query.ts +21 -32
  123. package/src/identity/.spec/api.d.ts +2 -2
  124. package/src/identity/__tests__/registration.test.ts +1 -1
  125. package/src/identity/registration.ts +3 -3
  126. package/src/keys/__tests__/keys.test.ts +4 -0
  127. package/src/keys/credential.ts +1 -0
  128. package/src/lib/__tests__/admin-target.test.ts +12 -0
  129. package/src/lib/__tests__/command-dx.test.ts +1 -1
  130. package/src/lib/__tests__/domain-publication.test.ts +138 -0
  131. package/src/lib/__tests__/idp-session.test.ts +22 -0
  132. package/src/lib/__tests__/idp.test.ts +36 -4
  133. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  134. package/src/lib/__tests__/instance-target.test.ts +7 -39
  135. package/src/lib/__tests__/instance.test.ts +6 -0
  136. package/src/lib/__tests__/log-errors.test.ts +64 -0
  137. package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
  138. package/src/lib/__tests__/update.test.ts +113 -8
  139. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  140. package/src/lib/__tests__/view-server.test.ts +18 -3
  141. package/src/lib/__tests__/view-session.test.ts +1 -1
  142. package/src/lib/admin-instance.ts +14 -8
  143. package/src/lib/admin-target.ts +21 -2
  144. package/src/lib/command-dx.ts +9 -9
  145. package/src/lib/domain-publication.ts +104 -0
  146. package/src/lib/failure-debug.ts +26 -0
  147. package/src/lib/idp.ts +39 -4
  148. package/src/lib/instance-candidates.ts +2 -2
  149. package/src/lib/instance-target.ts +3 -14
  150. package/src/lib/instance.ts +22 -12
  151. package/src/lib/log.ts +16 -9
  152. package/src/lib/login-flow.ts +13 -3
  153. package/src/lib/meta.ts +2 -2
  154. package/src/lib/provision-instance.ts +34 -57
  155. package/src/lib/update.ts +124 -30
  156. package/src/lib/validation.ts +2 -2
  157. package/src/lib/view/resolve.ts +1 -1
  158. package/src/lib/view/server.ts +17 -3
  159. package/src/program/__tests__/program.test.ts +20 -4
  160. package/src/program/build.ts +2 -2
  161. package/src/setup/__tests__/instance-step.test.ts +27 -10
  162. package/src/setup/steps/instance.ts +22 -15
  163. package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
  164. package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
  165. package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
  166. package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  167. package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
  168. package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
  169. package/studio/client/dist/index.html +3 -2
  170. package/studio/package.json +10 -14
  171. package/studio/server/agent/ask.test.ts +1 -1
  172. package/studio/server/agent/bridge/grant.test.ts +1 -1
  173. package/studio/server/agent/bridge/routes.test.ts +1 -1
  174. package/studio/server/agent/bridge/stdio.ts +8 -1
  175. package/studio/server/agent/conversation.test.ts +10 -5
  176. package/studio/server/agent/conversation.ts +56 -8
  177. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  178. package/studio/server/agent/harness/codex/loadout.ts +18 -21
  179. package/studio/server/agent/harness/gateway/config.ts +20 -18
  180. package/studio/server/agent/harness/selection.ts +9 -1
  181. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  182. package/studio/server/agent/prompts/anchors.ts +20 -49
  183. package/studio/server/agent/prompts/system.test.ts +3 -2
  184. package/studio/server/agent/prompts/system.ts +6 -5
  185. package/studio/server/agent/prompts/turn.ts +13 -4
  186. package/studio/server/agent/routes.test.ts +1 -1
  187. package/studio/server/agent/run/completion.ts +2 -2
  188. package/studio/server/agent/run/coordinator.test.ts +1 -1
  189. package/studio/server/agent/run/preparation.ts +6 -5
  190. package/studio/server/agent/run/transcript.test.ts +35 -1
  191. package/studio/server/agent/run/transcript.ts +169 -3
  192. package/studio/server/agent/run/usage.test.ts +24 -0
  193. package/studio/server/agent/run/usage.ts +26 -1
  194. package/studio/server/api/canvas.ts +43 -0
  195. package/studio/server/api/comments.ts +85 -0
  196. package/studio/server/api/context.ts +61 -0
  197. package/studio/server/api/deployment.ts +39 -0
  198. package/studio/server/api/documents.ts +55 -0
  199. package/studio/server/api/domain.ts +59 -0
  200. package/studio/server/api/http.ts +45 -0
  201. package/studio/server/api/project.ts +57 -0
  202. package/studio/server/api/schema.ts +12 -0
  203. package/studio/server/api/views.ts +57 -0
  204. package/studio/server/api/workspace.ts +60 -0
  205. package/studio/server/api-agent-loadout.test.ts +1 -1
  206. package/studio/server/api.test.ts +147 -0
  207. package/studio/server/api.ts +20 -422
  208. package/studio/server/cache.test.ts +122 -0
  209. package/studio/server/cache.ts +162 -11
  210. package/studio/server/cli-consumers.test.ts +494 -0
  211. package/studio/server/cli.test.ts +88 -0
  212. package/studio/server/cli.ts +240 -0
  213. package/studio/server/client-package.ts +25 -1
  214. package/studio/server/domain.test.ts +50 -40
  215. package/studio/server/domain.ts +83 -52
  216. package/studio/server/environment/dotenv-preview.test.ts +39 -0
  217. package/studio/server/environment/dotenv-preview.ts +27 -0
  218. package/studio/server/environment/files.test.ts +53 -0
  219. package/studio/server/{state/env.ts → environment/files.ts} +7 -48
  220. package/studio/server/{state → handoff}/copy.ts +21 -6
  221. package/studio/server/handoff/service.test.ts +22 -0
  222. package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
  223. package/studio/server/index.ts +1 -1
  224. package/studio/server/instances/active.ts +72 -0
  225. package/studio/server/instances/deploy-record.test.ts +31 -0
  226. package/studio/server/instances/deploy-record.ts +37 -0
  227. package/studio/server/instances/deploy.ts +56 -0
  228. package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
  229. package/studio/server/instances/probe.ts +67 -0
  230. package/studio/server/instances/status.test.ts +12 -0
  231. package/studio/server/instances/status.ts +49 -0
  232. package/studio/server/introspect/anatomy/client-tree.ts +57 -0
  233. package/studio/server/introspect/anatomy/env-fields.ts +66 -0
  234. package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
  235. package/studio/server/introspect/anatomy/source.ts +181 -0
  236. package/studio/server/introspect/anatomy/views/routes.ts +114 -0
  237. package/studio/server/introspect/anatomy/views.ts +53 -0
  238. package/studio/server/introspect/anatomy-extras.test.ts +106 -35
  239. package/studio/server/introspect/anatomy-extras.ts +7 -726
  240. package/studio/server/introspect/anatomy.test.ts +22 -14
  241. package/studio/server/introspect/anatomy.ts +52 -28
  242. package/studio/server/introspect/bundle.ts +15 -9
  243. package/studio/server/introspect/canonical-schema.test.ts +93 -309
  244. package/studio/server/introspect/canonical-schema.ts +257 -425
  245. package/studio/server/introspect/config-preview.test.ts +32 -0
  246. package/studio/server/introspect/config-preview.ts +119 -0
  247. package/studio/server/introspect/core-extractor.ts +18 -127
  248. package/studio/server/introspect/core.ts +1 -2
  249. package/studio/server/introspect/diff.test.ts +18 -18
  250. package/studio/server/introspect/diff.ts +44 -90
  251. package/studio/server/introspect/extractor.ts +23 -116
  252. package/studio/server/introspect/hash.ts +5 -2
  253. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  254. package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
  255. package/studio/server/introspect/overlay.test.ts +26 -54
  256. package/studio/server/introspect/overlay.ts +10 -37
  257. package/studio/server/introspect/revision.test.ts +54 -0
  258. package/studio/server/introspect/revision.ts +49 -0
  259. package/studio/server/introspect/runtime.test.ts +83 -143
  260. package/studio/server/introspect/runtime.ts +40 -11
  261. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  262. package/studio/server/introspect/schema-ir-json.ts +151 -0
  263. package/studio/server/introspect/schema-refs.test.ts +43 -88
  264. package/studio/server/introspect/schema-refs.ts +14 -49
  265. package/studio/server/introspect/source-overlay/annotations.ts +14 -0
  266. package/studio/server/introspect/source-overlay/handlers.ts +161 -0
  267. package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
  268. package/studio/server/introspect/source-overlay/project.ts +248 -0
  269. package/studio/server/introspect/source-overlay/spans.ts +330 -0
  270. package/studio/server/json.ts +46 -0
  271. package/studio/server/lifecycle.ts +5 -1
  272. package/studio/server/sse.test.ts +26 -0
  273. package/studio/server/sse.ts +4 -1
  274. package/studio/server/state/baseline.test.ts +223 -7
  275. package/studio/server/state/baseline.ts +148 -34
  276. package/studio/server/state/comments.test.ts +66 -1
  277. package/studio/server/state/comments.ts +173 -10
  278. package/studio/server/state/context.ts +34 -2
  279. package/studio/server/state/documents.ts +42 -1
  280. package/studio/server/state/integrations.ts +27 -1
  281. package/studio/server/state/layout.test.ts +34 -0
  282. package/studio/server/state/layout.ts +44 -17
  283. package/studio/server/state/settings.ts +29 -22
  284. package/studio/server/state/store.test.ts +122 -0
  285. package/studio/server/state/store.ts +66 -17
  286. package/studio/server/state/visibility.ts +22 -11
  287. package/studio/server/views/model.test.ts +57 -0
  288. package/studio/server/views/model.ts +66 -0
  289. package/studio/server/views/runtime.ts +40 -0
  290. package/studio/server/views/selection-repository.test.ts +31 -0
  291. package/studio/server/views/selection-repository.ts +60 -0
  292. package/studio/server/views/session.test.ts +73 -0
  293. package/studio/server/views/session.ts +166 -0
  294. package/studio/server/views/target.test.ts +78 -0
  295. package/studio/server/views/target.ts +222 -0
  296. package/studio/server/watch.test.ts +11 -11
  297. package/studio/server/watch.ts +9 -5
  298. package/studio/server/workspace/catalog.test.ts +17 -0
  299. package/studio/server/workspace/catalog.ts +43 -0
  300. package/studio/server/{state → workspace}/create.test.ts +1 -1
  301. package/studio/server/{state → workspace}/create.ts +1 -1
  302. package/studio/server/{state → workspace}/git.ts +1 -1
  303. package/studio/server/workspace/updates.ts +83 -0
  304. package/studio/server/workspace-state.ts +1 -1
  305. package/studio/server/workspace-watch.ts +2 -2
  306. package/studio/shared/contracts/README.md +16 -0
  307. package/studio/shared/contracts/agent.ts +270 -0
  308. package/studio/shared/contracts/runtime.ts +50 -0
  309. package/studio/shared/contracts/schema.ts +393 -0
  310. package/studio/shared/contracts/surface.test.ts +317 -0
  311. package/studio/shared/contracts/workspace.ts +265 -0
  312. package/studio/shared/layout.test.ts +116 -0
  313. package/studio/shared/schema/identity.test.ts +34 -0
  314. package/studio/shared/schema/identity.ts +68 -0
  315. package/studio/shared/types.ts +11 -1099
  316. package/studio/tsconfig.json +1 -1
  317. package/viewer/dist/main.js +40 -61
  318. package/.check-workspace.cjs +0 -40
  319. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  320. package/studio/client/dist/assets/elk-api-D2xgMJvi.js +0 -1
  321. package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
  322. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  323. package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
  324. package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
  325. package/studio/server/state/catalog.ts +0 -117
  326. package/studio/server/state/instance.ts +0 -280
  327. package/studio/server/state/updates.ts +0 -63
  328. package/studio/server/state/views.test.ts +0 -286
  329. package/studio/server/state/views.ts +0 -535
@@ -4,8 +4,9 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Domain Studio</title>
7
- <script type="module" crossorigin src="/assets/index-LGSWRrk8.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-BMdnsIJA.css">
7
+ <script type="module" crossorigin src="/assets/index-7YHdeCxp.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-Dd_uD5pT.js">
9
+ <link rel="stylesheet" crossorigin href="/assets/index-C0FAnwNw.css">
9
10
  </head>
10
11
  <body>
11
12
  <div id="root"></div>
@@ -16,10 +16,13 @@
16
16
  "build": "vite build",
17
17
  "start": "bun server/index.ts",
18
18
  "dev:client": "vite",
19
+ "test": "bun test client/src server shared",
20
+ "test:e2e": "pnpm build && playwright test",
19
21
  "typecheck": "tsgo --noEmit"
20
22
  },
21
23
  "dependencies": {
22
- "@astrale-os/shell": "file:../vendor/astrale-os-shell-0.3.8-beta.2.tgz",
24
+ "@astrale-os/sdk": "0.5.0-beta.38",
25
+ "@astrale-os/shell": "0.4.2-beta.3",
23
26
  "@dagrejs/dagre": "^3.0.0",
24
27
  "@radix-ui/react-collapsible": "^1.1.0",
25
28
  "@radix-ui/react-dialog": "^1.1.6",
@@ -29,7 +32,6 @@
29
32
  "@radix-ui/react-scroll-area": "^1.2.3",
30
33
  "@radix-ui/react-separator": "^1.1.2",
31
34
  "@radix-ui/react-slot": "^1.1.2",
32
- "@radix-ui/react-tabs": "^1.1.3",
33
35
  "@radix-ui/react-tooltip": "^1.1.8",
34
36
  "@tanstack/react-query": "^5.66.0",
35
37
  "@xyflow/react": "^12.4.4",
@@ -38,7 +40,7 @@
38
40
  "clsx": "^2.1.1",
39
41
  "cmdk": "^1.1.1",
40
42
  "elkjs": "^0.11.1",
41
- "lucide-react": "^0.475.0",
43
+ "lucide-react": "^1.31.0",
42
44
  "react": "^19.2.0",
43
45
  "react-dom": "^19.2.0",
44
46
  "react-markdown": "^10.1.0",
@@ -49,22 +51,16 @@
49
51
  "zustand": "^5.0.3"
50
52
  },
51
53
  "devDependencies": {
54
+ "@playwright/test": "^1.62.1",
52
55
  "@tailwindcss/vite": "^4.0.6",
53
56
  "@types/node": "^20.19.43",
54
57
  "@types/react": "^19.2.0",
55
58
  "@types/react-dom": "^19.2.0",
56
- "@vitejs/plugin-react": "^5.0.0",
59
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
60
+ "@vitejs/plugin-react": "^6.0.5",
57
61
  "bun-types": "^1.4.0",
58
62
  "tailwindcss": "^4.0.6",
59
- "typescript": "^5.7.3",
60
- "vite": "^7.0.0"
61
- },
62
- "overrides": {
63
- "@astrale-os/kernel-client": "file:../vendor/kernel/astrale-os-kernel-client-0.6.0-beta.3.tgz",
64
- "@astrale-os/kernel-core": "file:../vendor/kernel/astrale-os-kernel-core-0.9.0-beta.2.tgz",
65
- "@astrale-os/kernel-dsl": "file:../vendor/kernel/astrale-os-kernel-dsl-0.2.0-beta.2.tgz",
66
- "@astrale-os/kernel-protocol": "file:../vendor/kernel/astrale-os-kernel-protocol-0.5.0-beta.2.tgz",
67
- "@astrale-os/kernel-server": "file:../vendor/kernel/astrale-os-kernel-server-0.5.0-beta.3.tgz",
68
- "@astrale-os/sdk": "file:../vendor/astrale-os-sdk-0.5.0-beta.3.tgz"
63
+ "typescript": "~6.0.3",
64
+ "vite": "^8.2.1"
69
65
  }
70
66
  }
@@ -35,7 +35,7 @@ test('Ask uses the active harness model and matching per-harness conversation',
35
35
  roots.push(root)
36
36
  mkdirSync(join(root, 'schema'))
37
37
  writeFileSync(join(root, 'astrale.config.ts'), 'export default {}\n')
38
- writeFileSync(join(root, 'domain.ts'), 'export default {}\n')
38
+ writeFileSync(join(root, 'application.ts'), 'export default {}\n')
39
39
  writeFileSync(join(root, 'schema/index.ts'), 'export const Test = {}\n')
40
40
  const handle = registerDomain(root)!
41
41
  domainIds.push(handle.id)
@@ -18,7 +18,7 @@ function domain(root: string, id: string): DomainHandle {
18
18
  id,
19
19
  root,
20
20
  configFile: join(root, 'astrale.config.ts'),
21
- domainFile: join(root, 'domain.ts'),
21
+ applicationFile: join(root, 'application.ts'),
22
22
  schemaDirName: 'schema',
23
23
  schemaDir: join(root, 'schema'),
24
24
  schemaIndex: join(root, 'schema/index.ts'),
@@ -20,7 +20,7 @@ function domain(root: string, id: string): DomainHandle {
20
20
  id,
21
21
  root,
22
22
  configFile: join(root, 'astrale.config.ts'),
23
- domainFile: join(root, 'domain.ts'),
23
+ applicationFile: join(root, 'application.ts'),
24
24
  schemaDirName: 'schema',
25
25
  schemaDir: join(root, 'schema'),
26
26
  schemaIndex: join(root, 'schema/index.ts'),
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { readFileSync } from 'node:fs'
12
12
 
13
+ import { asJsonRecord, asString, parseJson } from '../../json'
13
14
  import { forwardBridgeTool } from './client'
14
15
 
15
16
  function configFromArgv(): { base?: string; token?: string } {
@@ -17,7 +18,13 @@ function configFromArgv(): { base?: string; token?: string } {
17
18
  const path = i >= 0 ? process.argv[i + 1] : undefined
18
19
  if (!path) return {}
19
20
  try {
20
- return JSON.parse(readFileSync(path, 'utf8')) as { base?: string; token?: string }
21
+ const record = asJsonRecord(parseJson(readFileSync(path, 'utf8')))
22
+ const base = asString(record?.base)
23
+ const token = asString(record?.token)
24
+ return {
25
+ ...(base === undefined ? {} : { base }),
26
+ ...(token === undefined ? {} : { token }),
27
+ }
21
28
  } catch {
22
29
  return {}
23
30
  }
@@ -3,6 +3,7 @@ import { mkdtempSync, rmSync } from 'node:fs'
3
3
  import { tmpdir } from 'node:os'
4
4
  import { join } from 'node:path'
5
5
 
6
+ import { asJsonRecord } from '../json'
6
7
  import { readJson, writeJson } from '../state/store'
7
8
  import {
8
9
  clearConversation,
@@ -60,10 +61,14 @@ describe('per-harness conversations', () => {
60
61
  expect(readConversation(dir, 'claude').turns).toBe(4)
61
62
 
62
63
  setConversationSession(dir, 'codex', 'codex-thread')
63
- const stored = readJson<any>(dir, '.cache/agent/session.json', {})
64
- expect(stored.version).toBe(1)
65
- expect(stored.conversations.claude.sessionId).toBe('legacy-session')
66
- expect(stored.conversations.codex.sessionId).toBe('codex-thread')
64
+ const stored = readJson(dir, '.cache/agent/session.json', asJsonRecord, {})
65
+ expect(stored).toMatchObject({
66
+ version: 1,
67
+ conversations: {
68
+ claude: { sessionId: 'legacy-session' },
69
+ codex: { sessionId: 'codex-thread' },
70
+ },
71
+ })
67
72
  })
68
73
 
69
74
  test('fails closed without rewriting a future conversation-store version', () => {
@@ -79,6 +84,6 @@ describe('per-harness conversations', () => {
79
84
  expect(() => setConversationSession(dir, 'claude', 'new-session')).toThrow(
80
85
  'unsupported agent conversation store version: 2',
81
86
  )
82
- expect(readJson<any>(dir, '.cache/agent/session.json', {})).toEqual(future)
87
+ expect(readJson(dir, '.cache/agent/session.json', asJsonRecord, {})).toEqual(future)
83
88
  })
84
89
  })
@@ -1,5 +1,6 @@
1
1
  import type { AgentSessionInfo, ConversationInfo } from '../../shared/types'
2
2
 
3
+ import { asFiniteNumber, asJsonRecord, asString } from '../json'
3
4
  import { readJson, removeState, writeJson } from '../state/store'
4
5
 
5
6
  const SESSION_FILE = '.cache/agent/session.json'
@@ -19,22 +20,69 @@ interface LegacySessionState extends HarnessConversation {
19
20
  harness?: string
20
21
  }
21
22
 
23
+ type DecodedConversationWire =
24
+ | {
25
+ kind: 'versioned'
26
+ version: number | undefined
27
+ conversations: Record<string, HarnessConversation>
28
+ }
29
+ | { kind: 'legacy'; state: LegacySessionState }
30
+
31
+ function decodeHarnessConversation(value: unknown): HarnessConversation | undefined {
32
+ const record = asJsonRecord(value)
33
+ if (!record) return undefined
34
+ const sessionId = asString(record.sessionId)
35
+ const turnsValue = asFiniteNumber(record.turns)
36
+ const turns =
37
+ turnsValue !== undefined && turnsValue >= 0 && Number.isInteger(turnsValue)
38
+ ? turnsValue
39
+ : undefined
40
+ const updatedAt = asString(record.updatedAt)
41
+ return {
42
+ ...(sessionId === undefined ? {} : { sessionId }),
43
+ ...(turns === undefined ? {} : { turns }),
44
+ ...(updatedAt === undefined ? {} : { updatedAt }),
45
+ }
46
+ }
47
+
48
+ function decodeConversationWire(value: unknown): DecodedConversationWire | undefined {
49
+ const record = asJsonRecord(value)
50
+ if (!record) return undefined
51
+ if ('conversations' in record) {
52
+ const conversations: Record<string, HarnessConversation> = {}
53
+ for (const [harness, candidate] of Object.entries(asJsonRecord(record.conversations) ?? {})) {
54
+ const conversation = decodeHarnessConversation(candidate)
55
+ if (conversation) conversations[harness] = conversation
56
+ }
57
+ return {
58
+ kind: 'versioned',
59
+ version: asFiniteNumber(record.version),
60
+ conversations,
61
+ }
62
+ }
63
+ const state = decodeHarnessConversation(record)
64
+ if (!state) return undefined
65
+ const harness = asString(record.harness)
66
+ return { kind: 'legacy', state: { ...state, ...(harness === undefined ? {} : { harness }) } }
67
+ }
68
+
22
69
  function readStore(root: string): ConversationStore {
23
- const raw = readJson<ConversationStore | LegacySessionState | null>(root, SESSION_FILE, null)
70
+ const raw = readJson(root, SESSION_FILE, decodeConversationWire, null)
24
71
  if (!raw) return { version: 1, conversations: {} }
25
- if ('conversations' in raw) {
72
+ if (raw.kind === 'versioned') {
26
73
  if (raw.version !== 1)
27
74
  throw new Error(`unsupported agent conversation store version: ${String(raw.version)}`)
28
- if (raw.conversations) return { version: 1, conversations: { ...raw.conversations } }
75
+ return { version: 1, conversations: { ...raw.conversations } }
29
76
  }
30
- if ('harness' in raw && raw.harness && raw.sessionId) {
77
+ const legacy = raw.state
78
+ if (legacy.harness && legacy.sessionId) {
31
79
  return {
32
80
  version: 1,
33
81
  conversations: {
34
- [raw.harness]: {
35
- sessionId: raw.sessionId,
36
- turns: raw.turns ?? 0,
37
- updatedAt: raw.updatedAt,
82
+ [legacy.harness]: {
83
+ sessionId: legacy.sessionId,
84
+ turns: legacy.turns ?? 0,
85
+ updatedAt: legacy.updatedAt,
38
86
  },
39
87
  },
40
88
  }
@@ -323,10 +323,20 @@ test('Claude Ask cancellation kills the entire stubborn subprocess group', async
323
323
  onDelta: () => {},
324
324
  })
325
325
 
326
- await waitFor(() => existsSync(pidLog))
327
- const pids = JSON.parse(readFileSync(pidLog, 'utf8')) as { parent: number; child: number }
328
- expect(processExists(pids.parent)).toBe(true)
329
- expect(processExists(pids.child)).toBe(true)
326
+ let pids: { parent: number; child: number } | undefined
327
+ await waitFor(() => {
328
+ if (!existsSync(pidLog)) return false
329
+ try {
330
+ pids = JSON.parse(readFileSync(pidLog, 'utf8')) as { parent: number; child: number }
331
+ return Number.isInteger(pids.parent) && Number.isInteger(pids.child)
332
+ } catch {
333
+ return false
334
+ }
335
+ })
336
+ if (!pids) throw new Error('fake Claude did not publish complete process evidence')
337
+ const processIds = pids
338
+ expect(processExists(processIds.parent)).toBe(true)
339
+ expect(processExists(processIds.child)).toBe(true)
330
340
  controller.abort()
331
341
 
332
342
  expect(await resultPromise).toEqual({
@@ -334,5 +344,5 @@ test('Claude Ask cancellation kills the entire stubborn subprocess group', async
334
344
  isError: true,
335
345
  errorMessage: 'canceled',
336
346
  })
337
- await waitFor(() => !processExists(pids.parent) && !processExists(pids.child))
347
+ await waitFor(() => !processExists(processIds.parent) && !processExists(processIds.child))
338
348
  })
@@ -1,18 +1,11 @@
1
1
  import type { HarnessLoadout } from '../../../../shared/types'
2
2
  import type { HarnessLoadoutOptions } from '../adapter'
3
3
 
4
+ import { asJsonArray, asJsonRecord, asString, parseJson } from '../../../json'
4
5
  import { captureCommand } from '../process'
5
6
  import { probeCodexModels } from './models'
6
7
  import { scanCodexSkills, type CodexPlugin } from './skills'
7
8
 
8
- function parseJson<T>(text: string, fallback: T): T {
9
- try {
10
- return JSON.parse(text) as T
11
- } catch {
12
- return fallback
13
- }
14
- }
15
-
16
9
  /** Inspect Codex configuration, plugins, skills, MCP servers, and models. */
17
10
  export async function loadCodexConfiguration(
18
11
  bin: string,
@@ -24,15 +17,15 @@ export async function loadCodexConfiguration(
24
17
  captureCommand(bin, ['plugin', 'list', '--json'], root),
25
18
  probeCodexModels(bin, root, options?.model, options?.env),
26
19
  ])
27
- const pluginWire = parseJson<any>(pluginResult.stdout, {})
28
- const plugins: CodexPlugin[] = (Array.isArray(pluginWire?.installed) ? pluginWire.installed : [])
29
- .map((plugin: any) => ({
30
- name: String(plugin?.name ?? plugin?.pluginId?.split('@')[0] ?? ''),
31
- path: String(plugin?.source?.path ?? ''),
32
- enabled: plugin?.enabled === true,
33
- }))
34
- .filter((plugin: CodexPlugin) => !!plugin.name && !!plugin.path)
35
- const mcpWire = parseJson<any[]>(mcpResult.stdout, [])
20
+ const pluginWire = asJsonRecord(parseJson(pluginResult.stdout))
21
+ const plugins: CodexPlugin[] = (asJsonArray(pluginWire?.installed) ?? []).flatMap((value) => {
22
+ const plugin = asJsonRecord(value)
23
+ const pluginId = asString(plugin?.pluginId)
24
+ const name = asString(plugin?.name) ?? pluginId?.split('@')[0] ?? ''
25
+ const path = asString(asJsonRecord(plugin?.source)?.path) ?? ''
26
+ return name && path ? [{ name, path, enabled: plugin?.enabled === true }] : []
27
+ })
28
+ const mcpWire = asJsonArray(parseJson(mcpResult.stdout)) ?? []
36
29
  return {
37
30
  ok: mcpResult.code === 0 && pluginResult.code === 0 && modelResult.ok,
38
31
  detail:
@@ -50,10 +43,14 @@ export async function loadCodexConfiguration(
50
43
  models: modelResult.models,
51
44
  cwd: root,
52
45
  tools: [],
53
- mcpServers: mcpWire.map((server) => ({
54
- name: String(server?.name ?? ''),
55
- status: server?.enabled === false ? 'disabled' : String(server?.auth_status ?? 'configured'),
56
- })),
46
+ mcpServers: mcpWire.map((value) => {
47
+ const server = asJsonRecord(value)
48
+ return {
49
+ name: asString(server?.name) ?? '',
50
+ status:
51
+ server?.enabled === false ? 'disabled' : (asString(server?.auth_status) ?? 'configured'),
52
+ }
53
+ }),
57
54
  skills: scanCodexSkills(root, plugins),
58
55
  agents: [],
59
56
  builtinCommandCount: 0,
@@ -22,6 +22,7 @@ import type {
22
22
  HarnessGatewayState,
23
23
  } from '../../../../shared/types'
24
24
 
25
+ import { asJsonRecord, asString, parseJson } from '../../../json'
25
26
  import { readJson, removeState, statePath, writeJson } from '../../../state/store'
26
27
  import { acquireGatewayToken } from './token'
27
28
 
@@ -32,29 +33,35 @@ const GLOBAL_FILE = join(homedir(), '.domain-studio', 'harness-gateway.json')
32
33
 
33
34
  /** Coerce a wire/disk auth block into a well-formed discriminated union. Default
34
35
  * is `mint` (no secret on disk). A legacy `{ apiKey }` shape maps to `token` mode. */
35
- function normalizeAuth(input: any): HarnessGatewayAuth {
36
- if (input?.mode === 'token' || (input?.token != null && input?.mode == null))
37
- return { mode: 'token', token: typeof input.token === 'string' ? input.token.trim() : '' }
38
- if (input?.mode === 'host') return { mode: 'host' }
39
- const instance = typeof input?.instance === 'string' ? input.instance.trim() : ''
36
+ function normalizeAuth(input: unknown): HarnessGatewayAuth {
37
+ const record = asJsonRecord(input)
38
+ if (record?.mode === 'token' || (record?.token != null && record?.mode == null))
39
+ return { mode: 'token', token: asString(record.token)?.trim() ?? '' }
40
+ if (record?.mode === 'host') return { mode: 'host' }
41
+ const instance = asString(record?.instance)?.trim() ?? ''
40
42
  return { mode: 'mint', ...(instance ? { instance } : {}) }
41
43
  }
42
44
 
43
45
  /** Coerce a wire/disk value into a well-formed config (trim, drop blanks). */
44
- function normalize(input: any): HarnessGatewayConfig {
45
- const model = typeof input?.model === 'string' ? input.model.trim() : ''
46
+ function normalize(input: unknown): HarnessGatewayConfig {
47
+ const record = asJsonRecord(input) ?? {}
48
+ const model = asString(record.model)?.trim() ?? ''
46
49
  // back-compat: a pre-union config stored only `apiKey` → treat as a static token
47
50
  const authInput =
48
- input?.auth ??
49
- (typeof input?.apiKey === 'string' ? { mode: 'token', token: input.apiKey } : undefined)
51
+ record.auth ??
52
+ (typeof record.apiKey === 'string' ? { mode: 'token', token: record.apiKey } : undefined)
50
53
  return {
51
- enabled: input?.enabled === true,
52
- baseUrl: typeof input?.baseUrl === 'string' ? input.baseUrl.trim() : '',
54
+ enabled: record.enabled === true,
55
+ baseUrl: asString(record.baseUrl)?.trim() ?? '',
53
56
  ...(model ? { model } : {}),
54
57
  auth: normalizeAuth(authInput),
55
58
  }
56
59
  }
57
60
 
61
+ function decodeConfig(value: unknown): HarnessGatewayConfig | undefined {
62
+ return asJsonRecord(value) ? normalize(value) : undefined
63
+ }
64
+
58
65
  function validateEnabledConfig(config: HarnessGatewayConfig): void {
59
66
  if (!config.enabled) return
60
67
  if (!config.baseUrl) throw new Error('gateway base URL is required while enabled')
@@ -71,17 +78,12 @@ function validateEnabledConfig(config: HarnessGatewayConfig): void {
71
78
  }
72
79
 
73
80
  function readLocal(root: string): HarnessGatewayConfig | null {
74
- const raw = readJson<HarnessGatewayConfig | null>(root, LOCAL_FILE, null)
75
- return raw ? normalize(raw) : null
81
+ return readJson(root, LOCAL_FILE, decodeConfig, null)
76
82
  }
77
83
 
78
84
  function readGlobal(): HarnessGatewayConfig | null {
79
85
  if (!existsSync(GLOBAL_FILE)) return null
80
- try {
81
- return normalize(JSON.parse(readFileSync(GLOBAL_FILE, 'utf8')))
82
- } catch {
83
- return null
84
- }
86
+ return decodeConfig(parseJson(readFileSync(GLOBAL_FILE, 'utf8'))) ?? null
85
87
  }
86
88
 
87
89
  /** Write (or, on null, delete) the global default. Not under any domain root, so
@@ -2,6 +2,7 @@ import type { AgentEffort, StudioSettings } from '../../../shared/types'
2
2
  import type { AgentHarness } from './adapter'
3
3
 
4
4
  import { effectiveAgentEffort } from '../../../shared/agent-effort'
5
+ import { asJsonRecord, asString } from '../../json'
5
6
  import { readSettings } from '../../state/settings'
6
7
  import { readJson, writeJson } from '../../state/store'
7
8
  import { resolveHarnessEnv } from './gateway/config'
@@ -27,11 +28,18 @@ export type HarnessConfigurationResult =
27
28
  | { ok: true; configuration: HarnessConfiguration }
28
29
  | { ok: false; error: string }
29
30
 
31
+ function decodeStoredSelection(value: unknown): { id?: string } | undefined {
32
+ const record = asJsonRecord(value)
33
+ if (!record) return undefined
34
+ const id = asString(record.id)
35
+ return id === undefined ? {} : { id }
36
+ }
37
+
30
38
  export function getHarnessSelection(root: string): HarnessSelection {
31
39
  const environment = process.env.DOMAIN_STUDIO_HARNESS?.trim().toLowerCase()
32
40
  if (environment && hasHarness(environment))
33
41
  return { id: environment, locked: true, source: 'environment' }
34
- const stored = readJson<{ id?: string }>(root, SELECTION_FILE, {})
42
+ const stored = readJson(root, SELECTION_FILE, decodeStoredSelection, {})
35
43
  const id = stored.id?.toLowerCase()
36
44
  if (id && hasHarness(id)) return { id, locked: false, source: 'domain' }
37
45
  return { id: 'claude', locked: false, source: 'default' }
@@ -4,30 +4,35 @@ import type { SchemaIR } from '../../../shared/types'
4
4
 
5
5
  import { describeAnchor } from './anchors'
6
6
 
7
- const importedKey = 'directory.example.dev:interface.Named' as const
8
-
7
+ const importedKey = 'directory.example.dev:class.Named' as const
9
8
  const ir: SchemaIR = {
10
9
  format: 'astrale.dsl',
11
10
  version: 'v1',
12
11
  domain: 'example.dev',
13
- types: {},
14
- interfaces: {},
15
- classes: {},
16
- imports: {},
12
+ classes: {
13
+ Item: {
14
+ type: 'node',
15
+ name: 'Item',
16
+ origin: 'example.dev',
17
+ ref: { origin: 'example.dev', kind: 'class', name: 'Item' },
18
+ properties: { count: { type: 'integer' } },
19
+ required: ['count'],
20
+ methods: {},
21
+ },
22
+ },
17
23
  importsByKey: {
18
24
  [importedKey]: {
19
25
  origin: 'directory.example.dev',
20
- definition: 'interface',
21
26
  key: importedKey,
22
- ref: { origin: 'directory.example.dev', kind: 'interface', name: 'Named' },
27
+ ref: { origin: 'directory.example.dev', kind: 'class', name: 'Named' },
23
28
  },
24
29
  },
25
- importedInterfacesByKey: {
30
+ importedClassesByKey: {
26
31
  [importedKey]: {
27
- type: 'interface',
32
+ type: 'node',
28
33
  name: 'Named',
29
34
  origin: 'directory.example.dev',
30
- ref: { origin: 'directory.example.dev', kind: 'interface', name: 'Named' },
35
+ ref: { origin: 'directory.example.dev', kind: 'class', name: 'Named' },
31
36
  properties: { label: { type: 'string' } },
32
37
  required: [],
33
38
  methods: {},
@@ -36,39 +41,30 @@ const ir: SchemaIR = {
36
41
  functions: {
37
42
  inspect: {
38
43
  name: 'inspect',
39
- input: {
40
- type: 'object',
41
- properties: { cursor: { type: 'string' } },
42
- required: [],
43
- },
44
- params: { cursor: { type: 'string' } },
45
- requiredParams: [],
44
+ input: { type: 'object', properties: { cursor: { type: 'string' } }, required: [] },
46
45
  output: { mode: 'stream', item: { type: 'integer' } },
47
- returns: { type: 'integer' },
48
- static: true,
49
- inheritance: 'default',
50
46
  auth: 'authenticated',
51
47
  },
52
48
  },
49
+ views: {},
50
+ policies: {},
51
+ dependencies: [],
52
+ core: {},
53
53
  }
54
54
 
55
- describe('canonical anchor descriptions', () => {
56
- test('describes standalone Functions with exact input, output mode, and auth', () => {
57
- expect(describeAnchor('function.inspect', ir, undefined)).toContain(
58
- 'inspect(cursor:string?)→stream<int> [static,authenticated]',
55
+ describe('anchor descriptions', () => {
56
+ test('describes local and exact imported Class properties', () => {
57
+ expect(describeAnchor('class.Item.property.count', ir, undefined)).toContain(
58
+ '**Item.count** : int',
59
+ )
60
+ expect(describeAnchor(`class.${importedKey}.property.label`, ir, undefined)).toContain(
61
+ '**Named.label** : string?',
59
62
  )
60
63
  })
61
64
 
62
- test('resolves an imported interface member by its qualified identity', () => {
63
- expect(
64
- describeAnchor(
65
- 'interface.directory.example.dev:interface.Named.property.label',
66
- ir,
67
- undefined,
68
- ),
69
- ).toBe('**Named.label** : string?')
70
- expect(
71
- describeAnchor('interface.directory.example.dev:interface.Named', ir, undefined),
72
- ).toContain('from directory.example.dev')
65
+ test('describes standalone Functions with output mode and authentication', () => {
66
+ expect(describeAnchor('function.inspect', ir, undefined)).toContain(
67
+ 'stream<int> [authenticated]',
68
+ )
73
69
  })
74
70
  })