ryco-cli 0.1.13 → 0.1.15

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 (217) hide show
  1. package/dist/{AcpNativeLogging-Be1KGJfF.cjs → AcpNativeLogging-OhEq3XNp.cjs} +1 -1
  2. package/dist/{AcpNativeLogging-Ba9Nn9Re.mjs → AcpNativeLogging-qZgtIa5K.mjs} +2 -2
  3. package/dist/{AzureDevOpsSourceControlProvider-CGlK6M0b.mjs → AzureDevOpsSourceControlProvider-B0YsaJyI.mjs} +3 -3
  4. package/dist/{AzureDevOpsSourceControlProvider-CVj-F-pW.cjs → AzureDevOpsSourceControlProvider-Dyu8KQ_S.cjs} +2 -2
  5. package/dist/{BitbucketSourceControlProvider-CEZEd4PX.cjs → BitbucketSourceControlProvider-3VHGKSl1.cjs} +2 -2
  6. package/dist/{BitbucketSourceControlProvider-BV6iRDi7.mjs → BitbucketSourceControlProvider-B8IPx2Ad.mjs} +3 -3
  7. package/dist/{ClaudeDriver-lBU7EyUX.cjs → ClaudeDriver-CBCy0_WX.cjs} +176 -11
  8. package/dist/{ClaudeDriver-rooMNrJz.mjs → ClaudeDriver-DsW8yDj9.mjs} +177 -12
  9. package/dist/{CodexDriver-CZCIJSLV.cjs → CodexDriver-3TZPgrGk.cjs} +3 -3
  10. package/dist/{CodexDriver-DBz2rPXb.mjs → CodexDriver-DLwPz5sk.mjs} +4 -4
  11. package/dist/{CodexTextGeneration-BeG7ymPC.mjs → CodexTextGeneration-D1vV8grr.mjs} +2 -2
  12. package/dist/{CodexTextGeneration-BvIcyD1P.cjs → CodexTextGeneration-DLHSW4Mz.cjs} +1 -1
  13. package/dist/{CopilotDriver-CX5zhEdZ.cjs → CopilotDriver-C7a8IhyK.cjs} +20 -16
  14. package/dist/{CopilotDriver-D36vbGbn.mjs → CopilotDriver-DXvGBv-s.mjs} +21 -17
  15. package/dist/{CursorDriver-DWuuOSkJ.mjs → CursorDriver-CeB_vMKJ.mjs} +4 -4
  16. package/dist/{CursorDriver-CPBVeesr.cjs → CursorDriver-uNsDetA3.cjs} +3 -3
  17. package/dist/{ForgejoSourceControlProvider-CzmmcAZO.cjs → ForgejoSourceControlProvider-CJLksvL_.cjs} +2 -2
  18. package/dist/{ForgejoSourceControlProvider-CeN7Snfr.mjs → ForgejoSourceControlProvider-Ds0rU_PN.mjs} +3 -3
  19. package/dist/{GitHubSourceControlProvider-Dmz1LJct.mjs → GitHubSourceControlProvider-C7CJAslU.mjs} +3 -3
  20. package/dist/{GitHubSourceControlProvider-DfFR9O2o.cjs → GitHubSourceControlProvider-CrYNFu8S.cjs} +2 -2
  21. package/dist/{GitLabSourceControlProvider-DGoelNmL.cjs → GitLabSourceControlProvider-jbX5M34A.cjs} +2 -2
  22. package/dist/{GitLabSourceControlProvider-C21lwphV.mjs → GitLabSourceControlProvider-u-Y-e8PV.mjs} +3 -3
  23. package/dist/{GrokDriver-CIXj_4ry.cjs → GrokDriver-BJ00ZiYg.cjs} +3 -3
  24. package/dist/{GrokDriver-qKX1a63G.mjs → GrokDriver-CFgjwnvE.mjs} +4 -4
  25. package/dist/{OpenCodeDriver-DDEuwtXl.cjs → OpenCodeDriver-BTxd2Q3Q.cjs} +487 -207
  26. package/dist/{OpenCodeDriver-CbdswhqU.mjs → OpenCodeDriver-DNApoGdu.mjs} +487 -207
  27. package/dist/{SourceControlProviderDiscoveryCatalog-DJWDCoup.cjs → SourceControlProviderDiscoveryCatalog-CPO3a9_U.cjs} +1 -1
  28. package/dist/{SourceControlProviderDiscoveryCatalog-4_4yahsa.mjs → SourceControlProviderDiscoveryCatalog-hXWNwRMn.mjs} +1 -1
  29. package/dist/bin.cjs +1324 -340
  30. package/dist/bin.mjs +1324 -343
  31. package/dist/client/assets/{AccountSettings-Be5_48k0.js → AccountSettings-Cey-16wq.js} +1 -1
  32. package/dist/client/assets/{AiFocusSettings-DIpQXLW2.js → AiFocusSettings-CaHQXDaQ.js} +1 -1
  33. package/dist/client/assets/{AnimatedHeight-BIsV_Z3J.js → AnimatedHeight-BC-qaTJY.js} +1 -1
  34. package/dist/client/assets/AppearanceSettings-B6UaU-_a.js +1 -0
  35. package/dist/client/assets/{BranchToolbar.logic-D7slG_zJ.js → BranchToolbar.logic-DILAA3Cz.js} +1 -1
  36. package/dist/client/assets/ChatRightPanel-D-AL07IU.js +27 -0
  37. package/dist/client/assets/{ChatThreadRouteView-CocRstME.js → ChatThreadRouteView-tEo-zoCf.js} +1 -1
  38. package/dist/client/assets/CommandPaletteDialog-s7yf5Y2S.js +1 -0
  39. package/dist/client/assets/{CompositeItem-F3NGn6aG.js → CompositeItem-97y1QiiT.js} +1 -1
  40. package/dist/client/assets/{CompositeRoot-CmJGfRtc.js → CompositeRoot-C7Mz4Y_2.js} +1 -1
  41. package/dist/client/assets/{ConnectionsSettings-CXabxSaH.js → ConnectionsSettings-B0-Hkwof.js} +2 -2
  42. package/dist/client/assets/{DiagnosticsSettings-CZ3vY43G.js → DiagnosticsSettings-DX5LH9Bt.js} +1 -1
  43. package/dist/client/assets/{DialogHandle-C4uSr9wX.js → DialogHandle-Cl9dQBJp.js} +1 -1
  44. package/dist/client/assets/{DialogPopup-Dck8r8Hn.js → DialogPopup-a1M74u16.js} +1 -1
  45. package/dist/client/assets/DialogRoot-C_DO1gtO.js +1 -0
  46. package/dist/client/assets/{DialogTitle-CCedPAjV.js → DialogTitle-Bk-w3xLJ.js} +1 -1
  47. package/dist/client/assets/{DialogTrigger-CYJ7_YcV.js → DialogTrigger-D9nkMFu2.js} +1 -1
  48. package/dist/client/assets/{DialogViewport-D-CrTM-P.js → DialogViewport-tgJz2Lwn.js} +1 -1
  49. package/dist/client/assets/{DraftChatThreadRouteView-D8Bt3Qnq.js → DraftChatThreadRouteView-BU2IGTR6.js} +1 -1
  50. package/dist/client/assets/{ExternalIdentityWeb.logic-D64j70NH.js → ExternalIdentityWeb.logic-Bn1HigS9.js} +1 -1
  51. package/dist/client/assets/GlassSurface-CDok2tTN.js +1 -0
  52. package/dist/client/assets/{HostedConnectionControls-DxAXv0Hd.js → HostedConnectionControls-Cux_sRCM.js} +1 -1
  53. package/dist/client/assets/HostedHubRoot-CyySCdJV.js +1 -0
  54. package/dist/client/assets/{HostedNativeAuthorizationRoute-CTQe7Vjt.js → HostedNativeAuthorizationRoute-490iDXmk.js} +1 -1
  55. package/dist/client/assets/{HostedRelayTrustNotice-BldMySVi.js → HostedRelayTrustNotice-CcDOAwgS.js} +1 -1
  56. package/dist/client/assets/{Icons-CT3nd2MA.js → Icons-BEtED8P8.js} +1 -1
  57. package/dist/client/assets/{IntegrationsSettingsPanel-D6f3KoqM.js → IntegrationsSettingsPanel-BFTAvxtn.js} +1 -1
  58. package/dist/client/assets/KeybindingsSettings-VYgbhiZF.js +7 -0
  59. package/dist/client/assets/{McpServersSettings-B7YqVvV4.js → McpServersSettings-DSDCjoTn.js} +1 -1
  60. package/dist/client/assets/{MobileSheet-CkeG6_SP.js → MobileSheet-BDvnUC5W.js} +1 -1
  61. package/dist/client/assets/{NewWorktreeDialog-CKr2ioue.js → NewWorktreeDialog-C65Aifeb.js} +1 -1
  62. package/dist/client/assets/{NoActiveThreadState-BD-eNmfn.js → NoActiveThreadState-DehHNgAp.js} +1 -1
  63. package/dist/client/assets/{NodeSecuritySettings-FWM_SeDi.js → NodeSecuritySettings-DW9GJ-kU.js} +1 -1
  64. package/dist/client/assets/{OpinionatedPluginsSettings-BtZQF4Ze.js → OpinionatedPluginsSettings-DbxPOokL.js} +1 -1
  65. package/dist/client/assets/{PhoneGetAppInterstitial-CooQgpSw.js → PhoneGetAppInterstitial-CbyVrtDn.js} +1 -1
  66. package/dist/client/assets/{PhoneGetAppInterstitialBackdrop-B8vfJdZd.js → PhoneGetAppInterstitialBackdrop-BA4R225F.js} +1 -1
  67. package/dist/client/assets/PhoneHome-c0j_TBEC.js +1 -0
  68. package/dist/client/assets/PhoneSettingsSurface-5LFRIx_5.js +1 -0
  69. package/dist/client/assets/{ProjectFavicon-qZGdjYCM.js → ProjectFavicon-CeVJCQCy.js} +1 -1
  70. package/dist/client/assets/{ProviderModelPicker-D0w23uWo.js → ProviderModelPicker-MFRYAv_3.js} +1 -1
  71. package/dist/client/assets/{ProviderUpdateLaunchNotification.logic-BkoRegCn.js → ProviderUpdateLaunchNotification.logic-CywRitn3.js} +1 -1
  72. package/dist/client/assets/ProvidersSettingsPanel-FYBEqSr_.js +1 -0
  73. package/dist/client/assets/{RedactedSensitiveText-CxtaUiKH.js → RedactedSensitiveText-BuWSWty8.js} +1 -1
  74. package/dist/client/assets/RootAppShell-5HrP6N8H.js +6 -0
  75. package/dist/client/assets/{RycoLetterMark-Bk0kvGJ_.js → RycoLetterMark-CZYntY8t.js} +1 -1
  76. package/dist/client/assets/SettingsDialog-CpwoqGS8.js +1 -0
  77. package/dist/client/assets/{SettingsPanels-Dr4f2y9l.js → SettingsPanels-COWRB29-.js} +3 -3
  78. package/dist/client/assets/{SettingsPanels.editor-B2x4U4rW.js → SettingsPanels.editor-lbLEbllb.js} +1 -1
  79. package/dist/client/assets/SourceControlSettings-DvBNelcO.js +1 -0
  80. package/dist/client/assets/{StatisticsPage-Bjouapmf.js → StatisticsPage-DxAKqvVX.js} +1 -1
  81. package/dist/client/assets/{StatisticsPanel-D_khPph6.js → StatisticsPanel-C0xGLlMA.js} +1 -1
  82. package/dist/client/assets/{StatisticsSettingsLink-Cx43bOeo.js → StatisticsSettingsLink-B7SZerf3.js} +1 -1
  83. package/dist/client/assets/ThreadStatusIndicators-CIOM98q2.js +0 -0
  84. package/dist/client/assets/{ThreadTerminalDrawer-DDHEuRGB.js → ThreadTerminalDrawer-DRelLlEP.js} +1 -1
  85. package/dist/client/assets/{ThreadWorkspacePanel-QF3KwbGm.js → ThreadWorkspacePanel-CktVSliZ.js} +3 -3
  86. package/dist/client/assets/{ToolbarRootContext-BgqqXVly.js → ToolbarRootContext-B1g8IP6k.js} +1 -1
  87. package/dist/client/assets/{WorkItemsTab-AOVwVvb7.js → WorkItemsTab-CahU_t_S.js} +12 -12
  88. package/dist/client/assets/{alert-LqMhbdE9.js → alert-DomE7dAt.js} +1 -1
  89. package/dist/client/assets/{alert-dialog-DxoA6ky8.js → alert-dialog-9Jyh0e8u.js} +1 -1
  90. package/dist/client/assets/appearancePreferences-BhNRCg6W.js +1 -0
  91. package/dist/client/assets/authorization-D8lJzXTE.js +1 -0
  92. package/dist/client/assets/{badge-CXw6fWrB.js → badge-w43sx8eF.js} +1 -1
  93. package/dist/client/assets/{branding-BDfN6Spd.js → branding-B7DcCXjn.js} +1 -1
  94. package/dist/client/assets/{button-BAbJxRzt.js → button-DG8WqjNn.js} +1 -1
  95. package/dist/client/assets/{capabilities-3zgirmmI.js → capabilities-B1FHGoov.js} +1 -1
  96. package/dist/client/assets/{chatThreadActions-DQ8aOQ1g.js → chatThreadActions-BZvyhfKr.js} +1 -1
  97. package/dist/client/assets/{collapsible-dxy6kc2k.js → collapsible-EhAEe5S9.js} +1 -1
  98. package/dist/client/assets/{command-CGNKG_Oe.js → command-Cyn6yIEa.js} +1 -1
  99. package/dist/client/assets/composerDraftStore-TYv9j3vY.js +11 -0
  100. package/dist/client/assets/{data-list-CYKBxN62.js → data-list-DTdqWMGN.js} +1 -1
  101. package/dist/client/assets/{desktopUpdateAtoms-CyfPW2jg.js → desktopUpdateAtoms-CPlZiFRm.js} +1 -1
  102. package/dist/client/assets/{desktopWorkspace-DHUZEpfy.js → desktopWorkspace-DEZ30LlY.js} +1 -1
  103. package/dist/client/assets/device-CHdXzvhB.js +168 -0
  104. package/dist/client/assets/{dialog-DQsYchqu.js → dialog-BNmFD6Nh.js} +1 -1
  105. package/dist/client/assets/{draft-input-CkzOk8BY.js → draft-input-dP7F8odz.js} +1 -1
  106. package/dist/client/assets/editorPreferences-B4GvqMiF.js +1 -0
  107. package/dist/client/assets/{empty-DwzqNgCP.js → empty-Ccxhyvdf.js} +1 -1
  108. package/dist/client/assets/{env-B4arEvJg.js → env-Bcq9YR3B.js} +1 -1
  109. package/dist/client/assets/{getPseudoElementBounds-X62ElHN8.js → getPseudoElementBounds-CO5HJT7x.js} +1 -1
  110. package/dist/client/assets/{group-D9ER9giz.js → group-CzdKmc45.js} +1 -1
  111. package/dist/client/assets/{index-CQmEMMQH.js → index-Gre6bNC8.js} +2 -2
  112. package/dist/client/assets/{input-CHEwW3oH.js → input-BZz4eLRl.js} +1 -1
  113. package/dist/client/assets/{kbd-DCGQZk18.js → kbd-DbvN3zTb.js} +1 -1
  114. package/dist/client/assets/{keybindings-CWJ7E9ZI.js → keybindings-BPE3eEAM.js} +1 -1
  115. package/dist/client/assets/{label-CVFHsLFO.js → label-DZf4lbNF.js} +1 -1
  116. package/dist/client/assets/{lib-qiiNMGgU.js → lib-DgOYoged.js} +1 -1
  117. package/dist/client/assets/{liquidGlass-CPsvmaF0.js → liquidGlass-yFkZrRk5.js} +1 -1
  118. package/dist/client/assets/{logging-M8H3z7rQ.js → logging-81iP6Hps.js} +1 -1
  119. package/dist/client/assets/main-DlGNPwsH.css +2 -0
  120. package/dist/client/assets/main-Dz0zookE.js +9 -0
  121. package/dist/client/assets/{menu-Dvxh8sD5.js → menu-B6UEFcn0.js} +1 -1
  122. package/dist/client/assets/{popover-CuH9Yrj3.js → popover-BuYzXGwl.js} +1 -1
  123. package/dist/client/assets/primary-CiDY2oUi.js +2 -0
  124. package/dist/client/assets/projectPaths-D6fHIU1b.js +1 -0
  125. package/dist/client/assets/{providerDriverMeta-I0TSo-QI.js → providerDriverMeta-sBwZhQoN.js} +1 -1
  126. package/dist/client/assets/{providerIconUtils-X0Z3EK-Q.js → providerIconUtils-DiDJeNtT.js} +1 -1
  127. package/dist/client/assets/providerInstances-vd2eZtHx.js +1 -0
  128. package/dist/client/assets/providerModels-vd2eZtHx.js +1 -0
  129. package/dist/client/assets/{qr-code-Bddq6K7S.js → qr-code-Ie92aZvE.js} +1 -1
  130. package/dist/client/assets/{radio-group-CBZFr4C8.js → radio-group-BuuTEtdC.js} +1 -1
  131. package/dist/client/assets/{resolveAriaLabelledBy-CD_ugzhJ.js → resolveAriaLabelledBy-0FA0k4xp.js} +1 -1
  132. package/dist/client/assets/{rightPanelRouteSearch-DB5gQGHK.js → rightPanelRouteSearch-BS8CkNS6.js} +1 -1
  133. package/dist/client/assets/runtime-CPM0EUhb.js +1 -0
  134. package/dist/client/assets/{scroll-area-Drsa8bNB.js → scroll-area-C0yF015F.js} +1 -1
  135. package/dist/client/assets/{scrollEdges-B-cqxY4l.js → scrollEdges-DI5Y3mtR.js} +1 -1
  136. package/dist/client/assets/{select-BYbVr-yg.js → select-CZukJlTn.js} +1 -1
  137. package/dist/client/assets/{separator-CdS5bi4Z.js → separator-D4ckGtPe.js} +1 -1
  138. package/dist/client/assets/session-logic-BalPN1Sc.js +4 -0
  139. package/dist/client/assets/{settingsDialogStore-ygYoScKe.js → settingsDialogStore-LxRFC5hh.js} +1 -1
  140. package/dist/client/assets/{settingsLayout-D8glO7f1.js → settingsLayout-CHJT5wtl.js} +1 -1
  141. package/dist/client/assets/{sheet-BO78gIKZ.js → sheet-BNfImQ-7.js} +1 -1
  142. package/dist/client/assets/{sidebar-Dm6l2GA6.js → sidebar-CFGg5Tkr.js} +1 -1
  143. package/dist/client/assets/sidebarProjectFolders-bhNsO9Z_.js +4 -0
  144. package/dist/client/assets/{sidebarStatusText-D0HT0fek.js → sidebarStatusText-C8QBhZhZ.js} +1 -1
  145. package/dist/client/assets/{skeleton-CvQSeJbw.js → skeleton-DOgQaVXv.js} +1 -1
  146. package/dist/client/assets/{spinner-ClF0jOcX.js → spinner-ClQu8SdC.js} +1 -1
  147. package/dist/client/assets/{src-Vf4LVnMX.js → src-DmPIm3ie.js} +1 -1
  148. package/dist/client/assets/storeSelectors-Cf2WDMfx.js +1 -0
  149. package/dist/client/assets/{switch-BTGo9Yip.js → switch-BZjA7VT9.js} +1 -1
  150. package/dist/client/assets/{terminal-links-CZ3c9AbA.js → terminal-links-CzJomeox.js} +1 -1
  151. package/dist/client/assets/{textarea-RFPODxWW.js → textarea-DHdmRD1r.js} +1 -1
  152. package/dist/client/assets/threadPinning-BLqwZebi.js +1 -0
  153. package/dist/client/assets/{threadPriorityRefreshRuntime-Ct5pnIbX.js → threadPriorityRefreshRuntime-BoNAlBXK.js} +1 -1
  154. package/dist/client/assets/{toast-CcSCAm4B.js → toast-C-0Ft2jD.js} +1 -1
  155. package/dist/client/assets/{toggle-I6h33Cu5.js → toggle-DsnOFDbJ.js} +1 -1
  156. package/dist/client/assets/{toggle-group-mLIkiJtU.js → toggle-group-Chxh9G6t.js} +1 -1
  157. package/dist/client/assets/{tooltip-C8sAONBj.js → tooltip-C_-9XEfA.js} +1 -1
  158. package/dist/client/assets/types-Cf2WDMfx.js +1 -0
  159. package/dist/client/assets/{uiStateStore-B6pjzSjj.js → uiStateStore-DzUrk2GS.js} +1 -1
  160. package/dist/client/assets/useAtlassian-CoHKzu-e.js +0 -0
  161. package/dist/client/assets/{useButton-D__1LqCF.js → useButton-BmvYhoMC.js} +1 -1
  162. package/dist/client/assets/{useCompositeListItem-Cmr_nuuG.js → useCompositeListItem-D0PvH4nv.js} +1 -1
  163. package/dist/client/assets/{useDebouncedValue-DHjoudTq.js → useDebouncedValue-s0BC8Yyp.js} +1 -1
  164. package/dist/client/assets/{useFloatingRootContext-D5EZmrCa.js → useFloatingRootContext-CLCaQEJk.js} +1 -1
  165. package/dist/client/assets/{useHandleNewThread-DX2FtXcP.js → useHandleNewThread-Bw460iXT.js} +1 -1
  166. package/dist/client/assets/{useLabelableId-DnQJ7amm.js → useLabelableId-CB_9OReR.js} +1 -1
  167. package/dist/client/assets/{useLocation-CDeYzWW6.js → useLocation-DGJMt6gP.js} +1 -1
  168. package/dist/client/assets/{useOpenInteractionType-CjtpACKR.js → useOpenInteractionType-BSSI2GzS.js} +1 -1
  169. package/dist/client/assets/{usePhoneThreadActions-BEa3VzGG.js → usePhoneThreadActions-BIDUSWSI.js} +1 -1
  170. package/dist/client/assets/{usePopupViewport-BuhsNdVy.js → usePopupViewport-8F-J1h5f.js} +1 -1
  171. package/dist/client/assets/{useScrollLock-D3tMGsRk.js → useScrollLock-CBz-5_MX.js} +1 -1
  172. package/dist/client/assets/{useStatistics-CtunoTE-.js → useStatistics-B91973jb.js} +2 -2
  173. package/dist/client/assets/{useSwipeDismiss-CbgDJvw1.js → useSwipeDismiss-D22_vuiH.js} +1 -1
  174. package/dist/client/assets/{useTheme-DiC-5xCb.js → useTheme-By1kfyiU.js} +1 -1
  175. package/dist/client/assets/{useThreadActions-fN-Al13y.js → useThreadActions-BCH01d6u.js} +1 -1
  176. package/dist/client/assets/{useTriggerFocusGuards-CrugmkhX.js → useTriggerFocusGuards-f7afwACm.js} +1 -1
  177. package/dist/client/assets/{useValueChanged-MQtIzPIU.js → useValueChanged-EkWF0C3k.js} +1 -1
  178. package/dist/client/assets/{utils-BofFIn5Y.js → utils-CV2fJJxC.js} +1 -1
  179. package/dist/client/index.html +1 -1
  180. package/dist/{collectUint8StreamText-Bb52hlpd.cjs → collectUint8StreamText-Dsbmrw73.cjs} +48 -10
  181. package/dist/{collectUint8StreamText-EDg4F0TU.mjs → collectUint8StreamText-oFvWyN3_.mjs} +37 -11
  182. package/dist/{makeManagedServerProvider-itynW7xv.cjs → makeManagedServerProvider-CANTNAsz.cjs} +9 -2
  183. package/dist/{makeManagedServerProvider-Cf8bNWwc.mjs → makeManagedServerProvider-PLtJj7EV.mjs} +10 -3
  184. package/package.json +1 -1
  185. package/dist/client/assets/AppearanceSettings-CYbSApl4.js +0 -1
  186. package/dist/client/assets/ChatRightPanel-BIS1DPGa.js +0 -27
  187. package/dist/client/assets/CommandPaletteDialog-C5xAo65V.js +0 -1
  188. package/dist/client/assets/DialogRoot-BpIvUdm7.js +0 -1
  189. package/dist/client/assets/GlassSurface-C3IIWMu9.js +0 -1
  190. package/dist/client/assets/HostedHubRoot-Cc8GYcK6.js +0 -1
  191. package/dist/client/assets/KeybindingsSettings-D2bNQPI-.js +0 -7
  192. package/dist/client/assets/PhoneHome-BtPE7bQn.js +0 -1
  193. package/dist/client/assets/PhoneSettingsSurface-tcFCccEL.js +0 -1
  194. package/dist/client/assets/ProvidersSettingsPanel-B3aBKY--.js +0 -1
  195. package/dist/client/assets/RootAppShell-C-0ChFVJ.js +0 -6
  196. package/dist/client/assets/SettingsDialog-Bbuoh793.js +0 -1
  197. package/dist/client/assets/SourceControlSettings-CkiYR4lR.js +0 -1
  198. package/dist/client/assets/ThreadStatusIndicators-ZImeLExQ.js +0 -0
  199. package/dist/client/assets/appearancePreferences-COvj0WMT.js +0 -1
  200. package/dist/client/assets/authorization-mIJKV2yp.js +0 -1
  201. package/dist/client/assets/composerDraftStore-CdJJZe42.js +0 -11
  202. package/dist/client/assets/device-B_qvyvtW.js +0 -168
  203. package/dist/client/assets/editorPreferences-DHIJntKF.js +0 -1
  204. package/dist/client/assets/main-BKS5Nf2_.js +0 -9
  205. package/dist/client/assets/main-DaYHZt-J.css +0 -2
  206. package/dist/client/assets/panel-right-BodNpkM9.js +0 -1
  207. package/dist/client/assets/primary-BzLEg2w1.js +0 -2
  208. package/dist/client/assets/projectPaths-BAd6NFcE.js +0 -1
  209. package/dist/client/assets/providerInstances-BJcfB_9E.js +0 -1
  210. package/dist/client/assets/providerModels-BJcfB_9E.js +0 -1
  211. package/dist/client/assets/runtime-CXut_g4p.js +0 -1
  212. package/dist/client/assets/session-logic-GZix7S2I.js +0 -4
  213. package/dist/client/assets/sidebarProjectFolders-cnmz3B_-.js +0 -4
  214. package/dist/client/assets/storeSelectors-DYekgeHu.js +0 -1
  215. package/dist/client/assets/types-DYekgeHu.js +0 -1
  216. package/dist/client/assets/useAppearancePreference-BlLlxQl7.js +0 -1
  217. package/dist/client/assets/useAtlassian-9-hy2f8z.js +0 -0
