@mastra/factory 0.24.0-alpha.0 → 0.24.0-alpha.10

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 (406) 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 +354 -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 +26 -22
  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/api.d.ts +9 -0
  77. package/dist/integrations/incidentio/api.d.ts.map +1 -1
  78. package/dist/integrations/incidentio/api.js +3 -0
  79. package/dist/integrations/incidentio/api.js.map +1 -1
  80. package/dist/integrations/incidentio/intake.d.ts +1 -1
  81. package/dist/integrations/incidentio/intake.d.ts.map +1 -1
  82. package/dist/integrations/incidentio/intake.js.map +1 -1
  83. package/dist/integrations/incidentio/integration.d.ts.map +1 -1
  84. package/dist/integrations/incidentio/integration.js +1 -0
  85. package/dist/integrations/incidentio/integration.js.map +1 -1
  86. package/dist/integrations/jira/api.d.ts +7 -0
  87. package/dist/integrations/jira/api.d.ts.map +1 -1
  88. package/dist/integrations/jira/api.js +4 -0
  89. package/dist/integrations/jira/api.js.map +1 -1
  90. package/dist/integrations/linear/agent-tools.d.ts.map +1 -1
  91. package/dist/integrations/linear/agent-tools.js.map +1 -1
  92. package/dist/integrations/platform/api-client.d.ts +6 -0
  93. package/dist/integrations/platform/api-client.d.ts.map +1 -1
  94. package/dist/integrations/platform/api-client.js +6 -1
  95. package/dist/integrations/platform/api-client.js.map +1 -1
  96. package/dist/integrations/platform/connect/routes.d.ts +1 -1
  97. package/dist/integrations/platform/connect/routes.d.ts.map +1 -1
  98. package/dist/integrations/platform/connect/routes.js.map +1 -1
  99. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  100. package/dist/integrations/platform/github/integration.js +27 -1
  101. package/dist/integrations/platform/github/integration.js.map +1 -1
  102. package/dist/integrations/platform/incidentio/integration.d.ts +1 -1
  103. package/dist/integrations/platform/incidentio/integration.d.ts.map +1 -1
  104. package/dist/integrations/platform/incidentio/integration.js +1 -0
  105. package/dist/integrations/platform/incidentio/integration.js.map +1 -1
  106. package/dist/integrations/platform/jira/integration.d.ts +1 -1
  107. package/dist/integrations/platform/jira/integration.d.ts.map +1 -1
  108. package/dist/integrations/platform/jira/integration.js +1 -0
  109. package/dist/integrations/platform/jira/integration.js.map +1 -1
  110. package/dist/integrations/platform/linear/event-worker.d.ts +1 -1
  111. package/dist/integrations/platform/linear/event-worker.d.ts.map +1 -1
  112. package/dist/integrations/platform/linear/event-worker.js.map +1 -1
  113. package/dist/integrations/slack/integration.d.ts.map +1 -1
  114. package/dist/integrations/slack/integration.js +33 -6
  115. package/dist/integrations/slack/integration.js.map +1 -1
  116. package/dist/integrations/slack/slack.d.ts +16 -5
  117. package/dist/integrations/slack/slack.d.ts.map +1 -1
  118. package/dist/integrations/slack/slack.js +137 -64
  119. package/dist/integrations/slack/slack.js.map +1 -1
  120. package/dist/integrations/subscription-session.d.ts +14 -0
  121. package/dist/integrations/subscription-session.d.ts.map +1 -1
  122. package/dist/integrations/subscription-session.js +30 -16
  123. package/dist/integrations/subscription-session.js.map +1 -1
  124. package/dist/mcp/disconnect.d.ts +10 -0
  125. package/dist/mcp/disconnect.d.ts.map +1 -0
  126. package/dist/mcp/disconnect.js +44 -0
  127. package/dist/mcp/disconnect.js.map +1 -0
  128. package/dist/mcp/routes.d.ts +46 -0
  129. package/dist/mcp/routes.d.ts.map +1 -0
  130. package/dist/mcp/routes.js +243 -0
  131. package/dist/mcp/routes.js.map +1 -0
  132. package/dist/provider-display-name.d.ts +2 -0
  133. package/dist/provider-display-name.d.ts.map +1 -0
  134. package/dist/provider-display-name.js +16 -0
  135. package/dist/provider-display-name.js.map +1 -0
  136. package/dist/review-verdict.d.ts +11 -0
  137. package/dist/review-verdict.d.ts.map +1 -1
  138. package/dist/review-verdict.js +16 -1
  139. package/dist/review-verdict.js.map +1 -1
  140. package/dist/routes/attention-activity.d.ts.map +1 -1
  141. package/dist/routes/attention-activity.js +5 -2
  142. package/dist/routes/attention-activity.js.map +1 -1
  143. package/dist/routes/attention-providers.d.ts +0 -1
  144. package/dist/routes/attention-providers.d.ts.map +1 -1
  145. package/dist/routes/attention-providers.js +5 -6
  146. package/dist/routes/attention-providers.js.map +1 -1
  147. package/dist/routes/config.d.ts +44 -5
  148. package/dist/routes/config.d.ts.map +1 -1
  149. package/dist/routes/config.js +181 -58
  150. package/dist/routes/config.js.map +1 -1
  151. package/dist/routes/contracts.d.ts +4 -0
  152. package/dist/routes/contracts.d.ts.map +1 -1
  153. package/dist/routes/contracts.js +3 -1
  154. package/dist/routes/contracts.js.map +1 -1
  155. package/dist/routes/custom-provider-source.d.ts +8 -0
  156. package/dist/routes/custom-provider-source.d.ts.map +1 -1
  157. package/dist/routes/custom-provider-source.js +22 -1
  158. package/dist/routes/custom-provider-source.js.map +1 -1
  159. package/dist/routes/oauth.js +1 -1
  160. package/dist/routes/oauth.js.map +1 -1
  161. package/dist/routes/projects.d.ts +1 -1
  162. package/dist/routes/projects.d.ts.map +1 -1
  163. package/dist/routes/projects.js +1 -1
  164. package/dist/routes/projects.js.map +1 -1
  165. package/dist/routes/provider-credentials.d.ts +7 -2
  166. package/dist/routes/provider-credentials.d.ts.map +1 -1
  167. package/dist/routes/provider-credentials.js +30 -8
  168. package/dist/routes/provider-credentials.js.map +1 -1
  169. package/dist/routes/skills.d.ts +2 -4
  170. package/dist/routes/skills.d.ts.map +1 -1
  171. package/dist/routes/skills.js +19 -65
  172. package/dist/routes/skills.js.map +1 -1
  173. package/dist/routes/source-control-sessions.d.ts +9 -1
  174. package/dist/routes/source-control-sessions.d.ts.map +1 -1
  175. package/dist/routes/source-control-sessions.js +131 -7
  176. package/dist/routes/source-control-sessions.js.map +1 -1
  177. package/dist/routes/surface.d.ts +3 -2
  178. package/dist/routes/surface.d.ts.map +1 -1
  179. package/dist/routes/surface.js +7 -3
  180. package/dist/routes/surface.js.map +1 -1
  181. package/dist/routes/work-items.d.ts.map +1 -1
  182. package/dist/routes/work-items.js +60 -120
  183. package/dist/routes/work-items.js.map +1 -1
  184. package/dist/rules/binding-context.js +7 -7
  185. package/dist/rules/binding-context.js.map +1 -1
  186. package/dist/rules/dispatch-errors.d.ts.map +1 -1
  187. package/dist/rules/dispatch-errors.js +12 -0
  188. package/dist/rules/dispatch-errors.js.map +1 -1
  189. package/dist/rules/dispatcher.d.ts +8 -1
  190. package/dist/rules/dispatcher.d.ts.map +1 -1
  191. package/dist/rules/dispatcher.js +117 -12
  192. package/dist/rules/dispatcher.js.map +1 -1
  193. package/dist/rules/processor.d.ts.map +1 -1
  194. package/dist/rules/processor.js +2 -1
  195. package/dist/rules/processor.js.map +1 -1
  196. package/dist/rules/start-coordinator.d.ts +4 -0
  197. package/dist/rules/start-coordinator.d.ts.map +1 -1
  198. package/dist/rules/start-coordinator.js +36 -4
  199. package/dist/rules/start-coordinator.js.map +1 -1
  200. package/dist/rules/tools.d.ts.map +1 -1
  201. package/dist/rules/tools.js +82 -3
  202. package/dist/rules/tools.js.map +1 -1
  203. package/dist/rules/transition-service.d.ts +17 -0
  204. package/dist/rules/transition-service.d.ts.map +1 -1
  205. package/dist/rules/transition-service.js +25 -0
  206. package/dist/rules/transition-service.js.map +1 -1
  207. package/dist/rules/types.d.ts +2 -4
  208. package/dist/rules/types.d.ts.map +1 -1
  209. package/dist/rules/types.js +1 -4
  210. package/dist/rules/types.js.map +1 -1
  211. package/dist/sandbox/local-factory-sandbox.d.ts.map +1 -1
  212. package/dist/sandbox/local-factory-sandbox.js +1 -0
  213. package/dist/sandbox/local-factory-sandbox.js.map +1 -1
  214. package/dist/sandbox/session-retirement.d.ts +27 -3
  215. package/dist/sandbox/session-retirement.d.ts.map +1 -1
  216. package/dist/sandbox/session-retirement.js +158 -20
  217. package/dist/sandbox/session-retirement.js.map +1 -1
  218. package/dist/secret-encryption.d.ts.map +1 -1
  219. package/dist/secret-encryption.js +65 -25
  220. package/dist/secret-encryption.js.map +1 -1
  221. package/dist/session/channel-reply-processor.d.ts +36 -0
  222. package/dist/session/channel-reply-processor.d.ts.map +1 -0
  223. package/dist/session/channel-reply-processor.js +46 -0
  224. package/dist/session/channel-reply-processor.js.map +1 -0
  225. package/dist/session/channel-session-link-processor.d.ts +39 -0
  226. package/dist/session/channel-session-link-processor.d.ts.map +1 -0
  227. package/dist/session/channel-session-link-processor.js +100 -0
  228. package/dist/session/channel-session-link-processor.js.map +1 -0
  229. package/dist/session/credential-policy.d.ts +1 -1
  230. package/dist/session/credential-policy.d.ts.map +1 -1
  231. package/dist/session/credential-policy.js +7 -6
  232. package/dist/session/credential-policy.js.map +1 -1
  233. package/dist/session/default-model-hydration.d.ts +1 -0
  234. package/dist/session/default-model-hydration.d.ts.map +1 -1
  235. package/dist/session/default-model-hydration.js +3 -2
  236. package/dist/session/default-model-hydration.js.map +1 -1
  237. package/dist/session/environment-state-processor.js +1 -1
  238. package/dist/session/environment-state-processor.js.map +1 -1
  239. package/dist/session/factory-session.d.ts +19 -1
  240. package/dist/session/factory-session.d.ts.map +1 -1
  241. package/dist/session/factory-session.js +5 -2
  242. package/dist/session/factory-session.js.map +1 -1
  243. package/dist/session/filesystem-capture.d.ts +3 -3
  244. package/dist/session/filesystem-capture.d.ts.map +1 -1
  245. package/dist/session/filesystem-capture.js +16 -17
  246. package/dist/session/filesystem-capture.js.map +1 -1
  247. package/dist/session/first-exec-capture.d.ts +1 -1
  248. package/dist/session/first-exec-capture.d.ts.map +1 -1
  249. package/dist/session/first-exec-capture.js +1 -1
  250. package/dist/session/first-exec-capture.js.map +1 -1
  251. package/dist/session/first-message-capture.d.ts +1 -1
  252. package/dist/session/first-message-capture.d.ts.map +1 -1
  253. package/dist/session/first-message-capture.js +1 -1
  254. package/dist/session/first-message-capture.js.map +1 -1
  255. package/dist/session/live-sessions.d.ts +1 -1
  256. package/dist/session/live-sessions.js +1 -1
  257. package/dist/session/live-sessions.js.map +1 -1
  258. package/dist/session/memory-settings-hydration.d.ts +1 -1
  259. package/dist/session/memory-settings-hydration.d.ts.map +1 -1
  260. package/dist/session/memory-settings-hydration.js +1 -1
  261. package/dist/session/memory-settings-hydration.js.map +1 -1
  262. package/dist/session/reply-credential-processor.d.ts +15 -0
  263. package/dist/session/reply-credential-processor.d.ts.map +1 -0
  264. package/dist/session/reply-credential-processor.js +38 -0
  265. package/dist/session/reply-credential-processor.js.map +1 -0
  266. package/dist/session/resource-migration.d.ts +87 -0
  267. package/dist/session/resource-migration.d.ts.map +1 -0
  268. package/dist/session/resource-migration.js +163 -0
  269. package/dist/session/resource-migration.js.map +1 -0
  270. package/dist/session/run-audit.d.ts +24 -0
  271. package/dist/session/run-audit.d.ts.map +1 -1
  272. package/dist/session/run-audit.js +93 -7
  273. package/dist/session/run-audit.js.map +1 -1
  274. package/dist/session/session-threads.d.ts +49 -0
  275. package/dist/session/session-threads.d.ts.map +1 -0
  276. package/dist/session/session-threads.js +70 -0
  277. package/dist/session/session-threads.js.map +1 -0
  278. package/dist/session/source-control-tools.d.ts +19 -1
  279. package/dist/session/source-control-tools.d.ts.map +1 -1
  280. package/dist/session/source-control-tools.js +78 -11
  281. package/dist/session/source-control-tools.js.map +1 -1
  282. package/dist/session/thinking-default.d.ts.map +1 -1
  283. package/dist/session/thinking-default.js +3 -4
  284. package/dist/session/thinking-default.js.map +1 -1
  285. package/dist/session/thread-session-stamp.d.ts +21 -0
  286. package/dist/session/thread-session-stamp.d.ts.map +1 -0
  287. package/dist/session/thread-session-stamp.js +20 -0
  288. package/dist/session/thread-session-stamp.js.map +1 -0
  289. package/dist/session/thread-title-mirror.d.ts +1 -1
  290. package/dist/session/thread-title-mirror.d.ts.map +1 -1
  291. package/dist/session/thread-title-mirror.js +1 -1
  292. package/dist/session/thread-title-mirror.js.map +1 -1
  293. package/dist/session/work-item-repository.d.ts +1 -1
  294. package/dist/session/work-item-repository.d.ts.map +1 -1
  295. package/dist/session/work-item-repository.js.map +1 -1
  296. package/dist/skills/service.d.ts +6 -8
  297. package/dist/skills/service.d.ts.map +1 -1
  298. package/dist/skills/service.js +3 -3
  299. package/dist/skills/service.js.map +1 -1
  300. package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -1
  301. package/dist/storage/domains/audit/agent-audit.js +2 -2
  302. package/dist/storage/domains/audit/agent-audit.js.map +1 -1
  303. package/dist/storage/domains/audit/domain.js +1 -1
  304. package/dist/storage/domains/filesystem/base.d.ts +4 -0
  305. package/dist/storage/domains/filesystem/base.d.ts.map +1 -1
  306. package/dist/storage/domains/filesystem/base.js +5 -0
  307. package/dist/storage/domains/filesystem/base.js.map +1 -1
  308. package/dist/storage/domains/integrations/base.d.ts +8 -0
  309. package/dist/storage/domains/integrations/base.d.ts.map +1 -1
  310. package/dist/storage/domains/integrations/base.js +7 -0
  311. package/dist/storage/domains/integrations/base.js.map +1 -1
  312. package/dist/storage/domains/projects/base.d.ts +6 -0
  313. package/dist/storage/domains/projects/base.d.ts.map +1 -1
  314. package/dist/storage/domains/projects/base.js +12 -0
  315. package/dist/storage/domains/projects/base.js.map +1 -1
  316. package/dist/storage/domains/source-control/base.d.ts +28 -0
  317. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  318. package/dist/storage/domains/source-control/base.js +48 -0
  319. package/dist/storage/domains/source-control/base.js.map +1 -1
  320. package/dist/storage/domains/source-control/inmemory.d.ts +8 -0
  321. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  322. package/dist/storage/domains/source-control/inmemory.js +13 -1
  323. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  324. package/dist/storage/domains/work-items/base.d.ts +79 -7
  325. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  326. package/dist/storage/domains/work-items/base.js +172 -30
  327. package/dist/storage/domains/work-items/base.js.map +1 -1
  328. package/dist/timing.d.ts +23 -0
  329. package/dist/timing.d.ts.map +1 -1
  330. package/dist/timing.js +85 -6
  331. package/dist/timing.js.map +1 -1
  332. package/dist/tools/annotations.d.ts +7 -0
  333. package/dist/tools/annotations.d.ts.map +1 -0
  334. package/dist/tools/annotations.js +102 -0
  335. package/dist/tools/annotations.js.map +1 -0
  336. package/dist/tools/approval-tools.d.ts +15 -0
  337. package/dist/tools/approval-tools.d.ts.map +1 -0
  338. package/dist/tools/approval-tools.js +79 -0
  339. package/dist/tools/approval-tools.js.map +1 -0
  340. package/dist/tools/deliver.d.ts +71 -0
  341. package/dist/tools/deliver.d.ts.map +1 -0
  342. package/dist/tools/deliver.js +129 -0
  343. package/dist/tools/deliver.js.map +1 -0
  344. package/dist/tools/index.d.ts +30 -0
  345. package/dist/tools/index.d.ts.map +1 -0
  346. package/dist/tools/index.js +36 -0
  347. package/dist/tools/index.js.map +1 -0
  348. package/dist/tools/messaging-tools.d.ts +28 -0
  349. package/dist/tools/messaging-tools.d.ts.map +1 -0
  350. package/dist/tools/messaging-tools.js +396 -0
  351. package/dist/tools/messaging-tools.js.map +1 -0
  352. package/dist/tools/permissions.d.ts +31 -0
  353. package/dist/tools/permissions.d.ts.map +1 -0
  354. package/dist/tools/permissions.js +48 -0
  355. package/dist/tools/permissions.js.map +1 -0
  356. package/dist/tools/read-tools.d.ts +30 -0
  357. package/dist/tools/read-tools.d.ts.map +1 -0
  358. package/dist/tools/read-tools.js +293 -0
  359. package/dist/tools/read-tools.js.map +1 -0
  360. package/dist/tools/reports.d.ts +174 -0
  361. package/dist/tools/reports.d.ts.map +1 -0
  362. package/dist/tools/reports.js +380 -0
  363. package/dist/tools/reports.js.map +1 -0
  364. package/dist/tools/run-watch.d.ts +46 -0
  365. package/dist/tools/run-watch.d.ts.map +1 -0
  366. package/dist/tools/run-watch.js +102 -0
  367. package/dist/tools/run-watch.js.map +1 -0
  368. package/dist/tools/scope.d.ts +54 -0
  369. package/dist/tools/scope.d.ts.map +1 -0
  370. package/dist/tools/scope.js +87 -0
  371. package/dist/tools/scope.js.map +1 -0
  372. package/dist/tools/session-tools.d.ts +43 -0
  373. package/dist/tools/session-tools.d.ts.map +1 -0
  374. package/dist/tools/session-tools.js +410 -0
  375. package/dist/tools/session-tools.js.map +1 -0
  376. package/dist/tools/sessions-state-processor.d.ts +41 -0
  377. package/dist/tools/sessions-state-processor.d.ts.map +1 -0
  378. package/dist/tools/sessions-state-processor.js +190 -0
  379. package/dist/tools/sessions-state-processor.js.map +1 -0
  380. package/dist/tools/side-sessions.d.ts +53 -0
  381. package/dist/tools/side-sessions.d.ts.map +1 -0
  382. package/dist/tools/side-sessions.js +83 -0
  383. package/dist/tools/side-sessions.js.map +1 -0
  384. package/dist/tools/work-item-tools.d.ts +28 -0
  385. package/dist/tools/work-item-tools.d.ts.map +1 -0
  386. package/dist/tools/work-item-tools.js +342 -0
  387. package/dist/tools/work-item-tools.js.map +1 -0
  388. package/dist/work-items/create-work-item.d.ts +55 -0
  389. package/dist/work-items/create-work-item.d.ts.map +1 -0
  390. package/dist/work-items/create-work-item.js +101 -0
  391. package/dist/work-items/create-work-item.js.map +1 -0
  392. package/dist/work-items/decision-actions.d.ts +42 -0
  393. package/dist/work-items/decision-actions.d.ts.map +1 -0
  394. package/dist/work-items/decision-actions.js +70 -0
  395. package/dist/work-items/decision-actions.js.map +1 -0
  396. package/dist/workspace.d.ts +1 -1
  397. package/dist/workspace.d.ts.map +1 -1
  398. package/dist/workspace.js +15 -7
  399. package/dist/workspace.js.map +1 -1
  400. package/factory-skills/factory-gitlab-rereview/SKILL.md +1 -1
  401. package/factory-skills/factory-gitlab-review/SKILL.md +1 -1
  402. package/factory-skills/factory-plan/SKILL.md +4 -4
  403. package/factory-skills/factory-rereview/SKILL.md +3 -1
  404. package/factory-skills/factory-review/SKILL.md +3 -1
  405. package/factory-skills/factory-self-review/SKILL.md +46 -0
  406. package/package.json +15 -15
