@zonease/happy 0.6.38 → 0.6.40

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 (112) hide show
  1. package/bin/happy.mjs +10 -0
  2. package/dist/{types-DvTsFaqR.cjs → api-C7FyJfZ1.cjs} +400 -1964
  3. package/dist/{types-BWpRU1VN.mjs → api-D6WL40-U.mjs} +220 -1729
  4. package/dist/auth-C7ZScWEw.cjs +274 -0
  5. package/dist/auth-DCsIoZLT.cjs +183 -0
  6. package/dist/auth-DO9GexAR.mjs +181 -0
  7. package/dist/auth-DxJ3VvrX.mjs +270 -0
  8. package/dist/browser-AoVGRX7y.mjs +20 -0
  9. package/dist/browser-DzgO4oaD.cjs +22 -0
  10. package/dist/claudeLocal-C6BdzhDx.cjs +352 -0
  11. package/dist/claudeLocal-CWNGpJ0-.mjs +344 -0
  12. package/dist/codex/happyMcpStdioBridge.cjs +4 -1
  13. package/dist/codex/happyMcpStdioBridge.mjs +4 -1
  14. package/dist/common-BdNgghUJ.mjs +75 -0
  15. package/dist/common-CZvSRU4p.cjs +83 -0
  16. package/dist/{config-0Xnc8ARM.cjs → config-CclB3QW9.cjs} +21 -34
  17. package/dist/{config-_GW4YBCP.mjs → config-DZk-mJ0K.mjs} +7 -20
  18. package/dist/connect-BXLUKJ5P.mjs +679 -0
  19. package/dist/connect-k9CqDJ-T.cjs +681 -0
  20. package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
  21. package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
  22. package/dist/controlClient-B23M-WPp.cjs +177 -0
  23. package/dist/controlClient-DB5tDU7V.mjs +167 -0
  24. package/dist/deviceKeys-BTdo34Uz.mjs +175 -0
  25. package/dist/deviceKeys-C540DcXl.cjs +182 -0
  26. package/dist/diagnose-B3D1a_v0.cjs +60 -0
  27. package/dist/diagnose-CuRKXxt1.mjs +58 -0
  28. package/dist/doctor-BQGLhrcI.cjs +214 -0
  29. package/dist/doctor-C08m5Z9f.cjs +78 -0
  30. package/dist/doctor-CU4JLGQ1.mjs +211 -0
  31. package/dist/doctor-ON7pN5G5.mjs +74 -0
  32. package/dist/downloadImage-DZXI3mXL.mjs +887 -0
  33. package/dist/downloadImage-cQ1Z7hkC.cjs +897 -0
  34. package/dist/enroll-B55BQR56.mjs +113 -0
  35. package/dist/enroll-Bo-CNio1.cjs +115 -0
  36. package/dist/evidence-DQp8QWcv.cjs +129 -0
  37. package/dist/evidence-DTYRAaOZ.mjs +127 -0
  38. package/dist/formatImageMessage-CixDYY6G.cjs +46 -0
  39. package/dist/formatImageMessage-DbKSSjMx.mjs +43 -0
  40. package/dist/github-DKcyF1zp.mjs +57 -0
  41. package/dist/github-h9GhJJ_C.cjs +59 -0
  42. package/dist/index-CDTNgfUf.cjs +578 -0
  43. package/dist/index-CPKdvi7J.mjs +554 -0
  44. package/dist/index.cjs +812 -40
  45. package/dist/index.mjs +813 -40
  46. package/dist/install-B1e6rdy7.mjs +94 -0
  47. package/dist/install-CgUPGIoF.mjs +95 -0
  48. package/dist/install-D7Ir7ciZ.cjs +96 -0
  49. package/dist/install-DSDufaPd.cjs +98 -0
  50. package/dist/lib.cjs +18 -12
  51. package/dist/lib.d.cts +77 -0
  52. package/dist/lib.d.mts +77 -0
  53. package/dist/lib.mjs +13 -7
  54. package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Bfei9wPq.mjs} +4 -2
  55. package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-CbLGtvST.cjs} +63 -61
  56. package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
  57. package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
  58. package/dist/persistence-CBTtC_dm.cjs +996 -0
  59. package/dist/persistence-DKfF81pd.mjs +944 -0
  60. package/dist/projectPath-BTBIMB57.mjs +10 -0
  61. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  62. package/dist/prompt-BTWDZZO0.cjs +25 -0
  63. package/dist/prompt-BsAZsPbo.mjs +22 -0
  64. package/dist/release-BMEzNONE.mjs +168 -0
  65. package/dist/release-EhOJeAZe.cjs +171 -0
  66. package/dist/run-BVZsMNwN.mjs +2164 -0
  67. package/dist/run-CURx7LhK.cjs +2188 -0
  68. package/dist/runClaude-6Gi0sYQy.mjs +3763 -0
  69. package/dist/runClaude-CL3Kt5ex.cjs +3766 -0
  70. package/dist/{runCodex-DiKzBf9q.mjs → runCodex-ClwEgJ7M.mjs} +36 -20
  71. package/dist/{runCodex-skq0j05d.cjs → runCodex-YKyVBkJ3.cjs} +169 -153
  72. package/dist/{runGemini-BeqrVq8R.mjs → runGemini-BPWxVr60.mjs} +34 -17
  73. package/dist/{runGemini-CVp-CEIh.cjs → runGemini-Xz2W1spn.cjs} +212 -195
  74. package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-CdCWiiLr.mjs} +14 -38
  75. package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-DjZyCvDI.cjs} +31 -55
  76. package/dist/{serve-BNdoEDVx.mjs → serve-B48JttQ3.mjs} +12 -35
  77. package/dist/{serve-BECdtivY.cjs → serve-B8vaWQA0.cjs} +35 -58
  78. package/dist/session-BXboDn2V.mjs +108 -0
  79. package/dist/session-BZO25zxp.cjs +110 -0
  80. package/dist/sessionKeyCache-B6cGadYL.mjs +33 -0
  81. package/dist/sessionKeyCache-CDmexJ9p.cjs +36 -0
  82. package/dist/sessionList-CgAYZpNj.mjs +51 -0
  83. package/dist/sessionList-lQ-nqEhc.cjs +54 -0
  84. package/dist/sessionSummary-CcORiQSq.cjs +393 -0
  85. package/dist/sessionSummary-DCWQoaDP.mjs +387 -0
  86. package/dist/spawnHappyCLI-KiazE3kL.cjs +70 -0
  87. package/dist/spawnHappyCLI-yBIP_Oqi.mjs +66 -0
  88. package/dist/ssh-q5uZhqBf.mjs +359 -0
  89. package/dist/ssh-yMllSHu5.cjs +365 -0
  90. package/dist/systemdScope-BeOtAkhk.mjs +25 -0
  91. package/dist/systemdScope-DW3-UoKB.cjs +29 -0
  92. package/dist/task-_nr7J19j.cjs +167 -0
  93. package/dist/task-wNX1N2i4.mjs +165 -0
  94. package/dist/time-Bj2HRkKH.cjs +33 -0
  95. package/dist/time-DgsBLJA_.mjs +29 -0
  96. package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
  97. package/dist/trimIdent-BAjmv_TG.mjs +20 -0
  98. package/dist/types-BoJh4Qfv.mjs +57 -0
  99. package/dist/types-DWeB7aqh.cjs +59 -0
  100. package/dist/uninstall-Buaz7d-X.cjs +77 -0
  101. package/dist/uninstall-Dxf6_4mQ.mjs +75 -0
  102. package/dist/update-CGlIfa8e.cjs +111 -0
  103. package/dist/update-CnnoX2cV.mjs +109 -0
  104. package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
  105. package/dist/workflowCommon-Bl568-rt.cjs +62 -0
  106. package/dist/workflowReports-BEWuQesA.cjs +113 -0
  107. package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
  108. package/package.json +1 -1
  109. package/dist/index-BbCDDvoB.cjs +0 -11376
  110. package/dist/index-vvZXdswy.mjs +0 -11336
  111. package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
  112. package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
