@growthub/cli 0.3.1 → 0.3.3

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