@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,274 @@
1
+ 'use strict';
2
+
3
+ var logger = require('./persistence-JLUn_Nou.cjs');
4
+ var node_crypto = require('node:crypto');
5
+ var tweetnacl = require('tweetnacl');
6
+ var axios = require('axios');
7
+ var qrcode = require('qrcode-terminal');
8
+ var time = require('./time-Bj2HRkKH.cjs');
9
+ var browser = require('./browser-Cc08m7of.cjs');
10
+ var React = require('react');
11
+ var ink = require('ink');
12
+ require('node:fs/promises');
13
+ require('node:fs');
14
+ require('node:os');
15
+ require('node:path');
16
+ require('zod');
17
+ require('chalk');
18
+ require('fs');
19
+ require('open');
20
+
21
+ function displayQRCode(url) {
22
+ console.log("=".repeat(80));
23
+ console.log("\u{1F4F1} To authenticate, scan this QR code with your mobile device:");
24
+ console.log("=".repeat(80));
25
+ qrcode.generate(url, { small: true }, (qr) => {
26
+ for (let l of qr.split("\n")) {
27
+ console.log(" ".repeat(10) + l);
28
+ }
29
+ });
30
+ console.log("=".repeat(80));
31
+ }
32
+
33
+ function generateWebAuthUrl(publicKey) {
34
+ const publicKeyBase64 = logger.encodeBase64(publicKey, "base64url");
35
+ return `${logger.configuration.webappUrl}/terminal/connect#key=${publicKeyBase64}`;
36
+ }
37
+
38
+ const AuthSelector = ({ onSelect, onCancel }) => {
39
+ const [selectedIndex, setSelectedIndex] = React.useState(0);
40
+ const options = [
41
+ {
42
+ method: "mobile",
43
+ label: "Mobile App"
44
+ },
45
+ {
46
+ method: "web",
47
+ label: "Web Browser"
48
+ }
49
+ ];
50
+ ink.useInput((input, key) => {
51
+ if (key.upArrow) {
52
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
53
+ } else if (key.downArrow) {
54
+ setSelectedIndex((prev) => Math.min(options.length - 1, prev + 1));
55
+ } else if (key.return) {
56
+ onSelect(options[selectedIndex].method);
57
+ } else if (key.escape || key.ctrl && input === "c") {
58
+ onCancel();
59
+ } else if (input === "1") {
60
+ setSelectedIndex(0);
61
+ onSelect("mobile");
62
+ } else if (input === "2") {
63
+ setSelectedIndex(1);
64
+ onSelect("web");
65
+ }
66
+ });
67
+ return /* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", paddingY: 1 }, /* @__PURE__ */ React.createElement(ink.Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(ink.Text, null, "How would you like to authenticate?")), /* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column" }, options.map((option, index) => {
68
+ const isSelected = selectedIndex === index;
69
+ return /* @__PURE__ */ React.createElement(ink.Box, { key: option.method, marginY: 0 }, /* @__PURE__ */ React.createElement(ink.Text, { color: isSelected ? "cyan" : "gray" }, isSelected ? "\u203A " : " ", index + 1, ". ", option.label));
70
+ })), /* @__PURE__ */ React.createElement(ink.Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(ink.Text, { dimColor: true }, "Use arrows or 1-2 to select, Enter to confirm")));
71
+ };
72
+
73
+ async function doAuth() {
74
+ console.clear();
75
+ const authMethod = await selectAuthenticationMethod();
76
+ if (!authMethod) {
77
+ console.log("\nAuthentication cancelled.\n");
78
+ process.exit(0);
79
+ }
80
+ const secret = new Uint8Array(node_crypto.randomBytes(32));
81
+ const keypair = tweetnacl.box.keyPair.fromSecretKey(secret);
82
+ try {
83
+ if (logger.isDebug()) {
84
+ console.log(`[AUTH DEBUG] Sending auth request to: ${logger.configuration.serverUrl}/v1/auth/request`);
85
+ console.log(`[AUTH DEBUG] Public key: ${logger.encodeBase64(keypair.publicKey).substring(0, 20)}...`);
86
+ }
87
+ await axios.post(`${logger.configuration.serverUrl}/v1/auth/request`, {
88
+ publicKey: logger.encodeBase64(keypair.publicKey),
89
+ supportsV2: true
90
+ });
91
+ if (logger.isDebug()) {
92
+ console.log(`[AUTH DEBUG] Auth request sent successfully`);
93
+ }
94
+ } catch (error) {
95
+ if (logger.isDebug()) {
96
+ console.log(`[AUTH DEBUG] Failed to send auth request:`, error);
97
+ }
98
+ console.log("Failed to create authentication request, please try again later.");
99
+ return null;
100
+ }
101
+ if (authMethod === "mobile") {
102
+ return await doMobileAuth(keypair);
103
+ } else {
104
+ return await doWebAuth(keypair);
105
+ }
106
+ }
107
+ function selectAuthenticationMethod() {
108
+ return new Promise((resolve) => {
109
+ let hasResolved = false;
110
+ const onSelect = (method) => {
111
+ if (!hasResolved) {
112
+ hasResolved = true;
113
+ app.unmount();
114
+ resolve(method);
115
+ }
116
+ };
117
+ const onCancel = () => {
118
+ if (!hasResolved) {
119
+ hasResolved = true;
120
+ app.unmount();
121
+ resolve(null);
122
+ }
123
+ };
124
+ const app = ink.render(React.createElement(AuthSelector, { onSelect, onCancel }), {
125
+ exitOnCtrlC: false,
126
+ patchConsole: false
127
+ });
128
+ });
129
+ }
130
+ async function doMobileAuth(keypair) {
131
+ console.clear();
132
+ console.log("\nMobile Authentication\n");
133
+ console.log("Scan this QR code with your Happy mobile app:\n");
134
+ const authUrl = "happy://terminal?" + logger.encodeBase64Url(keypair.publicKey);
135
+ displayQRCode(authUrl);
136
+ console.log("\nOr manually enter this URL:");
137
+ console.log(authUrl);
138
+ console.log("");
139
+ return await waitForAuthentication(keypair);
140
+ }
141
+ async function doWebAuth(keypair) {
142
+ console.clear();
143
+ console.log("\nWeb Authentication\n");
144
+ const webUrl = generateWebAuthUrl(keypair.publicKey);
145
+ console.log("Opening your browser...");
146
+ const browserOpened = await browser.openBrowser(webUrl);
147
+ if (browserOpened) {
148
+ console.log("\u2713 Browser opened\n");
149
+ console.log("Complete authentication in your browser window.");
150
+ } else {
151
+ console.log("Could not open browser automatically.");
152
+ }
153
+ console.log("\nIf the browser did not open, please copy and paste this URL:");
154
+ console.log(webUrl);
155
+ console.log("");
156
+ return await waitForAuthentication(keypair);
157
+ }
158
+ async function waitForAuthentication(keypair) {
159
+ process.stdout.write("Waiting for authentication");
160
+ let dots = 0;
161
+ let cancelled = false;
162
+ const handleInterrupt = () => {
163
+ cancelled = true;
164
+ console.log("\n\nAuthentication cancelled.");
165
+ process.exit(0);
166
+ };
167
+ process.on("SIGINT", handleInterrupt);
168
+ try {
169
+ while (!cancelled) {
170
+ try {
171
+ const response = await axios.post(`${logger.configuration.serverUrl}/v1/auth/request`, {
172
+ publicKey: logger.encodeBase64(keypair.publicKey),
173
+ supportsV2: true
174
+ });
175
+ if (response.data.state === "authorized") {
176
+ let token = response.data.token;
177
+ let r = logger.decodeBase64(response.data.response);
178
+ let decrypted = decryptWithEphemeralKey(r, keypair.secretKey);
179
+ if (decrypted) {
180
+ if (decrypted.length === 32) {
181
+ const credentials = {
182
+ secret: decrypted,
183
+ token
184
+ };
185
+ await logger.writeCredentialsLegacy(credentials);
186
+ console.log("\n\n\u2713 Authentication successful\n");
187
+ return {
188
+ encryption: {
189
+ type: "legacy",
190
+ secret: decrypted
191
+ },
192
+ token
193
+ };
194
+ } else {
195
+ if (decrypted[0] === 0) {
196
+ const credentials = {
197
+ publicKey: decrypted.slice(1, 33),
198
+ machineKey: node_crypto.randomBytes(32),
199
+ token
200
+ };
201
+ await logger.writeCredentialsDataKey(credentials);
202
+ console.log("\n\n\u2713 Authentication successful\n");
203
+ return {
204
+ encryption: {
205
+ type: "dataKey",
206
+ publicKey: credentials.publicKey,
207
+ machineKey: credentials.machineKey
208
+ },
209
+ token
210
+ };
211
+ } else {
212
+ console.log("\n\nFailed to decrypt response. Please try again.");
213
+ return null;
214
+ }
215
+ }
216
+ } else {
217
+ console.log("\n\nFailed to decrypt response. Please try again.");
218
+ return null;
219
+ }
220
+ }
221
+ } catch (error) {
222
+ console.log("\n\nFailed to check authentication status. Please try again.");
223
+ return null;
224
+ }
225
+ process.stdout.write("\rWaiting for authentication" + ".".repeat(dots % 3 + 1) + " ");
226
+ dots++;
227
+ await time.delay(1e3);
228
+ }
229
+ } finally {
230
+ process.off("SIGINT", handleInterrupt);
231
+ }
232
+ return null;
233
+ }
234
+ function decryptWithEphemeralKey(encryptedBundle, recipientSecretKey) {
235
+ const ephemeralPublicKey = encryptedBundle.slice(0, 32);
236
+ const nonce = encryptedBundle.slice(32, 32 + tweetnacl.box.nonceLength);
237
+ const encrypted = encryptedBundle.slice(32 + tweetnacl.box.nonceLength);
238
+ const decrypted = tweetnacl.box.open(encrypted, nonce, ephemeralPublicKey, recipientSecretKey);
239
+ if (!decrypted) {
240
+ return null;
241
+ }
242
+ return decrypted;
243
+ }
244
+ async function authAndSetupMachineIfNeeded() {
245
+ logger.logger.debug("[AUTH] Starting auth and machine setup...");
246
+ let credentials = await logger.readCredentials();
247
+ let newAuth = false;
248
+ if (!credentials) {
249
+ logger.logger.debug("[AUTH] No credentials found, starting authentication flow...");
250
+ const authResult = await doAuth();
251
+ if (!authResult) {
252
+ throw new Error("Authentication failed or was cancelled");
253
+ }
254
+ credentials = authResult;
255
+ newAuth = true;
256
+ } else {
257
+ logger.logger.debug("[AUTH] Using existing credentials");
258
+ }
259
+ const settings = await logger.updateSettings(async (s) => {
260
+ if (newAuth || !s.machineId) {
261
+ return {
262
+ ...s,
263
+ machineId: node_crypto.randomUUID()
264
+ };
265
+ }
266
+ return s;
267
+ });
268
+ logger.logger.debug(`[AUTH] Machine ID: ${settings.machineId}`);
269
+ return { credentials, machineId: settings.machineId };
270
+ }
271
+
272
+ exports.authAndSetupMachineIfNeeded = authAndSetupMachineIfNeeded;
273
+ exports.decryptWithEphemeralKey = decryptWithEphemeralKey;
274
+ exports.doAuth = doAuth;
@@ -0,0 +1,183 @@
1
+ 'use strict';
2
+
3
+ var chalk = require('chalk');
4
+ var logger = require('./persistence-JLUn_Nou.cjs');
5
+ var auth = require('./auth-BIleVCw0.cjs');
6
+ var fs = require('node:fs');
7
+ var node_readline = require('node:readline');
8
+ var controlClient = require('./controlClient-DZMIsKsT.cjs');
9
+ var os = require('node:os');
10
+ require('node:fs/promises');
11
+ require('node:path');
12
+ require('zod');
13
+ require('node:crypto');
14
+ require('tweetnacl');
15
+ require('fs');
16
+ require('axios');
17
+ require('qrcode-terminal');
18
+ require('./time-Bj2HRkKH.cjs');
19
+ require('./browser-Cc08m7of.cjs');
20
+ require('open');
21
+ require('react');
22
+ require('ink');
23
+ require('./projectPath-ChLhdOyt.cjs');
24
+ require('path');
25
+ require('url');
26
+
27
+ async function handleAuthCommand(args) {
28
+ const subcommand = args[0];
29
+ if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
30
+ showAuthHelp();
31
+ return;
32
+ }
33
+ switch (subcommand) {
34
+ case "login":
35
+ await handleAuthLogin(args.slice(1));
36
+ break;
37
+ case "logout":
38
+ await handleAuthLogout();
39
+ break;
40
+ case "status":
41
+ await handleAuthStatus();
42
+ break;
43
+ default:
44
+ console.error(chalk.red(`Unknown auth subcommand: ${subcommand}`));
45
+ showAuthHelp();
46
+ process.exit(1);
47
+ }
48
+ }
49
+ function showAuthHelp() {
50
+ console.log(`
51
+ ${chalk.bold("happy auth")} - Authentication management
52
+
53
+ ${chalk.bold("Usage:")}
54
+ happy auth login [--force] Authenticate with Happy
55
+ happy auth logout Remove authentication and machine data
56
+ happy auth status Show authentication status
57
+ happy auth help Show this help message
58
+
59
+ ${chalk.bold("Options:")}
60
+ --force Clear credentials, machine ID, and stop daemon before re-auth
61
+
62
+ ${chalk.gray("PS: Your master secret never leaves your mobile/web device. Each CLI machine")}
63
+ ${chalk.gray("receives only a derived key for per-machine encryption, so backup codes")}
64
+ ${chalk.gray("cannot be displayed from the CLI.")}
65
+ `);
66
+ }
67
+ async function handleAuthLogin(args) {
68
+ const forceAuth = args.includes("--force") || args.includes("-f");
69
+ if (forceAuth) {
70
+ console.log(chalk.yellow("Force authentication requested."));
71
+ console.log(chalk.gray("This will:"));
72
+ console.log(chalk.gray(" \u2022 Clear existing credentials"));
73
+ console.log(chalk.gray(" \u2022 Clear machine ID"));
74
+ console.log(chalk.gray(" \u2022 Stop daemon if running"));
75
+ console.log(chalk.gray(" \u2022 Re-authenticate and register machine\n"));
76
+ try {
77
+ logger.logger.debug("Stopping daemon for force auth...");
78
+ await controlClient.stopDaemon();
79
+ console.log(chalk.gray("\u2713 Stopped daemon"));
80
+ } catch (error) {
81
+ logger.logger.debug("Daemon was not running or failed to stop:", error);
82
+ }
83
+ await logger.clearCredentials();
84
+ console.log(chalk.gray("\u2713 Cleared credentials"));
85
+ await logger.clearMachineId();
86
+ console.log(chalk.gray("\u2713 Cleared machine ID"));
87
+ console.log("");
88
+ }
89
+ if (!forceAuth) {
90
+ const existingCreds = await logger.readCredentials();
91
+ const settings = await logger.readSettings();
92
+ if (existingCreds && settings?.machineId) {
93
+ console.log(chalk.green("\u2713 Already authenticated"));
94
+ console.log(chalk.gray(` Machine ID: ${settings.machineId}`));
95
+ console.log(chalk.gray(` Host: ${os.hostname()}`));
96
+ console.log(chalk.gray(` Use 'happy auth login --force' to re-authenticate`));
97
+ return;
98
+ } else if (existingCreds && !settings?.machineId) {
99
+ console.log(chalk.yellow("\u26A0\uFE0F Credentials exist but machine ID is missing"));
100
+ console.log(chalk.gray(" This can happen if --auth flag was used previously"));
101
+ console.log(chalk.gray(" Fixing by setting up machine...\n"));
102
+ }
103
+ }
104
+ try {
105
+ const result = await auth.authAndSetupMachineIfNeeded();
106
+ console.log(chalk.green("\n\u2713 Authentication successful"));
107
+ console.log(chalk.gray(` Machine ID: ${result.machineId}`));
108
+ } catch (error) {
109
+ console.error(chalk.red("Authentication failed:"), error instanceof Error ? error.message : "Unknown error");
110
+ process.exit(1);
111
+ }
112
+ }
113
+ async function handleAuthLogout() {
114
+ const happyDir = logger.configuration.happyHomeDir;
115
+ const credentials = await logger.readCredentials();
116
+ if (!credentials) {
117
+ console.log(chalk.yellow("Not currently authenticated"));
118
+ return;
119
+ }
120
+ console.log(chalk.blue("This will log you out of Happy"));
121
+ console.log(chalk.yellow("\u26A0\uFE0F You will need to re-authenticate to use Happy again"));
122
+ const rl = node_readline.createInterface({
123
+ input: process.stdin,
124
+ output: process.stdout
125
+ });
126
+ const answer = await new Promise((resolve) => {
127
+ rl.question(chalk.yellow("Are you sure you want to log out? (y/N): "), resolve);
128
+ });
129
+ rl.close();
130
+ if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
131
+ try {
132
+ try {
133
+ await controlClient.stopDaemon();
134
+ console.log(chalk.gray("Stopped daemon"));
135
+ } catch {
136
+ }
137
+ if (fs.existsSync(happyDir)) {
138
+ fs.rmSync(happyDir, { recursive: true, force: true });
139
+ }
140
+ console.log(chalk.green("\u2713 Successfully logged out"));
141
+ console.log(chalk.gray(' Run "happy auth login" to authenticate again'));
142
+ } catch (error) {
143
+ throw new Error(`Failed to logout: ${error instanceof Error ? error.message : "Unknown error"}`);
144
+ }
145
+ } else {
146
+ console.log(chalk.blue("Logout cancelled"));
147
+ }
148
+ }
149
+ async function handleAuthStatus() {
150
+ const credentials = await logger.readCredentials();
151
+ const settings = await logger.readSettings();
152
+ console.log(chalk.bold("\nAuthentication Status\n"));
153
+ if (!credentials) {
154
+ console.log(chalk.red("\u2717 Not authenticated"));
155
+ console.log(chalk.gray(' Run "happy auth login" to authenticate'));
156
+ return;
157
+ }
158
+ console.log(chalk.green("\u2713 Authenticated"));
159
+ const tokenPreview = credentials.token.substring(0, 30) + "...";
160
+ console.log(chalk.gray(` Token: ${tokenPreview}`));
161
+ if (settings?.machineId) {
162
+ console.log(chalk.green("\u2713 Machine registered"));
163
+ console.log(chalk.gray(` Machine ID: ${settings.machineId}`));
164
+ console.log(chalk.gray(` Host: ${os.hostname()}`));
165
+ } else {
166
+ console.log(chalk.yellow("\u26A0\uFE0F Machine not registered"));
167
+ console.log(chalk.gray(' Run "happy auth login --force" to fix this'));
168
+ }
169
+ console.log(chalk.gray(`
170
+ Data directory: ${logger.configuration.happyHomeDir}`));
171
+ try {
172
+ const running = await controlClient.checkIfDaemonRunningAndCleanupStaleState();
173
+ if (running) {
174
+ console.log(chalk.green("\u2713 Daemon running"));
175
+ } else {
176
+ console.log(chalk.gray("\u2717 Daemon not running"));
177
+ }
178
+ } catch {
179
+ console.log(chalk.gray("\u2717 Daemon not running"));
180
+ }
181
+ }
182
+
183
+ exports.handleAuthCommand = handleAuthCommand;
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ var open = require('open');
4
+ var logger = require('./persistence-JLUn_Nou.cjs');
5
+
6
+ async function openBrowser(url) {
7
+ try {
8
+ if (!process.stdout.isTTY || process.env.CI || process.env.HEADLESS) {
9
+ logger.logger.debug("[browser] Headless environment detected, skipping browser open");
10
+ return false;
11
+ }
12
+ logger.logger.debug(`[browser] Attempting to open URL: ${url}`);
13
+ await open(url);
14
+ logger.logger.debug("[browser] Browser opened successfully");
15
+ return true;
16
+ } catch (error) {
17
+ logger.logger.debug("[browser] Failed to open browser:", error);
18
+ return false;
19
+ }
20
+ }
21
+
22
+ exports.openBrowser = openBrowser;
@@ -0,0 +1,20 @@
1
+ import open from 'open';
2
+ import { l as logger } from './persistence-BFjvtUad.mjs';
3
+
4
+ async function openBrowser(url) {
5
+ try {
6
+ if (!process.stdout.isTTY || process.env.CI || process.env.HEADLESS) {
7
+ logger.debug("[browser] Headless environment detected, skipping browser open");
8
+ return false;
9
+ }
10
+ logger.debug(`[browser] Attempting to open URL: ${url}`);
11
+ await open(url);
12
+ logger.debug("[browser] Browser opened successfully");
13
+ return true;
14
+ } catch (error) {
15
+ logger.debug("[browser] Failed to open browser:", error);
16
+ return false;
17
+ }
18
+ }
19
+
20
+ export { openBrowser as o };