specrails-desktop 2.2.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/client/dist/assets/ActivityFeedPage-DJJlZ3mF.js +1 -0
  2. package/client/dist/assets/AgentsPage-49JaEDjR.js +86 -0
  3. package/client/dist/assets/{AnalyticsPage-BD0paa75.js → AnalyticsPage-BUd3gWYC.js} +1 -1
  4. package/client/dist/assets/{BarChart-D8ZZRab3.js → BarChart-HDe_YoUD.js} +1 -1
  5. package/client/dist/assets/CodePage-CqPPND47.js +2 -0
  6. package/client/dist/assets/{DesktopAnalyticsPage-mwd8460_.js → DesktopAnalyticsPage-CgvmSvF0.js} +1 -1
  7. package/client/dist/assets/DocsDialog-hHFd3Ejs.js +11 -0
  8. package/client/dist/assets/DocsPage-B4R1aksg.js +11 -0
  9. package/client/dist/assets/{ExportDropdown-CLYmQhic.js → ExportDropdown-f4dwQjlT.js} +1 -1
  10. package/client/dist/assets/IntegrationsPage-CX2Ybxx0.js +3 -0
  11. package/client/dist/assets/JobDetailPage-DN2Jc8Ti.js +16 -0
  12. package/client/dist/assets/JobsPage-DmdpqijT.js +1 -0
  13. package/client/dist/assets/code-BwIz8agY.js +1 -0
  14. package/client/dist/assets/code-CD7yNSK0.js +1 -0
  15. package/client/dist/assets/code-CDFlxUFC.js +1 -0
  16. package/client/dist/assets/code-CY85RXZU.js +1 -0
  17. package/client/dist/assets/code-Cp3Fdng-.js +1 -0
  18. package/client/dist/assets/code-D24e1Crx.js +1 -0
  19. package/client/dist/assets/code-DtZBQTi9.js +1 -0
  20. package/client/dist/assets/code-nKa0fkm_.js +1 -0
  21. package/client/dist/assets/{cssMode-Cc6ozl-J.js → cssMode-DzNPAYFh.js} +1 -1
  22. package/client/dist/assets/{dist-js-D3MxtOYa.js → dist-js-COfIfLRE.js} +1 -1
  23. package/client/dist/assets/{dist-js-BOu_cXw3.js → dist-js-CvScGQU_.js} +1 -1
  24. package/client/dist/assets/{editor.main-CfXxHimg.js → editor.main-C7Rmw-hR.js} +2 -2
  25. package/client/dist/assets/{freemarker2-DP7J1gG3.js → freemarker2-Cszs4SVo.js} +1 -1
  26. package/client/dist/assets/{handlebars-BjRlucw6.js → handlebars-Dp7Lsuym.js} +1 -1
  27. package/client/dist/assets/{html-OumBQJ-U.js → html-BURidrEm.js} +1 -1
  28. package/client/dist/assets/{htmlMode-CStc3zXM.js → htmlMode--k5M7GjZ.js} +1 -1
  29. package/client/dist/assets/index-DBpvYrDK.css +2 -0
  30. package/client/dist/assets/index-DGIXKRHE.js +142 -0
  31. package/client/dist/assets/{integrations-Cublz3m6.js → integrations-2C7MkGT0.js} +1 -1
  32. package/client/dist/assets/{integrations-HIlUxXVs.js → integrations-BDC670cg.js} +1 -1
  33. package/client/dist/assets/integrations-BqUmRUef.js +1 -0
  34. package/client/dist/assets/{integrations-DmQYCUvN.js → integrations-C2jQtv-s.js} +1 -1
  35. package/client/dist/assets/{integrations-DRdbki5W.js → integrations-CB98NeH5.js} +1 -1
  36. package/client/dist/assets/{integrations-C3p12Ms6.js → integrations-CX4p_bij.js} +1 -1
  37. package/client/dist/assets/{integrations-DaC4SzzL.js → integrations-_SuVeQIG.js} +1 -1
  38. package/client/dist/assets/{integrations-Cr6hH7XR.js → integrations-eQPHAYsE.js} +1 -1
  39. package/client/dist/assets/{javascript-CMk--e7g.js → javascript-kJQz__44.js} +1 -1
  40. package/client/dist/assets/jira-C-ATCti0.js +1 -0
  41. package/client/dist/assets/jira-CmVfRM-b.js +1 -0
  42. package/client/dist/assets/jira-D7bkKAX8.js +1 -0
  43. package/client/dist/assets/jira-DKImM1YH.js +1 -0
  44. package/client/dist/assets/jira-DOw8bkIR.js +1 -0
  45. package/client/dist/assets/jira-DlA-wGp-.js +1 -0
  46. package/client/dist/assets/jira-Fob8EGxN.js +1 -0
  47. package/client/dist/assets/jira-xZA2lixb.js +1 -0
  48. package/client/dist/assets/{jsonMode-C2h3ZcjZ.js → jsonMode-v5JYPpnz.js} +1 -1
  49. package/client/dist/assets/{lib-DQ2hrj8m.js → lib-Bro9Z0gp.js} +1 -1
  50. package/client/dist/assets/{liquid-mI3KJrBE.js → liquid-Dl9I6gWt.js} +1 -1
  51. package/client/dist/assets/{lspLanguageFeatures-DU09ggWi.js → lspLanguageFeatures-CPlEe0NK.js} +1 -1
  52. package/client/dist/assets/{mdx-C41VDTR_.js → mdx-Byl7TtzQ.js} +1 -1
  53. package/client/dist/assets/{monaco.contribution-CPObAXMC.js → monaco.contribution-YMAkHQcQ.js} +2 -2
  54. package/client/dist/assets/{python-Y27rKQtk.js → python-jWQwT6j2.js} +1 -1
  55. package/client/dist/assets/{razor-Cd5-q9Bp.js → razor-BWS3sP-E.js} +1 -1
  56. package/client/dist/assets/setup-C0dzw8j4.js +1 -0
  57. package/client/dist/assets/setup-C1IA-9YS.js +1 -0
  58. package/client/dist/assets/setup-CpfjaNut.js +1 -0
  59. package/client/dist/assets/setup-D3rNZA9A.js +1 -0
  60. package/client/dist/assets/setup-UD2aanGs.js +1 -0
  61. package/client/dist/assets/setup-WP6WOYQh.js +1 -0
  62. package/client/dist/assets/setup-gzLG8T6F.js +1 -0
  63. package/client/dist/assets/setup-pjgmYHx6.js +1 -0
  64. package/client/dist/assets/specs-4lA_u79w.js +1 -0
  65. package/client/dist/assets/{specs-D2FzlLn9.js → specs-BHjxcjOf.js} +1 -1
  66. package/client/dist/assets/{specs-CZ1PsXsC.js → specs-CXNQzPk9.js} +1 -1
  67. package/client/dist/assets/{specs-Dyc5hYeE.js → specs-DFnc2Huj.js} +1 -1
  68. package/client/dist/assets/{specs-BFfu3u-a.js → specs-DZCLH2-l.js} +1 -1
  69. package/client/dist/assets/{specs-B__C8-8a.js → specs-DgmyAE3N.js} +1 -1
  70. package/client/dist/assets/{specs-DaUTrNF9.js → specs-DicWhvwi.js} +1 -1
  71. package/client/dist/assets/{specs-k0PyLDVt.js → specs-dkro6lSM.js} +1 -1
  72. package/client/dist/assets/{tsMode-B0y_xEci.js → tsMode-BbOGOuSV.js} +1 -1
  73. package/client/dist/assets/{typescript-BzK0OgwW.js → typescript-eBtFQJLs.js} +1 -1
  74. package/client/dist/assets/{useProjectCache-BxY4aTjd.js → useProjectCache-D9juBhsO.js} +1 -1
  75. package/client/dist/assets/{workers-rt--R2Qy.js → workers-BvicOoDf.js} +1 -1
  76. package/client/dist/assets/{xml-eX9QXAmI.js → xml-BJepAPyM.js} +1 -1
  77. package/client/dist/assets/{yaml-fcsNkpOt.js → yaml-DabgV-eA.js} +1 -1
  78. package/client/dist/index.html +13 -12
  79. package/docs/jira-integration-plan.md +321 -0
  80. package/package.json +1 -1
  81. package/server/dist/agent-refine-manager.js +128 -153
  82. package/server/dist/chat-manager.js +242 -0
  83. package/server/dist/code-explorer-router.js +78 -0
  84. package/server/dist/command-resolver.js +17 -0
  85. package/server/dist/contract-refine-runner.js +42 -10
  86. package/server/dist/db.js +86 -0
  87. package/server/dist/desktop-db.js +3 -0
  88. package/server/dist/explore-stdin-session.js +129 -0
  89. package/server/dist/feature-flags.js +11 -0
  90. package/server/dist/jira/jira-adf.js +113 -0
  91. package/server/dist/jira/jira-backlog-config.js +58 -0
  92. package/server/dist/jira/jira-client.js +279 -0
  93. package/server/dist/jira/jira-credential-store.js +103 -0
  94. package/server/dist/jira/jira-db.js +341 -0
  95. package/server/dist/jira/jira-issue-fields.js +428 -0
  96. package/server/dist/jira/jira-materializer.js +250 -0
  97. package/server/dist/jira/jira-status-resolver.js +211 -0
  98. package/server/dist/jira/jira-sync-manager.js +1014 -0
  99. package/server/dist/jira/types.js +9 -0
  100. package/server/dist/jira-router.js +304 -0
  101. package/server/dist/mobile/mobile-auth.js +16 -0
  102. package/server/dist/project-registry.js +43 -1
  103. package/server/dist/project-router-chat.js +218 -0
  104. package/server/dist/project-router-helpers.js +275 -0
  105. package/server/dist/project-router-jobs.js +389 -0
  106. package/server/dist/project-router-settings.js +312 -0
  107. package/server/dist/project-router-setup.js +456 -0
  108. package/server/dist/project-router-spending.js +320 -0
  109. package/server/dist/project-router-terminals.js +312 -0
  110. package/server/dist/project-router-tickets.js +1815 -0
  111. package/server/dist/project-router.js +31 -3950
  112. package/server/dist/providers/claude-adapter.js +23 -0
  113. package/server/dist/providers/codex-adapter.js +6 -0
  114. package/server/dist/rails-router.js +12 -0
  115. package/server/dist/spawn-lifecycle.js +117 -0
  116. package/client/dist/assets/ActivityFeedPage-BpjXuX2H.js +0 -1
  117. package/client/dist/assets/AgentsPage-D-7fDbTc.js +0 -86
  118. package/client/dist/assets/CodePage-B6q6CiYJ.js +0 -2
  119. package/client/dist/assets/DocsDialog-D_dyF2h9.js +0 -11
  120. package/client/dist/assets/DocsPage-C9-Ru8wE.js +0 -11
  121. package/client/dist/assets/IntegrationsPage-3WWtx9hi.js +0 -3
  122. package/client/dist/assets/JobDetailPage-DgN-79s-.js +0 -16
  123. package/client/dist/assets/JobsPage-Du8_w1ob.js +0 -1
  124. package/client/dist/assets/code-AL1rVIMb.js +0 -1
  125. package/client/dist/assets/code-C0BKpkht.js +0 -1
  126. package/client/dist/assets/code-C0FTS3ew.js +0 -1
  127. package/client/dist/assets/code-CPcHxzxw.js +0 -1
  128. package/client/dist/assets/code-D3ryDniw.js +0 -1
  129. package/client/dist/assets/code-D3zVVQTj.js +0 -1
  130. package/client/dist/assets/code-PCmfS3dn.js +0 -1
  131. package/client/dist/assets/code-exI0G5Wd.js +0 -1
  132. package/client/dist/assets/index-D17R4Cjc.css +0 -2
  133. package/client/dist/assets/index-D9G_K4L-.js +0 -142
  134. package/client/dist/assets/integrations-D28q1kF6.js +0 -1
  135. package/client/dist/assets/setup--FMCsnQS.js +0 -1
  136. package/client/dist/assets/setup-B19ZpBNi.js +0 -1
  137. package/client/dist/assets/setup-BZPmkjSN.js +0 -1
  138. package/client/dist/assets/setup-BqYA02rS.js +0 -1
  139. package/client/dist/assets/setup-ChKQDHN9.js +0 -1
  140. package/client/dist/assets/setup-D2n9jMfM.js +0 -1
  141. package/client/dist/assets/setup-P3r6YP1D.js +0 -1
  142. package/client/dist/assets/setup-fnfEbwlv.js +0 -1
  143. package/client/dist/assets/specs-cKEh2LXt.js +0 -1
  144. /package/client/dist/assets/{abap-Bw6f2wDG.js → abap-s65oMlhi.js} +0 -0
  145. /package/client/dist/assets/{activity-BdrPln96.js → activity-BqqwnH_h.js} +0 -0
  146. /package/client/dist/assets/{activity-BEIp_Y1A.js → activity-C8qqEIoP.js} +0 -0
  147. /package/client/dist/assets/{activity-CpkRS8Sx.js → activity-CZVM4nlJ.js} +0 -0
  148. /package/client/dist/assets/{activity-DOUVEjJi.js → activity-Cyy07Tgo.js} +0 -0
  149. /package/client/dist/assets/{activity-DRwkql_y.js → activity-DlbWCa4y.js} +0 -0
  150. /package/client/dist/assets/{activity-DKCpESPt.js → activity-Dwq0heud.js} +0 -0
  151. /package/client/dist/assets/{activity-DcDQ7tjw.js → activity-qFTcMyW9.js} +0 -0
  152. /package/client/dist/assets/{addon-image-3WCl5Vhd.js → addon-image-CpF0L0jM.js} +0 -0
  153. /package/client/dist/assets/{addon-ligatures-C5OdliKs.js → addon-ligatures-hXysGZrA.js} +0 -0
  154. /package/client/dist/assets/{addon-webgl-BbX6pSjl.js → addon-webgl-Cn1slavz.js} +0 -0
  155. /package/client/dist/assets/{addspec-D33ocMxf.js → addspec-B1FTtI2a.js} +0 -0
  156. /package/client/dist/assets/{addspec-DFswZ0jK.js → addspec-BCT9vm_c.js} +0 -0
  157. /package/client/dist/assets/{addspec-DVZ15Jp8.js → addspec-DeDOztDr.js} +0 -0
  158. /package/client/dist/assets/{addspec-Fkv91Opc.js → addspec-DpRgmfmx.js} +0 -0
  159. /package/client/dist/assets/{addspec-BEeF5-zc.js → addspec-Dw-0Dg-4.js} +0 -0
  160. /package/client/dist/assets/{addspec-B5yl4Loj.js → addspec-rp496P_F.js} +0 -0
  161. /package/client/dist/assets/{addspec-DRE-jZv7.js → addspec-v8j6A7CD.js} +0 -0
  162. /package/client/dist/assets/{agents-DK-Dlc0i.js → agents-23iPejcA.js} +0 -0
  163. /package/client/dist/assets/{agents-Q6Ldfpxx.js → agents-BDx1RXcl.js} +0 -0
  164. /package/client/dist/assets/{agents-TeOSy-ax.js → agents-BFr3kUhK.js} +0 -0
  165. /package/client/dist/assets/{agents-Bm9rPqnt.js → agents-B_1L9xRg.js} +0 -0
  166. /package/client/dist/assets/{agents-1nCDWRmP.js → agents-BlPnx-mz.js} +0 -0
  167. /package/client/dist/assets/{agents-iTqjRajS.js → agents-DcxZHzNr.js} +0 -0
  168. /package/client/dist/assets/{agents-s87sMGzL.js → agents-G3shOewU.js} +0 -0
  169. /package/client/dist/assets/{agentstudio-B6Wb59E7.js → agentstudio-B-CMAQqy.js} +0 -0
  170. /package/client/dist/assets/{agentstudio-D3I62TLJ.js → agentstudio-Bk1eZcv4.js} +0 -0
  171. /package/client/dist/assets/{agentstudio-DuH9TogZ.js → agentstudio-ChxNuGAu.js} +0 -0
  172. /package/client/dist/assets/{agentstudio-Kw88_dUF.js → agentstudio-DNlme601.js} +0 -0
  173. /package/client/dist/assets/{agentstudio-BdidyBzZ.js → agentstudio-DpP9caEE.js} +0 -0
  174. /package/client/dist/assets/{agentstudio-BSnWLR63.js → agentstudio-Y3G0ddJ2.js} +0 -0
  175. /package/client/dist/assets/{agentstudio-BADhZ41e.js → agentstudio-kk9RB7Se.js} +0 -0
  176. /package/client/dist/assets/{aiedit-DJMny-D5.js → aiedit-5ETerMK1.js} +0 -0
  177. /package/client/dist/assets/{aiedit-D2ji6Qy0.js → aiedit-BBCrOpHq.js} +0 -0
  178. /package/client/dist/assets/{aiedit-DAhZTvtk.js → aiedit-BMtcGYNE.js} +0 -0
  179. /package/client/dist/assets/{aiedit-DvrcbwGv.js → aiedit-D9ddlgkM.js} +0 -0
  180. /package/client/dist/assets/{aiedit-WBSjT_C1.js → aiedit-De0SOH6S.js} +0 -0
  181. /package/client/dist/assets/{aiedit-BWxHGsYA.js → aiedit-DrfzQroF.js} +0 -0
  182. /package/client/dist/assets/{aiedit-DOcxERkU.js → aiedit-fMltW101.js} +0 -0
  183. /package/client/dist/assets/{analytics-C9Zc-rkM.js → analytics-BeTyviO8.js} +0 -0
  184. /package/client/dist/assets/{analytics-CrPCZRJ-.js → analytics-C4eEO260.js} +0 -0
  185. /package/client/dist/assets/{analytics-CYj0tfj7.js → analytics-C67cIA1b.js} +0 -0
  186. /package/client/dist/assets/{analytics-C6EzgtdE.js → analytics-CAguvW28.js} +0 -0
  187. /package/client/dist/assets/{analytics-CVx3YOc0.js → analytics-DBtt8Mgk.js} +0 -0
  188. /package/client/dist/assets/{analytics-CnY4kNG3.js → analytics-DUPtODxX.js} +0 -0
  189. /package/client/dist/assets/{analytics-BIdr0YfL.js → analytics-YIpQvPAc.js} +0 -0
  190. /package/client/dist/assets/{apex-Cw8_REBo.js → apex-BLUBIldB.js} +0 -0
  191. /package/client/dist/assets/{attachments-DYHGA2Dj.js → attachments-CCWasu-P.js} +0 -0
  192. /package/client/dist/assets/{attachments-Dd92KpUH.js → attachments-CHaDUfjB.js} +0 -0
  193. /package/client/dist/assets/{attachments-DzdU6DV6.js → attachments-CVSAbGNl.js} +0 -0
  194. /package/client/dist/assets/{attachments-Bcf6BG6V.js → attachments-Chg5poG1.js} +0 -0
  195. /package/client/dist/assets/{attachments-BW4L3l2L.js → attachments-DazTVJbH.js} +0 -0
  196. /package/client/dist/assets/{attachments-COcrGRFz.js → attachments-Dn-JImAK.js} +0 -0
  197. /package/client/dist/assets/{attachments-Bke8sCU4.js → attachments-LDA9kp2X.js} +0 -0
  198. /package/client/dist/assets/{azcli-Cz6HAoOw.js → azcli-DuWxh9mO.js} +0 -0
  199. /package/client/dist/assets/{bat-CcJ-xyqL.js → bat-UKoTejQm.js} +0 -0
  200. /package/client/dist/assets/{bicep-z1WDCKYz.js → bicep-4sTT4B3D.js} +0 -0
  201. /package/client/dist/assets/{browser-DGITz3fC.js → browser-BDd1dbFa.js} +0 -0
  202. /package/client/dist/assets/{browser-JsAIGCEW.js → browser-BWSgbfdX.js} +0 -0
  203. /package/client/dist/assets/{browser-M5-rbPlw.js → browser-D2Y_UAKA.js} +0 -0
  204. /package/client/dist/assets/{browser-BlYF4OOq.js → browser-DH9SGVfM.js} +0 -0
  205. /package/client/dist/assets/{browser-Bc-YdlVg.js → browser-DWOVYMlg.js} +0 -0
  206. /package/client/dist/assets/{browser-CT-ReZGt.js → browser-Dxc_VIRK.js} +0 -0
  207. /package/client/dist/assets/{browser-5ErDlJoR.js → browser-lTQwcDCI.js} +0 -0
  208. /package/client/dist/assets/{cameligo-BRewOpfa.js → cameligo-CAAryRYO.js} +0 -0
  209. /package/client/dist/assets/{chat-DwUm6W9z.js → chat-BO9MvVID.js} +0 -0
  210. /package/client/dist/assets/{chat-BEGuC03z.js → chat-CPgmgZOj.js} +0 -0
  211. /package/client/dist/assets/{chat-CboQguCi.js → chat-CUrG1eVg.js} +0 -0
  212. /package/client/dist/assets/{chat-DRCa9pOt.js → chat-CvOOKB2s.js} +0 -0
  213. /package/client/dist/assets/{chat-BEW60P_u.js → chat-DIh3hr6y.js} +0 -0
  214. /package/client/dist/assets/{chat-yoXwguQu.js → chat-UVVZqA57.js} +0 -0
  215. /package/client/dist/assets/{chat-BQNMD0PL.js → chat-mPn3UlMl.js} +0 -0
  216. /package/client/dist/assets/{clojure-DBjRWN6g.js → clojure-BlMERO1w.js} +0 -0
  217. /package/client/dist/assets/{clsx-DnqN-uhr.js → clsx-CnH-HMk3.js} +0 -0
  218. /package/client/dist/assets/{coffee-Cfk_XHGR.js → coffee-Cj8D-Wl1.js} +0 -0
  219. /package/client/dist/assets/{commands-sqrqsxyE.js → commands-B-MVT-2F.js} +0 -0
  220. /package/client/dist/assets/{commands-UD1NzmwX.js → commands-B0yFTp7e.js} +0 -0
  221. /package/client/dist/assets/{commands-DLrvnPNg.js → commands-BR1kDkHQ.js} +0 -0
  222. /package/client/dist/assets/{commands-CJxCry-o.js → commands-Cb21pDlG.js} +0 -0
  223. /package/client/dist/assets/{commands-CfgY-_of.js → commands-DWgp-8W1.js} +0 -0
  224. /package/client/dist/assets/{commands-B772IyDa.js → commands-ddsl1V91.js} +0 -0
  225. /package/client/dist/assets/{commands-BDDp6xFG.js → commands-t4frzhB0.js} +0 -0
  226. /package/client/dist/assets/{common-Dmm1GhdD.js → common-5ilvMOcH.js} +0 -0
  227. /package/client/dist/assets/{common-DltqHaAe.js → common-B4sqsKp7.js} +0 -0
  228. /package/client/dist/assets/{common-GbpxfPG8.js → common-BKpVwUIf.js} +0 -0
  229. /package/client/dist/assets/{common-DeDELLZJ.js → common-BzEC3kJU.js} +0 -0
  230. /package/client/dist/assets/{common-DnjcgkPH.js → common-CALKUpYm.js} +0 -0
  231. /package/client/dist/assets/{common-Dard9UNH.js → common-CTEbWVZS.js} +0 -0
  232. /package/client/dist/assets/{common-DCr6VzJ7.js → common-DQiza2Xp.js} +0 -0
  233. /package/client/dist/assets/{cpp-BVob6BaP.js → cpp-BPfKnaj_.js} +0 -0
  234. /package/client/dist/assets/{csharp-C4fbRuOu.js → csharp-gX-x5uD6.js} +0 -0
  235. /package/client/dist/assets/{csp-DthFP_vT.js → csp-DKGVt8SM.js} +0 -0
  236. /package/client/dist/assets/{css-CGMH0hcW.js → css-CPMdnAVq.js} +0 -0
  237. /package/client/dist/assets/{cypher-Pnf68BRV.js → cypher-ClMDrj9S.js} +0 -0
  238. /package/client/dist/assets/{dart-PMMOtxZX.js → dart-C4zbzpVv.js} +0 -0
  239. /package/client/dist/assets/{dashboard-BZBADHSj.js → dashboard--Y6yzMlf.js} +0 -0
  240. /package/client/dist/assets/{dashboard-I19DXBxw.js → dashboard--a4-6oYE.js} +0 -0
  241. /package/client/dist/assets/{dashboard-CB6Le1yN.js → dashboard-BiJ3CDTG.js} +0 -0
  242. /package/client/dist/assets/{dashboard-B4ixDVk8.js → dashboard-CiXjk63Z.js} +0 -0
  243. /package/client/dist/assets/{dashboard-C1MfeUHs.js → dashboard-Cx5VjCea.js} +0 -0
  244. /package/client/dist/assets/{dashboard-C7SK6xu5.js → dashboard-D7jg25XR.js} +0 -0
  245. /package/client/dist/assets/{dashboard-CoTpMOBM.js → dashboard-DpGYK2s1.js} +0 -0
  246. /package/client/dist/assets/{dockerfile-di1nsJCc.js → dockerfile-D9xw73D1.js} +0 -0
  247. /package/client/dist/assets/{ecl-D_WVcB5M.js → ecl-gqO8tIR9.js} +0 -0
  248. /package/client/dist/assets/{editor.api2-XLGzZfbc.js → editor.api2-BPnIxMjz.js} +0 -0
  249. /package/client/dist/assets/{elixir-OAdJEMOn.js → elixir-DSAhVF3_.js} +0 -0
  250. /package/client/dist/assets/{explore-D2EFgt8J.js → explore-BE5UmlbD.js} +0 -0
  251. /package/client/dist/assets/{explore-BV5Xxlsn.js → explore-BmTaI8dX.js} +0 -0
  252. /package/client/dist/assets/{explore-A8Ltoblq.js → explore-CCwkqoWq.js} +0 -0
  253. /package/client/dist/assets/{explore-4mFpnrKU.js → explore-CMdEoPDx.js} +0 -0
  254. /package/client/dist/assets/{explore-C3FSE42C.js → explore-CtdCL4QU.js} +0 -0
  255. /package/client/dist/assets/{explore-B9A3iN2W.js → explore-DHjxSkqQ.js} +0 -0
  256. /package/client/dist/assets/{explore-BrBJvfjP.js → explore-__BeALjE.js} +0 -0
  257. /package/client/dist/assets/{flow9-D3QEZjgn.js → flow9-DeQCSPOd.js} +0 -0
  258. /package/client/dist/assets/{format-command-CwGuwzGA.js → format-command-2VNoNnMv.js} +0 -0
  259. /package/client/dist/assets/{fsharp-BF0k_8N8.js → fsharp-CEfaXL-S.js} +0 -0
  260. /package/client/dist/assets/{go-BAQO5Jsz.js → go-Xp1OkZCh.js} +0 -0
  261. /package/client/dist/assets/{graphql-hdFVFkiV.js → graphql-BwRXrUwe.js} +0 -0
  262. /package/client/dist/assets/{hcl-DWnl1o-X.js → hcl-u06DtVFk.js} +0 -0
  263. /package/client/dist/assets/{ini-CB-6OVu3.js → ini-AmeIpFND.js} +0 -0
  264. /package/client/dist/assets/{java-d1CmfiHX.js → java-CyDbRQjX.js} +0 -0
  265. /package/client/dist/assets/{jobs-DPPT6bV6.js → jobs-8viuHLDV.js} +0 -0
  266. /package/client/dist/assets/{jobs-3j3_npyo.js → jobs-AW2eB5D-.js} +0 -0
  267. /package/client/dist/assets/{jobs-2N3RXDAM.js → jobs-BSm89DL5.js} +0 -0
  268. /package/client/dist/assets/{jobs-BqEbCCxD.js → jobs-BZ3sQHjZ.js} +0 -0
  269. /package/client/dist/assets/{jobs-cHYInoau.js → jobs-Bd8AdOTb.js} +0 -0
  270. /package/client/dist/assets/{jobs-DRzjWI9u.js → jobs-CRtsq_u0.js} +0 -0
  271. /package/client/dist/assets/{jobs-2f6Hdc72.js → jobs-CSRwFQ6K.js} +0 -0
  272. /package/client/dist/assets/{jobs-vGfzIDQa.js → jobs-CbEl7WMI.js} +0 -0
  273. /package/client/dist/assets/{julia-Bgv08lKa.js → julia-BqialFRG.js} +0 -0
  274. /package/client/dist/assets/{kotlin-u98kaVTf.js → kotlin-Dzz8TWAt.js} +0 -0
  275. /package/client/dist/assets/{less-CjYwpgg5.js → less-DHRJD3TR.js} +0 -0
  276. /package/client/dist/assets/{lexon-YTjaAFBB.js → lexon-5Y3QgTmT.js} +0 -0
  277. /package/client/dist/assets/{lua-BzmkWv27.js → lua-sKvhfPn5.js} +0 -0
  278. /package/client/dist/assets/{m3-CFwk9fw0.js → m3-DWDVwkFG.js} +0 -0
  279. /package/client/dist/assets/{markdown-CR5iMpSZ.js → markdown-CD_aSBxW.js} +0 -0
  280. /package/client/dist/assets/{mips-CcEalc17.js → mips-687T03hg.js} +0 -0
  281. /package/client/dist/assets/{msdax-BQbkawnr.js → msdax-C1St-dIV.js} +0 -0
  282. /package/client/dist/assets/{mysql-GTlaaW_P.js → mysql-BG7r8oBS.js} +0 -0
  283. /package/client/dist/assets/{nav-C2YXcbZS.js → nav-B05EYB0b.js} +0 -0
  284. /package/client/dist/assets/{nav-D2bOGSEg.js → nav-BNGCq-0y.js} +0 -0
  285. /package/client/dist/assets/{nav-BEL3MTwK.js → nav-BRInPX8a.js} +0 -0
  286. /package/client/dist/assets/{nav-CtYwmMgu.js → nav-Bf87DRHD.js} +0 -0
  287. /package/client/dist/assets/{nav-iH1V5j6o.js → nav-BkVzzFpc.js} +0 -0
  288. /package/client/dist/assets/{nav-0fwkrgHt.js → nav-BzFLtS1W.js} +0 -0
  289. /package/client/dist/assets/{nav-ClzOE4mA.js → nav-DBDbQOYn.js} +0 -0
  290. /package/client/dist/assets/{nav-B_G-TJDW.js → nav-X9sVtUWC.js} +0 -0
  291. /package/client/dist/assets/{objective-c-Byu1T5if.js → objective-c-Ds1-m05L.js} +0 -0
  292. /package/client/dist/assets/{pascal-BrfzBfRm.js → pascal-BKK9FpIi.js} +0 -0
  293. /package/client/dist/assets/{pascaligo-BXXKFUeo.js → pascaligo-SRS3nwtO.js} +0 -0
  294. /package/client/dist/assets/{perl-B3OikKq-.js → perl-B2hTOlrF.js} +0 -0
  295. /package/client/dist/assets/{pgsql-CTsa0Acc.js → pgsql-DIQJYNpL.js} +0 -0
  296. /package/client/dist/assets/{php-DiQh3FUW.js → php-BEaVe8X2.js} +0 -0
  297. /package/client/dist/assets/{pla-92uH8Fzm.js → pla-oPLHpZ-Q.js} +0 -0
  298. /package/client/dist/assets/{postiats-BbeWkKUr.js → postiats-D_vzrAzD.js} +0 -0
  299. /package/client/dist/assets/{powerquery-DgDMzpsm.js → powerquery-BKG6w-FH.js} +0 -0
  300. /package/client/dist/assets/{powershell-BfdUUzaG.js → powershell-B3dLhDt4.js} +0 -0
  301. /package/client/dist/assets/{protobuf-BojW2ftW.js → protobuf-DC8SGjcl.js} +0 -0
  302. /package/client/dist/assets/{pug-BxqTg3IU.js → pug-D5E-4fI0.js} +0 -0
  303. /package/client/dist/assets/{qsharp-BX_A-MW9.js → qsharp-6vJAWv0x.js} +0 -0
  304. /package/client/dist/assets/{r-D9BMnxvJ.js → r-CDwsEcbM.js} +0 -0
  305. /package/client/dist/assets/{redis-5cJqEQJJ.js → redis-CuQbbESS.js} +0 -0
  306. /package/client/dist/assets/{redshift-d8BBqiwb.js → redshift-B9e1k-qI.js} +0 -0
  307. /package/client/dist/assets/{restructuredtext-C8a6yIcZ.js → restructuredtext-BiJ5IwaU.js} +0 -0
  308. /package/client/dist/assets/{ruby-egeh-6KX.js → ruby-B0UAHY9b.js} +0 -0
  309. /package/client/dist/assets/{rust-a3r9IInB.js → rust-Dg_spmFr.js} +0 -0
  310. /package/client/dist/assets/{sb-y8iRIDei.js → sb-DjU66I8Q.js} +0 -0
  311. /package/client/dist/assets/{scala-BPDK2AmK.js → scala-qvStIdfG.js} +0 -0
  312. /package/client/dist/assets/{scheme-BIWUEoOs.js → scheme-FstEk5Rh.js} +0 -0
  313. /package/client/dist/assets/{scss-CA-PSzwg.js → scss-w0U3rQLK.js} +0 -0
  314. /package/client/dist/assets/{settings-CTcwN9RE.js → settings-5tzo0Rn3.js} +0 -0
  315. /package/client/dist/assets/{settings-D_dujJZI.js → settings-BDAW3trC.js} +0 -0
  316. /package/client/dist/assets/{settings-Bg0A3zoS.js → settings-BEWv3VEu.js} +0 -0
  317. /package/client/dist/assets/{settings-BgPqg2nv.js → settings-BORg56um.js} +0 -0
  318. /package/client/dist/assets/{settings-BSze3_9q.js → settings-D3LurcR5.js} +0 -0
  319. /package/client/dist/assets/{settings-CSJ0ahZ8.js → settings-DcqWIEM6.js} +0 -0
  320. /package/client/dist/assets/{settings-DYIV89nV.js → settings-Dfz8QbZS.js} +0 -0
  321. /package/client/dist/assets/{settings-DDcfx_ca.js → settings-yMubjqYw.js} +0 -0
  322. /package/client/dist/assets/{shell--LiT1Bja.js → shell-DJ78wREd.js} +0 -0
  323. /package/client/dist/assets/{solidity-DdqZccZg.js → solidity-1aGIVsdX.js} +0 -0
  324. /package/client/dist/assets/{sophia-S6-YxNG_.js → sophia-40LqcGjB.js} +0 -0
  325. /package/client/dist/assets/{sparql-BSf5kMp2.js → sparql-Cz5dqG_g.js} +0 -0
  326. /package/client/dist/assets/{sql-D7KgjR8G.js → sql-64f62Ni4.js} +0 -0
  327. /package/client/dist/assets/{st-BnoDa-Ml.js → st-gJe2yG8J.js} +0 -0
  328. /package/client/dist/assets/{swift-DEUHTkUX.js → swift-C6ME22mv.js} +0 -0
  329. /package/client/dist/assets/{systemverilog-Tqb_KPnW.js → systemverilog-CEWz259w.js} +0 -0
  330. /package/client/dist/assets/{tcl-BmBFS2qq.js → tcl-CcLVIi3m.js} +0 -0
  331. /package/client/dist/assets/{terminal-Bje4ziIa.js → terminal-BYtreaaF.js} +0 -0
  332. /package/client/dist/assets/{terminal-CSONJOex.js → terminal-C0xx0SjA.js} +0 -0
  333. /package/client/dist/assets/{terminal-DeWzh6ys.js → terminal-CPpK58RC.js} +0 -0
  334. /package/client/dist/assets/{terminal-C2WYcFHF.js → terminal-CdxkpafL.js} +0 -0
  335. /package/client/dist/assets/{terminal-DEqzGtcr.js → terminal-Ciia0wh2.js} +0 -0
  336. /package/client/dist/assets/{terminal-80yDMgMF.js → terminal-DHIkiWcs.js} +0 -0
  337. /package/client/dist/assets/{terminal-lkZYR4wJ.js → terminal-DY42QANg.js} +0 -0
  338. /package/client/dist/assets/{terminal-YOlsJCQj.js → terminal-DoxtVdma.js} +0 -0
  339. /package/client/dist/assets/{tickets-DYvafSaY.js → tickets-0rM0lIXd.js} +0 -0
  340. /package/client/dist/assets/{tickets-DNOANUXr.js → tickets-1UIGf_oA.js} +0 -0
  341. /package/client/dist/assets/{tickets-DlpC_iTg.js → tickets-9kdPXInd.js} +0 -0
  342. /package/client/dist/assets/{tickets-CF2PYelu.js → tickets-C6pwZwt4.js} +0 -0
  343. /package/client/dist/assets/{tickets-CB7N30gm.js → tickets-DAjtxAVb.js} +0 -0
  344. /package/client/dist/assets/{tickets-DU1aqsbr.js → tickets-DNmXcAwu.js} +0 -0
  345. /package/client/dist/assets/{tickets-clefmXLv.js → tickets-n23kDqJT.js} +0 -0
  346. /package/client/dist/assets/{tickets-DucYgtdl.js → tickets-tGx5AR5b.js} +0 -0
  347. /package/client/dist/assets/{twig-BQV8igWC.js → twig-DvsO-WjW.js} +0 -0
  348. /package/client/dist/assets/{typespec-DlFroUGY.js → typespec-Brkt3IAA.js} +0 -0
  349. /package/client/dist/assets/{vb-BlrJpIMX.js → vb-r121Uzxt.js} +0 -0
  350. /package/client/dist/assets/{wgsl-BWgIc6FZ.js → wgsl-BRX8uYh4.js} +0 -0
