@yeaft/webchat-agent 1.0.525 → 1.0.526
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/local-runtime/server/index.js +2 -0
- package/local-runtime/server/routes/installer-routes.js +19 -0
- package/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +148 -171
- package/local-runtime/web/app.bundle.js.gz +0 -0
- package/local-runtime/web/index.html +2 -2
- package/local-runtime/web/installers/install.ps1 +264 -0
- package/local-runtime/web/installers/install.sh +150 -0
- package/local-runtime/web/style.bundle.css +1 -1
- package/local-runtime/web/style.bundle.css.gz +0 -0
- package/package.json +1 -1
- package/service/linux.js +24 -11
- package/service/macos.js +23 -19
- package/service/windows.js +8 -7
|
Binary file
|
package/package.json
CHANGED
package/service/linux.js
CHANGED
|
@@ -12,17 +12,30 @@ export function getSystemdServicePath(instanceId = DEFAULT_INSTANCE_ID) {
|
|
|
12
12
|
return join(homedir(), '.config', 'systemd', 'user', `${getServiceName(instanceId)}.service`);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
// systemd unit values use C-style quoting and percent specifier expansion.
|
|
16
|
+
function quoteUnit(value, { executable = false } = {}) {
|
|
17
|
+
let escaped = String(value).replace(/%/g, '%%');
|
|
18
|
+
if (executable) escaped = escaped.replace(/\$/g, '$$$$');
|
|
19
|
+
return JSON.stringify(escaped);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function unitPath(value) {
|
|
23
|
+
const path = String(value);
|
|
24
|
+
if (/[\r\n\0]/.test(path)) throw new Error('Service paths cannot contain line breaks or NUL');
|
|
25
|
+
return path.replace(/%/g, '%%');
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
export function generateSystemdUnit(config) {
|
|
16
29
|
const nodePath = getNodePath();
|
|
17
30
|
const cliPath = getCliPath();
|
|
18
31
|
const logDir = getLogDir(config.instanceId);
|
|
19
32
|
const envLines = [];
|
|
20
|
-
if (config.instanceId) envLines.push(`Environment
|
|
21
|
-
if (config.serverUrl) envLines.push(`Environment
|
|
22
|
-
if (config.agentName) envLines.push(`Environment
|
|
23
|
-
if (config.agentSecret) envLines.push(`Environment
|
|
24
|
-
if (config.workDir) envLines.push(`Environment
|
|
25
|
-
if (config.yeaftDir) envLines.push(`Environment
|
|
33
|
+
if (config.instanceId) envLines.push(`Environment=${quoteUnit(`YEAFT_AGENT_INSTANCE=${config.instanceId}`)}`);
|
|
34
|
+
if (config.serverUrl) envLines.push(`Environment=${quoteUnit(`SERVER_URL=${config.serverUrl}`)}`);
|
|
35
|
+
if (config.agentName) envLines.push(`Environment=${quoteUnit(`AGENT_NAME=${config.agentName}`)}`);
|
|
36
|
+
if (config.agentSecret) envLines.push(`Environment=${quoteUnit(`AGENT_SECRET=${config.agentSecret}`)}`);
|
|
37
|
+
if (config.workDir) envLines.push(`Environment=${quoteUnit(`WORK_DIR=${config.workDir}`)}`);
|
|
38
|
+
if (config.yeaftDir) envLines.push(`Environment=${quoteUnit(`YEAFT_DIR=${config.yeaftDir}`)}`);
|
|
26
39
|
|
|
27
40
|
// Include node's bin dir in PATH for claude CLI access
|
|
28
41
|
const nodeBinDir = dirname(nodePath);
|
|
@@ -34,17 +47,17 @@ Wants=network-online.target
|
|
|
34
47
|
|
|
35
48
|
[Service]
|
|
36
49
|
Type=simple
|
|
37
|
-
ExecStart=${nodePath} ${cliPath}
|
|
38
|
-
WorkingDirectory=${config.workDir || homedir()}
|
|
50
|
+
ExecStart=${quoteUnit(nodePath, { executable: true })} ${quoteUnit(cliPath, { executable: true })}
|
|
51
|
+
WorkingDirectory=${unitPath(config.workDir || homedir())}
|
|
39
52
|
Restart=on-failure
|
|
40
53
|
RestartSec=10
|
|
41
54
|
KillMode=mixed
|
|
42
55
|
TimeoutStopSec=15
|
|
43
56
|
${envLines.join('\n')}
|
|
44
|
-
Environment
|
|
57
|
+
Environment=${quoteUnit(`PATH=${nodeBinDir}:${homedir()}/.local/bin:${homedir()}/.npm-global/bin:/usr/local/bin:/usr/bin:/bin`)}
|
|
45
58
|
|
|
46
|
-
StandardOutput=append:${logDir}/out.log
|
|
47
|
-
StandardError=append:${logDir}/error.log
|
|
59
|
+
StandardOutput=append:${unitPath(`${logDir}/out.log`)}
|
|
60
|
+
StandardError=append:${unitPath(`${logDir}/error.log`)}
|
|
48
61
|
|
|
49
62
|
[Install]
|
|
50
63
|
WantedBy=default.target
|
package/service/macos.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Service — macOS (launchd) platform implementation
|
|
3
3
|
*/
|
|
4
|
-
import { execSync } from 'child_process';
|
|
4
|
+
import { execFileSync, execSync } from 'child_process';
|
|
5
5
|
import { existsSync, writeFileSync, unlinkSync, mkdirSync } from 'fs';
|
|
6
6
|
import { join } from 'path';
|
|
7
7
|
import { homedir } from 'os';
|
|
@@ -12,33 +12,37 @@ export function getLaunchdPlistPath(instanceId = DEFAULT_INSTANCE_ID) {
|
|
|
12
12
|
return join(homedir(), 'Library', 'LaunchAgents', `${getLaunchdLabel(instanceId)}.plist`);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const xmlText = value => String(value).replace(/[&<>"']/g, char => ({
|
|
16
|
+
'&': '&', '<': '<', '>': '>', '"': '"', "'": ''',
|
|
17
|
+
})[char]);
|
|
18
|
+
|
|
19
|
+
export function generateLaunchdPlist(config) {
|
|
16
20
|
const nodePath = getNodePath();
|
|
17
21
|
const cliPath = getCliPath();
|
|
18
22
|
const logDir = getLogDir(config.instanceId);
|
|
19
23
|
const label = getLaunchdLabel(config.instanceId);
|
|
20
24
|
|
|
21
25
|
const envDict = [];
|
|
22
|
-
if (config.instanceId) envDict.push(` <key>YEAFT_AGENT_INSTANCE</key>\n <string>${config.instanceId}</string>`);
|
|
23
|
-
if (config.serverUrl) envDict.push(` <key>SERVER_URL</key>\n <string>${config.serverUrl}</string>`);
|
|
24
|
-
if (config.agentName) envDict.push(` <key>AGENT_NAME</key>\n <string>${config.agentName}</string>`);
|
|
25
|
-
if (config.agentSecret) envDict.push(` <key>AGENT_SECRET</key>\n <string>${config.agentSecret}</string>`);
|
|
26
|
-
if (config.workDir) envDict.push(` <key>WORK_DIR</key>\n <string>${config.workDir}</string>`);
|
|
27
|
-
if (config.yeaftDir) envDict.push(` <key>YEAFT_DIR</key>\n <string>${config.yeaftDir}</string>`);
|
|
26
|
+
if (config.instanceId) envDict.push(` <key>YEAFT_AGENT_INSTANCE</key>\n <string>${xmlText(config.instanceId)}</string>`);
|
|
27
|
+
if (config.serverUrl) envDict.push(` <key>SERVER_URL</key>\n <string>${xmlText(config.serverUrl)}</string>`);
|
|
28
|
+
if (config.agentName) envDict.push(` <key>AGENT_NAME</key>\n <string>${xmlText(config.agentName)}</string>`);
|
|
29
|
+
if (config.agentSecret) envDict.push(` <key>AGENT_SECRET</key>\n <string>${xmlText(config.agentSecret)}</string>`);
|
|
30
|
+
if (config.workDir) envDict.push(` <key>WORK_DIR</key>\n <string>${xmlText(config.workDir)}</string>`);
|
|
31
|
+
if (config.yeaftDir) envDict.push(` <key>YEAFT_DIR</key>\n <string>${xmlText(config.yeaftDir)}</string>`);
|
|
28
32
|
|
|
29
33
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
30
34
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
31
35
|
<plist version="1.0">
|
|
32
36
|
<dict>
|
|
33
37
|
<key>Label</key>
|
|
34
|
-
<string>${label}</string>
|
|
38
|
+
<string>${xmlText(label)}</string>
|
|
35
39
|
<key>ProgramArguments</key>
|
|
36
40
|
<array>
|
|
37
|
-
<string>${nodePath}</string>
|
|
38
|
-
<string>${cliPath}</string>
|
|
41
|
+
<string>${xmlText(nodePath)}</string>
|
|
42
|
+
<string>${xmlText(cliPath)}</string>
|
|
39
43
|
</array>
|
|
40
44
|
<key>WorkingDirectory</key>
|
|
41
|
-
<string>${config.workDir || homedir()}</string>
|
|
45
|
+
<string>${xmlText(config.workDir || homedir())}</string>
|
|
42
46
|
<key>EnvironmentVariables</key>
|
|
43
47
|
<dict>
|
|
44
48
|
${envDict.join('\n')}
|
|
@@ -53,9 +57,9 @@ ${envDict.join('\n')}
|
|
|
53
57
|
<key>ThrottleInterval</key>
|
|
54
58
|
<integer>10</integer>
|
|
55
59
|
<key>StandardOutPath</key>
|
|
56
|
-
<string>${logDir}/out.log</string>
|
|
60
|
+
<string>${xmlText(`${logDir}/out.log`)}</string>
|
|
57
61
|
<key>StandardErrorPath</key>
|
|
58
|
-
<string>${logDir}/error.log</string>
|
|
62
|
+
<string>${xmlText(`${logDir}/error.log`)}</string>
|
|
59
63
|
</dict>
|
|
60
64
|
</plist>
|
|
61
65
|
`;
|
|
@@ -68,10 +72,10 @@ export function macInstall(config) {
|
|
|
68
72
|
mkdirSync(getLogDir(config.instanceId), { recursive: true });
|
|
69
73
|
// Unload first if exists
|
|
70
74
|
if (existsSync(plistPath)) {
|
|
71
|
-
try {
|
|
75
|
+
try { execFileSync('launchctl', ['unload', plistPath], { stdio: 'pipe' }); } catch {}
|
|
72
76
|
}
|
|
73
77
|
writeFileSync(plistPath, generateLaunchdPlist(config));
|
|
74
|
-
|
|
78
|
+
execFileSync('launchctl', ['load', plistPath]);
|
|
75
79
|
console.log(`Service installed and started: ${getLaunchdLabel(config.instanceId)}`);
|
|
76
80
|
console.log(`\nManage with:`);
|
|
77
81
|
console.log(` yeaft-agent status --name ${config.instanceId}`);
|
|
@@ -83,7 +87,7 @@ export function macInstall(config) {
|
|
|
83
87
|
export function macUninstall(instanceId = DEFAULT_INSTANCE_ID) {
|
|
84
88
|
const plistPath = getLaunchdPlistPath(instanceId);
|
|
85
89
|
if (existsSync(plistPath)) {
|
|
86
|
-
try {
|
|
90
|
+
try { execFileSync('launchctl', ['unload', plistPath]); } catch {}
|
|
87
91
|
unlinkSync(plistPath);
|
|
88
92
|
}
|
|
89
93
|
console.log(`Service uninstalled: ${getLaunchdLabel(instanceId)}`);
|
|
@@ -95,14 +99,14 @@ export function macStart(instanceId = DEFAULT_INSTANCE_ID) {
|
|
|
95
99
|
console.error('Service not installed. Run "yeaft-agent install" first.');
|
|
96
100
|
process.exit(1);
|
|
97
101
|
}
|
|
98
|
-
|
|
102
|
+
execFileSync('launchctl', ['load', plistPath]);
|
|
99
103
|
console.log(`Service started: ${getLaunchdLabel(instanceId)}`);
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
export function macStop(instanceId = DEFAULT_INSTANCE_ID) {
|
|
103
107
|
const plistPath = getLaunchdPlistPath(instanceId);
|
|
104
108
|
if (existsSync(plistPath)) {
|
|
105
|
-
|
|
109
|
+
execFileSync('launchctl', ['unload', plistPath]);
|
|
106
110
|
}
|
|
107
111
|
console.log(`Service stopped: ${getLaunchdLabel(instanceId)}`);
|
|
108
112
|
}
|
package/service/windows.js
CHANGED
|
@@ -26,7 +26,7 @@ export function getEcosystemPath(instanceId = DEFAULT_INSTANCE_ID) {
|
|
|
26
26
|
return join(getConfigDir(instanceId), 'ecosystem.config.cjs');
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function generateEcosystem(config) {
|
|
29
|
+
export function generateEcosystem(config) {
|
|
30
30
|
const nodePath = getNodePath();
|
|
31
31
|
const cliPath = getCliPath();
|
|
32
32
|
const cliDir = dirname(cliPath);
|
|
@@ -43,18 +43,18 @@ function generateEcosystem(config) {
|
|
|
43
43
|
|
|
44
44
|
return `module.exports = {
|
|
45
45
|
apps: [{
|
|
46
|
-
name:
|
|
47
|
-
script:
|
|
48
|
-
interpreter:
|
|
49
|
-
cwd:
|
|
46
|
+
name: ${JSON.stringify(pm2AppName)},
|
|
47
|
+
script: ${JSON.stringify(cliPath)},
|
|
48
|
+
interpreter: ${JSON.stringify(nodePath)},
|
|
49
|
+
cwd: ${JSON.stringify(cliDir)},
|
|
50
50
|
env: ${JSON.stringify(env, null, 6)},
|
|
51
51
|
autorestart: true,
|
|
52
52
|
watch: false,
|
|
53
53
|
max_restarts: 10,
|
|
54
54
|
restart_delay: 5000,
|
|
55
55
|
log_date_format: 'YYYY-MM-DD HH:mm:ss',
|
|
56
|
-
error_file:
|
|
57
|
-
out_file:
|
|
56
|
+
error_file: ${JSON.stringify(join(logDir, 'error.log'))},
|
|
57
|
+
out_file: ${JSON.stringify(join(logDir, 'out.log'))},
|
|
58
58
|
merge_logs: true,
|
|
59
59
|
max_memory_restart: '500M',
|
|
60
60
|
}]
|
|
@@ -105,6 +105,7 @@ export function winInstall(config) {
|
|
|
105
105
|
// pm2-startup doesn't work well on Windows, use Startup folder approach
|
|
106
106
|
const trayScript = join(dirname(getCliPath()), 'scripts', 'agent-tray.ps1');
|
|
107
107
|
const startupDir = join(process.env.APPDATA, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');
|
|
108
|
+
mkdirSync(startupDir, { recursive: true });
|
|
108
109
|
const startupBat = join(startupDir, `${pm2AppName}.bat`);
|
|
109
110
|
// Resurrect pm2 processes + launch tray icon
|
|
110
111
|
let batContent = `@echo off\r\npm2 resurrect\r\n`;
|