@rudderhq/server 0.1.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (902) hide show
  1. package/LICENSE +14 -0
  2. package/dist/agent-auth-jwt.d.ts +14 -0
  3. package/dist/agent-auth-jwt.d.ts.map +1 -0
  4. package/dist/agent-auth-jwt.js +119 -0
  5. package/dist/agent-auth-jwt.js.map +1 -0
  6. package/dist/agent-runtimes/codex-models.d.ts +4 -0
  7. package/dist/agent-runtimes/codex-models.d.ts.map +1 -0
  8. package/dist/agent-runtimes/codex-models.js +98 -0
  9. package/dist/agent-runtimes/codex-models.js.map +1 -0
  10. package/dist/agent-runtimes/cursor-models.d.ts +13 -0
  11. package/dist/agent-runtimes/cursor-models.d.ts.map +1 -0
  12. package/dist/agent-runtimes/cursor-models.js +148 -0
  13. package/dist/agent-runtimes/cursor-models.js.map +1 -0
  14. package/dist/agent-runtimes/http/execute.d.ts +3 -0
  15. package/dist/agent-runtimes/http/execute.d.ts.map +1 -0
  16. package/dist/agent-runtimes/http/execute.js +39 -0
  17. package/dist/agent-runtimes/http/execute.js.map +1 -0
  18. package/dist/agent-runtimes/http/index.d.ts +3 -0
  19. package/dist/agent-runtimes/http/index.d.ts.map +1 -0
  20. package/dist/agent-runtimes/http/index.js +20 -0
  21. package/dist/agent-runtimes/http/index.js.map +1 -0
  22. package/dist/agent-runtimes/http/test.d.ts +3 -0
  23. package/dist/agent-runtimes/http/test.d.ts.map +1 -0
  24. package/dist/agent-runtimes/http/test.js +106 -0
  25. package/dist/agent-runtimes/http/test.js.map +1 -0
  26. package/dist/agent-runtimes/index.d.ts +4 -0
  27. package/dist/agent-runtimes/index.d.ts.map +1 -0
  28. package/dist/agent-runtimes/index.js +3 -0
  29. package/dist/agent-runtimes/index.js.map +1 -0
  30. package/dist/agent-runtimes/process/execute.d.ts +3 -0
  31. package/dist/agent-runtimes/process/execute.d.ts.map +1 -0
  32. package/dist/agent-runtimes/process/execute.js +63 -0
  33. package/dist/agent-runtimes/process/execute.js.map +1 -0
  34. package/dist/agent-runtimes/process/index.d.ts +3 -0
  35. package/dist/agent-runtimes/process/index.d.ts.map +1 -0
  36. package/dist/agent-runtimes/process/index.js +23 -0
  37. package/dist/agent-runtimes/process/index.js.map +1 -0
  38. package/dist/agent-runtimes/process/test.d.ts +3 -0
  39. package/dist/agent-runtimes/process/test.d.ts.map +1 -0
  40. package/dist/agent-runtimes/process/test.js +77 -0
  41. package/dist/agent-runtimes/process/test.js.map +1 -0
  42. package/dist/agent-runtimes/registry.d.ts +9 -0
  43. package/dist/agent-runtimes/registry.d.ts.map +1 -0
  44. package/dist/agent-runtimes/registry.js +189 -0
  45. package/dist/agent-runtimes/registry.js.map +1 -0
  46. package/dist/agent-runtimes/types.d.ts +2 -0
  47. package/dist/agent-runtimes/types.d.ts.map +1 -0
  48. package/dist/agent-runtimes/types.js +2 -0
  49. package/dist/agent-runtimes/types.js.map +1 -0
  50. package/dist/agent-runtimes/utils.d.ts +10 -0
  51. package/dist/agent-runtimes/utils.d.ts.map +1 -0
  52. package/dist/agent-runtimes/utils.js +14 -0
  53. package/dist/agent-runtimes/utils.js.map +1 -0
  54. package/dist/agent-workspace-key.d.ts +17 -0
  55. package/dist/agent-workspace-key.d.ts.map +1 -0
  56. package/dist/agent-workspace-key.js +49 -0
  57. package/dist/agent-workspace-key.js.map +1 -0
  58. package/dist/app.d.ts +14 -0
  59. package/dist/app.d.ts.map +1 -0
  60. package/dist/app.js +19 -0
  61. package/dist/app.js.map +1 -0
  62. package/dist/attachment-types.d.ts +33 -0
  63. package/dist/attachment-types.d.ts.map +1 -0
  64. package/dist/attachment-types.js +67 -0
  65. package/dist/attachment-types.js.map +1 -0
  66. package/dist/auth/better-auth.d.ts +24 -0
  67. package/dist/auth/better-auth.d.ts.map +1 -0
  68. package/dist/auth/better-auth.js +108 -0
  69. package/dist/auth/better-auth.js.map +1 -0
  70. package/dist/board-claim.d.ts +23 -0
  71. package/dist/board-claim.d.ts.map +1 -0
  72. package/dist/board-claim.js +115 -0
  73. package/dist/board-claim.js.map +1 -0
  74. package/dist/bootstrap/create-http-app.d.ts +6 -0
  75. package/dist/bootstrap/create-http-app.d.ts.map +1 -0
  76. package/dist/bootstrap/create-http-app.js +122 -0
  77. package/dist/bootstrap/create-http-app.js.map +1 -0
  78. package/dist/bootstrap/plugin-host-runtime.d.ts +116 -0
  79. package/dist/bootstrap/plugin-host-runtime.d.ts.map +1 -0
  80. package/dist/bootstrap/plugin-host-runtime.js +121 -0
  81. package/dist/bootstrap/plugin-host-runtime.js.map +1 -0
  82. package/dist/bootstrap/register-api-routes.d.ts +5 -0
  83. package/dist/bootstrap/register-api-routes.d.ts.map +1 -0
  84. package/dist/bootstrap/register-api-routes.js +65 -0
  85. package/dist/bootstrap/register-api-routes.js.map +1 -0
  86. package/dist/bootstrap/types.d.ts +24 -0
  87. package/dist/bootstrap/types.d.ts.map +1 -0
  88. package/dist/bootstrap/types.js +2 -0
  89. package/dist/bootstrap/types.js.map +1 -0
  90. package/dist/config-file.d.ts +5 -0
  91. package/dist/config-file.d.ts.map +1 -0
  92. package/dist/config-file.js +48 -0
  93. package/dist/config-file.js.map +1 -0
  94. package/dist/config.d.ts +45 -0
  95. package/dist/config.d.ts.map +1 -0
  96. package/dist/config.js +233 -0
  97. package/dist/config.js.map +1 -0
  98. package/dist/dev-server-status.d.ts +29 -0
  99. package/dist/dev-server-status.d.ts.map +1 -0
  100. package/dist/dev-server-status.js +75 -0
  101. package/dist/dev-server-status.js.map +1 -0
  102. package/dist/errors.d.ts +12 -0
  103. package/dist/errors.d.ts.map +1 -0
  104. package/dist/errors.js +28 -0
  105. package/dist/errors.js.map +1 -0
  106. package/dist/home-paths.d.ts +50 -0
  107. package/dist/home-paths.d.ts.map +1 -0
  108. package/dist/home-paths.js +183 -0
  109. package/dist/home-paths.js.map +1 -0
  110. package/dist/index.d.ts +69 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +827 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/langfuse-transcript.d.ts +32 -0
  115. package/dist/langfuse-transcript.d.ts.map +1 -0
  116. package/dist/langfuse-transcript.js +341 -0
  117. package/dist/langfuse-transcript.js.map +1 -0
  118. package/dist/langfuse.d.ts +93 -0
  119. package/dist/langfuse.d.ts.map +1 -0
  120. package/dist/langfuse.js +412 -0
  121. package/dist/langfuse.js.map +1 -0
  122. package/dist/local-runtime.d.ts +67 -0
  123. package/dist/local-runtime.d.ts.map +1 -0
  124. package/dist/local-runtime.js +302 -0
  125. package/dist/local-runtime.js.map +1 -0
  126. package/dist/log-redaction.d.ts +11 -0
  127. package/dist/log-redaction.d.ts.map +1 -0
  128. package/dist/log-redaction.js +118 -0
  129. package/dist/log-redaction.js.map +1 -0
  130. package/dist/middleware/auth.d.ts +12 -0
  131. package/dist/middleware/auth.d.ts.map +1 -0
  132. package/dist/middleware/auth.js +144 -0
  133. package/dist/middleware/auth.js.map +1 -0
  134. package/dist/middleware/board-mutation-guard.d.ts +3 -0
  135. package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
  136. package/dist/middleware/board-mutation-guard.js +59 -0
  137. package/dist/middleware/board-mutation-guard.js.map +1 -0
  138. package/dist/middleware/error-handler.d.ts +17 -0
  139. package/dist/middleware/error-handler.d.ts.map +1 -0
  140. package/dist/middleware/error-handler.js +37 -0
  141. package/dist/middleware/error-handler.js.map +1 -0
  142. package/dist/middleware/index.d.ts +4 -0
  143. package/dist/middleware/index.d.ts.map +1 -0
  144. package/dist/middleware/index.js +4 -0
  145. package/dist/middleware/index.js.map +1 -0
  146. package/dist/middleware/logger.d.ts +4 -0
  147. package/dist/middleware/logger.d.ts.map +1 -0
  148. package/dist/middleware/logger.js +133 -0
  149. package/dist/middleware/logger.js.map +1 -0
  150. package/dist/middleware/private-hostname-guard.d.ts +11 -0
  151. package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
  152. package/dist/middleware/private-hostname-guard.js +78 -0
  153. package/dist/middleware/private-hostname-guard.js.map +1 -0
  154. package/dist/middleware/validate.d.ts +4 -0
  155. package/dist/middleware/validate.d.ts.map +1 -0
  156. package/dist/middleware/validate.js +7 -0
  157. package/dist/middleware/validate.js.map +1 -0
  158. package/dist/onboarding-assets/ceo/AGENTS.md +33 -0
  159. package/dist/onboarding-assets/ceo/HEARTBEAT.md +77 -0
  160. package/dist/onboarding-assets/ceo/SOUL.md +33 -0
  161. package/dist/onboarding-assets/ceo/TOOLS.md +3 -0
  162. package/dist/onboarding-assets/default/AGENTS.md +9 -0
  163. package/dist/onboarding-assets/default/HEARTBEAT.md +36 -0
  164. package/dist/onboarding-assets/default/SOUL.md +23 -0
  165. package/dist/onboarding-assets/default/TOOLS.md +3 -0
  166. package/dist/paths.d.ts +3 -0
  167. package/dist/paths.d.ts.map +1 -0
  168. package/dist/paths.js +31 -0
  169. package/dist/paths.js.map +1 -0
  170. package/dist/realtime/live-events-ws.d.ts +28 -0
  171. package/dist/realtime/live-events-ws.d.ts.map +1 -0
  172. package/dist/realtime/live-events-ws.js +187 -0
  173. package/dist/realtime/live-events-ws.js.map +1 -0
  174. package/dist/redaction.d.ts +4 -0
  175. package/dist/redaction.d.ts.map +1 -0
  176. package/dist/redaction.js +63 -0
  177. package/dist/redaction.js.map +1 -0
  178. package/dist/routes/access.d.ts +57 -0
  179. package/dist/routes/access.d.ts.map +1 -0
  180. package/dist/routes/access.js +2266 -0
  181. package/dist/routes/access.js.map +1 -0
  182. package/dist/routes/activity.d.ts +3 -0
  183. package/dist/routes/activity.d.ts.map +1 -0
  184. package/dist/routes/activity.js +78 -0
  185. package/dist/routes/activity.js.map +1 -0
  186. package/dist/routes/agents.d.ts +3 -0
  187. package/dist/routes/agents.d.ts.map +1 -0
  188. package/dist/routes/agents.js +1913 -0
  189. package/dist/routes/agents.js.map +1 -0
  190. package/dist/routes/approvals.d.ts +3 -0
  191. package/dist/routes/approvals.d.ts.map +1 -0
  192. package/dist/routes/approvals.js +365 -0
  193. package/dist/routes/approvals.js.map +1 -0
  194. package/dist/routes/assets.d.ts +4 -0
  195. package/dist/routes/assets.d.ts.map +1 -0
  196. package/dist/routes/assets.js +309 -0
  197. package/dist/routes/assets.js.map +1 -0
  198. package/dist/routes/authz.d.ts +16 -0
  199. package/dist/routes/authz.d.ts.map +1 -0
  200. package/dist/routes/authz.js +47 -0
  201. package/dist/routes/authz.js.map +1 -0
  202. package/dist/routes/automations.d.ts +3 -0
  203. package/dist/routes/automations.d.ts.map +1 -0
  204. package/dist/routes/automations.js +277 -0
  205. package/dist/routes/automations.js.map +1 -0
  206. package/dist/routes/chats.d.ts +4 -0
  207. package/dist/routes/chats.d.ts.map +1 -0
  208. package/dist/routes/chats.js +1162 -0
  209. package/dist/routes/chats.js.map +1 -0
  210. package/dist/routes/costs.d.ts +3 -0
  211. package/dist/routes/costs.d.ts.map +1 -0
  212. package/dist/routes/costs.js +268 -0
  213. package/dist/routes/costs.js.map +1 -0
  214. package/dist/routes/dashboard.d.ts +3 -0
  215. package/dist/routes/dashboard.d.ts.map +1 -0
  216. package/dist/routes/dashboard.js +15 -0
  217. package/dist/routes/dashboard.js.map +1 -0
  218. package/dist/routes/execution-workspaces.d.ts +3 -0
  219. package/dist/routes/execution-workspaces.d.ts.map +1 -0
  220. package/dist/routes/execution-workspaces.js +165 -0
  221. package/dist/routes/execution-workspaces.js.map +1 -0
  222. package/dist/routes/goals.d.ts +3 -0
  223. package/dist/routes/goals.d.ts.map +1 -0
  224. package/dist/routes/goals.js +95 -0
  225. package/dist/routes/goals.js.map +1 -0
  226. package/dist/routes/health.d.ts +12 -0
  227. package/dist/routes/health.d.ts.map +1 -0
  228. package/dist/routes/health.js +85 -0
  229. package/dist/routes/health.js.map +1 -0
  230. package/dist/routes/index.d.ts +19 -0
  231. package/dist/routes/index.d.ts.map +1 -0
  232. package/dist/routes/index.js +19 -0
  233. package/dist/routes/index.js.map +1 -0
  234. package/dist/routes/instance-settings.d.ts +6 -0
  235. package/dist/routes/instance-settings.d.ts.map +1 -0
  236. package/dist/routes/instance-settings.js +250 -0
  237. package/dist/routes/instance-settings.js.map +1 -0
  238. package/dist/routes/issues-checkout-wakeup.d.ts +9 -0
  239. package/dist/routes/issues-checkout-wakeup.d.ts.map +1 -0
  240. package/dist/routes/issues-checkout-wakeup.js +12 -0
  241. package/dist/routes/issues-checkout-wakeup.js.map +1 -0
  242. package/dist/routes/issues.d.ts +4 -0
  243. package/dist/routes/issues.d.ts.map +1 -0
  244. package/dist/routes/issues.js +1615 -0
  245. package/dist/routes/issues.js.map +1 -0
  246. package/dist/routes/llms.d.ts +3 -0
  247. package/dist/routes/llms.d.ts.map +1 -0
  248. package/dist/routes/llms.js +78 -0
  249. package/dist/routes/llms.js.map +1 -0
  250. package/dist/routes/messenger.d.ts +3 -0
  251. package/dist/routes/messenger.d.ts.map +1 -0
  252. package/dist/routes/messenger.js +108 -0
  253. package/dist/routes/messenger.js.map +1 -0
  254. package/dist/routes/org-chart-logo.d.ts +2 -0
  255. package/dist/routes/org-chart-logo.d.ts.map +1 -0
  256. package/dist/routes/org-chart-logo.js +2 -0
  257. package/dist/routes/org-chart-logo.js.map +1 -0
  258. package/dist/routes/org-chart-svg.d.ts +25 -0
  259. package/dist/routes/org-chart-svg.d.ts.map +1 -0
  260. package/dist/routes/org-chart-svg.js +652 -0
  261. package/dist/routes/org-chart-svg.js.map +1 -0
  262. package/dist/routes/organization-skills.d.ts +3 -0
  263. package/dist/routes/organization-skills.d.ts.map +1 -0
  264. package/dist/routes/organization-skills.js +253 -0
  265. package/dist/routes/organization-skills.js.map +1 -0
  266. package/dist/routes/orgs.d.ts +4 -0
  267. package/dist/routes/orgs.d.ts.map +1 -0
  268. package/dist/routes/orgs.js +575 -0
  269. package/dist/routes/orgs.js.map +1 -0
  270. package/dist/routes/plugin-ui-static.d.ts +69 -0
  271. package/dist/routes/plugin-ui-static.d.ts.map +1 -0
  272. package/dist/routes/plugin-ui-static.js +411 -0
  273. package/dist/routes/plugin-ui-static.js.map +1 -0
  274. package/dist/routes/plugins.d.ts +120 -0
  275. package/dist/routes/plugins.d.ts.map +1 -0
  276. package/dist/routes/plugins.js +1776 -0
  277. package/dist/routes/plugins.js.map +1 -0
  278. package/dist/routes/projects.d.ts +3 -0
  279. package/dist/routes/projects.d.ts.map +1 -0
  280. package/dist/routes/projects.js +235 -0
  281. package/dist/routes/projects.js.map +1 -0
  282. package/dist/routes/run-intelligence.d.ts +3 -0
  283. package/dist/routes/run-intelligence.d.ts.map +1 -0
  284. package/dist/routes/run-intelligence.js +58 -0
  285. package/dist/routes/run-intelligence.js.map +1 -0
  286. package/dist/routes/secrets.d.ts +3 -0
  287. package/dist/routes/secrets.d.ts.map +1 -0
  288. package/dist/routes/secrets.js +128 -0
  289. package/dist/routes/secrets.js.map +1 -0
  290. package/dist/routes/sidebar-badges.d.ts +3 -0
  291. package/dist/routes/sidebar-badges.d.ts.map +1 -0
  292. package/dist/routes/sidebar-badges.js +70 -0
  293. package/dist/routes/sidebar-badges.js.map +1 -0
  294. package/dist/secrets/external-stub-providers.d.ts +5 -0
  295. package/dist/secrets/external-stub-providers.d.ts.map +1 -0
  296. package/dist/secrets/external-stub-providers.js +21 -0
  297. package/dist/secrets/external-stub-providers.js.map +1 -0
  298. package/dist/secrets/local-encrypted-provider.d.ts +3 -0
  299. package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
  300. package/dist/secrets/local-encrypted-provider.js +116 -0
  301. package/dist/secrets/local-encrypted-provider.js.map +1 -0
  302. package/dist/secrets/provider-registry.d.ts +5 -0
  303. package/dist/secrets/provider-registry.d.ts.map +1 -0
  304. package/dist/secrets/provider-registry.js +20 -0
  305. package/dist/secrets/provider-registry.js.map +1 -0
  306. package/dist/secrets/types.d.ts +21 -0
  307. package/dist/secrets/types.d.ts.map +1 -0
  308. package/dist/secrets/types.js +2 -0
  309. package/dist/secrets/types.js.map +1 -0
  310. package/dist/services/access.d.ts +113 -0
  311. package/dist/services/access.d.ts.map +1 -0
  312. package/dist/services/access.js +247 -0
  313. package/dist/services/access.js.map +1 -0
  314. package/dist/services/activity-log.d.ts +17 -0
  315. package/dist/services/activity-log.d.ts.map +1 -0
  316. package/dist/services/activity-log.js +109 -0
  317. package/dist/services/activity-log.js.map +1 -0
  318. package/dist/services/activity.d.ts +472 -0
  319. package/dist/services/activity.d.ts.map +1 -0
  320. package/dist/services/activity.js +134 -0
  321. package/dist/services/activity.js.map +1 -0
  322. package/dist/services/agent-enabled-skills.d.ts +9 -0
  323. package/dist/services/agent-enabled-skills.d.ts.map +1 -0
  324. package/dist/services/agent-enabled-skills.js +89 -0
  325. package/dist/services/agent-enabled-skills.js.map +1 -0
  326. package/dist/services/agent-instructions.d.ts +98 -0
  327. package/dist/services/agent-instructions.d.ts.map +1 -0
  328. package/dist/services/agent-instructions.js +596 -0
  329. package/dist/services/agent-instructions.js.map +1 -0
  330. package/dist/services/agent-name-pool.d.ts +10 -0
  331. package/dist/services/agent-name-pool.d.ts.map +1 -0
  332. package/dist/services/agent-name-pool.js +230 -0
  333. package/dist/services/agent-name-pool.js.map +1 -0
  334. package/dist/services/agent-permissions.d.ts +6 -0
  335. package/dist/services/agent-permissions.d.ts.map +1 -0
  336. package/dist/services/agent-permissions.js +18 -0
  337. package/dist/services/agent-permissions.js.map +1 -0
  338. package/dist/services/agent-run-context.d.ts +142 -0
  339. package/dist/services/agent-run-context.d.ts.map +1 -0
  340. package/dist/services/agent-run-context.js +451 -0
  341. package/dist/services/agent-run-context.js.map +1 -0
  342. package/dist/services/agents.d.ts +1713 -0
  343. package/dist/services/agents.d.ts.map +1 -0
  344. package/dist/services/agents.js +750 -0
  345. package/dist/services/agents.js.map +1 -0
  346. package/dist/services/approvals.d.ts +546 -0
  347. package/dist/services/approvals.d.ts.map +1 -0
  348. package/dist/services/approvals.js +212 -0
  349. package/dist/services/approvals.js.map +1 -0
  350. package/dist/services/assets.d.ts +33 -0
  351. package/dist/services/assets.d.ts.map +1 -0
  352. package/dist/services/assets.js +17 -0
  353. package/dist/services/assets.js.map +1 -0
  354. package/dist/services/automations.d.ts +135 -0
  355. package/dist/services/automations.d.ts.map +1 -0
  356. package/dist/services/automations.js +1105 -0
  357. package/dist/services/automations.js.map +1 -0
  358. package/dist/services/board-auth.d.ts +234 -0
  359. package/dist/services/board-auth.d.ts.map +1 -0
  360. package/dist/services/board-auth.js +295 -0
  361. package/dist/services/board-auth.js.map +1 -0
  362. package/dist/services/budgets.d.ts +38 -0
  363. package/dist/services/budgets.d.ts.map +1 -0
  364. package/dist/services/budgets.js +784 -0
  365. package/dist/services/budgets.js.map +1 -0
  366. package/dist/services/chat-assistant.d.ts +62 -0
  367. package/dist/services/chat-assistant.d.ts.map +1 -0
  368. package/dist/services/chat-assistant.js +943 -0
  369. package/dist/services/chat-assistant.js.map +1 -0
  370. package/dist/services/chat-generation-locks.d.ts +3 -0
  371. package/dist/services/chat-generation-locks.d.ts.map +1 -0
  372. package/dist/services/chat-generation-locks.js +16 -0
  373. package/dist/services/chat-generation-locks.js.map +1 -0
  374. package/dist/services/chats.d.ts +723 -0
  375. package/dist/services/chats.d.ts.map +1 -0
  376. package/dist/services/chats.js +1188 -0
  377. package/dist/services/chats.js.map +1 -0
  378. package/dist/services/costs.d.ts +114 -0
  379. package/dist/services/costs.d.ts.map +1 -0
  380. package/dist/services/costs.js +326 -0
  381. package/dist/services/costs.js.map +1 -0
  382. package/dist/services/cron.d.ts +80 -0
  383. package/dist/services/cron.d.ts.map +1 -0
  384. package/dist/services/cron.js +300 -0
  385. package/dist/services/cron.js.map +1 -0
  386. package/dist/services/dashboard.d.ts +26 -0
  387. package/dist/services/dashboard.d.ts.map +1 -0
  388. package/dist/services/dashboard.js +98 -0
  389. package/dist/services/dashboard.js.map +1 -0
  390. package/dist/services/default-agent-instructions.d.ts +9 -0
  391. package/dist/services/default-agent-instructions.d.ts.map +1 -0
  392. package/dist/services/default-agent-instructions.js +20 -0
  393. package/dist/services/default-agent-instructions.js.map +1 -0
  394. package/dist/services/documents.d.ts +164 -0
  395. package/dist/services/documents.d.ts.map +1 -0
  396. package/dist/services/documents.js +382 -0
  397. package/dist/services/documents.js.map +1 -0
  398. package/dist/services/execution-workspace-policy.d.ts +20 -0
  399. package/dist/services/execution-workspace-policy.d.ts.map +1 -0
  400. package/dist/services/execution-workspace-policy.js +172 -0
  401. package/dist/services/execution-workspace-policy.js.map +1 -0
  402. package/dist/services/execution-workspaces.d.ts +19 -0
  403. package/dist/services/execution-workspaces.d.ts.map +1 -0
  404. package/dist/services/execution-workspaces.js +87 -0
  405. package/dist/services/execution-workspaces.js.map +1 -0
  406. package/dist/services/finance.d.ts +93 -0
  407. package/dist/services/finance.d.ts.map +1 -0
  408. package/dist/services/finance.js +120 -0
  409. package/dist/services/finance.js.map +1 -0
  410. package/dist/services/goals.d.ts +433 -0
  411. package/dist/services/goals.d.ts.map +1 -0
  412. package/dist/services/goals.js +54 -0
  413. package/dist/services/goals.js.map +1 -0
  414. package/dist/services/heartbeat-run-summary.d.ts +2 -0
  415. package/dist/services/heartbeat-run-summary.d.ts.map +1 -0
  416. package/dist/services/heartbeat-run-summary.js +131 -0
  417. package/dist/services/heartbeat-run-summary.js.map +1 -0
  418. package/dist/services/heartbeat.d.ts +2 -0
  419. package/dist/services/heartbeat.d.ts.map +1 -0
  420. package/dist/services/heartbeat.js +2 -0
  421. package/dist/services/heartbeat.js.map +1 -0
  422. package/dist/services/hire-hook.d.ts +14 -0
  423. package/dist/services/hire-hook.d.ts.map +1 -0
  424. package/dist/services/hire-hook.js +85 -0
  425. package/dist/services/hire-hook.js.map +1 -0
  426. package/dist/services/index.d.ts +38 -0
  427. package/dist/services/index.d.ts.map +1 -0
  428. package/dist/services/index.js +38 -0
  429. package/dist/services/index.js.map +1 -0
  430. package/dist/services/instance-settings.d.ts +14 -0
  431. package/dist/services/instance-settings.d.ts.map +1 -0
  432. package/dist/services/instance-settings.js +158 -0
  433. package/dist/services/instance-settings.js.map +1 -0
  434. package/dist/services/issue-approvals.d.ts +56 -0
  435. package/dist/services/issue-approvals.d.ts.map +1 -0
  436. package/dist/services/issue-approvals.js +153 -0
  437. package/dist/services/issue-approvals.js.map +1 -0
  438. package/dist/services/issue-assignment-wakeup.d.ts +32 -0
  439. package/dist/services/issue-assignment-wakeup.d.ts.map +1 -0
  440. package/dist/services/issue-assignment-wakeup.js +43 -0
  441. package/dist/services/issue-assignment-wakeup.js.map +1 -0
  442. package/dist/services/issue-goal-fallback.d.ts +15 -0
  443. package/dist/services/issue-goal-fallback.d.ts.map +1 -0
  444. package/dist/services/issue-goal-fallback.js +15 -0
  445. package/dist/services/issue-goal-fallback.js.map +1 -0
  446. package/dist/services/issues.d.ts +580 -0
  447. package/dist/services/issues.d.ts.map +1 -0
  448. package/dist/services/issues.js +1464 -0
  449. package/dist/services/issues.js.map +1 -0
  450. package/dist/services/knowledge-portability/organization-portability.d.ts +23 -0
  451. package/dist/services/knowledge-portability/organization-portability.d.ts.map +1 -0
  452. package/dist/services/knowledge-portability/organization-portability.js +3795 -0
  453. package/dist/services/knowledge-portability/organization-portability.js.map +1 -0
  454. package/dist/services/knowledge-portability/organization-skills.d.ts +105 -0
  455. package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -0
  456. package/dist/services/knowledge-portability/organization-skills.js +3172 -0
  457. package/dist/services/knowledge-portability/organization-skills.js.map +1 -0
  458. package/dist/services/live-events.d.ts +17 -0
  459. package/dist/services/live-events.d.ts.map +1 -0
  460. package/dist/services/live-events.js +33 -0
  461. package/dist/services/live-events.js.map +1 -0
  462. package/dist/services/messenger.d.ts +111 -0
  463. package/dist/services/messenger.d.ts.map +1 -0
  464. package/dist/services/messenger.js +774 -0
  465. package/dist/services/messenger.js.map +1 -0
  466. package/dist/services/native-path-picker.d.ts +18 -0
  467. package/dist/services/native-path-picker.d.ts.map +1 -0
  468. package/dist/services/native-path-picker.js +119 -0
  469. package/dist/services/native-path-picker.js.map +1 -0
  470. package/dist/services/operator-profile.d.ts +7 -0
  471. package/dist/services/operator-profile.d.ts.map +1 -0
  472. package/dist/services/operator-profile.js +66 -0
  473. package/dist/services/operator-profile.js.map +1 -0
  474. package/dist/services/organization-export-readme.d.ts +17 -0
  475. package/dist/services/organization-export-readme.d.ts.map +1 -0
  476. package/dist/services/organization-export-readme.js +148 -0
  477. package/dist/services/organization-export-readme.js.map +1 -0
  478. package/dist/services/organization-portability.d.ts +2 -0
  479. package/dist/services/organization-portability.d.ts.map +1 -0
  480. package/dist/services/organization-portability.js +2 -0
  481. package/dist/services/organization-portability.js.map +1 -0
  482. package/dist/services/organization-skills.d.ts +2 -0
  483. package/dist/services/organization-skills.d.ts.map +1 -0
  484. package/dist/services/organization-skills.js +2 -0
  485. package/dist/services/organization-skills.js.map +1 -0
  486. package/dist/services/organization-workspace-browser.d.ts +8 -0
  487. package/dist/services/organization-workspace-browser.d.ts.map +1 -0
  488. package/dist/services/organization-workspace-browser.js +229 -0
  489. package/dist/services/organization-workspace-browser.js.map +1 -0
  490. package/dist/services/organization-workspace.d.ts +5 -0
  491. package/dist/services/organization-workspace.d.ts.map +1 -0
  492. package/dist/services/organization-workspace.js +71 -0
  493. package/dist/services/organization-workspace.js.map +1 -0
  494. package/dist/services/orgs.d.ts +163 -0
  495. package/dist/services/orgs.d.ts.map +1 -0
  496. package/dist/services/orgs.js +327 -0
  497. package/dist/services/orgs.js.map +1 -0
  498. package/dist/services/plugin-capability-validator.d.ts +108 -0
  499. package/dist/services/plugin-capability-validator.d.ts.map +1 -0
  500. package/dist/services/plugin-capability-validator.js +268 -0
  501. package/dist/services/plugin-capability-validator.js.map +1 -0
  502. package/dist/services/plugin-config-validator.d.ts +26 -0
  503. package/dist/services/plugin-config-validator.d.ts.map +1 -0
  504. package/dist/services/plugin-config-validator.js +41 -0
  505. package/dist/services/plugin-config-validator.js.map +1 -0
  506. package/dist/services/plugin-dev-watcher.d.ts +30 -0
  507. package/dist/services/plugin-dev-watcher.d.ts.map +1 -0
  508. package/dist/services/plugin-dev-watcher.js +241 -0
  509. package/dist/services/plugin-dev-watcher.js.map +1 -0
  510. package/dist/services/plugin-event-bus.d.ts +149 -0
  511. package/dist/services/plugin-event-bus.d.ts.map +1 -0
  512. package/dist/services/plugin-event-bus.js +258 -0
  513. package/dist/services/plugin-event-bus.js.map +1 -0
  514. package/dist/services/plugin-host-service-cleanup.d.ts +14 -0
  515. package/dist/services/plugin-host-service-cleanup.d.ts.map +1 -0
  516. package/dist/services/plugin-host-service-cleanup.js +37 -0
  517. package/dist/services/plugin-host-service-cleanup.js.map +1 -0
  518. package/dist/services/plugin-host-services.d.ts +13 -0
  519. package/dist/services/plugin-host-services.d.ts.map +1 -0
  520. package/dist/services/plugin-host-services.js +973 -0
  521. package/dist/services/plugin-host-services.js.map +1 -0
  522. package/dist/services/plugin-job-coordinator.d.ts +81 -0
  523. package/dist/services/plugin-job-coordinator.d.ts.map +1 -0
  524. package/dist/services/plugin-job-coordinator.js +172 -0
  525. package/dist/services/plugin-job-coordinator.js.map +1 -0
  526. package/dist/services/plugin-job-scheduler.d.ts +163 -0
  527. package/dist/services/plugin-job-scheduler.d.ts.map +1 -0
  528. package/dist/services/plugin-job-scheduler.js +564 -0
  529. package/dist/services/plugin-job-scheduler.js.map +1 -0
  530. package/dist/services/plugin-job-store.d.ts +208 -0
  531. package/dist/services/plugin-job-store.d.ts.map +1 -0
  532. package/dist/services/plugin-job-store.js +350 -0
  533. package/dist/services/plugin-job-store.js.map +1 -0
  534. package/dist/services/plugin-lifecycle.d.ts +203 -0
  535. package/dist/services/plugin-lifecycle.d.ts.map +1 -0
  536. package/dist/services/plugin-lifecycle.js +476 -0
  537. package/dist/services/plugin-lifecycle.js.map +1 -0
  538. package/dist/services/plugin-loader.d.ts +441 -0
  539. package/dist/services/plugin-loader.d.ts.map +1 -0
  540. package/dist/services/plugin-loader.js +1192 -0
  541. package/dist/services/plugin-loader.js.map +1 -0
  542. package/dist/services/plugin-log-retention.d.ts +20 -0
  543. package/dist/services/plugin-log-retention.d.ts.map +1 -0
  544. package/dist/services/plugin-log-retention.js +63 -0
  545. package/dist/services/plugin-log-retention.js.map +1 -0
  546. package/dist/services/plugin-manifest-validator.d.ts +79 -0
  547. package/dist/services/plugin-manifest-validator.d.ts.map +1 -0
  548. package/dist/services/plugin-manifest-validator.js +84 -0
  549. package/dist/services/plugin-manifest-validator.js.map +1 -0
  550. package/dist/services/plugin-registry.d.ts +2542 -0
  551. package/dist/services/plugin-registry.d.ts.map +1 -0
  552. package/dist/services/plugin-registry.js +539 -0
  553. package/dist/services/plugin-registry.js.map +1 -0
  554. package/dist/services/plugin-runtime-sandbox.d.ts +40 -0
  555. package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -0
  556. package/dist/services/plugin-runtime-sandbox.js +154 -0
  557. package/dist/services/plugin-runtime-sandbox.js.map +1 -0
  558. package/dist/services/plugin-secrets-handler.d.ts +81 -0
  559. package/dist/services/plugin-secrets-handler.d.ts.map +1 -0
  560. package/dist/services/plugin-secrets-handler.js +275 -0
  561. package/dist/services/plugin-secrets-handler.js.map +1 -0
  562. package/dist/services/plugin-state-store.d.ts +92 -0
  563. package/dist/services/plugin-state-store.d.ts.map +1 -0
  564. package/dist/services/plugin-state-store.js +190 -0
  565. package/dist/services/plugin-state-store.js.map +1 -0
  566. package/dist/services/plugin-stream-bus.d.ts +29 -0
  567. package/dist/services/plugin-stream-bus.d.ts.map +1 -0
  568. package/dist/services/plugin-stream-bus.js +48 -0
  569. package/dist/services/plugin-stream-bus.js.map +1 -0
  570. package/dist/services/plugin-tool-dispatcher.d.ts +180 -0
  571. package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -0
  572. package/dist/services/plugin-tool-dispatcher.js +224 -0
  573. package/dist/services/plugin-tool-dispatcher.js.map +1 -0
  574. package/dist/services/plugin-tool-registry.d.ts +192 -0
  575. package/dist/services/plugin-tool-registry.d.ts.map +1 -0
  576. package/dist/services/plugin-tool-registry.js +224 -0
  577. package/dist/services/plugin-tool-registry.js.map +1 -0
  578. package/dist/services/plugin-worker-manager.d.ts +260 -0
  579. package/dist/services/plugin-worker-manager.d.ts.map +1 -0
  580. package/dist/services/plugin-worker-manager.js +835 -0
  581. package/dist/services/plugin-worker-manager.js.map +1 -0
  582. package/dist/services/projects.d.ts +92 -0
  583. package/dist/services/projects.d.ts.map +1 -0
  584. package/dist/services/projects.js +705 -0
  585. package/dist/services/projects.js.map +1 -0
  586. package/dist/services/quota-windows.d.ts +9 -0
  587. package/dist/services/quota-windows.d.ts.map +1 -0
  588. package/dist/services/quota-windows.js +56 -0
  589. package/dist/services/quota-windows.js.map +1 -0
  590. package/dist/services/resource-catalog.d.ts +29 -0
  591. package/dist/services/resource-catalog.d.ts.map +1 -0
  592. package/dist/services/resource-catalog.js +298 -0
  593. package/dist/services/resource-catalog.js.map +1 -0
  594. package/dist/services/run-intelligence.d.ts +31 -0
  595. package/dist/services/run-intelligence.d.ts.map +1 -0
  596. package/dist/services/run-intelligence.js +315 -0
  597. package/dist/services/run-intelligence.js.map +1 -0
  598. package/dist/services/run-log-store.d.ts +36 -0
  599. package/dist/services/run-log-store.d.ts.map +1 -0
  600. package/dist/services/run-log-store.js +114 -0
  601. package/dist/services/run-log-store.js.map +1 -0
  602. package/dist/services/runtime-kernel/heartbeat.d.ts +882 -0
  603. package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -0
  604. package/dist/services/runtime-kernel/heartbeat.js +4345 -0
  605. package/dist/services/runtime-kernel/heartbeat.js.map +1 -0
  606. package/dist/services/runtime-trace-metadata.d.ts +12 -0
  607. package/dist/services/runtime-trace-metadata.d.ts.map +1 -0
  608. package/dist/services/runtime-trace-metadata.js +13 -0
  609. package/dist/services/runtime-trace-metadata.js.map +1 -0
  610. package/dist/services/secrets.d.ts +511 -0
  611. package/dist/services/secrets.d.ts.map +1 -0
  612. package/dist/services/secrets.js +289 -0
  613. package/dist/services/secrets.js.map +1 -0
  614. package/dist/services/sidebar-badges.d.ts +11 -0
  615. package/dist/services/sidebar-badges.d.ts.map +1 -0
  616. package/dist/services/sidebar-badges.js +43 -0
  617. package/dist/services/sidebar-badges.js.map +1 -0
  618. package/dist/services/work-products.d.ts +14 -0
  619. package/dist/services/work-products.d.ts.map +1 -0
  620. package/dist/services/work-products.js +100 -0
  621. package/dist/services/work-products.js.map +1 -0
  622. package/dist/services/workspace-operation-log-store.d.ts +35 -0
  623. package/dist/services/workspace-operation-log-store.d.ts.map +1 -0
  624. package/dist/services/workspace-operation-log-store.js +115 -0
  625. package/dist/services/workspace-operation-log-store.js.map +1 -0
  626. package/dist/services/workspace-operations.d.ts +46 -0
  627. package/dist/services/workspace-operations.d.ts.map +1 -0
  628. package/dist/services/workspace-operations.js +237 -0
  629. package/dist/services/workspace-operations.js.map +1 -0
  630. package/dist/services/workspace-runtime.d.ts +164 -0
  631. package/dist/services/workspace-runtime.d.ts.map +1 -0
  632. package/dist/services/workspace-runtime.js +1235 -0
  633. package/dist/services/workspace-runtime.js.map +1 -0
  634. package/dist/startup-banner.d.ts +31 -0
  635. package/dist/startup-banner.d.ts.map +1 -0
  636. package/dist/startup-banner.js +121 -0
  637. package/dist/startup-banner.js.map +1 -0
  638. package/dist/storage/index.d.ts +6 -0
  639. package/dist/storage/index.d.ts.map +1 -0
  640. package/dist/storage/index.js +29 -0
  641. package/dist/storage/index.js.map +1 -0
  642. package/dist/storage/local-disk-provider.d.ts +3 -0
  643. package/dist/storage/local-disk-provider.d.ts.map +1 -0
  644. package/dist/storage/local-disk-provider.js +79 -0
  645. package/dist/storage/local-disk-provider.js.map +1 -0
  646. package/dist/storage/provider-registry.d.ts +4 -0
  647. package/dist/storage/provider-registry.d.ts.map +1 -0
  648. package/dist/storage/provider-registry.js +15 -0
  649. package/dist/storage/provider-registry.js.map +1 -0
  650. package/dist/storage/s3-provider.d.ts +11 -0
  651. package/dist/storage/s3-provider.d.ts.map +1 -0
  652. package/dist/storage/s3-provider.js +123 -0
  653. package/dist/storage/s3-provider.js.map +1 -0
  654. package/dist/storage/service.d.ts +3 -0
  655. package/dist/storage/service.d.ts.map +1 -0
  656. package/dist/storage/service.js +120 -0
  657. package/dist/storage/service.js.map +1 -0
  658. package/dist/storage/types.d.ts +55 -0
  659. package/dist/storage/types.d.ts.map +1 -0
  660. package/dist/storage/types.js +2 -0
  661. package/dist/storage/types.js.map +1 -0
  662. package/dist/ui-branding.d.ts +14 -0
  663. package/dist/ui-branding.d.ts.map +1 -0
  664. package/dist/ui-branding.js +201 -0
  665. package/dist/ui-branding.js.map +1 -0
  666. package/dist/version.d.ts +2 -0
  667. package/dist/version.d.ts.map +1 -0
  668. package/dist/version.js +5 -0
  669. package/dist/version.js.map +1 -0
  670. package/package.json +101 -0
  671. package/resources/bundled-skills/para-memory-files/SKILL.md +114 -0
  672. package/resources/bundled-skills/para-memory-files/references/schemas.md +35 -0
  673. package/resources/bundled-skills/rudder/SKILL.md +265 -0
  674. package/resources/bundled-skills/rudder/references/api-reference.md +253 -0
  675. package/resources/bundled-skills/rudder/references/cli-reference.md +67 -0
  676. package/resources/bundled-skills/rudder/references/organization-skills.md +155 -0
  677. package/resources/bundled-skills/rudder-create-agent/SKILL.md +166 -0
  678. package/resources/bundled-skills/rudder-create-agent/references/api-reference.md +172 -0
  679. package/resources/bundled-skills/rudder-create-agent/references/cli-reference.md +126 -0
  680. package/resources/bundled-skills/rudder-create-plugin/SKILL.md +103 -0
  681. package/resources/community-skills/deep-research/README.md +124 -0
  682. package/resources/community-skills/deep-research/SKILL.md +107 -0
  683. package/resources/community-skills/deep-research/reference/continuation.md +169 -0
  684. package/resources/community-skills/deep-research/reference/html-generation.md +103 -0
  685. package/resources/community-skills/deep-research/reference/methodology.md +421 -0
  686. package/resources/community-skills/deep-research/reference/quality-gates.md +197 -0
  687. package/resources/community-skills/deep-research/reference/report-assembly.md +119 -0
  688. package/resources/community-skills/deep-research/reference/weasyprint_guidelines.md +324 -0
  689. package/resources/community-skills/deep-research/requirements.txt +14 -0
  690. package/resources/community-skills/deep-research/scripts/citation_manager.py +177 -0
  691. package/resources/community-skills/deep-research/scripts/md_to_html.py +330 -0
  692. package/resources/community-skills/deep-research/scripts/research_engine.py +582 -0
  693. package/resources/community-skills/deep-research/scripts/source_evaluator.py +292 -0
  694. package/resources/community-skills/deep-research/scripts/validate_report.py +403 -0
  695. package/resources/community-skills/deep-research/scripts/verify_citations.py +426 -0
  696. package/resources/community-skills/deep-research/scripts/verify_html.py +220 -0
  697. package/resources/community-skills/deep-research/templates/mckinsey_report_template.html +443 -0
  698. package/resources/community-skills/deep-research/templates/report_template.md +433 -0
  699. package/resources/community-skills/skill-creator/SKILL.md +9 -0
  700. package/resources/community-skills/software-product-advisor/SKILL.md +290 -0
  701. package/skills/para-memory-files/SKILL.md +114 -0
  702. package/skills/para-memory-files/references/schemas.md +35 -0
  703. package/skills/rudder/SKILL.md +265 -0
  704. package/skills/rudder/references/api-reference.md +253 -0
  705. package/skills/rudder/references/cli-reference.md +67 -0
  706. package/skills/rudder/references/organization-skills.md +155 -0
  707. package/skills/rudder-create-agent/SKILL.md +166 -0
  708. package/skills/rudder-create-agent/references/api-reference.md +172 -0
  709. package/skills/rudder-create-agent/references/cli-reference.md +126 -0
  710. package/skills/rudder-create-plugin/SKILL.md +103 -0
  711. package/ui-dist/android-chrome-192x192.png +0 -0
  712. package/ui-dist/android-chrome-512x512.png +0 -0
  713. package/ui-dist/android-chrome-maskable-512x512.png +0 -0
  714. package/ui-dist/apple-touch-icon.png +0 -0
  715. package/ui-dist/assets/_basePickBy-CjUu04_e.js +1 -0
  716. package/ui-dist/assets/_baseUniq-C9YNlrVG.js +1 -0
  717. package/ui-dist/assets/apl-B4CMkyY2.js +1 -0
  718. package/ui-dist/assets/arc-CSSZfktq.js +1 -0
  719. package/ui-dist/assets/architectureDiagram-2XIMDMQ5-Co78JKUi.js +36 -0
  720. package/ui-dist/assets/asciiarmor-Df11BRmG.js +1 -0
  721. package/ui-dist/assets/asn1-EdZsLKOL.js +1 -0
  722. package/ui-dist/assets/asterisk-B-8jnY81.js +1 -0
  723. package/ui-dist/assets/blockDiagram-WCTKOSBZ-2KUUIzzz.js +132 -0
  724. package/ui-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  725. package/ui-dist/assets/c4Diagram-IC4MRINW-C6pq8tPP.js +10 -0
  726. package/ui-dist/assets/channel-BEODbRMk.js +1 -0
  727. package/ui-dist/assets/chunk-4BX2VUAB-ojCLkixe.js +1 -0
  728. package/ui-dist/assets/chunk-55IACEB6-MGONqzmz.js +1 -0
  729. package/ui-dist/assets/chunk-FMBD7UC4-CmGuLv2P.js +15 -0
  730. package/ui-dist/assets/chunk-JSJVCQXG-BNBefVr6.js +1 -0
  731. package/ui-dist/assets/chunk-KX2RTZJC-DIGBQLn5.js +1 -0
  732. package/ui-dist/assets/chunk-NQ4KR5QH-_KEutsaQ.js +220 -0
  733. package/ui-dist/assets/chunk-QZHKN3VN-B6pzyuwm.js +1 -0
  734. package/ui-dist/assets/chunk-WL4C6EOR-B8NDzcfm.js +189 -0
  735. package/ui-dist/assets/classDiagram-VBA2DB6C-CsSqaaRj.js +1 -0
  736. package/ui-dist/assets/classDiagram-v2-RAHNMMFH-CsSqaaRj.js +1 -0
  737. package/ui-dist/assets/clike-B9uivgTg.js +1 -0
  738. package/ui-dist/assets/clojure-BMjYHr_A.js +1 -0
  739. package/ui-dist/assets/clone-5oWMCI0u.js +1 -0
  740. package/ui-dist/assets/cmake-BQqOBYOt.js +1 -0
  741. package/ui-dist/assets/cobol-CWcv1MsR.js +1 -0
  742. package/ui-dist/assets/coffeescript-S37ZYGWr.js +1 -0
  743. package/ui-dist/assets/commonlisp-DBKNyK5s.js +1 -0
  744. package/ui-dist/assets/cose-bilkent-S5V4N54A-B1t6ulcV.js +1 -0
  745. package/ui-dist/assets/crystal-SjHAIU92.js +1 -0
  746. package/ui-dist/assets/css-BnMrqG3P.js +1 -0
  747. package/ui-dist/assets/cypher-C_CwsFkJ.js +1 -0
  748. package/ui-dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  749. package/ui-dist/assets/d-pRatUO7H.js +1 -0
  750. package/ui-dist/assets/dagre-KLK3FWXG-DWVC5_HJ.js +4 -0
  751. package/ui-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  752. package/ui-dist/assets/diagram-E7M64L7V-C4ztYLox.js +24 -0
  753. package/ui-dist/assets/diagram-IFDJBPK2-DtWBGLnA.js +43 -0
  754. package/ui-dist/assets/diagram-P4PSJMXO-BiqiI4Df.js +24 -0
  755. package/ui-dist/assets/diff-DbItnlRl.js +1 -0
  756. package/ui-dist/assets/dockerfile-BKs6k2Af.js +1 -0
  757. package/ui-dist/assets/dtd-DF_7sFjM.js +1 -0
  758. package/ui-dist/assets/dylan-DwRh75JA.js +1 -0
  759. package/ui-dist/assets/ebnf-CDyGwa7X.js +1 -0
  760. package/ui-dist/assets/ecl-Cabwm37j.js +1 -0
  761. package/ui-dist/assets/eiffel-CnydiIhH.js +1 -0
  762. package/ui-dist/assets/elm-vLlmbW-K.js +1 -0
  763. package/ui-dist/assets/erDiagram-INFDFZHY-CUhr9rIh.js +70 -0
  764. package/ui-dist/assets/erlang-BNw1qcRV.js +1 -0
  765. package/ui-dist/assets/factor-kuTfRLto.js +1 -0
  766. package/ui-dist/assets/fcl-Kvtd6kyn.js +1 -0
  767. package/ui-dist/assets/flowDiagram-PKNHOUZH-BEqBmNL-.js +162 -0
  768. package/ui-dist/assets/forth-Ffai-XNe.js +1 -0
  769. package/ui-dist/assets/fortran-DYz_wnZ1.js +1 -0
  770. package/ui-dist/assets/ganttDiagram-A5KZAMGK-CdeWhdno.js +292 -0
  771. package/ui-dist/assets/gas-Bneqetm1.js +1 -0
  772. package/ui-dist/assets/gherkin-heZmZLOM.js +1 -0
  773. package/ui-dist/assets/gitGraphDiagram-K3NZZRJ6-CgG66QFg.js +65 -0
  774. package/ui-dist/assets/graph-rmownl79.js +1 -0
  775. package/ui-dist/assets/groovy-D9Dt4D0W.js +1 -0
  776. package/ui-dist/assets/haskell-Cw1EW3IL.js +1 -0
  777. package/ui-dist/assets/haxe-H-WmDvRZ.js +1 -0
  778. package/ui-dist/assets/http-DBlCnlav.js +1 -0
  779. package/ui-dist/assets/idl-BEugSyMb.js +1 -0
  780. package/ui-dist/assets/index-B1YyDqaG.js +1 -0
  781. package/ui-dist/assets/index-B7exNxYd.js +1 -0
  782. package/ui-dist/assets/index-BIuriVDl.js +1 -0
  783. package/ui-dist/assets/index-BT9rfwYt.js +1 -0
  784. package/ui-dist/assets/index-BZhmacJG.js +1 -0
  785. package/ui-dist/assets/index-B_ebS3U_.js +3 -0
  786. package/ui-dist/assets/index-BnQqZOsc.js +1 -0
  787. package/ui-dist/assets/index-BwPbAax6.js +1 -0
  788. package/ui-dist/assets/index-C5i670o5.js +1 -0
  789. package/ui-dist/assets/index-C9KwE7Yr.js +1 -0
  790. package/ui-dist/assets/index-CDId_UjP.js +1 -0
  791. package/ui-dist/assets/index-CI9ydSGM.js +1 -0
  792. package/ui-dist/assets/index-CKpm3WGI.css +1 -0
  793. package/ui-dist/assets/index-CMP_bzP3.js +2 -0
  794. package/ui-dist/assets/index-CRcHIoCW.js +1 -0
  795. package/ui-dist/assets/index-DZqNY-Lg.js +1 -0
  796. package/ui-dist/assets/index-DbDKJhW-.js +7 -0
  797. package/ui-dist/assets/index-Dkg6MwQ_.js +1 -0
  798. package/ui-dist/assets/index-Dn0iitKg.js +1 -0
  799. package/ui-dist/assets/index-GvHywIOA.js +1323 -0
  800. package/ui-dist/assets/index-WtX4Y4Fx.js +13 -0
  801. package/ui-dist/assets/index-iyC5PHC3.js +6 -0
  802. package/ui-dist/assets/index-jMlzlqoV.js +1 -0
  803. package/ui-dist/assets/index-pTIOLGTe.js +1 -0
  804. package/ui-dist/assets/infoDiagram-LFFYTUFH-CEhdbTYQ.js +2 -0
  805. package/ui-dist/assets/init-Gi6I4Gst.js +1 -0
  806. package/ui-dist/assets/ishikawaDiagram-PHBUUO56-g9GiiXI2.js +70 -0
  807. package/ui-dist/assets/javascript-iXu5QeM3.js +1 -0
  808. package/ui-dist/assets/journeyDiagram-4ABVD52K-CheeZzlg.js +139 -0
  809. package/ui-dist/assets/julia-DuME0IfC.js +1 -0
  810. package/ui-dist/assets/kanban-definition-K7BYSVSG-BTpuAgUJ.js +89 -0
  811. package/ui-dist/assets/katex-B1X10hvy.js +261 -0
  812. package/ui-dist/assets/layout-CuBgufef.js +1 -0
  813. package/ui-dist/assets/linear-CnXO6wXw.js +1 -0
  814. package/ui-dist/assets/livescript-BwQOo05w.js +1 -0
  815. package/ui-dist/assets/lua-BgMRiT3U.js +1 -0
  816. package/ui-dist/assets/mathematica-DTrFuWx2.js +1 -0
  817. package/ui-dist/assets/mbox-CNhZ1qSd.js +1 -0
  818. package/ui-dist/assets/mermaid.core-DVaYxfh9.js +255 -0
  819. package/ui-dist/assets/mindmap-definition-YRQLILUH-00nAuexq.js +68 -0
  820. package/ui-dist/assets/mirc-CjQqDB4T.js +1 -0
  821. package/ui-dist/assets/mllike-CXdrOF99.js +1 -0
  822. package/ui-dist/assets/modelica-Dc1JOy9r.js +1 -0
  823. package/ui-dist/assets/mscgen-BA5vi2Kp.js +1 -0
  824. package/ui-dist/assets/mumps-BT43cFF4.js +1 -0
  825. package/ui-dist/assets/nginx-DdIZxoE0.js +1 -0
  826. package/ui-dist/assets/nsis-LdVXkNf5.js +1 -0
  827. package/ui-dist/assets/ntriples-BfvgReVJ.js +1 -0
  828. package/ui-dist/assets/octave-Ck1zUtKM.js +1 -0
  829. package/ui-dist/assets/ordinal-Cboi1Yqb.js +1 -0
  830. package/ui-dist/assets/oz-BzwKVEFT.js +1 -0
  831. package/ui-dist/assets/pascal--L3eBynH.js +1 -0
  832. package/ui-dist/assets/perl-CdXCOZ3F.js +1 -0
  833. package/ui-dist/assets/pieDiagram-SKSYHLDU-NaOgRqIj.js +30 -0
  834. package/ui-dist/assets/pig-CevX1Tat.js +1 -0
  835. package/ui-dist/assets/powershell-CFHJl5sT.js +1 -0
  836. package/ui-dist/assets/properties-C78fOPTZ.js +1 -0
  837. package/ui-dist/assets/protobuf-ChK-085T.js +1 -0
  838. package/ui-dist/assets/pug-DeIclll2.js +1 -0
  839. package/ui-dist/assets/puppet-DMA9R1ak.js +1 -0
  840. package/ui-dist/assets/python-BuPzkPfP.js +1 -0
  841. package/ui-dist/assets/q-pXgVlZs6.js +1 -0
  842. package/ui-dist/assets/quadrantDiagram-337W2JSQ-Bnf9OCW0.js +7 -0
  843. package/ui-dist/assets/r-B6wPVr8A.js +1 -0
  844. package/ui-dist/assets/requirementDiagram-Z7DCOOCP-BiacZTTh.js +73 -0
  845. package/ui-dist/assets/rpm-CTu-6PCP.js +1 -0
  846. package/ui-dist/assets/ruby-B2Rjki9n.js +1 -0
  847. package/ui-dist/assets/sankeyDiagram-WA2Y5GQK-DOuD4D2Q.js +10 -0
  848. package/ui-dist/assets/sas-B4kiWyti.js +1 -0
  849. package/ui-dist/assets/scheme-C41bIUwD.js +1 -0
  850. package/ui-dist/assets/sequenceDiagram-2WXFIKYE-oV3M_w-H.js +145 -0
  851. package/ui-dist/assets/shell-CjFT_Tl9.js +1 -0
  852. package/ui-dist/assets/sieve-C3Gn_uJK.js +1 -0
  853. package/ui-dist/assets/simple-mode-GW_nhZxv.js +1 -0
  854. package/ui-dist/assets/smalltalk-CnHTOXQT.js +1 -0
  855. package/ui-dist/assets/solr-DehyRSwq.js +1 -0
  856. package/ui-dist/assets/sparql-DkYu6x3z.js +1 -0
  857. package/ui-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  858. package/ui-dist/assets/sql-D0XecflT.js +1 -0
  859. package/ui-dist/assets/stateDiagram-RAJIS63D-CdRc2Pqb.js +1 -0
  860. package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-CIMHFJYg.js +1 -0
  861. package/ui-dist/assets/stex-C3f8Ysf7.js +1 -0
  862. package/ui-dist/assets/stylus-B533Al4x.js +1 -0
  863. package/ui-dist/assets/swift-BzpIVaGY.js +1 -0
  864. package/ui-dist/assets/tcl-DVfN8rqt.js +1 -0
  865. package/ui-dist/assets/textile-CnDTJFAw.js +1 -0
  866. package/ui-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  867. package/ui-dist/assets/tiki-DGYXhP31.js +1 -0
  868. package/ui-dist/assets/timeline-definition-YZTLITO2-BCWQDIwt.js +61 -0
  869. package/ui-dist/assets/toml-Bm5Em-hy.js +1 -0
  870. package/ui-dist/assets/treemap-KZPCXAKY-BvsIxXAi.js +162 -0
  871. package/ui-dist/assets/troff-wAsdV37c.js +1 -0
  872. package/ui-dist/assets/ttcn-CfJYG6tj.js +1 -0
  873. package/ui-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  874. package/ui-dist/assets/turtle-B1tBg_DP.js +1 -0
  875. package/ui-dist/assets/vb-CmGdzxic.js +1 -0
  876. package/ui-dist/assets/vbscript-BuJXcnF6.js +1 -0
  877. package/ui-dist/assets/velocity-D8B20fx6.js +1 -0
  878. package/ui-dist/assets/vennDiagram-LZ73GAT5-BzibHs4r.js +34 -0
  879. package/ui-dist/assets/verilog-C6RDOZhf.js +1 -0
  880. package/ui-dist/assets/vhdl-lSbBsy5d.js +1 -0
  881. package/ui-dist/assets/webidl-ZXfAyPTL.js +1 -0
  882. package/ui-dist/assets/xquery-DzFWVndE.js +1 -0
  883. package/ui-dist/assets/xychartDiagram-JWTSCODW-CX_Xt_y-.js +7 -0
  884. package/ui-dist/assets/yacas-BJ4BC0dw.js +1 -0
  885. package/ui-dist/assets/z80-Hz9HOZM7.js +1 -0
  886. package/ui-dist/brands/opencode-logo-dark-square.svg +18 -0
  887. package/ui-dist/brands/opencode-logo-light-square.svg +18 -0
  888. package/ui-dist/favicon-16x16.png +0 -0
  889. package/ui-dist/favicon-32x32.png +0 -0
  890. package/ui-dist/favicon-dev-16x16.png +0 -0
  891. package/ui-dist/favicon-dev-32x32.png +0 -0
  892. package/ui-dist/favicon-dev.ico +0 -0
  893. package/ui-dist/favicon.ico +0 -0
  894. package/ui-dist/favicon.svg +1 -0
  895. package/ui-dist/index.html +61 -0
  896. package/ui-dist/rudder-logo.png +0 -0
  897. package/ui-dist/site.webmanifest +30 -0
  898. package/ui-dist/sw.js +42 -0
  899. package/ui-dist/worktree-favicon-16x16.png +0 -0
  900. package/ui-dist/worktree-favicon-32x32.png +0 -0
  901. package/ui-dist/worktree-favicon.ico +0 -0
  902. package/ui-dist/worktree-favicon.svg +1 -0
