@mastra/factory 0.25.0-alpha.4 → 0.25.0-alpha.6

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 (358) hide show
  1. package/README.md +3 -1
  2. package/dist/auth.js +1 -2
  3. package/dist/boards/define-board.js +1 -2
  4. package/dist/boards/index.js +1 -2
  5. package/dist/boards/registry.js +1 -2
  6. package/dist/boards/relocate.js +1 -2
  7. package/dist/boards/review.js +1 -2
  8. package/dist/boards/semantics.js +1 -2
  9. package/dist/boards/transition-policy.js +1 -2
  10. package/dist/boards/work-tool-rules.js +1 -2
  11. package/dist/boards/work-transition-policy.js +1 -2
  12. package/dist/boards/work.js +1 -2
  13. package/dist/default-thinking-level.d.ts +3 -0
  14. package/dist/default-thinking-level.d.ts.map +1 -0
  15. package/dist/default-thinking-level.js +5 -0
  16. package/dist/default-thinking-level.js.map +1 -0
  17. package/dist/environment/build-runner.js +1 -2
  18. package/dist/environment/build-schedule.js +1 -2
  19. package/dist/environment/build-workflow.js +1 -2
  20. package/dist/environment/build.js +1 -2
  21. package/dist/environment/heads.js +1 -2
  22. package/dist/factory.d.ts +4 -2
  23. package/dist/factory.d.ts.map +1 -1
  24. package/dist/factory.js +62 -21
  25. package/dist/factory.js.map +1 -1
  26. package/dist/feed-events.js +1 -2
  27. package/dist/index.js +2 -2
  28. package/dist/integrations/channel-thread-announcements.d.ts +8 -0
  29. package/dist/integrations/channel-thread-announcements.d.ts.map +1 -0
  30. package/dist/integrations/channel-thread-announcements.js +16 -0
  31. package/dist/integrations/channel-thread-announcements.js.map +1 -0
  32. package/dist/integrations/github/acceptance-labels.js +1 -2
  33. package/dist/integrations/github/app-identity.js +1 -2
  34. package/dist/integrations/github/commits.js +1 -2
  35. package/dist/integrations/github/config.js +1 -2
  36. package/dist/integrations/github/default-rules.js +2 -3
  37. package/dist/integrations/github/integration.js +3 -4
  38. package/dist/integrations/github/issue-reconciler.js +1 -2
  39. package/dist/integrations/github/pat.js +1 -2
  40. package/dist/integrations/github/provenance.d.ts.map +1 -1
  41. package/dist/integrations/github/provenance.js +2 -5
  42. package/dist/integrations/github/provenance.js.map +1 -1
  43. package/dist/integrations/github/reconcile-worker.js +1 -2
  44. package/dist/integrations/github/reconciliation-config.js +1 -2
  45. package/dist/integrations/github/routes.js +4 -5
  46. package/dist/integrations/github/rules.d.ts.map +1 -1
  47. package/dist/integrations/github/rules.js +14 -3
  48. package/dist/integrations/github/rules.js.map +1 -1
  49. package/dist/integrations/github/sandbox-release.js +1 -2
  50. package/dist/integrations/github/sandbox.js +1 -2
  51. package/dist/integrations/github/session-subscriptions.js +1 -2
  52. package/dist/integrations/github/settle-or-abort.js +1 -2
  53. package/dist/integrations/github/stale-reviews.js +1 -2
  54. package/dist/integrations/github/subscriptions.js +1 -2
  55. package/dist/integrations/github/token-refresh.js +1 -2
  56. package/dist/integrations/github/webhook.d.ts.map +1 -1
  57. package/dist/integrations/github/webhook.js +17 -3
  58. package/dist/integrations/github/webhook.js.map +1 -1
  59. package/dist/integrations/gitlab/agent-tools.js +1 -2
  60. package/dist/integrations/gitlab/api.js +1 -2
  61. package/dist/integrations/gitlab/default-rules.js +1 -2
  62. package/dist/integrations/gitlab/integration.d.ts +4 -0
  63. package/dist/integrations/gitlab/integration.d.ts.map +1 -1
  64. package/dist/integrations/gitlab/integration.js +12 -4
  65. package/dist/integrations/gitlab/integration.js.map +1 -1
  66. package/dist/integrations/gitlab/issue-reconciler.js +1 -2
  67. package/dist/integrations/gitlab/merge-request-reconciler.js +1 -2
  68. package/dist/integrations/gitlab/reconciler.js +1 -2
  69. package/dist/integrations/gitlab/reconciliation-config.js +1 -2
  70. package/dist/integrations/gitlab/routes.d.ts +6 -0
  71. package/dist/integrations/gitlab/routes.d.ts.map +1 -1
  72. package/dist/integrations/gitlab/routes.js +154 -3
  73. package/dist/integrations/gitlab/routes.js.map +1 -1
  74. package/dist/integrations/gitlab/rules.d.ts.map +1 -1
  75. package/dist/integrations/gitlab/rules.js +5 -3
  76. package/dist/integrations/gitlab/rules.js.map +1 -1
  77. package/dist/integrations/gitlab/session-subscriptions.js +1 -2
  78. package/dist/integrations/gitlab/subscriptions.js +1 -2
  79. package/dist/integrations/gitlab/version-control.js +1 -2
  80. package/dist/integrations/gitlab/webhook-dispatch.js +1 -2
  81. package/dist/integrations/gitlab/webhook.js +1 -2
  82. package/dist/integrations/incidentio/agent-tools.js +1 -2
  83. package/dist/integrations/incidentio/api.js +1 -2
  84. package/dist/integrations/incidentio/claim.js +1 -2
  85. package/dist/integrations/incidentio/default-rules.js +1 -2
  86. package/dist/integrations/incidentio/intake.js +1 -2
  87. package/dist/integrations/incidentio/integration.js +1 -2
  88. package/dist/integrations/incidentio/issue-reconciler.js +1 -2
  89. package/dist/integrations/incidentio/reconciliation-config.js +1 -2
  90. package/dist/integrations/incidentio/routes.js +1 -2
  91. package/dist/integrations/incidentio/rules.js +1 -2
  92. package/dist/integrations/issue-reconcile-worker.js +1 -2
  93. package/dist/integrations/issue-reconciler.js +1 -2
  94. package/dist/integrations/jira/adf.js +1 -2
  95. package/dist/integrations/jira/agent-tools.js +1 -2
  96. package/dist/integrations/jira/api.d.ts +1 -1
  97. package/dist/integrations/jira/api.d.ts.map +1 -1
  98. package/dist/integrations/jira/api.js +2 -3
  99. package/dist/integrations/jira/api.js.map +1 -1
  100. package/dist/integrations/jira/claim.js +1 -2
  101. package/dist/integrations/jira/default-rules.js +1 -2
  102. package/dist/integrations/jira/integration.d.ts +3 -1
  103. package/dist/integrations/jira/integration.d.ts.map +1 -1
  104. package/dist/integrations/jira/integration.js +18 -4
  105. package/dist/integrations/jira/integration.js.map +1 -1
  106. package/dist/integrations/jira/issue-reconciler.js +1 -2
  107. package/dist/integrations/jira/reconciliation-config.js +1 -2
  108. package/dist/integrations/jira/routes.js +1 -2
  109. package/dist/integrations/jira/rules.js +1 -2
  110. package/dist/integrations/linear/agent-tools.d.ts +1 -1
  111. package/dist/integrations/linear/agent-tools.d.ts.map +1 -1
  112. package/dist/integrations/linear/agent-tools.js +5 -5
  113. package/dist/integrations/linear/agent-tools.js.map +1 -1
  114. package/dist/integrations/linear/claim.js +1 -2
  115. package/dist/integrations/linear/default-rules.js +1 -2
  116. package/dist/integrations/linear/integration.d.ts +2 -0
  117. package/dist/integrations/linear/integration.d.ts.map +1 -1
  118. package/dist/integrations/linear/integration.js +2 -2
  119. package/dist/integrations/linear/integration.js.map +1 -1
  120. package/dist/integrations/linear/issue-reconciler.js +1 -2
  121. package/dist/integrations/linear/reconciliation-config.js +1 -2
  122. package/dist/integrations/linear/routes.js +1 -2
  123. package/dist/integrations/linear/rules.js +1 -2
  124. package/dist/integrations/platform/api-client.js +1 -2
  125. package/dist/integrations/platform/connect/routes.js +1 -2
  126. package/dist/integrations/platform/github/event-worker.js +6 -2
  127. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  128. package/dist/integrations/platform/github/integration.js +1 -2
  129. package/dist/integrations/platform/gitlab/event-worker.js +1 -2
  130. package/dist/integrations/platform/gitlab/integration.js +1 -2
  131. package/dist/integrations/platform/incidentio/integration.js +1 -2
  132. package/dist/integrations/platform/jira/agent-tools.js +1 -2
  133. package/dist/integrations/platform/jira/integration.js +1 -2
  134. package/dist/integrations/platform/jira/routes.js +1 -2
  135. package/dist/integrations/platform/linear/event-worker.js +1 -2
  136. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  137. package/dist/integrations/platform/linear/integration.js +2 -2
  138. package/dist/integrations/platform/linear/integration.js.map +1 -1
  139. package/dist/integrations/pull-request-head.d.ts +1 -0
  140. package/dist/integrations/pull-request-head.d.ts.map +1 -1
  141. package/dist/integrations/pull-request-head.js +3 -3
  142. package/dist/integrations/pull-request-head.js.map +1 -1
  143. package/dist/integrations/reconciliation-config.js +1 -2
  144. package/dist/integrations/slack/channel-reply-processor.d.ts +1 -0
  145. package/dist/integrations/slack/channel-reply-processor.d.ts.map +1 -1
  146. package/dist/integrations/slack/channel-reply-processor.js +16 -6
  147. package/dist/integrations/slack/channel-reply-processor.js.map +1 -1
  148. package/dist/integrations/slack/channel-session-link-processor.d.ts +1 -0
  149. package/dist/integrations/slack/channel-session-link-processor.d.ts.map +1 -1
  150. package/dist/integrations/slack/channel-session-link-processor.js +2 -3
  151. package/dist/integrations/slack/channel-session-link-processor.js.map +1 -1
  152. package/dist/integrations/slack/connect-route.js +1 -2
  153. package/dist/integrations/slack/emoji-shortcodes.generated.js +1 -2
  154. package/dist/integrations/slack/emoji.js +1 -2
  155. package/dist/integrations/slack/feed-publisher.js +1 -2
  156. package/dist/integrations/slack/integration.d.ts +5 -0
  157. package/dist/integrations/slack/integration.d.ts.map +1 -1
  158. package/dist/integrations/slack/integration.js +13 -2
  159. package/dist/integrations/slack/integration.js.map +1 -1
  160. package/dist/integrations/slack/reply-reminder-processor.js +1 -2
  161. package/dist/integrations/slack/reply-tool.d.ts.map +1 -1
  162. package/dist/integrations/slack/reply-tool.js +4 -13
  163. package/dist/integrations/slack/reply-tool.js.map +1 -1
  164. package/dist/integrations/slack/run-error-card.d.ts +3 -0
  165. package/dist/integrations/slack/run-error-card.d.ts.map +1 -0
  166. package/dist/integrations/slack/run-error-card.js +44 -0
  167. package/dist/integrations/slack/run-error-card.js.map +1 -0
  168. package/dist/integrations/slack/share-file-tool.js +1 -2
  169. package/dist/integrations/slack/slack.d.ts.map +1 -1
  170. package/dist/integrations/slack/slack.js +7 -4
  171. package/dist/integrations/slack/slack.js.map +1 -1
  172. package/dist/integrations/subscription-session.js +1 -2
  173. package/dist/integrations/workos/integration.js +1 -2
  174. package/dist/mcp/disconnect.js +1 -2
  175. package/dist/mcp/events.js +2 -3
  176. package/dist/mcp/routes.js +1 -2
  177. package/dist/packages/_internals/workspace/dist/index.js +1 -2
  178. package/dist/packages/_internals/workspace/dist/index.js.map +1 -1
  179. package/dist/platform-auth-host.js +1 -2
  180. package/dist/provider-display-name.js +1 -2
  181. package/dist/review-verdict.d.ts +1 -0
  182. package/dist/review-verdict.d.ts.map +1 -1
  183. package/dist/review-verdict.js +9 -3
  184. package/dist/review-verdict.js.map +1 -1
  185. package/dist/routes/attention-activity.js +1 -2
  186. package/dist/routes/attention-parked.js +1 -2
  187. package/dist/routes/attention-proposed.js +1 -2
  188. package/dist/routes/attention-providers.js +1 -2
  189. package/dist/routes/attention.js +1 -2
  190. package/dist/routes/automation-runs.js +1 -2
  191. package/dist/routes/config.d.ts +7 -0
  192. package/dist/routes/config.d.ts.map +1 -1
  193. package/dist/routes/config.js +29 -3
  194. package/dist/routes/config.js.map +1 -1
  195. package/dist/routes/contracts.js +1 -2
  196. package/dist/routes/custom-provider-source.js +1 -2
  197. package/dist/routes/fs.js +1 -2
  198. package/dist/routes/intake.js +6 -4
  199. package/dist/routes/intake.js.map +1 -1
  200. package/dist/routes/knowledge.js +1 -2
  201. package/dist/routes/oauth.js +1 -2
  202. package/dist/routes/projects.js +1 -2
  203. package/dist/routes/provider-credentials.js +1 -2
  204. package/dist/routes/route.js +1 -2
  205. package/dist/routes/session-access.js +1 -2
  206. package/dist/routes/skills.js +1 -2
  207. package/dist/routes/source-control-sessions.js +5 -6
  208. package/dist/routes/source-control-settings.js +1 -2
  209. package/dist/routes/surface.js +3 -4
  210. package/dist/routes/surface.js.map +1 -1
  211. package/dist/routes/telemetry.js +1 -2
  212. package/dist/routes/tenant-credentials.js +1 -2
  213. package/dist/routes/work-items.js +2 -3
  214. package/dist/rules/binding-context.js +1 -2
  215. package/dist/rules/decision-applicability.js +1 -2
  216. package/dist/rules/dispatch-errors.js +1 -2
  217. package/dist/rules/dispatcher.d.ts.map +1 -1
  218. package/dist/rules/dispatcher.js +9 -3
  219. package/dist/rules/dispatcher.js.map +1 -1
  220. package/dist/rules/event-rules.js +1 -2
  221. package/dist/rules/processor.js +1 -2
  222. package/dist/rules/resolve.js +1 -2
  223. package/dist/rules/review-source-tool.js +1 -2
  224. package/dist/rules/start-coordinator.js +1 -2
  225. package/dist/rules/terminal-cleanup.js +1 -2
  226. package/dist/rules/tools.js +1 -2
  227. package/dist/rules/transition-service.js +1 -2
  228. package/dist/rules/types.d.ts +4 -1
  229. package/dist/rules/types.d.ts.map +1 -1
  230. package/dist/rules/types.js +1 -2
  231. package/dist/rules/types.js.map +1 -1
  232. package/dist/rules/validation.js +1 -2
  233. package/dist/run-error.d.ts +13 -0
  234. package/dist/run-error.d.ts.map +1 -0
  235. package/dist/run-error.js +81 -0
  236. package/dist/run-error.js.map +1 -0
  237. package/dist/sandbox/callback-factory-sandbox.js +1 -2
  238. package/dist/sandbox/git-ref.js +1 -2
  239. package/dist/sandbox/local-factory-sandbox.d.ts +12 -4
  240. package/dist/sandbox/local-factory-sandbox.d.ts.map +1 -1
  241. package/dist/sandbox/local-factory-sandbox.js +32 -7
  242. package/dist/sandbox/local-factory-sandbox.js.map +1 -1
  243. package/dist/sandbox/materialization.js +1 -2
  244. package/dist/sandbox/session-retirement.js +1 -2
  245. package/dist/sandbox/session-sandbox.js +1 -2
  246. package/dist/sandbox/workdir.js +1 -2
  247. package/dist/secret-encryption.js +1 -2
  248. package/dist/server-error.js +1 -2
  249. package/dist/session/credential-policy.js +1 -2
  250. package/dist/session/default-model-hydration.js +1 -2
  251. package/dist/session/environment-repositories.js +1 -2
  252. package/dist/session/environment-state-processor.d.ts +0 -1
  253. package/dist/session/environment-state-processor.d.ts.map +1 -1
  254. package/dist/session/environment-state-processor.js +2 -3
  255. package/dist/session/environment-state-processor.js.map +1 -1
  256. package/dist/session/factory-session.js +1 -2
  257. package/dist/session/filesystem-capture.js +2 -3
  258. package/dist/session/filesystem-capture.js.map +1 -1
  259. package/dist/session/first-exec-capture.js +2 -3
  260. package/dist/session/first-exec-capture.js.map +1 -1
  261. package/dist/session/first-message-capture.js +1 -2
  262. package/dist/session/live-sessions.js +1 -2
  263. package/dist/session/memory-settings-hydration.js +1 -2
  264. package/dist/session/org-seed.js +1 -2
  265. package/dist/session/reply-credential-processor.js +1 -2
  266. package/dist/session/resource-migration.js +1 -2
  267. package/dist/session/run-audit.js +1 -2
  268. package/dist/session/session-threads.js +1 -2
  269. package/dist/session/session-title.js +1 -2
  270. package/dist/session/shell-commands.js +1 -2
  271. package/dist/session/source-control-tools.js +2 -3
  272. package/dist/session/thinking-default.d.ts +1 -1
  273. package/dist/session/thinking-default.d.ts.map +1 -1
  274. package/dist/session/thinking-default.js +11 -13
  275. package/dist/session/thinking-default.js.map +1 -1
  276. package/dist/session/thread-session-stamp.js +1 -2
  277. package/dist/session/thread-title-mirror.js +1 -2
  278. package/dist/session/thread-title-mirror.js.map +1 -1
  279. package/dist/session/work-item-repository.js +1 -2
  280. package/dist/session-owner-signal.js +1 -2
  281. package/dist/skills/catalog.js +1 -2
  282. package/dist/skills/service.js +1 -2
  283. package/dist/spa-static.js +1 -2
  284. package/dist/state-signing.js +1 -2
  285. package/dist/storage/domains/audit/actions.js +1 -2
  286. package/dist/storage/domains/audit/actors.js +1 -2
  287. package/dist/storage/domains/audit/agent-audit.js +1 -2
  288. package/dist/storage/domains/audit/base.js +1 -2
  289. package/dist/storage/domains/audit/domain.js +1 -2
  290. package/dist/storage/domains/audit/wire.js +1 -2
  291. package/dist/storage/domains/channel-identity/base.js +1 -2
  292. package/dist/storage/domains/comments/activity.js +1 -2
  293. package/dist/storage/domains/comments/actor.js +1 -2
  294. package/dist/storage/domains/comments/base.js +1 -2
  295. package/dist/storage/domains/comments/domain.js +1 -2
  296. package/dist/storage/domains/comments/feed-context.js +1 -2
  297. package/dist/storage/domains/comments/parse.js +1 -2
  298. package/dist/storage/domains/comments/routes.js +1 -2
  299. package/dist/storage/domains/comments/schema.js +1 -2
  300. package/dist/storage/domains/comments/wire.js +1 -2
  301. package/dist/storage/domains/credentials/base.d.ts +4 -1
  302. package/dist/storage/domains/credentials/base.d.ts.map +1 -1
  303. package/dist/storage/domains/credentials/base.js +40 -44
  304. package/dist/storage/domains/credentials/base.js.map +1 -1
  305. package/dist/storage/domains/custom-providers/base.js +1 -2
  306. package/dist/storage/domains/filesystem/base.js +1 -2
  307. package/dist/storage/domains/intake/base.d.ts +5 -0
  308. package/dist/storage/domains/intake/base.d.ts.map +1 -1
  309. package/dist/storage/domains/intake/base.js +10 -2
  310. package/dist/storage/domains/intake/base.js.map +1 -1
  311. package/dist/storage/domains/integrations/base.js +1 -2
  312. package/dist/storage/domains/memory-settings/base.js +1 -2
  313. package/dist/storage/domains/model-defaults/base.js +1 -2
  314. package/dist/storage/domains/projects/base.d.ts +0 -1
  315. package/dist/storage/domains/projects/base.d.ts.map +1 -1
  316. package/dist/storage/domains/projects/base.js +5 -6
  317. package/dist/storage/domains/projects/base.js.map +1 -1
  318. package/dist/storage/domains/queue-health/base.js +1 -2
  319. package/dist/storage/domains/source-control/base.js +1 -2
  320. package/dist/storage/domains/source-control/inmemory.js +1 -2
  321. package/dist/storage/domains/work-items/base.js +1 -2
  322. package/dist/storage/domains/work-items/board-version.js +1 -2
  323. package/dist/storage/domains/work-items/metrics.js +1 -2
  324. package/dist/telemetry-types.js +1 -2
  325. package/dist/telemetry.js +1 -2
  326. package/dist/timing.js +1 -2
  327. package/dist/tools/annotations.js +1 -2
  328. package/dist/tools/approval-tools.js +1 -2
  329. package/dist/tools/deliver.js +2 -3
  330. package/dist/tools/index.js +1 -2
  331. package/dist/tools/messaging-tools.js +1 -2
  332. package/dist/tools/permissions.js +1 -2
  333. package/dist/tools/read-tools.js +1 -2
  334. package/dist/tools/reports.js +1 -2
  335. package/dist/tools/run-watch.d.ts +0 -2
  336. package/dist/tools/run-watch.d.ts.map +1 -1
  337. package/dist/tools/run-watch.js +4 -44
  338. package/dist/tools/run-watch.js.map +1 -1
  339. package/dist/tools/sandbox-tools.js +1 -2
  340. package/dist/tools/scope.js +2 -3
  341. package/dist/tools/session-tools.js +1 -2
  342. package/dist/tools/sessions-state-processor.js +1 -2
  343. package/dist/tools/side-sessions.js +1 -2
  344. package/dist/tools/work-item-tools.js +1 -2
  345. package/dist/work-item-branch.js +1 -2
  346. package/dist/work-item-branch.js.map +1 -1
  347. package/dist/work-items/create-work-item.js +1 -2
  348. package/dist/work-items/decision-actions.js +1 -2
  349. package/dist/workspace.d.ts.map +1 -1
  350. package/dist/workspace.js +1 -3
  351. package/dist/workspace.js.map +1 -1
  352. package/factory-skills/factory-gitlab-review/SKILL.md +1 -1
  353. package/factory-skills/factory-plan/SKILL.md +1 -1
  354. package/factory-skills/factory-rereview/SKILL.md +14 -3
  355. package/factory-skills/factory-review/SKILL.md +14 -3
  356. package/factory-skills/factory-self-review/SKILL.md +1 -1
  357. package/factory-skills/factory-triage/SKILL.md +52 -29
  358. package/package.json +19 -17
