@mastra/factory 0.24.0-alpha.1 → 0.24.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 (389) hide show
  1. package/README.md +106 -4
  2. package/dist/auth.d.ts +14 -0
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +45 -9
  5. package/dist/auth.js.map +1 -1
  6. package/dist/boards/review.d.ts.map +1 -1
  7. package/dist/boards/review.js +21 -1
  8. package/dist/boards/review.js.map +1 -1
  9. package/dist/boards/work-transition-policy.d.ts.map +1 -1
  10. package/dist/boards/work-transition-policy.js +12 -1
  11. package/dist/boards/work-transition-policy.js.map +1 -1
  12. package/dist/boards/work.d.ts +14 -0
  13. package/dist/boards/work.d.ts.map +1 -1
  14. package/dist/boards/work.js +70 -7
  15. package/dist/boards/work.js.map +1 -1
  16. package/dist/capabilities/version-control.d.ts +26 -0
  17. package/dist/capabilities/version-control.d.ts.map +1 -1
  18. package/dist/factory.d.ts +8 -0
  19. package/dist/factory.d.ts.map +1 -1
  20. package/dist/factory.js +355 -27
  21. package/dist/factory.js.map +1 -1
  22. package/dist/integrations/base.d.ts +1 -1
  23. package/dist/integrations/base.d.ts.map +1 -1
  24. package/dist/integrations/github/default-rules.d.ts.map +1 -1
  25. package/dist/integrations/github/default-rules.js +1 -16
  26. package/dist/integrations/github/default-rules.js.map +1 -1
  27. package/dist/integrations/github/integration.d.ts.map +1 -1
  28. package/dist/integrations/github/integration.js +37 -1
  29. package/dist/integrations/github/integration.js.map +1 -1
  30. package/dist/integrations/github/routes.d.ts +1 -1
  31. package/dist/integrations/github/routes.d.ts.map +1 -1
  32. package/dist/integrations/github/routes.js +19 -11
  33. package/dist/integrations/github/routes.js.map +1 -1
  34. package/dist/integrations/github/rules.d.ts.map +1 -1
  35. package/dist/integrations/github/rules.js +76 -29
  36. package/dist/integrations/github/rules.js.map +1 -1
  37. package/dist/integrations/github/sandbox-release.d.ts +15 -3
  38. package/dist/integrations/github/sandbox-release.d.ts.map +1 -1
  39. package/dist/integrations/github/sandbox-release.js +20 -3
  40. package/dist/integrations/github/sandbox-release.js.map +1 -1
  41. package/dist/integrations/github/sandbox.d.ts +2 -3
  42. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  43. package/dist/integrations/github/sandbox.js +78 -7
  44. package/dist/integrations/github/sandbox.js.map +1 -1
  45. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
  46. package/dist/integrations/github/session-subscriptions.js +1 -2
  47. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  48. package/dist/integrations/github/subscriptions.d.ts +7 -4
  49. package/dist/integrations/github/subscriptions.d.ts.map +1 -1
  50. package/dist/integrations/github/subscriptions.js +5 -5
  51. package/dist/integrations/github/subscriptions.js.map +1 -1
  52. package/dist/integrations/github/webhook.d.ts +4 -2
  53. package/dist/integrations/github/webhook.d.ts.map +1 -1
  54. package/dist/integrations/github/webhook.js +59 -36
  55. package/dist/integrations/github/webhook.js.map +1 -1
  56. package/dist/integrations/gitlab/api.d.ts +16 -1
  57. package/dist/integrations/gitlab/api.d.ts.map +1 -1
  58. package/dist/integrations/gitlab/api.js +9 -0
  59. package/dist/integrations/gitlab/api.js.map +1 -1
  60. package/dist/integrations/gitlab/routes.d.ts.map +1 -1
  61. package/dist/integrations/gitlab/routes.js +10 -6
  62. package/dist/integrations/gitlab/routes.js.map +1 -1
  63. package/dist/integrations/gitlab/rules.d.ts.map +1 -1
  64. package/dist/integrations/gitlab/rules.js +28 -21
  65. package/dist/integrations/gitlab/rules.js.map +1 -1
  66. package/dist/integrations/gitlab/session-subscriptions.d.ts.map +1 -1
  67. package/dist/integrations/gitlab/session-subscriptions.js +1 -2
  68. package/dist/integrations/gitlab/session-subscriptions.js.map +1 -1
  69. package/dist/integrations/gitlab/subscriptions.d.ts +7 -4
  70. package/dist/integrations/gitlab/subscriptions.d.ts.map +1 -1
  71. package/dist/integrations/gitlab/subscriptions.js +5 -5
  72. package/dist/integrations/gitlab/subscriptions.js.map +1 -1
  73. package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
  74. package/dist/integrations/gitlab/version-control.js +37 -3
  75. package/dist/integrations/gitlab/version-control.js.map +1 -1
  76. package/dist/integrations/incidentio/intake.d.ts +1 -1
  77. package/dist/integrations/incidentio/intake.d.ts.map +1 -1
  78. package/dist/integrations/incidentio/intake.js.map +1 -1
  79. package/dist/integrations/linear/agent-tools.d.ts.map +1 -1
  80. package/dist/integrations/linear/agent-tools.js.map +1 -1
  81. package/dist/integrations/platform/connect/routes.d.ts +1 -1
  82. package/dist/integrations/platform/connect/routes.d.ts.map +1 -1
  83. package/dist/integrations/platform/connect/routes.js.map +1 -1
  84. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  85. package/dist/integrations/platform/github/integration.js +27 -1
  86. package/dist/integrations/platform/github/integration.js.map +1 -1
  87. package/dist/integrations/platform/incidentio/integration.d.ts +1 -1
  88. package/dist/integrations/platform/incidentio/integration.d.ts.map +1 -1
  89. package/dist/integrations/platform/incidentio/integration.js.map +1 -1
  90. package/dist/integrations/platform/jira/integration.d.ts +1 -1
  91. package/dist/integrations/platform/jira/integration.d.ts.map +1 -1
  92. package/dist/integrations/platform/jira/integration.js.map +1 -1
  93. package/dist/integrations/platform/linear/event-worker.d.ts +1 -1
  94. package/dist/integrations/platform/linear/event-worker.d.ts.map +1 -1
  95. package/dist/integrations/platform/linear/event-worker.js.map +1 -1
  96. package/dist/integrations/slack/integration.d.ts.map +1 -1
  97. package/dist/integrations/slack/integration.js +33 -6
  98. package/dist/integrations/slack/integration.js.map +1 -1
  99. package/dist/integrations/slack/slack.d.ts +16 -5
  100. package/dist/integrations/slack/slack.d.ts.map +1 -1
  101. package/dist/integrations/slack/slack.js +137 -64
  102. package/dist/integrations/slack/slack.js.map +1 -1
  103. package/dist/integrations/subscription-session.d.ts +14 -0
  104. package/dist/integrations/subscription-session.d.ts.map +1 -1
  105. package/dist/integrations/subscription-session.js +30 -16
  106. package/dist/integrations/subscription-session.js.map +1 -1
  107. package/dist/mcp/disconnect.d.ts +10 -0
  108. package/dist/mcp/disconnect.d.ts.map +1 -0
  109. package/dist/mcp/disconnect.js +44 -0
  110. package/dist/mcp/disconnect.js.map +1 -0
  111. package/dist/mcp/routes.d.ts +46 -0
  112. package/dist/mcp/routes.d.ts.map +1 -0
  113. package/dist/mcp/routes.js +243 -0
  114. package/dist/mcp/routes.js.map +1 -0
  115. package/dist/provider-display-name.d.ts +2 -0
  116. package/dist/provider-display-name.d.ts.map +1 -0
  117. package/dist/provider-display-name.js +16 -0
  118. package/dist/provider-display-name.js.map +1 -0
  119. package/dist/review-verdict.d.ts +11 -0
  120. package/dist/review-verdict.d.ts.map +1 -1
  121. package/dist/review-verdict.js +16 -1
  122. package/dist/review-verdict.js.map +1 -1
  123. package/dist/routes/attention-activity.d.ts.map +1 -1
  124. package/dist/routes/attention-activity.js +5 -2
  125. package/dist/routes/attention-activity.js.map +1 -1
  126. package/dist/routes/attention-providers.d.ts +0 -1
  127. package/dist/routes/attention-providers.d.ts.map +1 -1
  128. package/dist/routes/attention-providers.js +5 -6
  129. package/dist/routes/attention-providers.js.map +1 -1
  130. package/dist/routes/config.d.ts +44 -5
  131. package/dist/routes/config.d.ts.map +1 -1
  132. package/dist/routes/config.js +181 -58
  133. package/dist/routes/config.js.map +1 -1
  134. package/dist/routes/contracts.d.ts +4 -0
  135. package/dist/routes/contracts.d.ts.map +1 -1
  136. package/dist/routes/contracts.js +3 -1
  137. package/dist/routes/contracts.js.map +1 -1
  138. package/dist/routes/custom-provider-source.d.ts +8 -0
  139. package/dist/routes/custom-provider-source.d.ts.map +1 -1
  140. package/dist/routes/custom-provider-source.js +22 -1
  141. package/dist/routes/custom-provider-source.js.map +1 -1
  142. package/dist/routes/oauth.js +1 -1
  143. package/dist/routes/oauth.js.map +1 -1
  144. package/dist/routes/projects.d.ts +1 -1
  145. package/dist/routes/projects.d.ts.map +1 -1
  146. package/dist/routes/projects.js +1 -1
  147. package/dist/routes/projects.js.map +1 -1
  148. package/dist/routes/provider-credentials.d.ts +7 -2
  149. package/dist/routes/provider-credentials.d.ts.map +1 -1
  150. package/dist/routes/provider-credentials.js +30 -8
  151. package/dist/routes/provider-credentials.js.map +1 -1
  152. package/dist/routes/skills.d.ts +2 -4
  153. package/dist/routes/skills.d.ts.map +1 -1
  154. package/dist/routes/skills.js +19 -65
  155. package/dist/routes/skills.js.map +1 -1
  156. package/dist/routes/source-control-sessions.d.ts +9 -1
  157. package/dist/routes/source-control-sessions.d.ts.map +1 -1
  158. package/dist/routes/source-control-sessions.js +131 -7
  159. package/dist/routes/source-control-sessions.js.map +1 -1
  160. package/dist/routes/surface.d.ts +3 -2
  161. package/dist/routes/surface.d.ts.map +1 -1
  162. package/dist/routes/surface.js +7 -3
  163. package/dist/routes/surface.js.map +1 -1
  164. package/dist/routes/work-items.d.ts.map +1 -1
  165. package/dist/routes/work-items.js +60 -120
  166. package/dist/routes/work-items.js.map +1 -1
  167. package/dist/rules/binding-context.js +7 -7
  168. package/dist/rules/binding-context.js.map +1 -1
  169. package/dist/rules/dispatch-errors.d.ts.map +1 -1
  170. package/dist/rules/dispatch-errors.js +12 -0
  171. package/dist/rules/dispatch-errors.js.map +1 -1
  172. package/dist/rules/dispatcher.d.ts +8 -1
  173. package/dist/rules/dispatcher.d.ts.map +1 -1
  174. package/dist/rules/dispatcher.js +117 -12
  175. package/dist/rules/dispatcher.js.map +1 -1
  176. package/dist/rules/processor.d.ts.map +1 -1
  177. package/dist/rules/processor.js +2 -1
  178. package/dist/rules/processor.js.map +1 -1
  179. package/dist/rules/start-coordinator.d.ts +4 -0
  180. package/dist/rules/start-coordinator.d.ts.map +1 -1
  181. package/dist/rules/start-coordinator.js +36 -4
  182. package/dist/rules/start-coordinator.js.map +1 -1
  183. package/dist/rules/tools.d.ts.map +1 -1
  184. package/dist/rules/tools.js +82 -3
  185. package/dist/rules/tools.js.map +1 -1
  186. package/dist/rules/transition-service.d.ts +17 -0
  187. package/dist/rules/transition-service.d.ts.map +1 -1
  188. package/dist/rules/transition-service.js +25 -0
  189. package/dist/rules/transition-service.js.map +1 -1
  190. package/dist/rules/types.d.ts +2 -4
  191. package/dist/rules/types.d.ts.map +1 -1
  192. package/dist/rules/types.js +1 -4
  193. package/dist/rules/types.js.map +1 -1
  194. package/dist/sandbox/local-factory-sandbox.d.ts.map +1 -1
  195. package/dist/sandbox/local-factory-sandbox.js +1 -0
  196. package/dist/sandbox/local-factory-sandbox.js.map +1 -1
  197. package/dist/sandbox/session-retirement.d.ts +27 -3
  198. package/dist/sandbox/session-retirement.d.ts.map +1 -1
  199. package/dist/sandbox/session-retirement.js +158 -20
  200. package/dist/sandbox/session-retirement.js.map +1 -1
  201. package/dist/secret-encryption.d.ts.map +1 -1
  202. package/dist/secret-encryption.js +65 -25
  203. package/dist/secret-encryption.js.map +1 -1
  204. package/dist/session/channel-reply-processor.d.ts +36 -0
  205. package/dist/session/channel-reply-processor.d.ts.map +1 -0
  206. package/dist/session/channel-reply-processor.js +46 -0
  207. package/dist/session/channel-reply-processor.js.map +1 -0
  208. package/dist/session/channel-session-link-processor.d.ts +39 -0
  209. package/dist/session/channel-session-link-processor.d.ts.map +1 -0
  210. package/dist/session/channel-session-link-processor.js +100 -0
  211. package/dist/session/channel-session-link-processor.js.map +1 -0
  212. package/dist/session/credential-policy.d.ts +1 -1
  213. package/dist/session/credential-policy.d.ts.map +1 -1
  214. package/dist/session/credential-policy.js +7 -6
  215. package/dist/session/credential-policy.js.map +1 -1
  216. package/dist/session/default-model-hydration.d.ts +1 -0
  217. package/dist/session/default-model-hydration.d.ts.map +1 -1
  218. package/dist/session/default-model-hydration.js +3 -2
  219. package/dist/session/default-model-hydration.js.map +1 -1
  220. package/dist/session/environment-state-processor.js +1 -1
  221. package/dist/session/environment-state-processor.js.map +1 -1
  222. package/dist/session/factory-session.d.ts +19 -1
  223. package/dist/session/factory-session.d.ts.map +1 -1
  224. package/dist/session/factory-session.js +5 -2
  225. package/dist/session/factory-session.js.map +1 -1
  226. package/dist/session/filesystem-capture.d.ts +3 -3
  227. package/dist/session/filesystem-capture.d.ts.map +1 -1
  228. package/dist/session/filesystem-capture.js +16 -17
  229. package/dist/session/filesystem-capture.js.map +1 -1
  230. package/dist/session/first-exec-capture.d.ts +1 -1
  231. package/dist/session/first-exec-capture.d.ts.map +1 -1
  232. package/dist/session/first-exec-capture.js +1 -1
  233. package/dist/session/first-exec-capture.js.map +1 -1
  234. package/dist/session/first-message-capture.d.ts +1 -1
  235. package/dist/session/first-message-capture.d.ts.map +1 -1
  236. package/dist/session/first-message-capture.js +1 -1
  237. package/dist/session/first-message-capture.js.map +1 -1
  238. package/dist/session/live-sessions.d.ts +1 -1
  239. package/dist/session/live-sessions.js +1 -1
  240. package/dist/session/live-sessions.js.map +1 -1
  241. package/dist/session/memory-settings-hydration.d.ts +1 -1
  242. package/dist/session/memory-settings-hydration.d.ts.map +1 -1
  243. package/dist/session/memory-settings-hydration.js +1 -1
  244. package/dist/session/memory-settings-hydration.js.map +1 -1
  245. package/dist/session/reply-credential-processor.d.ts +15 -0
  246. package/dist/session/reply-credential-processor.d.ts.map +1 -0
  247. package/dist/session/reply-credential-processor.js +38 -0
  248. package/dist/session/reply-credential-processor.js.map +1 -0
  249. package/dist/session/resource-migration.d.ts +87 -0
  250. package/dist/session/resource-migration.d.ts.map +1 -0
  251. package/dist/session/resource-migration.js +163 -0
  252. package/dist/session/resource-migration.js.map +1 -0
  253. package/dist/session/run-audit.d.ts +24 -0
  254. package/dist/session/run-audit.d.ts.map +1 -1
  255. package/dist/session/run-audit.js +93 -7
  256. package/dist/session/run-audit.js.map +1 -1
  257. package/dist/session/session-threads.d.ts +49 -0
  258. package/dist/session/session-threads.d.ts.map +1 -0
  259. package/dist/session/session-threads.js +70 -0
  260. package/dist/session/session-threads.js.map +1 -0
  261. package/dist/session/source-control-tools.d.ts +19 -1
  262. package/dist/session/source-control-tools.d.ts.map +1 -1
  263. package/dist/session/source-control-tools.js +78 -11
  264. package/dist/session/source-control-tools.js.map +1 -1
  265. package/dist/session/thinking-default.d.ts.map +1 -1
  266. package/dist/session/thinking-default.js +3 -4
  267. package/dist/session/thinking-default.js.map +1 -1
  268. package/dist/session/thread-session-stamp.d.ts +21 -0
  269. package/dist/session/thread-session-stamp.d.ts.map +1 -0
  270. package/dist/session/thread-session-stamp.js +20 -0
  271. package/dist/session/thread-session-stamp.js.map +1 -0
  272. package/dist/session/thread-title-mirror.d.ts +1 -1
  273. package/dist/session/thread-title-mirror.d.ts.map +1 -1
  274. package/dist/session/thread-title-mirror.js +1 -1
  275. package/dist/session/thread-title-mirror.js.map +1 -1
  276. package/dist/session/work-item-repository.d.ts +1 -1
  277. package/dist/session/work-item-repository.d.ts.map +1 -1
  278. package/dist/session/work-item-repository.js.map +1 -1
  279. package/dist/skills/service.d.ts +6 -8
  280. package/dist/skills/service.d.ts.map +1 -1
  281. package/dist/skills/service.js +3 -3
  282. package/dist/skills/service.js.map +1 -1
  283. package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -1
  284. package/dist/storage/domains/audit/agent-audit.js +2 -2
  285. package/dist/storage/domains/audit/agent-audit.js.map +1 -1
  286. package/dist/storage/domains/audit/domain.js +1 -1
  287. package/dist/storage/domains/filesystem/base.d.ts +4 -0
  288. package/dist/storage/domains/filesystem/base.d.ts.map +1 -1
  289. package/dist/storage/domains/filesystem/base.js +5 -0
  290. package/dist/storage/domains/filesystem/base.js.map +1 -1
  291. package/dist/storage/domains/integrations/base.d.ts +8 -0
  292. package/dist/storage/domains/integrations/base.d.ts.map +1 -1
  293. package/dist/storage/domains/integrations/base.js +7 -0
  294. package/dist/storage/domains/integrations/base.js.map +1 -1
  295. package/dist/storage/domains/projects/base.d.ts +6 -0
  296. package/dist/storage/domains/projects/base.d.ts.map +1 -1
  297. package/dist/storage/domains/projects/base.js +12 -0
  298. package/dist/storage/domains/projects/base.js.map +1 -1
  299. package/dist/storage/domains/source-control/base.d.ts +28 -0
  300. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  301. package/dist/storage/domains/source-control/base.js +48 -0
  302. package/dist/storage/domains/source-control/base.js.map +1 -1
  303. package/dist/storage/domains/source-control/inmemory.d.ts +8 -0
  304. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  305. package/dist/storage/domains/source-control/inmemory.js +13 -1
  306. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  307. package/dist/storage/domains/work-items/base.d.ts +79 -7
  308. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  309. package/dist/storage/domains/work-items/base.js +172 -30
  310. package/dist/storage/domains/work-items/base.js.map +1 -1
  311. package/dist/timing.d.ts +23 -0
  312. package/dist/timing.d.ts.map +1 -1
  313. package/dist/timing.js +85 -6
  314. package/dist/timing.js.map +1 -1
  315. package/dist/tools/annotations.d.ts +7 -0
  316. package/dist/tools/annotations.d.ts.map +1 -0
  317. package/dist/tools/annotations.js +102 -0
  318. package/dist/tools/annotations.js.map +1 -0
  319. package/dist/tools/approval-tools.d.ts +15 -0
  320. package/dist/tools/approval-tools.d.ts.map +1 -0
  321. package/dist/tools/approval-tools.js +79 -0
  322. package/dist/tools/approval-tools.js.map +1 -0
  323. package/dist/tools/deliver.d.ts +71 -0
  324. package/dist/tools/deliver.d.ts.map +1 -0
  325. package/dist/tools/deliver.js +129 -0
  326. package/dist/tools/deliver.js.map +1 -0
  327. package/dist/tools/index.d.ts +30 -0
  328. package/dist/tools/index.d.ts.map +1 -0
  329. package/dist/tools/index.js +36 -0
  330. package/dist/tools/index.js.map +1 -0
  331. package/dist/tools/messaging-tools.d.ts +28 -0
  332. package/dist/tools/messaging-tools.d.ts.map +1 -0
  333. package/dist/tools/messaging-tools.js +396 -0
  334. package/dist/tools/messaging-tools.js.map +1 -0
  335. package/dist/tools/permissions.d.ts +31 -0
  336. package/dist/tools/permissions.d.ts.map +1 -0
  337. package/dist/tools/permissions.js +48 -0
  338. package/dist/tools/permissions.js.map +1 -0
  339. package/dist/tools/read-tools.d.ts +30 -0
  340. package/dist/tools/read-tools.d.ts.map +1 -0
  341. package/dist/tools/read-tools.js +293 -0
  342. package/dist/tools/read-tools.js.map +1 -0
  343. package/dist/tools/reports.d.ts +174 -0
  344. package/dist/tools/reports.d.ts.map +1 -0
  345. package/dist/tools/reports.js +380 -0
  346. package/dist/tools/reports.js.map +1 -0
  347. package/dist/tools/run-watch.d.ts +46 -0
  348. package/dist/tools/run-watch.d.ts.map +1 -0
  349. package/dist/tools/run-watch.js +102 -0
  350. package/dist/tools/run-watch.js.map +1 -0
  351. package/dist/tools/scope.d.ts +54 -0
  352. package/dist/tools/scope.d.ts.map +1 -0
  353. package/dist/tools/scope.js +87 -0
  354. package/dist/tools/scope.js.map +1 -0
  355. package/dist/tools/session-tools.d.ts +43 -0
  356. package/dist/tools/session-tools.d.ts.map +1 -0
  357. package/dist/tools/session-tools.js +410 -0
  358. package/dist/tools/session-tools.js.map +1 -0
  359. package/dist/tools/sessions-state-processor.d.ts +41 -0
  360. package/dist/tools/sessions-state-processor.d.ts.map +1 -0
  361. package/dist/tools/sessions-state-processor.js +190 -0
  362. package/dist/tools/sessions-state-processor.js.map +1 -0
  363. package/dist/tools/side-sessions.d.ts +53 -0
  364. package/dist/tools/side-sessions.d.ts.map +1 -0
  365. package/dist/tools/side-sessions.js +83 -0
  366. package/dist/tools/side-sessions.js.map +1 -0
  367. package/dist/tools/work-item-tools.d.ts +28 -0
  368. package/dist/tools/work-item-tools.d.ts.map +1 -0
  369. package/dist/tools/work-item-tools.js +342 -0
  370. package/dist/tools/work-item-tools.js.map +1 -0
  371. package/dist/work-items/create-work-item.d.ts +55 -0
  372. package/dist/work-items/create-work-item.d.ts.map +1 -0
  373. package/dist/work-items/create-work-item.js +101 -0
  374. package/dist/work-items/create-work-item.js.map +1 -0
  375. package/dist/work-items/decision-actions.d.ts +42 -0
  376. package/dist/work-items/decision-actions.d.ts.map +1 -0
  377. package/dist/work-items/decision-actions.js +70 -0
  378. package/dist/work-items/decision-actions.js.map +1 -0
  379. package/dist/workspace.d.ts +1 -1
  380. package/dist/workspace.d.ts.map +1 -1
  381. package/dist/workspace.js +15 -7
  382. package/dist/workspace.js.map +1 -1
  383. package/factory-skills/factory-gitlab-rereview/SKILL.md +1 -1
  384. package/factory-skills/factory-gitlab-review/SKILL.md +1 -1
  385. package/factory-skills/factory-plan/SKILL.md +4 -4
  386. package/factory-skills/factory-rereview/SKILL.md +3 -1
  387. package/factory-skills/factory-review/SKILL.md +3 -1
  388. package/factory-skills/factory-self-review/SKILL.md +46 -0
  389. package/package.json +14 -14
