very-happy-cli 0.2.192 → 0.2.193

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 (208) hide show
  1. package/dist/{AcpBackend-CGHTDJd9.mjs → AcpBackend-B4PwjqHt.mjs} +3 -3
  2. package/dist/{AcpBackend-BQO4ShOy.cjs → AcpBackend-DtJCgftG.cjs} +3 -3
  3. package/dist/{AcpSessionManager-G0xD6Jbq.mjs → AcpSessionManager-BzKWgkdP.mjs} +2 -2
  4. package/dist/{AcpSessionManager-LlUMmcpB.cjs → AcpSessionManager-D4qshX_H.cjs} +2 -2
  5. package/dist/{BasePermissionHandler-N6Ip3tFt.cjs → BasePermissionHandler-5iG-cvA2.cjs} +1 -1
  6. package/dist/{BasePermissionHandler-BmTIg376.mjs → BasePermissionHandler-DV6UM6e9.mjs} +1 -1
  7. package/dist/{account-CCVT-HO_.mjs → account-Dco_nGT4.mjs} +84 -27
  8. package/dist/{account-DtaouikP.cjs → account-DvpA60oU.cjs} +84 -27
  9. package/dist/{accountService-Dd9uqde2.mjs → accountService-Cd7bnkfd.mjs} +369 -19
  10. package/dist/{accountService-Bddy0zwL.cjs → accountService-CuUSJDhP.cjs} +369 -19
  11. package/dist/{acpSessionResume-BnHDk5eD.cjs → acpSessionResume-Bk9mjXZ9.cjs} +1 -1
  12. package/dist/{acpSessionResume-BWEUxNtC.mjs → acpSessionResume-TQwN9ZZE.mjs} +1 -1
  13. package/dist/{agentHome-B0VnjkZW.mjs → agentHome-Bep8semY.mjs} +4 -4
  14. package/dist/{agentHome-CqQ29YY7.cjs → agentHome-c2dlgcw1.cjs} +4 -4
  15. package/dist/{api-hMDsC6Wg.cjs → api-CBE_a88I.cjs} +10 -10
  16. package/dist/{api-_LeBScjg.mjs → api-DUfunY3x.mjs} +10 -10
  17. package/dist/{apiMachine-CqW2m6Zr.cjs → apiMachine-BqtG0IWm.cjs} +19 -18
  18. package/dist/{apiMachine-CgRldeJ6.mjs → apiMachine-CU_bw5nV.mjs} +19 -18
  19. package/dist/{attachmentContent-BEeT2J5n.cjs → attachmentContent-B3AzuYqk.cjs} +2 -2
  20. package/dist/{attachmentContent-CyptLIfq.mjs → attachmentContent-KNIZxwlu.mjs} +2 -2
  21. package/dist/{auth-CFQikywl.mjs → auth-CZ7pKS-j.mjs} +8 -8
  22. package/dist/{auth-C9NvNHhL.cjs → auth-DCjxpI6Z.cjs} +5 -5
  23. package/dist/{auth-CA1OClsW.cjs → auth-SJ_dPw7H.cjs} +8 -8
  24. package/dist/{auth-DL8_J9vu.mjs → auth-jN5dNqTO.mjs} +5 -5
  25. package/dist/{auto-uQOxlxLp.cjs → auto-B_59RYH1.cjs} +23 -21
  26. package/dist/{auto-CKI05w1D.mjs → auto-DC0Sq-qB.mjs} +23 -21
  27. package/dist/{bootstrap-DaZ0Np7X.mjs → bootstrap-B3gMpU9e.mjs} +2 -2
  28. package/dist/{bootstrap-DsZGc69k.cjs → bootstrap-CoJu9VnB.cjs} +2 -2
  29. package/dist/{browser-BUIaSHK2.mjs → browser-LHW2hBH8.mjs} +1 -1
  30. package/dist/{browser-Ft0ASDm7.cjs → browser-v1pdPP1E.cjs} +1 -1
  31. package/dist/{claudeAccountEnv-ON24i0qv.mjs → claudeAccountEnv-BL1pR_37.mjs} +2 -1
  32. package/dist/{claudeAccountEnv-BOBpJ3k8.cjs → claudeAccountEnv-CEX_EMZr.cjs} +2 -1
  33. package/dist/{claudeLocal-B1ZVtryl.mjs → claudeLocal-BZUgA5G2.mjs} +5 -5
  34. package/dist/{claudeLocal-BMf9t4Fa.cjs → claudeLocal-BrzM2RBI.cjs} +5 -5
  35. package/dist/{claudeLocalLauncher-Bp8bqF4y.mjs → claudeLocalLauncher-A0AQyHFi.mjs} +10 -10
  36. package/dist/{claudeLocalLauncher-C8TeJcfF.cjs → claudeLocalLauncher-XAMpXUM7.cjs} +10 -10
  37. package/dist/{claudeSessionFork-YiktY55n.cjs → claudeSessionFork-Mhn2fYe_.cjs} +1 -1
  38. package/dist/{claudeSessionFork-8AA47z8Y.mjs → claudeSessionFork-_GwIlmMB.mjs} +1 -1
  39. package/dist/{client-Cxlp_D4I.mjs → client-7RnI9J0W.mjs} +2 -2
  40. package/dist/{client-Bm4oKvW7.mjs → client-Bde4QVIn.mjs} +4 -2
  41. package/dist/{client-D8XROyZc.cjs → client-CJr8Pjwm.cjs} +4 -2
  42. package/dist/{client-Crh8_cNx.cjs → client-D2GWkd-T.cjs} +2 -2
  43. package/dist/{client-CFHZfh9x.cjs → client-DLlnmAPL.cjs} +4 -4
  44. package/dist/{client-BmPaBnDK.mjs → client-DwbhrX6D.mjs} +4 -4
  45. package/dist/codex/happyMcpStdioBridge.cjs +16 -16
  46. package/dist/codex/happyMcpStdioBridge.mjs +16 -16
  47. package/dist/codexAccount-BDQjRbtI.cjs +1028 -0
  48. package/dist/codexAccount-NOX5pmQf.mjs +1015 -0
  49. package/dist/{codexAppServerClient-BWJbLCQn.mjs → codexAppServerClient-B3QJV6Ey.mjs} +18 -7
  50. package/dist/{codexAppServerClient-q8GHQhyC.cjs → codexAppServerClient-DWEsZUC4.cjs} +18 -7
  51. package/dist/{codexCommand-BgpGg-Zy.cjs → codexCommand-Bg8AmxVm.cjs} +187 -57
  52. package/dist/{codexCommand-BfXfRQr4.mjs → codexCommand-D1xlj4sT.mjs} +188 -58
  53. package/dist/{codexTermination-CVUF0X75.cjs → codexTermination-ByX9GcEJ.cjs} +1 -1
  54. package/dist/{codexTermination-s9fd1gkA.mjs → codexTermination-CaWAVQjZ.mjs} +1 -1
  55. package/dist/{config-BAjyTyYp.cjs → config-B2GGbiTv.cjs} +3 -3
  56. package/dist/{config-BF8XgLyc.mjs → config-C2XYEwXz.mjs} +3 -3
  57. package/dist/{configuration-CXEVKAyF.cjs → configuration-BBK0rmmj.cjs} +1 -1
  58. package/dist/{configuration-IhRiLDVe.mjs → configuration-ThKBP_zY.mjs} +1 -1
  59. package/dist/{connect-LZh1gr08.mjs → connect-BirnCl9q.mjs} +13 -13
  60. package/dist/{connect-rCS56arw.cjs → connect-C3tZs_NC.cjs} +13 -13
  61. package/dist/{context-DO6F5YwH.mjs → context-C0EFLnOg.mjs} +1 -1
  62. package/dist/{context-3_S_mWz9.cjs → context-wDp0aZBK.cjs} +1 -1
  63. package/dist/{controlClient-8ILulwjc.mjs → controlClient-Ckl8N1MS.mjs} +3 -3
  64. package/dist/{controlClient-j7p5p3_7.cjs → controlClient-DwWTns3A.cjs} +3 -3
  65. package/dist/{createSessionMetadata-DwdD_uVo.cjs → createSessionMetadata-DqZ6h02H.cjs} +2 -2
  66. package/dist/{createSessionMetadata-oyaTZm1b.mjs → createSessionMetadata-vug4Cv8z.mjs} +2 -2
  67. package/dist/{daemonAccounts-BCjDgoNt.cjs → daemonAccounts-CpGDY_4k.cjs} +4 -1
  68. package/dist/{daemonAccounts-BJgt6IJe.mjs → daemonAccounts-DwPwKxvv.mjs} +5 -2
  69. package/dist/{defaultPermissionMode-BFShzF55.cjs → defaultPermissionMode-BakXiqRr.cjs} +1 -1
  70. package/dist/{defaultPermissionMode-Lt3PUCwY.mjs → defaultPermissionMode-DF5AfeBb.mjs} +1 -1
  71. package/dist/{deterministicJson-Dfp-7wUZ.mjs → deterministicJson-BzX94gi3.mjs} +13 -13
  72. package/dist/{deterministicJson-DUN0v3St.cjs → deterministicJson-t33SsuRC.cjs} +13 -13
  73. package/dist/{doctor-FgUYTbAT.cjs → doctor-B9ug1LZb.cjs} +7 -7
  74. package/dist/{doctor-B_UwMcVT.mjs → doctor-C1zyOSXw.mjs} +7 -7
  75. package/dist/{downloadTarget-C0d6jRx-.mjs → downloadTarget-Baslc6jW.mjs} +6 -6
  76. package/dist/{downloadTarget-BrrQEDxg.cjs → downloadTarget-T1id2Gh6.cjs} +6 -6
  77. package/dist/{ensureDaemonRunning-KUMFfIil.mjs → ensureDaemonRunning-C6ERYK-O.mjs} +5 -5
  78. package/dist/{ensureDaemonRunning-Cq4FYI5Q.cjs → ensureDaemonRunning-CoAg11Zi.cjs} +5 -5
  79. package/dist/{handleResumeCommand-BGhVo3QH.mjs → handleResumeCommand-CrlqDuz7.mjs} +5 -5
  80. package/dist/{handleResumeCommand-Cl9GIL5F.cjs → handleResumeCommand-DPi-sPm7.cjs} +5 -5
  81. package/dist/{index-CZaLMmPC.cjs → index-B1swQJUS.cjs} +4 -4
  82. package/dist/{index-CQ_hLLCj.cjs → index-B2dJA8VG.cjs} +3 -3
  83. package/dist/{index-BzAYnYct.cjs → index-BUFrKZeQ.cjs} +198 -108
  84. package/dist/{index-JQDyJ3Li.mjs → index-BbdV2mzy.mjs} +3 -3
  85. package/dist/{index-BjXjMhGY.mjs → index-BcSPg3c5.mjs} +4 -4
  86. package/dist/{index-D8ODb0_U.cjs → index-Bkslzin5.cjs} +42 -42
  87. package/dist/{index-v5EmjT8l.mjs → index-Cn73rdtQ.mjs} +4 -4
  88. package/dist/{index-DYD3GM1m.mjs → index-D1YnIih6.mjs} +195 -109
  89. package/dist/{index-Ca1Tt96A.mjs → index-fZO4nF6e.mjs} +43 -43
  90. package/dist/{index-CRipkiqo.cjs → index-rocrvOYG.cjs} +4 -4
  91. package/dist/index.cjs +2 -2
  92. package/dist/index.mjs +2 -2
  93. package/dist/{install-ClUA9tbC.cjs → install-CArXjPfW.cjs} +3 -3
  94. package/dist/{install-D6EHRtAN.mjs → install-CChhyV2G.mjs} +3 -3
  95. package/dist/lib.cjs +12 -12
  96. package/dist/lib.d.cts +97 -25
  97. package/dist/lib.d.mts +97 -25
  98. package/dist/lib.mjs +12 -12
  99. package/dist/{lidState-CZOXXdzv.mjs → lidState-B6yYKjNK.mjs} +1 -1
  100. package/dist/{lidState-DqoN7zH4.cjs → lidState-B_v6qgfE.cjs} +1 -1
  101. package/dist/{localHappyAgentAuth-YHxDZ4x4.mjs → localHappyAgentAuth-KRlg_aI0.mjs} +1 -1
  102. package/dist/{localHappyAgentAuth-BnGCpHRX.cjs → localHappyAgentAuth-jJH0n67S.cjs} +1 -1
  103. package/dist/{logger-8su64lqR.cjs → logger-CX3x2eI4.cjs} +2 -2
  104. package/dist/{logger-Fd_rNvgd.mjs → logger-JV7-4Q_6.mjs} +2 -2
  105. package/dist/{machineMetadata-1HIIC7Bc.mjs → machineMetadata-D5-SW9kv.mjs} +3 -3
  106. package/dist/{machineMetadata-DYXt3p6u.cjs → machineMetadata-DhZuM0iB.cjs} +3 -3
  107. package/dist/{main-C_GrcYkn.cjs → main-1x1HGQEy.cjs} +47 -47
  108. package/dist/{main-BI6GIzUL.mjs → main-CFOdXbPD.mjs} +47 -47
  109. package/dist/{mcp-BycIv9oQ.cjs → mcp-BnKBSEh7.cjs} +18 -18
  110. package/dist/{mcp-XGoxywno.mjs → mcp-R6lMcFLO.mjs} +18 -18
  111. package/dist/{mirrorProtocol-DXT3rv7T.mjs → mirrorProtocol-CD4ntuZJ.mjs} +3 -3
  112. package/dist/{mirrorProtocol-DVnB8EO8.cjs → mirrorProtocol-DO-KtvAL.cjs} +3 -3
  113. package/dist/{package-6KkRAops.mjs → package-Bw3H6VLn.mjs} +7 -7
  114. package/dist/{package-iuLlSiSF.cjs → package-uzlvxa5S.cjs} +7 -7
  115. package/dist/{panels-B5Di2zb2.mjs → panels-BamhZCoZ.mjs} +5 -5
  116. package/dist/{panels-0C89q0Tu.cjs → panels-C46FxjmH.cjs} +5 -5
  117. package/dist/{peerTools-CANTX_mG.cjs → peerTools-D-VNNFw-.cjs} +5 -5
  118. package/dist/{peerTools-CKJ-IDM4.mjs → peerTools-WtRgTSqG.mjs} +5 -5
  119. package/dist/{persistence-DWcHe035.mjs → persistence-Cg4sfjQV.mjs} +2 -2
  120. package/dist/{persistence-B4ttN-fR.cjs → persistence-CsmAgN-C.cjs} +2 -2
  121. package/dist/{piRunnerArgs-Bl5GpBoN.mjs → piRunnerArgs-BbaAQvb4.mjs} +1 -1
  122. package/dist/{piRunnerArgs-BOkfxyak.cjs → piRunnerArgs-vnFygygF.cjs} +1 -1
  123. package/dist/{piRuntime-BhwxzdQf.mjs → piRuntime-Bid7TBf5.mjs} +1 -1
  124. package/dist/{piRuntime-DzrIiZU8.cjs → piRuntime-C2uj5Ucx.cjs} +1 -1
  125. package/dist/{piTerminal-BdS7ol7v.cjs → piTerminal-Ckpjfoqa.cjs} +20 -20
  126. package/dist/{piTerminal-DnA2CbGr.mjs → piTerminal-CqxgrI13.mjs} +20 -20
  127. package/dist/{pushNotifications-BqFoLye2.cjs → pushNotifications-BCg7YAiu.cjs} +3 -3
  128. package/dist/{pushNotifications-DkQ0yvFs.mjs → pushNotifications-BbE-qV9I.mjs} +3 -3
  129. package/dist/{query-BRJYSkb1.mjs → query-Bfr9O_62.mjs} +1 -1
  130. package/dist/{query-BQ4br3yn.cjs → query-vQ-HG394.cjs} +1 -1
  131. package/dist/{rateLimitReporter-DK5SQuCc.cjs → rateLimitReporter-BZ8x0-6-.cjs} +3 -3
  132. package/dist/{rateLimitReporter-BRbYkmuP.mjs → rateLimitReporter-CAz7VMw4.mjs} +3 -3
  133. package/dist/{rateLimitWindows-DBfiuYeg.cjs → rateLimitWindows-BZl6GMwQ.cjs} +1 -1
  134. package/dist/{rateLimitWindows-Da5AR-4u.mjs → rateLimitWindows-CRARnKaI.mjs} +1 -1
  135. package/dist/{registerCommonHandlers-m6pxxf2J.cjs → registerCommonHandlers-CZGmrPbT.cjs} +2 -2
  136. package/dist/{registerCommonHandlers-yQ7Ru-l0.mjs → registerCommonHandlers-Cj3Nl9y-.mjs} +2 -2
  137. package/dist/{registerKillSessionHandler-BDNpi7YO.mjs → registerKillSessionHandler-Bg9t45Ub.mjs} +6 -6
  138. package/dist/{registerKillSessionHandler-BAOIa_Fs.cjs → registerKillSessionHandler-C3EDnW4F.cjs} +6 -6
  139. package/dist/{remoteSessionClient-CZ7aaNgj.mjs → remoteSessionClient--0vfA7I5.mjs} +5 -5
  140. package/dist/{remoteSessionClient-iJMXRN_D.cjs → remoteSessionClient-CcSP24Zq.cjs} +5 -5
  141. package/dist/{reportProgressTool-DfQhPu0s.mjs → reportProgressTool-DVru7jc_.mjs} +3 -3
  142. package/dist/{reportProgressTool-DpFs7pSe.cjs → reportProgressTool-Ddg1yVq2.cjs} +3 -3
  143. package/dist/{run-p-xp1_HY.cjs → run-BTrIT_jU.cjs} +178 -847
  144. package/dist/{run-CwN28mcj.mjs → run-HtvH6BLi.mjs} +176 -845
  145. package/dist/{runClaude-DRKtAGTm.mjs → runClaude-DsHTk5Bu.mjs} +25 -25
  146. package/dist/{runClaude-D6U1Z575.cjs → runClaude-ipjwAHPI.cjs} +25 -25
  147. package/dist/{runClaudeDeps-Dkofokgb.cjs → runClaudeDeps-BKpwL6ln.cjs} +41 -41
  148. package/dist/{runClaudeDeps-BheVcIlD.mjs → runClaudeDeps-BV3vpeyY.mjs} +46 -46
  149. package/dist/{runGemini-C8q3YCc0.cjs → runGemini-B-G0_7Ab.cjs} +33 -33
  150. package/dist/{runGemini-owbvhFbi.mjs → runGemini-DhjK6_Fp.mjs} +33 -33
  151. package/dist/{runOpenClaw-Dky3-mjO.mjs → runOpenClaw-B6lawk8n.mjs} +18 -18
  152. package/dist/{runOpenClaw-DGeN66-t.cjs → runOpenClaw-BHIo8tkn.cjs} +18 -18
  153. package/dist/{sandbox-D2CPyoCA.cjs → sandbox-BAsO0ILe.cjs} +4 -4
  154. package/dist/{sandbox-sq_wy9Gl.mjs → sandbox-CKb7pCXg.mjs} +4 -4
  155. package/dist/selfCheck-CZ-t1Xzq.mjs +88 -0
  156. package/dist/{selfCheck-BgLvQKSt.cjs → selfCheck-D4VvVZNi.cjs} +39 -39
  157. package/dist/{send-Cd10YhXh.cjs → send-Cz5m39QR.cjs} +8 -8
  158. package/dist/{send-K9vg-8t-.mjs → send-D8ipLKMY.mjs} +8 -8
  159. package/dist/{server-De4W1zuK.mjs → server-CjvgT3N9.mjs} +4 -4
  160. package/dist/{server-DRrV64r0.cjs → server-CySyJKPH.cjs} +6 -6
  161. package/dist/{sessionLock-Dl6i7IgA.mjs → sessionLock-B73fhgQN.mjs} +3 -3
  162. package/dist/{sessionLock-BDtSzzKS.cjs → sessionLock-DdDCuNUs.cjs} +3 -3
  163. package/dist/{sessionOps-gU88-W9F.mjs → sessionOps-C65Iej_C.mjs} +50 -8
  164. package/dist/{sessionOps-DvnEH4PL.cjs → sessionOps-XSEjIqNq.cjs} +50 -8
  165. package/dist/{sessionProvider-CKcIo7KO.mjs → sessionProvider-CLVNkfji.mjs} +11 -9
  166. package/dist/{sessionProvider-CbSZeZrl.cjs → sessionProvider-Dgsty8z_.cjs} +11 -9
  167. package/dist/{sessionScanner-7RtcCeyD.cjs → sessionScanner-D8IVXMMH.cjs} +3 -3
  168. package/dist/{sessionScanner-DR32uSby.mjs → sessionScanner-MW1P9Pm9.mjs} +3 -3
  169. package/dist/{sessions-BvuMjgvJ.cjs → sessions-BKz7gZqg.cjs} +10 -10
  170. package/dist/{sessions-DTt2Eguk.mjs → sessions-Dtk_agUL.mjs} +10 -10
  171. package/dist/{setupOfflineReconnection-BGnvhRfb.mjs → setupOfflineReconnection-Bvdy-2xd.mjs} +2 -2
  172. package/dist/{setupOfflineReconnection-DduOsw6p.cjs → setupOfflineReconnection-DxMiW7OV.cjs} +2 -2
  173. package/dist/{spawn-DMB6rRPA.cjs → spawn-DiPkJcrQ.cjs} +26 -16
  174. package/dist/{spawn-CL3cUc7b.mjs → spawn-Dm4xsZBX.mjs} +26 -16
  175. package/dist/{spawnAgents-CClb7buD.cjs → spawnAgents-B9olJ8xn.cjs} +1 -1
  176. package/dist/{spawnAgents-CRMfOJhh.mjs → spawnAgents-I29H9nO8.mjs} +1 -1
  177. package/dist/{spawnHappyCLI-DJdhX_Qx.cjs → spawnHappyCLI-BYGOUda1.cjs} +1 -1
  178. package/dist/{spawnHappyCLI-Cj_6IICe.mjs → spawnHappyCLI-CnMwzjWX.mjs} +1 -1
  179. package/dist/{startFileWatcher-LnOmVW6H.cjs → startFileWatcher-D14W6gn-.cjs} +1 -1
  180. package/dist/{startFileWatcher-DikVa8kg.mjs → startFileWatcher-DePAY1T5.mjs} +1 -1
  181. package/dist/{startupSessionCreate-CDdaLaMq.mjs → startupSessionCreate-DoK0IvJG.mjs} +3 -3
  182. package/dist/{startupSessionCreate-B3ND-917.cjs → startupSessionCreate-rBHd4tc1.cjs} +3 -3
  183. package/dist/{store-DV__wCvP.cjs → store-CkNa6oj4.cjs} +46 -9
  184. package/dist/{store--XN-7MS0.mjs → store-Vej_738f.mjs} +46 -10
  185. package/dist/{streamRelay-DFdOaLOn.cjs → streamRelay-C0G1HOOd.cjs} +1 -1
  186. package/dist/{streamRelay-sABnxEXq.mjs → streamRelay-C5U-C4GS.mjs} +1 -1
  187. package/dist/{sync-JoEZKRo8.mjs → sync-BP6vnxVP.mjs} +1 -1
  188. package/dist/{sync-_2lsZ1U2.cjs → sync-WYBwkJvG.cjs} +1 -1
  189. package/dist/{systemPrompt-CJEvNCuW.cjs → systemPrompt-BkQlCk5_.cjs} +2 -2
  190. package/dist/{systemPrompt-Zq4HyrZ5.mjs → systemPrompt-aRqBmkpw.mjs} +2 -2
  191. package/dist/{teams-qz4LqKJ2.mjs → teams-CGmC4ygu.mjs} +7 -7
  192. package/dist/{teams-BNZafnrT.cjs → teams-phbpwAGD.cjs} +7 -7
  193. package/dist/{template-LgvBbOna.cjs → template-B9pLEP8v.cjs} +2 -2
  194. package/dist/{template-CJ8BWSsc.mjs → template-CL9EvQLQ.mjs} +2 -2
  195. package/dist/{time-CaUlWSNJ.cjs → time-BTLcO8jp.cjs} +1 -1
  196. package/dist/{time-bzmet4s5.mjs → time-Cw0liIqB.mjs} +1 -1
  197. package/dist/{titleGenerator-BuIIu_JP.cjs → titleGenerator-Y1_7ceJC.cjs} +3 -3
  198. package/dist/{titleGenerator-CbTtJ_1D.mjs → titleGenerator-h6TmFe-c.mjs} +2 -2
  199. package/dist/{todo-CQ_BTf9C.cjs → todo-BxiPiCvB.cjs} +6 -6
  200. package/dist/{todo-DIrVF_Ak.mjs → todo-OKcTC_VC.mjs} +6 -6
  201. package/dist/{tools-cLOjBvPn.mjs → tools-BR-drXZ8.mjs} +3 -2
  202. package/dist/{tools-BnmmFZji.cjs → tools-CcebYtLj.cjs} +3 -2
  203. package/dist/{uninstall-uEEGKB84.cjs → uninstall-CnDeCC-M.cjs} +3 -3
  204. package/dist/{uninstall-C5OuW6dE.mjs → uninstall-D3stWKD2.mjs} +3 -3
  205. package/dist/{wrapperAccount-DXlD3bsO.mjs → wrapperAccount-BkufO_9g.mjs} +5 -4
  206. package/dist/{wrapperAccount-DzoGqS2b.cjs → wrapperAccount-D2A4DuZy.cjs} +6 -3
  207. package/package.json +7 -7
  208. package/dist/selfCheck-vkfrgQ7X.mjs +0 -88
