@zmeel/server 0.3.1

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 (772) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapters/codex-models.d.ts +4 -0
  3. package/dist/adapters/codex-models.d.ts.map +1 -0
  4. package/dist/adapters/codex-models.js +98 -0
  5. package/dist/adapters/codex-models.js.map +1 -0
  6. package/dist/adapters/cursor-models.d.ts +13 -0
  7. package/dist/adapters/cursor-models.d.ts.map +1 -0
  8. package/dist/adapters/cursor-models.js +148 -0
  9. package/dist/adapters/cursor-models.js.map +1 -0
  10. package/dist/adapters/http/execute.d.ts +3 -0
  11. package/dist/adapters/http/execute.d.ts.map +1 -0
  12. package/dist/adapters/http/execute.js +39 -0
  13. package/dist/adapters/http/execute.js.map +1 -0
  14. package/dist/adapters/http/index.d.ts +3 -0
  15. package/dist/adapters/http/index.d.ts.map +1 -0
  16. package/dist/adapters/http/index.js +20 -0
  17. package/dist/adapters/http/index.js.map +1 -0
  18. package/dist/adapters/http/test.d.ts +3 -0
  19. package/dist/adapters/http/test.d.ts.map +1 -0
  20. package/dist/adapters/http/test.js +106 -0
  21. package/dist/adapters/http/test.js.map +1 -0
  22. package/dist/adapters/index.d.ts +4 -0
  23. package/dist/adapters/index.d.ts.map +1 -0
  24. package/dist/adapters/index.js +3 -0
  25. package/dist/adapters/index.js.map +1 -0
  26. package/dist/adapters/process/execute.d.ts +3 -0
  27. package/dist/adapters/process/execute.d.ts.map +1 -0
  28. package/dist/adapters/process/execute.js +70 -0
  29. package/dist/adapters/process/execute.js.map +1 -0
  30. package/dist/adapters/process/index.d.ts +3 -0
  31. package/dist/adapters/process/index.d.ts.map +1 -0
  32. package/dist/adapters/process/index.js +23 -0
  33. package/dist/adapters/process/index.js.map +1 -0
  34. package/dist/adapters/process/test.d.ts +3 -0
  35. package/dist/adapters/process/test.d.ts.map +1 -0
  36. package/dist/adapters/process/test.js +77 -0
  37. package/dist/adapters/process/test.js.map +1 -0
  38. package/dist/adapters/registry.d.ts +14 -0
  39. package/dist/adapters/registry.d.ts.map +1 -0
  40. package/dist/adapters/registry.js +164 -0
  41. package/dist/adapters/registry.js.map +1 -0
  42. package/dist/adapters/types.d.ts +2 -0
  43. package/dist/adapters/types.d.ts.map +1 -0
  44. package/dist/adapters/types.js +2 -0
  45. package/dist/adapters/types.js.map +1 -0
  46. package/dist/adapters/utils.d.ts +41 -0
  47. package/dist/adapters/utils.d.ts.map +1 -0
  48. package/dist/adapters/utils.js +51 -0
  49. package/dist/adapters/utils.js.map +1 -0
  50. package/dist/agent-auth-jwt.d.ts +14 -0
  51. package/dist/agent-auth-jwt.d.ts.map +1 -0
  52. package/dist/agent-auth-jwt.js +117 -0
  53. package/dist/agent-auth-jwt.js.map +1 -0
  54. package/dist/app.d.ts +32 -0
  55. package/dist/app.d.ts.map +1 -0
  56. package/dist/app.js +281 -0
  57. package/dist/app.js.map +1 -0
  58. package/dist/attachment-types.d.ts +33 -0
  59. package/dist/attachment-types.d.ts.map +1 -0
  60. package/dist/attachment-types.js +67 -0
  61. package/dist/attachment-types.js.map +1 -0
  62. package/dist/auth/better-auth.d.ts +24 -0
  63. package/dist/auth/better-auth.d.ts.map +1 -0
  64. package/dist/auth/better-auth.js +108 -0
  65. package/dist/auth/better-auth.js.map +1 -0
  66. package/dist/board-claim.d.ts +23 -0
  67. package/dist/board-claim.d.ts.map +1 -0
  68. package/dist/board-claim.js +115 -0
  69. package/dist/board-claim.js.map +1 -0
  70. package/dist/config-file.d.ts +3 -0
  71. package/dist/config-file.d.ts.map +1 -0
  72. package/dist/config-file.js +16 -0
  73. package/dist/config-file.js.map +1 -0
  74. package/dist/config.d.ts +41 -0
  75. package/dist/config.d.ts.map +1 -0
  76. package/dist/config.js +173 -0
  77. package/dist/config.js.map +1 -0
  78. package/dist/dev-server-status.d.ts +27 -0
  79. package/dist/dev-server-status.d.ts.map +1 -0
  80. package/dist/dev-server-status.js +70 -0
  81. package/dist/dev-server-status.js.map +1 -0
  82. package/dist/dev-watch-ignore.d.ts +2 -0
  83. package/dist/dev-watch-ignore.d.ts.map +1 -0
  84. package/dist/dev-watch-ignore.js +33 -0
  85. package/dist/dev-watch-ignore.js.map +1 -0
  86. package/dist/errors.d.ts +12 -0
  87. package/dist/errors.d.ts.map +1 -0
  88. package/dist/errors.js +28 -0
  89. package/dist/errors.js.map +1 -0
  90. package/dist/home-paths.d.ts +17 -0
  91. package/dist/home-paths.d.ts.map +1 -0
  92. package/dist/home-paths.js +75 -0
  93. package/dist/home-paths.js.map +1 -0
  94. package/dist/index.d.ts +10 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +627 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/log-redaction.d.ts +11 -0
  99. package/dist/log-redaction.d.ts.map +1 -0
  100. package/dist/log-redaction.js +118 -0
  101. package/dist/log-redaction.js.map +1 -0
  102. package/dist/middleware/auth.d.ts +12 -0
  103. package/dist/middleware/auth.d.ts.map +1 -0
  104. package/dist/middleware/auth.js +144 -0
  105. package/dist/middleware/auth.js.map +1 -0
  106. package/dist/middleware/board-mutation-guard.d.ts +3 -0
  107. package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
  108. package/dist/middleware/board-mutation-guard.js +60 -0
  109. package/dist/middleware/board-mutation-guard.js.map +1 -0
  110. package/dist/middleware/error-handler.d.ts +17 -0
  111. package/dist/middleware/error-handler.d.ts.map +1 -0
  112. package/dist/middleware/error-handler.js +45 -0
  113. package/dist/middleware/error-handler.js.map +1 -0
  114. package/dist/middleware/index.d.ts +4 -0
  115. package/dist/middleware/index.d.ts.map +1 -0
  116. package/dist/middleware/index.js +4 -0
  117. package/dist/middleware/index.js.map +1 -0
  118. package/dist/middleware/logger.d.ts +4 -0
  119. package/dist/middleware/logger.d.ts.map +1 -0
  120. package/dist/middleware/logger.js +87 -0
  121. package/dist/middleware/logger.js.map +1 -0
  122. package/dist/middleware/private-hostname-guard.d.ts +11 -0
  123. package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
  124. package/dist/middleware/private-hostname-guard.js +78 -0
  125. package/dist/middleware/private-hostname-guard.js.map +1 -0
  126. package/dist/middleware/validate.d.ts +4 -0
  127. package/dist/middleware/validate.d.ts.map +1 -0
  128. package/dist/middleware/validate.js +7 -0
  129. package/dist/middleware/validate.js.map +1 -0
  130. package/dist/onboarding-assets/ceo/AGENTS.md +54 -0
  131. package/dist/onboarding-assets/ceo/HEARTBEAT.md +72 -0
  132. package/dist/onboarding-assets/ceo/SOUL.md +33 -0
  133. package/dist/onboarding-assets/ceo/TOOLS.md +3 -0
  134. package/dist/onboarding-assets/default/AGENTS.md +3 -0
  135. package/dist/paths.d.ts +3 -0
  136. package/dist/paths.d.ts.map +1 -0
  137. package/dist/paths.js +31 -0
  138. package/dist/paths.js.map +1 -0
  139. package/dist/realtime/live-events-ws.d.ts +28 -0
  140. package/dist/realtime/live-events-ws.d.ts.map +1 -0
  141. package/dist/realtime/live-events-ws.js +187 -0
  142. package/dist/realtime/live-events-ws.js.map +1 -0
  143. package/dist/redaction.d.ts +4 -0
  144. package/dist/redaction.d.ts.map +1 -0
  145. package/dist/redaction.js +63 -0
  146. package/dist/redaction.js.map +1 -0
  147. package/dist/routes/access.d.ts +62 -0
  148. package/dist/routes/access.d.ts.map +1 -0
  149. package/dist/routes/access.js +2296 -0
  150. package/dist/routes/access.js.map +1 -0
  151. package/dist/routes/activity.d.ts +3 -0
  152. package/dist/routes/activity.d.ts.map +1 -0
  153. package/dist/routes/activity.js +78 -0
  154. package/dist/routes/activity.js.map +1 -0
  155. package/dist/routes/agents.d.ts +3 -0
  156. package/dist/routes/agents.d.ts.map +1 -0
  157. package/dist/routes/agents.js +1918 -0
  158. package/dist/routes/agents.js.map +1 -0
  159. package/dist/routes/approvals.d.ts +3 -0
  160. package/dist/routes/approvals.d.ts.map +1 -0
  161. package/dist/routes/approvals.js +275 -0
  162. package/dist/routes/approvals.js.map +1 -0
  163. package/dist/routes/assets.d.ts +4 -0
  164. package/dist/routes/assets.d.ts.map +1 -0
  165. package/dist/routes/assets.js +309 -0
  166. package/dist/routes/assets.js.map +1 -0
  167. package/dist/routes/authz.d.ts +16 -0
  168. package/dist/routes/authz.d.ts.map +1 -0
  169. package/dist/routes/authz.js +47 -0
  170. package/dist/routes/authz.js.map +1 -0
  171. package/dist/routes/companies.d.ts +4 -0
  172. package/dist/routes/companies.d.ts.map +1 -0
  173. package/dist/routes/companies.js +356 -0
  174. package/dist/routes/companies.js.map +1 -0
  175. package/dist/routes/company-skills.d.ts +3 -0
  176. package/dist/routes/company-skills.d.ts.map +1 -0
  177. package/dist/routes/company-skills.js +228 -0
  178. package/dist/routes/company-skills.js.map +1 -0
  179. package/dist/routes/costs.d.ts +3 -0
  180. package/dist/routes/costs.d.ts.map +1 -0
  181. package/dist/routes/costs.js +268 -0
  182. package/dist/routes/costs.js.map +1 -0
  183. package/dist/routes/dashboard.d.ts +3 -0
  184. package/dist/routes/dashboard.d.ts.map +1 -0
  185. package/dist/routes/dashboard.js +15 -0
  186. package/dist/routes/dashboard.js.map +1 -0
  187. package/dist/routes/execution-workspaces.d.ts +3 -0
  188. package/dist/routes/execution-workspaces.d.ts.map +1 -0
  189. package/dist/routes/execution-workspaces.js +367 -0
  190. package/dist/routes/execution-workspaces.js.map +1 -0
  191. package/dist/routes/goals.d.ts +3 -0
  192. package/dist/routes/goals.d.ts.map +1 -0
  193. package/dist/routes/goals.js +95 -0
  194. package/dist/routes/goals.js.map +1 -0
  195. package/dist/routes/health.d.ts +9 -0
  196. package/dist/routes/health.d.ts.map +1 -0
  197. package/dist/routes/health.js +80 -0
  198. package/dist/routes/health.js.map +1 -0
  199. package/dist/routes/index.d.ts +18 -0
  200. package/dist/routes/index.d.ts.map +1 -0
  201. package/dist/routes/index.js +18 -0
  202. package/dist/routes/index.js.map +1 -0
  203. package/dist/routes/instance-settings.d.ts +3 -0
  204. package/dist/routes/instance-settings.d.ts.map +1 -0
  205. package/dist/routes/instance-settings.js +79 -0
  206. package/dist/routes/instance-settings.js.map +1 -0
  207. package/dist/routes/issues-checkout-wakeup.d.ts +9 -0
  208. package/dist/routes/issues-checkout-wakeup.d.ts.map +1 -0
  209. package/dist/routes/issues-checkout-wakeup.js +12 -0
  210. package/dist/routes/issues-checkout-wakeup.js.map +1 -0
  211. package/dist/routes/issues.d.ts +4 -0
  212. package/dist/routes/issues.d.ts.map +1 -0
  213. package/dist/routes/issues.js +1834 -0
  214. package/dist/routes/issues.js.map +1 -0
  215. package/dist/routes/llms.d.ts +3 -0
  216. package/dist/routes/llms.d.ts.map +1 -0
  217. package/dist/routes/llms.js +78 -0
  218. package/dist/routes/llms.js.map +1 -0
  219. package/dist/routes/org-chart-svg.d.ts +25 -0
  220. package/dist/routes/org-chart-svg.d.ts.map +1 -0
  221. package/dist/routes/org-chart-svg.js +656 -0
  222. package/dist/routes/org-chart-svg.js.map +1 -0
  223. package/dist/routes/plugin-ui-static.d.ts +69 -0
  224. package/dist/routes/plugin-ui-static.d.ts.map +1 -0
  225. package/dist/routes/plugin-ui-static.js +411 -0
  226. package/dist/routes/plugin-ui-static.js.map +1 -0
  227. package/dist/routes/plugins.d.ts +120 -0
  228. package/dist/routes/plugins.d.ts.map +1 -0
  229. package/dist/routes/plugins.js +1784 -0
  230. package/dist/routes/plugins.js.map +1 -0
  231. package/dist/routes/projects.d.ts +3 -0
  232. package/dist/routes/projects.d.ts.map +1 -0
  233. package/dist/routes/projects.js +386 -0
  234. package/dist/routes/projects.js.map +1 -0
  235. package/dist/routes/routines.d.ts +3 -0
  236. package/dist/routes/routines.d.ts.map +1 -0
  237. package/dist/routes/routines.js +277 -0
  238. package/dist/routes/routines.js.map +1 -0
  239. package/dist/routes/secrets.d.ts +3 -0
  240. package/dist/routes/secrets.d.ts.map +1 -0
  241. package/dist/routes/secrets.js +128 -0
  242. package/dist/routes/secrets.js.map +1 -0
  243. package/dist/routes/sidebar-badges.d.ts +3 -0
  244. package/dist/routes/sidebar-badges.d.ts.map +1 -0
  245. package/dist/routes/sidebar-badges.js +45 -0
  246. package/dist/routes/sidebar-badges.js.map +1 -0
  247. package/dist/secrets/external-stub-providers.d.ts +5 -0
  248. package/dist/secrets/external-stub-providers.d.ts.map +1 -0
  249. package/dist/secrets/external-stub-providers.js +21 -0
  250. package/dist/secrets/external-stub-providers.js.map +1 -0
  251. package/dist/secrets/local-encrypted-provider.d.ts +3 -0
  252. package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
  253. package/dist/secrets/local-encrypted-provider.js +116 -0
  254. package/dist/secrets/local-encrypted-provider.js.map +1 -0
  255. package/dist/secrets/provider-registry.d.ts +5 -0
  256. package/dist/secrets/provider-registry.d.ts.map +1 -0
  257. package/dist/secrets/provider-registry.js +20 -0
  258. package/dist/secrets/provider-registry.js.map +1 -0
  259. package/dist/secrets/types.d.ts +21 -0
  260. package/dist/secrets/types.d.ts.map +1 -0
  261. package/dist/secrets/types.js +2 -0
  262. package/dist/secrets/types.js.map +1 -0
  263. package/dist/services/access.d.ts +113 -0
  264. package/dist/services/access.d.ts.map +1 -0
  265. package/dist/services/access.js +247 -0
  266. package/dist/services/access.js.map +1 -0
  267. package/dist/services/activity-log.d.ts +17 -0
  268. package/dist/services/activity-log.d.ts.map +1 -0
  269. package/dist/services/activity-log.js +74 -0
  270. package/dist/services/activity-log.js.map +1 -0
  271. package/dist/services/activity.d.ts +764 -0
  272. package/dist/services/activity.d.ts.map +1 -0
  273. package/dist/services/activity.js +105 -0
  274. package/dist/services/activity.js.map +1 -0
  275. package/dist/services/agent-instructions.d.ts +91 -0
  276. package/dist/services/agent-instructions.d.ts.map +1 -0
  277. package/dist/services/agent-instructions.js +580 -0
  278. package/dist/services/agent-instructions.js.map +1 -0
  279. package/dist/services/agent-permissions.d.ts +6 -0
  280. package/dist/services/agent-permissions.d.ts.map +1 -0
  281. package/dist/services/agent-permissions.js +18 -0
  282. package/dist/services/agent-permissions.js.map +1 -0
  283. package/dist/services/agents.d.ts +1670 -0
  284. package/dist/services/agents.d.ts.map +1 -0
  285. package/dist/services/agents.js +566 -0
  286. package/dist/services/agents.js.map +1 -0
  287. package/dist/services/approvals.d.ts +546 -0
  288. package/dist/services/approvals.d.ts.map +1 -0
  289. package/dist/services/approvals.js +212 -0
  290. package/dist/services/approvals.js.map +1 -0
  291. package/dist/services/assets.d.ts +33 -0
  292. package/dist/services/assets.d.ts.map +1 -0
  293. package/dist/services/assets.js +17 -0
  294. package/dist/services/assets.js.map +1 -0
  295. package/dist/services/board-auth.d.ts +234 -0
  296. package/dist/services/board-auth.d.ts.map +1 -0
  297. package/dist/services/board-auth.js +295 -0
  298. package/dist/services/board-auth.js.map +1 -0
  299. package/dist/services/budgets.d.ts +38 -0
  300. package/dist/services/budgets.d.ts.map +1 -0
  301. package/dist/services/budgets.js +784 -0
  302. package/dist/services/budgets.js.map +1 -0
  303. package/dist/services/companies.d.ts +148 -0
  304. package/dist/services/companies.d.ts.map +1 -0
  305. package/dist/services/companies.js +260 -0
  306. package/dist/services/companies.js.map +1 -0
  307. package/dist/services/company-export-readme.d.ts +17 -0
  308. package/dist/services/company-export-readme.d.ts.map +1 -0
  309. package/dist/services/company-export-readme.js +148 -0
  310. package/dist/services/company-export-readme.js.map +1 -0
  311. package/dist/services/company-portability.d.ts +24 -0
  312. package/dist/services/company-portability.d.ts.map +1 -0
  313. package/dist/services/company-portability.js +3807 -0
  314. package/dist/services/company-portability.js.map +1 -0
  315. package/dist/services/company-skills.d.ts +77 -0
  316. package/dist/services/company-skills.d.ts.map +1 -0
  317. package/dist/services/company-skills.js +2063 -0
  318. package/dist/services/company-skills.js.map +1 -0
  319. package/dist/services/costs.d.ts +114 -0
  320. package/dist/services/costs.d.ts.map +1 -0
  321. package/dist/services/costs.js +294 -0
  322. package/dist/services/costs.js.map +1 -0
  323. package/dist/services/cron.d.ts +80 -0
  324. package/dist/services/cron.d.ts.map +1 -0
  325. package/dist/services/cron.js +300 -0
  326. package/dist/services/cron.js.map +1 -0
  327. package/dist/services/dashboard.d.ts +26 -0
  328. package/dist/services/dashboard.d.ts.map +1 -0
  329. package/dist/services/dashboard.js +98 -0
  330. package/dist/services/dashboard.js.map +1 -0
  331. package/dist/services/default-agent-instructions.d.ts +9 -0
  332. package/dist/services/default-agent-instructions.d.ts.map +1 -0
  333. package/dist/services/default-agent-instructions.js +20 -0
  334. package/dist/services/default-agent-instructions.js.map +1 -0
  335. package/dist/services/documents.d.ts +195 -0
  336. package/dist/services/documents.d.ts.map +1 -0
  337. package/dist/services/documents.js +409 -0
  338. package/dist/services/documents.js.map +1 -0
  339. package/dist/services/execution-workspace-policy.d.ts +21 -0
  340. package/dist/services/execution-workspace-policy.d.ts.map +1 -0
  341. package/dist/services/execution-workspace-policy.js +177 -0
  342. package/dist/services/execution-workspace-policy.js.map +1 -0
  343. package/dist/services/execution-workspaces.d.ts +22 -0
  344. package/dist/services/execution-workspaces.d.ts.map +1 -0
  345. package/dist/services/execution-workspaces.js +551 -0
  346. package/dist/services/execution-workspaces.js.map +1 -0
  347. package/dist/services/feedback-redaction.d.ts +23 -0
  348. package/dist/services/feedback-redaction.d.ts.map +1 -0
  349. package/dist/services/feedback-redaction.js +150 -0
  350. package/dist/services/feedback-redaction.js.map +1 -0
  351. package/dist/services/feedback-share-client.d.ts +9 -0
  352. package/dist/services/feedback-share-client.d.ts.map +1 -0
  353. package/dist/services/feedback-share-client.js +42 -0
  354. package/dist/services/feedback-share-client.js.map +1 -0
  355. package/dist/services/feedback.d.ts +91 -0
  356. package/dist/services/feedback.d.ts.map +1 -0
  357. package/dist/services/feedback.js +1662 -0
  358. package/dist/services/feedback.js.map +1 -0
  359. package/dist/services/finance.d.ts +93 -0
  360. package/dist/services/finance.d.ts.map +1 -0
  361. package/dist/services/finance.js +120 -0
  362. package/dist/services/finance.js.map +1 -0
  363. package/dist/services/github-fetch.d.ts +4 -0
  364. package/dist/services/github-fetch.d.ts.map +1 -0
  365. package/dist/services/github-fetch.js +23 -0
  366. package/dist/services/github-fetch.js.map +1 -0
  367. package/dist/services/goals.d.ts +433 -0
  368. package/dist/services/goals.d.ts.map +1 -0
  369. package/dist/services/goals.js +54 -0
  370. package/dist/services/goals.js.map +1 -0
  371. package/dist/services/heartbeat-run-summary.d.ts +2 -0
  372. package/dist/services/heartbeat-run-summary.d.ts.map +1 -0
  373. package/dist/services/heartbeat-run-summary.js +30 -0
  374. package/dist/services/heartbeat-run-summary.js.map +1 -0
  375. package/dist/services/heartbeat.d.ts +839 -0
  376. package/dist/services/heartbeat.d.ts.map +1 -0
  377. package/dist/services/heartbeat.js +3287 -0
  378. package/dist/services/heartbeat.js.map +1 -0
  379. package/dist/services/hire-hook.d.ts +14 -0
  380. package/dist/services/hire-hook.d.ts.map +1 -0
  381. package/dist/services/hire-hook.js +85 -0
  382. package/dist/services/hire-hook.js.map +1 -0
  383. package/dist/services/index.d.ts +34 -0
  384. package/dist/services/index.d.ts.map +1 -0
  385. package/dist/services/index.js +34 -0
  386. package/dist/services/index.js.map +1 -0
  387. package/dist/services/instance-settings.d.ts +11 -0
  388. package/dist/services/instance-settings.d.ts.map +1 -0
  389. package/dist/services/instance-settings.js +120 -0
  390. package/dist/services/instance-settings.js.map +1 -0
  391. package/dist/services/issue-approvals.d.ts +56 -0
  392. package/dist/services/issue-approvals.d.ts.map +1 -0
  393. package/dist/services/issue-approvals.js +153 -0
  394. package/dist/services/issue-approvals.js.map +1 -0
  395. package/dist/services/issue-assignment-wakeup.d.ts +29 -0
  396. package/dist/services/issue-assignment-wakeup.d.ts.map +1 -0
  397. package/dist/services/issue-assignment-wakeup.js +22 -0
  398. package/dist/services/issue-assignment-wakeup.js.map +1 -0
  399. package/dist/services/issue-goal-fallback.d.ts +18 -0
  400. package/dist/services/issue-goal-fallback.d.ts.map +1 -0
  401. package/dist/services/issue-goal-fallback.js +33 -0
  402. package/dist/services/issue-goal-fallback.js.map +1 -0
  403. package/dist/services/issues.d.ts +568 -0
  404. package/dist/services/issues.d.ts.map +1 -0
  405. package/dist/services/issues.js +1671 -0
  406. package/dist/services/issues.js.map +1 -0
  407. package/dist/services/live-events.d.ts +17 -0
  408. package/dist/services/live-events.d.ts.map +1 -0
  409. package/dist/services/live-events.js +33 -0
  410. package/dist/services/live-events.js.map +1 -0
  411. package/dist/services/local-service-supervisor.d.ts +55 -0
  412. package/dist/services/local-service-supervisor.d.ts.map +1 -0
  413. package/dist/services/local-service-supervisor.js +240 -0
  414. package/dist/services/local-service-supervisor.js.map +1 -0
  415. package/dist/services/plugin-capability-validator.d.ts +108 -0
  416. package/dist/services/plugin-capability-validator.d.ts.map +1 -0
  417. package/dist/services/plugin-capability-validator.js +269 -0
  418. package/dist/services/plugin-capability-validator.js.map +1 -0
  419. package/dist/services/plugin-config-validator.d.ts +26 -0
  420. package/dist/services/plugin-config-validator.d.ts.map +1 -0
  421. package/dist/services/plugin-config-validator.js +41 -0
  422. package/dist/services/plugin-config-validator.js.map +1 -0
  423. package/dist/services/plugin-dev-watcher.d.ts +30 -0
  424. package/dist/services/plugin-dev-watcher.d.ts.map +1 -0
  425. package/dist/services/plugin-dev-watcher.js +241 -0
  426. package/dist/services/plugin-dev-watcher.js.map +1 -0
  427. package/dist/services/plugin-event-bus.d.ts +149 -0
  428. package/dist/services/plugin-event-bus.d.ts.map +1 -0
  429. package/dist/services/plugin-event-bus.js +258 -0
  430. package/dist/services/plugin-event-bus.js.map +1 -0
  431. package/dist/services/plugin-host-service-cleanup.d.ts +14 -0
  432. package/dist/services/plugin-host-service-cleanup.d.ts.map +1 -0
  433. package/dist/services/plugin-host-service-cleanup.js +37 -0
  434. package/dist/services/plugin-host-service-cleanup.js.map +1 -0
  435. package/dist/services/plugin-host-services.d.ts +13 -0
  436. package/dist/services/plugin-host-services.d.ts.map +1 -0
  437. package/dist/services/plugin-host-services.js +983 -0
  438. package/dist/services/plugin-host-services.js.map +1 -0
  439. package/dist/services/plugin-job-coordinator.d.ts +81 -0
  440. package/dist/services/plugin-job-coordinator.d.ts.map +1 -0
  441. package/dist/services/plugin-job-coordinator.js +172 -0
  442. package/dist/services/plugin-job-coordinator.js.map +1 -0
  443. package/dist/services/plugin-job-scheduler.d.ts +163 -0
  444. package/dist/services/plugin-job-scheduler.d.ts.map +1 -0
  445. package/dist/services/plugin-job-scheduler.js +454 -0
  446. package/dist/services/plugin-job-scheduler.js.map +1 -0
  447. package/dist/services/plugin-job-store.d.ts +208 -0
  448. package/dist/services/plugin-job-store.d.ts.map +1 -0
  449. package/dist/services/plugin-job-store.js +350 -0
  450. package/dist/services/plugin-job-store.js.map +1 -0
  451. package/dist/services/plugin-lifecycle.d.ts +203 -0
  452. package/dist/services/plugin-lifecycle.d.ts.map +1 -0
  453. package/dist/services/plugin-lifecycle.js +476 -0
  454. package/dist/services/plugin-lifecycle.js.map +1 -0
  455. package/dist/services/plugin-loader.d.ts +441 -0
  456. package/dist/services/plugin-loader.d.ts.map +1 -0
  457. package/dist/services/plugin-loader.js +1192 -0
  458. package/dist/services/plugin-loader.js.map +1 -0
  459. package/dist/services/plugin-log-retention.d.ts +20 -0
  460. package/dist/services/plugin-log-retention.d.ts.map +1 -0
  461. package/dist/services/plugin-log-retention.js +63 -0
  462. package/dist/services/plugin-log-retention.js.map +1 -0
  463. package/dist/services/plugin-manifest-validator.d.ts +79 -0
  464. package/dist/services/plugin-manifest-validator.d.ts.map +1 -0
  465. package/dist/services/plugin-manifest-validator.js +84 -0
  466. package/dist/services/plugin-manifest-validator.js.map +1 -0
  467. package/dist/services/plugin-registry.d.ts +2542 -0
  468. package/dist/services/plugin-registry.d.ts.map +1 -0
  469. package/dist/services/plugin-registry.js +539 -0
  470. package/dist/services/plugin-registry.js.map +1 -0
  471. package/dist/services/plugin-runtime-sandbox.d.ts +40 -0
  472. package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -0
  473. package/dist/services/plugin-runtime-sandbox.js +154 -0
  474. package/dist/services/plugin-runtime-sandbox.js.map +1 -0
  475. package/dist/services/plugin-secrets-handler.d.ts +81 -0
  476. package/dist/services/plugin-secrets-handler.d.ts.map +1 -0
  477. package/dist/services/plugin-secrets-handler.js +275 -0
  478. package/dist/services/plugin-secrets-handler.js.map +1 -0
  479. package/dist/services/plugin-state-store.d.ts +92 -0
  480. package/dist/services/plugin-state-store.d.ts.map +1 -0
  481. package/dist/services/plugin-state-store.js +190 -0
  482. package/dist/services/plugin-state-store.js.map +1 -0
  483. package/dist/services/plugin-stream-bus.d.ts +29 -0
  484. package/dist/services/plugin-stream-bus.d.ts.map +1 -0
  485. package/dist/services/plugin-stream-bus.js +48 -0
  486. package/dist/services/plugin-stream-bus.js.map +1 -0
  487. package/dist/services/plugin-tool-dispatcher.d.ts +180 -0
  488. package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -0
  489. package/dist/services/plugin-tool-dispatcher.js +224 -0
  490. package/dist/services/plugin-tool-dispatcher.js.map +1 -0
  491. package/dist/services/plugin-tool-registry.d.ts +192 -0
  492. package/dist/services/plugin-tool-registry.d.ts.map +1 -0
  493. package/dist/services/plugin-tool-registry.js +224 -0
  494. package/dist/services/plugin-tool-registry.js.map +1 -0
  495. package/dist/services/plugin-worker-manager.d.ts +260 -0
  496. package/dist/services/plugin-worker-manager.d.ts.map +1 -0
  497. package/dist/services/plugin-worker-manager.js +835 -0
  498. package/dist/services/plugin-worker-manager.js.map +1 -0
  499. package/dist/services/project-workspace-runtime-config.d.ts +4 -0
  500. package/dist/services/project-workspace-runtime-config.d.ts.map +1 -0
  501. package/dist/services/project-workspace-runtime-config.js +43 -0
  502. package/dist/services/project-workspace-runtime-config.js.map +1 -0
  503. package/dist/services/projects.d.ts +88 -0
  504. package/dist/services/projects.d.ts.map +1 -0
  505. package/dist/services/projects.js +669 -0
  506. package/dist/services/projects.js.map +1 -0
  507. package/dist/services/quota-windows.d.ts +9 -0
  508. package/dist/services/quota-windows.d.ts.map +1 -0
  509. package/dist/services/quota-windows.js +56 -0
  510. package/dist/services/quota-windows.js.map +1 -0
  511. package/dist/services/routines.d.ts +136 -0
  512. package/dist/services/routines.d.ts.map +1 -0
  513. package/dist/services/routines.js +1268 -0
  514. package/dist/services/routines.js.map +1 -0
  515. package/dist/services/run-log-store.d.ts +34 -0
  516. package/dist/services/run-log-store.d.ts.map +1 -0
  517. package/dist/services/run-log-store.js +109 -0
  518. package/dist/services/run-log-store.js.map +1 -0
  519. package/dist/services/secrets.d.ts +511 -0
  520. package/dist/services/secrets.d.ts.map +1 -0
  521. package/dist/services/secrets.js +289 -0
  522. package/dist/services/secrets.js.map +1 -0
  523. package/dist/services/sidebar-badges.d.ts +9 -0
  524. package/dist/services/sidebar-badges.d.ts.map +1 -0
  525. package/dist/services/sidebar-badges.js +33 -0
  526. package/dist/services/sidebar-badges.js.map +1 -0
  527. package/dist/services/work-products.d.ts +14 -0
  528. package/dist/services/work-products.d.ts.map +1 -0
  529. package/dist/services/work-products.js +100 -0
  530. package/dist/services/work-products.js.map +1 -0
  531. package/dist/services/workspace-operation-log-store.d.ts +33 -0
  532. package/dist/services/workspace-operation-log-store.d.ts.map +1 -0
  533. package/dist/services/workspace-operation-log-store.js +110 -0
  534. package/dist/services/workspace-operation-log-store.js.map +1 -0
  535. package/dist/services/workspace-operations.d.ts +44 -0
  536. package/dist/services/workspace-operations.d.ts.map +1 -0
  537. package/dist/services/workspace-operations.js +211 -0
  538. package/dist/services/workspace-operations.js.map +1 -0
  539. package/dist/services/workspace-runtime.d.ts +188 -0
  540. package/dist/services/workspace-runtime.d.ts.map +1 -0
  541. package/dist/services/workspace-runtime.js +1705 -0
  542. package/dist/services/workspace-runtime.js.map +1 -0
  543. package/dist/startup-banner.d.ts +31 -0
  544. package/dist/startup-banner.d.ts.map +1 -0
  545. package/dist/startup-banner.js +117 -0
  546. package/dist/startup-banner.js.map +1 -0
  547. package/dist/storage/index.d.ts +6 -0
  548. package/dist/storage/index.d.ts.map +1 -0
  549. package/dist/storage/index.js +29 -0
  550. package/dist/storage/index.js.map +1 -0
  551. package/dist/storage/local-disk-provider.d.ts +3 -0
  552. package/dist/storage/local-disk-provider.d.ts.map +1 -0
  553. package/dist/storage/local-disk-provider.js +79 -0
  554. package/dist/storage/local-disk-provider.js.map +1 -0
  555. package/dist/storage/provider-registry.d.ts +4 -0
  556. package/dist/storage/provider-registry.d.ts.map +1 -0
  557. package/dist/storage/provider-registry.js +15 -0
  558. package/dist/storage/provider-registry.js.map +1 -0
  559. package/dist/storage/s3-provider.d.ts +11 -0
  560. package/dist/storage/s3-provider.d.ts.map +1 -0
  561. package/dist/storage/s3-provider.js +123 -0
  562. package/dist/storage/s3-provider.js.map +1 -0
  563. package/dist/storage/service.d.ts +3 -0
  564. package/dist/storage/service.d.ts.map +1 -0
  565. package/dist/storage/service.js +120 -0
  566. package/dist/storage/service.js.map +1 -0
  567. package/dist/storage/types.d.ts +55 -0
  568. package/dist/storage/types.d.ts.map +1 -0
  569. package/dist/storage/types.js +2 -0
  570. package/dist/storage/types.js.map +1 -0
  571. package/dist/telemetry.d.ts +6 -0
  572. package/dist/telemetry.d.ts.map +1 -0
  573. package/dist/telemetry.js +20 -0
  574. package/dist/telemetry.js.map +1 -0
  575. package/dist/ui-branding.d.ts +13 -0
  576. package/dist/ui-branding.d.ts.map +1 -0
  577. package/dist/ui-branding.js +187 -0
  578. package/dist/ui-branding.js.map +1 -0
  579. package/dist/version.d.ts +2 -0
  580. package/dist/version.d.ts.map +1 -0
  581. package/dist/version.js +5 -0
  582. package/dist/version.js.map +1 -0
  583. package/dist/worktree-config.d.ts +19 -0
  584. package/dist/worktree-config.d.ts.map +1 -0
  585. package/dist/worktree-config.js +365 -0
  586. package/dist/worktree-config.js.map +1 -0
  587. package/package.json +90 -0
  588. package/ui-dist/android-chrome-192x192.png +0 -0
  589. package/ui-dist/android-chrome-512x512.png +0 -0
  590. package/ui-dist/apple-touch-icon.png +0 -0
  591. package/ui-dist/assets/_basePickBy-D2fZf0o0.js +1 -0
  592. package/ui-dist/assets/_baseUniq-CWLG_Xqf.js +1 -0
  593. package/ui-dist/assets/apl-B4CMkyY2.js +1 -0
  594. package/ui-dist/assets/arc-DeECLtLk.js +1 -0
  595. package/ui-dist/assets/architectureDiagram-VXUJARFQ-a4Gzo-8u.js +36 -0
  596. package/ui-dist/assets/asciiarmor-Df11BRmG.js +1 -0
  597. package/ui-dist/assets/asn1-EdZsLKOL.js +1 -0
  598. package/ui-dist/assets/asterisk-B-8jnY81.js +1 -0
  599. package/ui-dist/assets/blockDiagram-VD42YOAC-tsACr-ke.js +122 -0
  600. package/ui-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  601. package/ui-dist/assets/c4Diagram-YG6GDRKO-CxIEiGp0.js +10 -0
  602. package/ui-dist/assets/channel-B8aOlvkH.js +1 -0
  603. package/ui-dist/assets/chunk-4BX2VUAB-DXyq1OVE.js +1 -0
  604. package/ui-dist/assets/chunk-55IACEB6-DE0IJwCp.js +1 -0
  605. package/ui-dist/assets/chunk-B4BG7PRW-C4VgkuRm.js +165 -0
  606. package/ui-dist/assets/chunk-DI55MBZ5-DUnVODLP.js +220 -0
  607. package/ui-dist/assets/chunk-FMBD7UC4-D14U1wU8.js +15 -0
  608. package/ui-dist/assets/chunk-QN33PNHL--9Fa_-d7.js +1 -0
  609. package/ui-dist/assets/chunk-QZHKN3VN-6vF9hrbB.js +1 -0
  610. package/ui-dist/assets/chunk-TZMSLE5B-BOKdVMfQ.js +1 -0
  611. package/ui-dist/assets/classDiagram-2ON5EDUG-CNtVQyHf.js +1 -0
  612. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-CNtVQyHf.js +1 -0
  613. package/ui-dist/assets/clike-B9uivgTg.js +1 -0
  614. package/ui-dist/assets/clojure-BMjYHr_A.js +1 -0
  615. package/ui-dist/assets/clone-DbnZAhBs.js +1 -0
  616. package/ui-dist/assets/cmake-BQqOBYOt.js +1 -0
  617. package/ui-dist/assets/cobol-CWcv1MsR.js +1 -0
  618. package/ui-dist/assets/coffeescript-S37ZYGWr.js +1 -0
  619. package/ui-dist/assets/commonlisp-DBKNyK5s.js +1 -0
  620. package/ui-dist/assets/cose-bilkent-S5V4N54A-BSFYrItZ.js +1 -0
  621. package/ui-dist/assets/crystal-SjHAIU92.js +1 -0
  622. package/ui-dist/assets/css-BnMrqG3P.js +1 -0
  623. package/ui-dist/assets/cypher-C_CwsFkJ.js +1 -0
  624. package/ui-dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  625. package/ui-dist/assets/d-pRatUO7H.js +1 -0
  626. package/ui-dist/assets/dagre-6UL2VRFP-D8xEb_jz.js +4 -0
  627. package/ui-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  628. package/ui-dist/assets/diagram-PSM6KHXK-kkdfif_P.js +24 -0
  629. package/ui-dist/assets/diagram-QEK2KX5R-BOA1wTkn.js +43 -0
  630. package/ui-dist/assets/diagram-S2PKOQOG-BMxIrdD_.js +24 -0
  631. package/ui-dist/assets/diff-DbItnlRl.js +1 -0
  632. package/ui-dist/assets/dockerfile-BKs6k2Af.js +1 -0
  633. package/ui-dist/assets/dtd-DF_7sFjM.js +1 -0
  634. package/ui-dist/assets/dylan-DwRh75JA.js +1 -0
  635. package/ui-dist/assets/ebnf-CDyGwa7X.js +1 -0
  636. package/ui-dist/assets/ecl-Cabwm37j.js +1 -0
  637. package/ui-dist/assets/eiffel-CnydiIhH.js +1 -0
  638. package/ui-dist/assets/elm-vLlmbW-K.js +1 -0
  639. package/ui-dist/assets/erDiagram-Q2GNP2WA-O1OwJuJt.js +60 -0
  640. package/ui-dist/assets/erlang-BNw1qcRV.js +1 -0
  641. package/ui-dist/assets/factor-kuTfRLto.js +1 -0
  642. package/ui-dist/assets/fcl-Kvtd6kyn.js +1 -0
  643. package/ui-dist/assets/flowDiagram-NV44I4VS-Ca9TsVEe.js +162 -0
  644. package/ui-dist/assets/forth-Ffai-XNe.js +1 -0
  645. package/ui-dist/assets/fortran-DYz_wnZ1.js +1 -0
  646. package/ui-dist/assets/ganttDiagram-JELNMOA3-CZ3k4lR4.js +267 -0
  647. package/ui-dist/assets/gas-Bneqetm1.js +1 -0
  648. package/ui-dist/assets/gherkin-heZmZLOM.js +1 -0
  649. package/ui-dist/assets/gitGraphDiagram-V2S2FVAM-CYXpu5VF.js +65 -0
  650. package/ui-dist/assets/graph-Ct1Mwc2w.js +1 -0
  651. package/ui-dist/assets/groovy-D9Dt4D0W.js +1 -0
  652. package/ui-dist/assets/haskell-Cw1EW3IL.js +1 -0
  653. package/ui-dist/assets/haxe-H-WmDvRZ.js +1 -0
  654. package/ui-dist/assets/http-DBlCnlav.js +1 -0
  655. package/ui-dist/assets/idl-BEugSyMb.js +1 -0
  656. package/ui-dist/assets/index-1-xGTyG8.js +1 -0
  657. package/ui-dist/assets/index-2BV3lexL.js +1 -0
  658. package/ui-dist/assets/index-7nZVjhgZ.js +1227 -0
  659. package/ui-dist/assets/index-B3cKIXfV.js +1 -0
  660. package/ui-dist/assets/index-BKVrlVnm.js +1 -0
  661. package/ui-dist/assets/index-BoQp7qpa.js +6 -0
  662. package/ui-dist/assets/index-Bso7Ph2z.js +1 -0
  663. package/ui-dist/assets/index-C016T1QA.js +1 -0
  664. package/ui-dist/assets/index-CKShy7qg.js +1 -0
  665. package/ui-dist/assets/index-CTeTAOP4.js +2 -0
  666. package/ui-dist/assets/index-CU0xjnJx.js +1 -0
  667. package/ui-dist/assets/index-CX3xG_nU.js +1 -0
  668. package/ui-dist/assets/index-ChGANpP5.js +1 -0
  669. package/ui-dist/assets/index-Cyi4EPvJ.js +13 -0
  670. package/ui-dist/assets/index-D4ERoZ49.js +1 -0
  671. package/ui-dist/assets/index-DAhE9Tae.js +1 -0
  672. package/ui-dist/assets/index-DYf-Vmt-.js +1 -0
  673. package/ui-dist/assets/index-DZ5z-1W5.js +1 -0
  674. package/ui-dist/assets/index-Dbx0Jq5s.js +1 -0
  675. package/ui-dist/assets/index-DcJU9_Xw.js +3 -0
  676. package/ui-dist/assets/index-DzvAUKSy.js +1 -0
  677. package/ui-dist/assets/index-Ip5TfL79.css +1 -0
  678. package/ui-dist/assets/index-b-wjeoWr.js +7 -0
  679. package/ui-dist/assets/index-zAFj8SiW.js +1 -0
  680. package/ui-dist/assets/infoDiagram-HS3SLOUP-BBoge3td.js +2 -0
  681. package/ui-dist/assets/init-Gi6I4Gst.js +1 -0
  682. package/ui-dist/assets/javascript-iXu5QeM3.js +1 -0
  683. package/ui-dist/assets/journeyDiagram-XKPGCS4Q-D6qBxJvS.js +139 -0
  684. package/ui-dist/assets/julia-DuME0IfC.js +1 -0
  685. package/ui-dist/assets/kanban-definition-3W4ZIXB7-BKw70hff.js +89 -0
  686. package/ui-dist/assets/katex-O9d3_IXG.js +261 -0
  687. package/ui-dist/assets/layout-C-MelZ5a.js +1 -0
  688. package/ui-dist/assets/linear-BDJBF_lN.js +1 -0
  689. package/ui-dist/assets/livescript-BwQOo05w.js +1 -0
  690. package/ui-dist/assets/lua-BgMRiT3U.js +1 -0
  691. package/ui-dist/assets/mathematica-DTrFuWx2.js +1 -0
  692. package/ui-dist/assets/mbox-CNhZ1qSd.js +1 -0
  693. package/ui-dist/assets/mermaid.core-C_LSSro9.js +256 -0
  694. package/ui-dist/assets/mindmap-definition-VGOIOE7T-DKTz8YjL.js +68 -0
  695. package/ui-dist/assets/mirc-CjQqDB4T.js +1 -0
  696. package/ui-dist/assets/mllike-CXdrOF99.js +1 -0
  697. package/ui-dist/assets/modelica-Dc1JOy9r.js +1 -0
  698. package/ui-dist/assets/mscgen-BA5vi2Kp.js +1 -0
  699. package/ui-dist/assets/mumps-BT43cFF4.js +1 -0
  700. package/ui-dist/assets/nginx-DdIZxoE0.js +1 -0
  701. package/ui-dist/assets/nsis-LdVXkNf5.js +1 -0
  702. package/ui-dist/assets/ntriples-BfvgReVJ.js +1 -0
  703. package/ui-dist/assets/octave-Ck1zUtKM.js +1 -0
  704. package/ui-dist/assets/ordinal-Cboi1Yqb.js +1 -0
  705. package/ui-dist/assets/oz-BzwKVEFT.js +1 -0
  706. package/ui-dist/assets/pascal--L3eBynH.js +1 -0
  707. package/ui-dist/assets/perl-CdXCOZ3F.js +1 -0
  708. package/ui-dist/assets/pieDiagram-ADFJNKIX-COzMH2F2.js +30 -0
  709. package/ui-dist/assets/pig-CevX1Tat.js +1 -0
  710. package/ui-dist/assets/powershell-CFHJl5sT.js +1 -0
  711. package/ui-dist/assets/properties-C78fOPTZ.js +1 -0
  712. package/ui-dist/assets/protobuf-ChK-085T.js +1 -0
  713. package/ui-dist/assets/pug-DeIclll2.js +1 -0
  714. package/ui-dist/assets/puppet-DMA9R1ak.js +1 -0
  715. package/ui-dist/assets/python-BuPzkPfP.js +1 -0
  716. package/ui-dist/assets/q-pXgVlZs6.js +1 -0
  717. package/ui-dist/assets/quadrantDiagram-AYHSOK5B-I8FRTFaI.js +7 -0
  718. package/ui-dist/assets/r-B6wPVr8A.js +1 -0
  719. package/ui-dist/assets/requirementDiagram-UZGBJVZJ-DI3nQy2l.js +64 -0
  720. package/ui-dist/assets/rpm-CTu-6PCP.js +1 -0
  721. package/ui-dist/assets/ruby-B2Rjki9n.js +1 -0
  722. package/ui-dist/assets/sankeyDiagram-TZEHDZUN-Pf_PmYIt.js +10 -0
  723. package/ui-dist/assets/sas-B4kiWyti.js +1 -0
  724. package/ui-dist/assets/scheme-C41bIUwD.js +1 -0
  725. package/ui-dist/assets/sequenceDiagram-WL72ISMW-DLgaS7kB.js +145 -0
  726. package/ui-dist/assets/shell-CjFT_Tl9.js +1 -0
  727. package/ui-dist/assets/sieve-C3Gn_uJK.js +1 -0
  728. package/ui-dist/assets/simple-mode-GW_nhZxv.js +1 -0
  729. package/ui-dist/assets/smalltalk-CnHTOXQT.js +1 -0
  730. package/ui-dist/assets/solr-DehyRSwq.js +1 -0
  731. package/ui-dist/assets/sparql-DkYu6x3z.js +1 -0
  732. package/ui-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  733. package/ui-dist/assets/sql-D0XecflT.js +1 -0
  734. package/ui-dist/assets/stateDiagram-FKZM4ZOC-BvMa1uU-.js +1 -0
  735. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-BKAZNp5l.js +1 -0
  736. package/ui-dist/assets/stex-C3f8Ysf7.js +1 -0
  737. package/ui-dist/assets/stylus-B533Al4x.js +1 -0
  738. package/ui-dist/assets/swift-BzpIVaGY.js +1 -0
  739. package/ui-dist/assets/tcl-DVfN8rqt.js +1 -0
  740. package/ui-dist/assets/textile-CnDTJFAw.js +1 -0
  741. package/ui-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  742. package/ui-dist/assets/tiki-DGYXhP31.js +1 -0
  743. package/ui-dist/assets/timeline-definition-IT6M3QCI-JQUCAkOQ.js +61 -0
  744. package/ui-dist/assets/toml-Bm5Em-hy.js +1 -0
  745. package/ui-dist/assets/treemap-GDKQZRPO-BK87qA0V.js +162 -0
  746. package/ui-dist/assets/troff-wAsdV37c.js +1 -0
  747. package/ui-dist/assets/ttcn-CfJYG6tj.js +1 -0
  748. package/ui-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  749. package/ui-dist/assets/turtle-B1tBg_DP.js +1 -0
  750. package/ui-dist/assets/vb-CmGdzxic.js +1 -0
  751. package/ui-dist/assets/vbscript-BuJXcnF6.js +1 -0
  752. package/ui-dist/assets/velocity-D8B20fx6.js +1 -0
  753. package/ui-dist/assets/verilog-C6RDOZhf.js +1 -0
  754. package/ui-dist/assets/vhdl-lSbBsy5d.js +1 -0
  755. package/ui-dist/assets/webidl-ZXfAyPTL.js +1 -0
  756. package/ui-dist/assets/xquery-DzFWVndE.js +1 -0
  757. package/ui-dist/assets/xychartDiagram-PRI3JC2R-UI3XP-6x.js +7 -0
  758. package/ui-dist/assets/yacas-BJ4BC0dw.js +1 -0
  759. package/ui-dist/assets/z80-Hz9HOZM7.js +1 -0
  760. package/ui-dist/brands/opencode-logo-dark-square.svg +18 -0
  761. package/ui-dist/brands/opencode-logo-light-square.svg +18 -0
  762. package/ui-dist/favicon-16x16.png +0 -0
  763. package/ui-dist/favicon-32x32.png +0 -0
  764. package/ui-dist/favicon.ico +0 -0
  765. package/ui-dist/favicon.svg +9 -0
  766. package/ui-dist/index.html +49 -0
  767. package/ui-dist/site.webmanifest +30 -0
  768. package/ui-dist/sw.js +42 -0
  769. package/ui-dist/worktree-favicon-16x16.png +0 -0
  770. package/ui-dist/worktree-favicon-32x32.png +0 -0
  771. package/ui-dist/worktree-favicon.ico +0 -0
  772. package/ui-dist/worktree-favicon.svg +9 -0
