@desplega.ai/agent-swarm 2.5.0 → 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 (160) hide show
  1. package/dist/{acp-adapter-11gp67nr.js → acp-adapter-csh0zz3b.js} +1 -1
  2. package/dist/{actions-8p2kze8j.js → actions-6xx079d1.js} +17 -17
  3. package/dist/{amp-adapter-z4qvhacj.js → amp-adapter-8n6f0hz8.js} +2 -2
  4. package/dist/{app-0qp0a2gk.js → app-ft6r6v23.js} +3 -3
  5. package/dist/{assistant-jedd3ktm.js → assistant-vt2cyfzd.js} +18 -18
  6. package/dist/{boot-reembed-n4wq5dd2.js → boot-reembed-r3e808ky.js} +1 -1
  7. package/dist/{boot-reembed-4xwq5tg0.js → boot-reembed-tgrfy27t.js} +1 -1
  8. package/dist/{boot-scrub-sweep-69h90xcq.js → boot-scrub-sweep-masdwxkm.js} +2 -2
  9. package/dist/{boot-seeds-3vn0m9sg.js → boot-seeds-0n82qc7q.js} +4 -4
  10. package/dist/{claude-adapter-221mvad5.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-8thjsk5e.js → claude-sdk-session-0zrdzyx2.js} +6905 -6855
  13. package/dist/{cli-y9jvxfhk.js → cli-0vgy5wfw.js} +2 -2
  14. package/dist/{cli-bgdtv62r.js → cli-14v1sxxy.js} +6 -6
  15. package/dist/{cli-fy1jyyym.js → cli-15xd0j7w.js} +18 -13
  16. package/dist/{cli-36j4jnk3.js → cli-3e9vs93g.js} +4 -4
  17. package/dist/{cli-5rvg1ddk.js → cli-4qkg9968.js} +3 -3
  18. package/dist/{cli-ba8ne1es.js → cli-4rvr7zfx.js} +10 -0
  19. package/dist/{cli-s4sntwt4.js → cli-6y43v79h.js} +1 -1
  20. package/dist/{cli-z63a269p.js → cli-7ccf7akh.js} +1 -1
  21. package/dist/{cli-0z3vjrpm.js → cli-86zpfje5.js} +116 -5
  22. package/dist/{cli-fes51ya2.js → cli-aaqnqpyw.js} +2 -2
  23. package/dist/{cli-mbfj11fq.js → cli-b1tv22wr.js} +1 -1
  24. package/dist/{cli-ftmq4nvk.js → cli-b63d08rs.js} +1 -1
  25. package/dist/{cli-xt768r5m.js → cli-b6tnjdvx.js} +11 -7
  26. package/dist/{cli-0y6f0ckq.js → cli-bpbcpd8b.js} +1 -1
  27. package/dist/{cli-sy8f9705.js → cli-cf63dnxj.js} +2 -2
  28. package/dist/{cli-fcc5qe3f.js → cli-csh8fnbg.js} +82 -16
  29. package/dist/{cli-x6vf4sad.js → cli-cyfgxnvb.js} +7 -7
  30. package/dist/{cli-9ce2xw98.js → cli-d172svcw.js} +5 -5
  31. package/dist/{cli-we0ra057.js → cli-e91vshb1.js} +41 -6
  32. package/dist/{cli-segs7hx9.js → cli-edtm741g.js} +5 -5
  33. package/dist/{cli-x21dqn18.js → cli-f3pfn4x3.js} +1 -1
  34. package/dist/{cli-nnvjb17s.js → cli-f55b6ky0.js} +1 -1
  35. package/dist/{cli-1pr672hz.js → cli-fgn7yg5r.js} +1 -1
  36. package/dist/{cli-5kzk3472.js → cli-h5d22pfs.js} +287 -78
  37. package/dist/{cli-r25qpaxt.js → cli-ha22h0eg.js} +20 -20
  38. package/dist/{cli-92mqenkc.js → cli-j3dwd4kz.js} +173 -134
  39. package/dist/{cli-j1eghqfm.js → cli-jmcjbjkt.js} +1 -1
  40. package/dist/{cli-179xcyky.js → cli-kcnwn85g.js} +4 -3
  41. package/dist/{cli-rh5smt8t.js → cli-mntxtkhn.js} +12 -2
  42. package/dist/{cli-7g40g8hq.js → cli-n2918sed.js} +9 -9
  43. package/dist/{cli-y4x8ww6s.js → cli-qrjv7t18.js} +1 -1
  44. package/dist/{cli-7bwtc6yx.js → cli-vaxw3bg0.js} +3 -3
  45. package/dist/{cli-4w24f7z3.js → cli-wadzapwb.js} +1 -1
  46. package/dist/{cli-jpxsrxcb.js → cli-xw9q173h.js} +1 -1
  47. package/dist/{cli-xawhpgc9.js → cli-xzge46sj.js} +2 -2
  48. package/dist/{cli-3zwye9sn.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-tcg1q3jk.js → codex-adapter-brh2tcxr.js} +1 -1
  52. package/dist/{codex-session-runner-xfx4wd9x.js → codex-session-runner-0dnj21qs.js} +1 -1
  53. package/dist/{commands-ew83nj70.js → commands-1cnvseqx.js} +2 -2
  54. package/dist/{controller-gnq1k1mf.js → controller-kc7s9xhn.js} +2 -2
  55. package/dist/{controllers-connect-tw1dan9r.js → controllers-connect-jzx7t4bn.js} +18 -18
  56. package/dist/{cursor-adapter-yq5xgfcg.js → cursor-adapter-qpwp5sfg.js} +1 -1
  57. package/dist/{db-t86xrnes.js → db-4vq88jkc.js} +3 -3
  58. package/dist/{db-7gbc53fd.js → db-v5ytg5pw.js} +1 -1
  59. package/dist/{dispatcher-64bdyhps.js → dispatcher-trtcrqae.js} +16 -16
  60. package/dist/{dsh-adapter-tvhc4k2d.js → dsh-adapter-f20xwn1z.js} +1 -1
  61. package/dist/{external-channel-e9nw24zv.js → external-channel-n9bymc2n.js} +2 -2
  62. package/dist/{grok-adapter-v82srhrx.js → grok-adapter-4kpmmnr6.js} +2 -2
  63. package/dist/{handlers-c9ajzhbn.js → handlers-ptsraqa8.js} +19 -19
  64. package/dist/{heartbeat-2vqs1319.js → heartbeat-60qtxtjf.js} +19 -19
  65. package/dist/{hook-01nk13wx.js → hook-ngtvh729.js} +1 -1
  66. package/dist/{hook-jzpheegg.js → hook-rbktcstg.js} +1 -1
  67. package/dist/{http-fc1k6ec8.js → http-z8xy72gp.js} +334 -86
  68. package/dist/{index-zdycv3ja.js → index-06qkmcx6.js} +10 -9
  69. package/dist/{index-07ef7nkm.js → index-1cscynkb.js} +16 -16
  70. package/dist/{index-sepja052.js → index-a9nsavhx.js} +1 -1
  71. package/dist/{index-q3t40ryv.js → index-r70q0xjx.js} +16 -16
  72. package/dist/{index-7yts8n9s.js → index-s193j5fh.js} +19 -19
  73. package/dist/{keepalive-5nh2rhmr.js → keepalive-a9srcphj.js} +3 -3
  74. package/dist/{lead-aayq64jn.js → lead-3devneqy.js} +26 -26
  75. package/dist/{maintenance-hjhzdt3k.js → maintenance-0er16h2y.js} +1 -1
  76. package/dist/{oauth-refresh-sweep-y3n1knmd.js → oauth-refresh-sweep-b65jcyw2.js} +2 -2
  77. package/dist/{onboard-1zq3m7db.js → onboard-wqywz5py.js} +2 -2
  78. package/dist/{otel-impl-h9yyza47.js → otel-impl-vk32s884.js} +1 -1
  79. package/dist/{pricing-refresh-nevhat8h.js → pricing-refresh-t27anv4z.js} +3 -3
  80. package/dist/rbac-roles-452665y0.js +26 -0
  81. package/dist/{rbac-roles-4y6ngvzq.js → rbac-roles-bmcgsxjn.js} +12 -2
  82. package/dist/{render-v2-cfsh13z3.js → render-v2-0ttsk2j4.js} +3 -3
  83. package/dist/{resume-5s2t0dbs.js → resume-a26kvr41.js} +5 -5
  84. package/dist/{session-access-dnbyp3cn.js → session-access-dgh9nkwk.js} +4 -4
  85. package/dist/{setup-1wj1y77j.js → setup-9vc9qahm.js} +1 -1
  86. package/dist/{work-objects-7mg6216g.js → work-objects-vn8nkxwn.js} +19 -19
  87. package/dist/{worker-nwb789mg.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/gitlab/auth.ts +8 -2
  102. package/src/gitlab/handlers.ts +60 -12
  103. package/src/gitlab/index.ts +1 -1
  104. package/src/http/all-routes.ts +1 -0
  105. package/src/http/approval-requests.ts +46 -6
  106. package/src/http/index.ts +2 -0
  107. package/src/http/schedules.ts +26 -0
  108. package/src/http/scripts.ts +2 -2
  109. package/src/http/sessions.ts +93 -2
  110. package/src/http/user-roles.ts +173 -0
  111. package/src/http/users.ts +9 -0
  112. package/src/http/x.ts +2 -2
  113. package/src/integrations/chat-sdk/commands.ts +14 -1
  114. package/src/integrations/chat-sdk/inbound.ts +40 -5
  115. package/src/integrations/chat-sdk/outbound.ts +35 -10
  116. package/src/integrations/chat-sdk/reactions.ts +107 -0
  117. package/src/integrations/chat-sdk/relay.ts +75 -7
  118. package/src/integrations/chat-sdk/thread-buffer.ts +2 -0
  119. package/src/integrations/reaction-events.ts +20 -0
  120. package/src/providers/amp-adapter.ts +1 -1
  121. package/src/rbac/legacy-policy.ts +3 -0
  122. package/src/rbac/permissions.ts +8 -0
  123. package/src/scheduler/schedule-task.ts +44 -3
  124. package/src/scheduler/scheduler.ts +4 -4
  125. package/src/scripts-runtime/loader.ts +8 -1
  126. package/src/slack/ack.ts +2 -1
  127. package/src/slack/reaction-shortcode.ts +4 -7
  128. package/src/tasks/worker-follow-up.ts +30 -0
  129. package/src/tests/approval-requests-notifications.test.ts +189 -0
  130. package/src/tests/chat-sdk-commands.test.ts +12 -0
  131. package/src/tests/chat-sdk-inbound.test.ts +163 -9
  132. package/src/tests/chat-sdk-outbound-files.test.ts +9 -2
  133. package/src/tests/chat-sdk-relay.test.ts +361 -10
  134. package/src/tests/chat-sdk-tools.test.ts +104 -0
  135. package/src/tests/docs-index-footprint.test.js +3 -3
  136. package/src/tests/gitlab-auth.test.ts +13 -5
  137. package/src/tests/gitlab-handlers.test.ts +270 -22
  138. package/src/tests/http-users.test.ts +38 -0
  139. package/src/tests/migration-237-session-inbox-cleanup.test.ts +136 -0
  140. package/src/tests/rbac-engine.test.ts +2 -0
  141. package/src/tests/rbac-roles.test.ts +10 -0
  142. package/src/tests/schedule-http-triage-tools.test.ts +44 -0
  143. package/src/tests/script-api-credential.test.ts +173 -0
  144. package/src/tests/script-connections.test.ts +4 -0
  145. package/src/tests/script-run-config-scope.test.ts +120 -0
  146. package/src/tests/script-run-token.test.ts +75 -0
  147. package/src/tests/scripts-http.test.ts +19 -0
  148. package/src/tests/sessions-tree.test.ts +242 -0
  149. package/src/tests/user-roles-http.test.ts +204 -0
  150. package/src/tests/workflow-hitl-dynamic-questions.test.ts +1 -1
  151. package/src/tools/chat-reply.ts +2 -0
  152. package/src/tools/schedules/patch-schedule.ts +18 -0
  153. package/src/tools/schedules/update-schedule.ts +18 -0
  154. package/src/types.ts +16 -0
  155. package/src/workflows/approval-notifications.ts +214 -0
  156. package/src/workflows/executors/human-in-the-loop.ts +11 -172
  157. package/src/workflows/executors/swarm-script.ts +2 -2
  158. package/templates/schedules/weekly-harness-upgrade-check/content.md +1 -1
  159. package/templates/skills/code-quality/content.md +1 -1
  160. package/dist/rbac-roles-exbg8xb6.js +0 -12
@@ -336,19 +336,19 @@ import {
336
336
  recordInlineScriptRun2,
337
337
  exports_db,
338
338
  init_db3
339
- } from "./cli-fcc5qe3f.js";
339
+ } from "./cli-csh8fnbg.js";
340
340
  import {
341
341
  getUserGrant2,
342
342
  init_rbac_roles
343
- } from "./cli-0z3vjrpm.js";
343
+ } from "./cli-86zpfje5.js";
344
344
  import {
345
345
  ensurePricingSeeded2,
346
346
  ensureRbacSeeded2,
347
347
  ensureModelProfilesSeeded2
348
- } from "./cli-36j4jnk3.js";
348
+ } from "./cli-3e9vs93g.js";
349
349
  import {
350
350
  loadModelsDevCache
351
- } from "./cli-0y6f0ckq.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-y9jvxfhk.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-92mqenkc.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-we0ra057.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-s4sntwt4.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-fy1jyyym.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-ftmq4nvk.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-3zwye9sn.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-9ce2xw98.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-5rvg1ddk.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-xt768r5m.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-179xcyky.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-0qp0a2gk.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-64bdyhps.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;
@@ -30912,7 +30935,9 @@ function getGitLabToken() {
30912
30935
  function getGitLabUrl() {
30913
30936
  return gitlabUrl;
30914
30937
  }
30915
- var GITLAB_BOT_NAME = process.env.GITLAB_BOT_NAME ?? "agent-swarm-bot";
30938
+ function getGitLabBotName() {
30939
+ return process.env.GITLAB_BOT_NAME || "agent-swarm-bot";
30940
+ }
30916
30941
  function resetGitLab() {
30917
30942
  initialized5 = false;
30918
30943
  webhookSecret5 = null;
@@ -31103,10 +31128,26 @@ function isDuplicate5(key) {
31103
31128
  function detectMention4(text) {
31104
31129
  if (!text)
31105
31130
  return false;
31106
- return new RegExp(`@${GITLAB_BOT_NAME}\\b`, "i").test(text);
31131
+ return new RegExp(`@${getGitLabBotName()}\\b`, "i").test(text);
31107
31132
  }
31108
31133
  function extractMentionContext4(text) {
31109
- return text.replace(new RegExp(`@${GITLAB_BOT_NAME}\\b`, "gi"), "").trim();
31134
+ return text.replace(new RegExp(`@${getGitLabBotName()}\\b`, "gi"), "").trim();
31135
+ }
31136
+ var LEGACY_SCOPE = {
31137
+ mr: {
31138
+ taskTypes: new Set(["gitlab-mr", "gitlab-ci"]),
31139
+ eventTypes: new Set(["merge_request", "note_on_mr", "pipeline"])
31140
+ },
31141
+ issue: {
31142
+ taskTypes: new Set(["gitlab-issue"]),
31143
+ eventTypes: new Set(["issue", "note_on_issue"])
31144
+ }
31145
+ };
31146
+ function isScopedTask(task, kind, contextKey) {
31147
+ if (task.contextKey)
31148
+ return task.contextKey === contextKey;
31149
+ const legacy = LEGACY_SCOPE[kind];
31150
+ return task.taskType !== undefined && legacy.taskTypes.has(task.taskType) || task.vcsEventType !== undefined && legacy.eventTypes.has(task.vcsEventType);
31110
31151
  }
31111
31152
  async function findLeadAgent5() {
31112
31153
  const agents = await getAllAgents2();
@@ -31205,11 +31246,16 @@ async function handleMergeRequest(event) {
31205
31246
  }
31206
31247
  case "close":
31207
31248
  case "merge": {
31208
- const existingTask = await findTaskByVcs2(repo, mr.iid, "gitlab");
31209
- if (existingTask) {
31210
- const reason = action === "merge" ? "MR was merged" : "MR was closed";
31211
- console.log(`[GitLab] Cancelling task ${existingTask.id} — ${reason}`);
31212
- await failTask2(existingTask.id, reason);
31249
+ const reason = action === "merge" ? "MR was merged" : "MR was closed";
31250
+ const mrContextKey = gitlabContextKey({
31251
+ projectId: String(project.id),
31252
+ kind: "mr",
31253
+ iid: mr.iid
31254
+ });
31255
+ const tasks = await findActiveTasksByVcs2(repo, mr.iid, "gitlab");
31256
+ for (const task of tasks.filter((t) => isScopedTask(t, "mr", mrContextKey))) {
31257
+ console.log(`[GitLab] Cancelling task ${task.id} — ${reason}`);
31258
+ await failTask2(task.id, reason);
31213
31259
  }
31214
31260
  return { created: false };
31215
31261
  }
@@ -31241,7 +31287,7 @@ async function handleIssue2(event) {
31241
31287
  case "open": {
31242
31288
  const hasMention = detectMention4(issue.description);
31243
31289
  if (!hasMention) {
31244
- const isBotAssigned = event.assignees?.some((a) => a.username.toLowerCase() === GITLAB_BOT_NAME.toLowerCase());
31290
+ const isBotAssigned = event.assignees?.some((a) => a.username.toLowerCase() === getGitLabBotName().toLowerCase());
31245
31291
  if (!isBotAssigned) {
31246
31292
  console.log(`[GitLab] Issue opened without bot mention/assignment, skipping`);
31247
31293
  return { created: false };
@@ -31288,7 +31334,12 @@ async function handleIssue2(event) {
31288
31334
  return { created: true, taskId: task.id };
31289
31335
  }
31290
31336
  case "close": {
31291
- const existingTask = await findTaskByVcs2(repo, issue.iid, "gitlab");
31337
+ const issueContextKey = gitlabContextKey({
31338
+ projectId: String(project.id),
31339
+ kind: "issue",
31340
+ iid: issue.iid
31341
+ });
31342
+ const existingTask = (await findActiveTasksByVcs2(repo, issue.iid, "gitlab")).find((t) => isScopedTask(t, "issue", issueContextKey));
31292
31343
  if (existingTask) {
31293
31344
  console.log(`[GitLab] Cancelling task ${existingTask.id} — issue closed`);
31294
31345
  await failTask2(existingTask.id, "Issue was closed");
@@ -32147,6 +32198,14 @@ function helpText() {
32147
32198
  return ["Commands:", ...CHAT_COMMANDS.map((c) => `/${c.command}: ${c.description}`)].join(`
32148
32199
  `);
32149
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
+ }
32150
32209
  function shortId(task) {
32151
32210
  return task.id.slice(0, 8);
32152
32211
  }
@@ -32192,6 +32251,8 @@ async function runChatCommand(command, threadId, requestedBy) {
32192
32251
  const name = command.replace(/^\//, "").toLowerCase();
32193
32252
  if (name === "help")
32194
32253
  return helpText();
32254
+ if (name === "start")
32255
+ return welcomeText();
32195
32256
  if (!CHAT_COMMANDS.some((c) => c.command === name)) {
32196
32257
  return `Unknown command /${name}.
32197
32258
  ${helpText()}`;
@@ -32903,12 +32964,13 @@ function escapeTelegramHashLines(markdown) {
32903
32964
  }).join(`
32904
32965
  `);
32905
32966
  }
32906
- async function postChunks(adapter, target, text) {
32967
+ async function postChunks(adapter, target, parts, replyFirst) {
32907
32968
  const messageIds = [];
32908
32969
  let threadId;
32909
- for (const chunk of splitChatMessage(text, chatMessageLimit(adapter))) {
32910
- const markdown = adapter === "telegram" ? escapeTelegramHashLines(chunk) : chunk;
32911
- 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);
32912
32974
  messageIds.push(sent.id);
32913
32975
  threadId ??= sent.threadId;
32914
32976
  }
@@ -33038,13 +33100,17 @@ async function postChatMessage(args) {
33038
33100
  const chat = getChatInstance(args.adapter);
33039
33101
  if (!chat)
33040
33102
  throw new ChatAdapterUnavailableError(args.adapter);
33041
- 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
+ `);
33042
33107
  let result;
33043
33108
  let target;
33044
33109
  if (args.threadId) {
33045
33110
  const thread = chat.thread(args.threadId);
33046
33111
  target = thread;
33047
- 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);
33048
33114
  result = {
33049
33115
  adapter: args.adapter,
33050
33116
  threadId: thread.id,
@@ -33055,7 +33121,7 @@ async function postChatMessage(args) {
33055
33121
  } else if (args.channelId) {
33056
33122
  const channel = chat.channel(args.channelId);
33057
33123
  target = channel;
33058
- const sent = await postChunks(args.adapter, channel, text);
33124
+ const sent = await postChunks(args.adapter, channel, parts);
33059
33125
  result = {
33060
33126
  adapter: args.adapter,
33061
33127
  threadId: sent.threadId ?? channel.id,
@@ -33072,7 +33138,7 @@ async function postChatMessage(args) {
33072
33138
  result.unsentFiles = sent.unsent;
33073
33139
  if (sent.unsent.length > 0) {
33074
33140
  const note = formatUnsentFilesNote(sent.unsent);
33075
- const noted = await postChunks(args.adapter, target, scrubSecrets(note));
33141
+ const noted = await postChunks(args.adapter, target, [scrubSecrets(note)]);
33076
33142
  result.messageIds.push(...noted.messageIds);
33077
33143
  }
33078
33144
  }
@@ -33087,6 +33153,10 @@ async function postChatMessage(args) {
33087
33153
  return result;
33088
33154
  }
33089
33155
 
33156
+ // src/integrations/chat-sdk/reactions.ts
33157
+ init_db3();
33158
+ init_secret_scrubber();
33159
+
33090
33160
  // src/integrations/chat-sdk/router.ts
33091
33161
  init_db3();
33092
33162
 
@@ -33214,6 +33284,63 @@ async function routeChatMessage(text, ctx) {
33214
33284
  return null;
33215
33285
  }
33216
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
+
33217
33344
  // src/integrations/chat-sdk/steering.ts
33218
33345
  init_db3();
33219
33346
  init_steering();
@@ -33407,9 +33534,12 @@ async function handleChatInbound(thread, message, kind) {
33407
33534
  });
33408
33535
  if (steering) {
33409
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;
33410
33540
  try {
33411
33541
  const ack = formatChatSteeringAck(steering.result);
33412
- const sent = await thread.post({ markdown: ack });
33542
+ const sent = thread.adapter.reply ? await thread.reply(message, { markdown: ack }) : await thread.post({ markdown: ack });
33413
33543
  emitChatMessageSent({
33414
33544
  adapter,
33415
33545
  channelId: thread.channelId,
@@ -33426,6 +33556,7 @@ async function handleChatInbound(thread, message, kind) {
33426
33556
  }
33427
33557
  }
33428
33558
  if (text || attachments.length > 0) {
33559
+ const acknowledge = kind !== "subscribed";
33429
33560
  bufferChatMessage(thread.id, {
33430
33561
  messageId: message.id,
33431
33562
  channelId: thread.channelId,
@@ -33435,11 +33566,14 @@ async function handleChatInbound(thread, message, kind) {
33435
33566
  botMentioned: mentioned || facts.replyToBot,
33436
33567
  isDirectMessage,
33437
33568
  addressed,
33569
+ reacted: acknowledge && chatAdapterReacts(adapter),
33438
33570
  facts,
33439
33571
  attachments
33440
33572
  });
33441
- if (kind !== "subscribed")
33573
+ if (acknowledge) {
33442
33574
  startTypingKeepalive(adapter, thread.id);
33575
+ await setChatMessageReaction(adapter, thread.id, message.id, immediate ? "now" : "accepted");
33576
+ }
33443
33577
  }
33444
33578
  if (immediate)
33445
33579
  await instantFlushChat(thread.id);
@@ -33557,6 +33691,8 @@ async function flushChatThread(threadId, items, immediate) {
33557
33691
  const isDirectMessage = items.some((item) => item.isDirectMessage);
33558
33692
  const requester = items.find((item) => item.addressed !== "none") ?? first;
33559
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);
33560
33696
  const resetAt = await getChatThreadResetAt(threadId);
33561
33697
  const previousTask = await getLatestTaskByContextKey2(contextKey);
33562
33698
  const mostRecentTask = previousTask && resetAt && new Date(previousTask.createdAt).getTime() <= resetAt.getTime() ? null : previousTask;
@@ -33582,6 +33718,7 @@ async function flushChatThread(threadId, items, immediate) {
33582
33718
  if (routeResult.action === "block") {
33583
33719
  console.info(`[chat-sdk] Extension blocked routing for ${threadId}:`, scrubSecrets(routeResult.reason));
33584
33720
  stopTypingKeepalive(threadId);
33721
+ await clearChatMessageReactions(adapter, threadId, reacted);
33585
33722
  return;
33586
33723
  }
33587
33724
  let target = null;
@@ -33597,10 +33734,12 @@ async function flushChatThread(threadId, items, immediate) {
33597
33734
  if (!target) {
33598
33735
  console.log(`[chat-sdk] ${threadId}: message not addressed to the swarm, ignored`);
33599
33736
  stopTypingKeepalive(threadId);
33737
+ await clearChatMessageReactions(adapter, threadId, reacted);
33600
33738
  return;
33601
33739
  }
33602
33740
  if (target.kind === "workflow") {
33603
33741
  stopTypingKeepalive(threadId);
33742
+ await clearChatMessageReactions(adapter, threadId, reacted);
33604
33743
  try {
33605
33744
  const { runId } = await handleWebhookTrigger(target.workflowId, {
33606
33745
  adapter,
@@ -33667,7 +33806,9 @@ ${combined}` : combined;
33667
33806
  requestedByUserId,
33668
33807
  parentTaskId: mostRecentTask?.id,
33669
33808
  inheritParentRequester: false,
33670
- inheritParentOutputSchema: false
33809
+ inheritParentOutputSchema: false,
33810
+ mentionMessageId: answered.messageId,
33811
+ mentionChannelId: first.channelId
33671
33812
  };
33672
33813
  try {
33673
33814
  const { task, unattached } = await createChatTaskWithFiles(description, options, inbound);
@@ -33685,8 +33826,12 @@ ${combined}` : combined;
33685
33826
  await rememberChatThreadRequester(threadId, requester.userId);
33686
33827
  await subscribe(thread);
33687
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");
33688
33832
  } else {
33689
33833
  stopTypingKeepalive(threadId);
33834
+ await clearChatMessageReactions(adapter, threadId, reacted);
33690
33835
  }
33691
33836
  } catch (_catch) {
33692
33837
  var _err = _catch, _hasErr = 1;
@@ -33852,18 +33997,56 @@ async function taskOutputChatFiles(taskId) {
33852
33997
  var RELAY_GIVE_UP_AFTER_MS = 24 * 60 * 60 * 1000;
33853
33998
  var SWEEP_EVERY_N_TICKS = 20;
33854
33999
  var EARLY_TICK_DEBOUNCE_MS = 250;
33855
- 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);
33856
34005
  const body = (task.output || task.failureReason || "").trim();
33857
34006
  if (task.status === "failed")
33858
- return body ? `**Task failed.**
33859
-
33860
- ${body}` : "**Task failed.**";
33861
- if (task.status === "cancelled") {
33862
- 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}
33863
34017
 
33864
- ${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)];
33865
34027
  }
33866
- 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
+ });
33867
34050
  }
33868
34051
  async function processPendingChatRelays(now = Date.now(), signal) {
33869
34052
  const retired = await giveUpStaleChatRelays2(now, RELAY_GIVE_UP_AFTER_MS);
@@ -33894,16 +34077,21 @@ async function processPendingChatRelays(now = Date.now(), signal) {
33894
34077
  if (!await markChatRelayAttempted2(task.id, now))
33895
34078
  continue;
33896
34079
  try {
34080
+ const agent = task.agentId ? await getAgentById2(task.agentId) : null;
33897
34081
  await postChatMessage({
33898
34082
  adapter: target.adapter,
33899
34083
  threadId: target.threadId,
33900
- text: formatChatRelayText(task),
34084
+ text: formatChatRelayMessages(task, target.adapter, agent?.name),
33901
34085
  taskId: task.id,
33902
- files: await taskOutputChatFiles(task.id)
34086
+ files: await taskOutputChatFiles(task.id),
34087
+ replyToMessageId: task.mentionMessageId
33903
34088
  });
33904
34089
  stopTypingKeepalive(target.threadId);
33905
34090
  await markChatRelayDelivered2(task.id, now);
33906
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
+ }
33907
34095
  } catch (error) {
33908
34096
  const message = errorMessage(error);
33909
34097
  await recordChatRelayError2(task.id, message, now);
@@ -34942,7 +35130,7 @@ async function notifySlack(text) {
34942
35130
  return;
34943
35131
  }
34944
35132
  try {
34945
- const { getSlackApp } = await import("./app-0qp0a2gk.js");
35133
+ const { getSlackApp } = await import("./app-ft6r6v23.js");
34946
35134
  const app = getSlackApp();
34947
35135
  if (!app) {
34948
35136
  console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
@@ -35013,7 +35201,7 @@ async function deleteJiraWebhook(webhookId) {
35013
35201
  console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
35014
35202
  }
35015
35203
  async function overwriteWebhookIds(next) {
35016
- const { getDbClient } = await import("./db-7gbc53fd.js");
35204
+ const { getDbClient } = await import("./db-v5ytg5pw.js");
35017
35205
  await getDbClient().transaction(async (tx) => {
35018
35206
  const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
35019
35207
  if (!row) {
@@ -108408,7 +108596,7 @@ async function reloadGlobalConfigsAndIntegrations() {
108408
108596
  return runWithoutRequestAuth(() => reloadGlobalConfigsAndIntegrationsInner());
108409
108597
  }
108410
108598
  async function reloadGlobalConfigsAndIntegrationsInner() {
108411
- const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-sepja052.js");
108599
+ const { getEmbeddingProvider, resetEmbeddingProvider } = await import("./index-a9nsavhx.js");
108412
108600
  const wasEmbeddingsConfigured = getEmbeddingProvider().isConfigured();
108413
108601
  const updated = await loadGlobalConfigsIntoEnv(true);
108414
108602
  await syncTelemetryEnabled("settings").catch((err) => {
@@ -108424,10 +108612,10 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
108424
108612
  integrations.push("embeddings");
108425
108613
  }
108426
108614
  if (!wasEmbeddingsConfigured && isEmbeddingsConfigured) {
108427
- import("./boot-reembed-n4wq5dd2.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
108615
+ import("./boot-reembed-r3e808ky.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
108428
108616
  console.error("[config-reload] memory backfill failed (non-fatal):", err);
108429
108617
  });
108430
- import("./boot-reembed-4xwq5tg0.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
108618
+ import("./boot-reembed-tgrfy27t.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
108431
108619
  console.error("[config-reload] script backfill failed (non-fatal):", err);
108432
108620
  });
108433
108621
  }
@@ -114138,7 +114326,8 @@ var registerChatReplyTool = (server) => {
114138
114326
  threadId: thread.threadId,
114139
114327
  text,
114140
114328
  taskId: task.id,
114141
- files: resolved.files
114329
+ files: resolved.files,
114330
+ replyToMessageId: task.mentionMessageId
114142
114331
  });
114143
114332
  return toolOk(`Posted to ${thread.adapter} thread ${sent.threadId}.${unsentFilesSummary(sent.unsentFiles)}`, {
114144
114333
  data: {
@@ -116510,6 +116699,7 @@ init_resolver();
116510
116699
  init_types();
116511
116700
  init_env_flag();
116512
116701
  init_task_attachment_links();
116702
+ init_context_key();
116513
116703
  init_templates2();
116514
116704
  var TaskFollowUpModifySchema = CreateTaskOptionsSchema.pick({
116515
116705
  agentId: true,
@@ -116697,6 +116887,7 @@ ${depLines.join(`
116697
116887
  taskType: "follow-up",
116698
116888
  priority: changes.priority,
116699
116889
  parentTaskId: task.id,
116890
+ contextKey: await deferredWorkChatContextKey(task),
116700
116891
  slackChannelId: task.slackChannelId,
116701
116892
  slackThreadTs: task.slackThreadTs,
116702
116893
  slackUserId: task.slackUserId,
@@ -116704,6 +116895,23 @@ ${depLines.join(`
116704
116895
  inheritParentOutputSchema: false
116705
116896
  }, { origin: "followUp" });
116706
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
+ }
116707
116915
  async function createResumeFollowUp(args) {
116708
116916
  const parent = await getTaskById2(args.parentId);
116709
116917
  if (!parent)
@@ -129765,6 +129973,7 @@ function validateRecurringTiming(merged) {
129765
129973
 
129766
129974
  // src/tools/schedules/patch-schedule.ts
129767
129975
  init_db2();
129976
+ init_rbac();
129768
129977
  init_types();
129769
129978
  var patchScheduleInputSchema = object2({
129770
129979
  key: AssetKeySchema.optional().describe("Move to a logical namespace."),
@@ -129861,6 +130070,14 @@ var registerPatchScheduleTool = (server) => {
129861
130070
  if (!caller) {
129862
130071
  return toolErr("Agent not found.");
129863
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
+ }
129864
130081
  if (schedule.scheduleType === "one_time" && !schedule.enabled && schedule.lastRunAt) {
129865
130082
  return toolErr(`One-time schedule "${schedule.name}" has already executed. Create a new one instead.`);
129866
130083
  }
@@ -130076,6 +130293,7 @@ init_zod();
130076
130293
  var import_cron_parser4 = __toESM(require_dist2(), 1);
130077
130294
  init_db3();
130078
130295
  init_db2();
130296
+ init_rbac();
130079
130297
  init_types();
130080
130298
  var updateScheduleInputSchema = object2({
130081
130299
  key: AssetKeySchema.optional().describe("Move to a logical namespace."),
@@ -130172,6 +130390,14 @@ var registerUpdateScheduleTool = (server) => {
130172
130390
  if (!caller) {
130173
130391
  return toolErr("Agent not found.");
130174
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
+ }
130175
130401
  if (schedule.scheduleType === "one_time" && !schedule.enabled && schedule.lastRunAt) {
130176
130402
  return toolErr(`One-time schedule "${schedule.name}" has already executed. Create a new one instead.`);
130177
130403
  }
@@ -133386,23 +133612,6 @@ var registerSlackListChannelsTool = (server) => {
133386
133612
  init_zod();
133387
133613
  init_db3();
133388
133614
  init_rbac();
133389
-
133390
- // src/slack/dm.ts
133391
- function isSlackUserId(id) {
133392
- return /^[UW][A-Z0-9]+$/.test(id);
133393
- }
133394
- async function resolveSlackConversationId(client, channelId) {
133395
- if (!isSlackUserId(channelId))
133396
- return channelId;
133397
- const result = await client.conversations.open({ users: channelId });
133398
- const dmId = result.channel?.id;
133399
- if (!dmId) {
133400
- throw new Error(`conversations.open returned no DM channel for user ${channelId}`);
133401
- }
133402
- return dmId;
133403
- }
133404
-
133405
- // src/tools/slack-post.ts
133406
133615
  var registerSlackPostTool = (server) => {
133407
133616
  createToolRegistrar(server)("slack-post", {
133408
133617
  title: "Post message to Slack channel",