@@ -1,10 +1,12 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { mkdirSync, writeFileSync, readFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
- import { u as AgentProfileAddRequestSchema, v as AgentProfileLoginStartRequestSchema, w as AgentProfileLoginSubmitRequestSchema, x as AgentProfileBindRequestSchema } from './index-DYD3GM1m.mjs';
4
+ import { G as AGENT_PROFILE_FEATURE_LAUNCH, H as AgentProfileAddRequestSchema, I as AgentProfileLoginStartRequestSchema, J as AgentProfileLoginSubmitRequestSchema, K as AgentProfileBindRequestSchema } from './index-D1YnIih6.mjs';
5
5
  import { spawn } from 'node:child_process';
6
- import { A as ACCOUNT_STRIPPED_ENV_KEYS } from './claudeAccountEnv-ON24i0qv.mjs';
7
- import { h as buildAgentProfilesState, d as defaultSecretProbe, a as readAccounts, s as summarizeAccount, c as readAccountsFileV2, n as newAccountId, i as writeAccountSecret, f as writeAccountsFile, j as sessionsBoundTo, r as readSessionBindings, k as removeAccountSecret, b as accountSecretPath, e as expandHome, l as SUBSCRIPTION_TOKEN_TTL_MS, w as writeSessionBinding, m as readSessionBindingV2 } from './store--XN-7MS0.mjs';
6
+ import { A as ACCOUNT_STRIPPED_ENV_KEYS } from './claudeAccountEnv-BL1pR_37.mjs';
7
+ import { C as CODEX_ALWAYS_STRIPPED_ENV_KEYS, r as readCodexProviders, s as syncCodexOverlay, b as baseCodexHome } from './codexAccount-NOX5pmQf.mjs';
8
+ import { createInterface } from 'node:readline';
9
+ import { h as buildAgentProfilesState, d as defaultSecretProbe, a as readAccounts, s as summarizeAccount, c as readAccountsFileV2, n as newAccountId, i as writeAccountSecret, f as writeAccountsFile, j as sessionsBoundTo, r as readSessionBindings, k as removeAccountSecret, b as accountSecretPath, e as expandHome, l as accountCodexHomePath, m as SUBSCRIPTION_TOKEN_TTL_MS, w as writeSessionBinding, o as readSessionBindingV2 } from './store-Vej_738f.mjs';
8
10
 
9
11
  const CHECK_TIMEOUT_MS = 2e4;
10
12
  const DEFAULT_CHECK_MODEL = "claude-haiku-4-5";
@@ -26,7 +28,7 @@ function lastLine(text) {
26
28
  return text.trim().split("\n").filter(Boolean).pop() ?? "";
27
29
  }
28
30
  function sanitizeDetail(text) {
29
- return text.replace(/sk-ant-[A-Za-z0-9_-]+/g, "sk-ant-\u2026").replace(/\s+/g, " ").trim().slice(0, 200);
31
+ return text.replace(/sk-ant-[A-Za-z0-9_-]+/g, "sk-ant-\u2026").replace(/\b(sk|rk)-[A-Za-z0-9_-]{16,}/g, "$1-\u2026").replace(/\s+/g, " ").trim().slice(0, 200);
30
32
  }
31
33
  async function checkApiAccount(record, key, now = Date.now) {
32
34
  const controller = new AbortController();
@@ -90,7 +92,7 @@ async function checkSubscriptionAccount(token, scratchDir, now = Date.now) {
90
92
  const LOGIN_CODE_TIMEOUT_MS = 10 * 6e4;
91
93
  const LOGIN_URL_TIMEOUT_MS = 2e4;
92
94
  const LOGIN_EXCHANGE_TIMEOUT_MS = 6e4;
93
- const LOGIN_RETAIN_MS = 10 * 6e4;
95
+ const LOGIN_RETAIN_MS$1 = 10 * 6e4;
94
96
  function stripAnsi(text) {
95
97
  return text.replace(/\x1b\][^\x07\x1b]*(\x07|\x1b\\)/g, "").replace(/\x1b\[[0-9;?<>=]*[ -/]*[@-~]/g, " ").replace(/\x1b[()][A-Za-z0-9]/g, "").replace(/\x1b[=>78]/g, "");
96
98
  }
@@ -233,11 +235,244 @@ class SetupTokenLoginManager {
233
235
  }
234
236
  entry.output = "";
235
237
  const loginId_ = loginId;
236
- const t = setTimeout(() => this.logins.delete(loginId_), LOGIN_RETAIN_MS);
238
+ const t = setTimeout(() => this.logins.delete(loginId_), LOGIN_RETAIN_MS$1);
237
239
  t.unref?.();
238
240
  }
239
241
  }
240
242
 
243
+ const DEVICE_LOGIN_TIMEOUT_MS = 15 * 6e4;
244
+ const DEVICE_LOGIN_START_TIMEOUT_MS = 2e4;
245
+ const LOGIN_RETAIN_MS = 10 * 6e4;
246
+ const END_AFTER_CLOSE_MS = 5e3;
247
+ function codexLoginEnv(base, codexHome) {
248
+ const env = {};
249
+ for (const [k, v] of Object.entries(base)) if (typeof v === "string") env[k] = v;
250
+ for (const key of CODEX_ALWAYS_STRIPPED_ENV_KEYS) delete env[key];
251
+ env.CODEX_HOME = codexHome;
252
+ env.RUST_LOG = "warn";
253
+ return env;
254
+ }
255
+ const spawnCodexRpc = (codexHome, env) => {
256
+ const child = spawn("codex", ["app-server", "--listen", "stdio://"], { env, cwd: codexHome, stdio: ["pipe", "pipe", "ignore"], windowsHide: true });
257
+ const pending = /* @__PURE__ */ new Map();
258
+ const listeners = [];
259
+ let nextId = 1;
260
+ createInterface({ input: child.stdout }).on("line", (line) => {
261
+ let msg;
262
+ try {
263
+ msg = JSON.parse(line);
264
+ } catch {
265
+ return;
266
+ }
267
+ if (msg.id != null && pending.has(msg.id)) {
268
+ const p = pending.get(msg.id);
269
+ pending.delete(msg.id);
270
+ if (msg.error) p.reject(new Error(msg.error.message ?? "codex app-server error"));
271
+ else p.resolve(msg.result);
272
+ } else if (msg.method && msg.id == null) {
273
+ for (const cb of listeners) cb(msg.method, msg.params);
274
+ }
275
+ });
276
+ const send = (obj) => child.stdin?.writable && child.stdin.write(JSON.stringify(obj) + "\n");
277
+ const request = (method, params, timeoutMs = 15e3) => new Promise((resolve, reject) => {
278
+ const id = nextId++;
279
+ const timer = setTimeout(() => {
280
+ pending.delete(id);
281
+ reject(new Error(`${method} timed out`));
282
+ }, timeoutMs);
283
+ pending.set(id, { resolve: (v) => {
284
+ clearTimeout(timer);
285
+ resolve(v);
286
+ }, reject: (e) => {
287
+ clearTimeout(timer);
288
+ reject(e);
289
+ } });
290
+ send({ jsonrpc: "2.0", id, method, params });
291
+ });
292
+ child.on("error", () => {
293
+ });
294
+ const initialized = request("initialize", { clientInfo: { name: "very-happy-accounts", version: "1" } }).then(() => send({ jsonrpc: "2.0", method: "initialized" }));
295
+ return {
296
+ request: async (method, params, timeoutMs) => {
297
+ await initialized;
298
+ return request(method, params, timeoutMs);
299
+ },
300
+ onNotification: (cb) => {
301
+ listeners.push(cb);
302
+ },
303
+ onExit: (cb) => {
304
+ child.on("exit", (code) => cb(code));
305
+ },
306
+ close: () => {
307
+ child.kill();
308
+ }
309
+ };
310
+ };
311
+ class CodexDeviceLoginManager {
312
+ constructor(deps) {
313
+ this.deps = deps;
314
+ this.now = deps.now ?? Date.now;
315
+ }
316
+ logins = /* @__PURE__ */ new Map();
317
+ now;
318
+ activeLoginId() {
319
+ for (const [id, e] of this.logins) if (e.status.state === "starting" || e.status.state === "waiting-code") return id;
320
+ return null;
321
+ }
322
+ has(loginId) {
323
+ return this.logins.has(loginId);
324
+ }
325
+ async start(codexHome) {
326
+ const busy = this.activeLoginId();
327
+ if (busy) throw Object.assign(new Error("another Codex sign-in is in progress"), { code: "login-busy", loginId: busy });
328
+ const loginId = this.deps.newId();
329
+ const entry = { status: { loginId, state: "starting", flow: "device-code" }, rpc: null, timers: [] };
330
+ this.logins.set(loginId, entry);
331
+ let rpc;
332
+ try {
333
+ rpc = this.deps.spawnRpc(codexHome, codexLoginEnv(this.deps.env, codexHome));
334
+ } catch (error) {
335
+ this.finish(entry, "failed", `could not start codex: ${error instanceof Error ? error.message : String(error)}`);
336
+ return { ...entry.status };
337
+ }
338
+ entry.rpc = rpc;
339
+ rpc.onExit(() => {
340
+ entry.rpc = null;
341
+ if (entry.status.state === "starting" || entry.status.state === "waiting-code") this.finish(entry, "failed", "codex app-server exited");
342
+ });
343
+ rpc.onNotification((method, params) => {
344
+ if (method !== "account/login/completed") return;
345
+ if (entry.status.state !== "starting" && entry.status.state !== "waiting-code") return;
346
+ if (params?.loginId && entry.codexLoginId && params.loginId !== entry.codexLoginId) return;
347
+ if (params?.success) void this.complete(entry);
348
+ else this.finish(entry, "failed", sanitizeDetail(String(params?.error ?? "sign-in failed")));
349
+ });
350
+ try {
351
+ const result = await rpc.request("account/login/start", { type: "chatgptDeviceCode" }, DEVICE_LOGIN_START_TIMEOUT_MS);
352
+ if (typeof result?.verificationUrl !== "string" || typeof result?.userCode !== "string") throw new Error("codex returned no device code");
353
+ entry.codexLoginId = typeof result.loginId === "string" ? result.loginId : void 0;
354
+ if (entry.status.state === "starting") {
355
+ entry.status = { ...entry.status, state: "waiting-code", url: result.verificationUrl, userCode: result.userCode, expiresAt: this.now() + DEVICE_LOGIN_TIMEOUT_MS };
356
+ entry.timers.push(setTimeout(() => {
357
+ if (entry.status.state === "waiting-code") this.finish(entry, "expired");
358
+ }, DEVICE_LOGIN_TIMEOUT_MS));
359
+ }
360
+ } catch (error) {
361
+ this.finish(entry, "failed", sanitizeDetail(error instanceof Error ? error.message : String(error)));
362
+ }
363
+ return { ...entry.status };
364
+ }
365
+ async complete(entry) {
366
+ if (entry.status.state !== "waiting-code" && entry.status.state !== "starting") return;
367
+ let account = {};
368
+ try {
369
+ const read = await entry.rpc?.request("account/read", { refreshToken: false });
370
+ const a = read?.account;
371
+ if (a?.type === "chatgpt") account = { ...a.email ? { email: String(a.email) } : {}, ...a.planType ? { planType: String(a.planType) } : {} };
372
+ } catch {
373
+ }
374
+ try {
375
+ const summary = await this.deps.onSuccess(entry.status.loginId, account);
376
+ entry.status = { ...entry.status, account: summary };
377
+ this.finish(entry, "succeeded");
378
+ } catch (error) {
379
+ this.finish(entry, "failed", error instanceof Error ? error.message : String(error));
380
+ }
381
+ }
382
+ status(loginId) {
383
+ return { ...this.get(loginId).status };
384
+ }
385
+ cancel(loginId) {
386
+ const entry = this.get(loginId);
387
+ if (entry.status.state === "starting" || entry.status.state === "waiting-code") {
388
+ if (entry.codexLoginId) void entry.rpc?.request("account/login/cancel", { loginId: entry.codexLoginId }, 5e3).catch(() => {
389
+ });
390
+ this.finish(entry, "canceled");
391
+ }
392
+ return { ...entry.status };
393
+ }
394
+ dispose() {
395
+ for (const entry of this.logins.values()) {
396
+ if (entry.status.state === "starting" || entry.status.state === "waiting-code") this.finish(entry, "canceled");
397
+ for (const t of entry.timers) clearTimeout(t);
398
+ }
399
+ this.logins.clear();
400
+ for (const end of [...this.pendingEnds]) end(true);
401
+ }
402
+ /** finish() → onEnd still waiting for its app-server to exit; dispose() runs them at once. */
403
+ pendingEnds = /* @__PURE__ */ new Set();
404
+ settleWaiters = [];
405
+ /** Resolves once every finished login's onEnd has run (a CLI exiting right after Ctrl-C waits for the cleanup). */
406
+ settle() {
407
+ if (this.pendingEnds.size === 0) return Promise.resolve();
408
+ return new Promise((resolve) => this.settleWaiters.push(resolve));
409
+ }
410
+ get(loginId) {
411
+ const entry = this.logins.get(loginId);
412
+ if (!entry) throw Object.assign(new Error(`no login "${loginId}"`), { code: "login-not-found" });
413
+ return entry;
414
+ }
415
+ finish(entry, state, error) {
416
+ entry.status = { ...entry.status, state, ...error ? { error } : {} };
417
+ for (const t2 of entry.timers) clearTimeout(t2);
418
+ entry.timers = [];
419
+ const rpc = entry.rpc;
420
+ entry.rpc = null;
421
+ const loginId = entry.status.loginId;
422
+ if (!rpc) this.deps.onEnd?.(loginId, state);
423
+ else {
424
+ let ended = false;
425
+ const end = (closeNow) => {
426
+ if (ended) return;
427
+ ended = true;
428
+ this.pendingEnds.delete(end);
429
+ if (closeNow) rpc.close();
430
+ this.deps.onEnd?.(loginId, state);
431
+ if (this.pendingEnds.size === 0) for (const resolve of this.settleWaiters.splice(0)) resolve();
432
+ };
433
+ this.pendingEnds.add(end);
434
+ rpc.onExit(() => end());
435
+ setTimeout(() => rpc.close(), state === "canceled" ? 500 : 0).unref?.();
436
+ setTimeout(() => end(), END_AFTER_CLOSE_MS).unref?.();
437
+ }
438
+ const t = setTimeout(() => this.logins.delete(entry.status.loginId), LOGIN_RETAIN_MS);
439
+ t.unref?.();
440
+ }
441
+ }
442
+ function classifyChatgptRead(read, now) {
443
+ const account = read?.account;
444
+ if (account && account.type === "chatgpt") return { status: "ok", at: now };
445
+ return { status: "expired", at: now, detail: "not signed in" };
446
+ }
447
+ async function checkCodexChatgptAccount(codexHome, env, spawnRpc = spawnCodexRpc, now = Date.now) {
448
+ let rpc = null;
449
+ try {
450
+ rpc = spawnRpc(codexHome, codexLoginEnv(env, codexHome));
451
+ const read = await rpc.request("account/read", { refreshToken: true }, CHECK_TIMEOUT_MS);
452
+ return classifyChatgptRead(read, now());
453
+ } catch (error) {
454
+ const message = error instanceof Error ? error.message : String(error);
455
+ if (/refresh token|401|unauthori[sz]ed|sign in again|log in again/i.test(message)) return { status: "expired", at: now(), detail: sanitizeDetail(message) };
456
+ return { status: "unverified", at: now(), detail: sanitizeDetail(message) };
457
+ } finally {
458
+ rpc?.close();
459
+ }
460
+ }
461
+ async function checkCodexProviderAccount(baseUrl, key, headers = {}, now = Date.now) {
462
+ const controller = new AbortController();
463
+ const timer = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
464
+ try {
465
+ const res = await fetch(`${baseUrl.replace(/\/+$/, "")}/models`, { signal: controller.signal, headers: { ...headers, authorization: `Bearer ${key}` } });
466
+ const body = res.ok ? "" : (await res.text().catch(() => "")).slice(0, 300);
467
+ return classifyHttpCheck("codex-provider", res.status, body, now());
468
+ } catch (error) {
469
+ return { status: "unverified", at: now(), detail: sanitizeDetail(error instanceof Error ? error.message : String(error)) };
470
+ } finally {
471
+ clearTimeout(timer);
472
+ }
473
+ }
474
+
475
+ const ACCOUNT_AGENTS = ["claude", "codex"];
241
476
  class AccountError extends Error {
242
477
  constructor(code, message, sessions) {
243
478
  super(message);
@@ -269,10 +504,14 @@ class AccountService {
269
504
  env;
270
505
  now;
271
506
  logins = null;
507
+ codexLogins = null;
272
508
  /** loginId → account to (re)write when its token arrives. */
273
509
  loginTargets = /* @__PURE__ */ new Map();
274
510
  state() {
275
- return buildAgentProfilesState(this.home, readAccounts(this.home), defaultSecretProbe(this.env), this.now(), this.deps.daemonPid ?? process.pid);
511
+ const state = buildAgentProfilesState(this.home, readAccounts(this.home), defaultSecretProbe(this.env), this.now(), this.deps.daemonPid ?? process.pid);
512
+ const codexProviders = readCodexProviders(this.env).map((p) => ({ id: p.id, ...p.name ? { name: p.name } : {}, ...p.baseUrl ? { baseUrl: p.baseUrl } : {}, ...p.envKey ? { envKey: p.envKey } : {} }));
513
+ const withFeatures = { ...state, features: [AGENT_PROFILE_FEATURE_LAUNCH] };
514
+ return codexProviders.length > 0 ? { ...withFeatures, codexProviders } : withFeatures;
276
515
  }
277
516
  summary(id) {
278
517
  const record = readAccounts(this.home).accounts[id];
@@ -299,8 +538,11 @@ class AccountService {
299
538
  const parsed = AgentProfileAddRequestSchema.safeParse(params);
300
539
  if (!parsed.success) throw new AccountError("invalid-params", parsed.error.issues[0]?.message ?? "invalid params");
301
540
  const req = parsed.data;
541
+ if (req.agent === "codex" && req.provider && !readCodexProviders(this.env).some((p) => p.id === req.provider)) {
542
+ throw new AccountError("not-found", `no [model_providers.${req.provider}] in the machine's Codex config.toml`);
543
+ }
302
544
  const file = readAccountsFileV2(this.home);
303
- const id = newAccountId(req.label, "claude-api", Object.keys(readAccounts(this.home).accounts));
545
+ const id = newAccountId(req.label, req.kind, Object.keys(readAccounts(this.home).accounts));
304
546
  const models = [];
305
547
  const contextWindows = {};
306
548
  for (const m of req.models ?? []) {
@@ -312,10 +554,12 @@ class AccountService {
312
554
  }
313
555
  const record = {
314
556
  label: req.label,
315
- agent: "claude",
316
- kind: "claude-api",
557
+ agent: req.agent,
558
+ kind: req.kind,
317
559
  createdAt: this.now(),
318
- baseUrl: req.baseUrl.replace(/\/+$/, ""),
560
+ ...req.baseUrl ? { baseUrl: req.baseUrl.replace(/\/+$/, "") } : {},
561
+ ...req.agent === "codex" && req.provider ? { provider: req.provider } : {},
562
+ ...req.agent === "codex" && req.wireApi ? { wireApi: req.wireApi } : {},
319
563
  key: req.key.source === "paste" ? { source: "stored" } : req.key.source === "file" ? { source: "file", path: req.key.path } : { source: "env", name: req.key.name },
320
564
  ...models.length > 0 ? { models } : {},
321
565
  ...Object.keys(contextWindows).length > 0 ? { contextWindows } : {}
@@ -373,7 +617,7 @@ class AccountService {
373
617
  return outcome.notRunning ? "skipped" : "failed";
374
618
  }
375
619
  setDefault(agent, accountId) {
376
- if (agent !== "claude") throw new AccountError("invalid-params", 'agent must be "claude"');
620
+ if (!ACCOUNT_AGENTS.includes(agent)) throw new AccountError("invalid-params", 'agent must be "claude" or "codex"');
377
621
  if (accountId !== null && typeof accountId !== "string") throw new AccountError("invalid-params", "accountId must be a string or null");
378
622
  if (typeof accountId === "string") {
379
623
  const record = readAccounts(this.home).accounts[accountId];
@@ -402,9 +646,17 @@ class AccountService {
402
646
  if (typeof accountId !== "string") throw new AccountError("invalid-params", "accountId is required");
403
647
  const record = readAccounts(this.home).accounts[accountId];
404
648
  if (!record) throw new AccountError("not-found", `no account "${accountId}"`);
405
- const secret = this.readSecretFor(accountId, record);
406
- if (!secret) return this.summary(accountId);
407
- const check = this.deps.check ? await this.deps.check(record, secret) : record.kind === "claude-subscription" ? await checkSubscriptionAccount(secret, join(this.home, "tmp", "account-check"), this.now) : await checkApiAccount(record, secret, this.now);
649
+ let check;
650
+ if (record.kind === "codex-chatgpt") {
651
+ if (this.summary(accountId).status === "missing-secret") return this.summary(accountId);
652
+ const codexHome = accountCodexHomePath(this.home, accountId);
653
+ syncCodexOverlay(codexHome, baseCodexHome(this.env), this.now());
654
+ check = this.deps.check ? await this.deps.check(record, "") : await checkCodexChatgptAccount(codexHome, this.env, this.deps.spawnCodexRpc ?? spawnCodexRpc, this.now);
655
+ } else {
656
+ const secret = this.readSecretFor(accountId, record);
657
+ if (!secret) return this.summary(accountId);
658
+ check = this.deps.check ? await this.deps.check(record, secret) : record.kind === "claude-subscription" ? await checkSubscriptionAccount(secret, join(this.home, "tmp", "account-check"), this.now) : record.kind === "codex-provider" ? await this.checkCodexProvider(record, secret) : await checkApiAccount(record, secret, this.now);
659
+ }
408
660
  if (!record.legacy) {
409
661
  const file = readAccountsFileV2(this.home);
410
662
  if (file.accounts[accountId]) {
@@ -416,6 +668,17 @@ class AccountService {
416
668
  }
417
669
  return { ...this.summary(accountId), status: check.status, checkedAt: check.at, ...check.detail ? { statusDetail: check.detail } : {} };
418
670
  }
671
+ async checkCodexProvider(record, secret) {
672
+ const base = record.provider ? readCodexProviders(this.env).find((p) => p.id === record.provider) : void 0;
673
+ const baseUrl = record.baseUrl ?? base?.baseUrl;
674
+ if (!baseUrl) return { status: "unverified", at: this.now(), detail: `provider "${record.provider}" is not in the machine's Codex config.toml` };
675
+ const headers = {};
676
+ const raw = base?.table.http_headers;
677
+ if (raw && typeof raw === "object") {
678
+ for (const [k, v] of Object.entries(raw)) if (typeof v === "string") headers[k] = v;
679
+ }
680
+ return checkCodexProviderAccount(baseUrl, secret, headers, this.now);
681
+ }
419
682
  // ---- remote login (claude setup-token) -------------------------------------
420
683
  loginManager() {
421
684
  if (this.logins) return this.logins;
@@ -457,6 +720,7 @@ class AccountService {
457
720
  async loginStart(params) {
458
721
  const parsed = AgentProfileLoginStartRequestSchema.safeParse(params);
459
722
  if (!parsed.success) throw new AccountError("invalid-params", parsed.error.issues[0]?.message ?? "invalid params");
723
+ if (parsed.data.agent === "codex") return this.codexLoginStart(parsed.data.accountId, parsed.data.label);
460
724
  const { accountId, label } = parsed.data;
461
725
  if (accountId) {
462
726
  const record = readAccounts(this.home).accounts[accountId];
@@ -472,10 +736,84 @@ class AccountService {
472
736
  throw new AccountError(code, error instanceof Error ? error.message : String(error));
473
737
  }
474
738
  this.loginTargets.set(status.loginId, { accountId, label });
739
+ return { ...status, flow: "paste-code" };
740
+ }
741
+ // ---- remote login (Codex ChatGPT device code) — B-850b ----------------------
742
+ codexLoginManager() {
743
+ if (this.codexLogins) return this.codexLogins;
744
+ this.codexLogins = new CodexDeviceLoginManager({
745
+ spawnRpc: this.deps.spawnCodexRpc ?? spawnCodexRpc,
746
+ env: this.env,
747
+ newId: () => randomUUID(),
748
+ now: this.now,
749
+ onSuccess: async (loginId, info) => {
750
+ const target = this.codexLoginTargets.get(loginId);
751
+ this.codexLoginTargets.delete(loginId);
752
+ if (!target) throw new AccountError("internal", "sign-in target lost");
753
+ return this.storeChatgptAccount(target, info);
754
+ },
755
+ onEnd: (loginId, state) => {
756
+ const target = this.codexLoginTargets.get(loginId);
757
+ if (state === "succeeded" || !target) return;
758
+ this.codexLoginTargets.delete(loginId);
759
+ if (target.isNew) removeAccountSecret(this.home, target.accountId);
760
+ }
761
+ });
762
+ return this.codexLogins;
763
+ }
764
+ /** loginId → the account a Codex sign-in writes. */
765
+ codexLoginTargets = /* @__PURE__ */ new Map();
766
+ async codexLoginStart(accountId, label) {
767
+ const accounts = readAccounts(this.home).accounts;
768
+ let target;
769
+ if (accountId) {
770
+ const record = accounts[accountId];
771
+ if (!record || record.kind !== "codex-chatgpt") throw new AccountError("not-found", `no ChatGPT account "${accountId}"`);
772
+ target = { accountId, isNew: false };
773
+ } else {
774
+ const taken = [...Object.keys(accounts), ...[...this.codexLoginTargets.values()].map((t) => t.accountId)];
775
+ target = { accountId: newAccountId(label ?? "", "codex-chatgpt", taken), ...label ? { label } : {}, isNew: true };
776
+ }
777
+ const manager = this.codexLoginManager();
778
+ const busy = manager.activeLoginId();
779
+ if (busy) throw new AccountError("login-busy", "another Codex sign-in is in progress");
780
+ const codexHome = accountCodexHomePath(this.home, target.accountId);
781
+ syncCodexOverlay(codexHome, baseCodexHome(this.env), this.now());
782
+ const status = await manager.start(codexHome);
783
+ if (status.state === "failed" || status.state === "canceled" || status.state === "expired") {
784
+ if (target.isNew) removeAccountSecret(this.home, target.accountId);
785
+ return status;
786
+ }
787
+ this.codexLoginTargets.set(status.loginId, target);
475
788
  return status;
476
789
  }
477
- loginOp(fn) {
790
+ /** A finished ChatGPT sign-in → the account record (new) or its refreshed status (re-login). */
791
+ storeChatgptAccount(target, info) {
792
+ const file = readAccountsFileV2(this.home);
793
+ const now = this.now();
794
+ const existing = file.accounts[target.accountId];
795
+ if (existing && existing.kind === "codex-chatgpt") {
796
+ existing.check = { status: "ok", at: now };
797
+ if (info.email) existing.email = info.email;
798
+ if (info.planType) existing.planType = info.planType;
799
+ } else {
800
+ file.accounts[target.accountId] = {
801
+ label: target.label?.trim() || info.email || "ChatGPT",
802
+ agent: "codex",
803
+ kind: "codex-chatgpt",
804
+ createdAt: now,
805
+ check: { status: "ok", at: now },
806
+ ...info.email ? { email: info.email } : {},
807
+ ...info.planType ? { planType: info.planType } : {}
808
+ };
809
+ }
810
+ writeAccountsFile(this.home, file);
811
+ this.changed();
812
+ return this.summary(target.accountId);
813
+ }
814
+ loginOp(fn, loginId, codex) {
478
815
  try {
816
+ if (codex && typeof loginId === "string" && this.codexLogins?.has(loginId)) return codex(this.codexLogins);
479
817
  return fn(this.loginManager());
480
818
  } catch (error) {
481
819
  const code = error.code ?? "internal";
@@ -485,20 +823,26 @@ class AccountService {
485
823
  loginSubmit(params) {
486
824
  const parsed = AgentProfileLoginSubmitRequestSchema.safeParse(params);
487
825
  if (!parsed.success) throw new AccountError("invalid-params", "loginId and code are required");
826
+ if (this.codexLogins?.has(parsed.data.loginId)) throw new AccountError("invalid-params", "a Codex device-code sign-in has nothing to submit: enter the code on the sign-in page");
488
827
  return this.loginOp((m) => m.submit(parsed.data.loginId, parsed.data.code));
489
828
  }
490
829
  loginStatus(loginId) {
491
830
  if (typeof loginId !== "string") throw new AccountError("invalid-params", "loginId is required");
492
- return this.loginOp((m) => m.status(loginId));
831
+ return this.loginOp((m) => m.status(loginId), loginId, (m) => m.status(loginId));
493
832
  }
494
833
  loginCancel(loginId) {
495
834
  if (typeof loginId !== "string") throw new AccountError("invalid-params", "loginId is required");
496
- const status = this.loginOp((m) => m.cancel(loginId));
835
+ const status = this.loginOp((m) => m.cancel(loginId), loginId, (m) => m.cancel(loginId));
497
836
  this.loginTargets.delete(loginId);
498
837
  return status;
499
838
  }
500
839
  dispose() {
501
840
  this.logins?.dispose();
841
+ this.codexLogins?.dispose();
842
+ }
843
+ /** B-850d2: waits until finished Codex sign-ins are cleaned up (their app-server gone, a canceled new account's overlay removed). */
844
+ settleLogins() {
845
+ return this.codexLogins?.settle() ?? Promise.resolve();
502
846
  }
503
847
  // ---- sessions --------------------------------------------------------------
504
848
  /** Validates and writes a session binding (no restart). */
@@ -506,8 +850,10 @@ class AccountService {
506
850
  if (accountId !== null) {
507
851
  const record = readAccounts(this.home).accounts[accountId];
508
852
  if (!record) throw new AccountError("not-found", `no account "${accountId}"`);
853
+ const agent = this.deps.sessionAgent?.(sessionId);
854
+ if (agent && agent !== record.agent) throw new AccountError("invalid-params", `"${accountId}" is a ${record.agent} account; this session runs ${agent}`);
509
855
  if (model !== void 0) {
510
- if (record.kind !== "claude-api") throw new AccountError("invalid-params", "model applies to API accounts only");
856
+ if (record.kind === "claude-subscription") throw new AccountError("invalid-params", "model applies to API and Codex accounts only");
511
857
  if (record.models && record.models.length > 0 && !record.models.includes(model)) {
512
858
  throw new AccountError("invalid-params", `model "${model}" is not in ${accountId}'s models (${record.models.join(", ")})`);
513
859
  }
@@ -539,6 +885,10 @@ class AccountService {
539
885
  if (outcome.notRunning) return { bound: true, restart: "skipped", error: outcome.error };
540
886
  return { bound: true, restart: "failed", error: outcome.error };
541
887
  }
888
+ /** B-850d: the account a session is bound to (null = machine login, also when unbound). */
889
+ sessionAccount(sessionId) {
890
+ return readSessionBindings(this.home)[sessionId]?.account ?? null;
891
+ }
542
892
  /**
543
893
  * Spawn-time choice → the account a NEW session starts on.
544
894
  * undefined → the machine default for this agent (none = machine login)