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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/README.md +23 -12
  2. package/dist/astrale.js +48048 -56798
  3. package/dist/public/connect-core.js +2011 -30765
  4. package/dist/public/keys/index.js +884 -29483
  5. package/dist/public/paths/index.js +13101 -41459
  6. package/dist/types/admin/binding.d.ts +19 -0
  7. package/dist/types/admin/instance/client.d.ts +22 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +5 -12
  10. package/dist/types/connection/auth.d.ts +3 -0
  11. package/dist/types/connection/call.d.ts +3 -0
  12. package/dist/types/connection/command.d.ts +27 -0
  13. package/dist/types/connection/credential.d.ts +14 -0
  14. package/dist/types/connection/errors.d.ts +1 -0
  15. package/dist/types/connection/exchange.d.ts +9 -0
  16. package/dist/types/connection/failure/classify.d.ts +2 -0
  17. package/dist/types/connection/failure/index.d.ts +5 -0
  18. package/dist/types/connection/failure/model.d.ts +25 -0
  19. package/dist/types/connection/failure/render.d.ts +3 -0
  20. package/dist/types/connection/index.d.ts +8 -0
  21. package/dist/types/connection/reasons.d.ts +37 -0
  22. package/dist/types/connection/self.d.ts +37 -0
  23. package/dist/types/connection/session.d.ts +31 -0
  24. package/dist/types/connection/target.d.ts +38 -0
  25. package/dist/types/errors.d.ts +1 -1
  26. package/dist/types/lib/admin-instance.d.ts +17 -0
  27. package/dist/types/lib/admin-target.d.ts +11 -36
  28. package/dist/types/lib/config.d.ts +7 -59
  29. package/dist/types/lib/failure-debug.d.ts +1 -0
  30. package/dist/types/lib/idp.d.ts +26 -168
  31. package/dist/types/lib/instance-target.d.ts +1 -1
  32. package/dist/types/lib/instance.d.ts +30 -88
  33. package/dist/types/lib/log.d.ts +5 -3
  34. package/dist/types/lib/meta.d.ts +2 -2
  35. package/dist/types/lib/proc.d.ts +43 -0
  36. package/dist/types/lib/self.d.ts +9 -0
  37. package/dist/types/lib/update.d.ts +91 -0
  38. package/dist/types/lib/validation.d.ts +4 -1
  39. package/package.json +16 -19
  40. package/src/__tests__/fixtures/publication.ts +20 -0
  41. package/src/admin/__tests__/binding.test.ts +31 -0
  42. package/src/admin/__tests__/fixture.ts +101 -0
  43. package/src/admin/binding.ts +98 -0
  44. package/src/admin/catalog/.spec/api.d.ts +2 -2
  45. package/src/admin/catalog/__tests__/client.test.ts +20 -49
  46. package/src/admin/catalog/client.ts +36 -32
  47. package/src/admin/catalog/model.ts +3 -4
  48. package/src/admin/graph/.spec/api.d.ts +4 -10
  49. package/src/admin/graph/nodes.ts +1 -1
  50. package/src/admin/instance/.spec/api.d.ts +2 -2
  51. package/src/admin/instance/__tests__/client.test.ts +39 -164
  52. package/src/admin/instance/client.ts +35 -124
  53. package/src/admin/instance/index.ts +1 -2
  54. package/src/admin/instance/model.ts +11 -20
  55. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  56. package/src/commands/__tests__/auth-login.test.ts +54 -1
  57. package/src/commands/__tests__/call-describe.test.ts +46 -33
  58. package/src/commands/__tests__/call.test.ts +5 -1
  59. package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
  60. package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
  61. package/src/commands/__tests__/domain-list.test.ts +63 -4
  62. package/src/commands/__tests__/install-identity-override.test.ts +19 -19
  63. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  64. package/src/commands/__tests__/instance-status.test.ts +139 -0
  65. package/src/commands/__tests__/read-commands.test.ts +35 -10
  66. package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
  67. package/src/commands/__tests__/update.test.ts +48 -19
  68. package/src/commands/call-describe.ts +60 -68
  69. package/src/commands/call.ts +43 -56
  70. package/src/commands/domain/install.ts +13 -17
  71. package/src/commands/domain/list.ts +18 -13
  72. package/src/commands/domain/publish.ts +14 -11
  73. package/src/commands/domain/uninstall.ts +2 -2
  74. package/src/commands/get.ts +14 -15
  75. package/src/commands/identity/__tests__/register.test.ts +3 -3
  76. package/src/commands/identity/register.ts +5 -4
  77. package/src/commands/instance/create.ts +8 -16
  78. package/src/commands/instance/delete.ts +12 -9
  79. package/src/commands/instance/list.ts +2 -2
  80. package/src/commands/instance/status.ts +66 -20
  81. package/src/commands/instance/use.ts +16 -12
  82. package/src/commands/introspect.ts +9 -16
  83. package/src/commands/logs.ts +24 -25
  84. package/src/commands/mutate.ts +6 -5
  85. package/src/commands/query.ts +27 -30
  86. package/src/commands/studio.ts +20 -0
  87. package/src/commands/token.ts +8 -7
  88. package/src/commands/update.ts +38 -14
  89. package/src/commands/view.ts +7 -6
  90. package/src/connection/.spec/api.d.ts +7 -8
  91. package/src/connection/.spec/architecture.md +5 -4
  92. package/src/connection/.spec/flows/session.ts +2 -2
  93. package/src/connection/.spec/laws/connection.ts +6 -2
  94. package/src/connection/.spec/layout.ts +1 -0
  95. package/src/connection/__tests__/credential.test.ts +20 -1
  96. package/src/connection/__tests__/errors.test.ts +43 -32
  97. package/src/connection/__tests__/exchange.test.ts +36 -6
  98. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  99. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  100. package/src/connection/__tests__/self.test.ts +31 -11
  101. package/src/connection/__tests__/session.test.ts +3 -3
  102. package/src/connection/__tests__/target.test.ts +1 -0
  103. package/src/connection/auth.ts +13 -0
  104. package/src/connection/call.ts +1 -1
  105. package/src/connection/credential.ts +2 -2
  106. package/src/connection/errors.ts +1 -355
  107. package/src/connection/exchange.ts +52 -27
  108. package/src/connection/failure/classify.ts +110 -0
  109. package/src/connection/failure/index.ts +18 -0
  110. package/src/connection/failure/model.ts +28 -0
  111. package/src/connection/failure/render.ts +116 -0
  112. package/src/connection/reasons.ts +16 -0
  113. package/src/connection/self.ts +39 -21
  114. package/src/connection/session.ts +19 -8
  115. package/src/errors.ts +3 -2
  116. package/src/graph/.spec/api.d.ts +12 -5
  117. package/src/graph/.spec/layout.ts +9 -1
  118. package/src/graph/__tests__/mutation.test.ts +2 -2
  119. package/src/graph/__tests__/query.test.ts +25 -6
  120. package/src/graph/class.ts +30 -0
  121. package/src/graph/index.ts +1 -0
  122. package/src/graph/query.ts +21 -32
  123. package/src/identity/.spec/api.d.ts +2 -2
  124. package/src/identity/__tests__/registration.test.ts +1 -1
  125. package/src/identity/registration.ts +3 -3
  126. package/src/keys/__tests__/keys.test.ts +4 -0
  127. package/src/keys/credential.ts +1 -0
  128. package/src/lib/__tests__/admin-target.test.ts +12 -0
  129. package/src/lib/__tests__/command-dx.test.ts +1 -1
  130. package/src/lib/__tests__/domain-publication.test.ts +138 -0
  131. package/src/lib/__tests__/idp-session.test.ts +22 -0
  132. package/src/lib/__tests__/idp.test.ts +36 -4
  133. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  134. package/src/lib/__tests__/instance-target.test.ts +7 -39
  135. package/src/lib/__tests__/instance.test.ts +6 -0
  136. package/src/lib/__tests__/log-errors.test.ts +64 -0
  137. package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
  138. package/src/lib/__tests__/update.test.ts +113 -8
  139. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  140. package/src/lib/__tests__/view-server.test.ts +18 -3
  141. package/src/lib/__tests__/view-session.test.ts +1 -1
  142. package/src/lib/admin-instance.ts +14 -8
  143. package/src/lib/admin-target.ts +21 -2
  144. package/src/lib/command-dx.ts +9 -9
  145. package/src/lib/domain-publication.ts +104 -0
  146. package/src/lib/failure-debug.ts +26 -0
  147. package/src/lib/idp.ts +39 -4
  148. package/src/lib/instance-candidates.ts +2 -2
  149. package/src/lib/instance-target.ts +3 -14
  150. package/src/lib/instance.ts +22 -12
  151. package/src/lib/log.ts +16 -9
  152. package/src/lib/login-flow.ts +13 -3
  153. package/src/lib/meta.ts +2 -2
  154. package/src/lib/provision-instance.ts +34 -57
  155. package/src/lib/update.ts +124 -30
  156. package/src/lib/validation.ts +2 -2
  157. package/src/lib/view/resolve.ts +1 -1
  158. package/src/lib/view/server.ts +17 -3
  159. package/src/program/__tests__/program.test.ts +20 -4
  160. package/src/program/build.ts +2 -2
  161. package/src/setup/__tests__/instance-step.test.ts +27 -10
  162. package/src/setup/steps/instance.ts +22 -15
  163. package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
  164. package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
  165. package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
  166. package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  167. package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
  168. package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
  169. package/studio/client/dist/index.html +3 -2
  170. package/studio/package.json +10 -14
  171. package/studio/server/agent/ask.test.ts +1 -1
  172. package/studio/server/agent/bridge/grant.test.ts +1 -1
  173. package/studio/server/agent/bridge/routes.test.ts +1 -1
  174. package/studio/server/agent/bridge/stdio.ts +8 -1
  175. package/studio/server/agent/conversation.test.ts +10 -5
  176. package/studio/server/agent/conversation.ts +56 -8
  177. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  178. package/studio/server/agent/harness/codex/loadout.ts +18 -21
  179. package/studio/server/agent/harness/gateway/config.ts +20 -18
  180. package/studio/server/agent/harness/selection.ts +9 -1
  181. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  182. package/studio/server/agent/prompts/anchors.ts +20 -49
  183. package/studio/server/agent/prompts/system.test.ts +3 -2
  184. package/studio/server/agent/prompts/system.ts +6 -5
  185. package/studio/server/agent/prompts/turn.ts +13 -4
  186. package/studio/server/agent/routes.test.ts +1 -1
  187. package/studio/server/agent/run/completion.ts +2 -2
  188. package/studio/server/agent/run/coordinator.test.ts +1 -1
  189. package/studio/server/agent/run/preparation.ts +6 -5
  190. package/studio/server/agent/run/transcript.test.ts +35 -1
  191. package/studio/server/agent/run/transcript.ts +169 -3
  192. package/studio/server/agent/run/usage.test.ts +24 -0
  193. package/studio/server/agent/run/usage.ts +26 -1
  194. package/studio/server/api/canvas.ts +43 -0
  195. package/studio/server/api/comments.ts +85 -0
  196. package/studio/server/api/context.ts +61 -0
  197. package/studio/server/api/deployment.ts +39 -0
  198. package/studio/server/api/documents.ts +55 -0
  199. package/studio/server/api/domain.ts +59 -0
  200. package/studio/server/api/http.ts +45 -0
  201. package/studio/server/api/project.ts +57 -0
  202. package/studio/server/api/schema.ts +12 -0
  203. package/studio/server/api/views.ts +57 -0
  204. package/studio/server/api/workspace.ts +60 -0
  205. package/studio/server/api-agent-loadout.test.ts +1 -1
  206. package/studio/server/api.test.ts +147 -0
  207. package/studio/server/api.ts +20 -422
  208. package/studio/server/cache.test.ts +122 -0
  209. package/studio/server/cache.ts +162 -11
  210. package/studio/server/cli-consumers.test.ts +494 -0
  211. package/studio/server/cli.test.ts +88 -0
  212. package/studio/server/cli.ts +240 -0
  213. package/studio/server/client-package.ts +25 -1
  214. package/studio/server/domain.test.ts +50 -40
  215. package/studio/server/domain.ts +83 -52
  216. package/studio/server/environment/dotenv-preview.test.ts +39 -0
  217. package/studio/server/environment/dotenv-preview.ts +27 -0
  218. package/studio/server/environment/files.test.ts +53 -0
  219. package/studio/server/{state/env.ts → environment/files.ts} +7 -48
  220. package/studio/server/{state → handoff}/copy.ts +21 -6
  221. package/studio/server/handoff/service.test.ts +22 -0
  222. package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
  223. package/studio/server/index.ts +1 -1
  224. package/studio/server/instances/active.ts +72 -0
  225. package/studio/server/instances/deploy-record.test.ts +31 -0
  226. package/studio/server/instances/deploy-record.ts +37 -0
  227. package/studio/server/instances/deploy.ts +56 -0
  228. package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
  229. package/studio/server/instances/probe.ts +67 -0
  230. package/studio/server/instances/status.test.ts +12 -0
  231. package/studio/server/instances/status.ts +49 -0
  232. package/studio/server/introspect/anatomy/client-tree.ts +57 -0
  233. package/studio/server/introspect/anatomy/env-fields.ts +66 -0
  234. package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
  235. package/studio/server/introspect/anatomy/source.ts +181 -0
  236. package/studio/server/introspect/anatomy/views/routes.ts +114 -0
  237. package/studio/server/introspect/anatomy/views.ts +53 -0
  238. package/studio/server/introspect/anatomy-extras.test.ts +106 -35
  239. package/studio/server/introspect/anatomy-extras.ts +7 -726
  240. package/studio/server/introspect/anatomy.test.ts +22 -14
  241. package/studio/server/introspect/anatomy.ts +52 -28
  242. package/studio/server/introspect/bundle.ts +15 -9
  243. package/studio/server/introspect/canonical-schema.test.ts +93 -309
  244. package/studio/server/introspect/canonical-schema.ts +257 -425
  245. package/studio/server/introspect/config-preview.test.ts +32 -0
  246. package/studio/server/introspect/config-preview.ts +119 -0
  247. package/studio/server/introspect/core-extractor.ts +18 -127
  248. package/studio/server/introspect/core.ts +1 -2
  249. package/studio/server/introspect/diff.test.ts +18 -18
  250. package/studio/server/introspect/diff.ts +44 -90
  251. package/studio/server/introspect/extractor.ts +23 -116
  252. package/studio/server/introspect/hash.ts +5 -2
  253. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  254. package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
  255. package/studio/server/introspect/overlay.test.ts +26 -54
  256. package/studio/server/introspect/overlay.ts +10 -37
  257. package/studio/server/introspect/revision.test.ts +54 -0
  258. package/studio/server/introspect/revision.ts +49 -0
  259. package/studio/server/introspect/runtime.test.ts +83 -143
  260. package/studio/server/introspect/runtime.ts +40 -11
  261. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  262. package/studio/server/introspect/schema-ir-json.ts +151 -0
  263. package/studio/server/introspect/schema-refs.test.ts +43 -88
  264. package/studio/server/introspect/schema-refs.ts +14 -49
  265. package/studio/server/introspect/source-overlay/annotations.ts +14 -0
  266. package/studio/server/introspect/source-overlay/handlers.ts +161 -0
  267. package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
  268. package/studio/server/introspect/source-overlay/project.ts +248 -0
  269. package/studio/server/introspect/source-overlay/spans.ts +330 -0
  270. package/studio/server/json.ts +46 -0
  271. package/studio/server/lifecycle.ts +5 -1
  272. package/studio/server/sse.test.ts +26 -0
  273. package/studio/server/sse.ts +4 -1
  274. package/studio/server/state/baseline.test.ts +223 -7
  275. package/studio/server/state/baseline.ts +148 -34
  276. package/studio/server/state/comments.test.ts +66 -1
  277. package/studio/server/state/comments.ts +173 -10
  278. package/studio/server/state/context.ts +34 -2
  279. package/studio/server/state/documents.ts +42 -1
  280. package/studio/server/state/integrations.ts +27 -1
  281. package/studio/server/state/layout.test.ts +34 -0
  282. package/studio/server/state/layout.ts +44 -17
  283. package/studio/server/state/settings.ts +29 -22
  284. package/studio/server/state/store.test.ts +122 -0
  285. package/studio/server/state/store.ts +66 -17
  286. package/studio/server/state/visibility.ts +22 -11
  287. package/studio/server/views/model.test.ts +57 -0
  288. package/studio/server/views/model.ts +66 -0
  289. package/studio/server/views/runtime.ts +40 -0
  290. package/studio/server/views/selection-repository.test.ts +31 -0
  291. package/studio/server/views/selection-repository.ts +60 -0
  292. package/studio/server/views/session.test.ts +73 -0
  293. package/studio/server/views/session.ts +166 -0
  294. package/studio/server/views/target.test.ts +78 -0
  295. package/studio/server/views/target.ts +222 -0
  296. package/studio/server/watch.test.ts +11 -11
  297. package/studio/server/watch.ts +9 -5
  298. package/studio/server/workspace/catalog.test.ts +17 -0
  299. package/studio/server/workspace/catalog.ts +43 -0
  300. package/studio/server/{state → workspace}/create.test.ts +1 -1
  301. package/studio/server/{state → workspace}/create.ts +1 -1
  302. package/studio/server/{state → workspace}/git.ts +1 -1
  303. package/studio/server/workspace/updates.ts +83 -0
  304. package/studio/server/workspace-state.ts +1 -1
  305. package/studio/server/workspace-watch.ts +2 -2
  306. package/studio/shared/contracts/README.md +16 -0
  307. package/studio/shared/contracts/agent.ts +270 -0
  308. package/studio/shared/contracts/runtime.ts +50 -0
  309. package/studio/shared/contracts/schema.ts +393 -0
  310. package/studio/shared/contracts/surface.test.ts +317 -0
  311. package/studio/shared/contracts/workspace.ts +265 -0
  312. package/studio/shared/layout.test.ts +116 -0
  313. package/studio/shared/schema/identity.test.ts +34 -0
  314. package/studio/shared/schema/identity.ts +68 -0
  315. package/studio/shared/types.ts +11 -1099
  316. package/studio/tsconfig.json +1 -1
  317. package/viewer/dist/main.js +40 -61
  318. package/.check-workspace.cjs +0 -40
  319. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  320. package/studio/client/dist/assets/elk-api-D2xgMJvi.js +0 -1
  321. package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
  322. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  323. package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
  324. package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
  325. package/studio/server/state/catalog.ts +0 -117
  326. package/studio/server/state/instance.ts +0 -280
  327. package/studio/server/state/updates.ts +0 -63
  328. package/studio/server/state/views.test.ts +0 -286
  329. package/studio/server/state/views.ts +0 -535
