@rudderhq/server 0.2.5-canary.9 → 0.2.5

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 (309) hide show
  1. package/dist/bootstrap/plugin-host-runtime.d.ts +39 -39
  2. package/dist/bundled-plugins/plugin-linear/dist/worker.js +101 -147
  3. package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +2 -2
  4. package/dist/bundled-plugins/plugin-linear/package.json +1 -1
  5. package/dist/routes/access-onboarding.helpers.d.ts +142 -0
  6. package/dist/routes/access-onboarding.helpers.d.ts.map +1 -0
  7. package/dist/routes/access-onboarding.helpers.js +762 -0
  8. package/dist/routes/access-onboarding.helpers.js.map +1 -0
  9. package/dist/routes/access.d.ts +2 -48
  10. package/dist/routes/access.d.ts.map +1 -1
  11. package/dist/routes/access.helpers.d.ts +109 -0
  12. package/dist/routes/access.helpers.d.ts.map +1 -0
  13. package/dist/routes/access.helpers.js +460 -0
  14. package/dist/routes/access.helpers.js.map +1 -0
  15. package/dist/routes/access.js +6 -1218
  16. package/dist/routes/access.js.map +1 -1
  17. package/dist/routes/agents.d.ts.map +1 -1
  18. package/dist/routes/agents.js +55 -1057
  19. package/dist/routes/agents.js.map +1 -1
  20. package/dist/routes/agents.management-routes.d.ts +12 -0
  21. package/dist/routes/agents.management-routes.d.ts.map +1 -0
  22. package/dist/routes/agents.management-routes.js +1067 -0
  23. package/dist/routes/agents.management-routes.js.map +1 -0
  24. package/dist/routes/chats.d.ts.map +1 -1
  25. package/dist/routes/chats.js +42 -652
  26. package/dist/routes/chats.js.map +1 -1
  27. package/dist/routes/chats.stream-routes.d.ts +12 -0
  28. package/dist/routes/chats.stream-routes.d.ts.map +1 -0
  29. package/dist/routes/chats.stream-routes.js +666 -0
  30. package/dist/routes/chats.stream-routes.js.map +1 -0
  31. package/dist/routes/issues.comments-attachments.d.ts +12 -0
  32. package/dist/routes/issues.comments-attachments.d.ts.map +1 -0
  33. package/dist/routes/issues.comments-attachments.js +511 -0
  34. package/dist/routes/issues.comments-attachments.js.map +1 -0
  35. package/dist/routes/issues.d.ts.map +1 -1
  36. package/dist/routes/issues.js +43 -1128
  37. package/dist/routes/issues.js.map +1 -1
  38. package/dist/routes/issues.mutations.d.ts +12 -0
  39. package/dist/routes/issues.mutations.d.ts.map +1 -0
  40. package/dist/routes/issues.mutations.js +635 -0
  41. package/dist/routes/issues.mutations.js.map +1 -0
  42. package/dist/routes/plugins.d.ts.map +1 -1
  43. package/dist/routes/plugins.js +14 -694
  44. package/dist/routes/plugins.js.map +1 -1
  45. package/dist/routes/plugins.operations-routes.d.ts +28 -0
  46. package/dist/routes/plugins.operations-routes.d.ts.map +1 -0
  47. package/dist/routes/plugins.operations-routes.js +720 -0
  48. package/dist/routes/plugins.operations-routes.js.map +1 -0
  49. package/dist/services/access.d.ts +21 -21
  50. package/dist/services/activity.d.ts +19 -19
  51. package/dist/services/agents.d.ts +158 -158
  52. package/dist/services/approvals.d.ts +29 -29
  53. package/dist/services/assets.d.ts +8 -8
  54. package/dist/services/automations.d.ts +41 -27
  55. package/dist/services/automations.d.ts.map +1 -1
  56. package/dist/services/automations.js +287 -110
  57. package/dist/services/automations.js.map +1 -1
  58. package/dist/services/automations.scheduler.d.ts +9 -0
  59. package/dist/services/automations.scheduler.d.ts.map +1 -0
  60. package/dist/services/automations.scheduler.js +101 -0
  61. package/dist/services/automations.scheduler.js.map +1 -0
  62. package/dist/services/board-auth.d.ts +32 -32
  63. package/dist/services/calendar.d.ts +26 -26
  64. package/dist/services/chat-assistant.d.ts +3 -47
  65. package/dist/services/chat-assistant.d.ts.map +1 -1
  66. package/dist/services/chat-assistant.helpers.d.ts +156 -0
  67. package/dist/services/chat-assistant.helpers.d.ts.map +1 -0
  68. package/dist/services/chat-assistant.helpers.js +862 -0
  69. package/dist/services/chat-assistant.helpers.js.map +1 -0
  70. package/dist/services/chat-assistant.js +2 -861
  71. package/dist/services/chat-assistant.js.map +1 -1
  72. package/dist/services/chats.d.ts +149 -247
  73. package/dist/services/chats.d.ts.map +1 -1
  74. package/dist/services/chats.helpers.d.ts +117 -0
  75. package/dist/services/chats.helpers.d.ts.map +1 -0
  76. package/dist/services/chats.helpers.js +285 -0
  77. package/dist/services/chats.helpers.js.map +1 -0
  78. package/dist/services/chats.js +6 -286
  79. package/dist/services/chats.js.map +1 -1
  80. package/dist/services/costs.d.ts +8 -8
  81. package/dist/services/finance.d.ts +18 -18
  82. package/dist/services/goals.d.ts +30 -30
  83. package/dist/services/heartbeat.d.ts +3 -1
  84. package/dist/services/heartbeat.d.ts.map +1 -1
  85. package/dist/services/heartbeat.js +3 -1
  86. package/dist/services/heartbeat.js.map +1 -1
  87. package/dist/services/issue-approvals.d.ts +4 -4
  88. package/dist/services/issue-review-wakeup.d.ts +3 -3
  89. package/dist/services/issues.comments-attachments.d.ts +141 -0
  90. package/dist/services/issues.comments-attachments.d.ts.map +1 -0
  91. package/dist/services/issues.comments-attachments.js +313 -0
  92. package/dist/services/issues.comments-attachments.js.map +1 -0
  93. package/dist/services/issues.d.ts +205 -256
  94. package/dist/services/issues.d.ts.map +1 -1
  95. package/dist/services/issues.helpers.d.ts +87 -0
  96. package/dist/services/issues.helpers.d.ts.map +1 -0
  97. package/dist/services/issues.helpers.js +270 -0
  98. package/dist/services/issues.helpers.js.map +1 -0
  99. package/dist/services/issues.js +5 -569
  100. package/dist/services/issues.js.map +1 -1
  101. package/dist/services/knowledge-portability/organization-portability.core.d.ts +210 -0
  102. package/dist/services/knowledge-portability/organization-portability.core.d.ts.map +1 -0
  103. package/dist/services/knowledge-portability/organization-portability.core.js +997 -0
  104. package/dist/services/knowledge-portability/organization-portability.core.js.map +1 -0
  105. package/dist/services/knowledge-portability/organization-portability.d.ts +6 -28
  106. package/dist/services/knowledge-portability/organization-portability.d.ts.map +1 -1
  107. package/dist/services/knowledge-portability/organization-portability.export.d.ts +24 -0
  108. package/dist/services/knowledge-portability/organization-portability.export.d.ts.map +1 -0
  109. package/dist/services/knowledge-portability/organization-portability.export.js +607 -0
  110. package/dist/services/knowledge-portability/organization-portability.export.js.map +1 -0
  111. package/dist/services/knowledge-portability/organization-portability.files.d.ts +69 -0
  112. package/dist/services/knowledge-portability/organization-portability.files.d.ts.map +1 -0
  113. package/dist/services/knowledge-portability/organization-portability.files.js +597 -0
  114. package/dist/services/knowledge-portability/organization-portability.files.js.map +1 -0
  115. package/dist/services/knowledge-portability/organization-portability.import.d.ts +31 -0
  116. package/dist/services/knowledge-portability/organization-portability.import.d.ts.map +1 -0
  117. package/dist/services/knowledge-portability/organization-portability.import.js +575 -0
  118. package/dist/services/knowledge-portability/organization-portability.import.js.map +1 -0
  119. package/dist/services/knowledge-portability/organization-portability.js +37 -3848
  120. package/dist/services/knowledge-portability/organization-portability.js.map +1 -1
  121. package/dist/services/knowledge-portability/organization-portability.package.d.ts +72 -0
  122. package/dist/services/knowledge-portability/organization-portability.package.d.ts.map +1 -0
  123. package/dist/services/knowledge-portability/organization-portability.package.js +749 -0
  124. package/dist/services/knowledge-portability/organization-portability.package.js.map +1 -0
  125. package/dist/services/knowledge-portability/organization-portability.preview.d.ts +18 -0
  126. package/dist/services/knowledge-portability/organization-portability.preview.d.ts.map +1 -0
  127. package/dist/services/knowledge-portability/organization-portability.preview.js +333 -0
  128. package/dist/services/knowledge-portability/organization-portability.preview.js.map +1 -0
  129. package/dist/services/knowledge-portability/organization-portability.resolve-source.d.ts +4 -0
  130. package/dist/services/knowledge-portability/organization-portability.resolve-source.d.ts.map +1 -0
  131. package/dist/services/knowledge-portability/organization-portability.resolve-source.js +86 -0
  132. package/dist/services/knowledge-portability/organization-portability.resolve-source.js.map +1 -0
  133. package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +221 -0
  134. package/dist/services/knowledge-portability/organization-skills.catalog.d.ts.map +1 -0
  135. package/dist/services/knowledge-portability/organization-skills.catalog.js +999 -0
  136. package/dist/services/knowledge-portability/organization-skills.catalog.js.map +1 -0
  137. package/dist/services/knowledge-portability/organization-skills.d.ts +4 -75
  138. package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -1
  139. package/dist/services/knowledge-portability/organization-skills.js +11 -2008
  140. package/dist/services/knowledge-portability/organization-skills.js.map +1 -1
  141. package/dist/services/knowledge-portability/organization-skills.scans.d.ts +16 -0
  142. package/dist/services/knowledge-portability/organization-skills.scans.d.ts.map +1 -0
  143. package/dist/services/knowledge-portability/organization-skills.scans.js +300 -0
  144. package/dist/services/knowledge-portability/organization-skills.scans.js.map +1 -0
  145. package/dist/services/knowledge-portability/organization-skills.sources.d.ts +68 -0
  146. package/dist/services/knowledge-portability/organization-skills.sources.d.ts.map +1 -0
  147. package/dist/services/knowledge-portability/organization-skills.sources.js +728 -0
  148. package/dist/services/knowledge-portability/organization-skills.sources.js.map +1 -0
  149. package/dist/services/messenger.d.ts +2 -2
  150. package/dist/services/messenger.js +2 -2
  151. package/dist/services/messenger.js.map +1 -1
  152. package/dist/services/organization-skills.d.ts +3 -1
  153. package/dist/services/organization-skills.d.ts.map +1 -1
  154. package/dist/services/organization-skills.js +3 -1
  155. package/dist/services/organization-skills.js.map +1 -1
  156. package/dist/services/orgs.d.ts +9 -9
  157. package/dist/services/plugin-loader.core.d.ts +14 -0
  158. package/dist/services/plugin-loader.core.d.ts.map +1 -0
  159. package/dist/services/plugin-loader.core.js +905 -0
  160. package/dist/services/plugin-loader.core.js.map +1 -0
  161. package/dist/services/plugin-loader.d.ts +3 -440
  162. package/dist/services/plugin-loader.d.ts.map +1 -1
  163. package/dist/services/plugin-loader.helpers.d.ts +468 -0
  164. package/dist/services/plugin-loader.helpers.d.ts.map +1 -0
  165. package/dist/services/plugin-loader.helpers.js +263 -0
  166. package/dist/services/plugin-loader.helpers.js.map +1 -0
  167. package/dist/services/plugin-loader.js +3 -1191
  168. package/dist/services/plugin-loader.js.map +1 -1
  169. package/dist/services/plugin-loader.worker-paths.d.ts +7 -0
  170. package/dist/services/plugin-loader.worker-paths.d.ts.map +1 -0
  171. package/dist/services/plugin-loader.worker-paths.js +85 -0
  172. package/dist/services/plugin-loader.worker-paths.js.map +1 -0
  173. package/dist/services/plugin-registry.d.ts +123 -123
  174. package/dist/services/projects.d.ts +8 -8
  175. package/dist/services/runtime-kernel/heartbeat.core.d.ts +725 -0
  176. package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -0
  177. package/dist/services/runtime-kernel/heartbeat.core.js +525 -0
  178. package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -0
  179. package/dist/services/runtime-kernel/heartbeat.d.ts +38 -259
  180. package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
  181. package/dist/services/runtime-kernel/heartbeat.execute.d.ts +5 -0
  182. package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -0
  183. package/dist/services/runtime-kernel/heartbeat.execute.js +1052 -0
  184. package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -0
  185. package/dist/services/runtime-kernel/heartbeat.js +50 -4142
  186. package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
  187. package/dist/services/runtime-kernel/heartbeat.misc.d.ts +30 -0
  188. package/dist/services/runtime-kernel/heartbeat.misc.d.ts.map +1 -0
  189. package/dist/services/runtime-kernel/heartbeat.misc.js +483 -0
  190. package/dist/services/runtime-kernel/heartbeat.misc.js.map +1 -0
  191. package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +38 -0
  192. package/dist/services/runtime-kernel/heartbeat.recovery.d.ts.map +1 -0
  193. package/dist/services/runtime-kernel/heartbeat.recovery.js +605 -0
  194. package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -0
  195. package/dist/services/runtime-kernel/heartbeat.release.d.ts +6 -0
  196. package/dist/services/runtime-kernel/heartbeat.release.d.ts.map +1 -0
  197. package/dist/services/runtime-kernel/heartbeat.release.js +398 -0
  198. package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -0
  199. package/dist/services/runtime-kernel/heartbeat.sessions.d.ts +229 -0
  200. package/dist/services/runtime-kernel/heartbeat.sessions.d.ts.map +1 -0
  201. package/dist/services/runtime-kernel/heartbeat.sessions.js +708 -0
  202. package/dist/services/runtime-kernel/heartbeat.sessions.js.map +1 -0
  203. package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts +5 -0
  204. package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts.map +1 -0
  205. package/dist/services/runtime-kernel/heartbeat.wakeup.js +552 -0
  206. package/dist/services/runtime-kernel/heartbeat.wakeup.js.map +1 -0
  207. package/dist/services/secrets.d.ts +25 -25
  208. package/dist/services/sidebar-badges.js +1 -1
  209. package/dist/services/sidebar-badges.js.map +1 -1
  210. package/dist/services/workspace-runtime.comments.d.ts +6 -0
  211. package/dist/services/workspace-runtime.comments.d.ts.map +1 -0
  212. package/dist/services/workspace-runtime.comments.js +17 -0
  213. package/dist/services/workspace-runtime.comments.js.map +1 -0
  214. package/dist/services/workspace-runtime.d.ts +4 -163
  215. package/dist/services/workspace-runtime.d.ts.map +1 -1
  216. package/dist/services/workspace-runtime.helpers.d.ts +163 -0
  217. package/dist/services/workspace-runtime.helpers.d.ts.map +1 -0
  218. package/dist/services/workspace-runtime.helpers.js +360 -0
  219. package/dist/services/workspace-runtime.helpers.js.map +1 -0
  220. package/dist/services/workspace-runtime.js +4 -1236
  221. package/dist/services/workspace-runtime.js.map +1 -1
  222. package/dist/services/workspace-runtime.lifecycle.d.ts +35 -0
  223. package/dist/services/workspace-runtime.lifecycle.d.ts.map +1 -0
  224. package/dist/services/workspace-runtime.lifecycle.js +266 -0
  225. package/dist/services/workspace-runtime.lifecycle.js.map +1 -0
  226. package/dist/services/workspace-runtime.services.d.ts +140 -0
  227. package/dist/services/workspace-runtime.services.d.ts.map +1 -0
  228. package/dist/services/workspace-runtime.services.js +606 -0
  229. package/dist/services/workspace-runtime.services.js.map +1 -0
  230. package/package.json +21 -15
  231. package/ui-dist/assets/{_basePickBy-B5mJzzqZ.js → _basePickBy-N8I9ml5Y.js} +1 -1
  232. package/ui-dist/assets/{_baseUniq-B10Ec09o.js → _baseUniq-BuSlpRSQ.js} +1 -1
  233. package/ui-dist/assets/{arc-Bw7wimOa.js → arc-qX-dPyA1.js} +1 -1
  234. package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-DZr0XEvv.js → architectureDiagram-2XIMDMQ5-DhjkbXsp.js} +1 -1
  235. package/ui-dist/assets/{blockDiagram-WCTKOSBZ-D0jl0LgB.js → blockDiagram-WCTKOSBZ-JS-tTu3J.js} +1 -1
  236. package/ui-dist/assets/{c4Diagram-IC4MRINW-BEFxBnEm.js → c4Diagram-IC4MRINW-4DqwCWIx.js} +1 -1
  237. package/ui-dist/assets/channel-CccCW5_a.js +1 -0
  238. package/ui-dist/assets/{chunk-4BX2VUAB-Cbul1GoA.js → chunk-4BX2VUAB-T37SqBpp.js} +1 -1
  239. package/ui-dist/assets/{chunk-55IACEB6-DuouC3bT.js → chunk-55IACEB6-BSj9hdqK.js} +1 -1
  240. package/ui-dist/assets/{chunk-FMBD7UC4-bN1jF9xw.js → chunk-FMBD7UC4-Dkrlh0Wk.js} +1 -1
  241. package/ui-dist/assets/{chunk-JSJVCQXG-B0-Ij6ZF.js → chunk-JSJVCQXG-C0ZE3QdB.js} +1 -1
  242. package/ui-dist/assets/{chunk-KX2RTZJC-BjI3IEjI.js → chunk-KX2RTZJC-DOZQM9gW.js} +1 -1
  243. package/ui-dist/assets/{chunk-NQ4KR5QH-MUoGr46n.js → chunk-NQ4KR5QH-5Yr3U2k8.js} +1 -1
  244. package/ui-dist/assets/{chunk-QZHKN3VN-CQoI9Ouy.js → chunk-QZHKN3VN-CvKTufwF.js} +1 -1
  245. package/ui-dist/assets/{chunk-WL4C6EOR-DSJh3iDp.js → chunk-WL4C6EOR-IoEM0jyx.js} +1 -1
  246. package/ui-dist/assets/classDiagram-VBA2DB6C-JKk4tCW2.js +1 -0
  247. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-JKk4tCW2.js +1 -0
  248. package/ui-dist/assets/clone-Onaweg8D.js +1 -0
  249. package/ui-dist/assets/{cose-bilkent-S5V4N54A-BPepglgB.js → cose-bilkent-S5V4N54A-CTvr1OFj.js} +1 -1
  250. package/ui-dist/assets/{dagre-KLK3FWXG-DhnHVZkt.js → dagre-KLK3FWXG-UZ-SNjVK.js} +1 -1
  251. package/ui-dist/assets/{diagram-E7M64L7V-DNvXtoOO.js → diagram-E7M64L7V-D7RAN0Hr.js} +1 -1
  252. package/ui-dist/assets/{diagram-IFDJBPK2-DhGlDTgn.js → diagram-IFDJBPK2-B4LViaFR.js} +1 -1
  253. package/ui-dist/assets/{diagram-P4PSJMXO-BmXEloWS.js → diagram-P4PSJMXO-CY1be7ak.js} +1 -1
  254. package/ui-dist/assets/{erDiagram-INFDFZHY-BTYVzaLM.js → erDiagram-INFDFZHY-Dca0KkvJ.js} +1 -1
  255. package/ui-dist/assets/{flowDiagram-PKNHOUZH-CqMNQUVv.js → flowDiagram-PKNHOUZH-i-qMvfwg.js} +1 -1
  256. package/ui-dist/assets/{ganttDiagram-A5KZAMGK-B2le_64a.js → ganttDiagram-A5KZAMGK-Wxq2lhbh.js} +1 -1
  257. package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-BtxOBq5A.js → gitGraphDiagram-K3NZZRJ6-DwzgPlAY.js} +1 -1
  258. package/ui-dist/assets/{graph-C5E6qFfm.js → graph-BAqf89Tz.js} +1 -1
  259. package/ui-dist/assets/{index-Piq-IPXt.js → index-4eCzaLuY.js} +1 -1
  260. package/ui-dist/assets/{index-DT6UN2ec.js → index-8uu-nKqK.js} +1 -1
  261. package/ui-dist/assets/{index-T5NVZ3nR.js → index-B-1NEcI_.js} +1 -1
  262. package/ui-dist/assets/{index-D-MoarxG.js → index-B0b_3Eu5.js} +1 -1
  263. package/ui-dist/assets/{index-CZiP3FBQ.js → index-B8v0eZjP.js} +1 -1
  264. package/ui-dist/assets/{index-C1Ga66FM.js → index-BN7Moj3u.js} +1 -1
  265. package/ui-dist/assets/{index-xBUfBdQn.js → index-BSpxh3cY.js} +1 -1
  266. package/ui-dist/assets/{index-CQcMWp51.js → index-BY44RIi9.js} +1 -1
  267. package/ui-dist/assets/{index-3a93sZNI.js → index-BhyQJhdZ.js} +1 -1
  268. package/ui-dist/assets/{index-BsVDit5y.js → index-BkPL_iGU.js} +1 -1
  269. package/ui-dist/assets/{index-88lBSTsW.js → index-BsPfoHXS.js} +1 -1
  270. package/ui-dist/assets/{index-CyJtcUF0.js → index-BstW7nmv.js} +1 -1
  271. package/ui-dist/assets/{index-BvZ0Ptfl.js → index-BwB67Zyz.js} +1 -1
  272. package/ui-dist/assets/index-C2peSkmT.css +1 -0
  273. package/ui-dist/assets/{index-vkCrQLeX.js → index-C3ktOsS_.js} +1 -1
  274. package/ui-dist/assets/{index-D2hZpQJT.js → index-CMyABlS-.js} +1 -1
  275. package/ui-dist/assets/{index-C4WCPEY4.js → index-CyBJ8ujC.js} +1 -1
  276. package/ui-dist/assets/{index-Bf7NB_lK.js → index-DAxM2W3O.js} +1 -1
  277. package/ui-dist/assets/{index-Dq7H6-Lm.js → index-DVZXPmhk.js} +1 -1
  278. package/ui-dist/assets/{index-CskDu6A3.js → index-Dc19uAyw.js} +1 -1
  279. package/ui-dist/assets/index-DzHrwZu1.js +1511 -0
  280. package/ui-dist/assets/{index-B20JneLK.js → index-LJuf53Ye.js} +1 -1
  281. package/ui-dist/assets/{index-D6McTDMQ.js → index-Ugw5VWWz.js} +1 -1
  282. package/ui-dist/assets/{index-CcVGS6HJ.js → index-YGraEFR7.js} +1 -1
  283. package/ui-dist/assets/{infoDiagram-LFFYTUFH-BiCCZcIW.js → infoDiagram-LFFYTUFH-jLmDtFVR.js} +1 -1
  284. package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-BiwBemM5.js → ishikawaDiagram-PHBUUO56-6OGMyLT8.js} +1 -1
  285. package/ui-dist/assets/{journeyDiagram-4ABVD52K-D8RGr2xl.js → journeyDiagram-4ABVD52K-yQjl6E0t.js} +1 -1
  286. package/ui-dist/assets/{kanban-definition-K7BYSVSG-C733Fj-E.js → kanban-definition-K7BYSVSG-DkdCeQlS.js} +1 -1
  287. package/ui-dist/assets/{layout-CM4c3NA_.js → layout-CqSYvZ_w.js} +1 -1
  288. package/ui-dist/assets/{linear-DzH21Xsf.js → linear-B8xGZaoi.js} +1 -1
  289. package/ui-dist/assets/{mermaid.core-Z2rpoVP2.js → mermaid.core-AKL_cdyk.js} +4 -4
  290. package/ui-dist/assets/{mindmap-definition-YRQLILUH-DylLLj9w.js → mindmap-definition-YRQLILUH-Zr-dXC0x.js} +1 -1
  291. package/ui-dist/assets/{pieDiagram-SKSYHLDU-617wI_rr.js → pieDiagram-SKSYHLDU-BvDAU-Nk.js} +1 -1
  292. package/ui-dist/assets/{quadrantDiagram-337W2JSQ-lxoCPJIL.js → quadrantDiagram-337W2JSQ-Dn9kM62o.js} +1 -1
  293. package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-C5XydQ9-.js → requirementDiagram-Z7DCOOCP-GIsIh7Sd.js} +1 -1
  294. package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK--grmq-Q8.js → sankeyDiagram-WA2Y5GQK-CUCuBkuf.js} +1 -1
  295. package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-BS2PeYH-.js → sequenceDiagram-2WXFIKYE-MDpUY2HM.js} +1 -1
  296. package/ui-dist/assets/{stateDiagram-RAJIS63D-CeuZtj2z.js → stateDiagram-RAJIS63D-BymMpuUU.js} +1 -1
  297. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-Bi2oCU6d.js +1 -0
  298. package/ui-dist/assets/{timeline-definition-YZTLITO2-DxHdMpRr.js → timeline-definition-YZTLITO2-B6ofPhhy.js} +1 -1
  299. package/ui-dist/assets/{treemap-KZPCXAKY-Bv1ZlC5h.js → treemap-KZPCXAKY-DnLO6w1l.js} +1 -1
  300. package/ui-dist/assets/{vennDiagram-LZ73GAT5-DvpZSXY2.js → vennDiagram-LZ73GAT5-D0MyZIDl.js} +1 -1
  301. package/ui-dist/assets/{xychartDiagram-JWTSCODW-DttOu1GC.js → xychartDiagram-JWTSCODW-rADY1iUG.js} +1 -1
  302. package/ui-dist/index.html +2 -2
  303. package/ui-dist/assets/channel-DGUh6rEi.js +0 -1
  304. package/ui-dist/assets/classDiagram-VBA2DB6C-1ntk2IOV.js +0 -1
  305. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-1ntk2IOV.js +0 -1
  306. package/ui-dist/assets/clone-BpddY88c.js +0 -1
  307. package/ui-dist/assets/index-C8AD6s7S.js +0 -1510
  308. package/ui-dist/assets/index-Ded0dPwB.css +0 -1
  309. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DXq0yC5C.js +0 -1
