@desplega.ai/agent-swarm 1.114.0 → 1.115.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 (117) hide show
  1. package/dist/{actions-bm8vdxys.js → actions-17ya5wde.js} +6 -6
  2. package/dist/{app-bhwdxmvp.js → app-4f718yk0.js} +4 -4
  3. package/dist/{assistant-15mp2apr.js → assistant-ah7csnjz.js} +9 -9
  4. package/dist/{boot-reembed-awr2179r.js → boot-reembed-4jpxhb25.js} +4 -4
  5. package/dist/{boot-reembed-b9sbk87z.js → boot-reembed-qata34xa.js} +3 -3
  6. package/dist/{boot-scrub-logs-c1zsaw9m.js → boot-scrub-logs-tv48nn3z.js} +2 -2
  7. package/dist/{claude-adapter-2k45y7p7.js → claude-adapter-3csn5bks.js} +2 -2
  8. package/dist/{cli-zmmp2r79.js → cli-12vb0xg6.js} +13 -2
  9. package/dist/{cli-jzwtn8rm.js → cli-15y7qhzp.js} +188 -18
  10. package/dist/{cli-w3nq88yc.js → cli-3samkyap.js} +2 -2
  11. package/dist/{cli-7rgh0w0k.js → cli-52fg7s7x.js} +10 -3
  12. package/dist/{cli-5afkmcfj.js → cli-65ekje01.js} +6 -6
  13. package/dist/{cli-113wmegp.js → cli-6aq8xhvm.js} +1 -1
  14. package/dist/{cli-byjcad11.js → cli-7xje5amz.js} +1 -1
  15. package/dist/{cli-0kgcv878.js → cli-86fdnerz.js} +63 -2
  16. package/dist/{cli-f5pzfvwb.js → cli-b23axgz4.js} +1 -1
  17. package/dist/{cli-a0t7vapf.js → cli-bc89my0z.js} +1 -1
  18. package/dist/{cli-q4e2x252.js → cli-beea4a3y.js} +73 -24
  19. package/dist/{cli-w4wk3kx6.js → cli-cchksf5q.js} +2 -2
  20. package/dist/{cli-f9n2jg31.js → cli-cmw9rzy5.js} +2 -2
  21. package/dist/{cli-hvg05qwm.js → cli-cnwssmsr.js} +1 -1
  22. package/dist/{cli-2t4e4ayk.js → cli-dcca6j8m.js} +46 -5
  23. package/dist/{cli-tkmm5nf9.js → cli-e61fs2hp.js} +59 -2
  24. package/dist/{cli-e2xbxmhd.js → cli-hrhye2rm.js} +90 -32
  25. package/dist/{cli-312v3c41.js → cli-k3y4z3h5.js} +1 -1
  26. package/dist/{cli-6xd0bvf8.js → cli-ma04faw5.js} +1 -1
  27. package/dist/{cli-ggy8c7tk.js → cli-mnbgv3w7.js} +1 -1
  28. package/dist/{cli-hq39e630.js → cli-pet3aev6.js} +95 -10
  29. package/dist/{cli-a6tzw6vq.js → cli-q1rx7g0d.js} +6 -6
  30. package/dist/{cli-pnfyyp6h.js → cli-r9f6ngrf.js} +6 -3
  31. package/dist/{cli-q1z5d5ss.js → cli-shvaxw27.js} +4 -4
  32. package/dist/{cli-49j095n9.js → cli-t0vqevnm.js} +1 -1
  33. package/dist/{cli-k6h2zkw3.js → cli-tece6zgm.js} +1 -1
  34. package/dist/{cli-5ktc9fd4.js → cli-tffvrh6j.js} +1 -1
  35. package/dist/cli-wh91zby6.js +187222 -0
  36. package/dist/{cli-r3mtrrzp.js → cli-zsrdty74.js} +12 -12
  37. package/dist/cli.js +10 -10
  38. package/dist/{codex-adapter-4z8m9mb5.js → codex-adapter-de3w0nch.js} +2 -2
  39. package/dist/{codex-session-runner-rbct46dg.js → codex-session-runner-bnw8cysk.js} +2 -2
  40. package/dist/{commands-zk4d6esf.js → commands-hch4e2k1.js} +2 -2
  41. package/dist/{db-stn16jp2.js → db-p3h2j06x.js} +12 -2
  42. package/dist/{handlers-gshprvpf.js → handlers-9er4zx9q.js} +9 -9
  43. package/dist/{hook-amzx9tap.js → hook-4axs756z.js} +1 -1
  44. package/dist/{http-6g0hfzax.js → http-809fvtz2.js} +182 -65
  45. package/dist/{index-ty42rxw9.js → index-47em3d2n.js} +10 -10
  46. package/dist/{index-jbm7qcqk.js → index-9fqaktjr.js} +8 -8
  47. package/dist/{index-f03rnnrs.js → index-9ht8gr56.js} +9 -9
  48. package/dist/{index-df8fmphk.js → index-rm85cfdx.js} +331 -30
  49. package/dist/{keepalive-pm6g2wpw.js → keepalive-3cps6e3e.js} +4 -4
  50. package/dist/{lead-h79fzpzw.js → lead-fkk95wgq.js} +24 -24
  51. package/dist/{maintenance-433zndy1.js → maintenance-fweqh0yj.js} +4 -4
  52. package/dist/{oauth-refresh-sweep-mjsbmsk2.js → oauth-refresh-sweep-sycqtbph.js} +3 -3
  53. package/dist/{onboard-vdr9hc3f.js → onboard-cy0rkgvx.js} +2 -2
  54. package/dist/{opencode-adapter-mqsxr170.js → opencode-adapter-p6bxnbm4.js} +2 -2
  55. package/dist/{otel-impl-yswd0fty.js → otel-impl-wbns8hf7.js} +1 -1
  56. package/dist/{pi-mono-adapter-vbrvg1p8.js → pi-mono-adapter-05sck1ds.js} +1 -1
  57. package/dist/{pricing-refresh-2kk2ap9b.js → pricing-refresh-0hvazmkf.js} +4 -4
  58. package/dist/{rbac-roles-xdc5208b.js → rbac-roles-kfesjy9y.js} +4 -4
  59. package/dist/{rbac-roles-2wgh9b5t.js → rbac-roles-mwcwhbxc.js} +11 -4
  60. package/dist/{seed-pricing-m9h69d2t.js → seed-pricing-h2kdq4cq.js} +3 -3
  61. package/dist/{setup-eynkvafa.js → setup-8506q97w.js} +2 -2
  62. package/dist/{worker-136q8dc2.js → worker-4r5c6zyb.js} +24 -24
  63. package/openapi.json +8 -4
  64. package/package.json +1 -1
  65. package/src/be/db.ts +253 -20
  66. package/src/be/migrations/113_task_routing_affinity.sql +9 -0
  67. package/src/be/migrations/114_backfill_gpt_5_6_pricing.sql +15 -0
  68. package/src/be/modelsdev-cache.json +135 -0
  69. package/src/be/rbac-audit.ts +19 -8
  70. package/src/be/rbac-roles.ts +8 -1
  71. package/src/be/script-connections.ts +4 -4
  72. package/src/be/scripts/typecheck.ts +11 -0
  73. package/src/be/seed-scripts/catalog/catalog-report.inline.ts +325 -24
  74. package/src/be/seed-scripts/catalog/catalog-report.ts +325 -24
  75. package/src/heartbeat/heartbeat.ts +143 -21
  76. package/src/http/favorites.ts +1 -5
  77. package/src/http/mcp-servers.ts +38 -0
  78. package/src/http/poll.ts +7 -2
  79. package/src/http/scripts.ts +6 -0
  80. package/src/http/skills.ts +11 -0
  81. package/src/http/tasks.ts +21 -9
  82. package/src/providers/codex-models.ts +100 -30
  83. package/src/providers/modelsdev-reasoning.json +51 -0
  84. package/src/providers/reasoning-effort.ts +11 -5
  85. package/src/rbac/admission.ts +26 -2
  86. package/src/rbac/index.ts +2 -2
  87. package/src/rbac/legacy-policy.ts +9 -0
  88. package/src/rbac/permissions.ts +36 -0
  89. package/src/scripts-runtime/api-client.ts +82 -6
  90. package/src/scripts-runtime/types/swarm-sdk.d.ts +11 -0
  91. package/src/server-user.ts +114 -59
  92. package/src/slack/responses.ts +91 -1
  93. package/src/slack/watcher.ts +9 -6
  94. package/src/tasks/worker-follow-up.ts +100 -3
  95. package/src/tests/codex-adapter.test.ts +46 -23
  96. package/src/tests/heartbeat.test.ts +48 -3
  97. package/src/tests/model-control.test.ts +8 -2
  98. package/src/tests/pool-affinity.test.ts +401 -0
  99. package/src/tests/rbac-admission-e2e.test.ts +152 -7
  100. package/src/tests/rbac-admission.test.ts +60 -1
  101. package/src/tests/rbac-engine.test.ts +9 -0
  102. package/src/tests/rbac-mcp-admission-e2e.test.ts +362 -0
  103. package/src/tests/rbac-roles.test.ts +2 -0
  104. package/src/tests/reasoning-effort.test.ts +15 -2
  105. package/src/tests/script-apis-mcp.test.ts +37 -13
  106. package/src/tests/script-connections.test.ts +27 -1
  107. package/src/tests/scripts-runtime.test.ts +187 -0
  108. package/src/tests/seed-scripts.test.ts +36 -0
  109. package/src/tests/slack-inline-output.test.ts +65 -0
  110. package/src/tests/user-token-rest-auth.test.ts +110 -0
  111. package/src/tools/script-apis.ts +62 -3
  112. package/src/tools/send-task.ts +15 -1
  113. package/src/tools/task-action.ts +34 -2
  114. package/src/tools/templates.ts +48 -0
  115. package/src/tools/utils.ts +2 -0
  116. package/src/types.ts +27 -5
  117. package/dist/cli-46b6kc7f.js +0 -1698
