very-happy-cli 0.2.159 → 0.2.160

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 (258) hide show
  1. package/dist/{AcpBackend-DUYFlyfN.cjs → AcpBackend-Bm2rdke8.cjs} +78 -76
  2. package/dist/{AcpBackend-VsfkZiVF.mjs → AcpBackend-mzv8Dhba.mjs} +4 -2
  3. package/dist/{AcpSessionManager-Bdv8LWXh.cjs → AcpSessionManager-BAY1Pggx.cjs} +9 -9
  4. package/dist/{AcpSessionManager-rYtVb0kN.mjs → AcpSessionManager-CoMWFVw3.mjs} +1 -1
  5. package/dist/BasePermissionHandler-CFHAxumV.cjs +157 -0
  6. package/dist/BasePermissionHandler-m3WVholL.mjs +155 -0
  7. package/dist/BaseReasoningProcessor-BFa9_rZA.cjs +200 -0
  8. package/dist/BaseReasoningProcessor-CYrKBXGm.mjs +198 -0
  9. package/dist/RemoteModeDisplay-D-HewyXg.mjs +150 -0
  10. package/dist/RemoteModeDisplay-NC1gPHtj.cjs +153 -0
  11. package/dist/agentAttachments-Dbw8iMCZ.cjs +20 -0
  12. package/dist/agentAttachments-M_B5qEF2.mjs +18 -0
  13. package/dist/agentGuidance-B5NATuFa.cjs +28 -0
  14. package/dist/agentGuidance-CQuNlNx8.mjs +20 -0
  15. package/dist/{agentHome-CHh4lmjM.cjs → agentHome-CboCeKWq.cjs} +14 -28
  16. package/dist/{agentHome-CvsJyeQB.mjs → agentHome-Dj1C43aJ.mjs} +8 -22
  17. package/dist/api-CLMUr-SX.mjs +3339 -0
  18. package/dist/api-CgundNNX.cjs +3346 -0
  19. package/dist/{types-Dh-s4Lqs.mjs → apiMachine-B9dLW_p5.mjs} +9116 -16205
  20. package/dist/{types-BbvK1Tr_.cjs → apiMachine-Bn8482VM.cjs} +9104 -16247
  21. package/dist/assistantTools-BTqPnlFl.cjs +380 -0
  22. package/dist/assistantTools-D6tuc6o4.mjs +376 -0
  23. package/dist/attachmentContent-DpiTJZb4.cjs +88 -0
  24. package/dist/attachmentContent-_kxRznNf.mjs +82 -0
  25. package/dist/attachmentLimits-CzVrqgLR.cjs +354 -0
  26. package/dist/attachmentLimits-yba1uHFO.mjs +348 -0
  27. package/dist/auth-BDOVh5h5.cjs +220 -0
  28. package/dist/auth-Cwutmdsa.mjs +225 -0
  29. package/dist/auth-PYHZQNPp.mjs +218 -0
  30. package/dist/auth-ba4WMYrN.cjs +227 -0
  31. package/dist/authRelay-BdYkC1Po.cjs +156 -0
  32. package/dist/authRelay-DSAvg1uv.mjs +143 -0
  33. package/dist/{auto-DKmEls8Z.cjs → auto-BOX_fgmR.cjs} +70 -79
  34. package/dist/{auto-nb8GhRRy.mjs → auto-BXu14yP_.mjs} +27 -36
  35. package/dist/backgroundTaskActivity-8PdPxrvy.mjs +149 -0
  36. package/dist/backgroundTaskActivity-CBvUdj39.cjs +157 -0
  37. package/dist/bootstrap-B5G1TijC.cjs +116 -0
  38. package/dist/bootstrap-hxXPCFMx.mjs +112 -0
  39. package/dist/browser-Y6Bl8L_O.cjs +22 -0
  40. package/dist/browser-jh2P0UVZ.mjs +20 -0
  41. package/dist/claudeCliPath-BqkaH2oR.mjs +8 -0
  42. package/dist/claudeCliPath-U4HHmV4r.cjs +10 -0
  43. package/dist/claudeLocal-BaY4fZKi.mjs +339 -0
  44. package/dist/claudeLocal-CRGG4Pea.cjs +343 -0
  45. package/dist/claudeLocalLauncher-D4T7MTqd.mjs +152 -0
  46. package/dist/claudeLocalLauncher-DyEbVzUN.cjs +154 -0
  47. package/dist/cliUpdate-DsKXPFYp.cjs +120 -0
  48. package/dist/cliUpdate-Y34VGe9Y.mjs +112 -0
  49. package/dist/client-3Ac-O4pw.cjs +104 -0
  50. package/dist/client-BPNbmtvO.cjs +119 -0
  51. package/dist/client-CeGKqqcJ.mjs +100 -0
  52. package/dist/client-ClR0K8zX.mjs +112 -0
  53. package/dist/codex/happyMcpStdioBridge.cjs +33 -14
  54. package/dist/codex/happyMcpStdioBridge.mjs +26 -7
  55. package/dist/codexAppServerClient-I3teiV-N.mjs +1088 -0
  56. package/dist/codexAppServerClient-q2FjnRcK.cjs +1090 -0
  57. package/dist/codexCommand-4zcccIoq.cjs +2088 -0
  58. package/dist/codexCommand-Cc9gcbdX.mjs +2086 -0
  59. package/dist/codexThreadFork-BH9IZPqD.cjs +350 -0
  60. package/dist/codexThreadFork-slzAseLx.mjs +338 -0
  61. package/dist/{config-ClLtM6F3.mjs → config-CTx_jb-C.mjs} +7 -40
  62. package/dist/{config-DLx-vW3I.cjs → config-Ci9Kpgwa.cjs} +26 -59
  63. package/dist/configuration-BSYpcPwE.cjs +181 -0
  64. package/dist/configuration-RfeNjFmd.mjs +170 -0
  65. package/dist/connect-BpOdzNbE.mjs +682 -0
  66. package/dist/connect-C2CiOUFs.cjs +684 -0
  67. package/dist/constants-BC4St0xd.mjs +11 -0
  68. package/dist/constants-VJ0N6WuG.cjs +17 -0
  69. package/dist/contentLogMetadata-BlWI0egu.mjs +51 -0
  70. package/dist/contentLogMetadata-ZSFk_NjQ.cjs +54 -0
  71. package/dist/context-DsDr6E2t.cjs +69 -0
  72. package/dist/context-H0Bcb9S_.mjs +65 -0
  73. package/dist/controlClient-BGbDcgWS.mjs +260 -0
  74. package/dist/controlClient-Bcwv3D21.cjs +279 -0
  75. package/dist/createSessionMetadata-BJxEnM-o.cjs +58 -0
  76. package/dist/createSessionMetadata-CVVkGjxV.mjs +54 -0
  77. package/dist/defaultPermissionMode-BnxJPVHT.mjs +4 -0
  78. package/dist/defaultPermissionMode-CxmTXUQR.cjs +7 -0
  79. package/dist/detectCLI-CSGMlV51.mjs +58 -0
  80. package/dist/detectCLI-DR9ZaN6B.cjs +61 -0
  81. package/dist/deterministicJson-C5CYTVpm.cjs +507 -0
  82. package/dist/deterministicJson-CzkFJWw1.mjs +502 -0
  83. package/dist/doctor-BPkYWSuq.mjs +75 -0
  84. package/dist/doctor-D2YJ-Yn2.cjs +395 -0
  85. package/dist/doctor-DOvByjbk.mjs +391 -0
  86. package/dist/doctor-u46qYYKX.cjs +79 -0
  87. package/dist/doctorReadiness-BCZGcN0a.cjs +151 -0
  88. package/dist/doctorReadiness-C208SMN9.mjs +142 -0
  89. package/dist/editPaths-BVfS_FFL.mjs +68 -0
  90. package/dist/editPaths-Bqp4OFPw.cjs +73 -0
  91. package/dist/ensureDaemonRunning-BCwNrMyv.cjs +64 -0
  92. package/dist/ensureDaemonRunning-Dqa2pOjY.mjs +61 -0
  93. package/dist/handleResumeCommand-BvXYf5El.mjs +240 -0
  94. package/dist/handleResumeCommand-C2cKchpX.cjs +245 -0
  95. package/dist/ids-B6ZC0HGt.cjs +13 -0
  96. package/dist/ids-DU6sLx4C.mjs +10 -0
  97. package/dist/index-B6UGRQ7h.mjs +102 -0
  98. package/dist/{index-BEOMECtE.cjs → index-B6pAdvJx.cjs} +121 -91
  99. package/dist/index-Bu5Zi_a9.cjs +182 -0
  100. package/dist/index-D3kI0hDR.cjs +107 -0
  101. package/dist/index-DA7yINuk.cjs +994 -0
  102. package/dist/index-DDeHXrIX.cjs +71 -0
  103. package/dist/index-DKLU_fD0.mjs +158 -0
  104. package/dist/{index-2mCaeKyf.mjs → index-DMZqWwsP.mjs} +68 -38
  105. package/dist/index-DVkMGPyS.mjs +68 -0
  106. package/dist/index-qdS1friN.mjs +949 -0
  107. package/dist/index.cjs +5 -46
  108. package/dist/index.mjs +5 -46
  109. package/dist/{install-BPhJppvd.mjs → install-BO_W7VhL.mjs} +37 -37
  110. package/dist/install-BgoC2e_2.cjs +88 -0
  111. package/dist/install-CFY3tYtJ.mjs +86 -0
  112. package/dist/{install-BOHrUaFM.cjs → install-Cs5qAPrB.cjs} +38 -38
  113. package/dist/{installPiTools-DuZ6jZvX.cjs → installPiTools-BKnXjrVu.cjs} +2 -3
  114. package/dist/{installPiTools-Cj7yU9Fc.mjs → installPiTools-B_CdM5_2.mjs} +1 -2
  115. package/dist/{installTerminalHooks-Cou3WUf3.cjs → installTerminalHooks-BQZbvxsZ.cjs} +5 -40
  116. package/dist/{installTerminalHooks-WeznjkuC.mjs → installTerminalHooks-By7gBMEF.mjs} +3 -38
  117. package/dist/lib.cjs +28 -19
  118. package/dist/lib.d.cts +12 -2
  119. package/dist/lib.d.mts +12 -2
  120. package/dist/lib.mjs +23 -14
  121. package/dist/lidState-BeDfxxEX.cjs +305 -0
  122. package/dist/lidState-CeEt442o.mjs +297 -0
  123. package/dist/limits-C-a7gr04.cjs +43 -0
  124. package/dist/limits-DIo7rEBR.mjs +36 -0
  125. package/dist/localHappyAgentAuth-C-HQyiv6.mjs +82 -0
  126. package/dist/localHappyAgentAuth-D6rFhaoc.cjs +86 -0
  127. package/dist/logger-6HYUEXNk.mjs +271 -0
  128. package/dist/logger-CS0mw3fa.cjs +275 -0
  129. package/dist/loginShellEnv-BkuYtExZ.cjs +182 -0
  130. package/dist/loginShellEnv-Dw8M7tkI.mjs +167 -0
  131. package/dist/machineMetadata-DyDbODYd.cjs +41 -0
  132. package/dist/machineMetadata-oOzBfDfs.mjs +38 -0
  133. package/dist/main-BkxJP6JQ.cjs +941 -0
  134. package/dist/main-BwNIAI1A.mjs +939 -0
  135. package/dist/manager-BQ4flvQZ.mjs +101 -0
  136. package/dist/manager-Cly8xVIR.cjs +105 -0
  137. package/dist/{mcp-Dy3f_K0h.mjs → mcp-B1A4I3TK.mjs} +27 -33
  138. package/dist/{mcp-CPYbtsYG.cjs → mcp-Hszd7qpS.cjs} +42 -48
  139. package/dist/messageBuffer-BWlGgR3A.mjs +71 -0
  140. package/dist/messageBuffer-fJMH6uY8.cjs +73 -0
  141. package/dist/mirrorProtocol-BNLtoWjO.mjs +170 -0
  142. package/dist/mirrorProtocol-BUtmg1ws.cjs +186 -0
  143. package/dist/oneShotPrompts-CL0dip9C.cjs +16 -0
  144. package/dist/oneShotPrompts-DT4p6RNd.mjs +12 -0
  145. package/dist/package-BhaKlnxz.mjs +171 -0
  146. package/dist/package-BwMrPwqH.cjs +173 -0
  147. package/dist/path-B7zW-WwE.cjs +18 -0
  148. package/dist/path-D2wdaNSk.mjs +15 -0
  149. package/dist/peerTools-BTqw97Gb.mjs +272 -0
  150. package/dist/peerTools-BvKtHXj8.cjs +283 -0
  151. package/dist/permissionMode-Cr5JCbB7.mjs +80 -0
  152. package/dist/permissionMode-CrV-XuMs.cjs +87 -0
  153. package/dist/persistence-HGW_ZVs9.mjs +372 -0
  154. package/dist/persistence-yKTH3-5X.cjs +414 -0
  155. package/dist/piExtension.mjs +2 -1
  156. package/dist/piRunnerArgs-BNloJCCg.cjs +66 -0
  157. package/dist/piRunnerArgs-BuX1UFWy.mjs +59 -0
  158. package/dist/{piRuntime-kLZNpAAl.mjs → piRuntime-CSGkwCKQ.mjs} +2 -2
  159. package/dist/{piRuntime-NtF0YqjH.cjs → piRuntime-C_H7MJCM.cjs} +4 -4
  160. package/dist/{piTerminal-B0fEOV_2.mjs → piTerminal-C8a1OrNQ.mjs} +32 -35
  161. package/dist/{piTerminal-9J0GAKzb.cjs → piTerminal-DNCZ6yTM.cjs} +32 -35
  162. package/dist/previewPath-B0rBdhy1.cjs +83 -0
  163. package/dist/previewPath-CXN4Vag0.mjs +81 -0
  164. package/dist/projectPath-BTBIMB57.mjs +10 -0
  165. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  166. package/dist/registerCommonHandlers-Ccvsz7Ou.mjs +536 -0
  167. package/dist/registerCommonHandlers-DskirN-_.cjs +538 -0
  168. package/dist/registerKillSessionHandler-DZeLXWcB.cjs +361 -0
  169. package/dist/registerKillSessionHandler-GYvHdipX.mjs +358 -0
  170. package/dist/remoteSessionClient-B0LraSB9.cjs +634 -0
  171. package/dist/remoteSessionClient-CYnXRynE.mjs +612 -0
  172. package/dist/resources-BdFBQi8r.mjs +117 -0
  173. package/dist/resources-JDPugcDq.cjs +120 -0
  174. package/dist/run-CJzxoHVh.cjs +5762 -0
  175. package/dist/run-D3ifupU3.mjs +5739 -0
  176. package/dist/runClaude-Ba01qT-u.mjs +848 -0
  177. package/dist/runClaude-Da3RirzE.cjs +850 -0
  178. package/dist/runClaudeDeps-DOt79DjU.mjs +3624 -0
  179. package/dist/runClaudeDeps-DOzEBMls.cjs +3649 -0
  180. package/dist/{runGemini-DV6Ouadt.mjs → runGemini-BGeTz57m.mjs} +58 -31
  181. package/dist/{runGemini-F-mqx3_K.cjs → runGemini-DSr9LIxL.cjs} +202 -175
  182. package/dist/{runOpenClaw-Qqo9j63M.cjs → runOpenClaw-B1mTxN35.cjs} +64 -65
  183. package/dist/{runOpenClaw-D7MlPS5n.mjs → runOpenClaw-CogSedIc.mjs} +31 -32
  184. package/dist/sandbox-CG7IyDTU.cjs +187 -0
  185. package/dist/sandbox-DTe6d54R.mjs +180 -0
  186. package/dist/selfCheck-C9mVrQwf.mjs +84 -0
  187. package/dist/selfCheck-Dc-mNSLb.cjs +87 -0
  188. package/dist/{send-4qJTCAYW.cjs → send-B7J_eaG3.cjs} +16 -9
  189. package/dist/{send-CLhYXNgy.mjs → send-CBXJKc6O.mjs} +12 -5
  190. package/dist/server-CZTP_iOn.cjs +407 -0
  191. package/dist/server-DcVBv04l.mjs +404 -0
  192. package/dist/sessionLock-Bys1PNSo.cjs +205 -0
  193. package/dist/sessionLock-D-EG2CfG.mjs +197 -0
  194. package/dist/sessionModeFile-DMl3dw3r.mjs +32 -0
  195. package/dist/sessionModeFile-RSm0NQkH.cjs +36 -0
  196. package/dist/sessionOps-Dn8z85h_.cjs +783 -0
  197. package/dist/sessionOps-SuHW8Dfe.mjs +760 -0
  198. package/dist/sessionScanner-BOrGjMXL.cjs +209 -0
  199. package/dist/sessionScanner-CX3onqXh.mjs +206 -0
  200. package/dist/{sessions-CzIH2rGp.mjs → sessions-BEG_HTSi.mjs} +17 -8
  201. package/dist/{sessions-Bh1pyddi.cjs → sessions-D74aJbhL.cjs} +37 -28
  202. package/dist/setupOfflineReconnection-ByElY60m.cjs +74 -0
  203. package/dist/setupOfflineReconnection-DpvWTt69.mjs +72 -0
  204. package/dist/smallFastModel-BLNgMrwR.mjs +18 -0
  205. package/dist/smallFastModel-D_uxGMo3.cjs +21 -0
  206. package/dist/{spawn-CPIWlPOM.mjs → spawn-B7yro0b2.mjs} +26 -38
  207. package/dist/{spawn-CmFOSVdW.cjs → spawn-DgR0RKRs.cjs} +52 -64
  208. package/dist/spawnAgents-BGQiEF-w.cjs +52 -0
  209. package/dist/spawnAgents-DZzZ9jMI.mjs +45 -0
  210. package/dist/spawnHappyCLI-B2H5s4B_.mjs +64 -0
  211. package/dist/spawnHappyCLI-DBhwZT7O.cjs +66 -0
  212. package/dist/specialCommands-BSqhYg5X.mjs +52 -0
  213. package/dist/specialCommands-DSsTeRej.cjs +54 -0
  214. package/dist/startFileWatcher-B4VsLgjD.cjs +71 -0
  215. package/dist/startFileWatcher-DErVWZE4.mjs +69 -0
  216. package/dist/startupPlan-BLMbfQIH.cjs +12 -0
  217. package/dist/startupPlan-DFMyNgAs.mjs +10 -0
  218. package/dist/streamRelay-BiKw59Cc.cjs +233 -0
  219. package/dist/streamRelay-FPVbHpbM.mjs +231 -0
  220. package/dist/sync-C8gyQFMc.mjs +69 -0
  221. package/dist/sync-DccIKZ5_.cjs +71 -0
  222. package/dist/systemPrompt-BwTPWfMu.cjs +97 -0
  223. package/dist/systemPrompt-DX521JJz.mjs +94 -0
  224. package/dist/{teams-CEahj4cm.mjs → teams-C32F1hqd.mjs} +9 -40
  225. package/dist/{teams-CB1R9-Z9.cjs → teams-Dl8g8kTI.cjs} +14 -45
  226. package/dist/template-BaHAmH2K.cjs +129 -0
  227. package/dist/template-CiOPa2rd.mjs +121 -0
  228. package/dist/{terminalTitleSuggest-DKgX3osW.mjs → terminalTitleSuggest-CeKsX_V6.mjs} +1 -9
  229. package/dist/{terminalTitleSuggest-Dji8I0Jy.cjs → terminalTitleSuggest-DhvRFX3H.cjs} +0 -10
  230. package/dist/terminals-B_bfC9c2.cjs +250 -0
  231. package/dist/terminals-Dlg0x3nY.mjs +235 -0
  232. package/dist/time-D0XyHOid.mjs +38 -0
  233. package/dist/time-DCuTyook.cjs +42 -0
  234. package/dist/titleGenerator-CQ8CoGhg.mjs +166 -0
  235. package/dist/titleGenerator-ChzMJsyg.cjs +172 -0
  236. package/dist/tmuxSocket-B8Yx20sT.mjs +19 -0
  237. package/dist/tmuxSocket-D-Xt6Vn-.cjs +24 -0
  238. package/dist/{todo-DqyRI4wP.cjs → todo-BvUOTa8G.cjs} +15 -12
  239. package/dist/{todo-Cknp5D4U.mjs → todo-CZ6cFrrn.mjs} +11 -8
  240. package/dist/tools-BZtHF_qQ.mjs +177 -0
  241. package/dist/tools-Be3AoAwu.cjs +63 -0
  242. package/dist/tools-DQj0AeLk.cjs +180 -0
  243. package/dist/tools-DkluDcG4.mjs +60 -0
  244. package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
  245. package/dist/trimIdent-BAjmv_TG.mjs +20 -0
  246. package/dist/types-CRS-srZK.cjs +66 -0
  247. package/dist/types-CkqAACXx.mjs +64 -0
  248. package/dist/uninstall-BkLzaJ6I.mjs +47 -0
  249. package/dist/uninstall-x-TUtf5H.cjs +49 -0
  250. package/package.json +7 -7
  251. package/dist/agentGuidance-BRDN1NoZ.cjs +0 -2217
  252. package/dist/agentGuidance-KgvYuF3R.mjs +0 -2145
  253. package/dist/index-BF6WfgV5.mjs +0 -19624
  254. package/dist/index-C-JazrMB.mjs +0 -52
  255. package/dist/index-blDSadUR.cjs +0 -58
  256. package/dist/index-rH3DrQ5B.cjs +0 -19688
  257. package/dist/limits-BH5CV5vR.cjs +0 -2683
  258. package/dist/limits-CjRj8IX5.mjs +0 -2558