package/dist/index.mjs CHANGED
@@ -1,45 +1,818 @@
1
- import 'chalk';
2
- import './types-BWpRU1VN.mjs';
3
- import './index-vvZXdswy.mjs';
4
- import 'zod';
5
- import 'node:child_process';
6
- import 'axios';
7
- import 'fs';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
2
+ import { l as logger, i as isDebug, r as readCredentials, a as readSettings, p as packageJson } from './persistence-DKfF81pd.mjs';
3
+ import { z } from 'zod';
4
+ import { execFileSync } from 'node:child_process';
5
+ import 'node:fs/promises';
8
6
  import 'node:fs';
9
7
  import 'node:os';
10
8
  import 'node:path';
11
- import 'node:events';
12
- import 'socket.io-client';
13
- import '@paralleldrive/cuid2';
14
9
  import 'node:crypto';
15
10
  import 'tweetnacl';
16
- import 'node:fs/promises';
17
- import 'node:util';
18
- import 'child_process';
19
- import 'util';
20
- import 'fs/promises';
21
- import 'path';
22
- import 'url';
23
- import 'node:module';
24
- import 'ws';
25
- import 'crypto';
26
- import '@stablelib/base64';
27
- import 'node:readline';
28
- import 'expo-server-sdk';
29
- import './mcpToolSchemas-CdPXJQmb.mjs';
30
- import 'ink';
31
- import 'react';
32
- import 'node:url';
33
- import 'ps-list';
34
- import 'cross-spawn';
35
- import 'os';
36
- import 'tmp';
37
- import 'qrcode-terminal';
38
- import 'open';
39
- import 'fastify';
40
- import 'fastify-type-provider-zod';
41
- import '@modelcontextprotocol/sdk/server/mcp.js';
42
- import 'node:http';
43
- import '@modelcontextprotocol/sdk/server/streamableHttp.js';
44
- import '@modelcontextprotocol/sdk/types.js';
45
- import 'http';
11
+ import 'fs';
12
+
13
+ async function spawnAndWaitForDaemon() {
14
+ const { spawnHappyCLI } = await import('./spawnHappyCLI-yBIP_Oqi.mjs').then(function (n) { return n.a; });
15
+ const { checkIfDaemonRunningAndCleanupStaleState } = await import('./controlClient-DB5tDU7V.mjs');
16
+ const child = spawnHappyCLI(["daemon", "start-sync"], {
17
+ detached: true,
18
+ stdio: "ignore"
19
+ });
20
+ child.unref();
21
+ for (let i = 0; i < 50; i++) {
22
+ if (await checkIfDaemonRunningAndCleanupStaleState()) {
23
+ return true;
24
+ }
25
+ await new Promise((resolve) => setTimeout(resolve, 100));
26
+ }
27
+ return false;
28
+ }
29
+ (async () => {
30
+ const args = process.argv.slice(2);
31
+ if (!args.includes("--version")) {
32
+ logger.debug("Starting happy CLI with args: ", process.argv);
33
+ }
34
+ const subcommand = args[0];
35
+ if (!args.includes("--version")) ;
36
+ if (subcommand === "orchestrator-oneshot") {
37
+ try {
38
+ const { runOrchestratorOneShot } = await import('./runOneShot-CdCWiiLr.mjs');
39
+ const exitCode = await runOrchestratorOneShot(args.slice(1));
40
+ process.exit(exitCode);
41
+ } catch (error) {
42
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
43
+ if (isDebug()) {
44
+ console.error(error);
45
+ }
46
+ process.exit(1);
47
+ }
48
+ return;
49
+ } else if (subcommand === "doctor") {
50
+ const { killRunawayHappyProcesses } = await import('./doctor-ON7pN5G5.mjs');
51
+ const { runDoctorCommand } = await import('./doctor-CU4JLGQ1.mjs');
52
+ if (args[1] === "clean") {
53
+ const result = await killRunawayHappyProcesses();
54
+ console.log(`Cleaned up ${result.killed} runaway processes`);
55
+ if (result.errors.length > 0) {
56
+ console.log("Errors:", result.errors);
57
+ }
58
+ process.exit(0);
59
+ }
60
+ await runDoctorCommand();
61
+ return;
62
+ } else if (subcommand === "auth") {
63
+ try {
64
+ const { handleAuthCommand } = await import('./auth-DO9GexAR.mjs');
65
+ await handleAuthCommand(args.slice(1));
66
+ } catch (error) {
67
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
68
+ if (isDebug()) {
69
+ console.error(error);
70
+ }
71
+ process.exit(1);
72
+ }
73
+ return;
74
+ } else if (subcommand === "connect") {
75
+ try {
76
+ const { handleConnectCommand } = await import('./connect-BXLUKJ5P.mjs');
77
+ await handleConnectCommand(args.slice(1));
78
+ } catch (error) {
79
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
80
+ if (isDebug()) {
81
+ console.error(error);
82
+ }
83
+ process.exit(1);
84
+ }
85
+ return;
86
+ } else if (subcommand === "codex") {
87
+ const { authAndSetupMachineIfNeeded } = await import('./auth-DxJ3VvrX.mjs');
88
+ const { isDaemonRunningCurrentlyInstalledHappyVersion } = await import('./controlClient-DB5tDU7V.mjs');
89
+ const { spawnHappyCLI } = await import('./spawnHappyCLI-yBIP_Oqi.mjs').then(function (n) { return n.a; });
90
+ try {
91
+ const { runCodex } = await import('./runCodex-ClwEgJ7M.mjs');
92
+ let startedBy = void 0;
93
+ for (let i = 1; i < args.length; i++) {
94
+ if (args[i] === "--started-by") {
95
+ startedBy = args[++i];
96
+ }
97
+ }
98
+ const {
99
+ credentials
100
+ } = await authAndSetupMachineIfNeeded();
101
+ logger.debug("Ensuring Happy background service is running & matches our version...");
102
+ if (!await isDaemonRunningCurrentlyInstalledHappyVersion()) {
103
+ logger.debug("Starting Happy background service...");
104
+ const daemonProcess = spawnHappyCLI(["daemon", "start-sync"], {
105
+ detached: true,
106
+ stdio: "ignore",
107
+ env: process.env
108
+ });
109
+ daemonProcess.unref();
110
+ await new Promise((resolve) => setTimeout(resolve, 200));
111
+ }
112
+ await runCodex({ credentials, startedBy });
113
+ } catch (error) {
114
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
115
+ if (isDebug()) {
116
+ console.error(error);
117
+ }
118
+ process.exit(1);
119
+ }
120
+ return;
121
+ } else if (subcommand === "gemini") {
122
+ const { authAndSetupMachineIfNeeded } = await import('./auth-DxJ3VvrX.mjs');
123
+ const { isDaemonRunningCurrentlyInstalledHappyVersion } = await import('./controlClient-DB5tDU7V.mjs');
124
+ const { spawnHappyCLI } = await import('./spawnHappyCLI-yBIP_Oqi.mjs').then(function (n) { return n.a; });
125
+ const geminiSubcommand = args[1];
126
+ if (geminiSubcommand === "model" && args[2] === "set" && args[3]) {
127
+ const modelName = args[3];
128
+ const validModels = ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-lite"];
129
+ if (!validModels.includes(modelName)) {
130
+ console.error(`Invalid model: ${modelName}`);
131
+ console.error(`Available models: ${validModels.join(", ")}`);
132
+ process.exit(1);
133
+ }
134
+ try {
135
+ const { existsSync, readFileSync, writeFileSync, mkdirSync } = require("fs");
136
+ const { join } = require("path");
137
+ const { homedir } = require("os");
138
+ const configDir = join(homedir(), ".gemini");
139
+ const configPath = join(configDir, "config.json");
140
+ if (!existsSync(configDir)) {
141
+ mkdirSync(configDir, { recursive: true });
142
+ }
143
+ let config = {};
144
+ if (existsSync(configPath)) {
145
+ try {
146
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
147
+ } catch (error) {
148
+ config = {};
149
+ }
150
+ }
151
+ config.model = modelName;
152
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
153
+ console.log(`\u2713 Model set to: ${modelName}`);
154
+ console.log(` Config saved to: ${configPath}`);
155
+ console.log(` This model will be used in future sessions.`);
156
+ process.exit(0);
157
+ } catch (error) {
158
+ console.error("Failed to save model configuration:", error);
159
+ process.exit(1);
160
+ }
161
+ }
162
+ if (geminiSubcommand === "model" && args[2] === "get") {
163
+ try {
164
+ const { existsSync, readFileSync } = require("fs");
165
+ const { join } = require("path");
166
+ const { homedir } = require("os");
167
+ const configPaths = [
168
+ join(homedir(), ".gemini", "config.json"),
169
+ join(homedir(), ".config", "gemini", "config.json")
170
+ ];
171
+ let model = null;
172
+ for (const configPath of configPaths) {
173
+ if (existsSync(configPath)) {
174
+ try {
175
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
176
+ model = config.model || config.GEMINI_MODEL || null;
177
+ if (model) break;
178
+ } catch (error) {
179
+ }
180
+ }
181
+ }
182
+ if (model) {
183
+ console.log(`Current model: ${model}`);
184
+ } else if (process.env.GEMINI_MODEL) {
185
+ console.log(`Current model: ${process.env.GEMINI_MODEL} (from GEMINI_MODEL env var)`);
186
+ } else {
187
+ console.log("Current model: gemini-2.5-pro (default)");
188
+ }
189
+ process.exit(0);
190
+ } catch (error) {
191
+ console.error("Failed to read model configuration:", error);
192
+ process.exit(1);
193
+ }
194
+ }
195
+ if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
196
+ const projectId = args[3];
197
+ try {
198
+ const { saveGoogleCloudProjectToConfig } = await import('./config-DZk-mJ0K.mjs');
199
+ const { readCredentials: readCredentials2 } = await import('./persistence-DKfF81pd.mjs').then(function (n) { return n.F; });
200
+ const { ApiClient } = await import('./api-D6WL40-U.mjs').then(function (n) { return n.m; });
201
+ let userEmail = void 0;
202
+ try {
203
+ const credentials = await readCredentials2();
204
+ if (credentials) {
205
+ const api = await ApiClient.create(credentials);
206
+ const vendorToken = await api.getVendorToken("gemini");
207
+ if (vendorToken?.oauth?.id_token) {
208
+ const parts = vendorToken.oauth.id_token.split(".");
209
+ if (parts.length === 3) {
210
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
211
+ userEmail = payload.email;
212
+ }
213
+ }
214
+ }
215
+ } catch {
216
+ }
217
+ saveGoogleCloudProjectToConfig(projectId, userEmail);
218
+ console.log(`\u2713 Google Cloud Project set to: ${projectId}`);
219
+ if (userEmail) {
220
+ console.log(` Linked to account: ${userEmail}`);
221
+ }
222
+ console.log(` This project will be used for Google Workspace accounts.`);
223
+ process.exit(0);
224
+ } catch (error) {
225
+ console.error("Failed to save project configuration:", error);
226
+ process.exit(1);
227
+ }
228
+ }
229
+ if (geminiSubcommand === "project" && args[2] === "get") {
230
+ try {
231
+ const { readGeminiLocalConfig } = await import('./config-DZk-mJ0K.mjs');
232
+ const config = readGeminiLocalConfig();
233
+ if (config.googleCloudProject) {
234
+ console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
235
+ if (config.googleCloudProjectEmail) {
236
+ console.log(` Linked to account: ${config.googleCloudProjectEmail}`);
237
+ } else {
238
+ console.log(` Applies to: all accounts (global)`);
239
+ }
240
+ } else if (process.env.GOOGLE_CLOUD_PROJECT) {
241
+ console.log(`Current Google Cloud Project: ${process.env.GOOGLE_CLOUD_PROJECT} (from env var)`);
242
+ } else {
243
+ console.log("No Google Cloud Project configured.");
244
+ console.log("");
245
+ console.log('If you see "Authentication required" error, you may need to set a project:');
246
+ console.log(" happy gemini project set <your-project-id>");
247
+ console.log("");
248
+ console.log("This is required for Google Workspace accounts.");
249
+ console.log("Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca");
250
+ }
251
+ process.exit(0);
252
+ } catch (error) {
253
+ console.error("Failed to read project configuration:", error);
254
+ process.exit(1);
255
+ }
256
+ }
257
+ if (geminiSubcommand === "project" && !args[2]) {
258
+ console.log("Usage: happy gemini project <command>");
259
+ console.log("");
260
+ console.log("Commands:");
261
+ console.log(" set <project-id> Set Google Cloud Project ID");
262
+ console.log(" get Show current Google Cloud Project ID");
263
+ console.log("");
264
+ console.log("Google Workspace accounts require a Google Cloud Project.");
265
+ console.log('If you see "Authentication required" error, set your project ID.');
266
+ console.log("");
267
+ console.log("Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca");
268
+ process.exit(0);
269
+ }
270
+ try {
271
+ const { runGemini } = await import('./runGemini-BPWxVr60.mjs');
272
+ let startedBy = void 0;
273
+ for (let i = 1; i < args.length; i++) {
274
+ if (args[i] === "--started-by") {
275
+ startedBy = args[++i];
276
+ }
277
+ }
278
+ const {
279
+ credentials
280
+ } = await authAndSetupMachineIfNeeded();
281
+ logger.debug("Ensuring Happy background service is running & matches our version...");
282
+ if (!await isDaemonRunningCurrentlyInstalledHappyVersion()) {
283
+ logger.debug("Starting Happy background service...");
284
+ const daemonProcess = spawnHappyCLI(["daemon", "start-sync"], {
285
+ detached: true,
286
+ stdio: "ignore",
287
+ env: process.env
288
+ });
289
+ daemonProcess.unref();
290
+ await new Promise((resolve) => setTimeout(resolve, 200));
291
+ }
292
+ await runGemini({ credentials, startedBy });
293
+ } catch (error) {
294
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
295
+ if (isDebug()) {
296
+ console.error(error);
297
+ }
298
+ process.exit(1);
299
+ }
300
+ return;
301
+ } else if (subcommand === "update") {
302
+ try {
303
+ const { handleUpdateCommand } = await import('./update-CnnoX2cV.mjs');
304
+ await handleUpdateCommand();
305
+ } catch (error) {
306
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
307
+ if (isDebug()) {
308
+ console.error(error);
309
+ }
310
+ process.exit(1);
311
+ }
312
+ return;
313
+ } else if (subcommand === "logout") {
314
+ console.log(chalk.yellow('Note: "happy logout" is deprecated. Use "happy auth logout" instead.\n'));
315
+ try {
316
+ const { handleAuthCommand } = await import('./auth-DO9GexAR.mjs');
317
+ await handleAuthCommand(["logout"]);
318
+ } catch (error) {
319
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
320
+ if (isDebug()) {
321
+ console.error(error);
322
+ }
323
+ process.exit(1);
324
+ }
325
+ return;
326
+ } else if (subcommand === "notify") {
327
+ try {
328
+ await handleNotifyCommand(args.slice(1));
329
+ } catch (error) {
330
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
331
+ if (isDebug()) {
332
+ console.error(error);
333
+ }
334
+ process.exit(1);
335
+ }
336
+ return;
337
+ } else if (subcommand === "session") {
338
+ try {
339
+ const { handleSessionCommand } = await import('./session-BXboDn2V.mjs');
340
+ await handleSessionCommand(args.slice(1));
341
+ } catch (error) {
342
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
343
+ if (isDebug()) {
344
+ console.error(error);
345
+ }
346
+ process.exit(1);
347
+ }
348
+ return;
349
+ } else if (subcommand === "task") {
350
+ try {
351
+ const { handleTaskCommand } = await import('./task-wNX1N2i4.mjs');
352
+ await handleTaskCommand(args.slice(1));
353
+ } catch (error) {
354
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
355
+ if (isDebug()) {
356
+ console.error(error);
357
+ }
358
+ process.exit(1);
359
+ }
360
+ return;
361
+ } else if (subcommand === "release") {
362
+ try {
363
+ const { handleReleaseCommand } = await import('./release-BMEzNONE.mjs');
364
+ await handleReleaseCommand(args.slice(1));
365
+ } catch (error) {
366
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
367
+ if (isDebug()) {
368
+ console.error(error);
369
+ }
370
+ process.exit(1);
371
+ }
372
+ return;
373
+ } else if (subcommand === "github") {
374
+ try {
375
+ const { handleGithubCommand } = await import('./github-DKcyF1zp.mjs');
376
+ await handleGithubCommand(args.slice(1));
377
+ } catch (error) {
378
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
379
+ if (isDebug()) {
380
+ console.error(error);
381
+ }
382
+ process.exit(1);
383
+ }
384
+ return;
385
+ } else if (subcommand === "diagnose") {
386
+ try {
387
+ const { handleDiagnoseCommand } = await import('./diagnose-CuRKXxt1.mjs');
388
+ await handleDiagnoseCommand(args.slice(1));
389
+ } catch (error) {
390
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
391
+ if (isDebug()) {
392
+ console.error(error);
393
+ }
394
+ process.exit(1);
395
+ }
396
+ return;
397
+ } else if (subcommand === "evidence") {
398
+ try {
399
+ const { handleEvidenceCommand } = await import('./evidence-DTYRAaOZ.mjs');
400
+ await handleEvidenceCommand(args.slice(1));
401
+ } catch (error) {
402
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
403
+ if (isDebug()) {
404
+ console.error(error);
405
+ }
406
+ process.exit(1);
407
+ }
408
+ return;
409
+ } else if (subcommand === "mcp") {
410
+ const mcpSubcommand = args[1];
411
+ if (mcpSubcommand !== "serve") {
412
+ console.error(chalk.red("Usage: happy mcp serve"));
413
+ process.exit(1);
414
+ }
415
+ try {
416
+ const { runMcpServe } = await import('./serve-B48JttQ3.mjs');
417
+ await runMcpServe();
418
+ } catch (error) {
419
+ process.stderr.write(`[happy-mcp] fatal: ${error instanceof Error ? error.message : "unknown error"}
420
+ `);
421
+ process.exit(1);
422
+ }
423
+ return;
424
+ } else if (subcommand === "ssh") {
425
+ const credentials = await readCredentials();
426
+ if (!credentials) {
427
+ console.error(chalk.red("Error:"), 'Not authenticated. Run "happy auth" first.');
428
+ process.exit(1);
429
+ }
430
+ const { parseSshArgs, runOnDevice, sshDevice, sshPickAndConnect } = await import('./ssh-q5uZhqBf.mjs');
431
+ const { target, command, timeoutMs, stream } = parseSshArgs(args.slice(1));
432
+ try {
433
+ if (command) {
434
+ if (!target) {
435
+ console.error(chalk.red("Error:"), "Which device? Usage: happy ssh <device> -- <command>");
436
+ process.exit(1);
437
+ }
438
+ process.exit(await runOnDevice(credentials, target, command, { timeoutMs, stream }));
439
+ }
440
+ if (!target) {
441
+ process.exit(await sshPickAndConnect(credentials));
442
+ }
443
+ process.exit(await sshDevice(credentials, target));
444
+ } catch (error) {
445
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
446
+ process.exit(1);
447
+ }
448
+ } else if (subcommand === "device") {
449
+ const deviceSubcommand = args[1];
450
+ if (deviceSubcommand === "enroll") {
451
+ const { enrollDevice } = await import('./enroll-B55BQR56.mjs');
452
+ const { install } = await import('./install-B1e6rdy7.mjs');
453
+ const token = args[2];
454
+ if (!token) {
455
+ console.error(chalk.red("Error:"), "Missing enrollment token. Usage: happy device enroll <token>");
456
+ process.exit(1);
457
+ }
458
+ try {
459
+ const result = await enrollDevice(token, { force: args.includes("--force") });
460
+ if (result.alreadyEnrolled) {
461
+ console.log("This machine is already linked to a Happy account. Re-run with --force to relink.");
462
+ } else {
463
+ console.log("Device enrolled");
464
+ }
465
+ await install();
466
+ console.log("Daemon installed and started");
467
+ } catch (error) {
468
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
469
+ process.exit(1);
470
+ }
471
+ process.exit(0);
472
+ }
473
+ console.log(`
474
+ ${chalk.bold("happy device")} - Device enrollment
475
+
476
+ ${chalk.bold("Usage:")}
477
+ happy device enroll <token> Link this machine to a Happy account and start the daemon
478
+ `);
479
+ process.exit(0);
480
+ } else if (subcommand === "daemon") {
481
+ const { startDaemon } = await import('./run-BVZsMNwN.mjs').then(function (n) { return n.r; });
482
+ const { install } = await import('./install-B1e6rdy7.mjs');
483
+ const { uninstall } = await import('./uninstall-Dxf6_4mQ.mjs');
484
+ const { runDoctorCommand } = await import('./doctor-CU4JLGQ1.mjs');
485
+ const { getLatestDaemonLog } = await import('./persistence-DKfF81pd.mjs').then(function (n) { return n.E; });
486
+ const { listDaemonSessions, stopDaemonSession, stopDaemon } = await import('./controlClient-DB5tDU7V.mjs');
487
+ const daemonSubcommand = args[1];
488
+ if (daemonSubcommand === "list") {
489
+ try {
490
+ const sessions = await listDaemonSessions();
491
+ if (sessions.length === 0) {
492
+ console.log("No active sessions this daemon is aware of (they might have been started by a previous version of the daemon)");
493
+ } else {
494
+ console.log("Active sessions:");
495
+ console.log(JSON.stringify(sessions, null, 2));
496
+ }
497
+ } catch (error) {
498
+ console.log("No daemon running");
499
+ }
500
+ return;
501
+ } else if (daemonSubcommand === "stop-session") {
502
+ const sessionId = args[2];
503
+ if (!sessionId) {
504
+ console.error("Session ID required");
505
+ process.exit(1);
506
+ }
507
+ try {
508
+ const success = await stopDaemonSession(sessionId);
509
+ console.log(success ? "Session stopped" : "Failed to stop session");
510
+ } catch (error) {
511
+ console.log("No daemon running");
512
+ }
513
+ return;
514
+ } else if (daemonSubcommand === "start") {
515
+ const started = await spawnAndWaitForDaemon();
516
+ console.log(started ? "Daemon started successfully" : "Failed to start daemon");
517
+ process.exit(started ? 0 : 1);
518
+ } else if (daemonSubcommand === "start-sync") {
519
+ await startDaemon();
520
+ process.exit(0);
521
+ } else if (daemonSubcommand === "stop") {
522
+ await stopDaemon();
523
+ process.exit(0);
524
+ } else if (daemonSubcommand === "restart") {
525
+ await stopDaemon();
526
+ const started = await spawnAndWaitForDaemon();
527
+ console.log(started ? "Daemon restarted successfully" : "Failed to restart daemon");
528
+ process.exit(started ? 0 : 1);
529
+ } else if (daemonSubcommand === "status") {
530
+ await runDoctorCommand("daemon");
531
+ process.exit(0);
532
+ } else if (daemonSubcommand === "logs") {
533
+ const latest = await getLatestDaemonLog();
534
+ if (!latest) {
535
+ console.log("No daemon logs found");
536
+ } else {
537
+ console.log(latest.path);
538
+ }
539
+ process.exit(0);
540
+ } else if (daemonSubcommand === "enable" || daemonSubcommand === "install") {
541
+ try {
542
+ await install();
543
+ } catch (error) {
544
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
545
+ process.exit(1);
546
+ }
547
+ process.exit(0);
548
+ } else if (daemonSubcommand === "disable" || daemonSubcommand === "uninstall") {
549
+ try {
550
+ await uninstall();
551
+ } catch (error) {
552
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
553
+ process.exit(1);
554
+ }
555
+ process.exit(0);
556
+ } else {
557
+ console.log(`
558
+ ${chalk.bold("happy daemon")} - Daemon management
559
+
560
+ ${chalk.bold("Usage:")}
561
+ happy daemon start Start the daemon (detached)
562
+ happy daemon stop Stop the daemon (sessions stay alive)
563
+ happy daemon restart Restart the daemon
564
+ happy daemon status Show daemon status
565
+ happy daemon list List active sessions
566
+ happy daemon enable Enable auto-start on boot
567
+ happy daemon disable Disable auto-start on boot
568
+
569
+ If you want to kill all happy related processes run
570
+ ${chalk.cyan("happy doctor clean")}
571
+
572
+ ${chalk.bold("Note:")} The daemon runs in the background and manages Claude sessions.
573
+
574
+ ${chalk.bold("To clean up runaway processes:")} Use ${chalk.cyan("happy doctor clean")}
575
+ `);
576
+ }
577
+ return;
578
+ } else {
579
+ if (args.length > 0 && args[0] === "claude") {
580
+ args.shift();
581
+ }
582
+ const options = {};
583
+ let showHelp = false;
584
+ let showVersion = false;
585
+ let chromeOverride = void 0;
586
+ const unknownArgs = [];
587
+ for (let i = 0; i < args.length; i++) {
588
+ const arg = args[i];
589
+ if (arg === "-h" || arg === "--help") {
590
+ showHelp = true;
591
+ unknownArgs.push(arg);
592
+ } else if (arg === "-v" || arg === "--version") {
593
+ showVersion = true;
594
+ unknownArgs.push(arg);
595
+ } else if (arg === "--happy-starting-mode") {
596
+ options.startingMode = z.enum(["local", "remote"]).parse(args[++i]);
597
+ } else if (arg === "--yolo") {
598
+ unknownArgs.push("--dangerously-skip-permissions");
599
+ } else if (arg === "--started-by") {
600
+ options.startedBy = args[++i];
601
+ } else if (arg === "--js-runtime") {
602
+ const runtime = args[++i];
603
+ if (runtime !== "node" && runtime !== "bun") {
604
+ console.error(chalk.red(`Invalid --js-runtime value: ${runtime}. Must be 'node' or 'bun'`));
605
+ process.exit(1);
606
+ }
607
+ options.jsRuntime = runtime;
608
+ } else if (arg === "--claude-env") {
609
+ const envArg = args[++i];
610
+ if (envArg && envArg.includes("=")) {
611
+ const eqIndex = envArg.indexOf("=");
612
+ const key = envArg.substring(0, eqIndex);
613
+ const value = envArg.substring(eqIndex + 1);
614
+ options.claudeEnvVars = options.claudeEnvVars || {};
615
+ options.claudeEnvVars[key] = value;
616
+ } else {
617
+ console.error(chalk.red(`Invalid --claude-env format: ${envArg}. Expected KEY=VALUE`));
618
+ process.exit(1);
619
+ }
620
+ } else if (arg === "--chrome") {
621
+ chromeOverride = true;
622
+ } else if (arg === "--no-chrome") {
623
+ chromeOverride = false;
624
+ } else if (arg === "--settings") {
625
+ const settingsValue = args[++i];
626
+ console.warn(chalk.yellow(`\u26A0\uFE0F Warning: --settings is used internally by Happy for session tracking.`));
627
+ console.warn(chalk.yellow(` Your settings file "${settingsValue}" will be ignored.`));
628
+ console.warn(chalk.yellow(` To configure Claude, edit ~/.claude/settings.json instead.`));
629
+ } else {
630
+ unknownArgs.push(arg);
631
+ if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
632
+ unknownArgs.push(args[++i]);
633
+ }
634
+ }
635
+ }
636
+ if (unknownArgs.length > 0) {
637
+ options.claudeArgs = [...options.claudeArgs || [], ...unknownArgs];
638
+ }
639
+ const settings = await readSettings();
640
+ const chromeEnabled = chromeOverride ?? settings.chromeMode ?? false;
641
+ if (chromeEnabled) {
642
+ options.claudeArgs = [...options.claudeArgs || [], "--chrome"];
643
+ }
644
+ if (showHelp) {
645
+ console.log(`
646
+ ${chalk.bold("happy")} - Claude Code On the Go
647
+
648
+ ${chalk.bold("Usage:")}
649
+ happy [options] Start Claude with mobile control
650
+ happy auth Manage authentication
651
+ happy codex Start Codex mode
652
+ happy gemini Start Gemini mode (ACP)
653
+ happy connect Connect AI vendor API keys
654
+ happy session Read Happy sessions
655
+ happy task Generate task handoff briefs
656
+ happy release Verify before publishing
657
+ happy github GitHub takeover helpers
658
+ happy diagnose Diagnosis evidence helpers
659
+ happy evidence Record screenshots/log evidence
660
+ happy notify Send push notification
661
+ happy daemon Manage background service
662
+ happy daemon enable Auto-start daemon on boot
663
+ happy doctor System diagnostics & troubleshooting
664
+ happy update Upgrade happy to the latest version
665
+
666
+ ${chalk.bold("Examples:")}
667
+ happy Start session
668
+ happy --yolo Start with bypassing permissions
669
+ happy sugar for --dangerously-skip-permissions
670
+ happy --chrome Enable Chrome browser access for this session
671
+ happy --no-chrome Disable Chrome even if default is on
672
+ happy --js-runtime bun Use bun instead of node to spawn Claude Code
673
+ happy --claude-env ANTHROPIC_BASE_URL=http://127.0.0.1:3456
674
+ Use a custom API endpoint (e.g., claude-code-router)
675
+ happy auth login --force Authenticate
676
+ happy task brief --recent --project .
677
+ Generate a continuation brief
678
+ happy release guard --package happy-cli
679
+ Run checks before publishing
680
+ happy doctor Run diagnostics
681
+
682
+ ${chalk.bold("Happy AI supports ALL Claude options!")}
683
+ Use any claude flag with happy as you would with claude. Our favorite:
684
+
685
+ happy --resume
686
+
687
+ ${chalk.gray("\u2500".repeat(60))}
688
+ ${chalk.bold.cyan("Claude Code Options (from `claude --help`):")}
689
+ `);
690
+ try {
691
+ const { claudeCliPath } = await import('./claudeLocal-CWNGpJ0-.mjs').then(function (n) { return n.d; });
692
+ const claudeHelp = execFileSync(claudeCliPath, ["--help"], { encoding: "utf8" });
693
+ console.log(claudeHelp);
694
+ } catch (e) {
695
+ console.log(chalk.yellow("Could not retrieve claude help. Make sure claude is installed."));
696
+ }
697
+ process.exit(0);
698
+ }
699
+ if (showVersion) {
700
+ const versions = [
701
+ { name: "Happy AI", version: packageJson.version }
702
+ ];
703
+ const checks = [
704
+ { name: "Claude", cmd: "claude", args: ["--version"] },
705
+ { name: "Codex", cmd: "codex", args: ["--version"] },
706
+ { name: "Gemini", cmd: "gemini", args: ["--version"] }
707
+ ];
708
+ for (const { name, cmd, args: vArgs } of checks) {
709
+ try {
710
+ const ver = execFileSync(cmd, vArgs, { encoding: "utf-8", timeout: 5e3 }).trim();
711
+ versions.push({ name, version: ver });
712
+ } catch {
713
+ }
714
+ }
715
+ const maxName = Math.max(...versions.map((v) => v.name.length));
716
+ for (const { name, version } of versions) {
717
+ console.log(`${chalk.bold(name.padEnd(maxName))} ${chalk.cyan(version)}`);
718
+ }
719
+ process.exit(0);
720
+ }
721
+ const { authAndSetupMachineIfNeeded } = await import('./auth-DxJ3VvrX.mjs');
722
+ const { isDaemonRunningCurrentlyInstalledHappyVersion } = await import('./controlClient-DB5tDU7V.mjs');
723
+ const { spawnHappyCLI } = await import('./spawnHappyCLI-yBIP_Oqi.mjs').then(function (n) { return n.a; });
724
+ const { runClaude } = await import('./runClaude-6Gi0sYQy.mjs');
725
+ const {
726
+ credentials
727
+ } = await authAndSetupMachineIfNeeded();
728
+ logger.debug("Ensuring Happy background service is running & matches our version...");
729
+ if (!await isDaemonRunningCurrentlyInstalledHappyVersion()) {
730
+ logger.debug("Starting Happy background service...");
731
+ const daemonProcess = spawnHappyCLI(["daemon", "start-sync"], {
732
+ detached: true,
733
+ stdio: "ignore",
734
+ env: process.env
735
+ });
736
+ daemonProcess.unref();
737
+ await new Promise((resolve) => setTimeout(resolve, 200));
738
+ }
739
+ try {
740
+ await runClaude(credentials, options);
741
+ } catch (error) {
742
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
743
+ if (isDebug()) {
744
+ console.error(error);
745
+ }
746
+ process.exit(1);
747
+ }
748
+ }
749
+ })();
750
+ async function handleNotifyCommand(args) {
751
+ let message = "";
752
+ let title = "";
753
+ let showHelp = false;
754
+ for (let i = 0; i < args.length; i++) {
755
+ const arg = args[i];
756
+ if (arg === "-p" && i + 1 < args.length) {
757
+ message = args[++i];
758
+ } else if (arg === "-t" && i + 1 < args.length) {
759
+ title = args[++i];
760
+ } else if (arg === "-h" || arg === "--help") {
761
+ showHelp = true;
762
+ } else {
763
+ console.error(chalk.red(`Unknown argument for notify command: ${arg}`));
764
+ process.exit(1);
765
+ }
766
+ }
767
+ if (showHelp) {
768
+ console.log(`
769
+ ${chalk.bold("happy notify")} - Send notification
770
+
771
+ ${chalk.bold("Usage:")}
772
+ happy notify -p <message> [-t <title>] Send notification with custom message and optional title
773
+ happy notify -h, --help Show this help
774
+
775
+ ${chalk.bold("Options:")}
776
+ -p <message> Notification message (required)
777
+ -t <title> Notification title (optional, defaults to "Happy AI")
778
+
779
+ ${chalk.bold("Examples:")}
780
+ happy notify -p "Deployment complete!"
781
+ happy notify -p "System update complete" -t "Server Status"
782
+ happy notify -t "Alert" -p "Database connection restored"
783
+ `);
784
+ return;
785
+ }
786
+ if (!message) {
787
+ console.error(chalk.red('Error: Message is required. Use -p "your message" to specify the notification text.'));
788
+ console.log(chalk.gray('Run "happy notify --help" for usage information.'));
789
+ process.exit(1);
790
+ }
791
+ let credentials = await readCredentials();
792
+ if (!credentials) {
793
+ console.error(chalk.red('Error: Not authenticated. Please run "happy auth login" first.'));
794
+ process.exit(1);
795
+ }
796
+ console.log(chalk.blue("\u{1F4F1} Sending push notification..."));
797
+ try {
798
+ const { ApiClient } = await import('./api-D6WL40-U.mjs').then(function (n) { return n.m; });
799
+ const api = await ApiClient.create(credentials);
800
+ const notificationTitle = title || "Happy AI";
801
+ api.push().sendToAllDevices(
802
+ notificationTitle,
803
+ message,
804
+ {
805
+ source: "cli",
806
+ timestamp: Date.now()
807
+ }
808
+ );
809
+ console.log(chalk.green("\u2713 Push notification sent successfully!"));
810
+ console.log(chalk.gray(` Title: ${notificationTitle}`));
811
+ console.log(chalk.gray(` Message: ${message}`));
812
+ console.log(chalk.gray(" Check your mobile device for the notification."));
813
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
814
+ } catch (error) {
815
+ console.error(chalk.red("\u2717 Failed to send push notification"));
816
+ throw error;
817
+ }
818
+ }