@@ -0,0 +1,1067 @@
1
+ import multer from "multer";
2
+ import { randomUUID } from "node:crypto";
3
+ import { agents as agentsTable, organizations, heartbeatRuns } from "@rudderhq/db";
4
+ import { and, desc, eq, inArray, not, sql } from "drizzle-orm";
5
+ import { createAgentKeySchema, createAgentHireSchema, createAgentSchema, upsertAgentInstructionsFileSchema, updateAgentInstructionsBundleSchema, updateAgentPermissionsSchema, updateAgentInstructionsPathSchema, wakeAgentSchema, updateAgentSchema, } from "@rudderhq/shared";
6
+ import { validate } from "../middleware/validate.js";
7
+ import { issueService, logActivity, syncInstructionsBundleConfigFromFilePath, } from "../services/index.js";
8
+ import { normalizeCreatedAgentAvatarIcon } from "../services/agents.js";
9
+ import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
10
+ import { redactEventPayload } from "../redaction.js";
11
+ import { redactCurrentUserValue } from "../log-redaction.js";
12
+ import { MAX_ATTACHMENT_BYTES } from "../attachment-types.js";
13
+ import { runClaudeLogin } from "@rudderhq/agent-runtime-claude-local/server";
14
+ export function registerAgentManagementRoutes(ctx) {
15
+ const { router, db, storage, svc, assets, access, approvalsSvc, budgets, heartbeat, issueApprovalsSvc, secretsSvc, instructions, organizationSkills, workspaceOperations, instanceSettings, avatarUpload, strictSecretsMode, persistReconciledInstructionsBundle, getCurrentUserRedactionOptions, canCreateAgents, buildAgentAccessState, assertCanCreateAgentsForCompany, parseSourceIssueIds, applyCreateDefaultsByAdapterType, resolveDesiredSkillAssignment, assertAdapterConfigConstraints, assertAgentAvatarAssetBelongsToOrg, materializeDefaultInstructionsBundleForNewAgent, applyDefaultAgentTaskAssignGrant, buildAgentDetail, assertCanUpdateAgent, runSingleFileUpload, AGENT_AVATAR_CONTENT_TYPES, compressAgentAvatar, assertCanManageInstructionsPath, asRecord, asNonEmptyString, resolveInstructionsFilePath, assertCanReadAgent, preserveInstructionsBundleConfig, summarizeAgentUpdateDetails, redactAgentConfiguration, stripPersistedSkillSyncConfig, withRuntimeSkillEntries, DEFAULT_INSTRUCTIONS_PATH_KEYS, DEFAULT_MANAGED_INSTRUCTIONS_ADAPTER_TYPES, KNOWN_INSTRUCTIONS_PATH_KEYS, KNOWN_INSTRUCTIONS_BUNDLE_KEYS, } = ctx;
16
+ router.post("/orgs/:orgId/agent-hires", validate(createAgentHireSchema), async (req, res) => {
17
+ const orgId = req.params.orgId;
18
+ await assertCanCreateAgentsForCompany(req, orgId);
19
+ const sourceIssueIds = parseSourceIssueIds(req.body);
20
+ const { desiredSkills: requestedDesiredSkills, sourceIssueId: _sourceIssueId, sourceIssueIds: _sourceIssueIds, ...hireInput } = req.body;
21
+ const requestedAdapterConfig = applyCreateDefaultsByAdapterType(hireInput.agentRuntimeType, (hireInput.agentRuntimeConfig ?? {}));
22
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(orgId, stripPersistedSkillSyncConfig(requestedAdapterConfig), { strictMode: strictSecretsMode });
23
+ const { config: runtimeAdapterConfig } = await secretsSvc.resolveAdapterConfigForRuntime(orgId, normalizedAdapterConfig);
24
+ const desiredSkillAssignment = await resolveDesiredSkillAssignment(orgId, hireInput.agentRuntimeType, runtimeAdapterConfig, Array.isArray(requestedDesiredSkills) ? requestedDesiredSkills : undefined);
25
+ await assertAdapterConfigConstraints(orgId, hireInput.agentRuntimeType, normalizedAdapterConfig);
26
+ const normalizedHireInput = {
27
+ ...hireInput,
28
+ icon: normalizeCreatedAgentAvatarIcon(hireInput.icon),
29
+ agentRuntimeConfig: normalizedAdapterConfig,
30
+ };
31
+ await assertAgentAvatarAssetBelongsToOrg(orgId, normalizedHireInput.icon);
32
+ const organization = await db
33
+ .select()
34
+ .from(organizations)
35
+ .where(eq(organizations.id, orgId))
36
+ .then((rows) => rows[0] ?? null);
37
+ if (!organization) {
38
+ res.status(404).json({ error: "Organization not found" });
39
+ return;
40
+ }
41
+ const requiresApproval = organization.requireBoardApprovalForNewAgents;
42
+ const status = requiresApproval ? "pending_approval" : "idle";
43
+ const createdAgent = await svc.create(orgId, {
44
+ ...normalizedHireInput,
45
+ status,
46
+ spentMonthlyCents: 0,
47
+ lastHeartbeatAt: null,
48
+ });
49
+ await organizationSkills.replaceEnabledSkillKeysForAgent(orgId, createdAgent.id, desiredSkillAssignment.desiredSkills);
50
+ const agent = await materializeDefaultInstructionsBundleForNewAgent(createdAgent);
51
+ let approval = null;
52
+ const actor = getActorInfo(req);
53
+ if (requiresApproval) {
54
+ const requestedAdapterType = normalizedHireInput.agentRuntimeType ?? agent.agentRuntimeType;
55
+ const requestedAdapterConfig = redactEventPayload((agent.agentRuntimeConfig ?? normalizedHireInput.agentRuntimeConfig)) ?? {};
56
+ const requestedRuntimeConfig = redactEventPayload((normalizedHireInput.runtimeConfig ?? agent.runtimeConfig)) ?? {};
57
+ const requestedMetadata = redactEventPayload((normalizedHireInput.metadata ?? agent.metadata ?? {})) ?? {};
58
+ approval = await approvalsSvc.create(orgId, {
59
+ type: "hire_agent",
60
+ requestedByAgentId: actor.actorType === "agent" ? actor.actorId : null,
61
+ requestedByUserId: actor.actorType === "user" ? actor.actorId : null,
62
+ status: "pending",
63
+ payload: {
64
+ name: agent.name,
65
+ role: normalizedHireInput.role,
66
+ title: normalizedHireInput.title ?? null,
67
+ icon: agent.icon ?? normalizedHireInput.icon ?? null,
68
+ reportsTo: normalizedHireInput.reportsTo ?? null,
69
+ capabilities: normalizedHireInput.capabilities ?? null,
70
+ agentRuntimeType: requestedAdapterType,
71
+ agentRuntimeConfig: requestedAdapterConfig,
72
+ runtimeConfig: requestedRuntimeConfig,
73
+ budgetMonthlyCents: typeof normalizedHireInput.budgetMonthlyCents === "number"
74
+ ? normalizedHireInput.budgetMonthlyCents
75
+ : agent.budgetMonthlyCents,
76
+ desiredSkills: desiredSkillAssignment.desiredSkills,
77
+ metadata: requestedMetadata,
78
+ agentId: agent.id,
79
+ requestedByAgentId: actor.actorType === "agent" ? actor.actorId : null,
80
+ requestedConfigurationSnapshot: {
81
+ agentRuntimeType: requestedAdapterType,
82
+ agentRuntimeConfig: requestedAdapterConfig,
83
+ runtimeConfig: requestedRuntimeConfig,
84
+ desiredSkills: desiredSkillAssignment.desiredSkills,
85
+ },
86
+ },
87
+ decisionNote: null,
88
+ decidedByUserId: null,
89
+ decidedAt: null,
90
+ updatedAt: new Date(),
91
+ });
92
+ if (sourceIssueIds.length > 0) {
93
+ const links = await issueApprovalsSvc.linkManyForApproval(approval.id, sourceIssueIds, {
94
+ agentId: actor.actorType === "agent" ? actor.actorId : null,
95
+ userId: actor.actorType === "user" ? actor.actorId : null,
96
+ });
97
+ for (const link of links) {
98
+ await logActivity(db, {
99
+ orgId,
100
+ actorType: actor.actorType,
101
+ actorId: actor.actorId,
102
+ agentId: actor.agentId,
103
+ runId: actor.runId,
104
+ action: "issue.approval_linked",
105
+ entityType: "issue",
106
+ entityId: link.issueId,
107
+ details: {
108
+ approvalId: approval.id,
109
+ linkCreatedAt: link.createdAt.toISOString(),
110
+ },
111
+ });
112
+ }
113
+ }
114
+ }
115
+ await logActivity(db, {
116
+ orgId,
117
+ actorType: actor.actorType,
118
+ actorId: actor.actorId,
119
+ agentId: actor.agentId,
120
+ runId: actor.runId,
121
+ action: "agent.hire_created",
122
+ entityType: "agent",
123
+ entityId: agent.id,
124
+ details: {
125
+ name: agent.name,
126
+ role: agent.role,
127
+ requiresApproval,
128
+ approvalId: approval?.id ?? null,
129
+ issueIds: sourceIssueIds,
130
+ desiredSkills: desiredSkillAssignment.desiredSkills,
131
+ },
132
+ });
133
+ await applyDefaultAgentTaskAssignGrant(orgId, agent.id, actor.actorType === "user" ? actor.actorId : null);
134
+ if (approval) {
135
+ await logActivity(db, {
136
+ orgId,
137
+ actorType: actor.actorType,
138
+ actorId: actor.actorId,
139
+ agentId: actor.agentId,
140
+ runId: actor.runId,
141
+ action: "approval.created",
142
+ entityType: "approval",
143
+ entityId: approval.id,
144
+ details: { type: approval.type, linkedAgentId: agent.id },
145
+ });
146
+ }
147
+ res.status(201).json({ agent, approval });
148
+ });
149
+ router.post("/orgs/:orgId/agents", validate(createAgentSchema), async (req, res) => {
150
+ const orgId = req.params.orgId;
151
+ assertCompanyAccess(req, orgId);
152
+ if (req.actor.type === "agent") {
153
+ assertBoard(req);
154
+ }
155
+ const { desiredSkills: requestedDesiredSkills, ...createInput } = req.body;
156
+ const requestedAdapterConfig = applyCreateDefaultsByAdapterType(createInput.agentRuntimeType, (createInput.agentRuntimeConfig ?? {}));
157
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(orgId, stripPersistedSkillSyncConfig(requestedAdapterConfig), { strictMode: strictSecretsMode });
158
+ const { config: runtimeAdapterConfig } = await secretsSvc.resolveAdapterConfigForRuntime(orgId, normalizedAdapterConfig);
159
+ const desiredSkillAssignment = await resolveDesiredSkillAssignment(orgId, createInput.agentRuntimeType, runtimeAdapterConfig, Array.isArray(requestedDesiredSkills) ? requestedDesiredSkills : undefined);
160
+ await assertAdapterConfigConstraints(orgId, createInput.agentRuntimeType, normalizedAdapterConfig);
161
+ await assertAgentAvatarAssetBelongsToOrg(orgId, createInput.icon);
162
+ const createdAgent = await svc.create(orgId, {
163
+ ...createInput,
164
+ icon: normalizeCreatedAgentAvatarIcon(createInput.icon),
165
+ agentRuntimeConfig: normalizedAdapterConfig,
166
+ status: "idle",
167
+ spentMonthlyCents: 0,
168
+ lastHeartbeatAt: null,
169
+ });
170
+ await organizationSkills.replaceEnabledSkillKeysForAgent(orgId, createdAgent.id, desiredSkillAssignment.desiredSkills);
171
+ const agent = await materializeDefaultInstructionsBundleForNewAgent(createdAgent);
172
+ const actor = getActorInfo(req);
173
+ await logActivity(db, {
174
+ orgId,
175
+ actorType: actor.actorType,
176
+ actorId: actor.actorId,
177
+ agentId: actor.agentId,
178
+ runId: actor.runId,
179
+ action: "agent.created",
180
+ entityType: "agent",
181
+ entityId: agent.id,
182
+ details: {
183
+ name: agent.name,
184
+ role: agent.role,
185
+ desiredSkills: desiredSkillAssignment.desiredSkills,
186
+ },
187
+ });
188
+ await applyDefaultAgentTaskAssignGrant(orgId, agent.id, req.actor.type === "board" ? (req.actor.userId ?? null) : null);
189
+ if (agent.budgetMonthlyCents > 0) {
190
+ await budgets.upsertPolicy(orgId, {
191
+ scopeType: "agent",
192
+ scopeId: agent.id,
193
+ amount: agent.budgetMonthlyCents,
194
+ windowKind: "calendar_month_utc",
195
+ }, actor.actorType === "user" ? actor.actorId : null);
196
+ }
197
+ res.status(201).json(agent);
198
+ });
199
+ router.patch("/agents/:id/permissions", validate(updateAgentPermissionsSchema), async (req, res) => {
200
+ const id = req.params.id;
201
+ const existing = await svc.getById(id);
202
+ if (!existing) {
203
+ res.status(404).json({ error: "Agent not found" });
204
+ return;
205
+ }
206
+ assertCompanyAccess(req, existing.orgId);
207
+ if (req.actor.type === "agent") {
208
+ const actorAgent = req.actor.agentId ? await svc.getById(req.actor.agentId) : null;
209
+ if (!actorAgent || actorAgent.orgId !== existing.orgId) {
210
+ res.status(403).json({ error: "Forbidden" });
211
+ return;
212
+ }
213
+ if (actorAgent.role !== "ceo") {
214
+ res.status(403).json({ error: "Only CEO can manage permissions" });
215
+ return;
216
+ }
217
+ }
218
+ const agent = await svc.updatePermissions(id, req.body);
219
+ if (!agent) {
220
+ res.status(404).json({ error: "Agent not found" });
221
+ return;
222
+ }
223
+ const effectiveCanAssignTasks = agent.role === "ceo" || Boolean(agent.permissions?.canCreateAgents) || req.body.canAssignTasks;
224
+ await access.ensureMembership(agent.orgId, "agent", agent.id, "member", "active");
225
+ await access.setPrincipalPermission(agent.orgId, "agent", agent.id, "tasks:assign", effectiveCanAssignTasks, req.actor.type === "board" ? (req.actor.userId ?? null) : null);
226
+ const actor = getActorInfo(req);
227
+ await logActivity(db, {
228
+ orgId: agent.orgId,
229
+ actorType: actor.actorType,
230
+ actorId: actor.actorId,
231
+ agentId: actor.agentId,
232
+ runId: actor.runId,
233
+ action: "agent.permissions_updated",
234
+ entityType: "agent",
235
+ entityId: agent.id,
236
+ details: {
237
+ canCreateAgents: agent.permissions?.canCreateAgents ?? false,
238
+ canAssignTasks: effectiveCanAssignTasks,
239
+ },
240
+ });
241
+ res.json(await buildAgentDetail(agent));
242
+ });
243
+ router.post("/agents/:id/avatar", async (req, res) => {
244
+ if (!storage) {
245
+ res.status(500).json({ error: "Storage service unavailable" });
246
+ return;
247
+ }
248
+ const id = req.params.id;
249
+ const existing = await svc.getById(id);
250
+ if (!existing) {
251
+ res.status(404).json({ error: "Agent not found" });
252
+ return;
253
+ }
254
+ await assertCanUpdateAgent(req, existing);
255
+ try {
256
+ await runSingleFileUpload(avatarUpload, req, res);
257
+ }
258
+ catch (err) {
259
+ if (err instanceof multer.MulterError) {
260
+ if (err.code === "LIMIT_FILE_SIZE") {
261
+ res.status(422).json({ error: `Image exceeds ${MAX_ATTACHMENT_BYTES} bytes` });
262
+ return;
263
+ }
264
+ res.status(400).json({ error: err.message });
265
+ return;
266
+ }
267
+ throw err;
268
+ }
269
+ const file = req.file;
270
+ if (!file) {
271
+ res.status(400).json({ error: "Missing file field 'file'" });
272
+ return;
273
+ }
274
+ const inputContentType = (file.mimetype || "").toLowerCase();
275
+ if (!AGENT_AVATAR_CONTENT_TYPES.has(inputContentType)) {
276
+ res.status(422).json({ error: `Unsupported avatar image type: ${inputContentType || "unknown"}` });
277
+ return;
278
+ }
279
+ const compressed = await compressAgentAvatar(file);
280
+ const actor = getActorInfo(req);
281
+ const stored = await storage.putFile({
282
+ orgId: existing.orgId,
283
+ namespace: `assets/agents/${existing.id}/avatars`,
284
+ originalFilename: file.originalname || "avatar.webp",
285
+ contentType: "image/webp",
286
+ body: compressed,
287
+ });
288
+ const asset = await assets.create(existing.orgId, {
289
+ provider: stored.provider,
290
+ objectKey: stored.objectKey,
291
+ contentType: stored.contentType,
292
+ byteSize: stored.byteSize,
293
+ sha256: stored.sha256,
294
+ originalFilename: stored.originalFilename,
295
+ createdByAgentId: actor.agentId,
296
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
297
+ });
298
+ const avatarIcon = `asset:${asset.id}`;
299
+ const agent = await svc.update(existing.id, { icon: avatarIcon });
300
+ if (!agent) {
301
+ res.status(404).json({ error: "Agent not found" });
302
+ return;
303
+ }
304
+ await logActivity(db, {
305
+ orgId: agent.orgId,
306
+ actorType: actor.actorType,
307
+ actorId: actor.actorId,
308
+ agentId: actor.agentId,
309
+ runId: actor.runId,
310
+ action: "agent.avatar_updated",
311
+ entityType: "agent",
312
+ entityId: agent.id,
313
+ details: {
314
+ assetId: asset.id,
315
+ contentType: asset.contentType,
316
+ byteSize: asset.byteSize,
317
+ originalFilename: asset.originalFilename,
318
+ },
319
+ });
320
+ res.status(201).json(agent);
321
+ });
322
+ router.patch("/agents/:id/instructions-path", validate(updateAgentInstructionsPathSchema), async (req, res) => {
323
+ const id = req.params.id;
324
+ const existing = await svc.getInternalById(id);
325
+ if (!existing) {
326
+ res.status(404).json({ error: "Agent not found" });
327
+ return;
328
+ }
329
+ await assertCanManageInstructionsPath(req, existing);
330
+ const existingAdapterConfig = asRecord(existing.agentRuntimeConfig) ?? {};
331
+ const explicitKey = asNonEmptyString(req.body.agentRuntimeConfigKey);
332
+ const defaultKey = DEFAULT_INSTRUCTIONS_PATH_KEYS[existing.agentRuntimeType] ?? null;
333
+ const agentRuntimeConfigKey = explicitKey ?? defaultKey;
334
+ if (!agentRuntimeConfigKey) {
335
+ res.status(422).json({
336
+ error: `No default instructions path key for adapter type '${existing.agentRuntimeType}'. Provide agentRuntimeConfigKey.`,
337
+ });
338
+ return;
339
+ }
340
+ const nextAdapterConfig = { ...existingAdapterConfig };
341
+ if (req.body.path === null) {
342
+ delete nextAdapterConfig[agentRuntimeConfigKey];
343
+ }
344
+ else {
345
+ nextAdapterConfig[agentRuntimeConfigKey] = resolveInstructionsFilePath(req.body.path, existingAdapterConfig);
346
+ }
347
+ const syncedAdapterConfig = syncInstructionsBundleConfigFromFilePath(existing, nextAdapterConfig);
348
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, syncedAdapterConfig, { strictMode: strictSecretsMode });
349
+ const actor = getActorInfo(req);
350
+ const agent = await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
351
+ recordRevision: {
352
+ createdByAgentId: actor.agentId,
353
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
354
+ source: "instructions_path_patch",
355
+ },
356
+ });
357
+ if (!agent) {
358
+ res.status(404).json({ error: "Agent not found" });
359
+ return;
360
+ }
361
+ const updatedAdapterConfig = asRecord(agent.agentRuntimeConfig) ?? {};
362
+ const pathValue = asNonEmptyString(updatedAdapterConfig[agentRuntimeConfigKey]);
363
+ await logActivity(db, {
364
+ orgId: agent.orgId,
365
+ actorType: actor.actorType,
366
+ actorId: actor.actorId,
367
+ agentId: actor.agentId,
368
+ runId: actor.runId,
369
+ action: "agent.instructions_path_updated",
370
+ entityType: "agent",
371
+ entityId: agent.id,
372
+ details: {
373
+ agentRuntimeConfigKey,
374
+ path: pathValue,
375
+ cleared: req.body.path === null,
376
+ },
377
+ });
378
+ res.json({
379
+ agentId: agent.id,
380
+ agentRuntimeType: agent.agentRuntimeType,
381
+ agentRuntimeConfigKey,
382
+ path: pathValue,
383
+ });
384
+ });
385
+ router.get("/agents/:id/instructions-bundle", async (req, res) => {
386
+ const id = req.params.id;
387
+ const existing = await svc.getInternalById(id);
388
+ if (!existing) {
389
+ res.status(404).json({ error: "Agent not found" });
390
+ return;
391
+ }
392
+ await assertCanReadAgent(req, existing);
393
+ const result = await instructions.reconcileBundle(existing);
394
+ await persistReconciledInstructionsBundle(existing, result);
395
+ res.json(result.bundle);
396
+ });
397
+ router.patch("/agents/:id/instructions-bundle", validate(updateAgentInstructionsBundleSchema), async (req, res) => {
398
+ const id = req.params.id;
399
+ const existing = await svc.getInternalById(id);
400
+ if (!existing) {
401
+ res.status(404).json({ error: "Agent not found" });
402
+ return;
403
+ }
404
+ await assertCanManageInstructionsPath(req, existing);
405
+ const actor = getActorInfo(req);
406
+ const { bundle, agentRuntimeConfig } = await instructions.updateBundle(existing, req.body);
407
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, agentRuntimeConfig, { strictMode: strictSecretsMode });
408
+ await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
409
+ recordRevision: {
410
+ createdByAgentId: actor.agentId,
411
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
412
+ source: "instructions_bundle_patch",
413
+ },
414
+ });
415
+ await logActivity(db, {
416
+ orgId: existing.orgId,
417
+ actorType: actor.actorType,
418
+ actorId: actor.actorId,
419
+ agentId: actor.agentId,
420
+ runId: actor.runId,
421
+ action: "agent.instructions_bundle_updated",
422
+ entityType: "agent",
423
+ entityId: existing.id,
424
+ details: {
425
+ mode: bundle.mode,
426
+ rootPath: bundle.rootPath,
427
+ entryFile: bundle.entryFile,
428
+ clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate === true,
429
+ },
430
+ });
431
+ res.json(bundle);
432
+ });
433
+ router.get("/agents/:id/instructions-bundle/file", async (req, res) => {
434
+ const id = req.params.id;
435
+ const existing = await svc.getInternalById(id);
436
+ if (!existing) {
437
+ res.status(404).json({ error: "Agent not found" });
438
+ return;
439
+ }
440
+ await assertCanReadAgent(req, existing);
441
+ const relativePath = typeof req.query.path === "string" ? req.query.path : "";
442
+ if (!relativePath.trim()) {
443
+ res.status(422).json({ error: "Query parameter 'path' is required" });
444
+ return;
445
+ }
446
+ const result = await instructions.reconcileBundle(existing);
447
+ const effectiveAgent = await persistReconciledInstructionsBundle(existing, result);
448
+ res.json(await instructions.readFile(effectiveAgent, relativePath));
449
+ });
450
+ router.put("/agents/:id/instructions-bundle/file", validate(upsertAgentInstructionsFileSchema), async (req, res) => {
451
+ const id = req.params.id;
452
+ const existing = await svc.getInternalById(id);
453
+ if (!existing) {
454
+ res.status(404).json({ error: "Agent not found" });
455
+ return;
456
+ }
457
+ await assertCanManageInstructionsPath(req, existing);
458
+ const actor = getActorInfo(req);
459
+ const result = await instructions.writeFile(existing, req.body.path, req.body.content, {
460
+ clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate,
461
+ });
462
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, result.agentRuntimeConfig, { strictMode: strictSecretsMode });
463
+ await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
464
+ recordRevision: {
465
+ createdByAgentId: actor.agentId,
466
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
467
+ source: "instructions_bundle_file_put",
468
+ },
469
+ });
470
+ await logActivity(db, {
471
+ orgId: existing.orgId,
472
+ actorType: actor.actorType,
473
+ actorId: actor.actorId,
474
+ agentId: actor.agentId,
475
+ runId: actor.runId,
476
+ action: "agent.instructions_file_updated",
477
+ entityType: "agent",
478
+ entityId: existing.id,
479
+ details: {
480
+ path: result.file.path,
481
+ size: result.file.size,
482
+ clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate === true,
483
+ },
484
+ });
485
+ res.json(result.file);
486
+ });
487
+ router.delete("/agents/:id/instructions-bundle/file", async (req, res) => {
488
+ const id = req.params.id;
489
+ const existing = await svc.getInternalById(id);
490
+ if (!existing) {
491
+ res.status(404).json({ error: "Agent not found" });
492
+ return;
493
+ }
494
+ await assertCanManageInstructionsPath(req, existing);
495
+ const relativePath = typeof req.query.path === "string" ? req.query.path : "";
496
+ if (!relativePath.trim()) {
497
+ res.status(422).json({ error: "Query parameter 'path' is required" });
498
+ return;
499
+ }
500
+ const actor = getActorInfo(req);
501
+ const result = await instructions.deleteFile(existing, relativePath);
502
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, result.agentRuntimeConfig, { strictMode: strictSecretsMode });
503
+ await svc.update(id, { agentRuntimeConfig: normalizedAdapterConfig }, {
504
+ recordRevision: {
505
+ createdByAgentId: actor.agentId,
506
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
507
+ source: "instructions_bundle_file_delete",
508
+ },
509
+ });
510
+ await logActivity(db, {
511
+ orgId: existing.orgId,
512
+ actorType: actor.actorType,
513
+ actorId: actor.actorId,
514
+ agentId: actor.agentId,
515
+ runId: actor.runId,
516
+ action: "agent.instructions_file_deleted",
517
+ entityType: "agent",
518
+ entityId: existing.id,
519
+ details: {
520
+ path: relativePath,
521
+ },
522
+ });
523
+ res.json(result.bundle);
524
+ });
525
+ router.patch("/agents/:id", validate(updateAgentSchema), async (req, res) => {
526
+ const id = req.params.id;
527
+ const existing = await svc.getInternalById(id);
528
+ if (!existing) {
529
+ res.status(404).json({ error: "Agent not found" });
530
+ return;
531
+ }
532
+ await assertCanUpdateAgent(req, existing);
533
+ if (Object.prototype.hasOwnProperty.call(req.body, "permissions")) {
534
+ res.status(422).json({ error: "Use /api/agents/:id/permissions for permission changes" });
535
+ return;
536
+ }
537
+ const patchData = { ...req.body };
538
+ const replaceAgentRuntimeConfig = patchData.replaceAgentRuntimeConfig === true;
539
+ delete patchData.replaceAgentRuntimeConfig;
540
+ if (Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeConfig")) {
541
+ const agentRuntimeConfig = asRecord(patchData.agentRuntimeConfig);
542
+ if (!agentRuntimeConfig) {
543
+ res.status(422).json({ error: "agentRuntimeConfig must be an object" });
544
+ return;
545
+ }
546
+ const changingInstructionsPath = Object.keys(agentRuntimeConfig).some((key) => KNOWN_INSTRUCTIONS_PATH_KEYS.has(key));
547
+ if (changingInstructionsPath) {
548
+ await assertCanManageInstructionsPath(req, existing);
549
+ }
550
+ patchData.agentRuntimeConfig = agentRuntimeConfig;
551
+ }
552
+ const requestedAdapterType = typeof patchData.agentRuntimeType === "string" ? patchData.agentRuntimeType : existing.agentRuntimeType;
553
+ const touchesAdapterConfiguration = Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeType") ||
554
+ Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeConfig");
555
+ if (touchesAdapterConfiguration) {
556
+ const existingAdapterConfig = asRecord(existing.agentRuntimeConfig) ?? {};
557
+ const changingAdapterType = typeof patchData.agentRuntimeType === "string" && patchData.agentRuntimeType !== existing.agentRuntimeType;
558
+ const requestedAdapterConfig = Object.prototype.hasOwnProperty.call(patchData, "agentRuntimeConfig")
559
+ ? (asRecord(patchData.agentRuntimeConfig) ?? {})
560
+ : null;
561
+ if (requestedAdapterConfig
562
+ && replaceAgentRuntimeConfig
563
+ && KNOWN_INSTRUCTIONS_BUNDLE_KEYS.some((key) => existingAdapterConfig[key] !== undefined && requestedAdapterConfig[key] === undefined)) {
564
+ await assertCanManageInstructionsPath(req, existing);
565
+ }
566
+ let rawEffectiveAdapterConfig = requestedAdapterConfig ?? existingAdapterConfig;
567
+ if (requestedAdapterConfig && !changingAdapterType && !replaceAgentRuntimeConfig) {
568
+ rawEffectiveAdapterConfig = { ...existingAdapterConfig, ...requestedAdapterConfig };
569
+ }
570
+ if (changingAdapterType) {
571
+ rawEffectiveAdapterConfig = preserveInstructionsBundleConfig(existingAdapterConfig, rawEffectiveAdapterConfig);
572
+ }
573
+ const effectiveAdapterConfig = applyCreateDefaultsByAdapterType(requestedAdapterType, rawEffectiveAdapterConfig);
574
+ const normalizedEffectiveAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.orgId, effectiveAdapterConfig, { strictMode: strictSecretsMode });
575
+ patchData.agentRuntimeConfig = syncInstructionsBundleConfigFromFilePath(existing, normalizedEffectiveAdapterConfig);
576
+ }
577
+ if (touchesAdapterConfiguration && requestedAdapterType === "opencode_local") {
578
+ const effectiveAdapterConfig = asRecord(patchData.agentRuntimeConfig) ?? {};
579
+ await assertAdapterConfigConstraints(existing.orgId, requestedAdapterType, effectiveAdapterConfig);
580
+ }
581
+ if (Object.prototype.hasOwnProperty.call(patchData, "icon")) {
582
+ await assertAgentAvatarAssetBelongsToOrg(existing.orgId, patchData.icon);
583
+ }
584
+ const actor = getActorInfo(req);
585
+ const agent = await svc.update(id, patchData, {
586
+ recordRevision: {
587
+ createdByAgentId: actor.agentId,
588
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
589
+ source: "patch",
590
+ },
591
+ });
592
+ if (!agent) {
593
+ res.status(404).json({ error: "Agent not found" });
594
+ return;
595
+ }
596
+ await logActivity(db, {
597
+ orgId: agent.orgId,
598
+ actorType: actor.actorType,
599
+ actorId: actor.actorId,
600
+ agentId: actor.agentId,
601
+ runId: actor.runId,
602
+ action: "agent.updated",
603
+ entityType: "agent",
604
+ entityId: agent.id,
605
+ details: summarizeAgentUpdateDetails(patchData),
606
+ });
607
+ res.json(agent);
608
+ });
609
+ router.post("/agents/:id/pause", async (req, res) => {
610
+ assertBoard(req);
611
+ const id = req.params.id;
612
+ const agent = await svc.pause(id);
613
+ if (!agent) {
614
+ res.status(404).json({ error: "Agent not found" });
615
+ return;
616
+ }
617
+ await heartbeat.cancelActiveForAgent(id);
618
+ await logActivity(db, {
619
+ orgId: agent.orgId,
620
+ actorType: "user",
621
+ actorId: req.actor.userId ?? "board",
622
+ action: "agent.paused",
623
+ entityType: "agent",
624
+ entityId: agent.id,
625
+ });
626
+ res.json(agent);
627
+ });
628
+ router.post("/agents/:id/resume", async (req, res) => {
629
+ assertBoard(req);
630
+ const id = req.params.id;
631
+ const agent = await svc.resume(id);
632
+ if (!agent) {
633
+ res.status(404).json({ error: "Agent not found" });
634
+ return;
635
+ }
636
+ await heartbeat.resumeDeferredWakeupsForAgent(id);
637
+ await logActivity(db, {
638
+ orgId: agent.orgId,
639
+ actorType: "user",
640
+ actorId: req.actor.userId ?? "board",
641
+ action: "agent.resumed",
642
+ entityType: "agent",
643
+ entityId: agent.id,
644
+ });
645
+ res.json(agent);
646
+ });
647
+ router.post("/agents/:id/terminate", async (req, res) => {
648
+ assertBoard(req);
649
+ const id = req.params.id;
650
+ const agent = await svc.terminate(id);
651
+ if (!agent) {
652
+ res.status(404).json({ error: "Agent not found" });
653
+ return;
654
+ }
655
+ await heartbeat.cancelActiveForAgent(id);
656
+ await logActivity(db, {
657
+ orgId: agent.orgId,
658
+ actorType: "user",
659
+ actorId: req.actor.userId ?? "board",
660
+ action: "agent.terminated",
661
+ entityType: "agent",
662
+ entityId: agent.id,
663
+ });
664
+ res.json(agent);
665
+ });
666
+ router.delete("/agents/:id", async (req, res) => {
667
+ assertBoard(req);
668
+ const id = req.params.id;
669
+ const agent = await svc.remove(id);
670
+ if (!agent) {
671
+ res.status(404).json({ error: "Agent not found" });
672
+ return;
673
+ }
674
+ await logActivity(db, {
675
+ orgId: agent.orgId,
676
+ actorType: "user",
677
+ actorId: req.actor.userId ?? "board",
678
+ action: "agent.deleted",
679
+ entityType: "agent",
680
+ entityId: agent.id,
681
+ });
682
+ res.json({ ok: true });
683
+ });
684
+ router.get("/agents/:id/keys", async (req, res) => {
685
+ assertBoard(req);
686
+ const id = req.params.id;
687
+ const keys = await svc.listKeys(id);
688
+ res.json(keys);
689
+ });
690
+ router.post("/agents/:id/keys", validate(createAgentKeySchema), async (req, res) => {
691
+ assertBoard(req);
692
+ const id = req.params.id;
693
+ const key = await svc.createApiKey(id, req.body.name);
694
+ const agent = await svc.getById(id);
695
+ if (agent) {
696
+ await logActivity(db, {
697
+ orgId: agent.orgId,
698
+ actorType: "user",
699
+ actorId: req.actor.userId ?? "board",
700
+ action: "agent.key_created",
701
+ entityType: "agent",
702
+ entityId: agent.id,
703
+ details: { keyId: key.id, name: key.name },
704
+ });
705
+ }
706
+ res.status(201).json(key);
707
+ });
708
+ router.delete("/agents/:id/keys/:keyId", async (req, res) => {
709
+ assertBoard(req);
710
+ const keyId = req.params.keyId;
711
+ const revoked = await svc.revokeKey(keyId);
712
+ if (!revoked) {
713
+ res.status(404).json({ error: "Key not found" });
714
+ return;
715
+ }
716
+ res.json({ ok: true });
717
+ });
718
+ router.post("/agents/:id/wakeup", validate(wakeAgentSchema), async (req, res) => {
719
+ const id = req.params.id;
720
+ const agent = await svc.getById(id);
721
+ if (!agent) {
722
+ res.status(404).json({ error: "Agent not found" });
723
+ return;
724
+ }
725
+ assertCompanyAccess(req, agent.orgId);
726
+ if (req.actor.type === "agent" && req.actor.agentId !== id) {
727
+ res.status(403).json({ error: "Agent can only invoke itself" });
728
+ return;
729
+ }
730
+ const run = await heartbeat.wakeup(id, {
731
+ source: req.body.source,
732
+ triggerDetail: req.body.triggerDetail ?? "manual",
733
+ reason: req.body.reason ?? null,
734
+ payload: req.body.payload ?? null,
735
+ idempotencyKey: req.body.idempotencyKey ?? null,
736
+ requestedByActorType: req.actor.type === "agent" ? "agent" : "user",
737
+ requestedByActorId: req.actor.type === "agent" ? req.actor.agentId ?? null : req.actor.userId ?? null,
738
+ contextSnapshot: {
739
+ triggeredBy: req.actor.type,
740
+ actorId: req.actor.type === "agent" ? req.actor.agentId : req.actor.userId,
741
+ forceFreshSession: req.body.forceFreshSession === true,
742
+ },
743
+ });
744
+ if (!run) {
745
+ res.status(202).json({ status: "skipped" });
746
+ return;
747
+ }
748
+ const actor = getActorInfo(req);
749
+ await logActivity(db, {
750
+ orgId: agent.orgId,
751
+ actorType: actor.actorType,
752
+ actorId: actor.actorId,
753
+ agentId: actor.agentId,
754
+ runId: actor.runId,
755
+ action: "heartbeat.invoked",
756
+ entityType: "heartbeat_run",
757
+ entityId: run.id,
758
+ details: { agentId: id },
759
+ });
760
+ res.status(202).json(run);
761
+ });
762
+ router.post("/agents/:id/heartbeat/invoke", async (req, res) => {
763
+ const id = req.params.id;
764
+ const agent = await svc.getById(id);
765
+ if (!agent) {
766
+ res.status(404).json({ error: "Agent not found" });
767
+ return;
768
+ }
769
+ assertCompanyAccess(req, agent.orgId);
770
+ if (req.actor.type === "agent" && req.actor.agentId !== id) {
771
+ res.status(403).json({ error: "Agent can only invoke itself" });
772
+ return;
773
+ }
774
+ const run = await heartbeat.invoke(id, "on_demand", {
775
+ triggeredBy: req.actor.type,
776
+ actorId: req.actor.type === "agent" ? req.actor.agentId : req.actor.userId,
777
+ }, "manual", {
778
+ actorType: req.actor.type === "agent" ? "agent" : "user",
779
+ actorId: req.actor.type === "agent" ? req.actor.agentId ?? null : req.actor.userId ?? null,
780
+ });
781
+ if (!run) {
782
+ res.status(202).json({ status: "skipped" });
783
+ return;
784
+ }
785
+ const actor = getActorInfo(req);
786
+ await logActivity(db, {
787
+ orgId: agent.orgId,
788
+ actorType: actor.actorType,
789
+ actorId: actor.actorId,
790
+ agentId: actor.agentId,
791
+ runId: actor.runId,
792
+ action: "heartbeat.invoked",
793
+ entityType: "heartbeat_run",
794
+ entityId: run.id,
795
+ details: { agentId: id },
796
+ });
797
+ res.status(202).json(run);
798
+ });
799
+ router.post("/agents/:id/claude-login", async (req, res) => {
800
+ assertBoard(req);
801
+ const id = req.params.id;
802
+ const agent = await svc.getById(id);
803
+ if (!agent) {
804
+ res.status(404).json({ error: "Agent not found" });
805
+ return;
806
+ }
807
+ assertCompanyAccess(req, agent.orgId);
808
+ if (agent.agentRuntimeType !== "claude_local") {
809
+ res.status(400).json({ error: "Login is only supported for claude_local agents" });
810
+ return;
811
+ }
812
+ const config = asRecord(agent.agentRuntimeConfig) ?? {};
813
+ const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(agent.orgId, config);
814
+ const result = await runClaudeLogin({
815
+ runId: `claude-login-${randomUUID()}`,
816
+ agent: {
817
+ id: agent.id,
818
+ orgId: agent.orgId,
819
+ name: agent.name,
820
+ agentRuntimeType: agent.agentRuntimeType,
821
+ agentRuntimeConfig: agent.agentRuntimeConfig,
822
+ },
823
+ config: runtimeConfig,
824
+ });
825
+ res.json(result);
826
+ });
827
+ router.get("/orgs/:orgId/heartbeat-runs", async (req, res) => {
828
+ const orgId = req.params.orgId;
829
+ assertCompanyAccess(req, orgId);
830
+ const agentId = req.query.agentId;
831
+ const limitParam = req.query.limit;
832
+ const limit = limitParam ? Math.max(1, Math.min(1000, parseInt(limitParam, 10) || 200)) : undefined;
833
+ const runs = await heartbeat.list(orgId, agentId, limit);
834
+ res.json(runs);
835
+ });
836
+ router.get("/orgs/:orgId/live-runs", async (req, res) => {
837
+ const orgId = req.params.orgId;
838
+ assertCompanyAccess(req, orgId);
839
+ const minCountParam = req.query.minCount;
840
+ const minCount = minCountParam ? Math.max(0, Math.min(20, parseInt(minCountParam, 10) || 0)) : 0;
841
+ const columns = {
842
+ id: heartbeatRuns.id,
843
+ status: heartbeatRuns.status,
844
+ invocationSource: heartbeatRuns.invocationSource,
845
+ triggerDetail: heartbeatRuns.triggerDetail,
846
+ startedAt: heartbeatRuns.startedAt,
847
+ finishedAt: heartbeatRuns.finishedAt,
848
+ createdAt: heartbeatRuns.createdAt,
849
+ stdoutExcerpt: heartbeatRuns.stdoutExcerpt,
850
+ resultJson: heartbeatRuns.resultJson,
851
+ agentId: heartbeatRuns.agentId,
852
+ agentName: agentsTable.name,
853
+ agentRuntimeType: agentsTable.agentRuntimeType,
854
+ issueId: sql `${heartbeatRuns.contextSnapshot} ->> 'issueId'`.as("issueId"),
855
+ };
856
+ const liveRuns = await db
857
+ .select(columns)
858
+ .from(heartbeatRuns)
859
+ .innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
860
+ .where(and(eq(heartbeatRuns.orgId, orgId), inArray(heartbeatRuns.status, ["queued", "running"])))
861
+ .orderBy(desc(heartbeatRuns.createdAt));
862
+ if (minCount > 0 && liveRuns.length < minCount) {
863
+ const activeIds = liveRuns.map((r) => r.id);
864
+ const recentRuns = await db
865
+ .select(columns)
866
+ .from(heartbeatRuns)
867
+ .innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
868
+ .where(and(eq(heartbeatRuns.orgId, orgId), not(inArray(heartbeatRuns.status, ["queued", "running"])), ...(activeIds.length > 0 ? [not(inArray(heartbeatRuns.id, activeIds))] : [])))
869
+ .orderBy(desc(heartbeatRuns.createdAt))
870
+ .limit(minCount - liveRuns.length);
871
+ res.json([...liveRuns, ...recentRuns]);
872
+ return;
873
+ }
874
+ res.json(liveRuns);
875
+ });
876
+ router.get("/heartbeat-runs/:runId", async (req, res) => {
877
+ const runId = req.params.runId;
878
+ const run = await heartbeat.getRun(runId);
879
+ if (!run) {
880
+ res.status(404).json({ error: "Heartbeat run not found" });
881
+ return;
882
+ }
883
+ assertCompanyAccess(req, run.orgId);
884
+ res.json(redactCurrentUserValue(run, await getCurrentUserRedactionOptions()));
885
+ });
886
+ router.post("/heartbeat-runs/:runId/cancel", async (req, res) => {
887
+ assertBoard(req);
888
+ const runId = req.params.runId;
889
+ const run = await heartbeat.cancelRun(runId);
890
+ if (run) {
891
+ await logActivity(db, {
892
+ orgId: run.orgId,
893
+ actorType: "user",
894
+ actorId: req.actor.userId ?? "board",
895
+ action: "heartbeat.cancelled",
896
+ entityType: "heartbeat_run",
897
+ entityId: run.id,
898
+ details: { agentId: run.agentId },
899
+ });
900
+ }
901
+ res.json(run);
902
+ });
903
+ router.post("/heartbeat-runs/:runId/retry", async (req, res) => {
904
+ assertBoard(req);
905
+ const runId = req.params.runId;
906
+ const originalRun = await heartbeat.getRun(runId);
907
+ if (!originalRun) {
908
+ res.status(404).json({ error: "Heartbeat run not found" });
909
+ return;
910
+ }
911
+ assertCompanyAccess(req, originalRun.orgId);
912
+ const actor = getActorInfo(req);
913
+ const run = await heartbeat.retryRun(runId, {
914
+ requestedByActorType: actor.actorType,
915
+ requestedByActorId: actor.actorId,
916
+ });
917
+ await logActivity(db, {
918
+ orgId: run.orgId,
919
+ actorType: actor.actorType,
920
+ actorId: actor.actorId,
921
+ action: "heartbeat.retried",
922
+ entityType: "heartbeat_run",
923
+ entityId: run.id,
924
+ details: {
925
+ agentId: run.agentId,
926
+ originalRunId: originalRun.id,
927
+ recoveryTrigger: "manual",
928
+ },
929
+ });
930
+ res.json(redactCurrentUserValue(run, await getCurrentUserRedactionOptions()));
931
+ });
932
+ router.get("/heartbeat-runs/:runId/events", async (req, res) => {
933
+ const runId = req.params.runId;
934
+ const run = await heartbeat.getRun(runId);
935
+ if (!run) {
936
+ res.status(404).json({ error: "Heartbeat run not found" });
937
+ return;
938
+ }
939
+ assertCompanyAccess(req, run.orgId);
940
+ const afterSeq = Number(req.query.afterSeq ?? 0);
941
+ const limit = Number(req.query.limit ?? 200);
942
+ const events = await heartbeat.listEvents(runId, Number.isFinite(afterSeq) ? afterSeq : 0, Number.isFinite(limit) ? limit : 200);
943
+ const currentUserRedactionOptions = await getCurrentUserRedactionOptions();
944
+ const redactedEvents = events.map((event) => redactCurrentUserValue({
945
+ ...event,
946
+ payload: redactEventPayload(event.payload),
947
+ }, currentUserRedactionOptions));
948
+ res.json(redactedEvents);
949
+ });
950
+ router.get("/heartbeat-runs/:runId/log", async (req, res) => {
951
+ const runId = req.params.runId;
952
+ const run = await heartbeat.getRun(runId);
953
+ if (!run) {
954
+ res.status(404).json({ error: "Heartbeat run not found" });
955
+ return;
956
+ }
957
+ assertCompanyAccess(req, run.orgId);
958
+ const offset = Number(req.query.offset ?? 0);
959
+ const limitBytes = Number(req.query.limitBytes ?? 256000);
960
+ const result = await heartbeat.readLog(runId, {
961
+ offset: Number.isFinite(offset) ? offset : 0,
962
+ limitBytes: Number.isFinite(limitBytes) ? limitBytes : 256000,
963
+ });
964
+ res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
965
+ res.json(result);
966
+ });
967
+ router.get("/heartbeat-runs/:runId/workspace-operations", async (req, res) => {
968
+ const runId = req.params.runId;
969
+ const run = await heartbeat.getRun(runId);
970
+ if (!run) {
971
+ res.status(404).json({ error: "Heartbeat run not found" });
972
+ return;
973
+ }
974
+ assertCompanyAccess(req, run.orgId);
975
+ const context = asRecord(run.contextSnapshot);
976
+ const executionWorkspaceId = asNonEmptyString(context?.executionWorkspaceId);
977
+ const operations = await workspaceOperations.listForRun(runId, executionWorkspaceId);
978
+ res.json(redactCurrentUserValue(operations, await getCurrentUserRedactionOptions()));
979
+ });
980
+ router.get("/workspace-operations/:operationId/log", async (req, res) => {
981
+ const operationId = req.params.operationId;
982
+ const operation = await workspaceOperations.getById(operationId);
983
+ if (!operation) {
984
+ res.status(404).json({ error: "Workspace operation not found" });
985
+ return;
986
+ }
987
+ assertCompanyAccess(req, operation.orgId);
988
+ const offset = Number(req.query.offset ?? 0);
989
+ const limitBytes = Number(req.query.limitBytes ?? 256000);
990
+ const result = await workspaceOperations.readLog(operationId, {
991
+ offset: Number.isFinite(offset) ? offset : 0,
992
+ limitBytes: Number.isFinite(limitBytes) ? limitBytes : 256000,
993
+ });
994
+ res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
995
+ res.json(result);
996
+ });
997
+ router.get("/issues/:issueId/live-runs", async (req, res) => {
998
+ const rawId = req.params.issueId;
999
+ const issueSvc = issueService(db);
1000
+ const isIdentifier = /^[A-Z]+-\d+$/i.test(rawId);
1001
+ const issue = isIdentifier ? await issueSvc.getByIdentifier(rawId) : await issueSvc.getById(rawId);
1002
+ if (!issue) {
1003
+ res.status(404).json({ error: "Issue not found" });
1004
+ return;
1005
+ }
1006
+ assertCompanyAccess(req, issue.orgId);
1007
+ const liveRuns = await db
1008
+ .select({
1009
+ id: heartbeatRuns.id,
1010
+ status: heartbeatRuns.status,
1011
+ invocationSource: heartbeatRuns.invocationSource,
1012
+ triggerDetail: heartbeatRuns.triggerDetail,
1013
+ startedAt: heartbeatRuns.startedAt,
1014
+ finishedAt: heartbeatRuns.finishedAt,
1015
+ createdAt: heartbeatRuns.createdAt,
1016
+ stdoutExcerpt: heartbeatRuns.stdoutExcerpt,
1017
+ resultJson: heartbeatRuns.resultJson,
1018
+ agentId: heartbeatRuns.agentId,
1019
+ agentName: agentsTable.name,
1020
+ agentRuntimeType: agentsTable.agentRuntimeType,
1021
+ })
1022
+ .from(heartbeatRuns)
1023
+ .innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
1024
+ .where(and(eq(heartbeatRuns.orgId, issue.orgId), inArray(heartbeatRuns.status, ["queued", "running"]), sql `${heartbeatRuns.contextSnapshot} ->> 'issueId' = ${issue.id}`))
1025
+ .orderBy(desc(heartbeatRuns.createdAt));
1026
+ res.json(liveRuns);
1027
+ });
1028
+ router.get("/issues/:issueId/active-run", async (req, res) => {
1029
+ const rawId = req.params.issueId;
1030
+ const issueSvc = issueService(db);
1031
+ const isIdentifier = /^[A-Z]+-\d+$/i.test(rawId);
1032
+ const issue = isIdentifier ? await issueSvc.getByIdentifier(rawId) : await issueSvc.getById(rawId);
1033
+ if (!issue) {
1034
+ res.status(404).json({ error: "Issue not found" });
1035
+ return;
1036
+ }
1037
+ assertCompanyAccess(req, issue.orgId);
1038
+ let run = issue.executionRunId ? await heartbeat.getRun(issue.executionRunId) : null;
1039
+ if (run && run.status !== "queued" && run.status !== "running") {
1040
+ run = null;
1041
+ }
1042
+ if (!run && issue.assigneeAgentId && issue.status === "in_progress") {
1043
+ const candidateRun = await heartbeat.getActiveRunForAgent(issue.assigneeAgentId);
1044
+ const candidateContext = asRecord(candidateRun?.contextSnapshot);
1045
+ const candidateIssueId = asNonEmptyString(candidateContext?.issueId);
1046
+ if (candidateRun && candidateIssueId === issue.id) {
1047
+ run = candidateRun;
1048
+ }
1049
+ }
1050
+ if (!run) {
1051
+ res.json(null);
1052
+ return;
1053
+ }
1054
+ const agent = await svc.getById(run.agentId);
1055
+ if (!agent) {
1056
+ res.json(null);
1057
+ return;
1058
+ }
1059
+ res.json({
1060
+ ...redactCurrentUserValue(run, await getCurrentUserRedactionOptions()),
1061
+ agentId: agent.id,
1062
+ agentName: agent.name,
1063
+ agentRuntimeType: agent.agentRuntimeType,
1064
+ });
1065
+ });
1066
+ }
1067
+ //# sourceMappingURL=agents.management-routes.js.map