@@ -1,17 +1,78 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { Go as RuntimeItemId, Jo as RuntimeSubagentId, Ko as RuntimeRequestId, Pn as TextGenerationError, Qo as TurnId, Ra as ProviderDriverKind, Ro as EventId, Wo as ProviderItemId, ar as OpenCodeSettings, za as ProviderInstanceId } from "./collectUint8StreamText-EDg4F0TU.mjs";
3
+ import { Ba as ProviderDriverKind, Bo as EventId, Jo as RuntimeRequestId, Ko as ProviderItemId, Pn as TextGenerationError, Va as ProviderInstanceId, Xo as RuntimeSubagentId, ar as OpenCodeSettings, bi as PROVIDER_SEND_TURN_MAX_ATTACHMENT_TOTAL_BYTES, es as TurnId, qo as RuntimeItemId } from "./collectUint8StreamText-oFvWyN3_.mjs";
4
4
  import { nt as sanitizeFeatureBranchName, st as ServerConfig, tt as sanitizeBranchFragment } from "./Metrics-BP9YjxZB.mjs";
5
- import { C as buildCommitMessagePrompt, D as buildThreadPriorityPrompt, Dn as enrichProviderSnapshotWithVersionAdvisory, E as buildPrContentPrompt, Fn as ServerSettingsService, In as resolveAttachmentPath, K as buildServerProvider, M as sanitizePrTitle, Mn as normalizeCommandPath, N as sanitizeThreadTitle, Nn as resolveProviderMaintenanceCapabilitiesEffect, O as buildThreadTitlePrompt, Pn as compareCliVersions, Q as providerModelsFromSettings, S as buildBranchNamePrompt, T as buildIssueContentTitlePrompt, Vn as getModelSelectionStringOptionValue, X as nonEmptyTrimmed, Z as parseGenericCliVersion, _ as ProviderEventLoggers, at as createProcessDeviceToolBinding, c as OpenCodeRuntimeError, ct as ProviderAdapterSessionClosedError, d as openCodeRuntimeErrorDetail, dt as ProviderDriverError, f as parseOpenCodeModelSlug, g as toOpenCodeQuestionAnswers, h as toOpenCodePermissionReply, j as sanitizeCommitSubject, k as extractJsonObject, kn as makePackageManagedProviderMaintenanceResolver, l as buildOpenCodePermissionRules, lt as ProviderAdapterSessionNotFoundError, m as toOpenCodeFileParts, ot as ProviderAdapterProcessError, p as runOpenCodeSdk, s as OpenCodeRuntime, st as ProviderAdapterRequestError, t as makeServerQueueMetrics, tt as agentControlHostContext, u as openCodeQuestionId, ut as ProviderAdapterValidationError, v as makeEventNdjsonLogger, w as buildIssueContentPolishPrompt, x as validateRankInboxThreadsResult, z as mergeProviderInstanceEnvironment, zn as createModelCapabilities } from "./bin.mjs";
5
+ import { $ as parseGenericCliVersion, A as buildThreadTitlePrompt, C as validateRankInboxThreadsResult, D as buildIssueContentTitlePrompt, E as buildIssueContentPolishPrompt, F as sanitizeThreadTitle, Fn as resolveProviderMaintenanceCapabilitiesEffect, Hn as createModelCapabilities, In as compareCliVersions, J as buildServerProvider, Ln as ServerSettingsService, N as sanitizeCommitSubject, O as buildPrContentPrompt, P as sanitizePrTitle, Pn as normalizeCommandPath, Q as nonEmptyTrimmed, Rn as readPersistedAttachment, T as buildCommitMessagePrompt, V as mergeProviderInstanceEnvironment, Wn as getModelSelectionStringOptionValue, _ as toOpenCodeQuestionAnswers, b as makeEventNdjsonLogger, c as OpenCodeRuntime, ct as ProviderAdapterProcessError, d as openCodeQuestionId, dt as ProviderAdapterSessionNotFoundError, et as providerModelsFromSettings, f as openCodeRuntimeErrorDetail, ft as ProviderAdapterValidationError, g as toOpenCodePermissionReply, h as toOpenCodeFileParts, j as extractJsonObject, jn as makePackageManagedProviderMaintenanceResolver, k as buildThreadPriorityPrompt, kn as enrichProviderSnapshotWithVersionAdvisory, l as OpenCodeRuntimeError, lt as ProviderAdapterRequestError, m as runOpenCodeSdk, p as parseOpenCodeModelSlug, pt as ProviderDriverError, rt as agentControlHostContext, s as MINIMUM_OPENCODE_VERSION, st as createProcessDeviceToolBinding, t as makeServerQueueMetrics, u as buildOpenCodePermissionRules, ut as ProviderAdapterSessionClosedError, v as verifyOpenCodeServerVersion, w as buildBranchNamePrompt, y as ProviderEventLoggers } from "./bin.mjs";
6
6
  import { t as formatSourceControlContextsForAgent } from "./sourceControlContextFormatter-DEwpnVAH.mjs";