@@ -0,0 +1,1671 @@
1
+ import { and, asc, desc, eq, inArray, isNull, ne, or, sql } from "drizzle-orm";
2
+ import { activityLog, agents, assets, companies, companyMemberships, documents, goals, heartbeatRuns, executionWorkspaces, issueAttachments, issueInboxArchives, issueLabels, issueComments, issueDocuments, issueReadStates, issues, labels, projectWorkspaces, projects, } from "@zmeel/db";
3
+ import { extractAgentMentionIds, extractProjectMentionIds, isUuidLike } from "@zmeel/shared";
4
+ import { conflict, notFound, unprocessable } from "../errors.js";
5
+ import { defaultIssueExecutionWorkspaceSettingsForProject, gateProjectExecutionWorkspacePolicy, issueExecutionWorkspaceModeForPersistedWorkspace, parseProjectExecutionWorkspacePolicy, } from "./execution-workspace-policy.js";
6
+ import { instanceSettingsService } from "./instance-settings.js";
7
+ import { redactCurrentUserText } from "../log-redaction.js";
8
+ import { resolveIssueGoalId, resolveNextIssueGoalId } from "./issue-goal-fallback.js";
9
+ import { getDefaultCompanyGoal } from "./goals.js";
10
+ const ALL_ISSUE_STATUSES = ["backlog", "todo", "in_progress", "in_review", "blocked", "done", "cancelled"];
11
+ const MAX_ISSUE_COMMENT_PAGE_LIMIT = 500;
12
+ function assertTransition(from, to) {
13
+ if (from === to)
14
+ return;
15
+ if (!ALL_ISSUE_STATUSES.includes(to)) {
16
+ throw conflict(`Unknown issue status: ${to}`);
17
+ }
18
+ }
19
+ function applyStatusSideEffects(status, patch) {
20
+ if (!status)
21
+ return patch;
22
+ if (status === "in_progress" && !patch.startedAt) {
23
+ patch.startedAt = new Date();
24
+ }
25
+ if (status === "done") {
26
+ patch.completedAt = new Date();
27
+ }
28
+ if (status === "cancelled") {
29
+ patch.cancelledAt = new Date();
30
+ }
31
+ return patch;
32
+ }
33
+ function sameRunLock(checkoutRunId, actorRunId) {
34
+ if (actorRunId)
35
+ return checkoutRunId === actorRunId;
36
+ return checkoutRunId == null;
37
+ }
38
+ const TERMINAL_HEARTBEAT_RUN_STATUSES = new Set(["succeeded", "failed", "cancelled", "timed_out"]);
39
+ function escapeLikePattern(value) {
40
+ return value.replace(/[\\%_]/g, "\\$&");
41
+ }
42
+ async function getProjectDefaultGoalId(db, companyId, projectId) {
43
+ if (!projectId)
44
+ return null;
45
+ const row = await db
46
+ .select({ goalId: projects.goalId })
47
+ .from(projects)
48
+ .where(and(eq(projects.id, projectId), eq(projects.companyId, companyId)))
49
+ .then((rows) => rows[0] ?? null);
50
+ return row?.goalId ?? null;
51
+ }
52
+ async function getWorkspaceInheritanceIssue(db, companyId, issueId) {
53
+ const issue = await db
54
+ .select({
55
+ id: issues.id,
56
+ projectId: issues.projectId,
57
+ projectWorkspaceId: issues.projectWorkspaceId,
58
+ executionWorkspaceId: issues.executionWorkspaceId,
59
+ executionWorkspaceSettings: issues.executionWorkspaceSettings,
60
+ })
61
+ .from(issues)
62
+ .where(and(eq(issues.id, issueId), eq(issues.companyId, companyId)))
63
+ .then((rows) => rows[0] ?? null);
64
+ if (!issue) {
65
+ throw notFound("Workspace inheritance issue not found");
66
+ }
67
+ return issue;
68
+ }
69
+ function touchedByUserCondition(companyId, userId) {
70
+ return sql `
71
+ (
72
+ ${issues.createdByUserId} = ${userId}
73
+ OR ${issues.assigneeUserId} = ${userId}
74
+ OR EXISTS (
75
+ SELECT 1
76
+ FROM ${issueReadStates}
77
+ WHERE ${issueReadStates.issueId} = ${issues.id}
78
+ AND ${issueReadStates.companyId} = ${companyId}
79
+ AND ${issueReadStates.userId} = ${userId}
80
+ )
81
+ OR EXISTS (
82
+ SELECT 1
83
+ FROM ${issueComments}
84
+ WHERE ${issueComments.issueId} = ${issues.id}
85
+ AND ${issueComments.companyId} = ${companyId}
86
+ AND ${issueComments.authorUserId} = ${userId}
87
+ )
88
+ )
89
+ `;
90
+ }
91
+ function participatedByAgentCondition(companyId, agentId) {
92
+ return sql `
93
+ (
94
+ ${issues.createdByAgentId} = ${agentId}
95
+ OR ${issues.assigneeAgentId} = ${agentId}
96
+ OR EXISTS (
97
+ SELECT 1
98
+ FROM ${issueComments}
99
+ WHERE ${issueComments.issueId} = ${issues.id}
100
+ AND ${issueComments.companyId} = ${companyId}
101
+ AND ${issueComments.authorAgentId} = ${agentId}
102
+ )
103
+ OR EXISTS (
104
+ SELECT 1
105
+ FROM ${activityLog}
106
+ WHERE ${activityLog.companyId} = ${companyId}
107
+ AND ${activityLog.entityType} = 'issue'
108
+ AND ${activityLog.entityId} = ${issues.id}::text
109
+ AND ${activityLog.agentId} = ${agentId}
110
+ )
111
+ )
112
+ `;
113
+ }
114
+ function myLastCommentAtExpr(companyId, userId) {
115
+ return sql `
116
+ (
117
+ SELECT MAX(${issueComments.createdAt})
118
+ FROM ${issueComments}
119
+ WHERE ${issueComments.issueId} = ${issues.id}
120
+ AND ${issueComments.companyId} = ${companyId}
121
+ AND ${issueComments.authorUserId} = ${userId}
122
+ )
123
+ `;
124
+ }
125
+ function myLastReadAtExpr(companyId, userId) {
126
+ return sql `
127
+ (
128
+ SELECT MAX(${issueReadStates.lastReadAt})
129
+ FROM ${issueReadStates}
130
+ WHERE ${issueReadStates.issueId} = ${issues.id}
131
+ AND ${issueReadStates.companyId} = ${companyId}
132
+ AND ${issueReadStates.userId} = ${userId}
133
+ )
134
+ `;
135
+ }
136
+ function myLastTouchAtExpr(companyId, userId) {
137
+ const myLastCommentAt = myLastCommentAtExpr(companyId, userId);
138
+ const myLastReadAt = myLastReadAtExpr(companyId, userId);
139
+ return sql `
140
+ GREATEST(
141
+ COALESCE(${myLastCommentAt}, to_timestamp(0)),
142
+ COALESCE(${myLastReadAt}, to_timestamp(0)),
143
+ COALESCE(CASE WHEN ${issues.createdByUserId} = ${userId} THEN ${issues.createdAt} ELSE NULL END, to_timestamp(0)),
144
+ COALESCE(CASE WHEN ${issues.assigneeUserId} = ${userId} THEN ${issues.updatedAt} ELSE NULL END, to_timestamp(0))
145
+ )
146
+ `;
147
+ }
148
+ function lastExternalCommentAtExpr(companyId, userId) {
149
+ return sql `
150
+ (
151
+ SELECT MAX(${issueComments.createdAt})
152
+ FROM ${issueComments}
153
+ WHERE ${issueComments.issueId} = ${issues.id}
154
+ AND ${issueComments.companyId} = ${companyId}
155
+ AND (
156
+ ${issueComments.authorUserId} IS NULL
157
+ OR ${issueComments.authorUserId} <> ${userId}
158
+ )
159
+ )
160
+ `;
161
+ }
162
+ function issueLastActivityAtExpr(companyId, userId) {
163
+ const lastExternalCommentAt = lastExternalCommentAtExpr(companyId, userId);
164
+ const myLastTouchAt = myLastTouchAtExpr(companyId, userId);
165
+ return sql `
166
+ GREATEST(
167
+ COALESCE(${lastExternalCommentAt}, to_timestamp(0)),
168
+ CASE
169
+ WHEN ${issues.updatedAt} > COALESCE(${myLastTouchAt}, to_timestamp(0))
170
+ THEN ${issues.updatedAt}
171
+ ELSE to_timestamp(0)
172
+ END
173
+ )
174
+ `;
175
+ }
176
+ const ISSUE_LOCAL_INBOX_ACTIVITY_ACTIONS = [
177
+ "issue.read_marked",
178
+ "issue.read_unmarked",
179
+ "issue.inbox_archived",
180
+ "issue.inbox_unarchived",
181
+ ];
182
+ function issueLatestCommentAtExpr(companyId) {
183
+ return sql `
184
+ (
185
+ SELECT MAX(${issueComments.createdAt})
186
+ FROM ${issueComments}
187
+ WHERE ${issueComments.issueId} = ${issues.id}
188
+ AND ${issueComments.companyId} = ${companyId}
189
+ )
190
+ `;
191
+ }
192
+ function issueLatestLogAtExpr(companyId) {
193
+ return sql `
194
+ (
195
+ SELECT MAX(${activityLog.createdAt})
196
+ FROM ${activityLog}
197
+ WHERE ${activityLog.companyId} = ${companyId}
198
+ AND ${activityLog.entityType} = 'issue'
199
+ AND ${activityLog.entityId} = ${issues.id}::text
200
+ AND ${activityLog.action} NOT IN (${sql.join(ISSUE_LOCAL_INBOX_ACTIVITY_ACTIONS.map((action) => sql `${action}`), sql `, `)})
201
+ )
202
+ `;
203
+ }
204
+ function issueCanonicalLastActivityAtExpr(companyId) {
205
+ const latestCommentAt = issueLatestCommentAtExpr(companyId);
206
+ const latestLogAt = issueLatestLogAtExpr(companyId);
207
+ return sql `
208
+ GREATEST(
209
+ ${issues.updatedAt},
210
+ COALESCE(${latestCommentAt}, to_timestamp(0)),
211
+ COALESCE(${latestLogAt}, to_timestamp(0))
212
+ )
213
+ `;
214
+ }
215
+ function unreadForUserCondition(companyId, userId) {
216
+ const touchedCondition = touchedByUserCondition(companyId, userId);
217
+ const myLastTouchAt = myLastTouchAtExpr(companyId, userId);
218
+ return sql `
219
+ (
220
+ ${touchedCondition}
221
+ AND EXISTS (
222
+ SELECT 1
223
+ FROM ${issueComments}
224
+ WHERE ${issueComments.issueId} = ${issues.id}
225
+ AND ${issueComments.companyId} = ${companyId}
226
+ AND (
227
+ ${issueComments.authorUserId} IS NULL
228
+ OR ${issueComments.authorUserId} <> ${userId}
229
+ )
230
+ AND ${issueComments.createdAt} > ${myLastTouchAt}
231
+ )
232
+ )
233
+ `;
234
+ }
235
+ function inboxVisibleForUserCondition(companyId, userId) {
236
+ const issueLastActivityAt = issueLastActivityAtExpr(companyId, userId);
237
+ return sql `
238
+ NOT EXISTS (
239
+ SELECT 1
240
+ FROM ${issueInboxArchives}
241
+ WHERE ${issueInboxArchives.issueId} = ${issues.id}
242
+ AND ${issueInboxArchives.companyId} = ${companyId}
243
+ AND ${issueInboxArchives.userId} = ${userId}
244
+ AND ${issueInboxArchives.archivedAt} >= ${issueLastActivityAt}
245
+ )
246
+ `;
247
+ }
248
+ /** Named entities commonly emitted in saved issue bodies; unknown `&name;` sequences are left unchanged. */
249
+ const WELL_KNOWN_NAMED_HTML_ENTITIES = {
250
+ amp: "&",
251
+ apos: "'",
252
+ copy: "\u00A9",
253
+ gt: ">",
254
+ lt: "<",
255
+ nbsp: "\u00A0",
256
+ quot: '"',
257
+ ensp: "\u2002",
258
+ emsp: "\u2003",
259
+ thinsp: "\u2009",
260
+ };
261
+ function decodeNumericHtmlEntity(digits, radix) {
262
+ const n = Number.parseInt(digits, radix);
263
+ if (Number.isNaN(n) || n < 0 || n > 0x10ffff)
264
+ return null;
265
+ try {
266
+ return String.fromCodePoint(n);
267
+ }
268
+ catch {
269
+ return null;
270
+ }
271
+ }
272
+ /** Decodes HTML character references in a raw @mention capture so UI-encoded bodies match agent names. */
273
+ export function normalizeAgentMentionToken(raw) {
274
+ let s = raw.replace(/&#x([0-9a-fA-F]+);/gi, (full, hex) => decodeNumericHtmlEntity(hex, 16) ?? full);
275
+ s = s.replace(/&#([0-9]+);/g, (full, dec) => decodeNumericHtmlEntity(dec, 10) ?? full);
276
+ s = s.replace(/&([a-z][a-z0-9]*);/gi, (full, name) => {
277
+ const decoded = WELL_KNOWN_NAMED_HTML_ENTITIES[name.toLowerCase()];
278
+ return decoded !== undefined ? decoded : full;
279
+ });
280
+ return s.trim();
281
+ }
282
+ export function deriveIssueUserContext(issue, userId, stats) {
283
+ const normalizeDate = (value) => {
284
+ if (!value)
285
+ return null;
286
+ if (value instanceof Date)
287
+ return Number.isNaN(value.getTime()) ? null : value;
288
+ const parsed = new Date(value);
289
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
290
+ };
291
+ const myLastCommentAt = normalizeDate(stats?.myLastCommentAt);
292
+ const myLastReadAt = normalizeDate(stats?.myLastReadAt);
293
+ const createdTouchAt = issue.createdByUserId === userId ? normalizeDate(issue.createdAt) : null;
294
+ const assignedTouchAt = issue.assigneeUserId === userId ? normalizeDate(issue.updatedAt) : null;
295
+ const myLastTouchAt = [myLastCommentAt, myLastReadAt, createdTouchAt, assignedTouchAt]
296
+ .filter((value) => value instanceof Date)
297
+ .sort((a, b) => b.getTime() - a.getTime())[0] ?? null;
298
+ const lastExternalCommentAt = normalizeDate(stats?.lastExternalCommentAt);
299
+ const isUnreadForMe = Boolean(myLastTouchAt &&
300
+ lastExternalCommentAt &&
301
+ lastExternalCommentAt.getTime() > myLastTouchAt.getTime());
302
+ return {
303
+ myLastTouchAt,
304
+ lastExternalCommentAt,
305
+ isUnreadForMe,
306
+ };
307
+ }
308
+ function latestIssueActivityAt(...values) {
309
+ const normalized = values
310
+ .map((value) => {
311
+ if (!value)
312
+ return null;
313
+ if (value instanceof Date)
314
+ return Number.isNaN(value.getTime()) ? null : value;
315
+ const parsed = new Date(value);
316
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
317
+ })
318
+ .filter((value) => value instanceof Date)
319
+ .sort((a, b) => b.getTime() - a.getTime());
320
+ return normalized[0] ?? null;
321
+ }
322
+ async function labelMapForIssues(dbOrTx, issueIds) {
323
+ const map = new Map();
324
+ if (issueIds.length === 0)
325
+ return map;
326
+ const rows = await dbOrTx
327
+ .select({
328
+ issueId: issueLabels.issueId,
329
+ label: labels,
330
+ })
331
+ .from(issueLabels)
332
+ .innerJoin(labels, eq(issueLabels.labelId, labels.id))
333
+ .where(inArray(issueLabels.issueId, issueIds))
334
+ .orderBy(asc(labels.name), asc(labels.id));
335
+ for (const row of rows) {
336
+ const existing = map.get(row.issueId);
337
+ if (existing)
338
+ existing.push(row.label);
339
+ else
340
+ map.set(row.issueId, [row.label]);
341
+ }
342
+ return map;
343
+ }
344
+ async function withIssueLabels(dbOrTx, rows) {
345
+ if (rows.length === 0)
346
+ return [];
347
+ const labelsByIssueId = await labelMapForIssues(dbOrTx, rows.map((row) => row.id));
348
+ return rows.map((row) => {
349
+ const issueLabels = labelsByIssueId.get(row.id) ?? [];
350
+ return {
351
+ ...row,
352
+ labels: issueLabels,
353
+ labelIds: issueLabels.map((label) => label.id),
354
+ };
355
+ });
356
+ }
357
+ const ACTIVE_RUN_STATUSES = ["queued", "running"];
358
+ async function activeRunMapForIssues(dbOrTx, issueRows) {
359
+ const map = new Map();
360
+ const runIds = issueRows
361
+ .map((row) => row.executionRunId)
362
+ .filter((id) => id != null);
363
+ if (runIds.length === 0)
364
+ return map;
365
+ const rows = await dbOrTx
366
+ .select({
367
+ id: heartbeatRuns.id,
368
+ status: heartbeatRuns.status,
369
+ agentId: heartbeatRuns.agentId,
370
+ invocationSource: heartbeatRuns.invocationSource,
371
+ triggerDetail: heartbeatRuns.triggerDetail,
372
+ startedAt: heartbeatRuns.startedAt,
373
+ finishedAt: heartbeatRuns.finishedAt,
374
+ createdAt: heartbeatRuns.createdAt,
375
+ })
376
+ .from(heartbeatRuns)
377
+ .where(and(inArray(heartbeatRuns.id, runIds), inArray(heartbeatRuns.status, ACTIVE_RUN_STATUSES)));
378
+ for (const row of rows) {
379
+ map.set(row.id, row);
380
+ }
381
+ return map;
382
+ }
383
+ function withActiveRuns(issueRows, runMap) {
384
+ return issueRows.map((row) => ({
385
+ ...row,
386
+ activeRun: row.executionRunId ? (runMap.get(row.executionRunId) ?? null) : null,
387
+ }));
388
+ }
389
+ export function issueService(db) {
390
+ const instanceSettings = instanceSettingsService(db);
391
+ async function getIssueByUuid(id) {
392
+ const row = await db
393
+ .select()
394
+ .from(issues)
395
+ .where(eq(issues.id, id))
396
+ .then((rows) => rows[0] ?? null);
397
+ if (!row)
398
+ return null;
399
+ const [enriched] = await withIssueLabels(db, [row]);
400
+ return enriched;
401
+ }
402
+ async function getIssueByIdentifier(identifier) {
403
+ const row = await db
404
+ .select()
405
+ .from(issues)
406
+ .where(eq(issues.identifier, identifier.toUpperCase()))
407
+ .then((rows) => rows[0] ?? null);
408
+ if (!row)
409
+ return null;
410
+ const [enriched] = await withIssueLabels(db, [row]);
411
+ return enriched;
412
+ }
413
+ function redactIssueComment(comment, censorUsernameInLogs) {
414
+ return {
415
+ ...comment,
416
+ body: redactCurrentUserText(comment.body, { enabled: censorUsernameInLogs }),
417
+ };
418
+ }
419
+ async function assertAssignableAgent(companyId, agentId) {
420
+ const assignee = await db
421
+ .select({
422
+ id: agents.id,
423
+ companyId: agents.companyId,
424
+ status: agents.status,
425
+ })
426
+ .from(agents)
427
+ .where(eq(agents.id, agentId))
428
+ .then((rows) => rows[0] ?? null);
429
+ if (!assignee)
430
+ throw notFound("Assignee agent not found");
431
+ if (assignee.companyId !== companyId) {
432
+ throw unprocessable("Assignee must belong to same company");
433
+ }
434
+ if (assignee.status === "pending_approval") {
435
+ throw conflict("Cannot assign work to pending approval agents");
436
+ }
437
+ if (assignee.status === "terminated") {
438
+ throw conflict("Cannot assign work to terminated agents");
439
+ }
440
+ }
441
+ async function assertAssignableUser(companyId, userId) {
442
+ const membership = await db
443
+ .select({ id: companyMemberships.id })
444
+ .from(companyMemberships)
445
+ .where(and(eq(companyMemberships.companyId, companyId), eq(companyMemberships.principalType, "user"), eq(companyMemberships.principalId, userId), eq(companyMemberships.status, "active")))
446
+ .then((rows) => rows[0] ?? null);
447
+ if (!membership) {
448
+ throw notFound("Assignee user not found");
449
+ }
450
+ }
451
+ async function assertValidProjectWorkspace(companyId, projectId, projectWorkspaceId, dbOrTx = db) {
452
+ const workspace = await dbOrTx
453
+ .select({
454
+ id: projectWorkspaces.id,
455
+ companyId: projectWorkspaces.companyId,
456
+ projectId: projectWorkspaces.projectId,
457
+ })
458
+ .from(projectWorkspaces)
459
+ .where(eq(projectWorkspaces.id, projectWorkspaceId))
460
+ .then((rows) => rows[0] ?? null);
461
+ if (!workspace)
462
+ throw notFound("Project workspace not found");
463
+ if (workspace.companyId !== companyId)
464
+ throw unprocessable("Project workspace must belong to same company");
465
+ if (projectId && workspace.projectId !== projectId) {
466
+ throw unprocessable("Project workspace must belong to the selected project");
467
+ }
468
+ }
469
+ async function assertValidExecutionWorkspace(companyId, projectId, executionWorkspaceId, dbOrTx = db) {
470
+ const workspace = await dbOrTx
471
+ .select({
472
+ id: executionWorkspaces.id,
473
+ companyId: executionWorkspaces.companyId,
474
+ projectId: executionWorkspaces.projectId,
475
+ })
476
+ .from(executionWorkspaces)
477
+ .where(eq(executionWorkspaces.id, executionWorkspaceId))
478
+ .then((rows) => rows[0] ?? null);
479
+ if (!workspace)
480
+ throw notFound("Execution workspace not found");
481
+ if (workspace.companyId !== companyId)
482
+ throw unprocessable("Execution workspace must belong to same company");
483
+ if (projectId && workspace.projectId !== projectId) {
484
+ throw unprocessable("Execution workspace must belong to the selected project");
485
+ }
486
+ }
487
+ async function assertValidLabelIds(companyId, labelIds, dbOrTx = db) {
488
+ if (labelIds.length === 0)
489
+ return;
490
+ const existing = await dbOrTx
491
+ .select({ id: labels.id })
492
+ .from(labels)
493
+ .where(and(eq(labels.companyId, companyId), inArray(labels.id, labelIds)));
494
+ if (existing.length !== new Set(labelIds).size) {
495
+ throw unprocessable("One or more labels are invalid for this company");
496
+ }
497
+ }
498
+ async function syncIssueLabels(issueId, companyId, labelIds, dbOrTx = db) {
499
+ const deduped = [...new Set(labelIds)];
500
+ await assertValidLabelIds(companyId, deduped, dbOrTx);
501
+ await dbOrTx.delete(issueLabels).where(eq(issueLabels.issueId, issueId));
502
+ if (deduped.length === 0)
503
+ return;
504
+ await dbOrTx.insert(issueLabels).values(deduped.map((labelId) => ({
505
+ issueId,
506
+ labelId,
507
+ companyId,
508
+ })));
509
+ }
510
+ async function isTerminalOrMissingHeartbeatRun(runId) {
511
+ const run = await db
512
+ .select({ status: heartbeatRuns.status })
513
+ .from(heartbeatRuns)
514
+ .where(eq(heartbeatRuns.id, runId))
515
+ .then((rows) => rows[0] ?? null);
516
+ if (!run)
517
+ return true;
518
+ return TERMINAL_HEARTBEAT_RUN_STATUSES.has(run.status);
519
+ }
520
+ async function adoptStaleCheckoutRun(input) {
521
+ const stale = await isTerminalOrMissingHeartbeatRun(input.expectedCheckoutRunId);
522
+ if (!stale)
523
+ return null;
524
+ const now = new Date();
525
+ const adopted = await db
526
+ .update(issues)
527
+ .set({
528
+ checkoutRunId: input.actorRunId,
529
+ executionRunId: input.actorRunId,
530
+ executionLockedAt: now,
531
+ updatedAt: now,
532
+ })
533
+ .where(and(eq(issues.id, input.issueId), eq(issues.status, "in_progress"), eq(issues.assigneeAgentId, input.actorAgentId), eq(issues.checkoutRunId, input.expectedCheckoutRunId)))
534
+ .returning({
535
+ id: issues.id,
536
+ status: issues.status,
537
+ assigneeAgentId: issues.assigneeAgentId,
538
+ checkoutRunId: issues.checkoutRunId,
539
+ executionRunId: issues.executionRunId,
540
+ })
541
+ .then((rows) => rows[0] ?? null);
542
+ return adopted;
543
+ }
544
+ return {
545
+ list: async (companyId, filters) => {
546
+ const conditions = [eq(issues.companyId, companyId)];
547
+ const touchedByUserId = filters?.touchedByUserId?.trim() || undefined;
548
+ const inboxArchivedByUserId = filters?.inboxArchivedByUserId?.trim() || undefined;
549
+ const unreadForUserId = filters?.unreadForUserId?.trim() || undefined;
550
+ const contextUserId = unreadForUserId ?? touchedByUserId ?? inboxArchivedByUserId;
551
+ const rawSearch = filters?.q?.trim() ?? "";
552
+ const hasSearch = rawSearch.length > 0;
553
+ const escapedSearch = hasSearch ? escapeLikePattern(rawSearch) : "";
554
+ const startsWithPattern = `${escapedSearch}%`;
555
+ const containsPattern = `%${escapedSearch}%`;
556
+ const titleStartsWithMatch = sql `${issues.title} ILIKE ${startsWithPattern} ESCAPE '\\'`;
557
+ const titleContainsMatch = sql `${issues.title} ILIKE ${containsPattern} ESCAPE '\\'`;
558
+ const identifierStartsWithMatch = sql `${issues.identifier} ILIKE ${startsWithPattern} ESCAPE '\\'`;
559
+ const identifierContainsMatch = sql `${issues.identifier} ILIKE ${containsPattern} ESCAPE '\\'`;
560
+ const descriptionContainsMatch = sql `${issues.description} ILIKE ${containsPattern} ESCAPE '\\'`;
561
+ const commentContainsMatch = sql `
562
+ EXISTS (
563
+ SELECT 1
564
+ FROM ${issueComments}
565
+ WHERE ${issueComments.issueId} = ${issues.id}
566
+ AND ${issueComments.companyId} = ${companyId}
567
+ AND ${issueComments.body} ILIKE ${containsPattern} ESCAPE '\\'
568
+ )
569
+ `;
570
+ if (filters?.status) {
571
+ const statuses = filters.status.split(",").map((s) => s.trim());
572
+ conditions.push(statuses.length === 1 ? eq(issues.status, statuses[0]) : inArray(issues.status, statuses));
573
+ }
574
+ if (filters?.assigneeAgentId) {
575
+ conditions.push(eq(issues.assigneeAgentId, filters.assigneeAgentId));
576
+ }
577
+ if (filters?.participantAgentId) {
578
+ conditions.push(participatedByAgentCondition(companyId, filters.participantAgentId));
579
+ }
580
+ if (filters?.assigneeUserId) {
581
+ conditions.push(eq(issues.assigneeUserId, filters.assigneeUserId));
582
+ }
583
+ if (touchedByUserId) {
584
+ conditions.push(touchedByUserCondition(companyId, touchedByUserId));
585
+ }
586
+ if (inboxArchivedByUserId) {
587
+ conditions.push(inboxVisibleForUserCondition(companyId, inboxArchivedByUserId));
588
+ }
589
+ if (unreadForUserId) {
590
+ conditions.push(unreadForUserCondition(companyId, unreadForUserId));
591
+ }
592
+ if (filters?.projectId)
593
+ conditions.push(eq(issues.projectId, filters.projectId));
594
+ if (filters?.executionWorkspaceId) {
595
+ conditions.push(eq(issues.executionWorkspaceId, filters.executionWorkspaceId));
596
+ }
597
+ if (filters?.parentId)
598
+ conditions.push(eq(issues.parentId, filters.parentId));
599
+ if (filters?.originKind)
600
+ conditions.push(eq(issues.originKind, filters.originKind));
601
+ if (filters?.originId)
602
+ conditions.push(eq(issues.originId, filters.originId));
603
+ if (filters?.labelId) {
604
+ const labeledIssueIds = await db
605
+ .select({ issueId: issueLabels.issueId })
606
+ .from(issueLabels)
607
+ .where(and(eq(issueLabels.companyId, companyId), eq(issueLabels.labelId, filters.labelId)));
608
+ if (labeledIssueIds.length === 0)
609
+ return [];
610
+ conditions.push(inArray(issues.id, labeledIssueIds.map((row) => row.issueId)));
611
+ }
612
+ if (hasSearch) {
613
+ conditions.push(or(titleContainsMatch, identifierContainsMatch, descriptionContainsMatch, commentContainsMatch));
614
+ }
615
+ if (!filters?.includeRoutineExecutions && !filters?.originKind && !filters?.originId) {
616
+ conditions.push(ne(issues.originKind, "routine_execution"));
617
+ }
618
+ conditions.push(isNull(issues.hiddenAt));
619
+ const priorityOrder = sql `CASE ${issues.priority} WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END`;
620
+ const searchOrder = sql `
621
+ CASE
622
+ WHEN ${titleStartsWithMatch} THEN 0
623
+ WHEN ${titleContainsMatch} THEN 1
624
+ WHEN ${identifierStartsWithMatch} THEN 2
625
+ WHEN ${identifierContainsMatch} THEN 3
626
+ WHEN ${descriptionContainsMatch} THEN 4
627
+ WHEN ${commentContainsMatch} THEN 5
628
+ ELSE 6
629
+ END
630
+ `;
631
+ const canonicalLastActivityAt = issueCanonicalLastActivityAtExpr(companyId);
632
+ const rows = await db
633
+ .select()
634
+ .from(issues)
635
+ .where(and(...conditions))
636
+ .orderBy(hasSearch ? asc(searchOrder) : asc(priorityOrder), asc(priorityOrder), desc(canonicalLastActivityAt), desc(issues.updatedAt));
637
+ const withLabels = await withIssueLabels(db, rows);
638
+ const runMap = await activeRunMapForIssues(db, withLabels);
639
+ const withRuns = withActiveRuns(withLabels, runMap);
640
+ if (withRuns.length === 0) {
641
+ return withRuns;
642
+ }
643
+ const issueIds = withRuns.map((row) => row.id);
644
+ const [statsRows, readRows, lastActivityRows] = await Promise.all([
645
+ contextUserId
646
+ ? db
647
+ .select({
648
+ issueId: issueComments.issueId,
649
+ myLastCommentAt: sql `
650
+ MAX(CASE WHEN ${issueComments.authorUserId} = ${contextUserId} THEN ${issueComments.createdAt} END)
651
+ `,
652
+ lastExternalCommentAt: sql `
653
+ MAX(
654
+ CASE
655
+ WHEN ${issueComments.authorUserId} IS NULL OR ${issueComments.authorUserId} <> ${contextUserId}
656
+ THEN ${issueComments.createdAt}
657
+ END
658
+ )
659
+ `,
660
+ })
661
+ .from(issueComments)
662
+ .where(and(eq(issueComments.companyId, companyId), inArray(issueComments.issueId, issueIds)))
663
+ .groupBy(issueComments.issueId)
664
+ : Promise.resolve([]),
665
+ contextUserId
666
+ ? db
667
+ .select({
668
+ issueId: issueReadStates.issueId,
669
+ myLastReadAt: issueReadStates.lastReadAt,
670
+ })
671
+ .from(issueReadStates)
672
+ .where(and(eq(issueReadStates.companyId, companyId), eq(issueReadStates.userId, contextUserId), inArray(issueReadStates.issueId, issueIds)))
673
+ : Promise.resolve([]),
674
+ Promise.all([
675
+ db
676
+ .select({
677
+ issueId: issueComments.issueId,
678
+ latestCommentAt: sql `MAX(${issueComments.createdAt})`,
679
+ })
680
+ .from(issueComments)
681
+ .where(and(eq(issueComments.companyId, companyId), inArray(issueComments.issueId, issueIds)))
682
+ .groupBy(issueComments.issueId),
683
+ db
684
+ .select({
685
+ issueId: activityLog.entityId,
686
+ latestLogAt: sql `MAX(${activityLog.createdAt})`,
687
+ })
688
+ .from(activityLog)
689
+ .where(and(eq(activityLog.companyId, companyId), eq(activityLog.entityType, "issue"), inArray(activityLog.entityId, issueIds), sql `${activityLog.action} NOT IN (${sql.join(ISSUE_LOCAL_INBOX_ACTIVITY_ACTIONS.map((action) => sql `${action}`), sql `, `)})`))
690
+ .groupBy(activityLog.entityId),
691
+ ]).then(([commentRows, logRows]) => {
692
+ const byIssueId = new Map();
693
+ for (const row of commentRows) {
694
+ byIssueId.set(row.issueId, {
695
+ issueId: row.issueId,
696
+ latestCommentAt: row.latestCommentAt,
697
+ latestLogAt: null,
698
+ });
699
+ }
700
+ for (const row of logRows) {
701
+ const existing = byIssueId.get(row.issueId);
702
+ if (existing)
703
+ existing.latestLogAt = row.latestLogAt;
704
+ else {
705
+ byIssueId.set(row.issueId, {
706
+ issueId: row.issueId,
707
+ latestCommentAt: null,
708
+ latestLogAt: row.latestLogAt,
709
+ });
710
+ }
711
+ }
712
+ return [...byIssueId.values()];
713
+ }),
714
+ ]);
715
+ const statsByIssueId = new Map(statsRows.map((row) => [row.issueId, row]));
716
+ const lastActivityByIssueId = new Map(lastActivityRows.map((row) => [row.issueId, row]));
717
+ if (!contextUserId) {
718
+ return withRuns.map((row) => {
719
+ const activity = lastActivityByIssueId.get(row.id);
720
+ const lastActivityAt = latestIssueActivityAt(row.updatedAt, activity?.latestCommentAt ?? null, activity?.latestLogAt ?? null) ?? row.updatedAt;
721
+ return {
722
+ ...row,
723
+ lastActivityAt,
724
+ };
725
+ });
726
+ }
727
+ const readByIssueId = new Map(readRows.map((row) => [row.issueId, row.myLastReadAt]));
728
+ return withRuns.map((row) => {
729
+ const activity = lastActivityByIssueId.get(row.id);
730
+ const lastActivityAt = latestIssueActivityAt(row.updatedAt, activity?.latestCommentAt ?? null, activity?.latestLogAt ?? null) ?? row.updatedAt;
731
+ return {
732
+ ...row,
733
+ lastActivityAt,
734
+ ...deriveIssueUserContext(row, contextUserId, {
735
+ myLastCommentAt: statsByIssueId.get(row.id)?.myLastCommentAt ?? null,
736
+ myLastReadAt: readByIssueId.get(row.id) ?? null,
737
+ lastExternalCommentAt: statsByIssueId.get(row.id)?.lastExternalCommentAt ?? null,
738
+ }),
739
+ };
740
+ });
741
+ },
742
+ countUnreadTouchedByUser: async (companyId, userId, status) => {
743
+ const conditions = [
744
+ eq(issues.companyId, companyId),
745
+ isNull(issues.hiddenAt),
746
+ unreadForUserCondition(companyId, userId),
747
+ ne(issues.originKind, "routine_execution"),
748
+ ];
749
+ if (status) {
750
+ const statuses = status.split(",").map((s) => s.trim()).filter(Boolean);
751
+ if (statuses.length === 1) {
752
+ conditions.push(eq(issues.status, statuses[0]));
753
+ }
754
+ else if (statuses.length > 1) {
755
+ conditions.push(inArray(issues.status, statuses));
756
+ }
757
+ }
758
+ const [row] = await db
759
+ .select({ count: sql `count(*)` })
760
+ .from(issues)
761
+ .where(and(...conditions));
762
+ return Number(row?.count ?? 0);
763
+ },
764
+ markRead: async (companyId, issueId, userId, readAt = new Date()) => {
765
+ const now = new Date();
766
+ const [row] = await db
767
+ .insert(issueReadStates)
768
+ .values({
769
+ companyId,
770
+ issueId,
771
+ userId,
772
+ lastReadAt: readAt,
773
+ updatedAt: now,
774
+ })
775
+ .onConflictDoUpdate({
776
+ target: [issueReadStates.companyId, issueReadStates.issueId, issueReadStates.userId],
777
+ set: {
778
+ lastReadAt: readAt,
779
+ updatedAt: now,
780
+ },
781
+ })
782
+ .returning();
783
+ return row;
784
+ },
785
+ markUnread: async (companyId, issueId, userId) => {
786
+ const deleted = await db
787
+ .delete(issueReadStates)
788
+ .where(and(eq(issueReadStates.companyId, companyId), eq(issueReadStates.issueId, issueId), eq(issueReadStates.userId, userId)))
789
+ .returning();
790
+ return deleted.length > 0;
791
+ },
792
+ archiveInbox: async (companyId, issueId, userId, archivedAt = new Date()) => {
793
+ const now = new Date();
794
+ const [row] = await db
795
+ .insert(issueInboxArchives)
796
+ .values({
797
+ companyId,
798
+ issueId,
799
+ userId,
800
+ archivedAt,
801
+ updatedAt: now,
802
+ })
803
+ .onConflictDoUpdate({
804
+ target: [issueInboxArchives.companyId, issueInboxArchives.issueId, issueInboxArchives.userId],
805
+ set: {
806
+ archivedAt,
807
+ updatedAt: now,
808
+ },
809
+ })
810
+ .returning();
811
+ return row;
812
+ },
813
+ unarchiveInbox: async (companyId, issueId, userId) => {
814
+ const [row] = await db
815
+ .delete(issueInboxArchives)
816
+ .where(and(eq(issueInboxArchives.companyId, companyId), eq(issueInboxArchives.issueId, issueId), eq(issueInboxArchives.userId, userId)))
817
+ .returning();
818
+ return row ?? null;
819
+ },
820
+ getById: async (raw) => {
821
+ const id = raw.trim();
822
+ if (/^[A-Z]+-\d+$/i.test(id)) {
823
+ return getIssueByIdentifier(id);
824
+ }
825
+ if (!isUuidLike(id)) {
826
+ return null;
827
+ }
828
+ return getIssueByUuid(id);
829
+ },
830
+ getByIdentifier: async (identifier) => {
831
+ return getIssueByIdentifier(identifier);
832
+ },
833
+ create: async (companyId, data) => {
834
+ const { labelIds: inputLabelIds, inheritExecutionWorkspaceFromIssueId, ...issueData } = data;
835
+ const isolatedWorkspacesEnabled = (await instanceSettings.getExperimental()).enableIsolatedWorkspaces;
836
+ if (!isolatedWorkspacesEnabled) {
837
+ delete issueData.executionWorkspaceId;
838
+ delete issueData.executionWorkspacePreference;
839
+ delete issueData.executionWorkspaceSettings;
840
+ }
841
+ if (data.assigneeAgentId && data.assigneeUserId) {
842
+ throw unprocessable("Issue can only have one assignee");
843
+ }
844
+ if (data.assigneeAgentId) {
845
+ await assertAssignableAgent(companyId, data.assigneeAgentId);
846
+ }
847
+ if (data.assigneeUserId) {
848
+ await assertAssignableUser(companyId, data.assigneeUserId);
849
+ }
850
+ if (data.status === "in_progress" && !data.assigneeAgentId && !data.assigneeUserId) {
851
+ throw unprocessable("in_progress issues require an assignee");
852
+ }
853
+ return db.transaction(async (tx) => {
854
+ const defaultCompanyGoal = await getDefaultCompanyGoal(tx, companyId);
855
+ const projectGoalId = await getProjectDefaultGoalId(tx, companyId, issueData.projectId);
856
+ let projectWorkspaceId = issueData.projectWorkspaceId ?? null;
857
+ let executionWorkspaceId = issueData.executionWorkspaceId ?? null;
858
+ let executionWorkspacePreference = issueData.executionWorkspacePreference ?? null;
859
+ let executionWorkspaceSettings = issueData.executionWorkspaceSettings ?? null;
860
+ const workspaceInheritanceIssueId = inheritExecutionWorkspaceFromIssueId ?? issueData.parentId ?? null;
861
+ const hasExplicitExecutionWorkspaceOverride = issueData.executionWorkspaceId !== undefined ||
862
+ issueData.executionWorkspacePreference !== undefined ||
863
+ issueData.executionWorkspaceSettings !== undefined;
864
+ if (workspaceInheritanceIssueId) {
865
+ const workspaceSource = await getWorkspaceInheritanceIssue(tx, companyId, workspaceInheritanceIssueId);
866
+ if (projectWorkspaceId == null && workspaceSource.projectWorkspaceId) {
867
+ projectWorkspaceId = workspaceSource.projectWorkspaceId;
868
+ }
869
+ if (isolatedWorkspacesEnabled &&
870
+ !hasExplicitExecutionWorkspaceOverride &&
871
+ workspaceSource.executionWorkspaceId) {
872
+ const sourceWorkspace = await tx
873
+ .select({
874
+ id: executionWorkspaces.id,
875
+ mode: executionWorkspaces.mode,
876
+ })
877
+ .from(executionWorkspaces)
878
+ .where(eq(executionWorkspaces.id, workspaceSource.executionWorkspaceId))
879
+ .then((rows) => rows[0] ?? null);
880
+ if (sourceWorkspace) {
881
+ executionWorkspaceId = sourceWorkspace.id;
882
+ executionWorkspacePreference = "reuse_existing";
883
+ executionWorkspaceSettings = {
884
+ ...(workspaceSource.executionWorkspaceSettings ?? {}),
885
+ mode: issueExecutionWorkspaceModeForPersistedWorkspace(sourceWorkspace.mode),
886
+ };
887
+ }
888
+ }
889
+ }
890
+ if (executionWorkspaceSettings == null &&
891
+ executionWorkspaceId == null &&
892
+ issueData.projectId) {
893
+ const project = await tx
894
+ .select({ executionWorkspacePolicy: projects.executionWorkspacePolicy })
895
+ .from(projects)
896
+ .where(and(eq(projects.id, issueData.projectId), eq(projects.companyId, companyId)))
897
+ .then((rows) => rows[0] ?? null);
898
+ executionWorkspaceSettings =
899
+ defaultIssueExecutionWorkspaceSettingsForProject(gateProjectExecutionWorkspacePolicy(parseProjectExecutionWorkspacePolicy(project?.executionWorkspacePolicy), isolatedWorkspacesEnabled));
900
+ }
901
+ if (!projectWorkspaceId && issueData.projectId) {
902
+ const project = await tx
903
+ .select({
904
+ executionWorkspacePolicy: projects.executionWorkspacePolicy,
905
+ })
906
+ .from(projects)
907
+ .where(and(eq(projects.id, issueData.projectId), eq(projects.companyId, companyId)))
908
+ .then((rows) => rows[0] ?? null);
909
+ const projectPolicy = parseProjectExecutionWorkspacePolicy(project?.executionWorkspacePolicy);
910
+ projectWorkspaceId = projectPolicy?.defaultProjectWorkspaceId ?? null;
911
+ if (!projectWorkspaceId) {
912
+ projectWorkspaceId = await tx
913
+ .select({ id: projectWorkspaces.id })
914
+ .from(projectWorkspaces)
915
+ .where(and(eq(projectWorkspaces.projectId, issueData.projectId), eq(projectWorkspaces.companyId, companyId)))
916
+ .orderBy(desc(projectWorkspaces.isPrimary), asc(projectWorkspaces.createdAt), asc(projectWorkspaces.id))
917
+ .then((rows) => rows[0]?.id ?? null);
918
+ }
919
+ }
920
+ if (projectWorkspaceId) {
921
+ await assertValidProjectWorkspace(companyId, issueData.projectId, projectWorkspaceId, tx);
922
+ }
923
+ if (executionWorkspaceId) {
924
+ await assertValidExecutionWorkspace(companyId, issueData.projectId, executionWorkspaceId, tx);
925
+ }
926
+ const [company] = await tx
927
+ .update(companies)
928
+ .set({ issueCounter: sql `${companies.issueCounter} + 1` })
929
+ .where(eq(companies.id, companyId))
930
+ .returning({ issueCounter: companies.issueCounter, issuePrefix: companies.issuePrefix });
931
+ const issueNumber = company.issueCounter;
932
+ const identifier = `${company.issuePrefix}-${issueNumber}`;
933
+ const values = {
934
+ ...issueData,
935
+ originKind: issueData.originKind ?? "manual",
936
+ goalId: resolveIssueGoalId({
937
+ projectId: issueData.projectId,
938
+ goalId: issueData.goalId,
939
+ projectGoalId,
940
+ defaultGoalId: defaultCompanyGoal?.id ?? null,
941
+ }),
942
+ ...(projectWorkspaceId ? { projectWorkspaceId } : {}),
943
+ ...(executionWorkspaceId ? { executionWorkspaceId } : {}),
944
+ ...(executionWorkspacePreference ? { executionWorkspacePreference } : {}),
945
+ ...(executionWorkspaceSettings ? { executionWorkspaceSettings } : {}),
946
+ companyId,
947
+ issueNumber,
948
+ identifier,
949
+ };
950
+ if (values.status === "in_progress" && !values.startedAt) {
951
+ values.startedAt = new Date();
952
+ }
953
+ if (values.status === "done") {
954
+ values.completedAt = new Date();
955
+ }
956
+ if (values.status === "cancelled") {
957
+ values.cancelledAt = new Date();
958
+ }
959
+ const [issue] = await tx.insert(issues).values(values).returning();
960
+ if (inputLabelIds) {
961
+ await syncIssueLabels(issue.id, companyId, inputLabelIds, tx);
962
+ }
963
+ const [enriched] = await withIssueLabels(tx, [issue]);
964
+ return enriched;
965
+ });
966
+ },
967
+ update: async (id, data) => {
968
+ const existing = await db
969
+ .select()
970
+ .from(issues)
971
+ .where(eq(issues.id, id))
972
+ .then((rows) => rows[0] ?? null);
973
+ if (!existing)
974
+ return null;
975
+ const { labelIds: nextLabelIds, ...issueData } = data;
976
+ const isolatedWorkspacesEnabled = (await instanceSettings.getExperimental()).enableIsolatedWorkspaces;
977
+ if (!isolatedWorkspacesEnabled) {
978
+ delete issueData.executionWorkspaceId;
979
+ delete issueData.executionWorkspacePreference;
980
+ delete issueData.executionWorkspaceSettings;
981
+ }
982
+ if (issueData.status) {
983
+ assertTransition(existing.status, issueData.status);
984
+ }
985
+ const patch = {
986
+ ...issueData,
987
+ updatedAt: new Date(),
988
+ };
989
+ const nextAssigneeAgentId = issueData.assigneeAgentId !== undefined ? issueData.assigneeAgentId : existing.assigneeAgentId;
990
+ const nextAssigneeUserId = issueData.assigneeUserId !== undefined ? issueData.assigneeUserId : existing.assigneeUserId;
991
+ if (nextAssigneeAgentId && nextAssigneeUserId) {
992
+ throw unprocessable("Issue can only have one assignee");
993
+ }
994
+ if (patch.status === "in_progress" && !nextAssigneeAgentId && !nextAssigneeUserId) {
995
+ throw unprocessable("in_progress issues require an assignee");
996
+ }
997
+ if (issueData.assigneeAgentId) {
998
+ await assertAssignableAgent(existing.companyId, issueData.assigneeAgentId);
999
+ }
1000
+ if (issueData.assigneeUserId) {
1001
+ await assertAssignableUser(existing.companyId, issueData.assigneeUserId);
1002
+ }
1003
+ const nextProjectId = issueData.projectId !== undefined ? issueData.projectId : existing.projectId;
1004
+ const nextProjectWorkspaceId = issueData.projectWorkspaceId !== undefined ? issueData.projectWorkspaceId : existing.projectWorkspaceId;
1005
+ const nextExecutionWorkspaceId = issueData.executionWorkspaceId !== undefined ? issueData.executionWorkspaceId : existing.executionWorkspaceId;
1006
+ if (nextProjectWorkspaceId) {
1007
+ await assertValidProjectWorkspace(existing.companyId, nextProjectId, nextProjectWorkspaceId);
1008
+ }
1009
+ if (nextExecutionWorkspaceId) {
1010
+ await assertValidExecutionWorkspace(existing.companyId, nextProjectId, nextExecutionWorkspaceId);
1011
+ }
1012
+ applyStatusSideEffects(issueData.status, patch);
1013
+ if (issueData.status && issueData.status !== "done") {
1014
+ patch.completedAt = null;
1015
+ }
1016
+ if (issueData.status && issueData.status !== "cancelled") {
1017
+ patch.cancelledAt = null;
1018
+ }
1019
+ if (issueData.status && issueData.status !== "in_progress") {
1020
+ patch.checkoutRunId = null;
1021
+ }
1022
+ if ((issueData.assigneeAgentId !== undefined && issueData.assigneeAgentId !== existing.assigneeAgentId) ||
1023
+ (issueData.assigneeUserId !== undefined && issueData.assigneeUserId !== existing.assigneeUserId)) {
1024
+ patch.checkoutRunId = null;
1025
+ }
1026
+ return db.transaction(async (tx) => {
1027
+ const defaultCompanyGoal = await getDefaultCompanyGoal(tx, existing.companyId);
1028
+ const [currentProjectGoalId, nextProjectGoalId] = await Promise.all([
1029
+ getProjectDefaultGoalId(tx, existing.companyId, existing.projectId),
1030
+ getProjectDefaultGoalId(tx, existing.companyId, issueData.projectId !== undefined ? issueData.projectId : existing.projectId),
1031
+ ]);
1032
+ patch.goalId = resolveNextIssueGoalId({
1033
+ currentProjectId: existing.projectId,
1034
+ currentGoalId: existing.goalId,
1035
+ currentProjectGoalId,
1036
+ projectId: issueData.projectId,
1037
+ goalId: issueData.goalId,
1038
+ projectGoalId: nextProjectGoalId,
1039
+ defaultGoalId: defaultCompanyGoal?.id ?? null,
1040
+ });
1041
+ const updated = await tx
1042
+ .update(issues)
1043
+ .set(patch)
1044
+ .where(eq(issues.id, id))
1045
+ .returning()
1046
+ .then((rows) => rows[0] ?? null);
1047
+ if (!updated)
1048
+ return null;
1049
+ if (nextLabelIds !== undefined) {
1050
+ await syncIssueLabels(updated.id, existing.companyId, nextLabelIds, tx);
1051
+ }
1052
+ const [enriched] = await withIssueLabels(tx, [updated]);
1053
+ return enriched;
1054
+ });
1055
+ },
1056
+ remove: (id) => db.transaction(async (tx) => {
1057
+ const attachmentAssetIds = await tx
1058
+ .select({ assetId: issueAttachments.assetId })
1059
+ .from(issueAttachments)
1060
+ .where(eq(issueAttachments.issueId, id));
1061
+ const issueDocumentIds = await tx
1062
+ .select({ documentId: issueDocuments.documentId })
1063
+ .from(issueDocuments)
1064
+ .where(eq(issueDocuments.issueId, id));
1065
+ const removedIssue = await tx
1066
+ .delete(issues)
1067
+ .where(eq(issues.id, id))
1068
+ .returning()
1069
+ .then((rows) => rows[0] ?? null);
1070
+ if (removedIssue && attachmentAssetIds.length > 0) {
1071
+ await tx
1072
+ .delete(assets)
1073
+ .where(inArray(assets.id, attachmentAssetIds.map((row) => row.assetId)));
1074
+ }
1075
+ if (removedIssue && issueDocumentIds.length > 0) {
1076
+ await tx
1077
+ .delete(documents)
1078
+ .where(inArray(documents.id, issueDocumentIds.map((row) => row.documentId)));
1079
+ }
1080
+ if (!removedIssue)
1081
+ return null;
1082
+ const [enriched] = await withIssueLabels(tx, [removedIssue]);
1083
+ return enriched;
1084
+ }),
1085
+ checkout: async (id, agentId, expectedStatuses, checkoutRunId) => {
1086
+ const issueCompany = await db
1087
+ .select({ companyId: issues.companyId })
1088
+ .from(issues)
1089
+ .where(eq(issues.id, id))
1090
+ .then((rows) => rows[0] ?? null);
1091
+ if (!issueCompany)
1092
+ throw notFound("Issue not found");
1093
+ await assertAssignableAgent(issueCompany.companyId, agentId);
1094
+ const now = new Date();
1095
+ const sameRunAssigneeCondition = checkoutRunId
1096
+ ? and(eq(issues.assigneeAgentId, agentId), or(isNull(issues.checkoutRunId), eq(issues.checkoutRunId, checkoutRunId)))
1097
+ : and(eq(issues.assigneeAgentId, agentId), isNull(issues.checkoutRunId));
1098
+ const executionLockCondition = checkoutRunId
1099
+ ? or(isNull(issues.executionRunId), eq(issues.executionRunId, checkoutRunId))
1100
+ : isNull(issues.executionRunId);
1101
+ const updated = await db
1102
+ .update(issues)
1103
+ .set({
1104
+ assigneeAgentId: agentId,
1105
+ assigneeUserId: null,
1106
+ checkoutRunId,
1107
+ executionRunId: checkoutRunId,
1108
+ status: "in_progress",
1109
+ startedAt: now,
1110
+ updatedAt: now,
1111
+ })
1112
+ .where(and(eq(issues.id, id), inArray(issues.status, expectedStatuses), or(isNull(issues.assigneeAgentId), sameRunAssigneeCondition), executionLockCondition))
1113
+ .returning()
1114
+ .then((rows) => rows[0] ?? null);
1115
+ if (updated) {
1116
+ const [enriched] = await withIssueLabels(db, [updated]);
1117
+ return enriched;
1118
+ }
1119
+ const current = await db
1120
+ .select({
1121
+ id: issues.id,
1122
+ status: issues.status,
1123
+ assigneeAgentId: issues.assigneeAgentId,
1124
+ checkoutRunId: issues.checkoutRunId,
1125
+ executionRunId: issues.executionRunId,
1126
+ })
1127
+ .from(issues)
1128
+ .where(eq(issues.id, id))
1129
+ .then((rows) => rows[0] ?? null);
1130
+ if (!current)
1131
+ throw notFound("Issue not found");
1132
+ if (current.assigneeAgentId === agentId &&
1133
+ current.status === "in_progress" &&
1134
+ current.checkoutRunId == null &&
1135
+ (current.executionRunId == null || current.executionRunId === checkoutRunId) &&
1136
+ checkoutRunId) {
1137
+ const adopted = await db
1138
+ .update(issues)
1139
+ .set({
1140
+ checkoutRunId,
1141
+ executionRunId: checkoutRunId,
1142
+ updatedAt: new Date(),
1143
+ })
1144
+ .where(and(eq(issues.id, id), eq(issues.status, "in_progress"), eq(issues.assigneeAgentId, agentId), isNull(issues.checkoutRunId), or(isNull(issues.executionRunId), eq(issues.executionRunId, checkoutRunId))))
1145
+ .returning()
1146
+ .then((rows) => rows[0] ?? null);
1147
+ if (adopted)
1148
+ return adopted;
1149
+ }
1150
+ if (checkoutRunId &&
1151
+ current.assigneeAgentId === agentId &&
1152
+ current.status === "in_progress" &&
1153
+ current.checkoutRunId &&
1154
+ current.checkoutRunId !== checkoutRunId) {
1155
+ const adopted = await adoptStaleCheckoutRun({
1156
+ issueId: id,
1157
+ actorAgentId: agentId,
1158
+ actorRunId: checkoutRunId,
1159
+ expectedCheckoutRunId: current.checkoutRunId,
1160
+ });
1161
+ if (adopted) {
1162
+ const row = await db.select().from(issues).where(eq(issues.id, id)).then((rows) => rows[0]);
1163
+ const [enriched] = await withIssueLabels(db, [row]);
1164
+ return enriched;
1165
+ }
1166
+ }
1167
+ // If this run already owns it and it's in_progress, return it (no self-409)
1168
+ if (current.assigneeAgentId === agentId &&
1169
+ current.status === "in_progress" &&
1170
+ sameRunLock(current.checkoutRunId, checkoutRunId)) {
1171
+ const row = await db.select().from(issues).where(eq(issues.id, id)).then((rows) => rows[0]);
1172
+ const [enriched] = await withIssueLabels(db, [row]);
1173
+ return enriched;
1174
+ }
1175
+ throw conflict("Issue checkout conflict", {
1176
+ issueId: current.id,
1177
+ status: current.status,
1178
+ assigneeAgentId: current.assigneeAgentId,
1179
+ checkoutRunId: current.checkoutRunId,
1180
+ executionRunId: current.executionRunId,
1181
+ });
1182
+ },
1183
+ assertCheckoutOwner: async (id, actorAgentId, actorRunId) => {
1184
+ const current = await db
1185
+ .select({
1186
+ id: issues.id,
1187
+ status: issues.status,
1188
+ assigneeAgentId: issues.assigneeAgentId,
1189
+ checkoutRunId: issues.checkoutRunId,
1190
+ })
1191
+ .from(issues)
1192
+ .where(eq(issues.id, id))
1193
+ .then((rows) => rows[0] ?? null);
1194
+ if (!current)
1195
+ throw notFound("Issue not found");
1196
+ if (current.status === "in_progress" &&
1197
+ current.assigneeAgentId === actorAgentId &&
1198
+ sameRunLock(current.checkoutRunId, actorRunId)) {
1199
+ return { ...current, adoptedFromRunId: null };
1200
+ }
1201
+ if (actorRunId &&
1202
+ current.status === "in_progress" &&
1203
+ current.assigneeAgentId === actorAgentId &&
1204
+ current.checkoutRunId &&
1205
+ current.checkoutRunId !== actorRunId) {
1206
+ const adopted = await adoptStaleCheckoutRun({
1207
+ issueId: id,
1208
+ actorAgentId,
1209
+ actorRunId,
1210
+ expectedCheckoutRunId: current.checkoutRunId,
1211
+ });
1212
+ if (adopted) {
1213
+ return {
1214
+ ...adopted,
1215
+ adoptedFromRunId: current.checkoutRunId,
1216
+ };
1217
+ }
1218
+ }
1219
+ throw conflict("Issue run ownership conflict", {
1220
+ issueId: current.id,
1221
+ status: current.status,
1222
+ assigneeAgentId: current.assigneeAgentId,
1223
+ checkoutRunId: current.checkoutRunId,
1224
+ actorAgentId,
1225
+ actorRunId,
1226
+ });
1227
+ },
1228
+ release: async (id, actorAgentId, actorRunId) => {
1229
+ const existing = await db
1230
+ .select()
1231
+ .from(issues)
1232
+ .where(eq(issues.id, id))
1233
+ .then((rows) => rows[0] ?? null);
1234
+ if (!existing)
1235
+ return null;
1236
+ if (actorAgentId && existing.assigneeAgentId && existing.assigneeAgentId !== actorAgentId) {
1237
+ throw conflict("Only assignee can release issue");
1238
+ }
1239
+ if (actorAgentId &&
1240
+ existing.status === "in_progress" &&
1241
+ existing.assigneeAgentId === actorAgentId &&
1242
+ existing.checkoutRunId &&
1243
+ !sameRunLock(existing.checkoutRunId, actorRunId ?? null)) {
1244
+ throw conflict("Only checkout run can release issue", {
1245
+ issueId: existing.id,
1246
+ assigneeAgentId: existing.assigneeAgentId,
1247
+ checkoutRunId: existing.checkoutRunId,
1248
+ actorRunId: actorRunId ?? null,
1249
+ });
1250
+ }
1251
+ const updated = await db
1252
+ .update(issues)
1253
+ .set({
1254
+ status: "todo",
1255
+ assigneeAgentId: null,
1256
+ checkoutRunId: null,
1257
+ updatedAt: new Date(),
1258
+ })
1259
+ .where(eq(issues.id, id))
1260
+ .returning()
1261
+ .then((rows) => rows[0] ?? null);
1262
+ if (!updated)
1263
+ return null;
1264
+ const [enriched] = await withIssueLabels(db, [updated]);
1265
+ return enriched;
1266
+ },
1267
+ listLabels: (companyId) => db.select().from(labels).where(eq(labels.companyId, companyId)).orderBy(asc(labels.name), asc(labels.id)),
1268
+ getLabelById: (id) => db
1269
+ .select()
1270
+ .from(labels)
1271
+ .where(eq(labels.id, id))
1272
+ .then((rows) => rows[0] ?? null),
1273
+ createLabel: async (companyId, data) => {
1274
+ const [created] = await db
1275
+ .insert(labels)
1276
+ .values({
1277
+ companyId,
1278
+ name: data.name.trim(),
1279
+ color: data.color,
1280
+ })
1281
+ .returning();
1282
+ return created;
1283
+ },
1284
+ deleteLabel: async (id) => db
1285
+ .delete(labels)
1286
+ .where(eq(labels.id, id))
1287
+ .returning()
1288
+ .then((rows) => rows[0] ?? null),
1289
+ listComments: async (issueId, opts) => {
1290
+ const order = opts?.order === "asc" ? "asc" : "desc";
1291
+ const afterCommentId = opts?.afterCommentId?.trim() || null;
1292
+ const limit = opts?.limit && opts.limit > 0
1293
+ ? Math.min(Math.floor(opts.limit), MAX_ISSUE_COMMENT_PAGE_LIMIT)
1294
+ : null;
1295
+ const conditions = [eq(issueComments.issueId, issueId)];
1296
+ if (afterCommentId) {
1297
+ const anchor = await db
1298
+ .select({
1299
+ id: issueComments.id,
1300
+ createdAt: issueComments.createdAt,
1301
+ })
1302
+ .from(issueComments)
1303
+ .where(and(eq(issueComments.issueId, issueId), eq(issueComments.id, afterCommentId)))
1304
+ .then((rows) => rows[0] ?? null);
1305
+ if (!anchor)
1306
+ return [];
1307
+ conditions.push(order === "asc"
1308
+ ? sql `(
1309
+ ${issueComments.createdAt} > ${anchor.createdAt}
1310
+ OR (${issueComments.createdAt} = ${anchor.createdAt} AND ${issueComments.id} > ${anchor.id})
1311
+ )`
1312
+ : sql `(
1313
+ ${issueComments.createdAt} < ${anchor.createdAt}
1314
+ OR (${issueComments.createdAt} = ${anchor.createdAt} AND ${issueComments.id} < ${anchor.id})
1315
+ )`);
1316
+ }
1317
+ const query = db
1318
+ .select()
1319
+ .from(issueComments)
1320
+ .where(and(...conditions))
1321
+ .orderBy(order === "asc" ? asc(issueComments.createdAt) : desc(issueComments.createdAt), order === "asc" ? asc(issueComments.id) : desc(issueComments.id));
1322
+ const comments = limit ? await query.limit(limit) : await query;
1323
+ const { censorUsernameInLogs } = await instanceSettings.getGeneral();
1324
+ return comments.map((comment) => redactIssueComment(comment, censorUsernameInLogs));
1325
+ },
1326
+ getCommentCursor: async (issueId) => {
1327
+ const [latest, countRow] = await Promise.all([
1328
+ db
1329
+ .select({
1330
+ latestCommentId: issueComments.id,
1331
+ latestCommentAt: issueComments.createdAt,
1332
+ })
1333
+ .from(issueComments)
1334
+ .where(eq(issueComments.issueId, issueId))
1335
+ .orderBy(desc(issueComments.createdAt), desc(issueComments.id))
1336
+ .limit(1)
1337
+ .then((rows) => rows[0] ?? null),
1338
+ db
1339
+ .select({
1340
+ totalComments: sql `count(*)::int`,
1341
+ })
1342
+ .from(issueComments)
1343
+ .where(eq(issueComments.issueId, issueId))
1344
+ .then((rows) => rows[0] ?? null),
1345
+ ]);
1346
+ return {
1347
+ totalComments: Number(countRow?.totalComments ?? 0),
1348
+ latestCommentId: latest?.latestCommentId ?? null,
1349
+ latestCommentAt: latest?.latestCommentAt ?? null,
1350
+ };
1351
+ },
1352
+ getComment: (commentId) => instanceSettings.getGeneral().then(({ censorUsernameInLogs }) => db
1353
+ .select()
1354
+ .from(issueComments)
1355
+ .where(eq(issueComments.id, commentId))
1356
+ .then((rows) => {
1357
+ const comment = rows[0] ?? null;
1358
+ return comment ? redactIssueComment(comment, censorUsernameInLogs) : null;
1359
+ })),
1360
+ addComment: async (issueId, body, actor) => {
1361
+ const issue = await db
1362
+ .select({ companyId: issues.companyId })
1363
+ .from(issues)
1364
+ .where(eq(issues.id, issueId))
1365
+ .then((rows) => rows[0] ?? null);
1366
+ if (!issue)
1367
+ throw notFound("Issue not found");
1368
+ const currentUserRedactionOptions = {
1369
+ enabled: (await instanceSettings.getGeneral()).censorUsernameInLogs,
1370
+ };
1371
+ const redactedBody = redactCurrentUserText(body, currentUserRedactionOptions);
1372
+ const [comment] = await db
1373
+ .insert(issueComments)
1374
+ .values({
1375
+ companyId: issue.companyId,
1376
+ issueId,
1377
+ authorAgentId: actor.agentId ?? null,
1378
+ authorUserId: actor.userId ?? null,
1379
+ createdByRunId: actor.runId ?? null,
1380
+ body: redactedBody,
1381
+ })
1382
+ .returning();
1383
+ // Update issue's updatedAt so comment activity is reflected in recency sorting
1384
+ await db
1385
+ .update(issues)
1386
+ .set({ updatedAt: new Date() })
1387
+ .where(eq(issues.id, issueId));
1388
+ return redactIssueComment(comment, currentUserRedactionOptions.enabled);
1389
+ },
1390
+ createAttachment: async (input) => {
1391
+ const issue = await db
1392
+ .select({ id: issues.id, companyId: issues.companyId })
1393
+ .from(issues)
1394
+ .where(eq(issues.id, input.issueId))
1395
+ .then((rows) => rows[0] ?? null);
1396
+ if (!issue)
1397
+ throw notFound("Issue not found");
1398
+ if (input.issueCommentId) {
1399
+ const comment = await db
1400
+ .select({ id: issueComments.id, companyId: issueComments.companyId, issueId: issueComments.issueId })
1401
+ .from(issueComments)
1402
+ .where(eq(issueComments.id, input.issueCommentId))
1403
+ .then((rows) => rows[0] ?? null);
1404
+ if (!comment)
1405
+ throw notFound("Issue comment not found");
1406
+ if (comment.companyId !== issue.companyId || comment.issueId !== issue.id) {
1407
+ throw unprocessable("Attachment comment must belong to same issue and company");
1408
+ }
1409
+ }
1410
+ return db.transaction(async (tx) => {
1411
+ const [asset] = await tx
1412
+ .insert(assets)
1413
+ .values({
1414
+ companyId: issue.companyId,
1415
+ provider: input.provider,
1416
+ objectKey: input.objectKey,
1417
+ contentType: input.contentType,
1418
+ byteSize: input.byteSize,
1419
+ sha256: input.sha256,
1420
+ originalFilename: input.originalFilename ?? null,
1421
+ createdByAgentId: input.createdByAgentId ?? null,
1422
+ createdByUserId: input.createdByUserId ?? null,
1423
+ })
1424
+ .returning();
1425
+ const [attachment] = await tx
1426
+ .insert(issueAttachments)
1427
+ .values({
1428
+ companyId: issue.companyId,
1429
+ issueId: issue.id,
1430
+ assetId: asset.id,
1431
+ issueCommentId: input.issueCommentId ?? null,
1432
+ })
1433
+ .returning();
1434
+ return {
1435
+ id: attachment.id,
1436
+ companyId: attachment.companyId,
1437
+ issueId: attachment.issueId,
1438
+ issueCommentId: attachment.issueCommentId,
1439
+ assetId: attachment.assetId,
1440
+ provider: asset.provider,
1441
+ objectKey: asset.objectKey,
1442
+ contentType: asset.contentType,
1443
+ byteSize: asset.byteSize,
1444
+ sha256: asset.sha256,
1445
+ originalFilename: asset.originalFilename,
1446
+ createdByAgentId: asset.createdByAgentId,
1447
+ createdByUserId: asset.createdByUserId,
1448
+ createdAt: attachment.createdAt,
1449
+ updatedAt: attachment.updatedAt,
1450
+ };
1451
+ });
1452
+ },
1453
+ listAttachments: async (issueId) => db
1454
+ .select({
1455
+ id: issueAttachments.id,
1456
+ companyId: issueAttachments.companyId,
1457
+ issueId: issueAttachments.issueId,
1458
+ issueCommentId: issueAttachments.issueCommentId,
1459
+ assetId: issueAttachments.assetId,
1460
+ provider: assets.provider,
1461
+ objectKey: assets.objectKey,
1462
+ contentType: assets.contentType,
1463
+ byteSize: assets.byteSize,
1464
+ sha256: assets.sha256,
1465
+ originalFilename: assets.originalFilename,
1466
+ createdByAgentId: assets.createdByAgentId,
1467
+ createdByUserId: assets.createdByUserId,
1468
+ createdAt: issueAttachments.createdAt,
1469
+ updatedAt: issueAttachments.updatedAt,
1470
+ })
1471
+ .from(issueAttachments)
1472
+ .innerJoin(assets, eq(issueAttachments.assetId, assets.id))
1473
+ .where(eq(issueAttachments.issueId, issueId))
1474
+ .orderBy(desc(issueAttachments.createdAt)),
1475
+ getAttachmentById: async (id) => db
1476
+ .select({
1477
+ id: issueAttachments.id,
1478
+ companyId: issueAttachments.companyId,
1479
+ issueId: issueAttachments.issueId,
1480
+ issueCommentId: issueAttachments.issueCommentId,
1481
+ assetId: issueAttachments.assetId,
1482
+ provider: assets.provider,
1483
+ objectKey: assets.objectKey,
1484
+ contentType: assets.contentType,
1485
+ byteSize: assets.byteSize,
1486
+ sha256: assets.sha256,
1487
+ originalFilename: assets.originalFilename,
1488
+ createdByAgentId: assets.createdByAgentId,
1489
+ createdByUserId: assets.createdByUserId,
1490
+ createdAt: issueAttachments.createdAt,
1491
+ updatedAt: issueAttachments.updatedAt,
1492
+ })
1493
+ .from(issueAttachments)
1494
+ .innerJoin(assets, eq(issueAttachments.assetId, assets.id))
1495
+ .where(eq(issueAttachments.id, id))
1496
+ .then((rows) => rows[0] ?? null),
1497
+ removeAttachment: async (id) => db.transaction(async (tx) => {
1498
+ const existing = await tx
1499
+ .select({
1500
+ id: issueAttachments.id,
1501
+ companyId: issueAttachments.companyId,
1502
+ issueId: issueAttachments.issueId,
1503
+ issueCommentId: issueAttachments.issueCommentId,
1504
+ assetId: issueAttachments.assetId,
1505
+ provider: assets.provider,
1506
+ objectKey: assets.objectKey,
1507
+ contentType: assets.contentType,
1508
+ byteSize: assets.byteSize,
1509
+ sha256: assets.sha256,
1510
+ originalFilename: assets.originalFilename,
1511
+ createdByAgentId: assets.createdByAgentId,
1512
+ createdByUserId: assets.createdByUserId,
1513
+ createdAt: issueAttachments.createdAt,
1514
+ updatedAt: issueAttachments.updatedAt,
1515
+ })
1516
+ .from(issueAttachments)
1517
+ .innerJoin(assets, eq(issueAttachments.assetId, assets.id))
1518
+ .where(eq(issueAttachments.id, id))
1519
+ .then((rows) => rows[0] ?? null);
1520
+ if (!existing)
1521
+ return null;
1522
+ await tx.delete(issueAttachments).where(eq(issueAttachments.id, id));
1523
+ await tx.delete(assets).where(eq(assets.id, existing.assetId));
1524
+ return existing;
1525
+ }),
1526
+ findMentionedAgents: async (companyId, body) => {
1527
+ const re = /\B@([^\s@,!?.]+)/g;
1528
+ const tokens = new Set();
1529
+ let m;
1530
+ while ((m = re.exec(body)) !== null) {
1531
+ const normalized = normalizeAgentMentionToken(m[1]);
1532
+ if (normalized)
1533
+ tokens.add(normalized.toLowerCase());
1534
+ }
1535
+ const explicitAgentMentionIds = extractAgentMentionIds(body);
1536
+ if (tokens.size === 0 && explicitAgentMentionIds.length === 0)
1537
+ return [];
1538
+ const rows = await db.select({ id: agents.id, name: agents.name })
1539
+ .from(agents).where(eq(agents.companyId, companyId));
1540
+ const resolved = new Set(explicitAgentMentionIds);
1541
+ for (const agent of rows) {
1542
+ if (tokens.has(agent.name.toLowerCase())) {
1543
+ resolved.add(agent.id);
1544
+ }
1545
+ }
1546
+ return [...resolved];
1547
+ },
1548
+ findMentionedProjectIds: async (issueId) => {
1549
+ const issue = await db
1550
+ .select({
1551
+ companyId: issues.companyId,
1552
+ title: issues.title,
1553
+ description: issues.description,
1554
+ })
1555
+ .from(issues)
1556
+ .where(eq(issues.id, issueId))
1557
+ .then((rows) => rows[0] ?? null);
1558
+ if (!issue)
1559
+ return [];
1560
+ const comments = await db
1561
+ .select({ body: issueComments.body })
1562
+ .from(issueComments)
1563
+ .where(eq(issueComments.issueId, issueId));
1564
+ const mentionedIds = new Set();
1565
+ for (const source of [
1566
+ issue.title,
1567
+ issue.description ?? "",
1568
+ ...comments.map((comment) => comment.body),
1569
+ ]) {
1570
+ for (const projectId of extractProjectMentionIds(source)) {
1571
+ mentionedIds.add(projectId);
1572
+ }
1573
+ }
1574
+ if (mentionedIds.size === 0)
1575
+ return [];
1576
+ const rows = await db
1577
+ .select({ id: projects.id })
1578
+ .from(projects)
1579
+ .where(and(eq(projects.companyId, issue.companyId), inArray(projects.id, [...mentionedIds])));
1580
+ const valid = new Set(rows.map((row) => row.id));
1581
+ return [...mentionedIds].filter((projectId) => valid.has(projectId));
1582
+ },
1583
+ getAncestors: async (issueId) => {
1584
+ const raw = [];
1585
+ const visited = new Set([issueId]);
1586
+ const start = await db.select().from(issues).where(eq(issues.id, issueId)).then(r => r[0] ?? null);
1587
+ let currentId = start?.parentId ?? null;
1588
+ while (currentId && !visited.has(currentId) && raw.length < 50) {
1589
+ visited.add(currentId);
1590
+ const parent = await db.select({
1591
+ id: issues.id, identifier: issues.identifier, title: issues.title, description: issues.description,
1592
+ status: issues.status, priority: issues.priority,
1593
+ assigneeAgentId: issues.assigneeAgentId, projectId: issues.projectId,
1594
+ goalId: issues.goalId, parentId: issues.parentId,
1595
+ }).from(issues).where(eq(issues.id, currentId)).then(r => r[0] ?? null);
1596
+ if (!parent)
1597
+ break;
1598
+ raw.push({
1599
+ id: parent.id, identifier: parent.identifier ?? null, title: parent.title, description: parent.description ?? null,
1600
+ status: parent.status, priority: parent.priority,
1601
+ assigneeAgentId: parent.assigneeAgentId ?? null,
1602
+ projectId: parent.projectId ?? null, goalId: parent.goalId ?? null,
1603
+ });
1604
+ currentId = parent.parentId ?? null;
1605
+ }
1606
+ // Batch-fetch referenced projects and goals
1607
+ const projectIds = [...new Set(raw.map(a => a.projectId).filter((id) => id != null))];
1608
+ const goalIds = [...new Set(raw.map(a => a.goalId).filter((id) => id != null))];
1609
+ const projectMap = new Map();
1610
+ const goalMap = new Map();
1611
+ if (projectIds.length > 0) {
1612
+ const workspaceRows = await db
1613
+ .select()
1614
+ .from(projectWorkspaces)
1615
+ .where(inArray(projectWorkspaces.projectId, projectIds))
1616
+ .orderBy(desc(projectWorkspaces.isPrimary), asc(projectWorkspaces.createdAt), asc(projectWorkspaces.id));
1617
+ const workspaceMap = new Map();
1618
+ for (const workspace of workspaceRows) {
1619
+ const existing = workspaceMap.get(workspace.projectId);
1620
+ if (existing)
1621
+ existing.push(workspace);
1622
+ else
1623
+ workspaceMap.set(workspace.projectId, [workspace]);
1624
+ }
1625
+ const rows = await db.select({
1626
+ id: projects.id, name: projects.name, description: projects.description,
1627
+ status: projects.status, goalId: projects.goalId,
1628
+ }).from(projects).where(inArray(projects.id, projectIds));
1629
+ for (const r of rows) {
1630
+ const projectWorkspaceRows = workspaceMap.get(r.id) ?? [];
1631
+ const workspaces = projectWorkspaceRows.map((workspace) => ({
1632
+ id: workspace.id,
1633
+ companyId: workspace.companyId,
1634
+ projectId: workspace.projectId,
1635
+ name: workspace.name,
1636
+ cwd: workspace.cwd,
1637
+ repoUrl: workspace.repoUrl ?? null,
1638
+ repoRef: workspace.repoRef ?? null,
1639
+ metadata: workspace.metadata ?? null,
1640
+ isPrimary: workspace.isPrimary,
1641
+ createdAt: workspace.createdAt,
1642
+ updatedAt: workspace.updatedAt,
1643
+ }));
1644
+ const primaryWorkspace = workspaces.find((workspace) => workspace.isPrimary) ?? workspaces[0] ?? null;
1645
+ projectMap.set(r.id, {
1646
+ ...r,
1647
+ workspaces,
1648
+ primaryWorkspace,
1649
+ });
1650
+ // Also collect goalIds from projects
1651
+ if (r.goalId && !goalIds.includes(r.goalId))
1652
+ goalIds.push(r.goalId);
1653
+ }
1654
+ }
1655
+ if (goalIds.length > 0) {
1656
+ const rows = await db.select({
1657
+ id: goals.id, title: goals.title, description: goals.description,
1658
+ level: goals.level, status: goals.status,
1659
+ }).from(goals).where(inArray(goals.id, goalIds));
1660
+ for (const r of rows)
1661
+ goalMap.set(r.id, r);
1662
+ }
1663
+ return raw.map(a => ({
1664
+ ...a,
1665
+ project: a.projectId ? projectMap.get(a.projectId) ?? null : null,
1666
+ goal: a.goalId ? goalMap.get(a.goalId) ?? null : null,
1667
+ }));
1668
+ },
1669
+ };
1670
+ }
1671
+ //# sourceMappingURL=issues.js.map