@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.
Files changed (226) hide show
  1. package/README.md +2 -2
  2. package/dist/{actions-kfv2dawe.js → actions-w53mbns9.js} +11 -11
  3. package/dist/{anthropic-messages-3xgme8my.js → anthropic-messages-rjmd2e7n.js} +5 -5
  4. package/dist/{app-q8vjk6e8.js → app-m9gwqsqv.js} +8 -8
  5. package/dist/{artifact-hg4t1nx7.js → artifact-jysj3wrg.js} +2 -2
  6. package/dist/{assistant-g037r345.js → assistant-bp65m6f3.js} +13 -13
  7. package/dist/{azure-openai-responses-xa4sh9f6.js → azure-openai-responses-c0yjmbfd.js} +8 -5
  8. package/dist/{boot-reembed-18pzsrxa.js → boot-reembed-62p0at2k.js} +6 -6
  9. package/dist/{boot-reembed-wpks2cj8.js → boot-reembed-xmfp6wdh.js} +7 -7
  10. package/dist/{boot-scrub-logs-n7szd57r.js → boot-scrub-logs-rr8q2dms.js} +5 -5
  11. package/dist/{claude-adapter-qz4r0ajt.js → claude-adapter-2y47mrkd.js} +9 -9
  12. package/dist/{cli-mhjnbgb6.js → cli-0rcyq6d9.js} +450 -186
  13. package/dist/{cli-ttkmehy0.js → cli-2q72qz2s.js} +274 -25
  14. package/dist/{cli-gztgc3hz.js → cli-2wadx7p2.js} +2 -2
  15. package/dist/cli-3fj60etf.js +153 -0
  16. package/dist/{cli-7ecgm5v0.js → cli-3kf51j15.js} +1 -1
  17. package/dist/{cli-vgexpfsr.js → cli-57khth04.js} +6 -3
  18. package/dist/{cli-2mbe7vk0.js → cli-5dsbcjjw.js} +1 -1
  19. package/dist/{cli-etr62zy6.js → cli-5kx36evn.js} +2 -2
  20. package/dist/{cli-v2tr6amf.js → cli-5n6e5yfn.js} +30 -8
  21. package/dist/{cli-hx02s9zq.js → cli-5v4rw6yd.js} +2 -2
  22. package/dist/{cli-v37yr6mf.js → cli-5ze9rv97.js} +4 -4
  23. package/dist/{cli-ch7t5v7n.js → cli-6map995v.js} +9 -4
  24. package/dist/{cli-h0457a67.js → cli-70xqj0z3.js} +3 -3
  25. package/dist/{cli-kk4f9r17.js → cli-72q8m8gk.js} +8 -6
  26. package/dist/{cli-7padk69a.js → cli-78xwvkhj.js} +2 -2
  27. package/dist/{cli-dxtxacy7.js → cli-9dr5qzc0.js} +45 -8
  28. package/dist/{cli-17zxdgsq.js → cli-a40rnf71.js} +6 -6
  29. package/dist/{cli-t53vnnxz.js → cli-a4jzdpa3.js} +2514 -1055
  30. package/dist/{cli-w10fkrf1.js → cli-akdvwc9v.js} +354 -115
  31. package/dist/{cli-1qkk5er0.js → cli-bmze986d.js} +1 -1
  32. package/dist/{cli-ga12dc1d.js → cli-bqw0mt1n.js} +3 -3
  33. package/dist/{cli-0sf92efp.js → cli-cdeg08wx.js} +1 -1
  34. package/dist/{cli-a8ynhkyj.js → cli-cvgjwnh1.js} +17 -15
  35. package/dist/{cli-9fxg3v5m.js → cli-d2tfkcga.js} +4 -4
  36. package/dist/{cli-nhcd7x43.js → cli-d3x3x1c9.js} +2 -2
  37. package/dist/{cli-6nh2qxvh.js → cli-darcwax3.js} +1 -1
  38. package/dist/{cli-yjbgmysx.js → cli-e7ckcg4v.js} +12 -12
  39. package/dist/{cli-4n2gcjpd.js → cli-efxfnq6q.js} +4 -3
  40. package/dist/{cli-z9xqqhfk.js → cli-er3a4bb0.js} +1 -1
  41. package/dist/{cli-xg2eezyv.js → cli-f1am9szv.js} +1 -1
  42. package/dist/{cli-xy4cwsm9.js → cli-fywms69x.js} +1 -1
  43. package/dist/{cli-33jj76y8.js → cli-g6b8x1h8.js} +1 -1
  44. package/dist/{cli-epsvdckx.js → cli-gm9cbhbq.js} +20 -10
  45. package/dist/{cli-rkndnn90.js → cli-k9qkf1hw.js} +6 -4
  46. package/dist/{cli-zejvt395.js → cli-kh3ba2zf.js} +1 -1
  47. package/dist/{cli-gb25p1h2.js → cli-nm5gtp1x.js} +2 -2
  48. package/dist/{cli-akxnpx17.js → cli-pm6xbh84.js} +1829 -1629
  49. package/dist/{cli-2k0ztbfp.js → cli-psh3c4va.js} +1 -1
  50. package/dist/{cli-39vgrsep.js → cli-qv61hp37.js} +2 -2
  51. package/dist/{cli-hv2fndhm.js → cli-r6kqqbj0.js} +6 -4
  52. package/dist/{cli-1y1cm570.js → cli-rzbpmxdr.js} +1 -1
  53. package/dist/{cli-mmrk00vp.js → cli-t1xze5qh.js} +1 -1
  54. package/dist/{cli-g252a9ky.js → cli-t55yw3a1.js} +2 -2
  55. package/dist/{cli-7bz8dzqa.js → cli-t76vw5db.js} +1184 -1522
  56. package/dist/{cli-4n4mdv21.js → cli-xpxde7rm.js} +7 -3
  57. package/dist/{cli-fpaa5k2q.js → cli-yw8vghx2.js} +54 -18
  58. package/dist/cli-zsspvvm2.js +490 -0
  59. package/dist/cli.js +27 -25
  60. package/dist/{codex-adapter-7v6t7ff6.js → codex-adapter-d24q75wk.js} +7 -7
  61. package/dist/{codex-hook-amndawyb.js → codex-hook-hq54t9ft.js} +2 -2
  62. package/dist/{codex-session-runner-e7j4khe2.js → codex-session-runner-g50vcsex.js} +7 -7
  63. package/dist/{commands-ex0k5tbf.js → commands-c3nrc5hg.js} +5 -5
  64. package/dist/{db-df7jatfc.js → db-nt7fg3tw.js} +5 -5
  65. package/dist/{google-generative-ai-y42hnw9p.js → google-generative-ai-hysrd8qx.js} +7 -5
  66. package/dist/{google-vertex-4sg66gb6.js → google-vertex-p5arrga0.js} +7 -5
  67. package/dist/{handlers-1j2cfqt2.js → handlers-fkr6swat.js} +13 -13
  68. package/dist/{hook-nx9a0mj3.js → hook-77wpvnjc.js} +7 -7
  69. package/dist/{hook-w6yaf6sy.js → hook-g019yehy.js} +8 -8
  70. package/dist/{http-4tz5h8wg.js → http-jewj0syk.js} +2993 -716
  71. package/dist/{index-0bpkzb09.js → index-070v4eyb.js} +3 -3
  72. package/dist/{index-0s67qv7h.js → index-6gm5he8h.js} +11 -11
  73. package/dist/{index-35gtv6gj.js → index-7n2xpbd4.js} +310 -40
  74. package/dist/{index-ker3gccb.js → index-9znhar3x.js} +4 -4
  75. package/dist/{index-5n2c8yay.js → index-hase6zbe.js} +2 -2
  76. package/dist/{index-kcf3tm9h.js → index-hfvggd0z.js} +12 -12
  77. package/dist/{index-7c0jqna0.js → index-hp1kdbjj.js} +13 -13
  78. package/dist/{keepalive-3j4a9168.js → keepalive-j0fjvqfd.js} +7 -7
  79. package/dist/{lead-6kpevymb.js → lead-1n8x30xe.js} +33 -33
  80. package/dist/{maintenance-m1k82ean.js → maintenance-gvev11sa.js} +7 -7
  81. package/dist/{mistral-conversations-bjkdfb6z.js → mistral-conversations-81fwav0j.js} +6 -6
  82. package/dist/{oauth-refresh-sweep-881k8e4q.js → oauth-refresh-sweep-s9ecsvh0.js} +6 -6
  83. package/dist/{onboard-c0ykffjn.js → onboard-pvm5b38w.js} +2 -2
  84. package/dist/{openai-codex-responses-xetseqvt.js → openai-codex-responses-5g27pd6f.js} +43 -23
  85. package/dist/{openai-completions-5r2g5axa.js → openai-completions-3vkmfz2a.js} +55 -11
  86. package/dist/{openai-responses-ce67hd23.js → openai-responses-dg4t7j7a.js} +8 -5
  87. package/dist/{openrouter-images-pzfp22jb.js → openrouter-images-g3gm8931.js} +1 -1
  88. package/dist/{otel-impl-sqagjerv.js → otel-impl-p6jvgd9c.js} +6 -4
  89. package/dist/{otel-3mp81ppd.js → otel-nqa12wf3.js} +2 -2
  90. package/dist/{pi-mono-adapter-k584k16g.js → pi-mono-adapter-t091s27g.js} +17117 -7517
  91. package/dist/{pricing-refresh-y82whbf9.js → pricing-refresh-k49rcyed.js} +7 -7
  92. package/dist/{rbac-roles-nvkqmzyd.js → rbac-roles-30pspvy7.js} +7 -7
  93. package/dist/{rbac-roles-4ht8gegc.js → rbac-roles-cr80g96t.js} +6 -6
  94. package/dist/{render-v2-wvqdgvvp.js → render-v2-xm457ng1.js} +8 -8
  95. package/dist/{seed-pricing-fy3rxhde.js → seed-pricing-yhpv35fr.js} +6 -6
  96. package/dist/{setup-ak5cnc6f.js → setup-nytnmwwr.js} +2 -2
  97. package/dist/{worker-d8769q8a.js → worker-msytr2cw.js} +33 -33
  98. package/openapi.json +34039 -11036
  99. package/package.json +8 -6
  100. package/src/apps/definition.ts +368 -26
  101. package/src/apps/row-store.ts +66 -10
  102. package/src/apps/schema-migrate.ts +95 -1
  103. package/src/apps/store.ts +13 -4
  104. package/src/apps/sync-run-as.ts +18 -0
  105. package/src/apps/sync.ts +934 -0
  106. package/src/apps/version.ts +16 -2
  107. package/src/assets/key.ts +8 -1
  108. package/src/be/asset-key-audit.ts +3 -1
  109. package/src/be/db-queries/mcp-oauth.ts +297 -24
  110. package/src/be/db.ts +42 -1
  111. package/src/be/migrations/129_asset_keys_apps_scripts.sql +161 -0
  112. package/src/be/scripts/db.ts +5 -2
  113. package/src/be/scripts/typecheck.ts +1 -0
  114. package/src/be/seed-scripts/catalog/app-sync-run.ts +32 -0
  115. package/src/be/seed-scripts/catalog/github-issues-pull.ts +102 -0
  116. package/src/be/seed-scripts/index.ts +18 -0
  117. package/src/be/seed-skills/index.ts +7 -0
  118. package/src/http/active-sessions.ts +26 -18
  119. package/src/http/agents.ts +94 -27
  120. package/src/http/api-keys.ts +91 -17
  121. package/src/http/approval-requests.ts +87 -10
  122. package/src/http/apps.ts +361 -53
  123. package/src/http/assets.ts +165 -31
  124. package/src/http/budgets.ts +7 -5
  125. package/src/http/codex-oauth-keep-warm.ts +21 -3
  126. package/src/http/config.ts +46 -16
  127. package/src/http/context.ts +33 -6
  128. package/src/http/ecosystem.ts +20 -6
  129. package/src/http/events.ts +24 -9
  130. package/src/http/favorites.ts +20 -6
  131. package/src/http/fs.ts +60 -17
  132. package/src/http/heartbeat.ts +18 -4
  133. package/src/http/inbox-state.ts +12 -6
  134. package/src/http/integrations.ts +25 -5
  135. package/src/http/kv.ts +36 -15
  136. package/src/http/mcp-bridge.ts +5 -1
  137. package/src/http/mcp-oauth.ts +332 -17
  138. package/src/http/mcp-servers.ts +56 -18
  139. package/src/http/memory.ts +282 -29
  140. package/src/http/metrics.ts +80 -17
  141. package/src/http/oauth-callback.ts +10 -4
  142. package/src/http/oauth-generic.ts +5 -1
  143. package/src/http/oauth-locks.ts +6 -3
  144. package/src/http/openapi.ts +57 -9
  145. package/src/http/page-proxy.ts +25 -5
  146. package/src/http/pages-public.ts +37 -20
  147. package/src/http/pages.ts +93 -28
  148. package/src/http/poll.ts +89 -5
  149. package/src/http/pricing.ts +9 -6
  150. package/src/http/prompt-templates.ts +85 -21
  151. package/src/http/route-def.ts +67 -4
  152. package/src/http/schedules.ts +63 -14
  153. package/src/http/script-connection-proxy.ts +30 -4
  154. package/src/http/script-connections.ts +393 -43
  155. package/src/http/script-runs.ts +73 -19
  156. package/src/http/scripts.ts +257 -39
  157. package/src/http/session-data.ts +87 -14
  158. package/src/http/sessions.ts +80 -5
  159. package/src/http/skills.ts +115 -35
  160. package/src/http/stats.ts +94 -13
  161. package/src/http/task-templates.ts +6 -4
  162. package/src/http/tasks.ts +230 -61
  163. package/src/http/trackers/jira.ts +90 -30
  164. package/src/http/trackers/linear.ts +46 -12
  165. package/src/http/users.ts +162 -25
  166. package/src/http/utils.ts +12 -2
  167. package/src/http/webhooks.ts +30 -16
  168. package/src/http/workflow-events.ts +18 -5
  169. package/src/http/workflows.ts +128 -39
  170. package/src/http/x.ts +37 -6
  171. package/src/oauth/ensure-mcp-token.ts +16 -1
  172. package/src/oauth/mcp-wrapper.ts +281 -26
  173. package/src/providers/pi-mono-adapter.ts +1 -1
  174. package/src/scripts-runtime/credential-broker/README.md +1 -1
  175. package/src/scripts-runtime/credential-broker/fetch-patch.ts +12 -2
  176. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  177. package/src/scripts-runtime/stdlib/fetch.ts +6 -0
  178. package/src/scripts-runtime/types/stdlib.d.ts +1 -0
  179. package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -0
  180. package/src/server.ts +2 -0
  181. package/src/tests/apps-rbac.test.ts +110 -0
  182. package/src/tests/apps-spike2.test.ts +4 -1
  183. package/src/tests/apps-sync-engine.test.ts +2540 -0
  184. package/src/tests/apps-sync.test.ts +1627 -0
  185. package/src/tests/asset-key-api.test.ts +48 -2
  186. package/src/tests/asset-key-invariants.test.ts +92 -0
  187. package/src/tests/asset-key-migration.test.ts +174 -8
  188. package/src/tests/asset-key-normalization.test.ts +2 -0
  189. package/src/tests/credential-broker.test.ts +27 -2
  190. package/src/tests/mcp-oauth-dcr-reuse.test.ts +743 -0
  191. package/src/tests/mcp-oauth-ensure-token.test.ts +45 -0
  192. package/src/tests/mcp-oauth-manual-client.test.ts +135 -2
  193. package/src/tests/mcp-oauth-queries.test.ts +153 -0
  194. package/src/tests/mcp-oauth-wrapper.test.ts +432 -0
  195. package/src/tests/memory-http-recall-gating.test.ts +2 -0
  196. package/src/tests/openapi-response-contract.test.ts +138 -0
  197. package/src/tests/rbac-admission-e2e.test.ts +68 -0
  198. package/src/tests/script-connections.test.ts +3 -0
  199. package/src/tests/scripts-runtime-fetch.test.ts +121 -0
  200. package/src/tests/scripts-runtime-secret-egress.test.ts +4 -2
  201. package/src/tests/seed-scripts.test.ts +2 -2
  202. package/src/tests/swarm-tool-result-gate.test.ts +32 -0
  203. package/src/tests/task-working-dir.test.ts +8 -4
  204. package/src/tests/whoami-route.test.ts +127 -0
  205. package/src/tests/workflow-engine-v2.test.ts +80 -7
  206. package/src/tests/workflow-swarm-script.test.ts +104 -0
  207. package/src/tools/app-get.ts +10 -2
  208. package/src/tools/app-rollback.ts +1 -0
  209. package/src/tools/app-sync.ts +112 -0
  210. package/src/tools/script-common.ts +20 -0
  211. package/src/tools/tool-config.ts +2 -1
  212. package/src/tools/utils.ts +11 -0
  213. package/src/tools/workflows/create-workflow.ts +4 -1
  214. package/src/types.ts +1394 -1206
  215. package/src/utils/template.ts +8 -1
  216. package/src/utils/zod-openapi.ts +11 -0
  217. package/src/workflows/engine.ts +27 -4
  218. package/src/workflows/executors/swarm-script.ts +28 -0
  219. package/src/workflows/retry-poller.ts +19 -2
  220. package/templates/skills/apps/content.md +94 -5
  221. package/templates/skills/asset-namespaces/content.md +2 -2
  222. package/templates/skills/scheduled-task-resilience/SKILL.md +102 -0
  223. package/templates/skills/scheduled-task-resilience/config.json +14 -0
  224. package/templates/skills/scheduled-task-resilience/content.md +97 -0
  225. package/dist/cli-7wmybrt5.js +0 -115
  226. package/dist/cli-d91pvmq1.js +0 -14
