@desplega.ai/agent-swarm 1.104.0 → 1.106.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 (142) hide show
  1. package/README.md +2 -0
  2. package/dist/{actions-2expzt47.js → actions-pk6xqa2y.js} +6 -6
  3. package/dist/{anthropic-messages-8q7p5vyq.js → anthropic-messages-8nc6r2dw.js} +10 -4
  4. package/dist/{app-dr8hwx7z.js → app-pmfvefkh.js} +3 -3
  5. package/dist/{assistant-9rhgsw7v.js → assistant-wcjpqxk6.js} +9 -9
  6. package/dist/{azure-openai-responses-0dmr2hzc.js → azure-openai-responses-6yfzw3qw.js} +10 -18
  7. package/dist/{boot-reembed-9kt97g1z.js → boot-reembed-atv4kcrh.js} +3 -3
  8. package/dist/{boot-reembed-3q1aywnz.js → boot-reembed-zanbm36c.js} +4 -4
  9. package/dist/{boot-scrub-logs-vskq108e.js → boot-scrub-logs-asq051ff.js} +2 -2
  10. package/dist/{claude-adapter-e3dhkq85.js → claude-adapter-w96mzan4.js} +2 -2
  11. package/dist/{claude-managed-adapter-z29hjgzz.js → claude-managed-adapter-vj9kzegz.js} +4 -4
  12. package/dist/{claude-managed-setup-ftbmvmvx.js → claude-managed-setup-t0wkvzgz.js} +1 -1
  13. package/dist/{cli-92fqyjcv.js → cli-07er7wrs.js} +1 -1
  14. package/dist/{cli-y9p3e94h.js → cli-08fnz4jm.js} +3 -3
  15. package/dist/{cli-yjt8a36k.js → cli-39jaysbv.js} +8 -6
  16. package/dist/{cli-5pf0b84v.js → cli-4fwzc50f.js} +2 -2
  17. package/dist/{cli-p03mawph.js → cli-50nss8e8.js} +928 -335
  18. package/dist/{cli-e7bwjntj.js → cli-6hqvenfv.js} +1 -1
  19. package/dist/{cli-0jw6j755.js → cli-6xn2xv4r.js} +24 -8
  20. package/dist/{cli-2g9jf9ek.js → cli-842gfjn1.js} +1 -1
  21. package/dist/{cli-v1syqkcb.js → cli-84gyjn6h.js} +146 -3
  22. package/dist/{cli-7b9ctyfq.js → cli-8da61htc.js} +1 -1
  23. package/dist/{cli-nzc0h54v.js → cli-8fhhmzbh.js} +1 -1
  24. package/dist/{cli-khe4x17a.js → cli-anrn8brw.js} +3 -3
  25. package/dist/{cli-2q1ct4en.js → cli-bsyka9ta.js} +104 -3
  26. package/dist/{cli-p04j6hjv.js → cli-dqhz8451.js} +1 -1
  27. package/dist/{cli-s42f54ja.js → cli-f7ypwjgh.js} +1 -1
  28. package/dist/{cli-p4cj4vhc.js → cli-hmqkes02.js} +1 -1
  29. package/dist/{cli-23zk7xqy.js → cli-j1172z85.js} +26 -18
  30. package/dist/{cli-yp2krx5r.js → cli-jk4tj5m6.js} +9 -3
  31. package/dist/{cli-q5tshxd6.js → cli-k7gt5r0p.js} +1 -1
  32. package/dist/{cli-54h5daha.js → cli-n38fcvhe.js} +6 -6
  33. package/dist/{cli-2hap19dv.js → cli-p7hff99g.js} +3 -3
  34. package/dist/cli-pscrc6tw.js +73 -0
  35. package/dist/{cli-yvektv79.js → cli-pxddwmyc.js} +1 -1
  36. package/dist/{cli-ncg70f07.js → cli-q44nxhwq.js} +1 -1
  37. package/dist/{cli-d4z1csms.js → cli-qtr61agf.js} +3 -3
  38. package/dist/{cli-zaxksbgj.js → cli-rp5kaak8.js} +5 -5
  39. package/dist/{cli-0fxvpa2q.js → cli-sdpnhajn.js} +150 -163
  40. package/dist/{cli-w1nfskkg.js → cli-sp3c9fwf.js} +2 -2
  41. package/dist/{cli-gj2n2ec1.js → cli-tfcrm7ds.js} +1 -1
  42. package/dist/{cli-0k9dc6ks.js → cli-tghre7g6.js} +1 -0
  43. package/dist/{cli-qvzgncd8.js → cli-v90vvqt8.js} +401 -125
  44. package/dist/{cli-zghef0em.js → cli-v9853xza.js} +1 -1
  45. package/dist/{cli-t9v14cnd.js → cli-wfhe4tgs.js} +1 -1
  46. package/dist/{cli-7v4y3hyd.js → cli-xgssgdqn.js} +2 -2
  47. package/dist/{cli-etvgz5x8.js → cli-xvs40j7w.js} +4 -4
  48. package/dist/{cli-jntqphs0.js → cli-ygcrdkqt.js} +15 -9
  49. package/dist/{cli-2957pqpj.js → cli-yv9dttkh.js} +32 -9
  50. package/dist/cli.js +20 -17
  51. package/dist/{codex-adapter-w0xharsg.js → codex-adapter-h9rj59tj.js} +5 -5
  52. package/dist/{codex-session-runner-kzbjcm2k.js → codex-session-runner-2ybavr0w.js} +5 -5
  53. package/dist/{commands-wfrkef57.js → commands-075ak6vf.js} +2 -2
  54. package/dist/{db-c42pxt7h.js → db-60fj8j7t.js} +2 -2
  55. package/dist/{google-generative-ai-mdn340ga.js → google-generative-ai-rf42vj2h.js} +9 -4
  56. package/dist/{google-vertex-mkdewpwe.js → google-vertex-m92pj5fb.js} +9 -4
  57. package/dist/{handlers-n36zkfvx.js → handlers-96j9z4gk.js} +9 -9
  58. package/dist/{hook-gw3vhv6s.js → hook-f58wyvmy.js} +3 -3
  59. package/dist/{http-59ygpn2h.js → http-naqhj1n0.js} +579 -52
  60. package/dist/{index-xf6fp4y1.js → index-45bqm6xc.js} +5 -5
  61. package/dist/{index-xz8vaa5c.js → index-f5e873a5.js} +10 -10
  62. package/dist/{index-jca7jdpt.js → index-jscerv2x.js} +10 -6
  63. package/dist/{index-881c1baf.js → index-v3r40ak0.js} +8 -8
  64. package/dist/{keepalive-mj4302vw.js → keepalive-8gbgeg21.js} +4 -4
  65. package/dist/{lead-qm0xjvkv.js → lead-hj6stakm.js} +26 -26
  66. package/dist/{maintenance-xppxbe4t.js → maintenance-1nvd0jva.js} +4 -4
  67. package/dist/{mistral-conversations-j380wd2q.js → mistral-conversations-26yrnbf1.js} +2 -2
  68. package/dist/{onboard-ejx6yxh8.js → onboard-8myqe0jh.js} +2 -2
  69. package/dist/{openai-codex-responses-v80z7kgx.js → openai-codex-responses-8h6kvfv8.js} +16 -25
  70. package/dist/{openai-completions-39vefwrq.js → openai-completions-x6kjnqjd.js} +11 -5
  71. package/dist/{openai-responses-dp5bkm3q.js → openai-responses-7jwyz3ds.js} +8 -16
  72. package/dist/{opencode-adapter-s8vsmzpy.js → opencode-adapter-p2w6efwc.js} +2 -2
  73. package/dist/{openrouter-images-54cva05t.js → openrouter-images-537nmn1r.js} +5 -1
  74. package/dist/{otel-impl-zs5exkpk.js → otel-impl-tddx9x81.js} +4510 -4465
  75. package/dist/{pi-mono-adapter-zf7dt1wg.js → pi-mono-adapter-y037wnp4.js} +596 -297
  76. package/dist/{pricing-refresh-nqyf8bkb.js → pricing-refresh-f6cgj5br.js} +4 -4
  77. package/dist/{seed-pricing-w3x550cj.js → seed-pricing-3tqmbe0p.js} +3 -3
  78. package/dist/{setup-7729ktfj.js → setup-tq3ept9k.js} +2 -2
  79. package/dist/{worker-4ttemwhw.js → worker-526psbtb.js} +26 -26
  80. package/openapi.json +315 -1
  81. package/package.json +8 -6
  82. package/src/be/db.ts +6 -2
  83. package/src/be/memory/access.ts +5 -0
  84. package/src/be/migrations/102_script_apis.sql +31 -0
  85. package/src/be/modelsdev-cache.json +22170 -7247
  86. package/src/be/scripts/db.ts +214 -1
  87. package/src/be/seed-pricing.ts +1 -1
  88. package/src/commands/claude-managed-setup.ts +1 -1
  89. package/src/hooks/tool-loop-detection.test.ts +81 -1
  90. package/src/hooks/tool-loop-detection.ts +53 -10
  91. package/src/http/index.ts +11 -1
  92. package/src/http/mcp.ts +49 -0
  93. package/src/http/memory.ts +21 -11
  94. package/src/http/pages-public.ts +123 -2
  95. package/src/http/scripts.ts +213 -0
  96. package/src/http/session-data.ts +16 -0
  97. package/src/http/x.ts +244 -0
  98. package/src/otel-impl.ts +73 -0
  99. package/src/otel.ts +12 -0
  100. package/src/prompts/session-templates.ts +5 -1
  101. package/src/providers/claude-managed-models.ts +9 -0
  102. package/src/server.ts +2 -0
  103. package/src/tests/agents-list-model-display.test.ts +5 -0
  104. package/src/tests/bedrock-model-groups.test.ts +3 -0
  105. package/src/tests/claude-managed-adapter.test.ts +14 -0
  106. package/src/tests/claude-managed-setup.test.ts +3 -3
  107. package/src/tests/context-window.test.ts +1 -0
  108. package/src/tests/harness-provider-resolution.test.ts +39 -0
  109. package/src/tests/http-api-integration.test.ts +1 -1
  110. package/src/tests/mcp-user-route.test.ts +70 -5
  111. package/src/tests/memory-get-tool.test.ts +132 -0
  112. package/src/tests/memory-http-recall-gating.test.ts +17 -1
  113. package/src/tests/migration-046-budgets.test.ts +32 -0
  114. package/src/tests/otel-impl-secret-scrubbing.test.ts +101 -3
  115. package/src/tests/otel-session-cost-metrics.test.ts +281 -0
  116. package/src/tests/pages-authed-mode.test.ts +50 -0
  117. package/src/tests/preload.ts +26 -0
  118. package/src/tests/register-service-security.test.ts +194 -0
  119. package/src/tests/script-apis-mcp.test.ts +308 -0
  120. package/src/tests/scripts-external-api.test.ts +449 -0
  121. package/src/tests/session-costs-model-key-normalize.test.ts +1 -0
  122. package/src/tests/update-profile-auth.test.ts +35 -1
  123. package/src/tools/memory-get.ts +17 -2
  124. package/src/tools/register-service.ts +68 -4
  125. package/src/tools/script-apis.ts +158 -0
  126. package/src/tools/script-common.ts +1 -1
  127. package/src/tools/tool-config.ts +2 -1
  128. package/src/tools/update-profile.ts +84 -1
  129. package/src/types.ts +27 -1
  130. package/src/utils/context-window.ts +1 -0
  131. package/src/utils/harness-provider.ts +35 -6
  132. package/src/utils/short-id.ts +44 -0
  133. package/templates/community/code-health-reports/run.sh +12 -6
  134. package/templates/community/dora-metrics/run.sh +10 -2
  135. package/templates/official/coder/start-up.sh +2 -2
  136. package/templates/official/content-reviewer/start-up.sh +2 -2
  137. package/templates/official/content-strategist/start-up.sh +2 -2
  138. package/templates/official/content-writer/start-up.sh +2 -2
  139. package/templates/official/discoverability-optimizer/start-up.sh +2 -2
  140. package/templates/official/ux-principles/start-up.sh +5 -5
  141. package/templates/skills/swarm-scripts/SKILL.md +4 -0
  142. package/templates/skills/swarm-scripts/content.md +4 -0