@@ -0,0 +1,1615 @@
1
+ import { Router } from "express";
2
+ import multer from "multer";
3
+ import { addIssueCommentSchema, createIssueAttachmentMetadataSchema, createIssueWorkProductSchema, createIssueLabelSchema, checkoutIssueSchema, createIssueSchema, linkIssueApprovalSchema, issueDocumentKeySchema, updateIssueLabelSchema, updateIssueWorkProductSchema, upsertIssueDocumentSchema, updateIssueSchema, } from "@rudderhq/shared";
4
+ import { validate } from "../middleware/validate.js";
5
+ import { accessService, agentService, executionWorkspaceService, goalService, heartbeatService, issueApprovalService, issueService, documentService, logActivity, projectService, automationService, workProductService, } from "../services/index.js";
6
+ import { logger } from "../middleware/logger.js";
7
+ import { forbidden, HttpError, unauthorized } from "../errors.js";
8
+ import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
9
+ import { shouldWakeAssigneeOnCheckout } from "./issues-checkout-wakeup.js";
10
+ import { isAllowedContentType, MAX_ATTACHMENT_BYTES } from "../attachment-types.js";
11
+ import { queueIssueAssignmentWakeup } from "../services/issue-assignment-wakeup.js";
12
+ const MAX_ISSUE_COMMENT_LIMIT = 500;
13
+ export function issueRoutes(db, storage) {
14
+ const router = Router();
15
+ const svc = issueService(db);
16
+ const access = accessService(db);
17
+ const heartbeat = heartbeatService(db);
18
+ const agentsSvc = agentService(db);
19
+ const projectsSvc = projectService(db);
20
+ const goalsSvc = goalService(db);
21
+ const issueApprovalsSvc = issueApprovalService(db);
22
+ const executionWorkspacesSvc = executionWorkspaceService(db);
23
+ const workProductsSvc = workProductService(db);
24
+ const documentsSvc = documentService(db);
25
+ const automationsSvc = automationService(db);
26
+ const upload = multer({
27
+ storage: multer.memoryStorage(),
28
+ limits: { fileSize: MAX_ATTACHMENT_BYTES, files: 1 },
29
+ });
30
+ function withContentPath(attachment) {
31
+ return {
32
+ ...attachment,
33
+ contentPath: `/api/attachments/${attachment.id}/content`,
34
+ };
35
+ }
36
+ async function runSingleFileUpload(req, res) {
37
+ await new Promise((resolve, reject) => {
38
+ upload.single("file")(req, res, (err) => {
39
+ if (err)
40
+ reject(err);
41
+ else
42
+ resolve();
43
+ });
44
+ });
45
+ }
46
+ async function assertCanManageIssueApprovalLinks(req, res, orgId) {
47
+ assertCompanyAccess(req, orgId);
48
+ if (req.actor.type === "board")
49
+ return true;
50
+ if (!req.actor.agentId) {
51
+ res.status(403).json({ error: "Agent authentication required" });
52
+ return false;
53
+ }
54
+ const actorAgent = await agentsSvc.getById(req.actor.agentId);
55
+ if (!actorAgent || actorAgent.orgId !== orgId) {
56
+ res.status(403).json({ error: "Forbidden" });
57
+ return false;
58
+ }
59
+ if (actorAgent.role === "ceo" || Boolean(actorAgent.permissions?.canCreateAgents))
60
+ return true;
61
+ res.status(403).json({ error: "Missing permission to link approvals" });
62
+ return false;
63
+ }
64
+ function canCreateAgentsLegacy(agent) {
65
+ if (agent.role === "ceo")
66
+ return true;
67
+ if (!agent.permissions || typeof agent.permissions !== "object")
68
+ return false;
69
+ return Boolean(agent.permissions.canCreateAgents);
70
+ }
71
+ async function assertCanAssignTasks(req, orgId) {
72
+ assertCompanyAccess(req, orgId);
73
+ if (req.actor.type === "board") {
74
+ if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)
75
+ return;
76
+ const allowed = await access.canUser(orgId, req.actor.userId, "tasks:assign");
77
+ if (!allowed)
78
+ throw forbidden("Missing permission: tasks:assign");
79
+ return;
80
+ }
81
+ if (req.actor.type === "agent") {
82
+ if (!req.actor.agentId)
83
+ throw forbidden("Agent authentication required");
84
+ const allowedByGrant = await access.hasPermission(orgId, "agent", req.actor.agentId, "tasks:assign");
85
+ if (allowedByGrant)
86
+ return;
87
+ const actorAgent = await agentsSvc.getById(req.actor.agentId);
88
+ if (actorAgent && actorAgent.orgId === orgId && canCreateAgentsLegacy(actorAgent))
89
+ return;
90
+ throw forbidden("Missing permission: tasks:assign");
91
+ }
92
+ throw unauthorized();
93
+ }
94
+ function requireAgentRunId(req, res) {
95
+ if (req.actor.type !== "agent")
96
+ return null;
97
+ const runId = req.actor.runId?.trim();
98
+ if (runId)
99
+ return runId;
100
+ res.status(401).json({ error: "Agent run id required" });
101
+ return null;
102
+ }
103
+ async function assertAgentRunCheckoutOwnership(req, res, issue) {
104
+ if (req.actor.type !== "agent")
105
+ return true;
106
+ const actorAgentId = req.actor.agentId;
107
+ if (!actorAgentId) {
108
+ res.status(403).json({ error: "Agent authentication required" });
109
+ return false;
110
+ }
111
+ if (issue.status !== "in_progress" || issue.assigneeAgentId !== actorAgentId) {
112
+ return true;
113
+ }
114
+ const runId = requireAgentRunId(req, res);
115
+ if (!runId)
116
+ return false;
117
+ const ownership = await svc.assertCheckoutOwner(issue.id, actorAgentId, runId);
118
+ if (ownership.adoptedFromRunId) {
119
+ const actor = getActorInfo(req);
120
+ await logActivity(db, {
121
+ orgId: issue.orgId,
122
+ actorType: actor.actorType,
123
+ actorId: actor.actorId,
124
+ agentId: actor.agentId,
125
+ runId: actor.runId,
126
+ action: "issue.checkout_lock_adopted",
127
+ entityType: "issue",
128
+ entityId: issue.id,
129
+ details: {
130
+ previousCheckoutRunId: ownership.adoptedFromRunId,
131
+ checkoutRunId: runId,
132
+ reason: "stale_checkout_run",
133
+ },
134
+ });
135
+ }
136
+ return true;
137
+ }
138
+ async function normalizeIssueIdentifier(rawId) {
139
+ if (/^[A-Z]+-\d+$/i.test(rawId)) {
140
+ const issue = await svc.getByIdentifier(rawId);
141
+ if (issue) {
142
+ return issue.id;
143
+ }
144
+ }
145
+ return rawId;
146
+ }
147
+ function boardUserId(req) {
148
+ assertBoard(req);
149
+ return req.actor.userId ?? "local-board";
150
+ }
151
+ // Resolve issue identifiers (e.g. "PAP-39") to UUIDs for all /issues/:id routes
152
+ router.param("id", async (req, res, next, rawId) => {
153
+ try {
154
+ req.params.id = await normalizeIssueIdentifier(rawId);
155
+ next();
156
+ }
157
+ catch (err) {
158
+ next(err);
159
+ }
160
+ });
161
+ // Resolve issue identifiers (e.g. "PAP-39") to UUIDs for organization-scoped attachment routes.
162
+ router.param("issueId", async (req, res, next, rawId) => {
163
+ try {
164
+ req.params.issueId = await normalizeIssueIdentifier(rawId);
165
+ next();
166
+ }
167
+ catch (err) {
168
+ next(err);
169
+ }
170
+ });
171
+ // Common malformed path when orgId is empty in "/api/orgs/{orgId}/issues".
172
+ router.get("/issues", (_req, res) => {
173
+ res.status(400).json({
174
+ error: "Missing orgId in path. Use /api/orgs/{orgId}/issues.",
175
+ });
176
+ });
177
+ router.get("/orgs/:orgId/issues", async (req, res) => {
178
+ const orgId = req.params.orgId;
179
+ assertCompanyAccess(req, orgId);
180
+ const assigneeUserFilterRaw = req.query.assigneeUserId;
181
+ const touchedByUserFilterRaw = req.query.touchedByUserId;
182
+ const unreadForUserFilterRaw = req.query.unreadForUserId;
183
+ const assigneeUserId = assigneeUserFilterRaw === "me" && req.actor.type === "board"
184
+ ? req.actor.userId
185
+ : assigneeUserFilterRaw;
186
+ const touchedByUserId = touchedByUserFilterRaw === "me" && req.actor.type === "board"
187
+ ? req.actor.userId
188
+ : touchedByUserFilterRaw;
189
+ const unreadForUserId = unreadForUserFilterRaw === "me" && req.actor.type === "board"
190
+ ? req.actor.userId
191
+ : unreadForUserFilterRaw;
192
+ if (assigneeUserFilterRaw === "me" && (!assigneeUserId || req.actor.type !== "board")) {
193
+ res.status(403).json({ error: "assigneeUserId=me requires board authentication" });
194
+ return;
195
+ }
196
+ if (touchedByUserFilterRaw === "me" && (!touchedByUserId || req.actor.type !== "board")) {
197
+ res.status(403).json({ error: "touchedByUserId=me requires board authentication" });
198
+ return;
199
+ }
200
+ if (unreadForUserFilterRaw === "me" && (!unreadForUserId || req.actor.type !== "board")) {
201
+ res.status(403).json({ error: "unreadForUserId=me requires board authentication" });
202
+ return;
203
+ }
204
+ const result = await svc.list(orgId, {
205
+ status: req.query.status,
206
+ assigneeAgentId: req.query.assigneeAgentId,
207
+ participantAgentId: req.query.participantAgentId,
208
+ assigneeUserId,
209
+ touchedByUserId,
210
+ unreadForUserId,
211
+ projectId: req.query.projectId,
212
+ parentId: req.query.parentId,
213
+ labelId: req.query.labelId,
214
+ originKind: req.query.originKind,
215
+ originId: req.query.originId,
216
+ includeAutomationExecutions: req.query.includeAutomationExecutions === "true" || req.query.includeAutomationExecutions === "1",
217
+ q: req.query.q,
218
+ });
219
+ res.json(result);
220
+ });
221
+ router.get("/orgs/:orgId/issues/follows", async (req, res) => {
222
+ const orgId = req.params.orgId;
223
+ assertCompanyAccess(req, orgId);
224
+ if (req.actor.type !== "board") {
225
+ res.status(403).json({ error: "Board authentication required" });
226
+ return;
227
+ }
228
+ const userId = req.actor.userId;
229
+ if (!userId) {
230
+ res.status(403).json({ error: "Board user context required" });
231
+ return;
232
+ }
233
+ const rows = await svc.listFollows(orgId, userId);
234
+ res.json(rows);
235
+ });
236
+ router.get("/orgs/:orgId/labels", async (req, res) => {
237
+ const orgId = req.params.orgId;
238
+ assertCompanyAccess(req, orgId);
239
+ const result = await svc.listLabels(orgId);
240
+ res.json(result);
241
+ });
242
+ router.post("/orgs/:orgId/labels", validate(createIssueLabelSchema), async (req, res) => {
243
+ const orgId = req.params.orgId;
244
+ assertCompanyAccess(req, orgId);
245
+ const label = await svc.createLabel(orgId, req.body);
246
+ const actor = getActorInfo(req);
247
+ await logActivity(db, {
248
+ orgId,
249
+ actorType: actor.actorType,
250
+ actorId: actor.actorId,
251
+ agentId: actor.agentId,
252
+ runId: actor.runId,
253
+ action: "label.created",
254
+ entityType: "label",
255
+ entityId: label.id,
256
+ details: { name: label.name, color: label.color },
257
+ });
258
+ res.status(201).json(label);
259
+ });
260
+ router.patch("/labels/:labelId", validate(updateIssueLabelSchema), async (req, res) => {
261
+ const labelId = req.params.labelId;
262
+ const existing = await svc.getLabelById(labelId);
263
+ if (!existing) {
264
+ res.status(404).json({ error: "Label not found" });
265
+ return;
266
+ }
267
+ assertCompanyAccess(req, existing.orgId);
268
+ const updated = await svc.updateLabel(labelId, req.body);
269
+ if (!updated) {
270
+ res.status(404).json({ error: "Label not found" });
271
+ return;
272
+ }
273
+ const actor = getActorInfo(req);
274
+ await logActivity(db, {
275
+ orgId: updated.orgId,
276
+ actorType: actor.actorType,
277
+ actorId: actor.actorId,
278
+ agentId: actor.agentId,
279
+ runId: actor.runId,
280
+ action: "label.updated",
281
+ entityType: "label",
282
+ entityId: updated.id,
283
+ details: { name: updated.name, color: updated.color },
284
+ });
285
+ res.json(updated);
286
+ });
287
+ router.delete("/labels/:labelId", async (req, res) => {
288
+ const labelId = req.params.labelId;
289
+ const existing = await svc.getLabelById(labelId);
290
+ if (!existing) {
291
+ res.status(404).json({ error: "Label not found" });
292
+ return;
293
+ }
294
+ assertCompanyAccess(req, existing.orgId);
295
+ const removed = await svc.deleteLabel(labelId);
296
+ if (!removed) {
297
+ res.status(404).json({ error: "Label not found" });
298
+ return;
299
+ }
300
+ const actor = getActorInfo(req);
301
+ await logActivity(db, {
302
+ orgId: removed.orgId,
303
+ actorType: actor.actorType,
304
+ actorId: actor.actorId,
305
+ agentId: actor.agentId,
306
+ runId: actor.runId,
307
+ action: "label.deleted",
308
+ entityType: "label",
309
+ entityId: removed.id,
310
+ details: { name: removed.name, color: removed.color },
311
+ });
312
+ res.json(removed);
313
+ });
314
+ router.get("/issues/:id", async (req, res) => {
315
+ const id = req.params.id;
316
+ const issue = await svc.getById(id);
317
+ if (!issue) {
318
+ res.status(404).json({ error: "Issue not found" });
319
+ return;
320
+ }
321
+ assertCompanyAccess(req, issue.orgId);
322
+ const [ancestors, project, goal, mentionedProjectIds, documentPayload] = await Promise.all([
323
+ svc.getAncestors(issue.id),
324
+ issue.projectId ? projectsSvc.getById(issue.projectId) : null,
325
+ issue.goalId
326
+ ? goalsSvc.getById(issue.goalId)
327
+ : !issue.projectId
328
+ ? goalsSvc.getDefaultCompanyGoal(issue.orgId)
329
+ : null,
330
+ svc.findMentionedProjectIds(issue.id),
331
+ documentsSvc.getIssueDocumentPayload(issue),
332
+ ]);
333
+ const mentionedProjects = mentionedProjectIds.length > 0
334
+ ? await projectsSvc.listByIds(issue.orgId, mentionedProjectIds)
335
+ : [];
336
+ const currentExecutionWorkspace = issue.executionWorkspaceId
337
+ ? await executionWorkspacesSvc.getById(issue.executionWorkspaceId)
338
+ : null;
339
+ const workProducts = await workProductsSvc.listForIssue(issue.id);
340
+ res.json({
341
+ ...issue,
342
+ goalId: goal?.id ?? issue.goalId,
343
+ ancestors,
344
+ ...documentPayload,
345
+ project: project ?? null,
346
+ goal: goal ?? null,
347
+ mentionedProjects,
348
+ currentExecutionWorkspace,
349
+ workProducts,
350
+ });
351
+ });
352
+ router.get("/issues/:id/heartbeat-context", async (req, res) => {
353
+ const id = req.params.id;
354
+ const issue = await svc.getById(id);
355
+ if (!issue) {
356
+ res.status(404).json({ error: "Issue not found" });
357
+ return;
358
+ }
359
+ assertCompanyAccess(req, issue.orgId);
360
+ const wakeCommentId = typeof req.query.wakeCommentId === "string" && req.query.wakeCommentId.trim().length > 0
361
+ ? req.query.wakeCommentId.trim()
362
+ : null;
363
+ const [ancestors, project, goal, commentCursor, wakeComment] = await Promise.all([
364
+ svc.getAncestors(issue.id),
365
+ issue.projectId ? projectsSvc.getById(issue.projectId) : null,
366
+ issue.goalId
367
+ ? goalsSvc.getById(issue.goalId)
368
+ : !issue.projectId
369
+ ? goalsSvc.getDefaultCompanyGoal(issue.orgId)
370
+ : null,
371
+ svc.getCommentCursor(issue.id),
372
+ wakeCommentId ? svc.getComment(wakeCommentId) : null,
373
+ ]);
374
+ res.json({
375
+ issue: {
376
+ id: issue.id,
377
+ identifier: issue.identifier,
378
+ title: issue.title,
379
+ description: issue.description,
380
+ status: issue.status,
381
+ priority: issue.priority,
382
+ projectId: issue.projectId,
383
+ goalId: goal?.id ?? issue.goalId,
384
+ parentId: issue.parentId,
385
+ assigneeAgentId: issue.assigneeAgentId,
386
+ assigneeUserId: issue.assigneeUserId,
387
+ updatedAt: issue.updatedAt,
388
+ },
389
+ ancestors: ancestors.map((ancestor) => ({
390
+ id: ancestor.id,
391
+ identifier: ancestor.identifier,
392
+ title: ancestor.title,
393
+ status: ancestor.status,
394
+ priority: ancestor.priority,
395
+ })),
396
+ project: project
397
+ ? {
398
+ id: project.id,
399
+ name: project.name,
400
+ status: project.status,
401
+ targetDate: project.targetDate,
402
+ }
403
+ : null,
404
+ goal: goal
405
+ ? {
406
+ id: goal.id,
407
+ title: goal.title,
408
+ status: goal.status,
409
+ level: goal.level,
410
+ parentId: goal.parentId,
411
+ }
412
+ : null,
413
+ commentCursor,
414
+ wakeComment: wakeComment && wakeComment.issueId === issue.id
415
+ ? wakeComment
416
+ : null,
417
+ });
418
+ });
419
+ router.get("/issues/:id/work-products", async (req, res) => {
420
+ const id = req.params.id;
421
+ const issue = await svc.getById(id);
422
+ if (!issue) {
423
+ res.status(404).json({ error: "Issue not found" });
424
+ return;
425
+ }
426
+ assertCompanyAccess(req, issue.orgId);
427
+ const workProducts = await workProductsSvc.listForIssue(issue.id);
428
+ res.json(workProducts);
429
+ });
430
+ router.get("/issues/:id/documents", async (req, res) => {
431
+ const id = req.params.id;
432
+ const issue = await svc.getById(id);
433
+ if (!issue) {
434
+ res.status(404).json({ error: "Issue not found" });
435
+ return;
436
+ }
437
+ assertCompanyAccess(req, issue.orgId);
438
+ const docs = await documentsSvc.listIssueDocuments(issue.id);
439
+ res.json(docs);
440
+ });
441
+ router.get("/issues/:id/documents/:key", async (req, res) => {
442
+ const id = req.params.id;
443
+ const issue = await svc.getById(id);
444
+ if (!issue) {
445
+ res.status(404).json({ error: "Issue not found" });
446
+ return;
447
+ }
448
+ assertCompanyAccess(req, issue.orgId);
449
+ const keyParsed = issueDocumentKeySchema.safeParse(String(req.params.key ?? "").trim().toLowerCase());
450
+ if (!keyParsed.success) {
451
+ res.status(400).json({ error: "Invalid document key", details: keyParsed.error.issues });
452
+ return;
453
+ }
454
+ const doc = await documentsSvc.getIssueDocumentByKey(issue.id, keyParsed.data);
455
+ if (!doc) {
456
+ res.status(404).json({ error: "Document not found" });
457
+ return;
458
+ }
459
+ res.json(doc);
460
+ });
461
+ router.put("/issues/:id/documents/:key", validate(upsertIssueDocumentSchema), async (req, res) => {
462
+ const id = req.params.id;
463
+ const issue = await svc.getById(id);
464
+ if (!issue) {
465
+ res.status(404).json({ error: "Issue not found" });
466
+ return;
467
+ }
468
+ assertCompanyAccess(req, issue.orgId);
469
+ const keyParsed = issueDocumentKeySchema.safeParse(String(req.params.key ?? "").trim().toLowerCase());
470
+ if (!keyParsed.success) {
471
+ res.status(400).json({ error: "Invalid document key", details: keyParsed.error.issues });
472
+ return;
473
+ }
474
+ const actor = getActorInfo(req);
475
+ const result = await documentsSvc.upsertIssueDocument({
476
+ issueId: issue.id,
477
+ key: keyParsed.data,
478
+ title: req.body.title ?? null,
479
+ format: req.body.format,
480
+ body: req.body.body,
481
+ changeSummary: req.body.changeSummary ?? null,
482
+ baseRevisionId: req.body.baseRevisionId ?? null,
483
+ createdByAgentId: actor.agentId ?? null,
484
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
485
+ });
486
+ const doc = result.document;
487
+ await logActivity(db, {
488
+ orgId: issue.orgId,
489
+ actorType: actor.actorType,
490
+ actorId: actor.actorId,
491
+ agentId: actor.agentId,
492
+ runId: actor.runId,
493
+ action: result.created ? "issue.document_created" : "issue.document_updated",
494
+ entityType: "issue",
495
+ entityId: issue.id,
496
+ details: {
497
+ key: doc.key,
498
+ documentId: doc.id,
499
+ title: doc.title,
500
+ format: doc.format,
501
+ revisionNumber: doc.latestRevisionNumber,
502
+ },
503
+ });
504
+ res.status(result.created ? 201 : 200).json(doc);
505
+ });
506
+ router.get("/issues/:id/documents/:key/revisions", async (req, res) => {
507
+ const id = req.params.id;
508
+ const issue = await svc.getById(id);
509
+ if (!issue) {
510
+ res.status(404).json({ error: "Issue not found" });
511
+ return;
512
+ }
513
+ assertCompanyAccess(req, issue.orgId);
514
+ const keyParsed = issueDocumentKeySchema.safeParse(String(req.params.key ?? "").trim().toLowerCase());
515
+ if (!keyParsed.success) {
516
+ res.status(400).json({ error: "Invalid document key", details: keyParsed.error.issues });
517
+ return;
518
+ }
519
+ const revisions = await documentsSvc.listIssueDocumentRevisions(issue.id, keyParsed.data);
520
+ res.json(revisions);
521
+ });
522
+ router.delete("/issues/:id/documents/:key", async (req, res) => {
523
+ const id = req.params.id;
524
+ const issue = await svc.getById(id);
525
+ if (!issue) {
526
+ res.status(404).json({ error: "Issue not found" });
527
+ return;
528
+ }
529
+ assertCompanyAccess(req, issue.orgId);
530
+ if (req.actor.type !== "board") {
531
+ res.status(403).json({ error: "Board authentication required" });
532
+ return;
533
+ }
534
+ const keyParsed = issueDocumentKeySchema.safeParse(String(req.params.key ?? "").trim().toLowerCase());
535
+ if (!keyParsed.success) {
536
+ res.status(400).json({ error: "Invalid document key", details: keyParsed.error.issues });
537
+ return;
538
+ }
539
+ const removed = await documentsSvc.deleteIssueDocument(issue.id, keyParsed.data);
540
+ if (!removed) {
541
+ res.status(404).json({ error: "Document not found" });
542
+ return;
543
+ }
544
+ const actor = getActorInfo(req);
545
+ await logActivity(db, {
546
+ orgId: issue.orgId,
547
+ actorType: actor.actorType,
548
+ actorId: actor.actorId,
549
+ agentId: actor.agentId,
550
+ runId: actor.runId,
551
+ action: "issue.document_deleted",
552
+ entityType: "issue",
553
+ entityId: issue.id,
554
+ details: {
555
+ key: removed.key,
556
+ documentId: removed.id,
557
+ title: removed.title,
558
+ },
559
+ });
560
+ res.json({ ok: true });
561
+ });
562
+ router.post("/issues/:id/work-products", validate(createIssueWorkProductSchema), async (req, res) => {
563
+ const id = req.params.id;
564
+ const issue = await svc.getById(id);
565
+ if (!issue) {
566
+ res.status(404).json({ error: "Issue not found" });
567
+ return;
568
+ }
569
+ assertCompanyAccess(req, issue.orgId);
570
+ const product = await workProductsSvc.createForIssue(issue.id, issue.orgId, {
571
+ ...req.body,
572
+ projectId: req.body.projectId ?? issue.projectId ?? null,
573
+ });
574
+ if (!product) {
575
+ res.status(422).json({ error: "Invalid work product payload" });
576
+ return;
577
+ }
578
+ const actor = getActorInfo(req);
579
+ await logActivity(db, {
580
+ orgId: issue.orgId,
581
+ actorType: actor.actorType,
582
+ actorId: actor.actorId,
583
+ agentId: actor.agentId,
584
+ runId: actor.runId,
585
+ action: "issue.work_product_created",
586
+ entityType: "issue",
587
+ entityId: issue.id,
588
+ details: { workProductId: product.id, type: product.type, provider: product.provider },
589
+ });
590
+ res.status(201).json(product);
591
+ });
592
+ router.patch("/work-products/:id", validate(updateIssueWorkProductSchema), async (req, res) => {
593
+ const id = req.params.id;
594
+ const existing = await workProductsSvc.getById(id);
595
+ if (!existing) {
596
+ res.status(404).json({ error: "Work product not found" });
597
+ return;
598
+ }
599
+ assertCompanyAccess(req, existing.orgId);
600
+ const product = await workProductsSvc.update(id, req.body);
601
+ if (!product) {
602
+ res.status(404).json({ error: "Work product not found" });
603
+ return;
604
+ }
605
+ const actor = getActorInfo(req);
606
+ await logActivity(db, {
607
+ orgId: existing.orgId,
608
+ actorType: actor.actorType,
609
+ actorId: actor.actorId,
610
+ agentId: actor.agentId,
611
+ runId: actor.runId,
612
+ action: "issue.work_product_updated",
613
+ entityType: "issue",
614
+ entityId: existing.issueId,
615
+ details: { workProductId: product.id, changedKeys: Object.keys(req.body).sort() },
616
+ });
617
+ res.json(product);
618
+ });
619
+ router.delete("/work-products/:id", async (req, res) => {
620
+ const id = req.params.id;
621
+ const existing = await workProductsSvc.getById(id);
622
+ if (!existing) {
623
+ res.status(404).json({ error: "Work product not found" });
624
+ return;
625
+ }
626
+ assertCompanyAccess(req, existing.orgId);
627
+ const removed = await workProductsSvc.remove(id);
628
+ if (!removed) {
629
+ res.status(404).json({ error: "Work product not found" });
630
+ return;
631
+ }
632
+ const actor = getActorInfo(req);
633
+ await logActivity(db, {
634
+ orgId: existing.orgId,
635
+ actorType: actor.actorType,
636
+ actorId: actor.actorId,
637
+ agentId: actor.agentId,
638
+ runId: actor.runId,
639
+ action: "issue.work_product_deleted",
640
+ entityType: "issue",
641
+ entityId: existing.issueId,
642
+ details: { workProductId: removed.id, type: removed.type },
643
+ });
644
+ res.json(removed);
645
+ });
646
+ router.post("/issues/:id/read", async (req, res) => {
647
+ const id = req.params.id;
648
+ const issue = await svc.getById(id);
649
+ if (!issue) {
650
+ res.status(404).json({ error: "Issue not found" });
651
+ return;
652
+ }
653
+ assertCompanyAccess(req, issue.orgId);
654
+ if (req.actor.type !== "board") {
655
+ res.status(403).json({ error: "Board authentication required" });
656
+ return;
657
+ }
658
+ if (!req.actor.userId) {
659
+ res.status(403).json({ error: "Board user context required" });
660
+ return;
661
+ }
662
+ const readState = await svc.markRead(issue.orgId, issue.id, req.actor.userId, new Date());
663
+ res.json(readState);
664
+ });
665
+ router.post("/issues/:id/follow", async (req, res) => {
666
+ const id = req.params.id;
667
+ const issue = await svc.getById(id);
668
+ if (!issue) {
669
+ res.status(404).json({ error: "Issue not found" });
670
+ return;
671
+ }
672
+ assertCompanyAccess(req, issue.orgId);
673
+ if (req.actor.type !== "board") {
674
+ res.status(403).json({ error: "Board authentication required" });
675
+ return;
676
+ }
677
+ const userId = req.actor.userId;
678
+ if (!userId) {
679
+ res.status(403).json({ error: "Board user context required" });
680
+ return;
681
+ }
682
+ const followed = await svc.followIssue(issue.orgId, issue.id, userId);
683
+ const actor = getActorInfo(req);
684
+ await logActivity(db, {
685
+ orgId: issue.orgId,
686
+ actorType: actor.actorType,
687
+ actorId: actor.actorId,
688
+ agentId: actor.agentId,
689
+ runId: actor.runId,
690
+ action: "issue.followed",
691
+ entityType: "issue",
692
+ entityId: issue.id,
693
+ details: {
694
+ issueId: issue.id,
695
+ identifier: issue.identifier,
696
+ title: issue.title,
697
+ },
698
+ });
699
+ res.status(201).json(followed);
700
+ });
701
+ router.delete("/issues/:id/follow", async (req, res) => {
702
+ const id = req.params.id;
703
+ const issue = await svc.getById(id);
704
+ if (!issue) {
705
+ res.status(404).json({ error: "Issue not found" });
706
+ return;
707
+ }
708
+ assertCompanyAccess(req, issue.orgId);
709
+ if (req.actor.type !== "board") {
710
+ res.status(403).json({ error: "Board authentication required" });
711
+ return;
712
+ }
713
+ const userId = req.actor.userId;
714
+ if (!userId) {
715
+ res.status(403).json({ error: "Board user context required" });
716
+ return;
717
+ }
718
+ const removed = await svc.unfollowIssue(issue.orgId, issue.id, userId);
719
+ if (removed) {
720
+ const actor = getActorInfo(req);
721
+ await logActivity(db, {
722
+ orgId: issue.orgId,
723
+ actorType: actor.actorType,
724
+ actorId: actor.actorId,
725
+ agentId: actor.agentId,
726
+ runId: actor.runId,
727
+ action: "issue.unfollowed",
728
+ entityType: "issue",
729
+ entityId: issue.id,
730
+ details: {
731
+ issueId: issue.id,
732
+ identifier: issue.identifier,
733
+ title: issue.title,
734
+ },
735
+ });
736
+ }
737
+ res.json({ ok: true });
738
+ });
739
+ router.get("/issues/:id/approvals", async (req, res) => {
740
+ const id = req.params.id;
741
+ const issue = await svc.getById(id);
742
+ if (!issue) {
743
+ res.status(404).json({ error: "Issue not found" });
744
+ return;
745
+ }
746
+ assertCompanyAccess(req, issue.orgId);
747
+ const approvals = await issueApprovalsSvc.listApprovalsForIssue(id);
748
+ res.json(approvals);
749
+ });
750
+ router.post("/issues/:id/approvals", validate(linkIssueApprovalSchema), async (req, res) => {
751
+ const id = req.params.id;
752
+ const issue = await svc.getById(id);
753
+ if (!issue) {
754
+ res.status(404).json({ error: "Issue not found" });
755
+ return;
756
+ }
757
+ if (!(await assertCanManageIssueApprovalLinks(req, res, issue.orgId)))
758
+ return;
759
+ const actor = getActorInfo(req);
760
+ await issueApprovalsSvc.link(id, req.body.approvalId, {
761
+ agentId: actor.agentId,
762
+ userId: actor.actorType === "user" ? actor.actorId : null,
763
+ });
764
+ await logActivity(db, {
765
+ orgId: issue.orgId,
766
+ actorType: actor.actorType,
767
+ actorId: actor.actorId,
768
+ agentId: actor.agentId,
769
+ runId: actor.runId,
770
+ action: "issue.approval_linked",
771
+ entityType: "issue",
772
+ entityId: issue.id,
773
+ details: { approvalId: req.body.approvalId },
774
+ });
775
+ const approvals = await issueApprovalsSvc.listApprovalsForIssue(id);
776
+ res.status(201).json(approvals);
777
+ });
778
+ router.delete("/issues/:id/approvals/:approvalId", async (req, res) => {
779
+ const id = req.params.id;
780
+ const approvalId = req.params.approvalId;
781
+ const issue = await svc.getById(id);
782
+ if (!issue) {
783
+ res.status(404).json({ error: "Issue not found" });
784
+ return;
785
+ }
786
+ if (!(await assertCanManageIssueApprovalLinks(req, res, issue.orgId)))
787
+ return;
788
+ await issueApprovalsSvc.unlink(id, approvalId);
789
+ const actor = getActorInfo(req);
790
+ await logActivity(db, {
791
+ orgId: issue.orgId,
792
+ actorType: actor.actorType,
793
+ actorId: actor.actorId,
794
+ agentId: actor.agentId,
795
+ runId: actor.runId,
796
+ action: "issue.approval_unlinked",
797
+ entityType: "issue",
798
+ entityId: issue.id,
799
+ details: { approvalId },
800
+ });
801
+ res.json({ ok: true });
802
+ });
803
+ router.post("/orgs/:orgId/issues", validate(createIssueSchema), async (req, res) => {
804
+ const orgId = req.params.orgId;
805
+ assertCompanyAccess(req, orgId);
806
+ if (req.body.assigneeAgentId || req.body.assigneeUserId) {
807
+ await assertCanAssignTasks(req, orgId);
808
+ }
809
+ const actor = getActorInfo(req);
810
+ const issue = await svc.create(orgId, {
811
+ ...req.body,
812
+ createdByAgentId: actor.agentId,
813
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
814
+ });
815
+ await logActivity(db, {
816
+ orgId,
817
+ actorType: actor.actorType,
818
+ actorId: actor.actorId,
819
+ agentId: actor.agentId,
820
+ runId: actor.runId,
821
+ action: "issue.created",
822
+ entityType: "issue",
823
+ entityId: issue.id,
824
+ details: { title: issue.title, identifier: issue.identifier },
825
+ });
826
+ void queueIssueAssignmentWakeup({
827
+ heartbeat,
828
+ issue,
829
+ reason: "issue_assigned",
830
+ mutation: "create",
831
+ contextSource: "issue.create",
832
+ requestedByActorType: actor.actorType,
833
+ requestedByActorId: actor.actorId,
834
+ });
835
+ res.status(201).json(issue);
836
+ });
837
+ router.patch("/issues/:id", validate(updateIssueSchema), async (req, res) => {
838
+ const id = req.params.id;
839
+ const existing = await svc.getById(id);
840
+ if (!existing) {
841
+ res.status(404).json({ error: "Issue not found" });
842
+ return;
843
+ }
844
+ assertCompanyAccess(req, existing.orgId);
845
+ const assigneeWillChange = (req.body.assigneeAgentId !== undefined && req.body.assigneeAgentId !== existing.assigneeAgentId) ||
846
+ (req.body.assigneeUserId !== undefined && req.body.assigneeUserId !== existing.assigneeUserId);
847
+ const isAgentReturningIssueToCreator = req.actor.type === "agent" &&
848
+ !!req.actor.agentId &&
849
+ existing.assigneeAgentId === req.actor.agentId &&
850
+ req.body.assigneeAgentId === null &&
851
+ typeof req.body.assigneeUserId === "string" &&
852
+ !!existing.createdByUserId &&
853
+ req.body.assigneeUserId === existing.createdByUserId;
854
+ if (assigneeWillChange) {
855
+ if (!isAgentReturningIssueToCreator) {
856
+ await assertCanAssignTasks(req, existing.orgId);
857
+ }
858
+ }
859
+ if (!(await assertAgentRunCheckoutOwnership(req, res, existing)))
860
+ return;
861
+ const actor = getActorInfo(req);
862
+ const isClosed = existing.status === "done" || existing.status === "cancelled";
863
+ const { comment: commentBody, reopen: reopenRequested, hiddenAt: hiddenAtRaw, ...updateFields } = req.body;
864
+ if (hiddenAtRaw !== undefined) {
865
+ updateFields.hiddenAt = hiddenAtRaw ? new Date(hiddenAtRaw) : null;
866
+ }
867
+ if (commentBody && reopenRequested === true && isClosed && updateFields.status === undefined) {
868
+ updateFields.status = "todo";
869
+ }
870
+ let issue;
871
+ try {
872
+ issue = await svc.update(id, updateFields);
873
+ }
874
+ catch (err) {
875
+ if (err instanceof HttpError && err.status === 422) {
876
+ logger.warn({
877
+ issueId: id,
878
+ orgId: existing.orgId,
879
+ assigneePatch: {
880
+ assigneeAgentId: req.body.assigneeAgentId === undefined ? "__omitted__" : req.body.assigneeAgentId,
881
+ assigneeUserId: req.body.assigneeUserId === undefined ? "__omitted__" : req.body.assigneeUserId,
882
+ },
883
+ currentAssignee: {
884
+ assigneeAgentId: existing.assigneeAgentId,
885
+ assigneeUserId: existing.assigneeUserId,
886
+ },
887
+ error: err.message,
888
+ details: err.details,
889
+ }, "issue update rejected with 422");
890
+ }
891
+ throw err;
892
+ }
893
+ if (!issue) {
894
+ res.status(404).json({ error: "Issue not found" });
895
+ return;
896
+ }
897
+ await automationsSvc.syncRunStatusForIssue(issue.id);
898
+ if (actor.runId) {
899
+ await heartbeat.reportRunActivity(actor.runId).catch((err) => logger.warn({ err, runId: actor.runId }, "failed to clear detached run warning after issue activity"));
900
+ }
901
+ // Build activity details with previous values for changed fields
902
+ const previous = {};
903
+ for (const key of Object.keys(updateFields)) {
904
+ if (key in existing && existing[key] !== updateFields[key]) {
905
+ previous[key] = existing[key];
906
+ }
907
+ }
908
+ const hasFieldChanges = Object.keys(previous).length > 0;
909
+ const reopened = commentBody &&
910
+ reopenRequested === true &&
911
+ isClosed &&
912
+ previous.status !== undefined &&
913
+ issue.status === "todo";
914
+ const reopenFromStatus = reopened ? existing.status : null;
915
+ await logActivity(db, {
916
+ orgId: issue.orgId,
917
+ actorType: actor.actorType,
918
+ actorId: actor.actorId,
919
+ agentId: actor.agentId,
920
+ runId: actor.runId,
921
+ action: "issue.updated",
922
+ entityType: "issue",
923
+ entityId: issue.id,
924
+ details: {
925
+ ...updateFields,
926
+ identifier: issue.identifier,
927
+ ...(commentBody ? { source: "comment" } : {}),
928
+ ...(reopened ? { reopened: true, reopenedFrom: reopenFromStatus } : {}),
929
+ _previous: hasFieldChanges ? previous : undefined,
930
+ },
931
+ });
932
+ let comment = null;
933
+ if (commentBody) {
934
+ comment = await svc.addComment(id, commentBody, {
935
+ agentId: actor.agentId ?? undefined,
936
+ userId: actor.actorType === "user" ? actor.actorId : undefined,
937
+ });
938
+ await logActivity(db, {
939
+ orgId: issue.orgId,
940
+ actorType: actor.actorType,
941
+ actorId: actor.actorId,
942
+ agentId: actor.agentId,
943
+ runId: actor.runId,
944
+ action: "issue.comment_added",
945
+ entityType: "issue",
946
+ entityId: issue.id,
947
+ details: {
948
+ commentId: comment.id,
949
+ bodySnippet: comment.body.slice(0, 120),
950
+ identifier: issue.identifier,
951
+ issueTitle: issue.title,
952
+ ...(reopened ? { reopened: true, reopenedFrom: reopenFromStatus, source: "comment" } : {}),
953
+ ...(hasFieldChanges ? { updated: true } : {}),
954
+ },
955
+ });
956
+ }
957
+ const assigneeChanged = assigneeWillChange;
958
+ const statusChangedFromBacklog = existing.status === "backlog" &&
959
+ issue.status !== "backlog" &&
960
+ req.body.status !== undefined;
961
+ // Merge all wakeups from this update into one enqueue per agent to avoid duplicate runs.
962
+ void (async () => {
963
+ const wakeups = new Map();
964
+ if (assigneeChanged && issue.assigneeAgentId && issue.status !== "backlog") {
965
+ wakeups.set(issue.assigneeAgentId, {
966
+ source: "assignment",
967
+ triggerDetail: "system",
968
+ reason: "issue_assigned",
969
+ payload: { issueId: issue.id, mutation: "update" },
970
+ requestedByActorType: actor.actorType,
971
+ requestedByActorId: actor.actorId,
972
+ contextSnapshot: {
973
+ issueId: issue.id,
974
+ source: "issue.update",
975
+ wakeSource: "assignment",
976
+ wakeReason: "issue_assigned",
977
+ issue: {
978
+ id: issue.id,
979
+ title: issue.title,
980
+ description: issue.description,
981
+ status: issue.status,
982
+ priority: issue.priority,
983
+ },
984
+ },
985
+ });
986
+ }
987
+ if (!assigneeChanged && statusChangedFromBacklog && issue.assigneeAgentId) {
988
+ wakeups.set(issue.assigneeAgentId, {
989
+ source: "automation",
990
+ triggerDetail: "system",
991
+ reason: "issue_status_changed",
992
+ payload: { issueId: issue.id, mutation: "update" },
993
+ requestedByActorType: actor.actorType,
994
+ requestedByActorId: actor.actorId,
995
+ contextSnapshot: {
996
+ issueId: issue.id,
997
+ source: "issue.status_change",
998
+ wakeSource: "automation",
999
+ wakeReason: "issue_status_changed",
1000
+ issue: {
1001
+ id: issue.id,
1002
+ title: issue.title,
1003
+ description: issue.description,
1004
+ status: issue.status,
1005
+ priority: issue.priority,
1006
+ },
1007
+ },
1008
+ });
1009
+ }
1010
+ if (commentBody && comment) {
1011
+ let mentionedIds = [];
1012
+ try {
1013
+ mentionedIds = await svc.findMentionedAgents(issue.orgId, commentBody);
1014
+ }
1015
+ catch (err) {
1016
+ logger.warn({ err, issueId: id }, "failed to resolve @-mentions");
1017
+ }
1018
+ for (const mentionedId of mentionedIds) {
1019
+ if (wakeups.has(mentionedId))
1020
+ continue;
1021
+ if (actor.actorType === "agent" && actor.actorId === mentionedId)
1022
+ continue;
1023
+ wakeups.set(mentionedId, {
1024
+ source: "automation",
1025
+ triggerDetail: "system",
1026
+ reason: "issue_comment_mentioned",
1027
+ payload: { issueId: id, commentId: comment.id },
1028
+ requestedByActorType: actor.actorType,
1029
+ requestedByActorId: actor.actorId,
1030
+ contextSnapshot: {
1031
+ issueId: id,
1032
+ taskId: id,
1033
+ commentId: comment.id,
1034
+ wakeCommentId: comment.id,
1035
+ wakeReason: "issue_comment_mentioned",
1036
+ wakeSource: "comment.mention",
1037
+ source: "comment.mention",
1038
+ issue: {
1039
+ id: issue.id,
1040
+ title: issue.title,
1041
+ description: issue.description,
1042
+ status: issue.status,
1043
+ priority: issue.priority,
1044
+ },
1045
+ comment: {
1046
+ id: comment.id,
1047
+ body: comment.body,
1048
+ authorAgentId: comment.authorAgentId,
1049
+ authorUserId: comment.authorUserId,
1050
+ },
1051
+ },
1052
+ });
1053
+ }
1054
+ }
1055
+ for (const [agentId, wakeup] of wakeups.entries()) {
1056
+ heartbeat
1057
+ .wakeup(agentId, wakeup)
1058
+ .catch((err) => logger.warn({ err, issueId: issue.id, agentId }, "failed to wake agent on issue update"));
1059
+ }
1060
+ })();
1061
+ res.json({ ...issue, comment });
1062
+ });
1063
+ router.delete("/issues/:id", async (req, res) => {
1064
+ const id = req.params.id;
1065
+ const existing = await svc.getById(id);
1066
+ if (!existing) {
1067
+ res.status(404).json({ error: "Issue not found" });
1068
+ return;
1069
+ }
1070
+ assertCompanyAccess(req, existing.orgId);
1071
+ const attachments = await svc.listAttachments(id);
1072
+ const issue = await svc.remove(id);
1073
+ if (!issue) {
1074
+ res.status(404).json({ error: "Issue not found" });
1075
+ return;
1076
+ }
1077
+ for (const attachment of attachments) {
1078
+ try {
1079
+ await storage.deleteObject(attachment.orgId, attachment.objectKey);
1080
+ }
1081
+ catch (err) {
1082
+ logger.warn({ err, issueId: id, attachmentId: attachment.id }, "failed to delete attachment object during issue delete");
1083
+ }
1084
+ }
1085
+ const actor = getActorInfo(req);
1086
+ await logActivity(db, {
1087
+ orgId: issue.orgId,
1088
+ actorType: actor.actorType,
1089
+ actorId: actor.actorId,
1090
+ agentId: actor.agentId,
1091
+ runId: actor.runId,
1092
+ action: "issue.deleted",
1093
+ entityType: "issue",
1094
+ entityId: issue.id,
1095
+ });
1096
+ res.json(issue);
1097
+ });
1098
+ router.post("/issues/:id/checkout", validate(checkoutIssueSchema), async (req, res) => {
1099
+ const id = req.params.id;
1100
+ const issue = await svc.getById(id);
1101
+ if (!issue) {
1102
+ res.status(404).json({ error: "Issue not found" });
1103
+ return;
1104
+ }
1105
+ assertCompanyAccess(req, issue.orgId);
1106
+ if (issue.projectId) {
1107
+ const project = await projectsSvc.getById(issue.projectId);
1108
+ if (project?.pausedAt) {
1109
+ res.status(409).json({
1110
+ error: project.pauseReason === "budget"
1111
+ ? "Project is paused because its budget hard-stop was reached"
1112
+ : "Project is paused",
1113
+ });
1114
+ return;
1115
+ }
1116
+ }
1117
+ if (req.actor.type === "agent" && req.actor.agentId !== req.body.agentId) {
1118
+ res.status(403).json({ error: "Agent can only checkout as itself" });
1119
+ return;
1120
+ }
1121
+ const checkoutRunId = requireAgentRunId(req, res);
1122
+ if (req.actor.type === "agent" && !checkoutRunId)
1123
+ return;
1124
+ const updated = await svc.checkout(id, req.body.agentId, req.body.expectedStatuses, checkoutRunId);
1125
+ const actor = getActorInfo(req);
1126
+ await logActivity(db, {
1127
+ orgId: issue.orgId,
1128
+ actorType: actor.actorType,
1129
+ actorId: actor.actorId,
1130
+ agentId: actor.agentId,
1131
+ runId: actor.runId,
1132
+ action: "issue.checked_out",
1133
+ entityType: "issue",
1134
+ entityId: issue.id,
1135
+ details: { agentId: req.body.agentId },
1136
+ });
1137
+ if (shouldWakeAssigneeOnCheckout({
1138
+ actorType: req.actor.type,
1139
+ actorAgentId: req.actor.type === "agent" ? req.actor.agentId ?? null : null,
1140
+ checkoutAgentId: req.body.agentId,
1141
+ checkoutRunId,
1142
+ })) {
1143
+ void heartbeat
1144
+ .wakeup(req.body.agentId, {
1145
+ source: "assignment",
1146
+ triggerDetail: "system",
1147
+ reason: "issue_checked_out",
1148
+ payload: { issueId: issue.id, mutation: "checkout" },
1149
+ requestedByActorType: actor.actorType,
1150
+ requestedByActorId: actor.actorId,
1151
+ contextSnapshot: { issueId: issue.id, source: "issue.checkout" },
1152
+ })
1153
+ .catch((err) => logger.warn({ err, issueId: issue.id }, "failed to wake assignee on issue checkout"));
1154
+ }
1155
+ res.json(updated);
1156
+ });
1157
+ router.post("/issues/:id/release", async (req, res) => {
1158
+ const id = req.params.id;
1159
+ const existing = await svc.getById(id);
1160
+ if (!existing) {
1161
+ res.status(404).json({ error: "Issue not found" });
1162
+ return;
1163
+ }
1164
+ assertCompanyAccess(req, existing.orgId);
1165
+ if (!(await assertAgentRunCheckoutOwnership(req, res, existing)))
1166
+ return;
1167
+ const actorRunId = requireAgentRunId(req, res);
1168
+ if (req.actor.type === "agent" && !actorRunId)
1169
+ return;
1170
+ const released = await svc.release(id, req.actor.type === "agent" ? req.actor.agentId : undefined, actorRunId);
1171
+ if (!released) {
1172
+ res.status(404).json({ error: "Issue not found" });
1173
+ return;
1174
+ }
1175
+ const actor = getActorInfo(req);
1176
+ await logActivity(db, {
1177
+ orgId: released.orgId,
1178
+ actorType: actor.actorType,
1179
+ actorId: actor.actorId,
1180
+ agentId: actor.agentId,
1181
+ runId: actor.runId,
1182
+ action: "issue.released",
1183
+ entityType: "issue",
1184
+ entityId: released.id,
1185
+ });
1186
+ res.json(released);
1187
+ });
1188
+ router.get("/issues/:id/comments", async (req, res) => {
1189
+ const id = req.params.id;
1190
+ const issue = await svc.getById(id);
1191
+ if (!issue) {
1192
+ res.status(404).json({ error: "Issue not found" });
1193
+ return;
1194
+ }
1195
+ assertCompanyAccess(req, issue.orgId);
1196
+ const afterCommentId = typeof req.query.after === "string" && req.query.after.trim().length > 0
1197
+ ? req.query.after.trim()
1198
+ : typeof req.query.afterCommentId === "string" && req.query.afterCommentId.trim().length > 0
1199
+ ? req.query.afterCommentId.trim()
1200
+ : null;
1201
+ const order = typeof req.query.order === "string" && req.query.order.trim().toLowerCase() === "asc"
1202
+ ? "asc"
1203
+ : "desc";
1204
+ const limitRaw = typeof req.query.limit === "string" && req.query.limit.trim().length > 0
1205
+ ? Number(req.query.limit)
1206
+ : null;
1207
+ const limit = limitRaw && Number.isFinite(limitRaw) && limitRaw > 0
1208
+ ? Math.min(Math.floor(limitRaw), MAX_ISSUE_COMMENT_LIMIT)
1209
+ : null;
1210
+ const comments = await svc.listComments(id, {
1211
+ afterCommentId,
1212
+ order,
1213
+ limit,
1214
+ });
1215
+ res.json(comments);
1216
+ });
1217
+ router.get("/issues/:id/comments/:commentId", async (req, res) => {
1218
+ const id = req.params.id;
1219
+ const commentId = req.params.commentId;
1220
+ const issue = await svc.getById(id);
1221
+ if (!issue) {
1222
+ res.status(404).json({ error: "Issue not found" });
1223
+ return;
1224
+ }
1225
+ assertCompanyAccess(req, issue.orgId);
1226
+ const comment = await svc.getComment(commentId);
1227
+ if (!comment || comment.issueId !== id) {
1228
+ res.status(404).json({ error: "Comment not found" });
1229
+ return;
1230
+ }
1231
+ res.json(comment);
1232
+ });
1233
+ router.post("/issues/:id/comments", validate(addIssueCommentSchema), async (req, res) => {
1234
+ const id = req.params.id;
1235
+ const issue = await svc.getById(id);
1236
+ if (!issue) {
1237
+ res.status(404).json({ error: "Issue not found" });
1238
+ return;
1239
+ }
1240
+ assertCompanyAccess(req, issue.orgId);
1241
+ if (!(await assertAgentRunCheckoutOwnership(req, res, issue)))
1242
+ return;
1243
+ const actor = getActorInfo(req);
1244
+ const reopenRequested = req.body.reopen === true;
1245
+ const interruptRequested = req.body.interrupt === true;
1246
+ const isClosed = issue.status === "done" || issue.status === "cancelled";
1247
+ let reopened = false;
1248
+ let reopenFromStatus = null;
1249
+ let interruptedRunId = null;
1250
+ let currentIssue = issue;
1251
+ if (reopenRequested && isClosed) {
1252
+ const reopenedIssue = await svc.update(id, { status: "todo" });
1253
+ if (!reopenedIssue) {
1254
+ res.status(404).json({ error: "Issue not found" });
1255
+ return;
1256
+ }
1257
+ reopened = true;
1258
+ reopenFromStatus = issue.status;
1259
+ currentIssue = reopenedIssue;
1260
+ await logActivity(db, {
1261
+ orgId: currentIssue.orgId,
1262
+ actorType: actor.actorType,
1263
+ actorId: actor.actorId,
1264
+ agentId: actor.agentId,
1265
+ runId: actor.runId,
1266
+ action: "issue.updated",
1267
+ entityType: "issue",
1268
+ entityId: currentIssue.id,
1269
+ details: {
1270
+ status: "todo",
1271
+ reopened: true,
1272
+ reopenedFrom: reopenFromStatus,
1273
+ source: "comment",
1274
+ identifier: currentIssue.identifier,
1275
+ },
1276
+ });
1277
+ }
1278
+ if (interruptRequested) {
1279
+ if (req.actor.type !== "board") {
1280
+ res.status(403).json({ error: "Only board users can interrupt active runs from issue comments" });
1281
+ return;
1282
+ }
1283
+ let runToInterrupt = currentIssue.executionRunId
1284
+ ? await heartbeat.getRun(currentIssue.executionRunId)
1285
+ : null;
1286
+ if ((!runToInterrupt || runToInterrupt.status !== "running") &&
1287
+ currentIssue.assigneeAgentId) {
1288
+ const activeRun = await heartbeat.getActiveRunForAgent(currentIssue.assigneeAgentId);
1289
+ const activeIssueId = activeRun &&
1290
+ activeRun.contextSnapshot &&
1291
+ typeof activeRun.contextSnapshot === "object" &&
1292
+ typeof activeRun.contextSnapshot.issueId === "string"
1293
+ ? activeRun.contextSnapshot.issueId
1294
+ : null;
1295
+ if (activeRun && activeRun.status === "running" && activeIssueId === currentIssue.id) {
1296
+ runToInterrupt = activeRun;
1297
+ }
1298
+ }
1299
+ if (runToInterrupt && runToInterrupt.status === "running") {
1300
+ const cancelled = await heartbeat.cancelRun(runToInterrupt.id);
1301
+ if (cancelled) {
1302
+ interruptedRunId = cancelled.id;
1303
+ await logActivity(db, {
1304
+ orgId: cancelled.orgId,
1305
+ actorType: actor.actorType,
1306
+ actorId: actor.actorId,
1307
+ agentId: actor.agentId,
1308
+ runId: actor.runId,
1309
+ action: "heartbeat.cancelled",
1310
+ entityType: "heartbeat_run",
1311
+ entityId: cancelled.id,
1312
+ details: { agentId: cancelled.agentId, source: "issue_comment_interrupt", issueId: currentIssue.id },
1313
+ });
1314
+ }
1315
+ }
1316
+ }
1317
+ const comment = await svc.addComment(id, req.body.body, {
1318
+ agentId: actor.agentId ?? undefined,
1319
+ userId: actor.actorType === "user" ? actor.actorId : undefined,
1320
+ });
1321
+ if (actor.runId) {
1322
+ await heartbeat.reportRunActivity(actor.runId).catch((err) => logger.warn({ err, runId: actor.runId }, "failed to clear detached run warning after issue comment"));
1323
+ }
1324
+ await logActivity(db, {
1325
+ orgId: currentIssue.orgId,
1326
+ actorType: actor.actorType,
1327
+ actorId: actor.actorId,
1328
+ agentId: actor.agentId,
1329
+ runId: actor.runId,
1330
+ action: "issue.comment_added",
1331
+ entityType: "issue",
1332
+ entityId: currentIssue.id,
1333
+ details: {
1334
+ commentId: comment.id,
1335
+ bodySnippet: comment.body.slice(0, 120),
1336
+ identifier: currentIssue.identifier,
1337
+ issueTitle: currentIssue.title,
1338
+ ...(reopened ? { reopened: true, reopenedFrom: reopenFromStatus, source: "comment" } : {}),
1339
+ ...(interruptedRunId ? { interruptedRunId } : {}),
1340
+ },
1341
+ });
1342
+ // Merge all wakeups from this comment into one enqueue per agent to avoid duplicate runs.
1343
+ void (async () => {
1344
+ const wakeups = new Map();
1345
+ const assigneeId = currentIssue.assigneeAgentId;
1346
+ const actorIsAgent = actor.actorType === "agent";
1347
+ const selfComment = actorIsAgent && actor.actorId === assigneeId;
1348
+ const skipWake = selfComment || isClosed;
1349
+ if (assigneeId && (reopened || !skipWake)) {
1350
+ if (reopened) {
1351
+ wakeups.set(assigneeId, {
1352
+ source: "automation",
1353
+ triggerDetail: "system",
1354
+ reason: "issue_reopened_via_comment",
1355
+ payload: {
1356
+ issueId: currentIssue.id,
1357
+ commentId: comment.id,
1358
+ reopenedFrom: reopenFromStatus,
1359
+ mutation: "comment",
1360
+ ...(interruptedRunId ? { interruptedRunId } : {}),
1361
+ },
1362
+ requestedByActorType: actor.actorType,
1363
+ requestedByActorId: actor.actorId,
1364
+ contextSnapshot: {
1365
+ issueId: currentIssue.id,
1366
+ taskId: currentIssue.id,
1367
+ commentId: comment.id,
1368
+ source: "issue.comment.reopen",
1369
+ wakeReason: "issue_reopened_via_comment",
1370
+ reopenedFrom: reopenFromStatus,
1371
+ ...(interruptedRunId ? { interruptedRunId } : {}),
1372
+ },
1373
+ });
1374
+ }
1375
+ else {
1376
+ wakeups.set(assigneeId, {
1377
+ source: "automation",
1378
+ triggerDetail: "system",
1379
+ reason: "issue_commented",
1380
+ payload: {
1381
+ issueId: currentIssue.id,
1382
+ commentId: comment.id,
1383
+ mutation: "comment",
1384
+ ...(interruptedRunId ? { interruptedRunId } : {}),
1385
+ },
1386
+ requestedByActorType: actor.actorType,
1387
+ requestedByActorId: actor.actorId,
1388
+ contextSnapshot: {
1389
+ issueId: currentIssue.id,
1390
+ taskId: currentIssue.id,
1391
+ commentId: comment.id,
1392
+ wakeCommentId: comment.id,
1393
+ source: "issue.comment",
1394
+ wakeReason: "issue_commented",
1395
+ issue: {
1396
+ id: currentIssue.id,
1397
+ title: currentIssue.title,
1398
+ description: currentIssue.description,
1399
+ status: currentIssue.status,
1400
+ priority: currentIssue.priority,
1401
+ },
1402
+ comment: {
1403
+ id: comment.id,
1404
+ body: comment.body,
1405
+ authorAgentId: comment.authorAgentId,
1406
+ authorUserId: comment.authorUserId,
1407
+ },
1408
+ ...(interruptedRunId ? { interruptedRunId } : {}),
1409
+ },
1410
+ });
1411
+ }
1412
+ }
1413
+ let mentionedIds = [];
1414
+ try {
1415
+ mentionedIds = await svc.findMentionedAgents(issue.orgId, req.body.body);
1416
+ }
1417
+ catch (err) {
1418
+ logger.warn({ err, issueId: id }, "failed to resolve @-mentions");
1419
+ }
1420
+ for (const mentionedId of mentionedIds) {
1421
+ if (wakeups.has(mentionedId))
1422
+ continue;
1423
+ if (actorIsAgent && actor.actorId === mentionedId)
1424
+ continue;
1425
+ wakeups.set(mentionedId, {
1426
+ source: "automation",
1427
+ triggerDetail: "system",
1428
+ reason: "issue_comment_mentioned",
1429
+ payload: { issueId: id, commentId: comment.id },
1430
+ requestedByActorType: actor.actorType,
1431
+ requestedByActorId: actor.actorId,
1432
+ contextSnapshot: {
1433
+ issueId: id,
1434
+ taskId: id,
1435
+ commentId: comment.id,
1436
+ wakeCommentId: comment.id,
1437
+ wakeReason: "issue_comment_mentioned",
1438
+ wakeSource: "comment.mention",
1439
+ source: "comment.mention",
1440
+ issue: {
1441
+ id: currentIssue.id,
1442
+ title: currentIssue.title,
1443
+ description: currentIssue.description,
1444
+ status: currentIssue.status,
1445
+ priority: currentIssue.priority,
1446
+ },
1447
+ comment: {
1448
+ id: comment.id,
1449
+ body: comment.body,
1450
+ authorAgentId: comment.authorAgentId,
1451
+ authorUserId: comment.authorUserId,
1452
+ },
1453
+ },
1454
+ });
1455
+ }
1456
+ for (const [agentId, wakeup] of wakeups.entries()) {
1457
+ heartbeat
1458
+ .wakeup(agentId, wakeup)
1459
+ .catch((err) => logger.warn({ err, issueId: currentIssue.id, agentId }, "failed to wake agent on issue comment"));
1460
+ }
1461
+ })();
1462
+ res.status(201).json(comment);
1463
+ });
1464
+ router.get("/issues/:id/attachments", async (req, res) => {
1465
+ const issueId = req.params.id;
1466
+ const issue = await svc.getById(issueId);
1467
+ if (!issue) {
1468
+ res.status(404).json({ error: "Issue not found" });
1469
+ return;
1470
+ }
1471
+ assertCompanyAccess(req, issue.orgId);
1472
+ const attachments = await svc.listAttachments(issueId);
1473
+ res.json(attachments.map(withContentPath));
1474
+ });
1475
+ router.post("/orgs/:orgId/issues/:issueId/attachments", async (req, res) => {
1476
+ const orgId = req.params.orgId;
1477
+ const issueId = req.params.issueId;
1478
+ assertCompanyAccess(req, orgId);
1479
+ const issue = await svc.getById(issueId);
1480
+ if (!issue) {
1481
+ res.status(404).json({ error: "Issue not found" });
1482
+ return;
1483
+ }
1484
+ if (issue.orgId !== orgId) {
1485
+ res.status(422).json({ error: "Issue does not belong to organization" });
1486
+ return;
1487
+ }
1488
+ try {
1489
+ await runSingleFileUpload(req, res);
1490
+ }
1491
+ catch (err) {
1492
+ if (err instanceof multer.MulterError) {
1493
+ if (err.code === "LIMIT_FILE_SIZE") {
1494
+ res.status(422).json({ error: `Attachment exceeds ${MAX_ATTACHMENT_BYTES} bytes` });
1495
+ return;
1496
+ }
1497
+ res.status(400).json({ error: err.message });
1498
+ return;
1499
+ }
1500
+ throw err;
1501
+ }
1502
+ const file = req.file;
1503
+ if (!file) {
1504
+ res.status(400).json({ error: "Missing file field 'file'" });
1505
+ return;
1506
+ }
1507
+ const contentType = (file.mimetype || "").toLowerCase();
1508
+ if (!isAllowedContentType(contentType)) {
1509
+ res.status(422).json({ error: `Unsupported attachment type: ${contentType || "unknown"}` });
1510
+ return;
1511
+ }
1512
+ if (file.buffer.length <= 0) {
1513
+ res.status(422).json({ error: "Attachment is empty" });
1514
+ return;
1515
+ }
1516
+ const parsedMeta = createIssueAttachmentMetadataSchema.safeParse(req.body ?? {});
1517
+ if (!parsedMeta.success) {
1518
+ res.status(400).json({ error: "Invalid attachment metadata", details: parsedMeta.error.issues });
1519
+ return;
1520
+ }
1521
+ const actor = getActorInfo(req);
1522
+ const stored = await storage.putFile({
1523
+ orgId,
1524
+ namespace: `issues/${issueId}`,
1525
+ originalFilename: file.originalname || null,
1526
+ contentType,
1527
+ body: file.buffer,
1528
+ });
1529
+ const attachment = await svc.createAttachment({
1530
+ issueId,
1531
+ issueCommentId: parsedMeta.data.issueCommentId ?? null,
1532
+ provider: stored.provider,
1533
+ objectKey: stored.objectKey,
1534
+ contentType: stored.contentType,
1535
+ byteSize: stored.byteSize,
1536
+ sha256: stored.sha256,
1537
+ originalFilename: stored.originalFilename,
1538
+ createdByAgentId: actor.agentId,
1539
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
1540
+ });
1541
+ await logActivity(db, {
1542
+ orgId,
1543
+ actorType: actor.actorType,
1544
+ actorId: actor.actorId,
1545
+ agentId: actor.agentId,
1546
+ runId: actor.runId,
1547
+ action: "issue.attachment_added",
1548
+ entityType: "issue",
1549
+ entityId: issueId,
1550
+ details: {
1551
+ attachmentId: attachment.id,
1552
+ originalFilename: attachment.originalFilename,
1553
+ contentType: attachment.contentType,
1554
+ byteSize: attachment.byteSize,
1555
+ },
1556
+ });
1557
+ res.status(201).json(withContentPath(attachment));
1558
+ });
1559
+ router.get("/attachments/:attachmentId/content", async (req, res, next) => {
1560
+ const attachmentId = req.params.attachmentId;
1561
+ const attachment = await svc.getAttachmentById(attachmentId);
1562
+ if (!attachment) {
1563
+ res.status(404).json({ error: "Attachment not found" });
1564
+ return;
1565
+ }
1566
+ assertCompanyAccess(req, attachment.orgId);
1567
+ const object = await storage.getObject(attachment.orgId, attachment.objectKey);
1568
+ res.setHeader("Content-Type", attachment.contentType || object.contentType || "application/octet-stream");
1569
+ res.setHeader("Content-Length", String(attachment.byteSize || object.contentLength || 0));
1570
+ res.setHeader("Cache-Control", "private, max-age=60");
1571
+ const filename = attachment.originalFilename ?? "attachment";
1572
+ res.setHeader("Content-Disposition", `inline; filename=\"${filename.replaceAll("\"", "")}\"`);
1573
+ object.stream.on("error", (err) => {
1574
+ next(err);
1575
+ });
1576
+ object.stream.pipe(res);
1577
+ });
1578
+ router.delete("/attachments/:attachmentId", async (req, res) => {
1579
+ const attachmentId = req.params.attachmentId;
1580
+ const attachment = await svc.getAttachmentById(attachmentId);
1581
+ if (!attachment) {
1582
+ res.status(404).json({ error: "Attachment not found" });
1583
+ return;
1584
+ }
1585
+ assertCompanyAccess(req, attachment.orgId);
1586
+ try {
1587
+ await storage.deleteObject(attachment.orgId, attachment.objectKey);
1588
+ }
1589
+ catch (err) {
1590
+ logger.warn({ err, attachmentId }, "storage delete failed while removing attachment");
1591
+ }
1592
+ const removed = await svc.removeAttachment(attachmentId);
1593
+ if (!removed) {
1594
+ res.status(404).json({ error: "Attachment not found" });
1595
+ return;
1596
+ }
1597
+ const actor = getActorInfo(req);
1598
+ await logActivity(db, {
1599
+ orgId: removed.orgId,
1600
+ actorType: actor.actorType,
1601
+ actorId: actor.actorId,
1602
+ agentId: actor.agentId,
1603
+ runId: actor.runId,
1604
+ action: "issue.attachment_removed",
1605
+ entityType: "issue",
1606
+ entityId: removed.issueId,
1607
+ details: {
1608
+ attachmentId: removed.id,
1609
+ },
1610
+ });
1611
+ res.json({ ok: true });
1612
+ });
1613
+ return router;
1614
+ }
1615
+ //# sourceMappingURL=issues.js.map