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.
- package/dist/{AcpBackend-CGHTDJd9.mjs → AcpBackend-B4PwjqHt.mjs} +3 -3
- package/dist/{AcpBackend-BQO4ShOy.cjs → AcpBackend-DtJCgftG.cjs} +3 -3
- package/dist/{AcpSessionManager-G0xD6Jbq.mjs → AcpSessionManager-BzKWgkdP.mjs} +2 -2
- package/dist/{AcpSessionManager-LlUMmcpB.cjs → AcpSessionManager-D4qshX_H.cjs} +2 -2
- package/dist/{BasePermissionHandler-N6Ip3tFt.cjs → BasePermissionHandler-5iG-cvA2.cjs} +1 -1
- package/dist/{BasePermissionHandler-BmTIg376.mjs → BasePermissionHandler-DV6UM6e9.mjs} +1 -1
- package/dist/{account-CCVT-HO_.mjs → account-Dco_nGT4.mjs} +84 -27
- package/dist/{account-DtaouikP.cjs → account-DvpA60oU.cjs} +84 -27
- package/dist/{accountService-Dd9uqde2.mjs → accountService-Cd7bnkfd.mjs} +369 -19
- package/dist/{accountService-Bddy0zwL.cjs → accountService-CuUSJDhP.cjs} +369 -19
- package/dist/{acpSessionResume-BnHDk5eD.cjs → acpSessionResume-Bk9mjXZ9.cjs} +1 -1
- package/dist/{acpSessionResume-BWEUxNtC.mjs → acpSessionResume-TQwN9ZZE.mjs} +1 -1
- package/dist/{agentHome-B0VnjkZW.mjs → agentHome-Bep8semY.mjs} +4 -4
- package/dist/{agentHome-CqQ29YY7.cjs → agentHome-c2dlgcw1.cjs} +4 -4
- package/dist/{api-hMDsC6Wg.cjs → api-CBE_a88I.cjs} +10 -10
- package/dist/{api-_LeBScjg.mjs → api-DUfunY3x.mjs} +10 -10
- package/dist/{apiMachine-CqW2m6Zr.cjs → apiMachine-BqtG0IWm.cjs} +19 -18
- package/dist/{apiMachine-CgRldeJ6.mjs → apiMachine-CU_bw5nV.mjs} +19 -18
- package/dist/{attachmentContent-BEeT2J5n.cjs → attachmentContent-B3AzuYqk.cjs} +2 -2
- package/dist/{attachmentContent-CyptLIfq.mjs → attachmentContent-KNIZxwlu.mjs} +2 -2
- package/dist/{auth-CFQikywl.mjs → auth-CZ7pKS-j.mjs} +8 -8
- package/dist/{auth-C9NvNHhL.cjs → auth-DCjxpI6Z.cjs} +5 -5
- package/dist/{auth-CA1OClsW.cjs → auth-SJ_dPw7H.cjs} +8 -8
- package/dist/{auth-DL8_J9vu.mjs → auth-jN5dNqTO.mjs} +5 -5
- package/dist/{auto-uQOxlxLp.cjs → auto-B_59RYH1.cjs} +23 -21
- package/dist/{auto-CKI05w1D.mjs → auto-DC0Sq-qB.mjs} +23 -21
- package/dist/{bootstrap-DaZ0Np7X.mjs → bootstrap-B3gMpU9e.mjs} +2 -2
- package/dist/{bootstrap-DsZGc69k.cjs → bootstrap-CoJu9VnB.cjs} +2 -2
- package/dist/{browser-BUIaSHK2.mjs → browser-LHW2hBH8.mjs} +1 -1
- package/dist/{browser-Ft0ASDm7.cjs → browser-v1pdPP1E.cjs} +1 -1
- package/dist/{claudeAccountEnv-ON24i0qv.mjs → claudeAccountEnv-BL1pR_37.mjs} +2 -1
- package/dist/{claudeAccountEnv-BOBpJ3k8.cjs → claudeAccountEnv-CEX_EMZr.cjs} +2 -1
- package/dist/{claudeLocal-B1ZVtryl.mjs → claudeLocal-BZUgA5G2.mjs} +5 -5
- package/dist/{claudeLocal-BMf9t4Fa.cjs → claudeLocal-BrzM2RBI.cjs} +5 -5
- package/dist/{claudeLocalLauncher-Bp8bqF4y.mjs → claudeLocalLauncher-A0AQyHFi.mjs} +10 -10
- package/dist/{claudeLocalLauncher-C8TeJcfF.cjs → claudeLocalLauncher-XAMpXUM7.cjs} +10 -10
- package/dist/{claudeSessionFork-YiktY55n.cjs → claudeSessionFork-Mhn2fYe_.cjs} +1 -1
- package/dist/{claudeSessionFork-8AA47z8Y.mjs → claudeSessionFork-_GwIlmMB.mjs} +1 -1
- package/dist/{client-Cxlp_D4I.mjs → client-7RnI9J0W.mjs} +2 -2
- package/dist/{client-Bm4oKvW7.mjs → client-Bde4QVIn.mjs} +4 -2
- package/dist/{client-D8XROyZc.cjs → client-CJr8Pjwm.cjs} +4 -2
- package/dist/{client-Crh8_cNx.cjs → client-D2GWkd-T.cjs} +2 -2
- package/dist/{client-CFHZfh9x.cjs → client-DLlnmAPL.cjs} +4 -4
- package/dist/{client-BmPaBnDK.mjs → client-DwbhrX6D.mjs} +4 -4
- package/dist/codex/happyMcpStdioBridge.cjs +16 -16
- package/dist/codex/happyMcpStdioBridge.mjs +16 -16
- package/dist/codexAccount-BDQjRbtI.cjs +1028 -0
- package/dist/codexAccount-NOX5pmQf.mjs +1015 -0
- package/dist/{codexAppServerClient-BWJbLCQn.mjs → codexAppServerClient-B3QJV6Ey.mjs} +18 -7
- package/dist/{codexAppServerClient-q8GHQhyC.cjs → codexAppServerClient-DWEsZUC4.cjs} +18 -7
- package/dist/{codexCommand-BgpGg-Zy.cjs → codexCommand-Bg8AmxVm.cjs} +187 -57
- package/dist/{codexCommand-BfXfRQr4.mjs → codexCommand-D1xlj4sT.mjs} +188 -58
- package/dist/{codexTermination-CVUF0X75.cjs → codexTermination-ByX9GcEJ.cjs} +1 -1
- package/dist/{codexTermination-s9fd1gkA.mjs → codexTermination-CaWAVQjZ.mjs} +1 -1
- package/dist/{config-BAjyTyYp.cjs → config-B2GGbiTv.cjs} +3 -3
- package/dist/{config-BF8XgLyc.mjs → config-C2XYEwXz.mjs} +3 -3
- package/dist/{configuration-CXEVKAyF.cjs → configuration-BBK0rmmj.cjs} +1 -1
- package/dist/{configuration-IhRiLDVe.mjs → configuration-ThKBP_zY.mjs} +1 -1
- package/dist/{connect-LZh1gr08.mjs → connect-BirnCl9q.mjs} +13 -13
- package/dist/{connect-rCS56arw.cjs → connect-C3tZs_NC.cjs} +13 -13
- package/dist/{context-DO6F5YwH.mjs → context-C0EFLnOg.mjs} +1 -1
- package/dist/{context-3_S_mWz9.cjs → context-wDp0aZBK.cjs} +1 -1
- package/dist/{controlClient-8ILulwjc.mjs → controlClient-Ckl8N1MS.mjs} +3 -3
- package/dist/{controlClient-j7p5p3_7.cjs → controlClient-DwWTns3A.cjs} +3 -3
- package/dist/{createSessionMetadata-DwdD_uVo.cjs → createSessionMetadata-DqZ6h02H.cjs} +2 -2
- package/dist/{createSessionMetadata-oyaTZm1b.mjs → createSessionMetadata-vug4Cv8z.mjs} +2 -2
- package/dist/{daemonAccounts-BCjDgoNt.cjs → daemonAccounts-CpGDY_4k.cjs} +4 -1
- package/dist/{daemonAccounts-BJgt6IJe.mjs → daemonAccounts-DwPwKxvv.mjs} +5 -2
- package/dist/{defaultPermissionMode-BFShzF55.cjs → defaultPermissionMode-BakXiqRr.cjs} +1 -1
- package/dist/{defaultPermissionMode-Lt3PUCwY.mjs → defaultPermissionMode-DF5AfeBb.mjs} +1 -1
- package/dist/{deterministicJson-Dfp-7wUZ.mjs → deterministicJson-BzX94gi3.mjs} +13 -13
- package/dist/{deterministicJson-DUN0v3St.cjs → deterministicJson-t33SsuRC.cjs} +13 -13
- package/dist/{doctor-FgUYTbAT.cjs → doctor-B9ug1LZb.cjs} +7 -7
- package/dist/{doctor-B_UwMcVT.mjs → doctor-C1zyOSXw.mjs} +7 -7
- package/dist/{downloadTarget-C0d6jRx-.mjs → downloadTarget-Baslc6jW.mjs} +6 -6
- package/dist/{downloadTarget-BrrQEDxg.cjs → downloadTarget-T1id2Gh6.cjs} +6 -6
- package/dist/{ensureDaemonRunning-KUMFfIil.mjs → ensureDaemonRunning-C6ERYK-O.mjs} +5 -5
- package/dist/{ensureDaemonRunning-Cq4FYI5Q.cjs → ensureDaemonRunning-CoAg11Zi.cjs} +5 -5
- package/dist/{handleResumeCommand-BGhVo3QH.mjs → handleResumeCommand-CrlqDuz7.mjs} +5 -5
- package/dist/{handleResumeCommand-Cl9GIL5F.cjs → handleResumeCommand-DPi-sPm7.cjs} +5 -5
- package/dist/{index-CZaLMmPC.cjs → index-B1swQJUS.cjs} +4 -4
- package/dist/{index-CQ_hLLCj.cjs → index-B2dJA8VG.cjs} +3 -3
- package/dist/{index-BzAYnYct.cjs → index-BUFrKZeQ.cjs} +198 -108
- package/dist/{index-JQDyJ3Li.mjs → index-BbdV2mzy.mjs} +3 -3
- package/dist/{index-BjXjMhGY.mjs → index-BcSPg3c5.mjs} +4 -4
- package/dist/{index-D8ODb0_U.cjs → index-Bkslzin5.cjs} +42 -42
- package/dist/{index-v5EmjT8l.mjs → index-Cn73rdtQ.mjs} +4 -4
- package/dist/{index-DYD3GM1m.mjs → index-D1YnIih6.mjs} +195 -109
- package/dist/{index-Ca1Tt96A.mjs → index-fZO4nF6e.mjs} +43 -43
- package/dist/{index-CRipkiqo.cjs → index-rocrvOYG.cjs} +4 -4
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{install-ClUA9tbC.cjs → install-CArXjPfW.cjs} +3 -3
- package/dist/{install-D6EHRtAN.mjs → install-CChhyV2G.mjs} +3 -3
- package/dist/lib.cjs +12 -12
- package/dist/lib.d.cts +97 -25
- package/dist/lib.d.mts +97 -25
- package/dist/lib.mjs +12 -12
- package/dist/{lidState-CZOXXdzv.mjs → lidState-B6yYKjNK.mjs} +1 -1
- package/dist/{lidState-DqoN7zH4.cjs → lidState-B_v6qgfE.cjs} +1 -1
- package/dist/{localHappyAgentAuth-YHxDZ4x4.mjs → localHappyAgentAuth-KRlg_aI0.mjs} +1 -1
- package/dist/{localHappyAgentAuth-BnGCpHRX.cjs → localHappyAgentAuth-jJH0n67S.cjs} +1 -1
- package/dist/{logger-8su64lqR.cjs → logger-CX3x2eI4.cjs} +2 -2
- package/dist/{logger-Fd_rNvgd.mjs → logger-JV7-4Q_6.mjs} +2 -2
- package/dist/{machineMetadata-1HIIC7Bc.mjs → machineMetadata-D5-SW9kv.mjs} +3 -3
- package/dist/{machineMetadata-DYXt3p6u.cjs → machineMetadata-DhZuM0iB.cjs} +3 -3
- package/dist/{main-C_GrcYkn.cjs → main-1x1HGQEy.cjs} +47 -47
- package/dist/{main-BI6GIzUL.mjs → main-CFOdXbPD.mjs} +47 -47
- package/dist/{mcp-BycIv9oQ.cjs → mcp-BnKBSEh7.cjs} +18 -18
- package/dist/{mcp-XGoxywno.mjs → mcp-R6lMcFLO.mjs} +18 -18
- package/dist/{mirrorProtocol-DXT3rv7T.mjs → mirrorProtocol-CD4ntuZJ.mjs} +3 -3
- package/dist/{mirrorProtocol-DVnB8EO8.cjs → mirrorProtocol-DO-KtvAL.cjs} +3 -3
- package/dist/{package-6KkRAops.mjs → package-Bw3H6VLn.mjs} +7 -7
- package/dist/{package-iuLlSiSF.cjs → package-uzlvxa5S.cjs} +7 -7
- package/dist/{panels-B5Di2zb2.mjs → panels-BamhZCoZ.mjs} +5 -5
- package/dist/{panels-0C89q0Tu.cjs → panels-C46FxjmH.cjs} +5 -5
- package/dist/{peerTools-CANTX_mG.cjs → peerTools-D-VNNFw-.cjs} +5 -5
- package/dist/{peerTools-CKJ-IDM4.mjs → peerTools-WtRgTSqG.mjs} +5 -5
- package/dist/{persistence-DWcHe035.mjs → persistence-Cg4sfjQV.mjs} +2 -2
- package/dist/{persistence-B4ttN-fR.cjs → persistence-CsmAgN-C.cjs} +2 -2
- package/dist/{piRunnerArgs-Bl5GpBoN.mjs → piRunnerArgs-BbaAQvb4.mjs} +1 -1
- package/dist/{piRunnerArgs-BOkfxyak.cjs → piRunnerArgs-vnFygygF.cjs} +1 -1
- package/dist/{piRuntime-BhwxzdQf.mjs → piRuntime-Bid7TBf5.mjs} +1 -1
- package/dist/{piRuntime-DzrIiZU8.cjs → piRuntime-C2uj5Ucx.cjs} +1 -1
- package/dist/{piTerminal-BdS7ol7v.cjs → piTerminal-Ckpjfoqa.cjs} +20 -20
- package/dist/{piTerminal-DnA2CbGr.mjs → piTerminal-CqxgrI13.mjs} +20 -20
- package/dist/{pushNotifications-BqFoLye2.cjs → pushNotifications-BCg7YAiu.cjs} +3 -3
- package/dist/{pushNotifications-DkQ0yvFs.mjs → pushNotifications-BbE-qV9I.mjs} +3 -3
- package/dist/{query-BRJYSkb1.mjs → query-Bfr9O_62.mjs} +1 -1
- package/dist/{query-BQ4br3yn.cjs → query-vQ-HG394.cjs} +1 -1
- package/dist/{rateLimitReporter-DK5SQuCc.cjs → rateLimitReporter-BZ8x0-6-.cjs} +3 -3
- package/dist/{rateLimitReporter-BRbYkmuP.mjs → rateLimitReporter-CAz7VMw4.mjs} +3 -3
- package/dist/{rateLimitWindows-DBfiuYeg.cjs → rateLimitWindows-BZl6GMwQ.cjs} +1 -1
- package/dist/{rateLimitWindows-Da5AR-4u.mjs → rateLimitWindows-CRARnKaI.mjs} +1 -1
- package/dist/{registerCommonHandlers-m6pxxf2J.cjs → registerCommonHandlers-CZGmrPbT.cjs} +2 -2
- package/dist/{registerCommonHandlers-yQ7Ru-l0.mjs → registerCommonHandlers-Cj3Nl9y-.mjs} +2 -2
- package/dist/{registerKillSessionHandler-BDNpi7YO.mjs → registerKillSessionHandler-Bg9t45Ub.mjs} +6 -6
- package/dist/{registerKillSessionHandler-BAOIa_Fs.cjs → registerKillSessionHandler-C3EDnW4F.cjs} +6 -6
- package/dist/{remoteSessionClient-CZ7aaNgj.mjs → remoteSessionClient--0vfA7I5.mjs} +5 -5
- package/dist/{remoteSessionClient-iJMXRN_D.cjs → remoteSessionClient-CcSP24Zq.cjs} +5 -5
- package/dist/{reportProgressTool-DfQhPu0s.mjs → reportProgressTool-DVru7jc_.mjs} +3 -3
- package/dist/{reportProgressTool-DpFs7pSe.cjs → reportProgressTool-Ddg1yVq2.cjs} +3 -3
- package/dist/{run-p-xp1_HY.cjs → run-BTrIT_jU.cjs} +178 -847
- package/dist/{run-CwN28mcj.mjs → run-HtvH6BLi.mjs} +176 -845
- package/dist/{runClaude-DRKtAGTm.mjs → runClaude-DsHTk5Bu.mjs} +25 -25
- package/dist/{runClaude-D6U1Z575.cjs → runClaude-ipjwAHPI.cjs} +25 -25
- package/dist/{runClaudeDeps-Dkofokgb.cjs → runClaudeDeps-BKpwL6ln.cjs} +41 -41
- package/dist/{runClaudeDeps-BheVcIlD.mjs → runClaudeDeps-BV3vpeyY.mjs} +46 -46
- package/dist/{runGemini-C8q3YCc0.cjs → runGemini-B-G0_7Ab.cjs} +33 -33
- package/dist/{runGemini-owbvhFbi.mjs → runGemini-DhjK6_Fp.mjs} +33 -33
- package/dist/{runOpenClaw-Dky3-mjO.mjs → runOpenClaw-B6lawk8n.mjs} +18 -18
- package/dist/{runOpenClaw-DGeN66-t.cjs → runOpenClaw-BHIo8tkn.cjs} +18 -18
- package/dist/{sandbox-D2CPyoCA.cjs → sandbox-BAsO0ILe.cjs} +4 -4
- package/dist/{sandbox-sq_wy9Gl.mjs → sandbox-CKb7pCXg.mjs} +4 -4
- package/dist/selfCheck-CZ-t1Xzq.mjs +88 -0
- package/dist/{selfCheck-BgLvQKSt.cjs → selfCheck-D4VvVZNi.cjs} +39 -39
- package/dist/{send-Cd10YhXh.cjs → send-Cz5m39QR.cjs} +8 -8
- package/dist/{send-K9vg-8t-.mjs → send-D8ipLKMY.mjs} +8 -8
- package/dist/{server-De4W1zuK.mjs → server-CjvgT3N9.mjs} +4 -4
- package/dist/{server-DRrV64r0.cjs → server-CySyJKPH.cjs} +6 -6
- package/dist/{sessionLock-Dl6i7IgA.mjs → sessionLock-B73fhgQN.mjs} +3 -3
- package/dist/{sessionLock-BDtSzzKS.cjs → sessionLock-DdDCuNUs.cjs} +3 -3
- package/dist/{sessionOps-gU88-W9F.mjs → sessionOps-C65Iej_C.mjs} +50 -8
- package/dist/{sessionOps-DvnEH4PL.cjs → sessionOps-XSEjIqNq.cjs} +50 -8
- package/dist/{sessionProvider-CKcIo7KO.mjs → sessionProvider-CLVNkfji.mjs} +11 -9
- package/dist/{sessionProvider-CbSZeZrl.cjs → sessionProvider-Dgsty8z_.cjs} +11 -9
- package/dist/{sessionScanner-7RtcCeyD.cjs → sessionScanner-D8IVXMMH.cjs} +3 -3
- package/dist/{sessionScanner-DR32uSby.mjs → sessionScanner-MW1P9Pm9.mjs} +3 -3
- package/dist/{sessions-BvuMjgvJ.cjs → sessions-BKz7gZqg.cjs} +10 -10
- package/dist/{sessions-DTt2Eguk.mjs → sessions-Dtk_agUL.mjs} +10 -10
- package/dist/{setupOfflineReconnection-BGnvhRfb.mjs → setupOfflineReconnection-Bvdy-2xd.mjs} +2 -2
- package/dist/{setupOfflineReconnection-DduOsw6p.cjs → setupOfflineReconnection-DxMiW7OV.cjs} +2 -2
- package/dist/{spawn-DMB6rRPA.cjs → spawn-DiPkJcrQ.cjs} +26 -16
- package/dist/{spawn-CL3cUc7b.mjs → spawn-Dm4xsZBX.mjs} +26 -16
- package/dist/{spawnAgents-CClb7buD.cjs → spawnAgents-B9olJ8xn.cjs} +1 -1
- package/dist/{spawnAgents-CRMfOJhh.mjs → spawnAgents-I29H9nO8.mjs} +1 -1
- package/dist/{spawnHappyCLI-DJdhX_Qx.cjs → spawnHappyCLI-BYGOUda1.cjs} +1 -1
- package/dist/{spawnHappyCLI-Cj_6IICe.mjs → spawnHappyCLI-CnMwzjWX.mjs} +1 -1
- package/dist/{startFileWatcher-LnOmVW6H.cjs → startFileWatcher-D14W6gn-.cjs} +1 -1
- package/dist/{startFileWatcher-DikVa8kg.mjs → startFileWatcher-DePAY1T5.mjs} +1 -1
- package/dist/{startupSessionCreate-CDdaLaMq.mjs → startupSessionCreate-DoK0IvJG.mjs} +3 -3
- package/dist/{startupSessionCreate-B3ND-917.cjs → startupSessionCreate-rBHd4tc1.cjs} +3 -3
- package/dist/{store-DV__wCvP.cjs → store-CkNa6oj4.cjs} +46 -9
- package/dist/{store--XN-7MS0.mjs → store-Vej_738f.mjs} +46 -10
- package/dist/{streamRelay-DFdOaLOn.cjs → streamRelay-C0G1HOOd.cjs} +1 -1
- package/dist/{streamRelay-sABnxEXq.mjs → streamRelay-C5U-C4GS.mjs} +1 -1
- package/dist/{sync-JoEZKRo8.mjs → sync-BP6vnxVP.mjs} +1 -1
- package/dist/{sync-_2lsZ1U2.cjs → sync-WYBwkJvG.cjs} +1 -1
- package/dist/{systemPrompt-CJEvNCuW.cjs → systemPrompt-BkQlCk5_.cjs} +2 -2
- package/dist/{systemPrompt-Zq4HyrZ5.mjs → systemPrompt-aRqBmkpw.mjs} +2 -2
- package/dist/{teams-qz4LqKJ2.mjs → teams-CGmC4ygu.mjs} +7 -7
- package/dist/{teams-BNZafnrT.cjs → teams-phbpwAGD.cjs} +7 -7
- package/dist/{template-LgvBbOna.cjs → template-B9pLEP8v.cjs} +2 -2
- package/dist/{template-CJ8BWSsc.mjs → template-CL9EvQLQ.mjs} +2 -2
- package/dist/{time-CaUlWSNJ.cjs → time-BTLcO8jp.cjs} +1 -1
- package/dist/{time-bzmet4s5.mjs → time-Cw0liIqB.mjs} +1 -1
- package/dist/{titleGenerator-BuIIu_JP.cjs → titleGenerator-Y1_7ceJC.cjs} +3 -3
- package/dist/{titleGenerator-CbTtJ_1D.mjs → titleGenerator-h6TmFe-c.mjs} +2 -2
- package/dist/{todo-CQ_BTf9C.cjs → todo-BxiPiCvB.cjs} +6 -6
- package/dist/{todo-DIrVF_Ak.mjs → todo-OKcTC_VC.mjs} +6 -6
- package/dist/{tools-cLOjBvPn.mjs → tools-BR-drXZ8.mjs} +3 -2
- package/dist/{tools-BnmmFZji.cjs → tools-CcebYtLj.cjs} +3 -2
- package/dist/{uninstall-uEEGKB84.cjs → uninstall-CnDeCC-M.cjs} +3 -3
- package/dist/{uninstall-C5OuW6dE.mjs → uninstall-D3stWKD2.mjs} +3 -3
- package/dist/{wrapperAccount-DXlD3bsO.mjs → wrapperAccount-BkufO_9g.mjs} +5 -4
- package/dist/{wrapperAccount-DzoGqS2b.cjs → wrapperAccount-D2A4DuZy.cjs} +6 -3
- package/package.json +7 -7
- 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 {
|
|
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-
|
|
7
|
-
import {
|
|
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
|
-
|
|
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,
|
|
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:
|
|
316
|
-
kind:
|
|
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
|
|
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
|
-
|
|
406
|
-
if (
|
|
407
|
-
|
|
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
|
-
|
|
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
|
|
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)
|