specrails-desktop 2.3.0 → 2.5.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.
- package/client/dist/assets/ActivityFeedPage-BTYWMRwB.js +1 -0
- package/client/dist/assets/AgentsPage-BfOCeHHt.js +86 -0
- package/client/dist/assets/{AnalyticsPage-Dyyz1ht3.js → AnalyticsPage-AbVXKh9v.js} +1 -1
- package/client/dist/assets/{BarChart-CMdLa6Es.js → BarChart-DlshJN3Z.js} +2 -2
- package/client/dist/assets/CodePage-DJCjDG4I.js +2 -0
- package/client/dist/assets/{DesktopAnalyticsPage-CTNwb639.js → DesktopAnalyticsPage-CTqZ9mbB.js} +1 -1
- package/client/dist/assets/DocsDialog-KiJOSRvX.js +11 -0
- package/client/dist/assets/DocsPage-B17CR54A.js +11 -0
- package/client/dist/assets/{ExportDropdown-DuoZcdYN.js → ExportDropdown-BAu6z3b6.js} +1 -1
- package/client/dist/assets/IntegrationsPage-CCG64Q-6.js +3 -0
- package/client/dist/assets/JobDetailPage-BnGJSMiS.js +16 -0
- package/client/dist/assets/JobsPage-B-tn4CIf.js +1 -0
- package/client/dist/assets/{cssMode-Cc6ozl-J.js → cssMode-DzNPAYFh.js} +1 -1
- package/client/dist/assets/dashboard--Ahnvfr3.js +1 -0
- package/client/dist/assets/dashboard-BN1C2pEh.js +1 -0
- package/client/dist/assets/dashboard-BZs_EzAn.js +1 -0
- package/client/dist/assets/dashboard-Bsw44L8_.js +1 -0
- package/client/dist/assets/dashboard-Bw3VECgY.js +1 -0
- package/client/dist/assets/{dashboard-Duo4DDCW.js → dashboard-CuOshSHn.js} +1 -1
- package/client/dist/assets/dashboard-DfouCM3_.js +1 -0
- package/client/dist/assets/dashboard-Pp5hwnZB.js +1 -0
- package/client/dist/assets/{dist-js-H6hyhSuv.js → dist-js-B16c3VyT.js} +1 -1
- package/client/dist/assets/{dist-js-4UEGaKhD.js → dist-js-P2FkJ6fA.js} +1 -1
- package/client/dist/assets/{editor.main-CfXxHimg.js → editor.main-C7Rmw-hR.js} +2 -2
- package/client/dist/assets/{freemarker2-DP7J1gG3.js → freemarker2-Cszs4SVo.js} +1 -1
- package/client/dist/assets/{handlebars-BjRlucw6.js → handlebars-Dp7Lsuym.js} +1 -1
- package/client/dist/assets/{html-OumBQJ-U.js → html-BURidrEm.js} +1 -1
- package/client/dist/assets/{htmlMode-CStc3zXM.js → htmlMode--k5M7GjZ.js} +1 -1
- package/client/dist/assets/index-AfVF6BgE.js +142 -0
- package/client/dist/assets/index-NlH5BbXJ.css +2 -0
- package/client/dist/assets/{integrations-Cublz3m6.js → integrations-2C7MkGT0.js} +1 -1
- package/client/dist/assets/{integrations-HIlUxXVs.js → integrations-BDC670cg.js} +1 -1
- package/client/dist/assets/integrations-BqUmRUef.js +1 -0
- package/client/dist/assets/{integrations-DmQYCUvN.js → integrations-C2jQtv-s.js} +1 -1
- package/client/dist/assets/{integrations-DRdbki5W.js → integrations-CB98NeH5.js} +1 -1
- package/client/dist/assets/{integrations-C3p12Ms6.js → integrations-CX4p_bij.js} +1 -1
- package/client/dist/assets/{integrations-DaC4SzzL.js → integrations-_SuVeQIG.js} +1 -1
- package/client/dist/assets/{integrations-Cr6hH7XR.js → integrations-eQPHAYsE.js} +1 -1
- package/client/dist/assets/{javascript-CMk--e7g.js → javascript-kJQz__44.js} +1 -1
- package/client/dist/assets/jira-C-ATCti0.js +1 -0
- package/client/dist/assets/jira-CmVfRM-b.js +1 -0
- package/client/dist/assets/jira-D7bkKAX8.js +1 -0
- package/client/dist/assets/jira-DKImM1YH.js +1 -0
- package/client/dist/assets/jira-DOw8bkIR.js +1 -0
- package/client/dist/assets/jira-DlA-wGp-.js +1 -0
- package/client/dist/assets/jira-Fob8EGxN.js +1 -0
- package/client/dist/assets/jira-xZA2lixb.js +1 -0
- package/client/dist/assets/jobs-BGkI19S_.js +1 -0
- package/client/dist/assets/jobs-Brp44JDd.js +1 -0
- package/client/dist/assets/jobs-D93lG6If.js +1 -0
- package/client/dist/assets/jobs-DAF8AGy5.js +1 -0
- package/client/dist/assets/jobs-Db3xrsp_.js +1 -0
- package/client/dist/assets/jobs-Do4Ltqdj.js +1 -0
- package/client/dist/assets/jobs-F5PGJwbW.js +1 -0
- package/client/dist/assets/jobs-fYWWxCUV.js +1 -0
- package/client/dist/assets/{jsonMode-C2h3ZcjZ.js → jsonMode-v5JYPpnz.js} +1 -1
- package/client/dist/assets/{lib-Cs5FrUJI.js → lib-rNNmltMb.js} +1 -1
- package/client/dist/assets/{liquid-mI3KJrBE.js → liquid-Dl9I6gWt.js} +1 -1
- package/client/dist/assets/{lspLanguageFeatures-DU09ggWi.js → lspLanguageFeatures-CPlEe0NK.js} +1 -1
- package/client/dist/assets/{mdx-C41VDTR_.js → mdx-Byl7TtzQ.js} +1 -1
- package/client/dist/assets/{monaco.contribution-CPObAXMC.js → monaco.contribution-YMAkHQcQ.js} +2 -2
- package/client/dist/assets/{python-Y27rKQtk.js → python-jWQwT6j2.js} +1 -1
- package/client/dist/assets/{razor-Cd5-q9Bp.js → razor-BWS3sP-E.js} +1 -1
- package/client/dist/assets/setup-C0dzw8j4.js +1 -0
- package/client/dist/assets/setup-C1IA-9YS.js +1 -0
- package/client/dist/assets/setup-CpfjaNut.js +1 -0
- package/client/dist/assets/setup-D3rNZA9A.js +1 -0
- package/client/dist/assets/setup-UD2aanGs.js +1 -0
- package/client/dist/assets/setup-WP6WOYQh.js +1 -0
- package/client/dist/assets/setup-gzLG8T6F.js +1 -0
- package/client/dist/assets/setup-pjgmYHx6.js +1 -0
- package/client/dist/assets/{specs-DaUTrNF9.js → specs-B4GuOzuZ.js} +1 -1
- package/client/dist/assets/{specs-CZ1PsXsC.js → specs-BVLKe2n5.js} +1 -1
- package/client/dist/assets/{specs-k0PyLDVt.js → specs-C62F2CDv.js} +1 -1
- package/client/dist/assets/specs-D-Sb6dre.js +1 -0
- package/client/dist/assets/{specs-B__C8-8a.js → specs-DFSkAeK8.js} +1 -1
- package/client/dist/assets/{specs-BFfu3u-a.js → specs-DfwDeADE.js} +1 -1
- package/client/dist/assets/{specs-D2FzlLn9.js → specs-VK-zXv7x.js} +1 -1
- package/client/dist/assets/{specs-Dyc5hYeE.js → specs-ghyBMnib.js} +1 -1
- package/client/dist/assets/{tsMode-B0y_xEci.js → tsMode-BbOGOuSV.js} +1 -1
- package/client/dist/assets/{typescript-BzK0OgwW.js → typescript-eBtFQJLs.js} +1 -1
- package/client/dist/assets/{useProjectCache-BZWYV-w-.js → useProjectCache-Cid_GxRM.js} +1 -1
- package/client/dist/assets/{workers-rt--R2Qy.js → workers-BvicOoDf.js} +1 -1
- package/client/dist/assets/{xml-eX9QXAmI.js → xml-BJepAPyM.js} +1 -1
- package/client/dist/assets/{yaml-fcsNkpOt.js → yaml-DabgV-eA.js} +1 -1
- package/client/dist/index.html +13 -12
- package/docs/jira-integration-plan.md +321 -0
- package/package.json +1 -1
- package/server/dist/chat-manager.js +19 -7
- package/server/dist/context-scope.js +29 -8
- package/server/dist/db.js +127 -2
- package/server/dist/feature-flags.js +26 -0
- package/server/dist/interactive-job-session.js +363 -0
- package/server/dist/jira/jira-adf.js +113 -0
- package/server/dist/jira/jira-backlog-config.js +58 -0
- package/server/dist/jira/jira-client.js +279 -0
- package/server/dist/jira/jira-credential-store.js +103 -0
- package/server/dist/jira/jira-db.js +341 -0
- package/server/dist/jira/jira-issue-fields.js +428 -0
- package/server/dist/jira/jira-materializer.js +250 -0
- package/server/dist/jira/jira-status-resolver.js +211 -0
- package/server/dist/jira/jira-sync-manager.js +1014 -0
- package/server/dist/jira/types.js +9 -0
- package/server/dist/jira-router.js +304 -0
- package/server/dist/project-registry.js +43 -1
- package/server/dist/project-router-jobs.js +42 -0
- package/server/dist/project-router-tickets.js +49 -1
- package/server/dist/project-router.js +4 -0
- package/server/dist/queue-manager.js +214 -54
- package/server/dist/rails-router.js +27 -1
- package/server/dist/util/stream-display.js +66 -0
- package/client/dist/assets/ActivityFeedPage-3Veccrvk.js +0 -1
- package/client/dist/assets/AgentsPage-2mFPghP4.js +0 -86
- package/client/dist/assets/CodePage-D7Xwjhut.js +0 -2
- package/client/dist/assets/DocsDialog-D8yoyZDD.js +0 -11
- package/client/dist/assets/DocsPage-CeO-fAxy.js +0 -11
- package/client/dist/assets/IntegrationsPage-iIZ0UEzf.js +0 -3
- package/client/dist/assets/JobDetailPage-DgJHAH2m.js +0 -16
- package/client/dist/assets/JobsPage-Bv_RpRAE.js +0 -1
- package/client/dist/assets/dashboard-B4ixDVk8.js +0 -1
- package/client/dist/assets/dashboard-BZBADHSj.js +0 -1
- package/client/dist/assets/dashboard-C1MfeUHs.js +0 -1
- package/client/dist/assets/dashboard-C7SK6xu5.js +0 -1
- package/client/dist/assets/dashboard-CB6Le1yN.js +0 -1
- package/client/dist/assets/dashboard-CoTpMOBM.js +0 -1
- package/client/dist/assets/dashboard-I19DXBxw.js +0 -1
- package/client/dist/assets/index-CGHKpC-N.js +0 -142
- package/client/dist/assets/index-D17R4Cjc.css +0 -2
- package/client/dist/assets/integrations-D28q1kF6.js +0 -1
- package/client/dist/assets/jobs-2N3RXDAM.js +0 -1
- package/client/dist/assets/jobs-2f6Hdc72.js +0 -1
- package/client/dist/assets/jobs-3j3_npyo.js +0 -1
- package/client/dist/assets/jobs-BqEbCCxD.js +0 -1
- package/client/dist/assets/jobs-DPPT6bV6.js +0 -1
- package/client/dist/assets/jobs-DRzjWI9u.js +0 -1
- package/client/dist/assets/jobs-cHYInoau.js +0 -1
- package/client/dist/assets/jobs-vGfzIDQa.js +0 -1
- package/client/dist/assets/setup--FMCsnQS.js +0 -1
- package/client/dist/assets/setup-B19ZpBNi.js +0 -1
- package/client/dist/assets/setup-BZPmkjSN.js +0 -1
- package/client/dist/assets/setup-BqYA02rS.js +0 -1
- package/client/dist/assets/setup-ChKQDHN9.js +0 -1
- package/client/dist/assets/setup-D2n9jMfM.js +0 -1
- package/client/dist/assets/setup-P3r6YP1D.js +0 -1
- package/client/dist/assets/setup-fnfEbwlv.js +0 -1
- package/client/dist/assets/specs-cKEh2LXt.js +0 -1
- /package/client/dist/assets/{abap-Bw6f2wDG.js → abap-s65oMlhi.js} +0 -0
- /package/client/dist/assets/{activity-BdrPln96.js → activity-BqqwnH_h.js} +0 -0
- /package/client/dist/assets/{activity-BEIp_Y1A.js → activity-C8qqEIoP.js} +0 -0
- /package/client/dist/assets/{activity-CpkRS8Sx.js → activity-CZVM4nlJ.js} +0 -0
- /package/client/dist/assets/{activity-DOUVEjJi.js → activity-Cyy07Tgo.js} +0 -0
- /package/client/dist/assets/{activity-DRwkql_y.js → activity-DlbWCa4y.js} +0 -0
- /package/client/dist/assets/{activity-DKCpESPt.js → activity-Dwq0heud.js} +0 -0
- /package/client/dist/assets/{activity-DcDQ7tjw.js → activity-qFTcMyW9.js} +0 -0
- /package/client/dist/assets/{addon-image-3WCl5Vhd.js → addon-image-CpF0L0jM.js} +0 -0
- /package/client/dist/assets/{addon-ligatures-C5OdliKs.js → addon-ligatures-hXysGZrA.js} +0 -0
- /package/client/dist/assets/{addon-webgl-BbX6pSjl.js → addon-webgl-Cn1slavz.js} +0 -0
- /package/client/dist/assets/{addspec-D33ocMxf.js → addspec-B1FTtI2a.js} +0 -0
- /package/client/dist/assets/{addspec-DFswZ0jK.js → addspec-BCT9vm_c.js} +0 -0
- /package/client/dist/assets/{addspec-DVZ15Jp8.js → addspec-DeDOztDr.js} +0 -0
- /package/client/dist/assets/{addspec-Fkv91Opc.js → addspec-DpRgmfmx.js} +0 -0
- /package/client/dist/assets/{addspec-BEeF5-zc.js → addspec-Dw-0Dg-4.js} +0 -0
- /package/client/dist/assets/{addspec-B5yl4Loj.js → addspec-rp496P_F.js} +0 -0
- /package/client/dist/assets/{addspec-DRE-jZv7.js → addspec-v8j6A7CD.js} +0 -0
- /package/client/dist/assets/{agents-DK-Dlc0i.js → agents-23iPejcA.js} +0 -0
- /package/client/dist/assets/{agents-Q6Ldfpxx.js → agents-BDx1RXcl.js} +0 -0
- /package/client/dist/assets/{agents-TeOSy-ax.js → agents-BFr3kUhK.js} +0 -0
- /package/client/dist/assets/{agents-Bm9rPqnt.js → agents-B_1L9xRg.js} +0 -0
- /package/client/dist/assets/{agents-1nCDWRmP.js → agents-BlPnx-mz.js} +0 -0
- /package/client/dist/assets/{agents-iTqjRajS.js → agents-DcxZHzNr.js} +0 -0
- /package/client/dist/assets/{agents-s87sMGzL.js → agents-G3shOewU.js} +0 -0
- /package/client/dist/assets/{agentstudio-B6Wb59E7.js → agentstudio-B-CMAQqy.js} +0 -0
- /package/client/dist/assets/{agentstudio-D3I62TLJ.js → agentstudio-Bk1eZcv4.js} +0 -0
- /package/client/dist/assets/{agentstudio-DuH9TogZ.js → agentstudio-ChxNuGAu.js} +0 -0
- /package/client/dist/assets/{agentstudio-Kw88_dUF.js → agentstudio-DNlme601.js} +0 -0
- /package/client/dist/assets/{agentstudio-BdidyBzZ.js → agentstudio-DpP9caEE.js} +0 -0
- /package/client/dist/assets/{agentstudio-BSnWLR63.js → agentstudio-Y3G0ddJ2.js} +0 -0
- /package/client/dist/assets/{agentstudio-BADhZ41e.js → agentstudio-kk9RB7Se.js} +0 -0
- /package/client/dist/assets/{aiedit-DJMny-D5.js → aiedit-5ETerMK1.js} +0 -0
- /package/client/dist/assets/{aiedit-D2ji6Qy0.js → aiedit-BBCrOpHq.js} +0 -0
- /package/client/dist/assets/{aiedit-DAhZTvtk.js → aiedit-BMtcGYNE.js} +0 -0
- /package/client/dist/assets/{aiedit-DvrcbwGv.js → aiedit-D9ddlgkM.js} +0 -0
- /package/client/dist/assets/{aiedit-WBSjT_C1.js → aiedit-De0SOH6S.js} +0 -0
- /package/client/dist/assets/{aiedit-BWxHGsYA.js → aiedit-DrfzQroF.js} +0 -0
- /package/client/dist/assets/{aiedit-DOcxERkU.js → aiedit-fMltW101.js} +0 -0
- /package/client/dist/assets/{analytics-C9Zc-rkM.js → analytics-BeTyviO8.js} +0 -0
- /package/client/dist/assets/{analytics-CrPCZRJ-.js → analytics-C4eEO260.js} +0 -0
- /package/client/dist/assets/{analytics-CYj0tfj7.js → analytics-C67cIA1b.js} +0 -0
- /package/client/dist/assets/{analytics-C6EzgtdE.js → analytics-CAguvW28.js} +0 -0
- /package/client/dist/assets/{analytics-CVx3YOc0.js → analytics-DBtt8Mgk.js} +0 -0
- /package/client/dist/assets/{analytics-CnY4kNG3.js → analytics-DUPtODxX.js} +0 -0
- /package/client/dist/assets/{analytics-BIdr0YfL.js → analytics-YIpQvPAc.js} +0 -0
- /package/client/dist/assets/{apex-Cw8_REBo.js → apex-BLUBIldB.js} +0 -0
- /package/client/dist/assets/{attachments-DYHGA2Dj.js → attachments-CCWasu-P.js} +0 -0
- /package/client/dist/assets/{attachments-Dd92KpUH.js → attachments-CHaDUfjB.js} +0 -0
- /package/client/dist/assets/{attachments-DzdU6DV6.js → attachments-CVSAbGNl.js} +0 -0
- /package/client/dist/assets/{attachments-Bcf6BG6V.js → attachments-Chg5poG1.js} +0 -0
- /package/client/dist/assets/{attachments-BW4L3l2L.js → attachments-DazTVJbH.js} +0 -0
- /package/client/dist/assets/{attachments-COcrGRFz.js → attachments-Dn-JImAK.js} +0 -0
- /package/client/dist/assets/{attachments-Bke8sCU4.js → attachments-LDA9kp2X.js} +0 -0
- /package/client/dist/assets/{azcli-Cz6HAoOw.js → azcli-DuWxh9mO.js} +0 -0
- /package/client/dist/assets/{bat-CcJ-xyqL.js → bat-UKoTejQm.js} +0 -0
- /package/client/dist/assets/{bicep-z1WDCKYz.js → bicep-4sTT4B3D.js} +0 -0
- /package/client/dist/assets/{browser-DGITz3fC.js → browser-BDd1dbFa.js} +0 -0
- /package/client/dist/assets/{browser-JsAIGCEW.js → browser-BWSgbfdX.js} +0 -0
- /package/client/dist/assets/{browser-M5-rbPlw.js → browser-D2Y_UAKA.js} +0 -0
- /package/client/dist/assets/{browser-BlYF4OOq.js → browser-DH9SGVfM.js} +0 -0
- /package/client/dist/assets/{browser-Bc-YdlVg.js → browser-DWOVYMlg.js} +0 -0
- /package/client/dist/assets/{browser-CT-ReZGt.js → browser-Dxc_VIRK.js} +0 -0
- /package/client/dist/assets/{browser-5ErDlJoR.js → browser-lTQwcDCI.js} +0 -0
- /package/client/dist/assets/{cameligo-BRewOpfa.js → cameligo-CAAryRYO.js} +0 -0
- /package/client/dist/assets/{chat-DwUm6W9z.js → chat-BO9MvVID.js} +0 -0
- /package/client/dist/assets/{chat-BEGuC03z.js → chat-CPgmgZOj.js} +0 -0
- /package/client/dist/assets/{chat-CboQguCi.js → chat-CUrG1eVg.js} +0 -0
- /package/client/dist/assets/{chat-DRCa9pOt.js → chat-CvOOKB2s.js} +0 -0
- /package/client/dist/assets/{chat-BEW60P_u.js → chat-DIh3hr6y.js} +0 -0
- /package/client/dist/assets/{chat-yoXwguQu.js → chat-UVVZqA57.js} +0 -0
- /package/client/dist/assets/{chat-BQNMD0PL.js → chat-mPn3UlMl.js} +0 -0
- /package/client/dist/assets/{clojure-DBjRWN6g.js → clojure-BlMERO1w.js} +0 -0
- /package/client/dist/assets/{clsx-DnqN-uhr.js → clsx-CnH-HMk3.js} +0 -0
- /package/client/dist/assets/{code-zCwBt3Uu.js → code-BwIz8agY.js} +0 -0
- /package/client/dist/assets/{code-g0qFMzyg.js → code-CD7yNSK0.js} +0 -0
- /package/client/dist/assets/{code-DDU0CRS0.js → code-CDFlxUFC.js} +0 -0
- /package/client/dist/assets/{code-L35Loak_.js → code-Cp3Fdng-.js} +0 -0
- /package/client/dist/assets/{code-D1z-YDt-.js → code-D24e1Crx.js} +0 -0
- /package/client/dist/assets/{code-BtsmPQLV.js → code-DtZBQTi9.js} +0 -0
- /package/client/dist/assets/{code-Coa8f2Sh.js → code-nKa0fkm_.js} +0 -0
- /package/client/dist/assets/{coffee-Cfk_XHGR.js → coffee-Cj8D-Wl1.js} +0 -0
- /package/client/dist/assets/{commands-sqrqsxyE.js → commands-B-MVT-2F.js} +0 -0
- /package/client/dist/assets/{commands-UD1NzmwX.js → commands-B0yFTp7e.js} +0 -0
- /package/client/dist/assets/{commands-DLrvnPNg.js → commands-BR1kDkHQ.js} +0 -0
- /package/client/dist/assets/{commands-CJxCry-o.js → commands-Cb21pDlG.js} +0 -0
- /package/client/dist/assets/{commands-CfgY-_of.js → commands-DWgp-8W1.js} +0 -0
- /package/client/dist/assets/{commands-B772IyDa.js → commands-ddsl1V91.js} +0 -0
- /package/client/dist/assets/{commands-BDDp6xFG.js → commands-t4frzhB0.js} +0 -0
- /package/client/dist/assets/{common-Dmm1GhdD.js → common-5ilvMOcH.js} +0 -0
- /package/client/dist/assets/{common-DltqHaAe.js → common-B4sqsKp7.js} +0 -0
- /package/client/dist/assets/{common-GbpxfPG8.js → common-BKpVwUIf.js} +0 -0
- /package/client/dist/assets/{common-DeDELLZJ.js → common-BzEC3kJU.js} +0 -0
- /package/client/dist/assets/{common-DnjcgkPH.js → common-CALKUpYm.js} +0 -0
- /package/client/dist/assets/{common-Dard9UNH.js → common-CTEbWVZS.js} +0 -0
- /package/client/dist/assets/{common-DCr6VzJ7.js → common-DQiza2Xp.js} +0 -0
- /package/client/dist/assets/{cpp-BVob6BaP.js → cpp-BPfKnaj_.js} +0 -0
- /package/client/dist/assets/{csharp-C4fbRuOu.js → csharp-gX-x5uD6.js} +0 -0
- /package/client/dist/assets/{csp-DthFP_vT.js → csp-DKGVt8SM.js} +0 -0
- /package/client/dist/assets/{css-CGMH0hcW.js → css-CPMdnAVq.js} +0 -0
- /package/client/dist/assets/{cypher-Pnf68BRV.js → cypher-ClMDrj9S.js} +0 -0
- /package/client/dist/assets/{dart-PMMOtxZX.js → dart-C4zbzpVv.js} +0 -0
- /package/client/dist/assets/{dockerfile-di1nsJCc.js → dockerfile-D9xw73D1.js} +0 -0
- /package/client/dist/assets/{ecl-D_WVcB5M.js → ecl-gqO8tIR9.js} +0 -0
- /package/client/dist/assets/{editor.api2-XLGzZfbc.js → editor.api2-BPnIxMjz.js} +0 -0
- /package/client/dist/assets/{elixir-OAdJEMOn.js → elixir-DSAhVF3_.js} +0 -0
- /package/client/dist/assets/{explore-D2EFgt8J.js → explore-BE5UmlbD.js} +0 -0
- /package/client/dist/assets/{explore-BV5Xxlsn.js → explore-BmTaI8dX.js} +0 -0
- /package/client/dist/assets/{explore-A8Ltoblq.js → explore-CCwkqoWq.js} +0 -0
- /package/client/dist/assets/{explore-4mFpnrKU.js → explore-CMdEoPDx.js} +0 -0
- /package/client/dist/assets/{explore-C3FSE42C.js → explore-CtdCL4QU.js} +0 -0
- /package/client/dist/assets/{explore-B9A3iN2W.js → explore-DHjxSkqQ.js} +0 -0
- /package/client/dist/assets/{explore-BrBJvfjP.js → explore-__BeALjE.js} +0 -0
- /package/client/dist/assets/{flow9-D3QEZjgn.js → flow9-DeQCSPOd.js} +0 -0
- /package/client/dist/assets/{format-command-CwGuwzGA.js → format-command-2VNoNnMv.js} +0 -0
- /package/client/dist/assets/{fsharp-BF0k_8N8.js → fsharp-CEfaXL-S.js} +0 -0
- /package/client/dist/assets/{go-BAQO5Jsz.js → go-Xp1OkZCh.js} +0 -0
- /package/client/dist/assets/{graphql-hdFVFkiV.js → graphql-BwRXrUwe.js} +0 -0
- /package/client/dist/assets/{hcl-DWnl1o-X.js → hcl-u06DtVFk.js} +0 -0
- /package/client/dist/assets/{ini-CB-6OVu3.js → ini-AmeIpFND.js} +0 -0
- /package/client/dist/assets/{java-d1CmfiHX.js → java-CyDbRQjX.js} +0 -0
- /package/client/dist/assets/{julia-Bgv08lKa.js → julia-BqialFRG.js} +0 -0
- /package/client/dist/assets/{kotlin-u98kaVTf.js → kotlin-Dzz8TWAt.js} +0 -0
- /package/client/dist/assets/{less-CjYwpgg5.js → less-DHRJD3TR.js} +0 -0
- /package/client/dist/assets/{lexon-YTjaAFBB.js → lexon-5Y3QgTmT.js} +0 -0
- /package/client/dist/assets/{lua-BzmkWv27.js → lua-sKvhfPn5.js} +0 -0
- /package/client/dist/assets/{m3-CFwk9fw0.js → m3-DWDVwkFG.js} +0 -0
- /package/client/dist/assets/{markdown-CR5iMpSZ.js → markdown-CD_aSBxW.js} +0 -0
- /package/client/dist/assets/{mips-CcEalc17.js → mips-687T03hg.js} +0 -0
- /package/client/dist/assets/{msdax-BQbkawnr.js → msdax-C1St-dIV.js} +0 -0
- /package/client/dist/assets/{mysql-GTlaaW_P.js → mysql-BG7r8oBS.js} +0 -0
- /package/client/dist/assets/{nav-C2YXcbZS.js → nav-B05EYB0b.js} +0 -0
- /package/client/dist/assets/{nav-D2bOGSEg.js → nav-BNGCq-0y.js} +0 -0
- /package/client/dist/assets/{nav-BEL3MTwK.js → nav-BRInPX8a.js} +0 -0
- /package/client/dist/assets/{nav-CtYwmMgu.js → nav-Bf87DRHD.js} +0 -0
- /package/client/dist/assets/{nav-iH1V5j6o.js → nav-BkVzzFpc.js} +0 -0
- /package/client/dist/assets/{nav-0fwkrgHt.js → nav-BzFLtS1W.js} +0 -0
- /package/client/dist/assets/{nav-ClzOE4mA.js → nav-DBDbQOYn.js} +0 -0
- /package/client/dist/assets/{nav-B_G-TJDW.js → nav-X9sVtUWC.js} +0 -0
- /package/client/dist/assets/{objective-c-Byu1T5if.js → objective-c-Ds1-m05L.js} +0 -0
- /package/client/dist/assets/{pascal-BrfzBfRm.js → pascal-BKK9FpIi.js} +0 -0
- /package/client/dist/assets/{pascaligo-BXXKFUeo.js → pascaligo-SRS3nwtO.js} +0 -0
- /package/client/dist/assets/{perl-B3OikKq-.js → perl-B2hTOlrF.js} +0 -0
- /package/client/dist/assets/{pgsql-CTsa0Acc.js → pgsql-DIQJYNpL.js} +0 -0
- /package/client/dist/assets/{php-DiQh3FUW.js → php-BEaVe8X2.js} +0 -0
- /package/client/dist/assets/{pla-92uH8Fzm.js → pla-oPLHpZ-Q.js} +0 -0
- /package/client/dist/assets/{postiats-BbeWkKUr.js → postiats-D_vzrAzD.js} +0 -0
- /package/client/dist/assets/{powerquery-DgDMzpsm.js → powerquery-BKG6w-FH.js} +0 -0
- /package/client/dist/assets/{powershell-BfdUUzaG.js → powershell-B3dLhDt4.js} +0 -0
- /package/client/dist/assets/{protobuf-BojW2ftW.js → protobuf-DC8SGjcl.js} +0 -0
- /package/client/dist/assets/{pug-BxqTg3IU.js → pug-D5E-4fI0.js} +0 -0
- /package/client/dist/assets/{qsharp-BX_A-MW9.js → qsharp-6vJAWv0x.js} +0 -0
- /package/client/dist/assets/{r-D9BMnxvJ.js → r-CDwsEcbM.js} +0 -0
- /package/client/dist/assets/{redis-5cJqEQJJ.js → redis-CuQbbESS.js} +0 -0
- /package/client/dist/assets/{redshift-d8BBqiwb.js → redshift-B9e1k-qI.js} +0 -0
- /package/client/dist/assets/{restructuredtext-C8a6yIcZ.js → restructuredtext-BiJ5IwaU.js} +0 -0
- /package/client/dist/assets/{ruby-egeh-6KX.js → ruby-B0UAHY9b.js} +0 -0
- /package/client/dist/assets/{rust-a3r9IInB.js → rust-Dg_spmFr.js} +0 -0
- /package/client/dist/assets/{sb-y8iRIDei.js → sb-DjU66I8Q.js} +0 -0
- /package/client/dist/assets/{scala-BPDK2AmK.js → scala-qvStIdfG.js} +0 -0
- /package/client/dist/assets/{scheme-BIWUEoOs.js → scheme-FstEk5Rh.js} +0 -0
- /package/client/dist/assets/{scss-CA-PSzwg.js → scss-w0U3rQLK.js} +0 -0
- /package/client/dist/assets/{settings-CTcwN9RE.js → settings-5tzo0Rn3.js} +0 -0
- /package/client/dist/assets/{settings-D_dujJZI.js → settings-BDAW3trC.js} +0 -0
- /package/client/dist/assets/{settings-Bg0A3zoS.js → settings-BEWv3VEu.js} +0 -0
- /package/client/dist/assets/{settings-BgPqg2nv.js → settings-BORg56um.js} +0 -0
- /package/client/dist/assets/{settings-BSze3_9q.js → settings-D3LurcR5.js} +0 -0
- /package/client/dist/assets/{settings-CSJ0ahZ8.js → settings-DcqWIEM6.js} +0 -0
- /package/client/dist/assets/{settings-DYIV89nV.js → settings-Dfz8QbZS.js} +0 -0
- /package/client/dist/assets/{settings-DDcfx_ca.js → settings-yMubjqYw.js} +0 -0
- /package/client/dist/assets/{shell--LiT1Bja.js → shell-DJ78wREd.js} +0 -0
- /package/client/dist/assets/{solidity-DdqZccZg.js → solidity-1aGIVsdX.js} +0 -0
- /package/client/dist/assets/{sophia-S6-YxNG_.js → sophia-40LqcGjB.js} +0 -0
- /package/client/dist/assets/{sparql-BSf5kMp2.js → sparql-Cz5dqG_g.js} +0 -0
- /package/client/dist/assets/{sql-D7KgjR8G.js → sql-64f62Ni4.js} +0 -0
- /package/client/dist/assets/{st-BnoDa-Ml.js → st-gJe2yG8J.js} +0 -0
- /package/client/dist/assets/{swift-DEUHTkUX.js → swift-C6ME22mv.js} +0 -0
- /package/client/dist/assets/{systemverilog-Tqb_KPnW.js → systemverilog-CEWz259w.js} +0 -0
- /package/client/dist/assets/{tcl-BmBFS2qq.js → tcl-CcLVIi3m.js} +0 -0
- /package/client/dist/assets/{terminal-Bje4ziIa.js → terminal-BYtreaaF.js} +0 -0
- /package/client/dist/assets/{terminal-CSONJOex.js → terminal-C0xx0SjA.js} +0 -0
- /package/client/dist/assets/{terminal-DeWzh6ys.js → terminal-CPpK58RC.js} +0 -0
- /package/client/dist/assets/{terminal-C2WYcFHF.js → terminal-CdxkpafL.js} +0 -0
- /package/client/dist/assets/{terminal-DEqzGtcr.js → terminal-Ciia0wh2.js} +0 -0
- /package/client/dist/assets/{terminal-80yDMgMF.js → terminal-DHIkiWcs.js} +0 -0
- /package/client/dist/assets/{terminal-lkZYR4wJ.js → terminal-DY42QANg.js} +0 -0
- /package/client/dist/assets/{terminal-YOlsJCQj.js → terminal-DoxtVdma.js} +0 -0
- /package/client/dist/assets/{tickets-DYvafSaY.js → tickets-0rM0lIXd.js} +0 -0
- /package/client/dist/assets/{tickets-DNOANUXr.js → tickets-1UIGf_oA.js} +0 -0
- /package/client/dist/assets/{tickets-DlpC_iTg.js → tickets-9kdPXInd.js} +0 -0
- /package/client/dist/assets/{tickets-CF2PYelu.js → tickets-C6pwZwt4.js} +0 -0
- /package/client/dist/assets/{tickets-CB7N30gm.js → tickets-DAjtxAVb.js} +0 -0
- /package/client/dist/assets/{tickets-DU1aqsbr.js → tickets-DNmXcAwu.js} +0 -0
- /package/client/dist/assets/{tickets-clefmXLv.js → tickets-n23kDqJT.js} +0 -0
- /package/client/dist/assets/{tickets-DucYgtdl.js → tickets-tGx5AR5b.js} +0 -0
- /package/client/dist/assets/{twig-BQV8igWC.js → twig-DvsO-WjW.js} +0 -0
- /package/client/dist/assets/{typespec-DlFroUGY.js → typespec-Brkt3IAA.js} +0 -0
- /package/client/dist/assets/{vb-BlrJpIMX.js → vb-r121Uzxt.js} +0 -0
- /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
|
+
}
|