@@ -1,4 +1,4 @@
1
- //#region src/integrations/incidentio/claim.ts
1
+ // src/integrations/incidentio/claim.ts
2
2
  /**
3
3
  * Org-wide ownership key for an incident.io follow-up's Factory card. Keyed by
4
4
  * the prefixed item reference the intake feed serves as `id`
@@ -8,7 +8,6 @@
8
8
  function incidentioClaimKey(itemRef) {
9
9
  return `incidentio:item:${itemRef}`;
10
10
  }
11
- //#endregion
12
11
  export { incidentioClaimKey };
13
12
 
14
13
  //# sourceMappingURL=claim.js.map
@@ -1,6 +1,6 @@
1
1
  import { recordExplicitRuleOverrides } from "../../rules/event-rules.js";
2
2
  import { incidentioClaimKey } from "./claim.js";
3
- //#region src/integrations/incidentio/default-rules.ts
3
+ // src/integrations/incidentio/default-rules.ts
4
4
  function incidentioFollowUpObserved(context) {
5
5
  if (context.item) return;
6
6
  return {
@@ -62,7 +62,6 @@ function resolveIncidentioRules(overrides) {
62
62
  }
63
63
  return recordExplicitRuleOverrides(Object.freeze(rules), overrides);
64
64
  }
65
- //#endregion
66
65
  export { defaultIncidentioRules, resolveIncidentioRules };
67
66
 
68
67
  //# sourceMappingURL=default-rules.js.map
@@ -1,5 +1,5 @@
1
1
  import { IncidentioApiError } from "./api.js";
2
- //#region src/integrations/incidentio/intake.ts
2
+ // src/integrations/incidentio/intake.ts
3
3
  const INCIDENTIO_INCIDENTS_SOURCE_ID = "incidentio:incidents";
4
4
  const INCIDENTIO_FOLLOW_UPS_SOURCE_ID = "incidentio:follow-ups";
5
5
  const INCIDENT_PREFIX = "incidentio:incident:";
@@ -301,7 +301,6 @@ function decodePageCursor(cursor) {
301
301
  return { sourceIndex: 0 };
302
302
  }
303
303
  }
304
- //#endregion
305
304
  export { INCIDENTIO_FOLLOW_UPS_SOURCE_ID, INCIDENTIO_INCIDENTS_SOURCE_ID, createIncidentioIntake };
306
305
 
307
306
  //# sourceMappingURL=intake.js.map
@@ -7,7 +7,7 @@ import { createIncidentioIntake } from "./intake.js";
7
7
  import { attachIncidentioRules } from "./rules.js";
8
8
  import { attachIncidentioIssueReconciler } from "./issue-reconciler.js";
9
9
  import { incidentioReconciliationEnabled, incidentioReconciliationInterval } from "./reconciliation-config.js";
10
- //#region src/integrations/incidentio/integration.ts
10
+ // src/integrations/incidentio/integration.ts
11
11
  const DIRECT_CONNECTION_TOKEN = "incidentio-direct-api-key";
12
12
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13
13
  var IncidentioIntegration = class {
@@ -136,7 +136,6 @@ var IncidentioIntegration = class {
136
136
  };
137
137
  }
138
138
  };
139
- //#endregion
140
139
  export { IncidentioIntegration };
141
140
 
142
141
  //# sourceMappingURL=integration.js.map
@@ -2,7 +2,7 @@ import { workItemPhaseSemantics } from "../../boards/semantics.js";
2
2
  import "../../boards/index.js";
3
3
  import { createIssueReconciler } from "../issue-reconciler.js";
4
4
  import { IncidentioRules } from "./rules.js";
5
- //#region src/integrations/incidentio/issue-reconciler.ts
5
+ // src/integrations/incidentio/issue-reconciler.ts
6
6
  function issueToIngress(itemRef, issue) {
7
7
  return {
8
8
  id: itemRef,
@@ -69,7 +69,6 @@ function attachIncidentioIssueReconciler(incidentio, context) {
69
69
  }
70
70
  });
71
71
  }
72
- //#endregion
73
72
  export { attachIncidentioIssueReconciler };
74
73
 
75
74
  //# sourceMappingURL=issue-reconciler.js.map
@@ -1,5 +1,5 @@
1
1
  import { optionalBoolean, optionalPositiveInteger } from "../reconciliation-config.js";
2
- //#region src/integrations/incidentio/reconciliation-config.ts
2
+ // src/integrations/incidentio/reconciliation-config.ts
3
3
  const RECONCILIATION_LABEL = "incident.io reconciliation";
4
4
  function incidentioReconciliationEnabled() {
5
5
  return optionalBoolean("MASTRACODE_INCIDENT_IO_RECONCILE_ENABLED", process.env.MASTRACODE_INCIDENT_IO_RECONCILE_ENABLED, RECONCILIATION_LABEL) ?? true;
@@ -11,7 +11,6 @@ function incidentioReconciliationInterval() {
11
11
  if (value?.trim() && interval === void 0) console.warn(`[${RECONCILIATION_LABEL}] ${name} must be a positive integer; received ${JSON.stringify(value)}.`);
12
12
  return interval;
13
13
  }
14
- //#endregion
15
14
  export { incidentioReconciliationEnabled, incidentioReconciliationInterval };
16
15
 
17
16
  //# sourceMappingURL=reconciliation-config.js.map
@@ -1,6 +1,6 @@
1
1
  import { IncidentioApiError } from "./api.js";
2
2
  import { registerApiRoute } from "@mastra/core/server";
3
- //#region src/integrations/incidentio/routes.ts
3
+ // src/integrations/incidentio/routes.ts
4
4
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
5
  const ITEM_REF_RE = /^incidentio:(?:follow-up|incident):[\w-]+$/;
6
6
  const FOLLOW_UP_PREFIX = "incidentio:follow-up:";
@@ -243,7 +243,6 @@ function buildIncidentioRoutes(options) {
243
243
  }));
244
244
  return routes;
245
245
  }
246
- //#endregion
247
246
  export { buildIncidentioRoutes, scopeSourceIdsToProject };
248
247
 
249
248
  //# sourceMappingURL=routes.js.map
@@ -3,7 +3,7 @@ import { boardEventHandlers, boardForWorkItem, eventBoardId, isTerminalWorkItem,
3
3
  import "../../boards/index.js";
4
4
  import { selectEventRule } from "../../rules/event-rules.js";
5
5
  import { incidentioClaimKey } from "./claim.js";
6
- //#region src/integrations/incidentio/rules.ts
6
+ // src/integrations/incidentio/rules.ts
7
7
  const RULE_TIMEOUT_MS = 5e3;
8
8
  async function withRuleTimeout(promise) {
9
9
  let timeout;
@@ -183,7 +183,6 @@ function attachIncidentioRules(incidentio, context) {
183
183
  });
184
184
  return (input) => rules.ingest(input);
185
185
  }
186
- //#endregion
187
186
  export { IncidentioRules, attachIncidentioRules };
188
187
 
189
188
  //# sourceMappingURL=rules.js.map
@@ -1,6 +1,6 @@
1
1
  import { NoopLeaseProvider, isLeaseProvider } from "@mastra/core/events";
2
2
  import { MastraWorker } from "@mastra/core/worker";
3
- //#region src/integrations/issue-reconcile-worker.ts
3
+ // src/integrations/issue-reconcile-worker.ts
4
4
  const DEFAULT_ISSUE_RECONCILE_INTERVAL_MS = 3e5;
5
5
  const MIN_LEASE_TTL_MS = 3e4;
6
6
  var IssueReconcileWorker = class extends MastraWorker {
@@ -91,7 +91,6 @@ function getLeaseProvider(pubsub) {
91
91
  if (typeof getProvider === "function") return getProvider.call(pubsub) ?? NoopLeaseProvider;
92
92
  return isLeaseProvider(pubsub) ? pubsub : pubsub.lease ?? NoopLeaseProvider;
93
93
  }
94
- //#endregion
95
94
  export { DEFAULT_ISSUE_RECONCILE_INTERVAL_MS, IssueReconcileWorker };
96
95
 
97
96
  //# sourceMappingURL=issue-reconcile-worker.js.map
@@ -1,4 +1,4 @@
1
- //#region src/integrations/issue-reconciler.ts
1
+ // src/integrations/issue-reconciler.ts
2
2
  const EXTERNAL_SOURCE_MISSING_KEY = "externalSourceMissingAt";
3
3
  const MISSING_RECHECK_MS = 864e5;
4
4
  function sameValue(left, right) {
@@ -152,7 +152,6 @@ function createIssueReconciler(options) {
152
152
  };
153
153
  return run;
154
154
  }
155
- //#endregion
156
155
  export { EXTERNAL_SOURCE_MISSING_KEY, createIssueReconciler };
157
156
 
158
157
  //# sourceMappingURL=issue-reconciler.js.map
@@ -1,4 +1,4 @@
1
- //#region src/integrations/jira/adf.ts
1
+ // src/integrations/jira/adf.ts
2
2
  /** Flatten an ADF document (or fragment) to plain text. */
