@zonease/happy 0.6.38 → 0.6.39

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 (109) hide show
  1. package/dist/{types-BWpRU1VN.mjs → api-CIZKyfSn.mjs} +136 -1725
  2. package/dist/{types-DvTsFaqR.cjs → api-CwOCQeLH.cjs} +317 -1961
  3. package/dist/auth-0VnlXT9f.mjs +181 -0
  4. package/dist/auth-BE8dD20T.mjs +270 -0
  5. package/dist/auth-BIleVCw0.cjs +274 -0
  6. package/dist/auth-Cas9DR3b.cjs +183 -0
  7. package/dist/browser-Cc08m7of.cjs +22 -0
  8. package/dist/browser-Dll5hxOV.mjs +20 -0
  9. package/dist/claudeLocal-CPT3zcIU.mjs +344 -0
  10. package/dist/claudeLocal-WkgLbl1a.cjs +352 -0
  11. package/dist/codex/happyMcpStdioBridge.cjs +4 -1
  12. package/dist/codex/happyMcpStdioBridge.mjs +4 -1
  13. package/dist/common-BdNgghUJ.mjs +75 -0
  14. package/dist/common-CZvSRU4p.cjs +83 -0
  15. package/dist/{config-0Xnc8ARM.cjs → config-Draa-5XC.cjs} +21 -34
  16. package/dist/{config-_GW4YBCP.mjs → config-rTT4qTU5.mjs} +7 -20
  17. package/dist/connect-BfC1tYP_.mjs +679 -0
  18. package/dist/connect-CJZ73syK.cjs +681 -0
  19. package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
  20. package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
  21. package/dist/controlClient-CM_QcJnB.mjs +159 -0
  22. package/dist/controlClient-DZMIsKsT.cjs +168 -0
  23. package/dist/deviceExec-CU1R9CRb.cjs +84 -0
  24. package/dist/deviceExec-D93AOVV4.mjs +81 -0
  25. package/dist/diagnose-B3D1a_v0.cjs +60 -0
  26. package/dist/diagnose-CuRKXxt1.mjs +58 -0
  27. package/dist/doctor-C08m5Z9f.cjs +78 -0
  28. package/dist/doctor-Cya9YSA0.cjs +214 -0
  29. package/dist/doctor-DZYB6IVc.mjs +211 -0
  30. package/dist/doctor-ON7pN5G5.mjs +74 -0
  31. package/dist/downloadImage-DfSFLb-h.mjs +887 -0
  32. package/dist/downloadImage-MQMrUUxS.cjs +897 -0
  33. package/dist/enroll-BxlbVftP.cjs +115 -0
  34. package/dist/enroll-C52x8oly.mjs +113 -0
  35. package/dist/evidence-Ccd9iYcj.mjs +127 -0
  36. package/dist/evidence-CjWBG5rX.cjs +129 -0
  37. package/dist/formatImageMessage-B4lSxlk2.mjs +43 -0
  38. package/dist/formatImageMessage-DbyG8c2j.cjs +46 -0
  39. package/dist/github-DKcyF1zp.mjs +57 -0
  40. package/dist/github-h9GhJJ_C.cjs +59 -0
  41. package/dist/index-CDTNgfUf.cjs +578 -0
  42. package/dist/index-CPKdvi7J.mjs +554 -0
  43. package/dist/index.cjs +812 -40
  44. package/dist/index.mjs +813 -40
  45. package/dist/install-BokHRgFW.cjs +98 -0
  46. package/dist/install-C_cp8b2-.cjs +96 -0
  47. package/dist/install-DAeCn8ae.mjs +94 -0
  48. package/dist/install-oRAjVLjP.mjs +95 -0
  49. package/dist/lib.cjs +18 -12
  50. package/dist/lib.mjs +13 -7
  51. package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Cuygmd4K.mjs} +4 -2
  52. package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-DDCJjywt.cjs} +63 -61
  53. package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
  54. package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
  55. package/dist/persistence-BFjvtUad.mjs +944 -0
  56. package/dist/persistence-JLUn_Nou.cjs +996 -0
  57. package/dist/projectPath-BTBIMB57.mjs +10 -0
  58. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  59. package/dist/prompt-BTWDZZO0.cjs +25 -0
  60. package/dist/prompt-BsAZsPbo.mjs +22 -0
  61. package/dist/release-BMEzNONE.mjs +168 -0
  62. package/dist/release-EhOJeAZe.cjs +171 -0
  63. package/dist/run-BDn2aE3Q.cjs +2152 -0
  64. package/dist/run-DBZqN6Kn.mjs +2128 -0
  65. package/dist/runClaude-DNHvERX0.mjs +3763 -0
  66. package/dist/runClaude-uaKxPZPm.cjs +3766 -0
  67. package/dist/{runCodex-skq0j05d.cjs → runCodex-82UrZLme.cjs} +169 -153
  68. package/dist/{runCodex-DiKzBf9q.mjs → runCodex-C-RTM0wA.mjs} +36 -20
  69. package/dist/{runGemini-BeqrVq8R.mjs → runGemini-Bm6-4Xm2.mjs} +34 -17
  70. package/dist/{runGemini-CVp-CEIh.cjs → runGemini-CXMr4Jwb.cjs} +212 -195
  71. package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-1B6RMYT7.cjs} +31 -55
  72. package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-ioARRHrx.mjs} +14 -38
  73. package/dist/{serve-BECdtivY.cjs → serve-BtdAhkIE.cjs} +35 -58
  74. package/dist/{serve-BNdoEDVx.mjs → serve-CwibwU6N.mjs} +12 -35
  75. package/dist/session-2sU4Bu1R.mjs +108 -0
  76. package/dist/session-D--F87zL.cjs +110 -0
  77. package/dist/sessionKeyCache-4Tp8pJ3N.cjs +36 -0
  78. package/dist/sessionKeyCache-D2BwO91C.mjs +33 -0
  79. package/dist/sessionList-BCSw3qYt.mjs +51 -0
  80. package/dist/sessionList-ICJsjNtJ.cjs +54 -0
  81. package/dist/sessionSummary-Bkz52BPh.cjs +393 -0
  82. package/dist/sessionSummary-lHGBWQSb.mjs +387 -0
  83. package/dist/spawnHappyCLI-CoORX0YW.mjs +66 -0
  84. package/dist/spawnHappyCLI-D_V-AAoP.cjs +70 -0
  85. package/dist/ssh-BTOlhhxi.cjs +333 -0
  86. package/dist/ssh-DL_AkRAD.mjs +328 -0
  87. package/dist/systemdScope-BeOtAkhk.mjs +25 -0
  88. package/dist/systemdScope-DW3-UoKB.cjs +29 -0
  89. package/dist/task-CQzrHRZe.mjs +165 -0
  90. package/dist/task-CSpaC9HX.cjs +167 -0
  91. package/dist/time-Bj2HRkKH.cjs +33 -0
  92. package/dist/time-DgsBLJA_.mjs +29 -0
  93. package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
  94. package/dist/trimIdent-BAjmv_TG.mjs +20 -0
  95. package/dist/types-BoJh4Qfv.mjs +57 -0
  96. package/dist/types-DWeB7aqh.cjs +59 -0
  97. package/dist/uninstall-BiKyRAb1.cjs +77 -0
  98. package/dist/uninstall-nFMFGUVM.mjs +75 -0
  99. package/dist/update-BcqRHXf2.mjs +109 -0
  100. package/dist/update-Dw8pgsAT.cjs +111 -0
  101. package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
  102. package/dist/workflowCommon-Bl568-rt.cjs +62 -0
  103. package/dist/workflowReports-BEWuQesA.cjs +113 -0
  104. package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
  105. package/package.json +1 -1
  106. package/dist/index-BbCDDvoB.cjs +0 -11376
  107. package/dist/index-vvZXdswy.mjs +0 -11336
  108. package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
  109. package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
