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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/README.md +23 -12
  2. package/dist/astrale.js +51494 -56307
  3. package/dist/public/connect-core.js +2028 -26846
  4. package/dist/public/keys/index.js +1755 -40694
  5. package/dist/public/paths/index.js +859 -39518
  6. package/dist/types/admin/binding.d.ts +19 -0
  7. package/dist/types/admin/instance/client.d.ts +22 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +5 -12
  10. package/dist/types/connection/auth.d.ts +3 -0
  11. package/dist/types/connection/call.d.ts +3 -0
  12. package/dist/types/connection/command.d.ts +27 -0
  13. package/dist/types/connection/credential.d.ts +14 -0
  14. package/dist/types/connection/errors.d.ts +1 -0
  15. package/dist/types/connection/exchange.d.ts +9 -0
  16. package/dist/types/connection/failure/classify.d.ts +2 -0
  17. package/dist/types/connection/failure/index.d.ts +5 -0
  18. package/dist/types/connection/failure/model.d.ts +25 -0
  19. package/dist/types/connection/failure/render.d.ts +3 -0
  20. package/dist/types/connection/index.d.ts +8 -0
  21. package/dist/types/connection/reasons.d.ts +37 -0
  22. package/dist/types/connection/self.d.ts +37 -0
  23. package/dist/types/connection/session.d.ts +31 -0
  24. package/dist/types/connection/target.d.ts +38 -0
  25. package/dist/types/errors.d.ts +1 -1
  26. package/dist/types/lib/admin-instance.d.ts +17 -0
  27. package/dist/types/lib/admin-target.d.ts +6 -2
  28. package/dist/types/lib/failure-debug.d.ts +1 -0
  29. package/dist/types/lib/idp.d.ts +7 -0
  30. package/dist/types/lib/instance-target.d.ts +1 -1
  31. package/dist/types/lib/instance.d.ts +10 -2
  32. package/dist/types/lib/log.d.ts +5 -3
  33. package/dist/types/lib/meta.d.ts +2 -2
  34. package/dist/types/lib/proc.d.ts +43 -0
  35. package/dist/types/lib/self.d.ts +9 -0
  36. package/dist/types/lib/update.d.ts +131 -0
  37. package/package.json +8 -10
  38. package/src/__tests__/fixtures/publication.ts +20 -0
  39. package/src/admin/__tests__/binding.test.ts +31 -0
  40. package/src/admin/__tests__/fixture.ts +101 -0
  41. package/src/admin/binding.ts +98 -0
  42. package/src/admin/catalog/.spec/api.d.ts +2 -2
  43. package/src/admin/catalog/__tests__/client.test.ts +20 -49
  44. package/src/admin/catalog/client.ts +36 -32
  45. package/src/admin/catalog/model.ts +3 -4
  46. package/src/admin/graph/.spec/api.d.ts +4 -10
  47. package/src/admin/graph/nodes.ts +1 -1
  48. package/src/admin/instance/.spec/api.d.ts +2 -2
  49. package/src/admin/instance/__tests__/client.test.ts +40 -163
  50. package/src/admin/instance/client.ts +35 -137
  51. package/src/admin/instance/index.ts +1 -2
  52. package/src/admin/instance/model.ts +11 -20
  53. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  54. package/src/commands/__tests__/auth-login.test.ts +54 -1
  55. package/src/commands/__tests__/call-describe.test.ts +46 -33
  56. package/src/commands/__tests__/call.test.ts +5 -1
  57. package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
  58. package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
  59. package/src/commands/__tests__/domain-list.test.ts +63 -4
  60. package/src/commands/__tests__/install-identity-override.test.ts +19 -19
  61. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  62. package/src/commands/__tests__/instance-status.test.ts +139 -0
  63. package/src/commands/__tests__/read-commands.test.ts +35 -10
  64. package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
  65. package/src/commands/__tests__/update.test.ts +95 -0
  66. package/src/commands/call-describe.ts +60 -68
  67. package/src/commands/call.ts +43 -56
  68. package/src/commands/domain/install.ts +13 -17
  69. package/src/commands/domain/list.ts +18 -13
  70. package/src/commands/domain/publish.ts +14 -11
  71. package/src/commands/domain/uninstall.ts +2 -2
  72. package/src/commands/get.ts +14 -15
  73. package/src/commands/identity/__tests__/register.test.ts +3 -3
  74. package/src/commands/identity/register.ts +5 -4
  75. package/src/commands/instance/create.ts +8 -16
  76. package/src/commands/instance/delete.ts +12 -9
  77. package/src/commands/instance/list.ts +2 -2
  78. package/src/commands/instance/status.ts +66 -20
  79. package/src/commands/instance/use.ts +16 -12
  80. package/src/commands/introspect.ts +9 -16
  81. package/src/commands/logs.ts +24 -25
  82. package/src/commands/mutate.ts +6 -5
  83. package/src/commands/query.ts +27 -30
  84. package/src/commands/studio.ts +20 -0
  85. package/src/commands/token.ts +8 -7
  86. package/src/commands/update.ts +68 -22
  87. package/src/commands/view.ts +7 -6
  88. package/src/connection/.spec/api.d.ts +7 -8
  89. package/src/connection/.spec/architecture.md +5 -4
  90. package/src/connection/.spec/flows/session.ts +2 -2
  91. package/src/connection/.spec/laws/connection.ts +6 -2
  92. package/src/connection/.spec/layout.ts +1 -0
  93. package/src/connection/__tests__/credential.test.ts +20 -1
  94. package/src/connection/__tests__/errors.test.ts +43 -32
  95. package/src/connection/__tests__/exchange.test.ts +36 -6
  96. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  97. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  98. package/src/connection/__tests__/self.test.ts +31 -11
  99. package/src/connection/__tests__/session.test.ts +3 -3
  100. package/src/connection/__tests__/target.test.ts +1 -0
  101. package/src/connection/auth.ts +13 -0
  102. package/src/connection/call.ts +1 -1
  103. package/src/connection/credential.ts +2 -2
  104. package/src/connection/errors.ts +1 -355
  105. package/src/connection/exchange.ts +52 -27
  106. package/src/connection/failure/classify.ts +110 -0
  107. package/src/connection/failure/index.ts +18 -0
  108. package/src/connection/failure/model.ts +28 -0
  109. package/src/connection/failure/render.ts +116 -0
  110. package/src/connection/reasons.ts +16 -0
  111. package/src/connection/self.ts +39 -21
  112. package/src/connection/session.ts +19 -8
  113. package/src/errors.ts +3 -2
  114. package/src/graph/.spec/api.d.ts +12 -5
  115. package/src/graph/.spec/layout.ts +9 -1
  116. package/src/graph/__tests__/mutation.test.ts +2 -2
  117. package/src/graph/__tests__/query.test.ts +25 -6
  118. package/src/graph/class.ts +30 -0
  119. package/src/graph/index.ts +1 -0
  120. package/src/graph/query.ts +21 -32
  121. package/src/identity/.spec/api.d.ts +2 -2
  122. package/src/identity/__tests__/registration.test.ts +1 -1
  123. package/src/identity/registration.ts +3 -3
  124. package/src/keys/__tests__/keys.test.ts +4 -0
  125. package/src/keys/credential.ts +1 -0
  126. package/src/lib/__tests__/admin-target.test.ts +12 -0
  127. package/src/lib/__tests__/command-dx.test.ts +1 -1
  128. package/src/lib/__tests__/domain-publication.test.ts +138 -0
  129. package/src/lib/__tests__/idp-session.test.ts +22 -0
  130. package/src/lib/__tests__/idp.test.ts +36 -4
  131. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  132. package/src/lib/__tests__/instance-target.test.ts +7 -39
  133. package/src/lib/__tests__/instance.test.ts +6 -0
  134. package/src/lib/__tests__/log-errors.test.ts +64 -0
  135. package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
  136. package/src/lib/__tests__/update.test.ts +113 -8
  137. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  138. package/src/lib/__tests__/view-server.test.ts +1 -1
  139. package/src/lib/__tests__/view-session.test.ts +1 -1
  140. package/src/lib/admin-instance.ts +14 -8
  141. package/src/lib/admin-target.ts +21 -2
  142. package/src/lib/command-dx.ts +9 -9
  143. package/src/lib/domain-publication.ts +104 -0
  144. package/src/lib/failure-debug.ts +26 -0
  145. package/src/lib/idp.ts +39 -4
  146. package/src/lib/instance-candidates.ts +2 -2
  147. package/src/lib/instance-target.ts +3 -14
  148. package/src/lib/instance.ts +22 -12
  149. package/src/lib/log.ts +16 -9
  150. package/src/lib/login-flow.ts +13 -3
  151. package/src/lib/meta.ts +2 -2
  152. package/src/lib/provision-instance.ts +34 -57
  153. package/src/lib/update.ts +124 -30
  154. package/src/lib/validation.ts +2 -2
  155. package/src/lib/view/resolve.ts +1 -1
  156. package/src/program/__tests__/program.test.ts +20 -4
  157. package/src/program/build.ts +2 -2
  158. package/src/setup/__tests__/instance-step.test.ts +27 -10
  159. package/src/setup/steps/instance.ts +22 -15
  160. package/studio/client/dist/assets/{elk-api-D2xgMJvi.js → elk-api-ByzoDZWH.js} +1 -1
  161. package/studio/client/dist/assets/index-B0RCgUOT.js +8 -0
  162. package/studio/client/dist/assets/index-BiGR8Oo9.css +1 -0
  163. package/studio/client/dist/assets/index-N8J8EKlB.js +81 -0
  164. package/studio/client/dist/index.html +2 -2
  165. package/studio/package.json +5 -10
  166. package/studio/server/agent/ask.test.ts +1 -1
  167. package/studio/server/agent/bridge/grant.test.ts +1 -1
  168. package/studio/server/agent/bridge/routes.test.ts +1 -1
  169. package/studio/server/agent/bridge/stdio.ts +8 -1
  170. package/studio/server/agent/conversation.test.ts +10 -5
  171. package/studio/server/agent/conversation.ts +56 -8
  172. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  173. package/studio/server/agent/harness/codex/loadout.ts +18 -21
  174. package/studio/server/agent/harness/gateway/config.ts +20 -18
  175. package/studio/server/agent/harness/selection.ts +9 -1
  176. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  177. package/studio/server/agent/prompts/anchors.ts +20 -49
  178. package/studio/server/agent/prompts/system.test.ts +3 -2
  179. package/studio/server/agent/prompts/system.ts +6 -5
  180. package/studio/server/agent/prompts/turn.ts +13 -4
  181. package/studio/server/agent/routes.test.ts +1 -1
  182. package/studio/server/agent/run/completion.ts +2 -2
  183. package/studio/server/agent/run/coordinator.test.ts +1 -1
  184. package/studio/server/agent/run/preparation.ts +6 -5
  185. package/studio/server/agent/run/transcript.test.ts +35 -1
  186. package/studio/server/agent/run/transcript.ts +169 -3
  187. package/studio/server/agent/run/usage.test.ts +24 -0
  188. package/studio/server/agent/run/usage.ts +26 -1
  189. package/studio/server/api/canvas.ts +43 -0
  190. package/studio/server/api/comments.ts +85 -0
  191. package/studio/server/api/context.ts +61 -0
  192. package/studio/server/api/deployment.ts +39 -0
  193. package/studio/server/api/documents.ts +55 -0
  194. package/studio/server/api/domain.ts +59 -0
  195. package/studio/server/api/http.ts +45 -0
  196. package/studio/server/api/project.ts +57 -0
  197. package/studio/server/api/schema.ts +12 -0
  198. package/studio/server/api/views.ts +57 -0
  199. package/studio/server/api/workspace.ts +60 -0
  200. package/studio/server/api-agent-loadout.test.ts +1 -1
  201. package/studio/server/api.test.ts +147 -0
  202. package/studio/server/api.ts +20 -422
  203. package/studio/server/cache.test.ts +122 -0
  204. package/studio/server/cache.ts +162 -11
  205. package/studio/server/cli-consumers.test.ts +494 -0
  206. package/studio/server/cli.test.ts +88 -0
  207. package/studio/server/cli.ts +240 -0
  208. package/studio/server/client-package.ts +25 -1
  209. package/studio/server/domain.test.ts +50 -40
  210. package/studio/server/domain.ts +83 -52
  211. package/studio/server/environment/dotenv-preview.test.ts +39 -0
  212. package/studio/server/environment/dotenv-preview.ts +27 -0
  213. package/studio/server/environment/files.test.ts +53 -0
  214. package/studio/server/{state/env.ts → environment/files.ts} +7 -48
  215. package/studio/server/{state → handoff}/copy.ts +21 -6
  216. package/studio/server/handoff/service.test.ts +22 -0
  217. package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
  218. package/studio/server/index.ts +1 -1
  219. package/studio/server/instances/active.ts +72 -0
  220. package/studio/server/instances/deploy-record.test.ts +31 -0
  221. package/studio/server/instances/deploy-record.ts +37 -0
  222. package/studio/server/instances/deploy.ts +56 -0
  223. package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
  224. package/studio/server/instances/probe.ts +67 -0
  225. package/studio/server/instances/status.test.ts +12 -0
  226. package/studio/server/instances/status.ts +49 -0
  227. package/studio/server/introspect/anatomy/client-tree.ts +57 -0
  228. package/studio/server/introspect/anatomy/env-fields.ts +66 -0
  229. package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
  230. package/studio/server/introspect/anatomy/source.ts +181 -0
  231. package/studio/server/introspect/anatomy/views/routes.ts +114 -0
  232. package/studio/server/introspect/anatomy/views.ts +53 -0
  233. package/studio/server/introspect/anatomy-extras.test.ts +106 -35
  234. package/studio/server/introspect/anatomy-extras.ts +7 -726
  235. package/studio/server/introspect/anatomy.test.ts +22 -14
  236. package/studio/server/introspect/anatomy.ts +52 -28
  237. package/studio/server/introspect/bundle.ts +15 -9
  238. package/studio/server/introspect/canonical-schema.test.ts +93 -309
  239. package/studio/server/introspect/canonical-schema.ts +257 -425
  240. package/studio/server/introspect/config-preview.test.ts +32 -0
  241. package/studio/server/introspect/config-preview.ts +119 -0
  242. package/studio/server/introspect/core-extractor.ts +18 -127
  243. package/studio/server/introspect/core.ts +1 -2
  244. package/studio/server/introspect/diff.test.ts +18 -18
  245. package/studio/server/introspect/diff.ts +44 -90
  246. package/studio/server/introspect/extractor.ts +23 -116
  247. package/studio/server/introspect/hash.ts +5 -2
  248. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  249. package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
  250. package/studio/server/introspect/overlay.test.ts +26 -54
  251. package/studio/server/introspect/overlay.ts +10 -37
  252. package/studio/server/introspect/revision.test.ts +54 -0
  253. package/studio/server/introspect/revision.ts +49 -0
  254. package/studio/server/introspect/runtime.test.ts +83 -143
  255. package/studio/server/introspect/runtime.ts +40 -11
  256. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  257. package/studio/server/introspect/schema-ir-json.ts +151 -0
  258. package/studio/server/introspect/schema-refs.test.ts +43 -88
  259. package/studio/server/introspect/schema-refs.ts +14 -49
  260. package/studio/server/introspect/source-overlay/annotations.ts +14 -0
  261. package/studio/server/introspect/source-overlay/handlers.ts +161 -0
  262. package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
  263. package/studio/server/introspect/source-overlay/project.ts +248 -0
  264. package/studio/server/introspect/source-overlay/spans.ts +330 -0
  265. package/studio/server/json.ts +46 -0
  266. package/studio/server/lifecycle.ts +5 -1
  267. package/studio/server/sse.test.ts +26 -0
  268. package/studio/server/sse.ts +4 -1
  269. package/studio/server/state/baseline.test.ts +223 -7
  270. package/studio/server/state/baseline.ts +148 -34
  271. package/studio/server/state/comments.test.ts +66 -1
  272. package/studio/server/state/comments.ts +173 -10
  273. package/studio/server/state/context.ts +34 -2
  274. package/studio/server/state/documents.ts +42 -1
  275. package/studio/server/state/integrations.ts +27 -1
  276. package/studio/server/state/layout.test.ts +34 -0
  277. package/studio/server/state/layout.ts +44 -17
  278. package/studio/server/state/settings.ts +29 -22
  279. package/studio/server/state/store.test.ts +122 -0
  280. package/studio/server/state/store.ts +66 -17
  281. package/studio/server/state/visibility.ts +22 -11
  282. package/studio/server/views/model.test.ts +57 -0
  283. package/studio/server/views/model.ts +66 -0
  284. package/studio/server/views/runtime.ts +40 -0
  285. package/studio/server/views/selection-repository.test.ts +31 -0
  286. package/studio/server/views/selection-repository.ts +60 -0
  287. package/studio/server/views/session.test.ts +73 -0
  288. package/studio/server/views/session.ts +166 -0
  289. package/studio/server/views/target.test.ts +78 -0
  290. package/studio/server/views/target.ts +222 -0
  291. package/studio/server/watch.test.ts +11 -11
  292. package/studio/server/watch.ts +9 -5
  293. package/studio/server/workspace/catalog.test.ts +17 -0
  294. package/studio/server/workspace/catalog.ts +43 -0
  295. package/studio/server/{state → workspace}/create.test.ts +1 -1
  296. package/studio/server/{state → workspace}/create.ts +1 -1
  297. package/studio/server/{state → workspace}/git.ts +1 -1
  298. package/studio/server/workspace/updates.ts +83 -0
  299. package/studio/server/workspace-state.ts +1 -1
  300. package/studio/server/workspace-watch.ts +2 -2
  301. package/studio/shared/contracts/README.md +16 -0
  302. package/studio/shared/contracts/agent.ts +270 -0
  303. package/studio/shared/contracts/runtime.ts +50 -0
  304. package/studio/shared/contracts/schema.ts +393 -0
  305. package/studio/shared/contracts/surface.test.ts +317 -0
  306. package/studio/shared/contracts/workspace.ts +265 -0
  307. package/studio/shared/layout.test.ts +116 -0
  308. package/studio/shared/schema/identity.test.ts +34 -0
  309. package/studio/shared/schema/identity.ts +68 -0
  310. package/studio/shared/types.ts +11 -1099
  311. package/studio/tsconfig.json +1 -1
  312. package/viewer/dist/main.js +40 -61
  313. package/.check-workspace.cjs +0 -40
  314. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  315. package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
  316. package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
  317. package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
  318. package/studio/server/state/catalog.ts +0 -117
  319. package/studio/server/state/instance.ts +0 -280
  320. package/studio/server/state/updates.ts +0 -63
  321. package/studio/server/state/views.test.ts +0 -286
  322. package/studio/server/state/views.ts +0 -535
