@astrale-os/cli 1.0.0-beta.2 → 1.0.0-beta.20

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 (282) hide show
  1. package/README.md +16 -1
  2. package/dist/astrale.js +51105 -58057
  3. package/dist/public/connect-core.js +2085 -30702
  4. package/dist/public/keys/index.js +884 -29476
  5. package/dist/public/paths/index.js +13101 -41452
  6. package/dist/types/admin/contract.d.ts +26 -0
  7. package/dist/types/admin/instance/client.d.ts +20 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +6 -10
  10. package/dist/types/connection/auth.d.ts +3 -0
  11. package/dist/types/connection/call.d.ts +3 -0
  12. package/dist/types/connection/command.d.ts +27 -0
  13. package/dist/types/connection/credential.d.ts +14 -0
  14. package/dist/types/connection/errors.d.ts +1 -0
  15. package/dist/types/connection/exchange.d.ts +9 -0
  16. package/dist/types/connection/failure/classify.d.ts +2 -0
  17. package/dist/types/connection/failure/index.d.ts +5 -0
  18. package/dist/types/connection/failure/model.d.ts +25 -0
  19. package/dist/types/connection/failure/render.d.ts +3 -0
  20. package/dist/types/connection/index.d.ts +8 -0
  21. package/dist/types/connection/reasons.d.ts +37 -0
  22. package/dist/types/connection/self.d.ts +37 -0
  23. package/dist/types/connection/session.d.ts +31 -0
  24. package/dist/types/connection/target.d.ts +38 -0
  25. package/dist/types/errors.d.ts +1 -1
  26. package/dist/types/lib/admin-instance.d.ts +17 -0
  27. package/dist/types/lib/admin-target.d.ts +11 -36
  28. package/dist/types/lib/config.d.ts +7 -59
  29. package/dist/types/lib/failure-debug.d.ts +1 -0
  30. package/dist/types/lib/idp.d.ts +25 -173
  31. package/dist/types/lib/instance-target.d.ts +1 -1
  32. package/dist/types/lib/instance.d.ts +30 -88
  33. package/dist/types/lib/log.d.ts +5 -3
  34. package/dist/types/lib/output.d.ts +1 -1
  35. package/dist/types/lib/proc.d.ts +43 -0
  36. package/dist/types/lib/self.d.ts +9 -0
  37. package/dist/types/lib/update.d.ts +109 -0
  38. package/dist/types/lib/validation.d.ts +4 -1
  39. package/package.json +15 -20
  40. package/src/__tests__/fixtures/publication.ts +20 -0
  41. package/src/admin/.spec/architecture.md +12 -5
  42. package/src/admin/__tests__/fixture.ts +25 -0
  43. package/src/admin/catalog/.spec/api.d.ts +1 -3
  44. package/src/admin/catalog/.spec/architecture.md +5 -4
  45. package/src/admin/catalog/__tests__/client.test.ts +143 -69
  46. package/src/admin/catalog/client.ts +40 -54
  47. package/src/admin/catalog/model.ts +3 -4
  48. package/src/admin/contract.ts +46 -0
  49. package/src/admin/graph/.spec/api.d.ts +4 -10
  50. package/src/admin/graph/nodes.ts +1 -1
  51. package/src/admin/instance/.spec/api.d.ts +5 -9
  52. package/src/admin/instance/.spec/architecture.md +7 -7
  53. package/src/admin/instance/__tests__/client.test.ts +157 -175
  54. package/src/admin/instance/client.ts +39 -128
  55. package/src/admin/instance/index.ts +1 -2
  56. package/src/admin/instance/model.ts +12 -18
  57. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  58. package/src/commands/__tests__/call-describe.test.ts +46 -33
  59. package/src/commands/__tests__/call.test.ts +34 -0
  60. package/src/commands/__tests__/domain-install-operation.test.ts +7 -22
  61. package/src/commands/__tests__/domain-install-owned.test.ts +1 -1
  62. package/src/commands/__tests__/domain-list.test.ts +5 -25
  63. package/src/commands/__tests__/install-direct.test.ts +115 -8
  64. package/src/commands/__tests__/install-identity-override.test.ts +3 -14
  65. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  66. package/src/commands/__tests__/instance-status.test.ts +139 -0
  67. package/src/commands/__tests__/introspect-parse.test.ts +80 -1
  68. package/src/commands/__tests__/logs.test.ts +250 -2
  69. package/src/commands/__tests__/read-commands.test.ts +62 -10
  70. package/src/commands/__tests__/token-ttl.test.ts +49 -4
  71. package/src/commands/__tests__/update.test.ts +25 -3
  72. package/src/commands/__tests__/view.test.ts +49 -0
  73. package/src/commands/call-describe.ts +60 -68
  74. package/src/commands/call.ts +71 -59
  75. package/src/commands/domain/install.ts +54 -35
  76. package/src/commands/domain/list.ts +1 -1
  77. package/src/commands/domain/publish.ts +14 -11
  78. package/src/commands/domain/uninstall.ts +2 -2
  79. package/src/commands/get.ts +14 -15
  80. package/src/commands/identity/__tests__/register.test.ts +3 -3
  81. package/src/commands/identity/register.ts +5 -4
  82. package/src/commands/instance/create.ts +8 -16
  83. package/src/commands/instance/delete.ts +12 -9
  84. package/src/commands/instance/list.ts +2 -2
  85. package/src/commands/instance/status.ts +66 -20
  86. package/src/commands/instance/use.ts +16 -12
  87. package/src/commands/introspect.ts +48 -35
  88. package/src/commands/logs.ts +123 -33
  89. package/src/commands/mutate.ts +6 -5
  90. package/src/commands/query.ts +35 -32
  91. package/src/commands/token.ts +42 -27
  92. package/src/commands/ui/__tests__/commands.test.ts +152 -0
  93. package/src/commands/ui/add.ts +51 -0
  94. package/src/commands/ui/doctor.ts +13 -0
  95. package/src/commands/ui/init.ts +38 -0
  96. package/src/commands/ui/list.ts +26 -0
  97. package/src/commands/ui/preset-apply.ts +19 -0
  98. package/src/commands/ui/preset-list.ts +12 -0
  99. package/src/commands/ui/shared.ts +25 -0
  100. package/src/commands/update.ts +31 -11
  101. package/src/commands/view.ts +82 -37
  102. package/src/connection/.spec/api.d.ts +7 -8
  103. package/src/connection/.spec/architecture.md +5 -4
  104. package/src/connection/.spec/flows/session.ts +2 -2
  105. package/src/connection/.spec/laws/connection.ts +6 -2
  106. package/src/connection/.spec/layout.ts +1 -0
  107. package/src/connection/__tests__/credential.test.ts +20 -1
  108. package/src/connection/__tests__/errors.test.ts +27 -20
  109. package/src/connection/__tests__/exchange.test.ts +30 -1
  110. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  111. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  112. package/src/connection/__tests__/self.test.ts +31 -11
  113. package/src/connection/__tests__/session.test.ts +3 -3
  114. package/src/connection/__tests__/target.test.ts +1 -0
  115. package/src/connection/auth.ts +13 -0
  116. package/src/connection/call.ts +1 -1
  117. package/src/connection/credential.ts +2 -2
  118. package/src/connection/errors.ts +1 -355
  119. package/src/connection/exchange.ts +47 -23
  120. package/src/connection/failure/classify.ts +110 -0
  121. package/src/connection/failure/index.ts +18 -0
  122. package/src/connection/failure/model.ts +28 -0
  123. package/src/connection/failure/render.ts +116 -0
  124. package/src/connection/reasons.ts +16 -0
  125. package/src/connection/self.ts +39 -21
  126. package/src/connection/session.ts +19 -8
  127. package/src/errors.ts +3 -2
  128. package/src/graph/.spec/api.d.ts +12 -5
  129. package/src/graph/.spec/layout.ts +9 -1
  130. package/src/graph/__tests__/mutation.test.ts +2 -2
  131. package/src/graph/__tests__/query.test.ts +25 -6
  132. package/src/graph/class.ts +30 -0
  133. package/src/graph/index.ts +1 -0
  134. package/src/graph/query.ts +21 -32
  135. package/src/identity/.spec/api.d.ts +2 -2
  136. package/src/identity/__tests__/registration.test.ts +1 -1
  137. package/src/identity/registration.ts +3 -3
  138. package/src/keys/__tests__/keys.test.ts +4 -0
  139. package/src/keys/credential.ts +1 -0
  140. package/src/lib/__tests__/admin-target.test.ts +12 -0
  141. package/src/lib/__tests__/binary.test.ts +16 -1
  142. package/src/lib/__tests__/command-dx.test.ts +1 -1
  143. package/src/lib/__tests__/domain-publication.test.ts +10 -16
  144. package/src/lib/__tests__/idp.test.ts +34 -4
  145. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  146. package/src/lib/__tests__/instance-target.test.ts +7 -39
  147. package/src/lib/__tests__/log-errors.test.ts +64 -0
  148. package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
  149. package/src/lib/__tests__/update.test.ts +264 -11
  150. package/src/lib/__tests__/view-assets.test.ts +14 -0
  151. package/src/lib/__tests__/view-external-open-intent.test.ts +150 -0
  152. package/src/lib/__tests__/view-external-open-origins.test.ts +27 -0
  153. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  154. package/src/lib/__tests__/view-server.test.ts +26 -3
  155. package/src/lib/__tests__/view-session.test.ts +2 -1
  156. package/src/lib/admin-instance.ts +14 -8
  157. package/src/lib/admin-target.ts +21 -2
  158. package/src/lib/binary.ts +22 -5
  159. package/src/lib/command-dx.ts +9 -9
  160. package/src/lib/domain-publication.ts +9 -7
  161. package/src/lib/failure-debug.ts +26 -0
  162. package/src/lib/idp.ts +34 -3
  163. package/src/lib/instance-candidates.ts +2 -2
  164. package/src/lib/instance-target.ts +3 -14
  165. package/src/lib/instance.ts +16 -11
  166. package/src/lib/log.ts +16 -9
  167. package/src/lib/output.ts +1 -1
  168. package/src/lib/proc.ts +7 -2
  169. package/src/lib/provision-instance.ts +34 -57
  170. package/src/lib/update.ts +298 -45
  171. package/src/lib/validation.ts +2 -2
  172. package/src/lib/view/assets.ts +11 -2
  173. package/src/lib/view/external-open-intent.ts +41 -0
  174. package/src/lib/view/external-open-origins.ts +37 -0
  175. package/src/lib/view/host-capabilities.ts +17 -0
  176. package/src/lib/view/resolve.ts +1 -1
  177. package/src/lib/view/server.ts +18 -3
  178. package/src/lib/view/session.ts +2 -0
  179. package/src/program/.spec/api.d.ts +1 -0
  180. package/src/program/__tests__/program.test.ts +163 -6
  181. package/src/program/argv.ts +14 -0
  182. package/src/program/build.ts +26 -4
  183. package/src/program/command.ts +1 -0
  184. package/src/program/index.ts +1 -0
  185. package/src/program/registry.ts +2 -1
  186. package/src/setup/__tests__/instance-step.test.ts +27 -10
  187. package/src/setup/steps/instance.ts +22 -15
  188. package/src/telemetry/__tests__/recorder.test.ts +1 -0
  189. package/src/telemetry/recorder.ts +9 -1
  190. package/src/ui/.spec/api.d.ts +14 -0
  191. package/src/ui/.spec/architecture.md +10 -0
  192. package/src/ui/.spec/laws.ts +36 -0
  193. package/src/ui/.spec/layout.ts +16 -0
  194. package/src/ui/__tests__/ui.test.ts +981 -0
  195. package/src/ui/index.ts +13 -0
  196. package/src/ui/lock.ts +87 -0
  197. package/src/ui/model.ts +83 -0
  198. package/src/ui/operations.ts +710 -0
  199. package/src/ui/project.ts +219 -0
  200. package/src/ui/release.ts +321 -0
  201. package/src/ui/runner.ts +18 -0
  202. package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
  203. package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
  204. package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
  205. package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  206. package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
  207. package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
  208. package/studio/client/dist/index.html +3 -2
  209. package/studio/package.json +7 -13
  210. package/studio/server/agent/ask.test.ts +1 -1
  211. package/studio/server/agent/bridge/grant.test.ts +1 -1
  212. package/studio/server/agent/bridge/routes.test.ts +1 -1
  213. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  214. package/studio/server/agent/harness/gateway/token.test.ts +1 -1
  215. package/studio/server/agent/harness/gateway/token.ts +3 -3
  216. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  217. package/studio/server/agent/prompts/anchors.ts +20 -49
  218. package/studio/server/agent/prompts/system.test.ts +3 -2
  219. package/studio/server/agent/prompts/system.ts +3 -3
  220. package/studio/server/agent/routes.test.ts +1 -1
  221. package/studio/server/agent/run/coordinator.test.ts +1 -1
  222. package/studio/server/api/canvas.ts +0 -1
  223. package/studio/server/api-agent-loadout.test.ts +1 -1
  224. package/studio/server/api.test.ts +1 -1
  225. package/studio/server/cache.test.ts +23 -12
  226. package/studio/server/cache.ts +12 -15
  227. package/studio/server/domain.test.ts +50 -68
  228. package/studio/server/domain.ts +82 -63
  229. package/studio/server/handoff/copy.ts +1 -1
  230. package/studio/server/index.ts +1 -1
  231. package/studio/server/instances/probe.test.ts +1 -1
  232. package/studio/server/introspect/anatomy/views/routes.ts +46 -37
  233. package/studio/server/introspect/anatomy/views.ts +9 -14
  234. package/studio/server/introspect/anatomy-extras.test.ts +26 -42
  235. package/studio/server/introspect/anatomy.test.ts +22 -14
  236. package/studio/server/introspect/anatomy.ts +6 -9
  237. package/studio/server/introspect/bundle.ts +0 -3
  238. package/studio/server/introspect/canonical-schema.test.ts +94 -389
  239. package/studio/server/introspect/canonical-schema.ts +227 -457
  240. package/studio/server/introspect/core-extractor.ts +18 -127
  241. package/studio/server/introspect/core.ts +1 -2
  242. package/studio/server/introspect/diff.test.ts +11 -7
  243. package/studio/server/introspect/diff.ts +18 -55
  244. package/studio/server/introspect/extractor.ts +22 -117
  245. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  246. package/studio/server/introspect/overlay.test.ts +26 -54
  247. package/studio/server/introspect/overlay.ts +10 -37
  248. package/studio/server/introspect/revision.test.ts +1 -1
  249. package/studio/server/introspect/revision.ts +1 -1
  250. package/studio/server/introspect/runtime.test.ts +65 -183
  251. package/studio/server/introspect/runtime.ts +8 -25
  252. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  253. package/studio/server/introspect/schema-ir-json.ts +38 -68
  254. package/studio/server/introspect/schema-refs.test.ts +43 -88
  255. package/studio/server/introspect/schema-refs.ts +14 -49
  256. package/studio/server/introspect/source-overlay/handlers.ts +116 -636
  257. package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -3
  258. package/studio/server/introspect/source-overlay/spans.ts +15 -45
  259. package/studio/server/state/baseline.test.ts +14 -9
  260. package/studio/server/state/baseline.ts +3 -5
  261. package/studio/server/state/visibility.ts +1 -5
  262. package/studio/server/views/model.ts +3 -3
  263. package/studio/server/views/target.test.ts +17 -74
  264. package/studio/server/views/target.ts +24 -50
  265. package/studio/server/watch.test.ts +11 -11
  266. package/studio/server/watch.ts +8 -4
  267. package/studio/server/workspace-watch.ts +2 -2
  268. package/studio/shared/contracts/schema.ts +38 -107
  269. package/studio/shared/contracts/surface.test.ts +13 -15
  270. package/studio/shared/contracts/workspace.ts +2 -11
  271. package/studio/shared/schema/identity.test.ts +20 -44
  272. package/studio/shared/schema/identity.ts +9 -23
  273. package/viewer/dist/main.js +30 -51
  274. package/.check-workspace.cjs +0 -40
  275. package/src/admin/binding.ts +0 -168
  276. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  277. package/studio/client/dist/assets/elk-api-lwhFo7vB.js +0 -1
  278. package/studio/client/dist/assets/index-B-c-smo9.js +0 -8
  279. package/studio/client/dist/assets/index-BckHuAWk.js +0 -81
  280. package/studio/client/dist/assets/index-C4aNQ6dz.css +0 -1
  281. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  282. package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