@@ -25,6 +25,7 @@ import {
25
25
  describeRequestRoute,
26
26
  emitBudgetRefusalSideEffects,
27
27
  enforceContentLengthCap,
28
+ enqueueAdmissionRow,
28
29
  enqueueAuditRow,
29
30
  executeReadOnlyQuery,
30
31
  expandCandidatesWithGraph,
@@ -122,7 +123,7 @@ import {
122
123
  withRemoteContext,
123
124
  withSpanContext,
124
125
  writeSkillsToFilesystem
125
- } from "./cli-e2xbxmhd.js";
126
+ } from "./cli-hrhye2rm.js";
126
127
  import"./cli-1z7048dy.js";
127
128
  import {
128
129
  BROWSER_SDK_JS,
@@ -142,20 +143,21 @@ import {
142
143
  } from "./cli-gz9sbyk3.js";
143
144
  import {
144
145
  reasoningCapability
145
- } from "./cli-tkmm5nf9.js";
146
- import"./cli-w3nq88yc.js";
146
+ } from "./cli-e61fs2hp.js";
147
+ import"./cli-3samkyap.js";
147
148
  import {
148
149
  normalizeModelKey
149
- } from "./cli-k6h2zkw3.js";
150
+ } from "./cli-tece6zgm.js";
150
151
  import {
151
152
  getUserGrant
152
- } from "./cli-7rgh0w0k.js";
153
+ } from "./cli-52fg7s7x.js";
153
154
  import {
154
155
  can,
155
156
  clearAuditSink,
157
+ decideToolAdmission,
156
158
  isRbacEnabled,
157
159
  setAuditSink
158
- } from "./cli-0kgcv878.js";
160
+ } from "./cli-86fdnerz.js";
159
161
  import {
160
162
  ensureAgentFsCredentialsForAgent,
161
163
  extractArgsJsonSchema,
@@ -163,16 +165,16 @@ import {
163
165
  scriptSdkTypesWithGeneratedApis,
164
166
  scriptStdlibTypesWithGeneratedApis,
165
167
  typecheckScript
166
- } from "./cli-zmmp2r79.js";
168
+ } from "./cli-12vb0xg6.js";
167
169
  import {
168
170
  checkHeartbeatChecklist,
169
171
  runHeartbeatSweep,
170
172
  stopHeartbeat
171
- } from "./cli-q4e2x252.js";
173
+ } from "./cli-beea4a3y.js";
172
174
  import {
173
175
  createResumeFollowUp,
174
176
  createWorkerTaskFollowUp
175
- } from "./cli-2t4e4ayk.js";
177
+ } from "./cli-dcca6j8m.js";
176
178
  import"./cli-fad8m16k.js";
