@desplega.ai/agent-swarm 1.129.0 → 1.131.0
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 +2 -2
- package/dist/{actions-kfv2dawe.js → actions-w53mbns9.js} +11 -11
- package/dist/{anthropic-messages-3xgme8my.js → anthropic-messages-rjmd2e7n.js} +5 -5
- package/dist/{app-q8vjk6e8.js → app-m9gwqsqv.js} +8 -8
- package/dist/{artifact-hg4t1nx7.js → artifact-jysj3wrg.js} +2 -2
- package/dist/{assistant-g037r345.js → assistant-bp65m6f3.js} +13 -13
- package/dist/{azure-openai-responses-xa4sh9f6.js → azure-openai-responses-c0yjmbfd.js} +8 -5
- package/dist/{boot-reembed-18pzsrxa.js → boot-reembed-62p0at2k.js} +6 -6
- package/dist/{boot-reembed-wpks2cj8.js → boot-reembed-xmfp6wdh.js} +7 -7
- package/dist/{boot-scrub-logs-n7szd57r.js → boot-scrub-logs-rr8q2dms.js} +5 -5
- package/dist/{claude-adapter-qz4r0ajt.js → claude-adapter-2y47mrkd.js} +9 -9
- package/dist/{cli-mhjnbgb6.js → cli-0rcyq6d9.js} +450 -186
- package/dist/{cli-ttkmehy0.js → cli-2q72qz2s.js} +274 -25
- package/dist/{cli-gztgc3hz.js → cli-2wadx7p2.js} +2 -2
- package/dist/cli-3fj60etf.js +153 -0
- package/dist/{cli-7ecgm5v0.js → cli-3kf51j15.js} +1 -1
- package/dist/{cli-vgexpfsr.js → cli-57khth04.js} +6 -3
- package/dist/{cli-2mbe7vk0.js → cli-5dsbcjjw.js} +1 -1
- package/dist/{cli-etr62zy6.js → cli-5kx36evn.js} +2 -2
- package/dist/{cli-v2tr6amf.js → cli-5n6e5yfn.js} +30 -8
- package/dist/{cli-hx02s9zq.js → cli-5v4rw6yd.js} +2 -2
- package/dist/{cli-v37yr6mf.js → cli-5ze9rv97.js} +4 -4
- package/dist/{cli-ch7t5v7n.js → cli-6map995v.js} +9 -4
- package/dist/{cli-h0457a67.js → cli-70xqj0z3.js} +3 -3
- package/dist/{cli-kk4f9r17.js → cli-72q8m8gk.js} +8 -6
- package/dist/{cli-7padk69a.js → cli-78xwvkhj.js} +2 -2
- package/dist/{cli-dxtxacy7.js → cli-9dr5qzc0.js} +45 -8
- package/dist/{cli-17zxdgsq.js → cli-a40rnf71.js} +6 -6
- package/dist/{cli-t53vnnxz.js → cli-a4jzdpa3.js} +2514 -1055
- package/dist/{cli-w10fkrf1.js → cli-akdvwc9v.js} +354 -115
- package/dist/{cli-1qkk5er0.js → cli-bmze986d.js} +1 -1
- package/dist/{cli-ga12dc1d.js → cli-bqw0mt1n.js} +3 -3
- package/dist/{cli-0sf92efp.js → cli-cdeg08wx.js} +1 -1
- package/dist/{cli-a8ynhkyj.js → cli-cvgjwnh1.js} +17 -15
- package/dist/{cli-9fxg3v5m.js → cli-d2tfkcga.js} +4 -4
- package/dist/{cli-nhcd7x43.js → cli-d3x3x1c9.js} +2 -2
- package/dist/{cli-6nh2qxvh.js → cli-darcwax3.js} +1 -1
- package/dist/{cli-yjbgmysx.js → cli-e7ckcg4v.js} +12 -12
- package/dist/{cli-4n2gcjpd.js → cli-efxfnq6q.js} +4 -3
- package/dist/{cli-z9xqqhfk.js → cli-er3a4bb0.js} +1 -1
- package/dist/{cli-xg2eezyv.js → cli-f1am9szv.js} +1 -1
- package/dist/{cli-xy4cwsm9.js → cli-fywms69x.js} +1 -1
- package/dist/{cli-33jj76y8.js → cli-g6b8x1h8.js} +1 -1
- package/dist/{cli-epsvdckx.js → cli-gm9cbhbq.js} +20 -10
- package/dist/{cli-rkndnn90.js → cli-k9qkf1hw.js} +6 -4
- package/dist/{cli-zejvt395.js → cli-kh3ba2zf.js} +1 -1
- package/dist/{cli-gb25p1h2.js → cli-nm5gtp1x.js} +2 -2
- package/dist/{cli-akxnpx17.js → cli-pm6xbh84.js} +1829 -1629
- package/dist/{cli-2k0ztbfp.js → cli-psh3c4va.js} +1 -1
- package/dist/{cli-39vgrsep.js → cli-qv61hp37.js} +2 -2
- package/dist/{cli-hv2fndhm.js → cli-r6kqqbj0.js} +6 -4
- package/dist/{cli-1y1cm570.js → cli-rzbpmxdr.js} +1 -1
- package/dist/{cli-mmrk00vp.js → cli-t1xze5qh.js} +1 -1
- package/dist/{cli-g252a9ky.js → cli-t55yw3a1.js} +2 -2
- package/dist/{cli-7bz8dzqa.js → cli-t76vw5db.js} +1184 -1522
- package/dist/{cli-4n4mdv21.js → cli-xpxde7rm.js} +7 -3
- package/dist/{cli-fpaa5k2q.js → cli-yw8vghx2.js} +54 -18
- package/dist/cli-zsspvvm2.js +490 -0
- package/dist/cli.js +27 -25
- package/dist/{codex-adapter-7v6t7ff6.js → codex-adapter-d24q75wk.js} +7 -7
- package/dist/{codex-hook-amndawyb.js → codex-hook-hq54t9ft.js} +2 -2
- package/dist/{codex-session-runner-e7j4khe2.js → codex-session-runner-g50vcsex.js} +7 -7
- package/dist/{commands-ex0k5tbf.js → commands-c3nrc5hg.js} +5 -5
- package/dist/{db-df7jatfc.js → db-nt7fg3tw.js} +5 -5
- package/dist/{google-generative-ai-y42hnw9p.js → google-generative-ai-hysrd8qx.js} +7 -5
- package/dist/{google-vertex-4sg66gb6.js → google-vertex-p5arrga0.js} +7 -5
- package/dist/{handlers-1j2cfqt2.js → handlers-fkr6swat.js} +13 -13
- package/dist/{hook-nx9a0mj3.js → hook-77wpvnjc.js} +7 -7
- package/dist/{hook-w6yaf6sy.js → hook-g019yehy.js} +8 -8
- package/dist/{http-4tz5h8wg.js → http-jewj0syk.js} +2993 -716
- package/dist/{index-0bpkzb09.js → index-070v4eyb.js} +3 -3
- package/dist/{index-0s67qv7h.js → index-6gm5he8h.js} +11 -11
- package/dist/{index-35gtv6gj.js → index-7n2xpbd4.js} +310 -40
- package/dist/{index-ker3gccb.js → index-9znhar3x.js} +4 -4
- package/dist/{index-5n2c8yay.js → index-hase6zbe.js} +2 -2
- package/dist/{index-kcf3tm9h.js → index-hfvggd0z.js} +12 -12
- package/dist/{index-7c0jqna0.js → index-hp1kdbjj.js} +13 -13
- package/dist/{keepalive-3j4a9168.js → keepalive-j0fjvqfd.js} +7 -7
- package/dist/{lead-6kpevymb.js → lead-1n8x30xe.js} +33 -33
- package/dist/{maintenance-m1k82ean.js → maintenance-gvev11sa.js} +7 -7
- package/dist/{mistral-conversations-bjkdfb6z.js → mistral-conversations-81fwav0j.js} +6 -6
- package/dist/{oauth-refresh-sweep-881k8e4q.js → oauth-refresh-sweep-s9ecsvh0.js} +6 -6
- package/dist/{onboard-c0ykffjn.js → onboard-pvm5b38w.js} +2 -2
- package/dist/{openai-codex-responses-xetseqvt.js → openai-codex-responses-5g27pd6f.js} +43 -23
- package/dist/{openai-completions-5r2g5axa.js → openai-completions-3vkmfz2a.js} +55 -11
- package/dist/{openai-responses-ce67hd23.js → openai-responses-dg4t7j7a.js} +8 -5
- package/dist/{openrouter-images-pzfp22jb.js → openrouter-images-g3gm8931.js} +1 -1
- package/dist/{otel-impl-sqagjerv.js → otel-impl-p6jvgd9c.js} +6 -4
- package/dist/{otel-3mp81ppd.js → otel-nqa12wf3.js} +2 -2
- package/dist/{pi-mono-adapter-k584k16g.js → pi-mono-adapter-t091s27g.js} +17117 -7517
- package/dist/{pricing-refresh-y82whbf9.js → pricing-refresh-k49rcyed.js} +7 -7
- package/dist/{rbac-roles-nvkqmzyd.js → rbac-roles-30pspvy7.js} +7 -7
- package/dist/{rbac-roles-4ht8gegc.js → rbac-roles-cr80g96t.js} +6 -6
- package/dist/{render-v2-wvqdgvvp.js → render-v2-xm457ng1.js} +8 -8
- package/dist/{seed-pricing-fy3rxhde.js → seed-pricing-yhpv35fr.js} +6 -6
- package/dist/{setup-ak5cnc6f.js → setup-nytnmwwr.js} +2 -2
- package/dist/{worker-d8769q8a.js → worker-msytr2cw.js} +33 -33
- package/openapi.json +34039 -11036
- package/package.json +8 -6
- package/src/apps/definition.ts +368 -26
- package/src/apps/row-store.ts +66 -10
- package/src/apps/schema-migrate.ts +95 -1
- package/src/apps/store.ts +13 -4
- package/src/apps/sync-run-as.ts +18 -0
- package/src/apps/sync.ts +934 -0
- package/src/apps/version.ts +16 -2
- package/src/assets/key.ts +8 -1
- package/src/be/asset-key-audit.ts +3 -1
- package/src/be/db-queries/mcp-oauth.ts +297 -24
- package/src/be/db.ts +42 -1
- package/src/be/migrations/129_asset_keys_apps_scripts.sql +161 -0
- package/src/be/scripts/db.ts +5 -2
- package/src/be/scripts/typecheck.ts +1 -0
- package/src/be/seed-scripts/catalog/app-sync-run.ts +32 -0
- package/src/be/seed-scripts/catalog/github-issues-pull.ts +102 -0
- package/src/be/seed-scripts/index.ts +18 -0
- package/src/be/seed-skills/index.ts +7 -0
- package/src/http/active-sessions.ts +26 -18
- package/src/http/agents.ts +94 -27
- package/src/http/api-keys.ts +91 -17
- package/src/http/approval-requests.ts +87 -10
- package/src/http/apps.ts +361 -53
- package/src/http/assets.ts +165 -31
- package/src/http/budgets.ts +7 -5
- package/src/http/codex-oauth-keep-warm.ts +21 -3
- package/src/http/config.ts +46 -16
- package/src/http/context.ts +33 -6
- package/src/http/ecosystem.ts +20 -6
- package/src/http/events.ts +24 -9
- package/src/http/favorites.ts +20 -6
- package/src/http/fs.ts +60 -17
- package/src/http/heartbeat.ts +18 -4
- package/src/http/inbox-state.ts +12 -6
- package/src/http/integrations.ts +25 -5
- package/src/http/kv.ts +36 -15
- package/src/http/mcp-bridge.ts +5 -1
- package/src/http/mcp-oauth.ts +332 -17
- package/src/http/mcp-servers.ts +56 -18
- package/src/http/memory.ts +282 -29
- package/src/http/metrics.ts +80 -17
- package/src/http/oauth-callback.ts +10 -4
- package/src/http/oauth-generic.ts +5 -1
- package/src/http/oauth-locks.ts +6 -3
- package/src/http/openapi.ts +57 -9
- package/src/http/page-proxy.ts +25 -5
- package/src/http/pages-public.ts +37 -20
- package/src/http/pages.ts +93 -28
- package/src/http/poll.ts +89 -5
- package/src/http/pricing.ts +9 -6
- package/src/http/prompt-templates.ts +85 -21
- package/src/http/route-def.ts +67 -4
- package/src/http/schedules.ts +63 -14
- package/src/http/script-connection-proxy.ts +30 -4
- package/src/http/script-connections.ts +393 -43
- package/src/http/script-runs.ts +73 -19
- package/src/http/scripts.ts +257 -39
- package/src/http/session-data.ts +87 -14
- package/src/http/sessions.ts +80 -5
- package/src/http/skills.ts +115 -35
- package/src/http/stats.ts +94 -13
- package/src/http/task-templates.ts +6 -4
- package/src/http/tasks.ts +230 -61
- package/src/http/trackers/jira.ts +90 -30
- package/src/http/trackers/linear.ts +46 -12
- package/src/http/users.ts +162 -25
- package/src/http/utils.ts +12 -2
- package/src/http/webhooks.ts +30 -16
- package/src/http/workflow-events.ts +18 -5
- package/src/http/workflows.ts +128 -39
- package/src/http/x.ts +37 -6
- package/src/oauth/ensure-mcp-token.ts +16 -1
- package/src/oauth/mcp-wrapper.ts +281 -26
- package/src/providers/pi-mono-adapter.ts +1 -1
- package/src/scripts-runtime/credential-broker/README.md +1 -1
- package/src/scripts-runtime/credential-broker/fetch-patch.ts +12 -2
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/stdlib/fetch.ts +6 -0
- package/src/scripts-runtime/types/stdlib.d.ts +1 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -0
- package/src/server.ts +2 -0
- package/src/tests/apps-rbac.test.ts +110 -0
- package/src/tests/apps-spike2.test.ts +4 -1
- package/src/tests/apps-sync-engine.test.ts +2540 -0
- package/src/tests/apps-sync.test.ts +1627 -0
- package/src/tests/asset-key-api.test.ts +48 -2
- package/src/tests/asset-key-invariants.test.ts +92 -0
- package/src/tests/asset-key-migration.test.ts +174 -8
- package/src/tests/asset-key-normalization.test.ts +2 -0
- package/src/tests/credential-broker.test.ts +27 -2
- package/src/tests/mcp-oauth-dcr-reuse.test.ts +743 -0
- package/src/tests/mcp-oauth-ensure-token.test.ts +45 -0
- package/src/tests/mcp-oauth-manual-client.test.ts +135 -2
- package/src/tests/mcp-oauth-queries.test.ts +153 -0
- package/src/tests/mcp-oauth-wrapper.test.ts +432 -0
- package/src/tests/memory-http-recall-gating.test.ts +2 -0
- package/src/tests/openapi-response-contract.test.ts +138 -0
- package/src/tests/rbac-admission-e2e.test.ts +68 -0
- package/src/tests/script-connections.test.ts +3 -0
- package/src/tests/scripts-runtime-fetch.test.ts +121 -0
- package/src/tests/scripts-runtime-secret-egress.test.ts +4 -2
- package/src/tests/seed-scripts.test.ts +2 -2
- package/src/tests/swarm-tool-result-gate.test.ts +32 -0
- package/src/tests/task-working-dir.test.ts +8 -4
- package/src/tests/whoami-route.test.ts +127 -0
- package/src/tests/workflow-engine-v2.test.ts +80 -7
- package/src/tests/workflow-swarm-script.test.ts +104 -0
- package/src/tools/app-get.ts +10 -2
- package/src/tools/app-rollback.ts +1 -0
- package/src/tools/app-sync.ts +112 -0
- package/src/tools/script-common.ts +20 -0
- package/src/tools/tool-config.ts +2 -1
- package/src/tools/utils.ts +11 -0
- package/src/tools/workflows/create-workflow.ts +4 -1
- package/src/types.ts +1394 -1206
- package/src/utils/template.ts +8 -1
- package/src/utils/zod-openapi.ts +11 -0
- package/src/workflows/engine.ts +27 -4
- package/src/workflows/executors/swarm-script.ts +28 -0
- package/src/workflows/retry-poller.ts +19 -2
- package/templates/skills/apps/content.md +94 -5
- package/templates/skills/asset-namespaces/content.md +2 -2
- package/templates/skills/scheduled-task-resilience/SKILL.md +102 -0
- package/templates/skills/scheduled-task-resilience/config.json +14 -0
- package/templates/skills/scheduled-task-resilience/content.md +97 -0
- package/dist/cli-7wmybrt5.js +0 -115
- package/dist/cli-d91pvmq1.js +0 -14
package/src/http/ecosystem.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
import { getServicesByAgentId } from "../be/db";
|
|
3
4
|
import { route } from "./route-def";
|
|
4
|
-
import {
|
|
5
|
+
import { jsonError } from "./utils";
|
|
5
6
|
|
|
6
7
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
7
8
|
|
|
9
|
+
const EcosystemAppSchema = z.object({
|
|
10
|
+
name: z.string(),
|
|
11
|
+
script: z.string(),
|
|
12
|
+
cwd: z.string().optional(),
|
|
13
|
+
interpreter: z.string().optional(),
|
|
14
|
+
args: z.array(z.string()).optional(),
|
|
15
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
type EcosystemApp = z.infer<typeof EcosystemAppSchema>;
|
|
19
|
+
|
|
8
20
|
const getEcosystem = route({
|
|
9
21
|
method: "get",
|
|
10
22
|
path: "/ecosystem",
|
|
@@ -13,7 +25,10 @@ const getEcosystem = route({
|
|
|
13
25
|
tags: ["Ecosystem"],
|
|
14
26
|
auth: { apiKey: true, agentId: true },
|
|
15
27
|
responses: {
|
|
16
|
-
200: {
|
|
28
|
+
200: {
|
|
29
|
+
description: "PM2 ecosystem config",
|
|
30
|
+
schema: z.object({ apps: z.array(EcosystemAppSchema) }),
|
|
31
|
+
},
|
|
17
32
|
400: { description: "Missing X-Agent-ID" },
|
|
18
33
|
},
|
|
19
34
|
});
|
|
@@ -39,7 +54,7 @@ export async function handleEcosystem(
|
|
|
39
54
|
apps: services
|
|
40
55
|
.filter((s) => s.script) // Only include services with script path
|
|
41
56
|
.map((s) => {
|
|
42
|
-
const app:
|
|
57
|
+
const app: EcosystemApp = {
|
|
43
58
|
name: s.name,
|
|
44
59
|
script: s.script,
|
|
45
60
|
};
|
|
@@ -48,14 +63,13 @@ export async function handleEcosystem(
|
|
|
48
63
|
if (s.interpreter) app.interpreter = s.interpreter;
|
|
49
64
|
if (s.args && s.args.length > 0) app.args = s.args;
|
|
50
65
|
if (s.env && Object.keys(s.env).length > 0) app.env = s.env;
|
|
51
|
-
if (s.port)
|
|
52
|
-
app.env = { ...((app.env as Record<string, string>) || {}), PORT: String(s.port) };
|
|
66
|
+
if (s.port) app.env = { ...(app.env || {}), PORT: String(s.port) };
|
|
53
67
|
|
|
54
68
|
return app;
|
|
55
69
|
}),
|
|
56
70
|
};
|
|
57
71
|
|
|
58
|
-
|
|
72
|
+
getEcosystem.respond(res, 200, ecosystem);
|
|
59
73
|
return true;
|
|
60
74
|
}
|
|
61
75
|
|
package/src/http/events.ts
CHANGED
|
@@ -11,9 +11,10 @@ import {
|
|
|
11
11
|
EventNameSchema,
|
|
12
12
|
EventSourceSchema,
|
|
13
13
|
EventStatusSchema,
|
|
14
|
+
SwarmEventSchema,
|
|
14
15
|
} from "../types";
|
|
15
16
|
import { route } from "./route-def";
|
|
16
|
-
import {
|
|
17
|
+
import { jsonError } from "./utils";
|
|
17
18
|
|
|
18
19
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
19
20
|
|
|
@@ -39,7 +40,10 @@ const createEventRoute = route({
|
|
|
39
40
|
tags: ["Events"],
|
|
40
41
|
body: eventBodySchema,
|
|
41
42
|
responses: {
|
|
42
|
-
201: {
|
|
43
|
+
201: {
|
|
44
|
+
description: "Event stored",
|
|
45
|
+
schema: z.object({ success: z.literal(true), event: SwarmEventSchema }),
|
|
46
|
+
},
|
|
43
47
|
400: { description: "Validation error" },
|
|
44
48
|
},
|
|
45
49
|
auth: { apiKey: true },
|
|
@@ -55,7 +59,10 @@ const createEventsBatchRoute = route({
|
|
|
55
59
|
events: z.array(eventBodySchema).min(1).max(500),
|
|
56
60
|
}),
|
|
57
61
|
responses: {
|
|
58
|
-
201: {
|
|
62
|
+
201: {
|
|
63
|
+
description: "Events stored",
|
|
64
|
+
schema: z.object({ success: z.literal(true), count: z.number().int() }),
|
|
65
|
+
},
|
|
59
66
|
400: { description: "Validation error" },
|
|
60
67
|
},
|
|
61
68
|
auth: { apiKey: true },
|
|
@@ -80,7 +87,10 @@ const getEventsRoute = route({
|
|
|
80
87
|
limit: z.coerce.number().int().min(1).max(1000).optional(),
|
|
81
88
|
}),
|
|
82
89
|
responses: {
|
|
83
|
-
200: {
|
|
90
|
+
200: {
|
|
91
|
+
description: "List of events",
|
|
92
|
+
schema: z.object({ events: z.array(SwarmEventSchema) }),
|
|
93
|
+
},
|
|
84
94
|
},
|
|
85
95
|
auth: { apiKey: true },
|
|
86
96
|
});
|
|
@@ -101,7 +111,12 @@ const getEventCountsRoute = route({
|
|
|
101
111
|
until: z.string().optional(),
|
|
102
112
|
}),
|
|
103
113
|
responses: {
|
|
104
|
-
200: {
|
|
114
|
+
200: {
|
|
115
|
+
description: "Event counts",
|
|
116
|
+
schema: z.object({
|
|
117
|
+
counts: z.array(z.object({ event: z.string(), count: z.number().int() })),
|
|
118
|
+
}),
|
|
119
|
+
},
|
|
105
120
|
},
|
|
106
121
|
auth: { apiKey: true },
|
|
107
122
|
});
|
|
@@ -122,7 +137,7 @@ export async function handleEvents(
|
|
|
122
137
|
|
|
123
138
|
try {
|
|
124
139
|
const count = createEventsBatch(parsed.body.events);
|
|
125
|
-
|
|
140
|
+
createEventsBatchRoute.respond(res, 201, { success: true, count });
|
|
126
141
|
} catch (error) {
|
|
127
142
|
console.error("[HTTP] Failed to create events batch:", error);
|
|
128
143
|
jsonError(res, "Failed to store events batch", 500);
|
|
@@ -144,7 +159,7 @@ export async function handleEvents(
|
|
|
144
159
|
since: parsed.query.since || undefined,
|
|
145
160
|
until: parsed.query.until || undefined,
|
|
146
161
|
});
|
|
147
|
-
|
|
162
|
+
getEventCountsRoute.respond(res, 200, { counts });
|
|
148
163
|
return true;
|
|
149
164
|
}
|
|
150
165
|
|
|
@@ -155,7 +170,7 @@ export async function handleEvents(
|
|
|
155
170
|
|
|
156
171
|
try {
|
|
157
172
|
const event = createEvent(parsed.body);
|
|
158
|
-
|
|
173
|
+
createEventRoute.respond(res, 201, { success: true, event });
|
|
159
174
|
} catch (error) {
|
|
160
175
|
console.error("[HTTP] Failed to create event:", error);
|
|
161
176
|
jsonError(res, "Failed to store event", 500);
|
|
@@ -180,7 +195,7 @@ export async function handleEvents(
|
|
|
180
195
|
until: parsed.query.until || undefined,
|
|
181
196
|
limit: parsed.query.limit ?? 100,
|
|
182
197
|
});
|
|
183
|
-
|
|
198
|
+
getEventsRoute.respond(res, 200, { events });
|
|
184
199
|
return true;
|
|
185
200
|
}
|
|
186
201
|
|
package/src/http/favorites.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { listFavorites as listFavoriteRows, setFavorite } from "../be/db";
|
|
4
|
-
import { FavoriteItemTypeSchema } from "../types";
|
|
4
|
+
import { FavoriteItemTypeSchema, UserFavoriteSchema } from "../types";
|
|
5
5
|
import { resolveHttpFavoriteOwner } from "./favorite-owner";
|
|
6
6
|
import { route } from "./route-def";
|
|
7
|
-
import {
|
|
7
|
+
import { jsonError } from "./utils";
|
|
8
8
|
|
|
9
9
|
const listFavorites = route({
|
|
10
10
|
method: "get",
|
|
@@ -17,7 +17,13 @@ const listFavorites = route({
|
|
|
17
17
|
itemIds: z.string().optional(),
|
|
18
18
|
}),
|
|
19
19
|
responses: {
|
|
20
|
-
200: {
|
|
20
|
+
200: {
|
|
21
|
+
description: "Favorite rows and favorite item ids",
|
|
22
|
+
schema: z.object({
|
|
23
|
+
favorites: z.array(UserFavoriteSchema),
|
|
24
|
+
favoriteIds: z.array(z.string()),
|
|
25
|
+
}),
|
|
26
|
+
},
|
|
21
27
|
401: { description: "No authenticated principal context" },
|
|
22
28
|
},
|
|
23
29
|
});
|
|
@@ -35,7 +41,15 @@ const putFavorite = route({
|
|
|
35
41
|
favorite: z.boolean(),
|
|
36
42
|
}),
|
|
37
43
|
responses: {
|
|
38
|
-
200: {
|
|
44
|
+
200: {
|
|
45
|
+
description: "Favorite state",
|
|
46
|
+
schema: z.object({
|
|
47
|
+
favorite: z.boolean(),
|
|
48
|
+
itemType: FavoriteItemTypeSchema,
|
|
49
|
+
itemId: z.string(),
|
|
50
|
+
row: UserFavoriteSchema.nullable(),
|
|
51
|
+
}),
|
|
52
|
+
},
|
|
39
53
|
401: { description: "No authenticated principal context" },
|
|
40
54
|
},
|
|
41
55
|
});
|
|
@@ -64,7 +78,7 @@ export async function handleFavorites(
|
|
|
64
78
|
itemType: parsed.query.itemType,
|
|
65
79
|
itemIds,
|
|
66
80
|
});
|
|
67
|
-
|
|
81
|
+
listFavorites.respond(res, 200, {
|
|
68
82
|
favorites,
|
|
69
83
|
favoriteIds: favorites.map((favorite) => favorite.itemId),
|
|
70
84
|
});
|
|
@@ -87,7 +101,7 @@ export async function handleFavorites(
|
|
|
87
101
|
favorite: parsed.body.favorite,
|
|
88
102
|
actorId: owner.actorId,
|
|
89
103
|
});
|
|
90
|
-
|
|
104
|
+
putFavorite.respond(res, 200, {
|
|
91
105
|
favorite: parsed.body.favorite,
|
|
92
106
|
itemType: parsed.body.itemType,
|
|
93
107
|
itemId: parsed.body.itemId,
|
package/src/http/fs.ts
CHANGED
|
@@ -15,12 +15,12 @@ import {
|
|
|
15
15
|
import { type FileObject, type FileScope, FilesError, normalizeFilesError } from "../fs/provider";
|
|
16
16
|
import { getFileStorageProvider } from "../fs/registry";
|
|
17
17
|
import { can, type RbacPrincipal, type RbacResource } from "../rbac";
|
|
18
|
-
import type
|
|
18
|
+
import { type TaskAttachment, TaskAttachmentSchema } from "../types";
|
|
19
19
|
import { attachmentContentDisposition } from "../utils/content-disposition";
|
|
20
20
|
import { getCurrentRequestAuth, getRequestAuth } from "../utils/request-auth-context";
|
|
21
21
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
22
22
|
import { route } from "./route-def";
|
|
23
|
-
import { BODY_TOO_LARGE, enforceContentLengthCap,
|
|
23
|
+
import { BODY_TOO_LARGE, enforceContentLengthCap, jsonError } from "./utils";
|
|
24
24
|
|
|
25
25
|
const MAX_UPLOAD_BYTES = 50 * 1024 * 1024;
|
|
26
26
|
|
|
@@ -38,6 +38,37 @@ const signedUrlQuery = z.object({
|
|
|
38
38
|
expiresIn: z.coerce.number().int().positive().max(3600).optional(),
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
// Mirrors `ProviderCapabilities` from src/fs/capabilities.ts — no zod schema
|
|
42
|
+
// exists there (it's a plain TS type consumed by provider implementations).
|
|
43
|
+
const providerCapabilitiesSchema = z.object({
|
|
44
|
+
signedUrl: z.object({
|
|
45
|
+
supported: z.boolean(),
|
|
46
|
+
maxExpiresIn: z.number().optional(),
|
|
47
|
+
}),
|
|
48
|
+
search: z.boolean().optional(),
|
|
49
|
+
comments: z.boolean().optional(),
|
|
50
|
+
versioning: z.boolean().optional(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const agentFsCredentialStateSchema = z.object({
|
|
54
|
+
enabled: z.boolean(),
|
|
55
|
+
created: z.boolean(),
|
|
56
|
+
agentId: z.string(),
|
|
57
|
+
email: z.string().optional(),
|
|
58
|
+
orgId: z.string().optional(),
|
|
59
|
+
driveId: z.string().optional(),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const agentFsInviteStateSchema = z.object({
|
|
63
|
+
orgId: z.string(),
|
|
64
|
+
invited: z.boolean(),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const signedUrlResponseSchema = z.object({
|
|
68
|
+
url: z.string(),
|
|
69
|
+
expiresIn: z.number(),
|
|
70
|
+
});
|
|
71
|
+
|
|
41
72
|
const capabilitiesRoute = route({
|
|
42
73
|
method: "get",
|
|
43
74
|
path: "/api/fs/capabilities",
|
|
@@ -45,7 +76,10 @@ const capabilitiesRoute = route({
|
|
|
45
76
|
summary: "Get active file-storage provider capabilities",
|
|
46
77
|
tags: ["FS"],
|
|
47
78
|
responses: {
|
|
48
|
-
200: {
|
|
79
|
+
200: {
|
|
80
|
+
description: "Active provider capabilities",
|
|
81
|
+
schema: z.object({ providerId: z.string(), capabilities: providerCapabilitiesSchema }),
|
|
82
|
+
},
|
|
49
83
|
401: { description: "Unauthorized" },
|
|
50
84
|
},
|
|
51
85
|
});
|
|
@@ -60,7 +94,7 @@ const ensureAgentCredentialsRoute = route({
|
|
|
60
94
|
tags: ["FS"],
|
|
61
95
|
body: z.object({}).optional(),
|
|
62
96
|
responses: {
|
|
63
|
-
200: { description: "Credential state" },
|
|
97
|
+
200: { description: "Credential state", schema: agentFsCredentialStateSchema },
|
|
64
98
|
400: { description: "Missing agent id" },
|
|
65
99
|
500: { description: "Provisioning failed" },
|
|
66
100
|
},
|
|
@@ -80,7 +114,7 @@ const inviteMemberRoute = route({
|
|
|
80
114
|
role: z.enum(["viewer", "editor", "admin"]).default("editor"),
|
|
81
115
|
}),
|
|
82
116
|
responses: {
|
|
83
|
-
200: { description: "Invite state ({ orgId, invited })" },
|
|
117
|
+
200: { description: "Invite state ({ orgId, invited })", schema: agentFsInviteStateSchema },
|
|
84
118
|
400: { description: "Invalid body" },
|
|
85
119
|
500: { description: "Provisioning or invite failed" },
|
|
86
120
|
},
|
|
@@ -99,7 +133,10 @@ const listTaskFilesRoute = route({
|
|
|
99
133
|
tags: ["FS"],
|
|
100
134
|
params: taskParams,
|
|
101
135
|
responses: {
|
|
102
|
-
200: {
|
|
136
|
+
200: {
|
|
137
|
+
description: "Task file attachments",
|
|
138
|
+
schema: z.object({ attachments: z.array(TaskAttachmentSchema) }),
|
|
139
|
+
},
|
|
103
140
|
404: { description: "Task not found" },
|
|
104
141
|
},
|
|
105
142
|
});
|
|
@@ -115,7 +152,7 @@ const uploadTaskFileRoute = route({
|
|
|
115
152
|
params: taskParams,
|
|
116
153
|
query: uploadQuery,
|
|
117
154
|
responses: {
|
|
118
|
-
201: { description: "Uploaded task attachment" },
|
|
155
|
+
201: { description: "Uploaded task attachment", schema: TaskAttachmentSchema },
|
|
119
156
|
400: { description: "Validation error" },
|
|
120
157
|
403: { description: "Caller cannot mutate this task" },
|
|
121
158
|
404: { description: "Task not found" },
|
|
@@ -133,7 +170,7 @@ const getTaskFileRoute = route({
|
|
|
133
170
|
tags: ["FS"],
|
|
134
171
|
params: attachmentParams,
|
|
135
172
|
responses: {
|
|
136
|
-
200: { description: "Task attachment metadata" },
|
|
173
|
+
200: { description: "Task attachment metadata", schema: TaskAttachmentSchema },
|
|
137
174
|
404: { description: "Task or attachment not found" },
|
|
138
175
|
},
|
|
139
176
|
});
|
|
@@ -147,7 +184,10 @@ const downloadTaskFileRoute = route({
|
|
|
147
184
|
tags: ["FS"],
|
|
148
185
|
params: attachmentParams,
|
|
149
186
|
responses: {
|
|
150
|
-
200: {
|
|
187
|
+
200: {
|
|
188
|
+
description: "Raw file bytes",
|
|
189
|
+
unstructured: "Streams raw binary file bytes (Content-Type varies per attachment)",
|
|
190
|
+
},
|
|
151
191
|
404: { description: "Task, attachment, or provider object not found" },
|
|
152
192
|
},
|
|
153
193
|
});
|
|
@@ -161,7 +201,7 @@ const signedUrlTaskFileRoute = route({
|
|
|
161
201
|
params: attachmentParams,
|
|
162
202
|
query: signedUrlQuery,
|
|
163
203
|
responses: {
|
|
164
|
-
200: { description: "Signed URL" },
|
|
204
|
+
200: { description: "Signed URL", schema: signedUrlResponseSchema },
|
|
165
205
|
404: { description: "Task, attachment, or provider object not found" },
|
|
166
206
|
501: { description: "Active provider does not support signed URLs" },
|
|
167
207
|
},
|
|
@@ -202,7 +242,7 @@ export async function handleFs(
|
|
|
202
242
|
}
|
|
203
243
|
try {
|
|
204
244
|
const result = await ensureAgentFsCredentialsForAgent(agentId);
|
|
205
|
-
|
|
245
|
+
ensureAgentCredentialsRoute.respond(res, 200, result);
|
|
206
246
|
} catch (error) {
|
|
207
247
|
const message = scrubSecrets(error instanceof Error ? error.message : String(error));
|
|
208
248
|
jsonError(res, `Failed to provision agent-fs credentials: ${message}`, 500);
|
|
@@ -215,7 +255,7 @@ export async function handleFs(
|
|
|
215
255
|
if (!parsed) return true;
|
|
216
256
|
try {
|
|
217
257
|
const result = await inviteEmailToSharedOrg(parsed.body.email, parsed.body.role);
|
|
218
|
-
|
|
258
|
+
inviteMemberRoute.respond(res, 200, result);
|
|
219
259
|
} catch (error) {
|
|
220
260
|
const message = scrubSecrets(error instanceof Error ? error.message : String(error));
|
|
221
261
|
jsonError(res, `Failed to invite member to agent-fs shared org: ${message}`, 500);
|
|
@@ -244,7 +284,7 @@ export async function handleFs(
|
|
|
244
284
|
if (!parsed) return true;
|
|
245
285
|
const attachment = findAttachment(parsed.params.taskId, parsed.params.attachmentId, res);
|
|
246
286
|
if (!attachment) return true;
|
|
247
|
-
|
|
287
|
+
getTaskFileRoute.respond(res, 200, attachment);
|
|
248
288
|
return true;
|
|
249
289
|
}
|
|
250
290
|
|
|
@@ -275,13 +315,16 @@ export async function handleFs(
|
|
|
275
315
|
const parsed = await listTaskFilesRoute.parse(req, res, pathSegments, queryParams);
|
|
276
316
|
if (!parsed) return true;
|
|
277
317
|
if (!getTaskById(parsed.params.taskId)) return notFound(res, "Task not found");
|
|
278
|
-
|
|
318
|
+
listTaskFilesRoute.respond(res, 200, { attachments: getTaskAttachments(parsed.params.taskId) });
|
|
279
319
|
return true;
|
|
280
320
|
}
|
|
281
321
|
|
|
282
322
|
if (capabilitiesRoute.match(req.method, pathSegments)) {
|
|
283
323
|
const provider = getFileStorageProvider();
|
|
284
|
-
|
|
324
|
+
capabilitiesRoute.respond(res, 200, {
|
|
325
|
+
providerId: provider.id,
|
|
326
|
+
capabilities: provider.capabilities,
|
|
327
|
+
});
|
|
285
328
|
return true;
|
|
286
329
|
}
|
|
287
330
|
|
|
@@ -338,7 +381,7 @@ async function sendUpload(
|
|
|
338
381
|
isPrimary: query.isPrimary === "true",
|
|
339
382
|
createdBy: auth?.kind === "user" ? auth.userId : undefined,
|
|
340
383
|
});
|
|
341
|
-
|
|
384
|
+
uploadTaskFileRoute.respond(res, 201, attachment);
|
|
342
385
|
} catch (error) {
|
|
343
386
|
try {
|
|
344
387
|
await provider.delete(scope);
|
|
@@ -397,7 +440,7 @@ async function sendSignedUrl(
|
|
|
397
440
|
}
|
|
398
441
|
try {
|
|
399
442
|
const url = await provider.url(scopeFromAttachment(attachment), { expiresIn });
|
|
400
|
-
|
|
443
|
+
signedUrlTaskFileRoute.respond(res, 200, { url, expiresIn: Math.min(expiresIn ?? 3600, 3600) });
|
|
401
444
|
} catch (error) {
|
|
402
445
|
return sendProviderError(res, error);
|
|
403
446
|
}
|
package/src/http/heartbeat.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
import { checkHeartbeatChecklist, runHeartbeatSweep } from "../heartbeat/heartbeat";
|
|
3
4
|
import { route } from "./route-def";
|
|
4
5
|
import { json } from "./utils";
|
|
5
6
|
|
|
7
|
+
// ─── Response schemas ───────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
const HeartbeatActionResultSchema = z.object({
|
|
10
|
+
success: z.literal(true),
|
|
11
|
+
message: z.string(),
|
|
12
|
+
});
|
|
13
|
+
|
|
6
14
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
7
15
|
|
|
8
16
|
const triggerSweep = route({
|
|
@@ -12,7 +20,7 @@ const triggerSweep = route({
|
|
|
12
20
|
summary: "Trigger an immediate heartbeat sweep",
|
|
13
21
|
tags: ["Heartbeat"],
|
|
14
22
|
responses: {
|
|
15
|
-
200: { description: "Sweep completed successfully" },
|
|
23
|
+
200: { description: "Sweep completed successfully", schema: HeartbeatActionResultSchema },
|
|
16
24
|
401: { description: "Unauthorized" },
|
|
17
25
|
},
|
|
18
26
|
auth: { apiKey: true },
|
|
@@ -25,7 +33,10 @@ const triggerChecklist = route({
|
|
|
25
33
|
summary: "Trigger an immediate heartbeat checklist check",
|
|
26
34
|
tags: ["Heartbeat"],
|
|
27
35
|
responses: {
|
|
28
|
-
200: {
|
|
36
|
+
200: {
|
|
37
|
+
description: "Checklist check completed successfully",
|
|
38
|
+
schema: HeartbeatActionResultSchema,
|
|
39
|
+
},
|
|
29
40
|
401: { description: "Unauthorized" },
|
|
30
41
|
},
|
|
31
42
|
auth: { apiKey: true },
|
|
@@ -44,7 +55,7 @@ export async function handleHeartbeat(
|
|
|
44
55
|
|
|
45
56
|
try {
|
|
46
57
|
await runHeartbeatSweep();
|
|
47
|
-
|
|
58
|
+
triggerSweep.respond(res, 200, { success: true, message: "Heartbeat sweep completed" });
|
|
48
59
|
} catch (err) {
|
|
49
60
|
const message = err instanceof Error ? err.message : "Unknown error during heartbeat sweep";
|
|
50
61
|
json(res, { success: false, error: message }, 500);
|
|
@@ -58,7 +69,10 @@ export async function handleHeartbeat(
|
|
|
58
69
|
|
|
59
70
|
try {
|
|
60
71
|
await checkHeartbeatChecklist();
|
|
61
|
-
|
|
72
|
+
triggerChecklist.respond(res, 200, {
|
|
73
|
+
success: true,
|
|
74
|
+
message: "Heartbeat checklist check completed",
|
|
75
|
+
});
|
|
62
76
|
} catch (err) {
|
|
63
77
|
const message =
|
|
64
78
|
err instanceof Error ? err.message : "Unknown error during heartbeat checklist check";
|
package/src/http/inbox-state.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { listInboxState, upsertInboxState } from "../be/db";
|
|
4
|
-
import { InboxItemStatusSchema, InboxItemTypeSchema } from "../types";
|
|
4
|
+
import { InboxItemStateSchema, InboxItemStatusSchema, InboxItemTypeSchema } from "../types";
|
|
5
5
|
import { route } from "./route-def";
|
|
6
|
-
import {
|
|
6
|
+
import { jsonError } from "./utils";
|
|
7
7
|
|
|
8
8
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
9
9
|
|
|
@@ -19,7 +19,10 @@ const listState = route({
|
|
|
19
19
|
itemType: InboxItemTypeSchema.optional(),
|
|
20
20
|
}),
|
|
21
21
|
responses: {
|
|
22
|
-
200: {
|
|
22
|
+
200: {
|
|
23
|
+
description: "Inbox state rows",
|
|
24
|
+
schema: z.object({ items: z.array(InboxItemStateSchema) }),
|
|
25
|
+
},
|
|
23
26
|
400: { description: "Validation error" },
|
|
24
27
|
401: { description: "Unauthorized" },
|
|
25
28
|
},
|
|
@@ -40,7 +43,10 @@ const upsertState = route({
|
|
|
40
43
|
snoozeUntil: z.string().datetime().optional(),
|
|
41
44
|
}),
|
|
42
45
|
responses: {
|
|
43
|
-
200: {
|
|
46
|
+
200: {
|
|
47
|
+
description: "Upserted inbox state row",
|
|
48
|
+
schema: z.object({ item: InboxItemStateSchema }),
|
|
49
|
+
},
|
|
44
50
|
400: { description: "Validation error" },
|
|
45
51
|
401: { description: "Unauthorized" },
|
|
46
52
|
},
|
|
@@ -63,7 +69,7 @@ export async function handleInboxState(
|
|
|
63
69
|
status: parsed.query.status,
|
|
64
70
|
itemType: parsed.query.itemType,
|
|
65
71
|
});
|
|
66
|
-
|
|
72
|
+
listState.respond(res, 200, { items });
|
|
67
73
|
return true;
|
|
68
74
|
}
|
|
69
75
|
|
|
@@ -78,7 +84,7 @@ export async function handleInboxState(
|
|
|
78
84
|
status: parsed.body.status,
|
|
79
85
|
snoozeUntil: parsed.body.snoozeUntil,
|
|
80
86
|
});
|
|
81
|
-
|
|
87
|
+
upsertState.respond(res, 200, { item });
|
|
82
88
|
} catch (err) {
|
|
83
89
|
jsonError(res, err instanceof Error ? err.message : "Failed to upsert inbox state", 500);
|
|
84
90
|
}
|
package/src/http/integrations.ts
CHANGED
|
@@ -3,7 +3,6 @@ import Anthropic from "@anthropic-ai/sdk";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { getResolvedConfig } from "../be/db";
|
|
5
5
|
import { route } from "./route-def";
|
|
6
|
-
import { json } from "./utils";
|
|
7
6
|
|
|
8
7
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
9
8
|
|
|
@@ -27,6 +26,25 @@ interface TestConnectionDeps {
|
|
|
27
26
|
buildClient?: (apiKey: string) => ClaudeManagedTestClient;
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
// ─── Response schemas ────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
const ClaudeManagedTestResultSchema = z.union([
|
|
32
|
+
z.object({
|
|
33
|
+
ok: z.literal(true),
|
|
34
|
+
agentName: z.string().nullable(),
|
|
35
|
+
model: z.string().nullable(),
|
|
36
|
+
}),
|
|
37
|
+
z.object({
|
|
38
|
+
ok: z.literal(false),
|
|
39
|
+
error: z.string(),
|
|
40
|
+
}),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const McpUserConfigSchema = z.object({
|
|
44
|
+
mcpBaseUrl: z.string(),
|
|
45
|
+
mcpUserUrl: z.string(),
|
|
46
|
+
});
|
|
47
|
+
|
|
30
48
|
// ─── Route Definition ────────────────────────────────────────────────────────
|
|
31
49
|
|
|
32
50
|
const claudeManagedTestRoute = route({
|
|
@@ -41,6 +59,7 @@ const claudeManagedTestRoute = route({
|
|
|
41
59
|
200: {
|
|
42
60
|
description:
|
|
43
61
|
"Connection result — `{ ok: true, agentName, model }` on success or `{ ok: false, error }` on any failure (missing config, Anthropic API error). Always 200 OK.",
|
|
62
|
+
schema: ClaudeManagedTestResultSchema,
|
|
44
63
|
},
|
|
45
64
|
},
|
|
46
65
|
});
|
|
@@ -55,6 +74,7 @@ const mcpUserConfigRoute = route({
|
|
|
55
74
|
200: {
|
|
56
75
|
description:
|
|
57
76
|
"Server-derived MCP user config. `mcpBaseUrl` is the API server base URL and `mcpUserUrl` appends `/mcp-user`.",
|
|
77
|
+
schema: McpUserConfigSchema,
|
|
58
78
|
},
|
|
59
79
|
},
|
|
60
80
|
});
|
|
@@ -116,7 +136,7 @@ export function createIntegrationsHandler(deps: TestConnectionDeps = {}) {
|
|
|
116
136
|
): Promise<boolean> {
|
|
117
137
|
if (mcpUserConfigRoute.match(req.method, pathSegments)) {
|
|
118
138
|
const mcpBaseUrl = resolveMcpBaseUrl();
|
|
119
|
-
|
|
139
|
+
mcpUserConfigRoute.respond(res, 200, { mcpBaseUrl, mcpUserUrl: `${mcpBaseUrl}/mcp-user` });
|
|
120
140
|
return true;
|
|
121
141
|
}
|
|
122
142
|
|
|
@@ -128,7 +148,7 @@ export function createIntegrationsHandler(deps: TestConnectionDeps = {}) {
|
|
|
128
148
|
const missing: string[] = [];
|
|
129
149
|
if (!apiKey) missing.push("ANTHROPIC_API_KEY");
|
|
130
150
|
if (!agentId) missing.push("MANAGED_AGENT_ID");
|
|
131
|
-
|
|
151
|
+
claudeManagedTestRoute.respond(res, 200, {
|
|
132
152
|
ok: false,
|
|
133
153
|
error: `Missing required config: ${missing.join(", ")}. Run \`bun run src/cli.tsx claude-managed-setup\` to populate.`,
|
|
134
154
|
});
|
|
@@ -144,14 +164,14 @@ export function createIntegrationsHandler(deps: TestConnectionDeps = {}) {
|
|
|
144
164
|
typeof agent.model === "string"
|
|
145
165
|
? agent.model
|
|
146
166
|
: ((agent.model as { id?: string } | null | undefined)?.id ?? null);
|
|
147
|
-
|
|
167
|
+
claudeManagedTestRoute.respond(res, 200, {
|
|
148
168
|
ok: true,
|
|
149
169
|
agentName: agent.name ?? null,
|
|
150
170
|
model: modelId,
|
|
151
171
|
});
|
|
152
172
|
} catch (err) {
|
|
153
173
|
const message = err instanceof Error ? err.message : String(err);
|
|
154
|
-
|
|
174
|
+
claudeManagedTestRoute.respond(res, 200, { ok: false, error: message });
|
|
155
175
|
}
|
|
156
176
|
return true;
|
|
157
177
|
}
|