@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
@@ -0,0 +1,94 @@
1
+ import { l as logger, r as readCredentials } from './persistence-DKfF81pd.mjs';
2
+ import { i as install$2 } from './install-CgUPGIoF.mjs';
3
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
4
+ import { execSync } from 'child_process';
5
+ import path from 'path';
6
+ import os from 'os';
7
+ import { t as trimIdent } from './trimIdent-BAjmv_TG.mjs';
8
+ import { p as projectPath } from './projectPath-BTBIMB57.mjs';
9
+ import { s as systemdScopeFor, i as isRootUser, S as SERVICE_NAME } from './systemdScope-BeOtAkhk.mjs';
10
+ import 'node:fs/promises';
11
+ import 'node:fs';
12
+ import 'node:os';
13
+ import 'node:path';
14
+ import 'zod';
15
+ import 'node:crypto';
16
+ import 'tweetnacl';
17
+ import 'chalk';
18
+ import 'url';
19
+
20
+ function environmentLines() {
21
+ const lines = ["Environment=HAPPY_DAEMON_SUPERVISED=1"];
22
+ if (process.env.HAPPY_SERVER_URL) lines.push(`Environment=HAPPY_SERVER_URL=${process.env.HAPPY_SERVER_URL}`);
23
+ if (process.env.HAPPY_HOME_DIR) lines.push(`Environment=HAPPY_HOME_DIR=${process.env.HAPPY_HOME_DIR}`);
24
+ if (process.env.HAPPY_WEBAPP_URL) lines.push(`Environment=HAPPY_WEBAPP_URL=${process.env.HAPPY_WEBAPP_URL}`);
25
+ return lines.length ? "\n " + lines.join("\n ") : "";
26
+ }
27
+ async function install$1() {
28
+ const daemonEnvironmentLines = environmentLines();
29
+ const runtime = process.execPath;
30
+ const entrypoint = path.join(projectPath(), "dist", "index.mjs");
31
+ if (!existsSync(entrypoint)) {
32
+ throw new Error(`Entrypoint not found: ${entrypoint}. Please build the project first.`);
33
+ }
34
+ const homedir = os.homedir();
35
+ const scope = systemdScopeFor(isRootUser());
36
+ const servicePath = scope.unitPath;
37
+ const serviceContent = trimIdent(`
38
+ [Unit]
39
+ Description=Happy AI CLI Daemon
40
+ After=network-online.target
41
+ Wants=network-online.target
42
+
43
+ [Service]
44
+ Type=simple
45
+ ExecStart=${runtime} --no-warnings --no-deprecation ${entrypoint} daemon start-sync
46
+ Restart=on-failure
47
+ RestartSec=30
48
+ Environment=HOME=${homedir}${daemonEnvironmentLines}
49
+
50
+ [Install]
51
+ WantedBy=${scope.wantedBy}
52
+ `);
53
+ mkdirSync(path.dirname(servicePath), { recursive: true });
54
+ writeFileSync(servicePath, serviceContent + "\n");
55
+ logger.info(`Created systemd ${scope.system ? "system" : "user"} service at ${servicePath}`);
56
+ try {
57
+ execSync(`systemctl ${scope.systemctlFlag} daemon-reload`.trim(), { stdio: "pipe" });
58
+ execSync(`systemctl ${scope.systemctlFlag} enable --now ${SERVICE_NAME}`.trim(), { stdio: "pipe" });
59
+ } catch (error) {
60
+ const detail = error instanceof Error ? error.message : String(error);
61
+ throw new Error(
62
+ scope.system ? `Failed to enable the systemd service: ${detail}` : `Failed to enable the systemd user service: ${detail}
63
+ A user service needs a systemd user session (systemctl --user status must work).
64
+ On a server, install it as root instead so it runs without a logged-in session: sudo happy daemon install`
65
+ );
66
+ }
67
+ if (!scope.system) {
68
+ try {
69
+ execSync(`loginctl enable-linger ${os.userInfo().username}`, { stdio: "pipe" });
70
+ } catch {
71
+ logger.info("Could not enable lingering \u2014 the daemon may stop when you log out. Fix with: sudo loginctl enable-linger $USER");
72
+ }
73
+ }
74
+ logger.info(scope.system ? "Daemon enabled and started. It will auto-start on boot." : "Daemon enabled and started. It will auto-start on login.");
75
+ logger.info("To disable: happy daemon disable");
76
+ }
77
+
78
+ async function install() {
79
+ const credentials = await readCredentials();
80
+ if (!credentials) {
81
+ throw new Error('Not authenticated. Please run "happy auth login" first.');
82
+ }
83
+ if (process.platform === "darwin") {
84
+ logger.info("Setting up daemon auto-start for macOS...");
85
+ await install$2();
86
+ } else if (process.platform === "linux") {
87
+ logger.info("Setting up daemon auto-start for Linux...");
88
+ await install$1();
89
+ } else {
90
+ throw new Error(`Unsupported platform: ${process.platform}. Only macOS and Linux are supported.`);
91
+ }
92
+ }
93
+
94
+ export { install };
@@ -0,0 +1,95 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { execSync } from 'child_process';
3
+ import os from 'os';
4
+ import { join } from 'path';
5
+ import { l as logger } from './persistence-DKfF81pd.mjs';
6
+ import { t as trimIdent } from './trimIdent-BAjmv_TG.mjs';
7
+ import { p as projectPath } from './projectPath-BTBIMB57.mjs';
8
+
9
+ const PLIST_LABEL = "com.happy-cli.daemon";
10
+ const PLIST_DIR = join(os.homedir(), "Library", "LaunchAgents");
11
+ const PLIST_FILE = join(PLIST_DIR, `${PLIST_LABEL}.plist`);
12
+ const LOG_DIR = join(os.homedir(), ".happy");
13
+ function plistEnvironment() {
14
+ const entries = [["HAPPY_DAEMON_SUPERVISED", "1"]];
15
+ if (process.env.HAPPY_SERVER_URL) entries.push(["HAPPY_SERVER_URL", process.env.HAPPY_SERVER_URL]);
16
+ if (process.env.HAPPY_HOME_DIR) entries.push(["HAPPY_HOME_DIR", process.env.HAPPY_HOME_DIR]);
17
+ if (process.env.HAPPY_WEBAPP_URL) entries.push(["HAPPY_WEBAPP_URL", process.env.HAPPY_WEBAPP_URL]);
18
+ return entries.map(([key, value]) => `
19
+ <key>${key}</key>
20
+ <string>${value}</string>`).join("");
21
+ }
22
+ async function install() {
23
+ const plistEnvironmentEntries = plistEnvironment();
24
+ const runtime = process.execPath;
25
+ const entrypoint = join(projectPath(), "dist", "index.mjs");
26
+ if (!existsSync(PLIST_DIR)) {
27
+ mkdirSync(PLIST_DIR, { recursive: true });
28
+ }
29
+ if (!existsSync(LOG_DIR)) {
30
+ mkdirSync(LOG_DIR, { recursive: true });
31
+ }
32
+ if (existsSync(PLIST_FILE)) {
33
+ logger.info("Daemon plist already exists. Unloading first...");
34
+ try {
35
+ execSync(`launchctl unload ${PLIST_FILE}`, { stdio: "ignore" });
36
+ } catch {
37
+ }
38
+ }
39
+ const plistContent = trimIdent(`
40
+ <?xml version="1.0" encoding="UTF-8"?>
41
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
42
+ <plist version="1.0">
43
+ <dict>
44
+ <key>Label</key>
45
+ <string>${PLIST_LABEL}</string>
46
+
47
+ <key>ProgramArguments</key>
48
+ <array>
49
+ <string>${runtime}</string>
50
+ <string>--no-warnings</string>
51
+ <string>--no-deprecation</string>
52
+ <string>${entrypoint}</string>
53
+ <string>daemon</string>
54
+ <string>start-sync</string>
55
+ </array>
56
+
57
+ <key>EnvironmentVariables</key>
58
+ <dict>${plistEnvironmentEntries}
59
+ </dict>
60
+
61
+ <key>RunAtLoad</key>
62
+ <true/>
63
+
64
+ <key>KeepAlive</key>
65
+ <dict>
66
+ <key>SuccessfulExit</key>
67
+ <false/>
68
+ </dict>
69
+
70
+ <key>ThrottleInterval</key>
71
+ <integer>30</integer>
72
+
73
+ <key>StandardOutPath</key>
74
+ <string>${join(LOG_DIR, "daemon.log")}</string>
75
+
76
+ <key>StandardErrorPath</key>
77
+ <string>${join(LOG_DIR, "daemon.err")}</string>
78
+
79
+ <key>WorkingDirectory</key>
80
+ <string>/tmp</string>
81
+ </dict>
82
+ </plist>
83
+ `);
84
+ writeFileSync(PLIST_FILE, plistContent);
85
+ logger.info(`Created LaunchAgent plist at ${PLIST_FILE}`);
86
+ try {
87
+ execSync(`launchctl load ${PLIST_FILE}`, { stdio: "pipe" });
88
+ } catch (error) {
89
+ throw new Error(`Failed to load LaunchAgent. You can try manually: launchctl load ${PLIST_FILE}`);
90
+ }
91
+ logger.info("Daemon enabled and started. It will auto-start on login.");
92
+ logger.info("To disable: happy daemon disable");
93
+ }
94
+
95
+ export { PLIST_LABEL as P, install as i };
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ var logger = require('./persistence-CBTtC_dm.cjs');
4
+ var install$2 = require('./install-DSDufaPd.cjs');
5
+ var fs = require('fs');
6
+ var child_process = require('child_process');
7
+ var path = require('path');
8
+ var os = require('os');
9
+ var trimIdent = require('./trimIdent-4gvk9Wk6.cjs');
10
+ var projectPath = require('./projectPath-ChLhdOyt.cjs');
11
+ var systemdScope = require('./systemdScope-DW3-UoKB.cjs');
12
+ require('node:fs/promises');
13
+ require('node:fs');
14
+ require('node:os');
15
+ require('node:path');
16
+ require('zod');
17
+ require('node:crypto');
18
+ require('tweetnacl');
19
+ require('chalk');
20
+ require('url');
21
+
22
+ function environmentLines() {
23
+ const lines = ["Environment=HAPPY_DAEMON_SUPERVISED=1"];
24
+ if (process.env.HAPPY_SERVER_URL) lines.push(`Environment=HAPPY_SERVER_URL=${process.env.HAPPY_SERVER_URL}`);
25
+ if (process.env.HAPPY_HOME_DIR) lines.push(`Environment=HAPPY_HOME_DIR=${process.env.HAPPY_HOME_DIR}`);
26
+ if (process.env.HAPPY_WEBAPP_URL) lines.push(`Environment=HAPPY_WEBAPP_URL=${process.env.HAPPY_WEBAPP_URL}`);
27
+ return lines.length ? "\n " + lines.join("\n ") : "";
28
+ }
29
+ async function install$1() {
30
+ const daemonEnvironmentLines = environmentLines();
31
+ const runtime = process.execPath;
32
+ const entrypoint = path.join(projectPath.projectPath(), "dist", "index.mjs");
33
+ if (!fs.existsSync(entrypoint)) {
34
+ throw new Error(`Entrypoint not found: ${entrypoint}. Please build the project first.`);
35
+ }
36
+ const homedir = os.homedir();
37
+ const scope = systemdScope.systemdScopeFor(systemdScope.isRootUser());
38
+ const servicePath = scope.unitPath;
39
+ const serviceContent = trimIdent.trimIdent(`
40
+ [Unit]
41
+ Description=Happy AI CLI Daemon
42
+ After=network-online.target
43
+ Wants=network-online.target
44
+
45
+ [Service]
46
+ Type=simple
47
+ ExecStart=${runtime} --no-warnings --no-deprecation ${entrypoint} daemon start-sync
48
+ Restart=on-failure
49
+ RestartSec=30
50
+ Environment=HOME=${homedir}${daemonEnvironmentLines}
51
+
52
+ [Install]
53
+ WantedBy=${scope.wantedBy}
54
+ `);
55
+ fs.mkdirSync(path.dirname(servicePath), { recursive: true });
56
+ fs.writeFileSync(servicePath, serviceContent + "\n");
57
+ logger.logger.info(`Created systemd ${scope.system ? "system" : "user"} service at ${servicePath}`);
58
+ try {
59
+ child_process.execSync(`systemctl ${scope.systemctlFlag} daemon-reload`.trim(), { stdio: "pipe" });
60
+ child_process.execSync(`systemctl ${scope.systemctlFlag} enable --now ${systemdScope.SERVICE_NAME}`.trim(), { stdio: "pipe" });
61
+ } catch (error) {
62
+ const detail = error instanceof Error ? error.message : String(error);
63
+ throw new Error(
64
+ scope.system ? `Failed to enable the systemd service: ${detail}` : `Failed to enable the systemd user service: ${detail}
65
+ A user service needs a systemd user session (systemctl --user status must work).
66
+ On a server, install it as root instead so it runs without a logged-in session: sudo happy daemon install`
67
+ );
68
+ }
69
+ if (!scope.system) {
70
+ try {
71
+ child_process.execSync(`loginctl enable-linger ${os.userInfo().username}`, { stdio: "pipe" });
72
+ } catch {
73
+ logger.logger.info("Could not enable lingering \u2014 the daemon may stop when you log out. Fix with: sudo loginctl enable-linger $USER");
74
+ }
75
+ }
76
+ logger.logger.info(scope.system ? "Daemon enabled and started. It will auto-start on boot." : "Daemon enabled and started. It will auto-start on login.");
77
+ logger.logger.info("To disable: happy daemon disable");
78
+ }
79
+
80
+ async function install() {
81
+ const credentials = await logger.readCredentials();
82
+ if (!credentials) {
83
+ throw new Error('Not authenticated. Please run "happy auth login" first.');
84
+ }
85
+ if (process.platform === "darwin") {
86
+ logger.logger.info("Setting up daemon auto-start for macOS...");
87
+ await install$2.install();
88
+ } else if (process.platform === "linux") {
89
+ logger.logger.info("Setting up daemon auto-start for Linux...");
90
+ await install$1();
91
+ } else {
92
+ throw new Error(`Unsupported platform: ${process.platform}. Only macOS and Linux are supported.`);
93
+ }
94
+ }
95
+
96
+ exports.install = install;
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs');
4
+ var child_process = require('child_process');
5
+ var os = require('os');
6
+ var path = require('path');
7
+ var logger = require('./persistence-CBTtC_dm.cjs');
8
+ var trimIdent = require('./trimIdent-4gvk9Wk6.cjs');
9
+ var projectPath = require('./projectPath-ChLhdOyt.cjs');
10
+
11
+ const PLIST_LABEL = "com.happy-cli.daemon";
12
+ const PLIST_DIR = path.join(os.homedir(), "Library", "LaunchAgents");
13
+ const PLIST_FILE = path.join(PLIST_DIR, `${PLIST_LABEL}.plist`);
14
+ const LOG_DIR = path.join(os.homedir(), ".happy");
15
+ function plistEnvironment() {
16
+ const entries = [["HAPPY_DAEMON_SUPERVISED", "1"]];
17
+ if (process.env.HAPPY_SERVER_URL) entries.push(["HAPPY_SERVER_URL", process.env.HAPPY_SERVER_URL]);
18
+ if (process.env.HAPPY_HOME_DIR) entries.push(["HAPPY_HOME_DIR", process.env.HAPPY_HOME_DIR]);
19
+ if (process.env.HAPPY_WEBAPP_URL) entries.push(["HAPPY_WEBAPP_URL", process.env.HAPPY_WEBAPP_URL]);
20
+ return entries.map(([key, value]) => `
21
+ <key>${key}</key>
22
+ <string>${value}</string>`).join("");
23
+ }
24
+ async function install() {
25
+ const plistEnvironmentEntries = plistEnvironment();
26
+ const runtime = process.execPath;
27
+ const entrypoint = path.join(projectPath.projectPath(), "dist", "index.mjs");
28
+ if (!fs.existsSync(PLIST_DIR)) {
29
+ fs.mkdirSync(PLIST_DIR, { recursive: true });
30
+ }
31
+ if (!fs.existsSync(LOG_DIR)) {
32
+ fs.mkdirSync(LOG_DIR, { recursive: true });
33
+ }
34
+ if (fs.existsSync(PLIST_FILE)) {
35
+ logger.logger.info("Daemon plist already exists. Unloading first...");
36
+ try {
37
+ child_process.execSync(`launchctl unload ${PLIST_FILE}`, { stdio: "ignore" });
38
+ } catch {
39
+ }
40
+ }
41
+ const plistContent = trimIdent.trimIdent(`
42
+ <?xml version="1.0" encoding="UTF-8"?>
43
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
44
+ <plist version="1.0">
45
+ <dict>
46
+ <key>Label</key>
47
+ <string>${PLIST_LABEL}</string>
48
+
49
+ <key>ProgramArguments</key>
50
+ <array>
51
+ <string>${runtime}</string>
52
+ <string>--no-warnings</string>
53
+ <string>--no-deprecation</string>
54
+ <string>${entrypoint}</string>
55
+ <string>daemon</string>
56
+ <string>start-sync</string>
57
+ </array>
58
+
59
+ <key>EnvironmentVariables</key>
60
+ <dict>${plistEnvironmentEntries}
61
+ </dict>
62
+
63
+ <key>RunAtLoad</key>
64
+ <true/>
65
+
66
+ <key>KeepAlive</key>
67
+ <dict>
68
+ <key>SuccessfulExit</key>
69
+ <false/>
70
+ </dict>
71
+
72
+ <key>ThrottleInterval</key>
73
+ <integer>30</integer>
74
+
75
+ <key>StandardOutPath</key>
76
+ <string>${path.join(LOG_DIR, "daemon.log")}</string>
77
+
78
+ <key>StandardErrorPath</key>
79
+ <string>${path.join(LOG_DIR, "daemon.err")}</string>
80
+
81
+ <key>WorkingDirectory</key>
82
+ <string>/tmp</string>
83
+ </dict>
84
+ </plist>
85
+ `);
86
+ fs.writeFileSync(PLIST_FILE, plistContent);
87
+ logger.logger.info(`Created LaunchAgent plist at ${PLIST_FILE}`);
88
+ try {
89
+ child_process.execSync(`launchctl load ${PLIST_FILE}`, { stdio: "pipe" });
90
+ } catch (error) {
91
+ throw new Error(`Failed to load LaunchAgent. You can try manually: launchctl load ${PLIST_FILE}`);
92
+ }
93
+ logger.logger.info("Daemon enabled and started. It will auto-start on login.");
94
+ logger.logger.info("To disable: happy daemon disable");
95
+ }
96
+
97
+ exports.PLIST_LABEL = PLIST_LABEL;
98
+ exports.install = install;
package/dist/lib.cjs CHANGED
@@ -1,37 +1,43 @@
1
1
  'use strict';