3
3
  function adfToText(node) {
4
4
  if (!node || typeof node !== "object") return "";
@@ -67,7 +67,6 @@ function render(node) {
67
67
  }
68
68
  }
69
69
  }
70
- //#endregion
71
70
  export { adfToText, textToAdf };
72
71
 
73
72
  //# sourceMappingURL=adf.js.map
@@ -2,7 +2,7 @@ import { JiraApiError } from "./api.js";
2
2
  import { DEPLOYMENT_CONNECTION } from "./integration.js";
3
3
  import { z } from "zod";
4
4
  import { createTool } from "@mastra/core/tools";
5
- //#region src/integrations/jira/agent-tools.ts
5
+ // src/integrations/jira/agent-tools.ts
6
6
  /**
7
7
  * Prompt-injection boundary: Jira descriptions and comments are authored by
8
8
  * third parties, so the tool labels them as evidence rather than letting them
@@ -81,7 +81,6 @@ async function buildJiraAgentTools({ requestContext, jira }) {
81
81
  jira_create_comment: createJiraCommentTool(jira)
82
82
  };
83
83
  }
84
- //#endregion
85
84
  export { JIRA_UNTRUSTED_CONTENT_NOTICE, buildJiraAgentTools };
86
85
 
87
86
  //# sourceMappingURL=agent-tools.js.map
@@ -133,7 +133,7 @@ export interface JiraTransition {
133
133
  export declare class JiraApiClient {
134
134
  #private;
135
135
  constructor(config: JiraApiClientConfig);
136
- /** Normalized site base URL (no trailing slash) — used for `/browse/<key>` links. */
136
+ /** Normalized API base URL (no trailing slash). */
137
137
  get baseUrl(): string;
138
138
  getServerInfo(): Promise<JiraServerInfo>;
139
139
  /** One page of the site's projects (Settings intake-source picker). */
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/integrations/jira/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/integrations/jira/api.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { textToAdf } from "./adf.js";
2
- //#region src/integrations/jira/api.ts
2
+ // src/integrations/jira/api.ts
3
3
  const JIRA_TIMEOUT_MS = 15e3;
4
4
  /** Hosts allowed to receive Basic credentials over plain http (local development mocks). */
5
5
  const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
@@ -66,7 +66,7 @@ var JiraApiClient = class {
66
66
  this.#baseUrl = config.baseUrl.replace(/\/+$/, "");
67
67
  this.#fetch = config.fetchImpl ?? globalThis.fetch;
68
68
  }
69
- /** Normalized site base URL (no trailing slash) — used for `/browse/<key>` links. */
69
+ /** Normalized API base URL (no trailing slash). */
70
70
  get baseUrl() {
71
71
  return this.#baseUrl;
72
72
  }
@@ -139,7 +139,6 @@ var JiraApiClient = class {
139
139
  await this.#request("POST", `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/transitions`, { body: { transition: { id: transitionId } } });
140
140
  }
141
141
  };
142
- //#endregion
143
142
  export { JIRA_COMMENTS_PAGE_SIZE, JIRA_ISSUES_PAGE_SIZE, JIRA_ISSUE_FIELDS, JIRA_PROJECTS_PAGE_SIZE, JiraApiClient, JiraApiError };
144
143
 
