@astrale-os/cli 0.8.0-alpha.0 → 0.8.1-alpha.2

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 (317) hide show
  1. package/README.md +4 -1
  2. package/dist/astrale.js +62968 -41240
  3. package/dist/public/connect-core.js +55030 -0
  4. package/dist/public/keys/index.js +45631 -0
  5. package/dist/public/paths/index.js +43990 -0
  6. package/dist/types/admin/instance/model.d.ts +40 -0
  7. package/dist/types/connect-core.d.ts +22 -0
  8. package/dist/types/connection/auth.d.ts +33 -0
  9. package/dist/types/errors.d.ts +23 -0
  10. package/dist/types/identity/registry.d.ts +25 -0
  11. package/dist/types/keys/algorithm.d.ts +6 -0
  12. package/dist/types/keys/credential.d.ts +21 -0
  13. package/dist/types/keys/index.d.ts +4 -0
  14. package/dist/types/keys/pair.d.ts +34 -0
  15. package/dist/types/lib/admin-target.d.ts +74 -0
  16. package/dist/types/lib/ca-fetch.d.ts +2 -0
  17. package/dist/types/lib/config.d.ts +71 -0
  18. package/dist/types/lib/format.d.ts +1 -0
  19. package/dist/types/lib/idp-session.d.ts +33 -0
  20. package/dist/types/lib/idp.d.ts +397 -0
  21. package/dist/types/lib/instance-target.d.ts +36 -0
  22. package/dist/types/lib/instance.d.ts +186 -0
  23. package/dist/types/lib/log.d.ts +30 -0
  24. package/dist/types/lib/login-flow.d.ts +49 -0
  25. package/dist/types/lib/meta.d.ts +36 -0
  26. package/dist/types/lib/output.d.ts +83 -0
  27. package/dist/types/lib/table.d.ts +18 -0
  28. package/dist/types/lib/validation.d.ts +11 -0
  29. package/dist/types/paths/index.d.ts +2 -0
  30. package/dist/types/state/exchange-credentials.d.ts +25 -0
  31. package/dist/types/state/files.d.ts +9 -0
  32. package/dist/types/state/identities.d.ts +42 -0
  33. package/dist/types/state/index.d.ts +8 -0
  34. package/dist/types/state/paths.d.ts +32 -0
  35. package/package.json +30 -8
  36. package/src/admin/.spec/api.d.ts +3 -0
  37. package/src/admin/.spec/architecture.md +15 -0
  38. package/src/admin/.spec/icon.svg +3 -0
  39. package/src/admin/.spec/layout.ts +6 -0
  40. package/src/admin/catalog/.spec/api.d.ts +65 -0
  41. package/src/admin/catalog/.spec/architecture.md +6 -0
  42. package/src/admin/catalog/.spec/icon.svg +3 -0
  43. package/src/admin/catalog/.spec/layout.ts +6 -0
  44. package/src/admin/catalog/__tests__/client.test.ts +171 -0
  45. package/src/admin/catalog/client.ts +214 -0
  46. package/src/admin/catalog/index.ts +13 -0
  47. package/src/admin/catalog/model.ts +42 -0
  48. package/src/admin/catalog/tsconfig.json +8 -0
  49. package/src/admin/graph/.spec/api.d.ts +28 -0
  50. package/src/admin/graph/.spec/architecture.md +5 -0
  51. package/src/admin/graph/.spec/icon.svg +3 -0
  52. package/src/admin/graph/.spec/layout.ts +3 -0
  53. package/src/admin/graph/index.ts +6 -0
  54. package/src/admin/graph/nodes.ts +56 -0
  55. package/src/admin/index.ts +2 -0
  56. package/src/admin/instance/.spec/api.d.ts +66 -0
  57. package/src/admin/instance/.spec/architecture.md +10 -0
  58. package/src/admin/instance/.spec/icon.svg +3 -0
  59. package/src/admin/instance/.spec/layout.ts +6 -0
  60. package/src/admin/instance/__tests__/client.test.ts +289 -0
  61. package/src/admin/instance/client.ts +298 -0
  62. package/src/admin/instance/index.ts +16 -0
  63. package/src/admin/instance/model.ts +65 -0
  64. package/src/admin/instance/tsconfig.json +8 -0
  65. package/src/commands/__tests__/admin-instance.test.ts +3 -36
  66. package/src/commands/__tests__/call.test.ts +21 -68
  67. package/src/commands/__tests__/domain-install-owned.test.ts +26 -27
  68. package/src/commands/__tests__/domain-list.test.ts +2 -6
  69. package/src/commands/__tests__/logs.test.ts +50 -98
  70. package/src/commands/__tests__/ls.test.ts +21 -17
  71. package/src/commands/__tests__/read-commands.test.ts +171 -101
  72. package/src/commands/__tests__/view.test.ts +100 -51
  73. package/src/commands/admin/status.ts +3 -3
  74. package/src/commands/admin/use.ts +29 -6
  75. package/src/commands/auth/login.ts +1 -1
  76. package/src/commands/auth/logout.ts +4 -2
  77. package/src/commands/auth/status.ts +2 -2
  78. package/src/commands/auth/token.ts +2 -2
  79. package/src/commands/browser.ts +1 -1
  80. package/src/commands/call.ts +55 -91
  81. package/src/commands/describe.ts +52 -147
  82. package/src/commands/domain/install.ts +81 -50
  83. package/src/commands/domain/list.ts +4 -8
  84. package/src/commands/domain/publish.ts +9 -31
  85. package/src/commands/get.ts +32 -65
  86. package/src/commands/identity/__tests__/register.test.ts +93 -0
  87. package/src/commands/identity/create.ts +2 -2
  88. package/src/commands/identity/delete.ts +2 -2
  89. package/src/commands/identity/export.ts +7 -33
  90. package/src/commands/identity/import.ts +21 -70
  91. package/src/commands/identity/list.ts +2 -2
  92. package/src/commands/identity/register.ts +148 -117
  93. package/src/commands/identity/sync.ts +2 -2
  94. package/src/commands/identity/unsync.ts +2 -2
  95. package/src/commands/identity/use.ts +2 -2
  96. package/src/commands/identity/whoami.ts +2 -2
  97. package/src/commands/idp/add.ts +1 -1
  98. package/src/commands/idp/list.ts +1 -1
  99. package/src/commands/idp/refresh.ts +1 -1
  100. package/src/commands/idp/remove.ts +2 -2
  101. package/src/commands/idp/show.ts +1 -1
  102. package/src/commands/instance/active.ts +2 -2
  103. package/src/commands/instance/bookmark.ts +8 -2
  104. package/src/commands/instance/create.ts +1 -1
  105. package/src/commands/instance/delete.ts +4 -10
  106. package/src/commands/instance/forget.ts +1 -1
  107. package/src/commands/instance/list.ts +3 -3
  108. package/src/commands/instance/status.ts +5 -7
  109. package/src/commands/instance/use.ts +3 -3
  110. package/src/commands/logs.ts +152 -279
  111. package/src/commands/ls.ts +78 -204
  112. package/src/commands/mutate.ts +70 -139
  113. package/src/commands/query.ts +100 -278
  114. package/src/commands/session/analyze.ts +1 -1
  115. package/src/commands/session/list.ts +1 -1
  116. package/src/commands/setup.ts +1 -1
  117. package/src/commands/status.ts +1 -1
  118. package/src/commands/studio.ts +1 -1
  119. package/src/commands/token.ts +26 -21
  120. package/src/commands/update.ts +1 -1
  121. package/src/commands/use.ts +2 -3
  122. package/src/commands/view-serve.ts +1 -1
  123. package/src/commands/view.ts +67 -109
  124. package/src/connect-core.test.ts +38 -0
  125. package/src/connect-core.ts +42 -0
  126. package/src/connection/.spec/api.d.ts +111 -0
  127. package/src/connection/.spec/architecture.md +41 -0
  128. package/src/connection/.spec/capabilities/connection.ts +13 -0
  129. package/src/connection/.spec/examples/call.ts +7 -0
  130. package/src/connection/.spec/flows/command.ts +20 -0
  131. package/src/connection/.spec/flows/session.ts +61 -0
  132. package/src/connection/.spec/laws/connection.ts +181 -0
  133. package/src/connection/.spec/layout.ts +19 -0
  134. package/src/{kernel → connection}/__tests__/auth.test.ts +26 -2
  135. package/src/connection/__tests__/ca-fetch.test.ts +53 -0
  136. package/src/connection/__tests__/call.test.ts +17 -0
  137. package/src/connection/__tests__/credential.test.ts +109 -0
  138. package/src/connection/__tests__/errors.test.ts +96 -0
  139. package/src/connection/__tests__/exchange.test.ts +224 -0
  140. package/src/connection/__tests__/fixtures/localhost-cert.pem +19 -0
  141. package/src/connection/__tests__/fixtures/localhost-key.base64 +1 -0
  142. package/src/connection/__tests__/managed.test.ts +39 -0
  143. package/src/connection/__tests__/self.test.ts +51 -0
  144. package/src/connection/__tests__/session.test.ts +140 -0
  145. package/src/connection/__tests__/target.test.ts +93 -0
  146. package/src/{kernel → connection}/auth.ts +8 -8
  147. package/src/connection/call.ts +7 -0
  148. package/src/{kernel/run.ts → connection/command.ts} +22 -13
  149. package/src/connection/credential.ts +114 -0
  150. package/src/{kernel → connection}/errors.ts +32 -9
  151. package/src/connection/exchange.ts +274 -0
  152. package/src/connection/index.ts +8 -0
  153. package/src/connection/self.ts +120 -0
  154. package/src/connection/session.ts +176 -0
  155. package/src/connection/target.ts +111 -0
  156. package/src/connection/tsconfig.json +6 -0
  157. package/src/graph/.spec/api.d.ts +34 -0
  158. package/src/graph/.spec/laws/documents.ts +24 -0
  159. package/src/graph/.spec/laws/projection.ts +13 -0
  160. package/src/graph/.spec/layout.ts +6 -0
  161. package/src/graph/__tests__/mutation.test.ts +43 -0
  162. package/src/graph/__tests__/projection.test.ts +22 -0
  163. package/src/graph/__tests__/query.test.ts +154 -0
  164. package/src/graph/index.ts +3 -0
  165. package/src/graph/mutation.ts +18 -0
  166. package/src/graph/projection.ts +21 -0
  167. package/src/graph/query.ts +108 -0
  168. package/src/graph/tsconfig.json +6 -0
  169. package/src/identity/.history/ard/bootstrap-root-transfer.md +57 -0
  170. package/src/identity/.history/ard/domain-mediated-registration.md +36 -0
  171. package/src/identity/.spec/api.d.ts +124 -0
  172. package/src/identity/.spec/architecture.md +33 -0
  173. package/src/identity/.spec/capabilities/identity.ts +7 -0
  174. package/src/identity/.spec/flows/bootstrap-root.ts +79 -0
  175. package/src/identity/.spec/flows/domain-mediated-registration.ts +51 -0
  176. package/src/identity/.spec/flows/import.ts +29 -0
  177. package/src/identity/.spec/laws/identity.ts +56 -0
  178. package/src/identity/.spec/layout.ts +13 -0
  179. package/src/identity/.spec/schemas/identity-export-v1.schema.json +25 -0
  180. package/src/identity/__tests__/fixtures/registry-journey.ts +53 -0
  181. package/src/identity/__tests__/registration.test.ts +64 -0
  182. package/src/identity/__tests__/registry.test.ts +70 -0
  183. package/src/identity/__tests__/transfer.test.ts +198 -0
  184. package/src/identity/index.ts +23 -0
  185. package/src/identity/registration.ts +72 -0
  186. package/src/identity/registry.ts +172 -0
  187. package/src/identity/transfer.ts +187 -0
  188. package/src/identity/tsconfig.json +6 -0
  189. package/src/index.ts +1 -0
  190. package/src/keys/.spec/api.d.ts +74 -0
  191. package/src/keys/.spec/architecture.md +13 -0
  192. package/src/keys/.spec/laws/keys.ts +43 -0
  193. package/src/keys/.spec/layout.ts +6 -0
  194. package/src/keys/__tests__/algorithm.test.ts +39 -0
  195. package/src/keys/__tests__/keys.test.ts +168 -0
  196. package/src/keys/algorithm.ts +33 -0
  197. package/src/keys/credential.ts +112 -0
  198. package/src/keys/index.ts +14 -0
  199. package/src/keys/pair.ts +219 -0
  200. package/src/keys/tsconfig.json +6 -0
  201. package/src/lib/__tests__/admin-target.test.ts +67 -7
  202. package/src/lib/__tests__/binary.test.ts +2 -3
  203. package/src/lib/__tests__/command-dx.test.ts +2 -2
  204. package/src/lib/__tests__/config.test.ts +3 -2
  205. package/src/lib/__tests__/idp.test.ts +4 -6
  206. package/src/lib/__tests__/instance-target.test.ts +7 -4
  207. package/src/lib/__tests__/local-status.test.ts +1 -1
  208. package/src/lib/__tests__/log.test.ts +31 -0
  209. package/src/lib/__tests__/meta.test.ts +55 -0
  210. package/src/lib/__tests__/sdk-deps.test.ts +1 -1
  211. package/src/lib/__tests__/self.test.ts +8 -230
  212. package/src/lib/__tests__/use-target.test.ts +1 -1
  213. package/src/lib/__tests__/view-open-intent.test.ts +78 -104
  214. package/src/lib/__tests__/view-session.test.ts +99 -0
  215. package/src/lib/admin-domain.ts +39 -25
  216. package/src/lib/admin-instance.ts +38 -43
  217. package/src/lib/admin-target.ts +67 -13
  218. package/src/lib/binary.ts +13 -34
  219. package/src/lib/browser.ts +1 -1
  220. package/src/{kernel → lib}/ca-fetch.ts +35 -27
  221. package/src/lib/config.ts +1 -1
  222. package/src/lib/idp-session.ts +1 -1
  223. package/src/lib/idp.ts +3 -8
  224. package/src/lib/instance-target.ts +12 -8
  225. package/src/lib/instance.ts +34 -2
  226. package/src/lib/local-status.ts +2 -2
  227. package/src/lib/log.ts +3 -1
  228. package/src/lib/login-flow.ts +32 -5
  229. package/src/lib/meta.ts +15 -11
  230. package/src/lib/provision-instance.ts +4 -12
  231. package/src/lib/self.ts +5 -147
  232. package/src/lib/update.ts +1 -1
  233. package/src/lib/use-target.ts +1 -1
  234. package/src/lib/validation.ts +2 -2
  235. package/src/lib/view/open-intent.ts +7 -37
  236. package/src/lib/view/port-allocation.ts +1 -1
  237. package/src/lib/view/resolve.ts +52 -45
  238. package/src/lib/view/server.ts +16 -33
  239. package/src/lib/view/session.ts +51 -22
  240. package/src/paths/.spec/api.d.ts +13 -0
  241. package/src/paths/.spec/architecture.md +5 -0
  242. package/src/paths/.spec/layout.ts +3 -0
  243. package/src/paths/index.ts +13 -0
  244. package/src/program/.spec/api.d.ts +42 -0
  245. package/src/program/.spec/architecture.md +18 -0
  246. package/src/program/.spec/laws/program.ts +29 -0
  247. package/src/program/.spec/layout.ts +14 -0
  248. package/src/program/__tests__/program.test.ts +359 -0
  249. package/src/program/build.ts +190 -0
  250. package/src/program/command.ts +42 -0
  251. package/src/program/index.ts +2 -0
  252. package/src/program/options.ts +40 -0
  253. package/src/{registry.ts → program/registry.ts} +5 -1
  254. package/src/program/tsconfig.json +6 -0
  255. package/src/setup/steps/admin.ts +18 -3
  256. package/src/setup/steps/instance.ts +1 -1
  257. package/src/state/.spec/api.d.ts +133 -0
  258. package/src/state/.spec/architecture.md +31 -0
  259. package/src/state/.spec/capabilities/state.ts +7 -0
  260. package/src/state/.spec/flows/identity-update.ts +22 -0
  261. package/src/state/.spec/laws/state.ts +73 -0
  262. package/src/state/.spec/layout.ts +14 -0
  263. package/src/state/__tests__/exchange-credentials.test.ts +188 -0
  264. package/src/state/__tests__/files.test.ts +113 -0
  265. package/src/state/__tests__/fixtures/identity-transition.ts +37 -0
  266. package/src/state/__tests__/identities.test.ts +142 -0
  267. package/src/state/__tests__/paths.test.ts +27 -0
  268. package/src/state/exchange-credentials.ts +219 -0
  269. package/src/state/files.ts +129 -0
  270. package/src/state/identities.ts +236 -0
  271. package/src/state/index.ts +29 -0
  272. package/src/state/paths.ts +61 -0
  273. package/src/state/tsconfig.json +6 -0
  274. package/src/telemetry/__tests__/redact.test.ts +3 -3
  275. package/src/telemetry/__tests__/trigger.test.ts +1 -1
  276. package/src/telemetry/settings.ts +1 -1
  277. package/src/telemetry/store.ts +1 -1
  278. package/src/test-utils.ts +1 -1
  279. package/studio/client/dist/assets/elk-api-D0cBetPW.js +1 -0
  280. package/studio/client/dist/assets/elk-worker.min-C9JGDOE-.js +6312 -0
  281. package/studio/client/dist/assets/index-BQnJ5sgd.css +1 -0
  282. package/studio/client/dist/assets/index-ChOr3yP0.css +1 -0
  283. package/studio/client/dist/assets/index-Dspir4w7.js +81 -0
  284. package/studio/client/dist/assets/index-bVD2KJgz.js +8 -0
  285. package/studio/client/dist/index.html +2 -2
  286. package/studio/package.json +10 -1
  287. package/studio/server/introspect/extractor.ts +1 -1
  288. package/studio/server/state/views.test.ts +3 -7
  289. package/studio/server/state/views.ts +23 -30
  290. package/studio/tsconfig.json +23 -0
  291. package/tsconfig.json +1 -1
  292. package/viewer/dist/main.js +65 -39
  293. package/viewer/tsconfig.json +13 -0
  294. package/src/command.ts +0 -42
  295. package/src/commands/__tests__/help-contract.test.ts +0 -164
  296. package/src/kernel/__tests__/client-owned-lookup.test.ts +0 -51
  297. package/src/kernel/__tests__/errors.test.ts +0 -43
  298. package/src/kernel/__tests__/expand.test.ts +0 -123
  299. package/src/kernel/client.ts +0 -214
  300. package/src/kernel/expand.ts +0 -192
  301. package/src/kernel/graph.ts +0 -96
  302. package/src/kernel/index.ts +0 -29
  303. package/src/kernel/options.ts +0 -22
  304. package/src/kernel/types.ts +0 -14
  305. package/src/lib/__tests__/domain-identity.test.ts +0 -60
  306. package/src/lib/__tests__/fs-atomic.test.ts +0 -104
  307. package/src/lib/__tests__/identity.test.ts +0 -79
  308. package/src/lib/__tests__/keys.test.ts +0 -129
  309. package/src/lib/domain-identity.ts +0 -49
  310. package/src/lib/env.ts +0 -49
  311. package/src/lib/fs-atomic.ts +0 -126
  312. package/src/lib/identity.ts +0 -256
  313. package/src/lib/keys.ts +0 -294
  314. package/src/lib/paths.ts +0 -11
  315. package/src/program.ts +0 -213
  316. package/studio/client/dist/assets/index-BaqEuIQJ.js +0 -109
  317. package/studio/client/dist/assets/index-jRdExahh.css +0 -1