2
2
 
3
- var persistence = require('./types-DvTsFaqR.cjs');
3
+ var api = require('./api-C7FyJfZ1.cjs');
4
+ var logger = require('./persistence-CBTtC_dm.cjs');
5
+ var types = require('./types-DWeB7aqh.cjs');
4
6
  require('axios');
5
- require('chalk');
6
- require('fs');
7
- require('node:fs');
8
- require('node:os');
9
- require('node:path');
10
7
  require('node:events');
11
8
  require('socket.io-client');
12
9
  require('zod');
10
+ require('./index-CDTNgfUf.cjs');
13
11
  require('@paralleldrive/cuid2');
12
+ require('./time-Bj2HRkKH.cjs');
14
13
  require('node:crypto');
15
- require('tweetnacl');
14
+ require('node:fs');
15
+ require('node:path');
16
16
  require('node:child_process');
17
17
  require('node:fs/promises');
18
+ require('node:os');
18
19
  require('node:util');
19
20
  require('child_process');
20
21
  require('util');
21
22
  require('fs/promises');
22
23
  require('path');
24
+ require('./projectPath-ChLhdOyt.cjs');
23
25
  require('url');
24
26
  require('node:module');
25
27
  require('ws');
26
28
  require('crypto');
29
+ require('tweetnacl');
27
30
  require('@stablelib/base64');