@@ -0,0 +1,681 @@
1
+ 'use strict';
2
+
3
+ var chalk = require('chalk');
4
+ var fs = require('fs');
5
+ var os = require('os');
6
+ var path = require('path');
7
+ var logger = require('./persistence-JLUn_Nou.cjs');
8
+ var api = require('./api-CwOCQeLH.cjs');
9
+ var http = require('http');
10
+ var crypto = require('crypto');
11
+ var browser = require('./browser-Cc08m7of.cjs');
12
+ var child_process = require('child_process');
13
+ var util = require('util');
14
+ require('node:fs/promises');
15
+ require('node:fs');
16
+ require('node:os');
17
+ require('node:path');
18
+ require('zod');
19
+ require('node:crypto');
20
+ require('tweetnacl');
21
+ require('axios');
22
+ require('node:events');
23
+ require('socket.io-client');
24
+ require('./index-CDTNgfUf.cjs');
25
+ require('@paralleldrive/cuid2');
26
+ require('./time-Bj2HRkKH.cjs');
27
+ require('node:child_process');
28
+ require('node:util');
29
+ require('fs/promises');
30
+ require('./projectPath-ChLhdOyt.cjs');
31
+ require('url');
32
+ require('node:module');
33
+ require('ws');
34
+ require('@stablelib/base64');
35
+ require('node:readline');
36
+ require('expo-server-sdk');
37
+ require('./sessionKeyCache-4Tp8pJ3N.cjs');
38
+ require('open');
39
+
40
+ const CLIENT_ID$2 = "app_EMoamEEZ73f0CkXaXp7hrann";
41
+ const AUTH_BASE_URL = "https://auth.openai.com";
42
+ const DEFAULT_PORT$2 = 1455;
43
+ function generatePKCE$2() {
44
+ const verifier = crypto.randomBytes(32).toString("base64url").replace(/[^a-zA-Z0-9\-._~]/g, "");
45
+ const challenge = crypto.createHash("sha256").update(verifier).digest("base64url").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
46
+ return { verifier, challenge };
47
+ }
48
+ function generateState$2() {
49
+ return crypto.randomBytes(16).toString("hex");
50
+ }
51
+ function parseJWT(token) {
52
+ const parts = token.split(".");
53
+ if (parts.length !== 3) {
54
+ throw new Error("Invalid JWT format");
55
+ }
56
+ const payload = Buffer.from(parts[1], "base64url").toString();
57
+ return JSON.parse(payload);
58
+ }
59
+ async function findAvailablePort$2() {
60
+ return new Promise((resolve) => {
61
+ const server = http.createServer();
62
+ server.listen(0, "127.0.0.1", () => {
63
+ const port = server.address().port;
64
+ server.close(() => resolve(port));
65
+ });
66
+ });
67
+ }
68
+ async function isPortAvailable$2(port) {
69
+ return new Promise((resolve) => {
70
+ const testServer = http.createServer();
71
+ testServer.once("error", () => {
72
+ testServer.close();
73
+ resolve(false);
74
+ });
75
+ testServer.listen(port, "127.0.0.1", () => {
76
+ testServer.close(() => resolve(true));
77
+ });
78
+ });
79
+ }
80
+ async function exchangeCodeForTokens$2(code, verifier, port) {
81
+ const response = await fetch(`${AUTH_BASE_URL}/oauth/token`, {
82
+ method: "POST",
83
+ headers: {
84
+ "Content-Type": "application/x-www-form-urlencoded"
85
+ },
86
+ body: new URLSearchParams({
87
+ grant_type: "authorization_code",
88
+ client_id: CLIENT_ID$2,
89
+ code,
90
+ code_verifier: verifier,
91
+ redirect_uri: `http://localhost:${port}/auth/callback`
92
+ })
93
+ });
94
+ if (!response.ok) {
95
+ const error = await response.text();
96
+ throw new Error(`Token exchange failed: ${error}`);
97
+ }
98
+ const data = await response.json();
99
+ const idTokenPayload = parseJWT(data.id_token);
100
+ let accountId = idTokenPayload.chatgpt_account_id;
101
+ if (!accountId) {
102
+ const authClaim = idTokenPayload["https://api.openai.com/auth"];
103
+ if (authClaim && typeof authClaim === "object") {
104
+ accountId = authClaim.chatgpt_account_id || authClaim.account_id;
105
+ }
106
+ }
107
+ return {
108
+ id_token: data.id_token,
109
+ access_token: data.access_token || data.id_token,
110
+ refresh_token: data.refresh_token,
111
+ account_id: accountId
112
+ };
113
+ }
114
+ async function startCallbackServer$2(state, verifier, port) {
115
+ return new Promise((resolve, reject) => {
116
+ const server = http.createServer(async (req, res) => {
117
+ const url = new URL(req.url, `http://localhost:${port}`);
118
+ if (url.pathname === "/auth/callback") {
119
+ const code = url.searchParams.get("code");
120
+ const receivedState = url.searchParams.get("state");
121
+ if (receivedState !== state) {
122
+ res.writeHead(400);
123
+ res.end("Invalid state parameter");
124
+ server.close();
125
+ reject(new Error("Invalid state parameter"));
126
+ return;
127
+ }
128
+ if (!code) {
129
+ res.writeHead(400);
130
+ res.end("No authorization code received");
131
+ server.close();
132
+ reject(new Error("No authorization code received"));
133
+ return;
134
+ }
135
+ try {
136
+ const tokens = await exchangeCodeForTokens$2(code, verifier, port);
137
+ res.writeHead(200, { "Content-Type": "text/html" });
138
+ res.end(`
139
+ <html>
140
+ <body style="font-family: sans-serif; padding: 20px;">
141
+ <h2>\u2705 Authentication Successful!</h2>
142
+ <p>You can close this window and return to your terminal.</p>
143
+ <script>setTimeout(() => window.close(), 3000);<\/script>
144
+ </body>
145
+ </html>
146
+ `);
147
+ server.close();
148
+ resolve(tokens);
149
+ } catch (error) {
150
+ res.writeHead(500);
151
+ res.end("Token exchange failed");
152
+ server.close();
153
+ reject(error);
154
+ }
155
+ }
156
+ });
157
+ server.listen(port, "127.0.0.1", () => {
158
+ });
159
+ setTimeout(() => {
160
+ server.close();
161
+ reject(new Error("Authentication timeout"));
162
+ }, 5 * 60 * 1e3);
163
+ });
164
+ }
165
+ async function authenticateCodex() {
166
+ const { verifier, challenge } = generatePKCE$2();
167
+ const state = generateState$2();
168
+ let port = DEFAULT_PORT$2;
169
+ const portAvailable = await isPortAvailable$2(port);
170
+ if (!portAvailable) {
171
+ port = await findAvailablePort$2();
172
+ }
173
+ const serverPromise = startCallbackServer$2(state, verifier, port);
174
+ await new Promise((resolve) => setTimeout(resolve, 100));
175
+ const redirect_uri = `http://localhost:${port}/auth/callback`;
176
+ const params = [
177
+ ["response_type", "code"],
178
+ ["client_id", CLIENT_ID$2],
179
+ ["redirect_uri", redirect_uri],
180
+ ["scope", "openid profile email offline_access"],
181
+ ["code_challenge", challenge],
182
+ ["code_challenge_method", "S256"],
183
+ ["id_token_add_organizations", "true"],
184
+ ["codex_cli_simplified_flow", "true"],
185
+ ["state", state]
186
+ ];
187
+ const queryString = params.map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
188
+ const authUrl = `${AUTH_BASE_URL}/oauth/authorize?${queryString}`;
189
+ console.log("\u{1F4CB} Opening browser for authentication...");
190
+ console.log(`If browser doesn't open, visit:
191
+ ${authUrl}
192
+ `);
193
+ await browser.openBrowser(authUrl);
194
+ const tokens = await serverPromise;
195
+ console.log("\u{1F389} Authentication successful!");
196
+ return tokens;
197
+ }
198
+
199
+ const CLIENT_ID$1 = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
200
+ const CLAUDE_AI_AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
201
+ const TOKEN_URL$1 = "https://console.anthropic.com/v1/oauth/token";
202
+ const DEFAULT_PORT$1 = 54545;
203
+ const SCOPE = "user:inference";
204
+ function generatePKCE$1() {
205
+ const verifier = crypto.randomBytes(32).toString("base64url").replace(/[^a-zA-Z0-9\-._~]/g, "");
206
+ const challenge = crypto.createHash("sha256").update(verifier).digest("base64url").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
207
+ return { verifier, challenge };
208
+ }
209
+ function generateState$1() {
210
+ return crypto.randomBytes(32).toString("base64url");
211
+ }
212
+ async function findAvailablePort$1() {
213
+ return new Promise((resolve) => {
214
+ const server = http.createServer();
215
+ server.listen(0, "127.0.0.1", () => {
216
+ const port = server.address().port;
217
+ server.close(() => resolve(port));
218
+ });
219
+ });
220
+ }
221
+ async function isPortAvailable$1(port) {
222
+ return new Promise((resolve) => {
223
+ const testServer = http.createServer();
224
+ testServer.once("error", () => {
225
+ testServer.close();
226
+ resolve(false);
227
+ });
228
+ testServer.listen(port, "127.0.0.1", () => {
229
+ testServer.close(() => resolve(true));
230
+ });
231
+ });
232
+ }
233
+ async function exchangeCodeForTokens$1(code, verifier, port, state) {
234
+ const tokenResponse = await fetch(TOKEN_URL$1, {
235
+ method: "POST",
236
+ headers: {
237
+ "Content-Type": "application/json"
238
+ },
239
+ body: JSON.stringify({
240
+ grant_type: "authorization_code",
241
+ code,
242
+ redirect_uri: `http://localhost:${port}/callback`,
243
+ client_id: CLIENT_ID$1,
244
+ code_verifier: verifier,
245
+ state
246
+ })
247
+ });
248
+ if (!tokenResponse.ok) {
249
+ throw new Error(`Token exchange failed: ${tokenResponse.statusText}`);
250
+ }
251
+ const tokenData = await tokenResponse.json();
252
+ return {
253
+ raw: tokenData,
254
+ token: tokenData.access_token,
255
+ expires: Date.now() + tokenData.expires_in * 1e3
256
+ };
257
+ }
258
+ async function startCallbackServer$1(state, verifier, port) {
259
+ return new Promise((resolve, reject) => {
260
+ const server = http.createServer(async (req, res) => {
261
+ const url = new URL(req.url, `http://localhost:${port}`);
262
+ if (url.pathname === "/callback") {
263
+ const code = url.searchParams.get("code");
264
+ const receivedState = url.searchParams.get("state");
265
+ if (receivedState !== state) {
266
+ res.writeHead(400);
267
+ res.end("Invalid state parameter");
268
+ server.close();
269
+ reject(new Error("Invalid state parameter"));
270
+ return;
271
+ }
272
+ if (!code) {
273
+ res.writeHead(400);
274
+ res.end("No authorization code received");
275
+ server.close();
276
+ reject(new Error("No authorization code received"));
277
+ return;
278
+ }
279
+ try {
280
+ const tokens = await exchangeCodeForTokens$1(code, verifier, port, state);
281
+ res.writeHead(302, {
282
+ "Location": "https://console.anthropic.com/oauth/code/success?app=claude-code"
283
+ });
284
+ res.end();
285
+ server.close();
286
+ resolve(tokens);
287
+ } catch (error) {
288
+ res.writeHead(500);
289
+ res.end("Token exchange failed");
290
+ server.close();
291
+ reject(error);
292
+ }
293
+ }
294
+ });
295
+ server.listen(port, "127.0.0.1", () => {
296
+ });
297
+ setTimeout(() => {
298
+ server.close();
299
+ reject(new Error("Authentication timeout"));
300
+ }, 5 * 60 * 1e3);
301
+ });
302
+ }
303
+ async function authenticateClaude() {
304
+ console.log("\u{1F680} Starting Anthropic Claude authentication...");
305
+ const { verifier, challenge } = generatePKCE$1();
306
+ const state = generateState$1();
307
+ let port = DEFAULT_PORT$1;
308
+ const portAvailable = await isPortAvailable$1(port);
309
+ if (!portAvailable) {
310
+ console.log(`Port ${port} is in use, finding an available port...`);
311
+ port = await findAvailablePort$1();
312
+ }
313
+ console.log(`\u{1F4E1} Using callback port: ${port}`);
314
+ const serverPromise = startCallbackServer$1(state, verifier, port);
315
+ await new Promise((resolve) => setTimeout(resolve, 100));
316
+ const redirect_uri = `http://localhost:${port}/callback`;
317
+ const params = new URLSearchParams({
318
+ code: "true",
319
+ // This tells Claude.ai to show the code AND redirect
320
+ client_id: CLIENT_ID$1,
321
+ response_type: "code",
322
+ redirect_uri,
323
+ scope: SCOPE,
324
+ code_challenge: challenge,
325
+ code_challenge_method: "S256",
326
+ state
327
+ });
328
+ const authUrl = `${CLAUDE_AI_AUTHORIZE_URL}?${params}`;
329
+ console.log("\u{1F4CB} Opening browser for authentication...");
330
+ console.log("If browser doesn't open, visit this URL:");
331
+ console.log();
332
+ console.log(`${authUrl}`);
333
+ console.log();
334
+ await browser.openBrowser(authUrl);
335
+ try {
336
+ const tokens = await serverPromise;
337
+ console.log("\u{1F389} Authentication successful!");
338
+ console.log("\u2705 OAuth tokens received");
339
+ return tokens;
340
+ } catch (error) {
341
+ console.error("\n\u274C Failed to authenticate with Anthropic");
342
+ throw error;
343
+ }
344
+ }
345
+
346
+ const execAsync = util.promisify(child_process.exec);
347
+ const CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
348
+ const CLIENT_SECRET = "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";
349
+ const AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
350
+ const TOKEN_URL = "https://oauth2.googleapis.com/token";
351
+ const DEFAULT_PORT = 54545;
352
+ const SCOPES = [
353
+ "https://www.googleapis.com/auth/cloud-platform",
354
+ "https://www.googleapis.com/auth/userinfo.email",
355
+ "https://www.googleapis.com/auth/userinfo.profile"
356
+ ].join(" ");
357
+ function generatePKCE() {
358
+ const verifier = crypto.randomBytes(32).toString("base64url").replace(/[^a-zA-Z0-9\-._~]/g, "");
359
+ const challenge = crypto.createHash("sha256").update(verifier).digest("base64url").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
360
+ return { verifier, challenge };
361
+ }
362
+ function generateState() {
363
+ return crypto.randomBytes(32).toString("hex");
364
+ }
365
+ async function findAvailablePort() {
366
+ return new Promise((resolve) => {
367
+ const server = http.createServer();
368
+ server.listen(0, "127.0.0.1", () => {
369
+ const port = server.address().port;
370
+ server.close(() => resolve(port));
371
+ });
372
+ });
373
+ }
374
+ async function isPortAvailable(port) {
375
+ return new Promise((resolve) => {
376
+ const testServer = http.createServer();
377
+ testServer.once("error", () => {
378
+ testServer.close();
379
+ resolve(false);
380
+ });
381
+ testServer.listen(port, "127.0.0.1", () => {
382
+ testServer.close(() => resolve(true));
383
+ });
384
+ });
385
+ }
386
+ async function exchangeCodeForTokens(code, verifier, port) {
387
+ const response = await fetch(TOKEN_URL, {
388
+ method: "POST",
389
+ headers: {
390
+ "Content-Type": "application/x-www-form-urlencoded"
391
+ },
392
+ body: new URLSearchParams({
393
+ grant_type: "authorization_code",
394
+ client_id: CLIENT_ID,
395
+ client_secret: CLIENT_SECRET,
396
+ code,
397
+ code_verifier: verifier,
398
+ redirect_uri: `http://localhost:${port}/oauth2callback`
399
+ })
400
+ });
401
+ if (!response.ok) {
402
+ const error = await response.text();
403
+ throw new Error(`Token exchange failed: ${error}`);
404
+ }
405
+ const data = await response.json();
406
+ return data;
407
+ }
408
+ async function startCallbackServer(state, verifier, port) {
409
+ return new Promise((resolve, reject) => {
410
+ const server = http.createServer(async (req, res) => {
411
+ const url = new URL(req.url, `http://localhost:${port}`);
412
+ if (url.pathname === "/oauth2callback") {
413
+ const code = url.searchParams.get("code");
414
+ const receivedState = url.searchParams.get("state");
415
+ const error = url.searchParams.get("error");
416
+ if (error) {
417
+ res.writeHead(302, {
418
+ "Location": "https://developers.google.com/gemini-code-assist/auth_failure_gemini"
419
+ });
420
+ res.end();
421
+ server.close();
422
+ reject(new Error(`Authentication error: ${error}`));
423
+ return;
424
+ }
425
+ if (receivedState !== state) {
426
+ res.writeHead(400);
427
+ res.end("State mismatch. Possible CSRF attack");
428
+ server.close();
429
+ reject(new Error("Invalid state parameter"));
430
+ return;
431
+ }
432
+ if (!code) {
433
+ res.writeHead(400);
434
+ res.end("No authorization code received");
435
+ server.close();
436
+ reject(new Error("No authorization code received"));
437
+ return;
438
+ }
439
+ try {
440
+ const tokens = await exchangeCodeForTokens(code, verifier, port);
441
+ res.writeHead(302, {
442
+ "Location": "https://developers.google.com/gemini-code-assist/auth_success_gemini"
443
+ });
444
+ res.end();
445
+ server.close();
446
+ resolve(tokens);
447
+ } catch (error2) {
448
+ res.writeHead(500);
449
+ res.end("Token exchange failed");
450
+ server.close();
451
+ reject(error2);
452
+ }
453
+ }
454
+ });
455
+ server.listen(port, "127.0.0.1", () => {
456
+ });
457
+ setTimeout(() => {
458
+ server.close();
459
+ reject(new Error("Authentication timeout"));
460
+ }, 5 * 60 * 1e3);
461
+ });
462
+ }
463
+ async function authenticateGemini() {
464
+ console.log("\u{1F680} Starting Google Gemini authentication...");
465
+ const { verifier, challenge } = generatePKCE();
466
+ const state = generateState();
467
+ let port = DEFAULT_PORT;
468
+ const portAvailable = await isPortAvailable(port);
469
+ if (!portAvailable) {
470
+ console.log(`Port ${port} is in use, finding an available port...`);
471
+ port = await findAvailablePort();
472
+ }
473
+ console.log(`\u{1F4E1} Using callback port: ${port}`);
474
+ const serverPromise = startCallbackServer(state, verifier, port);
475
+ await new Promise((resolve) => setTimeout(resolve, 100));
476
+ const redirect_uri = `http://localhost:${port}/oauth2callback`;
477
+ const params = new URLSearchParams({
478
+ client_id: CLIENT_ID,
479
+ response_type: "code",
480
+ redirect_uri,
481
+ scope: SCOPES,
482
+ access_type: "offline",
483
+ // To get refresh token
484
+ code_challenge: challenge,
485
+ code_challenge_method: "S256",
486
+ state,
487
+ prompt: "consent"
488
+ // Force consent to get refresh token
489
+ });
490
+ const authUrl = `${AUTHORIZE_URL}?${params}`;
491
+ console.log("\n\u{1F4CB} Opening browser for authentication...");
492
+ console.log("If browser doesn't open, visit this URL:");
493
+ console.log(`
494
+ ${authUrl}
495
+ `);
496
+ const platform = process.platform;
497
+ const openCommand = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
498
+ try {
499
+ await execAsync(`${openCommand} "${authUrl}"`);
500
+ } catch {
501
+ console.log("\u26A0\uFE0F Could not open browser automatically");
502
+ }
503
+ try {
504
+ const tokens = await serverPromise;
505
+ console.log("\n\u{1F389} Authentication successful!");
506
+ console.log("\u2705 OAuth tokens received");
507
+ return tokens;
508
+ } catch (error) {
509
+ console.error("\n\u274C Failed to authenticate with Google");
510
+ throw error;
511
+ }
512
+ }
513
+
514
+ function decodeJwtPayload(token) {
515
+ try {
516
+ const parts = token.split(".");
517
+ if (parts.length !== 3) {
518
+ return null;
519
+ }
520
+ const payload = parts[1];
521
+ const decoded = Buffer.from(payload, "base64url").toString("utf-8");
522
+ return JSON.parse(decoded);
523
+ } catch {
524
+ return null;
525
+ }
526
+ }
527
+
528
+ async function handleConnectCommand(args) {
529
+ const subcommand = args[0];
530
+ if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
531
+ showConnectHelp();
532
+ return;
533
+ }
534
+ switch (subcommand.toLowerCase()) {
535
+ case "codex":
536
+ await handleConnectVendor("codex", "OpenAI");
537
+ break;
538
+ case "claude":
539
+ await handleConnectVendor("claude", "Anthropic");
540
+ break;
541
+ case "gemini":
542
+ await handleConnectVendor("gemini", "Gemini");
543
+ break;
544
+ case "status":
545
+ await handleConnectStatus();
546
+ break;
547
+ default:
548
+ console.error(chalk.red(`Unknown connect target: ${subcommand}`));
549
+ showConnectHelp();
550
+ process.exit(1);
551
+ }
552
+ }
553
+ function showConnectHelp() {
554
+ console.log(`
555
+ ${chalk.bold("happy connect")} - Connect AI vendor API keys to Happy AI cloud
556
+
557
+ ${chalk.bold("Usage:")}
558
+ happy connect codex Store your Codex API key in Happy AI cloud
559
+ happy connect claude Store your Anthropic API key in Happy AI cloud
560
+ happy connect gemini Store your Gemini API key in Happy AI cloud
561
+ happy connect status Show connection status for all vendors
562
+ happy connect help Show this help message
563
+
564
+ ${chalk.bold("Description:")}
565
+ The connect command allows you to securely store your AI vendor API keys
566
+ in Happy AI cloud. This enables you to use these services through Happy
567
+ without exposing your API keys locally.
568
+
569
+ ${chalk.bold("Examples:")}
570
+ happy connect codex
571
+ happy connect claude
572
+ happy connect gemini
573
+ happy connect status
574
+
575
+ ${chalk.bold("Notes:")}
576
+ \u2022 You must be authenticated with Happy first (run 'happy auth login')
577
+ \u2022 API keys are encrypted and stored securely in Happy AI cloud
578
+ \u2022 You can manage your stored keys at happy.zonease.org
579
+ `);
580
+ }
581
+ async function handleConnectVendor(vendor, displayName) {
582
+ console.log(chalk.bold(`
583
+ \u{1F50C} Connecting ${displayName} to Happy AI cloud
584
+ `));
585
+ const credentials = await logger.readCredentials();
586
+ if (!credentials) {
587
+ console.log(chalk.yellow("\u26A0\uFE0F Not authenticated with Happy"));
588
+ console.log(chalk.gray(' Please run "happy auth login" first'));
589
+ process.exit(1);
590
+ }
591
+ const api$1 = await api.ApiClient.create(credentials);
592
+ if (vendor === "codex") {
593
+ console.log("\u{1F680} Registering Codex token with server");
594
+ const codexAuthTokens = await authenticateCodex();
595
+ await api$1.registerVendorToken("openai", { oauth: codexAuthTokens });
596
+ console.log("\u2705 Codex token registered with server");
597
+ process.exit(0);
598
+ } else if (vendor === "claude") {
599
+ console.log("\u{1F680} Registering Anthropic token with server");
600
+ const anthropicAuthTokens = await authenticateClaude();
601
+ await api$1.registerVendorToken("anthropic", { oauth: anthropicAuthTokens });
602
+ console.log("\u2705 Anthropic token registered with server");
603
+ process.exit(0);
604
+ } else if (vendor === "gemini") {
605
+ console.log("\u{1F680} Registering Gemini token with server");
606
+ const geminiAuthTokens = await authenticateGemini();
607
+ await api$1.registerVendorToken("gemini", { oauth: geminiAuthTokens });
608
+ console.log("\u2705 Gemini token registered with server");
609
+ updateLocalGeminiCredentials(geminiAuthTokens);
610
+ process.exit(0);
611
+ } else {
612
+ throw new Error(`Unsupported vendor: ${vendor}`);
613
+ }
614
+ }
615
+ async function handleConnectStatus() {
616
+ console.log(chalk.bold("\n\u{1F50C} Connection Status\n"));
617
+ const credentials = await logger.readCredentials();
618
+ if (!credentials) {
619
+ console.log(chalk.yellow("\u26A0\uFE0F Not authenticated with Happy"));
620
+ console.log(chalk.gray(' Please run "happy auth login" first'));
621
+ process.exit(1);
622
+ }
623
+ const api$1 = await api.ApiClient.create(credentials);
624
+ const vendors = [
625
+ { key: "gemini", name: "Gemini", display: "Google Gemini" },
626
+ { key: "openai", name: "Codex", display: "OpenAI Codex" },
627
+ { key: "anthropic", name: "Claude", display: "Anthropic Claude" }
628
+ ];
629
+ for (const vendor of vendors) {
630
+ try {
631
+ const token = await api$1.getVendorToken(vendor.key);
632
+ if (token?.oauth) {
633
+ let userInfo = "";
634
+ if (token.oauth.id_token) {
635
+ const payload = decodeJwtPayload(token.oauth.id_token);
636
+ if (payload?.email) {
637
+ userInfo = chalk.gray(` (${payload.email})`);
638
+ }
639
+ }
640
+ const expiresAt = token.oauth.expires_at || (token.oauth.expires_in ? Date.now() + token.oauth.expires_in * 1e3 : null);
641
+ const isExpired = expiresAt && expiresAt < Date.now();
642
+ if (isExpired) {
643
+ console.log(` ${chalk.yellow("\u26A0\uFE0F")} ${vendor.display}: ${chalk.yellow("expired")}${userInfo}`);
644
+ } else {
645
+ console.log(` ${chalk.green("\u2713")} ${vendor.display}: ${chalk.green("connected")}${userInfo}`);
646
+ }
647
+ } else {
648
+ console.log(` ${chalk.gray("\u25CB")} ${vendor.display}: ${chalk.gray("not connected")}`);
649
+ }
650
+ } catch {
651
+ console.log(` ${chalk.gray("\u25CB")} ${vendor.display}: ${chalk.gray("not connected")}`);
652
+ }
653
+ }
654
+ console.log("");
655
+ console.log(chalk.gray("To connect a vendor, run: happy connect <vendor>"));
656
+ console.log(chalk.gray("Example: happy connect gemini"));
657
+ console.log("");
658
+ }
659
+ function updateLocalGeminiCredentials(tokens) {
660
+ try {
661
+ const geminiDir = path.join(os.homedir(), ".gemini");
662
+ const credentialsPath = path.join(geminiDir, "oauth_creds.json");
663
+ if (!fs.existsSync(geminiDir)) {
664
+ fs.mkdirSync(geminiDir, { recursive: true });
665
+ }
666
+ const credentials = {
667
+ access_token: tokens.access_token,
668
+ token_type: tokens.token_type || "Bearer",
669
+ scope: tokens.scope || "https://www.googleapis.com/auth/cloud-platform",
670
+ ...tokens.refresh_token && { refresh_token: tokens.refresh_token },
671
+ ...tokens.id_token && { id_token: tokens.id_token },
672
+ ...tokens.expires_in && { expires_in: tokens.expires_in }
673
+ };
674
+ fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), "utf-8");
675
+ console.log(chalk.gray(` Updated local credentials: ${credentialsPath}`));
676
+ } catch (error) {
677
+ console.log(chalk.yellow(` \u26A0\uFE0F Could not update local credentials: ${error}`));
678
+ }
679
+ }
680
+
681
+ exports.handleConnectCommand = handleConnectCommand;
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var mcpToolSchemas = require('./mcpToolSchemas-f-kttjFw.cjs');
3
+ var prompt = require('./prompt-BTWDZZO0.cjs');
4
4
 
5
5
  const GEMINI_API_KEY_ENV = "GEMINI_API_KEY";
6
6
  const GOOGLE_API_KEY_ENV = "GOOGLE_API_KEY";
7
7
  const GEMINI_MODEL_ENV = "GEMINI_MODEL";
8
8
  const DEFAULT_GEMINI_MODEL = "gemini-2.5-pro";
9
9
  function getFirstTurnInstruction(env = process.env) {
10
- return mcpToolSchemas.getBaseSystemPrompt(env) ?? "";
10
+ return prompt.getBaseSystemPrompt(env) ?? "";
11
11
  }
12
12
 
13
13
  exports.DEFAULT_GEMINI_MODEL = DEFAULT_GEMINI_MODEL;
@@ -1,4 +1,4 @@
1
- import { g as getBaseSystemPrompt } from './mcpToolSchemas-CdPXJQmb.mjs';
1
+ import { g as getBaseSystemPrompt } from './prompt-BsAZsPbo.mjs';
2
2
 
3
3
  const GEMINI_API_KEY_ENV = "GEMINI_API_KEY";
4
4
  const GOOGLE_API_KEY_ENV = "GOOGLE_API_KEY";