@@ -1,9 +1,10 @@
1
- import type { CommandDefinition } from '../../command'
1
+ import type { CommandDefinition } from '../../program/index'
2
2
 
3
- import { getDefault, readIdentities } from '../../lib/identity'
3
+ import { getDefault, readIdentities } from '../../identity/index'
4
4
  import { deleteIdpSession, listIdpSessions } from '../../lib/idp'
5
5
  import { log } from '../../lib/log'
6
6
  import { output, RAW_OUTPUT_OPTIONS } from '../../lib/output'
7
+ import { ExchangeCredentialCache } from '../../state/index'
7
8
 
8
9
  export default {
9
10
  name: 'logout',
@@ -28,6 +29,7 @@ export default {
28
29
  }
29
30
 
30
31
  for (const name of names) await deleteIdpSession(name)
32
+ await new ExchangeCredentialCache().clear()
31
33
 
32
34
  if (opts.raw || opts.json) {
33
35
  output({ cleared: names }, opts)
@@ -1,9 +1,9 @@
1
1
  import chalk from 'chalk'
2
2
 
3
- import type { CommandDefinition } from '../../command'
4
3
  import type { ListOpts, ListProjection } from '../../lib/output'
4
+ import type { CommandDefinition } from '../../program/index'
5
5
 
6
- import { readIdentities } from '../../lib/identity'
6
+ import { readIdentities } from '../../identity/index'
7
7
  import { isSessionExpired, listIdpSessions } from '../../lib/idp'
8
8
  import { log } from '../../lib/log'
9
9
  import { isMachine, presentList, RAW_OUTPUT_OPTIONS } from '../../lib/output'
@@ -1,6 +1,6 @@
1
- import type { CommandDefinition } from '../../command'
1
+ import type { CommandDefinition } from '../../program/index'
2
2
 
3
- import { getDefault, getIdentity, readIdentities } from '../../lib/identity'
3
+ import { getDefault, getIdentity, readIdentities } from '../../identity/index'
4
4
  import { isSessionExpired, readIdpSession, type IdpSession } from '../../lib/idp'
5
5
  import { ensureFreshSession } from '../../lib/idp-session'
6
6
  import { log } from '../../lib/log'
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk'
2
2
  import { existsSync } from 'node:fs'
3
3
 
4
- import type { CommandDefinition } from '../command'
4
+ import type { CommandDefinition } from '../program/index'
5
5
 
6
6
  import {
7
7
  ab,
@@ -1,59 +1,40 @@
1
- import { K } from '@astrale-os/kernel-core'
1
+ import { Path } from '@astrale-os/sdk/graph/path'
2
2
 
3
- import type { CommandDefinition } from '../command'
4
- import type { CallCommandOpts, ClientContext, SelfExpansionMeta } from '../kernel'
3
+ import type { ConnectionContext, KernelCommandOpts } from '../connection'
4
+ import type { CommandDefinition } from '../program/index'
5
5
 
6
- import {
7
- bindGraph,
8
- buildSelfContext,
9
- nodeProp,
10
- resolveSelfIdLazy,
11
- runKernelCommand,
12
- withSelfHint,
13
- } from '../kernel'
14
- import { presentBinary, type BinaryLike } from '../lib/binary'
6
+ import { createPathCall, expandSelfInCall, runKernelCommand, withSelfHint } from '../connection'
7
+ import { nodeProperty } from '../graph/index'
8
+ import { presentBinary } from '../lib/binary'
15
9
  import { log } from '../lib/log'
16
10
  import { output, present } from '../lib/output'
17
- import { containsSelfRef, expandSelfReferences } from '../lib/self'
18
11
 
19
- type CallOpts = CallCommandOpts & { describe?: boolean; dryRun?: boolean; output?: string }
12
+ type CallOpts = KernelCommandOpts & {
13
+ data?: string
14
+ describe?: boolean
15
+ dryRun?: boolean
16
+ output?: string
17
+ }
20
18
 
21
- /** A call resolves to either a JSON value or a binary response. */
22
- type CallResult = { kind: 'binary'; response: BinaryLike } | { kind: 'value'; value: unknown }
19
+ type CallResult = Awaited<ReturnType<ConnectionContext['session']['dispatch']>>
20
+ type MaterializedCallResult =
21
+ | Exclude<CallResult, { readonly kind: 'stream' }>
22
+ | { readonly kind: 'stream'; readonly values: readonly unknown[] }
23
23
 
24
24
  export async function callCommand(
25
25
  path: string,
26
26
  rawParams: string[],
27
27
  opts: CallOpts,
28
28
  ): Promise<void> {
29
- // Expand @self before describe/execute so refusals are typed and stale IdP
30
- // registrations can refresh through whoami.
31
- let expandedPath = path
32
- let expandedRaw = rawParams
33
- let selfMeta: SelfExpansionMeta | undefined
34
- const inputsHaveSelf = containsSelfRef(path) || rawParams.some(containsSelfRef)
35
- if (inputsHaveSelf) {
36
- try {
37
- const selfCtx = await buildSelfContext(opts)
38
- const selfId = await resolveSelfIdLazy(selfCtx, opts)
39
- expandedPath = expandSelfReferences(path, selfId)
40
- expandedRaw = rawParams.map((p) => expandSelfReferences(p, selfId))
41
- // Stale-registration hints apply when @self appears in either path or params.
42
- const rawMutated = expandedRaw.some((p, i) => p !== rawParams[i])
43
- if (expandedPath !== path || rawMutated) {
44
- selfMeta = {
45
- original: path,
46
- expanded: expandedPath,
47
- selfId,
48
- identity: selfCtx.identity?.name,
49
- slug: selfCtx.instanceSlug,
50
- }
51
- }
52
- } catch (e) {
53
- log.error(e instanceof Error ? e.message : 'Invalid @self expansion')
54
- process.exit(1)
55
- }
29
+ // Expand @self before describe/execute through authenticated Identity.whoami.
30
+ let expanded: Awaited<ReturnType<typeof expandSelfInCall>>
31
+ try {
32
+ expanded = await expandSelfInCall(path, rawParams, opts)
33
+ } catch (error) {
34
+ log.error(error instanceof Error ? error.message : 'Invalid @self expansion')
35
+ process.exit(1)
56
36
  }
37
+ const expandedPath = expanded.path
57
38
 
58
39
  // ── Describe mode: show schema without executing ────────
59
40
  // Runs AFTER expansion so `astrale call @self::m --describe` works.
@@ -64,7 +45,7 @@ export async function callCommand(
64
45
  // ── Parse params ────────────────────────────────────────
65
46
  let params: Record<string, unknown>
66
47
  try {
67
- params = await parseParams(expandedRaw, opts.data)
48
+ params = await parseParams([...expanded.parameters], opts.data)
68
49
  } catch (e) {
69
50
  log.error(e instanceof Error ? e.message : 'Invalid params')
70
51
  process.exit(1)
@@ -77,56 +58,39 @@ export async function callCommand(
77
58
  }
78
59
 
79
60
  // ── Execute ────────────────────────────────────────────
80
- await runKernelCommand<CallResult>({
61
+ await runKernelCommand<MaterializedCallResult>({
81
62
  opts,
82
63
  label: expandedPath,
83
- fn: async (ctx): Promise<CallResult> => {
84
- // Binary outputs must be routed before dispatch; JSON decoding would corrupt bytes.
85
- if (await isBinaryOutput(ctx, expandedPath)) {
86
- const response = await withSelfHint(() => ctx.client.binary(expandedPath, params), selfMeta)
87
- return { kind: 'binary', response }
88
- }
89
- const value = await withSelfHint(() => ctx.client.call(expandedPath, params), selfMeta)
90
- return { kind: 'value', value }
91
- },
64
+ fn: (ctx) =>
65
+ withSelfHint(
66
+ async () =>
67
+ materializeCallResult(await ctx.session.dispatch(createPathCall(expandedPath, params))),
68
+ expanded.meta,
69
+ ),
92
70
  format: async (result, fmtOpts) => {
93
- if (result.kind === 'binary') {
94
- await presentBinary(result.response, fmtOpts, { outFile: opts.output })
95
- return
71
+ switch (result.kind) {
72
+ case 'value':
73
+ present(result.value, fmtOpts)
74
+ return
75
+ case 'binary':
76
+ await presentBinary(result.value, fmtOpts, { outFile: opts.output })
77
+ return
78
+ case 'stream':
79
+ output(result.values, fmtOpts)
80
+ return
81
+ case 'redirect':
82
+ throw new Error('Client Session returned an unresolved redirect.')
96
83
  }
97
- present(result.value, fmtOpts)
98
84
  },
99
85
  })
100
86
  }
101
87
 
102
- /**
103
- * Best-effort binary preflight. Static paths read the Function node directly;
104
- * instance paths probe the class method node and fall back to value transport on miss.
105
- */
106
- async function isBinaryOutput(ctx: ClientContext, path: string): Promise<boolean> {
107
- try {
108
- const target = path.includes('::') ? await instanceMethodNodePath(ctx, path) : path
109
- if (!target) return false
110
- const node = await bindGraph(ctx).get(target)
111
- // Props travel under fully-qualified keys; `output.key` IS that key.
112
- return node?.props?.[K.$.i('Function').output.key] === 'binary'
113
- } catch {
114
- return false
115
- }
116
- }
117
-
118
- /** `<node>::method` → the method's Function-node MethodPath, via the node's class. */
119
- async function instanceMethodNodePath(
120
- ctx: ClientContext,
121
- path: string,
122
- ): Promise<string | undefined> {
123
- const sep = path.lastIndexOf('::')
124
- const source = path.slice(0, sep)
125
- const method = path.slice(sep + 2)
126
- if (!source || !method) return undefined
127
- const node = await bindGraph(ctx).get(source)
128
- // ClassPath + method name forms the class-owned Function MethodPath.
129
- return node?.class ? `${node.class.raw}:${method}` : undefined
88
+ /** Drain a session-backed stream before the command-scoped Client Session closes. */
89
+ export async function materializeCallResult(result: CallResult): Promise<MaterializedCallResult> {
90
+ if (result.kind !== 'stream') return result
91
+ const values: unknown[] = []
92
+ for await (const value of result.stream) values.push(value)
93
+ return Object.freeze({ kind: 'stream', values: Object.freeze(values) })
130
94
  }
131
95
 
132
96
  async function describeOperation(path: string, opts: CallOpts): Promise<void> {
@@ -134,10 +98,10 @@ async function describeOperation(path: string, opts: CallOpts): Promise<void> {
134
98
  opts,
135
99
  label: `Schema for ${path}`,
136
100
  // The Function node carries the schemas as props (function.get depth:0).
137
- fn: async (ctx) => await bindGraph(ctx).get(path),
101
+ fn: async ({ graph }) => await graph.get(Path.parse(path)),
138
102
  format: (node, fmtOpts) => {
139
- const input = nodeProp(node, 'inputSchema')
140
- const outputSchema = nodeProp(node, 'outputSchema')
103
+ const input = nodeProperty(node, 'inputSchema')
104
+ const outputSchema = nodeProperty(node, 'outputSchema')
141
105
  const schema: Record<string, unknown> = {}
142
106
  if (input) schema.input = tryParseJson(input)
143
107
  if (outputSchema) schema.output = tryParseJson(outputSchema)
@@ -254,8 +218,8 @@ Self-reference:
254
218
  @self expands to your nodeId on the active instance (path head or
255
219
  bare param value, e.g. node=@self). --data and stdin payloads are
256
220
  sent verbatim — pre-resolve manually to a literal @<nodeId> there
257
- (e.g. via 'astrale describe @self -q', or shell-substituted from the
258
- registration record in ~/.astrale/identities.json).
221
+ (e.g. via 'astrale get @self --json'). Resolution authenticates to
222
+ the selected Kernel and never trusts a local registration or JWT sub.
259
223
 
260
224
  Examples:
261
225
  $ astrale call /:host.astrale.ai:class.KernelInstance:list
@@ -1,181 +1,86 @@
1
- import { ClassPath } from '@astrale-os/kernel-core/domain'
1
+ import type { Node } from '@astrale-os/sdk/graph/node'
2
+
3
+ import { ClassPath } from '@astrale-os/sdk/graph/class'
4
+ import { Path } from '@astrale-os/sdk/graph/path'
2
5
  import chalk from 'chalk'
3
6
 
4
- import type { CommandDefinition } from '../command'
5
- import type { GraphNode, KernelCommandOpts } from '../kernel'
7
+ import type { KernelCommandOpts } from '../connection'
8
+ import type { CommandDefinition } from '../program/index'
6
9
 
7
- import {
8
- bindGraph,
9
- expandSelfInPath,
10
- nodeProp,
11
- runKernelCommand,
12
- splitRoot,
13
- unqualifyKey,
14
- withSelfHint,
15
- } from '../kernel'
10
+ import { expandSelfInPath, runKernelCommand, withSelfHint } from '../connection'
11
+ import { unqualifyProperty } from '../graph/index'
16
12
  import { log } from '../lib/log'
17
13
  import { output } from '../lib/output'
18
14
 
19
- type DescribeResult = { node: GraphNode | undefined; children: GraphNode[] }
20
-
21
- // Commander turns `--no-schema` into `schema: false`.
22
15
  type DescribeOpts = KernelCommandOpts & { schema?: boolean }
16
+ type DescribedNode = Omit<Node, 'props'> & { readonly props: Readonly<Record<string, unknown>> }
23
17
 
24
- export async function describeCommand(path: string, opts: DescribeOpts): Promise<void> {
25
- let expandedPath: string
18
+ /** Describe only facts present on the canonical Node; no hierarchy is inferred from its Path. */
19
+ export async function describeCommand(target: string, opts: DescribeOpts): Promise<void> {
20
+ let path: string
26
21
  let meta
27
22
  try {
28
- ;({ path: expandedPath, meta } = await expandSelfInPath(path, opts))
29
- } catch (e) {
30
- log.error(e instanceof Error ? e.message : 'Invalid @self expansion')
23
+ ;({ path, meta } = await expandSelfInPath(target, opts))
24
+ } catch (error) {
25
+ log.error(error instanceof Error ? error.message : 'Invalid target')
31
26
  process.exit(1)
32
27
  }
33
- await runKernelCommand<DescribeResult>({
28
+
29
+ await runKernelCommand({
34
30
  opts,
35
- label: expandedPath,
36
- // One function.get depth:1 = the node AND its children (was ::get +
37
- // ::listChildren). Function-class children are the node's operations.
38
- fn: async (ctx) => {
39
- const result = await withSelfHint(
40
- () => bindGraph(ctx).query((q) => q.from(expandedPath).children()),
41
- meta,
42
- )
43
- const { root, children } = splitRoot(result.wire.nodes, expandedPath)
44
- return { node: root, children }
45
- },
46
- format: (result, fmtOpts, isRaw) => {
47
- const shown = opts.schema === false ? stripSchema(result) : result
48
- if (isRaw) {
49
- output(shown, fmtOpts)
50
- return
51
- }
52
- printDescribe(shown, expandedPath)
31
+ label: `Describe ${path}`,
32
+ fn: ({ graph }) => withSelfHint(() => graph.getOrThrow(Path.parse(path)), meta),
33
+ format: (node, format, machine) => {
34
+ const shown = opts.schema === false ? withoutSchema(node) : node
35
+ if (machine || format.format !== undefined) output(shown, format)
36
+ else printDescription(path, shown)
53
37
  },
54
38
  })
55
39
  }
56
40
 
57
- function stripSchema(result: DescribeResult): DescribeResult {
58
- if (!result.node) return result
59
- const entries = Object.entries(result.node.props).filter(([k]) => unqualifyKey(k) !== 'schema')
60
- return { ...result, node: { ...result.node, props: Object.fromEntries(entries) } }
61
- }
62
-
63
- // ── Pretty-print ────────────────────────────────────────────
64
-
65
- function printDescribe({ node, children }: DescribeResult, path: string): void {
66
- const kind = classNameOf(node) ?? 'Node'
67
- const name = basename(path) || path
68
- console.log(` ${chalk.bold.cyan(name)} ${chalk.dim(`(${kind})`)}`)
69
-
70
- const description = nodeProp(node, 'description')
71
- if (description) console.log(` ${chalk.dim(String(description))}`)
72
- console.log('')
73
-
74
- const operations = children.filter(isFunction)
75
- const otherChildren = children.filter((c) => !isFunction(c))
76
-
77
- if (operations.length > 0) {
78
- console.log(` ${chalk.bold('Operations:')}`)
79
- const names = operations.map((o) => basename(o.path))
80
- const slugW = Math.max(4, ...names.map((n) => n.length))
81
- operations.forEach((op, i) => {
82
- const opName = names[i].padEnd(slugW)
83
- const schema = formatInputSchema(op)
84
- console.log(` ${chalk.green(opName)} ${chalk.dim(schema)}`)
85
- })
86
- console.log('')
87
- }
88
-
89
- if (otherChildren.length > 0) {
90
- console.log(` ${chalk.bold('Children:')}`)
91
- for (const child of otherChildren) {
92
- const childKind = classNameOf(child) ?? '?'
93
- console.log(` ${chalk.cyan(basename(child.path) || '?')} ${chalk.dim(childKind)}`)
94
- }
95
- console.log('')
41
+ function withoutSchema(node: Node): DescribedNode {
42
+ return {
43
+ ...node,
44
+ props: Object.fromEntries(
45
+ Object.entries(node.props).filter(([key]) => unqualifyProperty(key) !== 'schema'),
46
+ ),
96
47
  }
97
-
98
- if (children.length === 0) {
99
- printProperties(node)
100
- }
101
- }
102
-
103
- /** `/a/b/c` → `c`; `/` → `/`. */
104
- function basename(path?: string): string {
105
- if (!path || path === '/') return path ?? ''
106
- return path.slice(path.lastIndexOf('/') + 1)
107
48
  }
108
49
 
109
- /** Short class name from the contract field `class` (a serialized ClassPath). */
110
- function classNameOf(item: GraphNode | undefined): string | undefined {
111
- return item?.class ? (ClassPath.tryParse(item.class)?.className ?? undefined) : undefined
112
- }
113
-
114
- function isFunction(item: GraphNode): boolean {
115
- return classNameOf(item) === 'Function'
116
- }
117
-
118
- function printProperties(node: GraphNode | undefined): void {
119
- if (!node) return
120
- const entries = Object.entries(node.props)
121
- .map(([k, v]) => [unqualifyKey(k), v] as const)
122
- .filter(([k]) => k !== '__labels' && k !== 'id')
123
- if (entries.length === 0) return
124
-
125
- console.log(` ${chalk.bold('Properties:')}`)
126
- for (const [k, v] of entries) {
127
- const val = typeof v === 'string' && v.length > 80 ? v.slice(0, 80) + '...' : String(v)
128
- console.log(` ${chalk.cyan(k)}: ${chalk.dim(val)}`)
129
- }
130
- }
131
-
132
- function formatInputSchema(node: GraphNode): string {
133
- const raw = nodeProp(node, 'inputSchema')
134
- if (!raw) return '{}'
135
-
136
- try {
137
- const schema = typeof raw === 'string' ? JSON.parse(raw) : raw
138
- if (typeof schema !== 'object' || schema === null) return '{}'
139
-
140
- const props = (schema as { properties?: Record<string, { type?: string }> }).properties
141
- if (!props || Object.keys(props).length === 0) return '{}'
142
-
143
- const required = new Set((schema as { required?: string[] }).required ?? [])
144
-
145
- const fields = Object.entries(props).map(([name, def]) => {
146
- const type = def?.type ?? '?'
147
- return required.has(name) ? `${name}: ${type}` : `${name}?: ${type}`
148
- })
149
-
150
- return `{ ${fields.join(', ')} }`
151
- } catch {
152
- return '{...}'
50
+ function printDescription(target: string, node: DescribedNode): void {
51
+ console.log(` ${chalk.bold.cyan(target)}`)
52
+ console.log(` ${chalk.dim('id')} ${node.id}`)
53
+ console.log(
54
+ ` ${chalk.dim('class')} ${ClassPath.name(node.class)} ${chalk.dim(`(${node.class})`)}`,
55
+ )
56
+
57
+ const properties = Object.entries(node.props)
58
+ if (properties.length === 0) return
59
+ console.log(`\n ${chalk.bold('Properties:')}`)
60
+ for (const [key, value] of properties) {
61
+ const rendered = typeof value === 'string' ? value : JSON.stringify(value)
62
+ console.log(` ${chalk.cyan(unqualifyProperty(key))}: ${chalk.dim(rendered)}`)
153
63
  }
154
64
  }
155
65
 
156
66
  export default {
157
67
  name: 'describe',
158
- description: 'Describe a node: its kind, operations, children, and schemas',
68
+ description: 'Describe the canonical facts of one node',
159
69
  afterHelpText: `
160
70
  Behavior:
161
- One function.get depth:1 the node plus its children (Function-class
162
- children are shown as Operations). Raw dump: full properties + children.
163
- For Domain nodes the properties include a multi-kB serialized 'schema' —
164
- use --no-schema, and pipe to jq rather than reading by eye.
71
+ Reads one canonical Node and presents its ID, Class, and properties.
72
+ It does not infer operations or children from path layout. --no-schema
73
+ omits schema-valued properties from Domain-sized results.
165
74
 
166
75
  Examples:
167
- $ astrale describe /kernel.astrale.ai
168
- $ astrale describe /host.astrale.ai --no-schema | jq .
76
+ $ astrale describe /:kernel.astrale.ai:class.Domain
77
+ $ astrale describe @self --no-schema
169
78
  `,
170
- arguments: [{ name: 'path', description: 'Node path (/domain/Class) or ID (@nodeId)' }],
79
+ arguments: [{ name: 'target', description: 'Canonical Node Path or @id' }],
171
80
  options: [
172
- {
173
- flags: '--no-schema',
174
- description:
175
- 'Omit the serialized `schema` property (useful for Domain nodes, where it is multi-kB)',
176
- },
81
+ { flags: '--no-schema', description: 'Omit properties whose qualified leaf is schema' },
177
82
  ],
178
- action: async (path, opts) => {
179
- await describeCommand(path as string, opts as DescribeOpts)
83
+ action: async (target, opts) => {
84
+ await describeCommand(target as string, opts as DescribeOpts)
180
85
  },
181
86
  } satisfies CommandDefinition