@desplega.ai/agent-swarm 2.5.1 → 2.5.2

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 (155) hide show
  1. package/dist/{acp-adapter-7g6bpwbk.js → acp-adapter-csh0zz3b.js} +1 -1
  2. package/dist/{actions-w8xd014k.js → actions-6xx079d1.js} +17 -17
  3. package/dist/{amp-adapter-z4qvhacj.js → amp-adapter-8n6f0hz8.js} +2 -2
  4. package/dist/{app-nndcvftq.js → app-ft6r6v23.js} +3 -3
  5. package/dist/{assistant-hjmqyscx.js → assistant-vt2cyfzd.js} +18 -18
  6. package/dist/{boot-reembed-r8rhf9h8.js → boot-reembed-r3e808ky.js} +1 -1
  7. package/dist/{boot-reembed-vwcj2y5d.js → boot-reembed-tgrfy27t.js} +1 -1
  8. package/dist/{boot-scrub-sweep-fr9q36ne.js → boot-scrub-sweep-masdwxkm.js} +2 -2
  9. package/dist/{boot-seeds-9jqwnegq.js → boot-seeds-0n82qc7q.js} +4 -4
  10. package/dist/{claude-adapter-2f8b85df.js → claude-adapter-s7j47k06.js} +2 -2
  11. package/dist/{claude-managed-setup-c3hp36ph.js → claude-managed-setup-3hzrgrnk.js} +1 -1
  12. package/dist/{claude-sdk-session-05kat8rv.js → claude-sdk-session-0zrdzyx2.js} +6905 -6855
  13. package/dist/{cli-mz2ygeyq.js → cli-0vgy5wfw.js} +2 -2
  14. package/dist/{cli-eym3jg7w.js → cli-14v1sxxy.js} +6 -6
  15. package/dist/{cli-e9btqw4y.js → cli-15xd0j7w.js} +18 -13
  16. package/dist/{cli-v2g93k4v.js → cli-3e9vs93g.js} +4 -4
  17. package/dist/{cli-1dp1zj04.js → cli-4qkg9968.js} +3 -3
  18. package/dist/{cli-ba8ne1es.js → cli-4rvr7zfx.js} +10 -0
  19. package/dist/{cli-rngde2jv.js → cli-6y43v79h.js} +1 -1
  20. package/dist/{cli-z63a269p.js → cli-7ccf7akh.js} +1 -1
  21. package/dist/{cli-z2dv25mf.js → cli-86zpfje5.js} +116 -5
  22. package/dist/{cli-fes51ya2.js → cli-aaqnqpyw.js} +2 -2
  23. package/dist/{cli-qfm6my86.js → cli-b1tv22wr.js} +1 -1
  24. package/dist/{cli-xc65x52q.js → cli-b63d08rs.js} +1 -1
  25. package/dist/{cli-gwcf52gz.js → cli-b6tnjdvx.js} +11 -7
  26. package/dist/{cli-9mm5ade4.js → cli-bpbcpd8b.js} +1 -1
  27. package/dist/{cli-qfjm4gvt.js → cli-cf63dnxj.js} +2 -2
  28. package/dist/{cli-q9pzwxvk.js → cli-csh8fnbg.js} +82 -16
  29. package/dist/{cli-0jy85zz4.js → cli-cyfgxnvb.js} +7 -7
  30. package/dist/{cli-y3zyaee5.js → cli-d172svcw.js} +5 -5
  31. package/dist/{cli-mq7kg1b1.js → cli-e91vshb1.js} +41 -6
  32. package/dist/{cli-cah5detr.js → cli-edtm741g.js} +5 -5
  33. package/dist/{cli-ajqhxtnz.js → cli-f3pfn4x3.js} +1 -1
  34. package/dist/{cli-hadv0725.js → cli-f55b6ky0.js} +1 -1
  35. package/dist/{cli-r9fy0ddc.js → cli-fgn7yg5r.js} +1 -1
  36. package/dist/{cli-kcsd1ez8.js → cli-h5d22pfs.js} +249 -68
  37. package/dist/{cli-2wba1ac9.js → cli-ha22h0eg.js} +20 -20
  38. package/dist/{cli-pyy4c9ch.js → cli-j3dwd4kz.js} +173 -134
  39. package/dist/{cli-j1eghqfm.js → cli-jmcjbjkt.js} +1 -1
  40. package/dist/{cli-22rmcjkg.js → cli-kcnwn85g.js} +4 -3
  41. package/dist/{cli-rh5smt8t.js → cli-mntxtkhn.js} +12 -2
  42. package/dist/{cli-2jg61wab.js → cli-n2918sed.js} +9 -9
  43. package/dist/{cli-3ee5z0q0.js → cli-qrjv7t18.js} +1 -1
  44. package/dist/{cli-sn1vbtg2.js → cli-vaxw3bg0.js} +3 -3
  45. package/dist/{cli-cwyafhw1.js → cli-wadzapwb.js} +1 -1
  46. package/dist/{cli-jpxsrxcb.js → cli-xw9q173h.js} +1 -1
  47. package/dist/{cli-znvq0k3t.js → cli-xzge46sj.js} +2 -2
  48. package/dist/{cli-nj12tn2c.js → cli-y3dzwyy3.js} +3 -3
  49. package/dist/{cli-xd4eqtr2.js → cli-ydg6ep51.js} +1 -1
  50. package/dist/cli.js +16 -15
  51. package/dist/{codex-adapter-p4ptwar5.js → codex-adapter-brh2tcxr.js} +1 -1
  52. package/dist/{codex-session-runner-964c7dnk.js → codex-session-runner-0dnj21qs.js} +1 -1
  53. package/dist/{commands-mbvhbrcy.js → commands-1cnvseqx.js} +2 -2
  54. package/dist/{controller-gnq1k1mf.js → controller-kc7s9xhn.js} +2 -2
  55. package/dist/{controllers-connect-6dkm71tg.js → controllers-connect-jzx7t4bn.js} +18 -18
  56. package/dist/{cursor-adapter-yq5xgfcg.js → cursor-adapter-qpwp5sfg.js} +1 -1
  57. package/dist/{db-af9y8nkf.js → db-4vq88jkc.js} +3 -3
  58. package/dist/{db-88wcymxt.js → db-v5ytg5pw.js} +1 -1
  59. package/dist/{dispatcher-606ydx5v.js → dispatcher-trtcrqae.js} +16 -16
  60. package/dist/{dsh-adapter-tvhc4k2d.js → dsh-adapter-f20xwn1z.js} +1 -1
  61. package/dist/{external-channel-y8q5z8z2.js → external-channel-n9bymc2n.js} +2 -2
  62. package/dist/{grok-adapter-39aha52t.js → grok-adapter-4kpmmnr6.js} +2 -2
  63. package/dist/{handlers-rk9dqech.js → handlers-ptsraqa8.js} +19 -19
  64. package/dist/{heartbeat-jfe9zfjr.js → heartbeat-60qtxtjf.js} +19 -19
  65. package/dist/{hook-ffevzed1.js → hook-ngtvh729.js} +1 -1
  66. package/dist/{hook-b1mez1m8.js → hook-rbktcstg.js} +1 -1
  67. package/dist/{http-d5b44f1r.js → http-z8xy72gp.js} +334 -86
  68. package/dist/{index-nq8hhv28.js → index-06qkmcx6.js} +10 -9
  69. package/dist/{index-d2qeem97.js → index-1cscynkb.js} +16 -16
  70. package/dist/{index-5en23s5z.js → index-a9nsavhx.js} +1 -1
  71. package/dist/{index-4q3vj1yr.js → index-r70q0xjx.js} +16 -16
  72. package/dist/{index-mj46rk9k.js → index-s193j5fh.js} +19 -19
  73. package/dist/{keepalive-wsby1btq.js → keepalive-a9srcphj.js} +3 -3
  74. package/dist/{lead-paa141j6.js → lead-3devneqy.js} +26 -26
  75. package/dist/{maintenance-vnshcyv9.js → maintenance-0er16h2y.js} +1 -1
  76. package/dist/{oauth-refresh-sweep-d6sqn5np.js → oauth-refresh-sweep-b65jcyw2.js} +2 -2
  77. package/dist/{onboard-nr4xhpzy.js → onboard-wqywz5py.js} +2 -2
  78. package/dist/{otel-impl-ytn9wyv9.js → otel-impl-vk32s884.js} +1 -1
  79. package/dist/{pricing-refresh-pva04zee.js → pricing-refresh-t27anv4z.js} +3 -3
  80. package/dist/rbac-roles-452665y0.js +26 -0
  81. package/dist/{rbac-roles-7rc1q3g4.js → rbac-roles-bmcgsxjn.js} +12 -2
  82. package/dist/{render-v2-pyfsg9zk.js → render-v2-0ttsk2j4.js} +3 -3
  83. package/dist/{resume-phj8xhqr.js → resume-a26kvr41.js} +5 -5
  84. package/dist/{session-access-jzx2z9h5.js → session-access-dgh9nkwk.js} +4 -4
  85. package/dist/{setup-rfg0f0sg.js → setup-9vc9qahm.js} +1 -1
  86. package/dist/{work-objects-44z2yjg8.js → work-objects-vn8nkxwn.js} +19 -19
  87. package/dist/{worker-zsfqzxhm.js → worker-1x1h8vnm.js} +26 -26
  88. package/openapi.json +463 -3
  89. package/package.json +4 -3
  90. package/src/be/db/session-tree.ts +89 -2
  91. package/src/be/db/session-visibility.ts +31 -0
  92. package/src/be/db/tasks/read.ts +18 -5
  93. package/src/be/db.ts +2 -0
  94. package/src/be/migrations/233_script_run_session_tokens.sql +8 -0
  95. package/src/be/migrations/235_chat_relay_defer.sql +86 -0
  96. package/src/be/migrations/237_session_inbox_cleanup.sql +75 -0
  97. package/src/be/rbac-roles.ts +138 -0
  98. package/src/be/scripts/run-credential.ts +64 -0
  99. package/src/be/scripts/run-saved.ts +3 -2
  100. package/src/be/users.ts +28 -4
  101. package/src/http/all-routes.ts +1 -0
  102. package/src/http/approval-requests.ts +46 -6
  103. package/src/http/index.ts +2 -0
  104. package/src/http/schedules.ts +26 -0
  105. package/src/http/scripts.ts +2 -2
  106. package/src/http/sessions.ts +93 -2
  107. package/src/http/user-roles.ts +173 -0
  108. package/src/http/users.ts +9 -0
  109. package/src/http/x.ts +2 -2
  110. package/src/integrations/chat-sdk/commands.ts +14 -1
  111. package/src/integrations/chat-sdk/inbound.ts +40 -5
  112. package/src/integrations/chat-sdk/outbound.ts +35 -10
  113. package/src/integrations/chat-sdk/reactions.ts +107 -0
  114. package/src/integrations/chat-sdk/relay.ts +75 -7
  115. package/src/integrations/chat-sdk/thread-buffer.ts +2 -0
  116. package/src/integrations/reaction-events.ts +20 -0
  117. package/src/providers/amp-adapter.ts +1 -1
  118. package/src/rbac/legacy-policy.ts +3 -0
  119. package/src/rbac/permissions.ts +8 -0
  120. package/src/scheduler/schedule-task.ts +44 -3
  121. package/src/scheduler/scheduler.ts +4 -4
  122. package/src/scripts-runtime/loader.ts +8 -1
  123. package/src/slack/ack.ts +2 -1
  124. package/src/slack/reaction-shortcode.ts +4 -7
  125. package/src/tasks/worker-follow-up.ts +30 -0
  126. package/src/tests/approval-requests-notifications.test.ts +189 -0
  127. package/src/tests/chat-sdk-commands.test.ts +12 -0
  128. package/src/tests/chat-sdk-inbound.test.ts +163 -9
  129. package/src/tests/chat-sdk-outbound-files.test.ts +9 -2
  130. package/src/tests/chat-sdk-relay.test.ts +361 -10
  131. package/src/tests/chat-sdk-tools.test.ts +104 -0
  132. package/src/tests/docs-index-footprint.test.js +3 -3
  133. package/src/tests/http-users.test.ts +38 -0
  134. package/src/tests/migration-237-session-inbox-cleanup.test.ts +136 -0
  135. package/src/tests/rbac-engine.test.ts +2 -0
  136. package/src/tests/rbac-roles.test.ts +10 -0
  137. package/src/tests/schedule-http-triage-tools.test.ts +44 -0
  138. package/src/tests/script-api-credential.test.ts +173 -0
  139. package/src/tests/script-connections.test.ts +4 -0
  140. package/src/tests/script-run-config-scope.test.ts +120 -0
  141. package/src/tests/script-run-token.test.ts +75 -0
  142. package/src/tests/scripts-http.test.ts +19 -0
  143. package/src/tests/sessions-tree.test.ts +242 -0
  144. package/src/tests/user-roles-http.test.ts +204 -0
  145. package/src/tests/workflow-hitl-dynamic-questions.test.ts +1 -1
  146. package/src/tools/chat-reply.ts +2 -0
  147. package/src/tools/schedules/patch-schedule.ts +18 -0
  148. package/src/tools/schedules/update-schedule.ts +18 -0
  149. package/src/types.ts +16 -0
  150. package/src/workflows/approval-notifications.ts +214 -0
  151. package/src/workflows/executors/human-in-the-loop.ts +11 -172
  152. package/src/workflows/executors/swarm-script.ts +2 -2
  153. package/templates/schedules/weekly-harness-upgrade-check/content.md +1 -1
  154. package/templates/skills/code-quality/content.md +1 -1
  155. package/dist/rbac-roles-ff1ffmec.js +0 -12
