@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.
- package/README.md +23 -12
- package/dist/astrale.js +48048 -56798
- package/dist/public/connect-core.js +2011 -30765
- package/dist/public/keys/index.js +884 -29483
- package/dist/public/paths/index.js +13101 -41459
- package/dist/types/admin/binding.d.ts +19 -0
- package/dist/types/admin/instance/client.d.ts +22 -0
- package/dist/types/admin/instance/index.d.ts +2 -0
- package/dist/types/admin/instance/model.d.ts +5 -12
- package/dist/types/connection/auth.d.ts +3 -0
- package/dist/types/connection/call.d.ts +3 -0
- package/dist/types/connection/command.d.ts +27 -0
- package/dist/types/connection/credential.d.ts +14 -0
- package/dist/types/connection/errors.d.ts +1 -0
- package/dist/types/connection/exchange.d.ts +9 -0
- package/dist/types/connection/failure/classify.d.ts +2 -0
- package/dist/types/connection/failure/index.d.ts +5 -0
- package/dist/types/connection/failure/model.d.ts +25 -0
- package/dist/types/connection/failure/render.d.ts +3 -0
- package/dist/types/connection/index.d.ts +8 -0
- package/dist/types/connection/reasons.d.ts +37 -0
- package/dist/types/connection/self.d.ts +37 -0
- package/dist/types/connection/session.d.ts +31 -0
- package/dist/types/connection/target.d.ts +38 -0
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/lib/admin-instance.d.ts +17 -0
- package/dist/types/lib/admin-target.d.ts +11 -36
- package/dist/types/lib/config.d.ts +7 -59
- package/dist/types/lib/failure-debug.d.ts +1 -0
- package/dist/types/lib/idp.d.ts +26 -168
- package/dist/types/lib/instance-target.d.ts +1 -1
- package/dist/types/lib/instance.d.ts +30 -88
- package/dist/types/lib/log.d.ts +5 -3
- package/dist/types/lib/meta.d.ts +2 -2
- package/dist/types/lib/proc.d.ts +43 -0
- package/dist/types/lib/self.d.ts +9 -0
- package/dist/types/lib/update.d.ts +91 -0
- package/dist/types/lib/validation.d.ts +4 -1
- package/package.json +16 -19
- package/src/__tests__/fixtures/publication.ts +20 -0
- package/src/admin/__tests__/binding.test.ts +31 -0
- package/src/admin/__tests__/fixture.ts +101 -0
- package/src/admin/binding.ts +98 -0
- package/src/admin/catalog/.spec/api.d.ts +2 -2
- package/src/admin/catalog/__tests__/client.test.ts +20 -49
- package/src/admin/catalog/client.ts +36 -32
- package/src/admin/catalog/model.ts +3 -4
- package/src/admin/graph/.spec/api.d.ts +4 -10
- package/src/admin/graph/nodes.ts +1 -1
- package/src/admin/instance/.spec/api.d.ts +2 -2
- package/src/admin/instance/__tests__/client.test.ts +39 -164
- package/src/admin/instance/client.ts +35 -124
- package/src/admin/instance/index.ts +1 -2
- package/src/admin/instance/model.ts +11 -20
- package/src/commands/__tests__/admin-instance.test.ts +11 -8
- package/src/commands/__tests__/auth-login.test.ts +54 -1
- package/src/commands/__tests__/call-describe.test.ts +46 -33
- package/src/commands/__tests__/call.test.ts +5 -1
- package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
- package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
- package/src/commands/__tests__/domain-list.test.ts +63 -4
- package/src/commands/__tests__/install-identity-override.test.ts +19 -19
- package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
- package/src/commands/__tests__/instance-status.test.ts +139 -0
- package/src/commands/__tests__/read-commands.test.ts +35 -10
- package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
- package/src/commands/__tests__/update.test.ts +48 -19
- package/src/commands/call-describe.ts +60 -68
- package/src/commands/call.ts +43 -56
- package/src/commands/domain/install.ts +13 -17
- package/src/commands/domain/list.ts +18 -13
- package/src/commands/domain/publish.ts +14 -11
- package/src/commands/domain/uninstall.ts +2 -2
- package/src/commands/get.ts +14 -15
- package/src/commands/identity/__tests__/register.test.ts +3 -3
- package/src/commands/identity/register.ts +5 -4
- package/src/commands/instance/create.ts +8 -16
- package/src/commands/instance/delete.ts +12 -9
- package/src/commands/instance/list.ts +2 -2
- package/src/commands/instance/status.ts +66 -20
- package/src/commands/instance/use.ts +16 -12
- package/src/commands/introspect.ts +9 -16
- package/src/commands/logs.ts +24 -25
- package/src/commands/mutate.ts +6 -5
- package/src/commands/query.ts +27 -30
- package/src/commands/studio.ts +20 -0
- package/src/commands/token.ts +8 -7
- package/src/commands/update.ts +38 -14
- package/src/commands/view.ts +7 -6
- package/src/connection/.spec/api.d.ts +7 -8
- package/src/connection/.spec/architecture.md +5 -4
- package/src/connection/.spec/flows/session.ts +2 -2
- package/src/connection/.spec/laws/connection.ts +6 -2
- package/src/connection/.spec/layout.ts +1 -0
- package/src/connection/__tests__/credential.test.ts +20 -1
- package/src/connection/__tests__/errors.test.ts +43 -32
- package/src/connection/__tests__/exchange.test.ts +36 -6
- package/src/connection/__tests__/failure-fixtures.ts +39 -0
- package/src/connection/__tests__/failure-safety.test.ts +75 -0
- package/src/connection/__tests__/self.test.ts +31 -11
- package/src/connection/__tests__/session.test.ts +3 -3
- package/src/connection/__tests__/target.test.ts +1 -0
- package/src/connection/auth.ts +13 -0
- package/src/connection/call.ts +1 -1
- package/src/connection/credential.ts +2 -2
- package/src/connection/errors.ts +1 -355
- package/src/connection/exchange.ts +52 -27
- package/src/connection/failure/classify.ts +110 -0
- package/src/connection/failure/index.ts +18 -0
- package/src/connection/failure/model.ts +28 -0
- package/src/connection/failure/render.ts +116 -0
- package/src/connection/reasons.ts +16 -0
- package/src/connection/self.ts +39 -21
- package/src/connection/session.ts +19 -8
- package/src/errors.ts +3 -2
- package/src/graph/.spec/api.d.ts +12 -5
- package/src/graph/.spec/layout.ts +9 -1
- package/src/graph/__tests__/mutation.test.ts +2 -2
- package/src/graph/__tests__/query.test.ts +25 -6
- package/src/graph/class.ts +30 -0
- package/src/graph/index.ts +1 -0
- package/src/graph/query.ts +21 -32
- package/src/identity/.spec/api.d.ts +2 -2
- package/src/identity/__tests__/registration.test.ts +1 -1
- package/src/identity/registration.ts +3 -3
- package/src/keys/__tests__/keys.test.ts +4 -0
- package/src/keys/credential.ts +1 -0
- package/src/lib/__tests__/admin-target.test.ts +12 -0
- package/src/lib/__tests__/command-dx.test.ts +1 -1
- package/src/lib/__tests__/domain-publication.test.ts +138 -0
- package/src/lib/__tests__/idp-session.test.ts +22 -0
- package/src/lib/__tests__/idp.test.ts +36 -4
- package/src/lib/__tests__/instance-candidates.test.ts +1 -3
- package/src/lib/__tests__/instance-target.test.ts +7 -39
- package/src/lib/__tests__/instance.test.ts +6 -0
- package/src/lib/__tests__/log-errors.test.ts +64 -0
- package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
- package/src/lib/__tests__/update.test.ts +113 -8
- package/src/lib/__tests__/view-open-intent.test.ts +0 -2
- package/src/lib/__tests__/view-server.test.ts +18 -3
- package/src/lib/__tests__/view-session.test.ts +1 -1
- package/src/lib/admin-instance.ts +14 -8
- package/src/lib/admin-target.ts +21 -2
- package/src/lib/command-dx.ts +9 -9
- package/src/lib/domain-publication.ts +104 -0
- package/src/lib/failure-debug.ts +26 -0
- package/src/lib/idp.ts +39 -4
- package/src/lib/instance-candidates.ts +2 -2
- package/src/lib/instance-target.ts +3 -14
- package/src/lib/instance.ts +22 -12
- package/src/lib/log.ts +16 -9
- package/src/lib/login-flow.ts +13 -3
- package/src/lib/meta.ts +2 -2
- package/src/lib/provision-instance.ts +34 -57
- package/src/lib/update.ts +124 -30
- package/src/lib/validation.ts +2 -2
- package/src/lib/view/resolve.ts +1 -1
- package/src/lib/view/server.ts +17 -3
- package/src/program/__tests__/program.test.ts +20 -4
- package/src/program/build.ts +2 -2
- package/src/setup/__tests__/instance-step.test.ts +27 -10
- package/src/setup/steps/instance.ts +22 -15
- package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
- package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
- package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
- package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
- package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
- package/studio/client/dist/index.html +3 -2
- package/studio/package.json +10 -14
- package/studio/server/agent/ask.test.ts +1 -1
- package/studio/server/agent/bridge/grant.test.ts +1 -1
- package/studio/server/agent/bridge/routes.test.ts +1 -1
- package/studio/server/agent/bridge/stdio.ts +8 -1
- package/studio/server/agent/conversation.test.ts +10 -5
- package/studio/server/agent/conversation.ts +56 -8
- package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
- package/studio/server/agent/harness/codex/loadout.ts +18 -21
- package/studio/server/agent/harness/gateway/config.ts +20 -18
- package/studio/server/agent/harness/selection.ts +9 -1
- package/studio/server/agent/prompts/anchors.test.ts +32 -36
- package/studio/server/agent/prompts/anchors.ts +20 -49
- package/studio/server/agent/prompts/system.test.ts +3 -2
- package/studio/server/agent/prompts/system.ts +6 -5
- package/studio/server/agent/prompts/turn.ts +13 -4
- package/studio/server/agent/routes.test.ts +1 -1
- package/studio/server/agent/run/completion.ts +2 -2
- package/studio/server/agent/run/coordinator.test.ts +1 -1
- package/studio/server/agent/run/preparation.ts +6 -5
- package/studio/server/agent/run/transcript.test.ts +35 -1
- package/studio/server/agent/run/transcript.ts +169 -3
- package/studio/server/agent/run/usage.test.ts +24 -0
- package/studio/server/agent/run/usage.ts +26 -1
- package/studio/server/api/canvas.ts +43 -0
- package/studio/server/api/comments.ts +85 -0
- package/studio/server/api/context.ts +61 -0
- package/studio/server/api/deployment.ts +39 -0
- package/studio/server/api/documents.ts +55 -0
- package/studio/server/api/domain.ts +59 -0
- package/studio/server/api/http.ts +45 -0
- package/studio/server/api/project.ts +57 -0
- package/studio/server/api/schema.ts +12 -0
- package/studio/server/api/views.ts +57 -0
- package/studio/server/api/workspace.ts +60 -0
- package/studio/server/api-agent-loadout.test.ts +1 -1
- package/studio/server/api.test.ts +147 -0
- package/studio/server/api.ts +20 -422
- package/studio/server/cache.test.ts +122 -0
- package/studio/server/cache.ts +162 -11
- package/studio/server/cli-consumers.test.ts +494 -0
- package/studio/server/cli.test.ts +88 -0
- package/studio/server/cli.ts +240 -0
- package/studio/server/client-package.ts +25 -1
- package/studio/server/domain.test.ts +50 -40
- package/studio/server/domain.ts +83 -52
- package/studio/server/environment/dotenv-preview.test.ts +39 -0
- package/studio/server/environment/dotenv-preview.ts +27 -0
- package/studio/server/environment/files.test.ts +53 -0
- package/studio/server/{state/env.ts → environment/files.ts} +7 -48
- package/studio/server/{state → handoff}/copy.ts +21 -6
- package/studio/server/handoff/service.test.ts +22 -0
- package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
- package/studio/server/index.ts +1 -1
- package/studio/server/instances/active.ts +72 -0
- package/studio/server/instances/deploy-record.test.ts +31 -0
- package/studio/server/instances/deploy-record.ts +37 -0
- package/studio/server/instances/deploy.ts +56 -0
- package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
- package/studio/server/instances/probe.ts +67 -0
- package/studio/server/instances/status.test.ts +12 -0
- package/studio/server/instances/status.ts +49 -0
- package/studio/server/introspect/anatomy/client-tree.ts +57 -0
- package/studio/server/introspect/anatomy/env-fields.ts +66 -0
- package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
- package/studio/server/introspect/anatomy/source.ts +181 -0
- package/studio/server/introspect/anatomy/views/routes.ts +114 -0
- package/studio/server/introspect/anatomy/views.ts +53 -0
- package/studio/server/introspect/anatomy-extras.test.ts +106 -35
- package/studio/server/introspect/anatomy-extras.ts +7 -726
- package/studio/server/introspect/anatomy.test.ts +22 -14
- package/studio/server/introspect/anatomy.ts +52 -28
- package/studio/server/introspect/bundle.ts +15 -9
- package/studio/server/introspect/canonical-schema.test.ts +93 -309
- package/studio/server/introspect/canonical-schema.ts +257 -425
- package/studio/server/introspect/config-preview.test.ts +32 -0
- package/studio/server/introspect/config-preview.ts +119 -0
- package/studio/server/introspect/core-extractor.ts +18 -127
- package/studio/server/introspect/core.ts +1 -2
- package/studio/server/introspect/diff.test.ts +18 -18
- package/studio/server/introspect/diff.ts +44 -90
- package/studio/server/introspect/extractor.ts +23 -116
- package/studio/server/introspect/hash.ts +5 -2
- package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
- package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
- package/studio/server/introspect/overlay.test.ts +26 -54
- package/studio/server/introspect/overlay.ts +10 -37
- package/studio/server/introspect/revision.test.ts +54 -0
- package/studio/server/introspect/revision.ts +49 -0
- package/studio/server/introspect/runtime.test.ts +83 -143
- package/studio/server/introspect/runtime.ts +40 -11
- package/studio/server/introspect/schema-ir-json.test.ts +70 -0
- package/studio/server/introspect/schema-ir-json.ts +151 -0
- package/studio/server/introspect/schema-refs.test.ts +43 -88
- package/studio/server/introspect/schema-refs.ts +14 -49
- package/studio/server/introspect/source-overlay/annotations.ts +14 -0
- package/studio/server/introspect/source-overlay/handlers.ts +161 -0
- package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
- package/studio/server/introspect/source-overlay/project.ts +248 -0
- package/studio/server/introspect/source-overlay/spans.ts +330 -0
- package/studio/server/json.ts +46 -0
- package/studio/server/lifecycle.ts +5 -1
- package/studio/server/sse.test.ts +26 -0
- package/studio/server/sse.ts +4 -1
- package/studio/server/state/baseline.test.ts +223 -7
- package/studio/server/state/baseline.ts +148 -34
- package/studio/server/state/comments.test.ts +66 -1
- package/studio/server/state/comments.ts +173 -10
- package/studio/server/state/context.ts +34 -2
- package/studio/server/state/documents.ts +42 -1
- package/studio/server/state/integrations.ts +27 -1
- package/studio/server/state/layout.test.ts +34 -0
- package/studio/server/state/layout.ts +44 -17
- package/studio/server/state/settings.ts +29 -22
- package/studio/server/state/store.test.ts +122 -0
- package/studio/server/state/store.ts +66 -17
- package/studio/server/state/visibility.ts +22 -11
- package/studio/server/views/model.test.ts +57 -0
- package/studio/server/views/model.ts +66 -0
- package/studio/server/views/runtime.ts +40 -0
- package/studio/server/views/selection-repository.test.ts +31 -0
- package/studio/server/views/selection-repository.ts +60 -0
- package/studio/server/views/session.test.ts +73 -0
- package/studio/server/views/session.ts +166 -0
- package/studio/server/views/target.test.ts +78 -0
- package/studio/server/views/target.ts +222 -0
- package/studio/server/watch.test.ts +11 -11
- package/studio/server/watch.ts +9 -5
- package/studio/server/workspace/catalog.test.ts +17 -0
- package/studio/server/workspace/catalog.ts +43 -0
- package/studio/server/{state → workspace}/create.test.ts +1 -1
- package/studio/server/{state → workspace}/create.ts +1 -1
- package/studio/server/{state → workspace}/git.ts +1 -1
- package/studio/server/workspace/updates.ts +83 -0
- package/studio/server/workspace-state.ts +1 -1
- package/studio/server/workspace-watch.ts +2 -2
- package/studio/shared/contracts/README.md +16 -0
- package/studio/shared/contracts/agent.ts +270 -0
- package/studio/shared/contracts/runtime.ts +50 -0
- package/studio/shared/contracts/schema.ts +393 -0
- package/studio/shared/contracts/surface.test.ts +317 -0
- package/studio/shared/contracts/workspace.ts +265 -0
- package/studio/shared/layout.test.ts +116 -0
- package/studio/shared/schema/identity.test.ts +34 -0
- package/studio/shared/schema/identity.ts +68 -0
- package/studio/shared/types.ts +11 -1099
- package/studio/tsconfig.json +1 -1
- package/viewer/dist/main.js +40 -61
- package/.check-workspace.cjs +0 -40
- package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
- package/studio/client/dist/assets/elk-api-D2xgMJvi.js +0 -1
- package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
- package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
- package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
- package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
- package/studio/server/state/catalog.ts +0 -117
- package/studio/server/state/instance.ts +0 -280
- package/studio/server/state/updates.ts +0 -63
- package/studio/server/state/views.test.ts +0 -286
- package/studio/server/state/views.ts +0 -535
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Schema-anchored review comment routes and agent reply merge. */
|
|
2
|
+
import { getBundle } from '../cache'
|
|
3
|
+
import { schemaRefs } from '../introspect/schema-refs'
|
|
4
|
+
import {
|
|
5
|
+
addThreadEntry,
|
|
6
|
+
deleteComment,
|
|
7
|
+
editThreadEntry,
|
|
8
|
+
markOrphans,
|
|
9
|
+
mergeReply,
|
|
10
|
+
readComments,
|
|
11
|
+
setStatus,
|
|
12
|
+
upsertComment,
|
|
13
|
+
} from '../state/comments'
|
|
14
|
+
import { badRequest, json, notFound, type DomainRouteContext } from './http'
|
|
15
|
+
|
|
16
|
+
export async function handleCommentRoute(context: DomainRouteContext): Promise<Response | null> {
|
|
17
|
+
const { req, rest, body, handle, notify } = context
|
|
18
|
+
const id = handle.id
|
|
19
|
+
const root = handle.root
|
|
20
|
+
|
|
21
|
+
if (rest === '/comments') {
|
|
22
|
+
if (req.method === 'GET') {
|
|
23
|
+
const bundle = await getBundle(id)
|
|
24
|
+
const valid = new Set<string>(bundle ? schemaRefs(bundle) : [])
|
|
25
|
+
for (const key of Object.keys(bundle?.overlay.sourceSpans ?? {})) valid.add(key)
|
|
26
|
+
const store = readComments(root)
|
|
27
|
+
for (const comment of store.comments) {
|
|
28
|
+
for (const anchor of comment.anchorRefs) {
|
|
29
|
+
if (anchor.kind !== 'schema') valid.add(anchor.ref)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return json(markOrphans(root, [...valid]))
|
|
33
|
+
}
|
|
34
|
+
if (body.action === 'create') {
|
|
35
|
+
const bundle = await getBundle(id)
|
|
36
|
+
const comment = upsertComment(root, {
|
|
37
|
+
anchors: body.anchors ?? [],
|
|
38
|
+
anchorRefs: body.anchorRefs ?? [],
|
|
39
|
+
text: body.text,
|
|
40
|
+
firstRole: body.firstRole,
|
|
41
|
+
type: body.type,
|
|
42
|
+
options: body.options,
|
|
43
|
+
schemaVersion: bundle?.renderFingerprint,
|
|
44
|
+
})
|
|
45
|
+
notify({ type: 'comments', domainId: id })
|
|
46
|
+
return json(comment)
|
|
47
|
+
}
|
|
48
|
+
if (body.action === 'reply') {
|
|
49
|
+
const comment = addThreadEntry(root, body.id, body.entry)
|
|
50
|
+
notify({ type: 'comments', domainId: id })
|
|
51
|
+
return comment ? json(comment) : notFound()
|
|
52
|
+
}
|
|
53
|
+
if (body.action === 'edit') {
|
|
54
|
+
const comment = editThreadEntry(root, body.id, body.entryId, String(body.text ?? ''))
|
|
55
|
+
notify({ type: 'comments', domainId: id })
|
|
56
|
+
return comment ? json(comment) : notFound()
|
|
57
|
+
}
|
|
58
|
+
if (body.action === 'status') {
|
|
59
|
+
const comment = setStatus(root, body.id, body.status, body.closeNote)
|
|
60
|
+
notify({ type: 'comments', domainId: id })
|
|
61
|
+
return comment ? json(comment) : notFound()
|
|
62
|
+
}
|
|
63
|
+
if (body.action === 'delete') {
|
|
64
|
+
const ok = deleteComment(root, body.id)
|
|
65
|
+
notify({ type: 'comments', domainId: id })
|
|
66
|
+
return json({ ok })
|
|
67
|
+
}
|
|
68
|
+
return badRequest('unknown comments action')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (rest === '/comments/merge' && req.method === 'POST') {
|
|
72
|
+
const bundle = await getBundle(id)
|
|
73
|
+
try {
|
|
74
|
+
const result = mergeReply(root, bundle?.renderFingerprint ?? '', String(body.text ?? ''), {
|
|
75
|
+
dedupeAuthorText: true,
|
|
76
|
+
})
|
|
77
|
+
notify({ type: 'comments', domainId: id })
|
|
78
|
+
return json(result)
|
|
79
|
+
} catch (error: any) {
|
|
80
|
+
return badRequest(String(error?.message ?? error))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Authored/automatic agent context and copy-handoff routes. */
|
|
2
|
+
import { getBundle } from '../cache'
|
|
3
|
+
import { buildCopyMarkdown } from '../handoff/copy'
|
|
4
|
+
import { refreshAuto } from '../handoff/service'
|
|
5
|
+
import { readComments } from '../state/comments'
|
|
6
|
+
import {
|
|
7
|
+
addUserContext,
|
|
8
|
+
deleteContext,
|
|
9
|
+
readContext,
|
|
10
|
+
setAutoInclude,
|
|
11
|
+
updateContext,
|
|
12
|
+
} from '../state/context'
|
|
13
|
+
import { listDocuments } from '../state/documents'
|
|
14
|
+
import { badRequest, json, notFound, type DomainRouteContext } from './http'
|
|
15
|
+
|
|
16
|
+
export async function handleContextRoute(context: DomainRouteContext): Promise<Response | null> {
|
|
17
|
+
const { req, rest, body, handle, notify } = context
|
|
18
|
+
const id = handle.id
|
|
19
|
+
const root = handle.root
|
|
20
|
+
|
|
21
|
+
if (rest === '/context') {
|
|
22
|
+
if (req.method === 'GET') return json(readContext(root))
|
|
23
|
+
if (body.action === 'add') {
|
|
24
|
+
const item = addUserContext(root, body)
|
|
25
|
+
notify({ type: 'comments', domainId: id })
|
|
26
|
+
return json(item)
|
|
27
|
+
}
|
|
28
|
+
if (body.action === 'update') {
|
|
29
|
+
const item = updateContext(root, body.id, body)
|
|
30
|
+
return item ? json(item) : notFound()
|
|
31
|
+
}
|
|
32
|
+
if (body.action === 'delete') return json({ ok: deleteContext(root, body.id) })
|
|
33
|
+
if (body.action === 'include') {
|
|
34
|
+
const item = setAutoInclude(root, body.id, body.include)
|
|
35
|
+
return item ? json(item) : notFound()
|
|
36
|
+
}
|
|
37
|
+
return badRequest('unknown context action')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (rest === '/copy-payload' && req.method === 'POST') {
|
|
41
|
+
await refreshAuto(handle)
|
|
42
|
+
const bundle = await getBundle(id)
|
|
43
|
+
const storedContext = readContext(root)
|
|
44
|
+
const openComments = readComments(root).comments.filter((comment) => comment.status === 'open')
|
|
45
|
+
const markdown = buildCopyMarkdown({
|
|
46
|
+
origin: bundle?.overlay.origin ?? id,
|
|
47
|
+
root,
|
|
48
|
+
renderFingerprint: bundle?.renderFingerprint ?? '',
|
|
49
|
+
schemaRevision: bundle?.schemaRevision,
|
|
50
|
+
openComments,
|
|
51
|
+
userContext: storedContext.user,
|
|
52
|
+
autoContext: body.includeAuto
|
|
53
|
+
? storedContext.auto.filter((item) => item.includeInHandoff)
|
|
54
|
+
: [],
|
|
55
|
+
documents: listDocuments(root),
|
|
56
|
+
})
|
|
57
|
+
return json({ markdown, openComments: openComments.length })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** CLI-owned update, installation status, and deploy routes for one domain. */
|
|
2
|
+
import { getAnatomy, getBundle } from '../cache'
|
|
3
|
+
import { runDeploy } from '../instances/deploy'
|
|
4
|
+
import { instanceStatus } from '../instances/status'
|
|
5
|
+
import { applyUpdates, getUpdates } from '../workspace/updates'
|
|
6
|
+
import { json, type DomainRouteContext } from './http'
|
|
7
|
+
|
|
8
|
+
function instanceTarget(prodTarget?: string): string | null {
|
|
9
|
+
const match = prodTarget?.match(/^instance:\s*(.+)$/)
|
|
10
|
+
return match ? match[1].trim() || null : null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function handleDeploymentRoute(context: DomainRouteContext): Promise<Response | null> {
|
|
14
|
+
const { req, rest, handle } = context
|
|
15
|
+
if (rest === '/updates' && req.method === 'GET') return json(await getUpdates(handle.root))
|
|
16
|
+
if (rest === '/updates/apply' && req.method === 'POST') {
|
|
17
|
+
return json(await applyUpdates(handle.root))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (rest === '/instance') {
|
|
21
|
+
const target = instanceTarget((await getAnatomy(handle.id))?.overview.prodTarget)
|
|
22
|
+
const bundle = await getBundle(handle.id)
|
|
23
|
+
return json(
|
|
24
|
+
await instanceStatus(
|
|
25
|
+
handle,
|
|
26
|
+
target,
|
|
27
|
+
bundle?.overlay.origin ?? null,
|
|
28
|
+
bundle?.schemaRevision ?? null,
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (rest === '/instance/deploy' && req.method === 'POST') {
|
|
34
|
+
const bundle = await getBundle(handle.id)
|
|
35
|
+
return json(await runDeploy(handle, bundle?.renderFingerprint ?? null))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Context-document HTTP transport, including multipart uploads and raw bodies. */
|
|
2
|
+
import {
|
|
3
|
+
addDocument,
|
|
4
|
+
deleteDocument,
|
|
5
|
+
listDocuments,
|
|
6
|
+
readDocument,
|
|
7
|
+
updateDocument,
|
|
8
|
+
} from '../state/documents'
|
|
9
|
+
import { json, notFound, type DomainRouteContext } from './http'
|
|
10
|
+
|
|
11
|
+
/** Routes that must run before POST bodies are parsed as JSON. */
|
|
12
|
+
export async function handleDocumentTransport(
|
|
13
|
+
req: Request,
|
|
14
|
+
rest: string,
|
|
15
|
+
root: string,
|
|
16
|
+
): Promise<Response | null> {
|
|
17
|
+
if (rest === '/context/documents' && req.method === 'GET') return json(listDocuments(root))
|
|
18
|
+
if (rest === '/context/documents' && req.method === 'POST') {
|
|
19
|
+
const form = await req.formData()
|
|
20
|
+
const added = []
|
|
21
|
+
for (const value of form.getAll('files')) {
|
|
22
|
+
if (value instanceof File) {
|
|
23
|
+
added.push(
|
|
24
|
+
addDocument(root, value.name, value.type, new Uint8Array(await value.arrayBuffer())),
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return json(added)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const raw = rest.match(/^\/context\/documents\/([^/]+)\/raw$/)
|
|
32
|
+
if (raw && req.method === 'GET') {
|
|
33
|
+
const document = readDocument(root, decodeURIComponent(raw[1]))
|
|
34
|
+
if (!document) return notFound()
|
|
35
|
+
return new Response(Bun.file(document.abs), {
|
|
36
|
+
headers: { 'content-type': document.meta.type },
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** JSON document mutations dispatched with the rest of the domain routes. */
|
|
44
|
+
export function handleDocumentMutation(context: DomainRouteContext): Response | null {
|
|
45
|
+
const { req, rest, body, handle } = context
|
|
46
|
+
const root = handle.root
|
|
47
|
+
if (rest === '/context/documents/delete' && req.method === 'POST') {
|
|
48
|
+
return json({ ok: deleteDocument(root, body.id) })
|
|
49
|
+
}
|
|
50
|
+
if (rest === '/context/documents/update' && req.method === 'POST') {
|
|
51
|
+
const meta = updateDocument(root, body.id, new TextEncoder().encode(String(body.content ?? '')))
|
|
52
|
+
return meta ? json(meta) : notFound()
|
|
53
|
+
}
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { DomainHandle } from '../domain'
|
|
2
|
+
import type { DomainRouteContext, Notify } from './http'
|
|
3
|
+
|
|
4
|
+
/** Domain-scoped route composition and the multipart/JSON body boundary. */
|
|
5
|
+
import { handleAgentRoute } from '../agent/routes'
|
|
6
|
+
import { handleCanvasRoute } from './canvas'
|
|
7
|
+
import { handleCommentRoute } from './comments'
|
|
8
|
+
import { handleContextRoute } from './context'
|
|
9
|
+
import { handleDeploymentRoute } from './deployment'
|
|
10
|
+
import { handleDocumentMutation, handleDocumentTransport } from './documents'
|
|
11
|
+
import { notFound } from './http'
|
|
12
|
+
import { handleProjectRoute } from './project'
|
|
13
|
+
import { handleSchemaRoute } from './schema'
|
|
14
|
+
import { handleViewRoute } from './views'
|
|
15
|
+
|
|
16
|
+
export async function handleDomainRoute(input: {
|
|
17
|
+
req: Request
|
|
18
|
+
url: URL
|
|
19
|
+
rest: string
|
|
20
|
+
handle: DomainHandle
|
|
21
|
+
notify: Notify
|
|
22
|
+
}): Promise<Response> {
|
|
23
|
+
const { req, url, rest, handle, notify } = input
|
|
24
|
+
|
|
25
|
+
const documentTransport = await handleDocumentTransport(req, rest, handle.root)
|
|
26
|
+
if (documentTransport) return documentTransport
|
|
27
|
+
|
|
28
|
+
const body = req.method === 'POST' ? await req.json().catch(() => ({})) : {}
|
|
29
|
+
const context: DomainRouteContext = { req, url, rest, body, handle, notify }
|
|
30
|
+
|
|
31
|
+
const documentMutation = handleDocumentMutation(context)
|
|
32
|
+
if (documentMutation) return documentMutation
|
|
33
|
+
|
|
34
|
+
const schema = await handleSchemaRoute(context)
|
|
35
|
+
if (schema) return schema
|
|
36
|
+
|
|
37
|
+
const deployment = await handleDeploymentRoute(context)
|
|
38
|
+
if (deployment) return deployment
|
|
39
|
+
|
|
40
|
+
const view = await handleViewRoute(context)
|
|
41
|
+
if (view) return view
|
|
42
|
+
|
|
43
|
+
const comment = await handleCommentRoute(context)
|
|
44
|
+
if (comment) return comment
|
|
45
|
+
|
|
46
|
+
const agent = await handleAgentRoute({ req, url, rest, body, handle, notify })
|
|
47
|
+
if (agent) return agent
|
|
48
|
+
|
|
49
|
+
const contextResponse = await handleContextRoute(context)
|
|
50
|
+
if (contextResponse) return contextResponse
|
|
51
|
+
|
|
52
|
+
const project = await handleProjectRoute(context)
|
|
53
|
+
if (project) return project
|
|
54
|
+
|
|
55
|
+
const canvas = await handleCanvasRoute(context)
|
|
56
|
+
if (canvas) return canvas
|
|
57
|
+
|
|
58
|
+
return notFound()
|
|
59
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Internal HTTP contract shared by Studio API route modules. */
|
|
2
|
+
import type { StudioEvent } from '../../shared/types'
|
|
3
|
+
import type { DomainHandle } from '../domain'
|
|
4
|
+
|
|
5
|
+
export type Notify = (event: StudioEvent) => void
|
|
6
|
+
|
|
7
|
+
export interface DomainRouteContext {
|
|
8
|
+
req: Request
|
|
9
|
+
url: URL
|
|
10
|
+
rest: string
|
|
11
|
+
body: any
|
|
12
|
+
handle: DomainHandle
|
|
13
|
+
notify: Notify
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function json(data: unknown, status = 200): Response {
|
|
17
|
+
return new Response(JSON.stringify(data), {
|
|
18
|
+
status,
|
|
19
|
+
headers: { 'content-type': 'application/json' },
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const notFound = () => json({ error: 'not found' }, 404)
|
|
24
|
+
export const badRequest = (message: string) => json({ error: message }, 400)
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Block cross-site state-changing requests. Same-origin browser requests and
|
|
28
|
+
* non-browser clients without Origin/Sec-Fetch-Site remain allowed.
|
|
29
|
+
*/
|
|
30
|
+
export function crossSiteBlocked(req: Request, url: URL): boolean {
|
|
31
|
+
if (req.method === 'GET' || req.method === 'HEAD') return false
|
|
32
|
+
const site = req.headers.get('sec-fetch-site')
|
|
33
|
+
if (site) return !(site === 'same-origin' || site === 'none')
|
|
34
|
+
const origin = req.headers.get('origin')
|
|
35
|
+
if (origin) {
|
|
36
|
+
try {
|
|
37
|
+
// Same-origin includes the scheme as well as host and effective port.
|
|
38
|
+
// Comparing only `host` would accept an HTTPS origin for an HTTP Studio.
|
|
39
|
+
return new URL(origin).origin !== url.origin
|
|
40
|
+
} catch {
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Domain project configuration routes: integrations, settings, and env files. */
|
|
2
|
+
import { getAnatomy, invalidate } from '../cache'
|
|
3
|
+
import { isEnvName, readEnvModel, writeEnvUpdates } from '../environment/files'
|
|
4
|
+
import { deleteIntegration, readIntegrations, upsertIntegration } from '../state/integrations'
|
|
5
|
+
import { readSettings, updateSettings } from '../state/settings'
|
|
6
|
+
import { badRequest, json, type DomainRouteContext } from './http'
|
|
7
|
+
|
|
8
|
+
export async function handleProjectRoute(context: DomainRouteContext): Promise<Response | null> {
|
|
9
|
+
const { req, url, rest, body, handle, notify } = context
|
|
10
|
+
const id = handle.id
|
|
11
|
+
const root = handle.root
|
|
12
|
+
|
|
13
|
+
if (rest === '/integrations') {
|
|
14
|
+
const detected = (await getAnatomy(id))?.detectedIntegrations ?? []
|
|
15
|
+
if (req.method === 'GET') return json(readIntegrations(root, detected))
|
|
16
|
+
if (body.action === 'upsert') return json(upsertIntegration(root, body))
|
|
17
|
+
if (body.action === 'delete') return json({ ok: deleteIntegration(root, body.id) })
|
|
18
|
+
return badRequest('unknown integrations action')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (rest === '/settings') {
|
|
22
|
+
if (req.method === 'GET') return json(readSettings(root))
|
|
23
|
+
if (body.action === 'update') {
|
|
24
|
+
const next = updateSettings(root, body.settings ?? {})
|
|
25
|
+
invalidate(id, 'anatomy')
|
|
26
|
+
notify({ type: 'anatomy-diff', domainId: id })
|
|
27
|
+
return json(next)
|
|
28
|
+
}
|
|
29
|
+
return badRequest('unknown settings action')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (rest === '/env') {
|
|
33
|
+
const envName = req.method === 'GET' ? url.searchParams.get('env') : body.env
|
|
34
|
+
if (!isEnvName(envName)) return badRequest('env must be "dev" or "prod"')
|
|
35
|
+
if (req.method === 'GET') return json(readEnvModel(root, envName))
|
|
36
|
+
if (req.method === 'POST') {
|
|
37
|
+
if (!body.updates || typeof body.updates !== 'object') {
|
|
38
|
+
return badRequest('updates object required')
|
|
39
|
+
}
|
|
40
|
+
const updates: Record<string, string | null> = {}
|
|
41
|
+
for (const [key, value] of Object.entries(body.updates as Record<string, unknown>)) {
|
|
42
|
+
if (!/^[A-Za-z_]\w*$/.test(key)) continue
|
|
43
|
+
updates[key] = value === null ? null : String(value)
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const model = writeEnvUpdates(root, envName, updates)
|
|
47
|
+
notify({ type: 'anatomy-diff', domainId: id })
|
|
48
|
+
return json(model)
|
|
49
|
+
} catch (error: any) {
|
|
50
|
+
return badRequest(String(error?.message ?? error))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return badRequest('GET or POST')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Canonical schema, anatomy, and genesis inspection routes. */
|
|
2
|
+
import { getAnatomy, getBundle, getCore } from '../cache'
|
|
3
|
+
import { json, type DomainRouteContext } from './http'
|
|
4
|
+
|
|
5
|
+
export async function handleSchemaRoute(context: DomainRouteContext): Promise<Response | null> {
|
|
6
|
+
const { rest, url, handle } = context
|
|
7
|
+
const fresh = url.searchParams.has('fresh')
|
|
8
|
+
if (rest === '/bundle') return json(await getBundle(handle.id, fresh))
|
|
9
|
+
if (rest === '/anatomy') return json(await getAnatomy(handle.id, fresh))
|
|
10
|
+
if (rest === '/core') return json(await getCore(handle.id, fresh))
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** CLI-resolved View target discovery and Shell session routes. */
|
|
2
|
+
import { getAnatomy, getBundle } from '../cache'
|
|
3
|
+
import { readSettings } from '../state/settings'
|
|
4
|
+
import { getViewRuntime } from '../views/runtime'
|
|
5
|
+
import { closeViewSession, launchViewSession } from '../views/session'
|
|
6
|
+
import { badRequest, json, notFound, type DomainRouteContext } from './http'
|
|
7
|
+
|
|
8
|
+
const VALID_SLUG = /^[a-z][a-z0-9-]*$/
|
|
9
|
+
|
|
10
|
+
export async function handleViewRoute(context: DomainRouteContext): Promise<Response | null> {
|
|
11
|
+
const { req, rest, body, handle } = context
|
|
12
|
+
const id = handle.id
|
|
13
|
+
const root = handle.root
|
|
14
|
+
|
|
15
|
+
if (rest === '/views/sessions/close' && req.method === 'POST') {
|
|
16
|
+
return json(await closeViewSession(String(body.sessionId ?? '')))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const runtimeMatch = rest.match(/^\/views\/([^/]+)\/runtime$/)
|
|
20
|
+
if (runtimeMatch && req.method === 'GET') {
|
|
21
|
+
const slug = decodeURIComponent(runtimeMatch[1])
|
|
22
|
+
if (!VALID_SLUG.test(slug)) return badRequest('invalid view slug')
|
|
23
|
+
const anatomy = await getAnatomy(id)
|
|
24
|
+
const view = anatomy?.views.find((candidate) => candidate.slug === slug)
|
|
25
|
+
if (!view) return notFound()
|
|
26
|
+
const bundle = await getBundle(id)
|
|
27
|
+
const origin = bundle?.overlay.origin || anatomy?.overview.origin
|
|
28
|
+
if (!origin) return badRequest('domain origin is unavailable')
|
|
29
|
+
return json(
|
|
30
|
+
await getViewRuntime(root, origin, view, bundle, readSettings(root).viewProbeTimeoutMs),
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const sessionMatch = rest.match(/^\/views\/([^/]+)\/session$/)
|
|
35
|
+
if (sessionMatch && req.method === 'POST') {
|
|
36
|
+
const slug = decodeURIComponent(sessionMatch[1])
|
|
37
|
+
if (!VALID_SLUG.test(slug)) return badRequest('invalid view slug')
|
|
38
|
+
const anatomy = await getAnatomy(id)
|
|
39
|
+
const view = anatomy?.views.find((candidate) => candidate.slug === slug)
|
|
40
|
+
if (!view) return notFound()
|
|
41
|
+
const bundle = await getBundle(id)
|
|
42
|
+
const origin = bundle?.overlay.origin || anatomy?.overview.origin
|
|
43
|
+
if (!origin) return badRequest('domain origin is unavailable')
|
|
44
|
+
return json(
|
|
45
|
+
await launchViewSession(
|
|
46
|
+
root,
|
|
47
|
+
origin,
|
|
48
|
+
view,
|
|
49
|
+
bundle,
|
|
50
|
+
body,
|
|
51
|
+
readSettings(root).viewProbeTimeoutMs,
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Workspace-wide routes that do not require a DomainHandle. */
|
|
2
|
+
import { getBundle } from '../cache'
|
|
3
|
+
import { allDomains, depsInstalled } from '../domain'
|
|
4
|
+
import { activeInstanceName, listInstances, setActiveInstance } from '../instances/active'
|
|
5
|
+
import { buildCatalog } from '../workspace/catalog'
|
|
6
|
+
import { createDomain } from '../workspace/create'
|
|
7
|
+
import { detectGit } from '../workspace/git'
|
|
8
|
+
import { badRequest, json, type Notify } from './http'
|
|
9
|
+
|
|
10
|
+
export async function handleWorkspaceRoute(
|
|
11
|
+
req: Request,
|
|
12
|
+
path: string,
|
|
13
|
+
notify: Notify,
|
|
14
|
+
): Promise<Response | null> {
|
|
15
|
+
if (path === '/api/workspace') {
|
|
16
|
+
const domains = await Promise.all(
|
|
17
|
+
allDomains().map(async (handle) => {
|
|
18
|
+
const bundle = await getBundle(handle.id)
|
|
19
|
+
return {
|
|
20
|
+
id: handle.id,
|
|
21
|
+
origin: bundle?.overlay.origin || handle.origin || handle.id,
|
|
22
|
+
path: handle.root,
|
|
23
|
+
schemaDir: handle.schemaDirName,
|
|
24
|
+
depsInstalled: depsInstalled(handle.root),
|
|
25
|
+
hasGit: detectGit(handle.root).hasGit,
|
|
26
|
+
configFile: handle.configFile,
|
|
27
|
+
}
|
|
28
|
+
}),
|
|
29
|
+
)
|
|
30
|
+
return json(domains)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (path === '/api/workspace/create' && req.method === 'POST') {
|
|
34
|
+
const body = await req.json().catch(() => ({}))
|
|
35
|
+
const result = await createDomain(String(body.name ?? ''), await activeInstanceName())
|
|
36
|
+
if (result.ok) notify({ type: 'workspace', domains: allDomains().map((domain) => domain.id) })
|
|
37
|
+
return json(result)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (path === '/api/catalog') {
|
|
41
|
+
return json(
|
|
42
|
+
buildCatalog(
|
|
43
|
+
allDomains().map((handle) => ({
|
|
44
|
+
origin: handle.origin ?? handle.id,
|
|
45
|
+
id: handle.id,
|
|
46
|
+
})),
|
|
47
|
+
),
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (path === '/api/instances' && req.method === 'GET') return json(await listInstances())
|
|
52
|
+
if (path === '/api/instances/use' && req.method === 'POST') {
|
|
53
|
+
const body = await req.json().catch(() => ({}))
|
|
54
|
+
const name = String(body.name ?? '').trim()
|
|
55
|
+
if (!name) return badRequest('name is required')
|
|
56
|
+
return json(await setActiveInstance(name))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
@@ -27,7 +27,7 @@ test('loadout fails closed instead of probing ambient Claude when gateway auth f
|
|
|
27
27
|
roots.push(root)
|
|
28
28
|
mkdirSync(join(root, 'schema'))
|
|
29
29
|
writeFileSync(join(root, 'astrale.config.ts'), 'export default {}\n')
|
|
30
|
-
writeFileSync(join(root, '
|
|
30
|
+
writeFileSync(join(root, 'application.ts'), 'export default {}\n')
|
|
31
31
|
writeFileSync(join(root, 'schema/index.ts'), 'export const Test = {}\n')
|
|
32
32
|
const handle = registerDomain(root)!
|
|
33
33
|
domainIds.push(handle.id)
|