package/src/http/stats.ts CHANGED
@@ -13,9 +13,87 @@ import {
13
13
  } from "../be/db";
14
14
  import { isSteeringEnabled } from "../be/steering";
15
15
  import type { AgentLog } from "../types";
16
+ import { AgentLogSchema, ScheduledTaskSchema, ServiceSchema } from "../types";
16
17
  import { resolveHttpFavoriteOwner } from "./favorite-owner";
17
18
  import { route } from "./route-def";
18
- import { json } from "./utils";
19
+
20
+ // ─── Response schemas ────────────────────────────────────────────────────────
21
+
22
+ const AgentCountsSchema = z.object({
23
+ total: z.number(),
24
+ idle: z.number(),
25
+ busy: z.number(),
26
+ offline: z.number(),
27
+ });
28
+
29
+ // getTaskStats() runs a scalar SUM(CASE ...) aggregate with no GROUP BY: on a
30
+ // totally empty agent_tasks table (fresh DB) every SUM comes back SQL NULL
31
+ // (COUNT(*) is the only one that reliably yields 0), so these must be
32
+ // nullable to match the actual wire payload.
33
+ const TaskCountsSchema = z.object({
34
+ total: z.number(),
35
+ unassigned: z.number().nullable(),
36
+ offered: z.number().nullable(),
37
+ reviewing: z.number().nullable(),
38
+ pending: z.number().nullable(),
39
+ in_progress: z.number().nullable(),
40
+ paused: z.number().nullable(),
41
+ completed: z.number().nullable(),
42
+ failed: z.number().nullable(),
43
+ });
44
+
45
+ /** Mirrors the object literal built by handleStats for GET /api/stats. */
46
+ const DashboardStatsSchema = z.object({
47
+ agents: AgentCountsSchema,
48
+ tasks: TaskCountsSchema,
49
+ steeringEnabled: z.boolean(),
50
+ });
51
+
52
+ /** Mirrors `SwarmMetrics` (src/be/db.ts). */
53
+ const SwarmMetricsSchema = z.object({
54
+ tasks: z.object({ total: z.number(), by_status: z.record(z.string(), z.number()) }),
55
+ agents: z.object({ total: z.number(), by_status: z.record(z.string(), z.number()) }),
56
+ workflows: z.object({ total: z.number(), enabled: z.number() }),
57
+ pages: z.object({ total: z.number() }),
58
+ sessions: z.object({ active: z.number() }),
59
+ skills: z.object({ total: z.number() }),
60
+ });
61
+
62
+ /** Mirrors `ConcurrentContext` (src/be/db.ts). */
63
+ const ConcurrentContextSchema = z.object({
64
+ processingInboxMessages: z.array(
65
+ z.object({
66
+ id: z.string(),
67
+ content: z.string(),
68
+ source: z.string(),
69
+ slackChannelId: z.string().nullable(),
70
+ slackThreadTs: z.string().nullable(),
71
+ createdAt: z.string(),
72
+ }),
73
+ ),
74
+ recentTaskDelegations: z.array(
75
+ z.object({
76
+ id: z.string(),
77
+ task: z.string(),
78
+ agentId: z.string().nullable(),
79
+ agentName: z.string().nullable(),
80
+ creatorAgentId: z.string().nullable(),
81
+ status: z.string(),
82
+ createdAt: z.string(),
83
+ }),
84
+ ),
85
+ activeSwarmTasks: z.array(
86
+ z.object({
87
+ id: z.string(),
88
+ task: z.string(),
89
+ agentId: z.string().nullable(),
90
+ agentName: z.string().nullable(),
91
+ status: z.string(),
92
+ createdAt: z.string(),
93
+ progress: z.string().nullable(),
94
+ }),
95
+ ),
96
+ });
19
97
 