@@ -9,6 +9,7 @@ import {
9
9
  applyRating,
10
10
  assertSelectOnlyQuery,
11
11
  canClaim,
12
+ canReadMemory,
12
13
  cancelTaskHandler,
13
14
  cancelTaskInputSchema,
14
15
  cancelTaskOutputSchema,
@@ -79,6 +80,7 @@ import {
79
80
  parseQueryParams,
80
81
  parseSkillContent,
81
82
  recordRetrievals,
83
+ recordSessionCost,
82
84
  registerJiraWebhook,
83
85
  reloadGlobalConfigsAndIntegrations,
84
86
  resolveHttpAuditUserId,
@@ -106,7 +108,7 @@ import {
106
108
  withRemoteContext,
107
109
  withSpanContext,
108
110
  writeSkillsToFilesystem
109
- } from "./cli-qvzgncd8.js";
111
+ } from "./cli-v90vvqt8.js";
110
112
  import {
111
113
  BROWSER_SDK_JS,
112
114
  SWARM_UI_JS
@@ -129,27 +131,27 @@ import {
129
131
  generateRandomState,
130
132
  getOAuthApp,
131
133
  getOAuthTokens
132
- } from "./cli-2g9jf9ek.js";
133
- import"./cli-w1nfskkg.js";
134
+ } from "./cli-842gfjn1.js";
135
+ import"./cli-sp3c9fwf.js";
134
136
  import {
135
137
  normalizeModelKey
136
- } from "./cli-7v4y3hyd.js";
138
+ } from "./cli-xgssgdqn.js";
137
139
  import {
138
140
  SCRIPT_STDLIB_TYPES,
139
141
  extractArgsJsonSchema,
140
142
  extractScriptSignature,
141
143
  scriptSdkTypesWithGeneratedApis,
142
144
  typecheckScript
143
- } from "./cli-t9v14cnd.js";
145
+ } from "./cli-wfhe4tgs.js";
144
146
  import {
145
147
  checkHeartbeatChecklist,
146
148
  runHeartbeatSweep,
147
149
  stopHeartbeat
148
- } from "./cli-d4z1csms.js";
150
+ } from "./cli-qtr61agf.js";
149
151
  import {
150
152
  createResumeFollowUp,
151
153
  createWorkerTaskFollowUp
152
- } from "./cli-s42f54ja.js";
154
+ } from "./cli-f7ypwjgh.js";
153
155
  import {
154
156
  RawLlmConfigSchema,
155
157
  buildScriptCredentialBindings,
@@ -160,23 +162,31 @@ import {
160
162
  retryFailedRun,
161
163
  runScript,
162
164
  snapshotWorkflow
163
- } from "./cli-54h5daha.js";
165
+ } from "./cli-n38fcvhe.js";
164
166
  import {
165
167
  getApiKey
166
168
  } from "./cli-f14fvzag.js";
