@mastra/factory 0.15.1-alpha.0 → 0.16.0-alpha.11

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 (372) hide show
  1. package/README.md +41 -3
  2. package/dist/auth.js +1 -1
  3. package/dist/auth.js.map +1 -1
  4. package/dist/boards/index.d.ts +1 -1
  5. package/dist/boards/index.d.ts.map +1 -1
  6. package/dist/boards/index.js +2 -2
  7. package/dist/boards/index.js.map +1 -1
  8. package/dist/boards/review.d.ts.map +1 -1
  9. package/dist/boards/review.js +23 -9
  10. package/dist/boards/review.js.map +1 -1
  11. package/dist/boards/semantics.d.ts +7 -0
  12. package/dist/boards/semantics.d.ts.map +1 -1
  13. package/dist/boards/semantics.js +15 -1
  14. package/dist/boards/semantics.js.map +1 -1
  15. package/dist/boards/work.d.ts.map +1 -1
  16. package/dist/boards/work.js +68 -6
  17. package/dist/boards/work.js.map +1 -1
  18. package/dist/capabilities/intake.d.ts +8 -0
  19. package/dist/capabilities/intake.d.ts.map +1 -1
  20. package/dist/capabilities/version-control.d.ts +15 -0
  21. package/dist/capabilities/version-control.d.ts.map +1 -1
  22. package/dist/factory.d.ts +8 -5
  23. package/dist/factory.d.ts.map +1 -1
  24. package/dist/factory.js +136 -53
  25. package/dist/factory.js.map +1 -1
  26. package/dist/integrations/base.d.ts +5 -0
  27. package/dist/integrations/base.d.ts.map +1 -1
  28. package/dist/integrations/github/integration.d.ts.map +1 -1
  29. package/dist/integrations/github/integration.js +21 -0
  30. package/dist/integrations/github/integration.js.map +1 -1
  31. package/dist/integrations/github/routes.js +2 -1
  32. package/dist/integrations/github/routes.js.map +1 -1
  33. package/dist/integrations/github/sandbox.d.ts +41 -42
  34. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  35. package/dist/integrations/github/sandbox.js +416 -227
  36. package/dist/integrations/github/sandbox.js.map +1 -1
  37. package/dist/integrations/github/webhook.d.ts +2 -5
  38. package/dist/integrations/github/webhook.d.ts.map +1 -1
  39. package/dist/integrations/github/webhook.js +8 -48
  40. package/dist/integrations/github/webhook.js.map +1 -1
  41. package/dist/integrations/gitlab/agent-tools.d.ts +14 -0
  42. package/dist/integrations/gitlab/agent-tools.d.ts.map +1 -0
  43. package/dist/integrations/gitlab/agent-tools.js +42 -0
  44. package/dist/integrations/gitlab/agent-tools.js.map +1 -0
  45. package/dist/integrations/gitlab/api.d.ts +222 -0
  46. package/dist/integrations/gitlab/api.d.ts.map +1 -0
  47. package/dist/integrations/gitlab/api.js +274 -0
  48. package/dist/integrations/gitlab/api.js.map +1 -0
  49. package/dist/integrations/gitlab/default-rules.d.ts +125 -0
  50. package/dist/integrations/gitlab/default-rules.d.ts.map +1 -0
  51. package/dist/integrations/gitlab/default-rules.js +172 -0
  52. package/dist/integrations/gitlab/default-rules.js.map +1 -0
  53. package/dist/integrations/gitlab/integration.d.ts +138 -0
  54. package/dist/integrations/gitlab/integration.d.ts.map +1 -0
  55. package/dist/integrations/gitlab/integration.js +705 -0
  56. package/dist/integrations/gitlab/integration.js.map +1 -0
  57. package/dist/integrations/gitlab/issue-reconciler.d.ts +6 -0
  58. package/dist/integrations/gitlab/issue-reconciler.d.ts.map +1 -0
  59. package/dist/integrations/gitlab/issue-reconciler.js +123 -0
  60. package/dist/integrations/gitlab/issue-reconciler.js.map +1 -0
  61. package/dist/integrations/gitlab/merge-request-reconciler.d.ts +6 -0
  62. package/dist/integrations/gitlab/merge-request-reconciler.d.ts.map +1 -0
  63. package/dist/integrations/gitlab/merge-request-reconciler.js +267 -0
  64. package/dist/integrations/gitlab/merge-request-reconciler.js.map +1 -0
  65. package/dist/integrations/gitlab/reconciler.d.ts +5 -0
  66. package/dist/integrations/gitlab/reconciler.d.ts.map +1 -0
  67. package/dist/integrations/gitlab/reconciler.js +31 -0
  68. package/dist/integrations/gitlab/reconciler.js.map +1 -0
  69. package/dist/integrations/gitlab/reconciliation-config.d.ts +3 -0
  70. package/dist/integrations/gitlab/reconciliation-config.d.ts.map +1 -0
  71. package/dist/integrations/gitlab/reconciliation-config.js +17 -0
  72. package/dist/integrations/gitlab/reconciliation-config.js.map +1 -0
  73. package/dist/integrations/gitlab/routes.d.ts +20 -0
  74. package/dist/integrations/gitlab/routes.d.ts.map +1 -0
  75. package/dist/integrations/gitlab/routes.js +473 -0
  76. package/dist/integrations/gitlab/routes.js.map +1 -0
  77. package/dist/integrations/gitlab/rules.d.ts +35 -0
  78. package/dist/integrations/gitlab/rules.d.ts.map +1 -0
  79. package/dist/integrations/gitlab/rules.js +391 -0
  80. package/dist/integrations/gitlab/rules.js.map +1 -0
  81. package/dist/integrations/gitlab/session-subscriptions.d.ts +32 -0
  82. package/dist/integrations/gitlab/session-subscriptions.d.ts.map +1 -0
  83. package/dist/integrations/gitlab/session-subscriptions.js +192 -0
  84. package/dist/integrations/gitlab/session-subscriptions.js.map +1 -0
  85. package/dist/integrations/gitlab/subscriptions.d.ts +70 -0
  86. package/dist/integrations/gitlab/subscriptions.d.ts.map +1 -0
  87. package/dist/integrations/gitlab/subscriptions.js +76 -0
  88. package/dist/integrations/gitlab/subscriptions.js.map +1 -0
  89. package/dist/integrations/gitlab/version-control.d.ts +16 -0
  90. package/dist/integrations/gitlab/version-control.d.ts.map +1 -0
  91. package/dist/integrations/gitlab/version-control.js +622 -0
  92. package/dist/integrations/gitlab/version-control.js.map +1 -0
  93. package/dist/integrations/gitlab/webhook-dispatch.d.ts +75 -0
  94. package/dist/integrations/gitlab/webhook-dispatch.d.ts.map +1 -0
  95. package/dist/integrations/gitlab/webhook-dispatch.js +235 -0
  96. package/dist/integrations/gitlab/webhook-dispatch.js.map +1 -0
  97. package/dist/integrations/gitlab/webhook.d.ts +72 -0
  98. package/dist/integrations/gitlab/webhook.d.ts.map +1 -0
  99. package/dist/integrations/gitlab/webhook.js +201 -0
  100. package/dist/integrations/gitlab/webhook.js.map +1 -0
  101. package/dist/integrations/incidentio/agent-tools.d.ts +49 -0
  102. package/dist/integrations/incidentio/agent-tools.d.ts.map +1 -0
  103. package/dist/integrations/incidentio/agent-tools.js +90 -0
  104. package/dist/integrations/incidentio/agent-tools.js.map +1 -0
  105. package/dist/integrations/incidentio/claim.d.ts +8 -0
  106. package/dist/integrations/incidentio/claim.d.ts.map +1 -0
  107. package/dist/integrations/incidentio/claim.js +14 -0
  108. package/dist/integrations/incidentio/claim.js.map +1 -0
  109. package/dist/integrations/incidentio/default-rules.d.ts +46 -0
  110. package/dist/integrations/incidentio/default-rules.d.ts.map +1 -0
  111. package/dist/integrations/incidentio/default-rules.js +66 -0
  112. package/dist/integrations/incidentio/default-rules.js.map +1 -0
  113. package/dist/integrations/incidentio/integration.d.ts +48 -2
  114. package/dist/integrations/incidentio/integration.d.ts.map +1 -1
  115. package/dist/integrations/incidentio/integration.js +89 -3
  116. package/dist/integrations/incidentio/integration.js.map +1 -1
  117. package/dist/integrations/incidentio/issue-reconciler.d.ts +2 -0
  118. package/dist/integrations/incidentio/issue-reconciler.d.ts.map +1 -1
  119. package/dist/integrations/incidentio/issue-reconciler.js +38 -2
  120. package/dist/integrations/incidentio/issue-reconciler.js.map +1 -1
  121. package/dist/integrations/incidentio/routes.d.ts +71 -0
  122. package/dist/integrations/incidentio/routes.d.ts.map +1 -0
  123. package/dist/integrations/incidentio/routes.js +245 -0
  124. package/dist/integrations/incidentio/routes.js.map +1 -0
  125. package/dist/integrations/incidentio/rules.d.ts +55 -0
  126. package/dist/integrations/incidentio/rules.d.ts.map +1 -0
  127. package/dist/integrations/incidentio/rules.js +175 -0
  128. package/dist/integrations/incidentio/rules.js.map +1 -0
  129. package/dist/integrations/issue-reconciler.d.ts +3 -3
  130. package/dist/integrations/issue-reconciler.d.ts.map +1 -1
  131. package/dist/integrations/issue-reconciler.js +22 -2
  132. package/dist/integrations/issue-reconciler.js.map +1 -1
  133. package/dist/integrations/jira/adf.d.ts +26 -0
  134. package/dist/integrations/jira/adf.d.ts.map +1 -0
  135. package/dist/integrations/jira/adf.js +73 -0
  136. package/dist/integrations/jira/adf.js.map +1 -0
  137. package/dist/integrations/jira/agent-tools.d.ts +45 -0
  138. package/dist/integrations/jira/agent-tools.d.ts.map +1 -0
  139. package/dist/integrations/jira/agent-tools.js +87 -0
  140. package/dist/integrations/jira/agent-tools.js.map +1 -0
  141. package/dist/integrations/jira/api.d.ts +157 -0
  142. package/dist/integrations/jira/api.d.ts.map +1 -0
  143. package/dist/integrations/jira/api.js +141 -0
  144. package/dist/integrations/jira/api.js.map +1 -0
  145. package/dist/integrations/jira/claim.d.ts +9 -0
  146. package/dist/integrations/jira/claim.d.ts.map +1 -0
  147. package/dist/integrations/jira/claim.js +15 -0
  148. package/dist/integrations/jira/claim.js.map +1 -0
  149. package/dist/integrations/jira/default-rules.d.ts +47 -0
  150. package/dist/integrations/jira/default-rules.d.ts.map +1 -0
  151. package/dist/integrations/jira/default-rules.js +67 -0
  152. package/dist/integrations/jira/default-rules.js.map +1 -0
  153. package/dist/integrations/jira/integration.d.ts +114 -0
  154. package/dist/integrations/jira/integration.d.ts.map +1 -0
  155. package/dist/integrations/jira/integration.js +401 -0
  156. package/dist/integrations/jira/integration.js.map +1 -0
  157. package/dist/integrations/jira/issue-reconciler.d.ts +10 -0
  158. package/dist/integrations/jira/issue-reconciler.d.ts.map +1 -0
  159. package/dist/integrations/jira/issue-reconciler.js +70 -0
  160. package/dist/integrations/jira/issue-reconciler.js.map +1 -0
  161. package/dist/integrations/jira/reconciliation-config.d.ts +3 -0
  162. package/dist/integrations/jira/reconciliation-config.d.ts.map +1 -0
  163. package/dist/integrations/jira/reconciliation-config.js +17 -0
  164. package/dist/integrations/jira/reconciliation-config.js.map +1 -0
  165. package/dist/integrations/jira/routes.d.ts +54 -0
  166. package/dist/integrations/jira/routes.d.ts.map +1 -0
  167. package/dist/integrations/jira/routes.js +260 -0
  168. package/dist/integrations/jira/routes.js.map +1 -0
  169. package/dist/integrations/jira/rules.d.ts +57 -0
  170. package/dist/integrations/jira/rules.d.ts.map +1 -0
  171. package/dist/integrations/jira/rules.js +175 -0
  172. package/dist/integrations/jira/rules.js.map +1 -0
  173. package/dist/integrations/linear/claim.d.ts +8 -0
  174. package/dist/integrations/linear/claim.d.ts.map +1 -0
  175. package/dist/integrations/linear/claim.js +14 -0
  176. package/dist/integrations/linear/claim.js.map +1 -0
  177. package/dist/integrations/linear/default-rules.d.ts +1 -0
  178. package/dist/integrations/linear/default-rules.d.ts.map +1 -1
  179. package/dist/integrations/linear/default-rules.js +2 -0
  180. package/dist/integrations/linear/default-rules.js.map +1 -1
  181. package/dist/integrations/linear/integration.d.ts +24 -6
  182. package/dist/integrations/linear/integration.d.ts.map +1 -1
  183. package/dist/integrations/linear/integration.js +257 -37
  184. package/dist/integrations/linear/integration.js.map +1 -1
  185. package/dist/integrations/linear/routes.d.ts +10 -0
  186. package/dist/integrations/linear/routes.d.ts.map +1 -1
  187. package/dist/integrations/linear/routes.js +74 -10
  188. package/dist/integrations/linear/routes.js.map +1 -1
  189. package/dist/integrations/linear/rules.d.ts +1 -1
  190. package/dist/integrations/linear/rules.d.ts.map +1 -1
  191. package/dist/integrations/linear/rules.js +27 -2
  192. package/dist/integrations/linear/rules.js.map +1 -1
  193. package/dist/integrations/platform/connect/routes.d.ts +39 -0
  194. package/dist/integrations/platform/connect/routes.d.ts.map +1 -0
  195. package/dist/integrations/platform/connect/routes.js +129 -0
  196. package/dist/integrations/platform/connect/routes.js.map +1 -0
  197. package/dist/integrations/platform/github/event-worker.js +1 -1
  198. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  199. package/dist/integrations/platform/github/integration.js +22 -1
  200. package/dist/integrations/platform/github/integration.js.map +1 -1
  201. package/dist/integrations/platform/gitlab/event-worker.d.ts +64 -0
  202. package/dist/integrations/platform/gitlab/event-worker.d.ts.map +1 -0
  203. package/dist/integrations/platform/gitlab/event-worker.js +306 -0
  204. package/dist/integrations/platform/gitlab/event-worker.js.map +1 -0
  205. package/dist/integrations/platform/gitlab/integration.d.ts +57 -0
  206. package/dist/integrations/platform/gitlab/integration.d.ts.map +1 -0
  207. package/dist/integrations/platform/gitlab/integration.js +125 -0
  208. package/dist/integrations/platform/gitlab/integration.js.map +1 -0
  209. package/dist/integrations/platform/incidentio/integration.d.ts +61 -4
  210. package/dist/integrations/platform/incidentio/integration.d.ts.map +1 -1
  211. package/dist/integrations/platform/incidentio/integration.js +372 -23
  212. package/dist/integrations/platform/incidentio/integration.js.map +1 -1
  213. package/dist/integrations/platform/jira/agent-tools.d.ts +36 -0
  214. package/dist/integrations/platform/jira/agent-tools.d.ts.map +1 -0
  215. package/dist/integrations/platform/jira/agent-tools.js +85 -0
  216. package/dist/integrations/platform/jira/agent-tools.js.map +1 -0
  217. package/dist/integrations/platform/jira/integration.d.ts +65 -0
  218. package/dist/integrations/platform/jira/integration.d.ts.map +1 -0
  219. package/dist/integrations/platform/jira/integration.js +540 -0
  220. package/dist/integrations/platform/jira/integration.js.map +1 -0
  221. package/dist/integrations/platform/jira/routes.d.ts +55 -0
  222. package/dist/integrations/platform/jira/routes.d.ts.map +1 -0
  223. package/dist/integrations/platform/jira/routes.js +274 -0
  224. package/dist/integrations/platform/jira/routes.js.map +1 -0
  225. package/dist/integrations/platform/linear/integration.d.ts +34 -1
  226. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  227. package/dist/integrations/platform/linear/integration.js +271 -48
  228. package/dist/integrations/platform/linear/integration.js.map +1 -1
  229. package/dist/integrations/slack/integration.d.ts.map +1 -1
  230. package/dist/integrations/slack/integration.js +3 -3
  231. package/dist/integrations/slack/integration.js.map +1 -1
  232. package/dist/integrations/slack/slack.d.ts +2 -0
  233. package/dist/integrations/slack/slack.d.ts.map +1 -1
  234. package/dist/integrations/slack/slack.js +21 -7
  235. package/dist/integrations/slack/slack.js.map +1 -1
  236. package/dist/integrations/subscription-session.d.ts +37 -0
  237. package/dist/integrations/subscription-session.d.ts.map +1 -0
  238. package/dist/integrations/subscription-session.js +83 -0
  239. package/dist/integrations/subscription-session.js.map +1 -0
  240. package/dist/packages/_internals/workspace/dist/index.js +1 -11
  241. package/dist/packages/_internals/workspace/dist/index.js.map +1 -1
  242. package/dist/routes/intake.d.ts.map +1 -1
  243. package/dist/routes/intake.js +16 -4
  244. package/dist/routes/intake.js.map +1 -1
  245. package/dist/routes/oauth.js +3 -6
  246. package/dist/routes/oauth.js.map +1 -1
  247. package/dist/routes/projects.d.ts +1 -0
  248. package/dist/routes/projects.d.ts.map +1 -1
  249. package/dist/routes/projects.js +1 -0
  250. package/dist/routes/projects.js.map +1 -1
  251. package/dist/routes/source-control-sessions.d.ts +20 -0
  252. package/dist/routes/source-control-sessions.d.ts.map +1 -0
  253. package/dist/routes/source-control-sessions.js +319 -0
  254. package/dist/routes/source-control-sessions.js.map +1 -0
  255. package/dist/routes/source-control-settings.d.ts +10 -0
  256. package/dist/routes/source-control-settings.d.ts.map +1 -0
  257. package/dist/routes/source-control-settings.js +87 -0
  258. package/dist/routes/source-control-settings.js.map +1 -0
  259. package/dist/routes/surface.d.ts +3 -3
  260. package/dist/routes/surface.d.ts.map +1 -1
  261. package/dist/routes/surface.js +79 -17
  262. package/dist/routes/surface.js.map +1 -1
  263. package/dist/routes/tenant-credentials.d.ts +8 -0
  264. package/dist/routes/tenant-credentials.d.ts.map +1 -1
  265. package/dist/routes/tenant-credentials.js +20 -3
  266. package/dist/routes/tenant-credentials.js.map +1 -1
  267. package/dist/routes/work-items.d.ts.map +1 -1
  268. package/dist/routes/work-items.js +1 -1
  269. package/dist/routes/work-items.js.map +1 -1
  270. package/dist/rules/dispatch-errors.d.ts.map +1 -1
  271. package/dist/rules/dispatch-errors.js +8 -0
  272. package/dist/rules/dispatch-errors.js.map +1 -1
  273. package/dist/rules/dispatcher.d.ts +1 -0
  274. package/dist/rules/dispatcher.d.ts.map +1 -1
  275. package/dist/rules/dispatcher.js +186 -106
  276. package/dist/rules/dispatcher.js.map +1 -1
  277. package/dist/rules/index.d.ts +2 -2
  278. package/dist/rules/index.d.ts.map +1 -1
  279. package/dist/rules/index.js +2 -2
  280. package/dist/rules/start-coordinator.d.ts +1 -1
  281. package/dist/rules/start-coordinator.d.ts.map +1 -1
  282. package/dist/rules/start-coordinator.js +7 -3
  283. package/dist/rules/start-coordinator.js.map +1 -1
  284. package/dist/rules/terminal-cleanup.d.ts +14 -1
  285. package/dist/rules/terminal-cleanup.d.ts.map +1 -1
  286. package/dist/rules/terminal-cleanup.js +20 -0
  287. package/dist/rules/terminal-cleanup.js.map +1 -1
  288. package/dist/rules/tools.d.ts +2 -0
  289. package/dist/rules/tools.d.ts.map +1 -1
  290. package/dist/rules/tools.js +30 -2
  291. package/dist/rules/tools.js.map +1 -1
  292. package/dist/rules/transition-service.d.ts +3 -0
  293. package/dist/rules/transition-service.d.ts.map +1 -1
  294. package/dist/rules/transition-service.js +10 -5
  295. package/dist/rules/transition-service.js.map +1 -1
  296. package/dist/rules/types.d.ts +136 -3
  297. package/dist/rules/types.d.ts.map +1 -1
  298. package/dist/rules/types.js +31 -2
  299. package/dist/rules/types.js.map +1 -1
  300. package/dist/rules/validation.d.ts.map +1 -1
  301. package/dist/rules/validation.js +15 -2
  302. package/dist/rules/validation.js.map +1 -1
  303. package/dist/sandbox/git-ref.d.ts +7 -0
  304. package/dist/sandbox/git-ref.d.ts.map +1 -0
  305. package/dist/sandbox/git-ref.js +15 -0
  306. package/dist/sandbox/git-ref.js.map +1 -0
  307. package/dist/sandbox/session-retirement.js +1 -1
  308. package/dist/sandbox/workdir.d.ts.map +1 -1
  309. package/dist/sandbox/workdir.js +6 -6
  310. package/dist/sandbox/workdir.js.map +1 -1
  311. package/dist/session/factory-session.d.ts +31 -1
  312. package/dist/session/factory-session.d.ts.map +1 -1
  313. package/dist/session/factory-session.js +60 -1
  314. package/dist/session/factory-session.js.map +1 -1
  315. package/dist/session/run-audit.d.ts +9 -0
  316. package/dist/session/run-audit.d.ts.map +1 -1
  317. package/dist/session/run-audit.js +37 -6
  318. package/dist/session/run-audit.js.map +1 -1
  319. package/dist/session/source-control-tools.d.ts +16 -0
  320. package/dist/session/source-control-tools.d.ts.map +1 -0
  321. package/dist/session/source-control-tools.js +464 -0
  322. package/dist/session/source-control-tools.js.map +1 -0
  323. package/dist/skills/service.d.ts +12 -0
  324. package/dist/skills/service.d.ts.map +1 -1
  325. package/dist/skills/service.js +27 -1
  326. package/dist/skills/service.js.map +1 -1
  327. package/dist/storage/domains/intake/base.d.ts +18 -0
  328. package/dist/storage/domains/intake/base.d.ts.map +1 -1
  329. package/dist/storage/domains/intake/base.js +77 -0
  330. package/dist/storage/domains/intake/base.js.map +1 -1
  331. package/dist/storage/domains/work-items/base.d.ts +41 -2
  332. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  333. package/dist/storage/domains/work-items/base.js +159 -12
  334. package/dist/storage/domains/work-items/base.js.map +1 -1
  335. package/dist/supervisor/session-messaging.d.ts +23 -0
  336. package/dist/supervisor/session-messaging.d.ts.map +1 -0
  337. package/dist/supervisor/session-messaging.js +15 -0
  338. package/dist/supervisor/session-messaging.js.map +1 -0
  339. package/dist/supervisor/write-tools.d.ts +2 -1
  340. package/dist/supervisor/write-tools.d.ts.map +1 -1
  341. package/dist/supervisor/write-tools.js +11 -7
  342. package/dist/supervisor/write-tools.js.map +1 -1
  343. package/dist/work-item-branch.d.ts +3 -1
  344. package/dist/work-item-branch.d.ts.map +1 -1
  345. package/dist/work-item-branch.js +26 -6
  346. package/dist/work-item-branch.js.map +1 -1
  347. package/dist/workspace.d.ts +15 -1
  348. package/dist/workspace.d.ts.map +1 -1
  349. package/dist/workspace.js +57 -23
  350. package/dist/workspace.js.map +1 -1
  351. package/factory-skills/factory-gitlab-rereview/SKILL.md +19 -0
  352. package/factory-skills/factory-gitlab-review/SKILL.md +30 -0
  353. package/factory-skills/factory-rereview/SKILL.md +13 -6
  354. package/factory-skills/factory-review/SKILL.md +13 -6
  355. package/factory-skills/factory-review/references/archaeology.md +225 -0
  356. package/factory-skills/factory-review/references/categories/README.md +34 -0
  357. package/factory-skills/factory-review/references/categories/behavior-change.md +36 -0
  358. package/factory-skills/factory-review/references/categories/bug-fix.md +37 -0
  359. package/factory-skills/factory-review/references/categories/docs.md +32 -0
  360. package/factory-skills/factory-review/references/categories/experimental-flagged.md +34 -0
  361. package/factory-skills/factory-review/references/categories/infra-tooling.md +37 -0
  362. package/factory-skills/factory-review/references/categories/internal-capability.md +35 -0
  363. package/factory-skills/factory-review/references/categories/large-cross-cutting.md +35 -0
  364. package/factory-skills/factory-review/references/categories/mechanical.md +36 -0
  365. package/factory-skills/factory-review/references/categories/performance.md +33 -0
  366. package/factory-skills/factory-review/references/categories/public-api.md +38 -0
  367. package/factory-skills/factory-review/references/categories/refactor.md +35 -0
  368. package/factory-skills/factory-review/references/categories/revert.md +31 -0
  369. package/factory-skills/factory-review/references/categories/schema-storage.md +39 -0
  370. package/factory-skills/factory-review/references/categories/security.md +35 -0
  371. package/factory-skills/factory-review/references/categories/tests-only.md +38 -0
  372. package/package.json +12 -12
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-credentials.js","names":["#orgId","#userId","#orgFirst","#credentials","#fetchedAt","#hydrating","#hydrate","#snapshot"],"sources":["../../src/routes/tenant-credentials.ts"],"sourcesContent":["/**\n * Per-tenant credential store for model resolution (deployed mode).\n *\n * The SDK's `resolveModel` asks the registered `CredentialStoreProvider` for a\n * store synchronously, so this module keeps a small per-tenant **snapshot** of\n * resolved credentials (user rows over org rows) hydrated from the\n * `model-credentials` domain. The snapshot serves the gateway's synchronous\n * path-selection reads (`get` / `getStoredApiKey`); the fetch-time\n * `getApiKey` is authoritative — it re-resolves against the domain and\n * refreshes expired OAuth tokens under the domain's row lock, so a slightly\n * stale snapshot can never send an expired token upstream.\n *\n * Snapshots are primed per request by `createTenantCredentialPrimer` (mounted\n * after the web auth gate) so the first model call of a request already sees\n * the caller's credentials. This store explicitly disables the SDK's\n * environment fallback so server-shell credentials never leak into tenants.\n */\n\nimport type { CredentialTenant as SdkCredentialTenant } from '@mastra/code-sdk/agents/credential-resolver';\nimport { setCredentialStoreProvider } from '@mastra/code-sdk/agents/credential-resolver';\nimport { getOAuthProvider } from '@mastra/code-sdk/auth/storage';\nimport type { AuthCredential, CredentialStore } from '@mastra/code-sdk/auth/types';\nimport type { MiddlewareHandler } from 'hono';\n\nimport { isOAuthCredentialExpired } from '../storage/domains/credentials/base.js';\nimport type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport { getTenantCredentialsStorage, tenantOrgId } from './provider-credentials.js';\nimport type { RouteAuth } from './route.js';\n\n/** How long a hydrated snapshot is considered fresh. */\nconst SNAPSHOT_TTL_MS = 15_000;\n\n/** Cap on cached tenant stores; oldest-inserted evicted beyond this. */\nconst MAX_CACHED_TENANTS = 1000;\n\nexport class TenantCredentialStore implements CredentialStore {\n readonly allowEnvironmentFallback = false;\n readonly #orgId: string;\n readonly #userId: string;\n readonly #orgFirst: boolean;\n readonly #credentials: ModelCredentialsStorage | undefined;\n #snapshot = new Map<string, AuthCredential>();\n #fetchedAt = 0;\n #hydrating: Promise<void> | undefined;\n\n constructor(orgId: string, userId: string, credentials: ModelCredentialsStorage | undefined, orgFirst = false) {\n this.#orgId = orgId;\n this.#userId = userId;\n this.#credentials = credentials;\n this.#orgFirst = orgFirst;\n }\n\n /** Hydrate the snapshot when stale; coalesces concurrent callers. */\n async ensureFresh(now = Date.now()): Promise<void> {\n if (now - this.#fetchedAt < SNAPSHOT_TTL_MS) return;\n this.#hydrating ??= this.#hydrate().finally(() => {\n this.#hydrating = undefined;\n });\n await this.#hydrating;\n }\n\n async #hydrate(): Promise<void> {\n const storage = await getTenantCredentialsStorage(this.#credentials);\n if (!storage) return; // Keep the last tenant-scoped snapshot.\n const records = await storage.listCredentials(this.#orgId, this.#userId);\n const next = new Map<string, AuthCredential>();\n // Lower-precedence rows first so higher-precedence rows overwrite them\n // (user > org normally; org > user for org-first automated runs).\n const [under, over] = this.#orgFirst ? (['user', 'org'] as const) : (['org', 'user'] as const);\n for (const record of records.filter(r => r.scope === under)) {\n next.set(record.provider, record.credential);\n }\n for (const record of records.filter(r => r.scope === over)) {\n next.set(record.provider, record.credential);\n }\n this.#snapshot = next;\n this.#fetchedAt = Date.now();\n }\n\n /** Sync by contract; kicks a background re-hydrate when the snapshot is stale. */\n reload(): void {\n if (Date.now() - this.#fetchedAt >= SNAPSHOT_TTL_MS) {\n void this.ensureFresh().catch(() => {});\n }\n }\n\n get(provider: string): AuthCredential | undefined {\n return this.#snapshot.get(provider);\n }\n\n getStoredApiKey(provider: string): string | undefined {\n const cred = this.#snapshot.get(provider);\n return cred?.type === 'api_key' ? cred.key : undefined;\n }\n\n /**\n * Authoritative fetch-time resolution: re-reads the domain (user > org) and\n * refreshes expired OAuth tokens under the domain's row lock. Mirrors\n * `AuthStorage.getApiKey` semantics: `undefined` on missing credential or\n * failed refresh (caller surfaces a re-login error).\n */\n async getApiKey(provider: string): Promise<string | undefined> {\n const storage = await getTenantCredentialsStorage(this.#credentials);\n if (!storage) {\n // Domain unavailable: best effort from the snapshot; expired OAuth\n // tokens cannot be refreshed without the domain's lock.\n const cred = this.#snapshot.get(provider);\n if (cred?.type === 'api_key') return cred.key;\n if (cred?.type === 'oauth' && !isOAuthCredentialExpired(cred)) {\n return getOAuthProvider(provider)?.getApiKey(cred);\n }\n return undefined;\n }\n\n const resolved = await storage.resolveCredential(\n this.#orgId,\n this.#userId,\n provider,\n this.#orgFirst ? 'org' : 'user',\n );\n if (!resolved) {\n this.#snapshot.delete(provider);\n return undefined;\n }\n this.#snapshot.set(provider, resolved.credential);\n\n if (resolved.credential.type === 'api_key') {\n return resolved.credential.key;\n }\n\n const oauthProvider = getOAuthProvider(provider);\n if (!oauthProvider) return undefined;\n\n if (!isOAuthCredentialExpired(resolved.credential)) {\n return oauthProvider.getApiKey(resolved.credential);\n }\n\n // Refresh at the scope the credential actually lives at (OAuth rows are\n // user-scoped by policy, but resolve defensively from the record).\n const rowTenant = resolved.scope === 'user' ? { orgId: this.#orgId, userId: this.#userId } : { orgId: this.#orgId };\n try {\n const refreshed = await storage.refreshOAuth(rowTenant, provider, async current => ({\n type: 'oauth' as const,\n ...(await oauthProvider.refreshToken(current)),\n }));\n if (!refreshed) return undefined;\n this.#snapshot.set(provider, refreshed);\n return oauthProvider.getApiKey(refreshed);\n } catch {\n // Refresh failed — user needs to re-login (same posture as AuthStorage).\n return undefined;\n }\n }\n}\n\nconst tenantStores = new Map<string, TenantCredentialStore>();\n\nfunction storeFor(tenant: SdkCredentialTenant, credentials: ModelCredentialsStorage): TenantCredentialStore {\n const orgId = tenantOrgId(tenant);\n const orgFirst = tenant.orgFirst === true;\n const key = `${orgId}\\u0000${tenant.userId}\\u0000${orgFirst ? 'org-first' : 'user-first'}`;\n let store = tenantStores.get(key);\n if (!store) {\n if (tenantStores.size >= MAX_CACHED_TENANTS) {\n const oldest = tenantStores.keys().next().value;\n if (oldest !== undefined) tenantStores.delete(oldest);\n }\n store = new TenantCredentialStore(orgId, tenant.userId, credentials, orgFirst);\n tenantStores.set(key, store);\n }\n return store;\n}\n\n/**\n * Register the web tenant credential store provider with the SDK. Called by\n * the factory after storage init with the `model-credentials` domain handle;\n * from then on `resolveModel` uses per-tenant credentials and the SDK skips\n * the `loadStoredApiKeysIntoEnv` env side-channel.\n */\nexport function registerTenantCredentialResolver(credentials: ModelCredentialsStorage): void {\n setCredentialStoreProvider(tenant => storeFor(tenant, credentials));\n}\n\n/** Test hook: clear registration and cached tenant snapshots. */\nexport function resetTenantCredentialResolverForTests(): void {\n setCredentialStoreProvider(undefined);\n tenantStores.clear();\n}\n\n/**\n * Drop cached snapshots after a credential write so the change is visible to\n * the next model call immediately instead of after the snapshot TTL. An org\n * write affects every member's resolved view, so all stores under the org are\n * invalidated; a user write only drops that user's store.\n */\nexport function invalidateTenantCredentialSnapshots(tenant: { orgId: string; userId?: string }): void {\n if (tenant.userId) {\n tenantStores.delete(`${tenant.orgId}\\u0000${tenant.userId}\\u0000user-first`);\n tenantStores.delete(`${tenant.orgId}\\u0000${tenant.userId}\\u0000org-first`);\n return;\n }\n for (const key of tenantStores.keys()) {\n if (key.startsWith(`${tenant.orgId}\\u0000`)) tenantStores.delete(key);\n }\n}\n\n/**\n * Middleware mounted after the web auth gate: primes both credential precedence\n * modes so the request's first model call can resolve user → organization when\n * `orgFirst` is false or organization → user when `orgFirst` is true. Cheap when\n * fresh because each store has a TTL.\n */\nexport async function primeTenantCredentials({\n tenant,\n credentials,\n}: {\n tenant: SdkCredentialTenant;\n credentials: ModelCredentialsStorage;\n}): Promise<void> {\n await Promise.all([\n storeFor({ ...tenant, orgFirst: false }, credentials).ensureFresh(),\n storeFor({ ...tenant, orgFirst: true }, credentials).ensureFresh(),\n ]);\n}\n\nexport function createTenantCredentialPrimer({\n auth,\n credentials,\n}: {\n auth: RouteAuth;\n credentials: ModelCredentialsStorage;\n}): MiddlewareHandler {\n return async (c, next) => {\n const tenant = auth.tenant(c);\n if (tenant) {\n try {\n await primeTenantCredentials({ tenant, credentials });\n } catch (error) {\n console.warn('[factory] Failed to prime tenant model credentials', {\n orgId: tenant.orgId,\n userId: tenant.userId,\n error,\n });\n }\n }\n await next();\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tenant-credentials.js","names":["#orgId","#userId","#orgFirst","#credentials","#fetchedAt","#hydrating","#hydrate","#snapshot"],"sources":["../../src/routes/tenant-credentials.ts"],"sourcesContent":["/**\n * Per-tenant credential store for model resolution (deployed mode).\n *\n * The SDK's `resolveModel` asks the registered `CredentialStoreProvider` for a\n * store synchronously, so this module keeps a small per-tenant **snapshot** of\n * resolved credentials (user rows over org rows) hydrated from the\n * `model-credentials` domain. The snapshot serves the gateway's synchronous\n * path-selection reads (`get` / `getStoredApiKey`); the fetch-time\n * `getApiKey` is authoritative — it re-resolves against the domain and\n * refreshes expired OAuth tokens under the domain's row lock, so a slightly\n * stale snapshot can never send an expired token upstream.\n *\n * Snapshots are primed per request by `createTenantCredentialPrimer` (mounted\n * after the web auth gate) so the first model call of a request already sees\n * the caller's credentials. This store explicitly disables the SDK's\n * environment fallback so server-shell credentials never leak into tenants.\n */\n\nimport type { CredentialTenant as SdkCredentialTenant } from '@mastra/code-sdk/agents/credential-resolver';\nimport {\n resolveTenantFromRequestContext,\n setCredentialStoreProvider,\n} from '@mastra/code-sdk/agents/credential-resolver';\nimport { getOAuthProvider } from '@mastra/code-sdk/auth/storage';\nimport type { AuthCredential, CredentialStore } from '@mastra/code-sdk/auth/types';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { MiddlewareHandler } from 'hono';\n\nimport { isOAuthCredentialExpired } from '../storage/domains/credentials/base.js';\nimport type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport { getTenantCredentialsStorage, tenantOrgId } from './provider-credentials.js';\nimport type { RouteAuth } from './route.js';\n\n/** How long a hydrated snapshot is considered fresh. */\nconst SNAPSHOT_TTL_MS = 15_000;\n\n/** Cap on cached tenant stores; oldest-inserted evicted beyond this. */\nconst MAX_CACHED_TENANTS = 1000;\n\nexport class TenantCredentialStore implements CredentialStore {\n readonly allowEnvironmentFallback = false;\n readonly #orgId: string;\n readonly #userId: string;\n readonly #orgFirst: boolean;\n readonly #credentials: ModelCredentialsStorage | undefined;\n #snapshot = new Map<string, AuthCredential>();\n #fetchedAt = 0;\n #hydrating: Promise<void> | undefined;\n\n constructor(orgId: string, userId: string, credentials: ModelCredentialsStorage | undefined, orgFirst = false) {\n this.#orgId = orgId;\n this.#userId = userId;\n this.#credentials = credentials;\n this.#orgFirst = orgFirst;\n }\n\n /** Hydrate the snapshot when stale; coalesces concurrent callers. */\n async ensureFresh(now = Date.now()): Promise<void> {\n if (now - this.#fetchedAt < SNAPSHOT_TTL_MS) return;\n this.#hydrating ??= this.#hydrate().finally(() => {\n this.#hydrating = undefined;\n });\n await this.#hydrating;\n }\n\n async #hydrate(): Promise<void> {\n const storage = await getTenantCredentialsStorage(this.#credentials);\n if (!storage) return; // Keep the last tenant-scoped snapshot.\n const records = await storage.listCredentials(this.#orgId, this.#userId);\n const next = new Map<string, AuthCredential>();\n // Lower-precedence rows first so higher-precedence rows overwrite them\n // (user > org normally; org > user for org-first automated runs).\n const [under, over] = this.#orgFirst ? (['user', 'org'] as const) : (['org', 'user'] as const);\n for (const record of records.filter(r => r.scope === under)) {\n next.set(record.provider, record.credential);\n }\n for (const record of records.filter(r => r.scope === over)) {\n next.set(record.provider, record.credential);\n }\n this.#snapshot = next;\n this.#fetchedAt = Date.now();\n }\n\n /** Sync by contract; kicks a background re-hydrate when the snapshot is stale. */\n reload(): void {\n if (Date.now() - this.#fetchedAt >= SNAPSHOT_TTL_MS) {\n void this.ensureFresh().catch(() => {});\n }\n }\n\n get(provider: string): AuthCredential | undefined {\n return this.#snapshot.get(provider);\n }\n\n getStoredApiKey(provider: string): string | undefined {\n const cred = this.#snapshot.get(provider);\n return cred?.type === 'api_key' ? cred.key : undefined;\n }\n\n /**\n * Authoritative fetch-time resolution: re-reads the domain (user > org) and\n * refreshes expired OAuth tokens under the domain's row lock. Mirrors\n * `AuthStorage.getApiKey` semantics: `undefined` on missing credential or\n * failed refresh (caller surfaces a re-login error).\n */\n async getApiKey(provider: string): Promise<string | undefined> {\n const storage = await getTenantCredentialsStorage(this.#credentials);\n if (!storage) {\n // Domain unavailable: best effort from the snapshot; expired OAuth\n // tokens cannot be refreshed without the domain's lock.\n const cred = this.#snapshot.get(provider);\n if (cred?.type === 'api_key') return cred.key;\n if (cred?.type === 'oauth' && !isOAuthCredentialExpired(cred)) {\n return getOAuthProvider(provider)?.getApiKey(cred);\n }\n return undefined;\n }\n\n const resolved = await storage.resolveCredential(\n this.#orgId,\n this.#userId,\n provider,\n this.#orgFirst ? 'org' : 'user',\n );\n if (!resolved) {\n this.#snapshot.delete(provider);\n return undefined;\n }\n this.#snapshot.set(provider, resolved.credential);\n\n if (resolved.credential.type === 'api_key') {\n return resolved.credential.key;\n }\n\n const oauthProvider = getOAuthProvider(provider);\n if (!oauthProvider) return undefined;\n\n if (!isOAuthCredentialExpired(resolved.credential)) {\n return oauthProvider.getApiKey(resolved.credential);\n }\n\n // Refresh at the scope the credential actually lives at (OAuth rows are\n // user-scoped by policy, but resolve defensively from the record).\n const rowTenant = resolved.scope === 'user' ? { orgId: this.#orgId, userId: this.#userId } : { orgId: this.#orgId };\n try {\n const refreshed = await storage.refreshOAuth(rowTenant, provider, async current => ({\n type: 'oauth' as const,\n ...(await oauthProvider.refreshToken(current)),\n }));\n if (!refreshed) return undefined;\n this.#snapshot.set(provider, refreshed);\n return oauthProvider.getApiKey(refreshed);\n } catch {\n // Refresh failed — user needs to re-login (same posture as AuthStorage).\n return undefined;\n }\n }\n}\n\nconst tenantStores = new Map<string, TenantCredentialStore>();\nlet registeredCredentials: ModelCredentialsStorage | undefined;\n\nfunction storeFor(tenant: SdkCredentialTenant, credentials: ModelCredentialsStorage): TenantCredentialStore {\n const orgId = tenantOrgId(tenant);\n const orgFirst = tenant.orgFirst === true;\n const key = `${orgId}\\u0000${tenant.userId}\\u0000${orgFirst ? 'org-first' : 'user-first'}`;\n let store = tenantStores.get(key);\n if (!store) {\n if (tenantStores.size >= MAX_CACHED_TENANTS) {\n const oldest = tenantStores.keys().next().value;\n if (oldest !== undefined) tenantStores.delete(oldest);\n }\n store = new TenantCredentialStore(orgId, tenant.userId, credentials, orgFirst);\n tenantStores.set(key, store);\n }\n return store;\n}\n\n/**\n * Register the web tenant credential store provider with the SDK. Called by\n * the factory after storage init with the `model-credentials` domain handle;\n * from then on `resolveModel` uses per-tenant credentials and the SDK skips\n * the `loadStoredApiKeysIntoEnv` env side-channel.\n */\nexport function registerTenantCredentialResolver(credentials: ModelCredentialsStorage): void {\n registeredCredentials = credentials;\n setCredentialStoreProvider(tenant => storeFor(tenant, credentials));\n}\n\n/**\n * Prime the tenant stores for a request context built outside the web layer,\n * such as a webhook-triggered session run. The auth middleware does this for\n * HTTP requests; a run that starts without one would otherwise resolve its\n * model against an empty snapshot and fail closed. No-op before registration.\n */\nexport async function primeTenantCredentialsForRequestContext(requestContext: RequestContext): Promise<void> {\n const tenant = resolveTenantFromRequestContext(requestContext);\n if (!tenant || !registeredCredentials) return;\n await primeTenantCredentials({ tenant, credentials: registeredCredentials });\n}\n\n/** Test hook: clear registration and cached tenant snapshots. */\nexport function resetTenantCredentialResolverForTests(): void {\n setCredentialStoreProvider(undefined);\n registeredCredentials = undefined;\n tenantStores.clear();\n}\n\n/**\n * Drop cached snapshots after a credential write so the change is visible to\n * the next model call immediately instead of after the snapshot TTL. An org\n * write affects every member's resolved view, so all stores under the org are\n * invalidated; a user write only drops that user's store.\n */\nexport function invalidateTenantCredentialSnapshots(tenant: { orgId: string; userId?: string }): void {\n if (tenant.userId) {\n tenantStores.delete(`${tenant.orgId}\\u0000${tenant.userId}\\u0000user-first`);\n tenantStores.delete(`${tenant.orgId}\\u0000${tenant.userId}\\u0000org-first`);\n return;\n }\n for (const key of tenantStores.keys()) {\n if (key.startsWith(`${tenant.orgId}\\u0000`)) tenantStores.delete(key);\n }\n}\n\n/**\n * Middleware mounted after the web auth gate: primes both credential precedence\n * modes so the request's first model call can resolve user → organization when\n * `orgFirst` is false or organization → user when `orgFirst` is true. Cheap when\n * fresh because each store has a TTL.\n */\nexport async function primeTenantCredentials({\n tenant,\n credentials,\n}: {\n tenant: SdkCredentialTenant;\n credentials: ModelCredentialsStorage;\n}): Promise<void> {\n await Promise.all([\n storeFor({ ...tenant, orgFirst: false }, credentials).ensureFresh(),\n storeFor({ ...tenant, orgFirst: true }, credentials).ensureFresh(),\n ]);\n}\n\nexport function createTenantCredentialPrimer({\n auth,\n credentials,\n}: {\n auth: RouteAuth;\n credentials: ModelCredentialsStorage;\n}): MiddlewareHandler {\n return async (c, next) => {\n const tenant = auth.tenant(c);\n if (tenant) {\n try {\n await primeTenantCredentials({ tenant, credentials });\n } catch (error) {\n console.warn('[factory] Failed to prime tenant model credentials', {\n orgId: tenant.orgId,\n userId: tenant.userId,\n error,\n });\n }\n }\n await next();\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"work-items.d.ts","sourceRoot":"","sources":["../../src/routes/work-items.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EACV,uBAAuB,EAGxB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAA4B,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAEzG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAElF,OAAO,KAAK,EACV,mBAAmB,EAEnB,mBAAmB,EAEnB,gBAAgB,EACjB,MAAM,uCAAuC,CAAC;AAU/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,KAAK,EAAE,YAAY,CAAC;IACpB,yFAAyF;IACzF,QAAQ,EAAE,sBAAsB,CAAC;IACjC,kDAAkD;IAClD,SAAS,EAAE,gBAAgB,CAAC;IAC5B,kDAAkD;IAClD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,8DAA8D;IAC9D,QAAQ,EAAE,uBAAuB,CAAC;IAClC,iDAAiD;IACjD,WAAW,EAAE,kBAAkB,CAAC;IAChC,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,YAAY,GAAG,eAAe,CAAC,CAAC;IACnF,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,CAAC;IAC5D,2GAA2G;IAC3G,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC,CAAC;CACvE;AAyCD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAG7E;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAG7E;AAyED,qBAAa,cAAe,SAAQ,KAAK,CAAC,kBAAkB,CAAC;;IA2H3D,gEAAgE;IAChE,MAAM,IAAI,QAAQ,EAAE;CAoarB"}
1
+ {"version":3,"file":"work-items.d.ts","sourceRoot":"","sources":["../../src/routes/work-items.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EACV,uBAAuB,EAGxB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAA4B,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAEzG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAElF,OAAO,KAAK,EACV,mBAAmB,EAEnB,mBAAmB,EAEnB,gBAAgB,EACjB,MAAM,uCAAuC,CAAC;AAU/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,KAAK,EAAE,YAAY,CAAC;IACpB,yFAAyF;IACzF,QAAQ,EAAE,sBAAsB,CAAC;IACjC,kDAAkD;IAClD,SAAS,EAAE,gBAAgB,CAAC;IAC5B,kDAAkD;IAClD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,8DAA8D;IAC9D,QAAQ,EAAE,uBAAuB,CAAC;IAClC,iDAAiD;IACjD,WAAW,EAAE,kBAAkB,CAAC;IAChC,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,YAAY,GAAG,eAAe,CAAC,CAAC;IACnF,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,CAAC;IAC5D,2GAA2G;IAC3G,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC,CAAC;CACvE;AAyCD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAG7E;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAG7E;AA8ED,qBAAa,cAAe,SAAQ,KAAK,CAAC,kBAAkB,CAAC;;IA2H3D,gEAAgE;IAChE,MAAM,IAAI,QAAQ,EAAE;CAoarB"}
@@ -83,7 +83,7 @@ function summaryRole(boards, decision) {
83
83
  function summarySource(decision) {
84
84
  if (decision.type !== "upsertLinkedWorkItem") return null;
85
85
  const source = decision.source;
86
- return source === "github-issue" || source === "github-pr" || source === "linear-issue" || source === "manual" ? source : null;
86
+ return source === "github-issue" || source === "github-pr" || source === "gitlab-issue" || source === "gitlab-pr" || source === "linear-issue" || source === "manual" ? source : null;
87
87
  }
88
88
  function decisionSummary(boards, decision) {
89
89
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"work-items.js","names":["#boards","#defaultBoards","#resolveTenant","#resolveProject","#auditWorkItemPatch","#proposalRoute"],"sources":["../../src/routes/work-items.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for Factory work items (the kanban board).\n *\n * Registered alongside the other `/web/*` routes behind the host auth gate.\n * The board is org-wide: every route re-resolves the caller's `(orgId, userId)`\n * tenant and scopes reads/writes by `orgId`, so any org member sees and moves\n * the same cards while `created_by` / stage history record who acted.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport { createBoardRegistry } from '../boards/index.js';\nimport type { BoardRegistry } from '../boards/index.js';\nimport { factoryDispatchFailureMetadata } from '../rules/dispatch-errors.js';\nimport type {\n FactoryStartCoordinator,\n FactoryStartPreparedResult,\n FactoryStartRequest,\n} from '../rules/start-coordinator.js';\nimport { FactoryStartTransitionError } from '../rules/start-coordinator.js';\nimport type { FactoryTransitionRequest, FactoryTransitionService } from '../rules/transition-service.js';\nimport type { WorkItemSource } from '../rules/types.js';\nimport type { LiveSessions } from '../session/live-sessions.js';\nimport { auditRequestOrigin } from '../storage/domains/audit/domain.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { WorkItemCommentsStorage } from '../storage/domains/comments/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport { thresholdsOrDefault } from '../storage/domains/queue-health/base.js';\nimport type {\n CreateWorkItemInput,\n FactoryDeferredDecisionRecord,\n UpdateWorkItemInput,\n WorkItemRow,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport {\n FACTORY_PULL_REQUEST_RECONCILIATION_KEY,\n FACTORY_RULE_MATERIALIZATION_KEY,\n WorkItemRelationError,\n WorkItemUpdateConflictError,\n} from '../storage/domains/work-items/base.js';\nimport { computeFactoryMetrics, parseMetricsRange } from '../storage/domains/work-items/metrics.js';\nimport { buildAttentionRoutes, factoryDecisionType } from './attention.js';\nimport { FACTORY_ROUTE_CONTRACTS } from './contracts.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\nimport { buildSupervisorRoutes } from './supervisor.js';\n\nexport interface WorkItemRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Factory projects domain — validates the `:id` project belongs to the caller's org. */\n projects: FactoryProjectsStorage;\n /** Work-items domain backing the kanban board. */\n workItems: WorkItemsStorage;\n /** Boards installed for this Factory instance. */\n boardRegistry?: BoardRegistry;\n /** Comments domain — backs the mention attention provider. */\n comments: WorkItemCommentsStorage;\n /** Per-project queue-health threshold config. */\n queueHealth: QueueHealthStorage;\n /** Governed stage-transition service. Stage moves 503 when absent. */\n transitionService?: Pick<FactoryTransitionService, 'transition' | 'configVersion'>;\n /** Coordinator that binds a Factory run before dispatching its kickoff. */\n startCoordinator?: Pick<FactoryStartCoordinator, 'prepare'>;\n /** Materialized sessions, read to report which of the listed cards are being worked or wait on someone. */\n liveSessions: Pick<LiveSessions, 'isRunning' | 'parked' | 'parkedIn'>;\n}\n\n/** The card as clients see it, without the dispatcher's internal bookkeeping. */\nfunction toWireWorkItem(item: WorkItemRow): WorkItemRow {\n if (\n !item.metadata ||\n (!(FACTORY_RULE_MATERIALIZATION_KEY in item.metadata) &&\n !(FACTORY_PULL_REQUEST_RECONCILIATION_KEY in item.metadata))\n ) {\n return item;\n }\n return { ...item, metadata: publicWorkItemMetadata(item.metadata) ?? {} };\n}\n\n/** Session ids of the listed cards that the predicate picks, each once. */\nfunction sessionIdsWhere(items: WorkItemRow[], predicate: (sessionId: string) => boolean): string[] {\n const picked = new Set<string>();\n for (const item of items) {\n for (const { sessionId } of Object.values(item.sessions)) {\n if (predicate(sessionId)) picked.add(sessionId);\n }\n }\n return [...picked];\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nfunction publicWorkItemMetadata(value: Record<string, unknown> | null): Record<string, unknown> | null {\n if (value === null) return null;\n const {\n [FACTORY_RULE_MATERIALIZATION_KEY]: _materialization,\n [FACTORY_PULL_REQUEST_RECONCILIATION_KEY]: _reconciliation,\n ...metadata\n } = value;\n return metadata;\n}\n\n/** Validate an untrusted create body. Unknown keys are dropped. */\nexport function parseCreateWorkItem(body: unknown): CreateWorkItemInput | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemCreate.bodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\n/** Validate an untrusted patch body. Unknown keys are dropped. */\nexport function parseUpdateWorkItem(body: unknown): UpdateWorkItemInput | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemUpdate.bodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\nasync function readJson(c: Context): Promise<unknown | undefined> {\n try {\n return await c.req.json();\n } catch {\n return undefined;\n }\n}\n\n/** Fields a PATCH touched, for the bounded `updated` event summary. */\nfunction patchedFields(patch: Record<string, unknown>): string[] {\n return Object.keys(patch).filter(key => patch[key] !== undefined);\n}\n\nfunction parseTransitionBody(\n body: unknown,\n): Omit<FactoryTransitionRequest, 'orgId' | 'factoryProjectId' | 'workItemId' | 'actor'> | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemTransition.bodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\nfunction parseStartBody(\n body: unknown,\n tenant: { orgId: string; userId: string },\n factoryProjectId: string,\n): FactoryStartRequest | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemStart.bodySchema.safeParse(body);\n return parsed.success ? { ...tenant, factoryProjectId, ...parsed.data } : null;\n}\n\nfunction encodeDecisionCursor(decision: FactoryDeferredDecisionRecord): string {\n return Buffer.from(JSON.stringify([decision.createdAt.toISOString(), decision.id]), 'utf8').toString('base64url');\n}\n\n/** A proposed transition names the seat its lane addresses, so the card can label what approving starts. */\nfunction summaryRole(boards: BoardRegistry, decision: Record<string, unknown>): string | null {\n if (typeof decision.role === 'string') return decision.role.slice(0, 32);\n if (decision.type !== 'transition') return null;\n const { board, stage } = decision;\n if (typeof board !== 'string' || typeof stage !== 'string') return null;\n return boards.get(board)?.roleForPhase(stage) ?? null;\n}\n\n/** A linked-card decision names where the card is synced from, so the UI can say \"GitHub\" rather than \"a linked card\". */\nfunction summarySource(decision: Record<string, unknown>): WorkItemSource | null {\n if (decision.type !== 'upsertLinkedWorkItem') return null;\n const source = decision.source;\n return source === 'github-issue' || source === 'github-pr' || source === 'linear-issue' || source === 'manual'\n ? source\n : null;\n}\n\nfunction decisionSummary(boards: BoardRegistry, decision: FactoryDeferredDecisionRecord) {\n return {\n id: decision.id,\n evaluationId: decision.evaluationId,\n workItemId: decision.workItemId,\n type: factoryDecisionType(decision),\n role: summaryRole(boards, decision.decision),\n source: summarySource(decision.decision),\n status: decision.status,\n attempts: decision.attempts,\n failureOccurrence: decision.failureOccurrence,\n failureCode: decision.failureCode,\n canRetry: factoryDispatchFailureMetadata(decision.failureCode).canRetry,\n lastError: decision.lastError?.slice(0, 512) ?? null,\n createdAt: decision.createdAt.toISOString(),\n updatedAt: decision.updatedAt.toISOString(),\n completedAt: decision.completedAt?.toISOString() ?? null,\n };\n}\n\nexport class WorkItemRoutes extends Route<WorkItemRoutesDeps> {\n #defaultBoards: BoardRegistry | undefined;\n\n get #boards(): BoardRegistry {\n return this.deps.boardRegistry ?? (this.#defaultBoards ??= createBoardRegistry());\n }\n\n /** Resolve the `(orgId, userId)` tenant or a ready-to-return error response. */\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'The Factory board requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n /**\n * Resolve the tenant AND the org-owned project from the `:id` param. Work\n * items hang off a project, so listing/creating requires the project to\n * exist in the caller's org.\n */\n async #resolveProject(\n c: Context,\n ): Promise<\n { orgId: string; userId: string; factoryProjectId: string; defaultModelId: string | null } | { response: Response }\n > {\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant;\n\n const parsedPath = FACTORY_ROUTE_CONTRACTS.projectGet.pathSchema.safeParse({ id: c.req.param('id') });\n if (!parsedPath.success) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n const projectId = parsedPath.data.id;\n const { projects } = this.deps;\n await projects.ensureReady();\n const project = await projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n return { ...tenant, factoryProjectId: projectId, defaultModelId: project.defaultModelId };\n }\n\n async #auditWorkItemPatch({\n context,\n item,\n patch,\n }: {\n context: Context;\n item: WorkItemRow;\n patch: Record<string, unknown>;\n }): Promise<void> {\n await this.deps.audit.emit({\n context,\n input: {\n action: 'factory.work_item.updated',\n factoryProjectId: item.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { fields: patchedFields(patch) },\n },\n });\n }\n\n /** Releasing a parked run and dropping it: same request, opposite outcomes, both audited as consent. */\n #proposalRoute({\n verb,\n settle,\n }: {\n verb: 'approve' | 'dismiss';\n settle: (\n orgId: string,\n factoryProjectId: string,\n decisionId: string,\n now: Date,\n userId: string,\n ) => Promise<FactoryDeferredDecisionRecord | null>;\n }): ApiRoute {\n const { audit, workItems } = this.deps;\n const contract =\n verb === 'approve' ? FACTORY_ROUTE_CONTRACTS.decisionApprove : FACTORY_ROUTE_CONTRACTS.decisionDismiss;\n return registerApiRoute(contract.path, {\n method: contract.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const parsedPath = contract.pathSchema.safeParse({\n id: resolved.factoryProjectId,\n decisionId: context.req.param('decisionId'),\n });\n if (!parsedPath.success) return c.json({ error: 'invalid_decision_id' }, 422);\n const { decisionId } = parsedPath.data;\n await workItems.ensureReady();\n const now = new Date();\n const decision = await settle(resolved.orgId, resolved.factoryProjectId, decisionId, now, resolved.userId);\n if (!decision) return c.json({ error: 'decision_not_proposed' }, 409);\n // Releasing a proposal is a person taking the item on. Approval arms the\n // item's autonomy inside the same storage transaction (see\n // approveDeferredDecision), so follow-up runs no longer wait for approval.\n await audit.emit({\n context,\n input: {\n action: verb === 'approve' ? 'factory.run.approved' : 'factory.run.dismissed',\n factoryProjectId: resolved.factoryProjectId,\n targets: decision.workItemId\n ? [{ type: 'work_item', id: decision.workItemId }]\n : [{ type: 'rule_decision', id: decision.id }],\n metadata: { decisionId: decision.id, effect: factoryDecisionType(decision) },\n },\n });\n return c.json({ decision: decisionSummary(this.#boards, decision) });\n },\n });\n }\n\n /** Build the Factory work-item routes as Mastra `apiRoutes`. */\n routes(): ApiRoute[] {\n const { audit, workItems, queueHealth, transitionService, startCoordinator, liveSessions } = this.deps;\n return [\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.boardCatalog.path, {\n method: FACTORY_ROUTE_CONTRACTS.boardCatalog.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n return c.json({\n boards: [...this.#boards].map(([id, board]) => ({\n id,\n title: board.title,\n initialPhase: board.initialPhase,\n phases: Object.entries(board.phases).map(([phaseId, phase]) => ({\n id: phaseId,\n title: phase.title,\n kind: phase.kind,\n ...(phase.kind === 'working' ? { role: phase.role } : {}),\n transitions: (board.transitions[phaseId] ?? []).map(({ outcome, to }) => ({ outcome, to })),\n })),\n })),\n });\n },\n }),\n // ── List the org's work items for a project, and which are being worked ─\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemList.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemList.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({\n workItems: items.map(toWireWorkItem),\n runningSessionIds: sessionIdsWhere(items, sessionId => liveSessions.isRunning(sessionId)),\n parkedSessionIds: sessionIdsWhere(items, sessionId => liveSessions.parked(sessionId) !== undefined),\n });\n },\n }),\n\n // ── Flow metrics aggregated over the project's work items ───────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.metricsGet.path, {\n method: FACTORY_ROUTE_CONTRACTS.metricsGet.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const query = FACTORY_ROUTE_CONTRACTS.metricsGet.querySchema.safeParse({\n from: context.req.query('from'),\n to: context.req.query('to'),\n });\n if (!query.success) return c.json({ error: 'invalid_metrics_range' }, 400);\n const { windowStart, windowEnd } = parseMetricsRange(query.data.from, query.data.to, new Date());\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ metrics: computeFactoryMetrics(items, { windowStart, windowEnd }) });\n },\n }),\n\n // ── Per-project queue-health age-threshold config (seconds) ─────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.healthThresholdsGet.path, {\n method: FACTORY_ROUTE_CONTRACTS.healthThresholdsGet.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await queueHealth.ensureReady();\n const stored = await queueHealth.getConfig(resolved.orgId, resolved.factoryProjectId);\n // Validate at the read choke point: `getConfig` round-trips a stored\n // JSONB row, and only `saveConfig` validates on write — a corrupted or\n // hand-edited row (empty / non-ascending) would otherwise flow to the\n // chart and invert bucket colors. Fall back to the default on invalid.\n return c.json({ thresholds: thresholdsOrDefault(stored) });\n },\n }),\n\n // ── Bounded durable rule-decision status ────────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.decisionList.path, {\n method: FACTORY_ROUTE_CONTRACTS.decisionList.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n\n const query = FACTORY_ROUTE_CONTRACTS.decisionList.querySchema.safeParse({\n statuses: context.req.query('statuses'),\n before: context.req.query('before'),\n limit: context.req.query('limit'),\n });\n if (!query.success) {\n const field = query.error.issues[0]?.path[0];\n return c.json({ error: field === 'before' ? 'invalid_cursor' : 'invalid_decision_query' }, 400);\n }\n await workItems.ensureReady();\n const page = await workItems.listDeferredDecisionPage({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n statuses: query.data.statuses,\n before: query.data.before,\n limit: query.data.limit,\n });\n const last = page.decisions.at(-1);\n return c.json({\n decisions: page.decisions.map(decision => decisionSummary(this.#boards, decision)),\n ...(page.hasMore && last ? { nextCursor: encodeDecisionCursor(last) } : {}),\n });\n },\n }),\n\n ...buildAttentionRoutes({\n workItems,\n comments: this.deps.comments,\n liveSessions,\n resolveProject: context => this.#resolveProject(loose(context)),\n }),\n\n ...buildSupervisorRoutes({\n workItems,\n boards: this.#boards,\n resolveProject: context => this.#resolveProject(loose(context)),\n }),\n\n this.#proposalRoute({ verb: 'approve', settle: workItems.approveDeferredDecision.bind(workItems) }),\n this.#proposalRoute({ verb: 'dismiss', settle: workItems.dismissDeferredDecision.bind(workItems) }),\n\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.decisionRetry.path, {\n method: FACTORY_ROUTE_CONTRACTS.decisionRetry.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const parsedPath = FACTORY_ROUTE_CONTRACTS.decisionRetry.pathSchema.safeParse({\n id: resolved.factoryProjectId,\n decisionId: context.req.param('decisionId'),\n });\n if (!parsedPath.success) return c.json({ error: 'invalid_decision_id' }, 422);\n const { decisionId } = parsedPath.data;\n await workItems.ensureReady();\n const current = await workItems.getDeferredDecision(resolved.orgId, resolved.factoryProjectId, decisionId);\n if (\n !current ||\n current.status !== 'failed' ||\n !factoryDispatchFailureMetadata(current.failureCode).canRetry\n ) {\n return c.json({ error: 'decision_not_retryable' }, 409);\n }\n const decision = await workItems.retryDeferredDecision(\n resolved.orgId,\n resolved.factoryProjectId,\n decisionId,\n new Date(),\n );\n if (!decision) return c.json({ error: 'decision_not_retryable' }, 409);\n return c.json({ decision: decisionSummary(this.#boards, decision) });\n },\n }),\n\n // ── Create (upsert on sourceKey) a work item ─────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemCreate.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemCreate.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const input = parseCreateWorkItem(body);\n if (!input) return c.json({ error: 'invalid_work_item' }, 400);\n const boardId = input.board ?? (input.externalSource?.type === 'pull-request' ? 'review' : 'work');\n const board = this.#boards.get(boardId);\n if (!board) return c.json({ error: 'invalid_board', message: `Board '${boardId}' is not installed.` }, 422);\n const initialStages = input.stages ?? [board.initialPhase];\n if (initialStages.length !== 1 || initialStages[0] !== board.initialPhase) {\n return c.json(\n {\n error: 'governed_transition_required',\n message: `New work items must enter through the '${board.initialPhase}' phase of board '${boardId}'.`,\n },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const result = await workItems.upsert({\n orgId: resolved.orgId,\n userId: resolved.userId,\n factoryProjectId: resolved.factoryProjectId,\n input: { ...input, board: boardId, stages: initialStages },\n reuseMode: 'non-stage',\n });\n let item = result.item;\n if (result.created) {\n if (!transitionService) {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ error: 'factory_transitions_unavailable' }, 503);\n }\n const entered = await transitionService.transition({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId: item.id,\n board: boardId,\n stage: board.initialPhase,\n expectedRevision: item.revision,\n actor: { type: 'human', id: resolved.userId },\n ...auditRequestOrigin(loose(c)),\n ingress: { type: 'human', identity: `work-item:${item.id}:initial-entry` },\n cause: 'work_item_created',\n initialEntry: true,\n });\n if (entered.status === 'rejected') {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ status: 'rejected', code: entered.code, reason: entered.reason }, 422);\n }\n item = (await workItems.getForProject(resolved.orgId, resolved.factoryProjectId, item.id)) ?? item;\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.created',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { externalSource: item.externalSource, stages: item.stages },\n },\n });\n } else {\n // Source-key reuse: the POST updated an existing card, not created one.\n const { stages: _stages, sessions: _sessions, ...boundedPatch } = input;\n await this.#auditWorkItemPatch({\n context: loose(c),\n item,\n patch: boundedPatch as unknown as Record<string, unknown>,\n });\n }\n return c.json({ workItem: toWireWorkItem(item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Authoritative stage transition ──────────────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemTransition.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemTransition.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const context = loose(c);\n const parsedPath = FACTORY_ROUTE_CONTRACTS.workItemTransition.pathSchema.safeParse({\n id: resolved.factoryProjectId,\n workItemId: context.req.param('workItemId'),\n });\n if (!parsedPath.success) return c.json({ error: 'Work item not found' }, 404);\n const { workItemId } = parsedPath.data;\n const parsed = parseTransitionBody(await readJson(context));\n if (!parsed) return c.json({ error: 'invalid_transition_request' }, 400);\n if (!transitionService) {\n return c.json({ error: 'factory_transition_unavailable' }, 503);\n }\n await workItems.ensureReady();\n const result = await transitionService.transition({\n ...parsed,\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId,\n actor: { type: 'human', id: resolved.userId },\n ...auditRequestOrigin(loose(c)),\n ingress: {\n ...parsed.ingress,\n identity: `human:${resolved.userId}:${parsed.ingress.identity}`,\n },\n });\n if (result.status === 'accepted') return c.json({ result });\n return c.json({ result }, result.code === 'stale' ? 409 : 422);\n },\n }),\n\n // ── Bind a Factory run before dispatching its kickoff ────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemStart.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemStart.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n if (!startCoordinator) {\n return c.json({ error: 'factory_start_unavailable' }, 503);\n }\n const input = parseStartBody(await readJson(loose(c)), resolved, resolved.factoryProjectId);\n if (!input) return c.json({ error: 'invalid_factory_start' }, 400);\n input.requestContext = loose(c).get('requestContext');\n input.defaultModelId = resolved.defaultModelId ?? undefined;\n await workItems.ensureReady();\n let prepared: FactoryStartPreparedResult;\n try {\n prepared = await startCoordinator.prepare(input);\n } catch (error) {\n if (error instanceof FactoryStartTransitionError) {\n return c.json({ result: error.result }, error.result.code === 'stale' ? 409 : 422);\n }\n throw error;\n }\n return c.json({ prepared }, 202);\n },\n }),\n\n // ── Patch non-stage metadata / sessions / title ──────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemUpdate.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemUpdate.method,\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const context = loose(c);\n const parsedPath = FACTORY_ROUTE_CONTRACTS.workItemUpdate.pathSchema.safeParse({\n id: context.req.param('id'),\n });\n if (!parsedPath.success) return c.json({ error: 'Work item not found' }, 404);\n const { id } = parsedPath.data;\n\n const body = await readJson(context);\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const patch = parseUpdateWorkItem(body);\n if (!patch) return c.json({ error: 'invalid_work_item_patch' }, 400);\n\n await workItems.ensureReady();\n const existing = await workItems.get({ orgId: tenant.orgId, id });\n if (!existing) return c.json({ error: 'Work item not found' }, 404);\n if (patch.board !== undefined) {\n const board = this.#boards.get(patch.board);\n const stage = patch.stages?.length === 1 ? patch.stages[0] : undefined;\n if (existing.board !== null) {\n return c.json({ error: 'board_already_assigned' }, 409);\n }\n if (!board) {\n return c.json({ error: 'board_not_installed' }, 400);\n }\n if (!stage || !Object.prototype.hasOwnProperty.call(board.phases, stage)) {\n return c.json({ error: 'invalid_board_migration_phase' }, 400);\n }\n } else if (patch.stages !== undefined) {\n return c.json(\n { error: 'governed_transition_required', message: 'Use the Factory transition endpoint to move stages.' },\n 409,\n );\n }\n\n try {\n const updated = await workItems.update({\n orgId: tenant.orgId,\n id,\n userId: tenant.userId,\n patch,\n ...(patch.board !== undefined ? { expectedRevision: existing.revision, expectedBoard: null } : {}),\n });\n if (!updated) return c.json({ error: 'Work item not found' }, 404);\n await this.#auditWorkItemPatch({\n context: loose(c),\n item: updated.item,\n patch: patch as Record<string, unknown>,\n });\n return c.json({ workItem: toWireWorkItem(updated.item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n if (error instanceof WorkItemUpdateConflictError) {\n return c.json({ error: error.reason === 'board' ? 'board_already_assigned' : error.code }, 409);\n }\n throw error;\n }\n },\n }),\n\n // ── Remove a work item ───────────────────────────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemDelete.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemDelete.method,\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const context = loose(c);\n const parsedPath = FACTORY_ROUTE_CONTRACTS.workItemDelete.pathSchema.safeParse({\n id: context.req.param('id'),\n });\n if (!parsedPath.success) return c.json({ error: 'Work item not found' }, 404);\n const { id } = parsedPath.data;\n\n await workItems.ensureReady();\n const deleted = await workItems.delete({ orgId: tenant.orgId, id });\n if (!deleted) return c.json({ error: 'Work item not found' }, 404);\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.deleted',\n factoryProjectId: deleted.factoryProjectId,\n targets: [{ type: 'work_item', id: deleted.id, name: deleted.title }],\n },\n });\n return c.json({ ok: true });\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"work-items.js","names":["#boards","#defaultBoards","#resolveTenant","#resolveProject","#auditWorkItemPatch","#proposalRoute"],"sources":["../../src/routes/work-items.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for Factory work items (the kanban board).\n *\n * Registered alongside the other `/web/*` routes behind the host auth gate.\n * The board is org-wide: every route re-resolves the caller's `(orgId, userId)`\n * tenant and scopes reads/writes by `orgId`, so any org member sees and moves\n * the same cards while `created_by` / stage history record who acted.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport { createBoardRegistry } from '../boards/index.js';\nimport type { BoardRegistry } from '../boards/index.js';\nimport { factoryDispatchFailureMetadata } from '../rules/dispatch-errors.js';\nimport type {\n FactoryStartCoordinator,\n FactoryStartPreparedResult,\n FactoryStartRequest,\n} from '../rules/start-coordinator.js';\nimport { FactoryStartTransitionError } from '../rules/start-coordinator.js';\nimport type { FactoryTransitionRequest, FactoryTransitionService } from '../rules/transition-service.js';\nimport type { WorkItemSource } from '../rules/types.js';\nimport type { LiveSessions } from '../session/live-sessions.js';\nimport { auditRequestOrigin } from '../storage/domains/audit/domain.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { WorkItemCommentsStorage } from '../storage/domains/comments/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport { thresholdsOrDefault } from '../storage/domains/queue-health/base.js';\nimport type {\n CreateWorkItemInput,\n FactoryDeferredDecisionRecord,\n UpdateWorkItemInput,\n WorkItemRow,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport {\n FACTORY_PULL_REQUEST_RECONCILIATION_KEY,\n FACTORY_RULE_MATERIALIZATION_KEY,\n WorkItemRelationError,\n WorkItemUpdateConflictError,\n} from '../storage/domains/work-items/base.js';\nimport { computeFactoryMetrics, parseMetricsRange } from '../storage/domains/work-items/metrics.js';\nimport { buildAttentionRoutes, factoryDecisionType } from './attention.js';\nimport { FACTORY_ROUTE_CONTRACTS } from './contracts.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\nimport { buildSupervisorRoutes } from './supervisor.js';\n\nexport interface WorkItemRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Factory projects domain — validates the `:id` project belongs to the caller's org. */\n projects: FactoryProjectsStorage;\n /** Work-items domain backing the kanban board. */\n workItems: WorkItemsStorage;\n /** Boards installed for this Factory instance. */\n boardRegistry?: BoardRegistry;\n /** Comments domain — backs the mention attention provider. */\n comments: WorkItemCommentsStorage;\n /** Per-project queue-health threshold config. */\n queueHealth: QueueHealthStorage;\n /** Governed stage-transition service. Stage moves 503 when absent. */\n transitionService?: Pick<FactoryTransitionService, 'transition' | 'configVersion'>;\n /** Coordinator that binds a Factory run before dispatching its kickoff. */\n startCoordinator?: Pick<FactoryStartCoordinator, 'prepare'>;\n /** Materialized sessions, read to report which of the listed cards are being worked or wait on someone. */\n liveSessions: Pick<LiveSessions, 'isRunning' | 'parked' | 'parkedIn'>;\n}\n\n/** The card as clients see it, without the dispatcher's internal bookkeeping. */\nfunction toWireWorkItem(item: WorkItemRow): WorkItemRow {\n if (\n !item.metadata ||\n (!(FACTORY_RULE_MATERIALIZATION_KEY in item.metadata) &&\n !(FACTORY_PULL_REQUEST_RECONCILIATION_KEY in item.metadata))\n ) {\n return item;\n }\n return { ...item, metadata: publicWorkItemMetadata(item.metadata) ?? {} };\n}\n\n/** Session ids of the listed cards that the predicate picks, each once. */\nfunction sessionIdsWhere(items: WorkItemRow[], predicate: (sessionId: string) => boolean): string[] {\n const picked = new Set<string>();\n for (const item of items) {\n for (const { sessionId } of Object.values(item.sessions)) {\n if (predicate(sessionId)) picked.add(sessionId);\n }\n }\n return [...picked];\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nfunction publicWorkItemMetadata(value: Record<string, unknown> | null): Record<string, unknown> | null {\n if (value === null) return null;\n const {\n [FACTORY_RULE_MATERIALIZATION_KEY]: _materialization,\n [FACTORY_PULL_REQUEST_RECONCILIATION_KEY]: _reconciliation,\n ...metadata\n } = value;\n return metadata;\n}\n\n/** Validate an untrusted create body. Unknown keys are dropped. */\nexport function parseCreateWorkItem(body: unknown): CreateWorkItemInput | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemCreate.bodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\n/** Validate an untrusted patch body. Unknown keys are dropped. */\nexport function parseUpdateWorkItem(body: unknown): UpdateWorkItemInput | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemUpdate.bodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\nasync function readJson(c: Context): Promise<unknown | undefined> {\n try {\n return await c.req.json();\n } catch {\n return undefined;\n }\n}\n\n/** Fields a PATCH touched, for the bounded `updated` event summary. */\nfunction patchedFields(patch: Record<string, unknown>): string[] {\n return Object.keys(patch).filter(key => patch[key] !== undefined);\n}\n\nfunction parseTransitionBody(\n body: unknown,\n): Omit<FactoryTransitionRequest, 'orgId' | 'factoryProjectId' | 'workItemId' | 'actor'> | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemTransition.bodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\nfunction parseStartBody(\n body: unknown,\n tenant: { orgId: string; userId: string },\n factoryProjectId: string,\n): FactoryStartRequest | null {\n const parsed = FACTORY_ROUTE_CONTRACTS.workItemStart.bodySchema.safeParse(body);\n return parsed.success ? { ...tenant, factoryProjectId, ...parsed.data } : null;\n}\n\nfunction encodeDecisionCursor(decision: FactoryDeferredDecisionRecord): string {\n return Buffer.from(JSON.stringify([decision.createdAt.toISOString(), decision.id]), 'utf8').toString('base64url');\n}\n\n/** A proposed transition names the seat its lane addresses, so the card can label what approving starts. */\nfunction summaryRole(boards: BoardRegistry, decision: Record<string, unknown>): string | null {\n if (typeof decision.role === 'string') return decision.role.slice(0, 32);\n if (decision.type !== 'transition') return null;\n const { board, stage } = decision;\n if (typeof board !== 'string' || typeof stage !== 'string') return null;\n return boards.get(board)?.roleForPhase(stage) ?? null;\n}\n\n/** A linked-card decision names where the card is synced from, so the UI can say \"GitHub\" rather than \"a linked card\". */\nfunction summarySource(decision: Record<string, unknown>): WorkItemSource | null {\n if (decision.type !== 'upsertLinkedWorkItem') return null;\n const source = decision.source;\n return source === 'github-issue' ||\n source === 'github-pr' ||\n source === 'gitlab-issue' ||\n source === 'gitlab-pr' ||\n source === 'linear-issue' ||\n source === 'manual'\n ? source\n : null;\n}\n\nfunction decisionSummary(boards: BoardRegistry, decision: FactoryDeferredDecisionRecord) {\n return {\n id: decision.id,\n evaluationId: decision.evaluationId,\n workItemId: decision.workItemId,\n type: factoryDecisionType(decision),\n role: summaryRole(boards, decision.decision),\n source: summarySource(decision.decision),\n status: decision.status,\n attempts: decision.attempts,\n failureOccurrence: decision.failureOccurrence,\n failureCode: decision.failureCode,\n canRetry: factoryDispatchFailureMetadata(decision.failureCode).canRetry,\n lastError: decision.lastError?.slice(0, 512) ?? null,\n createdAt: decision.createdAt.toISOString(),\n updatedAt: decision.updatedAt.toISOString(),\n completedAt: decision.completedAt?.toISOString() ?? null,\n };\n}\n\nexport class WorkItemRoutes extends Route<WorkItemRoutesDeps> {\n #defaultBoards: BoardRegistry | undefined;\n\n get #boards(): BoardRegistry {\n return this.deps.boardRegistry ?? (this.#defaultBoards ??= createBoardRegistry());\n }\n\n /** Resolve the `(orgId, userId)` tenant or a ready-to-return error response. */\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'The Factory board requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n /**\n * Resolve the tenant AND the org-owned project from the `:id` param. Work\n * items hang off a project, so listing/creating requires the project to\n * exist in the caller's org.\n */\n async #resolveProject(\n c: Context,\n ): Promise<\n { orgId: string; userId: string; factoryProjectId: string; defaultModelId: string | null } | { response: Response }\n > {\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant;\n\n const parsedPath = FACTORY_ROUTE_CONTRACTS.projectGet.pathSchema.safeParse({ id: c.req.param('id') });\n if (!parsedPath.success) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n const projectId = parsedPath.data.id;\n const { projects } = this.deps;\n await projects.ensureReady();\n const project = await projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n return { ...tenant, factoryProjectId: projectId, defaultModelId: project.defaultModelId };\n }\n\n async #auditWorkItemPatch({\n context,\n item,\n patch,\n }: {\n context: Context;\n item: WorkItemRow;\n patch: Record<string, unknown>;\n }): Promise<void> {\n await this.deps.audit.emit({\n context,\n input: {\n action: 'factory.work_item.updated',\n factoryProjectId: item.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { fields: patchedFields(patch) },\n },\n });\n }\n\n /** Releasing a parked run and dropping it: same request, opposite outcomes, both audited as consent. */\n #proposalRoute({\n verb,\n settle,\n }: {\n verb: 'approve' | 'dismiss';\n settle: (\n orgId: string,\n factoryProjectId: string,\n decisionId: string,\n now: Date,\n userId: string,\n ) => Promise<FactoryDeferredDecisionRecord | null>;\n }): ApiRoute {\n const { audit, workItems } = this.deps;\n const contract =\n verb === 'approve' ? FACTORY_ROUTE_CONTRACTS.decisionApprove : FACTORY_ROUTE_CONTRACTS.decisionDismiss;\n return registerApiRoute(contract.path, {\n method: contract.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const parsedPath = contract.pathSchema.safeParse({\n id: resolved.factoryProjectId,\n decisionId: context.req.param('decisionId'),\n });\n if (!parsedPath.success) return c.json({ error: 'invalid_decision_id' }, 422);\n const { decisionId } = parsedPath.data;\n await workItems.ensureReady();\n const now = new Date();\n const decision = await settle(resolved.orgId, resolved.factoryProjectId, decisionId, now, resolved.userId);\n if (!decision) return c.json({ error: 'decision_not_proposed' }, 409);\n // Releasing a proposal is a person taking the item on. Approval arms the\n // item's autonomy inside the same storage transaction (see\n // approveDeferredDecision), so follow-up runs no longer wait for approval.\n await audit.emit({\n context,\n input: {\n action: verb === 'approve' ? 'factory.run.approved' : 'factory.run.dismissed',\n factoryProjectId: resolved.factoryProjectId,\n targets: decision.workItemId\n ? [{ type: 'work_item', id: decision.workItemId }]\n : [{ type: 'rule_decision', id: decision.id }],\n metadata: { decisionId: decision.id, effect: factoryDecisionType(decision) },\n },\n });\n return c.json({ decision: decisionSummary(this.#boards, decision) });\n },\n });\n }\n\n /** Build the Factory work-item routes as Mastra `apiRoutes`. */\n routes(): ApiRoute[] {\n const { audit, workItems, queueHealth, transitionService, startCoordinator, liveSessions } = this.deps;\n return [\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.boardCatalog.path, {\n method: FACTORY_ROUTE_CONTRACTS.boardCatalog.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n return c.json({\n boards: [...this.#boards].map(([id, board]) => ({\n id,\n title: board.title,\n initialPhase: board.initialPhase,\n phases: Object.entries(board.phases).map(([phaseId, phase]) => ({\n id: phaseId,\n title: phase.title,\n kind: phase.kind,\n ...(phase.kind === 'working' ? { role: phase.role } : {}),\n transitions: (board.transitions[phaseId] ?? []).map(({ outcome, to }) => ({ outcome, to })),\n })),\n })),\n });\n },\n }),\n // ── List the org's work items for a project, and which are being worked ─\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemList.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemList.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({\n workItems: items.map(toWireWorkItem),\n runningSessionIds: sessionIdsWhere(items, sessionId => liveSessions.isRunning(sessionId)),\n parkedSessionIds: sessionIdsWhere(items, sessionId => liveSessions.parked(sessionId) !== undefined),\n });\n },\n }),\n\n // ── Flow metrics aggregated over the project's work items ───────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.metricsGet.path, {\n method: FACTORY_ROUTE_CONTRACTS.metricsGet.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const query = FACTORY_ROUTE_CONTRACTS.metricsGet.querySchema.safeParse({\n from: context.req.query('from'),\n to: context.req.query('to'),\n });\n if (!query.success) return c.json({ error: 'invalid_metrics_range' }, 400);\n const { windowStart, windowEnd } = parseMetricsRange(query.data.from, query.data.to, new Date());\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ metrics: computeFactoryMetrics(items, { windowStart, windowEnd }) });\n },\n }),\n\n // ── Per-project queue-health age-threshold config (seconds) ─────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.healthThresholdsGet.path, {\n method: FACTORY_ROUTE_CONTRACTS.healthThresholdsGet.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await queueHealth.ensureReady();\n const stored = await queueHealth.getConfig(resolved.orgId, resolved.factoryProjectId);\n // Validate at the read choke point: `getConfig` round-trips a stored\n // JSONB row, and only `saveConfig` validates on write — a corrupted or\n // hand-edited row (empty / non-ascending) would otherwise flow to the\n // chart and invert bucket colors. Fall back to the default on invalid.\n return c.json({ thresholds: thresholdsOrDefault(stored) });\n },\n }),\n\n // ── Bounded durable rule-decision status ────────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.decisionList.path, {\n method: FACTORY_ROUTE_CONTRACTS.decisionList.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n\n const query = FACTORY_ROUTE_CONTRACTS.decisionList.querySchema.safeParse({\n statuses: context.req.query('statuses'),\n before: context.req.query('before'),\n limit: context.req.query('limit'),\n });\n if (!query.success) {\n const field = query.error.issues[0]?.path[0];\n return c.json({ error: field === 'before' ? 'invalid_cursor' : 'invalid_decision_query' }, 400);\n }\n await workItems.ensureReady();\n const page = await workItems.listDeferredDecisionPage({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n statuses: query.data.statuses,\n before: query.data.before,\n limit: query.data.limit,\n });\n const last = page.decisions.at(-1);\n return c.json({\n decisions: page.decisions.map(decision => decisionSummary(this.#boards, decision)),\n ...(page.hasMore && last ? { nextCursor: encodeDecisionCursor(last) } : {}),\n });\n },\n }),\n\n ...buildAttentionRoutes({\n workItems,\n comments: this.deps.comments,\n liveSessions,\n resolveProject: context => this.#resolveProject(loose(context)),\n }),\n\n ...buildSupervisorRoutes({\n workItems,\n boards: this.#boards,\n resolveProject: context => this.#resolveProject(loose(context)),\n }),\n\n this.#proposalRoute({ verb: 'approve', settle: workItems.approveDeferredDecision.bind(workItems) }),\n this.#proposalRoute({ verb: 'dismiss', settle: workItems.dismissDeferredDecision.bind(workItems) }),\n\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.decisionRetry.path, {\n method: FACTORY_ROUTE_CONTRACTS.decisionRetry.method,\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const parsedPath = FACTORY_ROUTE_CONTRACTS.decisionRetry.pathSchema.safeParse({\n id: resolved.factoryProjectId,\n decisionId: context.req.param('decisionId'),\n });\n if (!parsedPath.success) return c.json({ error: 'invalid_decision_id' }, 422);\n const { decisionId } = parsedPath.data;\n await workItems.ensureReady();\n const current = await workItems.getDeferredDecision(resolved.orgId, resolved.factoryProjectId, decisionId);\n if (\n !current ||\n current.status !== 'failed' ||\n !factoryDispatchFailureMetadata(current.failureCode).canRetry\n ) {\n return c.json({ error: 'decision_not_retryable' }, 409);\n }\n const decision = await workItems.retryDeferredDecision(\n resolved.orgId,\n resolved.factoryProjectId,\n decisionId,\n new Date(),\n );\n if (!decision) return c.json({ error: 'decision_not_retryable' }, 409);\n return c.json({ decision: decisionSummary(this.#boards, decision) });\n },\n }),\n\n // ── Create (upsert on sourceKey) a work item ─────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemCreate.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemCreate.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const input = parseCreateWorkItem(body);\n if (!input) return c.json({ error: 'invalid_work_item' }, 400);\n const boardId = input.board ?? (input.externalSource?.type === 'pull-request' ? 'review' : 'work');\n const board = this.#boards.get(boardId);\n if (!board) return c.json({ error: 'invalid_board', message: `Board '${boardId}' is not installed.` }, 422);\n const initialStages = input.stages ?? [board.initialPhase];\n if (initialStages.length !== 1 || initialStages[0] !== board.initialPhase) {\n return c.json(\n {\n error: 'governed_transition_required',\n message: `New work items must enter through the '${board.initialPhase}' phase of board '${boardId}'.`,\n },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const result = await workItems.upsert({\n orgId: resolved.orgId,\n userId: resolved.userId,\n factoryProjectId: resolved.factoryProjectId,\n input: { ...input, board: boardId, stages: initialStages },\n reuseMode: 'non-stage',\n });\n let item = result.item;\n if (result.created) {\n if (!transitionService) {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ error: 'factory_transitions_unavailable' }, 503);\n }\n const entered = await transitionService.transition({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId: item.id,\n board: boardId,\n stage: board.initialPhase,\n expectedRevision: item.revision,\n actor: { type: 'human', id: resolved.userId },\n ...auditRequestOrigin(loose(c)),\n ingress: { type: 'human', identity: `work-item:${item.id}:initial-entry` },\n cause: 'work_item_created',\n initialEntry: true,\n });\n if (entered.status === 'rejected') {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ status: 'rejected', code: entered.code, reason: entered.reason }, 422);\n }\n item = (await workItems.getForProject(resolved.orgId, resolved.factoryProjectId, item.id)) ?? item;\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.created',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { externalSource: item.externalSource, stages: item.stages },\n },\n });\n } else {\n // Source-key reuse: the POST updated an existing card, not created one.\n const { stages: _stages, sessions: _sessions, ...boundedPatch } = input;\n await this.#auditWorkItemPatch({\n context: loose(c),\n item,\n patch: boundedPatch as unknown as Record<string, unknown>,\n });\n }\n return c.json({ workItem: toWireWorkItem(item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Authoritative stage transition ──────────────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemTransition.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemTransition.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const context = loose(c);\n const parsedPath = FACTORY_ROUTE_CONTRACTS.workItemTransition.pathSchema.safeParse({\n id: resolved.factoryProjectId,\n workItemId: context.req.param('workItemId'),\n });\n if (!parsedPath.success) return c.json({ error: 'Work item not found' }, 404);\n const { workItemId } = parsedPath.data;\n const parsed = parseTransitionBody(await readJson(context));\n if (!parsed) return c.json({ error: 'invalid_transition_request' }, 400);\n if (!transitionService) {\n return c.json({ error: 'factory_transition_unavailable' }, 503);\n }\n await workItems.ensureReady();\n const result = await transitionService.transition({\n ...parsed,\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId,\n actor: { type: 'human', id: resolved.userId },\n ...auditRequestOrigin(loose(c)),\n ingress: {\n ...parsed.ingress,\n identity: `human:${resolved.userId}:${parsed.ingress.identity}`,\n },\n });\n if (result.status === 'accepted') return c.json({ result });\n return c.json({ result }, result.code === 'stale' ? 409 : 422);\n },\n }),\n\n // ── Bind a Factory run before dispatching its kickoff ────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemStart.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemStart.method,\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n if (!startCoordinator) {\n return c.json({ error: 'factory_start_unavailable' }, 503);\n }\n const input = parseStartBody(await readJson(loose(c)), resolved, resolved.factoryProjectId);\n if (!input) return c.json({ error: 'invalid_factory_start' }, 400);\n input.requestContext = loose(c).get('requestContext');\n input.defaultModelId = resolved.defaultModelId ?? undefined;\n await workItems.ensureReady();\n let prepared: FactoryStartPreparedResult;\n try {\n prepared = await startCoordinator.prepare(input);\n } catch (error) {\n if (error instanceof FactoryStartTransitionError) {\n return c.json({ result: error.result }, error.result.code === 'stale' ? 409 : 422);\n }\n throw error;\n }\n return c.json({ prepared }, 202);\n },\n }),\n\n // ── Patch non-stage metadata / sessions / title ──────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemUpdate.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemUpdate.method,\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const context = loose(c);\n const parsedPath = FACTORY_ROUTE_CONTRACTS.workItemUpdate.pathSchema.safeParse({\n id: context.req.param('id'),\n });\n if (!parsedPath.success) return c.json({ error: 'Work item not found' }, 404);\n const { id } = parsedPath.data;\n\n const body = await readJson(context);\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const patch = parseUpdateWorkItem(body);\n if (!patch) return c.json({ error: 'invalid_work_item_patch' }, 400);\n\n await workItems.ensureReady();\n const existing = await workItems.get({ orgId: tenant.orgId, id });\n if (!existing) return c.json({ error: 'Work item not found' }, 404);\n if (patch.board !== undefined) {\n const board = this.#boards.get(patch.board);\n const stage = patch.stages?.length === 1 ? patch.stages[0] : undefined;\n if (existing.board !== null) {\n return c.json({ error: 'board_already_assigned' }, 409);\n }\n if (!board) {\n return c.json({ error: 'board_not_installed' }, 400);\n }\n if (!stage || !Object.prototype.hasOwnProperty.call(board.phases, stage)) {\n return c.json({ error: 'invalid_board_migration_phase' }, 400);\n }\n } else if (patch.stages !== undefined) {\n return c.json(\n { error: 'governed_transition_required', message: 'Use the Factory transition endpoint to move stages.' },\n 409,\n );\n }\n\n try {\n const updated = await workItems.update({\n orgId: tenant.orgId,\n id,\n userId: tenant.userId,\n patch,\n ...(patch.board !== undefined ? { expectedRevision: existing.revision, expectedBoard: null } : {}),\n });\n if (!updated) return c.json({ error: 'Work item not found' }, 404);\n await this.#auditWorkItemPatch({\n context: loose(c),\n item: updated.item,\n patch: patch as Record<string, unknown>,\n });\n return c.json({ workItem: toWireWorkItem(updated.item) });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n if (error instanceof WorkItemUpdateConflictError) {\n return c.json({ error: error.reason === 'board' ? 'board_already_assigned' : error.code }, 409);\n }\n throw error;\n }\n },\n }),\n\n // ── Remove a work item ───────────────────────────────────────────────────\n registerApiRoute(FACTORY_ROUTE_CONTRACTS.workItemDelete.path, {\n method: FACTORY_ROUTE_CONTRACTS.workItemDelete.method,\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const context = loose(c);\n const parsedPath = FACTORY_ROUTE_CONTRACTS.workItemDelete.pathSchema.safeParse({\n id: context.req.param('id'),\n });\n if (!parsedPath.success) return c.json({ error: 'Work item not found' }, 404);\n const { id } = parsedPath.data;\n\n await workItems.ensureReady();\n const deleted = await workItems.delete({ orgId: tenant.orgId, id });\n if (!deleted) return c.json({ error: 'Work item not found' }, 404);\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.deleted',\n factoryProjectId: deleted.factoryProjectId,\n targets: [{ type: 'work_item', id: deleted.id, name: deleted.title }],\n },\n });\n return c.json({ ok: true });\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-errors.d.ts","sourceRoot":"","sources":["../../src/rules/dispatch-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,gCAAgC,EACjC,MAAM,uCAAuC,CAAC;AAE/C,UAAU,8BAA8B;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAwBD,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,0BAA0B;gBAAhC,IAAI,EAAE,0BAA0B,EACzC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY;CAKzB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAErF;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,gCAAgC,GAAG,IAAI,GAC5C,8BAA8B,CAEhC"}
1
+ {"version":3,"file":"dispatch-errors.d.ts","sourceRoot":"","sources":["../../src/rules/dispatch-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,gCAAgC,EACjC,MAAM,uCAAuC,CAAC;AAE/C,UAAU,8BAA8B;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AA0BD,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,0BAA0B;gBAAhC,IAAI,EAAE,0BAA0B,EACzC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY;CAKzB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAErF;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,gCAAgC,GAAG,IAAI,GAC5C,8BAA8B,CAEhC"}
@@ -20,6 +20,14 @@ const FAILURE_METADATA = {
20
20
  canRetry: true,
21
21
  label: "Factory message delivery failed"
22
22
  },
23
+ run_terminal_event_missing: {
24
+ canRetry: false,
25
+ label: "Agent run terminal event was not observed"
26
+ },
27
+ skill_delivery_ambiguous: {
28
+ canRetry: false,
29
+ label: "Factory skill delivery could not be confirmed"
30
+ },
23
31
  run_overdue: {
24
32
  canRetry: false,
25
33
  label: "Agent run is overdue"
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-errors.js","names":[],"sources":["../../src/rules/dispatch-errors.ts"],"sourcesContent":["import type {\n FactoryDispatchFailureCode,\n StoredFactoryDispatchFailureCode,\n} from '../storage/domains/work-items/base.js';\n\ninterface FactoryDispatchFailureMetadata {\n canRetry: boolean;\n label: string;\n}\n\nconst FAILURE_METADATA = {\n session_unavailable: { canRetry: true, label: 'Factory session unavailable' },\n source_control_missing: { canRetry: true, label: 'Source-control connection unavailable' },\n source_repository_missing: { canRetry: true, label: 'Source repository unavailable' },\n unsupported_provider_item: { canRetry: false, label: 'Unsupported provider work item' },\n notification_delivery_failed: { canRetry: true, label: 'Factory message delivery failed' },\n run_overdue: { canRetry: false, label: 'Agent run is overdue' },\n repository_git_missing: { canRetry: false, label: 'Git is unavailable in the workspace' },\n repository_egress_blocked: { canRetry: false, label: 'Repository network access is blocked' },\n repository_clone_failed: { canRetry: true, label: 'Repository clone failed' },\n repository_pull_failed: { canRetry: true, label: 'Repository update failed' },\n repository_push_failed: { canRetry: true, label: 'Repository push failed' },\n repository_commit_failed: { canRetry: true, label: 'Repository commit failed' },\n repository_cli_missing: { canRetry: false, label: 'GitHub CLI is unavailable in the workspace' },\n repository_pr_failed: { canRetry: true, label: 'Pull request creation failed' },\n run_configuration_invalid: { canRetry: false, label: 'Run configuration rejected by provider' },\n unknown: { canRetry: true, label: 'Factory automation failed' },\n // Retired: no path writes these any more, stored rows still read through here.\n plan_awaiting_approval: { canRetry: false, label: 'Plan waiting for review' },\n run_awaiting_input: { canRetry: false, label: 'Agent is waiting for an answer' },\n} satisfies Record<StoredFactoryDispatchFailureCode, FactoryDispatchFailureMetadata>;\n\nexport class FactoryDispatchError extends Error {\n constructor(\n readonly code: FactoryDispatchFailureCode,\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = 'FactoryDispatchError';\n }\n}\n\nexport function factoryDispatchFailureCode(error: unknown): FactoryDispatchFailureCode {\n return error instanceof FactoryDispatchError ? error.code : 'unknown';\n}\n\nexport function factoryDispatchFailureMetadata(\n code: StoredFactoryDispatchFailureCode | null,\n): FactoryDispatchFailureMetadata {\n return code === null ? FAILURE_METADATA.unknown : FAILURE_METADATA[code];\n}\n"],"mappings":";AAUA,MAAM,mBAAmB;CACvB,qBAAqB;EAAE,UAAU;EAAM,OAAO;CAA8B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAwC;CACzF,2BAA2B;EAAE,UAAU;EAAM,OAAO;CAAgC;CACpF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAiC;CACtF,8BAA8B;EAAE,UAAU;EAAM,OAAO;CAAkC;CACzF,aAAa;EAAE,UAAU;EAAO,OAAO;CAAuB;CAC9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAAsC;CACxF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAuC;CAC5F,yBAAyB;EAAE,UAAU;EAAM,OAAO;CAA0B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAyB;CAC1E,0BAA0B;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC9E,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA6C;CAC/F,sBAAsB;EAAE,UAAU;EAAM,OAAO;CAA+B;CAC9E,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAyC;CAC9F,SAAS;EAAE,UAAU;EAAM,OAAO;CAA4B;CAE9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA0B;CAC5E,oBAAoB;EAAE,UAAU;EAAO,OAAO;CAAiC;AACjF;AAEA,IAAa,uBAAb,cAA0C,MAAM;CAEnC;CADX,YACE,MACA,SACA,SACA;EACA,MAAM,SAAS,OAAO;EAJb,KAAA,OAAA;EAKT,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,2BAA2B,OAA4C;CACrF,OAAO,iBAAiB,uBAAuB,MAAM,OAAO;AAC9D;AAEA,SAAgB,+BACd,MACgC;CAChC,OAAO,SAAS,OAAO,iBAAiB,UAAU,iBAAiB;AACrE"}
1
+ {"version":3,"file":"dispatch-errors.js","names":[],"sources":["../../src/rules/dispatch-errors.ts"],"sourcesContent":["import type {\n FactoryDispatchFailureCode,\n StoredFactoryDispatchFailureCode,\n} from '../storage/domains/work-items/base.js';\n\ninterface FactoryDispatchFailureMetadata {\n canRetry: boolean;\n label: string;\n}\n\nconst FAILURE_METADATA = {\n session_unavailable: { canRetry: true, label: 'Factory session unavailable' },\n source_control_missing: { canRetry: true, label: 'Source-control connection unavailable' },\n source_repository_missing: { canRetry: true, label: 'Source repository unavailable' },\n unsupported_provider_item: { canRetry: false, label: 'Unsupported provider work item' },\n notification_delivery_failed: { canRetry: true, label: 'Factory message delivery failed' },\n run_terminal_event_missing: { canRetry: false, label: 'Agent run terminal event was not observed' },\n skill_delivery_ambiguous: { canRetry: false, label: 'Factory skill delivery could not be confirmed' },\n run_overdue: { canRetry: false, label: 'Agent run is overdue' },\n repository_git_missing: { canRetry: false, label: 'Git is unavailable in the workspace' },\n repository_egress_blocked: { canRetry: false, label: 'Repository network access is blocked' },\n repository_clone_failed: { canRetry: true, label: 'Repository clone failed' },\n repository_pull_failed: { canRetry: true, label: 'Repository update failed' },\n repository_push_failed: { canRetry: true, label: 'Repository push failed' },\n repository_commit_failed: { canRetry: true, label: 'Repository commit failed' },\n repository_cli_missing: { canRetry: false, label: 'GitHub CLI is unavailable in the workspace' },\n repository_pr_failed: { canRetry: true, label: 'Pull request creation failed' },\n run_configuration_invalid: { canRetry: false, label: 'Run configuration rejected by provider' },\n unknown: { canRetry: true, label: 'Factory automation failed' },\n // Retired: no path writes these any more, stored rows still read through here.\n plan_awaiting_approval: { canRetry: false, label: 'Plan waiting for review' },\n run_awaiting_input: { canRetry: false, label: 'Agent is waiting for an answer' },\n} satisfies Record<StoredFactoryDispatchFailureCode, FactoryDispatchFailureMetadata>;\n\nexport class FactoryDispatchError extends Error {\n constructor(\n readonly code: FactoryDispatchFailureCode,\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = 'FactoryDispatchError';\n }\n}\n\nexport function factoryDispatchFailureCode(error: unknown): FactoryDispatchFailureCode {\n return error instanceof FactoryDispatchError ? error.code : 'unknown';\n}\n\nexport function factoryDispatchFailureMetadata(\n code: StoredFactoryDispatchFailureCode | null,\n): FactoryDispatchFailureMetadata {\n return code === null ? FAILURE_METADATA.unknown : FAILURE_METADATA[code];\n}\n"],"mappings":";AAUA,MAAM,mBAAmB;CACvB,qBAAqB;EAAE,UAAU;EAAM,OAAO;CAA8B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAwC;CACzF,2BAA2B;EAAE,UAAU;EAAM,OAAO;CAAgC;CACpF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAiC;CACtF,8BAA8B;EAAE,UAAU;EAAM,OAAO;CAAkC;CACzF,4BAA4B;EAAE,UAAU;EAAO,OAAO;CAA4C;CAClG,0BAA0B;EAAE,UAAU;EAAO,OAAO;CAAgD;CACpG,aAAa;EAAE,UAAU;EAAO,OAAO;CAAuB;CAC9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAAsC;CACxF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAuC;CAC5F,yBAAyB;EAAE,UAAU;EAAM,OAAO;CAA0B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAyB;CAC1E,0BAA0B;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC9E,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA6C;CAC/F,sBAAsB;EAAE,UAAU;EAAM,OAAO;CAA+B;CAC9E,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAyC;CAC9F,SAAS;EAAE,UAAU;EAAM,OAAO;CAA4B;CAE9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA0B;CAC5E,oBAAoB;EAAE,UAAU;EAAO,OAAO;CAAiC;AACjF;AAEA,IAAa,uBAAb,cAA0C,MAAM;CAEnC;CADX,YACE,MACA,SACA,SACA;EACA,MAAM,SAAS,OAAO;EAJb,KAAA,OAAA;EAKT,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,2BAA2B,OAA4C;CACrF,OAAO,iBAAiB,uBAAuB,MAAM,OAAO;AAC9D;AAEA,SAAgB,+BACd,MACgC;CAChC,OAAO,SAAS,OAAO,iBAAiB,UAAU,iBAAiB;AACrE"}
@@ -85,6 +85,7 @@ export declare const FACTORY_DISPATCH_CONSTANTS: {
85
85
  readonly maxBackoffMs: 60000;
86
86
  readonly skillCompletionObservationTimeoutMs: number;
87
87
  readonly runRegistryHeartbeatMs: number;
88
+ readonly openRunStaleMs: 30000;
88
89
  readonly maxInFlight: 25;
89
90
  readonly stages: readonly ["intake", "triage", "planning", "execute", "review", "done", "canceled"];
90
91
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/rules/dispatcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/rules/dispatcher.ts"],"names":[],"mappings":"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"}