177
179
  import {
178
180
  calculateNextRun,
@@ -180,7 +182,7 @@ import {
180
182
  ensure,
181
183
  initialize,
182
184
  require_dist
183
- } from "./cli-q1z5d5ss.js";
185
+ } from "./cli-shvaxw27.js";
184
186
  import {
185
187
  RawLlmConfigSchema,
186
188
  TriggerSchemaError,
@@ -202,7 +204,7 @@ import {
202
204
  validateDefinition,
203
205
  validateJsonSchema,
204
206
  verifyHmacSignature
205
- } from "./cli-a6tzw6vq.js";
207
+ } from "./cli-q1rx7g0d.js";
206
208
  import {
207
209
  getApiKey
208
210
  } from "./cli-f14fvzag.js";
@@ -254,11 +256,11 @@ import {
254
256
  upsertMcpOAuthToken,
255
257
  upsertScriptByName,
256
258
  upsertScriptConnection
257
- } from "./cli-pnfyyp6h.js";
259
+ } from "./cli-r9f6ngrf.js";
258
260
  import"./cli-jkhwmmgg.js";
259
261
  import {
260
262
  searchScripts
261
- } from "./cli-f9n2jg31.js";
263
+ } from "./cli-cmw9rzy5.js";
262
264
  import {
263
265
  CANDIDATE_SET_MULTIPLIER,
264
266
  getEmbeddingProvider,
@@ -266,7 +268,7 @@ import {
266
268
  init_constants,
267
269
  init_reranker,
268
270
  rerank
269
- } from "./cli-byjcad11.js";
271
+ } from "./cli-7xje5amz.js";
270
272
  import"./cli-q25ejbyn.js";
271
273
  import {
272
274
  acquireOAuthRefreshLock,
@@ -279,19 +281,20 @@ import {
279
281
  getOAuthTokens,
280
282
  releaseOAuthRefreshLock,
281
283
  upsertOAuthApp
282
- } from "./cli-49j095n9.js";
284
+ } from "./cli-t0vqevnm.js";
283
285
  import"./cli-0pygq9r1.js";
284
- import"./cli-5ktc9fd4.js";
286
+ import"./cli-tffvrh6j.js";
285
287
  import {
286
288
  getSlackApp,
287
289
  startSlackApp,
288
290
  stopSlackApp
289
- } from "./cli-hq39e630.js";
291
+ } from "./cli-pet3aev6.js";
290
292
  import"./cli-rkndnn90.js";
291
293
  import"./cli-b0p7rfnd.js";
292
294
  import {
293
295
  findOrCreateUserByEmail,
294
296
  findUserByExternalId,
297
+ findUserById,
295
298
  fingerprintApiKey,
296
299
  getUserIdentities,
297
300
  linkIdentity,
@@ -305,15 +308,15 @@ import {
305
308
  resolveUserByToken,
306
309
  revokeToken,
307
310
  unlinkIdentity
308
- } from "./cli-113wmegp.js";
309
- import"./cli-6xd0bvf8.js";
311
+ } from "./cli-6aq8xhvm.js";
312
+ import"./cli-ma04faw5.js";
310
313
  import"./cli-wspgs9bt.js";