145
144
  //# sourceMappingURL=api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","names":[],"sources":["../../../src/integrations/jira/api.ts"],"sourcesContent":["/**\n * Typed Jira Cloud REST client (API v3).\n *\n * Shared by the direct and Platform-managed Jira integrations. Direct Jira\n * uses Basic auth against an Atlassian site; Platform Jira points the same\n * client at a connection proxy with a bearer token. Both modes use the same\n * request shapes, timeout, and error normalization.\n *\n * Endpoint notes (Jira Cloud, 2026):\n * - Issue search is `POST /rest/api/3/search/jql` — the legacy\n * `GET /rest/api/3/search` endpoint has been removed. The new endpoint\n * returns only ids unless `fields` is requested explicitly, and pages with\n * an opaque `nextPageToken` cursor (no `startAt`/`total`).\n * - Project listing is `GET /rest/api/3/project/search` with classic\n * `startAt`/`isLast` paging.\n * - Descriptions and comment bodies are ADF documents (see `adf.ts`).\n */\n\nimport type { AdfNode } from './adf.js';\nimport { textToAdf } from './adf.js';\n\nconst JIRA_TIMEOUT_MS = 15_000;\n/** Hosts allowed to receive Basic credentials over plain http (local development mocks). */\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);\n/** Issue page size — Linear parity (`LINEAR_ISSUES_PAGE_SIZE`). */\nexport const JIRA_ISSUES_PAGE_SIZE = 30;\n/** Comment page size — Linear parity (`LINEAR_COMMENTS_PAGE_SIZE`). */\nexport const JIRA_COMMENTS_PAGE_SIZE = 50;\nexport const JIRA_PROJECTS_PAGE_SIZE = 50;\n\n/** Fields requested from issue reads — `search/jql` returns ids only without an explicit list. */\nexport const JIRA_ISSUE_FIELDS = [\n 'summary',\n 'description',\n 'status',\n 'assignee',\n 'reporter',\n 'labels',\n 'priority',\n 'issuetype',\n 'project',\n 'created',\n 'updated',\n] as const;\n\ninterface JiraApiClientBaseConfig {\n /** Jira API base URL, either the Atlassian site or a Platform connection proxy. */\n baseUrl: string;\n fetchImpl?: typeof fetch;\n}\n\nexport type JiraApiClientConfig = JiraApiClientBaseConfig &\n (\n | {\n /** Atlassian account email the API token belongs to. */\n email: string;\n /** API token from id.atlassian.com → Security → API tokens. */\n apiToken: string;\n accessToken?: never;\n }\n | {\n /** Bearer token used when the base URL is a Mastra Platform connection proxy. */\n accessToken: string;\n /**\n * Mastra project id sent as `x-mastra-project-id` so the platform can\n * attribute proxied Jira activity to the project. Falls back to the\n * `MASTRA_PROJECT_ID` environment variable. The platform strips the\n * header before forwarding the request to Atlassian.\n */\n projectId?: string;\n email?: never;\n apiToken?: never;\n }\n );\n\n/** Stable error code the routes/tools surface to the SPA and agents. */\nexport type JiraApiErrorCode = 'jira_auth_failed' | 'jira_request_failed';\n\n/** Normalized Jira API failure carrying the HTTP status and Jira's error detail. */\nexport class JiraApiError extends Error {\n readonly status: number | null;\n readonly code: JiraApiErrorCode;\n\n constructor(message: string, status: number | null) {\n super(message);\n this.name = 'JiraApiError';\n this.status = status;\n this.code = status === 401 || status === 403 ? 'jira_auth_failed' : 'jira_request_failed';\n }\n}\n\nexport interface JiraStatusCategory {\n /** `new` | `indeterminate` | `done` — Jira's fixed status families. */\n key: string;\n name?: string;\n}\n\nexport interface JiraStatus {\n name: string;\n statusCategory?: JiraStatusCategory;\n}\n\nexport interface JiraProject {\n id: string;\n key: string;\n name: string;\n}\n\nexport interface JiraProjectSearchPage {\n values: JiraProject[];\n startAt: number;\n isLast: boolean;\n}\n\nexport interface JiraServerInfo {\n baseUrl: string;\n serverTitle?: string;\n}\n\nexport interface JiraUser {\n displayName: string;\n}\n\nexport interface JiraComment {\n id: string;\n author?: JiraUser | null;\n body?: AdfNode | null;\n created: string;\n}\n\nexport interface JiraCommentPage {\n comments: JiraComment[];\n startAt: number;\n maxResults: number;\n total: number;\n}\n\nexport interface JiraIssueFields {\n summary?: string;\n description?: AdfNode | null;\n status?: JiraStatus;\n assignee?: JiraUser | null;\n reporter?: JiraUser | null;\n labels?: string[];\n priority?: { name: string } | null;\n issuetype?: { name: string };\n project?: { id: string; key: string; name?: string };\n created?: string;\n updated?: string;\n}\n\nexport interface JiraIssue {\n id: string;\n key: string;\n fields: JiraIssueFields;\n}\n\nexport interface JiraSearchPage {\n issues: JiraIssue[];\n /** Opaque cursor for the next page; absent on the last page. */\n nextPageToken?: string | null;\n}\n\nexport interface JiraTransition {\n id: string;\n name: string;\n /** Target status the transition moves the issue to. */\n to?: JiraStatus;\n}\n\nexport class JiraApiClient {\n readonly #baseUrl: string;\n readonly #authHeader: string;\n readonly #projectId: string | null;\n readonly #fetch: typeof fetch;\n\n constructor(config: JiraApiClientConfig) {\n if (!config.baseUrl) {\n throw new Error('JiraApiClient is missing required config: baseUrl.');\n }\n // Fail fast on a malformed base URL: a bare host like `acme.atlassian.net`\n // would otherwise surface later as an opaque `TypeError: Invalid URL`.\n let parsed: URL;\n try {\n parsed = new URL(config.baseUrl);\n } catch {\n throw new Error(`JiraApiClient baseUrl is not an absolute URL: \"${config.baseUrl}\".`);\n }\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new Error(`JiraApiClient baseUrl must be an http(s) URL: \"${config.baseUrl}\".`);\n }\n if (config.accessToken !== undefined) {\n if (!config.accessToken) {\n throw new Error('JiraApiClient is missing required config: accessToken.');\n }\n this.#authHeader = `Bearer ${config.accessToken}`;\n this.#projectId = (config.projectId ?? process.env.MASTRA_PROJECT_ID)?.trim() || null;\n } else {\n const missing = (['email', 'apiToken'] as const).filter(key => !config[key]);\n if (missing.length > 0) {\n throw new Error(`JiraApiClient is missing required config: ${missing.join(', ')}.`);\n }\n // Basic credentials ride on every request, so never send them over\n // plaintext to a remote host. Loopback stays allowed for local mocks.\n if (parsed.protocol === 'http:' && !LOOPBACK_HOSTS.has(parsed.hostname)) {\n throw new Error('JiraApiClient baseUrl must use https when Basic credentials are configured.');\n }\n this.#authHeader = `Basic ${Buffer.from(`${config.email}:${config.apiToken}`).toString('base64')}`;\n // Direct Atlassian mode: never send Mastra platform headers to Jira itself.\n this.#projectId = null;\n }\n this.#baseUrl = config.baseUrl.replace(/\\/+$/, '');\n this.#fetch = config.fetchImpl ?? globalThis.fetch;\n }\n\n /** Normalized site base URL (no trailing slash) — used for `/browse/<key>` links. */\n get baseUrl(): string {\n return this.#baseUrl;\n }\n\n async #request<T>(\n method: 'GET' | 'POST',\n path: string,\n options: { query?: Record<string, string | number | undefined>; body?: unknown } = {},\n ): Promise<T> {\n const url = new URL(`${this.#baseUrl}${path}`);\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n const hasBody = options.body !== undefined;\n const res = await this.#fetch(url, {\n method,\n signal: AbortSignal.timeout(JIRA_TIMEOUT_MS),\n headers: {\n authorization: this.#authHeader,\n accept: 'application/json',\n // Project attribution for the Mastra platform proxy; stripped by the\n // platform before the request reaches Atlassian.\n ...(this.#projectId ? { 'x-mastra-project-id': this.#projectId } : {}),\n ...(hasBody ? { 'content-type': 'application/json' } : {}),\n },\n ...(hasBody ? { body: JSON.stringify(options.body) } : {}),\n });\n if (!res.ok) {\n // Jira reports validation failures as `errorMessages` and `errors`;\n // the Platform proxy reports upstream failures through `detail`/`error`/`title`.\n let detail: string | null = null;\n try {\n const errBody = (await res.json()) as {\n errorMessages?: string[];\n errors?: Record<string, string>;\n detail?: string;\n error?: string;\n title?: string;\n };\n detail =\n errBody.errorMessages?.[0] ??\n Object.values(errBody.errors ?? {})[0] ??\n errBody.detail ??\n errBody.error ??\n errBody.title ??\n null;\n } catch {\n // Non-JSON error body; fall back to the status code alone.\n }\n throw new JiraApiError(`Jira API request failed (${res.status})${detail ? `: ${detail}` : ''}`, res.status);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n\n async getServerInfo(): Promise<JiraServerInfo> {\n return this.#request<JiraServerInfo>('GET', '/rest/api/3/serverInfo');\n }\n\n /** One page of the site's projects (Settings intake-source picker). */\n async listProjects(options: { startAt?: number } = {}): Promise<JiraProjectSearchPage> {\n return this.#request<JiraProjectSearchPage>('GET', '/rest/api/3/project/search', {\n query: { startAt: options.startAt ?? 0, maxResults: JIRA_PROJECTS_PAGE_SIZE },\n });\n }\n\n /** One page of a JQL search with explicitly requested fields. */\n async searchIssues(options: {\n jql: string;\n fields?: readonly string[];\n nextPageToken?: string;\n maxResults?: number;\n }): Promise<JiraSearchPage> {\n return this.#request<JiraSearchPage>('POST', '/rest/api/3/search/jql', {\n body: {\n jql: options.jql,\n fields: [...(options.fields ?? JIRA_ISSUE_FIELDS)],\n maxResults: options.maxResults ?? JIRA_ISSUES_PAGE_SIZE,\n ...(options.nextPageToken ? { nextPageToken: options.nextPageToken } : {}),\n },\n });\n }\n\n /** Full issue detail by key (`ENG-42`) or id. */\n async getIssue(keyOrId: string): Promise<JiraIssue> {\n return this.#request<JiraIssue>('GET', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}`, {\n query: { fields: JIRA_ISSUE_FIELDS.join(',') },\n });\n }\n\n /** One page of an issue's comments (oldest first, Jira default order). */\n async listComments(keyOrId: string, options: { startAt?: number } = {}): Promise<JiraCommentPage> {\n return this.#request<JiraCommentPage>('GET', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/comment`, {\n query: { startAt: options.startAt ?? 0, maxResults: JIRA_COMMENTS_PAGE_SIZE },\n });\n }\n\n /** Post a plain-text comment (wrapped into a minimal ADF document). */\n async createComment(keyOrId: string, body: string): Promise<JiraComment> {\n return this.#request<JiraComment>('POST', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/comment`, {\n body: { body: textToAdf(body) },\n });\n }\n\n /** Transitions currently legal for the issue (workflow-dependent). */\n async listTransitions(keyOrId: string): Promise<JiraTransition[]> {\n const data = await this.#request<{ transitions?: JiraTransition[] }>(\n 'GET',\n `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/transitions`,\n );\n return data.transitions ?? [];\n }\n\n /** Apply a transition by id (Jira responds 204 on success). */\n async applyTransition(keyOrId: string, transitionId: string): Promise<void> {\n await this.#request<void>('POST', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/transitions`, {\n body: { transition: { id: transitionId } },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"api.js","names":[],"sources":["../../../src/integrations/jira/api.ts"],"sourcesContent":["/**\n * Typed Jira Cloud REST client (API v3).\n *\n * Shared by the direct and Platform-managed Jira integrations. Direct Jira\n * uses Basic auth against an Atlassian site; Platform Jira points the same\n * client at a connection proxy with a bearer token. Both modes use the same\n * request shapes, timeout, and error normalization.\n *\n * Endpoint notes (Jira Cloud, 2026):\n * - Issue search is `POST /rest/api/3/search/jql` — the legacy\n * `GET /rest/api/3/search` endpoint has been removed. The new endpoint\n * returns only ids unless `fields` is requested explicitly, and pages with\n * an opaque `nextPageToken` cursor (no `startAt`/`total`).\n * - Project listing is `GET /rest/api/3/project/search` with classic\n * `startAt`/`isLast` paging.\n * - Descriptions and comment bodies are ADF documents (see `adf.ts`).\n */\n\nimport type { AdfNode } from './adf.js';\nimport { textToAdf } from './adf.js';\n\nconst JIRA_TIMEOUT_MS = 15_000;\n/** Hosts allowed to receive Basic credentials over plain http (local development mocks). */\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);\n/** Issue page size — Linear parity (`LINEAR_ISSUES_PAGE_SIZE`). */\nexport const JIRA_ISSUES_PAGE_SIZE = 30;\n/** Comment page size — Linear parity (`LINEAR_COMMENTS_PAGE_SIZE`). */\nexport const JIRA_COMMENTS_PAGE_SIZE = 50;\nexport const JIRA_PROJECTS_PAGE_SIZE = 50;\n\n/** Fields requested from issue reads — `search/jql` returns ids only without an explicit list. */\nexport const JIRA_ISSUE_FIELDS = [\n 'summary',\n 'description',\n 'status',\n 'assignee',\n 'reporter',\n 'labels',\n 'priority',\n 'issuetype',\n 'project',\n 'created',\n 'updated',\n] as const;\n\ninterface JiraApiClientBaseConfig {\n /** Jira API base URL, either the Atlassian site or a Platform connection proxy. */\n baseUrl: string;\n fetchImpl?: typeof fetch;\n}\n\nexport type JiraApiClientConfig = JiraApiClientBaseConfig &\n (\n | {\n /** Atlassian account email the API token belongs to. */\n email: string;\n /** API token from id.atlassian.com → Security → API tokens. */\n apiToken: string;\n accessToken?: never;\n }\n | {\n /** Bearer token used when the base URL is a Mastra Platform connection proxy. */\n accessToken: string;\n /**\n * Mastra project id sent as `x-mastra-project-id` so the platform can\n * attribute proxied Jira activity to the project. Falls back to the\n * `MASTRA_PROJECT_ID` environment variable. The platform strips the\n * header before forwarding the request to Atlassian.\n */\n projectId?: string;\n email?: never;\n apiToken?: never;\n }\n );\n\n/** Stable error code the routes/tools surface to the SPA and agents. */\nexport type JiraApiErrorCode = 'jira_auth_failed' | 'jira_request_failed';\n\n/** Normalized Jira API failure carrying the HTTP status and Jira's error detail. */\nexport class JiraApiError extends Error {\n readonly status: number | null;\n readonly code: JiraApiErrorCode;\n\n constructor(message: string, status: number | null) {\n super(message);\n this.name = 'JiraApiError';\n this.status = status;\n this.code = status === 401 || status === 403 ? 'jira_auth_failed' : 'jira_request_failed';\n }\n}\n\nexport interface JiraStatusCategory {\n /** `new` | `indeterminate` | `done` — Jira's fixed status families. */\n key: string;\n name?: string;\n}\n\nexport interface JiraStatus {\n name: string;\n statusCategory?: JiraStatusCategory;\n}\n\nexport interface JiraProject {\n id: string;\n key: string;\n name: string;\n}\n\nexport interface JiraProjectSearchPage {\n values: JiraProject[];\n startAt: number;\n isLast: boolean;\n}\n\nexport interface JiraServerInfo {\n baseUrl: string;\n serverTitle?: string;\n}\n\nexport interface JiraUser {\n displayName: string;\n}\n\nexport interface JiraComment {\n id: string;\n author?: JiraUser | null;\n body?: AdfNode | null;\n created: string;\n}\n\nexport interface JiraCommentPage {\n comments: JiraComment[];\n startAt: number;\n maxResults: number;\n total: number;\n}\n\nexport interface JiraIssueFields {\n summary?: string;\n description?: AdfNode | null;\n status?: JiraStatus;\n assignee?: JiraUser | null;\n reporter?: JiraUser | null;\n labels?: string[];\n priority?: { name: string } | null;\n issuetype?: { name: string };\n project?: { id: string; key: string; name?: string };\n created?: string;\n updated?: string;\n}\n\nexport interface JiraIssue {\n id: string;\n key: string;\n fields: JiraIssueFields;\n}\n\nexport interface JiraSearchPage {\n issues: JiraIssue[];\n /** Opaque cursor for the next page; absent on the last page. */\n nextPageToken?: string | null;\n}\n\nexport interface JiraTransition {\n id: string;\n name: string;\n /** Target status the transition moves the issue to. */\n to?: JiraStatus;\n}\n\nexport class JiraApiClient {\n readonly #baseUrl: string;\n readonly #authHeader: string;\n readonly #projectId: string | null;\n readonly #fetch: typeof fetch;\n\n constructor(config: JiraApiClientConfig) {\n if (!config.baseUrl) {\n throw new Error('JiraApiClient is missing required config: baseUrl.');\n }\n // Fail fast on a malformed base URL: a bare host like `acme.atlassian.net`\n // would otherwise surface later as an opaque `TypeError: Invalid URL`.\n let parsed: URL;\n try {\n parsed = new URL(config.baseUrl);\n } catch {\n throw new Error(`JiraApiClient baseUrl is not an absolute URL: \"${config.baseUrl}\".`);\n }\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new Error(`JiraApiClient baseUrl must be an http(s) URL: \"${config.baseUrl}\".`);\n }\n if (config.accessToken !== undefined) {\n if (!config.accessToken) {\n throw new Error('JiraApiClient is missing required config: accessToken.');\n }\n this.#authHeader = `Bearer ${config.accessToken}`;\n this.#projectId = (config.projectId ?? process.env.MASTRA_PROJECT_ID)?.trim() || null;\n } else {\n const missing = (['email', 'apiToken'] as const).filter(key => !config[key]);\n if (missing.length > 0) {\n throw new Error(`JiraApiClient is missing required config: ${missing.join(', ')}.`);\n }\n // Basic credentials ride on every request, so never send them over\n // plaintext to a remote host. Loopback stays allowed for local mocks.\n if (parsed.protocol === 'http:' && !LOOPBACK_HOSTS.has(parsed.hostname)) {\n throw new Error('JiraApiClient baseUrl must use https when Basic credentials are configured.');\n }\n this.#authHeader = `Basic ${Buffer.from(`${config.email}:${config.apiToken}`).toString('base64')}`;\n // Direct Atlassian mode: never send Mastra platform headers to Jira itself.\n this.#projectId = null;\n }\n this.#baseUrl = config.baseUrl.replace(/\\/+$/, '');\n this.#fetch = config.fetchImpl ?? globalThis.fetch;\n }\n\n /** Normalized API base URL (no trailing slash). */\n get baseUrl(): string {\n return this.#baseUrl;\n }\n\n async #request<T>(\n method: 'GET' | 'POST',\n path: string,\n options: { query?: Record<string, string | number | undefined>; body?: unknown } = {},\n ): Promise<T> {\n const url = new URL(`${this.#baseUrl}${path}`);\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) url.searchParams.set(key, String(value));\n }\n const hasBody = options.body !== undefined;\n const res = await this.#fetch(url, {\n method,\n signal: AbortSignal.timeout(JIRA_TIMEOUT_MS),\n headers: {\n authorization: this.#authHeader,\n accept: 'application/json',\n // Project attribution for the Mastra platform proxy; stripped by the\n // platform before the request reaches Atlassian.\n ...(this.#projectId ? { 'x-mastra-project-id': this.#projectId } : {}),\n ...(hasBody ? { 'content-type': 'application/json' } : {}),\n },\n ...(hasBody ? { body: JSON.stringify(options.body) } : {}),\n });\n if (!res.ok) {\n // Jira reports validation failures as `errorMessages` and `errors`;\n // the Platform proxy reports upstream failures through `detail`/`error`/`title`.\n let detail: string | null = null;\n try {\n const errBody = (await res.json()) as {\n errorMessages?: string[];\n errors?: Record<string, string>;\n detail?: string;\n error?: string;\n title?: string;\n };\n detail =\n errBody.errorMessages?.[0] ??\n Object.values(errBody.errors ?? {})[0] ??\n errBody.detail ??\n errBody.error ??\n errBody.title ??\n null;\n } catch {\n // Non-JSON error body; fall back to the status code alone.\n }\n throw new JiraApiError(`Jira API request failed (${res.status})${detail ? `: ${detail}` : ''}`, res.status);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n\n async getServerInfo(): Promise<JiraServerInfo> {\n return this.#request<JiraServerInfo>('GET', '/rest/api/3/serverInfo');\n }\n\n /** One page of the site's projects (Settings intake-source picker). */\n async listProjects(options: { startAt?: number } = {}): Promise<JiraProjectSearchPage> {\n return this.#request<JiraProjectSearchPage>('GET', '/rest/api/3/project/search', {\n query: { startAt: options.startAt ?? 0, maxResults: JIRA_PROJECTS_PAGE_SIZE },\n });\n }\n\n /** One page of a JQL search with explicitly requested fields. */\n async searchIssues(options: {\n jql: string;\n fields?: readonly string[];\n nextPageToken?: string;\n maxResults?: number;\n }): Promise<JiraSearchPage> {\n return this.#request<JiraSearchPage>('POST', '/rest/api/3/search/jql', {\n body: {\n jql: options.jql,\n fields: [...(options.fields ?? JIRA_ISSUE_FIELDS)],\n maxResults: options.maxResults ?? JIRA_ISSUES_PAGE_SIZE,\n ...(options.nextPageToken ? { nextPageToken: options.nextPageToken } : {}),\n },\n });\n }\n\n /** Full issue detail by key (`ENG-42`) or id. */\n async getIssue(keyOrId: string): Promise<JiraIssue> {\n return this.#request<JiraIssue>('GET', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}`, {\n query: { fields: JIRA_ISSUE_FIELDS.join(',') },\n });\n }\n\n /** One page of an issue's comments (oldest first, Jira default order). */\n async listComments(keyOrId: string, options: { startAt?: number } = {}): Promise<JiraCommentPage> {\n return this.#request<JiraCommentPage>('GET', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/comment`, {\n query: { startAt: options.startAt ?? 0, maxResults: JIRA_COMMENTS_PAGE_SIZE },\n });\n }\n\n /** Post a plain-text comment (wrapped into a minimal ADF document). */\n async createComment(keyOrId: string, body: string): Promise<JiraComment> {\n return this.#request<JiraComment>('POST', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/comment`, {\n body: { body: textToAdf(body) },\n });\n }\n\n /** Transitions currently legal for the issue (workflow-dependent). */\n async listTransitions(keyOrId: string): Promise<JiraTransition[]> {\n const data = await this.#request<{ transitions?: JiraTransition[] }>(\n 'GET',\n `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/transitions`,\n );\n return data.transitions ?? [];\n }\n\n /** Apply a transition by id (Jira responds 204 on success). */\n async applyTransition(keyOrId: string, transitionId: string): Promise<void> {\n await this.#request<void>('POST', `/rest/api/3/issue/${encodeURIComponent(keyOrId)}/transitions`, {\n body: { transition: { id: transitionId } },\n });\n }\n}\n"],"mappings":";;AAqBA,MAAM,kBAAkB;;AAExB,MAAM,iCAAiB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAS;AAAK,CAAC;;AAEzE,MAAa,wBAAwB;;AAErC,MAAa,0BAA0B;AACvC,MAAa,0BAA0B;;AAGvC,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAoCA,IAAa,eAAb,cAAkC,MAAM;CACtC;CACA;CAEA,YAAY,SAAiB,QAAuB;EAClD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,OAAO,WAAW,OAAO,WAAW,MAAM,qBAAqB;CACtE;AACF;AAiFA,IAAa,gBAAb,MAA2B;CACzB;CACA;CACA;CACA;CAEA,YAAY,QAA6B;EACvC,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,MAAM,oDAAoD;EAItE,IAAI;EACJ,IAAI;GACF,SAAS,IAAI,IAAI,OAAO,OAAO;EACjC,QAAQ;GACN,MAAM,IAAI,MAAM,kDAAkD,OAAO,QAAQ,GAAG;EACtF;EACA,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,SACtD,MAAM,IAAI,MAAM,kDAAkD,OAAO,QAAQ,GAAG;EAEtF,IAAI,OAAO,gBAAgB,KAAA,GAAW;GACpC,IAAI,CAAC,OAAO,aACV,MAAM,IAAI,MAAM,wDAAwD;GAE1E,KAAK,cAAc,UAAU,OAAO;GACpC,KAAK,cAAc,OAAO,aAAa,QAAQ,IAAI,kBAAA,EAAoB,KAAK,KAAK;EACnF,OAAO;GACL,MAAM,UAAW,CAAC,SAAS,UAAU,CAAC,CAAW,QAAO,QAAO,CAAC,OAAO,IAAI;GAC3E,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,MAAM,6CAA6C,QAAQ,KAAK,IAAI,EAAE,EAAE;GAIpF,IAAI,OAAO,aAAa,WAAW,CAAC,eAAe,IAAI,OAAO,QAAQ,GACpE,MAAM,IAAI,MAAM,6EAA6E;GAE/F,KAAK,cAAc,SAAS,OAAO,KAAK,GAAG,OAAO,MAAM,GAAG,OAAO,UAAU,CAAC,CAAC,SAAS,QAAQ;GAE/F,KAAK,aAAa;EACpB;EACA,KAAK,WAAW,OAAO,QAAQ,QAAQ,QAAQ,EAAE;EACjD,KAAK,SAAS,OAAO,aAAa,WAAW;CAC/C;;CAGA,IAAI,UAAkB;EACpB,OAAO,KAAK;CACd;CAEA,MAAM,SACJ,QACA,MACA,UAAmF,CAAC,GACxE;EACZ,MAAM,MAAM,IAAI,IAAI,GAAG,KAAK,WAAW,MAAM;EAC7C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,SAAS,CAAC,CAAC,GAC3D,IAAI,UAAU,KAAA,GAAW,IAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;EAElE,MAAM,UAAU,QAAQ,SAAS,KAAA;EACjC,MAAM,MAAM,MAAM,KAAK,OAAO,KAAK;GACjC;GACA,QAAQ,YAAY,QAAQ,eAAe;GAC3C,SAAS;IACP,eAAe,KAAK;IACpB,QAAQ;IAGR,GAAI,KAAK,aAAa,EAAE,uBAAuB,KAAK,WAAW,IAAI,CAAC;IACpE,GAAI,UAAU,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;GAC1D;GACA,GAAI,UAAU,EAAE,MAAM,KAAK,UAAU,QAAQ,IAAI,EAAE,IAAI,CAAC;EAC1D,CAAC;EACD,IAAI,CAAC,IAAI,IAAI;GAGX,IAAI,SAAwB;GAC5B,IAAI;IACF,MAAM,UAAW,MAAM,IAAI,KAAK;IAOhC,SACE,QAAQ,gBAAgB,MACxB,OAAO,OAAO,QAAQ,UAAU,CAAC,CAAC,CAAC,CAAC,MACpC,QAAQ,UACR,QAAQ,SACR,QAAQ,SACR;GACJ,QAAQ,CAER;GACA,MAAM,IAAI,aAAa,4BAA4B,IAAI,OAAO,GAAG,SAAS,KAAK,WAAW,MAAM,IAAI,MAAM;EAC5G;EACA,IAAI,IAAI,WAAW,KAAK,OAAO,KAAA;EAC/B,OAAQ,MAAM,IAAI,KAAK;CACzB;CAEA,MAAM,gBAAyC;EAC7C,OAAO,KAAK,SAAyB,OAAO,wBAAwB;CACtE;;CAGA,MAAM,aAAa,UAAgC,CAAC,GAAmC;EACrF,OAAO,KAAK,SAAgC,OAAO,8BAA8B,EAC/E,OAAO;GAAE,SAAS,QAAQ,WAAW;GAAG,YAAA;EAAoC,EAC9E,CAAC;CACH;;CAGA,MAAM,aAAa,SAKS;EAC1B,OAAO,KAAK,SAAyB,QAAQ,0BAA0B,EACrE,MAAM;GACJ,KAAK,QAAQ;GACb,QAAQ,CAAC,GAAI,QAAQ,UAAU,iBAAkB;GACjD,YAAY,QAAQ,cAAA;GACpB,GAAI,QAAQ,gBAAgB,EAAE,eAAe,QAAQ,cAAc,IAAI,CAAC;EAC1E,EACF,CAAC;CACH;;CAGA,MAAM,SAAS,SAAqC;EAClD,OAAO,KAAK,SAAoB,OAAO,qBAAqB,mBAAmB,OAAO,KAAK,EACzF,OAAO,EAAE,QAAQ,kBAAkB,KAAK,GAAG,EAAE,EAC/C,CAAC;CACH;;CAGA,MAAM,aAAa,SAAiB,UAAgC,CAAC,GAA6B;EAChG,OAAO,KAAK,SAA0B,OAAO,qBAAqB,mBAAmB,OAAO,EAAE,WAAW,EACvG,OAAO;GAAE,SAAS,QAAQ,WAAW;GAAG,YAAA;EAAoC,EAC9E,CAAC;CACH;;CAGA,MAAM,cAAc,SAAiB,MAAoC;EACvE,OAAO,KAAK,SAAsB,QAAQ,qBAAqB,mBAAmB,OAAO,EAAE,WAAW,EACpG,MAAM,EAAE,MAAM,UAAU,IAAI,EAAE,EAChC,CAAC;CACH;;CAGA,MAAM,gBAAgB,SAA4C;EAKhE,QAAO,MAJY,KAAK,SACtB,OACA,qBAAqB,mBAAmB,OAAO,EAAE,aACnD,EAAA,CACY,eAAe,CAAC;CAC9B;;CAGA,MAAM,gBAAgB,SAAiB,cAAqC;EAC1E,MAAM,KAAK,SAAe,QAAQ,qBAAqB,mBAAmB,OAAO,EAAE,eAAe,EAChG,MAAM,EAAE,YAAY,EAAE,IAAI,aAAa,EAAE,EAC3C,CAAC;CACH;AACF"}
