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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/README.md +23 -12
  2. package/dist/astrale.js +51471 -56290
  3. package/dist/public/connect-core.js +2028 -26846
  4. package/dist/public/keys/index.js +1755 -40694
  5. package/dist/public/paths/index.js +859 -39518
  6. package/dist/types/admin/binding.d.ts +19 -0
  7. package/dist/types/admin/instance/client.d.ts +22 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +5 -12
  10. package/dist/types/connection/auth.d.ts +3 -0
  11. package/dist/types/connection/call.d.ts +3 -0
  12. package/dist/types/connection/command.d.ts +27 -0
  13. package/dist/types/connection/credential.d.ts +14 -0
  14. package/dist/types/connection/errors.d.ts +1 -0
  15. package/dist/types/connection/exchange.d.ts +9 -0
  16. package/dist/types/connection/failure/classify.d.ts +2 -0
  17. package/dist/types/connection/failure/index.d.ts +5 -0
  18. package/dist/types/connection/failure/model.d.ts +25 -0
  19. package/dist/types/connection/failure/render.d.ts +3 -0
  20. package/dist/types/connection/index.d.ts +8 -0
  21. package/dist/types/connection/reasons.d.ts +37 -0
  22. package/dist/types/connection/self.d.ts +37 -0
  23. package/dist/types/connection/session.d.ts +31 -0
  24. package/dist/types/connection/target.d.ts +38 -0
  25. package/dist/types/errors.d.ts +1 -1
  26. package/dist/types/lib/admin-instance.d.ts +17 -0
  27. package/dist/types/lib/admin-target.d.ts +6 -2
  28. package/dist/types/lib/failure-debug.d.ts +1 -0
  29. package/dist/types/lib/idp.d.ts +7 -0
  30. package/dist/types/lib/instance-target.d.ts +1 -1
  31. package/dist/types/lib/instance.d.ts +10 -2
  32. package/dist/types/lib/log.d.ts +5 -3
  33. package/dist/types/lib/meta.d.ts +2 -2
  34. package/dist/types/lib/proc.d.ts +43 -0
  35. package/dist/types/lib/self.d.ts +9 -0
  36. package/dist/types/lib/update.d.ts +131 -0
  37. package/package.json +8 -10
  38. package/src/__tests__/fixtures/publication.ts +20 -0
  39. package/src/admin/__tests__/binding.test.ts +31 -0
  40. package/src/admin/__tests__/fixture.ts +101 -0
  41. package/src/admin/binding.ts +98 -0
  42. package/src/admin/catalog/.spec/api.d.ts +2 -2
  43. package/src/admin/catalog/__tests__/client.test.ts +20 -49
  44. package/src/admin/catalog/client.ts +36 -32
  45. package/src/admin/catalog/model.ts +3 -4
  46. package/src/admin/graph/.spec/api.d.ts +4 -10
  47. package/src/admin/graph/nodes.ts +1 -1
  48. package/src/admin/instance/.spec/api.d.ts +2 -2
  49. package/src/admin/instance/__tests__/client.test.ts +39 -164
  50. package/src/admin/instance/client.ts +35 -124
  51. package/src/admin/instance/index.ts +1 -2
  52. package/src/admin/instance/model.ts +11 -20
  53. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  54. package/src/commands/__tests__/auth-login.test.ts +54 -1
  55. package/src/commands/__tests__/call-describe.test.ts +46 -33
  56. package/src/commands/__tests__/call.test.ts +5 -1
  57. package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
  58. package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
  59. package/src/commands/__tests__/domain-list.test.ts +63 -4
  60. package/src/commands/__tests__/install-identity-override.test.ts +19 -19
  61. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  62. package/src/commands/__tests__/instance-status.test.ts +139 -0
  63. package/src/commands/__tests__/read-commands.test.ts +35 -10
  64. package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
  65. package/src/commands/__tests__/update.test.ts +48 -19
  66. package/src/commands/call-describe.ts +60 -68
  67. package/src/commands/call.ts +43 -56
  68. package/src/commands/domain/install.ts +13 -17
  69. package/src/commands/domain/list.ts +18 -13
  70. package/src/commands/domain/publish.ts +14 -11
  71. package/src/commands/domain/uninstall.ts +2 -2
  72. package/src/commands/get.ts +14 -15
  73. package/src/commands/identity/__tests__/register.test.ts +3 -3
  74. package/src/commands/identity/register.ts +5 -4
  75. package/src/commands/instance/create.ts +8 -16
  76. package/src/commands/instance/delete.ts +12 -9
  77. package/src/commands/instance/list.ts +2 -2
  78. package/src/commands/instance/status.ts +66 -20
  79. package/src/commands/instance/use.ts +16 -12
  80. package/src/commands/introspect.ts +9 -16
  81. package/src/commands/logs.ts +24 -25
  82. package/src/commands/mutate.ts +6 -5
  83. package/src/commands/query.ts +27 -30
  84. package/src/commands/studio.ts +20 -0
  85. package/src/commands/token.ts +8 -7
  86. package/src/commands/update.ts +38 -14
  87. package/src/commands/view.ts +7 -6
  88. package/src/connection/.spec/api.d.ts +7 -8
  89. package/src/connection/.spec/architecture.md +5 -4
  90. package/src/connection/.spec/flows/session.ts +2 -2
  91. package/src/connection/.spec/laws/connection.ts +6 -2
  92. package/src/connection/.spec/layout.ts +1 -0
  93. package/src/connection/__tests__/credential.test.ts +20 -1
  94. package/src/connection/__tests__/errors.test.ts +43 -32
  95. package/src/connection/__tests__/exchange.test.ts +36 -6
  96. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  97. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  98. package/src/connection/__tests__/self.test.ts +31 -11
  99. package/src/connection/__tests__/session.test.ts +3 -3
  100. package/src/connection/__tests__/target.test.ts +1 -0
  101. package/src/connection/auth.ts +13 -0
  102. package/src/connection/call.ts +1 -1
  103. package/src/connection/credential.ts +2 -2
  104. package/src/connection/errors.ts +1 -355
  105. package/src/connection/exchange.ts +52 -27
  106. package/src/connection/failure/classify.ts +110 -0
  107. package/src/connection/failure/index.ts +18 -0
  108. package/src/connection/failure/model.ts +28 -0
  109. package/src/connection/failure/render.ts +116 -0
  110. package/src/connection/reasons.ts +16 -0
  111. package/src/connection/self.ts +39 -21
  112. package/src/connection/session.ts +19 -8
  113. package/src/errors.ts +3 -2
  114. package/src/graph/.spec/api.d.ts +12 -5
  115. package/src/graph/.spec/layout.ts +9 -1
  116. package/src/graph/__tests__/mutation.test.ts +2 -2
  117. package/src/graph/__tests__/query.test.ts +25 -6
  118. package/src/graph/class.ts +30 -0
  119. package/src/graph/index.ts +1 -0
  120. package/src/graph/query.ts +21 -32
  121. package/src/identity/.spec/api.d.ts +2 -2
  122. package/src/identity/__tests__/registration.test.ts +1 -1
  123. package/src/identity/registration.ts +3 -3
  124. package/src/keys/__tests__/keys.test.ts +4 -0
  125. package/src/keys/credential.ts +1 -0
  126. package/src/lib/__tests__/admin-target.test.ts +12 -0
  127. package/src/lib/__tests__/command-dx.test.ts +1 -1
  128. package/src/lib/__tests__/domain-publication.test.ts +138 -0
  129. package/src/lib/__tests__/idp-session.test.ts +22 -0
  130. package/src/lib/__tests__/idp.test.ts +36 -4
  131. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  132. package/src/lib/__tests__/instance-target.test.ts +7 -39
  133. package/src/lib/__tests__/instance.test.ts +6 -0
  134. package/src/lib/__tests__/log-errors.test.ts +64 -0
  135. package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
  136. package/src/lib/__tests__/update.test.ts +113 -8
  137. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  138. package/src/lib/__tests__/view-server.test.ts +1 -1
  139. package/src/lib/__tests__/view-session.test.ts +1 -1
  140. package/src/lib/admin-instance.ts +14 -8
  141. package/src/lib/admin-target.ts +21 -2
  142. package/src/lib/command-dx.ts +9 -9
  143. package/src/lib/domain-publication.ts +104 -0
  144. package/src/lib/failure-debug.ts +26 -0
  145. package/src/lib/idp.ts +39 -4
  146. package/src/lib/instance-candidates.ts +2 -2
  147. package/src/lib/instance-target.ts +3 -14
  148. package/src/lib/instance.ts +22 -12
  149. package/src/lib/log.ts +16 -9
  150. package/src/lib/login-flow.ts +13 -3
  151. package/src/lib/meta.ts +2 -2
  152. package/src/lib/provision-instance.ts +34 -57
  153. package/src/lib/update.ts +124 -30
  154. package/src/lib/validation.ts +2 -2
  155. package/src/lib/view/resolve.ts +1 -1
  156. package/src/program/__tests__/program.test.ts +20 -4
  157. package/src/program/build.ts +2 -2
  158. package/src/setup/__tests__/instance-step.test.ts +27 -10
  159. package/src/setup/steps/instance.ts +22 -15
  160. package/studio/client/dist/assets/{elk-api-D2xgMJvi.js → elk-api-ByzoDZWH.js} +1 -1
  161. package/studio/client/dist/assets/index-B0RCgUOT.js +8 -0
  162. package/studio/client/dist/assets/index-BiGR8Oo9.css +1 -0
  163. package/studio/client/dist/assets/index-N8J8EKlB.js +81 -0
  164. package/studio/client/dist/index.html +2 -2
  165. package/studio/package.json +5 -10
  166. package/studio/server/agent/ask.test.ts +1 -1
  167. package/studio/server/agent/bridge/grant.test.ts +1 -1
  168. package/studio/server/agent/bridge/routes.test.ts +1 -1
  169. package/studio/server/agent/bridge/stdio.ts +8 -1
  170. package/studio/server/agent/conversation.test.ts +10 -5
  171. package/studio/server/agent/conversation.ts +56 -8
  172. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  173. package/studio/server/agent/harness/codex/loadout.ts +18 -21
  174. package/studio/server/agent/harness/gateway/config.ts +20 -18
  175. package/studio/server/agent/harness/selection.ts +9 -1
  176. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  177. package/studio/server/agent/prompts/anchors.ts +20 -49
  178. package/studio/server/agent/prompts/system.test.ts +3 -2
  179. package/studio/server/agent/prompts/system.ts +6 -5
  180. package/studio/server/agent/prompts/turn.ts +13 -4
  181. package/studio/server/agent/routes.test.ts +1 -1
  182. package/studio/server/agent/run/completion.ts +2 -2
  183. package/studio/server/agent/run/coordinator.test.ts +1 -1
  184. package/studio/server/agent/run/preparation.ts +6 -5
  185. package/studio/server/agent/run/transcript.test.ts +35 -1
  186. package/studio/server/agent/run/transcript.ts +169 -3
  187. package/studio/server/agent/run/usage.test.ts +24 -0
  188. package/studio/server/agent/run/usage.ts +26 -1
  189. package/studio/server/api/canvas.ts +43 -0
  190. package/studio/server/api/comments.ts +85 -0
  191. package/studio/server/api/context.ts +61 -0
  192. package/studio/server/api/deployment.ts +39 -0
  193. package/studio/server/api/documents.ts +55 -0
  194. package/studio/server/api/domain.ts +59 -0
  195. package/studio/server/api/http.ts +45 -0
  196. package/studio/server/api/project.ts +57 -0
  197. package/studio/server/api/schema.ts +12 -0
  198. package/studio/server/api/views.ts +57 -0
  199. package/studio/server/api/workspace.ts +60 -0
  200. package/studio/server/api-agent-loadout.test.ts +1 -1
  201. package/studio/server/api.test.ts +147 -0
  202. package/studio/server/api.ts +20 -422
  203. package/studio/server/cache.test.ts +122 -0
  204. package/studio/server/cache.ts +162 -11
  205. package/studio/server/cli-consumers.test.ts +494 -0
  206. package/studio/server/cli.test.ts +88 -0
  207. package/studio/server/cli.ts +240 -0
  208. package/studio/server/client-package.ts +25 -1
  209. package/studio/server/domain.test.ts +50 -40
  210. package/studio/server/domain.ts +83 -52
  211. package/studio/server/environment/dotenv-preview.test.ts +39 -0
  212. package/studio/server/environment/dotenv-preview.ts +27 -0
  213. package/studio/server/environment/files.test.ts +53 -0
  214. package/studio/server/{state/env.ts → environment/files.ts} +7 -48
  215. package/studio/server/{state → handoff}/copy.ts +21 -6
  216. package/studio/server/handoff/service.test.ts +22 -0
  217. package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
  218. package/studio/server/index.ts +1 -1
  219. package/studio/server/instances/active.ts +72 -0
  220. package/studio/server/instances/deploy-record.test.ts +31 -0
  221. package/studio/server/instances/deploy-record.ts +37 -0
  222. package/studio/server/instances/deploy.ts +56 -0
  223. package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
  224. package/studio/server/instances/probe.ts +67 -0
  225. package/studio/server/instances/status.test.ts +12 -0
  226. package/studio/server/instances/status.ts +49 -0
  227. package/studio/server/introspect/anatomy/client-tree.ts +57 -0
  228. package/studio/server/introspect/anatomy/env-fields.ts +66 -0
  229. package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
  230. package/studio/server/introspect/anatomy/source.ts +181 -0
  231. package/studio/server/introspect/anatomy/views/routes.ts +114 -0
  232. package/studio/server/introspect/anatomy/views.ts +53 -0
  233. package/studio/server/introspect/anatomy-extras.test.ts +106 -35
  234. package/studio/server/introspect/anatomy-extras.ts +7 -726
  235. package/studio/server/introspect/anatomy.test.ts +22 -14
  236. package/studio/server/introspect/anatomy.ts +52 -28
  237. package/studio/server/introspect/bundle.ts +15 -9
  238. package/studio/server/introspect/canonical-schema.test.ts +93 -309
  239. package/studio/server/introspect/canonical-schema.ts +257 -425
  240. package/studio/server/introspect/config-preview.test.ts +32 -0
  241. package/studio/server/introspect/config-preview.ts +119 -0
  242. package/studio/server/introspect/core-extractor.ts +18 -127
  243. package/studio/server/introspect/core.ts +1 -2
  244. package/studio/server/introspect/diff.test.ts +18 -18
  245. package/studio/server/introspect/diff.ts +44 -90
  246. package/studio/server/introspect/extractor.ts +23 -116
  247. package/studio/server/introspect/hash.ts +5 -2
  248. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  249. package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
  250. package/studio/server/introspect/overlay.test.ts +26 -54
  251. package/studio/server/introspect/overlay.ts +10 -37
  252. package/studio/server/introspect/revision.test.ts +54 -0
  253. package/studio/server/introspect/revision.ts +49 -0
  254. package/studio/server/introspect/runtime.test.ts +83 -143
  255. package/studio/server/introspect/runtime.ts +40 -11
  256. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  257. package/studio/server/introspect/schema-ir-json.ts +151 -0
  258. package/studio/server/introspect/schema-refs.test.ts +43 -88
  259. package/studio/server/introspect/schema-refs.ts +14 -49
  260. package/studio/server/introspect/source-overlay/annotations.ts +14 -0
  261. package/studio/server/introspect/source-overlay/handlers.ts +161 -0
  262. package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
  263. package/studio/server/introspect/source-overlay/project.ts +248 -0
  264. package/studio/server/introspect/source-overlay/spans.ts +330 -0
  265. package/studio/server/json.ts +46 -0
  266. package/studio/server/lifecycle.ts +5 -1
  267. package/studio/server/sse.test.ts +26 -0
  268. package/studio/server/sse.ts +4 -1
  269. package/studio/server/state/baseline.test.ts +223 -7
  270. package/studio/server/state/baseline.ts +148 -34
  271. package/studio/server/state/comments.test.ts +66 -1
  272. package/studio/server/state/comments.ts +173 -10
  273. package/studio/server/state/context.ts +34 -2
  274. package/studio/server/state/documents.ts +42 -1
  275. package/studio/server/state/integrations.ts +27 -1
  276. package/studio/server/state/layout.test.ts +34 -0
  277. package/studio/server/state/layout.ts +44 -17
  278. package/studio/server/state/settings.ts +29 -22
  279. package/studio/server/state/store.test.ts +122 -0
  280. package/studio/server/state/store.ts +66 -17
  281. package/studio/server/state/visibility.ts +22 -11
  282. package/studio/server/views/model.test.ts +57 -0
  283. package/studio/server/views/model.ts +66 -0
  284. package/studio/server/views/runtime.ts +40 -0
  285. package/studio/server/views/selection-repository.test.ts +31 -0
  286. package/studio/server/views/selection-repository.ts +60 -0
  287. package/studio/server/views/session.test.ts +73 -0
  288. package/studio/server/views/session.ts +166 -0
  289. package/studio/server/views/target.test.ts +78 -0
  290. package/studio/server/views/target.ts +222 -0
  291. package/studio/server/watch.test.ts +11 -11
  292. package/studio/server/watch.ts +9 -5
  293. package/studio/server/workspace/catalog.test.ts +17 -0
  294. package/studio/server/workspace/catalog.ts +43 -0
  295. package/studio/server/{state → workspace}/create.test.ts +1 -1
  296. package/studio/server/{state → workspace}/create.ts +1 -1
  297. package/studio/server/{state → workspace}/git.ts +1 -1
  298. package/studio/server/workspace/updates.ts +83 -0
  299. package/studio/server/workspace-state.ts +1 -1
  300. package/studio/server/workspace-watch.ts +2 -2
  301. package/studio/shared/contracts/README.md +16 -0
  302. package/studio/shared/contracts/agent.ts +270 -0
  303. package/studio/shared/contracts/runtime.ts +50 -0
  304. package/studio/shared/contracts/schema.ts +393 -0
  305. package/studio/shared/contracts/surface.test.ts +317 -0
  306. package/studio/shared/contracts/workspace.ts +265 -0
  307. package/studio/shared/layout.test.ts +116 -0
  308. package/studio/shared/schema/identity.test.ts +34 -0
  309. package/studio/shared/schema/identity.ts +68 -0
  310. package/studio/shared/types.ts +11 -1099
  311. package/studio/tsconfig.json +1 -1
  312. package/viewer/dist/main.js +40 -61
  313. package/.check-workspace.cjs +0 -40
  314. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  315. package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
  316. package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
  317. package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
  318. package/studio/server/state/catalog.ts +0 -117
  319. package/studio/server/state/instance.ts +0 -280
  320. package/studio/server/state/updates.ts +0 -63
  321. package/studio/server/state/views.test.ts +0 -286
  322. package/studio/server/state/views.ts +0 -535
