very-happy-cli 0.2.182 → 0.2.183
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-DLk3gMYH.mjs → AcpBackend-9c-Jeaxd.mjs} +3 -3
- package/dist/{AcpBackend-JA5eu8Y0.cjs → AcpBackend-B-aMuEzO.cjs} +3 -3
- package/dist/{AcpSessionManager-DjYidq4C.cjs → AcpSessionManager-BxXe24AV.cjs} +10 -3
- package/dist/{AcpSessionManager-OrCww-Qv.mjs → AcpSessionManager-CS0FOSQk.mjs} +10 -3
- package/dist/{BasePermissionHandler-u-neo-iN.mjs → BasePermissionHandler-BJ1ID_Br.mjs} +1 -1
- package/dist/{BasePermissionHandler-D3PMKLBS.cjs → BasePermissionHandler-BREjppjP.cjs} +1 -1
- package/dist/{acpSessionResume-u2TwX5Jd.mjs → acpSessionResume-BKtI9Jq_.mjs} +1 -1
- package/dist/{acpSessionResume-Dxo8222T.cjs → acpSessionResume-mVoJ75vI.cjs} +1 -1
- package/dist/{agentHome-D3hNrnoA.mjs → agentHome-B8Ctr_Nu.mjs} +4 -4
- package/dist/{agentHome-CP1tCBXz.cjs → agentHome-rzjm56o4.cjs} +4 -4
- package/dist/{api-C_YSQnsi.mjs → api-C29WLYkW.mjs} +79 -12
- package/dist/{api-CZWcG7uh.cjs → api-xZiqVynF.cjs} +81 -11
- package/dist/{apiMachine-DPGrED5C.cjs → apiMachine-B-FNBIYG.cjs} +14 -14
- package/dist/{apiMachine-C_GA5Bm-.mjs → apiMachine-Dz6Yfk0m.mjs} +14 -14
- package/dist/{attachmentContent-I_dJIevE.cjs → attachmentContent-COV4LF8k.cjs} +2 -2
- package/dist/{attachmentContent-Ckzyb1Uy.mjs → attachmentContent-DwY0uIg6.mjs} +2 -2
- package/dist/{auth-Lw_utSMV.cjs → auth-CYtk9_ga.cjs} +5 -5
- package/dist/{auth-BKnE7uv7.cjs → auth-D_qsnVr3.cjs} +8 -8
- package/dist/{auth-DOXMI-xp.mjs → auth-DvbSDalm.mjs} +8 -8
- package/dist/{auth-CGgpiJ5-.mjs → auth-xT70IYMx.mjs} +5 -5
- package/dist/{auto-CIgFHIyQ.cjs → auto-DT_PfpCx.cjs} +32 -25
- package/dist/{auto-Z56mMZnH.mjs → auto-IiPqvIsN.mjs} +32 -26
- package/dist/{bootstrap-DsXp74wv.cjs → bootstrap-C50NkfPx.cjs} +2 -2
- package/dist/{bootstrap-D3vlOROj.mjs → bootstrap-DS8Acdhm.mjs} +2 -2
- package/dist/{browser-CUxGoATV.mjs → browser-1j9gdZoD.mjs} +1 -1
- package/dist/{browser-CZlA9AkO.cjs → browser-CxKZLd2T.cjs} +1 -1
- package/dist/{claudeLocal-oELvwiZL.cjs → claudeLocal-CgNWpepB.cjs} +5 -5
- package/dist/{claudeLocal-FnTUgwCi.mjs → claudeLocal-U1Fa9sJo.mjs} +5 -5
- package/dist/{claudeLocalLauncher-CO5YHCzi.mjs → claudeLocalLauncher-BjCsfZUE.mjs} +10 -10
- package/dist/{claudeLocalLauncher-QsVXEVdE.cjs → claudeLocalLauncher-IyFm0D6a.cjs} +10 -10
- package/dist/{claudeSessionFork-Cspr6QW0.mjs → claudeSessionFork-6-1vKISn.mjs} +1 -1
- package/dist/{claudeSessionFork-BA4GE5AL.cjs → claudeSessionFork-BUO1XdSm.cjs} +1 -1
- package/dist/{client-xnWiHqdb.cjs → client--vZueZYF.cjs} +4 -4
- package/dist/{client-o-meK7-a.mjs → client-5_zDNdOh.mjs} +2 -2
- package/dist/{client-Ctbw05Xj.mjs → client-BgHvK7lo.mjs} +15 -7
- package/dist/{client-CDuW4MS9.cjs → client-DYGDBD0M.cjs} +15 -7
- package/dist/{client-DK8CzUry.cjs → client-DcKJ0ul_.cjs} +2 -2
- package/dist/{client-BGfmSbWc.mjs → client-DfDyE322.mjs} +4 -4
- package/dist/codex/happyMcpStdioBridge.cjs +16 -16
- package/dist/codex/happyMcpStdioBridge.mjs +16 -16
- package/dist/{codexAppServerClient-DhNDTU_i.cjs → codexAppServerClient-C3nrTfwY.cjs} +3 -3
- package/dist/{codexAppServerClient-BlsOZLul.mjs → codexAppServerClient-DvBg4hGc.mjs} +3 -3
- package/dist/{codexCommand-BGx5NMQR.mjs → codexCommand-Bqp2--g_.mjs} +94 -60
- package/dist/{codexCommand-DJDPfpIs.cjs → codexCommand-DSiU6MNt.cjs} +94 -60
- package/dist/{codexTermination-CqPMuokw.cjs → codexTermination-D9TRTglF.cjs} +1 -1
- package/dist/{codexTermination-CVhhwHZU.mjs → codexTermination-DsliWl_s.mjs} +1 -1
- package/dist/{config-CHpxzXBL.cjs → config-CRhWiOwi.cjs} +3 -3
- package/dist/{config-CWAe08-Q.mjs → config-DeaqRn3o.mjs} +3 -3
- package/dist/{configuration-B-CugKJ3.cjs → configuration-K3I6yOjZ.cjs} +1 -1
- package/dist/{configuration-YXw_Dcsb.mjs → configuration-elzht62L.mjs} +1 -1
- package/dist/{connect-BmHvMXH2.cjs → connect-B5UbfmO3.cjs} +13 -13
- package/dist/{connect-CPeJXHha.mjs → connect-CT5cOlnC.mjs} +13 -13
- package/dist/{context-Drzs_Z38.mjs → context-CLj1_RYF.mjs} +1 -1
- package/dist/{context-BtIVqHI5.cjs → context-DNKNF8Yh.cjs} +1 -1
- package/dist/{controlClient-D0kGwKYx.cjs → controlClient-ChqmxgbB.cjs} +3 -3
- package/dist/{controlClient-BL4hb4l3.mjs → controlClient-CuYQs2aZ.mjs} +3 -3
- package/dist/{createSessionMetadata-DvGDsnsn.mjs → createSessionMetadata-C1MbLQnh.mjs} +2 -2
- package/dist/{createSessionMetadata-L499emJn.cjs → createSessionMetadata-QfiRx4Tf.cjs} +2 -2
- package/dist/daemonSupervisor-57JYYzMf.cjs +268 -0
- package/dist/daemonSupervisor-DfzrtNhM.mjs +245 -0
- package/dist/{defaultPermissionMode-MXpZlXud.cjs → defaultPermissionMode-DQmdZZIg.cjs} +2 -2
- package/dist/{defaultPermissionMode-BLfxu-Yz.mjs → defaultPermissionMode-U9LuUeQh.mjs} +2 -2
- package/dist/{deterministicJson-CfLkBRvU.cjs → deterministicJson-BBRUcB8i.cjs} +569 -17
- package/dist/{deterministicJson-B_UAbmQ4.mjs → deterministicJson-BixlyPWV.mjs} +572 -21
- package/dist/{doctor-DMvlzmnE.cjs → doctor-CKgHUV4W.cjs} +7 -7
- package/dist/{doctor-bKScPtZu.mjs → doctor-Dban2oE2.mjs} +7 -7
- package/dist/{downloadTarget-D33BFvew.cjs → downloadTarget-CmC11Y7E.cjs} +6 -6
- package/dist/{downloadTarget-J9j37eFG.mjs → downloadTarget-VUTd9lEO.mjs} +6 -6
- package/dist/{ensureDaemonRunning-2IqWROJp.cjs → ensureDaemonRunning-L0fl0cLE.cjs} +5 -5
- package/dist/{ensureDaemonRunning-DLvwhpNg.mjs → ensureDaemonRunning-khb8Nr1n.mjs} +5 -5
- package/dist/{handleResumeCommand-CjtjQ_I7.mjs → handleResumeCommand-CLDGWpTJ.mjs} +5 -5
- package/dist/{handleResumeCommand-Dp2Y-p6V.cjs → handleResumeCommand-D9myBN2N.cjs} +5 -5
- package/dist/{index-BOT0Tg5E.mjs → index-BMZx-699.mjs} +4 -4
- package/dist/{index-CZC7egJA.cjs → index-BdJs0465.cjs} +3 -3
- package/dist/{index-BI0h2Zks.mjs → index-BptfFoXM.mjs} +268 -77
- package/dist/{index-DymOv3kK.cjs → index-COSjJPIv.cjs} +4 -4
- package/dist/{index-D_LvOWUN.mjs → index-CtwqBeH6.mjs} +3 -3
- package/dist/{index-DYVIbhAJ.cjs → index-DgA79dVw.cjs} +40 -40
- package/dist/{index-oh8XEozJ.cjs → index-Fq-jxjsB.cjs} +277 -76
- package/dist/{index-Cllzqoes.mjs → index-GkkbUZX-.mjs} +4 -4
- package/dist/{index-kA46KMxN.mjs → index-IRI8s8kz.mjs} +41 -41
- package/dist/{index-B_aNaW9w.cjs → index-y4JNyz9H.cjs} +4 -4
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{install-D2NCbeJ-.cjs → install-BATFlr_l.cjs} +2 -2
- package/dist/{install-D0inLCv-.mjs → install-F3rP8tBU.mjs} +2 -2
- package/dist/{install-C46mkr9a.mjs → install-JvCk2PJV.mjs} +3 -3
- package/dist/{install-BAa_Xmof.cjs → install-cn98bTCs.cjs} +3 -3
- package/dist/lib.cjs +12 -12
- package/dist/lib.d.cts +1 -1
- package/dist/lib.d.mts +1 -1
- package/dist/lib.mjs +12 -12
- package/dist/{lidState-DcPvwniz.cjs → lidState-Bcs5kRHi.cjs} +1 -1
- package/dist/{lidState-D8Iuvjgl.mjs → lidState-DXeYTsrm.mjs} +1 -1
- package/dist/{localHappyAgentAuth-D3rQDRd9.mjs → localHappyAgentAuth-C1A4ChCR.mjs} +1 -1
- package/dist/{localHappyAgentAuth-SD6GM97y.cjs → localHappyAgentAuth-CypTSe42.cjs} +1 -1
- package/dist/{logger-DK1ytCz6.cjs → logger-Cgwz30rK.cjs} +2 -2
- package/dist/{logger-DpqihN1f.mjs → logger-RMPh5aqe.mjs} +2 -2
- package/dist/{machineMetadata-IJc6_iyx.cjs → machineMetadata-BSOGMNRi.cjs} +3 -3
- package/dist/{machineMetadata-D4E3qoIG.mjs → machineMetadata-BTUtPRth.mjs} +3 -3
- package/dist/{main-DUXh2rgW.cjs → main-4iiwYpCR.cjs} +61 -56
- package/dist/{main-CpUmw7hm.mjs → main-DNDL6t8z.mjs} +61 -56
- package/dist/{mcp-D5f3Vd-z.cjs → mcp-C7eEoGhz.cjs} +15 -15
- package/dist/{mcp-66g1TJ8P.mjs → mcp-DXYDPOpJ.mjs} +15 -15
- package/dist/{mirrorProtocol-bsCUcaCY.mjs → mirrorProtocol-DQRy5PaT.mjs} +3 -3
- package/dist/{mirrorProtocol-DkWOcZh9.cjs → mirrorProtocol-c5g5MgNc.cjs} +3 -3
- package/dist/{package-BfeqAzyJ.cjs → package-3aPiSpZj.cjs} +7 -7
- package/dist/{package-CKj8zndE.mjs → package-CTrz6U3C.mjs} +7 -7
- package/dist/{panels-r8LmaBs6.mjs → panels-B5sZ84vA.mjs} +5 -5
- package/dist/{panels-2PXsw9-d.cjs → panels-BmsmKHbw.cjs} +5 -5
- package/dist/{peerTools-D_id4d41.mjs → peerTools-DIPOX033.mjs} +5 -5
- package/dist/{peerTools-BVp1z0T_.cjs → peerTools-Dxe7iCi_.cjs} +5 -5
- package/dist/{persistence-BdpwWXKh.cjs → persistence-DZRMUZZS.cjs} +2 -2
- package/dist/{persistence-jOEuAFTS.mjs → persistence-zJo4r7YI.mjs} +2 -2
- package/dist/{piRunnerArgs-vxCHKnSA.cjs → piRunnerArgs-BSPiS6tZ.cjs} +1 -1
- package/dist/{piRunnerArgs-68I5F_M1.mjs → piRunnerArgs-IVdoHUB6.mjs} +1 -1
- package/dist/{piRuntime-C3Dg5uni.cjs → piRuntime-BJzjlMcN.cjs} +2 -2
- package/dist/{piRuntime-DgLIard1.mjs → piRuntime-BvHO3vgO.mjs} +2 -2
- package/dist/{piTerminal-C135BcLP.cjs → piTerminal-Cz4pW55d.cjs} +18 -18
- package/dist/{piTerminal-DJL0w-uA.mjs → piTerminal-D7vBOpkE.mjs} +18 -18
- package/dist/{pushNotifications-CMmRsbKv.mjs → pushNotifications-C4R9-1hU.mjs} +3 -3
- package/dist/{pushNotifications-CyQVDThC.cjs → pushNotifications-CgIrYml3.cjs} +3 -3
- package/dist/{query-CK--1fbL.cjs → query-CZQG1PdU.cjs} +1 -1
- package/dist/{query-CPXnDURZ.mjs → query-DKPmDsHS.mjs} +1 -1
- package/dist/{rateLimitWindows-DJxnNw-X.cjs → rateLimitWindows-CPV0nLeq.cjs} +1 -1
- package/dist/{rateLimitWindows-Cqa4AGaB.mjs → rateLimitWindows-HlHATOQ0.mjs} +1 -1
- package/dist/{registerCommonHandlers-DbNoM39q.cjs → registerCommonHandlers-D1pC83Op.cjs} +2 -2
- package/dist/{registerCommonHandlers-K8dICQO2.mjs → registerCommonHandlers-a9lHojSV.mjs} +2 -2
- package/dist/{registerKillSessionHandler-O1iriOMO.mjs → registerKillSessionHandler-Bp-fuH-w.mjs} +6 -6
- package/dist/{registerKillSessionHandler-DiS_go8d.cjs → registerKillSessionHandler-nTi2vVJy.cjs} +6 -6
- package/dist/{remoteSessionClient-BlURPulk.mjs → remoteSessionClient-Cwrddscy.mjs} +5 -5
- package/dist/{remoteSessionClient-CtV9mDko.cjs → remoteSessionClient-HQAKAvVd.cjs} +5 -5
- package/dist/{reportProgressTool-DlD_xjzU.cjs → reportProgressTool-Be-8ADI4.cjs} +4 -4
- package/dist/{reportProgressTool-nCExrHZH.mjs → reportProgressTool-CcZ32nrd.mjs} +4 -4
- package/dist/{resources-CH1iP6Cv.mjs → resources-CLdQfe3b.mjs} +1 -1
- package/dist/{resources-BPyN59Iv.cjs → resources-CqwHPhdK.cjs} +1 -1
- package/dist/{run-drtwHYkO.mjs → run-BBU8GyxE.mjs} +59 -243
- package/dist/{run-BBNrcCfI.cjs → run-CxRJk9qq.cjs} +69 -254
- package/dist/{runClaude-CFp27Tyi.mjs → runClaude-DR6pEQwd.mjs} +22 -22
- package/dist/{runClaude-B3KSeby4.cjs → runClaude-Dd5zJaUZ.cjs} +22 -22
- package/dist/{runClaudeDeps-DMcv93lA.mjs → runClaudeDeps-COgZaUZm.mjs} +50 -45
- package/dist/{runClaudeDeps-C_C9TCI0.cjs → runClaudeDeps-CTtZ_1mC.cjs} +45 -40
- package/dist/{runGemini-Bc6SY-hd.mjs → runGemini-DVoVUfPp.mjs} +37 -35
- package/dist/{runGemini-DzdSBAr9.cjs → runGemini-DX72qB92.cjs} +37 -35
- package/dist/{runOpenClaw-DI0qMlgF.mjs → runOpenClaw-BHjzmzeC.mjs} +18 -18
- package/dist/{runOpenClaw-DN6rEVqC.cjs → runOpenClaw-BSg4hFVt.cjs} +18 -18
- package/dist/{sandbox-v-ffe8LR.mjs → sandbox-CWR9EqoN.mjs} +4 -4
- package/dist/{sandbox-DtttPBMA.cjs → sandbox-D1T_hmgZ.cjs} +4 -4
- package/dist/{selfCheck-B-yy6bW3.cjs → selfCheck-CE7vlnNS.cjs} +36 -36
- package/dist/selfCheck-ZGgBtxFQ.mjs +85 -0
- package/dist/{send-DpBwSZuj.mjs → send-BDF0Zvxo.mjs} +8 -8
- package/dist/{send-ShzXYPRu.cjs → send-BxZqRCcG.cjs} +8 -8
- package/dist/{server-DScgJXxa.mjs → server-B4JtnDLF.mjs} +4 -4
- package/dist/{server-CEzKrfKj.cjs → server-DB7_70Mi.cjs} +6 -6
- package/dist/{sessionLock-Dc0fadGG.cjs → sessionLock-BXvFN6uw.cjs} +3 -3
- package/dist/{sessionLock-B6K4SBZD.mjs → sessionLock-CXOOX-VD.mjs} +3 -3
- package/dist/{sessionOps-Dx7wARjI.cjs → sessionOps-BWlDlFYP.cjs} +4 -4
- package/dist/{sessionOps-D0BPWPoh.mjs → sessionOps-ByVggB_q.mjs} +4 -4
- package/dist/{sessionScanner-BJ35TVG6.cjs → sessionScanner-DkxPB5VA.cjs} +3 -3
- package/dist/{sessionScanner-9Fpgaxtf.mjs → sessionScanner-r66RtF95.mjs} +3 -3
- package/dist/{sessions-TZGGAry1.cjs → sessions-BiJTxFy9.cjs} +10 -10
- package/dist/{sessions-CFtDlyZd.mjs → sessions-C1lLK_a9.mjs} +10 -10
- package/dist/{setupOfflineReconnection-Biaus-0T.mjs → setupOfflineReconnection-Bl3DuakT.mjs} +2 -2
- package/dist/{setupOfflineReconnection-B1GsVA8P.cjs → setupOfflineReconnection-CecTiFZ-.cjs} +2 -2
- package/dist/{spawn-CsoQ-Ecz.mjs → spawn-D-8MlEM6.mjs} +14 -14
- package/dist/{spawn-BRTuypQ2.cjs → spawn-D79mVa3h.cjs} +14 -14
- package/dist/{spawnAgents-Co-SLcx-.mjs → spawnAgents-DJHjq01u.mjs} +1 -1
- package/dist/{spawnAgents-CG211IW7.cjs → spawnAgents-Sfnf-4pN.cjs} +1 -1
- package/dist/{spawnHappyCLI-D47kX6jg.cjs → spawnHappyCLI-CQwQs9G5.cjs} +1 -1
- package/dist/{spawnHappyCLI-D1doCjkZ.mjs → spawnHappyCLI-v_bJwZ4Z.mjs} +1 -1
- package/dist/{specialCommands-Ch-Gvy-i.cjs → specialCommands-CWMVfT5s.cjs} +3 -3
- package/dist/{specialCommands-xSmqT_Fu.mjs → specialCommands-yMnFvS-W.mjs} +3 -3
- package/dist/{startFileWatcher-CCl2fFxT.mjs → startFileWatcher-BCDkT_tr.mjs} +1 -1
- package/dist/{startFileWatcher-gKQTstR6.cjs → startFileWatcher-GW4_E7dV.cjs} +1 -1
- package/dist/{startupSessionCreate-DlZc8yPl.mjs → startupSessionCreate-BcAGYo51.mjs} +1 -1
- package/dist/{startupSessionCreate-BXqoUX30.cjs → startupSessionCreate-tBRa_ze8.cjs} +1 -1
- package/dist/{streamRelay-DnJXsi36.mjs → streamRelay-BEDiy6_b.mjs} +1 -1
- package/dist/{streamRelay-B-J-4St1.cjs → streamRelay-BZ8drtof.cjs} +1 -1
- package/dist/{sync-BbjMC3sR.mjs → sync--QUIOuf8.mjs} +1 -1
- package/dist/{sync-BxMdnZzz.cjs → sync-BMDkyo75.cjs} +1 -1
- package/dist/{systemPrompt-C2KojRmK.cjs → systemPrompt-DoHSXrH0.cjs} +2 -2
- package/dist/{systemPrompt-CmSDAoIx.mjs → systemPrompt-O0Kd6vbA.mjs} +2 -2
- package/dist/{teams-DESdalox.cjs → teams-BkZop-sP.cjs} +9 -9
- package/dist/{teams-lRy1MS0Z.mjs → teams-CTF1gT48.mjs} +9 -9
- package/dist/{template-BaHAmH2K.cjs → template-CeC1dYe-.cjs} +32 -2
- package/dist/{template-CiOPa2rd.mjs → template-D1fm22em.mjs} +31 -3
- package/dist/{time-Cfknl7xG.mjs → time-B2KKdAym.mjs} +1 -1
- package/dist/{time-DNLeIRgR.cjs → time-CdCotzKU.cjs} +1 -1
- package/dist/{titleGenerator-ClnMSzwC.mjs → titleGenerator-BFDczskR.mjs} +1 -1
- package/dist/{titleGenerator-YNutaU88.cjs → titleGenerator-DZH1XqAf.cjs} +2 -2
- package/dist/{todo-DZbK5POc.mjs → todo-C2gyOUom.mjs} +6 -6
- package/dist/{todo-DS75Mboz.cjs → todo-DnTFTHmV.cjs} +6 -6
- package/dist/{tools-ClYcb1YQ.cjs → tools-C8rpwyIl.cjs} +1 -1
- package/dist/{tools-BgdU0dWp.mjs → tools-DUjkqSQL.mjs} +1 -1
- package/dist/{uninstall-bXenFevR.mjs → uninstall-B5Ew50mZ.mjs} +3 -3
- package/dist/{uninstall-Di1vPBLV.cjs → uninstall-CKMPWTMv.cjs} +3 -3
- package/package.json +7 -7
- package/dist/daemonSupervisor-B-SPSqhs.cjs +0 -13
- package/dist/daemonSupervisor-C6urv3_8.mjs +0 -10
- package/dist/selfCheck-BDfTwxqB.mjs +0 -85
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_child_process = require('node:child_process');
|
|
4
|
+
var module$1 = require('node:module');
|
|
5
|
+
var node_crypto = require('node:crypto');
|
|
6
|
+
var path = require('node:path');
|
|
7
|
+
var os = require('node:os');
|
|
8
|
+
|
|
9
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
|
+
const CLAUDE_KEYCHAIN_SERVICE_PREFIX = "Claude Code";
|
|
11
|
+
function keychainIdentity(env = process.env, deps = {}) {
|
|
12
|
+
const home = deps.home ?? os.homedir();
|
|
13
|
+
const secureDir = env.CLAUDE_SECURESTORAGE_CONFIG_DIR?.trim();
|
|
14
|
+
const configDirEnv = env.CLAUDE_CONFIG_DIR?.trim();
|
|
15
|
+
const configDir = secureDir || configDirEnv || path.join(home, ".claude");
|
|
16
|
+
const hasCustomDir = Boolean(secureDir || configDirEnv);
|
|
17
|
+
const dirSuffix = hasCustomDir ? "-" + node_crypto.createHash("sha256").update(configDir.normalize("NFC")).digest("hex").slice(0, 8) : "";
|
|
18
|
+
const oauthSuffix = env.CLAUDE_CODE_OAUTH_CLIENT_ID?.trim() ? "-custom-oauth" : "";
|
|
19
|
+
const rawAccount = env.USER || safeUsername(deps.username);
|
|
20
|
+
const account = /^[a-zA-Z0-9._-]+$/.test(rawAccount) ? rawAccount : "claude-code-user";
|
|
21
|
+
return {
|
|
22
|
+
service: `${CLAUDE_KEYCHAIN_SERVICE_PREFIX}${oauthSuffix}-credentials${dirSuffix}`,
|
|
23
|
+
account,
|
|
24
|
+
configDir,
|
|
25
|
+
credentialsPath: path.join(configDir, ".credentials.json")
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function safeUsername(provider) {
|
|
29
|
+
try {
|
|
30
|
+
return provider ? provider() : os.userInfo().username;
|
|
31
|
+
} catch {
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CLAUDE_AUTH_PROBE_VERSION = 1;
|
|
37
|
+
const LOCAL_CREDENTIAL_SOURCE = "Claude local credentials";
|
|
38
|
+
function classifyAuthStatus(run, credentialSource) {
|
|
39
|
+
const localSource = credentialSource === void 0 || credentialSource === LOCAL_CREDENTIAL_SOURCE;
|
|
40
|
+
if (run.spawnError) {
|
|
41
|
+
return { status: "error", diagnosis: "probe-crash", detail: `could not run claude auth status: ${run.spawnError}` };
|
|
42
|
+
}
|
|
43
|
+
if (run.timedOut) {
|
|
44
|
+
return { status: "error", diagnosis: "probe-timeout", detail: "claude auth status did not answer within the timeout" };
|
|
45
|
+
}
|
|
46
|
+
const parsed = parseJsonObject(run.stdout);
|
|
47
|
+
if (!parsed) {
|
|
48
|
+
if (!localSource) return { status: "unknown", authMethod: credentialSource, detail: `auth status unparseable under ${credentialSource}` };
|
|
49
|
+
return { status: "error", diagnosis: "probe-crash", detail: `claude auth status returned no JSON (exit ${run.exitCode ?? "null"})` };
|
|
50
|
+
}
|
|
51
|
+
const authMethod = typeof parsed.authMethod === "string" ? parsed.authMethod : void 0;
|
|
52
|
+
const subscriptionType = typeof parsed.subscriptionType === "string" ? parsed.subscriptionType : void 0;
|
|
53
|
+
if (parsed.loggedIn === true) {
|
|
54
|
+
return { status: "ok", authMethod: localSource ? authMethod : credentialSource, subscriptionType };
|
|
55
|
+
}
|
|
56
|
+
if (!localSource) {
|
|
57
|
+
return { status: "unknown", authMethod: credentialSource, detail: `Claude Code reports loggedIn=false under ${credentialSource}; not a local-credential failure` };
|
|
58
|
+
}
|
|
59
|
+
return { status: "not-logged-in", authMethod, subscriptionType, detail: "Claude Code in the daemon context reports it is not logged in" };
|
|
60
|
+
}
|
|
61
|
+
function parseJsonObject(text) {
|
|
62
|
+
const trimmed = text.trim();
|
|
63
|
+
if (!trimmed) return null;
|
|
64
|
+
const start = trimmed.indexOf("{");
|
|
65
|
+
if (start < 0) return null;
|
|
66
|
+
try {
|
|
67
|
+
const value = JSON.parse(trimmed.slice(start));
|
|
68
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('daemonSupervisor-57JYYzMf.cjs', document.baseURI).href))).resolve(s)) {
|
|
74
|
+
const platformArch = `${platform}-${arch}`;
|
|
75
|
+
const candidates = [
|
|
76
|
+
`@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
|
|
77
|
+
`@anthropic-ai/claude-agent-sdk-${platformArch}/claude.exe`
|
|
78
|
+
];
|
|
79
|
+
for (const candidate of candidates) {
|
|
80
|
+
try {
|
|
81
|
+
return resolver(candidate);
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
function interpretSecurityRead(result) {
|
|
88
|
+
if (result.error === "ENOENT") return { kind: "unsupported" };
|
|
89
|
+
if (result.error === "timeout") return { kind: "error", detail: "security timed out" };
|
|
90
|
+
if (result.exitCode === 44) return { kind: "absent" };
|
|
91
|
+
if (result.exitCode === 36) return { kind: "unreadable" };
|
|
92
|
+
if (result.exitCode !== 0) return { kind: "error", detail: `security exited ${result.exitCode ?? "null"}` };
|
|
93
|
+
const raw = result.stdout.trim();
|
|
94
|
+
if (!raw) return { kind: "absent" };
|
|
95
|
+
const parsed = parseJsonObject(raw);
|
|
96
|
+
const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
|
|
97
|
+
if (!oauth) return { kind: "present", accessToken: "", refreshToken: "", raw };
|
|
98
|
+
return {
|
|
99
|
+
kind: "present",
|
|
100
|
+
accessToken: typeof oauth.accessToken === "string" ? oauth.accessToken : "",
|
|
101
|
+
refreshToken: typeof oauth.refreshToken === "string" ? oauth.refreshToken : "",
|
|
102
|
+
raw
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function interpretCredentialsFile(text) {
|
|
106
|
+
if (text === null) return { exists: false, hasTokens: false, refreshToken: "" };
|
|
107
|
+
const parsed = parseJsonObject(text);
|
|
108
|
+
const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
|
|
109
|
+
const access = oauth && typeof oauth.accessToken === "string" ? oauth.accessToken : "";
|
|
110
|
+
const refresh = oauth && typeof oauth.refreshToken === "string" ? oauth.refreshToken : "";
|
|
111
|
+
return { exists: true, hasTokens: access.length > 0 && refresh.length > 0, refreshToken: refresh };
|
|
112
|
+
}
|
|
113
|
+
function tokenTail(token) {
|
|
114
|
+
return token ? node_crypto.createHash("sha256").update(token).digest("hex").slice(-6) : "";
|
|
115
|
+
}
|
|
116
|
+
const CREDENTIALS_REJECTED_DETAIL = "Credentials exist but Claude Code rejects them in the daemon context \u2014 the refresh token has most likely been rotated away by another store or another machine using the same credentials. Log in again with `claude` on this machine.";
|
|
117
|
+
function diagnoseStores(input) {
|
|
118
|
+
const { status, keychain, file } = input;
|
|
119
|
+
if (keychain.kind === "present") {
|
|
120
|
+
const empty = keychain.accessToken.length === 0 && keychain.refreshToken.length === 0;
|
|
121
|
+
if (empty && file.hasTokens && status === "not-logged-in") {
|
|
122
|
+
return {
|
|
123
|
+
diagnosis: "keychain-empty-item",
|
|
124
|
+
repairable: "delete-empty-keychain-item",
|
|
125
|
+
keychainRaw: keychain.raw,
|
|
126
|
+
detail: "The login keychain holds a Claude Code credentials item with empty tokens; Claude Code prefers it over the valid ~/.claude/.credentials.json and reports not logged in."
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (!empty && file.hasTokens && tokenTail(keychain.refreshToken) !== tokenTail(file.refreshToken)) {
|
|
130
|
+
return {
|
|
131
|
+
diagnosis: "store-divergence",
|
|
132
|
+
detail: "Keychain and ~/.claude/.credentials.json hold different refresh tokens; one of them will stop working at its next refresh. Treat the daemon-context login as canonical, or pin credentialStore=file."
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return {};
|
|
136
|
+
}
|
|
137
|
+
if ((keychain.kind === "absent" || keychain.kind === "unreadable" || keychain.kind === "unsupported") && !file.hasTokens) {
|
|
138
|
+
return { diagnosis: "no-credentials", detail: "No Claude Code credentials found for this daemon context; log in with `claude` on this machine." };
|
|
139
|
+
}
|
|
140
|
+
if (keychain.kind === "unreadable" && file.hasTokens && status === "not-logged-in") {
|
|
141
|
+
return { diagnosis: "credentials-rejected", detail: CREDENTIALS_REJECTED_DETAIL };
|
|
142
|
+
}
|
|
143
|
+
if (keychain.kind === "error") {
|
|
144
|
+
return { detail: `keychain check failed: ${keychain.detail}` };
|
|
145
|
+
}
|
|
146
|
+
return {};
|
|
147
|
+
}
|
|
148
|
+
function securityReadArgs(identity) {
|
|
149
|
+
return ["find-generic-password", "-s", identity.service, "-a", identity.account, "-w"];
|
|
150
|
+
}
|
|
151
|
+
function securityDeleteArgs(identity) {
|
|
152
|
+
return ["delete-generic-password", "-s", identity.service, "-a", identity.account];
|
|
153
|
+
}
|
|
154
|
+
const HAPPY_DAEMON_LAUNCHD_LABEL = "com.mereith.happy-daemon";
|
|
155
|
+
function classifyLineage(input) {
|
|
156
|
+
if (input.platform !== "darwin") return "other";
|
|
157
|
+
const label = input.label ?? HAPPY_DAEMON_LAUNCHD_LABEL;
|
|
158
|
+
if (input.env.XPC_SERVICE_NAME !== label) return "other";
|
|
159
|
+
if (input.launchdJobPid !== null && input.ancestorPids.includes(input.launchdJobPid)) return "launchd";
|
|
160
|
+
return "inherited-env";
|
|
161
|
+
}
|
|
162
|
+
function parseLaunchctlPid(printOutput) {
|
|
163
|
+
const match = /^\s*pid\s*=\s*(\d+)/m.exec(printOutput);
|
|
164
|
+
return match ? Number(match[1]) : null;
|
|
165
|
+
}
|
|
166
|
+
function keychainOffShimDir(happyLibDir) {
|
|
167
|
+
return path.join(happyLibDir, "scripts", "shims", "keychain-off");
|
|
168
|
+
}
|
|
169
|
+
function withKeychainOffPath(path$1, shimDir) {
|
|
170
|
+
const parts = (path$1 ?? "").split(path.delimiter).filter((p) => p && p !== shimDir);
|
|
171
|
+
return [shimDir, ...parts].join(path.delimiter);
|
|
172
|
+
}
|
|
173
|
+
function buildClaudeAuthState(input) {
|
|
174
|
+
const { classification, diagnosis } = input;
|
|
175
|
+
const detail = (diagnosis?.detail ?? classification.detail)?.slice(0, 200);
|
|
176
|
+
const state = {
|
|
177
|
+
probeVersion: CLAUDE_AUTH_PROBE_VERSION,
|
|
178
|
+
daemonPid: input.daemonPid,
|
|
179
|
+
status: classification.status,
|
|
180
|
+
context: { platform: input.platform, lineage: input.lineage, credentialStore: input.credentialStore },
|
|
181
|
+
checkedAt: input.now ?? Date.now()
|
|
182
|
+
};
|
|
183
|
+
if (classification.authMethod) state.authMethod = classification.authMethod;
|
|
184
|
+
if (classification.subscriptionType) state.subscriptionType = classification.subscriptionType;
|
|
185
|
+
const diag = diagnosis?.diagnosis ?? classification.diagnosis;
|
|
186
|
+
if (diag) state.diagnosis = diag;
|
|
187
|
+
if (detail) state.detail = detail;
|
|
188
|
+
if (diagnosis?.repairable) state.repairable = diagnosis.repairable;
|
|
189
|
+
return state;
|
|
190
|
+
}
|
|
191
|
+
function claudeAuthStateChanged(prev, next) {
|
|
192
|
+
if (!prev) return true;
|
|
193
|
+
const strip = ({ checkedAt: _c, ...rest }) => JSON.stringify(rest);
|
|
194
|
+
return strip(prev) !== strip(next);
|
|
195
|
+
}
|
|
196
|
+
function keychainIdentityFor(env) {
|
|
197
|
+
return keychainIdentity(env);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function detectDaemonSupervisor(env, platform = process.platform, launchd = null) {
|
|
201
|
+
const explicit = env.HAPPY_DAEMON_SUPERVISOR?.trim().toLowerCase();
|
|
202
|
+
if (explicit === "systemd") return "systemd";
|
|
203
|
+
if (explicit === "none") return "none";
|
|
204
|
+
if (platform === "linux" && typeof env.INVOCATION_ID === "string" && env.INVOCATION_ID.trim() !== "") return "systemd";
|
|
205
|
+
if (platform === "darwin" && launchd && classifyLineage({ platform, env, launchdJobPid: launchd.jobPid, ancestorPids: launchd.ancestorPids }) === "launchd") return "launchd";
|
|
206
|
+
return "none";
|
|
207
|
+
}
|
|
208
|
+
function daemonLineage(supervisor, env, platform = process.platform, launchd = null) {
|
|
209
|
+
if (supervisor !== "none") return supervisor;
|
|
210
|
+
return classifyLineage({ platform, env, launchdJobPid: launchd?.jobPid ?? null, ancestorPids: launchd?.ancestorPids ?? [] });
|
|
211
|
+
}
|
|
212
|
+
function execText(file, args) {
|
|
213
|
+
return new Promise((resolve) => {
|
|
214
|
+
node_child_process.execFile(file, args, { timeout: LAUNCHD_PROBE_TIMEOUT_MS, maxBuffer: 1024 * 1024 }, (error, stdout) => resolve(error ? "" : String(stdout ?? "")));
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
const LAUNCHD_PROBE_TIMEOUT_MS = 3e3;
|
|
218
|
+
async function probeLaunchdJob(exec = execText) {
|
|
219
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
220
|
+
const jobPid = uid === null ? null : parseLaunchctlPid(await exec("launchctl", ["print", `gui/${uid}/${HAPPY_DAEMON_LAUNCHD_LABEL}`]));
|
|
221
|
+
const ancestorPids = [process.pid];
|
|
222
|
+
let pid = process.ppid;
|
|
223
|
+
for (let i = 0; i < 10 && pid > 1; i++) {
|
|
224
|
+
ancestorPids.push(pid);
|
|
225
|
+
const ppid = Number((await exec("ps", ["-o", "ppid=", "-p", String(pid)])).trim());
|
|
226
|
+
if (!Number.isFinite(ppid) || ppid <= 0 || ppid === pid) break;
|
|
227
|
+
pid = ppid;
|
|
228
|
+
}
|
|
229
|
+
return { jobPid, ancestorPids };
|
|
230
|
+
}
|
|
231
|
+
const SYSTEMD_RESTART_HINT = "systemctl --user restart very-happy-daemon";
|
|
232
|
+
async function kickstartLaunchdJob(run = (file, args) => node_child_process.spawnSync(file, args, { encoding: "utf8", timeout: LAUNCHD_PROBE_TIMEOUT_MS }), uid = typeof process.getuid === "function" ? process.getuid() : null, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
233
|
+
if (uid === null) return false;
|
|
234
|
+
const target = `gui/${uid}/${HAPPY_DAEMON_LAUNCHD_LABEL}`;
|
|
235
|
+
try {
|
|
236
|
+
for (let i = 0; i < 50; i++) {
|
|
237
|
+
const printed = run("launchctl", ["print", target]);
|
|
238
|
+
if (printed.status !== 0) return false;
|
|
239
|
+
if (parseLaunchctlPid(printed.stdout ?? "") === null) break;
|
|
240
|
+
await sleep(100);
|
|
241
|
+
}
|
|
242
|
+
return run("launchctl", ["kickstart", target]).status === 0;
|
|
243
|
+
} catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
exports.CREDENTIALS_REJECTED_DETAIL = CREDENTIALS_REJECTED_DETAIL;
|
|
249
|
+
exports.HAPPY_DAEMON_LAUNCHD_LABEL = HAPPY_DAEMON_LAUNCHD_LABEL;
|
|
250
|
+
exports.SYSTEMD_RESTART_HINT = SYSTEMD_RESTART_HINT;
|
|
251
|
+
exports.buildClaudeAuthState = buildClaudeAuthState;
|
|
252
|
+
exports.classifyAuthStatus = classifyAuthStatus;
|
|
253
|
+
exports.classifyLineage = classifyLineage;
|
|
254
|
+
exports.claudeAuthStateChanged = claudeAuthStateChanged;
|
|
255
|
+
exports.daemonLineage = daemonLineage;
|
|
256
|
+
exports.detectDaemonSupervisor = detectDaemonSupervisor;
|
|
257
|
+
exports.diagnoseStores = diagnoseStores;
|
|
258
|
+
exports.interpretCredentialsFile = interpretCredentialsFile;
|
|
259
|
+
exports.interpretSecurityRead = interpretSecurityRead;
|
|
260
|
+
exports.keychainIdentityFor = keychainIdentityFor;
|
|
261
|
+
exports.keychainOffShimDir = keychainOffShimDir;
|
|
262
|
+
exports.kickstartLaunchdJob = kickstartLaunchdJob;
|
|
263
|
+
exports.parseLaunchctlPid = parseLaunchctlPid;
|
|
264
|
+
exports.probeLaunchdJob = probeLaunchdJob;
|
|
265
|
+
exports.resolveSdkClaudeBinary = resolveSdkClaudeBinary;
|
|
266
|
+
exports.securityDeleteArgs = securityDeleteArgs;
|
|
267
|
+
exports.securityReadArgs = securityReadArgs;
|
|
268
|
+
exports.withKeychainOffPath = withKeychainOffPath;
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { spawnSync, execFile } from 'node:child_process';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { join, delimiter } from 'node:path';
|
|
5
|
+
import { homedir, userInfo } from 'node:os';
|
|
6
|
+
|
|
7
|
+
const CLAUDE_KEYCHAIN_SERVICE_PREFIX = "Claude Code";
|
|
8
|
+
function keychainIdentity(env = process.env, deps = {}) {
|
|
9
|
+
const home = deps.home ?? homedir();
|
|
10
|
+
const secureDir = env.CLAUDE_SECURESTORAGE_CONFIG_DIR?.trim();
|
|
11
|
+
const configDirEnv = env.CLAUDE_CONFIG_DIR?.trim();
|
|
12
|
+
const configDir = secureDir || configDirEnv || join(home, ".claude");
|
|
13
|
+
const hasCustomDir = Boolean(secureDir || configDirEnv);
|
|
14
|
+
const dirSuffix = hasCustomDir ? "-" + createHash("sha256").update(configDir.normalize("NFC")).digest("hex").slice(0, 8) : "";
|
|
15
|
+
const oauthSuffix = env.CLAUDE_CODE_OAUTH_CLIENT_ID?.trim() ? "-custom-oauth" : "";
|
|
16
|
+
const rawAccount = env.USER || safeUsername(deps.username);
|
|
17
|
+
const account = /^[a-zA-Z0-9._-]+$/.test(rawAccount) ? rawAccount : "claude-code-user";
|
|
18
|
+
return {
|
|
19
|
+
service: `${CLAUDE_KEYCHAIN_SERVICE_PREFIX}${oauthSuffix}-credentials${dirSuffix}`,
|
|
20
|
+
account,
|
|
21
|
+
configDir,
|
|
22
|
+
credentialsPath: join(configDir, ".credentials.json")
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function safeUsername(provider) {
|
|
26
|
+
try {
|
|
27
|
+
return provider ? provider() : userInfo().username;
|
|
28
|
+
} catch {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const CLAUDE_AUTH_PROBE_VERSION = 1;
|
|
34
|
+
const LOCAL_CREDENTIAL_SOURCE = "Claude local credentials";
|
|
35
|
+
function classifyAuthStatus(run, credentialSource) {
|
|
36
|
+
const localSource = credentialSource === void 0 || credentialSource === LOCAL_CREDENTIAL_SOURCE;
|
|
37
|
+
if (run.spawnError) {
|
|
38
|
+
return { status: "error", diagnosis: "probe-crash", detail: `could not run claude auth status: ${run.spawnError}` };
|
|
39
|
+
}
|
|
40
|
+
if (run.timedOut) {
|
|
41
|
+
return { status: "error", diagnosis: "probe-timeout", detail: "claude auth status did not answer within the timeout" };
|
|
42
|
+
}
|
|
43
|
+
const parsed = parseJsonObject(run.stdout);
|
|
44
|
+
if (!parsed) {
|
|
45
|
+
if (!localSource) return { status: "unknown", authMethod: credentialSource, detail: `auth status unparseable under ${credentialSource}` };
|
|
46
|
+
return { status: "error", diagnosis: "probe-crash", detail: `claude auth status returned no JSON (exit ${run.exitCode ?? "null"})` };
|
|
47
|
+
}
|
|
48
|
+
const authMethod = typeof parsed.authMethod === "string" ? parsed.authMethod : void 0;
|
|
49
|
+
const subscriptionType = typeof parsed.subscriptionType === "string" ? parsed.subscriptionType : void 0;
|
|
50
|
+
if (parsed.loggedIn === true) {
|
|
51
|
+
return { status: "ok", authMethod: localSource ? authMethod : credentialSource, subscriptionType };
|
|
52
|
+
}
|
|
53
|
+
if (!localSource) {
|
|
54
|
+
return { status: "unknown", authMethod: credentialSource, detail: `Claude Code reports loggedIn=false under ${credentialSource}; not a local-credential failure` };
|
|
55
|
+
}
|
|
56
|
+
return { status: "not-logged-in", authMethod, subscriptionType, detail: "Claude Code in the daemon context reports it is not logged in" };
|
|
57
|
+
}
|
|
58
|
+
function parseJsonObject(text) {
|
|
59
|
+
const trimmed = text.trim();
|
|
60
|
+
if (!trimmed) return null;
|
|
61
|
+
const start = trimmed.indexOf("{");
|
|
62
|
+
if (start < 0) return null;
|
|
63
|
+
try {
|
|
64
|
+
const value = JSON.parse(trimmed.slice(start));
|
|
65
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => createRequire(import.meta.url).resolve(s)) {
|
|
71
|
+
const platformArch = `${platform}-${arch}`;
|
|
72
|
+
const candidates = [
|
|
73
|
+
`@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
|
|
74
|
+
`@anthropic-ai/claude-agent-sdk-${platformArch}/claude.exe`
|
|
75
|
+
];
|
|
76
|
+
for (const candidate of candidates) {
|
|
77
|
+
try {
|
|
78
|
+
return resolver(candidate);
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function interpretSecurityRead(result) {
|
|
85
|
+
if (result.error === "ENOENT") return { kind: "unsupported" };
|
|
86
|
+
if (result.error === "timeout") return { kind: "error", detail: "security timed out" };
|
|
87
|
+
if (result.exitCode === 44) return { kind: "absent" };
|
|
88
|
+
if (result.exitCode === 36) return { kind: "unreadable" };
|
|
89
|
+
if (result.exitCode !== 0) return { kind: "error", detail: `security exited ${result.exitCode ?? "null"}` };
|
|
90
|
+
const raw = result.stdout.trim();
|
|
91
|
+
if (!raw) return { kind: "absent" };
|
|
92
|
+
const parsed = parseJsonObject(raw);
|
|
93
|
+
const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
|
|
94
|
+
if (!oauth) return { kind: "present", accessToken: "", refreshToken: "", raw };
|
|
95
|
+
return {
|
|
96
|
+
kind: "present",
|
|
97
|
+
accessToken: typeof oauth.accessToken === "string" ? oauth.accessToken : "",
|
|
98
|
+
refreshToken: typeof oauth.refreshToken === "string" ? oauth.refreshToken : "",
|
|
99
|
+
raw
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function interpretCredentialsFile(text) {
|
|
103
|
+
if (text === null) return { exists: false, hasTokens: false, refreshToken: "" };
|
|
104
|
+
const parsed = parseJsonObject(text);
|
|
105
|
+
const oauth = parsed && typeof parsed.claudeAiOauth === "object" && parsed.claudeAiOauth ? parsed.claudeAiOauth : null;
|
|
106
|
+
const access = oauth && typeof oauth.accessToken === "string" ? oauth.accessToken : "";
|
|
107
|
+
const refresh = oauth && typeof oauth.refreshToken === "string" ? oauth.refreshToken : "";
|
|
108
|
+
return { exists: true, hasTokens: access.length > 0 && refresh.length > 0, refreshToken: refresh };
|
|
109
|
+
}
|
|
110
|
+
function tokenTail(token) {
|
|
111
|
+
return token ? createHash("sha256").update(token).digest("hex").slice(-6) : "";
|
|
112
|
+
}
|
|
113
|
+
const CREDENTIALS_REJECTED_DETAIL = "Credentials exist but Claude Code rejects them in the daemon context \u2014 the refresh token has most likely been rotated away by another store or another machine using the same credentials. Log in again with `claude` on this machine.";
|
|
114
|
+
function diagnoseStores(input) {
|
|
115
|
+
const { status, keychain, file } = input;
|
|
116
|
+
if (keychain.kind === "present") {
|
|
117
|
+
const empty = keychain.accessToken.length === 0 && keychain.refreshToken.length === 0;
|
|
118
|
+
if (empty && file.hasTokens && status === "not-logged-in") {
|
|
119
|
+
return {
|
|
120
|
+
diagnosis: "keychain-empty-item",
|
|
121
|
+
repairable: "delete-empty-keychain-item",
|
|
122
|
+
keychainRaw: keychain.raw,
|
|
123
|
+
detail: "The login keychain holds a Claude Code credentials item with empty tokens; Claude Code prefers it over the valid ~/.claude/.credentials.json and reports not logged in."
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (!empty && file.hasTokens && tokenTail(keychain.refreshToken) !== tokenTail(file.refreshToken)) {
|
|
127
|
+
return {
|
|
128
|
+
diagnosis: "store-divergence",
|
|
129
|
+
detail: "Keychain and ~/.claude/.credentials.json hold different refresh tokens; one of them will stop working at its next refresh. Treat the daemon-context login as canonical, or pin credentialStore=file."
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {};
|
|
133
|
+
}
|
|
134
|
+
if ((keychain.kind === "absent" || keychain.kind === "unreadable" || keychain.kind === "unsupported") && !file.hasTokens) {
|
|
135
|
+
return { diagnosis: "no-credentials", detail: "No Claude Code credentials found for this daemon context; log in with `claude` on this machine." };
|
|
136
|
+
}
|
|
137
|
+
if (keychain.kind === "unreadable" && file.hasTokens && status === "not-logged-in") {
|
|
138
|
+
return { diagnosis: "credentials-rejected", detail: CREDENTIALS_REJECTED_DETAIL };
|
|
139
|
+
}
|
|
140
|
+
if (keychain.kind === "error") {
|
|
141
|
+
return { detail: `keychain check failed: ${keychain.detail}` };
|
|
142
|
+
}
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
function securityReadArgs(identity) {
|
|
146
|
+
return ["find-generic-password", "-s", identity.service, "-a", identity.account, "-w"];
|
|
147
|
+
}
|
|
148
|
+
function securityDeleteArgs(identity) {
|
|
149
|
+
return ["delete-generic-password", "-s", identity.service, "-a", identity.account];
|
|
150
|
+
}
|
|
151
|
+
const HAPPY_DAEMON_LAUNCHD_LABEL = "com.mereith.happy-daemon";
|
|
152
|
+
function classifyLineage(input) {
|
|
153
|
+
if (input.platform !== "darwin") return "other";
|
|
154
|
+
const label = input.label ?? HAPPY_DAEMON_LAUNCHD_LABEL;
|
|
155
|
+
if (input.env.XPC_SERVICE_NAME !== label) return "other";
|
|
156
|
+
if (input.launchdJobPid !== null && input.ancestorPids.includes(input.launchdJobPid)) return "launchd";
|
|
157
|
+
return "inherited-env";
|
|
158
|
+
}
|
|
159
|
+
function parseLaunchctlPid(printOutput) {
|
|
160
|
+
const match = /^\s*pid\s*=\s*(\d+)/m.exec(printOutput);
|
|
161
|
+
return match ? Number(match[1]) : null;
|
|
162
|
+
}
|
|
163
|
+
function keychainOffShimDir(happyLibDir) {
|
|
164
|
+
return join(happyLibDir, "scripts", "shims", "keychain-off");
|
|
165
|
+
}
|
|
166
|
+
function withKeychainOffPath(path, shimDir) {
|
|
167
|
+
const parts = (path ?? "").split(delimiter).filter((p) => p && p !== shimDir);
|
|
168
|
+
return [shimDir, ...parts].join(delimiter);
|
|
169
|
+
}
|
|
170
|
+
function buildClaudeAuthState(input) {
|
|
171
|
+
const { classification, diagnosis } = input;
|
|
172
|
+
const detail = (diagnosis?.detail ?? classification.detail)?.slice(0, 200);
|
|
173
|
+
const state = {
|
|
174
|
+
probeVersion: CLAUDE_AUTH_PROBE_VERSION,
|
|
175
|
+
daemonPid: input.daemonPid,
|
|
176
|
+
status: classification.status,
|
|
177
|
+
context: { platform: input.platform, lineage: input.lineage, credentialStore: input.credentialStore },
|
|
178
|
+
checkedAt: input.now ?? Date.now()
|
|
179
|
+
};
|
|
180
|
+
if (classification.authMethod) state.authMethod = classification.authMethod;
|
|
181
|
+
if (classification.subscriptionType) state.subscriptionType = classification.subscriptionType;
|
|
182
|
+
const diag = diagnosis?.diagnosis ?? classification.diagnosis;
|
|
183
|
+
if (diag) state.diagnosis = diag;
|
|
184
|
+
if (detail) state.detail = detail;
|
|
185
|
+
if (diagnosis?.repairable) state.repairable = diagnosis.repairable;
|
|
186
|
+
return state;
|
|
187
|
+
}
|
|
188
|
+
function claudeAuthStateChanged(prev, next) {
|
|
189
|
+
if (!prev) return true;
|
|
190
|
+
const strip = ({ checkedAt: _c, ...rest }) => JSON.stringify(rest);
|
|
191
|
+
return strip(prev) !== strip(next);
|
|
192
|
+
}
|
|
193
|
+
function keychainIdentityFor(env) {
|
|
194
|
+
return keychainIdentity(env);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function detectDaemonSupervisor(env, platform = process.platform, launchd = null) {
|
|
198
|
+
const explicit = env.HAPPY_DAEMON_SUPERVISOR?.trim().toLowerCase();
|
|
199
|
+
if (explicit === "systemd") return "systemd";
|
|
200
|
+
if (explicit === "none") return "none";
|
|
201
|
+
if (platform === "linux" && typeof env.INVOCATION_ID === "string" && env.INVOCATION_ID.trim() !== "") return "systemd";
|
|
202
|
+
if (platform === "darwin" && launchd && classifyLineage({ platform, env, launchdJobPid: launchd.jobPid, ancestorPids: launchd.ancestorPids }) === "launchd") return "launchd";
|
|
203
|
+
return "none";
|
|
204
|
+
}
|
|
205
|
+
function daemonLineage(supervisor, env, platform = process.platform, launchd = null) {
|
|
206
|
+
if (supervisor !== "none") return supervisor;
|
|
207
|
+
return classifyLineage({ platform, env, launchdJobPid: launchd?.jobPid ?? null, ancestorPids: launchd?.ancestorPids ?? [] });
|
|
208
|
+
}
|
|
209
|
+
function execText(file, args) {
|
|
210
|
+
return new Promise((resolve) => {
|
|
211
|
+
execFile(file, args, { timeout: LAUNCHD_PROBE_TIMEOUT_MS, maxBuffer: 1024 * 1024 }, (error, stdout) => resolve(error ? "" : String(stdout ?? "")));
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const LAUNCHD_PROBE_TIMEOUT_MS = 3e3;
|
|
215
|
+
async function probeLaunchdJob(exec = execText) {
|
|
216
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
217
|
+
const jobPid = uid === null ? null : parseLaunchctlPid(await exec("launchctl", ["print", `gui/${uid}/${HAPPY_DAEMON_LAUNCHD_LABEL}`]));
|
|
218
|
+
const ancestorPids = [process.pid];
|
|
219
|
+
let pid = process.ppid;
|
|
220
|
+
for (let i = 0; i < 10 && pid > 1; i++) {
|
|
221
|
+
ancestorPids.push(pid);
|
|
222
|
+
const ppid = Number((await exec("ps", ["-o", "ppid=", "-p", String(pid)])).trim());
|
|
223
|
+
if (!Number.isFinite(ppid) || ppid <= 0 || ppid === pid) break;
|
|
224
|
+
pid = ppid;
|
|
225
|
+
}
|
|
226
|
+
return { jobPid, ancestorPids };
|
|
227
|
+
}
|
|
228
|
+
const SYSTEMD_RESTART_HINT = "systemctl --user restart very-happy-daemon";
|
|
229
|
+
async function kickstartLaunchdJob(run = (file, args) => spawnSync(file, args, { encoding: "utf8", timeout: LAUNCHD_PROBE_TIMEOUT_MS }), uid = typeof process.getuid === "function" ? process.getuid() : null, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
230
|
+
if (uid === null) return false;
|
|
231
|
+
const target = `gui/${uid}/${HAPPY_DAEMON_LAUNCHD_LABEL}`;
|
|
232
|
+
try {
|
|
233
|
+
for (let i = 0; i < 50; i++) {
|
|
234
|
+
const printed = run("launchctl", ["print", target]);
|
|
235
|
+
if (printed.status !== 0) return false;
|
|
236
|
+
if (parseLaunchctlPid(printed.stdout ?? "") === null) break;
|
|
237
|
+
await sleep(100);
|
|
238
|
+
}
|
|
239
|
+
return run("launchctl", ["kickstart", target]).status === 0;
|
|
240
|
+
} catch {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export { CREDENTIALS_REJECTED_DETAIL as C, HAPPY_DAEMON_LAUNCHD_LABEL as H, SYSTEMD_RESTART_HINT as S, keychainIdentityFor as a, securityDeleteArgs as b, keychainOffShimDir as c, interpretCredentialsFile as d, buildClaudeAuthState as e, claudeAuthStateChanged as f, classifyAuthStatus as g, diagnoseStores as h, interpretSecurityRead as i, classifyLineage as j, kickstartLaunchdJob as k, probeLaunchdJob as l, detectDaemonSupervisor as m, daemonLineage as n, parseLaunchctlPid as p, resolveSdkClaudeBinary as r, securityReadArgs as s, withKeychainOffPath as w };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var logger = require('./logger-
|
|
4
|
-
var persistence = require('./persistence-
|
|
3
|
+
var logger = require('./logger-Cgwz30rK.cjs');
|
|
4
|
+
var persistence = require('./persistence-DZRMUZZS.cjs');
|
|
5
5
|
|
|
6
6
|
const PRESENCE_SETTLE_MS = 6e3;
|
|
7
7
|
async function commitHibernation(deps) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as logger } from './logger-
|
|
2
|
-
import { e as evaluateWrapperIdle, j as HIBERNATION_UNSUPPORTED_BACKOFF_MS } from './persistence-
|
|
1
|
+
import { l as logger } from './logger-RMPh5aqe.mjs';
|
|
2
|
+
import { e as evaluateWrapperIdle, j as HIBERNATION_UNSUPPORTED_BACKOFF_MS } from './persistence-zJo4r7YI.mjs';
|
|
3
3
|
|
|
4
4
|
const PRESENCE_SETTLE_MS = 6e3;
|
|
5
5
|
async function commitHibernation(deps) {
|