@@ -1,11 +1,19 @@
1
- import type { DomainBinding } from '@astrale-os/kernel-client/domain'
2
- import type { ClientSession } from '@astrale-os/kernel-client/session'
1
+ import type { ClientSession } from '@astrale-os/sdk/client/session'
3
2
  import type { Node } from '@astrale-os/sdk/graph/node'
3
+ import type { ResolvedClass } from '@astrale-os/sdk/schema'
4
4
 
5
- import { bind } from '@astrale-os/kernel-client/domain'
6
5
  import { Path } from '@astrale-os/sdk/graph/path'
7
6
  import { Query } from '@astrale-os/sdk/query'
8
7
 
8
+ import {
9
+ bindAdmin,
10
+ invokeAdminMethod,
11
+ requireAdminBinding,
12
+ requireAdminClass,
13
+ requireAdminCore,
14
+ requireAdminProperty,
15
+ type AdminBinding,
16
+ } from '../binding'
9
17
  import { readAllNodes, type AdminGraphApi } from '../graph'
10
18
  import {
11
19
  AdminDomainNotFoundError,
@@ -14,16 +22,9 @@ import {
14
22
  type PublishDomainResult,
15
23
  } from './model'
16
24
 
17
- const ADMIN_ORIGIN = 'admin.astrale.ai'
18
25
  const PAGE_SIZE = 256
19
26
  const MAXIMUM_DOMAINS = 10_000
20
27
  const MAXIMUM_PAGES = Math.ceil(MAXIMUM_DOMAINS / PAGE_SIZE) + 1
21
- const DomainRef = Object.freeze({ origin: ADMIN_ORIGIN, kind: 'class' as const, name: 'Domain' })
22
- const fleetInstallsByDefault = Object.freeze({
23
- origin: ADMIN_ORIGIN,
24
- kind: 'class' as const,
25
- name: 'fleet_installs_domain_by_default',
26
- })
27
28
 
28
29
  export interface AdminCatalogContext {
29
30
  readonly session: ClientSession
@@ -37,7 +38,7 @@ export interface AdminCatalogApi {
37
38
  }
38
39
 
39
40
  export interface AdminCatalogDependencies {
40
- readonly bind?: (session: ClientSession) => Promise<DomainBinding>
41
+ readonly bind?: (session: ClientSession) => Promise<AdminBinding>
41
42
  readonly operationId?: (kind: 'publish' | 'configure-default') => string
42
43
  }
43
44
 
@@ -46,21 +47,22 @@ export async function connectAdminCatalog(
46
47
  context: AdminCatalogContext,
47
48
  dependencies: AdminCatalogDependencies = {},
48
49
  ): Promise<AdminCatalogApi> {
49
- const binding = await (dependencies.bind ?? bindInstalledAdmin)(context.session)
50
- if (binding.$.publication?.origin !== ADMIN_ORIGIN || binding.$.origin !== ADMIN_ORIGIN) {
51
- throw new TypeError('Configured Admin target does not serve the Admin Domain.')
52
- }
53
- const Domain = binding.$.class('Domain')
54
- const Fleet = binding.$.class('Fleet')
55
- const fleet = binding.$.core.nodes.fleet?.path
56
- if (fleet === undefined) throw new TypeError('Admin Domain has no singleton Fleet receiver.')
50
+ const binding = requireAdminBinding(await (dependencies.bind ?? bindAdmin)(context.session))
51
+ const Domain = requireAdminClass(binding, 'Domain', 'node')
52
+ const Fleet = requireAdminClass(binding, 'Fleet', 'node')
53
+ const fleetInstallsByDefault = requireAdminClass(
54
+ binding,
55
+ 'fleet_installs_domain_by_default',
56
+ 'edge',
57
+ )
58
+ const fleet = requireAdminCore(binding, 'fleet')
57
59
  const operationId = dependencies.operationId ?? defaultOperationId
58
60
 
59
61
  const list = async (): Promise<DomainInfo[]> => {
60
62
  const [nodes, defaultsPage] = await Promise.all([
61
63
  readAllNodes(
62
64
  context.graph,
63
- Query.from({ kind: 'node', definitions: [DomainRef] }).select({
65
+ Query.from({ nodes: [Domain] }).select({
64
66
  kind: 'nodes',
65
67
  projection: { kind: 'value' },
66
68
  }),
@@ -108,13 +110,13 @@ export async function connectAdminCatalog(
108
110
  let entry = existing
109
111
  if (registryChanged) {
110
112
  entry = domainFromSummary(
111
- await binding.$.invoke(Fleet.$.method('publishDomain') as never, fleet, {
113
+ await invokeAdminMethod(context.session, binding, Fleet, 'publishDomain', fleet, {
112
114
  operationId: operationId('publish'),
113
115
  origin: input.origin,
114
116
  name: input.name,
115
117
  discoveryUrl: input.url,
116
118
  ...(description === undefined ? {} : { description }),
117
- } as never),
119
+ }),
118
120
  existing?.installByDefault === true,
119
121
  )
120
122
  }
@@ -125,13 +127,16 @@ export async function connectAdminCatalog(
125
127
  (entry.installByDefault ?? false) !== input.installByDefault
126
128
  if (defaultChanged) {
127
129
  entry = domainFromSummary(
128
- await binding.$.invoke(
129
- Domain.$.method('configureDefault') as never,
130
+ await invokeAdminMethod(
131
+ context.session,
132
+ binding,
133
+ Domain,
134
+ 'configureDefault',
130
135
  Path.parse(entry.id),
131
136
  {
132
137
  operationId: operationId('configure-default'),
133
138
  enabled: input.installByDefault,
134
- } as never,
139
+ },
135
140
  ),
136
141
  input.installByDefault === true,
137
142
  )
@@ -145,11 +150,7 @@ export async function connectAdminCatalog(
145
150
  })
146
151
  }
147
152
 
148
- async function bindInstalledAdmin(session: ClientSession): Promise<DomainBinding> {
149
- return bind(session, await session.installed(ADMIN_ORIGIN))
150
- }
151
-
152
- type DynamicDefinition = ReturnType<DomainBinding['$']['class']>
153
+ type DynamicDefinition = ResolvedClass<'node'>
153
154
 
154
155
  function domainFromNode(
155
156
  definition: DynamicDefinition,
@@ -185,7 +186,10 @@ function domainFromSummary(input: unknown, installByDefault: boolean): DomainInf
185
186
  }
186
187
 
187
188
  function requiredProperty(definition: DynamicDefinition, node: Node, name: string): string {
188
- return requiredString(node.props[definition.$.property(name).key], `Admin Domain.${name}`)
189
+ return requiredString(
190
+ node.props[requireAdminProperty(definition, name).key],
191
+ `Admin Domain.${name}`,
192
+ )
189
193
  }
190
194
 
191
195
  function optionalProperty(
@@ -193,7 +197,7 @@ function optionalProperty(
193
197
  node: Node,
194
198
  name: string,
195
199
  ): Readonly<Record<string, string>> {
196
- const value = node.props[definition.$.property(name).key]
200
+ const value = node.props[requireAdminProperty(definition, name).key]
197
201
  return value === undefined ? {} : { [name]: requiredString(value, `Admin Domain.${name}`) }
198
202
  }
199
203
 
@@ -33,10 +33,9 @@ export interface InstallDomainResult {
33
33
  readonly error?: string | null
34
34
  }
35
35
 
36
- export class AdminDomainNotFoundError extends Error {
37
- readonly name = 'NotFoundError'
38
-
36
+ export class AdminDomainNotFoundError extends AstraleError {
39
37
  constructor(readonly identifier: string) {
40
- super(`No visible Admin Domain matches ${JSON.stringify(identifier)}.`)
38
+ super('DOMAIN_NOT_FOUND', `No visible Admin Domain matches ${JSON.stringify(identifier)}.`)
41
39
  }
42
40
  }
41
+ import { AstraleError } from '../../errors'
@@ -1,18 +1,12 @@
1
- import type { GraphQueryOptions, NeighborsOptions, NodePage } from '@astrale-os/kernel-client/graph'
2
- import type { ClassPath } from '@astrale-os/sdk/graph/class'
1
+ import type { GraphApi } from '@astrale-os/sdk/client'
3
2
  import type { Node } from '@astrale-os/sdk/graph/node'
4
- import type { PathLike } from '@astrale-os/sdk/graph/path'
5
- import type { QueryAST, QueryResult } from '@astrale-os/sdk/query'
3
+ import type { QueryAST } from '@astrale-os/sdk/query'
6
4
 
7
5
  /** Smallest Kernel graph capability needed by bounded Admin graph reads. */
8
- export interface AdminGraphQueryApi {
9
- query(ast: QueryAST, options?: GraphQueryOptions): Promise<QueryResult>
10
- }
6
+ export type AdminGraphQueryApi = Pick<GraphApi, 'query'>
11
7
 
12
8
  /** Caller-scoped graph reads shared by the Admin catalog and Instance journeys. */
13
- export interface AdminGraphApi extends AdminGraphQueryApi {
14
- neighbors(source: PathLike, edge: ClassPath, options: NeighborsOptions): Promise<NodePage>
15
- }
9
+ export type AdminGraphApi = Pick<GraphApi, 'query' | 'neighbors'>
16
10
 
17
11
  export interface ReadAllNodesOptions {
18
12
  readonly label: string
@@ -1,4 +1,4 @@
1
- import type { GraphApi } from '@astrale-os/kernel-client/graph'
1
+ import type { GraphApi } from '@astrale-os/sdk/client'
2
2
  import type { Node } from '@astrale-os/sdk/graph/node'
3
3
  import type { QueryAST } from '@astrale-os/sdk/query'
4
4
 
@@ -1,5 +1,5 @@
1
- import type { DomainBinding } from '@astrale-os/kernel-client/domain'
2
- import type { ClientSession } from '@astrale-os/kernel-client/session'
1
+ import type { ClientSession } from '@astrale-os/sdk/client/session'
2
+ import type { DomainBinding } from '@astrale-os/shell'
3
3
 
4
4
  import type { AdminGraphApi } from '../../graph/.spec/api.js'
5
5
 
@@ -1,103 +1,28 @@
1
- import type { DomainBinding } from '@astrale-os/kernel-client/domain'
2
- import type { Node } from '@astrale-os/sdk/graph/node'
3
- import type { QueryAST } from '@astrale-os/sdk/query'
4
-
5
- import { ClassPath } from '@astrale-os/sdk/graph/class'
6
- import { NodeId } from '@astrale-os/sdk/graph/node'
7
- import { Path } from '@astrale-os/sdk/graph/path'
8
- import { describe, expect, mock, test } from 'bun:test'
9
-
10
- import type { AdminGraphApi } from '../../graph'
1
+ import { describe, expect, test } from 'bun:test'
11
2
 
3
+ import { adminBinding, adminSession } from '../../__tests__/fixture'
12
4
  import { connectAdminInstances } from '../client'
13
5
 
14
- const methods: Array<{ owner: string; name: string }> = []
15
-
16
- function definition(name: string) {
17
- return {
18
- name,
19
- $: {
20
- method(method: string) {
21
- const value = { owner: name, name: method }
22
- methods.push(value)
23
- return value
24
- },
25
- property(property: string) {
26
- return { key: property }
27
- },
28
- },
29
- }
30
- }
31
-
32
- function node(id: string, props: Record<string, unknown>): Node {
33
- return {
34
- id: NodeId(id),
35
- class: ClassPath.from('admin.astrale.ai', 'Instance'),
36
- props: props as never,
37
- }
38
- }
39
-
40
- function graphResult(nodes: readonly Node[], cursor?: string) {
41
- return {
42
- result: {
43
- kind: 'nodes' as const,
44
- nodes: nodes.map((value) => ({ kind: 'value' as const, value })),
45
- },
46
- page: cursor === undefined ? {} : { next: cursor },
47
- }
48
- }
49
-
50
- function sourceName(ast: QueryAST): string | undefined {
51
- const term = ast.source.terms[0]
52
- return term?.kind === 'definition' ? term.definition.name : undefined
53
- }
54
-
55
6
  function fixture(input: {
56
- instances?: readonly Node[]
57
- hosts?: readonly Node[]
58
- reserved?: Node | null
59
7
  invoke?: (method: { owner: string; name: string }, receiver: unknown, input: unknown) => unknown
60
8
  }) {
61
- methods.length = 0
62
- const Instance = definition('Instance')
63
- const Host = definition('Host')
64
- const Fleet = definition('Fleet')
65
- const invoke = mock(async (method: unknown, receiver: unknown, value: unknown) =>
66
- input.invoke?.(method as { owner: string; name: string }, receiver, value),
67
- )
68
- const binding = {
69
- $: {
70
- publication: { origin: 'admin.astrale.ai' },
71
- origin: 'admin.astrale.ai',
72
- class(name: string) {
73
- if (name === 'Instance') return Instance
74
- if (name === 'Host') return Host
75
- if (name === 'Fleet') return Fleet
76
- throw new Error(`Unexpected class ${name}`)
77
- },
78
- core: { nodes: { fleet: { path: Path.id(NodeId('fleet')) } } },
79
- invoke,
80
- },
81
- } as unknown as DomainBinding
82
- const query = mock(async (ast: QueryAST) => {
83
- const name = sourceName(ast)
84
- if (name === 'Instance') return graphResult(input.instances ?? [])
85
- if (name === 'Host') return graphResult(input.hosts ?? [])
86
- throw new Error(`Unexpected graph query ${String(name)}`)
9
+ const calls: Array<{
10
+ method: { owner: string; name: string }
11
+ receiver: string
12
+ value: unknown
13
+ }> = []
14
+ const remote = adminSession((method, receiver, value) => {
15
+ calls.push({ method, receiver: String(receiver), value })
16
+ return input.invoke?.(method, receiver, value)
87
17
  })
88
- const neighbors = mock(async (source: unknown, edge: { name?: string }) => {
89
- if (String(source) === '@fleet') return page(input.reserved ?? null)
90
- if (edge.name === 'instance_runs_on_host') return page(input.hosts?.[0] ?? null)
91
- throw new Error(`Unexpected neighbor query ${String(source)} ${String(edge)}`)
92
- })
93
- const graph = { query, neighbors } as unknown as AdminGraphApi
18
+ const binding = adminBinding()
94
19
  return {
95
20
  binding,
96
- graph,
97
- invoke,
21
+ invoke: remote.invoke,
22
+ calls,
98
23
  connect: () =>
99
24
  connectAdminInstances(
100
- { session: {} as never, graph },
25
+ { session: remote.session },
101
26
  {
102
27
  bind: async () => binding,
103
28
  operationId: (kind) => `cli.instance.${kind}:test`,
@@ -106,15 +31,6 @@ function fixture(input: {
106
31
  }
107
32
  }
108
33
 
109
- function page(item: Node | null) {
110
- return {
111
- nodes: item === null ? [] : [item],
112
- first: item,
113
- graph: { nodes: item === null ? [] : [item], edges: [] },
114
- cursor: null,
115
- }
116
- }
117
-
118
34
  describe('V2 Admin Instance adapter', () => {
119
35
  test('lists caller-visible Instances through the Admin-owned Fleet operation', async () => {
120
36
  const contract = fixture({
@@ -128,8 +44,6 @@ describe('V2 Admin Instance adapter', () => {
128
44
  state: 'ready',
129
45
  createdAt: '2026-08-12T00:00:00.000Z',
130
46
  updatedAt: '2026-08-12T00:00:00.000Z',
131
- hostId: '@host-node',
132
- region: 'fr-par',
133
47
  },
134
48
  ]
135
49
  : undefined,
@@ -142,18 +56,18 @@ describe('V2 Admin Instance adapter', () => {
142
56
  url: 'https://demo.eu.astrale.ai',
143
57
  state: 'ready',
144
58
  createdAt: '2026-08-12T00:00:00.000Z',
145
- hostId: '@host-node',
146
- region: 'fr-par',
147
59
  },
148
60
  ])
149
- expect(contract.invoke).toHaveBeenCalledWith(
150
- expect.objectContaining({ owner: 'Fleet', name: 'listInstances' }),
151
- Path.id(NodeId('fleet')),
152
- {},
153
- )
61
+ expect(contract.calls).toEqual([
62
+ {
63
+ method: { owner: 'Fleet', name: 'listInstances' },
64
+ receiver: '/:admin.astrale.ai:core.fleet::listInstances',
65
+ value: {},
66
+ },
67
+ ])
154
68
  })
155
69
 
156
- test('invokes Fleet.createInstance with an internal operation identity', async () => {
70
+ test('delegates default placement to Fleet without reading Host inventory', async () => {
157
71
  const created = {
158
72
  id: '@instance-node',
159
73
  slug: 'demo',
@@ -162,10 +76,7 @@ describe('V2 Admin Instance adapter', () => {
162
76
  createdAt: '2026-08-12T00:00:00.000Z',
163
77
  updatedAt: '2026-08-12T00:00:00.000Z',
164
78
  }
165
- const contract = fixture({
166
- hosts: [node('host-node', { id: 'host-paris', state: 'ready' })],
167
- invoke: () => created,
168
- })
79
+ const contract = fixture({ invoke: () => created })
169
80
 
170
81
  await expect((await contract.connect()).create('demo')).resolves.toMatchObject({
171
82
  id: created.id,
@@ -174,45 +85,17 @@ describe('V2 Admin Instance adapter', () => {
174
85
  state: created.state,
175
86
  createdAt: created.createdAt,
176
87
  })
177
- expect(contract.invoke).toHaveBeenCalledWith(
178
- expect.objectContaining({ owner: 'Fleet', name: 'createInstance' }),
179
- Path.id(NodeId('fleet')),
180
- { operationId: 'cli.instance.create:test', slug: 'demo' },
181
- )
182
- })
183
-
184
- test('resolves --host-id to an exact Host receiver and rejects the reserved Admin Host', async () => {
185
- const reserved = node('admin-host', { id: 'admin', state: 'ready' })
186
- const consumer = node('consumer-host', { id: 'consumer-paris', state: 'ready' })
187
- const contract = fixture({
188
- hosts: [reserved, consumer],
189
- reserved,
190
- invoke: () => ({
191
- id: '@instance-node',
192
- slug: 'demo',
193
- url: 'https://demo.eu.astrale.ai',
194
- state: 'ready',
195
- }),
196
- })
197
- const api = await contract.connect()
198
-
199
- await expect(api.create('demo', 'admin')).rejects.toMatchObject({ name: 'NotFoundError' })
200
- await expect(api.create('demo', 'consumer-paris')).resolves.toMatchObject({ slug: 'demo' })
201
- expect(contract.invoke).toHaveBeenCalledWith(
202
- expect.objectContaining({ owner: 'Host', name: 'createInstance' }),
203
- Path.id(NodeId('consumer-host')),
204
- { operationId: 'cli.instance.create:test', slug: 'demo' },
205
- )
88
+ expect(contract.calls).toEqual([
89
+ {
90
+ method: { owner: 'Fleet', name: 'createInstance' },
91
+ receiver: '/:admin.astrale.ai:core.fleet::createInstance',
92
+ value: { operationId: 'cli.instance.create:test', slug: 'demo' },
93
+ },
94
+ ])
206
95
  })
207
96
 
208
97
  test('refreshes and deletes through the resolved Instance receiver', async () => {
209
- const instance = node('instance-node', {
210
- slug: 'demo',
211
- url: 'https://demo.eu.astrale.ai',
212
- state: 'ready',
213
- })
214
98
  const contract = fixture({
215
- instances: [instance],
216
99
  invoke: (method) =>
217
100
  method.name === 'listInstances'
218
101
  ? [
@@ -236,22 +119,16 @@ describe('V2 Admin Instance adapter', () => {
236
119
 
237
120
  await expect(api.status('demo')).resolves.toMatchObject({ state: 'ready' })
238
121
  await expect(api.delete('@instance-node')).resolves.toMatchObject({ state: 'deleted' })
239
- expect(contract.invoke.mock.calls.map(([method]) => method)).toEqual([
240
- expect.objectContaining({ owner: 'Fleet', name: 'listInstances' }),
241
- expect.objectContaining({ owner: 'Instance', name: 'status' }),
242
- expect.objectContaining({ owner: 'Fleet', name: 'listInstances' }),
243
- expect.objectContaining({ owner: 'Instance', name: 'delete' }),
122
+ expect(contract.calls.map(({ method }) => method)).toEqual([
123
+ { owner: 'Fleet', name: 'listInstances' },
124
+ { owner: 'Instance', name: 'status' },
125
+ { owner: 'Fleet', name: 'listInstances' },
126
+ { owner: 'Instance', name: 'delete' },
244
127
  ])
245
128
  })
246
129
 
247
130
  test('installs a resolved catalog Domain through Instance.installDomain', async () => {
248
- const instance = node('instance-node', {
249
- slug: 'demo',
250
- url: 'https://demo.eu.astrale.ai',
251
- state: 'ready',
252
- })
253
131
  const contract = fixture({
254
- instances: [instance],
255
132
  invoke: (method) =>
256
133
  method.name === 'listInstances'
257
134
  ? [
@@ -280,10 +157,10 @@ describe('V2 Admin Instance adapter', () => {
280
157
  origin: 'crm.acme.dev',
281
158
  ok: true,
282
159
  })
283
- expect(contract.invoke).toHaveBeenCalledWith(
284
- expect.objectContaining({ owner: 'Instance', name: 'installDomain' }),
285
- Path.id(NodeId('instance-node')),
286
- { operationId: 'cli.instance.install-domain:test', domain: '@crm-domain' },
287
- )
160
+ expect(contract.calls.at(-1)).toEqual({
161
+ method: { owner: 'Instance', name: 'installDomain' },
162
+ receiver: '@instance-node::installDomain',
163
+ value: { operationId: 'cli.instance.install-domain:test', domain: '@crm-domain' },
164
+ })
288
165
  })
289
166
  })