@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.
- package/dist/{types-BWpRU1VN.mjs → api-CIZKyfSn.mjs} +136 -1725
- package/dist/{types-DvTsFaqR.cjs → api-CwOCQeLH.cjs} +317 -1961
- package/dist/auth-0VnlXT9f.mjs +181 -0
- package/dist/auth-BE8dD20T.mjs +270 -0
- package/dist/auth-BIleVCw0.cjs +274 -0
- package/dist/auth-Cas9DR3b.cjs +183 -0
- package/dist/browser-Cc08m7of.cjs +22 -0
- package/dist/browser-Dll5hxOV.mjs +20 -0
- package/dist/claudeLocal-CPT3zcIU.mjs +344 -0
- package/dist/claudeLocal-WkgLbl1a.cjs +352 -0
- package/dist/codex/happyMcpStdioBridge.cjs +4 -1
- package/dist/codex/happyMcpStdioBridge.mjs +4 -1
- package/dist/common-BdNgghUJ.mjs +75 -0
- package/dist/common-CZvSRU4p.cjs +83 -0
- package/dist/{config-0Xnc8ARM.cjs → config-Draa-5XC.cjs} +21 -34
- package/dist/{config-_GW4YBCP.mjs → config-rTT4qTU5.mjs} +7 -20
- package/dist/connect-BfC1tYP_.mjs +679 -0
- package/dist/connect-CJZ73syK.cjs +681 -0
- package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
- package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
- package/dist/controlClient-CM_QcJnB.mjs +159 -0
- package/dist/controlClient-DZMIsKsT.cjs +168 -0
- package/dist/deviceExec-CU1R9CRb.cjs +84 -0
- package/dist/deviceExec-D93AOVV4.mjs +81 -0
- package/dist/diagnose-B3D1a_v0.cjs +60 -0
- package/dist/diagnose-CuRKXxt1.mjs +58 -0
- package/dist/doctor-C08m5Z9f.cjs +78 -0
- package/dist/doctor-Cya9YSA0.cjs +214 -0
- package/dist/doctor-DZYB6IVc.mjs +211 -0
- package/dist/doctor-ON7pN5G5.mjs +74 -0
- package/dist/downloadImage-DfSFLb-h.mjs +887 -0
- package/dist/downloadImage-MQMrUUxS.cjs +897 -0
- package/dist/enroll-BxlbVftP.cjs +115 -0
- package/dist/enroll-C52x8oly.mjs +113 -0
- package/dist/evidence-Ccd9iYcj.mjs +127 -0
- package/dist/evidence-CjWBG5rX.cjs +129 -0
- package/dist/formatImageMessage-B4lSxlk2.mjs +43 -0
- package/dist/formatImageMessage-DbyG8c2j.cjs +46 -0
- package/dist/github-DKcyF1zp.mjs +57 -0
- package/dist/github-h9GhJJ_C.cjs +59 -0
- package/dist/index-CDTNgfUf.cjs +578 -0
- package/dist/index-CPKdvi7J.mjs +554 -0
- package/dist/index.cjs +812 -40
- package/dist/index.mjs +813 -40
- package/dist/install-BokHRgFW.cjs +98 -0
- package/dist/install-C_cp8b2-.cjs +96 -0
- package/dist/install-DAeCn8ae.mjs +94 -0
- package/dist/install-oRAjVLjP.mjs +95 -0
- package/dist/lib.cjs +18 -12
- package/dist/lib.mjs +13 -7
- package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Cuygmd4K.mjs} +4 -2
- package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-DDCJjywt.cjs} +63 -61
- package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
- package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
- package/dist/persistence-BFjvtUad.mjs +944 -0
- package/dist/persistence-JLUn_Nou.cjs +996 -0
- package/dist/projectPath-BTBIMB57.mjs +10 -0
- package/dist/projectPath-ChLhdOyt.cjs +13 -0
- package/dist/prompt-BTWDZZO0.cjs +25 -0
- package/dist/prompt-BsAZsPbo.mjs +22 -0
- package/dist/release-BMEzNONE.mjs +168 -0
- package/dist/release-EhOJeAZe.cjs +171 -0
- package/dist/run-BDn2aE3Q.cjs +2152 -0
- package/dist/run-DBZqN6Kn.mjs +2128 -0
- package/dist/runClaude-DNHvERX0.mjs +3763 -0
- package/dist/runClaude-uaKxPZPm.cjs +3766 -0
- package/dist/{runCodex-skq0j05d.cjs → runCodex-82UrZLme.cjs} +169 -153
- package/dist/{runCodex-DiKzBf9q.mjs → runCodex-C-RTM0wA.mjs} +36 -20
- package/dist/{runGemini-BeqrVq8R.mjs → runGemini-Bm6-4Xm2.mjs} +34 -17
- package/dist/{runGemini-CVp-CEIh.cjs → runGemini-CXMr4Jwb.cjs} +212 -195
- package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-1B6RMYT7.cjs} +31 -55
- package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-ioARRHrx.mjs} +14 -38
- package/dist/{serve-BECdtivY.cjs → serve-BtdAhkIE.cjs} +35 -58
- package/dist/{serve-BNdoEDVx.mjs → serve-CwibwU6N.mjs} +12 -35
- package/dist/session-2sU4Bu1R.mjs +108 -0
- package/dist/session-D--F87zL.cjs +110 -0
- package/dist/sessionKeyCache-4Tp8pJ3N.cjs +36 -0
- package/dist/sessionKeyCache-D2BwO91C.mjs +33 -0
- package/dist/sessionList-BCSw3qYt.mjs +51 -0
- package/dist/sessionList-ICJsjNtJ.cjs +54 -0
- package/dist/sessionSummary-Bkz52BPh.cjs +393 -0
- package/dist/sessionSummary-lHGBWQSb.mjs +387 -0
- package/dist/spawnHappyCLI-CoORX0YW.mjs +66 -0
- package/dist/spawnHappyCLI-D_V-AAoP.cjs +70 -0
- package/dist/ssh-BTOlhhxi.cjs +333 -0
- package/dist/ssh-DL_AkRAD.mjs +328 -0
- package/dist/systemdScope-BeOtAkhk.mjs +25 -0
- package/dist/systemdScope-DW3-UoKB.cjs +29 -0
- package/dist/task-CQzrHRZe.mjs +165 -0
- package/dist/task-CSpaC9HX.cjs +167 -0
- package/dist/time-Bj2HRkKH.cjs +33 -0
- package/dist/time-DgsBLJA_.mjs +29 -0
- package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
- package/dist/trimIdent-BAjmv_TG.mjs +20 -0
- package/dist/types-BoJh4Qfv.mjs +57 -0
- package/dist/types-DWeB7aqh.cjs +59 -0
- package/dist/uninstall-BiKyRAb1.cjs +77 -0
- package/dist/uninstall-nFMFGUVM.mjs +75 -0
- package/dist/update-BcqRHXf2.mjs +109 -0
- package/dist/update-Dw8pgsAT.cjs +111 -0
- package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
- package/dist/workflowCommon-Bl568-rt.cjs +62 -0
- package/dist/workflowReports-BEWuQesA.cjs +113 -0
- package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
- package/package.json +1 -1
- package/dist/index-BbCDDvoB.cjs +0 -11376
- package/dist/index-vvZXdswy.mjs +0 -11336
- package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
- package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chalk = require('chalk');
|
|
4
|
+
var logger = require('./persistence-JLUn_Nou.cjs');
|
|
5
|
+
var controlClient = require('./controlClient-DZMIsKsT.cjs');
|
|
6
|
+
var doctor = require('./doctor-C08m5Z9f.cjs');
|
|
7
|
+
var fs = require('node:fs');
|
|
8
|
+
var path = require('node:path');
|
|
9
|
+
var projectPath = require('./projectPath-ChLhdOyt.cjs');
|
|
10
|
+
require('node:fs/promises');
|
|
11
|
+
require('node:os');
|
|
12
|
+
require('zod');
|
|
13
|
+
require('node:crypto');
|
|
14
|
+
require('tweetnacl');
|
|
15
|
+
require('fs');
|
|
16
|
+
require('path');
|
|
17
|
+
require('ps-list');
|
|
18
|
+
require('cross-spawn');
|
|
19
|
+
require('url');
|
|
20
|
+
|
|
21
|
+
function getEnvironmentInfo() {
|
|
22
|
+
return {
|
|
23
|
+
PWD: process.env.PWD,
|
|
24
|
+
HAPPY_HOME_DIR: process.env.HAPPY_HOME_DIR,
|
|
25
|
+
HAPPY_SERVER_URL: process.env.HAPPY_SERVER_URL,
|
|
26
|
+
HAPPY_PROJECT_ROOT: process.env.HAPPY_PROJECT_ROOT,
|
|
27
|
+
DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING: process.env.DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING,
|
|
28
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
29
|
+
DEBUG: process.env.DEBUG,
|
|
30
|
+
workingDirectory: process.cwd(),
|
|
31
|
+
processArgv: process.argv,
|
|
32
|
+
happyDir: logger.configuration?.happyHomeDir,
|
|
33
|
+
serverUrl: logger.configuration?.serverUrl,
|
|
34
|
+
logsDir: logger.configuration?.logsDir,
|
|
35
|
+
processPid: process.pid,
|
|
36
|
+
nodeVersion: process.version,
|
|
37
|
+
platform: process.platform,
|
|
38
|
+
arch: process.arch,
|
|
39
|
+
user: process.env.USER,
|
|
40
|
+
home: process.env.HOME,
|
|
41
|
+
shell: process.env.SHELL,
|
|
42
|
+
terminal: process.env.TERM
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function getLogFiles(logDir) {
|
|
46
|
+
if (!fs.existsSync(logDir)) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return fs.readdirSync(logDir).filter((file) => file.endsWith(".log")).map((file) => {
|
|
51
|
+
const path$1 = path.join(logDir, file);
|
|
52
|
+
const stats = fs.statSync(path$1);
|
|
53
|
+
return { file, path: path$1, modified: stats.mtime };
|
|
54
|
+
}).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
55
|
+
} catch {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function runDoctorCommand(filter) {
|
|
60
|
+
if (!filter) {
|
|
61
|
+
filter = "all";
|
|
62
|
+
}
|
|
63
|
+
console.log(chalk.bold.cyan("\n\u{1FA7A} Happy AI CLI Doctor\n"));
|
|
64
|
+
if (filter === "all") {
|
|
65
|
+
console.log(chalk.bold("\u{1F4CB} Basic Information"));
|
|
66
|
+
console.log(`Happy AI CLI Version: ${chalk.green(logger.packageJson.version)}`);
|
|
67
|
+
console.log(`Platform: ${chalk.green(process.platform)} ${process.arch}`);
|
|
68
|
+
console.log(`Node.js Version: ${chalk.green(process.version)}`);
|
|
69
|
+
console.log("");
|
|
70
|
+
console.log(chalk.bold("\u{1F527} Daemon Spawn Diagnostics"));
|
|
71
|
+
const projectRoot = projectPath.projectPath();
|
|
72
|
+
const wrapperPath = path.join(projectRoot, "bin", "happy.mjs");
|
|
73
|
+
const cliEntrypoint = path.join(projectRoot, "dist", "index.mjs");
|
|
74
|
+
console.log(`Project Root: ${chalk.blue(projectRoot)}`);
|
|
75
|
+
console.log(`Wrapper Script: ${chalk.blue(wrapperPath)}`);
|
|
76
|
+
console.log(`CLI Entrypoint: ${chalk.blue(cliEntrypoint)}`);
|
|
77
|
+
console.log(`Wrapper Exists: ${fs.existsSync(wrapperPath) ? chalk.green("\u2713 Yes") : chalk.red("\u274C No")}`);
|
|
78
|
+
console.log(`CLI Exists: ${fs.existsSync(cliEntrypoint) ? chalk.green("\u2713 Yes") : chalk.red("\u274C No")}`);
|
|
79
|
+
console.log("");
|
|
80
|
+
console.log(chalk.bold("\u2699\uFE0F Configuration"));
|
|
81
|
+
console.log(`Happy AI Home: ${chalk.blue(logger.configuration.happyHomeDir)}`);
|
|
82
|
+
console.log(`Server URL: ${chalk.blue(logger.configuration.serverUrl)}`);
|
|
83
|
+
console.log(`Logs Dir: ${chalk.blue(logger.configuration.logsDir)}`);
|
|
84
|
+
console.log(chalk.bold("\n\u{1F30D} Environment Variables"));
|
|
85
|
+
const env = getEnvironmentInfo();
|
|
86
|
+
console.log(`HAPPY_HOME_DIR: ${env.HAPPY_HOME_DIR ? chalk.green(env.HAPPY_HOME_DIR) : chalk.gray("not set")}`);
|
|
87
|
+
console.log(`HAPPY_SERVER_URL: ${env.HAPPY_SERVER_URL ? chalk.green(env.HAPPY_SERVER_URL) : chalk.gray("not set")}`);
|
|
88
|
+
console.log(`DANGEROUSLY_LOG_TO_SERVER: ${env.DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING ? chalk.yellow("ENABLED") : chalk.gray("not set")}`);
|
|
89
|
+
console.log(`DEBUG: ${env.DEBUG ? chalk.green(env.DEBUG) : chalk.gray("not set")}`);
|
|
90
|
+
console.log(`NODE_ENV: ${env.NODE_ENV ? chalk.green(env.NODE_ENV) : chalk.gray("not set")}`);
|
|
91
|
+
try {
|
|
92
|
+
const settings = await logger.readSettings();
|
|
93
|
+
console.log(chalk.bold("\n\u{1F4C4} Settings (settings.json):"));
|
|
94
|
+
console.log(chalk.gray(JSON.stringify(settings, null, 2)));
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.log(chalk.bold("\n\u{1F4C4} Settings:"));
|
|
97
|
+
console.log(chalk.red("\u274C Failed to read settings"));
|
|
98
|
+
}
|
|
99
|
+
console.log(chalk.bold("\n\u{1F510} Authentication"));
|
|
100
|
+
try {
|
|
101
|
+
const credentials = await logger.readCredentials();
|
|
102
|
+
if (credentials) {
|
|
103
|
+
console.log(chalk.green("\u2713 Authenticated (credentials found)"));
|
|
104
|
+
} else {
|
|
105
|
+
console.log(chalk.yellow("\u26A0\uFE0F Not authenticated (no credentials)"));
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.log(chalk.red("\u274C Error reading credentials"));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
console.log(chalk.bold("\n\u{1F916} Daemon Status"));
|
|
112
|
+
try {
|
|
113
|
+
const isRunning = await controlClient.checkIfDaemonRunningAndCleanupStaleState();
|
|
114
|
+
const state = await logger.readDaemonState();
|
|
115
|
+
if (isRunning && state) {
|
|
116
|
+
console.log(chalk.green("\u2713 Daemon is running"));
|
|
117
|
+
console.log(` PID: ${state.pid}`);
|
|
118
|
+
console.log(` Started: ${new Date(state.startTime).toLocaleString()}`);
|
|
119
|
+
console.log(` CLI Version: ${state.startedWithCliVersion}`);
|
|
120
|
+
if (state.httpPort) {
|
|
121
|
+
console.log(` HTTP Port: ${state.httpPort}`);
|
|
122
|
+
}
|
|
123
|
+
} else if (state && !isRunning) {
|
|
124
|
+
console.log(chalk.yellow("\u26A0\uFE0F Daemon state exists but process not running (stale)"));
|
|
125
|
+
} else {
|
|
126
|
+
console.log(chalk.red("\u274C Daemon is not running"));
|
|
127
|
+
}
|
|
128
|
+
if (state) {
|
|
129
|
+
console.log(chalk.bold("\n\u{1F4C4} Daemon State:"));
|
|
130
|
+
console.log(chalk.blue(`Location: ${logger.configuration.daemonStateFile}`));
|
|
131
|
+
console.log(chalk.gray(JSON.stringify(state, null, 2)));
|
|
132
|
+
}
|
|
133
|
+
const allProcesses = await doctor.findAllHappyProcesses();
|
|
134
|
+
if (allProcesses.length > 0) {
|
|
135
|
+
console.log(chalk.bold("\n\u{1F50D} All Happy CLI Processes"));
|
|
136
|
+
const grouped = allProcesses.reduce((groups, process2) => {
|
|
137
|
+
if (!groups[process2.type]) groups[process2.type] = [];
|
|
138
|
+
groups[process2.type].push(process2);
|
|
139
|
+
return groups;
|
|
140
|
+
}, {});
|
|
141
|
+
Object.entries(grouped).forEach(([type, processes]) => {
|
|
142
|
+
const typeLabels = {
|
|
143
|
+
"current": "\u{1F4CD} Current Process",
|
|
144
|
+
"daemon": "\u{1F916} Daemon",
|
|
145
|
+
"daemon-version-check": "\u{1F50D} Daemon Version Check (stuck)",
|
|
146
|
+
"daemon-spawned-session": "\u{1F517} Daemon-Spawned Sessions",
|
|
147
|
+
"user-session": "\u{1F464} User Sessions",
|
|
148
|
+
"dev-daemon": "\u{1F6E0}\uFE0F Dev Daemon",
|
|
149
|
+
"dev-daemon-version-check": "\u{1F6E0}\uFE0F Dev Daemon Version Check (stuck)",
|
|
150
|
+
"dev-session": "\u{1F6E0}\uFE0F Dev Sessions",
|
|
151
|
+
"dev-doctor": "\u{1F6E0}\uFE0F Dev Doctor",
|
|
152
|
+
"dev-related": "\u{1F6E0}\uFE0F Dev Related",
|
|
153
|
+
"doctor": "\u{1FA7A} Doctor",
|
|
154
|
+
"unknown": "\u2753 Unknown"
|
|
155
|
+
};
|
|
156
|
+
console.log(chalk.blue(`
|
|
157
|
+
${typeLabels[type] || type}:`));
|
|
158
|
+
processes.forEach(({ pid, command }) => {
|
|
159
|
+
const color = type === "current" ? chalk.green : type.startsWith("dev") ? chalk.cyan : type.includes("daemon") ? chalk.blue : chalk.gray;
|
|
160
|
+
console.log(` ${color(`PID ${pid}`)}: ${chalk.gray(command)}`);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
} else {
|
|
164
|
+
console.log(chalk.red("\u274C No happy processes found"));
|
|
165
|
+
}
|
|
166
|
+
if (filter === "all" && allProcesses.length > 1) {
|
|
167
|
+
console.log(chalk.bold("\n\u{1F4A1} Process Management"));
|
|
168
|
+
console.log(chalk.gray("To clean up runaway processes: happy doctor clean"));
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.log(chalk.red("\u274C Error checking daemon status"));
|
|
172
|
+
}
|
|
173
|
+
if (filter === "all") {
|
|
174
|
+
console.log(chalk.bold("\n\u{1F4DD} Log Files"));
|
|
175
|
+
const allLogs = getLogFiles(logger.configuration.logsDir);
|
|
176
|
+
if (allLogs.length > 0) {
|
|
177
|
+
const daemonLogs = allLogs.filter(({ file }) => file.includes("daemon"));
|
|
178
|
+
const regularLogs = allLogs.filter(({ file }) => !file.includes("daemon"));
|
|
179
|
+
if (regularLogs.length > 0) {
|
|
180
|
+
console.log(chalk.blue("\nRecent Logs:"));
|
|
181
|
+
const logsToShow = regularLogs.slice(0, 10);
|
|
182
|
+
logsToShow.forEach(({ file, path, modified }) => {
|
|
183
|
+
console.log(` ${chalk.green(file)} - ${modified.toLocaleString()}`);
|
|
184
|
+
console.log(chalk.gray(` ${path}`));
|
|
185
|
+
});
|
|
186
|
+
if (regularLogs.length > 10) {
|
|
187
|
+
console.log(chalk.gray(` ... and ${regularLogs.length - 10} more log files`));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (daemonLogs.length > 0) {
|
|
191
|
+
console.log(chalk.blue("\nDaemon Logs:"));
|
|
192
|
+
const daemonLogsToShow = daemonLogs.slice(0, 5);
|
|
193
|
+
daemonLogsToShow.forEach(({ file, path, modified }) => {
|
|
194
|
+
console.log(` ${chalk.green(file)} - ${modified.toLocaleString()}`);
|
|
195
|
+
console.log(chalk.gray(` ${path}`));
|
|
196
|
+
});
|
|
197
|
+
if (daemonLogs.length > 5) {
|
|
198
|
+
console.log(chalk.gray(` ... and ${daemonLogs.length - 5} more daemon log files`));
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
console.log(chalk.yellow("\nNo daemon log files found"));
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
console.log(chalk.yellow("No log files found"));
|
|
205
|
+
}
|
|
206
|
+
console.log(chalk.bold("\n\u{1F41B} Support & Bug Reports"));
|
|
207
|
+
console.log(`Report issues: ${chalk.blue("https://github.com/ZonEaseTech/happy-wfs/issues")}`);
|
|
208
|
+
console.log(`Documentation: ${chalk.blue("https://github.com/ZonEaseTech/happy-wfs")}`);
|
|
209
|
+
}
|
|
210
|
+
console.log(chalk.green("\n\u2705 Doctor diagnosis complete!\n"));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
exports.getEnvironmentInfo = getEnvironmentInfo;
|
|
214
|
+
exports.runDoctorCommand = runDoctorCommand;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { p as packageJson, c as configuration, a as readSettings, r as readCredentials, j as readDaemonState } from './persistence-BFjvtUad.mjs';
|
|
3
|
+
import { checkIfDaemonRunningAndCleanupStaleState } from './controlClient-CM_QcJnB.mjs';
|
|
4
|
+
import { findAllHappyProcesses } from './doctor-ON7pN5G5.mjs';
|
|
5
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { p as projectPath } from './projectPath-BTBIMB57.mjs';
|
|
8
|
+
import 'node:fs/promises';
|
|
9
|
+
import 'node:os';
|
|
10
|
+
import 'zod';
|
|
11
|
+
import 'node:crypto';
|
|
12
|
+
import 'tweetnacl';
|
|
13
|
+
import 'fs';
|
|
14
|
+
import 'path';
|
|
15
|
+
import 'ps-list';
|
|
16
|
+
import 'cross-spawn';
|
|
17
|
+
import 'url';
|
|
18
|
+
|
|
19
|
+
function getEnvironmentInfo() {
|
|
20
|
+
return {
|
|
21
|
+
PWD: process.env.PWD,
|
|
22
|
+
HAPPY_HOME_DIR: process.env.HAPPY_HOME_DIR,
|
|
23
|
+
HAPPY_SERVER_URL: process.env.HAPPY_SERVER_URL,
|
|
24
|
+
HAPPY_PROJECT_ROOT: process.env.HAPPY_PROJECT_ROOT,
|
|
25
|
+
DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING: process.env.DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING,
|
|
26
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
27
|
+
DEBUG: process.env.DEBUG,
|
|
28
|
+
workingDirectory: process.cwd(),
|
|
29
|
+
processArgv: process.argv,
|
|
30
|
+
happyDir: configuration?.happyHomeDir,
|
|
31
|
+
serverUrl: configuration?.serverUrl,
|
|
32
|
+
logsDir: configuration?.logsDir,
|
|
33
|
+
processPid: process.pid,
|
|
34
|
+
nodeVersion: process.version,
|
|
35
|
+
platform: process.platform,
|
|
36
|
+
arch: process.arch,
|
|
37
|
+
user: process.env.USER,
|
|
38
|
+
home: process.env.HOME,
|
|
39
|
+
shell: process.env.SHELL,
|
|
40
|
+
terminal: process.env.TERM
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function getLogFiles(logDir) {
|
|
44
|
+
if (!existsSync(logDir)) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return readdirSync(logDir).filter((file) => file.endsWith(".log")).map((file) => {
|
|
49
|
+
const path = join(logDir, file);
|
|
50
|
+
const stats = statSync(path);
|
|
51
|
+
return { file, path, modified: stats.mtime };
|
|
52
|
+
}).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
53
|
+
} catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function runDoctorCommand(filter) {
|
|
58
|
+
if (!filter) {
|
|
59
|
+
filter = "all";
|
|
60
|
+
}
|
|
61
|
+
console.log(chalk.bold.cyan("\n\u{1FA7A} Happy AI CLI Doctor\n"));
|
|
62
|
+
if (filter === "all") {
|
|
63
|
+
console.log(chalk.bold("\u{1F4CB} Basic Information"));
|
|
64
|
+
console.log(`Happy AI CLI Version: ${chalk.green(packageJson.version)}`);
|
|
65
|
+
console.log(`Platform: ${chalk.green(process.platform)} ${process.arch}`);
|
|
66
|
+
console.log(`Node.js Version: ${chalk.green(process.version)}`);
|
|
67
|
+
console.log("");
|
|
68
|
+
console.log(chalk.bold("\u{1F527} Daemon Spawn Diagnostics"));
|
|
69
|
+
const projectRoot = projectPath();
|
|
70
|
+
const wrapperPath = join(projectRoot, "bin", "happy.mjs");
|
|
71
|
+
const cliEntrypoint = join(projectRoot, "dist", "index.mjs");
|
|
72
|
+
console.log(`Project Root: ${chalk.blue(projectRoot)}`);
|
|
73
|
+
console.log(`Wrapper Script: ${chalk.blue(wrapperPath)}`);
|
|
74
|
+
console.log(`CLI Entrypoint: ${chalk.blue(cliEntrypoint)}`);
|
|
75
|
+
console.log(`Wrapper Exists: ${existsSync(wrapperPath) ? chalk.green("\u2713 Yes") : chalk.red("\u274C No")}`);
|
|
76
|
+
console.log(`CLI Exists: ${existsSync(cliEntrypoint) ? chalk.green("\u2713 Yes") : chalk.red("\u274C No")}`);
|
|
77
|
+
console.log("");
|
|
78
|
+
console.log(chalk.bold("\u2699\uFE0F Configuration"));
|
|
79
|
+
console.log(`Happy AI Home: ${chalk.blue(configuration.happyHomeDir)}`);
|
|
80
|
+
console.log(`Server URL: ${chalk.blue(configuration.serverUrl)}`);
|
|
81
|
+
console.log(`Logs Dir: ${chalk.blue(configuration.logsDir)}`);
|
|
82
|
+
console.log(chalk.bold("\n\u{1F30D} Environment Variables"));
|
|
83
|
+
const env = getEnvironmentInfo();
|
|
84
|
+
console.log(`HAPPY_HOME_DIR: ${env.HAPPY_HOME_DIR ? chalk.green(env.HAPPY_HOME_DIR) : chalk.gray("not set")}`);
|
|
85
|
+
console.log(`HAPPY_SERVER_URL: ${env.HAPPY_SERVER_URL ? chalk.green(env.HAPPY_SERVER_URL) : chalk.gray("not set")}`);
|
|
86
|
+
console.log(`DANGEROUSLY_LOG_TO_SERVER: ${env.DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING ? chalk.yellow("ENABLED") : chalk.gray("not set")}`);
|
|
87
|
+
console.log(`DEBUG: ${env.DEBUG ? chalk.green(env.DEBUG) : chalk.gray("not set")}`);
|
|
88
|
+
console.log(`NODE_ENV: ${env.NODE_ENV ? chalk.green(env.NODE_ENV) : chalk.gray("not set")}`);
|
|
89
|
+
try {
|
|
90
|
+
const settings = await readSettings();
|
|
91
|
+
console.log(chalk.bold("\n\u{1F4C4} Settings (settings.json):"));
|
|
92
|
+
console.log(chalk.gray(JSON.stringify(settings, null, 2)));
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.log(chalk.bold("\n\u{1F4C4} Settings:"));
|
|
95
|
+
console.log(chalk.red("\u274C Failed to read settings"));
|
|
96
|
+
}
|
|
97
|
+
console.log(chalk.bold("\n\u{1F510} Authentication"));
|
|
98
|
+
try {
|
|
99
|
+
const credentials = await readCredentials();
|
|
100
|
+
if (credentials) {
|
|
101
|
+
console.log(chalk.green("\u2713 Authenticated (credentials found)"));
|
|
102
|
+
} else {
|
|
103
|
+
console.log(chalk.yellow("\u26A0\uFE0F Not authenticated (no credentials)"));
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.log(chalk.red("\u274C Error reading credentials"));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
console.log(chalk.bold("\n\u{1F916} Daemon Status"));
|
|
110
|
+
try {
|
|
111
|
+
const isRunning = await checkIfDaemonRunningAndCleanupStaleState();
|
|
112
|
+
const state = await readDaemonState();
|
|
113
|
+
if (isRunning && state) {
|
|
114
|
+
console.log(chalk.green("\u2713 Daemon is running"));
|
|
115
|
+
console.log(` PID: ${state.pid}`);
|
|
116
|
+
console.log(` Started: ${new Date(state.startTime).toLocaleString()}`);
|
|
117
|
+
console.log(` CLI Version: ${state.startedWithCliVersion}`);
|
|
118
|
+
if (state.httpPort) {
|
|
119
|
+
console.log(` HTTP Port: ${state.httpPort}`);
|
|
120
|
+
}
|
|
121
|
+
} else if (state && !isRunning) {
|
|
122
|
+
console.log(chalk.yellow("\u26A0\uFE0F Daemon state exists but process not running (stale)"));
|
|
123
|
+
} else {
|
|
124
|
+
console.log(chalk.red("\u274C Daemon is not running"));
|
|
125
|
+
}
|
|
126
|
+
if (state) {
|
|
127
|
+
console.log(chalk.bold("\n\u{1F4C4} Daemon State:"));
|
|
128
|
+
console.log(chalk.blue(`Location: ${configuration.daemonStateFile}`));
|
|
129
|
+
console.log(chalk.gray(JSON.stringify(state, null, 2)));
|
|
130
|
+
}
|
|
131
|
+
const allProcesses = await findAllHappyProcesses();
|
|
132
|
+
if (allProcesses.length > 0) {
|
|
133
|
+
console.log(chalk.bold("\n\u{1F50D} All Happy CLI Processes"));
|
|
134
|
+
const grouped = allProcesses.reduce((groups, process2) => {
|
|
135
|
+
if (!groups[process2.type]) groups[process2.type] = [];
|
|
136
|
+
groups[process2.type].push(process2);
|
|
137
|
+
return groups;
|
|
138
|
+
}, {});
|
|
139
|
+
Object.entries(grouped).forEach(([type, processes]) => {
|
|
140
|
+
const typeLabels = {
|
|
141
|
+
"current": "\u{1F4CD} Current Process",
|
|
142
|
+
"daemon": "\u{1F916} Daemon",
|
|
143
|
+
"daemon-version-check": "\u{1F50D} Daemon Version Check (stuck)",
|
|
144
|
+
"daemon-spawned-session": "\u{1F517} Daemon-Spawned Sessions",
|
|
145
|
+
"user-session": "\u{1F464} User Sessions",
|
|
146
|
+
"dev-daemon": "\u{1F6E0}\uFE0F Dev Daemon",
|
|
147
|
+
"dev-daemon-version-check": "\u{1F6E0}\uFE0F Dev Daemon Version Check (stuck)",
|
|
148
|
+
"dev-session": "\u{1F6E0}\uFE0F Dev Sessions",
|
|
149
|
+
"dev-doctor": "\u{1F6E0}\uFE0F Dev Doctor",
|
|
150
|
+
"dev-related": "\u{1F6E0}\uFE0F Dev Related",
|
|
151
|
+
"doctor": "\u{1FA7A} Doctor",
|
|
152
|
+
"unknown": "\u2753 Unknown"
|
|
153
|
+
};
|
|
154
|
+
console.log(chalk.blue(`
|
|
155
|
+
${typeLabels[type] || type}:`));
|
|
156
|
+
processes.forEach(({ pid, command }) => {
|
|
157
|
+
const color = type === "current" ? chalk.green : type.startsWith("dev") ? chalk.cyan : type.includes("daemon") ? chalk.blue : chalk.gray;
|
|
158
|
+
console.log(` ${color(`PID ${pid}`)}: ${chalk.gray(command)}`);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
} else {
|
|
162
|
+
console.log(chalk.red("\u274C No happy processes found"));
|
|
163
|
+
}
|
|
164
|
+
if (filter === "all" && allProcesses.length > 1) {
|
|
165
|
+
console.log(chalk.bold("\n\u{1F4A1} Process Management"));
|
|
166
|
+
console.log(chalk.gray("To clean up runaway processes: happy doctor clean"));
|
|
167
|
+
}
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.log(chalk.red("\u274C Error checking daemon status"));
|
|
170
|
+
}
|
|
171
|
+
if (filter === "all") {
|
|
172
|
+
console.log(chalk.bold("\n\u{1F4DD} Log Files"));
|
|
173
|
+
const allLogs = getLogFiles(configuration.logsDir);
|
|
174
|
+
if (allLogs.length > 0) {
|
|
175
|
+
const daemonLogs = allLogs.filter(({ file }) => file.includes("daemon"));
|
|
176
|
+
const regularLogs = allLogs.filter(({ file }) => !file.includes("daemon"));
|
|
177
|
+
if (regularLogs.length > 0) {
|
|
178
|
+
console.log(chalk.blue("\nRecent Logs:"));
|
|
179
|
+
const logsToShow = regularLogs.slice(0, 10);
|
|
180
|
+
logsToShow.forEach(({ file, path, modified }) => {
|
|
181
|
+
console.log(` ${chalk.green(file)} - ${modified.toLocaleString()}`);
|
|
182
|
+
console.log(chalk.gray(` ${path}`));
|
|
183
|
+
});
|
|
184
|
+
if (regularLogs.length > 10) {
|
|
185
|
+
console.log(chalk.gray(` ... and ${regularLogs.length - 10} more log files`));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (daemonLogs.length > 0) {
|
|
189
|
+
console.log(chalk.blue("\nDaemon Logs:"));
|
|
190
|
+
const daemonLogsToShow = daemonLogs.slice(0, 5);
|
|
191
|
+
daemonLogsToShow.forEach(({ file, path, modified }) => {
|
|
192
|
+
console.log(` ${chalk.green(file)} - ${modified.toLocaleString()}`);
|
|
193
|
+
console.log(chalk.gray(` ${path}`));
|
|
194
|
+
});
|
|
195
|
+
if (daemonLogs.length > 5) {
|
|
196
|
+
console.log(chalk.gray(` ... and ${daemonLogs.length - 5} more daemon log files`));
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
console.log(chalk.yellow("\nNo daemon log files found"));
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
console.log(chalk.yellow("No log files found"));
|
|
203
|
+
}
|
|
204
|
+
console.log(chalk.bold("\n\u{1F41B} Support & Bug Reports"));
|
|
205
|
+
console.log(`Report issues: ${chalk.blue("https://github.com/ZonEaseTech/happy-wfs/issues")}`);
|
|
206
|
+
console.log(`Documentation: ${chalk.blue("https://github.com/ZonEaseTech/happy-wfs")}`);
|
|
207
|
+
}
|
|
208
|
+
console.log(chalk.green("\n\u2705 Doctor diagnosis complete!\n"));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export { getEnvironmentInfo, runDoctorCommand };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import psList from 'ps-list';
|
|
2
|
+
import spawn from 'cross-spawn';
|
|
3
|
+
|
|
4
|
+
async function findAllHappyProcesses() {
|
|
5
|
+
try {
|
|
6
|
+
const processes = await psList();
|
|
7
|
+
const allProcesses = [];
|
|
8
|
+
for (const proc of processes) {
|
|
9
|
+
const cmd = proc.cmd || "";
|
|
10
|
+
const name = proc.name || "";
|
|
11
|
+
const isHappy = name.includes("happy") || name === "node" && (cmd.includes("happy-cli") || cmd.includes("dist/index.mjs")) || cmd.includes("happy.mjs") || cmd.includes("@zonease/happy") || cmd.includes("tsx") && cmd.includes("src/index.ts") && cmd.includes("happy-cli");
|
|
12
|
+
if (!isHappy) continue;
|
|
13
|
+
let type = "unknown";
|
|
14
|
+
if (proc.pid === process.pid) {
|
|
15
|
+
type = "current";
|
|
16
|
+
} else if (cmd.includes("--version")) {
|
|
17
|
+
type = cmd.includes("tsx") ? "dev-daemon-version-check" : "daemon-version-check";
|
|
18
|
+
} else if (cmd.includes("daemon start-sync") || cmd.includes("daemon start")) {
|
|
19
|
+
type = cmd.includes("tsx") ? "dev-daemon" : "daemon";
|
|
20
|
+
} else if (cmd.includes("--started-by daemon")) {
|
|
21
|
+
type = cmd.includes("tsx") ? "dev-daemon-spawned" : "daemon-spawned-session";
|
|
22
|
+
} else if (cmd.includes("doctor")) {
|
|
23
|
+
type = cmd.includes("tsx") ? "dev-doctor" : "doctor";
|
|
24
|
+
} else if (cmd.includes("--yolo")) {
|
|
25
|
+
type = "dev-session";
|
|
26
|
+
} else {
|
|
27
|
+
type = cmd.includes("tsx") ? "dev-related" : "user-session";
|
|
28
|
+
}
|
|
29
|
+
allProcesses.push({ pid: proc.pid, command: cmd || name, type });
|
|
30
|
+
}
|
|
31
|
+
return allProcesses;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function findRunawayHappyProcesses() {
|
|
37
|
+
const allProcesses = await findAllHappyProcesses();
|
|
38
|
+
return allProcesses.filter(
|
|
39
|
+
(p) => p.pid !== process.pid && (p.type === "daemon" || p.type === "dev-daemon" || p.type === "daemon-spawned-session" || p.type === "dev-daemon-spawned" || p.type === "daemon-version-check" || p.type === "dev-daemon-version-check")
|
|
40
|
+
).map((p) => ({ pid: p.pid, command: p.command }));
|
|
41
|
+
}
|
|
42
|
+
async function killRunawayHappyProcesses() {
|
|
43
|
+
const runawayProcesses = await findRunawayHappyProcesses();
|
|
44
|
+
const errors = [];
|
|
45
|
+
let killed = 0;
|
|
46
|
+
for (const { pid, command } of runawayProcesses) {
|
|
47
|
+
try {
|
|
48
|
+
console.log(`Killing runaway process PID ${pid}: ${command}`);
|
|
49
|
+
if (process.platform === "win32") {
|
|
50
|
+
const result = spawn.sync("taskkill", ["/F", "/PID", pid.toString()], { stdio: "pipe" });
|
|
51
|
+
if (result.error) throw result.error;
|
|
52
|
+
if (result.status !== 0) throw new Error(`taskkill exited with code ${result.status}`);
|
|
53
|
+
} else {
|
|
54
|
+
process.kill(pid, "SIGTERM");
|
|
55
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
56
|
+
const processes = await psList();
|
|
57
|
+
const stillAlive = processes.find((p) => p.pid === pid);
|
|
58
|
+
if (stillAlive) {
|
|
59
|
+
console.log(`Process PID ${pid} ignored SIGTERM, using SIGKILL`);
|
|
60
|
+
process.kill(pid, "SIGKILL");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
console.log(`Successfully killed runaway process PID ${pid}`);
|
|
64
|
+
killed++;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const errorMessage = error.message;
|
|
67
|
+
errors.push({ pid, error: errorMessage });
|
|
68
|
+
console.log(`Failed to kill process PID ${pid}: ${errorMessage}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return { killed, errors };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { findAllHappyProcesses, findRunawayHappyProcesses, killRunawayHappyProcesses };
|