@@ -1,4 +1,4 @@
1
- //#region src/integrations/jira/claim.ts
1
+ // src/integrations/jira/claim.ts
2
2
  /**
3
3
  * Org-wide ownership key for a Jira issue's Factory card. Keyed by the issue
4
4
  * reference the intake feed serves as `id` — the direct integration's stable
@@ -9,7 +9,6 @@
9
9
  function jiraClaimKey(issueRef) {
10
10
  return `jira:issue:${issueRef}`;
11
11
  }
12
- //#endregion
13
12
  export { jiraClaimKey };
14
13
 
15
14
  //# sourceMappingURL=claim.js.map
@@ -1,6 +1,6 @@
1
1
  import { recordExplicitRuleOverrides } from "../../rules/event-rules.js";
2
2
  import { jiraClaimKey } from "./claim.js";
3
- //#region src/integrations/jira/default-rules.ts
3
+ // src/integrations/jira/default-rules.ts
4
4
  function jiraIssueObserved(context) {
5
5
  if (context.item) return;
6
6
  return {
@@ -63,7 +63,6 @@ function resolveJiraRules(overrides) {
63
63
  }
64
64
  return recordExplicitRuleOverrides(Object.freeze(rules), overrides);
65
65
  }
66
- //#endregion
67
66
  export { defaultJiraRules, resolveJiraRules };
68
67
 
69
68
  //# sourceMappingURL=default-rules.js.map
@@ -26,8 +26,10 @@ import { JiraApiClient } from './api.js';
26
26
  import type { JiraEventRules, JiraRuleOverrides } from './default-rules.js';
27
27
  /** Deployment-global Jira Cloud credentials. All credential fields are required. */
28
28
  export interface JiraIntegrationConfig {
29
- /** Site base URL, e.g. `https://acme.atlassian.net`. */
29
+ /** Site base URL, e.g. `https://acme.atlassian.net`, used for browser links. */
30
30
  baseUrl: string;
31
+ /** API base URL for scoped tokens. Defaults to `baseUrl`. */
32
+ apiBaseUrl?: string;
31
33
  /** Atlassian account email the API token belongs to. */
32
34
  email: string;
33
35
  /** API token from id.atlassian.com → Security → API tokens. */
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/jira/integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAIV,MAAM,EACN,WAAW,EASZ,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAK3F,OAAO,EAAE,aAAa,EAAgB,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5E,oFAAoF;AACpF,MAAM,WAAW,qBAAqB;IACpC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAQD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,qBAA2E,CAAC;AAgChH,qBAAa,eAAgB,YAAW,kBAAkB;;IACxD,wDAAwD;IACxD,QAAQ,CAAC,EAAE,UAAU;IAGrB,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAS5B,IAAI,KAAK,IAAI,cAAc,CAE1B;gBAEW,MAAM,EAAE,qBAAqB;IAOzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;QAAE,QAAQ,EAAE,sBAAsB,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI;IAK3F,+EAA+E;IAC/E,IAAI,QAAQ,IAAI,sBAAsB,CAKrC;IAED;;;OAGG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;OAIG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAuB9D,oDAAoD;IACpD,WAAW,IAAI,IAAI;IAInB,0FAA0F;IAC1F,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,QAAQ,CAAC,MAAM,EAAE,MAAM,CAQrB;IA6EF;;;;OAIG;IACG,gBAAgB,CACpB,MAAM,CAAC,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC;QAAE,MAAM,EAAE,KAAK,CAAC,WAAW,GAAG;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAyH5F;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,QAAQ,EAAE;IAS3C;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,YAAY,EAAE;IAchD;;;;OAIG;IACG,UAAU,CAAC,IAAI,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIrF,sEAAsE;IACtE,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOvC"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/jira/integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAIV,MAAM,EACN,WAAW,EASZ,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAK3F,OAAO,EAAE,aAAa,EAAgB,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5E,oFAAoF;AACpF,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAQD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,qBAA2E,CAAC;AA6ChH,qBAAa,eAAgB,YAAW,kBAAkB;;IACxD,wDAAwD;IACxD,QAAQ,CAAC,EAAE,UAAU;IAIrB,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAS5B,IAAI,KAAK,IAAI,cAAc,CAE1B;gBAEW,MAAM,EAAE,qBAAqB;IAQzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;QAAE,QAAQ,EAAE,sBAAsB,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI;IAK3F,+EAA+E;IAC/E,IAAI,QAAQ,IAAI,sBAAsB,CAKrC;IAED;;;OAGG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;OAIG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAuB9D,oDAAoD;IACpD,WAAW,IAAI,IAAI;IAInB,0FAA0F;IAC1F,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,QAAQ,CAAC,MAAM,EAAE,MAAM,CAQrB;IA6EF;;;;OAIG;IACG,gBAAgB,CACpB,MAAM,CAAC,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC;QAAE,MAAM,EAAE,KAAK,CAAC,WAAW,GAAG;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAyH5F;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,QAAQ,EAAE;IAS3C;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,YAAY,EAAE;IAchD;;;;OAIG;IACG,UAAU,CAAC,IAAI,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIrF,sEAAsE;IACtE,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOvC"}
@@ -7,7 +7,7 @@ import { attachJiraIssueReconciler } from "./issue-reconciler.js";
7
7
  import { jiraReconciliationEnabled, jiraReconciliationInterval } from "./reconciliation-config.js";