@@ -1,4 +1,4 @@
1
- import type { Fetch } from '@astrale-os/kernel-client'
1
+ import type { Fetch } from '@astrale-os/sdk/client'
2
2
 
3
3
  import { issuer } from '@astrale-os/sdk/auth'
4
4
  import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
@@ -47,7 +47,7 @@ describe('Domain token exchange', () => {
47
47
  observed.push({ url, init, body })
48
48
  const index = observed.filter((entry) => entry.url === INVOCATION).length
49
49
  return invocationResponse(
50
- body.id,
50
+ body.requestId,
51
51
  index === 1
52
52
  ? { id: 'user-1' }
53
53
  : index === 2
@@ -121,7 +121,7 @@ describe('Domain token exchange', () => {
121
121
  if (url === INVOCATION) {
122
122
  const body = JSON.parse(await new Response(init?.body).text()) as Record<string, any>
123
123
  return invocationResponse(
124
- body.id,
124
+ body.requestId,
125
125
  body.call.input && Object.keys(body.call.input).length === 0
126
126
  ? { id: 'user-1' }
127
127
  : 'kernel-destination-envelope',
@@ -190,6 +190,35 @@ describe('Domain token exchange', () => {
190
190
  message: 'Token exchange returned an invalid success response.',
191
191
  })
192
192
  })
193
+
194
+ test('normalizes native issuer Fetch failures without exposing their message', async () => {
195
+ const native = new AggregateError([new Error('private DNS state')], '')
196
+ const resolver = createExchangeCredentialResolver(
197
+ TARGET,
198
+ { resolve: async () => SOURCE_TOKEN },
199
+ async (input, init) => {
200
+ if (String(input) === INVOCATION) {
201
+ const body = JSON.parse(await new Response(init?.body).text()) as Record<string, any>
202
+ return invocationResponse(
203
+ body.requestId,
204
+ body.call.input && Object.keys(body.call.input).length === 0
205
+ ? { id: 'user-1' }
206
+ : 'kernel-destination-envelope',
207
+ new Headers(init?.headers).get('accept')!,
208
+ )
209
+ }
210
+ throw native
211
+ },
212
+ 5_000,
213
+ new ExchangeCredentialCache(join(directory, 'native-failure.json')),
214
+ )
215
+
216
+ await expect(resolver.resolve(KERNEL, new AbortController().signal)).rejects.toMatchObject({
217
+ code: 'TOKEN_EXCHANGE_UNAVAILABLE',
218
+ message: 'Domain issuer discovery could not be reached.',
219
+ cause: native,
220
+ })
221
+ })
193
222
  })
194
223
 
195
224
  function exchangeFetch(
@@ -201,7 +230,7 @@ function exchangeFetch(
201
230
  if (url === INVOCATION) {
202
231
  const body = JSON.parse(await new Response(init?.body).text()) as Record<string, any>
203
232
  return invocationResponse(
204
- body.id,
233
+ body.requestId,
205
234
  body.call.input && Object.keys(body.call.input).length === 0
206
235
  ? { id: 'user-1' }
207
236
  : 'kernel-destination-envelope',
@@ -233,8 +262,9 @@ function configuration(enabled: boolean) {
233
262
  }
234
263
  }
235
264
 
236
- function invocationResponse(id: number, result: unknown, contentType: string): Response {
237
- return new Response(JSON.stringify({ id, result }), {
265
+ function invocationResponse(requestId: unknown, result: unknown, contentType: string): Response {
266
+ const invocation = { source: KERNEL, id: `exchange-${String(requestId)}` }
267
+ return new Response(JSON.stringify({ requestId, invocation, result }), {
238
268
  headers: { 'content-type': contentType, 'cache-control': 'no-store' },
239
269
  })
240
270
  }
@@ -0,0 +1,39 @@
1
+ import { ClientError, TransportError } from '@astrale-os/sdk/client'
2
+
3
+ import type { TransportDiagnosticContext } from '../failure/model'
4
+
5
+ type CompatibleTransportPhase = TransportError['phase'] | 'unknown'
6
+
7
+ export function transportFailure(
8
+ message: string,
9
+ phase: CompatibleTransportPhase,
10
+ context: TransportDiagnosticContext,
11
+ ): TransportError {
12
+ const error = new Error(message) as TransportError & {
13
+ context: TransportDiagnosticContext
14
+ }
15
+ Object.setPrototypeOf(error, TransportError.prototype)
16
+ Object.assign(error, { name: 'TransportError', phase, context })
17
+ return error
18
+ }
19
+
20
+ export function legacyTransportFailure(
21
+ message: string,
22
+ phase: CompatibleTransportPhase,
23
+ delivery: 'not-sent' | 'unknown',
24
+ ): TransportError {
25
+ const error = new Error(message) as TransportError & { delivery: typeof delivery }
26
+ Object.setPrototypeOf(error, TransportError.prototype)
27
+ Object.assign(error, { name: 'TransportError', phase, delivery })
28
+ return error
29
+ }
30
+
31
+ export function sessionFailure(
32
+ message: string,
33
+ failure: 'cancelled' | 'closed' | 'timeout',
34
+ ): ClientError {
35
+ const error = new Error(message) as ClientError & { failure: typeof failure }
36
+ Object.setPrototypeOf(error, ClientError.prototype)
37
+ Object.assign(error, { name: 'SessionError', failure })
38
+ return error
39
+ }
@@ -0,0 +1,75 @@
1
+ import { expect, test } from 'bun:test'
2
+
3
+ import { formatKernelError } from '../errors'
4
+ import { legacyTransportFailure, sessionFailure, transportFailure } from './failure-fixtures'
5
+
6
+ /** @evidence TEST-CLI-CONNECTION-FAILURE-SAFETY */
7
+ test('unknown and empty native failures never become ordinary diagnostics', async () => {
8
+ for (const failure of [new Error('private provider detail'), new Error(''), { secret: true }]) {
9
+ const output = await capture(() => formatKernelError(failure, true))
10
+ expect(JSON.parse(output)).toEqual({
11
+ error: 'UNEXPECTED_ERROR',
12
+ message: 'The CLI encountered an unexpected internal failure.',
13
+ })
14
+ expect(output).not.toContain('private provider detail')
15
+ }
16
+ })
17
+
18
+ test('Aggregate children are available only under explicit debug output', async () => {
19
+ const failure = new AggregateError([new Error('first private'), new Error('second private')], '')
20
+ const ordinary = await capture(() => formatKernelError(failure, true))
21
+ expect(ordinary).not.toContain('first private')
22
+ expect(ordinary).not.toContain('second private')
23
+
24
+ const debug = await capture(() => formatKernelError(failure, true, '', true))
25
+ expect(debug).toContain('aggregate: Error: first private')
26
+ expect(debug).toContain('aggregate: Error: second private')
27
+ })
28
+
29
+ test('Session and acquisition failures remain typed without unsafe recovery advice', async () => {
30
+ const session = await capture(() =>
31
+ formatKernelError(sessionFailure('Session operation timed out.', 'timeout'), true),
32
+ )
33
+ expect(JSON.parse(session)).toEqual({ error: 'TIMEOUT', message: 'Session operation timed out.' })
34
+
35
+ const acquisition = await capture(() =>
36
+ formatKernelError(
37
+ transportFailure('Publication failed.', 'unknown', {
38
+ kind: 'acquisition',
39
+ resource: 'publication',
40
+ }),
41
+ true,
42
+ '',
43
+ false,
44
+ { recovery: { operation: 'must-not-leak', retry: 'must-not-leak' } },
45
+ ),
46
+ )
47
+ expect(JSON.parse(acquisition)).toMatchObject({
48
+ error: 'TRANSPORT_ERROR',
49
+ transport: { kind: 'acquisition', resource: 'publication' },
50
+ })
51
+ expect(acquisition).not.toContain('must-not-leak')
52
+
53
+ const legacy = await capture(() =>
54
+ formatKernelError(legacyTransportFailure('Legacy send failed.', 'send', 'not-sent'), true),
55
+ )
56
+ expect(JSON.parse(legacy)).toMatchObject({
57
+ error: 'TRANSPORT_ERROR',
58
+ transport: { kind: 'invocation', delivery: 'not-sent' },
59
+ })
60
+ })
61
+
62
+ async function capture(action: () => Promise<void>): Promise<string> {
63
+ const writes: string[] = []
64
+ const original = process.stderr.write
65
+ process.stderr.write = ((chunk: string | Uint8Array) => {
66
+ writes.push(typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk))
67
+ return true
68
+ }) as typeof process.stderr.write
69
+ try {
70
+ await action()
71
+ return writes.join('')
72
+ } finally {
73
+ process.stderr.write = original
74
+ }
75
+ }
@@ -2,7 +2,11 @@ import { describe, expect, test } from 'bun:test'
2
2
  import { SignJWT } from 'jose'
3
3
  import { webcrypto } from 'node:crypto'
4
4
 
5
- import { resolveSelfIdAuthenticated } from '../self'
5
+ import type { ConnectionContext } from '../session'
6
+
7
+ import { expandSelfInCall, resolveSelfIdAuthenticated } from '../self'
8
+
9
+ const context = Object.freeze({}) as ConnectionContext
6
10
 
7
11
  describe('resolveSelfIdAuthenticated', () => {
8
12
  /** @evidence TEST-CLI-SELF-USES-AUTHENTICATED-EFFECTIVE-PRINCIPAL */
@@ -14,11 +18,9 @@ describe('resolveSelfIdAuthenticated', () => {
14
18
  .setSubject('manager-principal')
15
19
  .setAudience('https://child.example')
16
20
  .sign(key)
17
- const opts = { creds: credential, url: 'https://manager.example/children/child/invoke' }
18
-
19
- const resolved = await resolveSelfIdAuthenticated(opts, {
21
+ const resolved = await resolveSelfIdAuthenticated(context, {
20
22
  whoami: async (received) => {
21
- expect(received).toBe(opts)
23
+ expect(received).toBe(context)
22
24
  return { id: 'child-kernel-principal', slug: 'child' }
23
25
  },
24
26
  })
@@ -28,17 +30,35 @@ describe('resolveSelfIdAuthenticated', () => {
28
30
 
29
31
  test('resolves an imported root without requiring a local registration', async () => {
30
32
  await expect(
31
- resolveSelfIdAuthenticated(
32
- { as: 'platform-root', url: 'https://manager.example/invoke' },
33
- { whoami: async () => ({ id: 'manager-kernel-principal' }) },
34
- ),
33
+ resolveSelfIdAuthenticated(context, {
34
+ whoami: async () => ({ id: 'manager-kernel-principal' }),
35
+ }),
35
36
  ).resolves.toEqual({ id: 'manager-kernel-principal' })
36
37
  })
37
38
 
38
39
  test('fails closed when authenticated whoami returns no NodeId', async () => {
39
40
  await expect(
40
- resolveSelfIdAuthenticated({}, { whoami: async () => ({ id: ' ' }) }),
41
- ).rejects.toMatchObject({ name: 'SelfResolutionError' })
41
+ resolveSelfIdAuthenticated(context, { whoami: async () => ({ id: ' ' }) }),
42
+ ).rejects.toMatchObject({ code: 'SELF_RESOLUTION_FAILED' })
43
+ })
44
+ })
45
+
46
+ describe('expandSelfInCall', () => {
47
+ test('expands only top-level string values after local parameter admission', async () => {
48
+ const callContext = {
49
+ auth: { whoami: async () => ({ id: 'caller-id' }) },
50
+ target: {},
51
+ } as ConnectionContext
52
+ const expanded = await expandSelfInCall(
53
+ '/:people.example.dev:class.Person:get',
54
+ { owner: '@self', count: 2, nested: { owner: '@self' } },
55
+ callContext,
56
+ )
57
+ expect(expanded.parameters).toEqual({
58
+ owner: '@caller-id',
59
+ count: 2,
60
+ nested: { owner: '@self' },
61
+ })
42
62
  })
43
63
  })
44
64
 
@@ -1,6 +1,6 @@
1
- import type { AuthApi } from '@astrale-os/kernel-client/auth'
2
- import type { GraphApi } from '@astrale-os/kernel-client/graph'
3
- import type { ClientSession } from '@astrale-os/kernel-client/session'
1
+ import type { AuthApi } from '@astrale-os/sdk/auth'
2
+ import type { GraphApi } from '@astrale-os/sdk/client'
3
+ import type { ClientSession } from '@astrale-os/sdk/client/session'
4
4
 
5
5
  import { issuer } from '@astrale-os/sdk/auth'
6
6
  import { describe, expect, test } from 'bun:test'
@@ -68,6 +68,7 @@ describe('connection target', () => {
68
68
  id: 'managed-id',
69
69
  slug,
70
70
  url: 'https://managed.example',
71
+ state: 'ready',
71
72
  }),
72
73
  }),
73
74
  ).toEqual({
@@ -1,4 +1,5 @@
1
1
  import type { AstraleConfig } from '../lib/config'
2
+ import type { ConnectionOptions, ConnectionTarget } from './target'
2
3
 
3
4
  import { AuthError } from '../errors'
4
5
  import { getDefault, getIdentity, type Identity } from '../identity/registry'
@@ -21,6 +22,18 @@ export type KeyIdentityAuthOptions = {
21
22
  audience: string
22
23
  }
23
24
 
25
+ /** Pin the local identity label before a session performs any authenticated effect. */
26
+ export async function bindCredentialIdentity<Options extends ConnectionOptions>(
27
+ options: Options,
28
+ target: ConnectionTarget,
29
+ ): Promise<Options> {
30
+ if (options.anonymous === true || options.creds !== undefined || options.as !== undefined) {
31
+ return options
32
+ }
33
+ const identity = target.defaultIdentity ?? (await getDefault()).name
34
+ return Object.freeze({ ...options, as: identity })
35
+ }
36
+
24
37
  /**
25
38
  * Resolve a signed JWT credential from CLI options.
26
39
  *
@@ -1,4 +1,4 @@
1
- import { call, type Call } from '@astrale-os/kernel-client'
1
+ import { call, type Call } from '@astrale-os/sdk/client'
2
2
  import { Path } from '@astrale-os/sdk/graph/path'
3
3
 
4
4
  /** Convert the CLI's untrusted text/JSON boundary into the one public Call representation. */
@@ -1,5 +1,5 @@
1
- import type { Fetch } from '@astrale-os/kernel-client'
2
- import type { SessionAuth } from '@astrale-os/kernel-client/session'
1
+ import type { Fetch } from '@astrale-os/sdk/client'
2
+ import type { SessionAuth } from '@astrale-os/sdk/client/session'
3
3
 
4
4
  import { credential, type IssuerId } from '@astrale-os/sdk/auth'
5
5
 
@@ -1,355 +1 @@
1
- import chalk from 'chalk'
2
-
3
- import type { OperationRecovery } from './command'
4
-
5
- import { AstraleError } from '../errors'
6
- import { readLocalStatus, type LocalStatus } from '../lib/local-status'
7
- import { log } from '../lib/log'
8
- import {
9
- functionInputIssues,
10
- queryInputRepair,
11
- reasonCode,
12
- schemaUpgradeDetails,
13
- schemaUpgradeHint,
14
- type FunctionInputIssue,
15
- type QueryInputRepair,
16
- } from './reasons'
17
-
18
- export { functionInputIssues, schemaUpgradeHint } from './reasons'
19
-
20
- /**
21
- * Format and display a kernel client error.
22
- *
23
- * Handles CLI-local errors plus the current Kernel Client public error families.
24
- *
25
- * When `debug` is true, additional diagnostic information (class name, full
26
- * error chain, attached url/details) is printed after the user-facing line.
27
- */
28
- export async function formatKernelError(
29
- error: unknown,
30
- isRaw: boolean,
31
- urlArg = '',
32
- debug = false,
33
- opts: { recovery?: OperationRecovery } = {},
34
- ): Promise<void> {
35
- const url =
36
- urlArg || (error instanceof Error ? ((error as Error & { url?: string }).url ?? '') : '')
37
- const localContext = await contextForError(error)
38
- // Handle AstraleError (AuthError, etc.) with structured hints
39
- if (error instanceof AstraleError) {
40
- if (isRaw) {
41
- writeRaw({ error: error.code, message: error.message, hint: error.hint })
42
- } else {
43
- log.error(`${chalk.bold(error.code)}: ${error.message}`)
44
- if (error.hint) log.dim(` ${error.hint}`)
45
- }
46
- if (debug) printDebug(error, url)
47
- return
48
- }
49
-
50
- if (!(error instanceof Error)) {
51
- if (isRaw) writeRaw({ error: 'UNKNOWN', message: String(error) })
52
- else log.error(String(error))
53
- return
54
- }
55
-
56
- const name = error.name
57
-
58
- switch (name) {
59
- case 'TransportError':
60
- presentTransportError(error, isRaw, url, localContext, opts.recovery)
61
- break
62
-
63
- case 'ResponseError': {
64
- const code = (error as { readonly code?: unknown }).code
65
- const reason = (error as { readonly reason?: unknown }).reason
66
- const codeOfReason = reasonCode(reason)
67
- const inputIssues = functionInputIssues(reason)
68
- const queryRepair = queryInputRepair(reason)
69
- const upgrade = schemaUpgradeDetails(reason)
70
- const removalHint = schemaDataRemovalHint(reason)
71
- const domainAddressNotPublic = codeOfReason === 'SCHEMA_DOMAIN_ADDRESS_NOT_PUBLIC'
72
- const displayMessage = domainAddressNotPublic
73
- ? 'Expose the Domain through a public HTTPS URL or public tunnel, then retry.'
74
- : removalHint !== undefined && !isRaw
75
- ? 'Existing business data still uses schema definitions being removed.'
76
- : error.message
77
- const hint =
78
- codeOfReason === 'FUNCTION_INPUT_INVALID' && (isRaw || inputIssues.length === 0)
79
- ? 'Use `astrale introspect <path>` to see the callable input.'
80
- : (removalHint ?? (upgrade === undefined ? undefined : schemaUpgradeHint(upgrade)))
81
- if (isRaw) {
82
- writeRaw({
83
- error: 'RESPONSE_ERROR',
84
- ...(code === undefined ? {} : { code }),
85
- message: displayMessage,
86
- ...(reason === undefined ? {} : { reason }),
87
- ...(hint === undefined ? {} : { hint }),
88
- })
89
- } else {
90
- log.error(
91
- domainAddressNotPublic
92
- ? `${chalk.bold('SCHEMA_DOMAIN_ADDRESS_NOT_PUBLIC')}: ${displayMessage}`
93
- : removalHint !== undefined
94
- ? `${chalk.bold('DATA_MIGRATION_REQUIRED')}: ${displayMessage}`
95
- : `${chalk.bold(code === undefined ? 'RESPONSE_ERROR' : `RESPONSE_ERROR(${String(code)})`)}: ${displayMessage}`,
96
- )
97
- if (codeOfReason !== undefined && !domainAddressNotPublic && removalHint === undefined) {
98
- log.dim(` reason: ${codeOfReason}`)
99
- }
100
- presentFunctionInputIssues(inputIssues)
101
- if (queryRepair !== undefined) presentQueryInputRepair(queryRepair)
102
- if (upgrade?.issue === 'issuer-changed') {
103
- log.dim(` installed issuer: ${upgrade.installedIssuer}`)
104
- log.dim(` replacement issuer: ${upgrade.replacementIssuer}`)
105
- }
106
- if (hint !== undefined) log.dim(` ${hint}`)
107
- }
108
- break
109
- }
110
-
111
- default: {
112
- const mapped = mapPublicError(error)
113
- if (isRaw) {
114
- writeRaw({
115
- error: mapped.code,
116
- message: mapped.message,
117
- ...(mapped.hint === undefined ? {} : { hint: mapped.hint }),
118
- ...(mapped.timeoutMs === undefined ? {} : { timeoutMs: mapped.timeoutMs }),
119
- })
120
- } else {
121
- log.error(`${chalk.bold(mapped.code)}: ${mapped.message}`)
122
- if (mapped.hint) log.dim(` ${mapped.hint}`)
123
- }
124
- }
125
- }
126
-
127
- if (debug) printDebug(error, url)
128
- }
129
-
130
- function schemaDataRemovalHint(reason: unknown): string | undefined {
131
- if (reason === null || typeof reason !== 'object') return undefined
132
- const value = reason as { readonly code?: unknown; readonly details?: unknown }
133
- if (value.code !== 'DATA_MIGRATION_REQUIRED') return undefined
134
- if (value.details === null || typeof value.details !== 'object') return undefined
135
-
136
- const requirements = (value.details as { readonly requirements?: unknown }).requirements
137
- if (
138
- !Array.isArray(requirements) ||
139
- requirements.length === 0 ||
140
- !requirements.every(
141
- (requirement) =>
142
- requirement !== null &&
143
- typeof requirement === 'object' &&
144
- (requirement as { readonly operation?: unknown }).operation === 'remove-facts' &&
145
- (requirement as { readonly reason?: unknown }).reason === 'destructive-change',
146
- )
147
- ) {
148
- return undefined
149
- }
150
-
151
- return 'Delete this data explicitly, then retry. No data was deleted.'
152
- }
153
-
154
- function mapPublicError(error: Error): {
155
- code: string
156
- message: string
157
- hint?: string
158
- timeoutMs?: number
159
- } {
160
- const name = error.name
161
- if (name === 'PathError') {
162
- return { code: 'PATH_INVALID', message: error.message }
163
- }
164
- if (name === 'NodeUnavailableError') {
165
- return {
166
- code: 'NODE_UNAVAILABLE',
167
- message: error.message,
168
- hint: 'If this is a callable Path, use `astrale call` or `astrale introspect`.',
169
- }
170
- }
171
- if (name === 'AuthValueError') {
172
- return { code: 'AUTH_VALUE_INVALID', message: error.message }
173
- }
174
- if (name === 'ClientError' && /timed out/i.test(error.message)) {
175
- const timeoutMs = (error as { timeoutMs?: number }).timeoutMs
176
- return {
177
- code: 'TIMEOUT',
178
- message: error.message,
179
- hint: 'Try increasing with --timeout',
180
- ...(timeoutMs === undefined ? {} : { timeoutMs }),
181
- }
182
- }
183
- if (name === 'ClientError' && /Publication discovery returned HTTP/i.test(error.message)) {
184
- return {
185
- code: 'KERNEL_DISCOVERY_FAILED',
186
- message: error.message,
187
- hint: 'Pass the Kernel issuer URL (no /invoke suffix), e.g. https://host/kernel/host',
188
- }
189
- }
190
- return { code: name && name !== 'Error' ? name : 'UNKNOWN', message: error.message }
191
- }
192
-
193
- function presentTransportError(
194
- error: Error,
195
- isRaw: boolean,
196
- url: string,
197
- context: LocalStatus | undefined,
198
- recovery: OperationRecovery | undefined,
199
- ): void {
200
- const phase = transportPhase(error)
201
- const delivery = transportDelivery(error)
202
- const code =
203
- phase === 'connect'
204
- ? 'CONNECTION_ERROR'
205
- : phase === 'timeout'
206
- ? 'TIMEOUT'
207
- : phase === 'closed'
208
- ? 'DISCONNECTED'
209
- : 'TRANSPORT_ERROR'
210
- if (isRaw) {
211
- writeRaw({
212
- error: code,
213
- message: error.message,
214
- ...(url === '' ? {} : { url }),
215
- ...(phase === undefined ? {} : { phase }),
216
- ...(delivery === undefined ? {} : { delivery }),
217
- ...(context === undefined ? {} : { context }),
218
- ...(delivery === 'unknown' && recovery !== undefined ? recovery : {}),
219
- })
220
- return
221
- }
222
- log.error(`${chalk.bold(code)}: ${error.message}`)
223
- if (url !== '') log.dim(` target: ${url}`)
224
- if (phase !== undefined) log.dim(` phase: ${phase}`)
225
- if (phase === 'connect') log.dim(' Check the target and run `astrale status`.')
226
- else if (phase === 'timeout') log.dim(' Try increasing `--timeout`.')
227
- else if (delivery === 'unknown') printOperationRecovery(recovery)
228
- printLocalContext(context)
229
- }
230
-
231
- function printOperationRecovery(recovery: OperationRecovery | undefined): void {
232
- if (recovery === undefined) {
233
- log.dim(' Delivery is unknown; do not automatically retry a mutating call.')
234
- return
235
- }
236
- log.dim(' Delivery is unknown; retry with the same operation id:')
237
- log.dim(` operation: ${recovery.operation}`)
238
- log.dim(` ${recovery.retry}`)
239
- }
240
-
241
- function presentFunctionInputIssues(issues: readonly FunctionInputIssue[]): void {
242
- for (const issue of issues) {
243
- const location = issue.path === undefined || issue.path === '' ? '<input>' : issue.path
244
- console.log(chalk.red(` ${location}: ${issue.message} (${chalk.dim(issue.code)})`))
245
- }
246
- }
247
-
248
- function presentQueryInputRepair(repair: QueryInputRepair): void {
249
- if (repair.phase === 'plan') {
250
- log.dim(` ${repair.path ?? '/'} ${repair.issue}`)
251
- return
252
- }
253
- if (repair.phase === 'limit') {
254
- log.dim(` ${repair.path ?? '/'} ${repair.limit} limit ${repair.actual}/${repair.maximum}`)
255
- return
256
- }
257
- log.dim(` ${repair.path} ${repair.phase} input`)
258
- }
259
-
260
- function transportPhase(error: Error): string | undefined {
261
- const phase = (error as Error & { readonly phase?: unknown }).phase
262
- return phase === 'connect' ||
263
- phase === 'send' ||
264
- phase === 'receive' ||
265
- phase === 'timeout' ||
266
- phase === 'closed'
267
- ? phase
268
- : undefined
269
- }
270
-
271
- function transportDelivery(error: Error): string | undefined {
272
- const delivery = (error as Error & { readonly delivery?: unknown }).delivery
273
- return delivery === 'not-sent' || delivery === 'unknown' ? delivery : undefined
274
- }
275
-
276
- function writeRaw(payload: Record<string, unknown>): void {
277
- process.stderr.write(JSON.stringify(payload) + '\n')
278
- }
279
-
280
- async function contextForError(error: unknown): Promise<LocalStatus | undefined> {
281
- if (!(error instanceof Error)) return undefined
282
- if (error.name !== 'TransportError') return undefined
283
- return readLocalStatus().catch(() => undefined)
284
- }
285
-
286
- function printLocalContext(context: LocalStatus | undefined): void {
287
- if (!context) return
288
- process.stderr.write(chalk.dim('\nContext:\n'))
289
- if ('error' in context.admin) {
290
- process.stderr.write(chalk.dim(` admin: invalid (${context.admin.error})\n`))
291
- } else {
292
- process.stderr.write(chalk.dim(` admin: ${context.admin.name} -> ${context.admin.url}\n`))
293
- }
294
- if (context.instance) {
295
- process.stderr.write(
296
- chalk.dim(` instance: ${context.instance.active} -> ${context.instance.url}\n`),
297
- )
298
- } else {
299
- process.stderr.write(chalk.dim(' instance: none\n'))
300
- }
301
- if (context.identity) {
302
- const source =
303
- context.identity.source === 'idp'
304
- ? `idp:${context.identity.idp ?? 'unknown'}`
305
- : context.identity.source
306
- process.stderr.write(chalk.dim(` identity: ${context.identity.name} [${source}]\n`))
307
- if (context.identity.session?.cached) {
308
- const state = context.identity.session.requiresLogin ? 'login required' : 'ready'
309
- process.stderr.write(chalk.dim(` session: ${state}\n`))
310
- } else if (context.identity.source === 'idp') {
311
- process.stderr.write(chalk.dim(' session: not cached\n'))
312
- }
313
- } else {
314
- process.stderr.write(chalk.dim(' identity: none\n'))
315
- }
316
- }
317
-
318
- function printDebug(error: unknown, url: string): void {
319
- process.stderr.write('\n' + chalk.dim('── debug ─────────────────') + '\n')
320
- if (url) process.stderr.write(chalk.dim(`url: ${url}`) + '\n')
321
- if (error instanceof Error) {
322
- process.stderr.write(chalk.dim(`class: ${error.constructor.name}`) + '\n')
323
- if (error.stack) process.stderr.write(chalk.dim(error.stack) + '\n')
324
- // Walk cause chain
325
- let cause = (error as Error & { cause?: unknown }).cause
326
- while (cause instanceof Error) {
327
- process.stderr.write(
328
- chalk.dim(`caused by: ${cause.constructor.name}: ${cause.message}`) + '\n',
329
- )
330
- if (cause.stack) process.stderr.write(chalk.dim(cause.stack) + '\n')
331
- cause = (cause as Error & { cause?: unknown }).cause
332
- }
333
- // Any attached fields (code, details, etc.)
334
- const extras: Record<string, unknown> = {}
335
- const bag = error as unknown as Record<string, unknown>
336
- for (const key of [
337
- 'code',
338
- 'type',
339
- 'reason',
340
- 'details',
341
- 'errors',
342
- 'data',
343
- 'timeoutMs',
344
- 'requestId',
345
- ]) {
346
- const v = bag[key]
347
- if (v !== undefined) extras[key] = v
348
- }
349
- if (Object.keys(extras).length > 0) {
350
- process.stderr.write(chalk.dim(`extras: ${JSON.stringify(extras, null, 2)}`) + '\n')
351
- }
352
- } else {
353
- process.stderr.write(chalk.dim(String(error)) + '\n')
354
- }
355
- }
1
+ export { formatKernelError, functionInputIssues, schemaUpgradeHint } from './failure'