7
- import { n as requireRuntimeSessionId, r as stampRuntimeEvent, t as makeManagedServerProvider } from "./makeManagedServerProvider-Cf8bNWwc.mjs";
7
+ import { n as requireRuntimeSessionId, r as stampRuntimeEvent, t as makeManagedServerProvider } from "./makeManagedServerProvider-PLtJj7EV.mjs";
8
8
  import { t as defaultProviderContinuationIdentity } from "./ProviderDriver-kCV60GKk.mjs";
9
- import { Cause, Data, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, Stream } from "effect";
9
+ import { Cause, Data, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, Semaphore, Stream } from "effect";
10
10
  import { HttpClient } from "effect/unstable/http";
11
11
  import "effect/unstable/process";
12
12
  import * as Semaphore$1 from "effect/Semaphore";
13
+ //#region src/provider/OpenCodeServerOwner.ts
14
+ const OPENCODE_MANAGED_SERVER_IDLE_TTL = "30 seconds";
15
+ const makeOpenCodeServerOwner = Effect.fn("makeOpenCodeServerOwner")(function* (settings, environment = process.env) {
16
+ const runtime = yield* OpenCodeRuntime;
17
+ const ownerScope = yield* Effect.scope;
18
+ const mutex = yield* Semaphore$1.make(1);
19
+ let owned = null;
20
+ const closeOwned = (record) => Effect.gen(function* () {
21
+ if (owned === record) owned = null;
22
+ const idleFiber = record.idleCloseFiber;
23
+ record.idleCloseFiber = null;
24
+ if (idleFiber !== null) yield* Fiber.interrupt(idleFiber).pipe(Effect.ignore);
25
+ yield* Scope.close(record.scope, Exit.void).pipe(Effect.ignore);
26
+ });
27
+ const cancelIdleClose = (record) => Effect.gen(function* () {
28
+ const fiber = record.idleCloseFiber;
29
+ record.idleCloseFiber = null;
30
+ if (fiber !== null) yield* Fiber.interrupt(fiber).pipe(Effect.ignore);
31
+ });
32
+ const acquireProcess = mutex.withPermit(Effect.gen(function* () {
33
+ if (owned !== null) {
34
+ yield* cancelIdleClose(owned);
35
+ owned.leases += 1;
36
+ return owned.process;
37
+ }
38
+ return yield* Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
39
+ const processScope = yield* Scope.make();
40
+ const started = yield* Effect.exit(restore(runtime.startOpenCodeServerProcess({
41
+ binaryPath: settings.binaryPath,
42
+ ...settings.serverPassword ? { serverPassword: settings.serverPassword } : {},
43
+ environment
44
+ }).pipe(Effect.provideService(Scope.Scope, processScope))));
45
+ if (Exit.isFailure(started)) {
46
+ yield* Scope.close(processScope, Exit.void).pipe(Effect.ignore);
47
+ return yield* Effect.failCause(started.cause);
48
+ }
49
+ owned = {
50
+ process: started.value,
51
+ scope: processScope,
52
+ leases: 1,
53
+ idleCloseFiber: null
54
+ };
55
+ return started.value;
56
+ }));
57
+ }));
58
+ const releaseProcess = (process) => mutex.withPermit(Effect.gen(function* () {
59
+ const record = owned;
60
+ if (record === null || record.process !== process) return;
61
+ record.leases = Math.max(0, record.leases - 1);
62
+ if (record.leases > 0 || record.idleCloseFiber !== null) return;
63
+ record.idleCloseFiber = yield* Effect.sleep(OPENCODE_MANAGED_SERVER_IDLE_TTL).pipe(Effect.andThen(mutex.withPermit(Effect.gen(function* () {
64
+ if (owned !== record || record.leases > 0) return;
65
+ record.idleCloseFiber = null;
66
+ yield* closeOwned(record);
67
+ }))), Effect.forkIn(ownerScope));
68
+ }));
69
+ yield* Effect.addFinalizer(() => mutex.withPermit(Effect.gen(function* () {
70
+ if (owned !== null) yield* closeOwned(owned);
71
+ })));
72
+ return { acquire: Effect.acquireRelease(acquireProcess, releaseProcess) };
73
+ });
74
+ //#endregion
13
75
  //#region src/textGeneration/OpenCodeTextGeneration.ts