167
169
  import {
170
+ createScriptApi,
168
171
  deleteScript,
172
+ deleteScriptApi,
169
173
  getScript,
174
+ getScriptApiById,
170
175
  getScriptApiConnectionDescriptors,
176
+ getScriptApiSecret,
171
177
  getScriptApiTypes,
172
178
  getScriptById,
179
+ listScriptApisForScript,
173
180
  listScriptVersions,
174
181
  listScripts,
182
+ recordScriptApiUsage,
183
+ rotateScriptApiSecret,
184
+ updateScriptApi,
175
185
  upsertScriptByName
176
- } from "./cli-v1syqkcb.js";
186
+ } from "./cli-84gyjn6h.js";
177
187
  import {
178
188
  searchScripts
179
- } from "./cli-5pf0b84v.js";
189
+ } from "./cli-4fwzc50f.js";
180
190
  import {
181
191
  CANDIDATE_SET_MULTIPLIER,
182
192
  getEmbeddingProvider,
@@ -184,7 +194,7 @@ import {
184
194
  init_constants,
185
195
  init_reranker,
186
196
  rerank
187
- } from "./cli-p4cj4vhc.js";
197
+ } from "./cli-hmqkes02.js";
188
198
  import"./cli-3j01d33e.js";
189
199
  import"./cli-fad8m16k.js";
190
200
  import {
@@ -193,7 +203,7 @@ import {
193
203
  ensure,
194
204
  initialize,
195
205
  require_dist
196
- } from "./cli-y9p3e94h.js";
206
+ } from "./cli-08fnz4jm.js";
197
207
  import {
198
208
  TriggerSchemaError,
199
209
  WebhookError,
@@ -205,18 +215,18 @@ import {
205
215
  validateDefinition,
206
216
  validateJsonSchema,
207
217
  verifyHmacSignature
208
- } from "./cli-zghef0em.js";
209
- import"./cli-nzc0h54v.js";
218
+ } from "./cli-v9853xza.js";
219
+ import"./cli-8fhhmzbh.js";
210
220
  import {
211
221
  getSlackApp,
212
222
  startSlackApp,
213
223
  stopSlackApp
214
- } from "./cli-zaxksbgj.js";
224
+ } from "./cli-rp5kaak8.js";
215
225
  import"./cli-fete3y1e.js";
216
226
  import"./cli-b0p7rfnd.js";
217
227
  import {
218
228
  recordUnmappedIdentity
219
- } from "./cli-gj2n2ec1.js";
229
+ } from "./cli-tfcrm7ds.js";
220
230
  import {
221
231
  findOrCreateUserByEmail,
222
232
  findUserByExternalId,
@@ -230,7 +240,7 @@ import {
230
240
  resolveUserByToken,
231
241
  revokeToken,
232
242
  unlinkIdentity
233
- } from "./cli-yvektv79.js";
243
+ } from "./cli-pxddwmyc.js";
234
244
  import"./cli-z92pkwzn.js";