@@ -4,8 +4,8 @@ import type { ConnectionContext, KernelCommandOpts } from '../connection'
4
4
  import type { CommandDefinition } from '../program/index'
5
5
 
6
6
  import { createPathCall, expandSelfInCall, runKernelCommand, withSelfHint } from '../connection'
7
- import { presentBinary } from '../lib/binary'
8
- import { failClosed, log } from '../lib/log'
7
+ import { presentBinary, readBinaryBody } from '../lib/binary'
8
+ import { failInput, log } from '../lib/log'
9
9
  import { output, present } from '../lib/output'
10
10
 
11
11
  type CallOpts = KernelCommandOpts & {
@@ -15,8 +15,20 @@ type CallOpts = KernelCommandOpts & {
15
15
  }
16
16
 
17
17
  type CallResult = Awaited<ReturnType<ConnectionContext['session']['dispatch']>>
18
+ type BinaryCallResult = Extract<CallResult, { readonly kind: 'binary' }>
19
+ type BinaryCallInput = Omit<BinaryCallResult, 'value'> & {
20
+ readonly value: Omit<BinaryCallResult['value'], 'body' | 'status'> & {
21
+ readonly body: Uint8Array | AsyncIterable<Uint8Array>
22
+ readonly status?: number
23
+ }
24
+ }
25
+ type CallResultInput = Exclude<CallResult, { readonly kind: 'binary' }> | BinaryCallInput
26
+ type MaterializedBinaryCallResult = Omit<BinaryCallResult, 'value'> & {
27
+ readonly value: Omit<BinaryCallInput['value'], 'body'> & { readonly body: Uint8Array }
28
+ }
18
29
  type MaterializedCallResult =
19
- | Exclude<CallResult, { readonly kind: 'stream' }>
30
+ | Exclude<CallResult, { readonly kind: 'binary' | 'stream' }>
31
+ | MaterializedBinaryCallResult
20
32
  | { readonly kind: 'stream'; readonly values: readonly unknown[] }
21
33
 
22
34
  export async function callCommand(
@@ -24,64 +36,60 @@ export async function callCommand(
24
36
  rawParams: string[],
25
37
  opts: CallOpts,
26
38
  ): Promise<void> {
27
- // Expand @self before describe/execute through authenticated Identity.whoami.
28
- let expanded: Awaited<ReturnType<typeof expandSelfInCall>>
29
- try {
30
- expanded = await expandSelfInCall(path, rawParams, opts)
31
- } catch (error) {
32
- failClosed(error, opts)
33
- }
34
- const expandedPath = expanded.path
35
- try {
36
- Path.parse(expandedPath)
37
- } catch (error) {
38
- failClosed(error, opts)
39
- }
40
-
41
- // ── Parse params ────────────────────────────────────────
42
39
  let params: Record<string, unknown>
43
40
  try {
44
- params = await parseParams([...expanded.parameters], opts.data)
45
- } catch (e) {
46
- failClosed(e, opts)
47
- }
48
-
49
- // ── Dry-run: show what would be sent ─────────────────────
50
- if (opts.dryRun) {
51
- output({ method: expandedPath, params }, opts)
52
- return
41
+ Path.parse(path)
42
+ params = await parseParams(rawParams, opts.data)
43
+ } catch (error) {
44
+ failInput(error, opts)
53
45
  }
54
46
 
55
- // ── Execute ────────────────────────────────────────────
56
- await runKernelCommand<MaterializedCallResult>({
57
- opts,
58
- label: expandedPath,
59
- fn: (ctx) =>
60
- withSelfHint(
61
- async () =>
62
- materializeCallResult(await ctx.session.dispatch(createPathCall(expandedPath, params))),
63
- expanded.meta,
64
- ),
65
- format: async (result, fmtOpts) => {
66
- switch (result.kind) {
67
- case 'value':
68
- present(result.value, fmtOpts)
69
- return
70
- case 'binary':
71
- await presentBinary(result.value, fmtOpts, { outFile: opts.output })
72
- return
73
- case 'stream':
74
- output(result.values, fmtOpts)
75
- return
76
- case 'redirect':
77
- throw new Error('Client Session returned an unresolved redirect.')
78
- }
47
+ await runKernelCommand<MaterializedCallResult | { readonly kind: 'dry'; readonly call: unknown }>(
48
+ {
49
+ opts,
50
+ label: path,
51
+ fn: async (ctx) => {
52
+ const expanded = await expandSelfInCall(path, params, ctx)
53
+ const request = createPathCall(expanded.path, expanded.parameters)
54
+ if (opts.dryRun) return { kind: 'dry', call: request }
55
+ return withSelfHint(
56
+ async () => materializeCallResult(await ctx.session.dispatch(request)),
57
+ expanded.meta,
58
+ )
59
+ },
60
+ format: async (result, fmtOpts) => {
61
+ switch (result.kind) {
62
+ case 'dry':
63
+ output(result.call, fmtOpts)
64
+ return
65
+ case 'value':
66
+ present(result.value, fmtOpts)
67
+ return
68
+ case 'binary':
69
+ await presentBinary(result.value, fmtOpts, { outFile: opts.output })
70
+ return
71
+ case 'stream':
72
+ output(result.values, fmtOpts)
73
+ return
74
+ case 'redirect':
75
+ throw new Error('Client Session returned an unresolved redirect.')
76
+ }
77
+ },
79
78
  },
80
- })
79
+ )
81
80
  }
82
81
 
83
82
  /** Drain a session-backed stream before the command-scoped Client Session closes. */
84
- export async function materializeCallResult(result: CallResult): Promise<MaterializedCallResult> {
83
+ export async function materializeCallResult(
84
+ result: CallResultInput,
85
+ ): Promise<MaterializedCallResult> {
86
+ if (result.kind === 'binary') {
87
+ const body = await readBinaryBody(result.value.body)
88
+ return Object.freeze({
89
+ ...result,
90
+ value: Object.freeze({ ...result.value, body }),
91
+ })
92
+ }
85
93
  if (result.kind !== 'stream') return result
86
94
  const values: unknown[] = []
87
95
  for await (const value of result.stream) values.push(value)
@@ -101,7 +109,7 @@ export async function parseParams(
101
109
  try {
102
110
  return JSON.parse(dataFlag)
103
111
  } catch {
104
- throw new Error(`Invalid JSON in --data: ${dataFlag}`)
112
+ throw new TypeError(`Invalid JSON in --data: ${dataFlag}`)
105
113
  }
106
114
  }
107
115
 
@@ -114,7 +122,7 @@ export async function parseParams(
114
122
  try {
115
123
  return JSON.parse(stdin)
116
124
  } catch {
117
- throw new Error('Invalid JSON from stdin')
125
+ throw new TypeError('Invalid JSON from stdin')
118
126
  }
119
127
  }
120
128
 
@@ -142,7 +150,7 @@ export function parseKeyValue(pairs: string[]): Record<string, unknown> {
142
150
  for (const pair of pairs) {
143
151
  const eqIdx = pair.indexOf('=')
144
152
  if (eqIdx === -1) {
145
- throw new Error(`Invalid param "${pair}" — expected key=value format`)
153
+ throw new TypeError(`Invalid param "${pair}" — expected key=value format`)
146
154
  }
147
155
  const key = pair.slice(0, eqIdx)
148
156
  const raw = pair.slice(eqIdx + 1)
@@ -150,7 +158,7 @@ export function parseKeyValue(pairs: string[]): Record<string, unknown> {
150
158
  const hint = key.endsWith(':')
151
159
  ? ` (looks like httpie's "key:=value" syntax — Astrale CLI doesn't support it; use --data '{"${key.slice(0, -1)}":<value>}' for nested values)`
152
160
  : ` (keys must be identifier-shaped: letters, digits, underscore, hyphen)`
153
- throw new Error(`Invalid param key "${key}" in "${pair}"${hint}`)
161
+ throw new TypeError(`Invalid param key "${key}" in "${pair}"${hint}`)
154
162
  }
155
163
  result[key] = coerceValue(raw)
156
164
  }
@@ -184,6 +192,10 @@ Behavior:
184
192
  input without executing. Remote-bound functions auto-mint a
185
193
  worker-scoped credential; --creds overrides it.
186
194
 
195
+ Streaming binary bodies are consumed while the Client session remains live,
196
+ then presented through the same --output, --raw, and --json paths as buffered
197
+ binary. JSON retains the application HTTP status and text/base64 body.
198
+
187
199
  Self-reference:
188
200
  @self expands to your nodeId on the active instance (path head or
189
201
  bare param value, e.g. node=@self). --data and stdin payloads are
@@ -194,7 +206,7 @@ Self-reference:
194
206
  Callable input/output lives on astrale introspect <path>.
195
207
 
196
208
  Examples:
197
- $ astrale introspect /:host.astrale.ai:class.Manager:createInstance
209
+ $ astrale introspect /:kernel.astrale.ai:class.Identity:whois
198
210
  $ astrale call /:blog.acme.com:class.Author:list limit=10
199
211
  $ astrale call '@self::deactivate'
200
212
  $ astrale call /:kernel.astrale.ai:function.journal --data '{"limit":5}' --json
@@ -203,7 +215,7 @@ Examples:
203
215
  {
204
216
  name: 'path',
205
217
  description:
206
- 'Operation path (e.g., /:host.astrale.ai:class.Manager:createInstance or /node::method)',
218
+ 'Operation path (e.g., /:kernel.astrale.ai:class.Identity:whois or /node::method)',
207
219
  },
208
220
  { name: 'params...', description: 'Params as key=value pairs', required: false },
209
221
  ],
@@ -1,11 +1,11 @@
1
- import { Path } from '@astrale-os/sdk/graph/path'
2
- import { syscalls } from '@astrale-os/sdk/schema/kernel'
1
+ import type { InstallRequest, InstallResult, OperationId } from '@astrale-os/sdk/client/schema'
2
+
3
3
  import chalk from 'chalk'
4
4
 
5
5
  import type { KernelCommandOpts } from '../../connection'
6
6
  import type { CommandDefinition } from '../../program/index'
7
7
 
8
- import { createPathCall, runKernelCommand, withAdminClientSession } from '../../connection'
8
+ import { runKernelCommand, withAdminClientSession } from '../../connection'
9
9
  import { formatKernelError } from '../../connection/errors'
10
10
  import { AstraleError } from '../../errors'
11
11
  import {
@@ -23,35 +23,61 @@ import { confirmWithInput, promptText, selectFrom } from '../../lib/prompt'
23
23
  import { isHttpUrl } from '../../lib/validation'
24
24
 
25
25
  /** Public Kernel install syscall input for one remote URL. */
26
- export function directInstallCallInput(url: string, operation: string, token?: string) {
26
+ export function directInstallCallInput(
27
+ url: string,
28
+ operation: string,
29
+ token?: string,
30
+ ): InstallRequest {
31
+ const domain = Object.freeze({
32
+ publication: Object.freeze({
33
+ url,
34
+ ...(token === undefined ? {} : { token }),
35
+ }),
36
+ })
27
37
  return Object.freeze({
28
- operation,
29
- domains: [
30
- Object.freeze({
31
- source: Object.freeze({
32
- kind: 'remote' as const,
33
- url,
34
- ...(token === undefined ? {} : { token }),
35
- }),
36
- }),
37
- ],
38
+ operation: acceptOperationId(operation),
39
+ domains: Object.freeze([domain] as const),
38
40
  })
39
41
  }
40
42
 
41
- type DirectInstallResult = {
43
+ export interface DirectInstallPresentation {
42
44
  readonly operation: string
43
- readonly transitions: readonly {
44
- readonly intent: {
45
- readonly origin: string
46
- readonly target?: { readonly schemaRevision?: string } | null
45
+ readonly origin: string
46
+ readonly revision: string
47
+ readonly status: 'installed' | 'already current'
48
+ }
49
+
50
+ /** Stable CLI presentation derived from the canonical binary install result. */
51
+ export function directInstallPresentation(
52
+ result: InstallResult,
53
+ requestedOperation: string,
54
+ ): DirectInstallPresentation {
55
+ if (result.changed) {
56
+ const installed = result.receipt.transitions[0]?.intent
57
+ if (!installed) throw new Error('Kernel install returned no committed Domain transition.')
58
+ if (!installed.generation) {
59
+ throw new Error('Kernel install returned a committed transition without a Domain generation.')
47
60
  }
48
- }[]
61
+ return Object.freeze({
62
+ operation: result.receipt.operation,
63
+ origin: installed.origin,
64
+ revision: installed.generation.revision,
65
+ status: 'installed' as const,
66
+ })
67
+ }
68
+ const installed = result.domains[0]
69
+ return Object.freeze({
70
+ operation: requestedOperation,
71
+ origin: installed.origin,
72
+ revision: installed.revision,
73
+ status: 'already current' as const,
74
+ })
49
75
  }
50
76
 
51
77
  const OPERATION_ID_PATTERN =
52
78
  /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u
53
79
 
54
- function acceptOperationId(input: unknown): string {
80
+ function acceptOperationId(input: unknown): OperationId {
55
81
  if (typeof input !== 'string' || !OPERATION_ID_PATTERN.test(input)) {
56
82
  throw new AstraleError(
57
83
  'INVALID_FLAG',
@@ -59,10 +85,10 @@ function acceptOperationId(input: unknown): string {
59
85
  'Omit --operation for a fresh install; use it only with the exact UUID printed for recovery.',
60
86
  )
61
87
  }
62
- return input
88
+ return input as OperationId
63
89
  }
64
90
 
65
- function createOperationId(): string {
91
+ function createOperationId(): OperationId {
66
92
  return acceptOperationId(globalThis.crypto.randomUUID())
67
93
  }
68
94
 
@@ -407,27 +433,20 @@ export async function installDirect(
407
433
  const url = target as string
408
434
  const retry = directInstallRetry(url, operation, opts)
409
435
 
410
- await direct.runKernelCommand<DirectInstallResult>({
436
+ await direct.runKernelCommand<InstallResult>({
411
437
  opts,
412
438
  label: `Installing domain from ${url} (operation ${operation})`,
413
439
  recovery: { operation, retry },
414
440
  fn: async ({ session }) =>
415
- (await session.call(
416
- createPathCall(
417
- Path.project(syscalls.install.ref).raw,
418
- directInstallCallInput(url, operation, opts.token),
419
- ),
420
- )) as DirectInstallResult,
441
+ session.schema.install(directInstallCallInput(url, operation, opts.token)),
421
442
  format: (result, fmtOpts, isRaw) => {
422
443
  if (isRaw) {
423
444
  output(result, fmtOpts)
424
445
  return
425
446
  }
426
- const installed = result.transitions[0]?.intent
427
- if (!installed) throw new Error('Kernel install returned no committed Domain transition.')
428
- const revision = installed.target?.schemaRevision ?? result.operation
429
- log.success(`Domain installed: ${installed.origin}@${revision}`)
430
- log.dim(` operation: ${result.operation}`)
447
+ const installed = directInstallPresentation(result, operation)
448
+ log.success(`Domain ${installed.status}: ${installed.origin}@${installed.revision}`)
449
+ log.dim(` operation: ${installed.operation}`)
431
450
  // Belt-and-braces: the kernel-confirmed origin is authoritative. If it
432
451
  // aliases the host and the pre-install gate never consented to THAT
433
452
  // origin (lying or unavailable Publication), say so loudly after the fact.
@@ -73,7 +73,7 @@ Behavior:
73
73
  or with --json/--raw (agent-friendly — full DomainInfo objects). -q prints
74
74
  one install URL per line (pipeable into \`domain install\`); --count prints
75
75
  only the number. --default-only keeps the install-by-default entries (what
76
- every new instance gets via alphaCreate). --check probes each published URL's
76
+ every new instance receives during Admin-managed provisioning). --check probes each published URL's
77
77
  canonical Publication and adds a live/unreachable STATUS column
78
78
  (+ reachable/schemaRevision in machine output).
79
79
 
@@ -3,9 +3,11 @@ import chalk from 'chalk'
3
3
  import type { KernelCommandOpts } from '../../connection'
4
4
  import type { CommandDefinition } from '../../program/index'
5
5
 
6
+ import { formatKernelError } from '../../connection/errors'
6
7
  import { publishAdminDomain } from '../../lib/admin-domain'
7
8
  import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
8
- import { fatal, withSpinner } from '../../lib/log'
9
+ import { domainPublicationUrl } from '../../lib/domain-publication'
10
+ import { withSpinner } from '../../lib/log'
9
11
  import { isMachine, output } from '../../lib/output'
10
12
  import { promptText } from '../../lib/prompt'
11
13
  import { isHttpUrl, validateName, validateUrl } from '../../lib/validation'
@@ -48,9 +50,9 @@ Behavior:
48
50
 
49
51
  Publishing only makes the domain INSTALLABLE. Mount it on an instance with
50
52
  \`astrale domain install <url>\` (or rely on the admin's install-by-default
51
- policy). This is usually invoked for you by \`astrale-domain publish\` (which
52
- registers the already-deployed URL it does NOT deploy) or by
53
- \`astrale-domain deploy --publish\` (deploy AND register in one step).
53
+ policy). Deployment and catalog publication are separate owners: run the
54
+ project's \`astrale-domain deploy <environment>\`, then publish its observed
55
+ public URL with this command.
54
56
 
55
57
  Run in a terminal with flags omitted and it PROMPTS for origin / name /
56
58
  public-url (origin defaults to the URL host, name to the origin's first
@@ -68,17 +70,16 @@ Examples:
68
70
  { flags: '--description <text>', description: 'Optional human description for the catalog' },
69
71
  {
70
72
  flags: '--install-by-default',
71
- description: 'Mark the domain for install on every new instance (alphaCreate)',
73
+ description: 'Mark the domain for install on every new instance',
72
74
  },
73
75
  ],
74
76
  // No positional arguments → Commander passes (opts, command); `opts` is first.
75
77
  action: async (opts: PublishOpts) => {
76
78
  try {
77
79
  // Interactive fill (TTY only): a human running this by hand is prompted for
78
- // any missing field. The primary caller `astrale-domain publish` always
79
- // passes every flag, so it never prompts. No TTY / --ci / --no-prompt / CI
80
- // env no prompt: fall straight through to the required-flag error below,
81
- // so a piped / agent / LLM run fails fast instead of hanging on a read.
80
+ // any missing field. Automation passes every flag. No TTY / --ci /
81
+ // --no-prompt / CI env means no prompt: fall straight through to the
82
+ // required-flag error below so a piped or agent run fails fast.
82
83
  const interactive = !!process.stdin.isTTY && !(opts.ci || opts.noPrompt || process.env.CI)
83
84
  let { origin, name, publicUrl } = opts
84
85
  if (interactive) {
@@ -102,6 +103,7 @@ Examples:
102
103
  validateName(origin, 'origin')
103
104
  validateName(name, 'domain')
104
105
  validateUrl(publicUrl)
106
+ const discoveryUrl = domainPublicationUrl(publicUrl).href
105
107
 
106
108
  const result = await withSpinner(
107
109
  `Publishing ${name} → ${publicUrl}`,
@@ -110,7 +112,7 @@ Examples:
110
112
  publishAdminDomain(opts, {
111
113
  origin,
112
114
  name,
113
- url: publicUrl,
115
+ url: discoveryUrl,
114
116
  ...(opts.description ? { description: opts.description } : {}),
115
117
  ...(opts.installByDefault ? { installByDefault: true } : {}),
116
118
  }),
@@ -127,7 +129,8 @@ Examples:
127
129
  return
128
130
  }
129
131
  } catch (e) {
130
- fatal(e)
132
+ await formatKernelError(e, isMachine(opts), undefined, opts.debug)
133
+ process.exit(1)
131
134
  }
132
135
  },
133
136
  } satisfies CommandDefinition
@@ -1,5 +1,5 @@
1
1
  import { Path } from '@astrale-os/sdk/graph/path'
2
- import { syscalls } from '@astrale-os/sdk/schema/kernel'
2
+ import { K } from '@astrale-os/sdk/schema'
3
3
  import chalk from 'chalk'
4
4
 
5
5
  import type { KernelCommandOpts } from '../../connection'
@@ -77,7 +77,7 @@ Examples:
77
77
  label: `Uninstalling domain ${origin}`,
78
78
  fn: async ({ session }) =>
79
79
  (await session.call(
80
- createPathCall(Path.project(syscalls.uninstall.ref).raw, uninstallCallInput(origin)),
80
+ createPathCall(Path.project(K.functions.uninstall.ref).raw, uninstallCallInput(origin)),
81
81
  )) as UninstallResult,
82
82
  format: (result, formatOpts, machine) => {
83
83
  if (machine) {
@@ -4,40 +4,39 @@ import type { KernelCommandOpts } from '../connection'
4
4
  import type { CommandDefinition } from '../program/index'
5
5
 
6
6
  import { expandSelfInPath, runKernelCommand, withSelfHint } from '../connection'
7
- import { formatKernelError } from '../connection/errors'
8
7
  import { AstraleError } from '../errors'
9
- import { denoise, isMachine, output } from '../lib/output'
8
+ import { failInput, fatal } from '../lib/log'
9
+ import { denoise, output } from '../lib/output'
10
10
 
11
11
  type GetOpts = KernelCommandOpts & { schema?: boolean }
12
12
 
13
13
  /** Read one exact canonical Node. The caller's Path is not fabricated into the Node value. */
14
14
  export async function getCommand(target: string, opts: GetOpts): Promise<void> {
15
- let path: string
16
- let meta
17
15
  let parsed
18
16
  try {
19
- ;({ path, meta } = await expandSelfInPath(target, opts))
20
- parsed = Path.parse(path)
17
+ parsed = Path.parse(target)
21
18
  } catch (error) {
22
- await formatKernelError(error, isMachine(opts), undefined, opts.debug)
23
- process.exit(1)
19
+ failInput(error, opts)
24
20
  }
25
21
 
26
22
  const last = parsed.ast.steps.at(-1)
27
23
  if (last?.kind === 'method') {
28
24
  const error = new AstraleError(
29
25
  'NOT_A_NODE',
30
- `${path} is a callable Path, not a Node.`,
31
- `Use \`astrale call ${path}\` or \`astrale introspect ${path}\`.`,
26
+ `${target} is a callable Path, not a Node.`,
27
+ `Use \`astrale call ${target}\` or \`astrale introspect ${target}\`.`,
32
28
  )
33
- await formatKernelError(error, isMachine(opts), undefined, opts.debug)
34
- process.exit(1)
29
+ fatal(error, opts)
35
30
  }
36
31
 
37
32
  await runKernelCommand({
38
33
  opts,
39
- label: `Node ${path}`,
40
- fn: ({ graph }) => withSelfHint(() => graph.getOrThrow(parsed), meta),
34
+ label: `Node ${target}`,
35
+ fn: async (context) => {
36
+ const { path, meta } = await expandSelfInPath(target, context)
37
+ const resolved = meta === undefined ? parsed : Path.parse(path)
38
+ return withSelfHint(() => context.graph.getOrThrow(resolved), meta)
39
+ },
41
40
  format: (node, format) => output(opts.schema === true ? node : denoise(node), format),
42
41
  })
43
42
  }
@@ -60,7 +59,7 @@ Examples:
60
59
  $ astrale get /:notes.example.dev:class.Note
61
60
  $ astrale get @abc123 --json
62
61
  $ astrale get @self
63
- $ astrale get /:host.astrale.ai --schema
62
+ $ astrale get /:kernel.astrale.ai --schema
64
63
  `,
65
64
  arguments: [{ name: 'target', description: 'Canonical Node Path or @id' }],
66
65
  options: [{ flags: '--schema', description: 'Include schema-valued properties' }],
@@ -1,9 +1,9 @@
1
1
  import { issuer, jwk, provision } from '@astrale-os/sdk/auth'
2
- import { ClassPath } from '@astrale-os/sdk/graph/class'
3
2
  import { normalizeProperties } from '@astrale-os/sdk/graph/properties'
4
3
  import { expect, mock, test } from 'bun:test'
5
4
  import { exportJWK, generateKeyPair, jwtVerify } from 'jose'
6
5
 
6
+ import { classKey } from '../../../graph'
7
7
  import { formatIdentityRegistration, prepareIdentityProvision } from '../register'
8
8
 
9
9
  /** @evidence TEST-CLI-IDENTITY-REGISTER-JSON-EXACT */
@@ -46,7 +46,7 @@ test('builds one exact Mutation V3 identity birth bound to a self proof', async
46
46
  kid: 'alice-key',
47
47
  })
48
48
  const kernelIssuer = issuer.accept('https://kernel.example')
49
- const classPath = ClassPath.parse('/:accounts.example:class.User')
49
+ const classPath = classKey('/:accounts.example:class.User', '--class')
50
50
  const properties = normalizeProperties({
51
51
  'accounts.example:class.User.property.name': 'Alice',
52
52
  })
@@ -70,7 +70,7 @@ test('builds one exact Mutation V3 identity birth bound to a self proof', async
70
70
  {
71
71
  op: 'node.create',
72
72
  as: 'identity',
73
- class: '/:accounts.example:class.User',
73
+ class: 'accounts.example:class.User',
74
74
  props: { 'accounts.example:class.User.property.name': 'Alice' },
75
75
  },
76
76
  ],
@@ -1,9 +1,9 @@
1
1
  import type { IssuerId, JsonWebKey, ProvisionRequest } from '@astrale-os/sdk/auth'
2
+ import type { ClassKey as ClassKeyValue } from '@astrale-os/sdk/graph/class'
2
3
  import type { JWK } from 'jose'
3
4
 
4
5
  import { provision, jwk } from '@astrale-os/sdk/auth'
5
- import { ClassPath } from '@astrale-os/sdk/graph/class'
6
- import { LocalBinding } from '@astrale-os/sdk/graph/model'
6
+ import { LocalBinding } from '@astrale-os/sdk/graph'
7
7
  import { normalizeProperties } from '@astrale-os/sdk/graph/properties'
8
8
  import { MutationAST } from '@astrale-os/sdk/mutation'
9
9
  import { importJWK, SignJWT } from 'jose'
@@ -14,6 +14,7 @@ import type { IdentityRegistrationResult } from '../../identity/index'
14
14
  import type { CommandDefinition } from '../../program/index'
15
15
 
16
16
  import { registrationKeyForTarget, runKernelCommand } from '../../connection'
17
+ import { classKey } from '../../graph'
17
18
  import { getIdentity, setRegistration, submitIdentityProvision } from '../../identity/index'
18
19
  import { fileExists, keypairPaths } from '../../keys/index'
19
20
  import { fatal, log } from '../../lib/log'
@@ -83,7 +84,7 @@ Example:
83
84
 
84
85
  const privateKey = await readJwk(privatePath)
85
86
  const publicKey = jwk.acceptPublic(await readJwk(publicPath))
86
- const classPath = ClassPath.parse(opts.class)
87
+ const classPath = classKey(opts.class, '--class')
87
88
  const properties = normalizeProperties(opts.props ? JSON.parse(opts.props) : {})
88
89
 
89
90
  await runKernelCommand<IdentityRegistrationResult>({
@@ -142,7 +143,7 @@ export function formatIdentityRegistration(
142
143
  /** Build and self-prove one exact canonical provision request for the target Kernel. */
143
144
  export async function prepareIdentityProvision(input: {
144
145
  readonly name: string
145
- readonly classPath: ReturnType<typeof ClassPath.parse>
146
+ readonly classPath: ClassKeyValue
146
147
  readonly properties: ReturnType<typeof normalizeProperties>
147
148
  readonly privateKey: JWK
148
149
  readonly publicKey: JsonWebKey
@@ -1,15 +1,12 @@
1
1
  import type { CommandDefinition } from '../../program/index'
2
2
 
3
+ import { formatKernelError } from '../../connection/errors'
3
4
  import { ADMIN_TARGET_OPTIONS } from '../../lib/admin-target'
4
- import { fatal } from '../../lib/log'
5
5
  import { isMachine, output } from '../../lib/output'
6
6
  import { promptText } from '../../lib/prompt'
7
7
  import { provisionInstance, type ProvisionOpts } from '../../lib/provision-instance'
8
8
  import { validateSlug } from '../../lib/validation'
9
9
 
10
- // Re-exported for tests + `astrale setup`, which share the provisioning saga.
11
- export { assertAlphaCreateIdentity, parseEligibleHostIds } from '../../lib/provision-instance'
12
-
13
10
  /** inquirer `validate` for a slug: true when valid, else the human message. */
14
11
  function slugError(value: string): true | string {
15
12
  try {
@@ -22,12 +19,12 @@ function slugError(value: string): true | string {
22
19
 
23
20
  export default {
24
21
  name: 'create',
25
- description: 'Provision an alpha instance through the admin kernel (Instance.alphaCreate)',
22
+ description: 'Provision an instance through the Admin control plane',
26
23
  afterHelpText: `
27
24
  Behavior:
28
- Calls Instance.alphaCreate on the configured admin kernel. The caller must be
29
- logged in with WorkOS. When --host-id is omitted, the admin kernel chooses the
30
- caller's single eligible host. The new instance becomes the active instance.
25
+ Requests a new Instance from the configured Admin Domain. The caller must be
26
+ logged in with WorkOS. Admin owns infrastructure placement. The new instance
27
+ becomes the active instance.
31
28
 
32
29
  Run with no slug in a terminal and it prompts for one (validated live). With
33
30
  no TTY — or --ci / --no-prompt — the slug argument is required up front, so
@@ -38,13 +35,7 @@ Examples:
38
35
  $ astrale instance create demo
39
36
  `,
40
37
  arguments: [{ name: 'id', description: 'Instance slug', required: false }],
41
- options: [
42
- ...ADMIN_TARGET_OPTIONS,
43
- {
44
- flags: '--host-id <id>',
45
- description: 'Advanced: host node id to provision on when multiple hosts are available',
46
- },
47
- ],
38
+ options: [...ADMIN_TARGET_OPTIONS],
48
39
  action: async (id: string | undefined, opts: ProvisionOpts) => {
49
40
  try {
50
41
  // Interactive (TTY only): prompt for the slug when omitted, with live
@@ -63,7 +54,8 @@ Examples:
63
54
  return
64
55
  }
65
56
  } catch (e) {
66
- fatal(e, opts)
57
+ await formatKernelError(e, isMachine(opts), undefined, opts.debug)
58
+ process.exit(1)
67
59
  }
68
60
  },
69
61
  } satisfies CommandDefinition