20
98
  // ─── Route Definitions ───────────────────────────────────────────────────────
21
99
 
@@ -30,7 +108,7 @@ const listLogs = route({
30
108
  agentId: z.string().optional(),
31
109
  }),
32
110
  responses: {
33
- 200: { description: "Agent logs" },
111
+ 200: { description: "Agent logs", schema: z.object({ logs: z.array(AgentLogSchema) }) },
34
112
  },
35
113
  });
36
114
 
@@ -41,7 +119,7 @@ const getStats = route({
41
119
  summary: "Dashboard summary stats",
42
120
  tags: ["Stats"],
43
121
  responses: {
44
- 200: { description: "Agent and task statistics" },
122
+ 200: { description: "Agent and task statistics", schema: DashboardStatsSchema },
45
123
  },
46
124
  });
47
125
 
@@ -54,7 +132,7 @@ const getMetrics = route({
54
132
  "Single JSON object of cheap `COUNT(*)` metrics — tasks (by status), agents (by status), workflows (total + enabled), pages, active sessions, skills. Use this instead of fetching full list payloads just to count. Powers UI footers/sidebars and MCP context.",
55
133
  tags: ["Stats"],
56
134
  responses: {
57
- 200: { description: "Swarm metrics counts" },
135
+ 200: { description: "Swarm metrics counts", schema: SwarmMetricsSchema },
58
136
  },
59
137
  });