@@ -1 +1 @@
1
- {"version":3,"file":"run-audit.js","names":[],"sources":["../../src/session/run-audit.ts"],"sourcesContent":["import type { AgentControllerEvent } from '@mastra/core/agent-controller';\nimport { z } from 'zod';\n\nimport type { AuditActorType } from '../storage/domains/audit/base.js';\nimport type { AuditRecorder } from '../storage/domains/audit/domain.js';\n\nexport const FACTORY_OPEN_RUNS_SETTING = 'factoryOpenRuns';\n\nconst factoryOpenRunSchema = z.object({\n kickoffId: z.string(),\n bindingId: z.string(),\n role: z.string(),\n startedBy: z.string(),\n orgId: z.string(),\n factoryProjectId: z.string(),\n workItemId: z.string(),\n workItemName: z.string().optional(),\n sessionId: z.string(),\n threadId: z.string(),\n branch: z.string(),\n /**\n * Which dispatcher process is watching this run, and when it last said so\n * (epoch ms). The ledger is a thread setting shared by every replica, so a\n * remote reader needs these to tell a run that is live elsewhere from one\n * that died with its process. Absent on entries written before ownership\n * was recorded; those read as stale.\n */\n ownerId: z.string().optional(),\n heartbeatAt: z.number().optional(),\n});\n\nexport type FactoryOpenRun = z.infer<typeof factoryOpenRunSchema>;\n\n/** A heartbeat older than this means the owner is gone; nothing renews it once the run's dispatcher dies. */\nexport const FACTORY_OPEN_RUN_STALE_MS = 30_000;\n\nexport function isOpenRunLiveElsewhere(run: FactoryOpenRun, ownerId: string, now = Date.now()): boolean {\n return (\n run.ownerId !== undefined &&\n run.ownerId !== ownerId &&\n run.heartbeatAt !== undefined &&\n now - run.heartbeatAt < FACTORY_OPEN_RUN_STALE_MS\n );\n}\n\nexport interface RunEndCaptureSession {\n readonly thread: {\n getSetting(args: { key: string }): Promise<unknown>;\n setSetting(args: { key: string; value: unknown }): Promise<void>;\n };\n subscribe(listener: (event: AgentControllerEvent) => void): () => void;\n}\n\ntype RunEndReason = Extract<AgentControllerEvent, { type: 'agent_end' }>['reason'];\nconst pendingWrites = new WeakMap<RunEndCaptureSession, Promise<void>>();\n\nfunction serializeRunAudit(session: RunEndCaptureSession, write: () => Promise<void>): Promise<void> {\n const pending = (pendingWrites.get(session) ?? Promise.resolve())\n .then(write)\n .catch(error => console.warn('[Factory run audit] Unable to record run lifecycle.', error));\n pendingWrites.set(session, pending);\n return pending;\n}\n\nexport async function listSessionOpenRuns(session: RunEndCaptureSession): Promise<FactoryOpenRun[]> {\n const stored = await session.thread.getSetting({ key: FACTORY_OPEN_RUNS_SETTING });\n return z.array(factoryOpenRunSchema).parse(stored ?? []);\n}\n\nexport async function waitForSessionRunAudit(session: RunEndCaptureSession): Promise<void> {\n await (pendingWrites.get(session) ?? Promise.resolve());\n}\n\nfunction runAuditInput(run: FactoryOpenRun) {\n // Ownership fields are dispatcher bookkeeping, not part of the run's audit record.\n const { orgId, factoryProjectId, workItemId, workItemName, ownerId, heartbeatAt, ...metadata } = run;\n void ownerId;\n void heartbeatAt;\n return {\n orgId,\n factoryProjectId,\n idempotencyKey: run.kickoffId,\n targets: [{ type: 'work_item', id: workItemId, ...(workItemName ? { name: workItemName } : {}) }],\n metadata,\n };\n}\n\nasync function recordRunEnds(\n session: RunEndCaptureSession,\n audit: AuditRecorder,\n reason: RunEndReason,\n kickoffId?: string,\n): Promise<void> {\n if (!reason || reason === 'suspended') return;\n const runs = await listSessionOpenRuns(session);\n if (runs.length === 0) return;\n const remaining = [];\n for (const run of runs) {\n if (kickoffId && run.kickoffId !== kickoffId) {\n remaining.push(run);\n continue;\n }\n const input = runAuditInput(run);\n const recorded = await audit.record({\n ...input,\n actorId: `agent:${run.threadId}`,\n actorType: 'agent',\n action: 'factory.run.ended',\n metadata: { ...input.metadata, reason },\n });\n if (!recorded) remaining.push(run);\n }\n await session.thread.setSetting({ key: FACTORY_OPEN_RUNS_SETTING, value: remaining });\n}\n\nexport function recordSessionRunStart(\n session: RunEndCaptureSession,\n {\n audit,\n run,\n actorType,\n observedEnd,\n }: {\n audit: AuditRecorder;\n run: FactoryOpenRun;\n actorType: AuditActorType;\n observedEnd: () => RunEndReason;\n },\n): Promise<void> {\n return serializeRunAudit(session, async () => {\n const runs = await listSessionOpenRuns(session);\n if (!runs.some(existing => existing.kickoffId === run.kickoffId)) {\n await session.thread.setSetting({ key: FACTORY_OPEN_RUNS_SETTING, value: [...runs, run] });\n }\n await audit.record({\n ...runAuditInput(run),\n actorId: run.startedBy,\n actorType,\n action: 'factory.run.started',\n });\n await recordRunEnds(session, audit, observedEnd(), run.kickoffId);\n });\n}\n\n/** Renew this process's claim on an open run so other replicas keep treating it as live. */\nexport function heartbeatSessionOpenRun(\n session: RunEndCaptureSession,\n kickoffId: string,\n at = Date.now(),\n): Promise<void> {\n return serializeRunAudit(session, async () => {\n const runs = await listSessionOpenRuns(session);\n if (!runs.some(run => run.kickoffId === kickoffId)) return;\n await session.thread.setSetting({\n key: FACTORY_OPEN_RUNS_SETTING,\n value: runs.map(run => (run.kickoffId === kickoffId ? { ...run, heartbeatAt: at } : run)),\n });\n });\n}\n\nexport function observeSessionRunEnd(session: RunEndCaptureSession, { audit }: { audit: AuditRecorder }): () => void {\n return session.subscribe(event => {\n if (event.type !== 'agent_end' || !event.reason || event.reason === 'suspended') return;\n void serializeRunAudit(session, () => recordRunEnds(session, audit, event.reason));\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-audit.js","names":[],"sources":["../../src/session/run-audit.ts"],"sourcesContent":["import type { AgentControllerEvent } from '@mastra/core/agent-controller';\nimport { z } from 'zod';\n\nimport type { AuditActorType } from '../storage/domains/audit/base.js';\nimport type { AuditRecorder } from '../storage/domains/audit/domain.js';\n\nexport const FACTORY_OPEN_RUNS_SETTING = 'factoryOpenRuns';\n\nconst factoryOpenRunSchema = z.object({\n kickoffId: z.string(),\n bindingId: z.string(),\n role: z.string(),\n startedBy: z.string(),\n orgId: z.string(),\n factoryProjectId: z.string(),\n workItemId: z.string(),\n workItemName: z.string().optional(),\n sessionId: z.string(),\n threadId: z.string(),\n branch: z.string(),\n /**\n * Which dispatcher process is watching this run, and when it last said so\n * (epoch ms). The ledger is a thread setting shared by every replica, so a\n * remote reader needs these to tell a run that is live elsewhere from one\n * that died with its process. Absent on entries written before ownership\n * was recorded; those read as stale.\n */\n ownerId: z.string().optional(),\n heartbeatAt: z.number().optional(),\n});\n\nexport type FactoryOpenRun = z.infer<typeof factoryOpenRunSchema>;\n\n/** A heartbeat older than this means the owner is gone; nothing renews it once the run's dispatcher dies. */\nexport const FACTORY_OPEN_RUN_STALE_MS = 30_000;\n\nexport function isOpenRunLiveElsewhere(run: FactoryOpenRun, ownerId: string, now = Date.now()): boolean {\n return (\n run.ownerId !== undefined &&\n run.ownerId !== ownerId &&\n run.heartbeatAt !== undefined &&\n now - run.heartbeatAt < FACTORY_OPEN_RUN_STALE_MS\n );\n}\n\nexport interface RunEndCaptureSession {\n readonly thread: {\n getSetting(args: { key: string }): Promise<unknown>;\n setSetting(args: { key: string; value: unknown }): Promise<void>;\n };\n subscribe(listener: (event: AgentControllerEvent) => void): () => void;\n}\n\ntype RunEndReason = Extract<AgentControllerEvent, { type: 'agent_end' }>['reason'];\ntype StepUsage = Extract<AgentControllerEvent, { type: 'usage_update' }>['usage'];\nconst pendingWrites = new WeakMap<RunEndCaptureSession, Promise<void>>();\n\n/**\n * JSON budget for the per-step entries on a run's audit record. Audit metadata\n * is capped at 4 KB as a whole and an oversized record loses all of it, so\n * later steps are dropped (and counted) instead; totals always cover every step.\n */\nexport const FACTORY_RUN_USAGE_STEPS_JSON_BUDGET = 2400;\n\nconst USAGE_FIELDS = [\n 'promptTokens',\n 'completionTokens',\n 'totalTokens',\n 'reasoningTokens',\n 'cachedInputTokens',\n 'cacheCreationInputTokens',\n 'cacheCreationInputTokens5m',\n 'cacheCreationInputTokens1h',\n] as const;\n\ntype UsageCounts = Partial<Record<(typeof USAGE_FIELDS)[number], number>>;\n\n/**\n * Token usage attached to a run's `factory.run.ended` audit record.\n * `unreported` means this process saw no usage for the run (it ran elsewhere,\n * the process restarted, or the model reported none). It is never zero spend.\n */\nexport type FactoryRunUsage =\n | {\n status: 'recorded';\n stepCount: number;\n totals: UsageCounts;\n steps: UsageCounts[];\n stepsTruncated?: number;\n /** Other runs that ended in the same agent turn; the turn's usage can't be split between them. */\n sharedWithKickoffIds?: string[];\n }\n | { status: 'unreported' };\n\nfunction usageCounts(usage: StepUsage): UsageCounts {\n const counts: UsageCounts = {};\n for (const field of USAGE_FIELDS) {\n const value = usage[field];\n if (typeof value === 'number') counts[field] = value;\n }\n return counts;\n}\n\nfunction runUsage(steps: UsageCounts[]): FactoryRunUsage {\n if (steps.length === 0) return { status: 'unreported' };\n const totals: UsageCounts = {};\n for (const step of steps) {\n for (const field of USAGE_FIELDS) {\n if (step[field] !== undefined) totals[field] = (totals[field] ?? 0) + step[field];\n }\n }\n const kept: UsageCounts[] = [];\n let length = 2;\n for (const step of steps) {\n length += JSON.stringify(step).length + 1;\n if (length > FACTORY_RUN_USAGE_STEPS_JSON_BUDGET) break;\n kept.push(step);\n }\n return {\n status: 'recorded',\n stepCount: steps.length,\n totals,\n steps: kept,\n ...(steps.length > kept.length ? { stepsTruncated: steps.length - kept.length } : {}),\n };\n}\n\ninterface EndedTurn {\n steps: UsageCounts[];\n claimed: boolean;\n}\n\ninterface SessionUsage {\n /** Steps of the turn in progress; a suspended turn keeps accumulating into its resume. */\n current: UsageCounts[];\n /** The most recently ended turn, which a run whose ledger entry lands after that end may still claim. */\n lastTurn?: EndedTurn;\n /** Usage of runs whose end record failed to persist, kept for the retry. */\n held: Map<string, FactoryRunUsage>;\n}\n\nconst sessionUsage = new WeakMap<RunEndCaptureSession, SessionUsage>();\n\nfunction usageFor(session: RunEndCaptureSession): SessionUsage {\n let usage = sessionUsage.get(session);\n if (!usage) {\n usage = { current: [], held: new Map() };\n sessionUsage.set(session, usage);\n }\n return usage;\n}\n\nfunction serializeRunAudit(session: RunEndCaptureSession, write: () => Promise<void>): Promise<void> {\n const pending = (pendingWrites.get(session) ?? Promise.resolve())\n .then(write)\n .catch(error => console.warn('[Factory run audit] Unable to record run lifecycle.', error));\n pendingWrites.set(session, pending);\n return pending;\n}\n\nexport async function listSessionOpenRuns(session: RunEndCaptureSession): Promise<FactoryOpenRun[]> {\n const stored = await session.thread.getSetting({ key: FACTORY_OPEN_RUNS_SETTING });\n return z.array(factoryOpenRunSchema).parse(stored ?? []);\n}\n\nexport async function waitForSessionRunAudit(session: RunEndCaptureSession): Promise<void> {\n await (pendingWrites.get(session) ?? Promise.resolve());\n}\n\nfunction runAuditInput(run: FactoryOpenRun) {\n // Ownership fields are dispatcher bookkeeping, not part of the run's audit record.\n const { orgId, factoryProjectId, workItemId, workItemName, ownerId, heartbeatAt, ...metadata } = run;\n void ownerId;\n void heartbeatAt;\n return {\n orgId,\n factoryProjectId,\n idempotencyKey: run.kickoffId,\n targets: [{ type: 'work_item', id: workItemId, ...(workItemName ? { name: workItemName } : {}) }],\n metadata,\n };\n}\n\nasync function recordRunEnds(\n session: RunEndCaptureSession,\n audit: AuditRecorder,\n reason: RunEndReason,\n kickoffId?: string,\n endedTurn?: EndedTurn,\n): Promise<void> {\n if (!reason || reason === 'suspended') return;\n const usage = usageFor(session);\n const runs = await listSessionOpenRuns(session);\n if (runs.length === 0) return;\n const ending = runs.filter(run => !kickoffId || run.kickoffId === kickoffId);\n // An end event bills the turn it closed. A run whose ledger entry lands after its turn ended\n // bills the latest ended turn, unless an open run already claimed it.\n const turn = endedTurn ?? usage.lastTurn;\n const steps = turn && !turn.claimed ? turn.steps : [];\n if (turn && ending.length > 0) turn.claimed = true;\n const turnUsage = runUsage(steps);\n const remaining = [];\n for (const run of runs) {\n if (!ending.includes(run)) {\n remaining.push(run);\n continue;\n }\n let runUsageRecord = usage.held.get(run.kickoffId);\n if (!runUsageRecord) {\n const shared = ending.filter(other => other !== run).map(other => other.kickoffId);\n runUsageRecord =\n turnUsage.status === 'recorded' && shared.length > 0\n ? { ...turnUsage, sharedWithKickoffIds: shared }\n : turnUsage;\n usage.held.set(run.kickoffId, runUsageRecord);\n }\n const input = runAuditInput(run);\n const recorded = await audit.record({\n ...input,\n actorId: `agent:${run.threadId}`,\n actorType: 'agent',\n action: 'factory.run.ended',\n metadata: { ...input.metadata, reason, usage: runUsageRecord },\n });\n if (recorded) {\n usage.held.delete(run.kickoffId);\n } else {\n console.warn(\n `[Factory run audit] Token usage for run ${run.kickoffId} (${run.role}) was not persisted; keeping it for the next attempt.`,\n runUsageRecord,\n );\n remaining.push(run);\n }\n }\n await session.thread.setSetting({ key: FACTORY_OPEN_RUNS_SETTING, value: remaining });\n}\n\nexport function recordSessionRunStart(\n session: RunEndCaptureSession,\n {\n audit,\n run,\n actorType,\n observedEnd,\n }: {\n audit: AuditRecorder;\n run: FactoryOpenRun;\n actorType: AuditActorType;\n observedEnd: () => RunEndReason;\n },\n): Promise<void> {\n return serializeRunAudit(session, async () => {\n const runs = await listSessionOpenRuns(session);\n if (!runs.some(existing => existing.kickoffId === run.kickoffId)) {\n await session.thread.setSetting({ key: FACTORY_OPEN_RUNS_SETTING, value: [...runs, run] });\n }\n await audit.record({\n ...runAuditInput(run),\n actorId: run.startedBy,\n actorType,\n action: 'factory.run.started',\n });\n await recordRunEnds(session, audit, observedEnd(), run.kickoffId);\n });\n}\n\n/** Renew this process's claim on an open run so other replicas keep treating it as live. */\nexport function heartbeatSessionOpenRun(\n session: RunEndCaptureSession,\n kickoffId: string,\n at = Date.now(),\n): Promise<void> {\n return serializeRunAudit(session, async () => {\n const runs = await listSessionOpenRuns(session);\n if (!runs.some(run => run.kickoffId === kickoffId)) return;\n await session.thread.setSetting({\n key: FACTORY_OPEN_RUNS_SETTING,\n value: runs.map(run => (run.kickoffId === kickoffId ? { ...run, heartbeatAt: at } : run)),\n });\n });\n}\n\nexport function observeSessionRunEnd(session: RunEndCaptureSession, { audit }: { audit: AuditRecorder }): () => void {\n const usage = usageFor(session);\n return session.subscribe(event => {\n if (event.type === 'usage_update') {\n usage.current.push(usageCounts(event.usage));\n return;\n }\n if (event.type !== 'agent_end' || !event.reason || event.reason === 'suspended') return;\n // Close the turn now so a following turn's steps never land in this run.\n const turn: EndedTurn = { steps: usage.current, claimed: false };\n usage.current = [];\n usage.lastTurn = turn;\n void serializeRunAudit(session, () => recordRunEnds(session, audit, event.reason, undefined, turn));\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { AgentController, AgentControllerThread } from '@mastra/core/agent-controller';
2
+ import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
3
+ /** The Factory session row fields that say which memory resource it uses. */
4
+ export interface FactorySessionOwnership {
5
+ sessionId: string;
6
+ userId: string;
7
+ orgId?: string;
8
+ factoryProjectId?: string | null;
9
+ branch?: string;
10
+ visibility?: string;
11
+ originSessionId?: string | null;
12
+ }
13
+ /** Run bindings: the server-side record that a session runs work for its Factory. */
14
+ export type SessionRunBindings = Pick<WorkItemsStorage, 'hasRunBindingForSession'>;
15
+ type ThreadLookup = Pick<AgentController<any>, 'queryThreadById'>;
16
+ /**
17
+ * The one memory resource a Factory session runs under. A Slack session uses
18
+ * its Factory's, or its sender's for a DM; a side session uses its Factory's,
19
+ * or its owner's when private; any other session uses its owner's. A session's own thread can say otherwise
20
+ * only within what the server recorded for it: its own id (created before
21
+ * resources were shared, or a run kept on its own resource), and the Factory's
22
+ * only for a session with a run binding. A client can create a thread under the
23
+ * session's id, so the thread alone never makes a session the Factory's.
24
+ */
25
+ export declare function sessionMemoryResourceId(controller: ThreadLookup | undefined, session: FactorySessionOwnership, runs: SessionRunBindings | undefined): Promise<string>;
26
+ export declare function isRunBound(session: FactorySessionOwnership, runs: SessionRunBindings | undefined): Promise<boolean>;
27
+ /** {@link sessionMemoryResourceId} for a caller that already loaded the session's own thread. */
28
+ export declare function memoryResourceOf(session: FactorySessionOwnership, own: {
29
+ resourceId?: string | null;
30
+ } | null | undefined, runBound: boolean): string;
31
+ /**
32
+ * Whether a `factorySessionId` stamp naming this session counts on a thread
33
+ * under `resourceId`. Any org member can write a stamped thread under the
34
+ * Factory's resource, so a private session's stamp never counts there: only
35
+ * its own thread (`thread.id === sessionId`) does.
36
+ */
37
+ export declare function sessionStampCounts(session: FactorySessionOwnership, resourceId: string | null | undefined): boolean;
38
+ /**
39
+ * The threads of one Factory session. Sessions share their Factory's or user's
40
+ * resource, so listing by resource would return every session's threads. A
41
+ * session's own thread carries its id, threads it opens are stamped with
42
+ * `factorySessionId`, and a session created before resources were shared keeps
43
+ * its threads under its own id as the resource. Thread ids and stamps are
44
+ * client-writable, so the own and stamped threads only count under the
45
+ * session's memory resource.
46
+ */
47
+ export declare function listFactorySessionThreads(controller: Pick<AgentController<any>, 'queryThreads' | 'queryThreadById'>, session: FactorySessionOwnership, runs: SessionRunBindings | undefined): Promise<AgentControllerThread[]>;
48
+ export {};
49
+ //# sourceMappingURL=session-threads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-threads.d.ts","sourceRoot":"","sources":["../../src/session/session-threads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAE5F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,6EAA6E;AAC7E,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,qFAAqF;AACrF,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;AAEnF,KAAK,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAElE;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,YAAY,GAAG,SAAS,EACpC,OAAO,EAAE,uBAAuB,EAChC,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,kBAAkB,GAAG,SAAS,oBAOtG;AAED,iGAAiG;AACjG,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,uBAAuB,EAChC,GAAG,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EACtD,QAAQ,EAAE,OAAO,UAgBlB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEnH;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,cAAc,GAAG,iBAAiB,CAAC,EAC1E,OAAO,EAAE,uBAAuB,EAChC,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAgBlC"}
@@ -0,0 +1,70 @@
1
+ //#region src/session/session-threads.ts
2
+ /**
3
+ * The one memory resource a Factory session runs under. A Slack session uses
4
+ * its Factory's, or its sender's for a DM; a side session uses its Factory's,
5
+ * or its owner's when private; any other session uses its owner's. A session's own thread can say otherwise
6
+ * only within what the server recorded for it: its own id (created before
7
+ * resources were shared, or a run kept on its own resource), and the Factory's
8
+ * only for a session with a run binding. A client can create a thread under the
9
+ * session's id, so the thread alone never makes a session the Factory's.
10
+ */
11
+ async function sessionMemoryResourceId(controller, session, runs) {
12
+ const [own, runBound] = await Promise.all([controller?.queryThreadById({ threadId: session.sessionId }), isRunBound(session, runs)]);
13
+ return memoryResourceOf(session, own, runBound);
14
+ }
15
+ async function isRunBound(session, runs) {
16
+ if (!runs || !session.orgId || !session.factoryProjectId) return false;
17
+ return runs.hasRunBindingForSession({
18
+ orgId: session.orgId,
19
+ factoryProjectId: session.factoryProjectId,
20
+ sessionId: session.sessionId
21
+ });
22
+ }
23
+ /** {@link sessionMemoryResourceId} for a caller that already loaded the session's own thread. */
24
+ function memoryResourceOf(session, own, runBound) {
25
+ const factoryProjectId = session.factoryProjectId ?? void 0;
26
+ const shared = (session.branch?.startsWith("slack/") ?? false) || session.originSessionId ? session.visibility === "private" ? session.userId : factoryProjectId : void 0;
27
+ const allowed = shared ? [session.sessionId, shared] : [
28
+ session.sessionId,
29
+ session.userId,
30
+ ...runBound && factoryProjectId ? [factoryProjectId] : []
31
+ ];
32
+ if (own?.resourceId && allowed.includes(own.resourceId)) return own.resourceId;
33
+ return shared ?? session.userId;
34
+ }
35
+ /**
36
+ * Whether a `factorySessionId` stamp naming this session counts on a thread
37
+ * under `resourceId`. Any org member can write a stamped thread under the
38
+ * Factory's resource, so a private session's stamp never counts there: only
39
+ * its own thread (`thread.id === sessionId`) does.
40
+ */
41
+ function sessionStampCounts(session, resourceId) {
42
+ return !(session.visibility === "private" && !!session.factoryProjectId && resourceId === session.factoryProjectId);
43
+ }
44
+ /**
45
+ * The threads of one Factory session. Sessions share their Factory's or user's
46
+ * resource, so listing by resource would return every session's threads. A
47
+ * session's own thread carries its id, threads it opens are stamped with
48
+ * `factorySessionId`, and a session created before resources were shared keeps
49
+ * its threads under its own id as the resource. Thread ids and stamps are
50
+ * client-writable, so the own and stamped threads only count under the
51
+ * session's memory resource.
52
+ */
53
+ async function listFactorySessionThreads(controller, session, runs) {
54
+ const { sessionId } = session;
55
+ const [own, runBound, stamped, legacy] = await Promise.all([
56
+ controller.queryThreadById({ threadId: sessionId }),
57
+ isRunBound(session, runs),
58
+ controller.queryThreads({ metadata: { factorySessionId: sessionId } }),
59
+ controller.queryThreads({ resourceId: sessionId })
60
+ ]);
61
+ const resourceId = memoryResourceOf(session, own, runBound);
62
+ const threads = /* @__PURE__ */ new Map();
63
+ const owned = [...own?.resourceId === resourceId ? [own] : [], ...sessionStampCounts(session, resourceId) ? stamped.filter((thread) => thread.resourceId === resourceId) : []];
64
+ for (const thread of [...owned, ...legacy]) threads.set(thread.id, thread);
65
+ return [...threads.values()];
66
+ }
67
+ //#endregion
68
+ export { isRunBound, listFactorySessionThreads, memoryResourceOf, sessionMemoryResourceId, sessionStampCounts };
69
+
70
+ //# sourceMappingURL=session-threads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-threads.js","names":[],"sources":["../../src/session/session-threads.ts"],"sourcesContent":["import type { AgentController, AgentControllerThread } from '@mastra/core/agent-controller';\n\nimport type { WorkItemsStorage } from '../storage/domains/work-items/base.js';\n\n/** The Factory session row fields that say which memory resource it uses. */\nexport interface FactorySessionOwnership {\n sessionId: string;\n userId: string;\n orgId?: string;\n factoryProjectId?: string | null;\n branch?: string;\n visibility?: string;\n originSessionId?: string | null;\n}\n\n/** Run bindings: the server-side record that a session runs work for its Factory. */\nexport type SessionRunBindings = Pick<WorkItemsStorage, 'hasRunBindingForSession'>;\n\ntype ThreadLookup = Pick<AgentController<any>, 'queryThreadById'>;\n\n/**\n * The one memory resource a Factory session runs under. A Slack session uses\n * its Factory's, or its sender's for a DM; a side session uses its Factory's,\n * or its owner's when private; any other session uses its owner's. A session's own thread can say otherwise\n * only within what the server recorded for it: its own id (created before\n * resources were shared, or a run kept on its own resource), and the Factory's\n * only for a session with a run binding. A client can create a thread under the\n * session's id, so the thread alone never makes a session the Factory's.\n */\nexport async function sessionMemoryResourceId(\n controller: ThreadLookup | undefined,\n session: FactorySessionOwnership,\n runs: SessionRunBindings | undefined,\n): Promise<string> {\n const [own, runBound] = await Promise.all([\n controller?.queryThreadById({ threadId: session.sessionId }),\n isRunBound(session, runs),\n ]);\n return memoryResourceOf(session, own, runBound);\n}\n\nexport async function isRunBound(session: FactorySessionOwnership, runs: SessionRunBindings | undefined) {\n if (!runs || !session.orgId || !session.factoryProjectId) return false;\n return runs.hasRunBindingForSession({\n orgId: session.orgId,\n factoryProjectId: session.factoryProjectId,\n sessionId: session.sessionId,\n });\n}\n\n/** {@link sessionMemoryResourceId} for a caller that already loaded the session's own thread. */\nexport function memoryResourceOf(\n session: FactorySessionOwnership,\n own: { resourceId?: string | null } | null | undefined,\n runBound: boolean,\n) {\n const factoryProjectId = session.factoryProjectId ?? undefined;\n const slack = session.branch?.startsWith('slack/') ?? false;\n // A private Slack DM or side session stays with its owner.\n const shared =\n slack || session.originSessionId\n ? session.visibility === 'private'\n ? session.userId\n : factoryProjectId\n : undefined;\n const allowed = shared\n ? [session.sessionId, shared]\n : [session.sessionId, session.userId, ...(runBound && factoryProjectId ? [factoryProjectId] : [])];\n if (own?.resourceId && allowed.includes(own.resourceId)) return own.resourceId;\n return shared ?? session.userId;\n}\n\n/**\n * Whether a `factorySessionId` stamp naming this session counts on a thread\n * under `resourceId`. Any org member can write a stamped thread under the\n * Factory's resource, so a private session's stamp never counts there: only\n * its own thread (`thread.id === sessionId`) does.\n */\nexport function sessionStampCounts(session: FactorySessionOwnership, resourceId: string | null | undefined): boolean {\n return !(session.visibility === 'private' && !!session.factoryProjectId && resourceId === session.factoryProjectId);\n}\n\n/**\n * The threads of one Factory session. Sessions share their Factory's or user's\n * resource, so listing by resource would return every session's threads. A\n * session's own thread carries its id, threads it opens are stamped with\n * `factorySessionId`, and a session created before resources were shared keeps\n * its threads under its own id as the resource. Thread ids and stamps are\n * client-writable, so the own and stamped threads only count under the\n * session's memory resource.\n */\nexport async function listFactorySessionThreads(\n controller: Pick<AgentController<any>, 'queryThreads' | 'queryThreadById'>,\n session: FactorySessionOwnership,\n runs: SessionRunBindings | undefined,\n): Promise<AgentControllerThread[]> {\n const { sessionId } = session;\n const [own, runBound, stamped, legacy] = await Promise.all([\n controller.queryThreadById({ threadId: sessionId }),\n isRunBound(session, runs),\n controller.queryThreads({ metadata: { factorySessionId: sessionId } }),\n controller.queryThreads({ resourceId: sessionId }),\n ]);\n const resourceId = memoryResourceOf(session, own, runBound);\n const threads = new Map<string, AgentControllerThread>();\n const owned = [\n ...(own?.resourceId === resourceId ? [own] : []),\n ...(sessionStampCounts(session, resourceId) ? stamped.filter(thread => thread.resourceId === resourceId) : []),\n ];\n for (const thread of [...owned, ...legacy]) threads.set(thread.id, thread);\n return [...threads.values()];\n}\n"],"mappings":";;;;;;;;;;AA6BA,eAAsB,wBACpB,YACA,SACA,MACiB;CACjB,MAAM,CAAC,KAAK,YAAY,MAAM,QAAQ,IAAI,CACxC,YAAY,gBAAgB,EAAE,UAAU,QAAQ,UAAU,CAAC,GAC3D,WAAW,SAAS,IAAI,CAC1B,CAAC;CACD,OAAO,iBAAiB,SAAS,KAAK,QAAQ;AAChD;AAEA,eAAsB,WAAW,SAAkC,MAAsC;CACvG,IAAI,CAAC,QAAQ,CAAC,QAAQ,SAAS,CAAC,QAAQ,kBAAkB,OAAO;CACjE,OAAO,KAAK,wBAAwB;EAClC,OAAO,QAAQ;EACf,kBAAkB,QAAQ;EAC1B,WAAW,QAAQ;CACrB,CAAC;AACH;;AAGA,SAAgB,iBACd,SACA,KACA,UACA;CACA,MAAM,mBAAmB,QAAQ,oBAAoB,KAAA;CAGrD,MAAM,UAFQ,QAAQ,QAAQ,WAAW,QAAQ,KAAK,UAG3C,QAAQ,kBACb,QAAQ,eAAe,YACrB,QAAQ,SACR,mBACF,KAAA;CACN,MAAM,UAAU,SACZ,CAAC,QAAQ,WAAW,MAAM,IAC1B;EAAC,QAAQ;EAAW,QAAQ;EAAQ,GAAI,YAAY,mBAAmB,CAAC,gBAAgB,IAAI,CAAC;CAAE;CACnG,IAAI,KAAK,cAAc,QAAQ,SAAS,IAAI,UAAU,GAAG,OAAO,IAAI;CACpE,OAAO,UAAU,QAAQ;AAC3B;;;;;;;AAQA,SAAgB,mBAAmB,SAAkC,YAAgD;CACnH,OAAO,EAAE,QAAQ,eAAe,aAAa,CAAC,CAAC,QAAQ,oBAAoB,eAAe,QAAQ;AACpG;;;;;;;;;;AAWA,eAAsB,0BACpB,YACA,SACA,MACkC;CAClC,MAAM,EAAE,cAAc;CACtB,MAAM,CAAC,KAAK,UAAU,SAAS,UAAU,MAAM,QAAQ,IAAI;EACzD,WAAW,gBAAgB,EAAE,UAAU,UAAU,CAAC;EAClD,WAAW,SAAS,IAAI;EACxB,WAAW,aAAa,EAAE,UAAU,EAAE,kBAAkB,UAAU,EAAE,CAAC;EACrE,WAAW,aAAa,EAAE,YAAY,UAAU,CAAC;CACnD,CAAC;CACD,MAAM,aAAa,iBAAiB,SAAS,KAAK,QAAQ;CAC1D,MAAM,0BAAU,IAAI,IAAmC;CACvD,MAAM,QAAQ,CACZ,GAAI,KAAK,eAAe,aAAa,CAAC,GAAG,IAAI,CAAC,GAC9C,GAAI,mBAAmB,SAAS,UAAU,IAAI,QAAQ,QAAO,WAAU,OAAO,eAAe,UAAU,IAAI,CAAC,CAC9G;CACA,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,IAAI,OAAO,IAAI,MAAM;CACzE,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC;AAC7B"}
@@ -16,10 +16,28 @@ export declare function verdictEventMismatch(event: ReviewEvent, body: string |
16
16
  * disagree, or `undefined` when absent.
17
17
  */
18
18
  export declare function reviewedHeadFromBody(body: string | undefined): string | null | undefined;
19
- export declare function createSourceControlTools({ requestContext, providers, audit, }: {
19
+ /** Fixed server-side so an agent cannot publish under, and impersonate, another required check. */
20
+ export declare const FACTORY_TEST_CHECK_NAME = "Factory Review / tests";
21
+ export declare function createSourceControlTools({ requestContext, providers, audit, testChecksEnabled, selfReviewApprovedHead, boundChangeRequestId, }: {
20
22
  requestContext: RequestContext;
21
23
  providers: readonly SourceControlToolProvider[];
22
24
  audit: AuditAgentEmitter;
25
+ /** Per-project switch for `source_control_publish_test_check`. The host decides the default; Factory projects default to off. */
26
+ testChecksEnabled?: (input: {
27
+ orgId: string;
28
+ factoryProjectId: string;
29
+ }) => Promise<boolean>;
30
+ /**
31
+ * Self-review gate for opening a change request. `undefined` means the session
32
+ * is not gated (no Work item, or its change request predates Self-review);
33
+ * `null` means Self-review has not approved; a SHA is the approved head.
34
+ */
35
+ selfReviewApprovedHead?: () => Promise<string | null | undefined>;
36
+ /**
37
+ * The change request a Review-bound session reviews; test checks may only target it.
38
+ * When provided, sessions that are not Review-bound (it resolves `undefined`) cannot publish.
39
+ */
40
+ boundChangeRequestId?: () => Promise<string | undefined>;
23
41
  }): Promise<IntegrationTools>;
24
42
  export {};
25
43
  //# sourceMappingURL=source-control-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-control-tools.d.ts","sourceRoot":"","sources":["../../src/session/source-control-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAUhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,KAAK,EAIV,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AAUnD,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,0BAA0B,CAAC;IACpC,cAAc,EAAE,cAAc,CAAC;CAChC;AAcD,KAAK,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAE7D,kGAAkG;AAClG,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAUrG;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CASxF;AAuJD,wBAAsB,wBAAwB,CAAC,EAC7C,cAAc,EACd,SAAS,EACT,KAAK,GACN,EAAE;IACD,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChD,KAAK,EAAE,iBAAiB,CAAC;CAC1B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8c5B"}
1
+ {"version":3,"file":"source-control-tools.d.ts","sourceRoot":"","sources":["../../src/session/source-control-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAUhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,KAAK,EAIV,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AAUnD,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,0BAA0B,CAAC;IACpC,cAAc,EAAE,cAAc,CAAC;CAChC;AAcD,KAAK,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAE7D,kGAAkG;AAClG,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAUrG;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CASxF;AAkJD,mGAAmG;AACnG,eAAO,MAAM,uBAAuB,2BAA2B,CAAC;AAOhE,wBAAsB,wBAAwB,CAAC,EAC7C,cAAc,EACd,SAAS,EACT,KAAK,EACL,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,GACrB,EAAE;IACD,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChD,KAAK,EAAE,iBAAiB,CAAC;IACzB,iIAAiI;IACjI,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7F;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAClE;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1D,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoiB5B"}
@@ -36,10 +36,10 @@ function authIdentity(requestContext) {
36
36
  userId: getFactoryAuthUserId(user)
37
37
  };
38
38
  }
39
- async function resolveProviderSession(resourceId, providers) {
39
+ async function resolveProviderSession(sessionId, providers) {
40
40
  const matches = (await Promise.all(providers.map(async (provider) => ({
41
41
  provider,
42
- session: await provider.storage.sessions.getBySessionId(resourceId)
42
+ session: await provider.storage.sessions.getBySessionId(sessionId)
43
43
  })))).filter((match) => match.session !== null);
44
44
  if (matches.length !== 1) throw new Error(matches.length === 0 ? "The active session is not backed by a source-control repository." : "The active session is ambiguous across source-control providers.");
45
45
  return matches[0];
@@ -47,8 +47,8 @@ async function resolveProviderSession(resourceId, providers) {
47
47
  async function resolveSessionTarget(requestContext, providers, options = {}) {
48
48
  const context = requestContext.get("controller");
49
49
  const { orgId, userId } = authIdentity(requestContext);
50
- if (!context?.resourceId || !orgId || !userId) throw new Error("Source-control tools require an authenticated repository session.");
51
- const { provider, session } = await resolveProviderSession(context.resourceId, providers);
50
+ if (!context?.sessionId || !orgId || !userId) throw new Error("Source-control tools require an authenticated repository session.");
51
+ const { provider, session } = await resolveProviderSession(context.sessionId, providers);
52
52
  if (session.orgId !== orgId || session.visibility === "private" && session.userId !== userId) throw new Error("The active source-control session is not available to the authenticated user.");
53
53
  const ownRepository = session.projectRepositoryId ? await provider.storage.projectRepositories.get({
54
54
  orgId,
@@ -102,9 +102,9 @@ async function resolveSessionTarget(requestContext, providers, options = {}) {
102
102
  * descriptions. `undefined` when the session cannot be resolved; the tools
103
103
  * then describe the default without naming it.
104
104
  */
105
- async function describeSessionRepositories(resourceId, providers) {
105
+ async function describeSessionRepositories(sessionId, providers) {
106
106
  try {
107
- const { provider, session } = await resolveProviderSession(resourceId, providers);
107
+ const { provider, session } = await resolveProviderSession(sessionId, providers);
108
108
  const repositories = await resolveSessionRepositories({
109
109
  sourceControl: provider.storage,
110
110
  session
@@ -144,14 +144,16 @@ async function emitAgentAudit(audit, requestContext, input) {
144
144
  });
145
145
  }
146
146
  }
147
+ /** Fixed server-side so an agent cannot publish under, and impersonate, another required check. */
148
+ const FACTORY_TEST_CHECK_NAME = "Factory Review / tests";
147
149
  const repositorySchema = z.object({ repository: z.string().trim().min(1).optional() });
148
150
  const changeRequestSchema = repositorySchema.extend({ changeRequestId: z.union([z.string().trim().min(1), z.number().int().positive()]) });
149
- async function createSourceControlTools({ requestContext, providers, audit }) {
151
+ async function createSourceControlTools({ requestContext, providers, audit, testChecksEnabled, selfReviewApprovedHead, boundChangeRequestId }) {
150
152
  if (!requestContext || typeof requestContext.get !== "function") return {};
151
153
  const controller = requestContext.get("controller");
152
154
  const identity = authIdentity(requestContext);
153
- if (!controller?.resourceId || !identity.orgId || !identity.userId || providers.length === 0) return {};
154
- const repositoryArgument = repositoryArgumentDescription(await describeSessionRepositories(controller.resourceId, providers));
155
+ if (!controller?.sessionId || !identity.orgId || !identity.userId || providers.length === 0) return {};
156
+ const repositoryArgument = repositoryArgumentDescription(await describeSessionRepositories(controller.sessionId, providers));
155
157
  const withTarget = (options) => resolveSessionTarget(requestContext, providers, options);
156
158
  const targetFor = (input) => withTarget(input.repository !== void 0 ? { repository: input.repository } : void 0);
157
159
  const reference = async (target) => ({
@@ -264,8 +266,10 @@ async function createSourceControlTools({ requestContext, providers, audit }) {
264
266
  body: z.string().optional(),
265
267
  draft: z.boolean().optional()
266
268
  }),
267
- execute: async (input) => {
269
+ execute: async (input, execution) => {
268
270
  const target = await targetFor(input);
271
+ const approvedHead = target.ownRepository ? await selfReviewApprovedHead?.() : void 0;
272
+ if (approvedHead === null) throw new Error("Self-review has not approved this branch. Move the work item to Self-review; the change request opens after it approves.");
269
273
  const baseBranch = target.ownRepository ? target.session.baseBranch : target.projectRepository.branch ?? target.repository.defaultBranch;
270
274
  const created = await target.provider.versionControl.createPullRequest({
271
275
  ...await reference(target),
@@ -275,6 +279,13 @@ async function createSourceControlTools({ requestContext, providers, audit }) {
275
279
  headBranch: target.session.branch,
276
280
  ...input.draft !== void 0 ? { draft: input.draft } : {}
277
281
  });
282
+ if (approvedHead !== void 0 && created.headSha.toLowerCase() !== approvedHead.toLowerCase()) {
283
+ await target.provider.versionControl.closePullRequest({
284
+ ...await reference(target),
285
+ pullRequestId: created.id
286
+ });
287
+ throw new Error(`Self-review approved ${approvedHead}, but the pushed branch is at ${created.headSha}; the change request was closed. Push the approved head, or move the work item back to Self-review to review the new commits.`);
288
+ }
278
289
  await target.provider.storage.sessionRepositories.upsert({
279
290
  sessionId: target.session.sessionId,
280
291
  projectRepositoryId: target.projectRepository.id,
@@ -546,6 +557,62 @@ async function createSourceControlTools({ requestContext, providers, audit }) {
546
557
  });
547
558
  }
548
559
  }),
560
+ source_control_publish_test_check: createTool({
561
+ id: "source_control_publish_test_check",
562
+ description: `Publish the Factory review test result as a "${FACTORY_TEST_CHECK_NAME}" commit check on the change request's current head. Publish "in-progress" before running the test plan and a final status after. Refused when headSha is not the current head. ${repositoryArgument}`,
563
+ inputSchema: changeRequestSchema.extend({
564
+ headSha: z.string().trim().regex(/^([0-9a-f]{40}|[0-9a-f]{64})$/i, "headSha must be a full 40- or 64-character commit SHA."),
565
+ status: z.enum([
566
+ "in-progress",
567
+ "success",
568
+ "failure",
569
+ "neutral",
570
+ "cancelled",
571
+ "skipped"
572
+ ]),
573
+ title: z.string().trim().min(1),
574
+ summary: z.string().trim().min(1),
575
+ details: z.string().optional()
576
+ }),
577
+ execute: async (input) => {
578
+ const target = await targetFor(input);
579
+ if (testChecksEnabled) {
580
+ const connection = await target.provider.storage.connections.get({
581
+ orgId: target.orgId,
582
+ id: target.projectRepository.connectionId
583
+ });
584
+ if (connection?.factoryProjectId && !await testChecksEnabled({
585
+ orgId: target.orgId,
586
+ factoryProjectId: connection.factoryProjectId
587
+ })) throw new Error("Test check publishing is turned off for this Factory project; nothing was published. Report the test results in the test report comment instead.");
588
+ }
589
+ const publishCommitCheck = target.provider.versionControl.publishCommitCheck;
590
+ if (!publishCommitCheck) throw new Error(`${target.provider.id} does not support publishing commit checks; nothing was published.`);
591
+ const bound = boundChangeRequestId ? await boundChangeRequestId() : void 0;
592
+ if (bound === void 0) throw new Error("Only a Review session bound to this change request can publish test checks; nothing was published.");
593
+ if (bound !== changeRequestId(input.changeRequestId)) throw new Error(`This session reviews change request ${bound}, not ${input.changeRequestId}; nothing was published.`);
594
+ const ref = await reference(target);
595
+ const pullRequest = await target.provider.versionControl.getPullRequest({
596
+ ...ref,
597
+ pullRequestId: changeRequestId(input.changeRequestId)
598
+ });
599
+ if (!pullRequest || pullRequest.state !== "open") throw new Error(`Change request ${input.changeRequestId} is not open; nothing was published.`);
600
+ const headSha = input.headSha.toLowerCase();
601
+ if (pullRequest.headSha.toLowerCase() !== headSha) throw new Error(`headSha ${headSha} is not the current change-request head ${pullRequest.headSha}. Nothing was published. Re-run the test plan on the current head.`);
602
+ return publishCommitCheck({
603
+ connection: ref.connection,
604
+ sourceId: ref.sourceId,
605
+ actingUserId: ref.actingUserId,
606
+ headSha,
607
+ ref: pullRequest.headBranch,
608
+ name: FACTORY_TEST_CHECK_NAME,
609
+ status: input.status,
610
+ title: input.title,
611
+ summary: input.summary,
612
+ ...input.details !== void 0 ? { details: input.details } : {}
613
+ });
614
+ }
615
+ }),
549
616
  source_control_request_reviewers: createTool({
550
617
  id: "source_control_request_reviewers",
551
618
  description: `Request individual or team reviewers on a pull request or merge request. Provider limitations are returned explicitly. ${repositoryArgument}`,
@@ -589,6 +656,6 @@ async function createSourceControlTools({ requestContext, providers, audit }) {
589
656
  };
590
657
  }
591
658
  //#endregion
592
- export { createSourceControlTools, reviewedHeadFromBody, verdictEventMismatch };
659
+ export { FACTORY_TEST_CHECK_NAME, createSourceControlTools, reviewedHeadFromBody, verdictEventMismatch };
593
660
 
594
661
  //# sourceMappingURL=source-control-tools.js.map