8
8
  import { buildJiraRoutes } from "./routes.js";
9
9
  import { buildJiraAgentTools } from "./agent-tools.js";
10
- //#region src/integrations/jira/integration.ts
10
+ // src/integrations/jira/integration.ts
11
11
  /** Hard stop for comment pagination so a misbehaving `total` can't loop forever. */
12
12
  const ISSUE_COMMENTS_MAX_PAGES = 20;
13
13
  /** Hard stop for project pagination so a misbehaving `isLast` can't loop forever. */
@@ -25,6 +25,16 @@ const DEPLOYMENT_CONNECTION = {
25
25
  /** Jira issue keys look like `ENG-42`. */
26
26
  const ISSUE_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*-\d+$/;
27
27
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
28
+ function normalizeSiteBaseUrl(baseUrl) {
29
+ let parsed;
30
+ try {
31
+ parsed = new URL(baseUrl);
32
+ } catch {
33
+ throw new Error(`JiraIntegration baseUrl is not an absolute URL: "${baseUrl}".`);
34
+ }
35
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw new Error(`JiraIntegration baseUrl must be an http(s) URL: "${baseUrl}".`);
36
+ return baseUrl.replace(/\/+$/, "");
37
+ }
28
38
  /**
29
39
  * Capability state types (`capabilities/intake.ts`) → Jira status-category
30
40
  * keys. `canceled` has no Jira category — it is resolved separately against
@@ -48,6 +58,7 @@ var JiraIntegration = class {
48
58
  /** Stable integration identifier (see `../base.ts`). */
49
59
  id = "jira";
50
60
  #config;
61
+ #baseUrl;
51
62
  /** Typed REST client bound to the deployment credentials. */
52
63
  api;
53
64
  /** Bound once by the factory via `initialize()` before any surface is used. */
@@ -60,7 +71,11 @@ var JiraIntegration = class {
60
71
  }
61
72
  constructor(config) {
62
73
  this.#rules = resolveJiraRules(config.rules);
63
- this.api = new JiraApiClient(config);
74
+ this.#baseUrl = normalizeSiteBaseUrl(config.baseUrl);
75
+ this.api = new JiraApiClient({
76
+ ...config,
77
+ baseUrl: config.apiBaseUrl ?? config.baseUrl
78
+ });
64
79
  this.#config = config;
65
80
  }
66
81
  /**
@@ -112,7 +127,7 @@ var JiraIntegration = class {
112
127
  }
113
128
  /** Normalized site base URL (no trailing slash) — `/browse/<key>` links hang off this. */
114
129
  get baseUrl() {
115
- return this.api.baseUrl;
130
+ return this.#baseUrl;
116
131
  }
117
132
  intake = {
118
133
  resolveIntakeDispatch: (input) => this.#resolveIntakeDispatch(input),
@@ -401,7 +416,6 @@ function resolveTransition(transitions, target) {
401
416
  const category = STATE_TYPE_TO_CATEGORY[target.stateType];
402
417
  return transitions.find((transition) => transition.to?.statusCategory?.key === category) ?? null;
403
418
  }
404
- //#endregion
405
419
  export { DEPLOYMENT_CONNECTION, JiraIntegration };
406
420
 
407
421
  //# sourceMappingURL=integration.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"integration.js","names":[],"sources":["../../../src/integrations/jira/integration.ts"],"sourcesContent":["/**\n * `JiraIntegration` — the self-contained Jira Cloud integration.\n *\n * Implements the system-wide `FactoryIntegration` contract\n * (`../base.ts`): the deploy entry reads the `JIRA_*` env vars ONCE,\n * constructs an instance with explicit credentials, and passes it to\n * `MastraFactory`. Everything Jira-flavored the system does — project/issue\n * reads for Intake and the agent's issue tools — flows through this\n * instance. No other module reads `JIRA_*` env vars.\n *\n * Unlike Linear, credentials are **deployment-global** (Basic auth with\n * `email:apiToken` from the environment): there is no OAuth flow, no state\n * signer, and no per-org connection storage. The `IntegrationConnection`\n * arguments required by the `Intake` contract are accepted but not consulted\n * — the instance's own credentials authenticate every call.\n */\n\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\n\nimport type { IntegrationConnection } from '../../capabilities/connection.js';\nimport type {\n CreateIntakeCommentInput,\n CreatedIntakeComment,\n GetIntakeIssueInput,\n Intake,\n IntakeIssue,\n IntakeIssueDetail,\n IntakeItemPage,\n IntakeSource,\n ListIntakeIssuesInput,\n ListIntakeItemsInput,\n ResolveIntakeDispatchInput,\n ResolvedIntakeDispatch,\n UpdateIntakeIssueInput,\n} from '../../capabilities/intake.js';\nimport type { RouteAuth } from '../../routes/route.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../base.js';\nimport { IssueReconcileWorker } from '../issue-reconcile-worker.js';\nimport { adfToText } from './adf.js';\nimport { buildJiraAgentTools } from './agent-tools.js';\nimport type { JiraComment, JiraIssue, JiraTransition } from './api.js';\nimport { JiraApiClient, JiraApiError } from './api.js';\nimport type { JiraEventRules, JiraRuleOverrides } from './default-rules.js';\nimport { resolveJiraRules } from './default-rules.js';\nimport { attachJiraIssueReconciler } from './issue-reconciler.js';\nimport { jiraReconciliationEnabled, jiraReconciliationInterval } from './reconciliation-config.js';\nimport { buildJiraRoutes } from './routes.js';\nimport { attachJiraRules } from './rules.js';\n\n/** Deployment-global Jira Cloud credentials. All credential fields are required. */\nexport interface JiraIntegrationConfig {\n /** Site base URL, e.g. `https://acme.atlassian.net`. */\n baseUrl: string;\n /** Atlassian account email the API token belongs to. */\n email: string;\n /** API token from id.atlassian.com → Security → API tokens. */\n apiToken: string;\n /** Per-event replacements; omitted events retain defaults, null disables. */\n rules?: JiraRuleOverrides;\n}\n\n/** Hard stop for comment pagination so a misbehaving `total` can't loop forever. */\nconst ISSUE_COMMENTS_MAX_PAGES = 20;\n\n/** Hard stop for project pagination so a misbehaving `isLast` can't loop forever. */\nconst PROJECT_SEARCH_MAX_PAGES = 50;\n\n/**\n * The `Intake` contract requires a connection argument, but Jira credentials\n * live on the integration instance — this inert placeholder is accepted and\n * ignored everywhere, and keeps the real API token out of resolved dispatches\n * and agent-tool calls.\n */\nexport const DEPLOYMENT_CONNECTION: IntegrationConnection = { type: 'oauth', accessToken: 'deployment-global' };\n\n/** Jira issue keys look like `ENG-42`. */\nconst ISSUE_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*-\\d+$/;\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Capability state types (`capabilities/intake.ts`) → Jira status-category\n * keys. `canceled` has no Jira category — it is resolved separately against\n * `done`-category transitions whose status name contains \"cancel\".\n */\nconst STATE_TYPE_TO_CATEGORY: Record<'unstarted' | 'started' | 'completed', string> = {\n unstarted: 'new',\n started: 'indeterminate',\n completed: 'done',\n};\n\n/** Jira status-category keys → capability state types. */\nfunction stateTypeFromCategory(key: string | undefined): string | null {\n switch (key) {\n case 'new':\n return 'unstarted';\n case 'indeterminate':\n return 'started';\n case 'done':\n return 'completed';\n default:\n return null;\n }\n}\n\nexport class JiraIntegration implements FactoryIntegration {\n /** Stable integration identifier (see `../base.ts`). */\n readonly id = 'jira';\n\n readonly #config: JiraIntegrationConfig;\n /** Typed REST client bound to the deployment credentials. */\n readonly api: JiraApiClient;\n\n /** Bound once by the factory via `initialize()` before any surface is used. */\n #projects: FactoryProjectsStorage | undefined;\n #auth: RouteAuth | undefined;\n readonly #orgIdByResourceId = new Map<string, string | null>();\n\n readonly #rules: JiraEventRules;\n\n get rules(): JiraEventRules {\n return this.#rules;\n }\n\n constructor(config: JiraIntegrationConfig) {\n this.#rules = resolveJiraRules(config.rules);\n // JiraApiClient validates the credential group and normalizes the URL.\n this.api = new JiraApiClient(config);\n this.#config = config;\n }\n\n /**\n * Bind the projects domain and the host auth seam. Jira has no per-org\n * connection rows, so the generic storage handle is unused — credentials\n * are deployment-global constructor config.\n */\n initialize({ projects, auth }: { projects: FactoryProjectsStorage; auth: RouteAuth }): void {\n this.#projects = projects;\n this.#auth = auth;\n }\n\n /** Factory projects domain — maps a session's resourceId to its owning org. */\n get projects(): FactoryProjectsStorage {\n if (!this.#projects) {\n throw new Error('JiraIntegration is not initialized — the factory binds storage during prepare().');\n }\n return this.#projects;\n }\n\n /**\n * Whether the host runs with web auth enabled. Intake selections are\n * org-owned, so every Jira surface is inert without a tenant auth seam.\n */\n get authEnabled(): boolean {\n return this.#auth?.enabled() ?? false;\n }\n\n /**\n * Map a session's resourceId (the factory project id) to its owning org.\n * Same caching semantics as the Linear integration: definitive misses are\n * cached, transient database failures are not.\n */\n async resolveOrgId(resourceId: string): Promise<string | null> {\n const cached = this.#orgIdByResourceId.get(resourceId);\n if (cached !== undefined) return cached;\n // Non-UUID resource ids (local/dev resources) would make the uuid column\n // comparison throw — they're definitively \"not a project\", so cache that.\n if (!UUID_PATTERN.test(resourceId)) {\n this.#orgIdByResourceId.set(resourceId, null);\n return null;\n }\n let orgId: string | null;\n try {\n await this.projects.ensureReady();\n const project = await this.projects.getById({ id: resourceId });\n orgId = project?.orgId ?? null;\n } catch {\n // Transient database failure: skip the tools for this request but don't\n // cache the miss, so the next request retries the lookup.\n return null;\n }\n this.#orgIdByResourceId.set(resourceId, orgId);\n return orgId;\n }\n\n /** Test hook: clear the org cache between specs. */\n clearCaches(): void {\n this.#orgIdByResourceId.clear();\n }\n\n /** Normalized site base URL (no trailing slash) — `/browse/<key>` links hang off this. */\n get baseUrl(): string {\n return this.api.baseUrl;\n }\n\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: () => this.#listSources(),\n listItems: input => this.#listItems(input),\n listIssues: input => this.#listIssues(input),\n getIssue: input => this.#getIssue(input),\n createComment: input => this.#createComment(input),\n updateIssue: input => this.#updateIssue(input),\n };\n\n /**\n * Background-dispatch context. Credentials are deployment-global, so the\n * returned connection is a formality the Jira intake methods ignore; the\n * issue key is stored directly as the work item's `externalId` (mirroring\n * Linear, which stores the issue UUID).\n */\n async #resolveIntakeDispatch({ externalSource }: ResolveIntakeDispatchInput): Promise<ResolvedIntakeDispatch | null> {\n if (externalSource.type !== 'issue') return null;\n return {\n // Inert placeholder, never the real token: the Jira intake methods read\n // credentials from the client, and the resolved dispatch travels through\n // generic reconciler/dispatcher code that must stay secret-free.\n connection: DEPLOYMENT_CONNECTION,\n issueId: externalSource.externalId,\n };\n }\n\n /** All the site's projects (Settings intake-source picker), following `isLast` paging. */\n async #listSources(): Promise<IntakeSource[]> {\n const sources: IntakeSource[] = [];\n let startAt = 0;\n for (let pageCount = 0; pageCount < PROJECT_SEARCH_MAX_PAGES; pageCount++) {\n const page = await this.api.listProjects({ startAt });\n for (const project of page.values) {\n sources.push({\n id: project.id,\n name: project.name,\n type: 'project',\n metadata: { key: project.key },\n });\n }\n if (page.isLast || page.values.length === 0) break;\n startAt += page.values.length;\n }\n return sources;\n }\n\n async #listItems({ sourceIds, cursor }: ListIntakeItemsInput): Promise<IntakeItemPage> {\n if (sourceIds.length === 0) return { items: [], nextCursor: null };\n const page = await this.listActiveIssues(cursor, sourceIds);\n return {\n items: page.issues.map(issue => ({\n source: { type: 'issue', externalId: issue.identifier, url: issue.url },\n sourceId: issue.sourceId,\n title: `${issue.identifier}: ${issue.title}`,\n status: issue.state ?? undefined,\n labels: issue.labels,\n assignee: issue.assignee,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: {\n identifier: issue.identifier,\n issueRef: issue.identifier,\n state: issue.state,\n stateType: issue.stateType,\n priority: issue.priority,\n project: issue.source,\n assignee: issue.assignee,\n assignees: issue.assignees ?? [],\n creator: issue.author,\n author: issue.author,\n labels: issue.labels,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n },\n })),\n nextCursor: page.nextCursor,\n };\n }\n\n async #listIssues(input: ListIntakeIssuesInput): Promise<{ issues: IntakeIssue[]; nextCursor: string | null }> {\n const page = await this.listActiveIssues(input.cursor, input.sourceIds, input.labels);\n return { issues: page.issues, nextCursor: page.nextCursor };\n }\n\n /**\n * One page of active issues (status category not Done), most recently\n * updated first, optionally filtered to projects and labels. The\n * capability cursor is Jira's opaque `nextPageToken` passed through.\n */\n async listActiveIssues(\n cursor?: string,\n projectIds?: string[],\n labels?: string[],\n ): Promise<{ issues: Array<IntakeIssue & { sourceId: string }>; nextCursor: string | null }> {\n const page = await this.api.searchIssues({\n jql: buildIntakeJql(projectIds, labels),\n ...(cursor ? { nextPageToken: cursor } : {}),\n });\n return {\n issues: page.issues.map(issue => ({\n ...this.#toIntakeIssue(issue),\n sourceId: issue.fields.project?.id ?? '',\n })),\n nextCursor: page.nextPageToken ?? null,\n };\n }\n\n async #getIssue({ issueId }: GetIntakeIssueInput): Promise<IntakeIssueDetail | null> {\n let issue: JiraIssue;\n try {\n issue = await this.api.getIssue(issueId);\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n const { comments, total } = await this.#listAllComments(issue.key);\n return {\n ...this.#toIntakeIssue(issue),\n commentCount: total,\n description: issue.fields.description ? adfToText(issue.fields.description) || null : null,\n comments: comments.map(comment => ({\n author: comment.author?.displayName ?? null,\n body: adfToText(comment.body),\n createdAt: comment.created,\n })),\n };\n }\n\n /** Every comment on the issue, oldest first, bounded by {@link ISSUE_COMMENTS_MAX_PAGES}. */\n async #listAllComments(keyOrId: string): Promise<{ comments: JiraComment[]; total: number }> {\n const comments: JiraComment[] = [];\n let total = 0;\n for (let page = 0; page < ISSUE_COMMENTS_MAX_PAGES; page++) {\n const result = await this.api.listComments(keyOrId, { startAt: comments.length });\n comments.push(...result.comments);\n total = result.total;\n if (result.comments.length === 0 || comments.length >= total) break;\n }\n return { comments, total };\n }\n\n async #createComment({ issueId, body }: CreateIntakeCommentInput): Promise<CreatedIntakeComment | null> {\n // The browse URL needs the issue key; resolve it when the caller passed a\n // numeric id instead.\n let key = issueId;\n if (!ISSUE_KEY_PATTERN.test(issueId)) {\n try {\n key = (await this.api.getIssue(issueId)).key;\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n }\n let comment;\n try {\n comment = await this.api.createComment(key, body);\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n return {\n id: comment.id,\n url: `${this.baseUrl}/browse/${key}?focusedCommentId=${comment.id}`,\n };\n }\n\n /**\n * Move an issue to a target state by applying a workflow transition. Jira\n * only exposes transitions that are currently legal, so a policy miss (no\n * transition reaches the target) returns `null` per the `Intake` contract —\n * infrastructure errors (network, auth) still throw.\n */\n async #updateIssue(input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> {\n let issue: JiraIssue;\n try {\n issue = await this.api.getIssue(input.issueId);\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n if (currentStatusMatches(issue, input.state)) {\n return this.#toIntakeIssue(issue);\n }\n const transitions = await this.api.listTransitions(issue.key);\n const transition = resolveTransition(transitions, input.state);\n if (!transition) return null;\n await this.api.applyTransition(issue.key, transition.id);\n const fresh = await this.api.getIssue(issue.key);\n return this.#toIntakeIssue(fresh);\n }\n\n #toIntakeIssue(issue: JiraIssue): IntakeIssue {\n const { fields } = issue;\n return {\n id: issue.id,\n identifier: issue.key,\n title: fields.summary ?? issue.key,\n url: `${this.baseUrl}/browse/${issue.key}`,\n author: fields.reporter?.displayName ?? null,\n state: fields.status?.name ?? null,\n stateType: stateTypeFromCategory(fields.status?.statusCategory?.key),\n priority: fields.priority?.name ?? null,\n assignee: fields.assignee?.displayName ?? null,\n source: fields.project?.key ?? null,\n sourceId: fields.project?.id ?? null,\n labels: fields.labels ?? [],\n commentCount: null,\n createdAt: fields.created ?? '',\n updatedAt: fields.updated ?? '',\n };\n }\n\n // ── FactoryIntegration surface ───────────────────────────────────────────\n\n /**\n * The integration's HTTP surface: `/web/jira/*` Mastra `apiRoutes` (status,\n * projects + issues for Intake). No OAuth routes — credentials are\n * deployment-global. Handlers operate on this instance.\n */\n routes(ctx: IntegrationContext): ApiRoute[] {\n return buildJiraRoutes({\n jira: this,\n auth: ctx.auth,\n intake: ctx.storage.intake,\n ingestFactoryIssues: attachJiraRules(this, ctx),\n });\n }\n\n /**\n * Background reconciliation, matching the Platform integration: keeps filed\n * Jira cards' metadata fresh and replays close events through the rules\n * ingress. Registered only when reconciliation is enabled.\n */\n workers(ctx: IntegrationContext): MastraWorker[] {\n if (!jiraReconciliationEnabled()) return [];\n const reconcile = attachJiraIssueReconciler(this, ctx);\n if (!reconcile) return [];\n const intervalMs = jiraReconciliationInterval();\n return [\n new IssueReconcileWorker({\n integrationId: this.id,\n reconcile,\n ...(intervalMs ? { intervalMs } : {}),\n }),\n ];\n }\n\n /**\n * Org-scoped agent tools: the read-only issue-detail tool for sessions whose\n * resource is a factory project (Jira credentials are deployment-global,\n * so no per-org connection gates apply). v1 exposes no mutating Jira tools.\n */\n async agentTools(args: { requestContext: RequestContext }): Promise<IntegrationTools> {\n return buildJiraAgentTools({ requestContext: args.requestContext, jira: this });\n }\n\n /** Non-secret config snapshot for system diagnostics/startup logs. */\n diagnostics(): Record<string, unknown> {\n return {\n configured: true,\n site: new URL(this.baseUrl).host,\n email: maskEmail(this.#config.email),\n };\n }\n}\n\n/** `ops@acme.test` → `o***@acme.test` — enough to identify, never the value. */\nfunction maskEmail(email: string): string {\n const at = email.indexOf('@');\n if (at <= 0) return '***';\n return `${email[0]}***${email.slice(at)}`;\n}\n\n/**\n * Build the intake JQL. Source ids and labels come from stored org config /\n * request input, so both are sanitized before interpolation: numeric project\n * ids pass through bare, project keys are restricted to a safe charset, and\n * label quotes/backslashes are stripped.\n */\nfunction buildIntakeJql(projectIds?: string[], labels?: string[]): string {\n const clauses: string[] = [];\n const safeProjects = (projectIds ?? [])\n .map(id => id.trim())\n .filter(id => /^[A-Za-z0-9_]+$/.test(id))\n .map(id => (/^\\d+$/.test(id) ? id : `\"${id}\"`));\n if (safeProjects.length > 0) {\n clauses.push(`project IN (${safeProjects.join(', ')})`);\n }\n clauses.push('statusCategory != Done');\n const safeLabels = [...new Set((labels ?? []).map(label => label.trim().replace(/[\"\\\\]/g, '')).filter(Boolean))];\n if (safeLabels.length > 0) {\n clauses.push(`labels IN (${safeLabels.map(label => `\"${label}\"`).join(', ')})`);\n }\n return `${clauses.join(' AND ')} ORDER BY updated DESC`;\n}\n\n/** Whether the issue is already in the requested target state. */\nfunction currentStatusMatches(issue: JiraIssue, target: UpdateIntakeIssueInput['state']): boolean {\n const status = issue.fields.status;\n if (!status) return false;\n if (target.kind === 'byName') {\n return status.name.toLowerCase() === target.name.toLowerCase();\n }\n if (target.stateType === 'canceled') {\n return status.statusCategory?.key === 'done' && /cancel/i.test(status.name);\n }\n return status.statusCategory?.key === STATE_TYPE_TO_CATEGORY[target.stateType];\n}\n\n/** Resolve the target state against the issue's currently-legal transitions. */\nfunction resolveTransition(\n transitions: JiraTransition[],\n target: UpdateIntakeIssueInput['state'],\n): JiraTransition | null {\n if (target.kind === 'byName') {\n const wanted = target.name.toLowerCase();\n return transitions.find(transition => transition.to?.name.toLowerCase() === wanted) ?? null;\n }\n if (target.stateType === 'canceled') {\n return (\n transitions.find(\n transition => transition.to?.statusCategory?.key === 'done' && /cancel/i.test(transition.to.name),\n ) ?? null\n );\n }\n const category = STATE_TYPE_TO_CATEGORY[target.stateType];\n return transitions.find(transition => transition.to?.statusCategory?.key === category) ?? null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"integration.js","names":[],"sources":["../../../src/integrations/jira/integration.ts"],"sourcesContent":["/**\n * `JiraIntegration` — the self-contained Jira Cloud integration.\n *\n * Implements the system-wide `FactoryIntegration` contract\n * (`../base.ts`): the deploy entry reads the `JIRA_*` env vars ONCE,\n * constructs an instance with explicit credentials, and passes it to\n * `MastraFactory`. Everything Jira-flavored the system does — project/issue\n * reads for Intake and the agent's issue tools — flows through this\n * instance. No other module reads `JIRA_*` env vars.\n *\n * Unlike Linear, credentials are **deployment-global** (Basic auth with\n * `email:apiToken` from the environment): there is no OAuth flow, no state\n * signer, and no per-org connection storage. The `IntegrationConnection`\n * arguments required by the `Intake` contract are accepted but not consulted\n * — the instance's own credentials authenticate every call.\n */\n\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\n\nimport type { IntegrationConnection } from '../../capabilities/connection.js';\nimport type {\n CreateIntakeCommentInput,\n CreatedIntakeComment,\n GetIntakeIssueInput,\n Intake,\n IntakeIssue,\n IntakeIssueDetail,\n IntakeItemPage,\n IntakeSource,\n ListIntakeIssuesInput,\n ListIntakeItemsInput,\n ResolveIntakeDispatchInput,\n ResolvedIntakeDispatch,\n UpdateIntakeIssueInput,\n} from '../../capabilities/intake.js';\nimport type { RouteAuth } from '../../routes/route.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../base.js';\nimport { IssueReconcileWorker } from '../issue-reconcile-worker.js';\nimport { adfToText } from './adf.js';\nimport { buildJiraAgentTools } from './agent-tools.js';\nimport type { JiraComment, JiraIssue, JiraTransition } from './api.js';\nimport { JiraApiClient, JiraApiError } from './api.js';\nimport type { JiraEventRules, JiraRuleOverrides } from './default-rules.js';\nimport { resolveJiraRules } from './default-rules.js';\nimport { attachJiraIssueReconciler } from './issue-reconciler.js';\nimport { jiraReconciliationEnabled, jiraReconciliationInterval } from './reconciliation-config.js';\nimport { buildJiraRoutes } from './routes.js';\nimport { attachJiraRules } from './rules.js';\n\n/** Deployment-global Jira Cloud credentials. All credential fields are required. */\nexport interface JiraIntegrationConfig {\n /** Site base URL, e.g. `https://acme.atlassian.net`, used for browser links. */\n baseUrl: string;\n /** API base URL for scoped tokens. Defaults to `baseUrl`. */\n apiBaseUrl?: string;\n /** Atlassian account email the API token belongs to. */\n email: string;\n /** API token from id.atlassian.com → Security → API tokens. */\n apiToken: string;\n /** Per-event replacements; omitted events retain defaults, null disables. */\n rules?: JiraRuleOverrides;\n}\n\n/** Hard stop for comment pagination so a misbehaving `total` can't loop forever. */\nconst ISSUE_COMMENTS_MAX_PAGES = 20;\n\n/** Hard stop for project pagination so a misbehaving `isLast` can't loop forever. */\nconst PROJECT_SEARCH_MAX_PAGES = 50;\n\n/**\n * The `Intake` contract requires a connection argument, but Jira credentials\n * live on the integration instance — this inert placeholder is accepted and\n * ignored everywhere, and keeps the real API token out of resolved dispatches\n * and agent-tool calls.\n */\nexport const DEPLOYMENT_CONNECTION: IntegrationConnection = { type: 'oauth', accessToken: 'deployment-global' };\n\n/** Jira issue keys look like `ENG-42`. */\nconst ISSUE_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*-\\d+$/;\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nfunction normalizeSiteBaseUrl(baseUrl: string): string {\n let parsed: URL;\n try {\n parsed = new URL(baseUrl);\n } catch {\n throw new Error(`JiraIntegration baseUrl is not an absolute URL: \"${baseUrl}\".`);\n }\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new Error(`JiraIntegration baseUrl must be an http(s) URL: \"${baseUrl}\".`);\n }\n return baseUrl.replace(/\\/+$/, '');\n}\n\n/**\n * Capability state types (`capabilities/intake.ts`) → Jira status-category\n * keys. `canceled` has no Jira category — it is resolved separately against\n * `done`-category transitions whose status name contains \"cancel\".\n */\nconst STATE_TYPE_TO_CATEGORY: Record<'unstarted' | 'started' | 'completed', string> = {\n unstarted: 'new',\n started: 'indeterminate',\n completed: 'done',\n};\n\n/** Jira status-category keys → capability state types. */\nfunction stateTypeFromCategory(key: string | undefined): string | null {\n switch (key) {\n case 'new':\n return 'unstarted';\n case 'indeterminate':\n return 'started';\n case 'done':\n return 'completed';\n default:\n return null;\n }\n}\n\nexport class JiraIntegration implements FactoryIntegration {\n /** Stable integration identifier (see `../base.ts`). */\n readonly id = 'jira';\n\n readonly #config: JiraIntegrationConfig;\n readonly #baseUrl: string;\n /** Typed REST client bound to the deployment credentials. */\n readonly api: JiraApiClient;\n\n /** Bound once by the factory via `initialize()` before any surface is used. */\n #projects: FactoryProjectsStorage | undefined;\n #auth: RouteAuth | undefined;\n readonly #orgIdByResourceId = new Map<string, string | null>();\n\n readonly #rules: JiraEventRules;\n\n get rules(): JiraEventRules {\n return this.#rules;\n }\n\n constructor(config: JiraIntegrationConfig) {\n this.#rules = resolveJiraRules(config.rules);\n this.#baseUrl = normalizeSiteBaseUrl(config.baseUrl);\n // JiraApiClient validates the credential group and normalizes the API URL.\n this.api = new JiraApiClient({ ...config, baseUrl: config.apiBaseUrl ?? config.baseUrl });\n this.#config = config;\n }\n\n /**\n * Bind the projects domain and the host auth seam. Jira has no per-org\n * connection rows, so the generic storage handle is unused — credentials\n * are deployment-global constructor config.\n */\n initialize({ projects, auth }: { projects: FactoryProjectsStorage; auth: RouteAuth }): void {\n this.#projects = projects;\n this.#auth = auth;\n }\n\n /** Factory projects domain — maps a session's resourceId to its owning org. */\n get projects(): FactoryProjectsStorage {\n if (!this.#projects) {\n throw new Error('JiraIntegration is not initialized — the factory binds storage during prepare().');\n }\n return this.#projects;\n }\n\n /**\n * Whether the host runs with web auth enabled. Intake selections are\n * org-owned, so every Jira surface is inert without a tenant auth seam.\n */\n get authEnabled(): boolean {\n return this.#auth?.enabled() ?? false;\n }\n\n /**\n * Map a session's resourceId (the factory project id) to its owning org.\n * Same caching semantics as the Linear integration: definitive misses are\n * cached, transient database failures are not.\n */\n async resolveOrgId(resourceId: string): Promise<string | null> {\n const cached = this.#orgIdByResourceId.get(resourceId);\n if (cached !== undefined) return cached;\n // Non-UUID resource ids (local/dev resources) would make the uuid column\n // comparison throw — they're definitively \"not a project\", so cache that.\n if (!UUID_PATTERN.test(resourceId)) {\n this.#orgIdByResourceId.set(resourceId, null);\n return null;\n }\n let orgId: string | null;\n try {\n await this.projects.ensureReady();\n const project = await this.projects.getById({ id: resourceId });\n orgId = project?.orgId ?? null;\n } catch {\n // Transient database failure: skip the tools for this request but don't\n // cache the miss, so the next request retries the lookup.\n return null;\n }\n this.#orgIdByResourceId.set(resourceId, orgId);\n return orgId;\n }\n\n /** Test hook: clear the org cache between specs. */\n clearCaches(): void {\n this.#orgIdByResourceId.clear();\n }\n\n /** Normalized site base URL (no trailing slash) — `/browse/<key>` links hang off this. */\n get baseUrl(): string {\n return this.#baseUrl;\n }\n\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: () => this.#listSources(),\n listItems: input => this.#listItems(input),\n listIssues: input => this.#listIssues(input),\n getIssue: input => this.#getIssue(input),\n createComment: input => this.#createComment(input),\n updateIssue: input => this.#updateIssue(input),\n };\n\n /**\n * Background-dispatch context. Credentials are deployment-global, so the\n * returned connection is a formality the Jira intake methods ignore; the\n * issue key is stored directly as the work item's `externalId` (mirroring\n * Linear, which stores the issue UUID).\n */\n async #resolveIntakeDispatch({ externalSource }: ResolveIntakeDispatchInput): Promise<ResolvedIntakeDispatch | null> {\n if (externalSource.type !== 'issue') return null;\n return {\n // Inert placeholder, never the real token: the Jira intake methods read\n // credentials from the client, and the resolved dispatch travels through\n // generic reconciler/dispatcher code that must stay secret-free.\n connection: DEPLOYMENT_CONNECTION,\n issueId: externalSource.externalId,\n };\n }\n\n /** All the site's projects (Settings intake-source picker), following `isLast` paging. */\n async #listSources(): Promise<IntakeSource[]> {\n const sources: IntakeSource[] = [];\n let startAt = 0;\n for (let pageCount = 0; pageCount < PROJECT_SEARCH_MAX_PAGES; pageCount++) {\n const page = await this.api.listProjects({ startAt });\n for (const project of page.values) {\n sources.push({\n id: project.id,\n name: project.name,\n type: 'project',\n metadata: { key: project.key },\n });\n }\n if (page.isLast || page.values.length === 0) break;\n startAt += page.values.length;\n }\n return sources;\n }\n\n async #listItems({ sourceIds, cursor }: ListIntakeItemsInput): Promise<IntakeItemPage> {\n if (sourceIds.length === 0) return { items: [], nextCursor: null };\n const page = await this.listActiveIssues(cursor, sourceIds);\n return {\n items: page.issues.map(issue => ({\n source: { type: 'issue', externalId: issue.identifier, url: issue.url },\n sourceId: issue.sourceId,\n title: `${issue.identifier}: ${issue.title}`,\n status: issue.state ?? undefined,\n labels: issue.labels,\n assignee: issue.assignee,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: {\n identifier: issue.identifier,\n issueRef: issue.identifier,\n state: issue.state,\n stateType: issue.stateType,\n priority: issue.priority,\n project: issue.source,\n assignee: issue.assignee,\n assignees: issue.assignees ?? [],\n creator: issue.author,\n author: issue.author,\n labels: issue.labels,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n },\n })),\n nextCursor: page.nextCursor,\n };\n }\n\n async #listIssues(input: ListIntakeIssuesInput): Promise<{ issues: IntakeIssue[]; nextCursor: string | null }> {\n const page = await this.listActiveIssues(input.cursor, input.sourceIds, input.labels);\n return { issues: page.issues, nextCursor: page.nextCursor };\n }\n\n /**\n * One page of active issues (status category not Done), most recently\n * updated first, optionally filtered to projects and labels. The\n * capability cursor is Jira's opaque `nextPageToken` passed through.\n */\n async listActiveIssues(\n cursor?: string,\n projectIds?: string[],\n labels?: string[],\n ): Promise<{ issues: Array<IntakeIssue & { sourceId: string }>; nextCursor: string | null }> {\n const page = await this.api.searchIssues({\n jql: buildIntakeJql(projectIds, labels),\n ...(cursor ? { nextPageToken: cursor } : {}),\n });\n return {\n issues: page.issues.map(issue => ({\n ...this.#toIntakeIssue(issue),\n sourceId: issue.fields.project?.id ?? '',\n })),\n nextCursor: page.nextPageToken ?? null,\n };\n }\n\n async #getIssue({ issueId }: GetIntakeIssueInput): Promise<IntakeIssueDetail | null> {\n let issue: JiraIssue;\n try {\n issue = await this.api.getIssue(issueId);\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n const { comments, total } = await this.#listAllComments(issue.key);\n return {\n ...this.#toIntakeIssue(issue),\n commentCount: total,\n description: issue.fields.description ? adfToText(issue.fields.description) || null : null,\n comments: comments.map(comment => ({\n author: comment.author?.displayName ?? null,\n body: adfToText(comment.body),\n createdAt: comment.created,\n })),\n };\n }\n\n /** Every comment on the issue, oldest first, bounded by {@link ISSUE_COMMENTS_MAX_PAGES}. */\n async #listAllComments(keyOrId: string): Promise<{ comments: JiraComment[]; total: number }> {\n const comments: JiraComment[] = [];\n let total = 0;\n for (let page = 0; page < ISSUE_COMMENTS_MAX_PAGES; page++) {\n const result = await this.api.listComments(keyOrId, { startAt: comments.length });\n comments.push(...result.comments);\n total = result.total;\n if (result.comments.length === 0 || comments.length >= total) break;\n }\n return { comments, total };\n }\n\n async #createComment({ issueId, body }: CreateIntakeCommentInput): Promise<CreatedIntakeComment | null> {\n // The browse URL needs the issue key; resolve it when the caller passed a\n // numeric id instead.\n let key = issueId;\n if (!ISSUE_KEY_PATTERN.test(issueId)) {\n try {\n key = (await this.api.getIssue(issueId)).key;\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n }\n let comment;\n try {\n comment = await this.api.createComment(key, body);\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n return {\n id: comment.id,\n url: `${this.baseUrl}/browse/${key}?focusedCommentId=${comment.id}`,\n };\n }\n\n /**\n * Move an issue to a target state by applying a workflow transition. Jira\n * only exposes transitions that are currently legal, so a policy miss (no\n * transition reaches the target) returns `null` per the `Intake` contract —\n * infrastructure errors (network, auth) still throw.\n */\n async #updateIssue(input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> {\n let issue: JiraIssue;\n try {\n issue = await this.api.getIssue(input.issueId);\n } catch (err) {\n if (err instanceof JiraApiError && err.status === 404) return null;\n throw err;\n }\n if (currentStatusMatches(issue, input.state)) {\n return this.#toIntakeIssue(issue);\n }\n const transitions = await this.api.listTransitions(issue.key);\n const transition = resolveTransition(transitions, input.state);\n if (!transition) return null;\n await this.api.applyTransition(issue.key, transition.id);\n const fresh = await this.api.getIssue(issue.key);\n return this.#toIntakeIssue(fresh);\n }\n\n #toIntakeIssue(issue: JiraIssue): IntakeIssue {\n const { fields } = issue;\n return {\n id: issue.id,\n identifier: issue.key,\n title: fields.summary ?? issue.key,\n url: `${this.baseUrl}/browse/${issue.key}`,\n author: fields.reporter?.displayName ?? null,\n state: fields.status?.name ?? null,\n stateType: stateTypeFromCategory(fields.status?.statusCategory?.key),\n priority: fields.priority?.name ?? null,\n assignee: fields.assignee?.displayName ?? null,\n source: fields.project?.key ?? null,\n sourceId: fields.project?.id ?? null,\n labels: fields.labels ?? [],\n commentCount: null,\n createdAt: fields.created ?? '',\n updatedAt: fields.updated ?? '',\n };\n }\n\n // ── FactoryIntegration surface ───────────────────────────────────────────\n\n /**\n * The integration's HTTP surface: `/web/jira/*` Mastra `apiRoutes` (status,\n * projects + issues for Intake). No OAuth routes — credentials are\n * deployment-global. Handlers operate on this instance.\n */\n routes(ctx: IntegrationContext): ApiRoute[] {\n return buildJiraRoutes({\n jira: this,\n auth: ctx.auth,\n intake: ctx.storage.intake,\n ingestFactoryIssues: attachJiraRules(this, ctx),\n });\n }\n\n /**\n * Background reconciliation, matching the Platform integration: keeps filed\n * Jira cards' metadata fresh and replays close events through the rules\n * ingress. Registered only when reconciliation is enabled.\n */\n workers(ctx: IntegrationContext): MastraWorker[] {\n if (!jiraReconciliationEnabled()) return [];\n const reconcile = attachJiraIssueReconciler(this, ctx);\n if (!reconcile) return [];\n const intervalMs = jiraReconciliationInterval();\n return [\n new IssueReconcileWorker({\n integrationId: this.id,\n reconcile,\n ...(intervalMs ? { intervalMs } : {}),\n }),\n ];\n }\n\n /**\n * Org-scoped agent tools: the read-only issue-detail tool for sessions whose\n * resource is a factory project (Jira credentials are deployment-global,\n * so no per-org connection gates apply). v1 exposes no mutating Jira tools.\n */\n async agentTools(args: { requestContext: RequestContext }): Promise<IntegrationTools> {\n return buildJiraAgentTools({ requestContext: args.requestContext, jira: this });\n }\n\n /** Non-secret config snapshot for system diagnostics/startup logs. */\n diagnostics(): Record<string, unknown> {\n return {\n configured: true,\n site: new URL(this.baseUrl).host,\n email: maskEmail(this.#config.email),\n };\n }\n}\n\n/** `ops@acme.test` → `o***@acme.test` — enough to identify, never the value. */\nfunction maskEmail(email: string): string {\n const at = email.indexOf('@');\n if (at <= 0) return '***';\n return `${email[0]}***${email.slice(at)}`;\n}\n\n/**\n * Build the intake JQL. Source ids and labels come from stored org config /\n * request input, so both are sanitized before interpolation: numeric project\n * ids pass through bare, project keys are restricted to a safe charset, and\n * label quotes/backslashes are stripped.\n */\nfunction buildIntakeJql(projectIds?: string[], labels?: string[]): string {\n const clauses: string[] = [];\n const safeProjects = (projectIds ?? [])\n .map(id => id.trim())\n .filter(id => /^[A-Za-z0-9_]+$/.test(id))\n .map(id => (/^\\d+$/.test(id) ? id : `\"${id}\"`));\n if (safeProjects.length > 0) {\n clauses.push(`project IN (${safeProjects.join(', ')})`);\n }\n clauses.push('statusCategory != Done');\n const safeLabels = [...new Set((labels ?? []).map(label => label.trim().replace(/[\"\\\\]/g, '')).filter(Boolean))];\n if (safeLabels.length > 0) {\n clauses.push(`labels IN (${safeLabels.map(label => `\"${label}\"`).join(', ')})`);\n }\n return `${clauses.join(' AND ')} ORDER BY updated DESC`;\n}\n\n/** Whether the issue is already in the requested target state. */\nfunction currentStatusMatches(issue: JiraIssue, target: UpdateIntakeIssueInput['state']): boolean {\n const status = issue.fields.status;\n if (!status) return false;\n if (target.kind === 'byName') {\n return status.name.toLowerCase() === target.name.toLowerCase();\n }\n if (target.stateType === 'canceled') {\n return status.statusCategory?.key === 'done' && /cancel/i.test(status.name);\n }\n return status.statusCategory?.key === STATE_TYPE_TO_CATEGORY[target.stateType];\n}\n\n/** Resolve the target state against the issue's currently-legal transitions. */\nfunction resolveTransition(\n transitions: JiraTransition[],\n target: UpdateIntakeIssueInput['state'],\n): JiraTransition | null {\n if (target.kind === 'byName') {\n const wanted = target.name.toLowerCase();\n return transitions.find(transition => transition.to?.name.toLowerCase() === wanted) ?? null;\n }\n if (target.stateType === 'canceled') {\n return (\n transitions.find(\n transition => transition.to?.statusCategory?.key === 'done' && /cancel/i.test(transition.to.name),\n ) ?? null\n );\n }\n const category = STATE_TYPE_TO_CATEGORY[target.stateType];\n return transitions.find(transition => transition.to?.statusCategory?.key === category) ?? null;\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { workItemPhaseSemantics } from "../../boards/semantics.js";
2
2
  import "../../boards/index.js";
3
3
  import { createIssueReconciler } from "../issue-reconciler.js";
4
4
  import { JiraRules } from "./rules.js";
5
- //#region src/integrations/jira/issue-reconciler.ts
5
+ // src/integrations/jira/issue-reconciler.ts
6
6
  function issueToIngress(issueRef, issue) {
7
7
  return {
8
8
  id: issueRef,
@@ -64,7 +64,6 @@ function attachJiraIssueReconciler(jira, context) {
64
64
  }
65
65
  });
66
66
  }
67
- //#endregion
68
67
  export { attachJiraIssueReconciler };
69
68
 
70
69
  //# sourceMappingURL=issue-reconciler.js.map