60
138
 
@@ -70,7 +148,7 @@ const listServices = route({
70
148
  name: z.string().optional(),
71
149
  }),
72
150
  responses: {
73
- 200: { description: "Service list" },
151
+ 200: { description: "Service list", schema: z.object({ services: z.array(ServiceSchema) }) },
74
152
  },
75
153
  });
76
154
 
@@ -90,7 +168,10 @@ const listScheduledTasks = route({
90
168
  scriptName: z.string().optional(),
91
169
  }),
92
170
  responses: {
93
- 200: { description: "Scheduled tasks list" },
171
+ 200: {
172
+ description: "Scheduled tasks list",
173
+ schema: z.object({ scheduledTasks: z.array(ScheduledTaskSchema) }),
174
+ },
94
175
  },
95
176
  });
96
177
 
@@ -101,7 +182,7 @@ const getConcurrentContextRoute = route({
101
182
  summary: "Get concurrent session context for lead awareness",
102
183
  tags: ["Stats"],
103
184
  responses: {
104
- 200: { description: "Concurrent context data" },
185
+ 200: { description: "Concurrent context data", schema: ConcurrentContextSchema },
105
186
  },
106
187
  });
107
188
 
@@ -125,7 +206,7 @@ export async function handleStats(
125
206
  } else {
126
207
  logs = getAllLogs(limit);
127
208
  }