311
314
  import {
312
315
  agentContextKey,
313
316
  createTaskWithSiblingAwareness,
314
317
  gitlabContextKey,
315
318
  pageContextKey
316
- } from "./cli-312v3c41.js";
319
+ } from "./cli-k3y4z3h5.js";
317
320
  import {
318
321
  getAppUrl,
319
322
  getConfiguredAppUrls,
@@ -512,7 +515,7 @@ import {
512
515
  getTaskStats,
513
516
  getTasksCount,
514
517
  getTemplateDefinition,
515
- getUnassignedTaskIds,
518
+ getUnassignedTaskIdsForAgent,
516
519
  getUserById,
517
520
  getWorkflow,
518
521
  getWorkflowRun,
@@ -621,7 +624,7 @@ import {
621
624
  upsertSwarmConfig,
622
625
  validateConfigValue,
623
626
  withFavoriteFlags
624
- } from "./cli-jzwtn8rm.js";
627
+ } from "./cli-15y7qhzp.js";
625
628
  import"./cli-z2zcxes1.js";
626
629
  import {
627
630
  init_zod
@@ -636,7 +639,7 @@ import {
636
639
  import {
637
640
  init_package,
638
641
  package_default
639
- } from "./cli-f5pzfvwb.js";
642
+ } from "./cli-b23axgz4.js";
640
643
  import {
641
644
  init_secret_scrubber,
642
645
  registerVolatileSecret,
@@ -3550,7 +3553,7 @@ var putFavorite = route({
3550
3553
  pattern: ["api", "favorites"],
3551
3554
  summary: "Set favorite state for an item",
3552
3555
  tags: ["Favorites"],
3553
- rbac: { ungated: "self-scoped to the authenticated user; no cross-principal access" },
3556
+ rbac: { permission: "favorite.write.own" },
3554
3557
  body: exports_external.object({
3555
3558
  itemType: FavoriteItemTypeSchema,
3556
3559
  itemId: exports_external.string().min(1),
@@ -7214,6 +7217,7 @@ function stopMcpOAuthPendingGc() {
7214
7217
  // src/http/mcp-servers.ts
7215
7218
  init_zod();
7216
7219
  init_db();
7220
+ init_request_auth_context();
7217
7221
  var listMcpServersRoute = route({
7218
7222
  method: "get",
7219
7223
  path: "/api/mcp-servers",
@@ -7268,7 +7272,8 @@ var createMcpServerRoute = route({
7268
7272
  responses: {
7269
7273
  201: { description: "MCP server created" },
7270
7274
  400: { description: "Validation error" }
7271
- }
7275
+ },
7276
+ rbac: { permission: "mcp-server.create.swarm" }
7272
7277
  });
7273
7278
  var updateMcpServerRoute = route({
7274
7279
  method: "put",
@@ -7282,7 +7287,8 @@ var updateMcpServerRoute = route({
7282
7287
  responses: {
7283
7288
  200: { description: "MCP server updated" },
7284
7289
  404: { description: "MCP server not found" }
7285
- }
7290
+ },
7291
+ rbac: { permission: "mcp-server.update.any" }
7286
7292
  });
7287
7293
  var deleteMcpServerRoute = route({
7288
7294
  method: "delete",
@@ -7295,7 +7301,8 @@ var deleteMcpServerRoute = route({
7295
7301
  responses: {
7296
7302
  200: { description: "MCP server deleted" },
7297
7303
  404: { description: "MCP server not found" }
7298
- }
7304
+ },
7305
+ rbac: { permission: "mcp-server.delete.any" }
7299
7306
  });
7300
7307
  var installMcpServerRoute = route({
7301
7308
  method: "post",
@@ -7311,7 +7318,8 @@ var installMcpServerRoute = route({
7311
7318
  responses: {
7312
7319
  200: { description: "MCP server installed" },
7313
7320
  404: { description: "MCP server not found" }
7314
- }
7321
+ },
7322
+ rbac: { permission: "mcp-server.install.any" }
7315
7323
  });
7316
7324
  var uninstallMcpServerRoute = route({
7317
7325
  method: "delete",
@@ -7323,7 +7331,8 @@ var uninstallMcpServerRoute = route({
7323
7331
  params: exports_external.object({ id: exports_external.string(), agentId: exports_external.string() }),
7324
7332
  responses: {
7325
7333
  200: { description: "MCP server uninstalled" }
7326
- }
7334
+ },
7335
+ rbac: { permission: "mcp-server.uninstall.any" }
7327
7336
  });
7328
7337
  var getAgentMcpServersRoute = route({
7329
7338
  method: "get",
@@ -7340,6 +7349,27 @@ var getAgentMcpServersRoute = route({
7340
7349
  200: { description: "Agent MCP servers list" }
7341
7350
  }
7342
7351
  });
7352
+ function canResolveMcpSecretsForHttpUser(req) {
7353
+ const auth = getRequestAuth(req);
7354
+ if (auth?.kind !== "user")
7355
+ return true;
7356
+ if (!isRbacEnabled())
7357
+ return true;
7358
+ const verb = "mcp-server.read.secrets";
7359
+ const grant = getUserGrant(auth.userId);
7360
+ const decision = grant.grantsAll || grant.verbs.has(verb) ? { allow: true, verb } : {
7361
+ allow: false,
7362
+ reason: `admission: missing permission '${verb}'`,
7363
+ verb
7364
+ };
7365
+ enqueueAdmissionRow({
7366
+ userId: auth.userId,
7367
+ decision,
7368
+ method: req.method,
7369
+ route: getAgentMcpServersRoute.def.path
7370
+ });
7371
+ return decision.allow;
7372
+ }
7343
7373
  async function handleMcpServers(req, res, pathSegments, queryParams) {
7344
7374
  if (getAgentMcpServersRoute.match(req.method, pathSegments)) {
7345
7375
  const parsed = await getAgentMcpServersRoute.parse(req, res, pathSegments, queryParams);
@@ -7348,6 +7378,10 @@ async function handleMcpServers(req, res, pathSegments, queryParams) {
7348
7378
  const servers = getAgentMcpServers(parsed.params.id);
7349
7379
  const resolveSecrets = parsed.query.resolveSecrets === "true";
7350
7380
  if (resolveSecrets) {
7381
+ if (!canResolveMcpSecretsForHttpUser(req)) {
7382
+ jsonError(res, "Forbidden: admission: missing permission 'mcp-server.read.secrets'", 403);
7383
+ return true;
7384
+ }
7351
7385
  const configs = getResolvedConfig(parsed.params.id);
7352
7386
  const configMap = new Map(configs.map((c) => [c.key, c.value]));
7353
7387
  const serversWithSecrets = await Promise.all(servers.map(async (server) => {
@@ -7564,6 +7598,33 @@ var userSendTaskInputSchema = object({
7564
7598
  model: string().trim().min(1).optional().describe("Concrete model override interpreted by the assignee's harness/provider."),
7565
7599
  modelTier: ModelTierSchema.optional().describe("Portable model tier: 'smol', 'regular', 'smart', or 'ultra'. Resolved by the assignee's harness/provider.")
7566
7600
  });
7601
+ function permission(verb) {
7602
+ return { permission: verb };
7603
+ }
7604
+ async function maybeDenyUserToolAdmission(user, toolName, config) {
7605
+ if (!isRbacEnabled())
7606
+ return;
7607
+ const grant = getUserGrant(user.id);
7608
+ if (grant.grantsAll)
7609
+ return;
7610
+ const decision = decideToolAdmission({
7611
+ rbac: config.rbac,
7612
+ readOnly: config.annotations?.readOnlyHint ?? false,
7613
+ grant
7614
+ });
7615
+ enqueueAdmissionRow({
7616
+ userId: user.id,
7617
+ decision,
7618
+ source: "mcp",
7619
+ toolName
7620
+ });
7621
+ if (decision.allow)
7622
+ return;
7623
+ return {
7624
+ isError: true,
7625
+ content: [{ type: "text", text: `Forbidden: ${decision.reason}` }]
7626
+ };
7627
+ }
7567
7628
  function createUserServer(user) {
7568
7629
  const server = new McpServer({
7569
7630
  name: `${package_default.name}-user`,
@@ -7575,44 +7636,77 @@ function createUserServer(user) {
7575
7636
  }
7576
7637
  });
7577
7638
  const registerTool = createToolRegistrar(server);
7578
- registerTool("send-task", {
7639
+ const sendTaskConfig = {
7579
7640
  title: "Send a task",
7580
7641
  annotations: { destructiveHint: false },
7642
+ rbac: permission("task.create.own"),
7581
7643
  description: "Creates an unassigned task requested by the authenticated user.",
7582
7644
  inputSchema: userSendTaskInputSchema,
7583
7645
  outputSchema: sendTaskOutputSchema
7584
- }, async (args, info, _meta) => sendTaskHandler(userCtx(user, info.sessionId), {
7585
- offerMode: false,
7586
- allowDuplicate: false,
7587
- ...args
7588
- }));
7589
- registerTool("get-tasks", {
7646
+ };
7647
+ registerTool("send-task", sendTaskConfig, async (args, info, _meta) => {
7648
+ const denied = await maybeDenyUserToolAdmission(user, "send-task", sendTaskConfig);
7649
+ if (denied)
7650
+ return denied;
7651
+ return sendTaskHandler(userCtx(user, info.sessionId), {
7652
+ offerMode: false,
7653
+ allowDuplicate: false,
7654
+ ...args
7655
+ });
7656
+ });
7657
+ const getTasksConfig = {
7590
7658
  title: "Get tasks",
7591
7659
  description: "Returns tasks requested by the authenticated user.",
7592
7660
  annotations: { readOnlyHint: true },
7593
7661
  inputSchema: getTasksInputSchema,
7594
7662
  outputSchema: getTasksOutputSchema
7595
- }, async (args, info, _meta) => getTasksHandler(userCtx(user, info.sessionId), args));
7596
- registerTool("get-task-details", {
7663
+ };
7664
+ registerTool("get-tasks", getTasksConfig, async (args, info, _meta) => {
7665
+ const denied = await maybeDenyUserToolAdmission(user, "get-tasks", getTasksConfig);
7666
+ if (denied)
7667
+ return denied;
7668
+ return getTasksHandler(userCtx(user, info.sessionId), args);
7669
+ });
7670
+ const getTaskDetailsConfig = {
7597
7671
  title: "Get task details",
7598
7672
  description: "Returns detailed information about one of your tasks.",
7599
7673
  annotations: { readOnlyHint: true },
7600
7674
  inputSchema: getTaskDetailsInputSchema,
7601
7675
  outputSchema: getTaskDetailsOutputSchema
7602
- }, async (args, info, _meta) => getTaskDetailsHandler(userCtx(user, info.sessionId), args));
7603
- registerTool("cancel-task", {
7676
+ };
7677
+ registerTool("get-task-details", getTaskDetailsConfig, async (args, info, _meta) => {
7678
+ const denied = await maybeDenyUserToolAdmission(user, "get-task-details", getTaskDetailsConfig);
7679
+ if (denied)
7680
+ return denied;
7681
+ return getTaskDetailsHandler(userCtx(user, info.sessionId), args);
7682
+ });
7683
+ const cancelTaskConfig = {
7604
7684
  title: "Cancel Task",
7605
7685
  description: "Cancel one of your pending or in-progress tasks.",
7606
7686
  annotations: { destructiveHint: true },
7687
+ rbac: permission("task.cancel.own"),
7607
7688
  inputSchema: cancelTaskInputSchema,
7608
7689
  outputSchema: cancelTaskOutputSchema
7609
- }, async (args, info, _meta) => cancelTaskHandler(userCtx(user, info.sessionId), args));
7610
- registerTool("task-action", {
7690
+ };
7691
+ registerTool("cancel-task", cancelTaskConfig, async (args, info, _meta) => {
7692
+ const denied = await maybeDenyUserToolAdmission(user, "cancel-task", cancelTaskConfig);
7693
+ if (denied)
7694
+ return denied;
7695
+ return cancelTaskHandler(userCtx(user, info.sessionId), args);
7696
+ });
7697
+ const taskActionConfig = {
7611
7698
  title: "Task Pool Action",
7612
7699
  description: "Move one of your tasks to or from backlog.",
7700
+ rbac: permission("task.action.own"),
7613
7701
  inputSchema: taskActionInputSchema,
7614
7702
  outputSchema: taskActionOutputSchema
7615
- }, async (args, info, _meta) => taskActionHandler(userCtx(user, info.sessionId), args));
7703
+ };
7704
+ registerTool("task-action", taskActionConfig, async (args, info, _meta) => {
7705
+ const denied = await maybeDenyUserToolAdmission(user, "task-action", taskActionConfig);
7706
+ if (denied)
7707
+ return denied;
7708
+ return taskActionHandler(userCtx(user, info.sessionId), args);
7709
+ });
7616
7710
  return server;
7617
7711
  }
7618
7712
 
@@ -10804,7 +10898,7 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
10804
10898
  }
10805
10899
  if (agent.isLead) {} else {
10806
10900
  if (hasCapacity(myAgentId)) {
10807
- const unassignedIds = getUnassignedTaskIds(5);
10901
+ const unassignedIds = getUnassignedTaskIdsForAgent(myAgentId, 5);
10808
10902
  if (unassignedIds.length > 0) {
10809
10903
  const candidateId = unassignedIds[0];
10810
10904
  const candidateTask = getTaskById(candidateId);
@@ -14041,7 +14135,8 @@ var searchRoute = route({
14041
14135
  responses: {
14042
14136
  200: { description: "Matching scripts" },
14043
14137
  400: { description: "Validation error" }
14044
- }
14138
+ },
14139
+ rbac: { permission: "script.search" }
14045
14140
  });
14046
14141
  var deleteRoute = route({
14047
14142
  method: "delete",
@@ -14154,7 +14249,8 @@ var createScriptApiRoute = route({
14154
14249
  201: { description: "Endpoint created" },
14155
14250
  400: { description: "Validation error or script has no owning agent" },
14156
14251
  404: { description: "Script not found" }
14157
- }
14252
+ },
14253
+ rbac: { permission: "script.api.create" }
14158
14254
  });
14159
14255
  var listScriptApisRoute = route({
14160
14256
  method: "get",
@@ -14180,7 +14276,8 @@ var revealScriptApiSecretRoute = route({
14180
14276
  responses: {
14181
14277
  200: { description: "Decrypted token (null when authMode is 'none')" },
14182
14278
  404: { description: "Endpoint not found" }
14183
- }
14279
+ },
14280
+ rbac: { permission: "script.api.read.secrets" }
14184
14281
  });
14185
14282
  var patchScriptApiRoute = route({
14186
14283
  method: "patch",
@@ -14194,7 +14291,8 @@ var patchScriptApiRoute = route({
14194
14291
  responses: {
14195
14292
  200: { description: "Updated endpoint" },
14196
14293
  404: { description: "Endpoint not found" }
14197
- }
14294
+ },
14295
+ rbac: { permission: "script.api.update" }
14198
14296
  });
14199
14297
  var rotateScriptApiRoute = route({
14200
14298
  method: "post",
@@ -14208,7 +14306,8 @@ var rotateScriptApiRoute = route({
14208
14306
  200: { description: "Endpoint with new plaintext token" },
14209
14307
  400: { description: "Endpoint uses 'none' auth — nothing to rotate" },
14210
14308
  404: { description: "Endpoint not found" }
14211
- }
14309
+ },
14310
+ rbac: { permission: "script.api.rotate" }
14212
14311
  });
14213
14312
  var deleteScriptApiRoute = route({
14214
14313
  method: "delete",
@@ -14221,7 +14320,8 @@ var deleteScriptApiRoute = route({
14221
14320
  responses: {
14222
14321
  200: { description: "Deleted" },
14223
14322
  404: { description: "Endpoint not found" }
14224
- }
14323
+ },
14324
+ rbac: { permission: "script.api.delete" }
14225
14325
  });
14226
14326
  function requireAgent2(res, agentId) {
14227
14327
  if (!agentId) {
@@ -15108,6 +15208,7 @@ var bulkUpsertSkillFilesRoute = route({
15108
15208
  summary: "Bulk upsert bundled files for a skill",
15109
15209
  tags: ["Skills"],
15110
15210
  auth: { apiKey: true },
15211
+ rbac: { permission: "skill.update.any" },
15111
15212
  params: exports_external.object({ id: exports_external.string() }),
15112
15213
  body: exports_external.object({
15113
15214
  files: exports_external.array(skillFileWithPathSchema).max(100)
@@ -15140,6 +15241,7 @@ var upsertSkillFileRoute = route({
15140
15241
  summary: "Upsert a bundled skill file",
15141
15242
  tags: ["Skills"],
15142
15243
  auth: { apiKey: true },
15244
+ rbac: { permission: "skill.update.any" },
15143
15245
  params: exports_external.object({ id: exports_external.string(), path: exports_external.string() }),
15144
15246
  body: skillFileBodySchema,
15145
15247
  responses: {
@@ -15156,6 +15258,7 @@ var deleteSkillFileRoute = route({
15156
15258
  summary: "Delete a bundled skill file",
15157
15259
  tags: ["Skills"],
15158
15260
  auth: { apiKey: true },
15261
+ rbac: { permission: "skill.update.any" },
15159
15262
  params: exports_external.object({ id: exports_external.string(), path: exports_external.string() }),
15160
15263
  responses: {
15161
15264
  200: { description: "Skill file deleted" },
@@ -15169,6 +15272,7 @@ var createSkillRoute = route({
15169
15272
  summary: "Create a new skill",
15170
15273
  tags: ["Skills"],
15171
15274
  auth: { apiKey: true },
15275
+ rbac: { permission: "skill.create.swarm" },
15172
15276
  body: exports_external.object({
15173
15277
  content: exports_external.string().min(1),
15174
15278
  type: exports_external.string().optional(),
@@ -15188,6 +15292,7 @@ var updateSkillRoute = route({
15188
15292
  summary: "Update a skill",
15189
15293
  tags: ["Skills"],
15190
15294
  auth: { apiKey: true },
15295
+ rbac: { permission: "skill.update.any" },
15191
15296
  params: exports_external.object({ id: exports_external.string() }),
15192
15297
  body: exports_external.record(exports_external.string(), exports_external.unknown()),
15193
15298
  responses: {
@@ -15203,6 +15308,7 @@ var deleteSkillRoute = route({
15203
15308
  summary: "Delete a skill",
15204
15309
  tags: ["Skills"],
15205
15310
  auth: { apiKey: true },
15311
+ rbac: { permission: "skill.delete.any" },
15206
15312
  params: exports_external.object({ id: exports_external.string() }),
15207
15313
  responses: {
15208
15314
  200: { description: "Skill deleted" },
@@ -15217,6 +15323,7 @@ var installSkillRoute = route({
15217
15323
  summary: "Install skill for an agent",
15218
15324
  tags: ["Skills"],
15219
15325
  auth: { apiKey: true },
15326
+ rbac: { permission: "skill.install.any" },
15220
15327
  params: exports_external.object({ id: exports_external.string() }),
15221
15328
  body: exports_external.object({
15222
15329
  agentId: exports_external.string()
@@ -15233,6 +15340,7 @@ var uninstallSkillRoute = route({
15233
15340
  summary: "Uninstall skill for an agent",
15234
15341
  tags: ["Skills"],
15235
15342
  auth: { apiKey: true },
15343
+ rbac: { permission: "skill.uninstall.any" },
15236
15344
  params: exports_external.object({ id: exports_external.string(), agentId: exports_external.string() }),
15237
15345
  responses: {
15238
15346
  200: { description: "Skill uninstalled" }
@@ -15245,6 +15353,7 @@ var installRemoteRoute = route({
15245
15353
  summary: "Install a remote skill from GitHub",
15246
15354
  tags: ["Skills"],
15247
15355
  auth: { apiKey: true },
15356
+ rbac: { permission: "skill.install.global" },
15248
15357
  body: exports_external.object({
15249
15358
  sourceRepo: exports_external.string(),
15250
15359
  sourcePath: exports_external.string().optional(),
@@ -15263,6 +15372,7 @@ var syncRemoteRoute = route({
15263
15372
  summary: "Trigger remote skill sync",
15264
15373
  tags: ["Skills"],
15265
15374
  auth: { apiKey: true },
15375
+ rbac: { permission: "skill.update.any" },
15266
15376
  body: exports_external.object({
15267
15377
  skillId: exports_external.string().optional(),
15268
15378
  force: exports_external.boolean().optional()
@@ -15278,6 +15388,7 @@ var syncFilesystemRoute = route({
15278
15388
  summary: "Sync installed skills to agent filesystem",
15279
15389
  tags: ["Skills"],
15280
15390
  auth: { apiKey: true, agentId: true },
15391
+ rbac: { ungated: "self-scoped: syncs the caller's own agent FS" },
15281
15392
  responses: {
15282
15393
  200: { description: "Filesystem sync results" }
15283
15394
  }
@@ -16636,7 +16747,13 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
16636
16747
  const parsed = await createTask.parse(req, res, pathSegments, queryParams);
16637
16748
  if (!parsed)
16638
16749
  return true;
16639
- const requestedByUserId = resolveHttpAuditUserId(req, myAgentId) ?? undefined;
16750
+ let requestedByUserId = resolveHttpAuditUserId(req, myAgentId) ?? undefined;
16751
+ const trustBodyRequestedByUserId = process.env.TRUST_BODY_REQUESTED_BY_USER_ID === "true";
16752
+ if (trustBodyRequestedByUserId && !requestedByUserId && parsed.body.requestedByUserId) {
16753
+ const candidate = findUserById(parsed.body.requestedByUserId);
16754
+ if (candidate)
16755
+ requestedByUserId = candidate.id;
16756
+ }
16640
16757
  let defaultAgentId = parsed.body.agentId || undefined;
16641
16758
  if (!defaultAgentId) {
16642
16759
  const lead = getLeadAgent();
@@ -20199,14 +20316,14 @@ async function shutdown() {
20199
20316
  sessionsProcessed: getServerSessionsProcessed()
20200
20317
  });
20201
20318
  if (hasCapability("scheduling")) {
20202
- const { stopScheduler } = await import("./index-f03rnnrs.js");
20319
+ const { stopScheduler } = await import("./index-9ht8gr56.js");
20203
20320
  stopScheduler();
20204
20321
  }
20205
20322
  stopHeartbeat();
20206
20323
  stopScriptRunSupervisor();
20207
20324
  await stopSlackApp();
20208
20325
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
20209
- const { stopOAuthKeepalive } = await import("./keepalive-pm6g2wpw.js");
20326
+ const { stopOAuthKeepalive } = await import("./keepalive-3cps6e3e.js");
20210
20327
  await stopOAuthKeepalive();
20211
20328
  }
20212
20329
  stopMcpOAuthPendingGc();
@@ -20263,15 +20380,15 @@ try {
20263
20380
  throw err;
20264
20381
  }
20265
20382
  try {
20266
- const { seedPricingFromModelsDev } = await import("./seed-pricing-m9h69d2t.js");
20383
+ const { seedPricingFromModelsDev } = await import("./seed-pricing-h2kdq4cq.js");
20267
20384
  seedPricingFromModelsDev();
20268
- const { startPricingRefreshLoop } = await import("./pricing-refresh-2kk2ap9b.js");
20385
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-0hvazmkf.js");
20269
20386
  startPricingRefreshLoop();
20270
20387
  } catch (err) {
20271
20388
  console.error("[startup] Failed to seed pricing rows:", err);
20272
20389
  }
20273
20390
  try {
20274
- const { ensureRbacSeedsSynced } = await import("./rbac-roles-xdc5208b.js");
20391
+ const { ensureRbacSeedsSynced } = await import("./rbac-roles-kfesjy9y.js");
20275
20392
  ensureRbacSeedsSynced();
20276
20393
  } catch (err) {
20277
20394
  console.error("[startup] Failed to sync RBAC seed rows:", err);
@@ -20279,7 +20396,7 @@ try {
20279
20396
  throw err;
20280
20397
  }
20281
20398
  try {
20282
- const { runAllSeeders } = await import("./index-df8fmphk.js");
20399
+ const { runAllSeeders } = await import("./index-rm85cfdx.js");
20283
20400
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
20284
20401
  } catch (err) {
20285
20402
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -20315,35 +20432,35 @@ httpServer.listen(port, async () => {
20315
20432
  initWorkflows();
20316
20433
  startScriptRunSupervisor(getMcpBaseUrl());
20317
20434
  if (hasCapability("scheduling")) {
20318
- const { startScheduler } = await import("./index-f03rnnrs.js");
20319
- const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-jbm7qcqk.js");
20435
+ const { startScheduler } = await import("./index-9ht8gr56.js");
20436
+ const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-9fqaktjr.js");
20320
20437
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
20321
20438
  startScheduler(getExecutorRegistry2(), intervalMs, {
20322
20439
  runId: globalState.__runId
20323
20440
  });
20324
20441
  }
20325
20442
  if (process.env.HEARTBEAT_DISABLE !== "true") {
20326
- const { startHeartbeat } = await import("./index-ty42rxw9.js");
20443
+ const { startHeartbeat } = await import("./index-47em3d2n.js");
20327
20444
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
20328
20445
  startHeartbeat(heartbeatMs);
20329
20446
  }
20330
20447
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
20331
- const { startOAuthKeepalive } = await import("./keepalive-pm6g2wpw.js");
20448
+ const { startOAuthKeepalive } = await import("./keepalive-3cps6e3e.js");
20332
20449
  startOAuthKeepalive();
20333
20450
  }
20334
20451
  if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
20335
- const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-mjsbmsk2.js");
20452
+ const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-sycqtbph.js");
20336
20453
  startOAuthRefreshSweep();
20337
20454
  }
20338
20455
  startMcpOAuthPendingGc();
20339
20456
  startMemoryGc();
20340
- import("./boot-reembed-b9sbk87z.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
20457
+ import("./boot-reembed-qata34xa.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
20341
20458
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
20342
20459
  });
20343
- import("./boot-reembed-awr2179r.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
20460
+ import("./boot-reembed-4jpxhb25.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
20344
20461
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
20345
20462
  });
20346
- import("./boot-scrub-logs-c1zsaw9m.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
20463
+ import("./boot-scrub-logs-tv48nn3z.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
20347
20464
  console.error("[boot-scrub-logs] startup scrub failed (non-fatal):", err);
20348
20465
  });
20349
20466
  }).on("error", (err) => {
@@ -4,25 +4,25 @@ import {
4
4
  runRebootSweep,
5
5
  startHeartbeat,
6
6
  stopHeartbeat
7
- } from "./cli-q4e2x252.js";
8
- import"./cli-2t4e4ayk.js";
9
- import"./cli-a6tzw6vq.js";
7
+ } from "./cli-beea4a3y.js";
8
+ import"./cli-dcca6j8m.js";
9
+ import"./cli-q1rx7g0d.js";
10
10
  import"./cli-f14fvzag.js";
11
- import"./cli-pnfyyp6h.js";
11
+ import"./cli-r9f6ngrf.js";
12
12
  import"./cli-jkhwmmgg.js";
13
- import"./cli-f9n2jg31.js";
14
- import"./cli-byjcad11.js";
13
+ import"./cli-cmw9rzy5.js";
14
+ import"./cli-7xje5amz.js";
15
15
  import"./cli-q25ejbyn.js";
16
- import"./cli-49j095n9.js";
16
+ import"./cli-t0vqevnm.js";
17
17
  import"./cli-0pygq9r1.js";
18
18
  import"./cli-wspgs9bt.js";
19
- import"./cli-312v3c41.js";
19
+ import"./cli-k3y4z3h5.js";
20
20
  import"./cli-dh55d5fg.js";
21
- import"./cli-jzwtn8rm.js";
21
+ import"./cli-15y7qhzp.js";
22
22
  import"./cli-z2zcxes1.js";
23
23
  import"./cli-bw80ck94.js";
24
24
  import"./cli-xz9aq0rf.js";
25
- import"./cli-f5pzfvwb.js";
25
+ import"./cli-b23axgz4.js";
26
26
  import"./cli-4j2mrzag.js";
27
27
  import"./cli-9aryf9tv.js";
28
28
  import"./cli-p9swy5t3.js";