ryco-cli 0.1.29 → 0.1.31

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 (500) hide show
  1. package/README.md +37 -0
  2. package/dist/{AcpAdapter-8CSe4HK7.cjs → AcpAdapter-ByUp9-wk.cjs} +74 -54
  3. package/dist/{AcpAdapter-CG1wRWcf.mjs → AcpAdapter-CY_ANTKu.mjs} +74 -54
  4. package/dist/{AcpNativeLogging-B6TtnnKL.mjs → AcpNativeLogging-C7PC6imv.mjs} +30 -4
  5. package/dist/{AcpNativeLogging-DbjnRnTf.cjs → AcpNativeLogging-OQeAya9d.cjs} +33 -1
  6. package/dist/{AcpRegistryDriver-16ZTxUs3.cjs → AcpRegistryDriver-CD9GN7rI.cjs} +3 -3
  7. package/dist/{AcpRegistryDriver-DZFasKaz.mjs → AcpRegistryDriver-DMZ5VBWJ.mjs} +4 -4
  8. package/dist/AzureDevOpsSourceControlProvider-5giVYoNi.mjs +2053 -0
  9. package/dist/AzureDevOpsSourceControlProvider-BKMXEUaN.cjs +2055 -0
  10. package/dist/{BitbucketSourceControlProvider-DplKc8Wo.mjs → BitbucketSourceControlProvider-BVUBsEUF.mjs} +63 -23
  11. package/dist/{BitbucketSourceControlProvider-B-ZwKj72.cjs → BitbucketSourceControlProvider-BWnnrbch.cjs} +62 -22
  12. package/dist/{BunPTY-Dcl1Lp62.mjs → BunPTY-CMbDQ1Xb.mjs} +1 -1
  13. package/dist/{ClaudeDriver-r0lJ9vmE.cjs → ClaudeDriver-DCrqouOR.cjs} +1376 -194
  14. package/dist/{ClaudeDriver-0gGVop27.mjs → ClaudeDriver-DVOss8cC.mjs} +1377 -195
  15. package/dist/{CodexDriver-bJAbhSwY.cjs → CodexDriver-CBQPHJqU.cjs} +259 -29
  16. package/dist/{CodexDriver-baT02xVb.mjs → CodexDriver-DJoTky7Z.mjs} +261 -31
  17. package/dist/{CodexTextGeneration-Dwp6X3dq.mjs → CodexTextGeneration-BSgNgfZv.mjs} +6 -6
  18. package/dist/{CodexTextGeneration-DFZ5y4gj.cjs → CodexTextGeneration-C9MDQmZm.cjs} +7 -7
  19. package/dist/{CopilotDriver-C0OhnSB1.mjs → CopilotDriver-CUkdPXcH.mjs} +78 -20
  20. package/dist/{CopilotDriver-B_jEqfYQ.cjs → CopilotDriver-DbaMDH16.cjs} +76 -18
  21. package/dist/{CursorDriver-DinXkGP9.mjs → CursorDriver-B-ZilXJB.mjs} +115 -98
  22. package/dist/{CursorDriver-BBFEW7ZI.cjs → CursorDriver-DKQqPbKH.cjs} +116 -99
  23. package/dist/{ForgejoSourceControlProvider-iG9o7aZB.cjs → ForgejoSourceControlProvider-CgpjFECj.cjs} +94 -60
  24. package/dist/{ForgejoSourceControlProvider-Dr0fxfud.mjs → ForgejoSourceControlProvider-DemMYUye.mjs} +95 -61
  25. package/dist/{GitHubSourceControlProvider-L1yFpep4.cjs → GitHubSourceControlProvider-C4un6hOK.cjs} +218 -119
  26. package/dist/{GitHubSourceControlProvider-CnIu0n2Y.mjs → GitHubSourceControlProvider-CRSDYcjc.mjs} +206 -108
  27. package/dist/GitLabSourceControlProvider-D8W1ZLPh.cjs +2260 -0
  28. package/dist/GitLabSourceControlProvider-DpWkJ0M3.mjs +2258 -0
  29. package/dist/{GrokDriver-D_Ylzh5z.cjs → GrokDriver-BQ6G_7ZZ.cjs} +11 -12
  30. package/dist/{GrokDriver-pX-N6HGS.mjs → GrokDriver-Buvas9-q.mjs} +7 -8
  31. package/dist/{Metrics-BjqGlIP4.mjs → Metrics-C3vLS9rz.mjs} +1264 -1151
  32. package/dist/{Metrics-Bf96NJ4j.cjs → Metrics-DjRPLE98.cjs} +1295 -1134
  33. package/dist/{NodePTY-D7tFWuQe.mjs → NodePTY-DgnuBruq.mjs} +1 -1
  34. package/dist/{NodeSqliteClient-BGg70C7Q.cjs → NodeSqliteClient-D8bzGgPN.cjs} +1 -1
  35. package/dist/{OpenCodeDriver-Byu1pf_i.mjs → OpenCodeDriver-BWEZD841.mjs} +184 -50
  36. package/dist/{OpenCodeDriver-BFEw5t09.cjs → OpenCodeDriver-qUiX0RLH.cjs} +185 -51
  37. package/dist/{SideQuestionIsolation-81IoAuoi.mjs → SideQuestionIsolation-B1T-DsR0.mjs} +1 -1
  38. package/dist/{SideQuestionIsolation-CMPkCUP0.cjs → SideQuestionIsolation-BPC-Bxsz.cjs} +1 -1
  39. package/dist/bin.cjs +50689 -15659
  40. package/dist/bin.mjs +50578 -15585
  41. package/dist/client/assets/AccountSettings-B88Q_w9Y.js +1 -0
  42. package/dist/client/assets/AiFocusSettings-Bb0TrCPn.js +1 -0
  43. package/dist/client/assets/{AnimatedHeight-BNg7wnTK.js → AnimatedHeight-epXOsgdm.js} +1 -1
  44. package/dist/client/assets/AppearanceSettings-XS9WRVPU.js +1 -0
  45. package/dist/client/assets/AutomationsDialog-bZckh4Y3.js +1 -0
  46. package/dist/client/assets/AutomationsSummary-wPFZCF49.js +1 -0
  47. package/dist/client/assets/BranchToolbar.logic-DjzLKbbB.js +3 -0
  48. package/dist/client/assets/BrowserPanel-CdBLnnfz.js +1 -0
  49. package/dist/client/assets/ChatRightPanel-BCINd0vP.js +34 -0
  50. package/dist/client/assets/ChatThreadRouteView-BFZ0Si-l.js +1 -0
  51. package/dist/client/assets/ColorSwatchPicker-CGyo99o0.js +1 -0
  52. package/dist/client/assets/CommandPalette.logic-BIOMtnEQ.js +1 -0
  53. package/dist/client/assets/CommandPaletteDialog-Db4LH--z.js +2 -0
  54. package/dist/client/assets/CompositeRoot-DtnwMJKj.js +1 -0
  55. package/dist/client/assets/ComputerUseSettings-CkqCqDsU.js +1 -0
  56. package/dist/client/assets/ConnectionsSettings-B9mxExdG.js +7 -0
  57. package/dist/client/assets/CreatePullRequestDialog-CJ7pNCue.js +1 -0
  58. package/dist/client/assets/CreatePullRequestDialogHost-n4ZjdSr4.js +1 -0
  59. package/dist/client/assets/DiagnosticsSettings-f9rFG9re.js +2 -0
  60. package/dist/client/assets/DiagnosticsSettings.logic-Byf-Bu4S.js +1 -0
  61. package/dist/client/assets/DialogHandle-C0c_rK3I.js +1 -0
  62. package/dist/client/assets/{DialogPopup-DdZlhHuQ.js → DialogPopup-BKW1PEEa.js} +1 -1
  63. package/dist/client/assets/DialogRoot-BIubqrv0.js +1 -0
  64. package/dist/client/assets/DialogTitle-BAX_FLoG.js +1 -0
  65. package/dist/client/assets/{DialogViewport-BwuqbGLY.js → DialogViewport-C2iOUx0O.js} +1 -1
  66. package/dist/client/assets/DiffPanel-BkqDt_SS.js +25 -0
  67. package/dist/client/assets/DisclosureRegion-B8556yU0.js +1 -0
  68. package/dist/client/assets/DraftChatThreadRouteView-BKgRKJ2w.js +1 -0
  69. package/dist/client/assets/{ExternalIdentityWeb.logic-DsTJQkg-.js → ExternalIdentityWeb.logic-Cu6suNrN.js} +1 -1
  70. package/dist/client/assets/GlassSurface-DLYYzRdP.js +1 -0
  71. package/dist/client/assets/HostedConnectionControls-CoVqtnrK.js +1 -0
  72. package/dist/client/assets/HostedHubRoot-CM2CwPUr.js +2 -0
  73. package/dist/client/assets/{HostedNativeAuthorizationRoute-BSq_AlY2.js → HostedNativeAuthorizationRoute-Bizmqrh_.js} +2 -2
  74. package/dist/client/assets/HostedNodeRenameDialog-SXWMsTO0.js +1 -0
  75. package/dist/client/assets/HostedRelayTrustNotice-BfTyrBi5.js +1 -0
  76. package/dist/client/assets/InboxStatusGlyph-BPTqzp7l.js +1 -0
  77. package/dist/client/assets/IntegrationsSettingsPanel-DAPvkV4i.js +1 -0
  78. package/dist/client/assets/KeybindingsSettings-B8g-YI2O.js +1 -0
  79. package/dist/client/assets/LazyBrowserPanel-Ds9cdOC_.js +2 -0
  80. package/dist/client/assets/McpServersSettings-Dw6G3ff3.js +6 -0
  81. package/dist/client/assets/MobileSheet-DfgXNWbd.js +1 -0
  82. package/dist/client/assets/ModelTuningDial-DQBAbuNL.js +1 -0
  83. package/dist/client/assets/NewWorktreeDialog-CDZAJmK6.js +4 -0
  84. package/dist/client/assets/NodeSecuritySettings-3MELA9ru.js +1 -0
  85. package/dist/client/assets/NullStore-gT_6_xZE.js +1 -0
  86. package/dist/client/assets/OnboardingDialog-CAAtNnJf.js +1 -0
  87. package/dist/client/assets/OpinionatedPluginsSettings-AiDB0Vl4.js +1 -0
  88. package/dist/client/assets/{PdfAttachmentPreview-CTo1AyZs.js → PdfAttachmentPreview-BFNW2wjN.js} +2 -2
  89. package/dist/client/assets/{PhoneGetAppInterstitial-DwopOWnQ.js → PhoneGetAppInterstitial-D8fwZ8E9.js} +1 -1
  90. package/dist/client/assets/PhoneHome-YHgHljA0.js +1 -0
  91. package/dist/client/assets/PhoneSettingsSurface-BVxJppvK.js +2 -0
  92. package/dist/client/assets/PreviewPanel-BYcEnkv9.js +643 -0
  93. package/dist/client/assets/ProjectScriptDialog-K34K2Kzm.js +1 -0
  94. package/dist/client/assets/ProjectsPage-DXnMYLjb.js +1 -0
  95. package/dist/client/assets/PromoteChatDialog-CAY7_wJ-.js +1 -0
  96. package/dist/client/assets/ProviderLimitWindow-CK04BSkM.js +1 -0
  97. package/dist/client/assets/ProviderUpdateLaunchNotification.logic-BMBrDDOC.js +1 -0
  98. package/dist/client/assets/ProvidersSettingsPanel-C85PX9Es.js +1 -0
  99. package/dist/client/assets/PullRequestsPage-C0rgfGwB.js +1 -0
  100. package/dist/client/assets/{QuitShortcutFeedback-eCvP_MNj.js → QuitShortcutFeedback-DSkKqETs.js} +1 -1
  101. package/dist/client/assets/RedactedSensitiveText-DQ0YveQd.js +1 -0
  102. package/dist/client/assets/RollingText-BzvpP5fa.js +1 -0
  103. package/dist/client/assets/RootAppShell-BYQ-eGNT.js +6 -0
  104. package/dist/client/assets/{Separator-BiINUUQl.js → Separator-DpiW19Vw.js} +1 -1
  105. package/dist/client/assets/SettingsPage-BCFN7Ju2.js +2 -0
  106. package/dist/client/assets/SettingsPanels-CP6z2b1x.js +3 -0
  107. package/dist/client/assets/SettingsPanels.editor-D8U-TWWG.js +1 -0
  108. package/dist/client/assets/SettingsSelect-DEhNaz3E.js +1 -0
  109. package/dist/client/assets/Sidebar.logic-D_ODfSpl.js +1 -0
  110. package/dist/client/assets/SimulatorPanel-DCT6fZ0X.js +1 -0
  111. package/dist/client/assets/SourceControlSettings-DxUtvPMK.js +1 -0
  112. package/dist/client/assets/StatisticsPage-C9SrwtM4.js +1 -0
  113. package/dist/client/assets/StatisticsPanel-BMYLETs0.js +1 -0
  114. package/dist/client/assets/ThreadLinkList-BN5z5EpS.js +169 -0
  115. package/dist/client/assets/ThreadTerminalDrawer-CgIFOlR-.js +18 -0
  116. package/dist/client/assets/ThreadWorkspacePanel-DvXoqQPF.js +3 -0
  117. package/dist/client/assets/ToolbarRootContext-8FsV9Cpj.js +1 -0
  118. package/dist/client/assets/TraitsPicker-DcrpJahy.js +1 -0
  119. package/dist/client/assets/Virtualizer-CwXeUPla.js +1345 -0
  120. package/dist/client/assets/WorkspacePullRequestPanel-3mlcJn9G.js +1 -0
  121. package/dist/client/assets/WorkspaceReview-UGbCgXeK.js +2 -0
  122. package/dist/client/assets/{abnfDiagram-N423BO3Z-DAmGykdr.js → abnfDiagram-N423BO3Z-DVEM6Scc.js} +1 -1
  123. package/dist/client/assets/{activity-DRZlu-MC.js → activity-DVCuAejY.js} +1 -1
  124. package/dist/client/assets/{alert-CwrDisFU.js → alert-FV7ZIit_.js} +1 -1
  125. package/dist/client/assets/alert-dialog-CgXR9tED.js +1 -0
  126. package/dist/client/assets/app-window-3xtwqZgI.js +1 -0
  127. package/dist/client/assets/appChrome-COCz-T7w.js +1 -0
  128. package/dist/client/assets/{appearancePreferences-nFx4MHoI.js → appearancePreferences-NnsvXwBe.js} +1 -1
  129. package/dist/client/assets/architecture-7GRP2DOG-DXXb_0_g.js +1 -0
  130. package/dist/client/assets/{architectureDiagram-T3A2C74G-DypU2ERW.js → architectureDiagram-T3A2C74G-B6pcKiCj.js} +1 -1
  131. package/dist/client/assets/{arrow-left-XhcJWpRy.js → arrow-left-Blu3LSE2.js} +1 -1
  132. package/dist/client/assets/{arrow-right-BBs6iTUL.js → arrow-right-CO3CH0ne.js} +1 -1
  133. package/dist/client/assets/arrow-up-B69gV2Bq.js +1 -0
  134. package/dist/client/assets/{arrow-up-right-CJ9Vq7nK.js → arrow-up-right-BbPGFOLA.js} +1 -1
  135. package/dist/client/assets/authorization-Ob6YwWiI.js +1 -0
  136. package/dist/client/assets/autocomplete-RVpjsrDv.js +1 -0
  137. package/dist/client/assets/ban-BIm2PVkE.js +1 -0
  138. package/dist/client/assets/{blockDiagram-VBNYF7ZC-B9MhR9hY.js → blockDiagram-VBNYF7ZC-WNerGp9V.js} +1 -1
  139. package/dist/client/assets/{bot-D5wgL7pu.js → bot-C9nWtaWq.js} +1 -1
  140. package/dist/client/assets/browserState-jt47YsqD.js +1 -0
  141. package/dist/client/assets/{c4Diagram-5PPSVZJV-C22FWSoE.js → c4Diagram-5PPSVZJV-wp1ioOoM.js} +1 -1
  142. package/dist/client/assets/camera-C13VoW3c.js +1 -0
  143. package/dist/client/assets/capabilities-CfOhq009.js +1 -0
  144. package/dist/client/assets/channel-56r2qL2v.js +1 -0
  145. package/dist/client/assets/{chart-column-D6Lnkklk.js → chart-column-DRv0YtL_.js} +1 -1
  146. package/dist/client/assets/checkbox-CIIIY9FA.js +1 -0
  147. package/dist/client/assets/checks-Dw022Bvy.js +1 -0
  148. package/dist/client/assets/{chunk-2GRJ4B5K-D1tZuCzA.js → chunk-2GRJ4B5K-DRl3ILpc.js} +1 -1
  149. package/dist/client/assets/{chunk-4I5QYGJK-Clf86zK0.js → chunk-4I5QYGJK-CYTRl4bo.js} +1 -1
  150. package/dist/client/assets/{chunk-5RXB4S5H-B36N5RYZ.js → chunk-5RXB4S5H-VCNwRsOa.js} +1 -1
  151. package/dist/client/assets/{chunk-6Q2QTUOP-IAxdzsQJ.js → chunk-6Q2QTUOP-DnSeKGPG.js} +1 -1
  152. package/dist/client/assets/{chunk-7Z6QIM7H-Ctqebv_4.js → chunk-7Z6QIM7H-Cjilh9TF.js} +1 -1
  153. package/dist/client/assets/{chunk-GF5L2VYU-CAfciJae.js → chunk-GF5L2VYU-CGR7AW0t.js} +1 -1
  154. package/dist/client/assets/{chunk-I66GZJ75-BZ7XtZf4.js → chunk-I66GZJ75-CXSn8dDu.js} +1 -1
  155. package/dist/client/assets/{chunk-JQJVKLGR-DVuZCWnv.js → chunk-JQJVKLGR-Dro-75lU.js} +1 -1
  156. package/dist/client/assets/{chunk-KBJHAD2P-DtWbzsRm.js → chunk-KBJHAD2P-BDqN2kVf.js} +1 -1
  157. package/dist/client/assets/{chunk-NSK5VX7P-BVMz_Hc4.js → chunk-NSK5VX7P-DGo5UczH.js} +1 -1
  158. package/dist/client/assets/{chunk-QR6OTTB3-DWitTCy-.js → chunk-QR6OTTB3-RWuyWnBI.js} +1 -1
  159. package/dist/client/assets/{chunk-UBXNYLIW-BuxXXP2s.js → chunk-UBXNYLIW-BPRzeB0w.js} +1 -1
  160. package/dist/client/assets/{chunk-W5SLKNZC-Bnf3sQl4.js → chunk-W5SLKNZC-DYWocTFi.js} +1 -1
  161. package/dist/client/assets/{chunk-WRU74C26-xu-KDOon.js → chunk-WRU74C26-ChbB1jY3.js} +1 -1
  162. package/dist/client/assets/circle-stop-D8B4hRpY.js +1 -0
  163. package/dist/client/assets/circle-x-CNLfrTqR.js +1 -0
  164. package/dist/client/assets/classDiagram-JCYQIIEL-DGvmFev3.js +1 -0
  165. package/dist/client/assets/classDiagram-v2-OCEON4UE-DGvmFev3.js +1 -0
  166. package/dist/client/assets/{clipboard-copy-oDSkUUg4.js → clipboard-copy-DGi8FKNO.js} +1 -1
  167. package/dist/client/assets/clock-3-DmJ4_XPI.js +1 -0
  168. package/dist/client/assets/clock-DZIuPtNG.js +1 -0
  169. package/dist/client/assets/color-picker-BdBXje-a.js +1 -0
  170. package/dist/client/assets/columns-2-CWlMOClK.js +1 -0
  171. package/dist/client/assets/combobox-Dtjtf7AB.js +1 -0
  172. package/dist/client/assets/{cynefin-OW5HDTMX-DGNyiNSf.js → cynefin-OW5HDTMX-TuShvMuM.js} +1 -1
  173. package/dist/client/assets/{cynefinDiagram-MW4NZA55-_ctibv4i.js → cynefinDiagram-MW4NZA55-B0Edt2Em.js} +1 -1
  174. package/dist/client/assets/{dagre-VZM6K2ZE-Bo-bS1Y0.js → dagre-VZM6K2ZE-D-eiuqHx.js} +1 -1
  175. package/dist/client/assets/{data-list-DLsM39Hp.js → data-list-BAx6jBY1.js} +1 -1
  176. package/dist/client/assets/desktopUpdateAtoms-BjrLa3tl.js +1 -0
  177. package/dist/client/assets/desktopWorkspace-C2wXVBhc.js +1 -0
  178. package/dist/client/assets/{deviceName-z0ZWSq0z.js → deviceName-B4youG0v.js} +1 -1
  179. package/dist/client/assets/{diagram-7IWD3JNH-DSjtw1SY.js → diagram-7IWD3JNH-DgM6lMlR.js} +1 -1
  180. package/dist/client/assets/{diagram-B4RE2ZJO-B7fWEvIa.js → diagram-B4RE2ZJO-CyHNDjzV.js} +1 -1
  181. package/dist/client/assets/{diagram-LBJQPF4R-trRYCE5d.js → diagram-LBJQPF4R-DDzuLIN5.js} +1 -1
  182. package/dist/client/assets/{diagram-Q27KOJAE-_DYcRggk.js → diagram-Q27KOJAE-BaBvK9QB.js} +1 -1
  183. package/dist/client/assets/{diagram-UB23O5K3-BkMzOHX8.js → diagram-UB23O5K3-CzZ2ewuZ.js} +1 -1
  184. package/dist/client/assets/dialogWords-Cg0YkJVg.js +1 -0
  185. package/dist/client/assets/diffRouteSearch-D2MKN_ah.js +1 -0
  186. package/dist/client/assets/disclosureMotion-cbMJn5-z.js +1 -0
  187. package/dist/client/assets/{download-CHdS3R_v.js → download-TvtXS4hE.js} +1 -1
  188. package/dist/client/assets/{ebnfDiagram-BXEA7PRR-DubiOMCG.js → ebnfDiagram-BXEA7PRR-CL1vdOKi.js} +1 -1
  189. package/dist/client/assets/editorPreferences-DqKyA-2Z.js +1 -0
  190. package/dist/client/assets/ellipsis-CDK1dNFZ.js +1 -0
  191. package/dist/client/assets/ellipsis-vertical-CwzEUTwV.js +1 -0
  192. package/dist/client/assets/{empty-BlBl_Vvw.js → empty-BovKoxbn.js} +1 -1
  193. package/dist/client/assets/{erDiagram-JOGREHBK-CFDiNfSJ.js → erDiagram-JOGREHBK-DmQR2if6.js} +1 -1
  194. package/dist/client/assets/eventmodeling-NTZA5JFV-D272GIcY.js +1 -0
  195. package/dist/client/assets/external-link-CJeVJZ7s.js +1 -0
  196. package/dist/client/assets/eye-BUmrXqzg.js +1 -0
  197. package/dist/client/assets/file-diff-BWc3mYsz.js +1 -0
  198. package/dist/client/assets/flowDiagram-UKHOOZJN-DLyS38Mm.js +1 -0
  199. package/dist/client/assets/folder-git-2-CPxg5wKP.js +1 -0
  200. package/dist/client/assets/folder-open-DcMymvp1.js +1 -0
  201. package/dist/client/assets/formatCount-B4KLI651.js +1 -0
  202. package/dist/client/assets/{ganttDiagram-PKOTCBZU-DT2XhE-m.js → ganttDiagram-PKOTCBZU-1q2nUL92.js} +1 -1
  203. package/dist/client/assets/git-pull-request-BFPwpm3c.js +1 -0
  204. package/dist/client/assets/{gitGraph-4MIJSDKK-BI5UGiqb.js → gitGraph-4MIJSDKK-COtwmv2S.js} +1 -1
  205. package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-CzAB97Rd.js → gitGraphDiagram-DS77QQ5N-ChsvaxX4.js} +1 -1
  206. package/dist/client/assets/{group-DZJuSiJL.js → group-DWWn0dTx.js} +1 -1
  207. package/dist/client/assets/hammer-BXo-EU88.js +1 -0
  208. package/dist/client/assets/hostedConnectionCoordinator-BkAE-RhA.js +1 -0
  209. package/dist/client/assets/hostedPairing-5n5srRC9.js +1 -0
  210. package/dist/client/assets/{index-BAJdq3TK.js → index-DARIYokI.js} +2 -2
  211. package/dist/client/assets/{info-A6RAGUB7-DdGYYgLX.js → info-A6RAGUB7-CI2qZ9wW.js} +1 -1
  212. package/dist/client/assets/{infoDiagram-6WML65LV-zhUpER6a.js → infoDiagram-6WML65LV-BPmgcTPH.js} +1 -1
  213. package/dist/client/assets/{input-CzU08wbL.js → input-CCie4mm1.js} +1 -1
  214. package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-BQLkqykE.js → ishikawaDiagram-WSZJBQD7-LyS9p3Yg.js} +1 -1
  215. package/dist/client/assets/{journeyDiagram-NVQOT4AX-DBgsbKOF.js → journeyDiagram-NVQOT4AX-BYaAmN65.js} +1 -1
  216. package/dist/client/assets/{kanban-definition-27J2QSJJ-DF-Rr-xs.js → kanban-definition-27J2QSJJ-D-pwzqFt.js} +1 -1
  217. package/dist/client/assets/{key-round-CvyrSjb2.js → key-round-BlrUTfxB.js} +1 -1
  218. package/dist/client/assets/keyboard-DlBdq6sz.js +1 -0
  219. package/dist/client/assets/label-ChtVI9lp.js +1 -0
  220. package/dist/client/assets/layers-BB-ruGvd.js +1 -0
  221. package/dist/client/assets/lifecycleSuggestionPolicy-0ERe_O53.js +1 -0
  222. package/dist/client/assets/list-checks-BkM_ZRsj.js +1 -0
  223. package/dist/client/assets/loader-3vQnfqIT.js +1 -0
  224. package/dist/client/assets/{log-out-D3rICSt5.js → log-out-CKq9YiLY.js} +1 -1
  225. package/dist/client/assets/{logging-C6tXZlGQ.js → logging-CCg76rgn.js} +1 -1
  226. package/dist/client/assets/main-Ch0bwS-M.js +9 -0
  227. package/dist/client/assets/main-Di0isH9D.css +2 -0
  228. package/dist/client/assets/{mermaid-parser.core-BiGKtilP.js → mermaid-parser.core-RK9ah5RM.js} +2 -2
  229. package/dist/client/assets/{mermaidEngine-Cjfgf3Bg.js → mermaidEngine-Dr8UsPhH.js} +3 -3
  230. package/dist/client/assets/message-circle-dashed-BrjwqS7-.js +1 -0
  231. package/dist/client/assets/messageQueueDrain-B7R7Qmq6.js +1 -0
  232. package/dist/client/assets/messages-square-cDTkDJv_.js +1 -0
  233. package/dist/client/assets/{mindmap-definition-FAOFIHXS-SiU9JwWJ.js → mindmap-definition-FAOFIHXS-DVudWasx.js} +1 -1
  234. package/dist/client/assets/{packet-AYTQ26CC-F-HuW5Dr.js → packet-AYTQ26CC-DnkTsVhD.js} +1 -1
  235. package/dist/client/assets/{pairingUrl-rQM9kSGT.js → pairingUrl-Dn1e2CVw.js} +1 -1
  236. package/dist/client/assets/panels-top-left-B7jZiLth.js +1 -0
  237. package/dist/client/assets/path-text-3Rfu6lt8.js +1 -0
  238. package/dist/client/assets/{pegDiagram-VL7TDLO6-cC-QUd7I.js → pegDiagram-VL7TDLO6-Do5PIp8B.js} +1 -1
  239. package/dist/client/assets/pencil-Bzg-nc6d.js +1 -0
  240. package/dist/client/assets/{pie-WAS4IAKB-BI3XUcLN.js → pie-WAS4IAKB-B_nNQOzn.js} +1 -1
  241. package/dist/client/assets/{pieDiagram-7S7Q4E2Y-BP4gJ4ZK.js → pieDiagram-7S7Q4E2Y-D_IG4xwA.js} +1 -1
  242. package/dist/client/assets/{play-BJZrOx6T.js → play-DpXXQ1qB.js} +1 -1
  243. package/dist/client/assets/popover-OWEv6cQz.js +48 -0
  244. package/dist/client/assets/presentationTier-DPVAxTK4.js +1 -0
  245. package/dist/client/assets/previewRouteSearch-BjZdTuSf.js +1 -0
  246. package/dist/client/assets/primary-Cf-xJExj.js +4 -0
  247. package/dist/client/assets/primitives-CxTBN7D4.js +1 -0
  248. package/dist/client/assets/projectCheckouts.logic-DUT4AxXr.js +1 -0
  249. package/dist/client/assets/projectPaths-B8aVmOZX.js +1 -0
  250. package/dist/client/assets/projectPreferences-CzWBItFj.js +1 -0
  251. package/dist/client/assets/providerCapabilities-B2YOPsLN.js +1 -0
  252. package/dist/client/assets/providerDriverMeta-BHHL9uw0.js +1 -0
  253. package/dist/client/assets/providerModels-v9PYbzRE.js +1 -0
  254. package/dist/client/assets/providerStatus-CDPaqb0S.js +1 -0
  255. package/dist/client/assets/pullRequestsModel.logic-Dv_om_C4.js +1 -0
  256. package/dist/client/assets/{qr-code-BFO8lV1M.js → qr-code-BlbiBIwH.js} +1 -1
  257. package/dist/client/assets/{qr-code-Cmfz5JKf.js → qr-code-DywzVgQC.js} +1 -1
  258. package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-DO-N1m-q.js → quadrantDiagram-CIZ2JOQS-DY6fJyrM.js} +1 -1
  259. package/dist/client/assets/{radar-RG4KPBEZ-CfayXQ5F.js → radar-RG4KPBEZ-D9689I5m.js} +1 -1
  260. package/dist/client/assets/radio-group-DVwD6Cuy.js +1 -0
  261. package/dist/client/assets/{railroad-74A4TZTK-CT6f-etT.js → railroad-74A4TZTK-DVzWbQnl.js} +1 -1
  262. package/dist/client/assets/railroad-abnf-HS5TGJTU-C_2P6umA.js +1 -0
  263. package/dist/client/assets/railroad-ebnf-LZEXJU2U-aGlR3R3z.js +1 -0
  264. package/dist/client/assets/railroad-peg-WCYAUIDC-DCB9oE8y.js +1 -0
  265. package/dist/client/assets/{railroadDiagram-AXF67PYL-DC8egbob.js → railroadDiagram-AXF67PYL-D1oJ6Jtl.js} +1 -1
  266. package/dist/client/assets/readCache-B7cDPz2O.js +1 -0
  267. package/dist/client/assets/{refresh-cw-K_hU8_ld.js → refresh-cw-CRUTivd6.js} +1 -1
  268. package/dist/client/assets/{requirementDiagram-LRYGKXZP-DJMzcLk_.js → requirementDiagram-LRYGKXZP-7RM8iREp.js} +1 -1
  269. package/dist/client/assets/rotate-ccw-BE2ZCwL6.js +1 -0
  270. package/dist/client/assets/roving-radio-group-NMPWrDqe.js +1 -0
  271. package/dist/client/assets/rows-2-DDS4dGTX.js +1 -0
  272. package/dist/client/assets/runtime-DjjjAcTE.js +18 -0
  273. package/dist/client/assets/safePolygon-C1AzMRS4.js +1 -0
  274. package/dist/client/assets/{sankeyDiagram-W5VNT64P-YR6aIYLj.js → sankeyDiagram-W5VNT64P-C1tKAPGN.js} +1 -1
  275. package/dist/client/assets/{save-Mh-PA_2P.js → save-OZdkPs_y.js} +1 -1
  276. package/dist/client/assets/scroll-area-80P7vbjw.js +1 -0
  277. package/dist/client/assets/{scrollEdges-Zcpuz3un.js → scrollEdges-C0Oc-5qi.js} +1 -1
  278. package/dist/client/assets/select-Cb9FUPHD.js +1 -0
  279. package/dist/client/assets/separator-CO8bC7Wc.js +1 -0
  280. package/dist/client/assets/{sequenceDiagram-SI44F4Z6-BVeSqWDA.js → sequenceDiagram-SI44F4Z6-DGVpb7jL.js} +1 -1
  281. package/dist/client/assets/settings-2-PrRDu6Lc.js +1 -0
  282. package/dist/client/assets/settingsLayout-CRFNCk_D.js +1 -0
  283. package/dist/client/assets/sheet-C5DW7qVO.js +1 -0
  284. package/dist/client/assets/{shield-i098Bm_B.js → shield-CBHYqlkR.js} +1 -1
  285. package/dist/client/assets/{shield-alert-CXmR7fM9.js → shield-alert-Dc2cGwyR.js} +1 -1
  286. package/dist/client/assets/{shield-check-CdFhWT_o.js → shield-check-_wl7R4Js.js} +1 -1
  287. package/dist/client/assets/sidebar-0BBaFNm3.js +1 -0
  288. package/dist/client/assets/sidebarProjectFolders-BjWzbt8C.js +3 -0
  289. package/dist/client/assets/sidebarProjectGrouping-nQRStWrZ.js +1 -0
  290. package/dist/client/assets/sidebarStatusText-BBKuNies.js +1 -0
  291. package/dist/client/assets/sidebarUndo-Dfq1lvyF.js +1 -0
  292. package/dist/client/assets/{skeleton-BwFgUtuE.js → skeleton-DfUe6VV_.js} +1 -1
  293. package/dist/client/assets/sliders-horizontal-BGXkwvKv.js +1 -0
  294. package/dist/client/assets/sliding-tabs-BnDSjRU3.js +39 -0
  295. package/dist/client/assets/{smartphone-DGfizz51.js → smartphone-OEAQOTdv.js} +1 -1
  296. package/dist/client/assets/spinner-lHRJWsym.js +1 -0
  297. package/dist/client/assets/square-B05NKv3e.js +1 -0
  298. package/dist/client/assets/{star-J3x3fktG.js → star-C8mHmfZu.js} +1 -1
  299. package/dist/client/assets/{stateDiagram-OKZ733FA-DoIZN669.js → stateDiagram-OKZ733FA-CCOAegCG.js} +1 -1
  300. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-D60qqBed.js +1 -0
  301. package/dist/client/assets/storeSelectors-BichCKDC.js +1 -0
  302. package/dist/client/assets/surfaceMorph-BTRijmlU.js +1 -0
  303. package/dist/client/assets/{swimlanes-SLNWSIFB-BoFLigyK.js → swimlanes-SLNWSIFB-CFsLYT4h.js} +1 -1
  304. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-D0SaJgSn.js +8 -0
  305. package/dist/client/assets/switch-oQc7Ifbl.js +1 -0
  306. package/dist/client/assets/text-wrap-DSRdSfDm.js +1 -0
  307. package/dist/client/assets/textarea-VyiIZ0wQ.js +1 -0
  308. package/dist/client/assets/threadPriorityRefreshRuntime-H656C1J_.js +1 -0
  309. package/dist/client/assets/ticker-CPutfhZ4.js +1 -0
  310. package/dist/client/assets/{timeline-definition-Z64GVDOM-D65EmNWc.js → timeline-definition-Z64GVDOM-B4agmO7R.js} +1 -1
  311. package/dist/client/assets/toggle-DFqtCPt-.js +1 -0
  312. package/dist/client/assets/toggle-group-C5ICmqkI.js +1 -0
  313. package/dist/client/assets/{tokenModePresentation-C0-NgmX5.js → tokenModePresentation-umDRm4k1.js} +1 -1
  314. package/dist/client/assets/tooltip-DbqhseXd.js +1 -0
  315. package/dist/client/assets/{treeView-Q6P3EWNA-C2S-OPgI.js → treeView-Q6P3EWNA-C_S3udFB.js} +1 -1
  316. package/dist/client/assets/{treemap-WGGIJYW6-6Ovsu9iH.js → treemap-WGGIJYW6-B-kUSAkE.js} +1 -1
  317. package/dist/client/assets/undo-2-lyluTGMW.js +1 -0
  318. package/dist/client/assets/{unplug-BEfcl9Ht.js → unplug-D6iu-qlh.js} +1 -1
  319. package/dist/client/assets/usage-ClF-eUmy.js +1 -0
  320. package/dist/client/assets/useActiveIndicator-R5NWu8Fg.js +1 -0
  321. package/dist/client/assets/useAppSidebarCollapsed-BbMxfio5.js +1 -0
  322. package/dist/client/assets/useAppearancePreference-Ix13pMKy.js +1 -0
  323. package/dist/client/assets/useAtlassian-BYDCc9lv.js +0 -0
  324. package/dist/client/assets/useCheckoutResolution-CR-oOp5-.js +1 -0
  325. package/dist/client/assets/useDesktopRelaunchGuard-Jmh615iZ.js +1 -0
  326. package/dist/client/assets/useDiffFileNavigation-DeuzdD5E.js +15 -0
  327. package/dist/client/assets/useDiffLayout-DhcXwhBL.js +1 -0
  328. package/dist/client/assets/useEnvironmentSettingsTarget-DM6BRDT7.js +1 -0
  329. package/dist/client/assets/useFocus-CV0KIZwg.js +1 -0
  330. package/dist/client/assets/useGit-CUcs7h5_.js +1 -0
  331. package/dist/client/assets/useGitBranchSearch-CeKFtnCL.js +1 -0
  332. package/dist/client/assets/useHostedDraftExecutionTarget-DvQU5UOq.js +1 -0
  333. package/dist/client/assets/useLabelableId-CEgCRi6q.js +1 -0
  334. package/dist/client/assets/useLandingFlash-BfOOlFtW.js +1 -0
  335. package/dist/client/assets/useLogicalProjectSnapshots-CRNZke74.js +1 -0
  336. package/dist/client/assets/useNavigate-sQZthdyT.js +1 -0
  337. package/dist/client/assets/usePageLeadingInsetClass-Bf4nUvx4.js +1 -0
  338. package/dist/client/assets/usePhoneThreadActions-VaQ-mZex.js +1 -0
  339. package/dist/client/assets/usePopupHandleStore-DimKo2Yy.js +1 -0
  340. package/dist/client/assets/usePopupViewport-YeqX_UM3.js +1 -0
  341. package/dist/client/assets/usePresentationTier-B9kCQ4YH.js +1 -0
  342. package/dist/client/assets/useProject-Kt74Z12J.js +1 -0
  343. package/dist/client/assets/useProviderOptionsUpdater-CTzNh2B7.js +2 -0
  344. package/dist/client/assets/usePullRequestFilesViewed-D5Snmzys.js +1 -0
  345. package/dist/client/assets/usePullRequestsModel-DJL5HHbP.js +40 -0
  346. package/dist/client/assets/useScrollLock-CLZ31xsK.js +1 -0
  347. package/dist/client/assets/useSidebarThreadActions-n6EkLATf.js +6 -0
  348. package/dist/client/assets/{useStatistics-D55-xLMz.js → useStatistics-DD0mYS4J.js} +14 -14
  349. package/dist/client/assets/{useTheme-B441xg4F.js → useTheme-Bdy-BDs-.js} +1 -1
  350. package/dist/client/assets/useValueChanged-DoumqMnV.js +1 -0
  351. package/dist/client/assets/{user-round-C-U7TZKG.js → user-round-BPDXr8Gq.js} +1 -1
  352. package/dist/client/assets/{vennDiagram-T6HMQDX7-fZAexcYr.js → vennDiagram-T6HMQDX7-B1UEn_j_.js} +1 -1
  353. package/dist/client/assets/{vscode-icons-BYX6fBsM.js → vscode-icons-Ccy-gzFN.js} +1 -1
  354. package/dist/client/assets/{wardley-WFR3VGLG-gdYWSMxK.js → wardley-WFR3VGLG-gPdyDc-7.js} +1 -1
  355. package/dist/client/assets/{wardleyDiagram-T6FBY63Y-iDJxQb70.js → wardleyDiagram-T6FBY63Y-2aDcwOA4.js} +1 -1
  356. package/dist/client/assets/workspaceLifecycle-OJ1aKksw.js +3 -0
  357. package/dist/client/assets/workspaceMetadataProjection-CyEyJhUa.js +1 -0
  358. package/dist/client/assets/workspaceRouteSearch-CCavUdbH.js +1 -0
  359. package/dist/client/assets/{wrench-D79uBUSl.js → wrench-CPUCA_rn.js} +1 -1
  360. package/dist/client/assets/wsTransport-C88seBPA.js +15 -0
  361. package/dist/client/assets/{xychartDiagram-ELKLHX3M-B4cfMwpJ.js → xychartDiagram-ELKLHX3M-C1_7Q-1i.js} +1 -1
  362. package/dist/client/favicon.svg +1 -1
  363. package/dist/client/index.html +1 -1
  364. package/dist/collectUint8StreamText-BsLSgI8i.mjs +710 -0
  365. package/dist/collectUint8StreamText-D5olwfpM.cjs +757 -0
  366. package/dist/{deviceHostWorker-L8C9wy38.mjs → deviceHostWorker-B-Dn-6An.mjs} +1 -1
  367. package/dist/{deviceHostWorker-CYnrwfrv.cjs → deviceHostWorker-D4HauWIV.cjs} +1 -1
  368. package/dist/{makeManagedServerProvider-CUwxc0Pn.cjs → makeManagedServerProvider-B5tP7tvg.cjs} +2 -2
  369. package/dist/{makeManagedServerProvider-B_lPFNpL.mjs → makeManagedServerProvider-B65ipCxM.mjs} +2 -2
  370. package/dist/resource-monitor/linux-arm64/ryco-resource-monitor +0 -0
  371. package/dist/resource-monitor/ryco-resource-monitor +0 -0
  372. package/dist/resource-monitor/ryco-resource-monitor.exe +0 -0
  373. package/dist/resource-monitor/win32-arm64/ryco-resource-monitor.exe +0 -0
  374. package/dist/resource-monitor/win32-x64/ryco-resource-monitor.exe +0 -0
  375. package/dist/{rolldown-runtime-LGfotAqq.cjs → rolldown-runtime-HbSU0i7K.cjs} +7 -0
  376. package/dist/{runtimeSession-V3RIy8Ao.mjs → runtimeSession-D_BZ-wRH.mjs} +1 -1
  377. package/dist/{src-BzVJd3Me.cjs → src-FmeCeBJ9.cjs} +3408 -308
  378. package/dist/{src-7E1M4gTQ.mjs → src-VTj60bUm.mjs} +2154 -140
  379. package/package.json +1 -1
  380. package/dist/AzureDevOpsSourceControlProvider-DmJD1-WL.cjs +0 -190
  381. package/dist/AzureDevOpsSourceControlProvider-d5Ogsspk.mjs +0 -188
  382. package/dist/GitLabSourceControlProvider-BZdwXdJl.mjs +0 -186
  383. package/dist/GitLabSourceControlProvider-CrcBR6KQ.cjs +0 -188
  384. package/dist/client/assets/AccountSettings-FN7pwqYA.js +0 -1
  385. package/dist/client/assets/AiFocusSettings-xcDAMaqH.js +0 -1
  386. package/dist/client/assets/AppearanceSettings-BvsvAOsG.js +0 -1
  387. package/dist/client/assets/BranchToolbar.logic-DFsXV3Qs.js +0 -3
  388. package/dist/client/assets/BrowserPanel-D-g_xDZs.js +0 -1
  389. package/dist/client/assets/ChatRightPanel-Bm906qNi.js +0 -201
  390. package/dist/client/assets/ChatThreadRouteView-CATwakjI.js +0 -1
  391. package/dist/client/assets/CommandPaletteDialog-Obv1bvxj.js +0 -1
  392. package/dist/client/assets/CompositeRoot-CfkIdky8.js +0 -1
  393. package/dist/client/assets/ComputerUseSettings-ljYmTHea.js +0 -1
  394. package/dist/client/assets/ConnectionsSettings-CIXs7x_E.js +0 -7
  395. package/dist/client/assets/ContextHandoffEndpointLabel-BzI4Wi1i.js +0 -4
  396. package/dist/client/assets/DiagnosticsSettings-DGX_2T2M.js +0 -2
  397. package/dist/client/assets/DialogHandle-CTtSYpsC.js +0 -1
  398. package/dist/client/assets/DialogRoot-k2_0SNKA.js +0 -1
  399. package/dist/client/assets/DialogTitle-Du7CAbaO.js +0 -1
  400. package/dist/client/assets/DialogTrigger-VpFh8Xza.js +0 -1
  401. package/dist/client/assets/DraftChatThreadRouteView-Cmc5HpWf.js +0 -1
  402. package/dist/client/assets/GlassSurface-BlWIlQ0s.js +0 -1
  403. package/dist/client/assets/HostedConnectionControls-ySHqwr4K.js +0 -1
  404. package/dist/client/assets/HostedHubRoot-Caz8PElK.js +0 -2
  405. package/dist/client/assets/HostedNodeRenameDialog-ChxJdr-Z.js +0 -1
  406. package/dist/client/assets/HostedRelayTrustNotice-DPVrIfj_.js +0 -1
  407. package/dist/client/assets/IntegrationsSettingsPanel-eAq5h-D5.js +0 -2
  408. package/dist/client/assets/KeybindingsSettings-D1XaEVGH.js +0 -7
  409. package/dist/client/assets/LazyBrowserPanel-B6POLJh3.js +0 -2
  410. package/dist/client/assets/McpServersSettings-DqLA6n5v.js +0 -6
  411. package/dist/client/assets/MobileSheet-CtQIYRlY.js +0 -1
  412. package/dist/client/assets/NodeSecuritySettings-Skm7GQDl.js +0 -1
  413. package/dist/client/assets/NullStore-b8PhjwPZ.js +0 -1
  414. package/dist/client/assets/OnboardingDialog-8-fKvY5H.js +0 -1
  415. package/dist/client/assets/OpinionatedPluginsSettings-BIJfJ34L.js +0 -1
  416. package/dist/client/assets/PhoneHome-CUzxhhR4.js +0 -1
  417. package/dist/client/assets/PhoneSettingsSurface-BK2RHmYJ.js +0 -2
  418. package/dist/client/assets/ProvidersSettingsPanel-DPxL7AsR.js +0 -1
  419. package/dist/client/assets/RedactedSensitiveText-DH4mWpB6.js +0 -1
  420. package/dist/client/assets/RootAppShell-DwiWD4Cy.js +0 -7
  421. package/dist/client/assets/SettingsDialog-CE8qy0qL.js +0 -2
  422. package/dist/client/assets/SettingsPanels-BYknk6GO.js +0 -3
  423. package/dist/client/assets/SettingsPanels.editor-64bM0lhg.js +0 -2
  424. package/dist/client/assets/SourceControlSettings-BbveiAj3.js +0 -1
  425. package/dist/client/assets/StatisticsPage-CAO_tCeC.js +0 -1
  426. package/dist/client/assets/StatisticsPanel-SNlgMv2o.js +0 -1
  427. package/dist/client/assets/StatisticsSettingsLink-BpkNubL2.js +0 -1
  428. package/dist/client/assets/ThreadTerminalDrawer-9x_kqQPy.js +0 -18
  429. package/dist/client/assets/ThreadWorkspacePanel-BXE17C4x.js +0 -2073
  430. package/dist/client/assets/appChrome-B_VWWDFj.js +0 -1
  431. package/dist/client/assets/architecture-7GRP2DOG-CQNNG5gU.js +0 -1
  432. package/dist/client/assets/authorization-BugIGt5e.js +0 -1
  433. package/dist/client/assets/badge-BswOCwph.js +0 -1
  434. package/dist/client/assets/capabilities-Bj_X9FZ-.js +0 -1
  435. package/dist/client/assets/channel-BtX-w3CK.js +0 -1
  436. package/dist/client/assets/chevron-right-Ddq5gL-L.js +0 -1
  437. package/dist/client/assets/classDiagram-JCYQIIEL-BgDa3HFl.js +0 -1
  438. package/dist/client/assets/classDiagram-v2-OCEON4UE-BgDa3HFl.js +0 -1
  439. package/dist/client/assets/compiler-runtime-C4g8XhC5.js +0 -1
  440. package/dist/client/assets/desktopWorkspace-Ocqt625W.js +0 -1
  441. package/dist/client/assets/editorPreferences-DVhg0CXd.js +0 -1
  442. package/dist/client/assets/eventmodeling-NTZA5JFV-DpzGHjmu.js +0 -1
  443. package/dist/client/assets/flowDiagram-UKHOOZJN-CaDVMm72.js +0 -1
  444. package/dist/client/assets/hostedConnectionCoordinator-BztHfGNt.js +0 -1
  445. package/dist/client/assets/hostedPairing-CqhLPQqG.js +0 -1
  446. package/dist/client/assets/hubRoutes-DExWSvVE.js +0 -1
  447. package/dist/client/assets/kbd-DKuvGqFP.js +0 -1
  448. package/dist/client/assets/layers-CwP65mnC.js +0 -1
  449. package/dist/client/assets/liquidGlass-CA2o_Cq0.js +0 -1
  450. package/dist/client/assets/liquidGlass.worker-icvLJKHf.js +0 -1
  451. package/dist/client/assets/main-BqSANuAs.css +0 -2
  452. package/dist/client/assets/main-RFllWEko.js +0 -9
  453. package/dist/client/assets/motion-C9rN_t9p.js +0 -1
  454. package/dist/client/assets/palette-gaqgtube.js +0 -1
  455. package/dist/client/assets/perfInstrumentation-BT27w4tn.js +0 -1
  456. package/dist/client/assets/presentationTier-xlIjcFab.js +0 -1
  457. package/dist/client/assets/primary-CQh_KHGG.js +0 -5
  458. package/dist/client/assets/providerDriverMeta-LJ2vJxm-.js +0 -1
  459. package/dist/client/assets/providerStatus-DBGvvkyF.js +0 -1
  460. package/dist/client/assets/radio-group-BueX1AVO.js +0 -1
  461. package/dist/client/assets/railroad-abnf-HS5TGJTU-B890iayj.js +0 -1
  462. package/dist/client/assets/railroad-ebnf-LZEXJU2U-C079Tzw6.js +0 -1
  463. package/dist/client/assets/railroad-peg-WCYAUIDC-DxvOX5Rh.js +0 -1
  464. package/dist/client/assets/runtime-OM-uAtaj.js +0 -18
  465. package/dist/client/assets/scroll-area-BC-LB_zE.js +0 -1
  466. package/dist/client/assets/separator-yx1r9ZDw.js +0 -1
  467. package/dist/client/assets/settingsLayout-BbjDM-p0.js +0 -1
  468. package/dist/client/assets/sheet-CpEwjOWn.js +0 -1
  469. package/dist/client/assets/sidebar-DayQTDZp.js +0 -1
  470. package/dist/client/assets/sidebarProjectFolders-DXqx3OlZ.js +0 -4
  471. package/dist/client/assets/sidebarStatusText-kdA6QMZS.js +0 -1
  472. package/dist/client/assets/sidebarUndo-BHFfJj0k.js +0 -1
  473. package/dist/client/assets/square-Cd2WS1gv.js +0 -1
  474. package/dist/client/assets/src-DHNjfMxR.js +0 -14
  475. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-BnzsGHaN.js +0 -1
  476. package/dist/client/assets/storeSelectors-D60AAN01.js +0 -1
  477. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-BnA-oDvU.js +0 -8
  478. package/dist/client/assets/switch-D9inWKdd.js +0 -48
  479. package/dist/client/assets/toggle-group-YNqzWsK0.js +0 -1
  480. package/dist/client/assets/toggle-wMq3LLn1.js +0 -1
  481. package/dist/client/assets/tooltip-mwOCSCXF.js +0 -1
  482. package/dist/client/assets/usage-DF8oQrsy.js +0 -1
  483. package/dist/client/assets/useAppSidebarCollapsed-C0jpPtER.js +0 -1
  484. package/dist/client/assets/useAppearancePreference-Dlh9P8iu.js +0 -1
  485. package/dist/client/assets/useBaseUiId-Bz8dcyjd.js +0 -1
  486. package/dist/client/assets/useLabelableId-C8bc9a0F.js +0 -1
  487. package/dist/client/assets/useNavigate-01O5dMQe.js +0 -1
  488. package/dist/client/assets/usePhoneThreadActions-BIdh81kF.js +0 -1
  489. package/dist/client/assets/usePopupViewport-DYYZwfTW.js +0 -1
  490. package/dist/client/assets/usePresentationTier-hxB7Yv_Q.js +0 -1
  491. package/dist/client/assets/useScrollLock-BO185DkJ.js +0 -1
  492. package/dist/client/assets/useTriggerFocusGuards-CMLVr18J.js +0 -1
  493. package/dist/client/assets/useValueChanged-DSyRHPje.js +0 -1
  494. package/dist/client/assets/workspaceMetadataProjection-So9-wSEZ.js +0 -1
  495. package/dist/collectUint8StreamText-BAUF-vzz.mjs +0 -37
  496. package/dist/collectUint8StreamText-vagpNUMJ.cjs +0 -42
  497. package/dist/git-BKwGfw8A.mjs +0 -132
  498. package/dist/git-Dn5wrgFY.cjs +0 -218
  499. package/dist/sourceControl-B0D1Op29.cjs +0 -253
  500. package/dist/sourceControl-BiEBxN01.mjs +0 -224
