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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/README.md +16 -1
  2. package/dist/astrale.js +51105 -58057
  3. package/dist/public/connect-core.js +2085 -30702
  4. package/dist/public/keys/index.js +884 -29476
  5. package/dist/public/paths/index.js +13101 -41452
  6. package/dist/types/admin/contract.d.ts +26 -0
  7. package/dist/types/admin/instance/client.d.ts +20 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +6 -10
  10. package/dist/types/connection/auth.d.ts +3 -0
  11. package/dist/types/connection/call.d.ts +3 -0
  12. package/dist/types/connection/command.d.ts +27 -0
  13. package/dist/types/connection/credential.d.ts +14 -0
  14. package/dist/types/connection/errors.d.ts +1 -0
  15. package/dist/types/connection/exchange.d.ts +9 -0
  16. package/dist/types/connection/failure/classify.d.ts +2 -0
  17. package/dist/types/connection/failure/index.d.ts +5 -0
  18. package/dist/types/connection/failure/model.d.ts +25 -0
  19. package/dist/types/connection/failure/render.d.ts +3 -0
  20. package/dist/types/connection/index.d.ts +8 -0
  21. package/dist/types/connection/reasons.d.ts +37 -0
  22. package/dist/types/connection/self.d.ts +37 -0
  23. package/dist/types/connection/session.d.ts +31 -0
  24. package/dist/types/connection/target.d.ts +38 -0
  25. package/dist/types/errors.d.ts +1 -1
  26. package/dist/types/lib/admin-instance.d.ts +17 -0
  27. package/dist/types/lib/admin-target.d.ts +11 -36
  28. package/dist/types/lib/config.d.ts +7 -59
  29. package/dist/types/lib/failure-debug.d.ts +1 -0
  30. package/dist/types/lib/idp.d.ts +25 -173
  31. package/dist/types/lib/instance-target.d.ts +1 -1
  32. package/dist/types/lib/instance.d.ts +30 -88
  33. package/dist/types/lib/log.d.ts +5 -3
  34. package/dist/types/lib/output.d.ts +1 -1
  35. package/dist/types/lib/proc.d.ts +43 -0
  36. package/dist/types/lib/self.d.ts +9 -0
  37. package/dist/types/lib/update.d.ts +109 -0
  38. package/dist/types/lib/validation.d.ts +4 -1
  39. package/package.json +15 -20
  40. package/src/__tests__/fixtures/publication.ts +20 -0
  41. package/src/admin/.spec/architecture.md +12 -5
  42. package/src/admin/__tests__/fixture.ts +25 -0
  43. package/src/admin/catalog/.spec/api.d.ts +1 -3
  44. package/src/admin/catalog/.spec/architecture.md +5 -4
  45. package/src/admin/catalog/__tests__/client.test.ts +143 -69
  46. package/src/admin/catalog/client.ts +40 -54
  47. package/src/admin/catalog/model.ts +3 -4
  48. package/src/admin/contract.ts +46 -0
  49. package/src/admin/graph/.spec/api.d.ts +4 -10
  50. package/src/admin/graph/nodes.ts +1 -1
  51. package/src/admin/instance/.spec/api.d.ts +5 -9
  52. package/src/admin/instance/.spec/architecture.md +7 -7
  53. package/src/admin/instance/__tests__/client.test.ts +157 -175
  54. package/src/admin/instance/client.ts +39 -128
  55. package/src/admin/instance/index.ts +1 -2
  56. package/src/admin/instance/model.ts +12 -18
  57. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  58. package/src/commands/__tests__/call-describe.test.ts +46 -33
  59. package/src/commands/__tests__/call.test.ts +34 -0
  60. package/src/commands/__tests__/domain-install-operation.test.ts +7 -22
  61. package/src/commands/__tests__/domain-install-owned.test.ts +1 -1
  62. package/src/commands/__tests__/domain-list.test.ts +5 -25
  63. package/src/commands/__tests__/install-direct.test.ts +115 -8
  64. package/src/commands/__tests__/install-identity-override.test.ts +3 -14
  65. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  66. package/src/commands/__tests__/instance-status.test.ts +139 -0
  67. package/src/commands/__tests__/introspect-parse.test.ts +80 -1
  68. package/src/commands/__tests__/logs.test.ts +250 -2
  69. package/src/commands/__tests__/read-commands.test.ts +62 -10
  70. package/src/commands/__tests__/token-ttl.test.ts +49 -4
  71. package/src/commands/__tests__/update.test.ts +25 -3
  72. package/src/commands/__tests__/view.test.ts +49 -0
  73. package/src/commands/call-describe.ts +60 -68
  74. package/src/commands/call.ts +71 -59
  75. package/src/commands/domain/install.ts +54 -35
  76. package/src/commands/domain/list.ts +1 -1
  77. package/src/commands/domain/publish.ts +14 -11
  78. package/src/commands/domain/uninstall.ts +2 -2
  79. package/src/commands/get.ts +14 -15
  80. package/src/commands/identity/__tests__/register.test.ts +3 -3
  81. package/src/commands/identity/register.ts +5 -4
  82. package/src/commands/instance/create.ts +8 -16
  83. package/src/commands/instance/delete.ts +12 -9
  84. package/src/commands/instance/list.ts +2 -2
  85. package/src/commands/instance/status.ts +66 -20
  86. package/src/commands/instance/use.ts +16 -12
  87. package/src/commands/introspect.ts +48 -35
  88. package/src/commands/logs.ts +123 -33
  89. package/src/commands/mutate.ts +6 -5
  90. package/src/commands/query.ts +35 -32
  91. package/src/commands/token.ts +42 -27
  92. package/src/commands/ui/__tests__/commands.test.ts +152 -0
  93. package/src/commands/ui/add.ts +51 -0
  94. package/src/commands/ui/doctor.ts +13 -0
  95. package/src/commands/ui/init.ts +38 -0
  96. package/src/commands/ui/list.ts +26 -0
  97. package/src/commands/ui/preset-apply.ts +19 -0
  98. package/src/commands/ui/preset-list.ts +12 -0
  99. package/src/commands/ui/shared.ts +25 -0
  100. package/src/commands/update.ts +31 -11
  101. package/src/commands/view.ts +82 -37
  102. package/src/connection/.spec/api.d.ts +7 -8
  103. package/src/connection/.spec/architecture.md +5 -4
  104. package/src/connection/.spec/flows/session.ts +2 -2
  105. package/src/connection/.spec/laws/connection.ts +6 -2
  106. package/src/connection/.spec/layout.ts +1 -0
  107. package/src/connection/__tests__/credential.test.ts +20 -1
  108. package/src/connection/__tests__/errors.test.ts +27 -20
  109. package/src/connection/__tests__/exchange.test.ts +30 -1
  110. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  111. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  112. package/src/connection/__tests__/self.test.ts +31 -11
  113. package/src/connection/__tests__/session.test.ts +3 -3
  114. package/src/connection/__tests__/target.test.ts +1 -0
  115. package/src/connection/auth.ts +13 -0
  116. package/src/connection/call.ts +1 -1
  117. package/src/connection/credential.ts +2 -2
  118. package/src/connection/errors.ts +1 -355
  119. package/src/connection/exchange.ts +47 -23
  120. package/src/connection/failure/classify.ts +110 -0
  121. package/src/connection/failure/index.ts +18 -0
  122. package/src/connection/failure/model.ts +28 -0
  123. package/src/connection/failure/render.ts +116 -0
  124. package/src/connection/reasons.ts +16 -0
  125. package/src/connection/self.ts +39 -21
  126. package/src/connection/session.ts +19 -8
  127. package/src/errors.ts +3 -2
  128. package/src/graph/.spec/api.d.ts +12 -5
  129. package/src/graph/.spec/layout.ts +9 -1
  130. package/src/graph/__tests__/mutation.test.ts +2 -2
  131. package/src/graph/__tests__/query.test.ts +25 -6
  132. package/src/graph/class.ts +30 -0
  133. package/src/graph/index.ts +1 -0
  134. package/src/graph/query.ts +21 -32
  135. package/src/identity/.spec/api.d.ts +2 -2
  136. package/src/identity/__tests__/registration.test.ts +1 -1
  137. package/src/identity/registration.ts +3 -3
  138. package/src/keys/__tests__/keys.test.ts +4 -0
  139. package/src/keys/credential.ts +1 -0
  140. package/src/lib/__tests__/admin-target.test.ts +12 -0
  141. package/src/lib/__tests__/binary.test.ts +16 -1
  142. package/src/lib/__tests__/command-dx.test.ts +1 -1
  143. package/src/lib/__tests__/domain-publication.test.ts +10 -16
  144. package/src/lib/__tests__/idp.test.ts +34 -4
  145. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  146. package/src/lib/__tests__/instance-target.test.ts +7 -39
  147. package/src/lib/__tests__/log-errors.test.ts +64 -0
  148. package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
  149. package/src/lib/__tests__/update.test.ts +264 -11
  150. package/src/lib/__tests__/view-assets.test.ts +14 -0
  151. package/src/lib/__tests__/view-external-open-intent.test.ts +150 -0
  152. package/src/lib/__tests__/view-external-open-origins.test.ts +27 -0
  153. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  154. package/src/lib/__tests__/view-server.test.ts +26 -3
  155. package/src/lib/__tests__/view-session.test.ts +2 -1
  156. package/src/lib/admin-instance.ts +14 -8
  157. package/src/lib/admin-target.ts +21 -2
  158. package/src/lib/binary.ts +22 -5
  159. package/src/lib/command-dx.ts +9 -9
  160. package/src/lib/domain-publication.ts +9 -7
  161. package/src/lib/failure-debug.ts +26 -0
  162. package/src/lib/idp.ts +34 -3
  163. package/src/lib/instance-candidates.ts +2 -2
  164. package/src/lib/instance-target.ts +3 -14
  165. package/src/lib/instance.ts +16 -11
  166. package/src/lib/log.ts +16 -9
  167. package/src/lib/output.ts +1 -1
  168. package/src/lib/proc.ts +7 -2
  169. package/src/lib/provision-instance.ts +34 -57
  170. package/src/lib/update.ts +298 -45
  171. package/src/lib/validation.ts +2 -2
  172. package/src/lib/view/assets.ts +11 -2
  173. package/src/lib/view/external-open-intent.ts +41 -0
  174. package/src/lib/view/external-open-origins.ts +37 -0
  175. package/src/lib/view/host-capabilities.ts +17 -0
  176. package/src/lib/view/resolve.ts +1 -1
  177. package/src/lib/view/server.ts +18 -3
  178. package/src/lib/view/session.ts +2 -0
  179. package/src/program/.spec/api.d.ts +1 -0
  180. package/src/program/__tests__/program.test.ts +163 -6
  181. package/src/program/argv.ts +14 -0
  182. package/src/program/build.ts +26 -4
  183. package/src/program/command.ts +1 -0
  184. package/src/program/index.ts +1 -0
  185. package/src/program/registry.ts +2 -1
  186. package/src/setup/__tests__/instance-step.test.ts +27 -10
  187. package/src/setup/steps/instance.ts +22 -15
  188. package/src/telemetry/__tests__/recorder.test.ts +1 -0
  189. package/src/telemetry/recorder.ts +9 -1
  190. package/src/ui/.spec/api.d.ts +14 -0
  191. package/src/ui/.spec/architecture.md +10 -0
  192. package/src/ui/.spec/laws.ts +36 -0
  193. package/src/ui/.spec/layout.ts +16 -0
  194. package/src/ui/__tests__/ui.test.ts +981 -0
  195. package/src/ui/index.ts +13 -0
  196. package/src/ui/lock.ts +87 -0
  197. package/src/ui/model.ts +83 -0
  198. package/src/ui/operations.ts +710 -0
  199. package/src/ui/project.ts +219 -0
  200. package/src/ui/release.ts +321 -0
  201. package/src/ui/runner.ts +18 -0
  202. package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
  203. package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
  204. package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
  205. package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  206. package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
  207. package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
  208. package/studio/client/dist/index.html +3 -2
  209. package/studio/package.json +7 -13
  210. package/studio/server/agent/ask.test.ts +1 -1
  211. package/studio/server/agent/bridge/grant.test.ts +1 -1
  212. package/studio/server/agent/bridge/routes.test.ts +1 -1
  213. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  214. package/studio/server/agent/harness/gateway/token.test.ts +1 -1
  215. package/studio/server/agent/harness/gateway/token.ts +3 -3
  216. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  217. package/studio/server/agent/prompts/anchors.ts +20 -49
  218. package/studio/server/agent/prompts/system.test.ts +3 -2
  219. package/studio/server/agent/prompts/system.ts +3 -3
  220. package/studio/server/agent/routes.test.ts +1 -1
  221. package/studio/server/agent/run/coordinator.test.ts +1 -1
  222. package/studio/server/api/canvas.ts +0 -1
  223. package/studio/server/api-agent-loadout.test.ts +1 -1
  224. package/studio/server/api.test.ts +1 -1
  225. package/studio/server/cache.test.ts +23 -12
  226. package/studio/server/cache.ts +12 -15
  227. package/studio/server/domain.test.ts +50 -68
  228. package/studio/server/domain.ts +82 -63
  229. package/studio/server/handoff/copy.ts +1 -1
  230. package/studio/server/index.ts +1 -1
  231. package/studio/server/instances/probe.test.ts +1 -1
  232. package/studio/server/introspect/anatomy/views/routes.ts +46 -37
  233. package/studio/server/introspect/anatomy/views.ts +9 -14
  234. package/studio/server/introspect/anatomy-extras.test.ts +26 -42
  235. package/studio/server/introspect/anatomy.test.ts +22 -14
  236. package/studio/server/introspect/anatomy.ts +6 -9
  237. package/studio/server/introspect/bundle.ts +0 -3
  238. package/studio/server/introspect/canonical-schema.test.ts +94 -389
  239. package/studio/server/introspect/canonical-schema.ts +227 -457
  240. package/studio/server/introspect/core-extractor.ts +18 -127
  241. package/studio/server/introspect/core.ts +1 -2
  242. package/studio/server/introspect/diff.test.ts +11 -7
  243. package/studio/server/introspect/diff.ts +18 -55
  244. package/studio/server/introspect/extractor.ts +22 -117
  245. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  246. package/studio/server/introspect/overlay.test.ts +26 -54
  247. package/studio/server/introspect/overlay.ts +10 -37
  248. package/studio/server/introspect/revision.test.ts +1 -1
  249. package/studio/server/introspect/revision.ts +1 -1
  250. package/studio/server/introspect/runtime.test.ts +65 -183
  251. package/studio/server/introspect/runtime.ts +8 -25
  252. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  253. package/studio/server/introspect/schema-ir-json.ts +38 -68
  254. package/studio/server/introspect/schema-refs.test.ts +43 -88
  255. package/studio/server/introspect/schema-refs.ts +14 -49
  256. package/studio/server/introspect/source-overlay/handlers.ts +116 -636
  257. package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -3
  258. package/studio/server/introspect/source-overlay/spans.ts +15 -45
  259. package/studio/server/state/baseline.test.ts +14 -9
  260. package/studio/server/state/baseline.ts +3 -5
  261. package/studio/server/state/visibility.ts +1 -5
  262. package/studio/server/views/model.ts +3 -3
  263. package/studio/server/views/target.test.ts +17 -74
  264. package/studio/server/views/target.ts +24 -50
  265. package/studio/server/watch.test.ts +11 -11
  266. package/studio/server/watch.ts +8 -4
  267. package/studio/server/workspace-watch.ts +2 -2
  268. package/studio/shared/contracts/schema.ts +38 -107
  269. package/studio/shared/contracts/surface.test.ts +13 -15
  270. package/studio/shared/contracts/workspace.ts +2 -11
  271. package/studio/shared/schema/identity.test.ts +20 -44
  272. package/studio/shared/schema/identity.ts +9 -23
  273. package/viewer/dist/main.js +30 -51
  274. package/.check-workspace.cjs +0 -40
  275. package/src/admin/binding.ts +0 -168
  276. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  277. package/studio/client/dist/assets/elk-api-lwhFo7vB.js +0 -1
  278. package/studio/client/dist/assets/index-B-c-smo9.js +0 -8
  279. package/studio/client/dist/assets/index-BckHuAWk.js +0 -81
  280. package/studio/client/dist/assets/index-C4aNQ6dz.css +0 -1
  281. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  282. package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