128
- json(res, { logs });
209
+ listLogs.respond(res, 200, { logs });
129
210
  return true;
130
211
  }
131
212
 
@@ -156,12 +237,12 @@ export async function handleStats(
156
237
  steeringEnabled: isSteeringEnabled(),
157
238
  };
158
239
 
159
- json(res, stats);
240
+ getStats.respond(res, 200, stats);
160
241
  return true;
161
242
  }
162
243
 
163
244
  if (getMetrics.match(req.method, pathSegments)) {
164
- json(res, getSwarmMetrics());
245
+ getMetrics.respond(res, 200, getSwarmMetrics());
165
246
  return true;
166
247
  }
167
248
 
@@ -173,7 +254,7 @@ export async function handleStats(
173
254
  agentId: parsed.query.agentId || undefined,
174
255
  name: parsed.query.name || undefined,
175
256
  });
176
- json(res, { services });
257
+ listServices.respond(res, 200, { services });
177
258
  return true;
178
259
  }
179
260
 
@@ -193,7 +274,7 @@ export async function handleStats(
193
274
  scriptName: parsed.query.scriptName,
194
275
  });
195
276
  const favoriteScope = resolveHttpFavoriteOwner(req, myAgentId)?.scope;
196
- json(res, {
277
+ listScheduledTasks.respond(res, 200, {
197
278
  scheduledTasks: withFavoriteFlags(scheduledTasks, { favoriteScope, itemType: "schedule" }),
198
279
  });
199
280
  return true;
@@ -201,7 +282,7 @@ export async function handleStats(
201
282
 
202
283
  if (getConcurrentContextRoute.match(req.method, pathSegments)) {
203
284
  const context = getConcurrentContext();
204
- json(res, context);
285
+ getConcurrentContextRoute.respond(res, 200, context);
205
286
  return true;
206
287
  }
207
288
 
@@ -1,9 +1,8 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
2
  import { z } from "zod";
3
3
  import { listTaskTemplates } from "../be/db";
4
- import { TaskTemplateKindSchema } from "../types";
4
+ import { TaskTemplateKindSchema, TaskTemplateSchema } from "../types";
5
5
  import { route } from "./route-def";
6
- import { json } from "./utils";
7
6
 
8
7
  // ─── Route Definitions ───────────────────────────────────────────────────────
9
8
 
@@ -21,7 +20,10 @@ const listTemplates = route({
21
20
  query: z.string().optional(),
22
21
  }),
23
22
  responses: {
24
- 200: { description: "Task template list" },
23
+ 200: {
24
+ description: "Task template list",
25
+ schema: z.object({ templates: z.array(TaskTemplateSchema) }),
26
+ },
25
27
  401: { description: "Unauthorized" },
26
28
  },
27
29
  auth: { apiKey: true },
@@ -43,7 +45,7 @@ export async function handleTaskTemplates(
43
45
  kind: parsed.query.kind,
44
46
  query: parsed.query.query,
45
47
  });
46
- json(res, { templates });
48
+ listTemplates.respond(res, 200, { templates });
47
49
  return true;
48
50
  }
49
51