@@ -0,0 +1,2260 @@
1
+ #!/usr/bin/env node
2
+
3
+ const require_src = require("./src-FmeCeBJ9.cjs");
4
+ const require_bin = require("./bin.cjs");
5
+ let effect = require("effect");
6
+ let node_crypto = require("node:crypto");
7
+ //#region src/sourceControl/gitLabMergeRequestDiffs.ts
8
+ /**
9
+ * GitLab file diffs (merge request `/diffs`, commit `/diff`) and the line
10
+ * arithmetic GitLab positions need. Pure and side-effect free.
11
+ *
12
+ * Docs:
13
+ * - https://docs.gitlab.com/api/merge_requests/#list-merge-request-diffs
14
+ * - https://docs.gitlab.com/api/commits/#retrieve-commit-diff
15
+ * - https://docs.gitlab.com/api/discussions/#create-a-new-thread-in-the-merge-request-diff
16
+ * (unchanged lines need both `old_line` and `new_line`; line codes are
17
+ * `<sha1(path)>_<old>_<new>`)
18
+ */
19
+ const GitLabDiffEntrySchema = effect.Schema.Struct({
20
+ old_path: effect.Schema.String,
21
+ new_path: effect.Schema.String,
22
+ a_mode: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
23
+ b_mode: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
24
+ diff: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
25
+ new_file: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
26
+ renamed_file: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
27
+ deleted_file: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
28
+ collapsed: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
29
+ too_large: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean))
30
+ });
31
+ /** GitLab's `DiffFile#file_path`: the new path, or the old one when there is none. */
32
+ function gitLabDiffFilePath(entry) {
33
+ return entry.new_path || entry.old_path;
34
+ }
35
+ function findGitLabDiffEntry(entries, path) {
36
+ return entries.find((entry) => entry.new_path === path) ?? entries.find((entry) => entry.old_path === path);
37
+ }
38
+ /**
39
+ * Rebuild a git-style unified diff from GitLab's per-file JSON. GitLab sends
40
+ * only the hunks, so the `diff --git` / mode / rename / `---` `+++` headers are
41
+ * restored here; a file without hunk text (binary, too large, pure rename or
42
+ * mode change) keeps only its extended headers, as `git diff` prints them.
43
+ */
44
+ function buildGitLabUnifiedDiff(entries) {
45
+ const out = [];
46
+ for (const entry of entries) {
47
+ const oldPath = entry.old_path || entry.new_path;
48
+ const newPath = entry.new_path || entry.old_path;
49
+ out.push(`diff --git a/${oldPath} b/${newPath}`);
50
+ if (entry.new_file === true) out.push(`new file mode ${entry.b_mode || "100644"}`);
51
+ else if (entry.deleted_file === true) out.push(`deleted file mode ${entry.a_mode || "100644"}`);
52
+ else if (entry.a_mode && entry.b_mode && entry.a_mode !== entry.b_mode) out.push(`old mode ${entry.a_mode}`, `new mode ${entry.b_mode}`);
53
+ if (entry.renamed_file === true && oldPath !== newPath) out.push(`rename from ${oldPath}`, `rename to ${newPath}`);
54
+ const body = entry.diff ?? "";
55
+ if (body.trim().length === 0) continue;
56
+ out.push(entry.new_file === true ? "--- /dev/null" : `--- a/${oldPath}`);
57
+ out.push(entry.deleted_file === true ? "+++ /dev/null" : `+++ b/${newPath}`);
58
+ out.push(body.endsWith("\n") ? body.slice(0, -1) : body);
59
+ }
60
+ return out.length === 0 ? "" : `${out.join("\n")}\n`;
61
+ }
62
+ const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/u;
63
+ function parseGitLabDiffHunks(diff) {
64
+ const hunks = [];
65
+ const rows = diff.split("\n");
66
+ if (rows.at(-1) === "") rows.pop();
67
+ let current = null;
68
+ const flush = () => {
69
+ if (current) {
70
+ const { oldPos: _oldPos, newPos: _newPos, ...hunk } = current;
71
+ hunks.push(hunk);
72
+ }
73
+ };
74
+ for (const row of rows) {
75
+ const header = HUNK_HEADER.exec(row);
76
+ if (header) {
77
+ flush();
78
+ const oldStart = Number(header[1]);
79
+ const newStart = Number(header[3]);
80
+ current = {
81
+ header: row,
82
+ oldStart,
83
+ oldCount: header[2] === void 0 ? 1 : Number(header[2]),
84
+ newStart,
85
+ newCount: header[4] === void 0 ? 1 : Number(header[4]),
86
+ rawLines: [],
87
+ lines: [],
88
+ oldPos: oldStart,
89
+ newPos: newStart
90
+ };
91
+ continue;
92
+ }
93
+ if (!current) continue;
94
+ const rawIndex = current.rawLines.length;
95
+ current.rawLines.push(row);
96
+ const marker = row[0];
97
+ if (marker === "\\") continue;
98
+ if (marker === "+") {
99
+ current.lines.push({
100
+ kind: "added",
101
+ oldPos: current.oldPos,
102
+ newPos: current.newPos,
103
+ rawIndex
104
+ });
105
+ current.newPos += 1;
106
+ } else if (marker === "-") {
107
+ current.lines.push({
108
+ kind: "removed",
109
+ oldPos: current.oldPos,
110
+ newPos: current.newPos,
111
+ rawIndex
112
+ });
113
+ current.oldPos += 1;
114
+ } else {
115
+ current.lines.push({
116
+ kind: "context",
117
+ oldPos: current.oldPos,
118
+ newPos: current.newPos,
119
+ rawIndex
120
+ });
121
+ current.oldPos += 1;
122
+ current.newPos += 1;
123
+ }
124
+ }
125
+ flush();
126
+ return hunks;
127
+ }
128
+ function lineMatches(line, side, number) {
129
+ return side === "left" ? line.kind !== "added" && line.oldPos === number : line.kind !== "removed" && line.newPos === number;
130
+ }
131
+ function gitLabLineCode(filePath, oldPos, newPos) {
132
+ return `${(0, node_crypto.createHash)("sha1").update(filePath).digest("hex")}_${oldPos}_${newPos}`;
133
+ }
134
+ /**
135
+ * Anchor `line` on `side` of a file's diff. Lines inside a hunk take their
136
+ * hunk position; unchanged lines between hunks (expanded context) are
137
+ * shifted by the hunks before them. Null when the line is not in the file.
138
+ */
139
+ function resolveGitLabLineAnchor(entry, side, line) {
140
+ const filePath = gitLabDiffFilePath(entry);
141
+ const hunks = parseGitLabDiffHunks(entry.diff ?? "");
142
+ let delta = 0;
143
+ for (const hunk of hunks) {
144
+ const start = side === "left" ? hunk.oldStart : hunk.newStart;
145
+ const count = side === "left" ? hunk.oldCount : hunk.newCount;
146
+ const first = count === 0 ? start + 1 : start;
147
+ if (line < first) break;
148
+ if (line < first + count) {
149
+ const found = hunk.lines.find((candidate) => lineMatches(candidate, side, line));
150
+ return found ? {
151
+ kind: found.kind,
152
+ oldLine: found.kind === "added" ? null : found.oldPos,
153
+ newLine: found.kind === "removed" ? null : found.newPos,
154
+ lineCode: gitLabLineCode(filePath, found.oldPos, found.newPos)
155
+ } : null;
156
+ }
157
+ delta += hunk.newCount - hunk.oldCount;
158
+ }
159
+ if (entry.new_file === true || entry.deleted_file === true) return null;
160
+ const oldLine = side === "left" ? line : line - delta;
161
+ const newLine = side === "left" ? line + delta : line;
162
+ if (oldLine < 1 || newLine < 1) return null;
163
+ return {
164
+ kind: "context",
165
+ oldLine,
166
+ newLine,
167
+ lineCode: gitLabLineCode(filePath, oldLine, newLine)
168
+ };
169
+ }
170
+ /**
171
+ * The hunk excerpt a thread was written against (as GitHub's `diffHunk`):
172
+ * the hunk header and its lines up to and including the commented line.
173
+ */
174
+ function gitLabDiffHunkExcerpt(entry, side, line) {
175
+ for (const hunk of parseGitLabDiffHunks(entry.diff ?? "")) {
176
+ const found = hunk.lines.find((candidate) => lineMatches(candidate, side, line));
177
+ if (found) return [hunk.header, ...hunk.rawLines.slice(0, found.rawIndex + 1)].join("\n");
178
+ }
179
+ return null;
180
+ }
181
+ function rangePoint(anchor) {
182
+ return {
183
+ line_code: anchor.lineCode,
184
+ type: anchor.kind === "added" ? "new" : "old",
185
+ ...anchor.oldLine !== null ? { old_line: anchor.oldLine } : {},
186
+ ...anchor.newLine !== null ? { new_line: anchor.newLine } : {}
187
+ };
188
+ }
189
+ /**
190
+ * `POST .../draft_notes` body for one review comment, anchored to the diff
191
+ * the reviewer saw (`diffRefs` must be the head they reviewed).
192
+ * Docs: https://docs.gitlab.com/api/draft_notes/#create-a-draft-note
193
+ */
194
+ function buildGitLabDraftNoteBody(input) {
195
+ const { comment, diffRefs } = input;
196
+ const entry = findGitLabDiffEntry(input.entries, comment.path);
197
+ if (!entry) return effect.Result.fail(`${comment.path} is not part of this merge request's diff.`);
198
+ const shas = {
199
+ base_sha: diffRefs.base_sha,
200
+ start_sha: diffRefs.start_sha,
201
+ head_sha: diffRefs.head_sha,
202
+ old_path: entry.old_path,
203
+ new_path: entry.new_path
204
+ };
205
+ if (comment.subjectType === "file") return effect.Result.succeed({
206
+ note: comment.body,
207
+ position: {
208
+ position_type: "file",
209
+ ...shas
210
+ }
211
+ });
212
+ if (comment.line === void 0) return effect.Result.fail(`The line comment on ${comment.path} is missing its line number.`);
213
+ const side = comment.side ?? "right";
214
+ const anchor = resolveGitLabLineAnchor(entry, side, comment.line);
215
+ if (!anchor) return effect.Result.fail(`Line ${comment.line} of ${comment.path} is not part of this merge request's diff.`);
216
+ const startSide = comment.startSide ?? side;
217
+ const isRange = comment.startLine !== void 0 && (comment.startLine !== comment.line || startSide !== side);
218
+ let lineRange;
219
+ if (isRange && comment.startLine !== void 0) {
220
+ const start = resolveGitLabLineAnchor(entry, startSide, comment.startLine);
221
+ if (!start) return effect.Result.fail(`Line ${comment.startLine} of ${comment.path} is not part of this merge request's diff.`);
222
+ lineRange = {
223
+ start: rangePoint(start),
224
+ end: rangePoint(anchor)
225
+ };
226
+ }
227
+ return effect.Result.succeed({
228
+ note: comment.body,
229
+ position: {
230
+ position_type: "text",
231
+ ...shas,
232
+ ...anchor.oldLine !== null ? { old_line: anchor.oldLine } : {},
233
+ ...anchor.newLine !== null ? { new_line: anchor.newLine } : {},
234
+ ...lineRange ? { line_range: lineRange } : {}
235
+ }
236
+ });
237
+ }
238
+ /** Thread openers by one author this close together came from one published review. */
239
+ const REVIEW_BATCH_WINDOW_MS = 6e4;
240
+ const GitLabLineRangePointSchema = effect.Schema.Struct({
241
+ line_code: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
242
+ type: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
243
+ old_line: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
244
+ new_line: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number))
245
+ });
246
+ const GitLabPositionSchema = effect.Schema.Struct({
247
+ base_sha: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
248
+ start_sha: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
249
+ head_sha: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
250
+ old_path: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
251
+ new_path: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
252
+ position_type: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
253
+ old_line: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
254
+ new_line: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
255
+ line_range: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Struct({
256
+ start: effect.Schema.optional(effect.Schema.NullOr(GitLabLineRangePointSchema)),
257
+ end: effect.Schema.optional(effect.Schema.NullOr(GitLabLineRangePointSchema))
258
+ })))
259
+ });
260
+ const GitLabNoteSchema = effect.Schema.Struct({
261
+ id: effect.Schema.Number,
262
+ type: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
263
+ body: effect.Schema.String,
264
+ author: effect.Schema.optional(effect.Schema.NullOr(require_bin.GitLabUserRefSchema)),
265
+ created_at: effect.Schema.String,
266
+ updated_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
267
+ system: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
268
+ position: effect.Schema.optional(effect.Schema.NullOr(GitLabPositionSchema)),
269
+ resolvable: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
270
+ resolved: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
271
+ resolved_by: effect.Schema.optional(effect.Schema.NullOr(require_bin.GitLabUserRefSchema)),
272
+ internal: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean))
273
+ });
274
+ const GitLabDiscussionSchema = effect.Schema.Struct({
275
+ id: effect.Schema.String,
276
+ individual_note: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
277
+ resolvable: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
278
+ resolved: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
279
+ notes: effect.Schema.Array(GitLabNoteSchema)
280
+ });
281
+ const GitLabStateEventSchema = effect.Schema.Struct({
282
+ id: effect.Schema.Number,
283
+ user: effect.Schema.optional(effect.Schema.NullOr(require_bin.GitLabUserRefSchema)),
284
+ created_at: effect.Schema.String,
285
+ state: effect.Schema.String
286
+ });
287
+ const GitLabLabelEventSchema = effect.Schema.Struct({
288
+ id: effect.Schema.Number,
289
+ user: effect.Schema.optional(effect.Schema.NullOr(require_bin.GitLabUserRefSchema)),
290
+ created_at: effect.Schema.String,
291
+ action: effect.Schema.String,
292
+ label: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Struct({
293
+ name: effect.Schema.String,
294
+ color: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
295
+ description: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
296
+ })))
297
+ });
298
+ const GitLabCommitSchema = effect.Schema.Struct({
299
+ id: effect.Schema.String,
300
+ short_id: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
301
+ title: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
302
+ message: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
303
+ author_name: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
304
+ authored_date: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
305
+ committed_date: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
306
+ created_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
307
+ });
308
+ const GitLabVersionSchema = effect.Schema.Struct({
309
+ id: effect.Schema.Number,
310
+ head_commit_sha: effect.Schema.String,
311
+ base_commit_sha: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
312
+ start_commit_sha: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
313
+ created_at: effect.Schema.String
314
+ });
315
+ const GitLabDraftNoteSchema = effect.Schema.Struct({
316
+ id: effect.Schema.Number,
317
+ author_id: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
318
+ note: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
319
+ });
320
+ const GitLabCurrentUserSchema = effect.Schema.Struct({
321
+ id: effect.Schema.Number,
322
+ username: effect.Schema.String,
323
+ avatar_url: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
324
+ bot: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean))
325
+ });
326
+ const isTimelineItem = effect.Schema.is(require_src.ChangeRequestTimelineItem);
327
+ const isReviewThread = effect.Schema.is(require_src.ChangeRequestReviewThread);
328
+ function trimmed$1(value) {
329
+ const text = value?.trim() ?? "";
330
+ return text.length > 0 ? text : null;
331
+ }
332
+ function positiveInt(value) {
333
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
334
+ }
335
+ function gitLabActor(user) {
336
+ const login = trimmed$1(user?.username);
337
+ if (!login) return null;
338
+ const avatarUrl = trimmed$1(user?.avatar_url);
339
+ return {
340
+ login,
341
+ ...avatarUrl ? { avatarUrl } : {},
342
+ ...user?.bot === true ? { isBot: true } : {}
343
+ };
344
+ }
345
+ const HTML_ENTITIES = {
346
+ amp: "&",
347
+ lt: "<",
348
+ gt: ">",
349
+ quot: "\"",
350
+ apos: "'",
351
+ nbsp: " "
352
+ };
353
+ function decodeHtmlEntities(text) {
354
+ return text.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/giu, (match, entity) => {
355
+ if (entity.startsWith("#x") || entity.startsWith("#X")) return String.fromCodePoint(Number.parseInt(entity.slice(2), 16));
356
+ if (entity.startsWith("#")) return String.fromCodePoint(Number(entity.slice(1)));
357
+ return HTML_ENTITIES[entity.toLowerCase()] ?? match;
358
+ });
359
+ }
360
+ /** System notes are Markdown or (newer GitLab) HTML; compare them as plain text. */
361
+ function gitLabSystemNoteText(body) {
362
+ return decodeHtmlEntities(body.replace(/<[^>]*>/gu, "")).replace(/\*\*/gu, "").replace(/\s+/gu, " ").trim();
363
+ }
364
+ /** Strip GitLab's inline-diff markers (`{-old-}`, `{+new+}`) from a title. */
365
+ function stripInlineDiffMarkers(text) {
366
+ return text.replace(/\{[-+]|[-+]\}/gu, "");
367
+ }
368
+ /** The two titles of a "changed title from … to …" note, HTML or Markdown form. */
369
+ function parseGitLabTitleChange(body) {
370
+ const html = [...body.matchAll(/<code[^>]*class="idiff"[^>]*>([\s\S]*?)<\/code>/giu)];
371
+ if (html.length >= 2 && html[0]?.[1] !== void 0 && html[1]?.[1] !== void 0) return {
372
+ previousTitle: decodeHtmlEntities(html[0][1].replace(/<[^>]*>/gu, "")).trim(),
373
+ currentTitle: decodeHtmlEntities(html[1][1].replace(/<[^>]*>/gu, "")).trim()
374
+ };
375
+ const markdown = /changed title from \*\*([\s\S]*)\*\* to \*\*([\s\S]*)\*\*\s*$/u.exec(body.trim());
376
+ if (markdown?.[1] !== void 0 && markdown[2] !== void 0) return {
377
+ previousTitle: stripInlineDiffMarkers(markdown[1]).trim(),
378
+ currentTitle: stripInlineDiffMarkers(markdown[2]).trim()
379
+ };
380
+ return null;
381
+ }
382
+ /** `@user` mentions in one clause of a system note. */
383
+ function mentionedUsers(text) {
384
+ return [...text.matchAll(/@([\w.-]+)/gu)].flatMap((match) => match[1] ? [match[1].replace(/\.+$/u, "")] : []);
385
+ }
386
+ /** Split "requested review from @a and removed review request for @b" into its clauses. */
387
+ function clauses(text, phrases) {
388
+ const lower = text.toLowerCase();
389
+ const found = phrases.flatMap((phrase) => {
390
+ const index = lower.indexOf(phrase);
391
+ return index >= 0 ? [{
392
+ phrase,
393
+ index
394
+ }] : [];
395
+ }).toSorted((left, right) => left.index - right.index);
396
+ return found.map((entry, position) => {
397
+ const end = found[position + 1]?.index ?? text.length;
398
+ return {
399
+ phrase: entry.phrase,
400
+ users: mentionedUsers(text.slice(entry.index + entry.phrase.length, end))
401
+ };
402
+ });
403
+ }
404
+ function projectWebUrl(mergeRequestUrl) {
405
+ const index = mergeRequestUrl.indexOf("/-/merge_requests/");
406
+ return index > 0 ? mergeRequestUrl.slice(0, index) : null;
407
+ }
408
+ function crossReference(text, mergeRequestUrl) {
409
+ const match = /^mentioned in (merge request|issue) ([\w./-]*?)([!#])(\d+)$/u.exec(text);
410
+ const number = match?.[4] ? positiveInt(Number(match[4])) : null;
411
+ const projectUrl = projectWebUrl(mergeRequestUrl);
412
+ if (!match || number === null || !projectUrl) return null;
413
+ const kind = match[1] === "merge request" ? "change-request" : "issue";
414
+ const repository = trimmed$1(match[2]);
415
+ return {
416
+ kind,
417
+ number,
418
+ url: `${repository ? `${new URL(projectUrl).origin}/${repository}` : projectUrl}/-/${kind === "change-request" ? "merge_requests" : "issues"}/${number}`,
419
+ ...repository ? { repository } : {}
420
+ };
421
+ }
422
+ /**
423
+ * One system note as timeline items. GitLab writes system notes as prose, so
424
+ * only its documented, stable phrasings are recognised; anything else is
425
+ * dropped rather than guessed at. State and label changes come from their
426
+ * resource-event APIs, commits from the commit list, so their notes drop too.
427
+ */
428
+ function gitLabSystemNoteItems(note, context) {
429
+ const createdAt = require_bin.parseGitLabTimestamp(note.created_at);
430
+ if (!createdAt) return [];
431
+ const actor = gitLabActor(note.author);
432
+ const base = {
433
+ createdAt,
434
+ ...actor ? { actor } : {}
435
+ };
436
+ const id = `note:${note.id}`;
437
+ const text = gitLabSystemNoteText(note.body);
438
+ const lower = text.toLowerCase();
439
+ if (lower.startsWith("changed title from")) {
440
+ const titles = parseGitLabTitleChange(note.body);
441
+ return titles ? [{
442
+ ...base,
443
+ id,
444
+ kind: "renamed",
445
+ ...titles
446
+ }] : [];
447
+ }
448
+ if (lower === "marked this merge request as draft" || lower === "marked as a work in progress" || lower === "marked this merge request as a draft") return [{
449
+ ...base,
450
+ id,
451
+ kind: "converted-to-draft"
452
+ }];
453
+ if (lower === "marked this merge request as ready" || lower === "unmarked as a work in progress") return [{
454
+ ...base,
455
+ id,
456
+ kind: "ready-for-review"
457
+ }];
458
+ if (lower.startsWith("requested review from") || lower.startsWith("removed review request for")) return clauses(text, ["requested review from", "removed review request for"]).flatMap((clause) => clause.users.map((reviewer) => ({
459
+ ...base,
460
+ id: `${id}:${clause.phrase === "requested review from" ? "review-requested" : "review-request-removed"}:${reviewer}`,
461
+ kind: clause.phrase === "requested review from" ? "review-requested" : "review-request-removed",
462
+ reviewer,
463
+ reviewerKind: "user"
464
+ })));
465
+ if (lower.startsWith("assigned to") || lower.startsWith("unassigned")) return clauses(text, ["assigned to", "unassigned"]).flatMap((clause) => clause.users.map((assignee) => ({
466
+ ...base,
467
+ id: `${id}:${clause.phrase === "assigned to" ? "assigned" : "unassigned"}:${assignee}`,
468
+ kind: clause.phrase === "assigned to" ? "assigned" : "unassigned",
469
+ assignee
470
+ })));
471
+ if (lower === "approved this merge request") return [{
472
+ ...base,
473
+ id,
474
+ kind: "review",
475
+ state: "approved",
476
+ body: "",
477
+ threadIds: []
478
+ }];
479
+ if (lower === "requested changes") return [{
480
+ ...base,
481
+ id,
482
+ kind: "review",
483
+ state: "changes_requested",
484
+ body: "",
485
+ threadIds: []
486
+ }];
487
+ if (lower === "unapproved this merge request" || lower.startsWith("revoked approval for this merge request")) return actor ? [{
488
+ ...base,
489
+ id,
490
+ kind: "review-dismissed",
491
+ reviewAuthor: actor.login
492
+ }] : [];
493
+ if (lower.startsWith("reset approvals from")) {
494
+ const dismissed = [];
495
+ for (const reviewAuthor of mentionedUsers(text)) dismissed.push({
496
+ ...base,
497
+ id: `${id}:review-dismissed:${reviewAuthor}`,
498
+ kind: "review-dismissed",
499
+ reviewAuthor,
500
+ message: "Approvals reset by a push to the branch."
501
+ });
502
+ return dismissed;
503
+ }
504
+ if (/^enabled (?:an )?automatic (?:merge|add to merge train)/u.test(lower)) return [{
505
+ ...base,
506
+ id,
507
+ kind: "auto-merge-enabled"
508
+ }];
509
+ if (/^(?:canceled|cancelled|aborted) (?:the )?automatic (?:merge|add to merge train)/u.test(lower)) return [{
510
+ ...base,
511
+ id,
512
+ kind: "auto-merge-disabled"
513
+ }];
514
+ const target = /^changed target branch from `?(.+?)`? to `?(.+?)`?$/u.exec(text);
515
+ if (target?.[1] && target[2]) return [{
516
+ ...base,
517
+ id,
518
+ kind: "base-ref-changed",
519
+ previousRefName: target[1],
520
+ currentRefName: target[2]
521
+ }];
522
+ const reference = crossReference(text, context.mergeRequestUrl);
523
+ if (reference) return [{
524
+ ...base,
525
+ id,
526
+ kind: "cross-referenced",
527
+ source: {
528
+ ...reference,
529
+ title: ""
530
+ }
531
+ }];
532
+ return [];
533
+ }
534
+ /** Commits a push note ("added 2 commits … <li>abc123 - …") credits to its author. */
535
+ function gitLabPushedCommitPrefixes(note) {
536
+ const text = gitLabSystemNoteText(note.body);
537
+ if (!/^added \d+ (?:new )?commits?/iu.test(text)) return [];
538
+ return [...note.body.matchAll(/<li>\s*([0-9a-f]{7,40})\s+-/giu)].flatMap((match) => match[1] ? [match[1].toLowerCase()] : []);
539
+ }
540
+ function noteComment(note, context) {
541
+ const createdAt = require_bin.parseGitLabTimestamp(note.created_at);
542
+ if (!createdAt) return null;
543
+ const updatedAt = require_bin.parseGitLabTimestamp(note.updated_at);
544
+ const own = context.viewerId !== null && note.author?.id === context.viewerId;
545
+ return {
546
+ id: String(note.id),
547
+ author: gitLabActor(note.author) ?? { login: "ghost" },
548
+ body: note.body,
549
+ createdAt,
550
+ ...updatedAt && effect.DateTime.toEpochMillis(updatedAt) !== effect.DateTime.toEpochMillis(createdAt) ? { updatedAt } : {},
551
+ url: `${context.mergeRequestUrl}#note_${note.id}`,
552
+ state: "submitted",
553
+ viewerCanUpdate: own,
554
+ viewerCanDelete: own
555
+ };
556
+ }
557
+ function lineOf(point) {
558
+ const newLine = positiveInt(point.new_line);
559
+ if (newLine !== null) return {
560
+ side: "right",
561
+ line: newLine
562
+ };
563
+ const oldLine = positiveInt(point.old_line);
564
+ return oldLine !== null ? {
565
+ side: "left",
566
+ line: oldLine
567
+ } : null;
568
+ }
569
+ /**
570
+ * A discussion with a diff position as a review thread. Positions follow the
571
+ * merge request across pushes: GitLab moves a note's `position` to the new
572
+ * head while its line still exists, so a position still on an older head no
573
+ * longer maps onto the diff and the thread is outdated.
574
+ */
575
+ function gitLabReviewThread(discussion, context) {
576
+ const notes = discussion.notes.filter((note) => note.system !== true);
577
+ const opener = notes[0];
578
+ const position = opener?.position;
579
+ if (!opener || !position) return null;
580
+ const positionType = position.position_type?.trim().toLowerCase() ?? "text";
581
+ if (positionType !== "text" && positionType !== "file") return null;
582
+ const path = trimmed$1(position.new_path) ?? trimmed$1(position.old_path);
583
+ const openerCreatedAt = require_bin.parseGitLabTimestamp(opener.created_at);
584
+ if (!path || !openerCreatedAt) return null;
585
+ const positionHead = trimmed$1(position.head_sha);
586
+ const isOutdated = positionHead !== null && context.headSha !== null && positionHead !== context.headSha;
587
+ const anchor = positionType === "text" ? lineOf(position) : null;
588
+ if (positionType === "text" && !anchor) return null;
589
+ const side = anchor?.side ?? "right";
590
+ const rangeStart = position.line_range?.start ? lineOf(position.line_range.start) : null;
591
+ const start = anchor && rangeStart && (rangeStart.line !== anchor.line || rangeStart.side !== anchor.side) ? rangeStart : null;
592
+ const entry = !isOutdated && anchor && context.diffEntries ? findGitLabDiffEntry(context.diffEntries, path) : void 0;
593
+ const diffHunk = entry && anchor ? gitLabDiffHunkExcerpt(entry, anchor.side, anchor.line) : null;
594
+ const resolvable = notes.filter((note) => note.resolvable === true);
595
+ const isResolvable = resolvable.length > 0 || discussion.resolvable === true;
596
+ const isResolved = resolvable.length > 0 ? resolvable.every((note) => note.resolved === true) : discussion.resolved === true;
597
+ const resolvedBy = isResolved ? resolvable.map((note) => trimmed$1(note.resolved_by?.username)).findLast(Boolean) ?? null : null;
598
+ const comments = notes.slice(0, 100).flatMap((note) => {
599
+ const comment = noteComment(note, context);
600
+ return comment ? [comment] : [];
601
+ });
602
+ const thread = {
603
+ id: discussion.id,
604
+ path,
605
+ subjectType: positionType === "file" ? "file" : "line",
606
+ side,
607
+ ...start ? { startSide: start.side } : {},
608
+ line: anchor && !isOutdated ? anchor.line : null,
609
+ ...start ? { startLine: isOutdated ? null : start.line } : {},
610
+ ...anchor ? { originalLine: anchor.line } : {},
611
+ ...start ? { originalStartLine: start.line } : {},
612
+ ...positionHead ? { originalCommitOid: positionHead } : {},
613
+ ...diffHunk ? { diffHunk } : {},
614
+ isResolved,
615
+ isOutdated,
616
+ ...resolvedBy ? { resolvedBy } : {},
617
+ viewerCanReply: context.viewerCanReply,
618
+ viewerCanResolve: isResolvable && !isResolved && context.viewerCanResolve,
619
+ viewerCanUnresolve: isResolvable && isResolved && context.viewerCanResolve,
620
+ comments,
621
+ totalComments: Math.max(notes.length, comments.length)
622
+ };
623
+ if (!isReviewThread(thread)) return null;
624
+ return {
625
+ thread,
626
+ openerAuthor: trimmed$1(opener.author?.username),
627
+ openerCreatedAt
628
+ };
629
+ }
630
+ function gitLabViewerCapabilities(input) {
631
+ const { user, facts } = input;
632
+ const login = trimmed$1(user?.username);
633
+ if (!user || !login) return null;
634
+ const access = require_bin.gitLabAccessLevel(input.project);
635
+ const isAuthor = facts.authorId !== null ? facts.authorId === user.id : facts.authorUsername === login;
636
+ const canUpdate = isAuthor || access >= 30;
637
+ const canMerge = facts.canMerge === true;
638
+ return {
639
+ login,
640
+ isAuthor,
641
+ canUpdate,
642
+ canMerge,
643
+ canReview: !facts.discussionLocked || access > 0,
644
+ canUpdateBranch: canUpdate,
645
+ canEnableAutoMerge: canMerge,
646
+ canDisableAutoMerge: canMerge || facts.autoMergeBy !== null && facts.autoMergeBy === login
647
+ };
648
+ }
649
+ function epoch(value) {
650
+ return effect.DateTime.toEpochMillis(value);
651
+ }
652
+ function commitItems(input, pushers) {
653
+ return input.commits.items.flatMap((commit) => {
654
+ const createdAt = require_bin.parseGitLabTimestamp(commit.committed_date) ?? require_bin.parseGitLabTimestamp(commit.created_at) ?? require_bin.parseGitLabTimestamp(commit.authored_date);
655
+ const oid = trimmed$1(commit.id);
656
+ if (!createdAt || !oid) return [];
657
+ const [headline = "", ...rest] = (commit.message ?? commit.title ?? "").split("\n");
658
+ const body = rest.join("\n").trim();
659
+ const actor = [...pushers.entries()].find(([prefix]) => oid.toLowerCase().startsWith(prefix))?.[1];
660
+ return [{
661
+ id: `commit:${oid}`,
662
+ kind: "commit",
663
+ createdAt,
664
+ ...actor ? { actor } : {},
665
+ oid,
666
+ shortOid: trimmed$1(commit.short_id) ?? oid.slice(0, 8),
667
+ messageHeadline: trimmed$1(commit.title) ?? headline.trim(),
668
+ ...body ? { messageBody: body } : {}
669
+ }];
670
+ });
671
+ }
672
+ /**
673
+ * A push that rewrote history: the previous version's head is no longer one
674
+ * of the merge request's commits. Undecidable when the commit list is cut.
675
+ */
676
+ function forcePushItems(input) {
677
+ if (input.commits.truncated) return [];
678
+ const known = new Set(input.commits.items.map((commit) => commit.id.toLowerCase()));
679
+ const versions = input.versions.flatMap((version) => {
680
+ const createdAt = require_bin.parseGitLabTimestamp(version.created_at);
681
+ return createdAt ? [{
682
+ version,
683
+ createdAt
684
+ }] : [];
685
+ }).toSorted((left, right) => epoch(left.createdAt) - epoch(right.createdAt));
686
+ const items = [];
687
+ for (let index = 1; index < versions.length; index += 1) {
688
+ const previous = versions[index - 1];
689
+ const current = versions[index];
690
+ if (!previous || !current) continue;
691
+ const before = previous.version.head_commit_sha.trim();
692
+ const after = current.version.head_commit_sha.trim();
693
+ if (!before || !after || before === after || known.has(before.toLowerCase())) continue;
694
+ items.push({
695
+ id: `version:${current.version.id}`,
696
+ kind: "force-pushed",
697
+ createdAt: current.createdAt,
698
+ beforeOid: before,
699
+ afterOid: after
700
+ });
701
+ }
702
+ return items;
703
+ }
704
+ function eventItems(input) {
705
+ const items = [];
706
+ for (const event of input.stateEvents) {
707
+ const createdAt = require_bin.parseGitLabTimestamp(event.created_at);
708
+ if (!createdAt) continue;
709
+ const actor = gitLabActor(event.user);
710
+ const base = {
711
+ id: `state:${event.id}`,
712
+ createdAt,
713
+ ...actor ? { actor } : {}
714
+ };
715
+ switch (event.state.trim().toLowerCase()) {
716
+ case "merged":
717
+ items.push({
718
+ ...base,
719
+ kind: "merged",
720
+ ...input.facts.mergeCommitSha ? { commitOid: input.facts.mergeCommitSha } : {},
721
+ baseRefName: input.facts.targetBranch
722
+ });
723
+ break;
724
+ case "closed":
725
+ items.push({
726
+ ...base,
727
+ kind: "closed"
728
+ });
729
+ break;
730
+ case "reopened": items.push({
731
+ ...base,
732
+ kind: "reopened"
733
+ });
734
+ }
735
+ }
736
+ for (const event of input.labelEvents) {
737
+ const createdAt = require_bin.parseGitLabTimestamp(event.created_at);
738
+ const name = trimmed$1(event.label?.name);
739
+ const action = event.action.trim().toLowerCase();
740
+ if (!createdAt || !name || action !== "add" && action !== "remove") continue;
741
+ const actor = gitLabActor(event.user);
742
+ const color = trimmed$1(event.label?.color)?.replace(/^#/u, "").toLowerCase();
743
+ const description = trimmed$1(event.label?.description);
744
+ items.push({
745
+ id: `label:${event.id}`,
746
+ kind: action === "add" ? "labeled" : "unlabeled",
747
+ createdAt,
748
+ ...actor ? { actor } : {},
749
+ label: {
750
+ name,
751
+ ...color && /^[0-9a-f]{3,8}$/u.test(color) ? { color } : {},
752
+ ...description ? { description } : {}
753
+ }
754
+ });
755
+ }
756
+ return items;
757
+ }
758
+ /** Threads published together (one author, openers within a minute) form one review. */
759
+ function reviewItems(entries) {
760
+ const sorted = entries.toSorted((left, right) => epoch(left.openerCreatedAt) - epoch(right.openerCreatedAt));
761
+ const items = [];
762
+ let batch = [];
763
+ const flush = () => {
764
+ const first = batch[0];
765
+ if (!first) return;
766
+ const actor = first.thread.comments[0]?.author;
767
+ items.push({
768
+ id: `review:${first.thread.id}`,
769
+ kind: "review",
770
+ createdAt: first.openerCreatedAt,
771
+ ...actor ? { actor } : {},
772
+ state: "commented",
773
+ body: "",
774
+ threadIds: batch.map((entry) => entry.thread.id)
775
+ });
776
+ batch = [];
777
+ };
778
+ for (const entry of sorted) {
779
+ const last = batch.at(-1);
780
+ if (last && (last.openerAuthor !== entry.openerAuthor || epoch(entry.openerCreatedAt) - epoch(last.openerCreatedAt) > REVIEW_BATCH_WINDOW_MS)) flush();
781
+ batch.push(entry);
782
+ }
783
+ flush();
784
+ return items;
785
+ }
786
+ function assembleGitLabChangeRequestActivity(input) {
787
+ const { facts } = input;
788
+ const viewer = gitLabViewerCapabilities(input);
789
+ const access = require_bin.gitLabAccessLevel(input.project);
790
+ const threadContext = {
791
+ mergeRequestUrl: facts.webUrl,
792
+ headSha: facts.headSha,
793
+ viewerId: input.user?.id ?? null,
794
+ viewerCanReply: viewer !== null && viewer.canReview,
795
+ viewerCanResolve: viewer !== null && (viewer.isAuthor || access >= 30),
796
+ diffEntries: input.diffEntries
797
+ };
798
+ const threadEntries = input.discussions.items.flatMap((discussion) => {
799
+ const entry = gitLabReviewThread(discussion, threadContext);
800
+ return entry ? [entry] : [];
801
+ });
802
+ const threadIds = new Set(threadEntries.map((entry) => entry.thread.id));
803
+ const pushers = /* @__PURE__ */ new Map();
804
+ const timeline = [];
805
+ const seen = /* @__PURE__ */ new Set();
806
+ const push = (item) => {
807
+ if (seen.has(item.id) || !isTimelineItem(item)) return;
808
+ seen.add(item.id);
809
+ timeline.push(item);
810
+ };
811
+ const notes = input.notes.items.toSorted((left, right) => Date.parse(left.created_at) - Date.parse(right.created_at) || left.id - right.id);
812
+ for (const note of notes) {
813
+ if (note.system === true) {
814
+ const actor = gitLabActor(note.author);
815
+ if (actor) for (const prefix of gitLabPushedCommitPrefixes(note)) pushers.set(prefix, actor);
816
+ for (const item of gitLabSystemNoteItems(note, {
817
+ mergeRequestUrl: facts.webUrl,
818
+ targetBranch: facts.targetBranch
819
+ })) push(item);
820
+ continue;
821
+ }
822
+ if (note.position || note.type === "DiffNote") continue;
823
+ const comment = noteComment(note, {
824
+ ...threadContext,
825
+ diffEntries: null
826
+ });
827
+ if (!comment) continue;
828
+ push({
829
+ id: `note:${note.id}`,
830
+ kind: "comment",
831
+ createdAt: comment.createdAt,
832
+ actor: comment.author,
833
+ body: comment.body,
834
+ ...comment.updatedAt ? { updatedAt: comment.updatedAt } : {},
835
+ ...comment.url ? { url: comment.url } : {},
836
+ viewerCanUpdate: comment.viewerCanUpdate === true,
837
+ viewerCanDelete: comment.viewerCanDelete === true
838
+ });
839
+ }
840
+ const cutoff = input.notes.truncated && notes[0] ? Date.parse(notes[0].created_at) : null;
841
+ for (const item of [
842
+ ...eventItems(input),
843
+ ...commitItems(input, pushers),
844
+ ...forcePushItems(input),
845
+ ...reviewItems(threadEntries.filter((entry) => threadIds.has(entry.thread.id)))
846
+ ]) {
847
+ if (cutoff !== null && epoch(item.createdAt) < cutoff) continue;
848
+ push(item);
849
+ }
850
+ timeline.sort((left, right) => epoch(left.createdAt) - epoch(right.createdAt));
851
+ return {
852
+ provider: "gitlab",
853
+ number: facts.iid,
854
+ headSha: facts.headSha,
855
+ viewer,
856
+ timeline,
857
+ timelineTruncated: input.notes.truncated || input.commits.truncated,
858
+ reviewThreads: threadEntries.map((entry) => entry.thread),
859
+ reviewThreadsTruncated: input.discussions.truncated,
860
+ pendingReview: input.draftNotes && input.draftNotes.length > 0 ? {
861
+ id: "draft-notes",
862
+ commentsCount: input.draftNotes.length
863
+ } : null
864
+ };
865
+ }
866
+ //#endregion
867
+ //#region src/sourceControl/gitLabPipelines.ts
868
+ /**
869
+ * GitLab CI as the page's checks: pipelines are workflow runs, jobs are jobs
870
+ * (GitLab jobs have no steps), commit statuses are the check rollup. Pure.
871
+ *
872
+ * Docs:
873
+ * - https://docs.gitlab.com/api/merge_requests/#list-merge-request-pipelines
874
+ * - https://docs.gitlab.com/api/pipelines/#list-project-pipelines
875
+ * - https://docs.gitlab.com/api/jobs/#list-all-jobs-by-pipeline
876
+ * - https://docs.gitlab.com/api/jobs/#retrieve-a-log-file-for-a-job
877
+ * - https://docs.gitlab.com/api/commits/#list-commit-statuses
878
+ */
879
+ const GitLabPipelineSchema = effect.Schema.Struct({
880
+ id: effect.Schema.Number,
881
+ iid: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
882
+ sha: effect.Schema.String,
883
+ ref: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
884
+ status: effect.Schema.String,
885
+ source: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
886
+ name: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
887
+ web_url: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
888
+ created_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
889
+ updated_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
890
+ started_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
891
+ finished_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
892
+ duration: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
893
+ user: effect.Schema.optional(effect.Schema.NullOr(require_bin.GitLabUserRefSchema))
894
+ });
895
+ const GitLabJobSchema = effect.Schema.Struct({
896
+ id: effect.Schema.Number,
897
+ name: effect.Schema.String,
898
+ stage: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
899
+ status: effect.Schema.String,
900
+ allow_failure: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
901
+ started_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
902
+ finished_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
903
+ duration: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
904
+ web_url: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
905
+ });
906
+ const GitLabCommitStatusSchema = effect.Schema.Struct({
907
+ id: effect.Schema.Number,
908
+ /** GitLab 17.9+. */
909
+ pipeline_id: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Number)),
910
+ name: effect.Schema.String,
911
+ status: effect.Schema.String,
912
+ target_url: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
913
+ allow_failure: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Boolean)),
914
+ created_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
915
+ started_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
916
+ finished_at: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
917
+ });
918
+ function trimmed(value) {
919
+ const text = value?.trim() ?? "";
920
+ return text.length > 0 ? text : null;
921
+ }
922
+ function optionString(value) {
923
+ const text = trimmed(value);
924
+ return text ? effect.Option.some(text) : effect.Option.none();
925
+ }
926
+ function optionTime(value) {
927
+ const parsed = require_bin.parseGitLabTimestamp(value);
928
+ return parsed ? effect.Option.some(parsed) : effect.Option.none();
929
+ }
930
+ function durationMs(seconds) {
931
+ return typeof seconds === "number" && Number.isFinite(seconds) && seconds >= 0 ? effect.Option.some(Math.round(seconds * 1e3)) : effect.Option.none();
932
+ }
933
+ /**
934
+ * GitLab pipeline/job/status values as the GitHub-style status + conclusion
935
+ * the page classifies. A failure GitLab tolerates (`allow_failure`) is
936
+ * neutral, an optional manual job is skipped, a blocking one waits.
937
+ */
938
+ function gitLabCheckState(status, allowFailure = false) {
939
+ switch (status.trim().toLowerCase()) {
940
+ case "success": return {
941
+ status: "completed",
942
+ conclusion: "success"
943
+ };
944
+ case "failed": return {
945
+ status: "completed",
946
+ conclusion: allowFailure ? "neutral" : "failure"
947
+ };
948
+ case "canceled":
949
+ case "cancelled": return {
950
+ status: "completed",
951
+ conclusion: "cancelled"
952
+ };
953
+ case "skipped": return {
954
+ status: "completed",
955
+ conclusion: "skipped"
956
+ };
957
+ case "manual": return allowFailure ? {
958
+ status: "completed",
959
+ conclusion: "skipped"
960
+ } : {
961
+ status: "waiting",
962
+ conclusion: null
963
+ };
964
+ case "running":
965
+ case "canceling": return {
966
+ status: "in_progress",
967
+ conclusion: null
968
+ };
969
+ case "created":
970
+ case "pending":
971
+ case "preparing":
972
+ case "scheduled":
973
+ case "waiting_for_resource":
974
+ case "waiting_for_callback": return {
975
+ status: "queued",
976
+ conclusion: null
977
+ };
978
+ default: return {
979
+ status: status.trim().toLowerCase() || "unknown",
980
+ conclusion: null
981
+ };
982
+ }
983
+ }
984
+ /**
985
+ * A pipeline's name on the page: its `name` (`workflow:name`), else
986
+ * `Pipeline #<iid>`. The runs list and the check rollup both use it, so the
987
+ * rollup's jobs group under their pipeline.
988
+ */
989
+ function gitLabPipelineRunName(pipeline) {
990
+ return trimmed(pipeline.name) ?? `Pipeline #${pipeline.iid ?? pipeline.id}`;
991
+ }
992
+ /**
993
+ * @param sourceHeadOid The merge request head the pipeline verifies when it
994
+ * ran on a merged-results or merge-train commit (see `sourceHeadOid`).
995
+ */
996
+ function gitLabWorkflowRun(pipeline, sourceHeadOid) {
997
+ const sha = trimmed(pipeline.sha);
998
+ const url = trimmed(pipeline.web_url);
999
+ if (!sha || !url) return null;
1000
+ const state = gitLabCheckState(pipeline.status);
1001
+ const event = trimmed(pipeline.source);
1002
+ const source = trimmed(sourceHeadOid);
1003
+ return {
1004
+ provider: "gitlab",
1005
+ runId: String(pipeline.id),
1006
+ workflowName: gitLabPipelineRunName(pipeline),
1007
+ branch: optionString(pipeline.ref),
1008
+ ...event ? { event } : {},
1009
+ commit: {
1010
+ oid: sha,
1011
+ shortOid: sha.slice(0, 8)
1012
+ },
1013
+ ...source && source !== sha ? { sourceHeadOid: source } : {},
1014
+ actor: optionString(pipeline.user?.username),
1015
+ status: state.status,
1016
+ conclusion: optionString(state.conclusion),
1017
+ startedAt: optionTime(pipeline.started_at ?? pipeline.created_at),
1018
+ updatedAt: optionTime(pipeline.updated_at ?? pipeline.finished_at),
1019
+ durationMs: durationMs(pipeline.duration),
1020
+ url
1021
+ };
1022
+ }
1023
+ /**
1024
+ * The merge request's pipelines for its current head: those on the head
1025
+ * commit plus the head pipeline itself, whose SHA is the merged-results or
1026
+ * merge-train commit rather than the head.
1027
+ */
1028
+ function selectGitLabHeadPipelines(pipelines, head) {
1029
+ return pipelines.filter((pipeline) => head.headSha !== null && pipeline.sha === head.headSha || head.headPipelineId !== null && pipeline.id === head.headPipelineId);
1030
+ }
1031
+ function gitLabWorkflowJob(job) {
1032
+ const state = gitLabCheckState(job.status, job.allow_failure === true);
1033
+ const stage = trimmed(job.stage);
1034
+ const name = trimmed(job.name) ?? `Job ${job.id}`;
1035
+ return {
1036
+ jobId: String(job.id),
1037
+ name: stage ? `${stage} / ${name}` : name,
1038
+ status: state.status,
1039
+ conclusion: optionString(state.conclusion),
1040
+ startedAt: optionTime(job.started_at),
1041
+ completedAt: optionTime(job.finished_at),
1042
+ durationMs: durationMs(job.duration),
1043
+ url: optionString(job.web_url),
1044
+ steps: []
1045
+ };
1046
+ }
1047
+ /**
1048
+ * The newest status per name (retries replace earlier attempts). GitLab lists
1049
+ * every CI job as a commit status too (a job is a `CommitStatus` row with the
1050
+ * same id), so the head pipeline's jobs become check runs of that pipeline,
1051
+ * named and linked as its jobs list names them; only what is left (external
1052
+ * statuses, trigger jobs, other pipelines) stays a status context. Without the
1053
+ * head pipeline's jobs, every status is a status context.
1054
+ */
1055
+ function gitLabCheckRollup(statuses, headPipeline) {
1056
+ const latest = /* @__PURE__ */ new Map();
1057
+ for (const status of statuses) {
1058
+ const name = trimmed(status.name);
1059
+ if (!name) continue;
1060
+ const existing = latest.get(name);
1061
+ if (!existing || existing.id < status.id) latest.set(name, status);
1062
+ }
1063
+ const jobsById = new Map((headPipeline?.jobs ?? []).map((job) => [job.id, job]));
1064
+ return [...latest.values()].toSorted((left, right) => left.id - right.id).map((status) => {
1065
+ const state = gitLabCheckState(status.status, status.allow_failure === true);
1066
+ const job = jobsById.get(status.id);
1067
+ const statusUrl = optionString(status.target_url);
1068
+ const startedAt = optionTime(status.started_at ?? status.created_at);
1069
+ const completedAt = optionTime(status.finished_at);
1070
+ if (job && headPipeline) {
1071
+ const mapped = gitLabWorkflowJob(job);
1072
+ return {
1073
+ kind: "check-run",
1074
+ name: mapped.name,
1075
+ workflowName: headPipeline.runName,
1076
+ status: effect.Option.some(state.status),
1077
+ conclusion: optionString(state.conclusion),
1078
+ url: effect.Option.orElse(mapped.url, () => statusUrl),
1079
+ startedAt,
1080
+ completedAt
1081
+ };
1082
+ }
1083
+ return {
1084
+ kind: "status-context",
1085
+ name: status.name.trim(),
1086
+ status: effect.Option.some(state.status),
1087
+ conclusion: optionString(state.conclusion),
1088
+ url: statusUrl,
1089
+ startedAt,
1090
+ completedAt
1091
+ };
1092
+ });
1093
+ }
1094
+ /**
1095
+ * A list row's pipeline as a one-item rollup: the newest pipeline on the
1096
+ * merge request's refs (`refs/merge-requests/<iid>/…`) or its branch head.
1097
+ */
1098
+ function gitLabListRowRollup(pipelines, row) {
1099
+ const mergeRequestRef = `refs/merge-requests/${row.iid}/`;
1100
+ const pipeline = pipelines.filter((candidate) => candidate.ref?.startsWith(mergeRequestRef) === true || candidate.ref === row.sourceBranch && row.headSha !== null && candidate.sha === row.headSha).toSorted((left, right) => right.id - left.id)[0];
1101
+ if (!pipeline) return null;
1102
+ const state = gitLabCheckState(pipeline.status);
1103
+ return [{
1104
+ kind: "unknown",
1105
+ name: trimmed(pipeline.name) ?? "Pipeline",
1106
+ status: effect.Option.some(state.status),
1107
+ conclusion: optionString(state.conclusion),
1108
+ url: optionString(pipeline.web_url),
1109
+ startedAt: optionTime(pipeline.started_at ?? pipeline.created_at),
1110
+ completedAt: optionTime(pipeline.finished_at)
1111
+ }];
1112
+ }
1113
+ const SECTION_MARKER = /section_(?:start|end):\d+:[^\r\n\u001b]*(?:\r?\u001b\[0K)?/gu;
1114
+ const ANSI_ESCAPE = /\u001b\[[0-9;?]*[A-Za-z]/gu;
1115
+ /**
1116
+ * Plain text, newest output kept: the end of a log is where a job failed.
1117
+ * `startCut`: the raw log is already only its tail, so its first line may
1118
+ * begin inside a section marker or escape and is dropped.
1119
+ */
1120
+ function gitLabJobLogTail(raw, options) {
1121
+ const startCut = options?.startCut === true;
1122
+ const newline = startCut ? raw.indexOf("\n") : -1;
1123
+ const plain = (startCut ? newline >= 0 ? raw.slice(newline + 1) : "" : raw).replace(SECTION_MARKER, "").replace(ANSI_ESCAPE, "").replace(/\r\n/gu, "\n");
1124
+ const bytes = Buffer.from(plain, "utf8");
1125
+ if (bytes.byteLength <= 204800) return {
1126
+ log: plain,
1127
+ truncated: startCut
1128
+ };
1129
+ let tail = bytes.subarray(bytes.byteLength - require_src.SOURCE_CONTROL_WORKFLOW_LOG_MAX_BYTES);
1130
+ let offset = 0;
1131
+ while (offset < tail.length && ((tail[offset] ?? 0) & 192) === 128) offset += 1;
1132
+ tail = tail.subarray(offset);
1133
+ return {
1134
+ log: tail.toString("utf8"),
1135
+ truncated: true
1136
+ };
1137
+ }
1138
+ //#endregion
1139
+ //#region src/sourceControl/gitLabMergeRequestPage.ts
1140
+ /** List pages can carry long bodies; the process default (1 MB) is too small. */
1141
+ const LIST_PAGE_MAX_BYTES = 16777216;
1142
+ const DIFF_PAGE_MAX_BYTES = 33554432;
1143
+ const DIFF_TIMEOUT_MS = 6e4;
1144
+ /** Files read for a whole merge request diff (100 per page). */
1145
+ const DIFF_MAX_PAGES = 30;
1146
+ /** Files read to anchor review comments / excerpt thread hunks. */
1147
+ const ACTIVITY_DIFF_MAX_PAGES = 3;
1148
+ const COMMIT_PAGES = 3;
1149
+ /**
1150
+ * Raw bytes kept from the end of a job log: room for the shown tail
1151
+ * (`SOURCE_CONTROL_WORKFLOW_LOG_MAX_BYTES`) once colours and section markers
1152
+ * are stripped. Longer logs stream through and only their end is kept.
1153
+ */
1154
+ const JOB_LOG_TAIL_BYTES = 8 * require_src.SOURCE_CONTROL_WORKFLOW_LOG_MAX_BYTES;
1155
+ /** First GitLab release whose `bulk_publish` records `reviewer_state` (verify). */
1156
+ const REQUEST_CHANGES_MIN_VERSION = {
1157
+ major: 19,
1158
+ minor: 2
1159
+ };
1160
+ function fail(operation, detail, status) {
1161
+ return new require_bin.GitLabCliError({
1162
+ operation,
1163
+ detail,
1164
+ ...status !== void 0 ? { status } : {}
1165
+ });
1166
+ }
1167
+ function gitLabStaleHeadError(operation) {
1168
+ return fail(operation, "The merge request's head changed since it was loaded. Refresh and review the new commits, then try again.", 409);
1169
+ }
1170
+ function isStatus(status) {
1171
+ return (error) => error.status === status;
1172
+ }
1173
+ function requireGitLabMergeRequestRef(operation, reference) {
1174
+ const ref = require_bin.parseGitLabMergeRequestReference(reference);
1175
+ return ref ? effect.Effect.succeed(ref) : effect.Effect.fail(fail(operation, `"${reference}" is not a merge request number or merge request URL.`));
1176
+ }
1177
+ function decodeJson(operation, schema, raw) {
1178
+ return effect.Schema.decodeEffect(effect.Schema.fromJsonString(schema))(raw.trim()).pipe(effect.Effect.mapError((error) => fail(operation, `GitLab returned an unexpected response: ${effect.SchemaIssue.makeFormatterDefault()(error.issue)}`)));
1179
+ }
1180
+ const decodeUnknownArray = effect.Schema.fromJsonString(effect.Schema.Array(effect.Schema.Unknown));
1181
+ /** A JSON array, keeping the entries `item` decodes (one odd entry must not hide the rest). */
1182
+ function decodeList(operation, item, raw) {
1183
+ const decodeItem = effect.Schema.decodeUnknownExit(item);
1184
+ return effect.Schema.decodeEffect(decodeUnknownArray)(raw.trim() || "[]").pipe(effect.Effect.mapError((error) => fail(operation, `GitLab returned an unexpected list: ${effect.SchemaIssue.makeFormatterDefault()(error.issue)}`)), effect.Effect.map((entries) => entries.flatMap((entry) => {
1185
+ const decoded = decodeItem(entry);
1186
+ return effect.Exit.isSuccess(decoded) ? [decoded.value] : [];
1187
+ })));
1188
+ }
1189
+ function getJson(call, operation, request, schema) {
1190
+ return call(operation, request, { maxOutputBytes: LIST_PAGE_MAX_BYTES }).pipe(effect.Effect.flatMap((output) => decodeJson(operation, schema, output.stdout)));
1191
+ }
1192
+ /**
1193
+ * Read up to `maxPages` pages of a list endpoint. A short page ends the
1194
+ * list; a full last page means more exist (`truncated`).
1195
+ */
1196
+ function getGitLabPages(call, operation, input) {
1197
+ const perPage = input.perPage ?? 100;
1198
+ return effect.Effect.gen(function* () {
1199
+ const items = [];
1200
+ for (let page = 1; page <= input.maxPages; page += 1) {
1201
+ const raw = (yield* call(operation, require_bin.gitLabGet(input.ref, require_bin.withGitLabQuery(input.endpoint, {
1202
+ per_page: perPage,
1203
+ page
1204
+ })), {
1205
+ maxOutputBytes: input.maxOutputBytes ?? LIST_PAGE_MAX_BYTES,
1206
+ ...input.timeoutMs !== void 0 ? { timeoutMs: input.timeoutMs } : {}
1207
+ })).stdout.trim() || "[]";
1208
+ const count = yield* effect.Schema.decodeEffect(decodeUnknownArray)(raw).pipe(effect.Effect.map((entries) => entries.length), effect.Effect.mapError(() => fail(operation, "GitLab returned an unexpected list.")));
1209
+ items.push(...yield* decodeList(operation, input.item, raw));
1210
+ if (require_bin.isLastGitLabPage(count, perPage)) return {
1211
+ items,
1212
+ truncated: false
1213
+ };
1214
+ }
1215
+ return {
1216
+ items,
1217
+ truncated: true
1218
+ };
1219
+ });
1220
+ }
1221
+ function getGitLabMergeRequestFacts(call, operation, ref) {
1222
+ return getJson(call, operation, require_bin.gitLabGet(ref, require_bin.gitLabMergeRequestEndpoint(ref)), require_bin.GitLabMergeRequestDetailSchema).pipe(effect.Effect.map(require_bin.gitLabMergeRequestFacts));
1223
+ }
1224
+ function getCurrentUser(call, operation, ref) {
1225
+ return getJson(call, operation, require_bin.gitLabGet(ref, "user"), GitLabCurrentUserSchema);
1226
+ }
1227
+ function getProject(call, operation, ref) {
1228
+ return getJson(call, operation, require_bin.gitLabGet(ref, require_bin.gitLabProjectEndpoint(ref)), require_bin.GitLabProjectSchema);
1229
+ }
1230
+ /** A best-effort read: a failure is logged and reads as `fallback`. */
1231
+ function optional(effect$2, fallback) {
1232
+ return effect$2.pipe(effect.Effect.catch((error) => effect.Effect.logWarning("GitLab read failed; continuing without it.", {
1233
+ operation: error.operation,
1234
+ detail: error.detail
1235
+ }).pipe(effect.Effect.as(fallback))));
1236
+ }
1237
+ function getDiffEntries(call, operation, ref, maxPages) {
1238
+ return getGitLabPages(call, operation, {
1239
+ ref,
1240
+ endpoint: require_bin.gitLabMergeRequestEndpoint(ref, "/diffs"),
1241
+ item: GitLabDiffEntrySchema,
1242
+ maxPages,
1243
+ maxOutputBytes: DIFF_PAGE_MAX_BYTES,
1244
+ timeoutMs: DIFF_TIMEOUT_MS
1245
+ });
1246
+ }
1247
+ function hasActiveLineThread(discussions, headSha) {
1248
+ return discussions.some((discussion) => {
1249
+ const position = discussion.notes.find((note) => note.system !== true)?.position;
1250
+ return position?.position_type !== "file" && position !== void 0 && position !== null && (headSha === null || position.head_sha === headSha);
1251
+ });
1252
+ }
1253
+ function fetchGitLabChangeRequestActivity(call, reference) {
1254
+ const operation = "getChangeRequestActivity";
1255
+ return effect.Effect.gen(function* () {
1256
+ const ref = yield* requireGitLabMergeRequestRef(operation, reference);
1257
+ const pages = (suffix, item, maxPages) => getGitLabPages(call, operation, {
1258
+ ref,
1259
+ endpoint: require_bin.gitLabMergeRequestEndpoint(ref, suffix),
1260
+ item,
1261
+ maxPages
1262
+ });
1263
+ const read = yield* effect.Effect.all({
1264
+ facts: getGitLabMergeRequestFacts(call, operation, ref),
1265
+ user: optional(getCurrentUser(call, operation, ref), null),
1266
+ project: optional(getProject(call, operation, ref), null),
1267
+ notes: pages(require_bin.withGitLabQuery("/notes", {
1268
+ sort: "desc",
1269
+ order_by: "created_at"
1270
+ }), GitLabNoteSchema, 3),
1271
+ discussions: pages("/discussions", GitLabDiscussionSchema, 3),
1272
+ stateEvents: optional(pages("/resource_state_events", GitLabStateEventSchema, 1), {
1273
+ items: [],
1274
+ truncated: false
1275
+ }),
1276
+ labelEvents: optional(pages("/resource_label_events", GitLabLabelEventSchema, 1), {
1277
+ items: [],
1278
+ truncated: false
1279
+ }),
1280
+ commits: optional(pages("/commits", GitLabCommitSchema, 1), {
1281
+ items: [],
1282
+ truncated: false
1283
+ }),
1284
+ versions: optional(pages("/versions", GitLabVersionSchema, 1), {
1285
+ items: [],
1286
+ truncated: false
1287
+ }),
1288
+ draftNotes: optional(pages("/draft_notes", GitLabDraftNoteSchema, 1).pipe(effect.Effect.map((page) => page.items)), null)
1289
+ }, { concurrency: 6 });
1290
+ const diffEntries = hasActiveLineThread(read.discussions.items, read.facts.headSha) ? yield* optional(getDiffEntries(call, operation, ref, ACTIVITY_DIFF_MAX_PAGES).pipe(effect.Effect.map((page) => page.items)), null) : null;
1291
+ return assembleGitLabChangeRequestActivity({
1292
+ facts: read.facts,
1293
+ user: read.user,
1294
+ project: read.project,
1295
+ notes: read.notes,
1296
+ discussions: read.discussions,
1297
+ stateEvents: read.stateEvents.items,
1298
+ labelEvents: read.labelEvents.items,
1299
+ commits: read.commits,
1300
+ versions: read.versions.items,
1301
+ draftNotes: read.draftNotes,
1302
+ diffEntries
1303
+ });
1304
+ });
1305
+ }
1306
+ /** One discussion re-read as a review thread (after a reply). */
1307
+ function fetchGitLabReviewThread(call, operation, ref, discussionId) {
1308
+ return effect.Effect.gen(function* () {
1309
+ const read = yield* effect.Effect.all({
1310
+ discussion: getJson(call, operation, require_bin.gitLabGet(ref, require_bin.gitLabMergeRequestEndpoint(ref, `/discussions/${discussionId}`)), GitLabDiscussionSchema),
1311
+ facts: getGitLabMergeRequestFacts(call, operation, ref),
1312
+ user: optional(getCurrentUser(call, operation, ref), null),
1313
+ project: optional(getProject(call, operation, ref), null)
1314
+ }, { concurrency: 4 });
1315
+ const diffEntries = hasActiveLineThread([read.discussion], read.facts.headSha) ? yield* optional(getDiffEntries(call, operation, ref, ACTIVITY_DIFF_MAX_PAGES).pipe(effect.Effect.map((page) => page.items)), null) : null;
1316
+ const viewer = gitLabViewerCapabilities(read);
1317
+ const entry = gitLabReviewThread(read.discussion, {
1318
+ mergeRequestUrl: read.facts.webUrl,
1319
+ headSha: read.facts.headSha,
1320
+ viewerId: read.user?.id ?? null,
1321
+ viewerCanReply: viewer !== null && viewer.canReview,
1322
+ viewerCanResolve: viewer !== null && (viewer.isAuthor || require_bin.gitLabAccessLevel(read.project) >= 30),
1323
+ diffEntries
1324
+ });
1325
+ if (!entry) return yield* fail(operation, "This discussion is not a review thread on the diff.");
1326
+ return entry.thread;
1327
+ });
1328
+ }
1329
+ /** The merge request's commit SHAs (newest first), bounded. */
1330
+ function listCommitShas(call, operation, ref) {
1331
+ return getGitLabPages(call, operation, {
1332
+ ref,
1333
+ endpoint: require_bin.gitLabMergeRequestEndpoint(ref, "/commits"),
1334
+ item: GitLabCommitSchema,
1335
+ maxPages: COMMIT_PAGES
1336
+ });
1337
+ }
1338
+ /**
1339
+ * The whole merge request diff (merge base → head, as GitLab shows it) or
1340
+ * one of its commits against its parent, as a unified diff. With
1341
+ * `expectedHeadSha`, a head that moves before or during the read fails.
1342
+ */
1343
+ function fetchGitLabChangeRequestDiff(call, input) {
1344
+ const operation = "getChangeRequestDiff";
1345
+ return effect.Effect.gen(function* () {
1346
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1347
+ const verifyHead = () => getGitLabMergeRequestFacts(call, operation, ref).pipe(effect.Effect.flatMap((facts) => facts.headSha === input.expectedHeadSha ? effect.Effect.void : effect.Effect.fail(gitLabStaleHeadError(operation))));
1348
+ if (input.expectedHeadSha) yield* verifyHead();
1349
+ const commitSha = input.commitSha?.trim();
1350
+ let entries;
1351
+ if (commitSha) {
1352
+ const commits = yield* listCommitShas(call, operation, ref);
1353
+ const wanted = commitSha.toLowerCase();
1354
+ const matches = commits.items.filter((commit) => wanted.length >= 7 ? commit.id.toLowerCase().startsWith(wanted) : commit.id.toLowerCase() === wanted);
1355
+ const commit = matches.length === 1 ? matches[0] : void 0;
1356
+ if (!commit || !require_bin.isGitSha(commit.id)) return yield* fail(operation, `Commit ${commitSha} is not part of merge request !${ref.iid}.`);
1357
+ entries = yield* getGitLabPages(call, operation, {
1358
+ ref,
1359
+ endpoint: require_bin.gitLabProjectEndpoint(ref, `/repository/commits/${commit.id}/diff`),
1360
+ item: GitLabDiffEntrySchema,
1361
+ maxPages: DIFF_MAX_PAGES,
1362
+ maxOutputBytes: DIFF_PAGE_MAX_BYTES,
1363
+ timeoutMs: DIFF_TIMEOUT_MS
1364
+ });
1365
+ } else entries = yield* getDiffEntries(call, operation, ref, DIFF_MAX_PAGES);
1366
+ if (entries.truncated) return yield* fail(operation, "This diff has too many files to display.");
1367
+ if (input.expectedHeadSha) yield* verifyHead();
1368
+ return buildGitLabUnifiedDiff(entries.items);
1369
+ });
1370
+ }
1371
+ function isRepositoryFilePath(path) {
1372
+ return path.length > 0 && !path.startsWith("/") && !path.split("/").some((segment) => segment === "" || segment === "." || segment === "..");
1373
+ }
1374
+ function fetchFileAtRevision(call, operation, ref, path, revision) {
1375
+ return call(operation, require_bin.gitLabGet(ref, require_bin.withGitLabQuery(require_bin.gitLabProjectEndpoint(ref, `/repository/files/${encodeURIComponent(path)}/raw`), { ref: revision })), {
1376
+ maxOutputBytes: require_src.CHANGE_REQUEST_FILE_CONTENTS_MAX_BYTES,
1377
+ truncateOutputAtMaxBytes: true
1378
+ }).pipe(effect.Effect.map((output) => output.stdout.includes("\0") ? {
1379
+ contents: null,
1380
+ truncated: false
1381
+ } : {
1382
+ contents: output.stdout,
1383
+ truncated: output.stdoutTruncated
1384
+ }), effect.Effect.catchIf(isStatus(404), () => effect.Effect.succeed({
1385
+ contents: null,
1386
+ truncated: false
1387
+ })));
1388
+ }
1389
+ function fetchGitLabFileContents(call, input) {
1390
+ const operation = "getChangeRequestFileContents";
1391
+ return effect.Effect.gen(function* () {
1392
+ for (const path of [input.path, input.previousPath]) if (path !== void 0 && !isRepositoryFilePath(path)) return yield* fail(operation, `Invalid repository file path: ${path}`);
1393
+ for (const sha of [input.headSha, input.baseSha]) if (sha !== void 0 && !require_bin.isGitSha(sha)) return yield* fail(operation, `Invalid commit SHA: ${sha}`);
1394
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1395
+ let baseSha = input.baseSha;
1396
+ if (!baseSha) {
1397
+ const facts = yield* getGitLabMergeRequestFacts(call, operation, ref);
1398
+ baseSha = facts.diffRefs && facts.diffRefs.head_sha === input.headSha ? facts.diffRefs.base_sha : (yield* getJson(call, operation, require_bin.gitLabGet(ref, require_bin.withGitLabQuery(require_bin.gitLabProjectEndpoint(ref, "/repository/merge_base"), { refs: [facts.targetBranch, input.headSha] })), GitLabCommitSchema)).id;
1399
+ }
1400
+ const [oldSide, newSide] = yield* effect.Effect.all([fetchFileAtRevision(call, operation, ref, input.previousPath ?? input.path, baseSha), fetchFileAtRevision(call, operation, ref, input.path, input.headSha)], { concurrency: 2 });
1401
+ return {
1402
+ path: input.path,
1403
+ oldContents: oldSide.contents,
1404
+ newContents: newSide.contents,
1405
+ truncated: oldSide.truncated || newSide.truncated
1406
+ };
1407
+ });
1408
+ }
1409
+ function parseGitLabVersion(version) {
1410
+ const match = /^(\d+)\.(\d+)/u.exec(version.trim());
1411
+ return match?.[1] && match[2] ? {
1412
+ major: Number(match[1]),
1413
+ minor: Number(match[2])
1414
+ } : null;
1415
+ }
1416
+ function gitLabSupportsReviewerState(version) {
1417
+ const parsed = parseGitLabVersion(version);
1418
+ if (!parsed) return false;
1419
+ return parsed.major > REQUEST_CHANGES_MIN_VERSION.major || parsed.major === REQUEST_CHANGES_MIN_VERSION.major && parsed.minor >= REQUEST_CHANGES_MIN_VERSION.minor;
1420
+ }
1421
+ const GitLabVersionInfoSchema = effect.Schema.Struct({ version: effect.Schema.String });
1422
+ const GitLabCreatedIdSchema = effect.Schema.Struct({ id: effect.Schema.Number });
1423
+ /**
1424
+ * A review is GitLab's pending-draft flow: each comment (and the summary) is
1425
+ * created as a draft note on the reviewed head, then `bulk_publish` publishes
1426
+ * them together with any drafts the viewer started on the web. An approval
1427
+ * carries `sha`, so GitLab refuses it (409) when the head moved.
1428
+ */
1429
+ function submitGitLabReview(call, input) {
1430
+ const operation = "submitChangeRequestReview";
1431
+ return effect.Effect.gen(function* () {
1432
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1433
+ const facts = yield* getGitLabMergeRequestFacts(call, operation, ref);
1434
+ if (facts.headSha !== input.expectedHeadSha) return yield* gitLabStaleHeadError(operation);
1435
+ if (input.event === "request_changes") {
1436
+ const version = yield* getJson(call, operation, require_bin.gitLabGet(ref, "version"), GitLabVersionInfoSchema);
1437
+ if (!gitLabSupportsReviewerState(version.version)) return yield* fail(operation, `This GitLab instance (${version.version}) cannot record "request changes" through its API; it needs GitLab ${REQUEST_CHANGES_MIN_VERSION.major}.${REQUEST_CHANGES_MIN_VERSION.minor} or later.`);
1438
+ }
1439
+ const bodies = [];
1440
+ if (input.comments.length > 0) {
1441
+ const diffRefs = facts.diffRefs;
1442
+ if (!diffRefs) return yield* fail(operation, "GitLab has not computed this merge request's diff yet.");
1443
+ const entries = yield* getDiffEntries(call, operation, ref, DIFF_MAX_PAGES);
1444
+ for (const comment of input.comments) {
1445
+ const built = buildGitLabDraftNoteBody({
1446
+ comment,
1447
+ diffRefs,
1448
+ entries: entries.items
1449
+ });
1450
+ if (effect.Result.isFailure(built)) return yield* fail(operation, built.failure);
1451
+ bodies.push(built.success);
1452
+ }
1453
+ }
1454
+ if ((input.body?.trim() ?? "").length > 0) bodies.push({ note: input.body });
1455
+ const existing = yield* getGitLabPages(call, operation, {
1456
+ ref,
1457
+ endpoint: require_bin.gitLabMergeRequestEndpoint(ref, "/draft_notes"),
1458
+ item: GitLabDraftNoteSchema,
1459
+ maxPages: 1
1460
+ }).pipe(effect.Effect.map((page) => page.items.length));
1461
+ if (input.event === "comment" && bodies.length === 0 && existing === 0) return yield* fail(operation, "Add a comment before submitting a review.");
1462
+ const created = [];
1463
+ const discardCreated = effect.Effect.suspend(() => effect.Effect.forEach([...created], (id) => call(operation, require_bin.gitLabWrite(ref, "DELETE", require_bin.gitLabMergeRequestEndpoint(ref, `/draft_notes/${id}`))).pipe(effect.Effect.ignore), { discard: true }));
1464
+ yield* effect.Effect.forEach(bodies, (body) => call(operation, require_bin.gitLabWrite(ref, "POST", require_bin.gitLabMergeRequestEndpoint(ref, "/draft_notes"), body)).pipe(effect.Effect.flatMap((output) => decodeJson(operation, GitLabCreatedIdSchema, output.stdout)), effect.Effect.tap((draft) => effect.Effect.sync(() => created.push(draft.id)))), { discard: true }).pipe(effect.Effect.tapError(() => discardCreated));
1465
+ if (input.event === "approve") yield* call(operation, require_bin.gitLabWrite(ref, "POST", require_bin.gitLabMergeRequestEndpoint(ref, "/approve"), { sha: input.expectedHeadSha })).pipe(effect.Effect.mapError((error) => error.status === 409 ? gitLabStaleHeadError(operation) : error.status === 401 || error.status === 403 ? fail(operation, "GitLab did not accept your approval: you are not an eligible approver for this merge request.", error.status) : error), effect.Effect.tapError(() => discardCreated));
1466
+ if (created.length + existing > 0 || input.event === "request_changes") yield* call(operation, require_bin.gitLabWrite(ref, "POST", require_bin.gitLabMergeRequestEndpoint(ref, "/draft_notes/bulk_publish"), input.event === "request_changes" ? { reviewer_state: "requested_changes" } : void 0)).pipe(effect.Effect.mapError((error) => input.event === "approve" ? fail(operation, `Approved, but publishing the review comments failed; they are kept as pending drafts. ${error.detail}`, error.status) : error));
1467
+ if (input.event === "request_changes") yield* verifyGitLabChangesRequested(call, operation, ref);
1468
+ const lastId = created.at(-1);
1469
+ return {
1470
+ reviewId: lastId !== void 0 ? `draft-note:${lastId}` : input.event === "approve" ? `approval:${input.expectedHeadSha}` : "draft-notes",
1471
+ state: input.event === "approve" ? "approved" : input.event === "request_changes" ? "changes_requested" : "commented",
1472
+ url: facts.webUrl
1473
+ };
1474
+ });
1475
+ }
1476
+ /**
1477
+ * `bulk_publish` answers 204 even when GitLab's `UpdateReviewerStateService`
1478
+ * refused the state: the viewer cannot update the merge request (a Reporter,
1479
+ * an external contributor), or is not a reviewer and cannot be added (Free
1480
+ * allows one reviewer). The reviewers are re-read so a refused change request
1481
+ * is reported instead of claimed. When that read fails the outcome is unknown
1482
+ * and the submission stands; the next activity read shows what GitLab kept.
1483
+ */
1484
+ function verifyGitLabChangesRequested(call, operation, ref) {
1485
+ return effect.Effect.gen(function* () {
1486
+ const read = yield* effect.Effect.all({
1487
+ viewer: getCurrentUser(call, operation, ref),
1488
+ reviewers: getJson(call, operation, require_bin.gitLabGet(ref, require_bin.gitLabMergeRequestEndpoint(ref, "/reviewers")), effect.Schema.Array(require_bin.GitLabReviewerSchema))
1489
+ }, { concurrency: 2 }).pipe(effect.Effect.option);
1490
+ if (effect.Option.isNone(read)) return;
1491
+ const { viewer, reviewers } = read.value;
1492
+ if (reviewers.find((reviewer) => reviewer.user.id === viewer.id || reviewer.user.username?.toLowerCase() === viewer.username.toLowerCase())?.state?.trim().toLowerCase() === "requested_changes") return;
1493
+ return yield* fail(operation, "Your review was published, but GitLab did not record your change request: you need to be a reviewer of this merge request with permission to update it.");
1494
+ });
1495
+ }
1496
+ function replyToGitLabThread(call, input) {
1497
+ const operation = "replyToReviewThread";
1498
+ return effect.Effect.gen(function* () {
1499
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1500
+ if (!require_bin.isGitLabDiscussionId(input.threadId)) return yield* fail(operation, `Unknown review thread: ${input.threadId}`);
1501
+ yield* call(operation, require_bin.gitLabWrite(ref, "POST", require_bin.gitLabMergeRequestEndpoint(ref, `/discussions/${input.threadId}/notes`), { body: input.body }));
1502
+ return yield* fetchGitLabReviewThread(call, operation, ref, input.threadId);
1503
+ });
1504
+ }
1505
+ function setGitLabThreadResolved(call, input) {
1506
+ const operation = "setReviewThreadResolved";
1507
+ return effect.Effect.gen(function* () {
1508
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1509
+ if (!require_bin.isGitLabDiscussionId(input.threadId)) return yield* fail(operation, `Unknown review thread: ${input.threadId}`);
1510
+ const output = yield* call(operation, require_bin.gitLabWrite(ref, "PUT", require_bin.withGitLabQuery(require_bin.gitLabMergeRequestEndpoint(ref, `/discussions/${input.threadId}`), { resolved: input.resolved })));
1511
+ const discussion = yield* decodeJson(operation, GitLabDiscussionSchema, output.stdout);
1512
+ const resolvable = discussion.notes.filter((note) => note.resolvable === true);
1513
+ const isResolved = resolvable.length > 0 ? resolvable.every((note) => note.resolved === true) : discussion.resolved === true;
1514
+ const resolvedBy = isResolved ? resolvable.map((note) => note.resolved_by?.username?.trim()).findLast(Boolean) : void 0;
1515
+ return {
1516
+ threadId: discussion.id,
1517
+ isResolved,
1518
+ ...resolvedBy ? { resolvedBy } : {}
1519
+ };
1520
+ });
1521
+ }
1522
+ /** Top-level notes, diff notes, and review summaries are all notes on GitLab. */
1523
+ function updateGitLabComment(call, input) {
1524
+ const operation = "updateChangeRequestComment";
1525
+ return effect.Effect.gen(function* () {
1526
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1527
+ if (!require_bin.isGitLabNumericId(input.commentId)) return yield* fail(operation, `Unknown comment: ${input.commentId}`);
1528
+ const endpoint = require_bin.gitLabMergeRequestEndpoint(ref, `/notes/${input.commentId}`);
1529
+ if (input.action === "delete") {
1530
+ yield* call(operation, require_bin.gitLabWrite(ref, "DELETE", endpoint));
1531
+ return {
1532
+ commentId: input.commentId,
1533
+ deleted: true
1534
+ };
1535
+ }
1536
+ yield* call(operation, require_bin.gitLabWrite(ref, "PUT", endpoint, { body: input.body }));
1537
+ return {
1538
+ commentId: input.commentId,
1539
+ deleted: false
1540
+ };
1541
+ });
1542
+ }
1543
+ function addGitLabComment(call, input) {
1544
+ const operation = "addChangeRequestComment";
1545
+ return effect.Effect.gen(function* () {
1546
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1547
+ yield* call(operation, require_bin.gitLabWrite(ref, "POST", require_bin.gitLabMergeRequestEndpoint(ref, "/notes"), { body: input.body }));
1548
+ });
1549
+ }
1550
+ const GitLabUserLookupSchema = effect.Schema.Struct({
1551
+ id: effect.Schema.Number,
1552
+ username: effect.Schema.String
1553
+ });
1554
+ function resolveUserIds(call, operation, ref, logins) {
1555
+ return effect.Effect.forEach(logins, (login) => getJson(call, operation, require_bin.gitLabGet(ref, require_bin.withGitLabQuery("users", { username: login })), effect.Schema.Array(GitLabUserLookupSchema)).pipe(effect.Effect.flatMap((users) => {
1556
+ const match = users.find((user) => user.username.toLowerCase() === login.trim().toLowerCase());
1557
+ return match ? effect.Effect.succeed(match.id) : effect.Effect.fail(fail(operation, `No GitLab user named @${login}.`));
1558
+ })), { concurrency: 4 });
1559
+ }
1560
+ /** The full id list GitLab's update takes: current minus removed plus added. */
1561
+ function nextGitLabUserIds(input) {
1562
+ const removed = new Set(input.removeLogins.map((login) => login.trim().toLowerCase()));
1563
+ const ids = input.current.flatMap((user) => typeof user.id === "number" && !removed.has(user.username?.trim().toLowerCase() ?? "") ? [user.id] : []);
1564
+ for (const id of input.addIds) if (!ids.includes(id)) ids.push(id);
1565
+ return ids.length > 0 ? ids : [0];
1566
+ }
1567
+ const GitLabCancelAutoMergeSchema = effect.Schema.Struct({
1568
+ status: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
1569
+ message: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
1570
+ });
1571
+ function deleteSourceBranch(call, operation, ref, facts) {
1572
+ if (facts.isCrossRepository) return effect.Effect.fail(fail(operation, "The source branch lives in a fork, which Ryco does not delete."));
1573
+ return call(operation, require_bin.gitLabWrite(ref, "DELETE", require_bin.gitLabProjectEndpoint(ref, `/repository/branches/${encodeURIComponent(facts.sourceBranch)}`))).pipe(effect.Effect.asVoid);
1574
+ }
1575
+ /** Apply one lifecycle action; the provider re-reads the detail afterwards. */
1576
+ function updateGitLabMergeRequest(call, input) {
1577
+ const operation = "updateChangeRequest";
1578
+ return effect.Effect.gen(function* () {
1579
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1580
+ const endpoint = require_bin.gitLabMergeRequestEndpoint(ref);
1581
+ const update = (body) => call(operation, require_bin.gitLabWrite(ref, "PUT", endpoint, body)).pipe(effect.Effect.asVoid);
1582
+ const action = input.action;
1583
+ switch (action.kind) {
1584
+ case "edit": {
1585
+ const body = {
1586
+ ...action.title !== void 0 ? { title: action.title } : {},
1587
+ ...action.body !== void 0 ? { description: action.body } : {},
1588
+ ...action.baseRefName !== void 0 ? { target_branch: action.baseRefName } : {}
1589
+ };
1590
+ if (Object.keys(body).length === 0) return yield* fail(operation, "Nothing to update.");
1591
+ return yield* update(body);
1592
+ }
1593
+ case "set-draft": {
1594
+ const facts = yield* getGitLabMergeRequestFacts(call, operation, ref);
1595
+ if (facts.isDraft === action.draft) return;
1596
+ return yield* update({ title: require_bin.gitLabDraftTitle(facts.title, action.draft) });
1597
+ }
1598
+ case "close":
1599
+ yield* update({ state_event: "close" });
1600
+ if (action.deleteBranch === true) {
1601
+ const facts = yield* getGitLabMergeRequestFacts(call, operation, ref);
1602
+ yield* deleteSourceBranch(call, operation, ref, facts);
1603
+ }
1604
+ return;
1605
+ case "reopen": return yield* update({ state_event: "reopen" });
1606
+ case "labels": {
1607
+ const body = {
1608
+ ...action.add.length > 0 ? { add_labels: action.add.join(",") } : {},
1609
+ ...action.remove.length > 0 ? { remove_labels: action.remove.join(",") } : {}
1610
+ };
1611
+ if (Object.keys(body).length === 0) return;
1612
+ return yield* update(body);
1613
+ }
1614
+ case "reviewers":
1615
+ case "assignees": {
1616
+ if (action.add.length === 0 && action.remove.length === 0) return;
1617
+ const facts = yield* getGitLabMergeRequestFacts(call, operation, ref);
1618
+ const addIds = yield* resolveUserIds(call, operation, ref, action.add);
1619
+ const ids = nextGitLabUserIds({
1620
+ current: action.kind === "reviewers" ? facts.reviewers : facts.assignees,
1621
+ removeLogins: action.remove,
1622
+ addIds
1623
+ });
1624
+ return yield* update(action.kind === "reviewers" ? { reviewer_ids: ids } : { assignee_ids: ids });
1625
+ }
1626
+ case "update-branch":
1627
+ if (action.method !== "rebase") return yield* fail(operation, "GitLab updates a merge request's branch by rebasing it; merging the target branch in is not available.");
1628
+ if ((yield* getGitLabMergeRequestFacts(call, operation, ref)).headSha !== action.expectedHeadSha) return yield* gitLabStaleHeadError(operation);
1629
+ yield* call(operation, require_bin.gitLabWrite(ref, "PUT", require_bin.gitLabMergeRequestEndpoint(ref, "/rebase")));
1630
+ return;
1631
+ case "auto-merge": {
1632
+ if (!action.enabled) {
1633
+ const output = yield* call(operation, require_bin.gitLabWrite(ref, "POST", require_bin.gitLabMergeRequestEndpoint(ref, "/cancel_merge_when_pipeline_succeeds")));
1634
+ const result = yield* decodeJson(operation, GitLabCancelAutoMergeSchema, output.stdout);
1635
+ if (result.status?.trim().toLowerCase() === "error") return yield* fail(operation, result.message?.trim() || "GitLab could not cancel the automatic merge.");
1636
+ return;
1637
+ }
1638
+ const [facts, project] = yield* effect.Effect.all([getGitLabMergeRequestFacts(call, operation, ref), getProject(call, operation, ref)], { concurrency: 2 });
1639
+ if (action.expectedHeadSha && facts.headSha !== action.expectedHeadSha) return yield* gitLabStaleHeadError(operation);
1640
+ if (action.mergeMethod && !require_bin.gitLabMergeCapabilities(project)[action.mergeMethod]) return yield* fail(operation, `The ${action.mergeMethod} merge method is not available for this project.`);
1641
+ const sha = action.expectedHeadSha ?? facts.headSha;
1642
+ yield* call(operation, require_bin.gitLabWrite(ref, "PUT", require_bin.gitLabMergeRequestEndpoint(ref, "/merge"), {
1643
+ auto_merge: true,
1644
+ merge_when_pipeline_succeeds: true,
1645
+ ...sha ? { sha } : {},
1646
+ ...action.mergeMethod ? { squash: action.mergeMethod === "squash" } : {}
1647
+ })).pipe(effect.Effect.mapError((error) => mergeError(operation, error)));
1648
+ return;
1649
+ }
1650
+ case "delete-branch": {
1651
+ const facts = yield* getGitLabMergeRequestFacts(call, operation, ref);
1652
+ return yield* deleteSourceBranch(call, operation, ref, facts);
1653
+ }
1654
+ }
1655
+ });
1656
+ }
1657
+ function mergeError(operation, error) {
1658
+ switch (error.status) {
1659
+ case 409: return gitLabStaleHeadError(operation);
1660
+ case 401: return fail(operation, "You do not have permission to merge this merge request.", 401);
1661
+ case 405: return fail(operation, "GitLab cannot merge this merge request right now (HTTP 405). Check its pipeline, approvals, open threads, conflicts and draft status.", 405);
1662
+ case 422: return fail(operation, `GitLab could not merge the branch (HTTP 422). ${error.detail}`, 422);
1663
+ default: return error;
1664
+ }
1665
+ }
1666
+ const GitLabMergeResultSchema = effect.Schema.Struct({ state: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)) });
1667
+ /**
1668
+ * `PUT .../merge` with `sha` (GitLab refuses a moved head with 409). The
1669
+ * merge method is the project's (merge commit or fast-forward), so only it
1670
+ * and squash are accepted. A merge request GitLab queues (merge train,
1671
+ * pending pipeline) reports `enqueued`.
1672
+ */
1673
+ function mergeGitLabMergeRequest(call, input) {
1674
+ const operation = "mergeChangeRequest";
1675
+ return effect.Effect.gen(function* () {
1676
+ const ref = yield* requireGitLabMergeRequestRef(operation, input.reference);
1677
+ const [facts, project] = yield* effect.Effect.all([getGitLabMergeRequestFacts(call, operation, ref), getProject(call, operation, ref)], { concurrency: 2 });
1678
+ if (input.expectedHeadSha && facts.headSha !== input.expectedHeadSha) return yield* gitLabStaleHeadError(operation);
1679
+ if (!require_bin.gitLabMergeCapabilities(project)[input.mergeMethod]) return yield* fail(operation, `The ${input.mergeMethod} merge method is not available for this project.`);
1680
+ const output = yield* call(operation, require_bin.gitLabWrite(ref, "PUT", require_bin.gitLabMergeRequestEndpoint(ref, "/merge"), {
1681
+ squash: input.mergeMethod === "squash",
1682
+ ...input.expectedHeadSha ? { sha: input.expectedHeadSha } : {},
1683
+ ...input.deleteBranch !== void 0 ? { should_remove_source_branch: input.deleteBranch } : {}
1684
+ })).pipe(effect.Effect.mapError((error) => mergeError(operation, error)));
1685
+ return { outcome: (yield* decodeJson(operation, GitLabMergeResultSchema, output.stdout)).state?.trim().toLowerCase() === "merged" ? "merged" : "enqueued" };
1686
+ });
1687
+ }
1688
+ function toDetailCommit(commit) {
1689
+ const oid = commit.id.trim();
1690
+ if (!oid) return null;
1691
+ const author = commit.author_name?.trim();
1692
+ const committedDate = commit.committed_date?.trim();
1693
+ return {
1694
+ oid,
1695
+ shortOid: commit.short_id?.trim() || oid.slice(0, 8),
1696
+ messageHeadline: commit.title?.trim() ?? (commit.message ?? "").split("\n")[0]?.trim() ?? "",
1697
+ ...committedDate ? { committedDate } : {},
1698
+ ...author ? { author } : {}
1699
+ };
1700
+ }
1701
+ const GitLabCommitParentsSchema = effect.Schema.Struct({
1702
+ id: effect.Schema.String,
1703
+ parent_ids: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Array(effect.Schema.String)))
1704
+ });
1705
+ /**
1706
+ * `head_pipeline` when it verifies the current head: on the head commit, or
1707
+ * on a merged-results or merge-train commit that has the head as a parent.
1708
+ * Any other SHA is an earlier head's pipeline (GitLab keeps it after a push
1709
+ * that started none), which would show stale checks, so it is dropped; so is
1710
+ * one whose merge commit cannot be read.
1711
+ */
1712
+ function resolveGitLabHeadPipeline(call, operation, ref, facts) {
1713
+ const pipeline = facts.headPipeline;
1714
+ const head = facts.headSha?.toLowerCase() ?? null;
1715
+ const sha = pipeline?.sha?.toLowerCase() ?? null;
1716
+ if (!pipeline || !sha || !head || !require_bin.isGitSha(sha)) return effect.Effect.succeed(null);
1717
+ const resolved = {
1718
+ id: pipeline.id,
1719
+ sha,
1720
+ runName: gitLabPipelineRunName(pipeline)
1721
+ };
1722
+ if (sha === head) return effect.Effect.succeed(resolved);
1723
+ return optional(getJson(call, operation, require_bin.gitLabGet(ref, require_bin.gitLabProjectEndpoint(ref, `/repository/commits/${sha}`)), GitLabCommitParentsSchema), null).pipe(effect.Effect.map((commit) => commit?.parent_ids?.some((parent) => parent.toLowerCase() === head) === true ? resolved : null));
1724
+ }
1725
+ /**
1726
+ * Readiness facts for the detail: reviewers' states and approvals, the merge
1727
+ * state, the project's merge methods, head pipeline statuses and commits.
1728
+ * Each read is optional; a failed one leaves its facts out (never guessed).
1729
+ */
1730
+ function fetchGitLabDetailReadiness(call, facts, reference) {
1731
+ const operation = "getChangeRequestDetail";
1732
+ return effect.Effect.gen(function* () {
1733
+ const ref = yield* requireGitLabMergeRequestRef(operation, reference);
1734
+ const headPipeline = yield* resolveGitLabHeadPipeline(call, operation, ref, facts);
1735
+ const statusSha = headPipeline?.sha ?? facts.headSha;
1736
+ const read = yield* effect.Effect.all({
1737
+ reviewers: optional(getJson(call, operation, require_bin.gitLabGet(ref, require_bin.gitLabMergeRequestEndpoint(ref, "/reviewers")), effect.Schema.Array(require_bin.GitLabReviewerSchema)), null),
1738
+ approvals: optional(getJson(call, operation, require_bin.gitLabGet(ref, require_bin.gitLabMergeRequestEndpoint(ref, "/approvals")), require_bin.GitLabApprovalStateSchema), null),
1739
+ project: optional(getProject(call, operation, ref), null),
1740
+ statuses: statusSha && require_bin.isGitSha(statusSha) ? optional(getGitLabPages(call, operation, {
1741
+ ref,
1742
+ endpoint: require_bin.gitLabProjectEndpoint(ref, `/repository/commits/${statusSha}/statuses`),
1743
+ item: GitLabCommitStatusSchema,
1744
+ maxPages: 1
1745
+ }).pipe(effect.Effect.map((page) => page.items)), null) : effect.Effect.succeed(null),
1746
+ headJobs: headPipeline ? optional(getGitLabPages(call, operation, {
1747
+ ref,
1748
+ endpoint: require_bin.gitLabProjectEndpoint(ref, `/pipelines/${headPipeline.id}/jobs`),
1749
+ item: GitLabJobSchema,
1750
+ maxPages: 1
1751
+ }).pipe(effect.Effect.map((page) => page.items)), null) : effect.Effect.succeed(null),
1752
+ commits: optional(getGitLabPages(call, operation, {
1753
+ ref,
1754
+ endpoint: require_bin.gitLabMergeRequestEndpoint(ref, "/commits"),
1755
+ item: GitLabCommitSchema,
1756
+ maxPages: 1
1757
+ }).pipe(effect.Effect.map((page) => page.items)), null)
1758
+ }, { concurrency: 6 });
1759
+ const reviewerStates = read.reviewers !== null ? require_bin.gitLabReviewerStates({
1760
+ reviewers: read.reviewers,
1761
+ approvals: read.approvals
1762
+ }) : null;
1763
+ const reviewDecision = reviewerStates !== null && read.approvals !== null ? require_bin.gitLabReviewDecision({
1764
+ reviewerStates,
1765
+ approvals: read.approvals
1766
+ }) : void 0;
1767
+ const mergeStateStatus = facts.isDraft ? "draft" : require_bin.gitLabMergeStateStatus(facts.detailedMergeStatus);
1768
+ const reviewers = facts.reviewers.flatMap((user) => user.username?.trim() ? [user.username.trim()] : []);
1769
+ const commits = read.commits?.flatMap((commit) => {
1770
+ const mapped = toDetailCommit(commit);
1771
+ return mapped ? [mapped] : [];
1772
+ }).toReversed();
1773
+ const checkRollup = read.statuses !== null ? gitLabCheckRollup(read.statuses, headPipeline && read.headJobs ? {
1774
+ runName: headPipeline.runName,
1775
+ jobs: read.headJobs
1776
+ } : null) : null;
1777
+ return {
1778
+ ...facts.headSha ? { headSha: facts.headSha } : {},
1779
+ ...reviewerStates !== null ? { reviewerStates } : {},
1780
+ ...reviewDecision !== void 0 ? { reviewDecision } : {},
1781
+ ...mergeStateStatus ? { mergeStateStatus } : {},
1782
+ ...read.project !== null ? { mergeCapabilities: require_bin.gitLabMergeCapabilities(read.project) } : {},
1783
+ ...facts.state === "open" && read.project !== null ? { autoMerge: require_bin.gitLabAutoMerge({
1784
+ facts,
1785
+ project: read.project
1786
+ }) } : {},
1787
+ ...facts.forceRemoveSourceBranch !== null ? { deleteBranchOnMerge: facts.forceRemoveSourceBranch } : {},
1788
+ ...checkRollup !== null ? { checkRollup } : {},
1789
+ ...commits && commits.length > 0 ? { commits } : {},
1790
+ ...reviewers.length > 0 ? { reviewers } : {},
1791
+ ...facts.closedAt && facts.state === "closed" ? { closedAt: facts.closedAt } : {},
1792
+ ...facts.mergedAt ? { mergedAt: facts.mergedAt } : {},
1793
+ ...facts.mergedBy && facts.state === "merged" ? { mergedBy: facts.mergedBy } : {},
1794
+ ...facts.changesCount !== null ? { changedFiles: facts.changesCount } : {}
1795
+ };
1796
+ });
1797
+ }
1798
+ const STATE_QUERY = {
1799
+ open: "opened",
1800
+ closed: "closed",
1801
+ merged: "merged",
1802
+ all: "all"
1803
+ };
1804
+ /**
1805
+ * A server-side filtered list: involvement relative to the authenticated
1806
+ * user (`author_username`, `reviewer_username`, `assignee_id`), free-text
1807
+ * `search`, state, and source branch. GitLab has no "mentioned" or
1808
+ * "involved" filter, so those fail instead of returning everything.
1809
+ */
1810
+ function listGitLabMergeRequestsFiltered(call, input) {
1811
+ const operation = "listChangeRequests";
1812
+ return effect.Effect.gen(function* () {
1813
+ let involvementQuery = {};
1814
+ if (input.involvement !== void 0) {
1815
+ if (input.involvement === "mentioned" || input.involvement === "involved") return yield* fail(operation, `GitLab cannot filter merge requests by "${input.involvement}"; use authored, review requested, or assigned.`);
1816
+ const user = yield* getCurrentUser(call, operation, null);
1817
+ involvementQuery = input.involvement === "authored" ? { author_username: user.username } : input.involvement === "review-requested" ? { reviewer_username: user.username } : { assignee_id: user.id };
1818
+ }
1819
+ const query = input.query?.trim();
1820
+ const output = yield* call(operation, require_bin.gitLabGet(null, require_bin.withGitLabQuery(require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, "/merge_requests"), {
1821
+ state: STATE_QUERY[input.state],
1822
+ ...involvementQuery,
1823
+ ...query ? { search: query } : {},
1824
+ ...input.sourceBranch ? { source_branch: input.sourceBranch } : {},
1825
+ order_by: "updated_at",
1826
+ sort: "desc",
1827
+ per_page: Math.min(Math.max(input.limit ?? 20, 1), 100)
1828
+ })), { maxOutputBytes: LIST_PAGE_MAX_BYTES });
1829
+ const decoded = require_bin.decodeGitLabMergeRequestListJson(output.stdout.trim() || "[]");
1830
+ return effect.Result.isSuccess(decoded) ? decoded.success : yield* fail(operation, "GitLab returned an unexpected merge request list.");
1831
+ });
1832
+ }
1833
+ /** One rollup per list row from the project's recent pipelines (one request for the page). */
1834
+ function enrichGitLabListRowsWithPipelines(call, rows) {
1835
+ if (!rows.some((row) => row.state === "open")) return effect.Effect.succeed(rows);
1836
+ return optional(getGitLabPages(call, "listChangeRequests", {
1837
+ ref: null,
1838
+ endpoint: require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, "/pipelines"),
1839
+ item: GitLabPipelineSchema,
1840
+ maxPages: 1
1841
+ }).pipe(effect.Effect.map((page) => page.items)), []).pipe(effect.Effect.map((pipelines) => rows.map((row) => {
1842
+ if (row.state !== "open" || row.checkRollup) return row;
1843
+ const checkRollup = gitLabListRowRollup(pipelines, {
1844
+ iid: row.number,
1845
+ sourceBranch: row.headRefName,
1846
+ headSha: row.headSha ?? null
1847
+ });
1848
+ return checkRollup ? {
1849
+ ...row,
1850
+ checkRollup
1851
+ } : row;
1852
+ })));
1853
+ }
1854
+ const GitLabLabelSchema = effect.Schema.Struct({
1855
+ name: effect.Schema.String,
1856
+ color: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
1857
+ description: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
1858
+ });
1859
+ const GitLabMemberSchema = effect.Schema.Struct({
1860
+ username: effect.Schema.String,
1861
+ name: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
1862
+ avatar_url: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
1863
+ state: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
1864
+ });
1865
+ function listGitLabLabels(call) {
1866
+ return getGitLabPages(call, "listLabels", {
1867
+ ref: null,
1868
+ endpoint: require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, "/labels"),
1869
+ item: GitLabLabelSchema,
1870
+ maxPages: 3
1871
+ }).pipe(effect.Effect.map((page) => page.items.flatMap((label) => {
1872
+ const name = label.name.trim();
1873
+ if (!name) return [];
1874
+ const color = label.color?.trim().replace(/^#/u, "").toLowerCase();
1875
+ const description = label.description?.trim();
1876
+ return [{
1877
+ name,
1878
+ ...color && /^[0-9a-f]{3,8}$/u.test(color) ? { color } : {},
1879
+ ...description ? { description } : {}
1880
+ }];
1881
+ })));
1882
+ }
1883
+ /** Active members, inherited ones included (reviewer and assignee candidates). */
1884
+ function listGitLabAssignees(call) {
1885
+ return getGitLabPages(call, "listAssignees", {
1886
+ ref: null,
1887
+ endpoint: require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, "/members/all"),
1888
+ item: GitLabMemberSchema,
1889
+ maxPages: 3
1890
+ }).pipe(effect.Effect.map((page) => page.items.flatMap((member) => {
1891
+ const login = member.username.trim();
1892
+ if (!login || member.state && member.state !== "active") return [];
1893
+ const displayName = member.name?.trim();
1894
+ const avatarUrl = member.avatar_url?.trim();
1895
+ return [{
1896
+ login,
1897
+ ...displayName ? { displayName } : {},
1898
+ ...avatarUrl ? { avatarUrl } : {}
1899
+ }];
1900
+ })));
1901
+ }
1902
+ function requireNumericId(operation, label, value) {
1903
+ return require_bin.isGitLabNumericId(value) ? effect.Effect.succeed(value) : effect.Effect.fail(fail(operation, `Unknown ${label}: ${value}`));
1904
+ }
1905
+ /**
1906
+ * Pipelines for a merge request's head (`pullRequestNumber`), a commit, or a
1907
+ * branch's newest commit, newest first.
1908
+ */
1909
+ function listGitLabWorkflowRuns(call, input) {
1910
+ const operation = "listWorkflowRuns";
1911
+ return effect.Effect.gen(function* () {
1912
+ const perPage = Math.min(Math.max(input.limit ?? 50, 1), 100);
1913
+ const project = require_bin.CURRENT_GITLAB_PROJECT;
1914
+ let pipelines;
1915
+ let sourceHeadOf = () => null;
1916
+ let headSha = input.commitSha?.trim() || null;
1917
+ if (headSha !== null && !require_bin.isGitSha(headSha)) return yield* fail(operation, `Invalid commit SHA: ${headSha}`);
1918
+ if (input.pullRequestNumber !== void 0) {
1919
+ const ref = {
1920
+ ...project,
1921
+ iid: input.pullRequestNumber
1922
+ };
1923
+ const facts = yield* getGitLabMergeRequestFacts(call, operation, ref);
1924
+ headSha = headSha ?? facts.headSha;
1925
+ const { page, headPipeline } = yield* effect.Effect.all({
1926
+ page: getGitLabPages(call, operation, {
1927
+ ref,
1928
+ endpoint: require_bin.gitLabMergeRequestEndpoint(ref, "/pipelines"),
1929
+ item: GitLabPipelineSchema,
1930
+ maxPages: 1,
1931
+ perPage
1932
+ }),
1933
+ headPipeline: input.commitSha ? effect.Effect.succeed(null) : resolveGitLabHeadPipeline(call, operation, ref, facts)
1934
+ }, { concurrency: 2 });
1935
+ pipelines = selectGitLabHeadPipelines(page.items, {
1936
+ headSha,
1937
+ headPipelineId: headPipeline?.id ?? null
1938
+ });
1939
+ sourceHeadOf = (pipeline) => pipeline.id === headPipeline?.id ? facts.headSha : null;
1940
+ } else if (headSha !== null) pipelines = (yield* getGitLabPages(call, operation, {
1941
+ ref: null,
1942
+ endpoint: require_bin.withGitLabQuery(require_bin.gitLabProjectEndpoint(project, "/pipelines"), { sha: headSha }),
1943
+ item: GitLabPipelineSchema,
1944
+ maxPages: 1,
1945
+ perPage
1946
+ })).items;
1947
+ else if (input.branch?.trim()) {
1948
+ const page = yield* getGitLabPages(call, operation, {
1949
+ ref: null,
1950
+ endpoint: require_bin.withGitLabQuery(require_bin.gitLabProjectEndpoint(project, "/pipelines"), { ref: input.branch.trim() }),
1951
+ item: GitLabPipelineSchema,
1952
+ maxPages: 1,
1953
+ perPage
1954
+ });
1955
+ headSha = page.items[0]?.sha ?? null;
1956
+ pipelines = page.items.filter((pipeline) => pipeline.sha === headSha);
1957
+ } else pipelines = [];
1958
+ return {
1959
+ provider: "gitlab",
1960
+ repository: effect.Option.none(),
1961
+ pullRequestNumber: input.pullRequestNumber !== void 0 ? effect.Option.some(input.pullRequestNumber) : effect.Option.none(),
1962
+ headSha: headSha ? effect.Option.some(headSha) : effect.Option.none(),
1963
+ runs: pipelines.flatMap((pipeline) => {
1964
+ const run = gitLabWorkflowRun(pipeline, sourceHeadOf(pipeline));
1965
+ return run ? [run] : [];
1966
+ })
1967
+ };
1968
+ });
1969
+ }
1970
+ function listGitLabPipelineJobs(call, runId) {
1971
+ const operation = "getWorkflowRunJobs";
1972
+ return effect.Effect.gen(function* () {
1973
+ yield* requireNumericId(operation, "pipeline", runId);
1974
+ return {
1975
+ provider: "gitlab",
1976
+ runId,
1977
+ jobs: (yield* getGitLabPages(call, operation, {
1978
+ ref: null,
1979
+ endpoint: require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, `/pipelines/${runId}/jobs`),
1980
+ item: GitLabJobSchema,
1981
+ maxPages: 3
1982
+ })).items.toSorted((left, right) => left.id - right.id).map(gitLabWorkflowJob)
1983
+ };
1984
+ });
1985
+ }
1986
+ function getGitLabJobLog(call, input) {
1987
+ const operation = "getWorkflowJobLog";
1988
+ return effect.Effect.gen(function* () {
1989
+ yield* requireNumericId(operation, "job", input.jobId);
1990
+ const output = yield* call(operation, require_bin.gitLabGet(null, require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, `/jobs/${input.jobId}/trace`)), {
1991
+ maxOutputBytes: JOB_LOG_TAIL_BYTES,
1992
+ keepOutputTail: true,
1993
+ timeoutMs: 6e4
1994
+ });
1995
+ const tail = gitLabJobLogTail(output.stdout, { startCut: output.stdoutTruncated });
1996
+ return {
1997
+ provider: "gitlab",
1998
+ runId: input.runId,
1999
+ jobId: input.jobId,
2000
+ log: tail.log,
2001
+ truncated: tail.truncated || output.stdoutTruncated
2002
+ };
2003
+ });
2004
+ }
2005
+ /** `failed-jobs` retries a pipeline's failed and canceled jobs; `job` retries one. */
2006
+ function rerunGitLabPipeline(call, input) {
2007
+ const operation = "rerunWorkflow";
2008
+ return effect.Effect.gen(function* () {
2009
+ if (input.target === "job") {
2010
+ yield* requireNumericId(operation, "job", input.jobId);
2011
+ yield* call(operation, require_bin.gitLabWrite(require_bin.CURRENT_GITLAB_PROJECT, "POST", require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, `/jobs/${input.jobId}/retry`)));
2012
+ return {
2013
+ provider: "gitlab",
2014
+ runId: input.runId,
2015
+ target: "job",
2016
+ jobId: input.jobId
2017
+ };
2018
+ }
2019
+ yield* requireNumericId(operation, "pipeline", input.runId);
2020
+ yield* call(operation, require_bin.gitLabWrite(require_bin.CURRENT_GITLAB_PROJECT, "POST", require_bin.gitLabProjectEndpoint(require_bin.CURRENT_GITLAB_PROJECT, `/pipelines/${input.runId}/retry`)));
2021
+ return {
2022
+ provider: "gitlab",
2023
+ runId: input.runId,
2024
+ target: "failed-jobs"
2025
+ };
2026
+ });
2027
+ }
2028
+ //#endregion
2029
+ //#region src/sourceControl/GitLabSourceControlProvider.ts
2030
+ function providerError(operation, cause) {
2031
+ return new require_src.SourceControlProviderError({
2032
+ provider: "gitlab",
2033
+ operation,
2034
+ detail: cause.detail,
2035
+ cause
2036
+ });
2037
+ }
2038
+ function toChangeRequest(summary) {
2039
+ return {
2040
+ provider: "gitlab",
2041
+ number: summary.number,
2042
+ title: summary.title,
2043
+ url: summary.url,
2044
+ baseRefName: summary.baseRefName,
2045
+ headRefName: summary.headRefName,
2046
+ state: summary.state ?? "open",
2047
+ updatedAt: summary.updatedAt ?? effect.Option.none(),
2048
+ ...summary.isCrossRepository !== void 0 ? { isCrossRepository: summary.isCrossRepository } : {},
2049
+ ...summary.headRepositoryNameWithOwner !== void 0 ? { headRepositoryNameWithOwner: summary.headRepositoryNameWithOwner } : {},
2050
+ ...summary.headRepositoryOwnerLogin !== void 0 ? { headRepositoryOwnerLogin: summary.headRepositoryOwnerLogin } : {},
2051
+ ...summary.isDraft !== void 0 ? { isDraft: summary.isDraft } : {},
2052
+ ...summary.author ? { author: summary.author } : {},
2053
+ ...summary.assignees && summary.assignees.length > 0 ? { assignees: summary.assignees } : {},
2054
+ ...summary.labels && summary.labels.length > 0 ? { labels: summary.labels } : {},
2055
+ ...summary.commentsCount !== void 0 ? { commentsCount: summary.commentsCount } : {},
2056
+ ...summary.headSha ? { headSha: summary.headSha } : {},
2057
+ ...summary.mergeability ? { mergeability: summary.mergeability } : {},
2058
+ ...summary.mergeStateStatus ? { mergeStateStatus: summary.mergeStateStatus } : {},
2059
+ ...summary.reviewDecision ? { reviewDecision: summary.reviewDecision } : {},
2060
+ ...summary.createdAt ? { createdAt: summary.createdAt } : {}
2061
+ };
2062
+ }
2063
+ function toIssueSummary(raw) {
2064
+ return {
2065
+ provider: "gitlab",
2066
+ number: raw.number,
2067
+ title: raw.title,
2068
+ url: raw.url,
2069
+ state: raw.state,
2070
+ ...raw.author ? { author: raw.author } : {},
2071
+ updatedAt: raw.updatedAt.pipe(effect.Option.map((s) => effect.DateTime.fromDateUnsafe(new Date(s)))),
2072
+ labels: raw.labels.map((name) => ({ name }))
2073
+ };
2074
+ }
2075
+ function toIssueDetail(raw, options) {
2076
+ const content = options.fullContent ? {
2077
+ body: raw.body,
2078
+ comments: raw.comments,
2079
+ truncated: false
2080
+ } : require_src.truncateSourceControlDetailContent({
2081
+ body: raw.body,
2082
+ comments: raw.comments
2083
+ });
2084
+ return {
2085
+ ...toIssueSummary(raw),
2086
+ body: content.body,
2087
+ comments: content.comments.map((c) => ({
2088
+ author: c.author,
2089
+ body: c.body,
2090
+ createdAt: effect.DateTime.fromDateUnsafe(new Date(c.createdAt))
2091
+ })),
2092
+ truncated: content.truncated
2093
+ };
2094
+ }
2095
+ function toChangeRequestDetail(raw, options) {
2096
+ const content = options.fullContent ? {
2097
+ body: raw.body,
2098
+ comments: raw.comments,
2099
+ truncated: false
2100
+ } : require_src.truncateSourceControlDetailContent({
2101
+ body: raw.body,
2102
+ comments: raw.comments
2103
+ });
2104
+ return {
2105
+ ...toChangeRequest(raw),
2106
+ body: content.body,
2107
+ comments: content.comments.map((c) => ({
2108
+ author: c.author,
2109
+ body: c.body,
2110
+ createdAt: effect.DateTime.fromDateUnsafe(new Date(c.createdAt))
2111
+ })),
2112
+ truncated: content.truncated
2113
+ };
2114
+ }
2115
+ const make = effect.Effect.fn("makeGitLabSourceControlProvider")(function* () {
2116
+ const gitlab = yield* require_bin.GitLabCli;
2117
+ /** The page runner for one checkout: `glab api` resolves `:fullpath` from `cwd`. */
2118
+ const callIn = (cwd) => (operation, request, options) => gitlab.api({
2119
+ cwd,
2120
+ operation,
2121
+ request,
2122
+ ...options
2123
+ });
2124
+ const run = (operation, effect$1) => effect$1.pipe(effect.Effect.mapError((error) => providerError(operation, error)));
2125
+ const getChangeRequestDetail = (input) => effect.Effect.gen(function* () {
2126
+ const raw = yield* gitlab.getMergeRequestDetail({
2127
+ cwd: input.cwd,
2128
+ reference: input.reference
2129
+ });
2130
+ const detail = toChangeRequestDetail(raw, { fullContent: input.fullContent ?? false });
2131
+ if (!raw.facts) return detail;
2132
+ const readiness = yield* fetchGitLabDetailReadiness(callIn(input.cwd), raw.facts, String(raw.number));
2133
+ return {
2134
+ ...detail,
2135
+ ...readiness
2136
+ };
2137
+ }).pipe(effect.Effect.mapError((error) => providerError("getChangeRequestDetail", error)));
2138
+ const freshDetail = (input) => getChangeRequestDetail({
2139
+ cwd: input.cwd,
2140
+ reference: input.reference,
2141
+ fullContent: true
2142
+ });
2143
+ const provider = require_bin.SourceControlProvider.of({
2144
+ kind: "gitlab",
2145
+ listChangeRequests: (input) => {
2146
+ const source = require_bin.sourceControlRefFromInput(input);
2147
+ const query = input.query?.trim() ?? "";
2148
+ const call = callIn(input.cwd);
2149
+ return (input.involvement !== void 0 || query.length > 0 ? listGitLabMergeRequestsFiltered(call, {
2150
+ state: input.state,
2151
+ involvement: input.involvement,
2152
+ query,
2153
+ sourceBranch: require_bin.sourceBranch(input) || void 0,
2154
+ limit: input.limit
2155
+ }) : gitlab.listMergeRequests({
2156
+ cwd: input.cwd,
2157
+ headSelector: input.headSelector,
2158
+ ...source ? { source } : {},
2159
+ state: input.state,
2160
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2161
+ })).pipe(effect.Effect.map((items) => items.map(toChangeRequest)), effect.Effect.flatMap((rows) => input.headSelector.trim().length === 0 && input.includeStackSummary !== false ? enrichGitLabListRowsWithPipelines(call, rows) : effect.Effect.succeed(rows)), effect.Effect.mapError((error) => providerError("listChangeRequests", error)));
2162
+ },
2163
+ getChangeRequest: (input) => gitlab.getMergeRequest(input).pipe(effect.Effect.map(toChangeRequest), effect.Effect.mapError((error) => providerError("getChangeRequest", error))),
2164
+ createChangeRequest: (input) => {
2165
+ const source = require_bin.sourceControlRefFromInput(input);
2166
+ return gitlab.createMergeRequest({
2167
+ cwd: input.cwd,
2168
+ baseBranch: input.baseRefName,
2169
+ headSelector: input.headSelector,
2170
+ ...source ? { source } : {},
2171
+ ...input.target ? { target: input.target } : {},
2172
+ title: input.title,
2173
+ bodyFile: input.bodyFile,
2174
+ ...input.draft === true ? { draft: true } : {}
2175
+ }).pipe(effect.Effect.mapError((error) => providerError("createChangeRequest", error)));
2176
+ },
2177
+ getRepositoryCloneUrls: (input) => gitlab.getRepositoryCloneUrls(input).pipe(effect.Effect.mapError((error) => providerError("getRepositoryCloneUrls", error))),
2178
+ createRepository: (input) => gitlab.createRepository(input).pipe(effect.Effect.mapError((error) => providerError("createRepository", error))),
2179
+ getDefaultBranch: (input) => gitlab.getDefaultBranch(input).pipe(effect.Effect.mapError((error) => providerError("getDefaultBranch", error))),
2180
+ checkoutChangeRequest: (input) => gitlab.checkoutMergeRequest(input).pipe(effect.Effect.mapError((error) => providerError("checkoutChangeRequest", error))),
2181
+ listIssues: (input) => gitlab.listIssues({
2182
+ cwd: input.cwd,
2183
+ state: input.state,
2184
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2185
+ }).pipe(effect.Effect.map((items) => items.map(toIssueSummary)), effect.Effect.mapError((error) => providerError("listIssues", error))),
2186
+ getIssue: (input) => gitlab.getIssue({
2187
+ cwd: input.cwd,
2188
+ reference: input.reference
2189
+ }).pipe(effect.Effect.map((raw) => toIssueDetail(raw, { fullContent: input.fullContent ?? false })), effect.Effect.mapError((error) => providerError("getIssue", error))),
2190
+ addIssueComment: () => effect.Effect.fail(new require_src.SourceControlProviderError({
2191
+ provider: "gitlab",
2192
+ operation: "addIssueComment",
2193
+ detail: "Not implemented for gitlab"
2194
+ })),
2195
+ addIssueCommentReaction: () => effect.Effect.fail(new require_src.SourceControlProviderError({
2196
+ provider: "gitlab",
2197
+ operation: "addIssueCommentReaction",
2198
+ detail: "Not implemented for gitlab"
2199
+ })),
2200
+ searchIssues: (input) => gitlab.searchIssues({
2201
+ cwd: input.cwd,
2202
+ query: input.query,
2203
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2204
+ }).pipe(effect.Effect.map((items) => items.map(toIssueSummary)), effect.Effect.mapError((error) => providerError("searchIssues", error))),
2205
+ searchChangeRequests: (input) => gitlab.searchMergeRequests({
2206
+ cwd: input.cwd,
2207
+ query: input.query,
2208
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2209
+ }).pipe(effect.Effect.map((items) => items.map(toChangeRequest)), effect.Effect.mapError((error) => providerError("searchChangeRequests", error))),
2210
+ getChangeRequestDetail,
2211
+ addChangeRequestComment: (input) => run("addChangeRequestComment", addGitLabComment(callIn(input.cwd), input)).pipe(effect.Effect.andThen(() => freshDetail(input))),
2212
+ addChangeRequestCommentReaction: () => effect.Effect.fail(new require_src.SourceControlProviderError({
2213
+ provider: "gitlab",
2214
+ operation: "addChangeRequestCommentReaction",
2215
+ detail: "GitLab does not support comment reactions."
2216
+ })),
2217
+ getChangeRequestDiff: (input) => run("getChangeRequestDiff", fetchGitLabChangeRequestDiff(callIn(input.cwd), input)),
2218
+ mergeChangeRequest: (input) => run("mergeChangeRequest", mergeGitLabMergeRequest(callIn(input.cwd), input)),
2219
+ getChangeRequestActivity: (input) => run("getChangeRequestActivity", fetchGitLabChangeRequestActivity(callIn(input.cwd), input.reference)),
2220
+ getChangeRequestFileContents: ({ context: _context, ...input }) => run("getChangeRequestFileContents", fetchGitLabFileContents(callIn(input.cwd), input)),
2221
+ submitChangeRequestReview: ({ context: _context, ...input }) => run("submitChangeRequestReview", submitGitLabReview(callIn(input.cwd), input)),
2222
+ replyToReviewThread: (input) => run("replyToReviewThread", replyToGitLabThread(callIn(input.cwd), input)).pipe(effect.Effect.map((thread) => ({ thread }))),
2223
+ setReviewThreadResolved: (input) => run("setReviewThreadResolved", setGitLabThreadResolved(callIn(input.cwd), input)),
2224
+ updateChangeRequestComment: ({ context: _context, ...input }) => run("updateChangeRequestComment", updateGitLabComment(callIn(input.cwd), input)),
2225
+ updateChangeRequest: (input) => run("updateChangeRequest", updateGitLabMergeRequest(callIn(input.cwd), input)).pipe(effect.Effect.andThen(() => freshDetail(input)), effect.Effect.map((detail) => ({ detail }))),
2226
+ createIssue: () => effect.Effect.fail(new require_src.SourceControlProviderError({
2227
+ provider: "gitlab",
2228
+ operation: "createIssue",
2229
+ detail: "Not implemented in Phase 1"
2230
+ })),
2231
+ listLabels: (input) => run("listLabels", listGitLabLabels(callIn(input.cwd))),
2232
+ listAssignees: (input) => run("listAssignees", listGitLabAssignees(callIn(input.cwd))),
2233
+ getPullRequestState: (input) => gitlab.getMergeRequest({
2234
+ cwd: input.cwd,
2235
+ reference: String(input.number)
2236
+ }).pipe(effect.Effect.map((summary) => {
2237
+ const state = summary.state ?? "open";
2238
+ return {
2239
+ state,
2240
+ isDraft: summary.isDraft ?? false,
2241
+ terminalAt: state === "merged" ? summary.mergedAt ?? summary.closedAt ?? null : state === "closed" ? summary.closedAt ?? null : null
2242
+ };
2243
+ }), effect.Effect.mapError((error) => providerError("getPullRequestState", error))),
2244
+ getIssueState: () => effect.Effect.fail(new require_src.SourceControlProviderError({
2245
+ provider: "gitlab",
2246
+ operation: "getIssueState",
2247
+ detail: "Not implemented for gitlab"
2248
+ })),
2249
+ listWorkflowRuns: (input) => run("listWorkflowRuns", listGitLabWorkflowRuns(callIn(input.cwd), input)),
2250
+ getWorkflowRunJobs: (input) => run("getWorkflowRunJobs", listGitLabPipelineJobs(callIn(input.cwd), input.runId)),
2251
+ getWorkflowJobLog: (input) => run("getWorkflowJobLog", getGitLabJobLog(callIn(input.cwd), input)),
2252
+ rerunWorkflow: ({ context: _context, ...input }) => run("rerunWorkflow", rerunGitLabPipeline(callIn(input.cwd), input))
2253
+ });
2254
+ return require_bin.withUnsupportedChangeRequestOptionGuards(provider);
2255
+ });
2256
+ const layer = effect.Layer.effect(require_bin.SourceControlProvider, make());
2257
+ //#endregion
2258
+ exports.discovery = require_bin.gitlabDiscovery;
2259
+ exports.layer = layer;
2260
+ exports.make = make;