@yeaft/webchat-agent 0.1.208 → 0.1.210
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/cli.js +9 -1
- package/connection/upgrade.js +24 -10
- package/package.json +1 -1
- package/service/doctor.js +296 -0
- package/service/index.js +3 -0
- package/service.js +2 -1
package/cli.js
CHANGED
|
@@ -19,7 +19,9 @@ const subArgs = args.slice(1);
|
|
|
19
19
|
// Service management subcommands
|
|
20
20
|
const SERVICE_COMMANDS = ['install', 'uninstall', 'start', 'stop', 'restart', 'status', 'logs'];
|
|
21
21
|
|
|
22
|
-
if (command === '
|
|
22
|
+
if (command === 'doctor') {
|
|
23
|
+
handleDoctorCommand();
|
|
24
|
+
} else if (command === 'upgrade') {
|
|
23
25
|
upgrade();
|
|
24
26
|
} else if (command === '--version' || command === '-v') {
|
|
25
27
|
console.log(pkg.version);
|
|
@@ -45,6 +47,7 @@ function printHelp() {
|
|
|
45
47
|
yeaft-agent restart Restart installed service
|
|
46
48
|
yeaft-agent status Show service status
|
|
47
49
|
yeaft-agent logs View service logs (follow mode)
|
|
50
|
+
yeaft-agent doctor Diagnose service configuration
|
|
48
51
|
yeaft-agent upgrade Upgrade to latest version
|
|
49
52
|
yeaft-agent --version Show version
|
|
50
53
|
|
|
@@ -82,6 +85,11 @@ async function handleServiceCommand(command, args) {
|
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
async function handleDoctorCommand() {
|
|
89
|
+
const { doctor } = await import('./service.js');
|
|
90
|
+
doctor();
|
|
91
|
+
}
|
|
92
|
+
|
|
85
93
|
function parseAndStart(args) {
|
|
86
94
|
// Parse CLI flags → set environment variables (env vars take precedence over flags)
|
|
87
95
|
for (let i = 0; i < args.length; i++) {
|
package/connection/upgrade.js
CHANGED
|
@@ -10,6 +10,13 @@ import { stopAgentHeartbeat } from './heartbeat.js';
|
|
|
10
10
|
|
|
11
11
|
const PM2_APP_NAME = 'yeaft-agent';
|
|
12
12
|
|
|
13
|
+
// Derive absolute paths for npm/pm2 from current node executable.
|
|
14
|
+
// In launchd/systemd environments, PATH may not include nvm/node dirs,
|
|
15
|
+
// but process.execPath always points to the running node binary.
|
|
16
|
+
const nodeBinDir = dirname(process.execPath);
|
|
17
|
+
const npmPath = join(nodeBinDir, 'npm');
|
|
18
|
+
const pm2Path = join(nodeBinDir, 'pm2');
|
|
19
|
+
|
|
13
20
|
// Shared cleanup logic for restart/upgrade
|
|
14
21
|
function cleanupAndExit(exitCode) {
|
|
15
22
|
setTimeout(() => {
|
|
@@ -46,7 +53,7 @@ export async function handleUpgradeAgent() {
|
|
|
46
53
|
const pkgName = ctx.pkgName || '@yeaft/webchat-agent';
|
|
47
54
|
// Check latest version (async to avoid blocking heartbeat)
|
|
48
55
|
const latestVersion = await new Promise((resolve, reject) => {
|
|
49
|
-
execFile(
|
|
56
|
+
execFile(npmPath, ['view', pkgName, 'version'], { stdio: 'pipe' }, (err, stdout) => {
|
|
50
57
|
if (err) reject(err); else resolve(stdout.toString().trim());
|
|
51
58
|
});
|
|
52
59
|
});
|
|
@@ -74,7 +81,7 @@ export async function handleUpgradeAgent() {
|
|
|
74
81
|
|
|
75
82
|
// 判断全局安装 vs 局部安装
|
|
76
83
|
const isGlobalInstall = await new Promise((resolve) => {
|
|
77
|
-
execFile(
|
|
84
|
+
execFile(npmPath, ['prefix', '-g'], (err, stdout) => {
|
|
78
85
|
if (err) { resolve(false); return; }
|
|
79
86
|
const globalPrefix = stdout.toString().trim().replace(/\\/g, '/');
|
|
80
87
|
resolve(installDir === globalPrefix || installDir === globalPrefix + '/lib');
|
|
@@ -94,7 +101,7 @@ export async function handleUpgradeAgent() {
|
|
|
94
101
|
const isPm2 = !!process.env.pm_id;
|
|
95
102
|
if (isPm2) {
|
|
96
103
|
try {
|
|
97
|
-
execFileSync(
|
|
104
|
+
execFileSync(pm2Path, ['delete', PM2_APP_NAME], { stdio: 'pipe' });
|
|
98
105
|
console.log(`[Agent] PM2 app deleted to prevent auto-restart during upgrade`);
|
|
99
106
|
} catch {
|
|
100
107
|
console.log(`[Agent] PM2 delete skipped (app may not be registered)`);
|
|
@@ -131,6 +138,8 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
|
|
|
131
138
|
// Determine the target package directory inside node_modules
|
|
132
139
|
const pkgDir = join(installDir, 'node_modules', ...pkgName.split('/')).replace(/\//g, '\\');
|
|
133
140
|
|
|
141
|
+
const pm2Win = pm2Path.replace(/\//g, '\\');
|
|
142
|
+
|
|
134
143
|
const batLines = [
|
|
135
144
|
'@echo off',
|
|
136
145
|
'setlocal',
|
|
@@ -178,7 +187,7 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
|
|
|
178
187
|
// Use Node.js worker for file-level upgrade (avoids EBUSY on directory rename)
|
|
179
188
|
batLines.push(
|
|
180
189
|
'echo [Upgrade] Running upgrade worker at %time%... >> "%LOGFILE%"',
|
|
181
|
-
'
|
|
190
|
+
`"${process.execPath.replace(/\//g, '\\')}" "%WORKER%" "%PKG%" "%PKG_DIR%" "%LOGFILE%"`,
|
|
182
191
|
'if not "%errorlevel%"=="0" (',
|
|
183
192
|
' echo [Upgrade] Worker failed with exit code %errorlevel% at %time% >> "%LOGFILE%"',
|
|
184
193
|
' goto CLEANUP',
|
|
@@ -193,8 +202,8 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
|
|
|
193
202
|
batLines.push(
|
|
194
203
|
'echo [Upgrade] Re-registering agent via PM2... >> "%LOGFILE%"',
|
|
195
204
|
`if exist "${ecoPath}" (`,
|
|
196
|
-
` call
|
|
197
|
-
|
|
205
|
+
` call "${pm2Win}" start "${ecoPath}" >> "%LOGFILE%" 2>&1`,
|
|
206
|
+
` call "${pm2Win}" save >> "%LOGFILE%" 2>&1`,
|
|
198
207
|
' echo [Upgrade] PM2 app re-registered at %time% >> "%LOGFILE%"',
|
|
199
208
|
') else (',
|
|
200
209
|
' echo [Upgrade] WARNING: ecosystem.config.cjs not found, PM2 not restarted >> "%LOGFILE%"',
|
|
@@ -241,12 +250,17 @@ function spawnUnixUpgradeScript(pkgName, installDir, isGlobalInstall, latestVers
|
|
|
241
250
|
const isLaunchd = platform() === 'darwin' && existsSync(join(process.env.HOME || '', 'Library', 'LaunchAgents', 'com.yeaft.agent.plist'));
|
|
242
251
|
const cwd = isGlobalInstall ? undefined : installDir;
|
|
243
252
|
|
|
253
|
+
// Ensure PATH includes the node bin dir (critical for launchd which has minimal PATH)
|
|
254
|
+
const currentPath = process.env.PATH || '/usr/bin:/bin:/usr/sbin:/sbin';
|
|
255
|
+
const exportPath = currentPath.includes(nodeBinDir) ? currentPath : `${nodeBinDir}:${currentPath}`;
|
|
256
|
+
|
|
244
257
|
const shLines = [
|
|
245
258
|
'#!/bin/bash',
|
|
246
259
|
`PID=${pid}`,
|
|
247
260
|
`PKG="${pkgName}@latest"`,
|
|
261
|
+
`NPM="${npmPath}"`,
|
|
248
262
|
`LOGFILE="${join(configDir, 'logs', 'upgrade.log')}"`,
|
|
249
|
-
`export PATH="${
|
|
263
|
+
`export PATH="${exportPath}"`,
|
|
250
264
|
'',
|
|
251
265
|
'# Redirect all output to log file',
|
|
252
266
|
'exec > "$LOGFILE" 2>&1',
|
|
@@ -285,10 +299,10 @@ function spawnUnixUpgradeScript(pkgName, installDir, isGlobalInstall, latestVers
|
|
|
285
299
|
);
|
|
286
300
|
}
|
|
287
301
|
|
|
288
|
-
// npm install
|
|
302
|
+
// npm install (use absolute path via $NPM variable)
|
|
289
303
|
const npmCmd = isGlobalInstall
|
|
290
|
-
? `
|
|
291
|
-
: `cd "$INSTALL_DIR" &&
|
|
304
|
+
? `"$NPM" install -g "$PKG"`
|
|
305
|
+
: `cd "$INSTALL_DIR" && "$NPM" install "$PKG"`;
|
|
292
306
|
|
|
293
307
|
shLines.push(
|
|
294
308
|
'echo "[Upgrade] Installing $PKG..."',
|
package/package.json
CHANGED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service — doctor command
|
|
3
|
+
* Diagnoses service configuration issues: checks paths, service status, version consistency.
|
|
4
|
+
*/
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
import { existsSync, readFileSync, statSync } from 'fs';
|
|
7
|
+
import { join, dirname } from 'path';
|
|
8
|
+
import { platform, homedir } from 'os';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { SERVICE_NAME } from './config.js';
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
|
|
14
|
+
// ── Platform-specific service config paths ─────────────────────────────────
|
|
15
|
+
|
|
16
|
+
function getMacPlistPath() {
|
|
17
|
+
return join(homedir(), 'Library', 'LaunchAgents', 'com.yeaft.agent.plist');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getLinuxServicePath() {
|
|
21
|
+
return join(homedir(), '.config', 'systemd', 'user', `${SERVICE_NAME}.service`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getWindowsEcosystemPath() {
|
|
25
|
+
const appData = process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');
|
|
26
|
+
return join(appData, SERVICE_NAME, 'ecosystem.config.cjs');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── Parse paths from service config files ──────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parse node path and cli path from macOS launchd plist.
|
|
33
|
+
* ProgramArguments is an array: [nodePath, cliPath]
|
|
34
|
+
*/
|
|
35
|
+
function parseMacPaths(plistPath) {
|
|
36
|
+
const content = readFileSync(plistPath, 'utf-8');
|
|
37
|
+
const args = [];
|
|
38
|
+
// Match <string> values inside <array> after ProgramArguments
|
|
39
|
+
const arrayMatch = content.match(/<key>ProgramArguments<\/key>\s*<array>([\s\S]*?)<\/array>/);
|
|
40
|
+
if (arrayMatch) {
|
|
41
|
+
const stringRegex = /<string>(.*?)<\/string>/g;
|
|
42
|
+
let m;
|
|
43
|
+
while ((m = stringRegex.exec(arrayMatch[1])) !== null) {
|
|
44
|
+
args.push(m[1]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { nodePath: args[0] || null, cliPath: args[1] || null };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parse node path and cli path from Linux systemd unit.
|
|
52
|
+
* ExecStart=<nodePath> <cliPath>
|
|
53
|
+
*/
|
|
54
|
+
function parseLinuxPaths(servicePath) {
|
|
55
|
+
const content = readFileSync(servicePath, 'utf-8');
|
|
56
|
+
const match = content.match(/^ExecStart=(.+)$/m);
|
|
57
|
+
if (match) {
|
|
58
|
+
const parts = match[1].trim().split(/\s+/);
|
|
59
|
+
return { nodePath: parts[0] || null, cliPath: parts[1] || null };
|
|
60
|
+
}
|
|
61
|
+
return { nodePath: null, cliPath: null };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Parse node path and cli path from Windows pm2 ecosystem config.
|
|
66
|
+
* interpreter: '<nodePath>', script: '<cliPath>'
|
|
67
|
+
*/
|
|
68
|
+
function parseWindowsPaths(ecoPath) {
|
|
69
|
+
const content = readFileSync(ecoPath, 'utf-8');
|
|
70
|
+
const interpreterMatch = content.match(/interpreter:\s*'([^']+)'/);
|
|
71
|
+
const scriptMatch = content.match(/script:\s*'([^']+)'/);
|
|
72
|
+
return {
|
|
73
|
+
nodePath: interpreterMatch ? interpreterMatch[1].replace(/\\\\/g, '\\') : null,
|
|
74
|
+
cliPath: scriptMatch ? scriptMatch[1].replace(/\\\\/g, '\\') : null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Check helpers ──────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
function isExecutable(filePath) {
|
|
81
|
+
try {
|
|
82
|
+
const stat = statSync(filePath);
|
|
83
|
+
if (platform() === 'win32') {
|
|
84
|
+
return stat.isFile();
|
|
85
|
+
}
|
|
86
|
+
// On Unix, check if any execute bit is set
|
|
87
|
+
return stat.isFile() && (stat.mode & 0o111) !== 0;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getNodeVersion(nodePath) {
|
|
94
|
+
try {
|
|
95
|
+
return execSync(`"${nodePath}" --version`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getCliVersion(nodePath, cliPath) {
|
|
102
|
+
try {
|
|
103
|
+
return execSync(`"${nodePath}" "${cliPath}" --version`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getCurrentNodePath() {
|
|
110
|
+
return process.execPath;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function getCurrentNodeVersion() {
|
|
114
|
+
return process.version;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── Service status checks ──────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
function getMacServiceStatus() {
|
|
120
|
+
try {
|
|
121
|
+
const output = execSync('launchctl list | grep com.yeaft.agent', {
|
|
122
|
+
encoding: 'utf-8',
|
|
123
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
124
|
+
});
|
|
125
|
+
if (output.trim()) {
|
|
126
|
+
const parts = output.trim().split(/\s+/);
|
|
127
|
+
const pid = parts[0];
|
|
128
|
+
if (pid !== '-') {
|
|
129
|
+
return { running: true, pid };
|
|
130
|
+
}
|
|
131
|
+
return { running: false, pid: null };
|
|
132
|
+
}
|
|
133
|
+
return { running: false, pid: null };
|
|
134
|
+
} catch {
|
|
135
|
+
return { running: false, pid: null };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getLinuxServiceStatus() {
|
|
140
|
+
try {
|
|
141
|
+
const output = execSync(`systemctl --user is-active ${SERVICE_NAME}`, {
|
|
142
|
+
encoding: 'utf-8',
|
|
143
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
144
|
+
}).trim();
|
|
145
|
+
if (output === 'active') {
|
|
146
|
+
// Try to get PID
|
|
147
|
+
let pid = null;
|
|
148
|
+
try {
|
|
149
|
+
pid = execSync(`systemctl --user show ${SERVICE_NAME} --property=MainPID --value`, {
|
|
150
|
+
encoding: 'utf-8',
|
|
151
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
152
|
+
}).trim();
|
|
153
|
+
if (pid === '0') pid = null;
|
|
154
|
+
} catch {}
|
|
155
|
+
return { running: true, pid };
|
|
156
|
+
}
|
|
157
|
+
return { running: false, pid: null };
|
|
158
|
+
} catch {
|
|
159
|
+
return { running: false, pid: null };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function getWindowsServiceStatus() {
|
|
164
|
+
try {
|
|
165
|
+
const output = execSync('pm2 jlist', {
|
|
166
|
+
encoding: 'utf-8',
|
|
167
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
168
|
+
});
|
|
169
|
+
const apps = JSON.parse(output);
|
|
170
|
+
const app = Array.isArray(apps) && apps.find(a => a.name === 'yeaft-agent');
|
|
171
|
+
if (app) {
|
|
172
|
+
const running = app.pm2_env && app.pm2_env.status === 'online';
|
|
173
|
+
const pid = running ? app.pid : null;
|
|
174
|
+
return { running, pid: pid ? String(pid) : null };
|
|
175
|
+
}
|
|
176
|
+
return { running: false, pid: null };
|
|
177
|
+
} catch {
|
|
178
|
+
return { running: false, pid: null };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ── Tilde shorthand for display ────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
function tildeify(filePath) {
|
|
185
|
+
const home = homedir();
|
|
186
|
+
if (filePath && filePath.startsWith(home)) {
|
|
187
|
+
return '~' + filePath.slice(home.length);
|
|
188
|
+
}
|
|
189
|
+
return filePath;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ── Main doctor logic ──────────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
export function doctor() {
|
|
195
|
+
const os = platform();
|
|
196
|
+
let configPath = null;
|
|
197
|
+
let parsePaths = null;
|
|
198
|
+
let getServiceStatus = null;
|
|
199
|
+
|
|
200
|
+
console.log('');
|
|
201
|
+
|
|
202
|
+
// 1. Determine platform and config path
|
|
203
|
+
if (os === 'darwin') {
|
|
204
|
+
configPath = getMacPlistPath();
|
|
205
|
+
parsePaths = parseMacPaths;
|
|
206
|
+
getServiceStatus = getMacServiceStatus;
|
|
207
|
+
} else if (os === 'linux') {
|
|
208
|
+
configPath = getLinuxServicePath();
|
|
209
|
+
parsePaths = parseLinuxPaths;
|
|
210
|
+
getServiceStatus = getLinuxServiceStatus;
|
|
211
|
+
} else if (os === 'win32') {
|
|
212
|
+
configPath = getWindowsEcosystemPath();
|
|
213
|
+
parsePaths = parseWindowsPaths;
|
|
214
|
+
getServiceStatus = getWindowsServiceStatus;
|
|
215
|
+
} else {
|
|
216
|
+
console.log(`\u26a0\ufe0f Unsupported platform: ${os}`);
|
|
217
|
+
console.log(` The doctor command supports macOS, Linux, and Windows.`);
|
|
218
|
+
console.log('');
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// 2. Check if service config exists
|
|
223
|
+
if (!existsSync(configPath)) {
|
|
224
|
+
console.log(`\u26a0\ufe0f No service configuration found.`);
|
|
225
|
+
console.log(` Run 'yeaft-agent install --server <url> --name <name> --secret <secret>' to set up.`);
|
|
226
|
+
console.log('');
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
console.log(`\u2705 Service installed: ${tildeify(configPath)}`);
|
|
231
|
+
|
|
232
|
+
let hasErrors = false;
|
|
233
|
+
|
|
234
|
+
// 3. Parse paths from config
|
|
235
|
+
const { nodePath, cliPath } = parsePaths(configPath);
|
|
236
|
+
|
|
237
|
+
// 4. Check node path
|
|
238
|
+
if (!nodePath) {
|
|
239
|
+
console.log(`\u274c Node path: not found in service config`);
|
|
240
|
+
hasErrors = true;
|
|
241
|
+
} else if (!existsSync(nodePath)) {
|
|
242
|
+
console.log(`\u274c Node path invalid: ${nodePath} (file not found)`);
|
|
243
|
+
console.log(` Current node: ${getCurrentNodePath()} (${getCurrentNodeVersion()})`);
|
|
244
|
+
hasErrors = true;
|
|
245
|
+
} else if (!isExecutable(nodePath)) {
|
|
246
|
+
console.log(`\u274c Node path not executable: ${nodePath}`);
|
|
247
|
+
console.log(` Current node: ${getCurrentNodePath()} (${getCurrentNodeVersion()})`);
|
|
248
|
+
hasErrors = true;
|
|
249
|
+
} else {
|
|
250
|
+
const nodeVersion = getNodeVersion(nodePath);
|
|
251
|
+
console.log(`\u2705 Node path valid: ${nodePath} (${nodeVersion || 'unknown version'})`);
|
|
252
|
+
|
|
253
|
+
// 4a. Version consistency check
|
|
254
|
+
const currentVersion = getCurrentNodeVersion();
|
|
255
|
+
if (nodeVersion && nodeVersion !== currentVersion) {
|
|
256
|
+
console.log(` \u26a0\ufe0f Version mismatch: service uses ${nodeVersion}, current terminal uses ${currentVersion}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 5. Check cli path
|
|
261
|
+
if (!cliPath) {
|
|
262
|
+
console.log(`\u274c CLI path: not found in service config`);
|
|
263
|
+
hasErrors = true;
|
|
264
|
+
} else if (!existsSync(cliPath)) {
|
|
265
|
+
console.log(`\u274c CLI path invalid: ${cliPath} (file not found)`);
|
|
266
|
+
hasErrors = true;
|
|
267
|
+
} else {
|
|
268
|
+
// Try to get CLI version
|
|
269
|
+
let versionStr = '';
|
|
270
|
+
if (nodePath && existsSync(nodePath)) {
|
|
271
|
+
const cliVersion = getCliVersion(nodePath, cliPath);
|
|
272
|
+
if (cliVersion) versionStr = ` (v${cliVersion})`;
|
|
273
|
+
}
|
|
274
|
+
console.log(`\u2705 CLI path valid: ${tildeify(cliPath)}${versionStr}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 6. Check service status
|
|
278
|
+
const status = getServiceStatus();
|
|
279
|
+
if (status.running) {
|
|
280
|
+
console.log(`\u2705 Service running: PID ${status.pid}`);
|
|
281
|
+
} else {
|
|
282
|
+
console.log(`\u274c Service not running`);
|
|
283
|
+
hasErrors = true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 7. Summary
|
|
287
|
+
console.log('');
|
|
288
|
+
if (hasErrors) {
|
|
289
|
+
console.log('Fix: Run the following commands:');
|
|
290
|
+
console.log(' npm install -g @yeaft/webchat-agent');
|
|
291
|
+
console.log(' yeaft-agent install --server <your-server-url> --name <your-agent-name> --secret <your-secret>');
|
|
292
|
+
} else {
|
|
293
|
+
console.log('All checks passed.');
|
|
294
|
+
}
|
|
295
|
+
console.log('');
|
|
296
|
+
}
|
package/service/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { getSystemdServicePath, linuxInstall, linuxUninstall, linuxStart, linuxStop, linuxRestart, linuxStatus, linuxLogs } from './linux.js';
|
|
13
13
|
import { getLaunchdPlistPath, macInstall, macUninstall, macStart, macStop, macRestart, macStatus, macLogs } from './macos.js';
|
|
14
14
|
import { winInstall, winUninstall, winStart, winStop, winRestart, winStatus, winLogs } from './windows.js';
|
|
15
|
+
import { doctor } from './doctor.js';
|
|
15
16
|
|
|
16
17
|
export {
|
|
17
18
|
getConfigDir, getLogDir, getConfigPath,
|
|
@@ -97,3 +98,5 @@ export function logs() {
|
|
|
97
98
|
else if (os === 'darwin') macLogs();
|
|
98
99
|
else if (os === 'win32') winLogs();
|
|
99
100
|
}
|
|
101
|
+
|
|
102
|
+
export { doctor };
|