14
- const OPENCODE_TEXT_GENERATION_IDLE_TTL = "30 seconds";
15
76
  function getOpenCodePromptErrorMessage(error) {
16
77
  if (!error || typeof error !== "object") return null;
17
78
  const message = "data" in error && error.data && typeof error.data === "object" && "message" in error.data && typeof error.data.message === "string" ? error.data.message.trim() : "";
@@ -30,105 +91,58 @@ function getOpenCodeTextResponse(parts) {
30
91
  return [part.text];
31
92
  }).join("").trim();
32
93
  }
33
- const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(function* (openCodeSettings, environment = process.env) {
94
+ const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(function* (openCodeSettings, environment = process.env, options) {
34
95
  const serverConfig = yield* ServerConfig;
35
96
  const openCodeRuntime = yield* OpenCodeRuntime;
36
- const idleFiberScope = yield* Effect.acquireRelease(Scope.make(), (scope) => Scope.close(scope, Exit.void));
37
- const sharedServerMutex = yield* Semaphore$1.make(1);
38
- const sharedServerState = {
39
- server: null,
40
- serverScope: null,
41
- binaryPath: null,
42
- activeRequests: 0,
43
- idleCloseFiber: null
44
- };
45
- const closeSharedServer = Effect.fn("closeSharedServer")(function* () {
46
- const scope = sharedServerState.serverScope;
47
- sharedServerState.server = null;
48
- sharedServerState.serverScope = null;
49
- sharedServerState.binaryPath = null;
50
- if (scope !== null) yield* Scope.close(scope, Exit.void).pipe(Effect.ignore);
51
- });
52
- const cancelIdleCloseFiber = Effect.fn("cancelIdleCloseFiber")(function* () {
53
- const idleCloseFiber = sharedServerState.idleCloseFiber;
54
- sharedServerState.idleCloseFiber = null;
55
- if (idleCloseFiber !== null) yield* Fiber.interrupt(idleCloseFiber).pipe(Effect.ignore);
56
- });
57
- const scheduleIdleClose = Effect.fn("scheduleIdleClose")(function* (server) {
58
- yield* cancelIdleCloseFiber();
59
- const fiber = yield* Effect.sleep(OPENCODE_TEXT_GENERATION_IDLE_TTL).pipe(Effect.andThen(sharedServerMutex.withPermit(Effect.gen(function* () {
60
- if (sharedServerState.server !== server || sharedServerState.activeRequests > 0) return;
61
- sharedServerState.idleCloseFiber = null;
62
- yield* closeSharedServer();
63
- }))), Effect.forkIn(idleFiberScope));
64
- sharedServerState.idleCloseFiber = fiber;
65
- });
66
- const acquireSharedServer = (input) => sharedServerMutex.withPermit(Effect.gen(function* () {
67
- yield* cancelIdleCloseFiber();
68
- const existingServer = sharedServerState.server;
69
- if (existingServer !== null) {
70
- if (sharedServerState.binaryPath !== input.binaryPath && sharedServerState.activeRequests === 0) yield* closeSharedServer();
71
- else {
72
- if (sharedServerState.binaryPath !== input.binaryPath) yield* Effect.logWarning("OpenCode shared server binary path mismatch: requested " + input.binaryPath + " but active server uses " + sharedServerState.binaryPath + "; reusing existing server because there are active requests");
73
- sharedServerState.activeRequests += 1;
74
- return existingServer;
75
- }
76
- }
77
- return yield* Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
78
- const serverScope = yield* Scope.make();
79
- const startedExit = yield* Effect.exit(restore(openCodeRuntime.startOpenCodeServerProcess({
80
- binaryPath: input.binaryPath,
81
- environment
82
- }).pipe(Effect.provideService(Scope.Scope, serverScope), Effect.mapError((cause) => new TextGenerationError({
83
- operation: input.operation,
84
- detail: openCodeRuntimeErrorDetail(cause),
85
- cause
86
- })))));
87
- if (startedExit._tag === "Failure") {
88
- yield* Scope.close(serverScope, Exit.void).pipe(Effect.ignore);
89
- return yield* Effect.failCause(startedExit.cause);
90
- }
91
- const server = startedExit.value;
92
- sharedServerState.server = server;
93
- sharedServerState.serverScope = serverScope;
94
- sharedServerState.binaryPath = input.binaryPath;
95
- sharedServerState.activeRequests = 1;
96
- return server;
97
- }));
98
- }));
99
- const releaseSharedServer = (server) => sharedServerMutex.withPermit(Effect.gen(function* () {
100
- if (sharedServerState.server !== server) return;
101
- sharedServerState.activeRequests = Math.max(0, sharedServerState.activeRequests - 1);
102
- if (sharedServerState.activeRequests === 0) yield* scheduleIdleClose(server);
103
- }));
104
- yield* Effect.addFinalizer(() => sharedServerMutex.withPermit(Effect.gen(function* () {
105
- yield* cancelIdleCloseFiber();
106
- sharedServerState.activeRequests = 0;
107
- yield* closeSharedServer();
108
- })));
97
+ const serverOwner = options?.serverOwner ?? (openCodeSettings.serverUrl.trim().length === 0 ? yield* makeOpenCodeServerOwner(openCodeSettings, environment) : void 0);
109
98
  const runOpenCodeJson = Effect.fn("runOpenCodeJson")(function* (input) {
110
99
  const parsedModel = parseOpenCodeModelSlug(input.modelSelection.model);
111
100
  if (!parsedModel) return yield* new TextGenerationError({
112
101
  operation: input.operation,
113
102
  detail: "OpenCode model selection must use the 'provider/model' format."
114
103
  });
115
- const fileParts = toOpenCodeFileParts({
116
- attachments: input.attachments,
117
- resolveAttachmentPath: (attachment) => resolveAttachmentPath({
104
+ const declaredAttachmentBytes = (input.attachments ?? []).reduce((total, attachment) => total + attachment.sizeBytes, 0);
105
+ if (declaredAttachmentBytes > 52428800) return yield* new TextGenerationError({
106
+ operation: input.operation,
107
+ detail: `Attachments total ${declaredAttachmentBytes} bytes; limit is ${PROVIDER_SEND_TURN_MAX_ATTACHMENT_TOTAL_BYTES} bytes.`
108
+ });
109
+ const attachmentUrlById = /* @__PURE__ */ new Map();
110
+ let attachmentTotalBytes = 0;
111
+ for (const attachment of input.attachments ?? []) {
112
+ const persisted = readPersistedAttachment({
118
113
  attachmentsDir: serverConfig.attachmentsDir,
119
114
  attachment
120
- })
115
+ });
116
+ if (!persisted.ok) return yield* new TextGenerationError({
117
+ operation: input.operation,
118
+ detail: persisted.reason
119
+ });
120
+ attachmentTotalBytes += persisted.sizeBytes;
121
+ if (attachmentTotalBytes > 52428800) return yield* new TextGenerationError({
122
+ operation: input.operation,
123
+ detail: `Attachments total ${attachmentTotalBytes} bytes; limit is ${PROVIDER_SEND_TURN_MAX_ATTACHMENT_TOTAL_BYTES} bytes.`
124
+ });
125
+ attachmentUrlById.set(attachment.id, `data:${attachment.mimeType};base64,${persisted.bytes.toString("base64")}`);
126
+ }
127
+ const fileParts = toOpenCodeFileParts({
128
+ attachments: input.attachments,
129
+ resolveAttachmentUrl: (attachment) => attachmentUrlById.get(attachment.id) ?? null
121
130
  });
122
131
  const runAgainstServer = (server) => Effect.gen(function* () {
123
132
  const client = yield* openCodeRuntime.createOpenCodeSdkClient({
124
133
  baseUrl: server.url,
125
134
  directory: input.cwd,
126
- ...openCodeSettings.serverUrl.length > 0 && openCodeSettings.serverPassword ? { serverPassword: openCodeSettings.serverPassword } : {}
135
+ ...server.serverPassword ? { serverPassword: server.serverPassword } : {}
127
136
  }).pipe(Effect.mapError((cause) => new TextGenerationError({
128
137
  operation: input.operation,
129
138
  detail: openCodeRuntimeErrorDetail(cause),
130
139
  cause
131
140
  })));
141
+ yield* verifyOpenCodeServerVersion(client).pipe(Effect.mapError((cause) => new TextGenerationError({
142
+ operation: input.operation,
143
+ detail: openCodeRuntimeErrorDetail(cause),
144
+ cause
145
+ })));
132
146
  return yield* Effect.tryPromise({
133
147
  try: async () => {
134
148
  const session = await client.session.create({
@@ -166,10 +180,14 @@ const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(funct
166
180
  })
167
181
  });
168
182
  });
169
- const rawOutput = openCodeSettings.serverUrl.length > 0 ? yield* runAgainstServer({ url: openCodeSettings.serverUrl }) : yield* Effect.acquireUseRelease(acquireSharedServer({
170
- binaryPath: openCodeSettings.binaryPath,
171
- operation: input.operation
172
- }), runAgainstServer, releaseSharedServer);
183
+ const rawOutput = openCodeSettings.serverUrl.length > 0 ? yield* runAgainstServer({
184
+ url: openCodeSettings.serverUrl,
185
+ ...openCodeSettings.serverPassword ? { serverPassword: openCodeSettings.serverPassword } : {}
186
+ }) : yield* Effect.scoped(serverOwner.acquire.pipe(Effect.mapError((cause) => new TextGenerationError({
187
+ operation: input.operation,
188
+ detail: openCodeRuntimeErrorDetail(cause),
189
+ cause
190
+ })), Effect.flatMap(runAgainstServer)));
173
191
  return yield* Schema.decodeEffect(Schema.fromJsonString(input.outputSchemaJson))(extractJsonObject(rawOutput)).pipe(Effect.catchTag("SchemaError", (cause) => Effect.fail(new TextGenerationError({
174
192
  operation: input.operation,
175
193
  detail: "OpenCode returned invalid structured output.",
@@ -292,6 +310,7 @@ const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(funct
292
310
  //#endregion
293
311
  //#region src/provider/Layers/OpenCodeAdapter.ts
294
312
  const PROVIDER$1 = ProviderDriverKind.make("opencode");
313
+ const OPENCODE_RESUME_VERSION = 1;
295
314
  function nowIso() {
296
315
  return (/* @__PURE__ */ new Date()).toISOString();
297
316
  }
@@ -299,6 +318,15 @@ function nonEmptyString(value) {
299
318
  const trimmed = value?.trim();
300
319
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
301
320
  }
321
+ function parseOpenCodeResume(value) {
322
+ if (!value || typeof value !== "object") return;
323
+ const cursor = value;
324
+ return cursor.schemaVersion === OPENCODE_RESUME_VERSION && typeof cursor.sessionId === "string" && cursor.sessionId.trim().length > 0 ? { sessionId: cursor.sessionId } : void 0;
325
+ }
326
+ function isOpenCodeNotFound(error) {
327
+ const cause = error.cause;
328
+ return typeof cause === "object" && cause !== null && "response" in cause && cause.response?.status === 404;
329
+ }
302
330
  function scopedOpenCodeId(sessionId, id) {
303
331
  return `${sessionId}:${id}`;
304
332
  }
@@ -311,6 +339,9 @@ function subagentKey(subagentId) {
311
339
  function statusFromOpenCodeSubagentState(status) {
312
340
  return status;
313
341
  }
342
+ function isOpenCodeRequestEvent(event) {
343
+ return event.type === "permission.asked" || event.type === "permission.replied" || event.type === "question.asked" || event.type === "question.replied" || event.type === "question.rejected";
344
+ }
314
345
  function subagentCompletionStatus(status) {
315
346
  return status;
316
347
  }
@@ -320,6 +351,7 @@ function metadataWithEntries(entries) {
320
351
  }
321
352
  function makeSubtaskSubagentRef(part) {
322
353
  const description = nonEmptyString(part.description) ?? nonEmptyString(part.prompt);
354
+ const model = part.model ? `${part.model.providerID}/${part.model.modelID}` : void 0;
323
355
  const label = nonEmptyString(part.agent) ?? nonEmptyString(part.command) ?? (description ? "OpenCode subtask" : void 0);
324
356
  return {
325
357
  subagentId: openCodeSubagentId("subtask", part.id),
@@ -327,6 +359,7 @@ function makeSubtaskSubagentRef(part) {
327
359
  capability: "summary",
328
360
  ...label ? { label } : {},
329
361
  ...description ? { description } : {},
362
+ ...model ? { model } : {},
330
363
  parentProviderItemId: ProviderItemId.make(part.id),
331
364
  metadata: metadataWithEntries([
332
365
  ["source", "opencode.subtask"],
@@ -345,6 +378,8 @@ function mergeOpenCodeChildSessionRef(existing, session, parentSessionId) {
345
378
  capability: "transcript",
346
379
  label,
347
380
  ...existing?.description ? { description: existing.description } : {},
381
+ ...existing?.model ? { model: existing.model } : {},
382
+ ...existing?.effort ? { effort: existing.effort } : {},
348
383
  providerSessionId: session.id,
349
384
  providerThreadId: session.id,
350
385
  ...existing?.parentProviderItemId && { parentProviderItemId: existing.parentProviderItemId },
@@ -381,6 +416,13 @@ const toProcessError = (threadId, cause) => new ProviderAdapterProcessError({
381
416
  detail: OpenCodeRuntimeError.is(cause) ? cause.detail : openCodeRuntimeErrorDetail(cause),
382
417
  cause
383
418
  });
419
+ const abortOpenCodeSession = (context, sessionID) => runOpenCodeSdk("session.abort", (signal) => context.client.session.abort({ sessionID }, { signal })).pipe(Effect.timeoutOrElse({
420
+ duration: "2 seconds",
421
+ orElse: () => Effect.fail(new OpenCodeRuntimeError({
422
+ operation: "session.abort",
423
+ detail: `Timed out aborting OpenCode session '${sessionID}'.`
424
+ }))
425
+ }));
384
426
  const buildEventBase = (input) => Effect.sync(() => crypto.randomUUID()).pipe(Effect.map((uuid) => ({
385
427
  eventId: EventId.make(uuid),
386
428
  provider: PROVIDER$1,
@@ -540,7 +582,12 @@ function updateProviderSession(context, patch, options) {
540
582
  }
541
583
  const stopOpenCodeContext = Effect.fn("stopOpenCodeContext")(function* (context) {
542
584
  if (yield* Ref.getAndSet(context.stopped, true)) return false;
543
- yield* runOpenCodeSdk("session.abort", () => context.client.session.abort({ sessionID: context.openCodeSessionId })).pipe(Effect.ignore({ log: true }));
585
+ const pendingPrompt = context.pendingPrompt;
586
+ if (pendingPrompt) {
587
+ context.pendingPrompt = void 0;
588
+ yield* Fiber.interrupt(pendingPrompt.fiber).pipe(Effect.ignore);
589
+ }
590
+ yield* Effect.forEach([context.openCodeSessionId, ...context.childSessionIds], (sessionID) => abortOpenCodeSession(context, sessionID).pipe(Effect.ignore({ log: true })), { discard: true });
544
591
  yield* Scope.close(context.sessionScope, Exit.void);
545
592
  return true;
546
593
  });
@@ -627,6 +674,13 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
627
674
  }
628
675
  });
629
676
  });
677
+ const emitStoppedOpenCodeChildren = Effect.fn("emitStoppedOpenCodeChildren")(function* (context, raw) {
678
+ for (const subagent of context.subagentBySessionId.values()) yield* emitOpenCodeSubagentCompleted(context, {
679
+ subagent,
680
+ status: subagentCompletionStatus("stopped"),
681
+ raw
682
+ });
683
+ });
630
684
  const bindOpenCodeSubtaskPart = Effect.fn("bindOpenCodeSubtaskPart")(function* (context, part, raw) {
631
685
  const partKey = scopedOpenCodeId(part.sessionID, part.id);
632
686
  const existing = context.subagentBySubtaskPartId.get(partKey);
@@ -648,8 +702,8 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
648
702
  return context.subagentBySubtaskPartId.get(partKey);
649
703
  };
650
704
  const registerOpenCodeChildSession = Effect.fn("registerOpenCodeChildSession")(function* (context, session, raw) {
651
- if (session.parentID !== context.openCodeSessionId) return;
652
- const subagent = mergeOpenCodeChildSessionRef(context.subagentBySessionId.get(session.id) ?? takeUnboundOpenCodeSubtask(context), session, context.openCodeSessionId);
705
+ if (session.parentID !== context.openCodeSessionId && (session.parentID === void 0 || !context.childSessionIds.has(session.parentID))) return;
706
+ const subagent = mergeOpenCodeChildSessionRef(context.subagentBySessionId.get(session.id) ?? takeUnboundOpenCodeSubtask(context), session, session.parentID ?? context.openCodeSessionId);
653
707
  const known = context.childSessionIds.has(session.id);
654
708
  context.childSessionIds.add(session.id);
655
709
  context.subagentBySessionId.set(session.id, subagent);
@@ -693,6 +747,89 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
693
747
  child
694
748
  });
695
749
  });
750
+ const isRelatedOpenCodeSession = Effect.fn("isRelatedOpenCodeSession")(function* (context, candidateSessionId) {
751
+ if (candidateSessionId === context.openCodeSessionId || context.childSessionIds.has(candidateSessionId)) return true;
752
+ const seen = /* @__PURE__ */ new Set();
753
+ let sessionId = candidateSessionId;
754
+ for (let depth = 0; sessionId !== void 0 && depth < 32; depth += 1) {
755
+ if (sessionId === context.openCodeSessionId || context.childSessionIds.has(sessionId)) {
756
+ for (const relatedId of seen) context.childSessionIds.add(relatedId);
757
+ return true;
758
+ }
759
+ if (seen.has(sessionId)) return false;
760
+ seen.add(sessionId);
761
+ const currentSessionId = sessionId;
762
+ const response = yield* runOpenCodeSdk("session.get", () => context.client.session.get({ sessionID: currentSessionId })).pipe(Effect.catchIf(isOpenCodeNotFound, () => Effect.succeed(void 0)));
763
+ if (!response?.data) return false;
764
+ sessionId = response.data.parentID;
765
+ }
766
+ return false;
767
+ });
768
+ const recoverPendingOpenCodeRequests = Effect.fn("recoverPendingOpenCodeRequests")(function* (context) {
769
+ for (let attempt = 0; attempt < 5; attempt += 1) {
770
+ if (yield* Ref.get(context.stopped)) return;
771
+ const result = yield* Effect.all({
772
+ permissions: runOpenCodeSdk("permission.list", () => context.client.permission.list()),
773
+ questions: runOpenCodeSdk("question.list", () => context.client.question.list())
774
+ }).pipe(Effect.exit);
775
+ if (Exit.isFailure(result)) {
776
+ if (attempt === 4) {
777
+ yield* emitForContext(context, {
778
+ ...yield* buildEventBase({ threadId: context.session.threadId }),
779
+ type: "runtime.warning",
780
+ payload: {
781
+ message: "OpenCode pending request recovery failed.",
782
+ detail: openCodeRuntimeErrorDetail(Cause.squash(result.cause))
783
+ }
784
+ });
785
+ return;
786
+ }
787
+ yield* Effect.sleep(`${250 * 2 ** attempt} millis`);
788
+ continue;
789
+ }
790
+ for (const request of result.value.permissions.data ?? []) {
791
+ if (context.resolvedRequestIds.has(request.id) || context.pendingPermissions.has(request.id) || !(yield* isRelatedOpenCodeSession(context, request.sessionID))) continue;
792
+ context.pendingPermissions.set(request.id, request);
793
+ yield* emitForContext(context, {
794
+ ...yield* buildEventBase({
795
+ threadId: context.session.threadId,
796
+ turnId: context.activeTurnId,
797
+ requestId: request.id,
798
+ raw: {
799
+ type: "permission.asked",
800
+ properties: request,
801
+ recovered: true
802
+ }
803
+ }),
804
+ type: "request.opened",
805
+ payload: {
806
+ requestType: mapPermissionToRequestType(request.permission),
807
+ detail: request.patterns.length > 0 ? request.patterns.join("\n") : request.permission,
808
+ args: request.metadata
809
+ }
810
+ });
811
+ }
812
+ for (const request of result.value.questions.data ?? []) {
813
+ if (context.resolvedRequestIds.has(request.id) || context.pendingQuestions.has(request.id) || !(yield* isRelatedOpenCodeSession(context, request.sessionID))) continue;
814
+ context.pendingQuestions.set(request.id, request);
815
+ yield* emitForContext(context, {
816
+ ...yield* buildEventBase({
817
+ threadId: context.session.threadId,
818
+ turnId: context.activeTurnId,
819
+ requestId: request.id,
820
+ raw: {
821
+ type: "question.asked",
822
+ properties: request,
823
+ recovered: true
824
+ }
825
+ }),
826
+ type: "user-input.requested",
827
+ payload: { questions: normalizeQuestionRequest(request) }
828
+ });
829
+ }
830
+ return;
831
+ }
832
+ });
696
833
  const emitUnexpectedExit = Effect.fn("emitUnexpectedExit")(function* (context, message) {
697
834
  if (yield* Ref.getAndSet(context.stopped, true)) return;
698
835
  const turnId = context.activeTurnId;
@@ -720,7 +857,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
720
857
  }
721
858
  }).pipe(Effect.ignore);
722
859
  sessions.delete(context.session.threadId);
723
- yield* runOpenCodeSdk("session.abort", () => context.client.session.abort({ sessionID: context.openCodeSessionId })).pipe(Effect.ignore({ log: true }));
860
+ yield* Effect.forEach([context.openCodeSessionId, ...context.childSessionIds], (sessionID) => runOpenCodeSdk("session.abort", () => context.client.session.abort({ sessionID })).pipe(Effect.ignore({ log: true })), { discard: true });
724
861
  yield* Scope.close(context.sessionScope, Exit.void);
725
862
  });
726
863
  /** Emit content.delta and item.completed events for an assistant text part. */
@@ -795,8 +932,9 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
795
932
  const eventSessionId = typeof payloadSessionId === "string" ? payloadSessionId : void 0;
796
933
  const isRootSessionEvent = eventSessionId === context.openCodeSessionId;
797
934
  const isKnownChildSessionEvent = eventSessionId !== void 0 && context.childSessionIds.has(eventSessionId);
798
- const isChildSessionCreatedEvent = event.type === "session.created" && event.properties.info.parentID === context.openCodeSessionId;
799
- if (!isRootSessionEvent && !isKnownChildSessionEvent && !isChildSessionCreatedEvent) return;
935
+ const isChildSessionCreatedEvent = event.type === "session.created" && (event.properties.info.parentID === context.openCodeSessionId || event.properties.info.parentID !== void 0 && context.childSessionIds.has(event.properties.info.parentID));
936
+ const isRelatedRequestEvent = eventSessionId !== void 0 && isOpenCodeRequestEvent(event) && (yield* isRelatedOpenCodeSession(context, eventSessionId).pipe(Effect.orElseSucceed(() => false)));
937
+ if (!isRootSessionEvent && !isKnownChildSessionEvent && !isChildSessionCreatedEvent && !isRelatedRequestEvent) return;
800
938
  const turnId = context.activeTurnId;
801
939
  yield* writeNativeEventBestEffort(context.session.threadId, {
802
940
  observedAt: nowIso(),
@@ -919,6 +1057,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
919
1057
  break;
920
1058
  }
921
1059
  case "permission.asked":
1060
+ if (context.resolvedRequestIds.has(event.properties.id) || context.pendingPermissions.has(event.properties.id)) break;
922
1061
  context.pendingPermissions.set(event.properties.id, event.properties);
923
1062
  yield* emitForContext(context, {
924
1063
  ...yield* buildEventBase({
@@ -936,6 +1075,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
936
1075
  });
937
1076
  break;
938
1077
  case "permission.replied":
1078
+ context.resolvedRequestIds.add(event.properties.requestID);
939
1079
  context.pendingPermissions.delete(event.properties.requestID);
940
1080
  yield* emitForContext(context, {
941
1081
  ...yield* buildEventBase({
@@ -952,6 +1092,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
952
1092
  });
953
1093
  break;
954
1094
  case "question.asked":
1095
+ if (context.resolvedRequestIds.has(event.properties.id) || context.pendingQuestions.has(event.properties.id)) break;
955
1096
  context.pendingQuestions.set(event.properties.id, event.properties);
956
1097
  yield* emitForContext(context, {
957
1098
  ...yield* buildEventBase({
@@ -965,6 +1106,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
965
1106
  });
966
1107
  break;
967
1108
  case "question.replied": {
1109
+ context.resolvedRequestIds.add(event.properties.requestID);
968
1110
  const request = context.pendingQuestions.get(event.properties.requestID);
969
1111
  context.pendingQuestions.delete(event.properties.requestID);
970
1112
  const answers = Object.fromEntries((request?.questions ?? []).map((question, index) => [openCodeQuestionId(index, question), event.properties.answers[index]?.join(", ") ?? ""]));
@@ -981,6 +1123,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
981
1123
  break;
982
1124
  }
983
1125
  case "question.rejected":
1126
+ context.resolvedRequestIds.add(event.properties.requestID);
984
1127
  context.pendingQuestions.delete(event.properties.requestID);
985
1128
  yield* emitForContext(context, {
986
1129
  ...yield* buildEventBase({
@@ -1032,7 +1175,13 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1032
1175
  break;
1033
1176
  }
1034
1177
  if (event.properties.status.type === "idle" && turnId) {
1178
+ if (context.pendingPrompt?.turnId === turnId) {
1179
+ context.pendingPrompt.idleEvent = event;
1180
+ break;
1181
+ }
1035
1182
  context.activeTurnId = void 0;
1183
+ context.activeAgent = void 0;
1184
+ context.activeVariant = void 0;
1036
1185
  updateProviderSession(context, { status: "ready" }, { clearActiveTurnId: true });
1037
1186
  yield* emitForContext(context, {
1038
1187
  ...yield* buildEventBase({
@@ -1068,7 +1217,14 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1068
1217
  break;
1069
1218
  }
1070
1219
  const activeTurnId = context.activeTurnId;
1220
+ const pendingPrompt = context.pendingPrompt;
1221
+ if (pendingPrompt && pendingPrompt.turnId === activeTurnId) {
1222
+ context.pendingPrompt = void 0;
1223
+ yield* Fiber.interrupt(pendingPrompt.fiber).pipe(Effect.ignore);
1224
+ }
1071
1225
  context.activeTurnId = void 0;
1226
+ context.activeAgent = void 0;
1227
+ context.activeVariant = void 0;
1072
1228
  updateProviderSession(context, {
1073
1229
  status: "error",
1074
1230
  lastError: message
@@ -1133,6 +1289,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1133
1289
  const serverUrl = openCodeSettings.serverUrl;
1134
1290
  const serverPassword = openCodeSettings.serverPassword;
1135
1291
  const directory = input.cwd ?? serverConfig.cwd;
1292
+ const resumeSessionId = input.resumePolicy === "fresh" ? void 0 : parseOpenCodeResume(input.resumeCursor)?.sessionId;
1136
1293
  const existing = sessions.get(input.threadId);
1137
1294
  if (existing) {
1138
1295
  if (existing.session.runtimeSessionId === runtimeSessionId) return existing.session;
@@ -1151,16 +1308,23 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1151
1308
  const sessionScope = yield* Scope.make();
1152
1309
  if (deviceToolBinding) yield* Scope.addFinalizer(sessionScope, Effect.sync(() => deviceToolBinding.dispose()));
1153
1310
  const startedExit = yield* Effect.exit(Effect.gen(function* () {
1154
- const server = yield* openCodeRuntime.connectToOpenCodeServer({
1311
+ const server = options?.serverOwner ? yield* options.serverOwner.acquire.pipe(Effect.map((process) => ({
1312
+ url: process.url,
1313
+ ...process.serverPassword ? { serverPassword: process.serverPassword } : {},
1314
+ exitCode: process.exitCode,
1315
+ external: false
1316
+ }))) : yield* openCodeRuntime.connectToOpenCodeServer({
1155
1317
  binaryPath,
1156
1318
  serverUrl,
1319
+ ...serverPassword ? { serverPassword } : {},
1157
1320
  ...options?.environment ? { environment: options.environment } : {}
1158
1321
  });
1159
1322
  const client = yield* openCodeRuntime.createOpenCodeSdkClient({
1160
1323
  baseUrl: server.url,
1161
1324
  directory,
1162
- ...server.external && serverPassword ? { serverPassword } : {}
1325
+ ...server.serverPassword ? { serverPassword: server.serverPassword } : {}
1163
1326
  });
1327
+ yield* verifyOpenCodeServerVersion(client);
1164
1328
  if (deviceToolBinding) yield* runOpenCodeSdk("mcp.add", () => client.mcp.add({
1165
1329
  directory,
1166
1330
  name: `ryco_device_${runtimeSessionId}`,
@@ -1172,13 +1336,18 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1172
1336
  enabled: true
1173
1337
  }
1174
1338
  }));
1175
- const openCodeSession = yield* runOpenCodeSdk("session.create", () => client.session.create({
1339
+ const adoptedSession = resumeSessionId ? yield* runOpenCodeSdk("session.get", () => client.session.get({ sessionID: resumeSessionId })).pipe(Effect.map((response) => response.data), Effect.catchIf(isOpenCodeNotFound, () => Effect.succeed(void 0))) : void 0;
1340
+ if (adoptedSession) yield* runOpenCodeSdk("session.update", () => client.session.update({
1341
+ sessionID: adoptedSession.id,
1342
+ permission: buildOpenCodePermissionRules(input.runtimeMode)
1343
+ }));
1344
+ const openCodeSession = adoptedSession ? { data: adoptedSession } : yield* runOpenCodeSdk("session.create", () => client.session.create({
1176
1345
  title: `Ryco ${input.threadId}`,
1177
1346
  permission: buildOpenCodePermissionRules(input.runtimeMode)
1178
1347
  }));
1179
1348
  if (!openCodeSession.data) return yield* new OpenCodeRuntimeError({
1180
- operation: "session.create",
1181
- detail: "OpenCode session.create returned no session payload."
1349
+ operation: adoptedSession ? "session.get" : "session.create",
1350
+ detail: adoptedSession ? "OpenCode session.get returned no session payload." : "OpenCode session.create returned no session payload."
1182
1351
  });
1183
1352
  return {
1184
1353
  sessionScope,
@@ -1211,6 +1380,10 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1211
1380
  cwd: directory,
1212
1381
  ...input.modelSelection ? { model: input.modelSelection.model } : {},
1213
1382
  threadId: input.threadId,
1383
+ resumeCursor: {
1384
+ schemaVersion: OPENCODE_RESUME_VERSION,
1385
+ sessionId: started.openCodeSession.id
1386
+ },
1214
1387
  createdAt,
1215
1388
  updatedAt: createdAt
1216
1389
  };
@@ -1222,6 +1395,7 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1222
1395
  openCodeSessionId: started.openCodeSession.id,
1223
1396
  pendingPermissions: /* @__PURE__ */ new Map(),
1224
1397
  pendingQuestions: /* @__PURE__ */ new Map(),
1398
+ resolvedRequestIds: /* @__PURE__ */ new Set(),
1225
1399
  partById: /* @__PURE__ */ new Map(),
1226
1400
  emittedTextByPartId: /* @__PURE__ */ new Map(),
1227
1401
  messageRoleById: /* @__PURE__ */ new Map(),
@@ -1236,6 +1410,9 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1236
1410
  activeTurnId: void 0,
1237
1411
  activeAgent: void 0,
1238
1412
  activeVariant: void 0,
1413
+ promptSemaphore: yield* Semaphore.make(1),
1414
+ pendingPrompt: void 0,
1415
+ promptGeneration: 0,
1239
1416
  agentControlHostContextDelivered: false,
1240
1417
  stopped: yield* Ref.make(false),
1241
1418
  sessionScope: started.sessionScope
@@ -1253,120 +1430,206 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1253
1430
  payload: { providerThreadId: started.openCodeSession.id }
1254
1431
  });
1255
1432
  yield* startEventPump(context);
1256
- yield* hydrateOpenCodeChildSessions(context).pipe(Effect.forkIn(context.sessionScope));
1433
+ yield* Effect.gen(function* () {
1434
+ yield* hydrateOpenCodeChildSessions(context);
1435
+ yield* recoverPendingOpenCodeRequests(context);
1436
+ }).pipe(Effect.forkIn(context.sessionScope));
1257
1437
  return session;
1258
1438
  });
1259
1439
  const sendTurn = Effect.fn("sendTurn")(function* (input) {
1260
1440
  const context = ensureSessionContext(sessions, input.threadId);
1261
- const turnId = TurnId.make(`opencode-turn-${yield* Effect.sync(() => crypto.randomUUID())}`);
1262
- const modelSelection = input.modelSelection ?? (context.session.model ? {
1263
- instanceId: boundInstanceId,
1264
- model: context.session.model
1265
- } : void 0);
1266
- if (modelSelection !== void 0 && modelSelection.instanceId !== boundInstanceId) return yield* new ProviderAdapterValidationError({
1267
- provider: PROVIDER$1,
1268
- operation: "sendTurn",
1269
- issue: `OpenCode model selection is bound to instance '${modelSelection?.instanceId}', expected '${boundInstanceId}'.`
1270
- });
1271
- const parsedModel = parseOpenCodeModelSlug(modelSelection?.model);
1272
- if (!parsedModel) return yield* new ProviderAdapterValidationError({
1273
- provider: PROVIDER$1,
1274
- operation: "sendTurn",
1275
- issue: "OpenCode model selection must use the 'provider/model' format."
1276
- });
1277
- const formatted = formatSourceControlContextsForAgent(input.sourceControlContexts ?? []);
1278
- let text = formatted ? formatted + "\n\n" + (input.input?.trim() ?? "") : input.input?.trim();
1279
- const fileParts = toOpenCodeFileParts({
1280
- attachments: input.attachments,
1281
- resolveAttachmentPath: (attachment) => resolveAttachmentPath({
1282
- attachmentsDir: serverConfig.attachmentsDir,
1283
- attachment
1284
- })
1285
- });
1286
- if ((!text || text.length === 0) && fileParts.length === 0) return yield* new ProviderAdapterValidationError({
1287
- provider: PROVIDER$1,
1288
- operation: "sendTurn",
1289
- issue: "OpenCode turns require text input or at least one attachment."
1290
- });
1291
- if (!context.agentControlHostContextDelivered) {
1292
- text = `<ryco_host_context>${agentControlHostContext(false)}</ryco_host_context>${text ? `\n\n${text}` : ""}`;
1293
- context.agentControlHostContextDelivered = true;
1294
- }
1295
- const agent = getModelSelectionStringOptionValue(modelSelection, "agent");
1296
- const variant = getModelSelectionStringOptionValue(modelSelection, "variant");
1297
- context.activeTurnId = turnId;
1298
- context.activeAgent = agent ?? (input.interactionMode === "plan" || input.interactionMode === "ask" ? "plan" : void 0);
1299
- context.activeVariant = variant;
1300
- updateProviderSession(context, {
1301
- status: "running",
1302
- activeTurnId: turnId,
1303
- model: modelSelection?.model ?? context.session.model
1304
- }, { clearLastError: true });
1305
- yield* emitForContext(context, {
1306
- ...yield* buildEventBase({
1307
- threadId: input.threadId,
1308
- turnId
1309
- }),
1310
- type: "turn.started",
1311
- payload: {
1312
- model: modelSelection?.model ?? context.session.model,
1313
- ...variant ? { effort: variant } : {}
1441
+ return yield* context.promptSemaphore.withPermits(1)(Effect.gen(function* () {
1442
+ if (sessions.get(input.threadId) !== context || (yield* Ref.get(context.stopped))) return yield* new ProviderAdapterSessionClosedError({
1443
+ provider: PROVIDER$1,
1444
+ threadId: input.threadId
1445
+ });
1446
+ const turnId = TurnId.make(`opencode-turn-${yield* Effect.sync(() => crypto.randomUUID())}`);
1447
+ const modelSelection = input.modelSelection ?? (context.session.model ? {
1448
+ instanceId: boundInstanceId,
1449
+ model: context.session.model
1450
+ } : void 0);
1451
+ if (modelSelection !== void 0 && modelSelection.instanceId !== boundInstanceId) return yield* new ProviderAdapterValidationError({
1452
+ provider: PROVIDER$1,
1453
+ operation: "sendTurn",
1454
+ issue: `OpenCode model selection is bound to instance '${modelSelection?.instanceId}', expected '${boundInstanceId}'.`
1455
+ });
1456
+ const parsedModel = parseOpenCodeModelSlug(modelSelection?.model);
1457
+ if (!parsedModel) return yield* new ProviderAdapterValidationError({
1458
+ provider: PROVIDER$1,
1459
+ operation: "sendTurn",
1460
+ issue: "OpenCode model selection must use the 'provider/model' format."
1461
+ });
1462
+ const formatted = formatSourceControlContextsForAgent(input.sourceControlContexts ?? []);
1463
+ let text = formatted ? formatted + "\n\n" + (input.input?.trim() ?? "") : input.input?.trim();
1464
+ const attachmentUrlById = /* @__PURE__ */ new Map();
1465
+ const declaredAttachmentBytes = (input.attachments ?? []).reduce((total, attachment) => total + attachment.sizeBytes, 0);
1466
+ if (declaredAttachmentBytes > 52428800) return yield* new ProviderAdapterRequestError({
1467
+ provider: PROVIDER$1,
1468
+ method: "session.prompt",
1469
+ detail: `Attachments total ${declaredAttachmentBytes} bytes; limit is ${PROVIDER_SEND_TURN_MAX_ATTACHMENT_TOTAL_BYTES} bytes.`
1470
+ });
1471
+ let attachmentTotalBytes = 0;
1472
+ for (const attachment of input.attachments ?? []) {
1473
+ const persisted = readPersistedAttachment({
1474
+ attachmentsDir: serverConfig.attachmentsDir,
1475
+ attachment
1476
+ });
1477
+ if (!persisted.ok) return yield* new ProviderAdapterRequestError({
1478
+ provider: PROVIDER$1,
1479
+ method: "session.prompt",
1480
+ detail: persisted.reason
1481
+ });
1482
+ attachmentUrlById.set(attachment.id, `data:${attachment.mimeType};base64,${persisted.bytes.toString("base64")}`);
1483
+ attachmentTotalBytes += persisted.sizeBytes;
1484
+ if (attachmentTotalBytes > 52428800) return yield* new ProviderAdapterRequestError({
1485
+ provider: PROVIDER$1,
1486
+ method: "session.prompt",
1487
+ detail: `Attachments total ${attachmentTotalBytes} bytes; limit is ${PROVIDER_SEND_TURN_MAX_ATTACHMENT_TOTAL_BYTES} bytes.`
1488
+ });
1314
1489
  }
1315
- });
1316
- yield* runOpenCodeSdk("session.promptAsync", () => context.client.session.promptAsync({
1317
- sessionID: context.openCodeSessionId,
1318
- model: parsedModel,
1319
- ...context.activeAgent ? { agent: context.activeAgent } : {},
1320
- ...context.activeVariant ? { variant: context.activeVariant } : {},
1321
- parts: [...text ? [{
1322
- type: "text",
1323
- text
1324
- }] : [], ...fileParts]
1325
- })).pipe(Effect.mapError(toRequestError), Effect.tapError((requestError) => Effect.gen(function* () {
1326
- context.activeTurnId = void 0;
1327
- context.activeAgent = void 0;
1328
- context.activeVariant = void 0;
1490
+ const fileParts = toOpenCodeFileParts({
1491
+ attachments: input.attachments,
1492
+ resolveAttachmentUrl: (attachment) => attachmentUrlById.get(attachment.id) ?? null
1493
+ });
1494
+ if ((!text || text.length === 0) && fileParts.length === 0) return yield* new ProviderAdapterValidationError({
1495
+ provider: PROVIDER$1,
1496
+ operation: "sendTurn",
1497
+ issue: "OpenCode turns require text input or at least one attachment."
1498
+ });
1499
+ if (!context.agentControlHostContextDelivered) {
1500
+ text = `<ryco_host_context>${agentControlHostContext(false)}</ryco_host_context>${text ? `\n\n${text}` : ""}`;
1501
+ context.agentControlHostContextDelivered = true;
1502
+ }
1503
+ const agent = getModelSelectionStringOptionValue(modelSelection, "agent");
1504
+ const variant = getModelSelectionStringOptionValue(modelSelection, "variant");
1505
+ context.activeTurnId = turnId;
1506
+ context.activeAgent = agent ?? (input.interactionMode === "plan" || input.interactionMode === "ask" ? "plan" : void 0);
1507
+ context.activeVariant = variant;
1329
1508
  updateProviderSession(context, {
1330
- status: "ready",
1331
- model: modelSelection?.model ?? context.session.model,
1332
- lastError: requestError.detail
1333
- }, { clearActiveTurnId: true });
1509
+ status: "running",
1510
+ activeTurnId: turnId,
1511
+ model: modelSelection?.model ?? context.session.model
1512
+ }, { clearLastError: true });
1334
1513
  yield* emitForContext(context, {
1335
1514
  ...yield* buildEventBase({
1336
1515
  threadId: input.threadId,
1337
1516
  turnId
1338
1517
  }),
1339
- type: "turn.aborted",
1340
- payload: { reason: requestError.detail }
1518
+ type: "turn.started",
1519
+ payload: {
1520
+ model: modelSelection?.model ?? context.session.model,
1521
+ ...variant ? { effort: variant } : {}
1522
+ }
1341
1523
  });
1342
- })));
1343
- return {
1344
- threadId: input.threadId,
1345
- turnId
1346
- };
1524
+ context.promptGeneration += 1;
1525
+ const generation = context.promptGeneration;
1526
+ const promptFiber = yield* runOpenCodeSdk("session.promptAsync", (signal) => context.client.session.promptAsync({
1527
+ sessionID: context.openCodeSessionId,
1528
+ model: parsedModel,
1529
+ ...context.activeAgent ? { agent: context.activeAgent } : {},
1530
+ ...context.activeVariant ? { variant: context.activeVariant } : {},
1531
+ parts: [...text ? [{
1532
+ type: "text",
1533
+ text
1534
+ }] : [], ...fileParts]
1535
+ }, { signal })).pipe(Effect.mapError(toRequestError), Effect.tapError((requestError) => context.activeTurnId === turnId && context.promptGeneration === generation ? Effect.gen(function* () {
1536
+ context.activeTurnId = void 0;
1537
+ context.activeAgent = void 0;
1538
+ context.activeVariant = void 0;
1539
+ updateProviderSession(context, {
1540
+ status: "ready",
1541
+ model: modelSelection?.model ?? context.session.model,
1542
+ lastError: requestError.detail
1543
+ }, { clearActiveTurnId: true });
1544
+ yield* emitForContext(context, {
1545
+ ...yield* buildEventBase({
1546
+ threadId: input.threadId,
1547
+ turnId
1548
+ }),
1549
+ type: "turn.aborted",
1550
+ payload: { reason: requestError.detail }
1551
+ });
1552
+ }) : Effect.void)).pipe(Effect.forkIn(context.sessionScope));
1553
+ const pendingPrompt = {
1554
+ turnId,
1555
+ fiber: promptFiber
1556
+ };
1557
+ context.pendingPrompt = pendingPrompt;
1558
+ yield* Fiber.join(promptFiber).pipe(Effect.ensuring(Effect.sync(() => {
1559
+ if (context.pendingPrompt?.fiber === promptFiber) context.pendingPrompt = void 0;
1560
+ })));
1561
+ const completedDuringAdmission = pendingPrompt.idleEvent !== void 0;
1562
+ if (completedDuringAdmission && context.activeTurnId === turnId) {
1563
+ context.activeTurnId = void 0;
1564
+ context.activeAgent = void 0;
1565
+ context.activeVariant = void 0;
1566
+ updateProviderSession(context, { status: "ready" }, { clearActiveTurnId: true });
1567
+ yield* emitForContext(context, {
1568
+ ...yield* buildEventBase({
1569
+ threadId: context.session.threadId,
1570
+ turnId,
1571
+ raw: pendingPrompt.idleEvent
1572
+ }),
1573
+ type: "turn.completed",
1574
+ payload: { state: "completed" }
1575
+ });
1576
+ }
1577
+ if (sessions.get(input.threadId) !== context || (yield* Ref.get(context.stopped)) || !completedDuringAdmission && context.activeTurnId !== turnId || context.promptGeneration !== generation) return yield* Effect.interrupt;
1578
+ return {
1579
+ threadId: input.threadId,
1580
+ turnId,
1581
+ resumeCursor: context.session.resumeCursor
1582
+ };
1583
+ }));
1347
1584
  });
1348
1585
  const interruptTurn = Effect.fn("interruptTurn")(function* (threadId, turnId) {
1349
1586
  const context = ensureSessionContext(sessions, threadId);
1350
- yield* runOpenCodeSdk("session.abort", () => context.client.session.abort({ sessionID: context.openCodeSessionId })).pipe(Effect.mapError(toRequestError));
1351
- if (turnId ?? context.activeTurnId) yield* emitForContext(context, {
1352
- ...yield* buildEventBase({
1353
- threadId,
1354
- turnId: turnId ?? context.activeTurnId
1355
- }),
1356
- type: "turn.aborted",
1357
- payload: { reason: "Interrupted by user." }
1587
+ const interruptedTurnId = turnId ?? context.activeTurnId;
1588
+ if (turnId !== void 0 && context.activeTurnId !== void 0 && turnId !== context.activeTurnId) return;
1589
+ const pendingPrompt = context.pendingPrompt;
1590
+ if (pendingPrompt && pendingPrompt.turnId === interruptedTurnId) {
1591
+ context.pendingPrompt = void 0;
1592
+ yield* Fiber.interrupt(pendingPrompt.fiber).pipe(Effect.ignore);
1593
+ }
1594
+ const rootAbortExit = yield* abortOpenCodeSession(context, context.openCodeSessionId).pipe(Effect.mapError(toRequestError), Effect.exit);
1595
+ yield* Effect.forEach(context.childSessionIds, (sessionID) => abortOpenCodeSession(context, sessionID).pipe(Effect.ignore({ log: true })), { discard: true });
1596
+ yield* emitStoppedOpenCodeChildren(context, {
1597
+ method: "session.abort",
1598
+ reason: "turn-interrupted"
1358
1599
  });
1600
+ if (Exit.isFailure(rootAbortExit)) return yield* Effect.failCause(rootAbortExit.cause);
1601
+ if (interruptedTurnId) {
1602
+ if (context.activeTurnId === interruptedTurnId) {
1603
+ context.activeTurnId = void 0;
1604
+ context.activeAgent = void 0;
1605
+ context.activeVariant = void 0;
1606
+ updateProviderSession(context, { status: "ready" }, {
1607
+ clearActiveTurnId: true,
1608
+ clearLastError: true
1609
+ });
1610
+ }
1611
+ yield* emitForContext(context, {
1612
+ ...yield* buildEventBase({
1613
+ threadId,
1614
+ turnId: interruptedTurnId
1615
+ }),
1616
+ type: "turn.aborted",
1617
+ payload: { reason: "Interrupted by user." }
1618
+ });
1619
+ }
1359
1620
  });
1360
1621
  const respondToRequest = Effect.fn("respondToRequest")(function* (threadId, requestId, decision) {
1361
1622
  const context = ensureSessionContext(sessions, threadId);
1362
- if (!context.pendingPermissions.has(requestId)) return yield* new ProviderAdapterRequestError({
1623
+ const request = context.pendingPermissions.get(requestId);
1624
+ if (!request) return yield* new ProviderAdapterRequestError({
1363
1625
  provider: PROVIDER$1,
1364
- method: "permission.reply",
1626
+ method: "permission.respond",
1365
1627
  detail: `Unknown pending permission request: ${requestId}`
1366
1628
  });
1367
- yield* runOpenCodeSdk("permission.reply", () => context.client.permission.reply({
1368
- requestID: requestId,
1369
- reply: toOpenCodePermissionReply(decision)
1629
+ yield* runOpenCodeSdk("permission.respond", () => context.client.permission.respond({
1630
+ sessionID: request.sessionID,
1631
+ permissionID: requestId,
1632
+ response: toOpenCodePermissionReply(decision)
1370
1633
  })).pipe(Effect.mapError(toRequestError));
1371
1634
  });
1372
1635
  const respondToUserInput = Effect.fn("respondToUserInput")(function* (threadId, requestId, answers) {
@@ -1389,6 +1652,10 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
1389
1652
  threadId
1390
1653
  });
1391
1654
  if (!(yield* stopOpenCodeContext(context))) return;
1655
+ yield* emitStoppedOpenCodeChildren(context, {
1656
+ method: "session.abort",
1657
+ reason: "session-stopped"
1658
+ });
1392
1659
  yield* emitForContext(context, {
1393
1660
  ...yield* buildEventBase({ threadId }),
1394
1661
  type: "session.exited",
@@ -1458,7 +1725,6 @@ const OPENCODE_PRESENTATION = {
1458
1725
  displayName: "OpenCode",
1459
1726
  showInteractionModeToggle: false
1460
1727
  };
1461
- const MINIMUM_OPENCODE_VERSION = "1.14.19";
1462
1728
  var OpenCodeProbeError = class extends Data.TaggedError("OpenCodeProbeError") {};
1463
1729
  function normalizeProbeMessage(message) {
1464
1730
  const trimmed = message.trim();
@@ -1518,7 +1784,7 @@ function inferDefaultAgent(agents) {
1518
1784
  }
1519
1785
  const DEFAULT_OPENCODE_MODEL_CAPABILITIES = createModelCapabilities({ optionDescriptors: [] });
1520
1786
  function openCodeCapabilitiesForModel(input) {
1521
- const variantValues = Object.keys(input.model.variants ?? {});
1787
+ const variantValues = Object.entries(input.model.variants ?? {}).filter(([, configuration]) => configuration.disabled !== true).map(([variant]) => variant).toSorted((left, right) => left.localeCompare(right));
1522
1788
  const defaultVariant = inferDefaultVariant(input.providerID, variantValues);
1523
1789
  const variantOptions = variantValues.map((value) => defaultVariant === value ? {
1524
1790
  id: value,
@@ -1528,7 +1794,7 @@ function openCodeCapabilitiesForModel(input) {
1528
1794
  id: value,
1529
1795
  label: titleCaseSlug(value)
1530
1796
  });
1531
- const primaryAgents = input.agents.filter((agent) => !agent.hidden && (agent.mode === "primary" || agent.mode === "all"));
1797
+ const primaryAgents = [...new Map(input.agents.filter((agent) => !agent.hidden && (agent.mode === "primary" || agent.mode === "all")).map((agent) => [agent.name, agent])).values()].toSorted((left, right) => left.name.localeCompare(right.name));
1532
1798
  const defaultAgent = inferDefaultAgent(primaryAgents);
1533
1799
  const agentOptions = primaryAgents.map((agent) => defaultAgent === agent.name ? {
1534
1800
  id: agent.name,
@@ -1554,16 +1820,19 @@ function openCodeCapabilitiesForModel(input) {
1554
1820
  }
1555
1821
  function flattenOpenCodeModels(input) {
1556
1822
  const connected = new Set(input.providerList.connected);
1557
- const models = [];
1823
+ const models = /* @__PURE__ */ new Map();
1558
1824
  for (const provider of input.providerList.all) {
1559
1825
  if (!connected.has(provider.id)) continue;
1560
1826
  for (const model of Object.values(provider.models)) {
1827
+ const modelId = nonEmptyTrimmed(model.id);
1561
1828
  const name = nonEmptyTrimmed(model.name);
1562
- if (!name) continue;
1829
+ if (!modelId || !name) continue;
1563
1830
  const subProvider = nonEmptyTrimmed(provider.name);
1564
1831
  const shortName = subProvider ? deriveShortNameByStrippingPrefix(name, subProvider) : void 0;
1565
- models.push({
1566
- slug: `${provider.id}/${model.id}`,
1832
+ const slug = `${provider.id}/${modelId}`;
1833
+ if (models.has(slug)) continue;
1834
+ models.set(slug, {
1835
+ slug,
1567
1836
  name,
1568
1837
  ...subProvider ? { subProvider } : {},
1569
1838
  ...shortName ? { shortName } : {},
@@ -1576,7 +1845,7 @@ function flattenOpenCodeModels(input) {
1576
1845
  });
1577
1846
  }
1578
1847
  }
1579
- return models.toSorted((left, right) => left.name.localeCompare(right.name));
1848
+ return [...models.values()].toSorted((left, right) => left.name.localeCompare(right.name) || left.slug.localeCompare(right.slug));
1580
1849
  }
1581
1850
  /**
1582
1851
  * Strip a leading provider prefix from `name` so the chat-box trigger doesn't
@@ -1671,7 +1940,7 @@ const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatus")(fun
1671
1940
  if (versionExit._tag === "Failure") return fallback(Cause.squash(versionExit.cause));
1672
1941
  version = parseGenericCliVersion(versionExit.value.stdout) ?? null;
1673
1942
  if (!version) return fallback(/* @__PURE__ */ new Error(`Unable to determine OpenCode version from \`opencode --version\` output. Ryco requires OpenCode v${MINIMUM_OPENCODE_VERSION} or newer.`), null);
1674
- if (compareCliVersions(version, MINIMUM_OPENCODE_VERSION) < 0) return buildServerProvider({
1943
+ if (compareCliVersions(version, "1.14.19") < 0) return buildServerProvider({
1675
1944
  presentation: OPENCODE_PRESENTATION,
1676
1945
  enabled: openCodeSettings.enabled,
1677
1946
  checkedAt,
@@ -1689,6 +1958,7 @@ const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatus")(fun
1689
1958
  const server = yield* openCodeRuntime.connectToOpenCodeServer({
1690
1959
  binaryPath: openCodeSettings.binaryPath,
1691
1960
  serverUrl: openCodeSettings.serverUrl,
1961
+ ...openCodeSettings.serverPassword ? { serverPassword: openCodeSettings.serverPassword } : {},
1692
1962
  environment
1693
1963
  }).pipe(Effect.mapError((cause) => new OpenCodeProbeError({
1694
1964
  cause,
@@ -1697,19 +1967,27 @@ const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatus")(fun
1697
1967
  const client = yield* openCodeRuntime.createOpenCodeSdkClient({
1698
1968
  baseUrl: server.url,
1699
1969
  directory: cwd,
1700
- ...isExternalServer && openCodeSettings.serverPassword ? { serverPassword: openCodeSettings.serverPassword } : {}
1970
+ ...server.serverPassword ? { serverPassword: server.serverPassword } : {}
1701
1971
  }).pipe(Effect.mapError((cause) => new OpenCodeProbeError({
1702
1972
  cause,
1703
1973
  detail: openCodeRuntimeErrorDetail(cause)
1704
1974
  })));
1705
- return yield* openCodeRuntime.loadOpenCodeInventory(client).pipe(Effect.mapError((cause) => new OpenCodeProbeError({
1975
+ const serverVersion = yield* verifyOpenCodeServerVersion(client).pipe(Effect.mapError((cause) => new OpenCodeProbeError({
1706
1976
  cause,
1707
1977
  detail: openCodeRuntimeErrorDetail(cause)
1708
1978
  })));
1979
+ return {
1980
+ inventory: yield* openCodeRuntime.loadOpenCodeInventory(client).pipe(Effect.mapError((cause) => new OpenCodeProbeError({
1981
+ cause,
1982
+ detail: openCodeRuntimeErrorDetail(cause)
1983
+ }))),
1984
+ serverVersion
1985
+ };
1709
1986
  })));
1710
1987
  if (inventoryExit._tag === "Failure") return fallback(Cause.squash(inventoryExit.cause), version);
1711
- const models = providerModelsFromSettings(flattenOpenCodeModels(inventoryExit.value), PROVIDER, customModels, DEFAULT_OPENCODE_MODEL_CAPABILITIES);
1712
- const connectedCount = inventoryExit.value.providerList.connected.length;
1988
+ version = inventoryExit.value.serverVersion;
1989
+ const models = providerModelsFromSettings(flattenOpenCodeModels(inventoryExit.value.inventory), PROVIDER, customModels, DEFAULT_OPENCODE_MODEL_CAPABILITIES);
1990
+ const connectedCount = new Set(inventoryExit.value.inventory.providerList.connected).size;
1713
1991
  return buildServerProvider({
1714
1992
  presentation: OPENCODE_PRESENTATION,
1715
1993
  enabled: true,
@@ -1738,8 +2016,7 @@ const checkOpenCodeProviderStatus = Effect.fn("checkOpenCodeProviderStatus")(fun
1738
2016
  *
1739
2017
  * Two instances with different `serverUrl`s therefore talk to independent
1740
2018
  * OpenCode servers; when no `serverUrl` is set, the adapter + text-generation
1741
- * shares spin up their own scoped child processes, and those child
1742
- * processes are released when the registry scope closes.
2019
+ * shares reuse one scoped child process owned by the provider instance.
1743
2020
  *
1744
2021
  * @module provider/Drivers/OpenCodeDriver
1745
2022
  */
@@ -1800,12 +2077,14 @@ const OpenCodeDriver = {
1800
2077
  binaryPath: effectiveConfig.binaryPath,
1801
2078
  env: processEnv
1802
2079
  });
2080
+ const serverOwner = effectiveConfig.serverUrl.trim().length === 0 ? yield* makeOpenCodeServerOwner(effectiveConfig, processEnv) : void 0;
1803
2081
  const adapter = yield* makeOpenCodeAdapter(effectiveConfig, {
1804
2082
  instanceId,
1805
2083
  environment: processEnv,
2084
+ ...serverOwner ? { serverOwner } : {},
1806
2085
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}
1807
2086
  });
1808
- const textGeneration = yield* makeOpenCodeTextGeneration(effectiveConfig, processEnv);
2087
+ const textGeneration = yield* makeOpenCodeTextGeneration(effectiveConfig, processEnv, serverOwner ? { serverOwner } : void 0);
1809
2088
  const checkProvider = checkOpenCodeProviderStatus(effectiveConfig, serverConfig.cwd, processEnv).pipe(Effect.map(stampIdentity), Effect.provideService(OpenCodeRuntime, openCodeRuntime));
1810
2089
  const snapshot = yield* makeManagedServerProvider({
1811
2090
  maintenanceCapabilities,
@@ -1815,6 +2094,7 @@ const OpenCodeDriver = {
1815
2094
  initialSnapshot: (settings) => stampIdentity(makePendingOpenCodeProvider(settings)),
1816
2095
  checkProvider,
1817
2096
  enrichSnapshot: ({ snapshot, publishSnapshot }) => enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities).pipe(Effect.provideService(HttpClient.HttpClient, httpClient), Effect.provideService(ServerSettingsService, serverSettings), Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot))),
2097
+ retainInventoryOnError: true,
1818
2098
  refreshInterval: null
1819
2099
  }).pipe(Effect.mapError((cause) => new ProviderDriverError({
1820
2100
  driver: DRIVER_KIND,