@@ -0,0 +1,227 @@
1
+ 'use strict';
2
+
3
+ var authRelay = require('./authRelay-BdYkC1Po.cjs');
4
+ var configuration = require('./configuration-BSYpcPwE.cjs');
5
+ var node_crypto = require('node:crypto');
6
+ var tweetnacl = require('tweetnacl');
7
+ var axios = require('axios');
8
+ var time = require('./time-DCuTyook.cjs');
9
+ var persistence = require('./persistence-yKTH3-5X.cjs');
10
+ var browser = require('./browser-Y6Bl8L_O.cjs');
11
+ var logger = require('./logger-CS0mw3fa.cjs');
12
+
13
+ function generateWebAuthUrl(publicKey) {
14
+ const publicKeyBase64 = authRelay.encodeBase64(publicKey, "base64url");
15
+ return `${configuration.configuration.webappUrl}/terminal/connect#key=${publicKeyBase64}`;
16
+ }
17
+
18
+ function decideMachineId(input) {
19
+ const { read, newAuth } = input;
20
+ if (read.kind === "unreadable") {
21
+ return {
22
+ action: "refuse",
23
+ reason: `settings exist but could not be read (${read.error}); refusing to mint a new machine id \u2014 fix or remove the settings file, or run \`very-happy auth login --force\` to deliberately re-register this machine`
24
+ };
25
+ }
26
+ if (newAuth) return { action: "mint", reason: "new-auth" };
27
+ if (read.kind === "absent") return { action: "mint", reason: "no-settings-file" };
28
+ const existing = read.settings.machineId;
29
+ if (typeof existing === "string" && existing.length > 0) {
30
+ return { action: "reuse", machineId: existing };
31
+ }
32
+ return { action: "mint", reason: "no-machine-id" };
33
+ }
34
+
35
+ async function doAuth() {
36
+ console.clear();
37
+ const secret = new Uint8Array(node_crypto.randomBytes(32));
38
+ const keypair = tweetnacl.box.keyPair.fromSecretKey(secret);
39
+ const claimSecret = authRelay.encodeBase64Url(node_crypto.randomBytes(32));
40
+ try {
41
+ if (process.env.DEBUG) {
42
+ console.log(`[AUTH DEBUG] Sending auth request to: ${configuration.configuration.serverUrl}/v1/auth/request`);
43
+ }
44
+ const createResponse = await axios.post(`${configuration.configuration.serverUrl}/v1/auth/request`, {
45
+ publicKey: authRelay.encodeBase64(keypair.publicKey),
46
+ supportsV2: true,
47
+ supportsClaimSecret: true,
48
+ claimSecret,
49
+ pairingAction: "create"
50
+ }, {
51
+ headers: {
52
+ "X-Happy-Client": `cli/${configuration.configuration.currentCliVersion}`
53
+ }
54
+ });
55
+ if (createResponse.data?.protocolVersion !== 3 || createResponse.data?.claimSecretRequired !== true) {
56
+ console.log("This server does not support secure CLI pairing. Upgrade the server before signing in.");
57
+ return null;
58
+ }
59
+ if (process.env.DEBUG) {
60
+ console.log(`[AUTH DEBUG] Auth request sent successfully`);
61
+ }
62
+ } catch {
63
+ if (process.env.DEBUG) {
64
+ console.log("[AUTH DEBUG] Failed to send secure auth request");
65
+ }
66
+ console.log("Failed to create authentication request, please try again later.");
67
+ return null;
68
+ }
69
+ return await doWebAuth(keypair, claimSecret);
70
+ }
71
+ async function doWebAuth(keypair, claimSecret) {
72
+ console.clear();
73
+ console.log("\nWeb Authentication\n");
74
+ const webUrl = generateWebAuthUrl(keypair.publicKey);
75
+ console.log("Opening your browser...");
76
+ const browserOpened = await browser.openBrowser(webUrl);
77
+ if (browserOpened) {
78
+ console.log("\u2713 Browser opened\n");
79
+ console.log("Complete authentication in your browser window.");
80
+ } else {
81
+ console.log("Could not open browser automatically.");
82
+ }
83
+ console.log("\nIf the browser did not open, please copy and paste this URL:");
84
+ console.log(webUrl);
85
+ console.log("");
86
+ return await waitForAuthentication(keypair, claimSecret);
87
+ }
88
+ async function waitForAuthentication(keypair, claimSecret) {
89
+ process.stdout.write("Waiting for authentication");
90
+ let dots = 0;
91
+ let cancelled = false;
92
+ const handleInterrupt = () => {
93
+ cancelled = true;
94
+ console.log("\n\nAuthentication cancelled.");
95
+ process.exit(0);
96
+ };
97
+ process.on("SIGINT", handleInterrupt);
98
+ try {
99
+ while (!cancelled) {
100
+ try {
101
+ const response = await axios.post(`${configuration.configuration.serverUrl}/v1/auth/request`, {
102
+ publicKey: authRelay.encodeBase64(keypair.publicKey),
103
+ supportsV2: true,
104
+ supportsClaimSecret: true,
105
+ claimSecret,
106
+ pairingAction: "poll"
107
+ }, {
108
+ headers: {
109
+ "X-Happy-Client": `cli/${configuration.configuration.currentCliVersion}`
110
+ }
111
+ });
112
+ if (response.data?.protocolVersion !== 3 || response.data?.claimSecretRequired !== true) {
113
+ console.log("\n\nThis server does not support secure CLI pairing. Upgrade the server before signing in.");
114
+ return null;
115
+ }
116
+ if (response.data.state === "authorized") {
117
+ let token = response.data.token;
118
+ let r = authRelay.decodeBase64(response.data.response);
119
+ let decrypted = decryptWithEphemeralKey(r, keypair.secretKey);
120
+ if (decrypted) {
121
+ if (decrypted.length === 32) {
122
+ const credentials = {
123
+ secret: decrypted,
124
+ token
125
+ };
126
+ await persistence.writeCredentialsLegacy(credentials);
127
+ console.log("\n\n\u2713 Authentication successful\n");
128
+ return {
129
+ encryption: {
130
+ type: "legacy",
131
+ secret: decrypted
132
+ },
133
+ token
134
+ };
135
+ } else {
136
+ if (decrypted[0] === 0) {
137
+ const credentials = {
138
+ publicKey: decrypted.slice(1, 33),
139
+ machineKey: node_crypto.randomBytes(32),
140
+ token
141
+ };
142
+ await persistence.writeCredentialsDataKey(credentials);
143
+ console.log("\n\n\u2713 Authentication successful\n");
144
+ return {
145
+ encryption: {
146
+ type: "dataKey",
147
+ publicKey: credentials.publicKey,
148
+ machineKey: credentials.machineKey
149
+ },
150
+ token
151
+ };
152
+ } else {
153
+ console.log("\n\nFailed to decrypt response. Please try again.");
154
+ return null;
155
+ }
156
+ }
157
+ } else {
158
+ console.log("\n\nFailed to decrypt response. Please try again.");
159
+ return null;
160
+ }
161
+ }
162
+ } catch (error) {
163
+ console.log("\n\nFailed to check authentication status. Please try again.");
164
+ return null;
165
+ }
166
+ process.stdout.write("\rWaiting for authentication" + ".".repeat(dots % 3 + 1) + " ");
167
+ dots++;
168
+ await time.delay(1e3);
169
+ }
170
+ } finally {
171
+ process.off("SIGINT", handleInterrupt);
172
+ }
173
+ return null;
174
+ }
175
+ function decryptWithEphemeralKey(encryptedBundle, recipientSecretKey) {
176
+ const ephemeralPublicKey = encryptedBundle.slice(0, 32);
177
+ const nonce = encryptedBundle.slice(32, 32 + tweetnacl.box.nonceLength);
178
+ const encrypted = encryptedBundle.slice(32 + tweetnacl.box.nonceLength);
179
+ const decrypted = tweetnacl.box.open(encrypted, nonce, ephemeralPublicKey, recipientSecretKey);
180
+ if (!decrypted) {
181
+ return null;
182
+ }
183
+ return decrypted;
184
+ }
185
+ async function authAndSetupMachineIfNeeded() {
186
+ logger.logger.debug("[AUTH] Starting auth and machine setup...");
187
+ let credentials = await persistence.readCredentials();
188
+ let newAuth = false;
189
+ if (credentials) {
190
+ const relayProblem = authRelay.credentialRelayProblem(credentials.authServerUrl, configuration.configuration.serverUrl);
191
+ if (relayProblem) {
192
+ throw new Error(
193
+ `${relayProblem} Use a separate HAPPY_HOME_DIR for this relay, or run \`very-happy auth login --force\` before starting an agent or daemon.`
194
+ );
195
+ }
196
+ }
197
+ if (!credentials) {
198
+ logger.logger.debug("[AUTH] No credentials found, starting authentication flow...");
199
+ const authResult = await doAuth();
200
+ if (!authResult) {
201
+ throw new Error("Authentication failed or was cancelled");
202
+ }
203
+ credentials = authResult;
204
+ newAuth = true;
205
+ } else {
206
+ logger.logger.debug("[AUTH] Using existing credentials");
207
+ }
208
+ const decision = decideMachineId({
209
+ read: await persistence.readSettingsOutcome(),
210
+ newAuth
211
+ });
212
+ if (decision.action === "refuse") {
213
+ throw new Error(`Cannot establish this machine's identity: ${decision.reason}`);
214
+ }
215
+ let machineId;
216
+ if (decision.action === "reuse") {
217
+ machineId = decision.machineId;
218
+ } else {
219
+ machineId = node_crypto.randomUUID();
220
+ logger.logger.warn(`[AUTH] Registering a NEW machine id (${decision.reason})`);
221
+ await persistence.updateSettings(async (s) => ({ ...s, machineId }));
222
+ }
223
+ logger.logger.debug(`[AUTH] Machine ID: ${machineId}`);
224
+ return { credentials, machineId };
225
+ }
226
+
227
+ exports.authAndSetupMachineIfNeeded = authAndSetupMachineIfNeeded;
@@ -0,0 +1,156 @@
1
+ 'use strict';
2
+
3
+ var node_crypto = require('node:crypto');
4
+ var tweetnacl = require('tweetnacl');
5
+
6
+ function encodeBase64(buffer, variant = "base64") {
7
+ if (variant === "base64url") {
8
+ return encodeBase64Url(buffer);
9
+ }
10
+ return Buffer.from(buffer).toString("base64");
11
+ }
12
+ function encodeBase64Url(buffer) {
13
+ return Buffer.from(buffer).toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
14
+ }
15
+ function decodeBase64(base64, variant = "base64") {
16
+ if (variant === "base64url") {
17
+ const base64Standard = base64.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - base64.length % 4) % 4);
18
+ return new Uint8Array(Buffer.from(base64Standard, "base64"));
19
+ }
20
+ return new Uint8Array(Buffer.from(base64, "base64"));
21
+ }
22
+ function getRandomBytes(size) {
23
+ return new Uint8Array(node_crypto.randomBytes(size));
24
+ }
25
+ function libsodiumPublicKeyFromSecretKey(seed) {
26
+ const hashedSeed = new Uint8Array(node_crypto.createHash("sha512").update(seed).digest());
27
+ const secretKey = hashedSeed.slice(0, 32);
28
+ return new Uint8Array(tweetnacl.box.keyPair.fromSecretKey(secretKey).publicKey);
29
+ }
30
+ function libsodiumEncryptForPublicKey(data, recipientPublicKey) {
31
+ const ephemeralKeyPair = tweetnacl.box.keyPair();
32
+ const nonce = getRandomBytes(tweetnacl.box.nonceLength);
33
+ const encrypted = tweetnacl.box(data, nonce, recipientPublicKey, ephemeralKeyPair.secretKey);
34
+ const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
35
+ result.set(ephemeralKeyPair.publicKey, 0);
36
+ result.set(nonce, ephemeralKeyPair.publicKey.length);
37
+ result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
38
+ return result;
39
+ }
40
+ function encryptLegacy(data, secret) {
41
+ const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
42
+ const encrypted = tweetnacl.secretbox(new TextEncoder().encode(JSON.stringify(data)), nonce, secret);
43
+ const result = new Uint8Array(nonce.length + encrypted.length);
44
+ result.set(nonce);
45
+ result.set(encrypted, nonce.length);
46
+ return result;
47
+ }
48
+ function decryptLegacy(data, secret) {
49
+ const nonce = data.slice(0, tweetnacl.secretbox.nonceLength);
50
+ const encrypted = data.slice(tweetnacl.secretbox.nonceLength);
51
+ const decrypted = tweetnacl.secretbox.open(encrypted, nonce, secret);
52
+ if (!decrypted) {
53
+ return null;
54
+ }
55
+ return JSON.parse(new TextDecoder().decode(decrypted));
56
+ }
57
+ function decryptBlob(bundle, key) {
58
+ if (bundle.length < tweetnacl.secretbox.nonceLength + 16) {
59
+ return null;
60
+ }
61
+ const nonce = bundle.slice(0, tweetnacl.secretbox.nonceLength);
62
+ const ciphertext = bundle.slice(tweetnacl.secretbox.nonceLength);
63
+ const decrypted = tweetnacl.secretbox.open(ciphertext, nonce, key);
64
+ if (!decrypted) {
65
+ return null;
66
+ }
67
+ return new Uint8Array(decrypted);
68
+ }
69
+ function encryptWithDataKey(data, dataKey) {
70
+ const nonce = getRandomBytes(12);
71
+ const cipher = node_crypto.createCipheriv("aes-256-gcm", dataKey, nonce);
72
+ const plaintext = new TextEncoder().encode(JSON.stringify(data));
73
+ const encrypted = Buffer.concat([
74
+ cipher.update(plaintext),
75
+ cipher.final()
76
+ ]);
77
+ const authTag = cipher.getAuthTag();
78
+ const bundle = new Uint8Array(12 + encrypted.length + 16 + 1);
79
+ bundle.set([0], 0);
80
+ bundle.set(nonce, 1);
81
+ bundle.set(new Uint8Array(encrypted), 13);
82
+ bundle.set(new Uint8Array(authTag), 13 + encrypted.length);
83
+ return bundle;
84
+ }
85
+ function decryptWithDataKey(bundle, dataKey) {
86
+ if (bundle.length < 1) {
87
+ return null;
88
+ }
89
+ if (bundle[0] !== 0) {
90
+ return null;
91
+ }
92
+ if (bundle.length < 12 + 16 + 1) {
93
+ return null;
94
+ }
95
+ const nonce = bundle.slice(1, 13);
96
+ const authTag = bundle.slice(bundle.length - 16);
97
+ const ciphertext = bundle.slice(13, bundle.length - 16);
98
+ try {
99
+ const decipher = node_crypto.createDecipheriv("aes-256-gcm", dataKey, nonce);
100
+ decipher.setAuthTag(authTag);
101
+ const decrypted = Buffer.concat([
102
+ decipher.update(ciphertext),
103
+ decipher.final()
104
+ ]);
105
+ return JSON.parse(new TextDecoder().decode(decrypted));
106
+ } catch (error) {
107
+ return null;
108
+ }
109
+ }
110
+ function encrypt(key, variant, data) {
111
+ if (variant === "legacy") {
112
+ return encryptLegacy(data, key);
113
+ } else {
114
+ return encryptWithDataKey(data, key);
115
+ }
116
+ }
117
+ function decrypt(key, variant, data) {
118
+ if (variant === "legacy") {
119
+ return decryptLegacy(data, key);
120
+ } else {
121
+ return decryptWithDataKey(data, key);
122
+ }
123
+ }
124
+
125
+ const DEFAULT_SERVER_URL = "https://veryhappy.dev";
126
+ const LEGACY_CLOUD_SERVER_URL = "https://happy.mereith.com";
127
+ const CLOUD_SERVER_URLS = [DEFAULT_SERVER_URL, LEGACY_CLOUD_SERVER_URL];
128
+ function sameRelay(left, right) {
129
+ try {
130
+ return new URL(left).origin === new URL(right).origin;
131
+ } catch {
132
+ return left.replace(/\/+$/, "") === right.replace(/\/+$/, "");
133
+ }
134
+ }
135
+ function credentialRelayProblem(credentialServerUrl, configuredServerUrl) {
136
+ if (credentialServerUrl) {
137
+ return sameRelay(credentialServerUrl, configuredServerUrl) ? void 0 : `Credentials belong to ${credentialServerUrl}, but the active relay is ${configuredServerUrl}.`;
138
+ }
139
+ if (CLOUD_SERVER_URLS.some((cloudUrl) => sameRelay(configuredServerUrl, cloudUrl))) {
140
+ return void 0;
141
+ }
142
+ return `These credentials predate relay tracking, so they cannot be safely reused with ${configuredServerUrl}.`;
143
+ }
144
+
145
+ exports.credentialRelayProblem = credentialRelayProblem;
146
+ exports.decodeBase64 = decodeBase64;
147
+ exports.decrypt = decrypt;
148
+ exports.decryptBlob = decryptBlob;
149
+ exports.decryptLegacy = decryptLegacy;
150
+ exports.decryptWithDataKey = decryptWithDataKey;
151
+ exports.encodeBase64 = encodeBase64;
152
+ exports.encodeBase64Url = encodeBase64Url;
153
+ exports.encrypt = encrypt;
154
+ exports.getRandomBytes = getRandomBytes;
155
+ exports.libsodiumEncryptForPublicKey = libsodiumEncryptForPublicKey;
156
+ exports.libsodiumPublicKeyFromSecretKey = libsodiumPublicKeyFromSecretKey;
@@ -0,0 +1,143 @@
1
+ import { randomBytes, createCipheriv, createDecipheriv, createHash } from 'node:crypto';
2
+ import tweetnacl from 'tweetnacl';
3
+
4
+ function encodeBase64(buffer, variant = "base64") {
5
+ if (variant === "base64url") {
6
+ return encodeBase64Url(buffer);
7
+ }
8
+ return Buffer.from(buffer).toString("base64");
9
+ }
10
+ function encodeBase64Url(buffer) {
11
+ return Buffer.from(buffer).toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
12
+ }
13
+ function decodeBase64(base64, variant = "base64") {
14
+ if (variant === "base64url") {
15
+ const base64Standard = base64.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - base64.length % 4) % 4);
16
+ return new Uint8Array(Buffer.from(base64Standard, "base64"));
17
+ }
18
+ return new Uint8Array(Buffer.from(base64, "base64"));
19
+ }
20
+ function getRandomBytes(size) {
21
+ return new Uint8Array(randomBytes(size));
22
+ }
23
+ function libsodiumPublicKeyFromSecretKey(seed) {
24
+ const hashedSeed = new Uint8Array(createHash("sha512").update(seed).digest());
25
+ const secretKey = hashedSeed.slice(0, 32);
26
+ return new Uint8Array(tweetnacl.box.keyPair.fromSecretKey(secretKey).publicKey);
27
+ }
28
+ function libsodiumEncryptForPublicKey(data, recipientPublicKey) {
29
+ const ephemeralKeyPair = tweetnacl.box.keyPair();
30
+ const nonce = getRandomBytes(tweetnacl.box.nonceLength);
31
+ const encrypted = tweetnacl.box(data, nonce, recipientPublicKey, ephemeralKeyPair.secretKey);
32
+ const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
33
+ result.set(ephemeralKeyPair.publicKey, 0);
34
+ result.set(nonce, ephemeralKeyPair.publicKey.length);
35
+ result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
36
+ return result;
37
+ }
38
+ function encryptLegacy(data, secret) {
39
+ const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
40
+ const encrypted = tweetnacl.secretbox(new TextEncoder().encode(JSON.stringify(data)), nonce, secret);
41
+ const result = new Uint8Array(nonce.length + encrypted.length);
42
+ result.set(nonce);
43
+ result.set(encrypted, nonce.length);
44
+ return result;
45
+ }
46
+ function decryptLegacy(data, secret) {
47
+ const nonce = data.slice(0, tweetnacl.secretbox.nonceLength);
48
+ const encrypted = data.slice(tweetnacl.secretbox.nonceLength);
49
+ const decrypted = tweetnacl.secretbox.open(encrypted, nonce, secret);
50
+ if (!decrypted) {
51
+ return null;
52
+ }
53
+ return JSON.parse(new TextDecoder().decode(decrypted));
54
+ }
55
+ function decryptBlob(bundle, key) {
56
+ if (bundle.length < tweetnacl.secretbox.nonceLength + 16) {
57
+ return null;
58
+ }
59
+ const nonce = bundle.slice(0, tweetnacl.secretbox.nonceLength);
60
+ const ciphertext = bundle.slice(tweetnacl.secretbox.nonceLength);
61
+ const decrypted = tweetnacl.secretbox.open(ciphertext, nonce, key);
62
+ if (!decrypted) {
63
+ return null;
64
+ }
65
+ return new Uint8Array(decrypted);
66
+ }
67
+ function encryptWithDataKey(data, dataKey) {
68
+ const nonce = getRandomBytes(12);
69
+ const cipher = createCipheriv("aes-256-gcm", dataKey, nonce);
70
+ const plaintext = new TextEncoder().encode(JSON.stringify(data));
71
+ const encrypted = Buffer.concat([
72
+ cipher.update(plaintext),
73
+ cipher.final()
74
+ ]);
75
+ const authTag = cipher.getAuthTag();
76
+ const bundle = new Uint8Array(12 + encrypted.length + 16 + 1);
77
+ bundle.set([0], 0);
78
+ bundle.set(nonce, 1);
79
+ bundle.set(new Uint8Array(encrypted), 13);
80
+ bundle.set(new Uint8Array(authTag), 13 + encrypted.length);
81
+ return bundle;
82
+ }
83
+ function decryptWithDataKey(bundle, dataKey) {
84
+ if (bundle.length < 1) {
85
+ return null;
86
+ }
87
+ if (bundle[0] !== 0) {
88
+ return null;
89
+ }
90
+ if (bundle.length < 12 + 16 + 1) {
91
+ return null;
92
+ }
93
+ const nonce = bundle.slice(1, 13);
94
+ const authTag = bundle.slice(bundle.length - 16);
95
+ const ciphertext = bundle.slice(13, bundle.length - 16);
96
+ try {
97
+ const decipher = createDecipheriv("aes-256-gcm", dataKey, nonce);
98
+ decipher.setAuthTag(authTag);
99
+ const decrypted = Buffer.concat([
100
+ decipher.update(ciphertext),
101
+ decipher.final()
102
+ ]);
103
+ return JSON.parse(new TextDecoder().decode(decrypted));
104
+ } catch (error) {
105
+ return null;
106
+ }
107
+ }
108
+ function encrypt(key, variant, data) {
109
+ if (variant === "legacy") {
110
+ return encryptLegacy(data, key);
111
+ } else {
112
+ return encryptWithDataKey(data, key);
113
+ }
114
+ }
115
+ function decrypt(key, variant, data) {
116
+ if (variant === "legacy") {
117
+ return decryptLegacy(data, key);
118
+ } else {
119
+ return decryptWithDataKey(data, key);
120
+ }
121
+ }
122
+
123
+ const DEFAULT_SERVER_URL = "https://veryhappy.dev";
124
+ const LEGACY_CLOUD_SERVER_URL = "https://happy.mereith.com";
125
+ const CLOUD_SERVER_URLS = [DEFAULT_SERVER_URL, LEGACY_CLOUD_SERVER_URL];
126
+ function sameRelay(left, right) {
127
+ try {
128
+ return new URL(left).origin === new URL(right).origin;
129
+ } catch {
130
+ return left.replace(/\/+$/, "") === right.replace(/\/+$/, "");
131
+ }
132
+ }
133
+ function credentialRelayProblem(credentialServerUrl, configuredServerUrl) {
134
+ if (credentialServerUrl) {
135
+ return sameRelay(credentialServerUrl, configuredServerUrl) ? void 0 : `Credentials belong to ${credentialServerUrl}, but the active relay is ${configuredServerUrl}.`;
136
+ }
137
+ if (CLOUD_SERVER_URLS.some((cloudUrl) => sameRelay(configuredServerUrl, cloudUrl))) {
138
+ return void 0;
139
+ }
140
+ return `These credentials predate relay tracking, so they cannot be safely reused with ${configuredServerUrl}.`;
141
+ }
142
+
143
+ export { decryptWithDataKey as a, decryptLegacy as b, credentialRelayProblem as c, decodeBase64 as d, encodeBase64 as e, encodeBase64Url as f, encrypt as g, decrypt as h, decryptBlob as i, libsodiumPublicKeyFromSecretKey as j, getRandomBytes as k, libsodiumEncryptForPublicKey as l };