@@ -0,0 +1,54 @@
1
+ import type { RequestContext } from '@mastra/core/request-context';
2
+ import { FACTORY_INTERACTIVE_KEY } from '../auth.js';
3
+ import type { SourceControlSessionLookup } from '../session/factory-session.js';
4
+ import type { AuditActorProfileInput } from '../storage/domains/audit/base.js';
5
+ import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';
6
+ import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
7
+ export { FACTORY_INTERACTIVE_KEY };
8
+ /** Linked Slack sender, separate from the session owner's model-credential identity. */
9
+ export declare const FACTORY_SLACK_SENDER_KEY = "mastra__factorySlackSender";
10
+ /** Who is calling Factory tools, and from which session. Everything a tool needs to stay in scope. */
11
+ export interface FactoryToolScope {
12
+ orgId: string;
13
+ factoryProjectId: string;
14
+ /** The signed-in caller for a user session; the session row's owner for a worker. */
15
+ userId: string;
16
+ /** The source-control session id. */
17
+ sessionId: string;
18
+ /** The memory resource the session runs under. */
19
+ resourceId: string;
20
+ threadId: string;
21
+ /** `worker` sessions are bound to a work item run; only `user` sessions manage the Factory. */
22
+ kind: 'user' | 'worker';
23
+ /** True only for turns a signed-in person started over HTTP (see {@link FACTORY_INTERACTIVE_KEY}). */
24
+ interactive: boolean;
25
+ /** The caller's name and avatar, stamped on audit events so the board can show who acted. */
26
+ actorProfile?: AuditActorProfileInput;
27
+ /** Set for a side session: the user session and thread that started it. */
28
+ origin?: {
29
+ sessionId: string;
30
+ threadId: string;
31
+ };
32
+ }
33
+ export interface ResolveFactoryToolScopeOptions {
34
+ requestContext: RequestContext;
35
+ /** `routeAuth.enabled()`; when false every caller is the shared `local` tenant. */
36
+ authEnabled: boolean;
37
+ sessions: Pick<SourceControlSessionLookup, 'getBySessionId'>;
38
+ projects: Pick<FactoryProjectsStorage, 'get'>;
39
+ workItems: Pick<WorkItemsStorage, 'hasRunBindingForSession'>;
40
+ }
41
+ /**
42
+ * Resolve the Factory a session's agent may act in. The scope comes from the
43
+ * stored source-control session row and the authenticated caller, never from
44
+ * the `factoryProjectId` thread tag alone: the browser sets that tag and
45
+ * nothing clears it.
46
+ */
47
+ export declare function resolveFactoryToolScope({ requestContext, authEnabled, sessions, projects, workItems, }: ResolveFactoryToolScopeOptions): Promise<FactoryToolScope | null>;
48
+ /**
49
+ * Refuses an action only a signed-in person may take. Turns nobody signed in
50
+ * started (notification wakes, webhooks, dispatcher notices) carry text other
51
+ * people wrote, so they can't approve, resolve proposals, or waive plan approval.
52
+ */
53
+ export declare function requirePerson(scope: FactoryToolScope, action: string): void;
54
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/tools/scope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EACL,uBAAuB,EAIxB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAEhF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAEnC,wFAAwF;AACxF,eAAO,MAAM,wBAAwB,+BAA+B,CAAC;AAErE,sGAAsG;AACtG,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,sGAAsG;IACtG,WAAW,EAAE,OAAO,CAAC;IACrB,6FAA6F;IAC7F,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD;AAED,MAAM,WAAW,8BAA8B;IAC7C,cAAc,EAAE,cAAc,CAAC;IAC/B,mFAAmF;IACnF,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,IAAI,CAAC,0BAA0B,EAAE,gBAAgB,CAAC,CAAC;IAC7D,QAAQ,EAAE,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IAC9C,SAAS,EAAE,IAAI,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;CAC9D;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,cAAc,EACd,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,SAAS,GACV,EAAE,8BAA8B,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAkEnE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAK3E"}
@@ -0,0 +1,87 @@
1
+ import { FACTORY_INTERACTIVE_KEY, factoryUserOrgId, getFactoryAuthUserFromContext, getFactoryAuthUserId } from "../auth.js";
2
+ import { auditActorProfile } from "../storage/domains/audit/base.js";
3
+ //#region src/tools/scope.ts
4
+ /** Linked Slack sender, separate from the session owner's model-credential identity. */
5
+ const FACTORY_SLACK_SENDER_KEY = "mastra__factorySlackSender";
6
+ /**
7
+ * Resolve the Factory a session's agent may act in. The scope comes from the
8
+ * stored source-control session row and the authenticated caller, never from
9
+ * the `factoryProjectId` thread tag alone: the browser sets that tag and
10
+ * nothing clears it.
11
+ */
12
+ async function resolveFactoryToolScope({ requestContext, authEnabled, sessions, projects, workItems }) {
13
+ if (typeof requestContext?.get !== "function") return null;
14
+ const controller = requestContext.get("controller");
15
+ const sessionId = controller?.sessionId;
16
+ const resourceId = controller?.resourceId;
17
+ const threadId = controller?.threadId;
18
+ if (!sessionId || !resourceId || !threadId) return null;
19
+ let caller = null;
20
+ if (authEnabled) {
21
+ const slackSender = requestContext.get(FACTORY_SLACK_SENDER_KEY);
22
+ const user = getFactoryAuthUserFromContext(requestContext);
23
+ if (slackSender && factoryUserOrgId(user) !== slackSender.orgId) return null;
24
+ const userId = slackSender?.userId ?? getFactoryAuthUserId(user);
25
+ const orgId = slackSender?.orgId ?? factoryUserOrgId(user);
26
+ const actorProfile = slackSender ? void 0 : auditActorProfile(user);
27
+ if (userId && orgId) caller = {
28
+ orgId,
29
+ userId,
30
+ ...actorProfile ? { actorProfile } : {}
31
+ };
32
+ } else caller = {
33
+ orgId: "local",
34
+ userId: "local"
35
+ };
36
+ const row = await sessions.getBySessionId(sessionId);
37
+ if (!row?.factoryProjectId) return null;
38
+ if (caller && row.orgId !== caller.orgId) return null;
39
+ const origin = row.originSessionId && row.originThreadId ? {
40
+ sessionId: row.originSessionId,
41
+ threadId: row.originThreadId
42
+ } : void 0;
43
+ const worker = origin !== void 0 || await workItems.hasRunBindingForSession({
44
+ orgId: row.orgId,
45
+ factoryProjectId: row.factoryProjectId,
46
+ sessionId: row.sessionId
47
+ });
48
+ let identity;
49
+ if (worker) identity = {
50
+ orgId: row.orgId,
51
+ userId: row.userId
52
+ };
53
+ else {
54
+ if (!caller) return null;
55
+ if (row.visibility === "private" && row.userId !== caller.userId) return null;
56
+ identity = caller;
57
+ }
58
+ if (!await projects.get({
59
+ orgId: identity.orgId,
60
+ id: row.factoryProjectId
61
+ })) return null;
62
+ return {
63
+ orgId: identity.orgId,
64
+ factoryProjectId: row.factoryProjectId,
65
+ userId: identity.userId,
66
+ sessionId: row.sessionId,
67
+ resourceId,
68
+ threadId,
69
+ kind: worker ? "worker" : "user",
70
+ interactive: requestContext.get(FACTORY_INTERACTIVE_KEY) === true,
71
+ ...identity.actorProfile ? { actorProfile: identity.actorProfile } : {},
72
+ ...origin ? { origin } : {}
73
+ };
74
+ }
75
+ /**
76
+ * Refuses an action only a signed-in person may take. Turns nobody signed in
77
+ * started (notification wakes, webhooks, dispatcher notices) carry text other
78
+ * people wrote, so they can't approve, resolve proposals, or waive plan approval.
79
+ */
80
+ function requirePerson(scope, action) {
81
+ if (scope.interactive) return;
82
+ throw new Error(`Only a person can ${action}. Nobody signed in started this turn (it came from a notification, webhook or rule); ask the person to do it from the board or by messaging this session.`);
83
+ }
84
+ //#endregion
85
+ export { FACTORY_INTERACTIVE_KEY, FACTORY_SLACK_SENDER_KEY, requirePerson, resolveFactoryToolScope };
86
+
87
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","names":[],"sources":["../../src/tools/scope.ts"],"sourcesContent":["import type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\n\nimport {\n FACTORY_INTERACTIVE_KEY,\n factoryUserOrgId,\n getFactoryAuthUserFromContext,\n getFactoryAuthUserId,\n} from '../auth.js';\nimport type { SourceControlSessionLookup } from '../session/factory-session.js';\nimport { auditActorProfile } from '../storage/domains/audit/base.js';\nimport type { AuditActorProfileInput } from '../storage/domains/audit/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { WorkItemsStorage } from '../storage/domains/work-items/base.js';\n\nexport { FACTORY_INTERACTIVE_KEY };\n\n/** Linked Slack sender, separate from the session owner's model-credential identity. */\nexport const FACTORY_SLACK_SENDER_KEY = 'mastra__factorySlackSender';\n\n/** Who is calling Factory tools, and from which session. Everything a tool needs to stay in scope. */\nexport interface FactoryToolScope {\n orgId: string;\n factoryProjectId: string;\n /** The signed-in caller for a user session; the session row's owner for a worker. */\n userId: string;\n /** The source-control session id. */\n sessionId: string;\n /** The memory resource the session runs under. */\n resourceId: string;\n threadId: string;\n /** `worker` sessions are bound to a work item run; only `user` sessions manage the Factory. */\n kind: 'user' | 'worker';\n /** True only for turns a signed-in person started over HTTP (see {@link FACTORY_INTERACTIVE_KEY}). */\n interactive: boolean;\n /** The caller's name and avatar, stamped on audit events so the board can show who acted. */\n actorProfile?: AuditActorProfileInput;\n /** Set for a side session: the user session and thread that started it. */\n origin?: { sessionId: string; threadId: string };\n}\n\nexport interface ResolveFactoryToolScopeOptions {\n requestContext: RequestContext;\n /** `routeAuth.enabled()`; when false every caller is the shared `local` tenant. */\n authEnabled: boolean;\n sessions: Pick<SourceControlSessionLookup, 'getBySessionId'>;\n projects: Pick<FactoryProjectsStorage, 'get'>;\n workItems: Pick<WorkItemsStorage, 'hasRunBindingForSession'>;\n}\n\n/**\n * Resolve the Factory a session's agent may act in. The scope comes from the\n * stored source-control session row and the authenticated caller, never from\n * the `factoryProjectId` thread tag alone: the browser sets that tag and\n * nothing clears it.\n */\nexport async function resolveFactoryToolScope({\n requestContext,\n authEnabled,\n sessions,\n projects,\n workItems,\n}: ResolveFactoryToolScopeOptions): Promise<FactoryToolScope | null> {\n if (typeof requestContext?.get !== 'function') return null;\n const controller = requestContext.get('controller') as AgentControllerRequestContext<unknown> | undefined;\n const sessionId = controller?.sessionId;\n const resourceId = controller?.resourceId;\n const threadId = controller?.threadId;\n if (!sessionId || !resourceId || !threadId) return null;\n\n let caller: { orgId: string; userId: string; actorProfile?: AuditActorProfileInput } | null = null;\n if (authEnabled) {\n const slackSender = requestContext.get(FACTORY_SLACK_SENDER_KEY) as { userId: string; orgId: string } | undefined;\n const user = getFactoryAuthUserFromContext(requestContext);\n if (slackSender && factoryUserOrgId(user) !== slackSender.orgId) return null;\n const userId = slackSender?.userId ?? getFactoryAuthUserId(user);\n const orgId = slackSender?.orgId ?? factoryUserOrgId(user);\n const actorProfile = slackSender ? undefined : auditActorProfile(user);\n if (userId && orgId) caller = { orgId, userId, ...(actorProfile ? { actorProfile } : {}) };\n } else {\n caller = { orgId: 'local', userId: 'local' };\n }\n\n const row = await sessions.getBySessionId(sessionId);\n if (!row?.factoryProjectId) return null;\n // A caller from another org never acts here, worker or not.\n if (caller && row.orgId !== caller.orgId) return null;\n\n // A side session works for the session that started it. Otherwise any\n // binding, active or revoked, on any thread: a session that ever ran a role stays a worker.\n const origin =\n row.originSessionId && row.originThreadId\n ? { sessionId: row.originSessionId, threadId: row.originThreadId }\n : undefined;\n const worker =\n origin !== undefined ||\n (await workItems.hasRunBindingForSession({\n orgId: row.orgId,\n factoryProjectId: row.factoryProjectId,\n sessionId: row.sessionId,\n }));\n\n // A worker acts as its session row: dispatcher-driven runs carry no signed-in user.\n // A user session acts as the signed-in caller, who must be able to see it.\n let identity: { orgId: string; userId: string; actorProfile?: AuditActorProfileInput };\n if (worker) {\n identity = { orgId: row.orgId, userId: row.userId };\n } else {\n if (!caller) return null;\n if (row.visibility === 'private' && row.userId !== caller.userId) return null;\n identity = caller;\n }\n\n const project = await projects.get({ orgId: identity.orgId, id: row.factoryProjectId });\n if (!project) return null;\n\n return {\n orgId: identity.orgId,\n factoryProjectId: row.factoryProjectId,\n userId: identity.userId,\n sessionId: row.sessionId,\n resourceId,\n threadId,\n kind: worker ? 'worker' : 'user',\n interactive: requestContext.get(FACTORY_INTERACTIVE_KEY) === true,\n ...(identity.actorProfile ? { actorProfile: identity.actorProfile } : {}),\n ...(origin ? { origin } : {}),\n };\n}\n\n/**\n * Refuses an action only a signed-in person may take. Turns nobody signed in\n * started (notification wakes, webhooks, dispatcher notices) carry text other\n * people wrote, so they can't approve, resolve proposals, or waive plan approval.\n */\nexport function requirePerson(scope: FactoryToolScope, action: string): void {\n if (scope.interactive) return;\n throw new Error(\n `Only a person can ${action}. Nobody signed in started this turn (it came from a notification, webhook or rule); ask the person to do it from the board or by messaging this session.`,\n );\n}\n"],"mappings":";;;;AAkBA,MAAa,2BAA2B;;;;;;;AAsCxC,eAAsB,wBAAwB,EAC5C,gBACA,aACA,UACA,UACA,aACmE;CACnE,IAAI,OAAO,gBAAgB,QAAQ,YAAY,OAAO;CACtD,MAAM,aAAa,eAAe,IAAI,YAAY;CAClD,MAAM,YAAY,YAAY;CAC9B,MAAM,aAAa,YAAY;CAC/B,MAAM,WAAW,YAAY;CAC7B,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,UAAU,OAAO;CAEnD,IAAI,SAA0F;CAC9F,IAAI,aAAa;EACf,MAAM,cAAc,eAAe,IAAI,wBAAwB;EAC/D,MAAM,OAAO,8BAA8B,cAAc;EACzD,IAAI,eAAe,iBAAiB,IAAI,MAAM,YAAY,OAAO,OAAO;EACxE,MAAM,SAAS,aAAa,UAAU,qBAAqB,IAAI;EAC/D,MAAM,QAAQ,aAAa,SAAS,iBAAiB,IAAI;EACzD,MAAM,eAAe,cAAc,KAAA,IAAY,kBAAkB,IAAI;EACrE,IAAI,UAAU,OAAO,SAAS;GAAE;GAAO;GAAQ,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;EAAG;CAC3F,OACE,SAAS;EAAE,OAAO;EAAS,QAAQ;CAAQ;CAG7C,MAAM,MAAM,MAAM,SAAS,eAAe,SAAS;CACnD,IAAI,CAAC,KAAK,kBAAkB,OAAO;CAEnC,IAAI,UAAU,IAAI,UAAU,OAAO,OAAO,OAAO;CAIjD,MAAM,SACJ,IAAI,mBAAmB,IAAI,iBACvB;EAAE,WAAW,IAAI;EAAiB,UAAU,IAAI;CAAe,IAC/D,KAAA;CACN,MAAM,SACJ,WAAW,KAAA,KACV,MAAM,UAAU,wBAAwB;EACvC,OAAO,IAAI;EACX,kBAAkB,IAAI;EACtB,WAAW,IAAI;CACjB,CAAC;CAIH,IAAI;CACJ,IAAI,QACF,WAAW;EAAE,OAAO,IAAI;EAAO,QAAQ,IAAI;CAAO;MAC7C;EACL,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,IAAI,eAAe,aAAa,IAAI,WAAW,OAAO,QAAQ,OAAO;EACzE,WAAW;CACb;CAGA,IAAI,CAAC,MADiB,SAAS,IAAI;EAAE,OAAO,SAAS;EAAO,IAAI,IAAI;CAAiB,CAAC,GACxE,OAAO;CAErB,OAAO;EACL,OAAO,SAAS;EAChB,kBAAkB,IAAI;EACtB,QAAQ,SAAS;EACjB,WAAW,IAAI;EACf;EACA;EACA,MAAM,SAAS,WAAW;EAC1B,aAAa,eAAe,IAAI,uBAAuB,MAAM;EAC7D,GAAI,SAAS,eAAe,EAAE,cAAc,SAAS,aAAa,IAAI,CAAC;EACvE,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC7B;AACF;;;;;;AAOA,SAAgB,cAAc,OAAyB,QAAsB;CAC3E,IAAI,MAAM,aAAa;CACvB,MAAM,IAAI,MACR,qBAAqB,OAAO,0JAC9B;AACF"}
@@ -0,0 +1,43 @@
1
+ import type { BoardRegistry } from '../boards/registry.js';
2
+ import type { IntegrationTools } from '../integrations/base.js';
3
+ import type { FactoryStartCoordinator } from '../rules/start-coordinator.js';
4
+ import type { SourceControlSessionLookup } from '../session/factory-session.js';
5
+ import type { AuditRecorder } from '../storage/domains/audit/domain.js';
6
+ import type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';
7
+ import type { CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';
8
+ import type { IntakeStorage } from '../storage/domains/intake/base.js';
9
+ import type { ModelDefaultsStorage } from '../storage/domains/model-defaults/base.js';
10
+ import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';
11
+ import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
12
+ import type { FactoryMessaging } from './messaging-tools.js';
13
+ import type { FactoryToolScope } from './scope.js';
14
+ /** Who renews the open-run entries this process writes; one id per process, like the dispatcher's. */
15
+ export declare const FACTORY_TOOLS_OWNER_ID: string;
16
+ export interface FactorySessionToolDependencies {
17
+ sessions: Pick<SourceControlSessionLookup, 'getBySessionId' | 'getSourceControlBySessionId'>;
18
+ sessionModel: {
19
+ projects: FactoryProjectsStorage;
20
+ modelDefaults: ModelDefaultsStorage;
21
+ /**
22
+ * Tenant credential stores, present when auth is on. Model switches then
23
+ * check the target session's credential scope, like the Settings picker;
24
+ * without them the server's own keys decide.
25
+ */
26
+ tenantCatalog?: {
27
+ credentials: Pick<ModelCredentialsStorage, 'listCredentials'>;
28
+ customProviders?: Pick<CustomProvidersStorage, 'ensureReady' | 'list'>;
29
+ deploymentProviders?: ReadonlySet<string>;
30
+ };
31
+ };
32
+ /** Resolved lazily: the controller only exists once the mount is up. */
33
+ messaging: () => Promise<FactoryMessaging | null>;
34
+ workItems: Pick<WorkItemsStorage, 'list' | 'getForProject' | 'listRunBindings' | 'findActiveRunBindingForSession' | 'findRunBindingByThread' | 'hasRunBindingForSession' | 'subscribeToWorkItem' | 'unsubscribeFromWorkItem' | 'listSessionSubscriptions' | 'listWorkItemSubscribers'>;
35
+ boards: BoardRegistry;
36
+ auditRecorder: AuditRecorder;
37
+ intake?: Pick<IntakeStorage, 'getConfig'>;
38
+ /** The browser Start's coordinator; absent until the Factory runtime is ready. */
39
+ startCoordinator: () => Pick<FactoryStartCoordinator, 'prepare'> | undefined;
40
+ }
41
+ /** Tools that start sessions on the caller's behalf, or switch their models. User sessions only. */
42
+ export declare function createFactorySessionTools(scope: FactoryToolScope, deps: FactorySessionToolDependencies): IntegrationTools;
43
+ //# sourceMappingURL=session-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tools.d.ts","sourceRoot":"","sources":["../../src/tools/session-tools.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAKhE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAE7E,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAQhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAElF,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAE3F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,sGAAsG;AACtG,eAAO,MAAM,sBAAsB,QAAoD,CAAC;AAExF,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,IAAI,CAAC,0BAA0B,EAAE,gBAAgB,GAAG,6BAA6B,CAAC,CAAC;IAC7F,YAAY,EAAE;QACZ,QAAQ,EAAE,sBAAsB,CAAC;QACjC,aAAa,EAAE,oBAAoB,CAAC;QACpC;;;;WAIG;QACH,aAAa,CAAC,EAAE;YACd,WAAW,EAAE,IAAI,CAAC,uBAAuB,EAAE,iBAAiB,CAAC,CAAC;YAC9D,eAAe,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,GAAG,MAAM,CAAC,CAAC;YACvE,mBAAmB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;SAC3C,CAAC;KACH,CAAC;IACF,wEAAwE;IACxE,SAAS,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAClD,SAAS,EAAE,IAAI,CACb,gBAAgB,EACd,MAAM,GACN,eAAe,GACf,iBAAiB,GACjB,gCAAgC,GAChC,wBAAwB,GACxB,yBAAyB,GACzB,qBAAqB,GACrB,yBAAyB,GACzB,0BAA0B,GAC1B,yBAAyB,CAC5B,CAAC;IACF,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAC1C,kFAAkF;IAClF,gBAAgB,EAAE,MAAM,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC;CAC9E;AA0BD,oGAAoG;AACpG,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,8BAA8B,GACnC,gBAAgB,CAsYlB"}
@@ -0,0 +1,410 @@
1
+ import { boardForWorkItem } from "../boards/semantics.js";
2
+ import "../boards/index.js";
3
+ import { primeTenantCredentialsForTenant } from "../routes/tenant-credentials.js";
4
+ import { effectiveModelScope } from "../storage/domains/projects/base.js";
5
+ import { ensureFactorySourceSession, hydrateFactorySession, resolveFactorySessionModel } from "../session/factory-session.js";
6
+ import { resolveSessionThread } from "./deliver.js";
7
+ import { findWorkItem, workItemNotFound, workItemNumber, workItemRefSchema } from "./read-tools.js";
8
+ import { resolveFactoryModelPolicy } from "../session/credential-policy.js";
9
+ import { buildModelCatalog, listSessionScopedCredentials } from "../routes/config.js";
10
+ import { USER_SESSION_BRANCH_PREFIX } from "../routes/source-control-sessions.js";
11
+ import { resolveWorkItemRepository } from "../session/work-item-repository.js";
12
+ import { FactoryStartTransitionError, WorkItemRepositoryError } from "../rules/start-coordinator.js";
13
+ import { recordSessionRunStart } from "../session/run-audit.js";
14
+ import { heartbeatOpenRunUntilEnd } from "./run-watch.js";
15
+ import { RequestContext } from "@mastra/core/request-context";
16
+ import { z } from "zod";
17
+ import { createTool } from "@mastra/core/tools";
18
+ //#region src/tools/session-tools.ts
19
+ const TITLE_LENGTH = 120;
20
+ /** Who renews the open-run entries this process writes; one id per process, like the dispatcher's. */
21
+ const FACTORY_TOOLS_OWNER_ID = `factory-tools:${globalThis.crypto.randomUUID()}`;
22
+ const LISTED_MODELS = 8;
23
+ function ambiguousRepository(candidates) {
24
+ return `This item has several repositories (${candidates.join(", ")}); v1 can't choose one.`;
25
+ }
26
+ function startErrorMessage(error) {
27
+ if (error instanceof WorkItemRepositoryError) return error.code === "repository_ambiguous" ? ambiguousRepository(error.candidates) : error.message;
28
+ if (error instanceof FactoryStartTransitionError) return `The start was refused: ${error.result.reason}`;
29
+ return null;
30
+ }
31
+ function workItemLabel(item) {
32
+ const number = workItemNumber(item);
33
+ return number === null ? `"${item.title}"` : `#${number}`;
34
+ }
35
+ function titleFrom(prompt) {
36
+ return (prompt.split("\n").find((line) => line.trim()) ?? prompt).trim().slice(0, TITLE_LENGTH);
37
+ }
38
+ /** Tools that start sessions on the caller's behalf, or switch their models. User sessions only. */
39
+ function createFactorySessionTools(scope, deps) {
40
+ /** The models a session can switch to, resolved from the target session's owner and project policy. */
41
+ async function sessionModelCatalog(controller, sessionId, threadId, resourceId) {
42
+ const models = await controller.listAvailableModels();
43
+ const known = new Set(models.flatMap((model) => typeof model.id === "string" ? [model.id] : []));
44
+ const tenantCatalog = deps.sessionModel.tenantCatalog;
45
+ if (!tenantCatalog) return {
46
+ usable: (await buildModelCatalog({ controller })).map((model) => model.id),
47
+ known,
48
+ scopeLabel: "server"
49
+ };
50
+ const requestContext = new RequestContext();
51
+ requestContext.set("user", {
52
+ id: scope.userId,
53
+ organizationId: scope.orgId
54
+ });
55
+ requestContext.set("controller", {
56
+ sessionId,
57
+ resourceId,
58
+ threadId
59
+ });
60
+ const policy = await resolveFactoryModelPolicy(requestContext, {
61
+ projects: deps.sessionModel.projects,
62
+ sourceControl: deps.sessions,
63
+ workItems: deps.workItems
64
+ });
65
+ if (!policy) throw new Error("Session model policy is unavailable.");
66
+ const modelScope = policy.tenant.credentialScope ?? "user";
67
+ const orgId = policy.tenant.orgId ?? scope.orgId;
68
+ const customProviders = tenantCatalog.customProviders;
69
+ const usable = (await buildModelCatalog({
70
+ controller,
71
+ tenantCredentials: await listSessionScopedCredentials({
72
+ credentials: tenantCatalog.credentials,
73
+ orgId,
74
+ userId: policy.tenant.userId,
75
+ modelScope
76
+ }),
77
+ deploymentProviders: tenantCatalog.deploymentProviders,
78
+ listCustomProviders: customProviders ? async () => {
79
+ await customProviders.ensureReady();
80
+ return customProviders.list({ orgId });
81
+ } : void 0
82
+ })).map((model) => model.id);
83
+ for (const id of usable) known.add(id);
84
+ return {
85
+ usable,
86
+ known,
87
+ scopeLabel: modelScope === "factory" ? "Factory" : "session owner"
88
+ };
89
+ }
90
+ const switchModel = createTool({
91
+ id: "factory_switch_session_model",
92
+ description: "Switch the model of a session you own in this Factory (side, work item, or review session) without recreating it. A running session switches immediately; a stopped one uses the model on its next run. The model must be one the session credentials can run: the owner credentials for a user-scoped session, the Factory credentials for a Factory-scoped one. Use a session ID from the Factory session or work item tools.",
93
+ inputSchema: z.object({
94
+ sessionId: z.string().trim().min(1).max(200),
95
+ modelId: z.string().trim().min(1).max(200)
96
+ }).strict(),
97
+ execute: async ({ sessionId, modelId }) => {
98
+ const row = await deps.sessions.getBySessionId(sessionId);
99
+ if (!row || row.orgId !== scope.orgId || row.factoryProjectId !== scope.factoryProjectId || row.userId !== scope.userId) throw new Error("Session not found or not owned by you in this Factory.");
100
+ if (!scope.interactive && sessionId !== scope.sessionId && row.originSessionId !== scope.sessionId) throw new Error("Without a person in this turn, only this session and the side sessions it started can switch models.");
101
+ const messaging = await deps.messaging();
102
+ if (!messaging) throw new Error("Session model switching is not available on this server.");
103
+ const threadId = await resolveSessionThread({
104
+ controller: messaging.controller,
105
+ sessions: deps.sessions,
106
+ workItems: deps.workItems,
107
+ sessionId
108
+ });
109
+ if (!threadId) throw new Error("Session has no conversation thread yet.");
110
+ const resourceId = (await messaging.controller.queryThreadById({ threadId }))?.resourceId ?? sessionId;
111
+ const catalog = await sessionModelCatalog(messaging.controller, sessionId, threadId, resourceId);
112
+ if (!catalog.usable.includes(modelId)) {
113
+ const options = catalog.usable.length ? ` Models available to it: ${catalog.usable.slice(0, LISTED_MODELS).join(", ")}${catalog.usable.length > LISTED_MODELS ? ", …" : ""}.` : " No models are available to it; connect a provider credential first.";
114
+ throw new Error(catalog.known.has(modelId) ? `Model ${modelId} exists, but this session's credential scope (${catalog.scopeLabel}) has no credential for its provider.${options}` : `Unknown model ${modelId}.${options}`);
115
+ }
116
+ const { live } = await messaging.controller.setThreadModel({
117
+ resourceId,
118
+ threadId,
119
+ modelId
120
+ });
121
+ return {
122
+ sessionId,
123
+ threadId,
124
+ modelId,
125
+ live
126
+ };
127
+ }
128
+ });
129
+ const start = createTool({
130
+ id: "factory_start_session",
131
+ description: [
132
+ "Start a side session in this Factory with a prompt. It runs on its own sandbox and branch as you, and reports back to this session with `factory-session` notifications.",
133
+ "Use it for self-contained investigations; when the result should land as a pull request, file a work item instead.",
134
+ "With `workItem` and `role` it starts that role on the work item instead, without moving the card, and this session follows the item.",
135
+ "A role that already has a session on the item (current or past) can't be started again from here: message that session with factory_signal_session, or ask the person to use the board."
136
+ ].join(" "),
137
+ inputSchema: z.object({
138
+ prompt: z.string().trim().min(1).max(8e3).describe("The first message the new session receives."),
139
+ title: z.string().trim().min(1).max(TITLE_LENGTH).optional(),
140
+ workItem: workItemRefSchema.optional(),
141
+ role: z.string().trim().min(1).max(64).optional()
142
+ }).strict().refine((input) => input.role === void 0 || input.workItem !== void 0, {
143
+ message: "Pass workItem together with role.",
144
+ path: ["role"]
145
+ }),
146
+ execute: async ({ prompt, title, workItem, role }) => {
147
+ if (workItem !== void 0) {
148
+ if (!scope.interactive) throw new Error("Starting a role on a work item needs a person in this turn; start a side session, or ask the person to use the board.");
149
+ return startWorkItemRole({
150
+ prompt,
151
+ title,
152
+ workItem,
153
+ role
154
+ });
155
+ }
156
+ const parent = await deps.sessions.getBySessionId(scope.sessionId);
157
+ const sourceControl = await deps.sessions.getSourceControlBySessionId(scope.sessionId);
158
+ if (!parent || !sourceControl) throw new Error("This session has no Factory session row to start from.");
159
+ const messaging = await deps.messaging();
160
+ if (!messaging) throw new Error("Starting sessions is not available on this server.");
161
+ const sessionId = globalThis.crypto.randomUUID();
162
+ const ensured = await ensureFactorySourceSession({
163
+ sourceControl,
164
+ orgId: scope.orgId,
165
+ factoryProjectId: scope.factoryProjectId,
166
+ sessionId,
167
+ branch: `${USER_SESSION_BRANCH_PREFIX}${sessionId}`,
168
+ attributeToUserId: scope.userId,
169
+ ...parent.projectRepositoryId ? { projectRepositoryId: parent.projectRepositoryId } : {},
170
+ visibility: parent.visibility,
171
+ origin: {
172
+ sessionId: scope.sessionId,
173
+ threadId: scope.threadId
174
+ }
175
+ });
176
+ const sessionModel = await resolveFactorySessionModel({
177
+ ...deps.sessionModel,
178
+ factoryProjectId: scope.factoryProjectId,
179
+ orgId: scope.orgId,
180
+ ownerUserId: scope.userId,
181
+ context: "session"
182
+ });
183
+ const kickoffContext = new RequestContext();
184
+ kickoffContext.set("user", {
185
+ workosId: scope.userId,
186
+ organizationId: scope.orgId
187
+ });
188
+ const tags = {
189
+ factoryProjectId: scope.factoryProjectId,
190
+ projectRepositoryId: ensured.projectRepositoryId
191
+ };
192
+ const session = await messaging.controller.createSession({
193
+ id: ensured.sessionId,
194
+ ownerId: scope.userId,
195
+ resourceId: parent.visibility === "private" ? scope.userId : scope.factoryProjectId,
196
+ threadId: ensured.sessionId,
197
+ requestContext: kickoffContext,
198
+ tags
199
+ });
200
+ await session.state.set(tags);
201
+ await hydrateFactorySession(session, {
202
+ orgId: scope.orgId,
203
+ modelScope: sessionModel.modelScope,
204
+ ownerUserId: scope.userId,
205
+ defaultModelId: sessionModel.modelId
206
+ });
207
+ const threadId = session.thread.requireId();
208
+ const threadTitle = title ?? titleFrom(prompt);
209
+ await session.thread.rename({
210
+ title: threadTitle,
211
+ pin: false
212
+ });
213
+ await sourceControl.sessions.rename({
214
+ sessionId: ensured.sessionId,
215
+ title: threadTitle
216
+ });
217
+ await session.thread.setSetting({
218
+ key: "factorySessionId",
219
+ value: ensured.sessionId
220
+ });
221
+ await primeTenantCredentialsForTenant({
222
+ orgId: scope.orgId,
223
+ userId: scope.userId,
224
+ credentialScope: sessionModel.modelScope
225
+ });
226
+ await session.sendSignal({
227
+ id: globalThis.crypto.randomUUID(),
228
+ type: "user",
229
+ tagName: "user",
230
+ contents: prompt
231
+ }, {
232
+ requestContext: kickoffContext,
233
+ requireDelivery: true
234
+ }).accepted;
235
+ return {
236
+ mode: "side",
237
+ sessionId: ensured.sessionId,
238
+ threadId,
239
+ title: threadTitle
240
+ };
241
+ }
242
+ });
243
+ async function startWorkItemRole({ prompt, title, workItem, role }) {
244
+ if (!role) throw new Error("Pass the role to start on the work item.");
245
+ const coordinator = deps.startCoordinator();
246
+ if (!coordinator) throw new Error("Factory sessions can't be started yet; try again shortly.");
247
+ const item = await findWorkItem(deps.workItems, scope, workItem);
248
+ if (!item) throw workItemNotFound(workItem);
249
+ const label = workItemLabel(item);
250
+ if (!deps.boards.get(boardForWorkItem(item))?.phaseForRole(role)) throw new Error(`${label}'s board has no ${role} role.`);
251
+ const seated = item.sessions[role];
252
+ if (seated) throw new Error(`${label} already has a ${role} session ${seated.sessionId}; message it with factory_signal_session.`);
253
+ const parent = await deps.sessions.getBySessionId(scope.sessionId);
254
+ const sourceControl = await deps.sessions.getSourceControlBySessionId(scope.sessionId);
255
+ if (!parent || !sourceControl) throw new Error("This session has no Factory session row to start from.");
256
+ const messaging = await deps.messaging();
257
+ if (!messaging) throw new Error("Starting sessions is not available on this server.");
258
+ const project = await deps.sessionModel.projects.get({
259
+ orgId: scope.orgId,
260
+ id: scope.factoryProjectId
261
+ });
262
+ if (!project) throw new Error("This Factory no longer exists.");
263
+ const modelScope = effectiveModelScope(project.modelScope, "run");
264
+ const projectRepositoryId = await resolveRepository(sourceControl, item);
265
+ const sessionId = globalThis.crypto.randomUUID();
266
+ const ensured = await ensureFactorySourceSession({
267
+ sourceControl,
268
+ orgId: scope.orgId,
269
+ factoryProjectId: scope.factoryProjectId,
270
+ sessionId,
271
+ branch: `${USER_SESSION_BRANCH_PREFIX}${sessionId}`,
272
+ projectRepositoryId,
273
+ attributeToUserId: scope.userId,
274
+ visibility: parent.visibility
275
+ });
276
+ const followScope = {
277
+ orgId: scope.orgId,
278
+ factoryProjectId: scope.factoryProjectId
279
+ };
280
+ const alreadyFollowing = (await deps.workItems.listSessionSubscriptions({
281
+ ...followScope,
282
+ sessionId: scope.sessionId
283
+ })).some((subscription) => subscription.workItemId === item.id);
284
+ await deps.workItems.subscribeToWorkItem({
285
+ ...followScope,
286
+ workItemId: item.id,
287
+ sessionId: scope.sessionId,
288
+ threadId: scope.threadId,
289
+ resourceId: scope.resourceId,
290
+ userId: scope.userId,
291
+ reason: "started"
292
+ });
293
+ const startedAt = /* @__PURE__ */ new Date();
294
+ let prepared;
295
+ try {
296
+ prepared = await coordinator.prepare({
297
+ orgId: scope.orgId,
298
+ userId: scope.userId,
299
+ factoryProjectId: scope.factoryProjectId,
300
+ sessionId: ensured.sessionId,
301
+ threadTitle: title ?? `${label} ${role}`,
302
+ kickoffKey: globalThis.crypto.randomUUID(),
303
+ modelScope,
304
+ defaultModelId: modelScope === "factory" ? project.defaultModelId ?? void 0 : void 0,
305
+ workItem: {
306
+ id: item.id,
307
+ role,
308
+ input: {
309
+ externalSource: item.externalSource,
310
+ parentWorkItemId: item.parentWorkItemId,
311
+ title: item.title,
312
+ stages: item.stages,
313
+ sessions: item.sessions,
314
+ metadata: item.metadata
315
+ }
316
+ }
317
+ });
318
+ } catch (error) {
319
+ if (!alreadyFollowing) await deps.workItems.unsubscribeFromWorkItem({
320
+ orgId: scope.orgId,
321
+ workItemId: item.id,
322
+ sessionId: scope.sessionId
323
+ });
324
+ const message = startErrorMessage(error);
325
+ if (message) throw new Error(message);
326
+ throw error;
327
+ }
328
+ const replaced = (await deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId, item.id)).find((binding) => binding.role === role && binding.id !== prepared.bindingId && binding.revokedAt !== null && binding.revokedAt >= startedAt);
329
+ const session = await messaging.controller.getSession(prepared.sessionId);
330
+ if (!session) throw new Error(`The ${role} session was bound but is not running; open it from the board.`);
331
+ const kickoffId = globalThis.crypto.randomUUID();
332
+ const heartbeat = heartbeatOpenRunUntilEnd(session, kickoffId);
333
+ const kickoffContext = new RequestContext();
334
+ kickoffContext.set("user", {
335
+ workosId: scope.userId,
336
+ organizationId: scope.orgId
337
+ });
338
+ try {
339
+ await session.sendSignal({
340
+ id: kickoffId,
341
+ type: "user",
342
+ tagName: "user",
343
+ contents: prompt
344
+ }, {
345
+ requestContext: kickoffContext,
346
+ requireDelivery: true
347
+ }).accepted;
348
+ } catch (error) {
349
+ heartbeat.stop();
350
+ throw error;
351
+ }
352
+ await recordSessionRunStart(session, {
353
+ audit: deps.auditRecorder,
354
+ actorType: "human",
355
+ observedEnd: heartbeat.endReason,
356
+ run: {
357
+ kickoffId,
358
+ ownerId: FACTORY_TOOLS_OWNER_ID,
359
+ heartbeatAt: Date.now(),
360
+ bindingId: prepared.bindingId,
361
+ role,
362
+ startedBy: scope.userId,
363
+ orgId: scope.orgId,
364
+ factoryProjectId: scope.factoryProjectId,
365
+ workItemId: item.id,
366
+ workItemName: item.title,
367
+ sessionId: prepared.sessionId,
368
+ threadId: prepared.threadId,
369
+ branch: prepared.branch
370
+ }
371
+ });
372
+ const number = workItemNumber(item);
373
+ return {
374
+ mode: "work-item",
375
+ workItem: {
376
+ id: item.id,
377
+ ...number === null ? {} : { number }
378
+ },
379
+ role,
380
+ sessionId: prepared.sessionId,
381
+ threadId: prepared.threadId,
382
+ bindingId: prepared.bindingId,
383
+ ...replaced ? { replacedSessionId: replaced.sessionId } : {}
384
+ };
385
+ }
386
+ async function resolveRepository(sourceControl, item) {
387
+ const intakeConfig = await deps.intake?.getConfig({
388
+ orgId: scope.orgId,
389
+ integrationIds: ["linear"]
390
+ });
391
+ const repository = await resolveWorkItemRepository({
392
+ sourceControl,
393
+ orgId: scope.orgId,
394
+ factoryProjectId: scope.factoryProjectId,
395
+ item,
396
+ linearRepositoryMap: intakeConfig?.linear?.repositoryByLinearProject
397
+ });
398
+ if (repository.status === "ambiguous") throw new Error(ambiguousRepository(repository.candidates));
399
+ if (repository.status === "unlinked") throw new Error(repository.hint);
400
+ return repository.projectRepositoryId;
401
+ }
402
+ return {
403
+ factory_start_session: start,
404
+ factory_switch_session_model: switchModel
405
+ };
406
+ }
407
+ //#endregion
408
+ export { FACTORY_TOOLS_OWNER_ID, createFactorySessionTools };
409
+
410
+ //# sourceMappingURL=session-tools.js.map