@@ -0,0 +1,341 @@
1
+ "use strict";
2
+ // Data-access layer for the per-project Jira tables (migration 29).
3
+ //
4
+ // All three tables live in the per-project `jobs.sqlite`. The outbox is the
5
+ // durable source of truth for "what must reach Jira": an outbox row is inserted
6
+ // in the SAME SQLite transaction as the record of a status change, so a crash
7
+ // between the local cache mutation and the network flush can never lose a write.
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getConnection = getConnection;
10
+ exports.getDecryptedToken = getDecryptedToken;
11
+ exports.hasToken = hasToken;
12
+ exports.getConnectionPublic = getConnectionPublic;
13
+ exports.upsertConnection = upsertConnection;
14
+ exports.setConnectionEnabled = setConnectionEnabled;
15
+ exports.setHighWater = setHighWater;
16
+ exports.setSprintFieldId = setSprintFieldId;
17
+ exports.setDiscardStatus = setDiscardStatus;
18
+ exports.setStatusMap = setStatusMap;
19
+ exports.deleteConnection = deleteConnection;
20
+ exports.getLinkByIssueId = getLinkByIssueId;
21
+ exports.getLinkByLocalId = getLinkByLocalId;
22
+ exports.listLinks = listLinks;
23
+ exports.ensureLink = ensureLink;
24
+ exports.nextLocalId = nextLocalId;
25
+ exports.insertLinkWithId = insertLinkWithId;
26
+ exports.updateLinkStatusCategory = updateLinkStatusCategory;
27
+ exports.setLinkState = setLinkState;
28
+ exports.tombstoneLink = tombstoneLink;
29
+ exports.enqueueOutbox = enqueueOutbox;
30
+ exports.enqueueMany = enqueueMany;
31
+ exports.claimDrainable = claimDrainable;
32
+ exports.markOutboxDone = markOutboxDone;
33
+ exports.markOutboxRetry = markOutboxRetry;
34
+ exports.markOutboxDead = markOutboxDead;
35
+ exports.resetInflight = resetInflight;
36
+ exports.retryDeadOutbox = retryDeadOutbox;
37
+ exports.listOutbox = listOutbox;
38
+ exports.countOutboxByState = countOutboxByState;
39
+ const jira_credential_store_1 = require("./jira-credential-store");
40
+ function mapConnection(r) {
41
+ let statusMap = null;
42
+ if (r.status_map) {
43
+ try {
44
+ statusMap = JSON.parse(r.status_map);
45
+ }
46
+ catch {
47
+ statusMap = null;
48
+ }
49
+ }
50
+ return {
51
+ projectId: r.project_id,
52
+ baseUrl: r.base_url,
53
+ deployment: r.deployment,
54
+ apiVersion: r.api_version === '2' ? '2' : '3',
55
+ authScheme: r.auth_scheme === 'bearer' ? 'bearer' : 'basic',
56
+ accountEmail: r.account_email,
57
+ jiraProjectKey: r.jira_project_key,
58
+ jiraProjectId: r.jira_project_id,
59
+ enabled: r.enabled === 1,
60
+ statusMap,
61
+ highWaterMs: r.high_water_ms,
62
+ sprintFieldId: r.sprint_field_id ?? null,
63
+ discardStatus: r.discard_status ?? null,
64
+ createdAt: r.created_at,
65
+ updatedAt: r.updated_at,
66
+ };
67
+ }
68
+ function getConnection(db, projectId) {
69
+ const row = db.prepare('SELECT * FROM jira_connection WHERE project_id = ?').get(projectId);
70
+ return row ? mapConnection(row) : null;
71
+ }
72
+ /** Read the raw encrypted token blob (server-internal only — never returned to client). */
73
+ function getDecryptedToken(db, projectId) {
74
+ const row = db.prepare('SELECT encrypted_token FROM jira_connection WHERE project_id = ?').get(projectId);
75
+ if (!row?.encrypted_token)
76
+ return null;
77
+ try {
78
+ return (0, jira_credential_store_1.getSecretStore)().decrypt(row.encrypted_token);
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ function hasToken(db, projectId) {
85
+ const row = db.prepare('SELECT encrypted_token FROM jira_connection WHERE project_id = ?').get(projectId);
86
+ return !!row?.encrypted_token;
87
+ }
88
+ /** Client-safe connection (token redacted to a boolean). */
89
+ function getConnectionPublic(db, projectId) {
90
+ const conn = getConnection(db, projectId);
91
+ if (!conn)
92
+ return null;
93
+ return { ...conn, hasToken: hasToken(db, projectId) };
94
+ }
95
+ function upsertConnection(db, input) {
96
+ const existing = getConnection(db, input.projectId);
97
+ const now = new Date().toISOString();
98
+ const prevToken = existing
99
+ ? db.prepare('SELECT encrypted_token FROM jira_connection WHERE project_id = ?').get(input.projectId)?.encrypted_token ?? null
100
+ : null;
101
+ const encryptedToken = input.token !== undefined ? (0, jira_credential_store_1.getSecretStore)().encrypt(input.token) : prevToken;
102
+ const statusMapJson = input.statusMap !== undefined
103
+ ? input.statusMap === null
104
+ ? null
105
+ : JSON.stringify(input.statusMap)
106
+ : existing?.statusMap
107
+ ? JSON.stringify(existing.statusMap)
108
+ : null;
109
+ const enabled = input.enabled !== undefined ? (input.enabled ? 1 : 0) : existing ? (existing.enabled ? 1 : 0) : 1;
110
+ db.prepare(`INSERT INTO jira_connection
111
+ (project_id, base_url, deployment, api_version, auth_scheme, account_email,
112
+ jira_project_key, jira_project_id, encrypted_token, enabled, status_map,
113
+ high_water_ms, created_at, updated_at)
114
+ VALUES (@project_id, @base_url, @deployment, @api_version, @auth_scheme, @account_email,
115
+ @jira_project_key, @jira_project_id, @encrypted_token, @enabled, @status_map,
116
+ @high_water_ms, @created_at, @updated_at)
117
+ ON CONFLICT(project_id) DO UPDATE SET
118
+ base_url=@base_url, deployment=@deployment, api_version=@api_version,
119
+ auth_scheme=@auth_scheme, account_email=@account_email,
120
+ jira_project_key=@jira_project_key, jira_project_id=@jira_project_id,
121
+ encrypted_token=@encrypted_token, enabled=@enabled, status_map=@status_map,
122
+ updated_at=@updated_at`).run({
123
+ project_id: input.projectId,
124
+ base_url: input.baseUrl,
125
+ deployment: input.deployment,
126
+ api_version: input.apiVersion,
127
+ auth_scheme: input.authScheme,
128
+ account_email: input.accountEmail,
129
+ jira_project_key: input.jiraProjectKey,
130
+ jira_project_id: input.jiraProjectId,
131
+ encrypted_token: encryptedToken,
132
+ enabled,
133
+ status_map: statusMapJson,
134
+ high_water_ms: existing?.highWaterMs ?? null,
135
+ created_at: existing?.createdAt ?? now,
136
+ updated_at: now,
137
+ });
138
+ return getConnection(db, input.projectId);
139
+ }
140
+ function setConnectionEnabled(db, projectId, enabled) {
141
+ db.prepare('UPDATE jira_connection SET enabled = ?, updated_at = ? WHERE project_id = ?').run(enabled ? 1 : 0, new Date().toISOString(), projectId);
142
+ }
143
+ function setHighWater(db, projectId, highWaterMs) {
144
+ db.prepare('UPDATE jira_connection SET high_water_ms = ?, updated_at = ? WHERE project_id = ?').run(highWaterMs, new Date().toISOString(), projectId);
145
+ }
146
+ /** Cache the discovered sprint custom-field id ('none' when none exists). */
147
+ function setSprintFieldId(db, projectId, fieldId) {
148
+ db.prepare('UPDATE jira_connection SET sprint_field_id = ?, updated_at = ? WHERE project_id = ?').run(fieldId, new Date().toISOString(), projectId);
149
+ }
150
+ /** Set (or clear with null) the discard target status name. */
151
+ function setDiscardStatus(db, projectId, status) {
152
+ db.prepare('UPDATE jira_connection SET discard_status = ?, updated_at = ? WHERE project_id = ?').run(status && status.trim() ? status.trim() : null, new Date().toISOString(), projectId);
153
+ }
154
+ /** Replace (or clear with null/empty) the per-logical-state status map. */
155
+ function setStatusMap(db, projectId, statusMap) {
156
+ const json = statusMap && Object.keys(statusMap).length ? JSON.stringify(statusMap) : null;
157
+ db.prepare('UPDATE jira_connection SET status_map = ?, updated_at = ? WHERE project_id = ?').run(json, new Date().toISOString(), projectId);
158
+ }
159
+ function deleteConnection(db, projectId) {
160
+ db.prepare('DELETE FROM jira_connection WHERE project_id = ?').run(projectId);
161
+ }
162
+ function mapLink(r) {
163
+ return {
164
+ localId: r.local_id,
165
+ jiraIssueId: r.jira_issue_id,
166
+ jiraKey: r.jira_key,
167
+ jiraProjectId: r.jira_project_id,
168
+ deployment: r.deployment,
169
+ statusCategory: r.status_category ?? null,
170
+ state: r.state ?? 'linked',
171
+ tombstoned: r.tombstoned === 1,
172
+ createdAt: r.created_at,
173
+ updatedAt: r.updated_at,
174
+ };
175
+ }
176
+ function getLinkByIssueId(db, jiraIssueId) {
177
+ const row = db.prepare('SELECT * FROM jira_links WHERE jira_issue_id = ?').get(jiraIssueId);
178
+ return row ? mapLink(row) : null;
179
+ }
180
+ function getLinkByLocalId(db, localId) {
181
+ const row = db.prepare('SELECT * FROM jira_links WHERE local_id = ?').get(localId);
182
+ return row ? mapLink(row) : null;
183
+ }
184
+ function listLinks(db) {
185
+ return db.prepare('SELECT * FROM jira_links ORDER BY local_id').all().map(mapLink);
186
+ }
187
+ /**
188
+ * Resolve (or mint) the stable local `#id` for a Jira issue. The local id is
189
+ * monotonic and never reused — tombstoned rows keep their id so a previously
190
+ * issued `/specrails:implement #N` never rebinds to a different issue.
191
+ */
192
+ function ensureLink(db, args) {
193
+ const existing = getLinkByIssueId(db, args.jiraIssueId);
194
+ const now = new Date().toISOString();
195
+ if (existing) {
196
+ // Refresh the display key (issues can be moved/renamed; id is immutable).
197
+ if (args.jiraKey && args.jiraKey !== existing.jiraKey) {
198
+ db.prepare('UPDATE jira_links SET jira_key = ?, updated_at = ? WHERE jira_issue_id = ?').run(args.jiraKey, now, args.jiraIssueId);
199
+ return getLinkByIssueId(db, args.jiraIssueId);
200
+ }
201
+ return existing;
202
+ }
203
+ const localId = nextLocalId(db);
204
+ db.prepare(`INSERT INTO jira_links (local_id, jira_issue_id, jira_key, jira_project_id, deployment, created_at, updated_at)
205
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(localId, args.jiraIssueId, args.jiraKey, args.jiraProjectId, args.deployment, now, now);
206
+ return getLinkByLocalId(db, localId);
207
+ }
208
+ /** Next monotonic local id: max(existing local_ids) + 1, never reusing. */
209
+ function nextLocalId(db) {
210
+ const row = db.prepare('SELECT MAX(local_id) AS maxId FROM jira_links').get();
211
+ return (row.maxId ?? 0) + 1;
212
+ }
213
+ /**
214
+ * Insert a link with a caller-chosen local id. Used by the materializer, which
215
+ * allocates ids from the UNION of the ticket store's `next_id` and the jira_links
216
+ * max so Jira-sourced `#id`s never collide with locally-created specs.
217
+ */
218
+ function insertLinkWithId(db, args) {
219
+ const now = new Date().toISOString();
220
+ db.prepare(`INSERT INTO jira_links (local_id, jira_issue_id, jira_key, jira_project_id, deployment, created_at, updated_at)
221
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(args.localId, args.jiraIssueId, args.jiraKey, args.jiraProjectId, args.deployment, now, now);
222
+ return getLinkByLocalId(db, args.localId);
223
+ }
224
+ function updateLinkStatusCategory(db, jiraIssueId, category) {
225
+ db.prepare('UPDATE jira_links SET status_category = ?, updated_at = ? WHERE jira_issue_id = ?').run(category, new Date().toISOString(), jiraIssueId);
226
+ }
227
+ function setLinkState(db, jiraIssueId, state) {
228
+ db.prepare('UPDATE jira_links SET state = ?, updated_at = ? WHERE jira_issue_id = ?').run(state, new Date().toISOString(), jiraIssueId);
229
+ }
230
+ /** Tombstone a deleted/orphaned issue's link (keeps the local id reserved). */
231
+ function tombstoneLink(db, jiraIssueId) {
232
+ db.prepare("UPDATE jira_links SET tombstoned = 1, state = 'orphaned', updated_at = ? WHERE jira_issue_id = ?").run(new Date().toISOString(), jiraIssueId);
233
+ }
234
+ function mapOutbox(r) {
235
+ return {
236
+ id: r.id,
237
+ jiraIssueId: r.jira_issue_id,
238
+ opType: r.op_type,
239
+ idempotencyKey: r.idempotency_key,
240
+ payload: r.payload,
241
+ state: r.state,
242
+ attempts: r.attempts,
243
+ nextAttemptAt: r.next_attempt_at,
244
+ lastError: r.last_error,
245
+ deadReason: r.dead_reason,
246
+ createdAt: r.created_at,
247
+ updatedAt: r.updated_at,
248
+ };
249
+ }
250
+ /**
251
+ * Insert an outbox op. Idempotent on `idempotencyKey` (INSERT OR IGNORE) so a
252
+ * crash-replay of the same logical op never double-enqueues. Returns the row id
253
+ * (existing or new). Intended to be called inside a transaction together with
254
+ * the status-change record (see `enqueueMany`).
255
+ */
256
+ function enqueueOutbox(db, input) {
257
+ const now = new Date().toISOString();
258
+ const info = db
259
+ .prepare(`INSERT OR IGNORE INTO jira_outbox
260
+ (jira_issue_id, op_type, idempotency_key, payload, state, attempts, created_at, updated_at)
261
+ VALUES (?, ?, ?, ?, 'pending', 0, ?, ?)`)
262
+ .run(input.jiraIssueId, input.opType, input.idempotencyKey, JSON.stringify(input.payload), now, now);
263
+ if (info.changes > 0)
264
+ return Number(info.lastInsertRowid);
265
+ const existing = db.prepare('SELECT id FROM jira_outbox WHERE idempotency_key = ?').get(input.idempotencyKey);
266
+ return existing?.id ?? 0;
267
+ }
268
+ /** Enqueue several ops atomically (one SQLite transaction). */
269
+ function enqueueMany(db, ops) {
270
+ const tx = db.transaction((items) => {
271
+ for (const op of items)
272
+ enqueueOutbox(db, op);
273
+ });
274
+ tx(ops);
275
+ }
276
+ /**
277
+ * Claim the next batch of drainable ops (state=pending and due), one per issue
278
+ * (FIFO-per-issue: never two concurrent ops on the same issue), up to `limit`
279
+ * distinct issues. Marks them `inflight`.
280
+ */
281
+ function claimDrainable(db, limit, nowIso = new Date().toISOString()) {
282
+ const tx = db.transaction((max) => {
283
+ const rows = db
284
+ .prepare(`SELECT * FROM jira_outbox
285
+ WHERE state = 'pending' AND (next_attempt_at IS NULL OR next_attempt_at <= ?)
286
+ ORDER BY id ASC`)
287
+ .all(nowIso);
288
+ const claimed = [];
289
+ const seenIssues = new Set();
290
+ for (const r of rows) {
291
+ if (seenIssues.has(r.jira_issue_id))
292
+ continue; // one op per issue per drain pass
293
+ seenIssues.add(r.jira_issue_id);
294
+ db.prepare("UPDATE jira_outbox SET state = 'inflight', updated_at = ? WHERE id = ?").run(nowIso, r.id);
295
+ claimed.push(mapOutbox({ ...r, state: 'inflight' }));
296
+ if (claimed.length >= max)
297
+ break;
298
+ }
299
+ return claimed;
300
+ });
301
+ return tx(limit);
302
+ }
303
+ function markOutboxDone(db, id) {
304
+ db.prepare("UPDATE jira_outbox SET state = 'done', updated_at = ? WHERE id = ?").run(new Date().toISOString(), id);
305
+ }
306
+ function markOutboxRetry(db, id, nextAttemptAt, error) {
307
+ db.prepare("UPDATE jira_outbox SET state = 'pending', attempts = attempts + 1, next_attempt_at = ?, last_error = ?, updated_at = ? WHERE id = ?").run(nextAttemptAt, error.slice(0, 500), new Date().toISOString(), id);
308
+ }
309
+ function markOutboxDead(db, id, reason) {
310
+ db.prepare("UPDATE jira_outbox SET state = 'dead', dead_reason = ?, updated_at = ? WHERE id = ?").run(reason.slice(0, 500), new Date().toISOString(), id);
311
+ }
312
+ /** Reset all `inflight` rows back to `pending` (startup recovery after a crash). */
313
+ function resetInflight(db) {
314
+ const info = db
315
+ .prepare("UPDATE jira_outbox SET state = 'pending', updated_at = ? WHERE state = 'inflight'")
316
+ .run(new Date().toISOString());
317
+ return info.changes;
318
+ }
319
+ /** Re-queue a dead-lettered op for a manual retry. */
320
+ function retryDeadOutbox(db, id) {
321
+ const info = db
322
+ .prepare("UPDATE jira_outbox SET state = 'pending', next_attempt_at = NULL, dead_reason = NULL, last_error = NULL, updated_at = ? WHERE id = ? AND state = 'dead'")
323
+ .run(new Date().toISOString(), id);
324
+ return info.changes > 0;
325
+ }
326
+ function listOutbox(db, opts = {}) {
327
+ const limit = Math.min(opts.limit ?? 200, 1000);
328
+ if (opts.state) {
329
+ return db.prepare('SELECT * FROM jira_outbox WHERE state = ? ORDER BY id DESC LIMIT ?').all(opts.state, limit).map(mapOutbox);
330
+ }
331
+ return db.prepare('SELECT * FROM jira_outbox ORDER BY id DESC LIMIT ?').all(limit).map(mapOutbox);
332
+ }
333
+ function countOutboxByState(db) {
334
+ const rows = db.prepare('SELECT state, COUNT(*) AS n FROM jira_outbox GROUP BY state').all();
335
+ const out = { pending: 0, inflight: 0, done: 0, dead: 0 };
336
+ for (const r of rows) {
337
+ if (r.state in out)
338
+ out[r.state] = r.n;
339
+ }
340
+ return out;
341
+ }