28
31
  require('node:readline');
29
32
  require('expo-server-sdk');
33
+ require('./sessionKeyCache-CDmexJ9p.cjs');
34
+ require('chalk');
35
+ require('fs');
30
36
 
31
37
 
32
38
 
33
- exports.ApiClient = persistence.ApiClient;
34
- exports.ApiSessionClient = persistence.ApiSessionClient;
35
- exports.RawJSONLinesSchema = persistence.RawJSONLinesSchema;
36
- exports.configuration = persistence.configuration;
37
- exports.logger = persistence.logger;
39
+ exports.ApiClient = api.ApiClient;
40
+ exports.ApiSessionClient = api.ApiSessionClient;
41
+ exports.configuration = logger.configuration;
42
+ exports.logger = logger.logger;
43
+ exports.RawJSONLinesSchema = types.RawJSONLinesSchema;
package/dist/lib.d.cts CHANGED
@@ -1606,6 +1606,80 @@ type SpawnSessionResult = {
1606
1606
  * Similar to ApiSessionClient but for machine-scoped connections
1607
1607
  */
1608
1608
 
1609
+ interface ServerToDaemonEvents {
1610
+ update: (data: Update) => void;
1611
+ 'rpc-request': (data: {
1612
+ method: string;
1613
+ params: string;
1614
+ }, callback: (response: string) => void) => void;
1615
+ 'rpc-registered': (data: {
1616
+ method: string;
1617
+ }) => void;
1618
+ 'rpc-unregistered': (data: {
1619
+ method: string;
1620
+ }) => void;
1621
+ 'rpc-error': (data: {
1622
+ type: string;
1623
+ error: string;
1624
+ }) => void;
1625
+ auth: (data: {
1626
+ success: boolean;
1627
+ user: string;
1628
+ }) => void;
1629
+ error: (data: {
1630
+ message: string;
1631
+ }) => void;
1632
+ }
1633
+ interface DaemonToServerEvents {
1634
+ 'machine-alive': (data: {
1635
+ machineId: string;
1636
+ time: number;
1637
+ }) => void;
1638
+ 'machine-update-metadata': (data: {
1639
+ machineId: string;
1640
+ metadata: string;
1641
+ expectedVersion: number;
1642
+ }, cb: (answer: {
1643
+ result: 'error';
1644
+ } | {
1645
+ result: 'version-mismatch';
1646
+ version: number;
1647
+ metadata: string;
1648
+ } | {
1649
+ result: 'success';
1650
+ version: number;
1651
+ metadata: string;
1652
+ }) => void) => void;
1653
+ 'machine-update-state': (data: {
1654
+ machineId: string;
1655
+ daemonState: string;
1656
+ expectedVersion: number;
1657
+ }, cb: (answer: {
1658
+ result: 'error';
1659
+ } | {
1660
+ result: 'version-mismatch';
1661
+ version: number;
1662
+ daemonState: string;
1663
+ } | {
1664
+ result: 'success';
1665
+ version: number;
1666
+ daemonState: string;
1667
+ }) => void) => void;
1668
+ 'rpc-register': (data: {
1669
+ method: string;
1670
+ }) => void;
1671
+ 'rpc-unregister': (data: {
1672
+ method: string;
1673
+ }) => void;
1674
+ 'rpc-call': (data: {
1675
+ method: string;
1676
+ params: any;
1677
+ }, callback: (response: {
1678
+ ok: boolean;
1679
+ result?: any;
1680
+ error?: string;
1681
+ }) => void) => void;
1682
+ }
1609
1683
  type MachineRpcHandlers = {
1610
1684
  spawnSession: (options: SpawnSessionOptions) => Promise<SpawnSessionResult>;
1611
1685
  stopSession: (sessionId: string) => boolean;
@@ -1641,6 +1715,9 @@ declare class ApiMachineClient {
1641
1715
  private machine;
1642
1716
  private currentRuntimeDaemonState?;
1643
1717
  private socket;
1718
+ /** The daemon's live connection. Reused for device RPC so a CLI command does
1719
+ * not spend ~500ms building its own TLS + WebSocket handshake. */
1720
+ get rpcSocket(): Socket<ServerToDaemonEvents, DaemonToServerEvents>;
1644
1721
  private keepAliveInterval;
1645
1722
  private rpcHandlerManager;
1646
1723
  private claudeCache;
package/dist/lib.d.mts CHANGED
@@ -1606,6 +1606,80 @@ type SpawnSessionResult = {
1606
1606
  * Similar to ApiSessionClient but for machine-scoped connections
1607
1607
  */
1608
1608
 
1609
+ interface ServerToDaemonEvents {
1610
+ update: (data: Update) => void;
1611
+ 'rpc-request': (data: {
1612
+ method: string;
1613
+ params: string;
1614
+ }, callback: (response: string) => void) => void;
1615
+ 'rpc-registered': (data: {
1616
+ method: string;
1617
+ }) => void;
1618
+ 'rpc-unregistered': (data: {
1619
+ method: string;
1620
+ }) => void;
1621
+ 'rpc-error': (data: {
1622
+ type: string;
1623
+ error: string;
1624
+ }) => void;
1625
+ auth: (data: {
1626
+ success: boolean;
1627
+ user: string;
1628
+ }) => void;
1629
+ error: (data: {
1630
+ message: string;
1631
+ }) => void;
1632
+ }
1633
+ interface DaemonToServerEvents {
1634
+ 'machine-alive': (data: {
1635
+ machineId: string;
1636
+ time: number;
1637
+ }) => void;
1638
+ 'machine-update-metadata': (data: {
1639
+ machineId: string;
1640
+ metadata: string;
1641
+ expectedVersion: number;
1642
+ }, cb: (answer: {
1643
+ result: 'error';
1644
+ } | {
1645
+ result: 'version-mismatch';
1646
+ version: number;
1647
+ metadata: string;
1648
+ } | {
1649
+ result: 'success';
1650
+ version: number;
1651
+ metadata: string;
1652
+ }) => void) => void;
1653
+ 'machine-update-state': (data: {
1654
+ machineId: string;
1655
+ daemonState: string;
1656
+ expectedVersion: number;
1657
+ }, cb: (answer: {
1658
+ result: 'error';
1659
+ } | {
1660
+ result: 'version-mismatch';
1661
+ version: number;
1662
+ daemonState: string;
1663
+ } | {
1664
+ result: 'success';
1665
+ version: number;
1666
+ daemonState: string;
1667
+ }) => void) => void;
1668
+ 'rpc-register': (data: {
1669
+ method: string;
1670
+ }) => void;
1671
+ 'rpc-unregister': (data: {
1672
+ method: string;
1673
+ }) => void;
1674
+ 'rpc-call': (data: {
1675
+ method: string;
1676
+ params: any;
1677
+ }, callback: (response: {
1678
+ ok: boolean;
1679
+ result?: any;
1680
+ error?: string;
1681
+ }) => void) => void;
1682
+ }
1609
1683
  type MachineRpcHandlers = {
1610
1684
  spawnSession: (options: SpawnSessionOptions) => Promise<SpawnSessionResult>;
1611
1685
  stopSession: (sessionId: string) => boolean;
@@ -1641,6 +1715,9 @@ declare class ApiMachineClient {
1641
1715
  private machine;
1642
1716
  private currentRuntimeDaemonState?;
1643
1717
  private socket;
1718
+ /** The daemon's live connection. Reused for device RPC so a CLI command does
1719
+ * not spend ~500ms building its own TLS + WebSocket handshake. */
1720
+ get rpcSocket(): Socket<ServerToDaemonEvents, DaemonToServerEvents>;
1644
1721
  private keepAliveInterval;
1645
1722
  private rpcHandlerManager;
1646
1723
  private claudeCache;
package/dist/lib.mjs CHANGED
@@ -1,27 +1,33 @@
1
- export { A as ApiClient, a as ApiSessionClient, R as RawJSONLinesSchema, c as configuration, l as logger } from './types-BWpRU1VN.mjs';
1
+ export { A as ApiClient, a as ApiSessionClient } from './api-D6WL40-U.mjs';
2
+ export { c as configuration, l as logger } from './persistence-DKfF81pd.mjs';
3
+ export { R as RawJSONLinesSchema } from './types-BoJh4Qfv.mjs';
2
4
  import 'axios';
3
- import 'chalk';
4
- import 'fs';
5
- import 'node:fs';
6
- import 'node:os';
7
- import 'node:path';
8
5
  import 'node:events';
9
6
  import 'socket.io-client';
10
7
  import 'zod';
8
+ import './index-CPKdvi7J.mjs';
11
9
  import '@paralleldrive/cuid2';
10
+ import './time-DgsBLJA_.mjs';
12
11
  import 'node:crypto';
13
- import 'tweetnacl';
12
+ import 'node:fs';
13
+ import 'node:path';
14
14
  import 'node:child_process';
15
15
  import 'node:fs/promises';
16
+ import 'node:os';
16
17
  import 'node:util';
17
18
  import 'child_process';
18
19
  import 'util';
19
20
  import 'fs/promises';
20
21
  import 'path';
22
+ import './projectPath-BTBIMB57.mjs';
21
23
  import 'url';
22
24
  import 'node:module';
23
25
  import 'ws';
24
26
  import 'crypto';
27
+ import 'tweetnacl';
25
28
  import '@stablelib/base64';
26
29
  import 'node:readline';
27
30
  import 'expo-server-sdk';
31
+ import './sessionKeyCache-B6cGadYL.mjs';
32
+ import 'chalk';
33
+ import 'fs';
@@ -1,9 +1,11 @@
1
- import { l as logger, h as resolveToolsDir, j as projectPath, c as configuration, k as packageJson, s as startOfflineReconnection, m as saveToolOutputRecord } from './types-BWpRU1VN.mjs';
1
+ import { l as logger, c as configuration, p as packageJson } from './persistence-DKfF81pd.mjs';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { readFileSync, existsSync, readdirSync } from 'node:fs';
4
4
  import os, { homedir } from 'node:os';
5
5
  import { join, basename, dirname } from 'node:path';
6
- import { e as detectGitWorktree } from './index-vvZXdswy.mjs';
6
+ import { p as projectPath } from './projectPath-BTBIMB57.mjs';
7
+ import { r as resolveToolsDir, s as startOfflineReconnection, b as saveToolOutputRecord } from './api-D6WL40-U.mjs';
8
+ import { a as detectGitWorktree } from './downloadImage-DZXI3mXL.mjs';
7
9
 
8
10
  class BasePermissionHandler {
9
11
  pendingRequests = /* @__PURE__ */ new Map();