@@ -6,6 +6,7 @@ import {
6
6
  DEFAULT_ADMIN_TARGET_NAME,
7
7
  DEFAULT_ADMIN_DOMAIN_ISSUER,
8
8
  DEFAULT_ADMIN_TARGET_URL,
9
+ defaultAdminTargetForChannel,
9
10
  resolveAdminTargetFromStore,
10
11
  } from '../admin-target'
11
12
  import { DEFAULT_CONFIG, type AstraleConfig } from '../config'
@@ -32,6 +33,17 @@ const instances: InstanceStore = {
32
33
  }
33
34
 
34
35
  describe('resolveAdminTargetFromStore', () => {
36
+ test('derives hosted Admin defaults from the release channel', () => {
37
+ expect(defaultAdminTargetForChannel('beta')).toEqual({
38
+ url: 'https://admin.eu.beta.astrale.ai/api',
39
+ domainIssuer: 'https://admin.beta.astrale.ai',
40
+ })
41
+ expect(defaultAdminTargetForChannel('stable')).toEqual({
42
+ url: 'https://admin.eu.astrale.ai/api',
43
+ domainIssuer: 'https://admin.astrale.ai',
44
+ })
45
+ })
46
+
35
47
  test('uses hosted admin default without active instance coupling', () => {
36
48
  expect(resolveAdminTargetFromStore({}, DEFAULT_CONFIG, instances)).toEqual({
37
49
  name: DEFAULT_ADMIN_TARGET_NAME,
@@ -39,11 +39,26 @@ describe('presentBinary', () => {
39
39
 
40
40
  test('--json inlines text for text-like content types', async () => {
41
41
  await presentBinary(
42
- { mediaType: 'text/plain', body: new TextEncoder().encode('hi') },
42
+ { mediaType: 'text/plain', status: 202, body: new TextEncoder().encode('hi') },
43
43
  { json: true },
44
44
  )
45
45
  const obj = JSON.parse(Buffer.concat(chunks).toString())
46
46
  expect(obj.body).toBe('hi')
47
+ expect(obj.status).toBe(202)
48
+ })
49
+
50
+ test('--raw drains streaming binary chunks in exact order', async () => {
51
+ await presentBinary(
52
+ {
53
+ mediaType: 'application/octet-stream',
54
+ body: (async function* () {
55
+ yield new Uint8Array([1, 2])
56
+ yield new Uint8Array([3, 4])
57
+ })(),
58
+ },
59
+ { raw: true },
60
+ )
61
+ expect(Array.from(Buffer.concat(chunks))).toEqual([1, 2, 3, 4])
47
62
  })
48
63
 
49
64
  test('-o writes raw bytes to a file', async () => {
@@ -16,7 +16,7 @@ function dx(
16
16
  error: CommanderError,
17
17
  argv: string[],
18
18
  ) {
19
- const rendered = JSON.parse(stripAnsi(renderCommanderError(program, error, argv))) as {
19
+ const rendered = JSON.parse(stripAnsi(renderCommanderError(program, error, argv, true))) as {
20
20
  error: string
21
21
  message: string
22
22
  detail: string
@@ -1,26 +1,15 @@
1
- import { publication } from '@astrale-os/kernel-protocol'
2
- import { defineDomain } from '@astrale-os/sdk'
3
- import { issuer } from '@astrale-os/sdk/auth'
4
- import { createDeployment } from '@astrale-os/sdk/deployment'
5
- import { defineSchema } from '@astrale-os/sdk/schema/v1'
1
+ import { publication } from '@astrale-os/sdk/publication'
2
+ import { defineSchema } from '@astrale-os/sdk/schema'
6
3
  import { describe, expect, test } from 'bun:test'
7
4
 
8
- import { fetchDomainPublication } from '../domain-publication'
5
+ import { releaseFor } from '../../__tests__/fixtures/publication'
6
+ import { domainPublicationUrl, fetchDomainPublication } from '../domain-publication'
9
7
 
10
8
  const ROOT = 'https://publication-reader.example.dev'
11
9
  const PUBLICATION_URL = `${ROOT}/.well-known/astrale/domain.json`
12
10
  const MAXIMUM_PUBLICATION_BYTES = 1024 * 1024
13
11
  const schema = defineSchema('publication-reader.example.dev', {})
14
- const definition = defineDomain({
15
- schema,
16
- handlers: { functions: {}, classes: {}, interfaces: {} },
17
- })
18
- const deployed = createDeployment({
19
- definition,
20
- issuer: issuer.accept(ROOT),
21
- bundleHref: `${ROOT}/domain.bundle.json`,
22
- bindings: { callables: [] },
23
- }).publication
12
+ const deployed = releaseFor(schema, ROOT).publication
24
13
 
25
14
  describe('Domain Publication reader', () => {
26
15
  test('fetches only the canonical path with redirects disabled', async () => {
@@ -34,6 +23,11 @@ describe('Domain Publication reader', () => {
34
23
  expect(requests).toEqual([{ url: PUBLICATION_URL, redirect: 'error' }])
35
24
  })
36
25
 
26
+ test('normalizes an origin and admits the exact canonical Publication URL', () => {
27
+ expect(domainPublicationUrl(ROOT).href).toBe(PUBLICATION_URL)
28
+ expect(domainPublicationUrl(PUBLICATION_URL).href).toBe(PUBLICATION_URL)
29
+ })
30
+
37
31
  test('propagates redirect rejection instead of accepting another target', async () => {
38
32
  const fetch = async (_input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
39
33
  expect(init?.redirect).toBe('error')
@@ -9,6 +9,7 @@ import {
9
9
  IdpSessionSchema,
10
10
  isSessionExpired,
11
11
  issuerFromToken,
12
+ legacyBuiltinWorkosReplacement,
12
13
  normalizeTokenResponse,
13
14
  OAuthTokenError,
14
15
  OidcMetadataSchema,
@@ -63,8 +64,11 @@ describe('IdP schemas and token helpers', () => {
63
64
  expect(config?.client.token_request_format).toBe('json')
64
65
  })
65
66
 
66
- test('does not invent a WorkOS environment when no client id is configured', () => {
67
- expect(builtinIdpConfig('workos', undefined, {})).toBeNull()
67
+ test('builds the built-in WorkOS IdP with the public client id by default', () => {
68
+ const config = builtinIdpConfig('workos', undefined, {})
69
+
70
+ expect(config?.entry.builtIn).toBe(true)
71
+ expect(config?.client.client_id).toBe('client_01KC29HET5F3QAQ8GNTPZ7F320')
68
72
  })
69
73
 
70
74
  test('reads WorkOS client id from WORKOS_CLIENT_ID before VITE_WORKOS_CLIENT_ID', () => {
@@ -75,8 +79,34 @@ describe('IdP schemas and token helpers', () => {
75
79
  }),
76
80
  ).toBe('client_primary')
77
81
  expect(workosClientIdFromEnv({ VITE_WORKOS_CLIENT_ID: 'client_vite' })).toBe('client_vite')
78
- expect(workosClientIdFromEnv({})).toBeUndefined()
79
- expect(workosClientIdFromEnv({ WORKOS_CLIENT_ID: ' ' })).toBeUndefined()
82
+ expect(workosClientIdFromEnv({})).toBe('client_01KC29HET5F3QAQ8GNTPZ7F320')
83
+ expect(workosClientIdFromEnv({ WORKOS_CLIENT_ID: ' ' })).toBe(
84
+ 'client_01KC29HET5F3QAQ8GNTPZ7F320',
85
+ )
86
+ })
87
+
88
+ test('replaces only the legacy persisted built-in WorkOS client', () => {
89
+ const legacy = builtinIdpConfig('workos', 'client_01KC29HEGD7B40TV2C4QZ436BG', {})!
90
+ const replacement = legacyBuiltinWorkosReplacement(legacy, undefined, {})
91
+
92
+ expect(replacement?.client.client_id).toBe('client_01KC29HET5F3QAQ8GNTPZ7F320')
93
+ expect(replacement?.metadata.jwks_uri).toBe(
94
+ 'https://api.workos.com/sso/jwks/client_01KC29HET5F3QAQ8GNTPZ7F320',
95
+ )
96
+ expect(
97
+ legacyBuiltinWorkosReplacement(
98
+ { ...legacy, entry: { ...legacy.entry, builtIn: false } },
99
+ undefined,
100
+ {},
101
+ ),
102
+ ).toBeUndefined()
103
+ expect(
104
+ legacyBuiltinWorkosReplacement(
105
+ { ...legacy, client: { ...legacy.client, client_id: 'client_custom' } },
106
+ undefined,
107
+ {},
108
+ ),
109
+ ).toBeUndefined()
80
110
  })
81
111
 
82
112
  test('stores client secret env names, not secret material', () => {
@@ -18,7 +18,6 @@ const managedDemo: OwnedInstanceInfo = {
18
18
  slug: 'demo',
19
19
  url: 'https://demo.eu.astrale.ai',
20
20
  state: 'ready',
21
- region: 'eu',
22
21
  }
23
22
 
24
23
  describe('collectInstanceCandidates', () => {
@@ -138,11 +137,10 @@ describe('describeInstanceCandidate', () => {
138
137
  slug: 'twin',
139
138
  url: 'https://twin.eu.astrale.ai',
140
139
  state: 'ready',
141
- region: 'eu',
142
140
  },
143
141
  ])
144
142
  expect(describeInstanceCandidate(managed!)).toBe(
145
- 'twin (managed) https://twin.eu.astrale.ai/api — eu',
143
+ 'twin (managed) https://twin.eu.astrale.ai/api',
146
144
  )
147
145
  })
148
146
  })
@@ -3,6 +3,7 @@ import { describe, expect, test } from 'bun:test'
3
3
  import type { AstraleConfig } from '../config'
4
4
  import type { InstanceStore } from '../instance'
5
5
 
6
+ import { AdminInstanceNotFoundError } from '../../admin/instance/model'
6
7
  import { AstraleError } from '../../errors'
7
8
  import { DEFAULT_CONFIG } from '../config'
8
9
  import {
@@ -112,6 +113,7 @@ describe('resolveInstanceTarget', () => {
112
113
  id: 'node-1',
113
114
  slug,
114
115
  url: `https://${slug}.eu.astrale.ai`,
116
+ state: 'ready',
115
117
  }),
116
118
  },
117
119
  ),
@@ -124,9 +126,6 @@ describe('resolveInstanceTarget', () => {
124
126
  })
125
127
 
126
128
  test('unknown slugs surface the original instance-not-found error', async () => {
127
- const notFound = new Error('Path not found: "/admin/instances/missing"')
128
- notFound.name = 'NotFoundError'
129
-
130
129
  await expect(
131
130
  resolveInstanceTarget(
132
131
  { source: 'name', name: 'missing' },
@@ -134,7 +133,7 @@ describe('resolveInstanceTarget', () => {
134
133
  config: DEFAULT_CONFIG,
135
134
  instances: emptyStore,
136
135
  managed: async () => {
137
- throw notFound
136
+ throw new AdminInstanceNotFoundError('missing')
138
137
  },
139
138
  },
140
139
  ),
@@ -168,14 +167,8 @@ describe('instance target helpers', () => {
168
167
  expect(couldBeConfiguredAdminInstance('bryan', directAdminConfig)).toBe(false)
169
168
  })
170
169
 
171
- test('treats wrapped remote Instance.info misses as managed lookup not-found', () => {
172
- const wrapped = new Error('Path not found: "/admin/instances/admin"') as Error & {
173
- data?: unknown
174
- }
175
- wrapped.name = 'KernelError'
176
- wrapped.data = { type: 'NotFoundError' }
177
-
178
- expect(isManagedInstanceNotFound(wrapped)).toBe(true)
170
+ test('treats the owner-scoped Admin error as managed lookup not-found', () => {
171
+ expect(isManagedInstanceNotFound(new AdminInstanceNotFoundError('admin'))).toBe(true)
179
172
  })
180
173
 
181
174
  test('does not hide non-not-found managed lookup failures', () => {
@@ -194,37 +187,12 @@ describe('instance target helpers', () => {
194
187
  })
195
188
  })
196
189
 
197
- describe('isManagedInstanceNotFound: kernel InternalKernelError wrap', () => {
198
- test('NOT_FOUND-prefixed InternalKernelError is an instance miss', () => {
199
- const e = new Error('NOT_FOUND: no instance node for "knowledge"')
200
- e.name = 'InternalKernelError'
201
- expect(isManagedInstanceNotFound(e)).toBe(true)
202
- })
203
- test('other InternalKernelError messages are not swallowed', () => {
190
+ describe('isManagedInstanceNotFound: unknown errors', () => {
191
+ test('does not infer a miss from an InternalKernelError message', () => {
204
192
  const e = new Error('DISPATCH_FAILED: handler crashed')
205
193
  e.name = 'InternalKernelError'
206
194
  expect(isManagedInstanceNotFound(e)).toBe(false)
207
195
  })
208
- test('resolveNamedInstanceTarget maps the wrap to typed INSTANCE_NOT_FOUND', async () => {
209
- const managed = async () => {
210
- const e = new Error('NOT_FOUND: no instance node for "ghost"')
211
- e.name = 'InternalKernelError'
212
- throw e
213
- }
214
- const opts = {
215
- config: DEFAULT_CONFIG,
216
- instances: { instances: {} },
217
- managed,
218
- } as unknown as Parameters<typeof resolveInstanceTarget>[1]
219
- let caught: unknown
220
- try {
221
- await resolveInstanceTarget({ source: 'name', name: 'ghost' }, opts)
222
- } catch (e) {
223
- caught = e
224
- }
225
- expect(caught).toBeInstanceOf(AstraleError)
226
- expect((caught as AstraleError).code).toBe('INSTANCE_NOT_FOUND')
227
- })
228
196
 
229
197
  test('maps Admin token-exchange failure to INSTANCE_NOT_FOUND', async () => {
230
198
  const managed = async () => {
@@ -0,0 +1,64 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
2
+
3
+ import { AstraleError } from '../../errors'
4
+ import { failInput, fatal } from '../log'
5
+
6
+ class ExitError extends Error {}
7
+
8
+ let stderr = ''
9
+ let exit: typeof process.exit
10
+ let write: typeof process.stderr.write
11
+
12
+ beforeEach(() => {
13
+ stderr = ''
14
+ exit = process.exit
15
+ write = process.stderr.write
16
+ process.exit = (() => {
17
+ throw new ExitError()
18
+ }) as typeof process.exit
19
+ process.stderr.write = ((chunk: string | Uint8Array) => {
20
+ stderr += String(chunk)
21
+ return true
22
+ }) as typeof process.stderr.write
23
+ })
24
+
25
+ afterEach(() => {
26
+ process.exit = exit
27
+ process.stderr.write = write
28
+ })
29
+
30
+ describe('terminal error safety', () => {
31
+ test('renders an empty aggregate as an honest non-blank unexpected failure', () => {
32
+ expect(() => fatal(new AggregateError([], ''), { json: true })).toThrow(ExitError)
33
+ expect(JSON.parse(stderr)).toEqual({
34
+ error: 'UNEXPECTED_ERROR',
35
+ message: 'The CLI encountered an unexpected internal failure.',
36
+ })
37
+ })
38
+
39
+ test('retains unknown failure evidence only under explicit debug output', () => {
40
+ const failure = new AggregateError([new Error('provider rejected organization scope')], '')
41
+
42
+ expect(() => fatal(failure, { json: true, debug: true })).toThrow(ExitError)
43
+
44
+ expect(stderr).toContain(
45
+ '{"error":"UNEXPECTED_ERROR","message":"The CLI encountered an unexpected internal failure."}',
46
+ )
47
+ expect(stderr).toContain('aggregate: Error: provider rejected organization scope')
48
+ })
49
+
50
+ test('rejects blank admitted CLI diagnostics', () => {
51
+ expect(() => new AstraleError('INVALID_INPUT', ' ')).toThrow(TypeError)
52
+ })
53
+
54
+ test('labels only expected admission failures as invalid input', () => {
55
+ expect(() => failInput(new TypeError('Authored value is invalid.'), { json: true })).toThrow(
56
+ ExitError,
57
+ )
58
+ expect(JSON.parse(stderr)).toMatchObject({ error: 'INVALID_INPUT' })
59
+
60
+ stderr = ''
61
+ expect(() => failInput(new AggregateError([], ''), { json: true })).toThrow(ExitError)
62
+ expect(JSON.parse(stderr)).toMatchObject({ error: 'UNEXPECTED_ERROR' })
63
+ })
64
+ })
@@ -103,7 +103,7 @@ describe('studio server runtime deps', () => {
103
103
  describe('studio test gate', () => {
104
104
  test('the root and Studio suites include all client, server, and shared tests', () => {
105
105
  expect(cliPackage.scripts?.test).toBe(
106
- 'bun test src studio/client/src studio/server studio/shared && node --test scripts/*.test.mjs',
106
+ 'node scripts/qualification/source-boundary.mjs --target && bun test src studio/client/src studio/server studio/shared && node --test scripts/*.test.mjs',
107
107
  )
108
108
  expect(cliPackage.scripts?.['test:studio']).toBe('pnpm --dir studio test')
109
109
  expect(studioPackage.scripts?.test).toBe('bun test client/src server shared')