@@ -336,19 +336,19 @@ import {
336
336
  recordInlineScriptRun2,
337
337
  exports_db,
338
338
  init_db3
339
- } from "./cli-q9pzwxvk.js";
339
+ } from "./cli-csh8fnbg.js";
340
340
  import {
341
341
  getUserGrant2,
342
342
  init_rbac_roles
343
- } from "./cli-z2dv25mf.js";
343
+ } from "./cli-86zpfje5.js";
344
344
  import {
345
345
  ensurePricingSeeded2,
346
346
  ensureRbacSeeded2,
347
347
  ensureModelProfilesSeeded2
348
- } from "./cli-v2g93k4v.js";
348
+ } from "./cli-3e9vs93g.js";
349
349
  import {
350
350
  loadModelsDevCache
351
- } from "./cli-9mm5ade4.js";
351
+ } from "./cli-bpbcpd8b.js";
352
352
  import {
353
353
  buildCatalogEntries,
354
354
  listModelCatalog,
@@ -358,12 +358,12 @@ import {
358
358
  loadModelsCatalog,
359
359
  requestModelCatalogRefresh2,
360
360
  startPricingRefreshLoop2
361
- } from "./cli-mz2ygeyq.js";
361
+ } from "./cli-0vgy5wfw.js";
362
362
  import {
363
363
  ampPinProviderError,
364
364
  ampPinCatalogError,
365
365
  ampModelError
366
- } from "./cli-jpxsrxcb.js";
366
+ } from "./cli-xw9q173h.js";
367
367
  import {
368
368
  notifyAutomationPreflightFailure,
369
369
  isNeedsSetupFailure,
@@ -373,6 +373,7 @@ import {
373
373
  schedulePreflightInput,
374
374
  recordSchedulePreflightFailure,
375
375
  BaseExecutor,
376
+ resolveSlackConversationId,
376
377
  postApprovalCancellationUpdates,
377
378
  createApprovalFollowUpTask,
378
379
  HumanInTheLoopExecutor,
@@ -415,7 +416,7 @@ import {
415
416
  definitionNodeIds,
416
417
  validateDefinition,
417
418
  applyDefinitionPatch
418
- } from "./cli-pyy4c9ch.js";
419
+ } from "./cli-j3dwd4kz.js";
419
420
  import {
420
421
  require_dist2,
421
422
  publicEndpointSsrfOptions,
@@ -446,7 +447,7 @@ import {
446
447
  MAX_SCRIPT_WALL_CLOCK_MS,
447
448
  DEFAULT_SCRIPT_RESOURCES,
448
449
  validateScriptImports,
449
- runScript,
450
+ runScriptWithRunCredential,
450
451
  extractScriptSignature,
451
452
  extractArgsJsonSchema,
452
453
  getSavedScriptOwnerAgentId,
@@ -475,14 +476,14 @@ import {
475
476
  deleteApp,
476
477
  typecheckScript,
477
478
  parseSkillContent
478
- } from "./cli-mq7kg1b1.js";
479
+ } from "./cli-e91vshb1.js";
479
480
  import {
480
481
  buildAuthorizationUrl,
481
482
  onAuthorizationRefreshed,
482
483
  ensureAuthorizationTokenOrThrow,
483
484
  ensureToken,
484
485
  ensureTokenOrThrow
485
- } from "./cli-rngde2jv.js";
486
+ } from "./cli-6y43v79h.js";
486
487
  import {
487
488
  detachedProcessGroup,
488
489
  registerProcessGroup,
@@ -490,6 +491,7 @@ import {
490
491
  } from "./cli-3ggwdtb0.js";
491
492
  import {
492
493
  noteSlackInboundSideEffect,
494
+ terminalReactionEvent,
493
495
  withSpan2,
494
496
  getTaskLink,
495
497
  getTaskUrl,
@@ -512,14 +514,14 @@ import {
512
514
  getSlackApp2,
513
515
  startSlackApp2,
514
516
  stopSlackApp2
515
- } from "./cli-e9btqw4y.js";
517
+ } from "./cli-15xd0j7w.js";
516
518
  import {
517
519
  slackCode,
518
520
  slackMissingScopeMessage,
519
521
  withAutoJoin,
520
522
  externalChannelToolError2,
521
523
  getChannelBlockReason2
522
- } from "./cli-xc65x52q.js";
524
+ } from "./cli-b63d08rs.js";
523
525
  import {
524
526
  workflowEventBus2,
525
527
  init_event_bus
@@ -541,7 +543,7 @@ import {
541
543
  recoverResolvedWaitState2,
542
544
  resumeFromChildRun2,
543
545
  initWaitBusSubscriptions2
544
- } from "./cli-nj12tn2c.js";
546
+ } from "./cli-y3dzwyy3.js";
545
547
  import {
546
548
  duplicateGuardedQueryKey,
547
549
  parseQueryParams,
@@ -568,7 +570,7 @@ import {
568
570
  isPublicRoute,
569
571
  findRoute,
570
572
  route
571
- } from "./cli-y3zyaee5.js";
573
+ } from "./cli-d172svcw.js";
572
574
  import {
573
575
  isMultiRuntimeEnabled
574
576
  } from "./cli-e8xyjvfc.js";
@@ -582,7 +584,7 @@ import {
582
584
  import {
583
585
  getRuntimePool2,
584
586
  init_db
585
- } from "./cli-1dp1zj04.js";
587
+ } from "./cli-4qkg9968.js";
586
588
  import {
587
589
  getMemoryRaterNames,
588
590
  REFERENCES_SOURCE_MAX_LENGTH,
@@ -623,7 +625,7 @@ import {
623
625
  resolveSessionToken,
624
626
  fingerprintApiKey,
625
627
  init_users
626
- } from "./cli-gwcf52gz.js";
628
+ } from "./cli-b6tnjdvx.js";
627
629
  import {
628
630
  isRbacEnabled,
629
631
  decideAdmission,
@@ -632,7 +634,7 @@ import {
632
634
  init_elevated_agents,
633
635
  can,
634
636
  init_rbac
635
- } from "./cli-ba8ne1es.js";
637
+ } from "./cli-4rvr7zfx.js";
636
638
  import {
637
639
  normalizeAssetKey,
638
640
  parseAssetKey,
@@ -692,7 +694,7 @@ import {
692
694
  KvNamespaceSchema,
693
695
  KvKeySchema,
694
696
  init_types
695
- } from "./cli-rh5smt8t.js";
697
+ } from "./cli-mntxtkhn.js";
696
698
  import {
697
699
  generateDefaultClaudeMd2,
698
700
  generateDefaultSoulMd2,
@@ -761,7 +763,7 @@ import {
761
763
  import {
762
764
  init_package,
763
765
  package_default
764
- } from "./cli-22rmcjkg.js";
766
+ } from "./cli-kcnwn85g.js";
765
767
  import {
766
768
  realtimeBus,
767
769
  init_bus
@@ -21119,7 +21121,7 @@ class NotifyExecutor extends BaseExecutor {
21119
21121
  }
21120
21122
  }
21121
21123
  case "slack": {
21122
- const { getSlackApp } = await import("./app-nndcvftq.js");
21124
+ const { getSlackApp } = await import("./app-ft6r6v23.js");
21123
21125
  const app = getSlackApp();
21124
21126
  if (!app) {
21125
21127
  return {
@@ -21538,7 +21540,7 @@ class SwarmScriptExecutor extends BaseExecutor {
21538
21540
  const credentials = await buildScriptCredentialBindingsWithFailures({
21539
21541
  agentId: agentId ?? undefined
21540
21542
  });
21541
- const output = await runScript({
21543
+ const output = await runScriptWithRunCredential({
21542
21544
  source: resolved.source,
21543
21545
  args: config.args,
21544
21546
  fsMode: "none",
@@ -21950,6 +21952,27 @@ init_event_bus();
21950
21952
  init_db3();
21951
21953
  init_steering();
21952
21954
  init_context_key();
21955
+ async function answersInChat(task) {
21956
+ if (task.source === "chat")
21957
+ return true;
21958
+ if (task.source === "system" && task.taskType === "follow-up")
21959
+ return true;
21960
+ if (task.source === "schedule" && task.taskType === "deferred")
21961
+ return true;
21962
+ if (task.source === "system" && task.taskType === "resume" && task.agentId) {
21963
+ return (await getAgentById2(task.agentId))?.isLead === true;
21964
+ }
21965
+ return false;
21966
+ }
21967
+ async function scheduleTaskContextKey(schedule) {
21968
+ if (schedule.taskType === "deferred" && schedule.parentTaskId) {
21969
+ const parent = await getTaskById2(schedule.parentTaskId);
21970
+ if (parent?.contextKey && chatThreadOfContextKey(parent.contextKey) && parent.agentId && schedule.targetAgentId === parent.agentId && schedule.createdByAgentId === parent.agentId && await answersInChat(parent)) {
21971
+ return parent.contextKey;
21972
+ }
21973
+ }
21974
+ return scheduleContextKey({ scheduleId: schedule.id });
21975
+ }
21953
21976
  async function prepareStandaloneScheduleTask(schedule, extraTags = []) {
21954
21977
  if (!schedule.taskTemplate) {
21955
21978
  throw new Error(`Schedule "${schedule.name}" has no taskTemplate (targetType=agent-task)`);
@@ -21968,7 +21991,7 @@ async function prepareStandaloneScheduleTask(schedule, extraTags = []) {
21968
21991
  scheduleId: schedule.id,
21969
21992
  source: "schedule",
21970
21993
  requestedByUserId: schedule.createdBy,
21971
- contextKey: scheduleContextKey({ scheduleId: schedule.id }),
21994
+ contextKey: await scheduleTaskContextKey(schedule),
21972
21995
  parentTaskId: schedule.parentTaskId,
21973
21996
  inheritParentFollowUpConfig: schedule.taskType === "deferred" && !!schedule.parentTaskId
21974
21997
  }, { origin: "schedule" });
@@ -22207,7 +22230,7 @@ async function executeScheduleScript(schedule) {
22207
22230
  let output;
22208
22231
  try {
22209
22232
  const credentials = await buildScriptCredentialBindingsWithFailures({ agentId });
22210
- output = await runScript({
22233
+ output = await runScriptWithRunCredential({
22211
22234
  source: script.source,
22212
22235
  args,
22213
22236
  fsMode: "none",
@@ -24482,7 +24505,7 @@ function setPreloadedTools(server, names) {
24482
24505
  async function applyPreToolCall(name, args, requestInfo, inputSchema) {
24483
24506
  if (requestInfo.callOrigin !== "mcp")
24484
24507
  return { args };
24485
- const dispatcher = await import("./dispatcher-606ydx5v.js");
24508
+ const dispatcher = await import("./dispatcher-trtcrqae.js");
24486
24509
  const result = await dispatcher.dispatchPre("pre.tool.call", { tool: name, args, requestInfo }, inputSchema ? {
24487
24510
  validateModify: async (data) => {
24488
24511
  const schema = normalizeObjectSchema(inputSchema) ?? inputSchema;
@@ -32175,6 +32198,14 @@ function helpText() {
32175
32198
  return ["Commands:", ...CHAT_COMMANDS.map((c) => `/${c.command}: ${c.description}`)].join(`
32176
32199
  `);
32177
32200
  }
32201
+ function welcomeText() {
32202
+ return [
32203
+ "Hi! Send a message here (in a group, mention me) and the swarm picks it up. Each answer arrives as a reply to your message.",
32204
+ "",
32205
+ helpText()
32206
+ ].join(`
32207
+ `);
32208
+ }
32178
32209
  function shortId(task) {
32179
32210
  return task.id.slice(0, 8);
32180
32211
  }
@@ -32220,6 +32251,8 @@ async function runChatCommand(command, threadId, requestedBy) {
32220
32251
  const name = command.replace(/^\//, "").toLowerCase();
32221
32252
  if (name === "help")
32222
32253
  return helpText();
32254
+ if (name === "start")
32255
+ return welcomeText();
32223
32256
  if (!CHAT_COMMANDS.some((c) => c.command === name)) {
32224
32257
  return `Unknown command /${name}.
32225
32258
  ${helpText()}`;
@@ -32931,12 +32964,13 @@ function escapeTelegramHashLines(markdown) {
32931
32964
  }).join(`
32932
32965
  `);
32933
32966
  }
32934
- async function postChunks(adapter, target, text) {
32967
+ async function postChunks(adapter, target, parts, replyFirst) {
32935
32968
  const messageIds = [];
32936
32969
  let threadId;
32937
- for (const chunk of splitChatMessage(text, chatMessageLimit(adapter))) {
32938
- const markdown = adapter === "telegram" ? escapeTelegramHashLines(chunk) : chunk;
32939
- const sent = await target.post({ markdown });
32970
+ const limit = chatMessageLimit(adapter);
32971
+ for (const chunk of parts.flatMap((part) => splitChatMessage(part, limit))) {
32972
+ const message = { markdown: adapter === "telegram" ? escapeTelegramHashLines(chunk) : chunk };
32973
+ const sent = replyFirst && messageIds.length === 0 ? await replyFirst(message) : await target.post(message);
32940
32974
  messageIds.push(sent.id);
32941
32975
  threadId ??= sent.threadId;
32942
32976
  }
@@ -33066,13 +33100,17 @@ async function postChatMessage(args) {
33066
33100
  const chat = getChatInstance(args.adapter);
33067
33101
  if (!chat)
33068
33102
  throw new ChatAdapterUnavailableError(args.adapter);
33069
- const text = scrubSecrets(args.text);
33103
+ const parts = (typeof args.text === "string" ? [args.text] : args.text).map(scrubSecrets);
33104
+ const text = parts.join(`
33105
+
33106
+ `);
33070
33107
  let result;
33071
33108
  let target;
33072
33109
  if (args.threadId) {
33073
33110
  const thread = chat.thread(args.threadId);
33074
33111
  target = thread;
33075
- const sent = await postChunks(args.adapter, thread, text);
33112
+ const replyTo = args.replyToMessageId;
33113
+ const sent = await postChunks(args.adapter, thread, parts, replyTo && thread.adapter.reply ? (message) => thread.reply(replyTo, message) : undefined);
33076
33114
  result = {
33077
33115
  adapter: args.adapter,
33078
33116
  threadId: thread.id,
@@ -33083,7 +33121,7 @@ async function postChatMessage(args) {
33083
33121
  } else if (args.channelId) {
33084
33122
  const channel = chat.channel(args.channelId);
33085
33123
  target = channel;
33086
- const sent = await postChunks(args.adapter, channel, text);
33124
+ const sent = await postChunks(args.adapter, channel, parts);
33087
33125
  result = {
33088
33126
  adapter: args.adapter,
33089
33127
  threadId: sent.threadId ?? channel.id,
@@ -33100,7 +33138,7 @@ async function postChatMessage(args) {
33100
33138
  result.unsentFiles = sent.unsent;
33101
33139
  if (sent.unsent.length > 0) {
33102
33140
  const note = formatUnsentFilesNote(sent.unsent);
33103
- const noted = await postChunks(args.adapter, target, scrubSecrets(note));
33141
+ const noted = await postChunks(args.adapter, target, [scrubSecrets(note)]);
33104
33142
  result.messageIds.push(...noted.messageIds);
33105
33143
  }
33106
33144
  }
@@ -33115,6 +33153,10 @@ async function postChatMessage(args) {
33115
33153
  return result;
33116
33154
  }
33117
33155
 
33156
+ // src/integrations/chat-sdk/reactions.ts
33157
+ init_db3();
33158
+ init_secret_scrubber();
33159
+
33118
33160
  // src/integrations/chat-sdk/router.ts
33119
33161
  init_db3();
33120
33162
 
@@ -33242,6 +33284,63 @@ async function routeChatMessage(text, ctx) {
33242
33284
  return null;
33243
33285
  }
33244
33286
 
33287
+ // src/integrations/chat-sdk/reactions.ts
33288
+ var TELEGRAM_REACTIONS = {
33289
+ accepted: "\uD83D\uDC40",
33290
+ buffered: "\uD83D\uDC40",
33291
+ now: "⚡",
33292
+ steered: "✍",
33293
+ completed: "\uD83D\uDC4D",
33294
+ failed: "\uD83D\uDC4E"
33295
+ };
33296
+ var CHAT_REACTIONS = {
33297
+ telegram: TELEGRAM_REACTIONS
33298
+ };
33299
+ function chatAdapterReacts(adapter) {
33300
+ return adapter in CHAT_REACTIONS;
33301
+ }
33302
+ async function setChatMessageReaction(adapter, threadId, messageId, event) {
33303
+ const emoji = CHAT_REACTIONS[adapter]?.[event];
33304
+ if (!emoji)
33305
+ return;
33306
+ try {
33307
+ const target = getChatInstance(adapter)?.getAdapter(adapter);
33308
+ if (!target)
33309
+ return;
33310
+ assertTrustedChatTarget(threadId);
33311
+ await target.addReaction(threadId, messageId, emoji);
33312
+ } catch (error) {
33313
+ console.warn(scrubSecrets(`[chat-sdk] Could not set the ${event} reaction on ${messageId} in ${threadId}: ${errorMessage(error)}`));
33314
+ }
33315
+ }
33316
+ async function clearChatMessageReactions(adapter, threadId, messageIds) {
33317
+ if (!chatAdapterReacts(adapter) || messageIds.length === 0)
33318
+ return;
33319
+ const target = getChatInstance(adapter)?.getAdapter(adapter);
33320
+ if (!target)
33321
+ return;
33322
+ for (const messageId of messageIds) {
33323
+ try {
33324
+ await target.removeReaction(threadId, messageId, TELEGRAM_REACTIONS.accepted);
33325
+ } catch (error) {
33326
+ console.warn(scrubSecrets(`[chat-sdk] Could not clear the reaction on ${messageId} in ${threadId}: ${errorMessage(error)}`));
33327
+ }
33328
+ }
33329
+ }
33330
+ var CHAT_CHANNEL_SETTINGS_NAMESPACE = "integrations:chat:channel-settings";
33331
+ async function wantsChatTextAck(adapter, channelId) {
33332
+ if (!chatAdapterReacts(adapter))
33333
+ return true;
33334
+ try {
33335
+ const row = await getKv2(CHAT_CHANNEL_SETTINGS_NAMESPACE, chatChannelKey(adapter, channelId));
33336
+ const settings = row?.value;
33337
+ return typeof settings === "object" && settings !== null && settings.textAcks === true;
33338
+ } catch (error) {
33339
+ console.warn(`[chat-sdk] Could not read the channel settings: ${errorMessage(error)}`);
33340
+ return false;
33341
+ }
33342
+ }
33343
+
33245
33344
  // src/integrations/chat-sdk/steering.ts
33246
33345
  init_db3();
33247
33346
  init_steering();
@@ -33435,9 +33534,12 @@ async function handleChatInbound(thread, message, kind) {
33435
33534
  });
33436
33535
  if (steering) {
33437
33536
  console.log(`[chat-sdk] ${adapter} message steered task ${steering.task.id} (${steering.result.outcome})`);
33537
+ await setChatMessageReaction(adapter, thread.id, message.id, "steered");
33538
+ if (!await wantsChatTextAck(adapter, thread.channelId))
33539
+ return;
33438
33540
  try {
33439
33541
  const ack = formatChatSteeringAck(steering.result);
33440
- const sent = await thread.post({ markdown: ack });
33542
+ const sent = thread.adapter.reply ? await thread.reply(message, { markdown: ack }) : await thread.post({ markdown: ack });
33441
33543
  emitChatMessageSent({
33442
33544
  adapter,
33443
33545
  channelId: thread.channelId,
@@ -33454,6 +33556,7 @@ async function handleChatInbound(thread, message, kind) {
33454
33556
  }
33455
33557
  }
33456
33558
  if (text || attachments.length > 0) {
33559
+ const acknowledge = kind !== "subscribed";
33457
33560
  bufferChatMessage(thread.id, {
33458
33561
  messageId: message.id,
33459
33562
  channelId: thread.channelId,
@@ -33463,11 +33566,14 @@ async function handleChatInbound(thread, message, kind) {
33463
33566
  botMentioned: mentioned || facts.replyToBot,
33464
33567
  isDirectMessage,
33465
33568
  addressed,
33569
+ reacted: acknowledge && chatAdapterReacts(adapter),
33466
33570
  facts,
33467
33571
  attachments
33468
33572
  });
33469
- if (kind !== "subscribed")
33573
+ if (acknowledge) {
33470
33574
  startTypingKeepalive(adapter, thread.id);
33575
+ await setChatMessageReaction(adapter, thread.id, message.id, immediate ? "now" : "accepted");
33576
+ }
33471
33577
  }
33472
33578
  if (immediate)
33473
33579
  await instantFlushChat(thread.id);
@@ -33585,6 +33691,8 @@ async function flushChatThread(threadId, items, immediate) {
33585
33691
  const isDirectMessage = items.some((item) => item.isDirectMessage);
33586
33692
  const requester = items.find((item) => item.addressed !== "none") ?? first;
33587
33693
  const otherSenders = new Set(items.map((item) => item.userId)).size - 1;
33694
+ const answered = items.at(-1) ?? first;
33695
+ const reacted = items.filter((item) => item.reacted).map((item) => item.messageId);
33588
33696
  const resetAt = await getChatThreadResetAt(threadId);
33589
33697
  const previousTask = await getLatestTaskByContextKey2(contextKey);
33590
33698
  const mostRecentTask = previousTask && resetAt && new Date(previousTask.createdAt).getTime() <= resetAt.getTime() ? null : previousTask;
@@ -33610,6 +33718,7 @@ async function flushChatThread(threadId, items, immediate) {
33610
33718
  if (routeResult.action === "block") {
33611
33719
  console.info(`[chat-sdk] Extension blocked routing for ${threadId}:`, scrubSecrets(routeResult.reason));
33612
33720
  stopTypingKeepalive(threadId);
33721
+ await clearChatMessageReactions(adapter, threadId, reacted);
33613
33722
  return;
33614
33723
  }
33615
33724
  let target = null;
@@ -33625,10 +33734,12 @@ async function flushChatThread(threadId, items, immediate) {
33625
33734
  if (!target) {
33626
33735
  console.log(`[chat-sdk] ${threadId}: message not addressed to the swarm, ignored`);
33627
33736
  stopTypingKeepalive(threadId);
33737
+ await clearChatMessageReactions(adapter, threadId, reacted);
33628
33738
  return;
33629
33739
  }
33630
33740
  if (target.kind === "workflow") {
33631
33741
  stopTypingKeepalive(threadId);
33742
+ await clearChatMessageReactions(adapter, threadId, reacted);
33632
33743
  try {
33633
33744
  const { runId } = await handleWebhookTrigger(target.workflowId, {
33634
33745
  adapter,
@@ -33695,7 +33806,9 @@ ${combined}` : combined;
33695
33806
  requestedByUserId,
33696
33807
  parentTaskId: mostRecentTask?.id,
33697
33808
  inheritParentRequester: false,
33698
- inheritParentOutputSchema: false
33809
+ inheritParentOutputSchema: false,
33810
+ mentionMessageId: answered.messageId,
33811
+ mentionChannelId: first.channelId
33699
33812
  };
33700
33813
  try {
33701
33814
  const { task, unattached } = await createChatTaskWithFiles(description, options, inbound);
@@ -33713,8 +33826,12 @@ ${combined}` : combined;
33713
33826
  await rememberChatThreadRequester(threadId, requester.userId);
33714
33827
  await subscribe(thread);
33715
33828
  startTypingKeepalive(adapter, threadId);
33829
+ await clearChatMessageReactions(adapter, threadId, reacted.filter((id) => id !== answered.messageId));
33830
+ if (!answered.reacted)
33831
+ await setChatMessageReaction(adapter, threadId, answered.messageId, "accepted");
33716
33832
  } else {
33717
33833
  stopTypingKeepalive(threadId);
33834
+ await clearChatMessageReactions(adapter, threadId, reacted);
33718
33835
  }
33719
33836
  } catch (_catch) {
33720
33837
  var _err = _catch, _hasErr = 1;
@@ -33880,18 +33997,56 @@ async function taskOutputChatFiles(taskId) {
33880
33997
  var RELAY_GIVE_UP_AFTER_MS = 24 * 60 * 60 * 1000;
33881
33998
  var SWEEP_EVERY_N_TICKS = 20;
33882
33999
  var EARLY_TICK_DEBOUNCE_MS = 250;
33883
- function formatChatRelayText(task) {
34000
+ function formatChatTaskTag(task, agentName) {
34001
+ return agentName ? `#${shortId(task)} · ${agentName}` : `#${shortId(task)}`;
34002
+ }
34003
+ function relayHeadAndBody(task, agentName) {
34004
+ const tag = formatChatTaskTag(task, agentName);
33884
34005
  const body = (task.output || task.failureReason || "").trim();
33885
34006
  if (task.status === "failed")
33886
- return body ? `**Task failed.**
33887
-
33888
- ${body}` : "**Task failed.**";
33889
- if (task.status === "cancelled") {
33890
- return body ? `**Task cancelled.**
34007
+ return { head: `${tag}
34008
+ **Task failed.**`, body };
34009
+ if (task.status === "cancelled")
34010
+ return { head: `${tag}
34011
+ **Task cancelled.**`, body };
34012
+ return { head: tag, body: body || "Task completed." };
34013
+ }
34014
+ function formatChatRelayText(task, agentName) {
34015
+ const { head, body } = relayHeadAndBody(task, agentName);
34016
+ return body ? `${head}
33891
34017
 
33892
- ${body}` : "**Task cancelled.**";
34018
+ ${body}` : head;
34019
+ }
34020
+ var TELEGRAM_FOLD_CHARS = 1000;
34021
+ var FOLD_LEAD_MAX_CHARS = 280;
34022
+ var FOLD_MARKUP_CHARS = 80;
34023
+ function formatChatRelayMessages(task, adapter, agentName) {
34024
+ const { head, body } = relayHeadAndBody(task, agentName);
34025
+ if (adapter !== "telegram" || body.length <= TELEGRAM_FOLD_CHARS) {
34026
+ return [formatChatRelayText(task, agentName)];
33893
34027
  }
33894
- return body || "Task completed.";
34028
+ const breakAt = body.indexOf(`
34029
+
34030
+ `);
34031
+ const lead = breakAt > 0 && breakAt <= FOLD_LEAD_MAX_CHARS ? body.slice(0, breakAt) : "";
34032
+ const rest = lead ? body.slice(breakAt).trim() : body;
34033
+ const top = lead ? `${head}
34034
+
34035
+ ${lead}` : head;
34036
+ const room = chatMessageLimit(adapter) - top.length - FOLD_MARKUP_CHARS;
34037
+ const pieces = splitChatMessage(rest, room);
34038
+ return pieces.map((piece, index) => {
34039
+ const label = lead ? "Rest of the answer" : "Full answer";
34040
+ const summary = pieces.length > 1 ? `${label} (${index + 1}/${pieces.length})` : label;
34041
+ const block = `<details><summary>${summary}</summary>
34042
+
34043
+ ${piece}
34044
+
34045
+ </details>`;
34046
+ return index === 0 ? `${top}
34047
+
34048
+ ${block}` : block;
34049
+ });
33895
34050
  }
33896
34051
  async function processPendingChatRelays(now = Date.now(), signal) {
33897
34052
  const retired = await giveUpStaleChatRelays2(now, RELAY_GIVE_UP_AFTER_MS);
@@ -33922,16 +34077,21 @@ async function processPendingChatRelays(now = Date.now(), signal) {
33922
34077
  if (!await markChatRelayAttempted2(task.id, now))
33923
34078
  continue;
33924
34079
  try {
34080
+ const agent = task.agentId ? await getAgentById2(task.agentId) : null;
33925
34081
  await postChatMessage({
33926
34082
  adapter: target.adapter,
33927
34083
  threadId: target.threadId,
33928
- text: formatChatRelayText(task),
34084
+ text: formatChatRelayMessages(task, target.adapter, agent?.name),
33929
34085
  taskId: task.id,
33930
- files: await taskOutputChatFiles(task.id)
34086
+ files: await taskOutputChatFiles(task.id),
34087
+ replyToMessageId: task.mentionMessageId
33931
34088
  });
33932
34089
  stopTypingKeepalive(target.threadId);
33933
34090
  await markChatRelayDelivered2(task.id, now);
33934
34091
  console.log(`[chat-sdk] Relayed ${task.status} task ${task.id} to ${target.adapter}`);
34092
+ if (task.mentionMessageId) {
34093
+ await setChatMessageReaction(target.adapter, target.threadId, task.mentionMessageId, terminalReactionEvent(task.status));
34094
+ }
33935
34095
  } catch (error) {
33936
34096
  const message = errorMessage(error);
33937
34097
  await recordChatRelayError2(task.id, message, now);
@@ -34970,7 +35130,7 @@ async function notifySlack(text) {
34970
35130
  return;
34971
35131
  }
34972
35132
  try {
34973
- const { getSlackApp } = await import("./app-nndcvftq.js");
35133
+ const { getSlackApp } = await import("./app-ft6r6v23.js");
34974
35134
  const app = getSlackApp();
34975
35135
  if (!app) {
34976
35136
  console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
@@ -35041,7 +35201,7 @@ async function deleteJiraWebhook(webhookId) {
35041
35201
  console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
35042
35202
  }
35043
35203
  async function overwriteWebhookIds(next) {
35044
- const { getDbClient } = await import("./db-88wcymxt.js");
35204
+ const { getDbClient } = await import("./db-v5ytg5pw.js");
35045
35205
  await getDbClient().transaction(async (tx) => {
35046
35206
  const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
35047
35207
  if (!row) {
@@ -108436,7 +108596,7 @@ async function reloadGlobalConfigsAndIntegrations() {
108436
108596
  return runWithoutRequestAuth(() => reloadGlobalConfigsAndIntegrationsInner());
108437
108597
  }
108438
108598
  async function reloadGlobalConfigsAndIntegrationsInner() {
108439
- const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-5en23s5z.js");
108599
+ const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-a9nsavhx.js");
108440
108600
  const wasEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
108441
108601
  const updated = await loadGlobalConfigsIntoEnv(true);
108442
108602
  await syncTelemetryEnabled("settings").catch((err) => {
@@ -108452,10 +108612,10 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
108452
108612
  integrations.push("embeddings");
108453
108613
  }
108454
108614
  if (!wasEmbeddingsConfigured && isEmbeddingsConfigured) {
108455
- import("./boot-reembed-r8rhf9h8.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
108615
+ import("./boot-reembed-r3e808ky.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
108456
108616
  console.error("[config-reload] memory backfill failed (non-fatal):", err);
108457
108617
  });
108458
- import("./boot-reembed-vwcj2y5d.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
108618
+ import("./boot-reembed-tgrfy27t.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
108459
108619
  console.error("[config-reload] script backfill failed (non-fatal):", err);
108460
108620
  });
108461
108621
  }
@@ -114166,7 +114326,8 @@ var registerChatReplyTool = (server) => {
114166
114326
  threadId: thread.threadId,
114167
114327
  text,
114168
114328
  taskId: task.id,
114169
- files: resolved.files
114329
+ files: resolved.files,
114330
+ replyToMessageId: task.mentionMessageId
114170
114331
  });
114171
114332
  return toolOk(`Posted to ${thread.adapter} thread ${sent.threadId}.${unsentFilesSummary(sent.unsentFiles)}`, {
114172
114333
  data: {
@@ -116538,6 +116699,7 @@ init_resolver();
116538
116699
  init_types();
116539
116700
  init_env_flag();
116540
116701
  init_task_attachment_links();
116702
+ init_context_key();
116541
116703
  init_templates2();
116542
116704
  var TaskFollowUpModifySchema = CreateTaskOptionsSchema.pick({
116543
116705
  agentId: true,
@@ -116725,6 +116887,7 @@ ${depLines.join(`
116725
116887
  taskType: "follow-up",
116726
116888
  priority: changes.priority,
116727
116889
  parentTaskId: task.id,
116890
+ contextKey: await deferredWorkChatContextKey(task),
116728
116891
  slackChannelId: task.slackChannelId,
116729
116892
  slackThreadTs: task.slackThreadTs,
116730
116893
  slackUserId: task.slackUserId,
@@ -116732,6 +116895,23 @@ ${depLines.join(`
116732
116895
  inheritParentOutputSchema: false
116733
116896
  }, { origin: "followUp" });
116734
116897
  }
116898
+ var MAX_CONTINUATION_HOPS = 32;
116899
+ async function deferredWorkChatContextKey(task) {
116900
+ if (chatThreadOfContextKey(task.contextKey))
116901
+ return;
116902
+ const seen = new Set;
116903
+ let current = task;
116904
+ while (current && !seen.has(current.id) && seen.size < MAX_CONTINUATION_HOPS) {
116905
+ if (chatThreadOfContextKey(current.contextKey))
116906
+ return current.contextKey;
116907
+ const continuation = current.source === "schedule" && current.taskType === "deferred" || current.source === "system" && current.taskType === "resume";
116908
+ if (!continuation || !current.parentTaskId)
116909
+ return;
116910
+ seen.add(current.id);
116911
+ current = await getTaskById2(current.parentTaskId);
116912
+ }
116913
+ return;
116914
+ }
116735
116915
  async function createResumeFollowUp(args) {
116736
116916
  const parent = await getTaskById2(args.parentId);
116737
116917
  if (!parent)
@@ -129793,6 +129973,7 @@ function validateRecurringTiming(merged) {
129793
129973
 
129794
129974
  // src/tools/schedules/patch-schedule.ts
129795
129975
  init_db2();
129976
+ init_rbac();
129796
129977
  init_types();
129797
129978
  var patchScheduleInputSchema = object2({
129798
129979
  key: AssetKeySchema.optional().describe("Move to a logical namespace."),
@@ -129889,6 +130070,14 @@ var registerPatchScheduleTool = (server) => {
129889
130070
  if (!caller) {
129890
130071
  return toolErr("Agent not found.");
129891
130072
  }
130073
+ if (schedule.taskType === "deferred" && !can({
130074
+ principal: { kind: "agent", agentId: caller.id, isLead: caller.isLead },
130075
+ verb: "schedule.deferral.update.any",
130076
+ resource: { kind: "owned", ownerAgentId: schedule.createdByAgentId },
130077
+ source: "mcp"
130078
+ }).allow) {
130079
+ return toolErr(`Schedule "${schedule.name}" defers another agent's task. Only that agent or a lead can change it.`);
130080
+ }
129892
130081
  if (schedule.scheduleType === "one_time" && !schedule.enabled && schedule.lastRunAt) {
129893
130082
  return toolErr(`One-time schedule "${schedule.name}" has already executed. Create a new one instead.`);
129894
130083
  }
@@ -130104,6 +130293,7 @@ init_zod();
130104
130293
  var import_cron_parser4 = __toESM(require_dist2(), 1);
130105
130294
  init_db3();
130106
130295
  init_db2();
130296
+ init_rbac();
130107
130297
  init_types();
130108
130298
  var updateScheduleInputSchema = object2({
130109
130299
  key: AssetKeySchema.optional().describe("Move to a logical namespace."),
@@ -130200,6 +130390,14 @@ var registerUpdateScheduleTool = (server) => {
130200
130390
  if (!caller) {
130201
130391
  return toolErr("Agent not found.");
130202
130392
  }
130393
+ if (schedule.taskType === "deferred" && !can({
130394
+ principal: { kind: "agent", agentId: caller.id, isLead: caller.isLead },
130395
+ verb: "schedule.deferral.update.any",
130396
+ resource: { kind: "owned", ownerAgentId: schedule.createdByAgentId },
130397
+ source: "mcp"
130398
+ }).allow) {
130399
+ return toolErr(`Schedule "${schedule.name}" defers another agent's task. Only that agent or a lead can change it.`);
130400
+ }
130203
130401
  if (schedule.scheduleType === "one_time" && !schedule.enabled && schedule.lastRunAt) {
130204
130402
  return toolErr(`One-time schedule "${schedule.name}" has already executed. Create a new one instead.`);
130205
130403
  }
@@ -133414,23 +133612,6 @@ var registerSlackListChannelsTool = (server) => {
133414
133612
  init_zod();
133415
133613
  init_db3();
133416
133614
  init_rbac();
133417
-
133418
- // src/slack/dm.ts
133419
- function isSlackUserId(id) {
133420
- return /^[UW][A-Z0-9]+$/.test(id);
133421
- }
133422
- async function resolveSlackConversationId(client, channelId) {
133423
- if (!isSlackUserId(channelId))
133424
- return channelId;
133425
- const result = await client.conversations.open({ users: channelId });
133426
- const dmId = result.channel?.id;
133427
- if (!dmId) {
133428
- throw new Error(`conversations.open returned no DM channel for user ${channelId}`);
133429
- }
133430
- return dmId;
133431
- }
133432
-
133433
- // src/tools/slack-post.ts
133434
133615
  var registerSlackPostTool = (server) => {
133435
133616
  createToolRegistrar(server)("slack-post", {
133436
133617
  title: "Post message to Slack channel",