235
245
  import {
236
246
  getAppUrl,
@@ -243,7 +253,7 @@ import {
243
253
  createTaskWithSiblingAwareness,
244
254
  gitlabContextKey,
245
255
  pageContextKey
246
- } from "./cli-e7bwjntj.js";
256
+ } from "./cli-6hqvenfv.js";
247
257
  import {
248
258
  AgentCredStatusSchema,
249
259
  AgentLatestModelSchema,
@@ -280,6 +290,7 @@ import {
280
290
  RepoGuidelinesSchema,
281
291
  RepoHooksSchema,
282
292
  ResumeReasonSchema,
293
+ ScriptApiAuthModeSchema,
283
294
  ScriptFsModeSchema,
284
295
  ScriptRunStatusSchema,
285
296
  ScriptScopeSchema,
@@ -536,7 +547,7 @@ import {
536
547
  upsertSkillFiles,
537
548
  upsertSwarmConfig,
538
549
  validateConfigValue
539
- } from "./cli-0jw6j755.js";
550
+ } from "./cli-6xn2xv4r.js";
540
551
  import"./cli-z2zcxes1.js";
541
552
  import {
542
553
  init_zod
@@ -551,7 +562,7 @@ import {
551
562
  import {
552
563
  init_package,
553
564
  package_default
554
- } from "./cli-yjt8a36k.js";
565
+ } from "./cli-39jaysbv.js";
555
566
  import {
556
567
  init_secret_scrubber,
557
568
  registerVolatileSecret,
@@ -565,17 +576,18 @@ import {
565
576
  } from "./cli-9aryf9tv.js";
566
577
  import {
567
578
  bedrockProviderModule
568
- } from "./cli-jntqphs0.js";
579
+ } from "./cli-ygcrdkqt.js";
569
580
  import"./cli-jvv0g8bh.js";
570
581
  import {
571
582
  setBedrockProviderModule
572
583
  } from "./cli-xw7p4wkq.js";
573
584
  import"./cli-6kqcg4zv.js";
574
585
  import"./cli-cwy5hqbq.js";
586
+ import"./cli-pscrc6tw.js";
575
587
  import"./cli-4wgngmwv.js";
576
588
  import"./cli-vapyk8sw.js";
577
589
  import"./cli-zyxs93y9.js";
578
- import"./cli-2q1ct4en.js";
590
+ import"./cli-bsyka9ta.js";
579
591
  import"./cli-y2apkfe2.js";
580
592
  import"./cli-m6pzzhqr.js";
581
593
  import"./cli-7sgrxg9a.js";
@@ -5071,6 +5083,7 @@ class StreamableHTTPServerTransport {
5071
5083
  }
5072
5084
 
5073
5085
  // src/http/mcp.ts
5086
+ init_db();
5074
5087
  var DEFAULT_MCP_TRANSPORT_IDLE_TIMEOUT_MS = 2 * 60 * 60 * 1000;
5075
5088
  function markMcpTransportActivity(sessionActivity, sessionId, now = Date.now()) {
5076
5089
  if (sessionId) {
@@ -5102,11 +5115,45 @@ function closeIdleMcpTransports(transports, sessionActivity, options = {}) {
5102
5115
  }
5103
5116
  return closed;
5104
5117
  }
5105
- async function handleMcp(req, res, transports, sessionActivity = {}) {
5118
+ function unauthorized(res, message = "Unauthorized") {
5119
+ res.writeHead(401, { "Content-Type": "application/json" });
5120
+ res.end(JSON.stringify({ error: message }));
5121
+ return true;
5122
+ }
5123
+ function headerValue(value) {
5124
+ return Array.isArray(value) ? value[0] : value;
5125
+ }
5126
+ function requireKnownAgent(req, res) {
5127
+ const agentId = headerValue(req.headers["x-agent-id"]);
5128
+ if (!agentId)
5129
+ return unauthorized(res, "Missing X-Agent-ID header");
5130
+ if (!getAgentById(agentId))
5131
+ return unauthorized(res, "Agent not found");
5132
+ return agentId;
5133
+ }
5134
+ function validateBoundAgent(req, res, sessionId, sessionAgents) {
5135
+ if (!sessionId)
5136
+ return;
5137
+ const boundAgentId = sessionAgents[sessionId];
5138
+ if (!boundAgentId)
5139
+ return;
5140
+ const agentId = headerValue(req.headers["x-agent-id"]);
5141
+ if (!agentId) {
5142
+ return unauthorized(res, "Missing X-Agent-ID header");
5143
+ }
5144
+ if (agentId !== boundAgentId) {
5145
+ return unauthorized(res, "X-Agent-ID does not match MCP session");
5146
+ }
5147
+ return;
5148
+ }
5149
+ async function handleMcp(req, res, transports, sessionActivity = {}, sessionAgents = {}) {
5106
5150
  const sessionId = req.headers["mcp-session-id"];
5107
5151
  if (req.url !== "/mcp") {
5108
5152
  return false;
5109
5153
  }
5154
+ const agentMismatch = validateBoundAgent(req, res, sessionId, sessionAgents);
5155
+ if (agentMismatch)
5156
+ return true;
5110
5157
  if (req.method === "POST") {
5111
5158
  const chunks = [];
5112
5159
  for await (const chunk of req) {
@@ -5118,20 +5165,26 @@ async function handleMcp(req, res, transports, sessionActivity = {}) {
5118
5165
  transport = transports[sessionId];
5119
5166
  markMcpTransportActivity(sessionActivity, sessionId);
5120
5167
  } else if (!sessionId && isInitializeRequest(body)) {
5168
+ const agentId = requireKnownAgent(req, res);
5169
+ if (agentId === true)
5170
+ return true;
5121
5171
  transport = new StreamableHTTPServerTransport({
5122
5172
  sessionIdGenerator: () => randomUUID(),
5123
5173
  onsessioninitialized: (id) => {
5124
5174
  transports[id] = transport;
5175
+ sessionAgents[id] = agentId;
5125
5176
  markMcpTransportActivity(sessionActivity, id);
5126
5177
  },
5127
5178
  onsessionclosed: (id) => {
5128
5179
  delete transports[id];
5180
+ delete sessionAgents[id];
5129
5181
  delete sessionActivity[id];
5130
5182
  }
5131
5183
  });
5132
5184
  transport.onclose = () => {
5133
5185
  if (transport.sessionId) {
5134
5186
  delete transports[transport.sessionId];
5187
+ delete sessionAgents[transport.sessionId];
5135
5188
  delete sessionActivity[transport.sessionId];
5136
5189
  }
5137
5190
  };
@@ -6824,7 +6877,7 @@ function createUserServer(user) {
6824
6877
  }
6825
6878
 
6826
6879
  // src/http/mcp-user.ts
6827
- function unauthorized(res) {
6880
+ function unauthorized2(res) {
6828
6881
  res.writeHead(401, { "Content-Type": "application/json" });
6829
6882
  res.end(JSON.stringify({ error: "Unauthorized" }));
6830
6883
  return true;
@@ -6852,9 +6905,9 @@ async function handleMcpUser(req, res, transports, sessionUsers, sessionActivity
6852
6905
  }
6853
6906
  const user = resolveActiveUser(req);
6854
6907
  if (!user)
6855
- return unauthorized(res);
6908
+ return unauthorized2(res);
6856
6909
  if (sessionId && transports[sessionId] && sessionUsers[sessionId] !== user.id) {
6857
- return unauthorized(res);
6910
+ return unauthorized2(res);
6858
6911
  }
6859
6912
  if (req.method === "POST") {
6860
6913
  const chunks = [];
@@ -7385,6 +7438,7 @@ async function handleMemory(req, res, pathSegments, myAgentId) {
7385
7438
  persistMemory,
7386
7439
  contextKey
7387
7440
  } = parsed.body;
7441
+ const memoryAgentId = agentId ?? (scope === "agent" ? myAgentId : undefined);
7388
7442
  if (source === "session_summary" && sourceTaskId) {
7389
7443
  const sourceTask = getTaskById(sourceTaskId);
7390
7444
  if (sourceTask && !shouldPersistAutomaticTaskMemory(sourceTask, persistMemory)) {
@@ -7403,11 +7457,11 @@ async function handleMemory(req, res, pathSegments, myAgentId) {
7403
7457
  }
7404
7458
  const store = getMemoryStore();
7405
7459
  const provider = getEmbeddingProvider();
7406
- if (sourcePath && agentId && contentChunks.length === 1) {
7407
- const existing = store.list(agentId, {
7460
+ if (sourcePath && memoryAgentId && contentChunks.length === 1) {
7461
+ const existing = store.list(memoryAgentId, {
7408
7462
  scope,
7409
7463
  limit: 2,
7410
- ownerAgentId: agentId,
7464
+ ownerAgentId: memoryAgentId,
7411
7465
  sourcePath
7412
7466
  }).filter((memory) => memory.sourcePath === sourcePath);
7413
7467
  if (existing.length === 1 && existing[0]?.totalChunks === 1) {
@@ -7422,7 +7476,7 @@ async function handleMemory(req, res, pathSegments, myAgentId) {
7422
7476
  if (embedding)
7423
7477
  store.updateEmbedding(result.memory.id, embedding, provider.name);
7424
7478
  try {
7425
- storeLinks(result.memory.id, agentId, result.memory.content);
7479
+ storeLinks(result.memory.id, memoryAgentId, result.memory.content);
7426
7480
  } catch (err) {
7427
7481
  console.error(`[memory] Link resolution failed for ${result.memory.id}:`, err.message);
7428
7482
  }
@@ -7430,13 +7484,13 @@ async function handleMemory(req, res, pathSegments, myAgentId) {
7430
7484
  return true;
7431
7485
  }
7432
7486
  }
7433
- if (sourcePath && agentId) {
7434
- store.deleteBySourcePath(sourcePath, agentId);
7487
+ if (sourcePath && memoryAgentId) {
7488
+ store.deleteBySourcePath(sourcePath, memoryAgentId);
7435
7489
  }
7436
7490
  const headerContextKey = req.headers["x-context-key"];
7437
7491
  const resolvedContextKey = contextKey ?? (Array.isArray(headerContextKey) ? headerContextKey[0] : headerContextKey) ?? undefined;
7438
7492
  const memories = store.storeBatch(contentChunks.map((chunk) => ({
7439
- agentId: agentId || null,
7493
+ agentId: memoryAgentId || null,
7440
7494
  content: chunk.content,
7441
7495
  name,
7442
7496
  scope,
@@ -7450,10 +7504,10 @@ async function handleMemory(req, res, pathSegments, myAgentId) {
7450
7504
  intent: "index memory content",
7451
7505
  key: sourcePath || null
7452
7506
  })));
7453
- if (agentId) {
7507
+ if (memoryAgentId) {
7454
7508
  for (const memory of memories) {
7455
7509
  try {
7456
- storeLinks(memory.id, agentId, memory.content);
7510
+ storeLinks(memory.id, memoryAgentId, memory.content);
7457
7511
  } catch (err) {
7458
7512
  console.error(`[memory] Link resolution failed for ${memory.id}:`, err.message);
7459
7513
  }
@@ -7819,11 +7873,17 @@ async function handleMemory(req, res, pathSegments, myAgentId) {
7819
7873
  const parsed = await getMemoryById.parse(req, res, pathSegments, queryParams);
7820
7874
  if (!parsed)
7821
7875
  return true;
7822
- const memory = getMemoryStore().get(parsed.params.id);
7823
- if (!memory) {
7876
+ const store = getMemoryStore();
7877
+ const memoryForAuth = store.peek(parsed.params.id);
7878
+ if (!memoryForAuth) {
7824
7879
  jsonError(res, "Memory not found", 404);
7825
7880
  return true;
7826
7881
  }
7882
+ if (!canReadMemory(memoryForAuth, myAgentId)) {
7883
+ jsonError(res, "Not authorized", 403);
7884
+ return true;
7885
+ }
7886
+ const memory = store.get(parsed.params.id);
7827
7887
  const { intent } = parsed.query;
7828
7888
  const sourceTaskIdHeader = req.headers["x-source-task-id"];
7829
7889
  const sourceTaskId = Array.isArray(sourceTaskIdHeader) ? sourceTaskIdHeader[0] : sourceTaskIdHeader;
@@ -9076,6 +9136,86 @@ function injectBrowserSdk(html) {
9076
9136
  }
9077
9137
  return injection + html;
9078
9138
  }
9139
+ var PRINT_AUTOTRIGGER_SCRIPT = `<script>
9140
+ (function () {
9141
+ function print() { setTimeout(function () { window.print(); }, 400); }
9142
+ window.addEventListener("load", function () {
9143
+ var fonts = document.fonts;
9144
+ if (fonts && fonts.ready && typeof fonts.ready.then === "function") {
9145
+ fonts.ready.then(print, print);
9146
+ } else {
9147
+ print();
9148
+ }
9149
+ });
9150
+ })();
9151
+ </script>`;
9152
+ function escapeHtml(value) {
9153
+ return value.replace(/[&<>"']/g, (char) => {
9154
+ switch (char) {
9155
+ case "&":
9156
+ return "&amp;";
9157
+ case "<":
9158
+ return "&lt;";
9159
+ case ">":
9160
+ return "&gt;";
9161
+ case '"':
9162
+ return "&quot;";
9163
+ default:
9164
+ return "&#39;";
9165
+ }
9166
+ });
9167
+ }
9168
+ function printableJsonPageHtml(page) {
9169
+ let body = page.body;
9170
+ try {
9171
+ body = JSON.stringify(JSON.parse(page.body), null, 2);
9172
+ } catch {}
9173
+ const description = page.description ? `<p class="description">${escapeHtml(page.description)}</p>` : "";
9174
+ return `<!doctype html>
9175
+ <html>
9176
+ <head>
9177
+ <meta charset="utf-8">
9178
+ <title>${escapeHtml(page.title)}</title>
9179
+ <style>
9180
+ body {
9181
+ color: #111827;
9182
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
9183
+ line-height: 1.5;
9184
+ margin: 0;
9185
+ padding: 24px;
9186
+ }
9187
+ h1 {
9188
+ font-size: 24px;
9189
+ line-height: 1.2;
9190
+ margin: 0 0 8px;
9191
+ }
9192
+ .description {
9193
+ color: #4b5563;
9194
+ margin: 0 0 20px;
9195
+ }
9196
+ pre {
9197
+ background: #f8fafc;
9198
+ border: 1px solid #e5e7eb;
9199
+ border-radius: 6px;
9200
+ color: #111827;
9201
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
9202
+ font-size: 11px;
9203
+ line-height: 1.45;
9204
+ margin: 0;
9205
+ overflow-wrap: anywhere;
9206
+ padding: 16px;
9207
+ white-space: pre-wrap;
9208
+ }
9209
+ </style>
9210
+ </head>
9211
+ <body>
9212
+ <h1>${escapeHtml(page.title)}</h1>
9213
+ ${description}
9214
+ <pre>${escapeHtml(body)}</pre>
9215
+ ${PRINT_AUTOTRIGGER_SCRIPT}
9216
+ </body>
9217
+ </html>`;
9218
+ }
9079
9219
  function stripJsonSuffix(idSegment) {
9080
9220
  return idSegment.endsWith(".json") ? idSegment.slice(0, -".json".length) : null;
9081
9221
  }
@@ -9257,7 +9397,22 @@ async function handlePagesPublic(req, res, pathSegments, queryParams) {
9257
9397
  bumpViewCount(page.id);
9258
9398
  return true;
9259
9399
  }
9400
+ const wantsPrint = queryParams.get("print") === "1";
9260
9401
  if (page.contentType === "application/json") {
9402
+ if (wantsPrint) {
9403
+ const headers4 = {
9404
+ "Content-Type": "text/html; charset=utf-8",
9405
+ "Cache-Control": "no-store",
9406
+ "Content-Security-Policy": buildCsp(),
9407
+ "X-Content-Type-Options": "nosniff"
9408
+ };
9409
+ if (inlineSetCookie)
9410
+ headers4["Set-Cookie"] = inlineSetCookie;
9411
+ res.writeHead(200, headers4);
9412
+ res.end(printableJsonPageHtml(page));
9413
+ bumpViewCount(page.id);
9414
+ return true;
9415
+ }
9261
9416
  const headers3 = { Location: `${getAppBaseUrl2()}/pages/${page.id}` };
9262
9417
  if (inlineSetCookie)
9263
9418
  headers3["Set-Cookie"] = inlineSetCookie;
@@ -9265,7 +9420,7 @@ async function handlePagesPublic(req, res, pathSegments, queryParams) {
9265
9420
  res.end();
9266
9421
  return true;
9267
9422
  }
9268
- const html = injectBrowserSdk(page.body);
9423
+ const html = injectBrowserSdk(page.body) + (wantsPrint ? PRINT_AUTOTRIGGER_SCRIPT : "");
9269
9424
  const headers2 = {
9270
9425
  "Content-Type": "text/html; charset=utf-8",
9271
9426
  "Cache-Control": "no-store",
@@ -11519,6 +11674,102 @@ var listVersionsRoute = route({
11519
11674
  404: { description: "Script not found" }
11520
11675
  }
11521
11676
  });
11677
+ var apiEndpointParamsSchema = exports_external.object({
11678
+ id: exports_external.string().uuid(),
11679
+ endpointId: exports_external.string()
11680
+ });
11681
+ var createScriptApiBodySchema = exports_external.object({
11682
+ authMode: ScriptApiAuthModeSchema.default("bearer"),
11683
+ label: exports_external.string().max(200).optional(),
11684
+ agentId: exports_external.string().optional()
11685
+ });
11686
+ var patchScriptApiBodySchema = exports_external.object({
11687
+ enabled: exports_external.boolean().optional(),
11688
+ label: exports_external.string().max(200).nullable().optional()
11689
+ });
11690
+ var createScriptApiRoute = route({
11691
+ method: "post",
11692
+ path: "/api/scripts/{id}/apis",
11693
+ pattern: ["api", "scripts", null, "apis"],
11694
+ operationId: "scripts_api_create",
11695
+ summary: "Expose a script as an external HTTP API endpoint",
11696
+ description: "Returns the endpoint plus the plaintext bearer token (when authMode is 'bearer').",
11697
+ tags: ["Scripts"],
11698
+ params: idParamsSchema2,
11699
+ body: createScriptApiBodySchema,
11700
+ responses: {
11701
+ 201: { description: "Endpoint created" },
11702
+ 400: { description: "Validation error or script has no owning agent" },
11703
+ 404: { description: "Script not found" }
11704
+ }
11705
+ });
11706
+ var listScriptApisRoute = route({
11707
+ method: "get",
11708
+ path: "/api/scripts/{id}/apis",
11709
+ pattern: ["api", "scripts", null, "apis"],
11710
+ operationId: "scripts_api_list",
11711
+ summary: "List external API endpoints for a script",
11712
+ tags: ["Scripts"],
11713
+ params: idParamsSchema2,
11714
+ responses: {
11715
+ 200: { description: "Endpoints (without secrets)" },
11716
+ 404: { description: "Script not found" }
11717
+ }
11718
+ });
11719
+ var revealScriptApiSecretRoute = route({
11720
+ method: "get",
11721
+ path: "/api/scripts/{id}/apis/{endpointId}/secret",
11722
+ pattern: ["api", "scripts", null, "apis", null, "secret"],
11723
+ operationId: "scripts_api_reveal_secret",
11724
+ summary: "Reveal an endpoint's bearer token",
11725
+ tags: ["Scripts"],
11726
+ params: apiEndpointParamsSchema,
11727
+ responses: {
11728
+ 200: { description: "Decrypted token (null when authMode is 'none')" },
11729
+ 404: { description: "Endpoint not found" }
11730
+ }
11731
+ });
11732
+ var patchScriptApiRoute = route({
11733
+ method: "patch",
11734
+ path: "/api/scripts/{id}/apis/{endpointId}",
11735
+ pattern: ["api", "scripts", null, "apis", null],
11736
+ operationId: "scripts_api_update",
11737
+ summary: "Enable/disable or relabel an external API endpoint",
11738
+ tags: ["Scripts"],
11739
+ params: apiEndpointParamsSchema,
11740
+ body: patchScriptApiBodySchema,
11741
+ responses: {
11742
+ 200: { description: "Updated endpoint" },
11743
+ 404: { description: "Endpoint not found" }
11744
+ }
11745
+ });
11746
+ var rotateScriptApiRoute = route({
11747
+ method: "post",
11748
+ path: "/api/scripts/{id}/apis/{endpointId}/rotate",
11749
+ pattern: ["api", "scripts", null, "apis", null, "rotate"],
11750
+ operationId: "scripts_api_rotate",
11751
+ summary: "Rotate an endpoint's bearer token",
11752
+ tags: ["Scripts"],
11753
+ params: apiEndpointParamsSchema,
11754
+ responses: {
11755
+ 200: { description: "Endpoint with new plaintext token" },
11756
+ 400: { description: "Endpoint uses 'none' auth — nothing to rotate" },
11757
+ 404: { description: "Endpoint not found" }
11758
+ }
11759
+ });
11760
+ var deleteScriptApiRoute = route({
11761
+ method: "delete",
11762
+ path: "/api/scripts/{id}/apis/{endpointId}",
11763
+ pattern: ["api", "scripts", null, "apis", null],
11764
+ operationId: "scripts_api_delete",
11765
+ summary: "Delete an external API endpoint",
11766
+ tags: ["Scripts"],
11767
+ params: apiEndpointParamsSchema,
11768
+ responses: {
11769
+ 200: { description: "Deleted" },
11770
+ 404: { description: "Endpoint not found" }
11771
+ }
11772
+ });
11522
11773
  function requireAgent2(res, agentId) {
11523
11774
  if (!agentId) {
11524
11775
  jsonError(res, "X-Agent-ID required for scripts API", 400);
@@ -11834,6 +12085,99 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
11834
12085
  json(res, { deleted });
11835
12086
  return true;
11836
12087
  }
12088
+ if (createScriptApiRoute.match(req.method, pathSegments)) {
12089
+ const parsed = await createScriptApiRoute.parse(req, res, pathSegments, queryParams);
12090
+ if (!parsed)
12091
+ return true;
12092
+ const script = getScriptById(parsed.params.id);
12093
+ if (!script) {
12094
+ jsonError(res, "Script not found", 404);
12095
+ return true;
12096
+ }
12097
+ const runAsAgentId = parsed.body.agentId ?? script.scopeId ?? script.createdByAgentId;
12098
+ if (!runAsAgentId) {
12099
+ jsonError(res, "agentId is required: this script has no owning agent to run as", 400);
12100
+ return true;
12101
+ }
12102
+ const endpoint = createScriptApi({
12103
+ scriptId: script.id,
12104
+ agentId: runAsAgentId,
12105
+ authMode: parsed.body.authMode,
12106
+ label: parsed.body.label ?? null,
12107
+ createdBy: resolveHttpAuditUserId(req, agentId)
12108
+ });
12109
+ json(res, endpoint, 201);
12110
+ return true;
12111
+ }
12112
+ if (listScriptApisRoute.match(req.method, pathSegments)) {
12113
+ const parsed = await listScriptApisRoute.parse(req, res, pathSegments, queryParams);
12114
+ if (!parsed)
12115
+ return true;
12116
+ if (!getScriptById(parsed.params.id)) {
12117
+ jsonError(res, "Script not found", 404);
12118
+ return true;
12119
+ }
12120
+ json(res, { apis: listScriptApisForScript(parsed.params.id) });
12121
+ return true;
12122
+ }
12123
+ if (revealScriptApiSecretRoute.match(req.method, pathSegments)) {
12124
+ const parsed = await revealScriptApiSecretRoute.parse(req, res, pathSegments, queryParams);
12125
+ if (!parsed)
12126
+ return true;
12127
+ const endpoint = getScriptApiById(parsed.params.endpointId);
12128
+ if (!endpoint || endpoint.scriptId !== parsed.params.id) {
12129
+ jsonError(res, "Endpoint not found", 404);
12130
+ return true;
12131
+ }
12132
+ json(res, { token: getScriptApiSecret(endpoint.id) });
12133
+ return true;
12134
+ }
12135
+ if (rotateScriptApiRoute.match(req.method, pathSegments)) {
12136
+ const parsed = await rotateScriptApiRoute.parse(req, res, pathSegments, queryParams);
12137
+ if (!parsed)
12138
+ return true;
12139
+ const endpoint = getScriptApiById(parsed.params.endpointId);
12140
+ if (!endpoint || endpoint.scriptId !== parsed.params.id) {
12141
+ jsonError(res, "Endpoint not found", 404);
12142
+ return true;
12143
+ }
12144
+ const rotated = rotateScriptApiSecret(endpoint.id, resolveHttpAuditUserId(req, agentId));
12145
+ if (!rotated) {
12146
+ jsonError(res, "Cannot rotate a token on a 'none' auth endpoint", 400);
12147
+ return true;
12148
+ }
12149
+ json(res, rotated);
12150
+ return true;
12151
+ }
12152
+ if (patchScriptApiRoute.match(req.method, pathSegments)) {
12153
+ const parsed = await patchScriptApiRoute.parse(req, res, pathSegments, queryParams);
12154
+ if (!parsed)
12155
+ return true;
12156
+ const endpoint = getScriptApiById(parsed.params.endpointId);
12157
+ if (!endpoint || endpoint.scriptId !== parsed.params.id) {
12158
+ jsonError(res, "Endpoint not found", 404);
12159
+ return true;
12160
+ }
12161
+ const updated = updateScriptApi(endpoint.id, {
12162
+ enabled: parsed.body.enabled,
12163
+ label: parsed.body.label,
12164
+ updatedBy: resolveHttpAuditUserId(req, agentId)
12165
+ });
12166
+ json(res, updated);
12167
+ return true;
12168
+ }
12169
+ if (deleteScriptApiRoute.match(req.method, pathSegments)) {
12170
+ const parsed = await deleteScriptApiRoute.parse(req, res, pathSegments, queryParams);
12171
+ if (!parsed)
12172
+ return true;
12173
+ const endpoint = getScriptApiById(parsed.params.endpointId);
12174
+ if (!endpoint || endpoint.scriptId !== parsed.params.id) {
12175
+ jsonError(res, "Endpoint not found", 404);
12176
+ return true;
12177
+ }
12178
+ json(res, { deleted: deleteScriptApi(endpoint.id) });
12179
+ return true;
12180
+ }
11837
12181
  return false;
11838
12182
  }
11839
12183
 
@@ -12025,6 +12369,21 @@ async function handleSessionData(req, res, pathSegments, queryParams, _myAgentId
12025
12369
  isError: parsed.body.isError ?? false,
12026
12370
  costSource
12027
12371
  });
12372
+ recordSessionCost({
12373
+ totalCostUsd,
12374
+ harness: parsed.body.provider ?? "unknown",
12375
+ model,
12376
+ costSource,
12377
+ isError: parsed.body.isError ?? false,
12378
+ tokens: {
12379
+ input: inputTokens,
12380
+ output: outputTokens,
12381
+ cacheRead: cachedInputTokens,
12382
+ cacheWrite: parsed.body.cacheWriteTokens ?? 0,
12383
+ reasoning: parsed.body.reasoningOutputTokens ?? 0,
12384
+ thinking: parsed.body.thinkingTokens ?? 0
12385
+ }
12386
+ });
12028
12387
  incrementServerSessionsProcessed();
12029
12388
  json(res, { success: true, cost }, 201);
12030
12389
  } catch (error) {
@@ -16918,6 +17277,167 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
16918
17277
  return false;
16919
17278
  }
16920
17279
 
17280
+ // src/http/x.ts
17281
+ init_zod();
17282
+ init_db();
17283
+ import { timingSafeEqual as timingSafeEqual3 } from "node:crypto";
17284
+ init_secret_scrubber();
17285
+ var DEFAULT_TIMEOUT_MS = 60000;
17286
+ var MIN_TIMEOUT_MS = 1000;
17287
+ var MAX_TIMEOUT_MS = 300000;
17288
+ var TIMEOUT_HEADER = "x-swarm-timeout-ms";
17289
+ var MAX_BODY_BYTES = 1 * 1024 * 1024;
17290
+ var scriptApiRoute = route({
17291
+ method: "post",
17292
+ path: "/api/x/script/{endpointId}",
17293
+ pattern: ["api", "x", "script", null],
17294
+ operationId: "x_script_run",
17295
+ summary: "Invoke an externally-exposed swarm script",
17296
+ description: "Runs the script bound to this endpoint and returns a JSON envelope " + "`{ ok, result, error, durationMs }` (HTTP 200) once execution is reached. " + "Auth/routing failures use 401 (bad/missing bearer) and 404 (unknown or " + "disabled endpoint). Optional `X-Swarm-Timeout-Ms` header (default 60000, " + "clamped 1000–300000) sets the wall-clock timeout.",
17297
+ tags: ["External APIs"],
17298
+ params: exports_external.object({ endpointId: exports_external.string() }),
17299
+ auth: { apiKey: false },
17300
+ responses: {
17301
+ 200: { description: "Script executed — see `ok` in the envelope" },
17302
+ 401: { description: "Missing or invalid bearer token" },
17303
+ 404: { description: "Endpoint not found or disabled" },
17304
+ 501: { description: "workspace-rw scripts are not supported" }
17305
+ }
17306
+ });
17307
+ function extractBearer3(req) {
17308
+ const raw = req.headers.authorization;
17309
+ const header = Array.isArray(raw) ? raw[0] : raw;
17310
+ if (!header)
17311
+ return null;
17312
+ const match = /^Bearer\s+(.+)$/i.exec(header.trim());
17313
+ return match?.[1] ?? null;
17314
+ }
17315
+ function timingSafeEqualStr(a, b) {
17316
+ const ab = Buffer.from(a);
17317
+ const bb = Buffer.from(b);
17318
+ if (ab.length !== bb.length)
17319
+ return false;
17320
+ return timingSafeEqual3(ab, bb);
17321
+ }
17322
+ function resolveTimeoutMs(req) {
17323
+ const raw = req.headers[TIMEOUT_HEADER];
17324
+ const val = Array.isArray(raw) ? raw[0] : raw;
17325
+ if (!val)
17326
+ return DEFAULT_TIMEOUT_MS;
17327
+ const n = Number(val);
17328
+ if (!Number.isFinite(n))
17329
+ return DEFAULT_TIMEOUT_MS;
17330
+ return Math.min(MAX_TIMEOUT_MS, Math.max(MIN_TIMEOUT_MS, Math.floor(n)));
17331
+ }
17332
+ function buildExecutionError(output) {
17333
+ if (output.runtimeError) {
17334
+ return {
17335
+ type: "runtime_error",
17336
+ message: `${output.runtimeError.name}: ${output.runtimeError.message}`
17337
+ };
17338
+ }
17339
+ switch (output.error) {
17340
+ case "timeout":
17341
+ return { type: "timeout", message: "Script timed out" };
17342
+ case "import_violation":
17343
+ return { type: "import_violation", message: output.stderr || "Disallowed import" };
17344
+ default:
17345
+ return {
17346
+ type: "runtime_error",
17347
+ message: output.error ? `Script failed: ${output.error}` : `Script exited with code ${output.exitCode}`
17348
+ };
17349
+ }
17350
+ }
17351
+ async function handleX(req, res, pathSegments) {
17352
+ if (!scriptApiRoute.match(req.method, pathSegments))
17353
+ return false;
17354
+ const endpointId = pathSegments[3] ?? "";
17355
+ const endpoint = getScriptApiById(endpointId);
17356
+ if (!endpoint || !endpoint.enabled) {
17357
+ json(res, { error: { type: "not_found", message: "Endpoint not found" } }, 404);
17358
+ return true;
17359
+ }
17360
+ if (endpoint.authMode === "bearer") {
17361
+ const provided = extractBearer3(req);
17362
+ const expected = getScriptApiSecret(endpointId);
17363
+ if (!provided || !expected || !timingSafeEqualStr(provided, expected)) {
17364
+ json(res, { error: { type: "unauthorized", message: "Invalid or missing bearer token" } }, 401);
17365
+ return true;
17366
+ }
17367
+ }
17368
+ if (enforceContentLengthCap(req, res, MAX_BODY_BYTES) === BODY_TOO_LARGE)
17369
+ return true;
17370
+ let args;
17371
+ try {
17372
+ args = await parseBody(req);
17373
+ } catch {
17374
+ json(res, {
17375
+ ok: false,
17376
+ result: null,
17377
+ error: { type: "invalid_json", message: "Request body must be valid JSON" },
17378
+ durationMs: 0
17379
+ });
17380
+ return true;
17381
+ }
17382
+ const script = getScriptById(endpoint.scriptId);
17383
+ if (!script) {
17384
+ json(res, { error: { type: "not_found", message: "Script not found" } }, 404);
17385
+ return true;
17386
+ }
17387
+ if (script.fsMode === "workspace-rw") {
17388
+ jsonError(res, "workspace-rw scripts are not supported", 501);
17389
+ return true;
17390
+ }
17391
+ if (script.argsJsonSchema) {
17392
+ try {
17393
+ const schema = JSON.parse(script.argsJsonSchema);
17394
+ const errors = validateJsonSchema(schema, args ?? null);
17395
+ if (errors.length > 0) {
17396
+ json(res, {
17397
+ ok: false,
17398
+ result: null,
17399
+ error: { type: "args_validation", message: errors.join("; "), details: errors },
17400
+ durationMs: 0
17401
+ });
17402
+ return true;
17403
+ }
17404
+ } catch {}
17405
+ }
17406
+ const timeoutMs = resolveTimeoutMs(req);
17407
+ const startedAt = new Date().toISOString();
17408
+ const output = await runScript({
17409
+ source: script.source,
17410
+ args: args ?? null,
17411
+ fsMode: "none",
17412
+ agentId: endpoint.agentId,
17413
+ timeoutMs,
17414
+ egressSecrets: buildScriptCredentialBindings({ agentId: endpoint.agentId }),
17415
+ apiConnections: getScriptApiConnectionDescriptors({ agentId: endpoint.agentId })
17416
+ });
17417
+ const ok = output.exitCode === 0 && !output.error && !output.runtimeError;
17418
+ const error = ok ? null : buildExecutionError(output);
17419
+ try {
17420
+ recordScriptApiUsage(endpointId);
17421
+ } catch {}
17422
+ try {
17423
+ recordInlineScriptRun({
17424
+ id: crypto.randomUUID(),
17425
+ agentId: endpoint.agentId,
17426
+ source: script.source,
17427
+ args: scrubObject(args ?? null),
17428
+ scriptName: script.name,
17429
+ status: ok ? "completed" : "failed",
17430
+ output: scrubObject(output.result),
17431
+ error: ok ? undefined : scrubSecrets(error?.message ?? "Script failed"),
17432
+ startedAt,
17433
+ finishedAt: new Date().toISOString(),
17434
+ apiEndpointId: endpointId
17435
+ });
17436
+ } catch {}
17437
+ json(res, scrubObject({ ok, result: ok ? output.result : null, error, durationMs: output.durationMs }));
17438
+ return true;
17439
+ }
17440
+
16921
17441
  // src/http/index.ts
16922
17442
  process.on("uncaughtException", (err) => {
16923
17443
  console.error("[fatal] uncaughtException:", err);
@@ -16958,7 +17478,10 @@ function startApiGcInterval() {
16958
17478
  const interval = setInterval(() => {
16959
17479
  const closedOwnerTransports = closeIdleMcpTransports(transports, transportActivity, {
16960
17480
  idleTimeoutMs: MCP_TRANSPORT_IDLE_TIMEOUT_MS,
16961
- label: "MCP"
17481
+ label: "MCP",
17482
+ onClose: (id) => {
17483
+ delete mcpSessionAgents[id];
17484
+ }
16962
17485
  });
16963
17486
  const closedUserTransports = closeIdleMcpUserTransports(transportsUser, sessionUsers, transportActivityUser, { idleTimeoutMs: MCP_TRANSPORT_IDLE_TIMEOUT_MS });
16964
17487
  if (closedOwnerTransports > 0 || closedUserTransports > 0) {
@@ -16974,6 +17497,7 @@ if (globalState.__httpServer) {
16974
17497
  globalState.__httpServer.close();
16975
17498
  }
16976
17499
  var transports = globalState.__transports ?? {};
17500
+ var mcpSessionAgents = globalState.__mcpSessionAgents ?? {};
16977
17501
  var transportsUser = globalState.__transportsUser ?? {};
16978
17502
  var sessionUsers = globalState.__sessionUsers ?? {};
16979
17503
  var transportActivity = globalState.__transportActivity ?? {};
@@ -17071,6 +17595,7 @@ var httpServer = createHttpServer(async (req, res) => {
17071
17595
  () => handleSkills(req, res, pathSegments, queryParams, myAgentId),
17072
17596
  () => handleScriptRuns(req, res, pathSegments, queryParams, myAgentId),
17073
17597
  () => handleScripts(req, res, pathSegments, queryParams, myAgentId),
17598
+ () => handleX(req, res, pathSegments),
17074
17599
  () => handleMcpBridge(req, res, pathSegments, queryParams, myAgentId),
17075
17600
  () => handleMcpServers(req, res, pathSegments, queryParams),
17076
17601
  () => handleMcpOAuth(req, res, pathSegments, queryParams),
@@ -17085,7 +17610,7 @@ var httpServer = createHttpServer(async (req, res) => {
17085
17610
  () => handleSessions(req, res, pathSegments, queryParams),
17086
17611
  () => handleInboxState(req, res, pathSegments, queryParams),
17087
17612
  () => handleTaskTemplates(req, res, pathSegments, queryParams),
17088
- () => handleMcp(req, res, transports, transportActivity),
17613
+ () => handleMcp(req, res, transports, transportActivity, mcpSessionAgents),
17089
17614
  () => handleMcpUser(req, res, transportsUser, sessionUsers, transportActivityUser)
17090
17615
  ];
17091
17616
  try {
@@ -17120,6 +17645,7 @@ var httpServer = createHttpServer(async (req, res) => {
17120
17645
  globalState.__httpServer = httpServer;
17121
17646
  globalState.__transports = transports;
17122
17647
  globalState.__transportsUser = transportsUser;
17648
+ globalState.__mcpSessionAgents = mcpSessionAgents;
17123
17649
  globalState.__sessionUsers = sessionUsers;
17124
17650
  globalState.__transportActivity = transportActivity;
17125
17651
  globalState.__transportActivityUser = transportActivityUser;
@@ -17131,14 +17657,14 @@ async function shutdown() {
17131
17657
  sessionsProcessed: getServerSessionsProcessed()
17132
17658
  });
17133
17659
  if (hasCapability("scheduling")) {
17134
- const { stopScheduler } = await import("./index-xf6fp4y1.js");
17660
+ const { stopScheduler } = await import("./index-45bqm6xc.js");
17135
17661
  stopScheduler();
17136
17662
  }
17137
17663
  stopHeartbeat();
17138
17664
  stopScriptRunSupervisor();
17139
17665
  await stopSlackApp();
17140
17666
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
17141
- const { stopOAuthKeepalive } = await import("./keepalive-mj4302vw.js");
17667
+ const { stopOAuthKeepalive } = await import("./keepalive-8gbgeg21.js");
17142
17668
  await stopOAuthKeepalive();
17143
17669
  }
17144
17670
  stopMcpOAuthPendingGc();
@@ -17151,6 +17677,7 @@ async function shutdown() {
17151
17677
  console.log(`[HTTP] Closing transport ${id}`);
17152
17678
  transport.close();
17153
17679
  delete transports[id];
17680
+ delete mcpSessionAgents[id];
17154
17681
  delete transportActivity[id];
17155
17682
  }
17156
17683
  for (const [id, transport] of Object.entries(transportsUser)) {
@@ -17190,15 +17717,15 @@ try {
17190
17717
  throw err;
17191
17718
  }
17192
17719
  try {
17193
- const { seedPricingFromModelsDev } = await import("./seed-pricing-w3x550cj.js");
17720
+ const { seedPricingFromModelsDev } = await import("./seed-pricing-3tqmbe0p.js");
17194
17721
  seedPricingFromModelsDev();
17195
- const { startPricingRefreshLoop } = await import("./pricing-refresh-nqyf8bkb.js");
17722
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-f6cgj5br.js");
17196
17723
  startPricingRefreshLoop();
17197
17724
  } catch (err) {
17198
17725
  console.error("[startup] Failed to seed pricing rows:", err);
17199
17726
  }
17200
17727
  try {
17201
- const { runAllSeeders } = await import("./index-jca7jdpt.js");
17728
+ const { runAllSeeders } = await import("./index-jscerv2x.js");
17202
17729
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
17203
17730
  } catch (err) {
17204
17731
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -17231,31 +17758,31 @@ httpServer.listen(port, async () => {
17231
17758
  initWorkflows();
17232
17759
  startScriptRunSupervisor(getMcpBaseUrl());
17233
17760
  if (hasCapability("scheduling")) {
17234
- const { startScheduler } = await import("./index-xf6fp4y1.js");
17235
- const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-881c1baf.js");
17761
+ const { startScheduler } = await import("./index-45bqm6xc.js");
17762
+ const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-v3r40ak0.js");
17236
17763
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
17237
17764
  startScheduler(getExecutorRegistry2(), intervalMs, {
17238
17765
  runId: globalState.__runId
17239
17766
  });
17240
17767
  }
17241
17768
  if (process.env.HEARTBEAT_DISABLE !== "true") {
17242
- const { startHeartbeat } = await import("./index-xz8vaa5c.js");
17769
+ const { startHeartbeat } = await import("./index-f5e873a5.js");
17243
17770
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
17244
17771
  startHeartbeat(heartbeatMs);
17245
17772
  }
17246
17773
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
17247
- const { startOAuthKeepalive } = await import("./keepalive-mj4302vw.js");
17774
+ const { startOAuthKeepalive } = await import("./keepalive-8gbgeg21.js");
17248
17775
  startOAuthKeepalive();
17249
17776
  }
17250
17777
  startMcpOAuthPendingGc();
17251
17778
  startMemoryGc();
17252
- import("./boot-reembed-9kt97g1z.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
17779
+ import("./boot-reembed-atv4kcrh.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
17253
17780
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
17254
17781
  });
17255
- import("./boot-reembed-3q1aywnz.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
17782
+ import("./boot-reembed-zanbm36c.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
17256
17783
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
17257
17784
  });
17258
- import("./boot-scrub-logs-vskq108e.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
17785
+ import("./boot-scrub-logs-asq051ff.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
17259
17786
  console.error("[boot-scrub-logs] startup scrub failed (non-fatal):", err);
17260
17787
  });
17261
17788
  }).on("error", (err) => {