@@ -36,6 +36,8 @@ let mutations: unknown[] = []
36
36
  let queryResult: unknown
37
37
  let getResult: unknown
38
38
  let mutationResult: unknown
39
+ let selfFailure: unknown
40
+ let selfContexts: unknown[] = []
39
41
 
40
42
  const queryMock = mock(async (ast: unknown, options?: unknown) => {
41
43
  queryCalls.push({ ast, options })
@@ -49,7 +51,9 @@ const mutateMock = mock(async (mutation: unknown) => {
49
51
  mutations.push(mutation)
50
52
  return mutationResult
51
53
  })
52
- const expandSelfInPathMock = mock(async (path: string) => {
54
+ const expandSelfInPathMock = mock(async (path: string, context: unknown) => {
55
+ selfContexts.push(context)
56
+ if (selfFailure !== undefined) throw selfFailure
53
57
  if (path === '@self') {
54
58
  return {
55
59
  path: '@expanded-self',
@@ -59,10 +63,11 @@ const expandSelfInPathMock = mock(async (path: string) => {
59
63
  return { path, meta: undefined }
60
64
  })
61
65
  const withSelfHintMock = mock(async (action: () => Promise<unknown>) => action())
66
+ const commandContext = {
67
+ graph: { query: queryMock, getOrThrow: getOrThrowMock, mutate: mutateMock },
68
+ }
62
69
  const runKernelCommandMock = mock(async (run: RunOpts) => {
63
- const result = await run.fn({
64
- graph: { query: queryMock, getOrThrow: getOrThrowMock, mutate: mutateMock },
65
- })
70
+ const result = await run.fn(commandContext)
66
71
  await run.format?.(result, run.opts, true)
67
72
  })
68
73
 
@@ -88,6 +93,8 @@ beforeEach(() => {
88
93
  }
89
94
  getResult = undefined
90
95
  mutationResult = { createdNodes: {} }
96
+ selfFailure = undefined
97
+ selfContexts = []
91
98
  queryMock.mockClear()
92
99
  getOrThrowMock.mockClear()
93
100
  mutateMock.mockClear()
@@ -161,7 +168,7 @@ describe('query command', () => {
161
168
  ])
162
169
  })
163
170
 
164
- test('authors a Definition source through the same canonical Query V6 call', async () => {
171
+ test('authors a Class source through the same canonical Query V6 call', async () => {
165
172
  const { queryCommand } = await import('../query')
166
173
 
167
174
  await queryCommand([], {
@@ -179,8 +186,8 @@ describe('query command', () => {
179
186
  kind: 'node',
180
187
  terms: [
181
188
  {
182
- kind: 'definition',
183
- definition: { origin: 'issues.astrale.ai', kind: 'class', name: 'Issue' },
189
+ kind: 'class',
190
+ class: { origin: 'issues.astrale.ai', kind: 'class', name: 'Issue' },
184
191
  },
185
192
  ],
186
193
  binding: 'n0',
@@ -193,6 +200,17 @@ describe('query command', () => {
193
200
  ])
194
201
  })
195
202
 
203
+ test('resolves @self inside the command session and never relabels transport failure as input', async () => {
204
+ const { queryCommand } = await import('../query')
205
+ await queryCommand(['@self'], { json: true, limit: '2' })
206
+ expect(selfContexts).toEqual([commandContext])
207
+
208
+ const aggregate = new AggregateError([], '')
209
+ selfFailure = aggregate
210
+ await expect(queryCommand(['@self'], { json: true, limit: '2' })).rejects.toBe(aggregate)
211
+ expect(errors.join('\n')).not.toContain('INVALID_INPUT')
212
+ })
213
+
196
214
  /** @evidence TEST-CLI-QUERY-REJECTS-V1-BEFORE-CONNECTION */
197
215
  test('rejects a legacy AST before opening the command connection', async () => {
198
216
  const { queryCommand } = await import('../query')
@@ -215,7 +233,7 @@ describe('get command', () => {
215
233
  const { getCommand } = await import('../get')
216
234
  getResult = {
217
235
  id: 'note-1',
218
- class: '/:notes.example.dev:class.Note',
236
+ class: 'notes.example.dev:class.Note',
219
237
  props: { 'notes.example.dev:class.Note.property.title': 'Hello' },
220
238
  }
221
239
 
@@ -226,6 +244,13 @@ describe('get command', () => {
226
244
  expect(stdout).not.toContain('__labels')
227
245
  expect(stdout).not.toContain('classId')
228
246
  })
247
+
248
+ test('resolves @self through the same point-read command context', async () => {
249
+ const { getCommand } = await import('../get')
250
+ await getCommand('@self', { json: true })
251
+ expect(selfContexts).toEqual([commandContext])
252
+ expect(getTargets).toEqual(['@expanded-self'])
253
+ })
229
254
  })
230
255
 
231
256
  describe('mutate command', () => {
@@ -242,7 +267,7 @@ describe('mutate command', () => {
242
267
  {
243
268
  op: 'node.create',
244
269
  as: 'note',
245
- class: '/:notes.example.dev:class.Note',
270
+ class: 'notes.example.dev:class.Note',
246
271
  props: {},
247
272
  },
248
273
  ],
@@ -258,7 +283,7 @@ describe('mutate command', () => {
258
283
  {
259
284
  op: 'node.create',
260
285
  as: 'note',
261
- class: '/:notes.example.dev:class.Note',
286
+ class: 'notes.example.dev:class.Note',
262
287
  props: {},
263
288
  },
264
289
  ],
@@ -0,0 +1,22 @@
1
+ import { expect, test } from 'bun:test'
2
+ import { realpathSync } from 'node:fs'
3
+
4
+ import { encodeStudioCliDescriptor } from '../studio'
5
+
6
+ test('Studio descriptor preserves the exact runtime and script entrypoint', () => {
7
+ expect(JSON.parse(encodeStudioCliDescriptor(process.execPath, import.meta.path))).toEqual({
8
+ version: 1,
9
+ executable: process.execPath,
10
+ args: [realpathSync(import.meta.path)],
11
+ })
12
+ })
13
+
14
+ test('Studio descriptor reinvokes a compiled executable without its virtual bunfs entry', () => {
15
+ expect(JSON.parse(encodeStudioCliDescriptor('/opt/bin/astrale', '/$bunfs/root/astrale'))).toEqual(
16
+ {
17
+ version: 1,
18
+ executable: '/opt/bin/astrale',
19
+ args: [],
20
+ },
21
+ )
22
+ })
@@ -6,14 +6,17 @@ describe('CLI update staleness', () => {
6
6
  test('trusts the release manifest for a script install without consulting npm latest', async () => {
7
7
  const fetchPackageVersion = mock(async () => '0.8.1-alpha.7')
8
8
  const result = await cliStale(
9
- { channel: 'beta' },
9
+ {},
10
10
  {
11
- update: async () => ({
12
- status: 'up-to-date',
13
- currentVersion: '1.0.0-beta.0',
14
- latestVersion: '1.0.0-beta.0',
15
- channel: 'beta',
16
- }),
11
+ update: async ({ channel }) => {
12
+ expect(channel).toBe('beta')
13
+ return {
14
+ status: 'up-to-date',
15
+ currentVersion: '1.0.0-beta.0',
16
+ latestVersion: '1.0.0-beta.0',
17
+ channel: 'beta',
18
+ }
19
+ },
17
20
  fetchPackageVersion,
18
21
  },
19
22
  )
@@ -28,37 +31,63 @@ describe('CLI update staleness', () => {
28
31
  expect(fetchPackageVersion).not.toHaveBeenCalled()
29
32
  })
30
33
 
31
- test('uses the selected npm dist-tag only for package-managed installs', async () => {
34
+ test('uses an explicit npm dist-tag only for package-managed installs', async () => {
32
35
  const result = await cliStale(
33
- { channel: 'beta' },
36
+ { channel: 'canary' },
34
37
  {
35
- update: async () => {
36
- throw new Error('package managed')
37
- },
38
+ update: async () => ({
39
+ status: 'managed',
40
+ currentVersion: '1.0.0-beta.0',
41
+ executable: '/opt/homebrew/bin/node',
42
+ }),
38
43
  fetchPackageVersion: async ({ channel }) => {
39
- expect(channel).toBe('beta')
40
- return '1.0.0-beta.0'
44
+ expect(channel).toBe('canary')
45
+ return '1.0.0-canary.0'
41
46
  },
42
47
  },
43
48
  )
44
49
 
45
50
  expect(result).toMatchObject({
46
51
  managed: true,
47
- latest: '1.0.0-beta.0',
52
+ latest: '1.0.0-canary.0',
48
53
  channel: 'npm',
49
54
  })
50
55
  })
51
56
 
52
- test('maps the stable channel to the npm latest dist-tag', async () => {
57
+ test('does not misclassify a script update failure as package-managed', async () => {
58
+ const fetchPackageVersion = mock(async () => '9.9.9')
59
+ const result = await cliStale(
60
+ {},
61
+ {
62
+ update: async () => {
63
+ throw new Error('release endpoint unavailable')
64
+ },
65
+ fetchPackageVersion,
66
+ },
67
+ )
68
+
69
+ expect(result).toMatchObject({
70
+ stale: false,
71
+ managed: false,
72
+ error: 'release endpoint unavailable',
73
+ })
74
+ expect(fetchPackageVersion).not.toHaveBeenCalled()
75
+ })
76
+
77
+ test('maps the default to beta and the stable channel to npm latest', async () => {
53
78
  const originalFetch = globalThis.fetch
54
79
  const fetchMock = mock(async (input: RequestInfo | URL) => {
55
- expect(String(input)).toBe('https://registry.npmjs.org/@astrale-os/cli/latest')
56
- return Response.json({ version: '1.0.0' })
80
+ const target = String(input).split('/').at(-1)
81
+ return Response.json({ version: target === 'beta' ? '1.0.0-beta.0' : '1.0.0' })
57
82
  })
58
83
  globalThis.fetch = fetchMock as unknown as typeof fetch
59
84
  try {
85
+ expect(await fetchNpmTargetVersion({})).toBe('1.0.0-beta.0')
60
86
  expect(await fetchNpmTargetVersion({ channel: 'stable' })).toBe('1.0.0')
61
- expect(fetchMock).toHaveBeenCalledTimes(1)
87
+ expect(fetchMock.mock.calls.map(([input]) => String(input))).toEqual([
88
+ 'https://registry.npmjs.org/@astrale-os/cli/beta',
89
+ 'https://registry.npmjs.org/@astrale-os/cli/latest',
90
+ ])
62
91
  } finally {
63
92
  globalThis.fetch = originalFetch
64
93
  }
@@ -1,8 +1,9 @@
1
1
  import type { Path } from '@astrale-os/sdk/graph/path'
2
+ import type { ResolvedFunction, ResolvedMethod } from '@astrale-os/sdk/schema'
2
3
 
3
- import { AstraleError } from '../errors'
4
+ import { bundle, schema } from '@astrale-os/sdk/schema'
4
5
 
5
- type JsonRecord = Record<string, unknown>
6
+ import { AstraleError } from '../errors'
6
7
 
7
8
  export interface CallableDescription {
8
9
  readonly path: string
@@ -18,40 +19,40 @@ export interface CallableDescription {
18
19
  readonly candidates?: readonly CallableDescription[]
19
20
  }
20
21
 
21
- /** Resolve one callable's input/output from an installed Domain schema document. */
22
- export function describeCallableFromSchema(
22
+ /** Resolve one callable from an admitted installed Domain bundle. */
23
+ export function describeCallableFromBundle(
23
24
  path: Path,
24
- schema: unknown,
25
+ input: unknown,
25
26
  ): CallableDescription | undefined {
26
27
  if (path.ast.anchor.kind !== 'domain') return undefined
27
28
  const origin = path.ast.anchor.origin
28
29
  const last = path.ast.steps.at(-1)
29
- const document = asRecord(schema)
30
- if (document === undefined || last === undefined) return undefined
30
+ if (last === undefined) return undefined
31
+ const domain = schema.resolve(bundle.accept(input).root)
32
+ if (domain.origin !== origin) return undefined
31
33
 
32
34
  if (last.kind === 'method') {
33
- const owner = path.ast.steps.at(-2)
34
- if (
35
- owner?.kind === 'projection' &&
36
- (owner.projection.kind === 'class' || owner.projection.kind === 'interface')
37
- ) {
38
- const bag = asRecord(
39
- owner.projection.kind === 'class' ? document.classes : document.interfaces,
35
+ const ownerStep = path.ast.steps.at(-2)
36
+ if (ownerStep?.kind === 'projection' && ownerStep.projection.kind === 'class') {
37
+ const owner = domain.classes[ownerStep.projection.name]
38
+ if (owner?.kind !== 'node') return undefined
39
+ const method = namedMethod(
40
+ last.dispatch === 'static' ? owner.static.methods : owner.methods,
41
+ last.name,
42
+ last.dispatch,
40
43
  )
41
- const definition = asRecord(bag?.[owner.projection.name])
42
- const method = asRecord(asRecord(definition?.methods)?.[last.name])
43
- if (method !== undefined) {
44
- return Object.freeze({
45
- path: path.raw,
46
- origin,
47
- class: owner.projection.name,
48
- method: last.name,
49
- dispatch: last.dispatch,
50
- ...callableFields(method),
51
- })
52
- }
44
+ return method === undefined
45
+ ? undefined
46
+ : description(path, origin, owner.ref.name, method, last.dispatch)
53
47
  }
54
- const matches = findNamedMethods(document, origin, path.raw, last.name, last.dispatch)
48
+
49
+ const matches = Object.values(domain.classes).flatMap((owner) => {
50
+ if (owner.kind !== 'node') return []
51
+ const method = namedMethod(owner.methods, last.name, last.dispatch)
52
+ return method === undefined
53
+ ? []
54
+ : [description(path, origin, owner.ref.name, method, last.dispatch)]
55
+ })
55
56
  if (matches.length === 1) return matches[0]
56
57
  if (matches.length > 1) {
57
58
  return Object.freeze({
@@ -66,13 +67,13 @@ export function describeCallableFromSchema(
66
67
  }
67
68
 
68
69
  if (last.kind === 'projection' && last.projection.kind === 'function') {
69
- const fn = asRecord(asRecord(document.functions)?.[last.projection.name])
70
- if (fn === undefined) return undefined
70
+ const callable = domain.functions[last.projection.name]
71
+ if (callable === undefined) return undefined
71
72
  return Object.freeze({
72
73
  path: path.raw,
73
74
  origin,
74
- function: last.projection.name,
75
- ...callableFields(fn),
75
+ function: callable.ref.name,
76
+ ...callableFields(callable),
76
77
  })
77
78
  }
78
79
  return undefined
@@ -82,50 +83,41 @@ export function missingCallableDescription(path: string): AstraleError {
82
83
  return new AstraleError(
83
84
  'CALL_DESCRIBE_UNAVAILABLE',
84
85
  `No callable schema is installed for ${path}.`,
85
- 'Use a Domain-rooted Path such as /:host.astrale.ai:class.Manager:createInstance. Method Paths are not Function nodes.',
86
+ 'Use a Domain-rooted Path such as /:kernel.astrale.ai:class.Identity:whois. Method Paths are not Function nodes.',
86
87
  )
87
88
  }
88
89
 
89
- function findNamedMethods(
90
- schema: JsonRecord,
90
+ function namedMethod(
91
+ methods: Iterable<ResolvedMethod>,
92
+ name: string,
93
+ dispatch: 'static' | 'instance',
94
+ ): ResolvedMethod | undefined {
95
+ const expectedStatic = dispatch === 'static'
96
+ return [...methods].find((method) => method.name === name && method.static === expectedStatic)
97
+ }
98
+
99
+ function description(
100
+ path: Path,
91
101
  origin: string,
92
- path: string,
93
- method: string,
102
+ className: string,
103
+ callable: ResolvedMethod,
94
104
  dispatch: 'static' | 'instance',
95
- ): CallableDescription[] {
96
- const matches: CallableDescription[] = []
97
- for (const bag of [schema.classes, schema.interfaces]) {
98
- const definitions = asRecord(bag)
99
- if (definitions === undefined) continue
100
- for (const [className, definition] of Object.entries(definitions)) {
101
- const methodDef = asRecord(asRecord(asRecord(definition)?.methods)?.[method])
102
- if (methodDef === undefined) continue
103
- matches.push(
104
- Object.freeze({
105
- path,
106
- origin,
107
- class: className,
108
- method,
109
- dispatch,
110
- ...callableFields(methodDef),
111
- }),
112
- )
113
- }
114
- }
115
- return matches
105
+ ): CallableDescription {
106
+ return Object.freeze({
107
+ path: path.raw,
108
+ origin,
109
+ class: className,
110
+ method: callable.name,
111
+ dispatch,
112
+ ...callableFields(callable),
113
+ })
116
114
  }
117
115
 
118
- function callableFields(value: JsonRecord): Partial<CallableDescription> {
116
+ function callableFields(callable: ResolvedFunction | ResolvedMethod): Partial<CallableDescription> {
119
117
  return {
120
- ...(typeof value.description === 'string' ? { description: value.description } : {}),
121
- ...(value.auth === undefined ? {} : { auth: value.auth }),
122
- ...(value.input === undefined ? {} : { input: value.input }),
123
- ...(value.output === undefined ? {} : { output: value.output }),
118
+ ...(callable.description === undefined ? {} : { description: callable.description }),
119
+ auth: callable.auth,
120
+ input: callable.input,
121
+ output: callable.output,
124
122
  }
125
123
  }
126
-
127
- function asRecord(input: unknown): JsonRecord | undefined {
128
- return input !== null && typeof input === 'object' && !Array.isArray(input)
129
- ? (input as JsonRecord)
130
- : undefined
131
- }
@@ -5,7 +5,7 @@ import type { CommandDefinition } from '../program/index'
5
5
 
6
6
  import { createPathCall, expandSelfInCall, runKernelCommand, withSelfHint } from '../connection'
7
7
  import { presentBinary } from '../lib/binary'
8
- import { failClosed, log } from '../lib/log'
8
+ import { failInput, log } from '../lib/log'
9
9
  import { output, present } from '../lib/output'
10
10
 
11
11
  type CallOpts = KernelCommandOpts & {
@@ -24,60 +24,47 @@ export async function callCommand(
24
24
  rawParams: string[],
25
25
  opts: CallOpts,
26
26
  ): 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
27
  let params: Record<string, unknown>
43
28
  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
29
+ Path.parse(path)
30
+ params = await parseParams(rawParams, opts.data)
31
+ } catch (error) {
32
+ failInput(error, opts)
53
33
  }
54
34
 
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
- }
35
+ await runKernelCommand<MaterializedCallResult | { readonly kind: 'dry'; readonly call: unknown }>(
36
+ {
37
+ opts,
38
+ label: path,
39
+ fn: async (ctx) => {
40
+ const expanded = await expandSelfInCall(path, params, ctx)
41
+ const request = createPathCall(expanded.path, expanded.parameters)
42
+ if (opts.dryRun) return { kind: 'dry', call: request }
43
+ return withSelfHint(
44
+ async () => materializeCallResult(await ctx.session.dispatch(request)),
45
+ expanded.meta,
46
+ )
47
+ },
48
+ format: async (result, fmtOpts) => {
49
+ switch (result.kind) {
50
+ case 'dry':
51
+ output(result.call, fmtOpts)
52
+ return
53
+ case 'value':
54
+ present(result.value, fmtOpts)
55
+ return
56
+ case 'binary':
57
+ await presentBinary(result.value, fmtOpts, { outFile: opts.output })
58
+ return
59
+ case 'stream':
60
+ output(result.values, fmtOpts)
61
+ return
62
+ case 'redirect':
63
+ throw new Error('Client Session returned an unresolved redirect.')
64
+ }
65
+ },
79
66
  },
80
- })
67
+ )
81
68
  }
82
69
 
83
70
  /** Drain a session-backed stream before the command-scoped Client Session closes. */
@@ -101,7 +88,7 @@ export async function parseParams(
101
88
  try {
102
89
  return JSON.parse(dataFlag)
103
90
  } catch {
104
- throw new Error(`Invalid JSON in --data: ${dataFlag}`)
91
+ throw new TypeError(`Invalid JSON in --data: ${dataFlag}`)
105
92
  }
106
93
  }
107
94
 
@@ -114,7 +101,7 @@ export async function parseParams(
114
101
  try {
115
102
  return JSON.parse(stdin)
116
103
  } catch {
117
- throw new Error('Invalid JSON from stdin')
104
+ throw new TypeError('Invalid JSON from stdin')
118
105
  }
119
106
  }
120
107
 
@@ -142,7 +129,7 @@ export function parseKeyValue(pairs: string[]): Record<string, unknown> {
142
129
  for (const pair of pairs) {
143
130
  const eqIdx = pair.indexOf('=')
144
131
  if (eqIdx === -1) {
145
- throw new Error(`Invalid param "${pair}" — expected key=value format`)
132
+ throw new TypeError(`Invalid param "${pair}" — expected key=value format`)
146
133
  }
147
134
  const key = pair.slice(0, eqIdx)
148
135
  const raw = pair.slice(eqIdx + 1)
@@ -150,7 +137,7 @@ export function parseKeyValue(pairs: string[]): Record<string, unknown> {
150
137
  const hint = key.endsWith(':')
151
138
  ? ` (looks like httpie's "key:=value" syntax — Astrale CLI doesn't support it; use --data '{"${key.slice(0, -1)}":<value>}' for nested values)`
152
139
  : ` (keys must be identifier-shaped: letters, digits, underscore, hyphen)`
153
- throw new Error(`Invalid param key "${key}" in "${pair}"${hint}`)
140
+ throw new TypeError(`Invalid param key "${key}" in "${pair}"${hint}`)
154
141
  }
155
142
  result[key] = coerceValue(raw)
156
143
  }
@@ -194,7 +181,7 @@ Self-reference:
194
181
  Callable input/output lives on astrale introspect <path>.
195
182
 
196
183
  Examples:
197
- $ astrale introspect /:host.astrale.ai:class.Manager:createInstance
184
+ $ astrale introspect /:kernel.astrale.ai:class.Identity:whois
198
185
  $ astrale call /:blog.acme.com:class.Author:list limit=10
199
186
  $ astrale call '@self::deactivate'
200
187
  $ astrale call /:kernel.astrale.ai:function.journal --data '{"limit":5}' --json
@@ -203,7 +190,7 @@ Examples:
203
190
  {
204
191
  name: 'path',
205
192
  description:
206
- 'Operation path (e.g., /:host.astrale.ai:class.Manager:createInstance or /node::method)',
193
+ 'Operation path (e.g., /:kernel.astrale.ai:class.Identity:whois or /node::method)',
207
194
  },
208
195
  { name: 'params...', description: 'Params as key=value pairs', required: false },
209
196
  ],
@@ -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'
@@ -15,6 +15,7 @@ import {
15
15
  } from '../../lib/admin-domain'
16
16
  import { listOwnedInstancesInContext, type OwnedInstanceInfo } from '../../lib/admin-instance'
17
17
  import { ADMIN_TARGET_OPTIONS, type AdminTargetCommandOpts } from '../../lib/admin-target'
18
+ import { fetchDomainPublication } from '../../lib/domain-publication'
18
19
  import { getActive } from '../../lib/instance'
19
20
  import { fatal, log, withSpinner } from '../../lib/log'
20
21
  import { isMachine, output } from '../../lib/output'
@@ -413,7 +414,7 @@ export async function installDirect(
413
414
  fn: async ({ session }) =>
414
415
  (await session.call(
415
416
  createPathCall(
416
- Path.project(syscalls.install.ref).raw,
417
+ Path.project(K.functions.install.ref).raw,
417
418
  directInstallCallInput(url, operation, opts.token),
418
419
  ),
419
420
  )) as DirectInstallResult,
@@ -429,11 +430,11 @@ export async function installDirect(
429
430
  log.dim(` operation: ${result.operation}`)
430
431
  // Belt-and-braces: the kernel-confirmed origin is authoritative. If it
431
432
  // aliases the host and the pre-install gate never consented to THAT
432
- // origin (lying or absent `/meta`), say so loudly after the fact.
433
+ // origin (lying or unavailable Publication), say so loudly after the fact.
433
434
  if (isIdentityOverride(installed.origin, host) && installed.origin !== consentedOrigin) {
434
435
  log.warn(
435
436
  `Installed origin "${installed.origin}" differs from the serving host "${host}" ` +
436
- `and was not confirmed before install (the worker's /meta did not declare it). ` +
437
+ `and was not confirmed before install (the worker Publication was unavailable). ` +
437
438
  `Every ${installed.origin}/* call on this instance now routes to ${host}.`,
438
439
  )
439
440
  }
@@ -478,10 +479,10 @@ export function isIdentityOverride(origin: string, host: string): boolean {
478
479
  * Claiming an origin that differs from the serving host is an explicit actAs
479
480
  * and needs typed consent (or `--allow-identity-override` in scripts).
480
481
  *
481
- * The pre-install check reads the worker's self-reported `/meta.origin`,
482
+ * The pre-install check reads the worker's canonical Publication origin,
482
483
  * so it is consent UX, not enforcement — a hostile worker can lie here, and
483
484
  * the kernel anchors the cryptographic identity (`iss`) on the real URL
484
- * regardless. When `/meta` is unreachable or silent on the origin, the gate
485
+ * regardless. When the Publication is unreachable or invalid, the gate
485
486
  * degrades to a warning and the kernel-confirmed origin is re-checked after
486
487
  * install (see `format` above).
487
488
  *
@@ -496,7 +497,8 @@ async function ensureIdentityOverrideConsent(
496
497
  const origin = await probeDeclaredOrigin(url)
497
498
  if (origin === undefined) {
498
499
  log.warn(
499
- `Could not read a declared origin from ${new URL('/meta', url).href} — ` +
500
+ `Could not read a declared origin from ` +
501
+ `${new URL('/.well-known/astrale/domain.json', url).href} — ` +
500
502
  `skipping the pre-install identity check (the installed origin is verified after install).`,
501
503
  )
502
504
  return undefined
@@ -534,19 +536,13 @@ async function ensureIdentityOverrideConsent(
534
536
  return origin
535
537
  }
536
538
 
537
- /** Best-effort read of the worker's declared origin from its `/meta` probe. */
539
+ /** Best-effort read of the worker's origin from its admitted canonical Publication. */
538
540
  export async function probeDeclaredOrigin(url: string): Promise<string | undefined> {
539
541
  try {
540
- const res = await fetch(new URL('/meta', url), { signal: AbortSignal.timeout(10_000) })
541
- if (!res.ok) return undefined
542
- // SDK workers serve `origin`; `domainName` is the pre-Kernel-V2 name, kept
543
- // as a fallback for workers deployed before the rename.
544
- const body = (await res.json()) as { origin?: unknown; domainName?: unknown }
545
- const declared = body.origin ?? body.domainName
546
- return typeof declared === 'string' && declared.length > 0 ? declared : undefined
542
+ return (await fetchDomainPublication(url, AbortSignal.timeout(10_000))).origin
547
543
  } catch {
548
- // Unreachable /meta is not fatal here: the caller warns and the install
549
- // itself will surface a dead worker with its own error.
544
+ // An unreachable or invalid Publication is not fatal here: the caller warns
545
+ // and the install itself will surface a dead worker with its own error.
550
546
  return undefined
551
547
  }
552
548
  }