@crewspaceai/server 2026.412.0-canary.0

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