@yeaft/webchat-agent 0.1.135 → 0.1.136
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 +67 -12
- package/connection/upgrade.js +38 -16
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -178,10 +178,26 @@ function upgradeWindows(latestVersion) {
|
|
|
178
178
|
const logDir = join(configDir, 'logs');
|
|
179
179
|
mkdirSync(logDir, { recursive: true });
|
|
180
180
|
const batPath = join(configDir, 'upgrade-cli.bat');
|
|
181
|
+
const vbsPath = join(configDir, 'upgrade-cli.vbs');
|
|
181
182
|
const logPath = join(logDir, 'upgrade.log');
|
|
182
183
|
const pid = process.pid;
|
|
183
184
|
const pkgSpec = `${pkg.name}@${latestVersion}`;
|
|
184
185
|
|
|
186
|
+
// --- PM2 handling: delete app before exit to prevent auto-restart ---
|
|
187
|
+
let isPm2 = false;
|
|
188
|
+
const ecoPath = join(configDir, 'ecosystem.config.cjs');
|
|
189
|
+
try {
|
|
190
|
+
const pm2List = execSync('pm2 jlist', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
191
|
+
const apps = JSON.parse(pm2List);
|
|
192
|
+
isPm2 = Array.isArray(apps) && apps.some(app => app.name === 'yeaft-agent');
|
|
193
|
+
if (isPm2) {
|
|
194
|
+
execSync('pm2 delete yeaft-agent', { stdio: 'pipe' });
|
|
195
|
+
console.log('PM2 app deleted to prevent auto-restart during upgrade.');
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
// PM2 not installed or not managing yeaft-agent — continue
|
|
199
|
+
}
|
|
200
|
+
|
|
185
201
|
const batLines = [
|
|
186
202
|
'@echo off',
|
|
187
203
|
'setlocal',
|
|
@@ -195,6 +211,8 @@ function upgradeWindows(latestVersion) {
|
|
|
195
211
|
'cd /d "%TEMP%"',
|
|
196
212
|
'',
|
|
197
213
|
'echo [Upgrade] Started at %date% %time% > "%LOGFILE%"',
|
|
214
|
+
`echo [Upgrade] Version: ${pkg.version} -> ${latestVersion} >> "%LOGFILE%"`,
|
|
215
|
+
`echo [Upgrade] PM2 managed: ${isPm2 ? 'yes (deleted pre-exit)' : 'no'} >> "%LOGFILE%"`,
|
|
198
216
|
'echo [Upgrade] Waiting for CLI process (PID %PID%) to exit... >> "%LOGFILE%"',
|
|
199
217
|
'',
|
|
200
218
|
':WAIT_LOOP',
|
|
@@ -202,34 +220,71 @@ function upgradeWindows(latestVersion) {
|
|
|
202
220
|
'if errorlevel 1 goto PID_EXITED',
|
|
203
221
|
'set /A COUNT+=1',
|
|
204
222
|
'if %COUNT% GEQ %MAX_WAIT% (',
|
|
205
|
-
' echo [Upgrade] Timeout waiting for PID %PID% to exit after %MAX_WAIT%
|
|
223
|
+
' echo [Upgrade] Timeout waiting for PID %PID% to exit after %MAX_WAIT%s >> "%LOGFILE%"',
|
|
206
224
|
' goto PID_EXITED',
|
|
207
225
|
')',
|
|
208
226
|
'ping -n 3 127.0.0.1 >NUL',
|
|
209
227
|
'goto WAIT_LOOP',
|
|
210
228
|
':PID_EXITED',
|
|
211
229
|
'',
|
|
212
|
-
'
|
|
230
|
+
':: Extra wait for file locks to release',
|
|
231
|
+
'echo [Upgrade] Process exited at %time%, waiting for file locks... >> "%LOGFILE%"',
|
|
232
|
+
'ping -n 5 127.0.0.1 >NUL',
|
|
233
|
+
'',
|
|
234
|
+
'echo [Upgrade] Running npm install -g %PKG%... >> "%LOGFILE%"',
|
|
213
235
|
'call npm install -g %PKG% >> "%LOGFILE%" 2>&1',
|
|
214
236
|
'if not "%errorlevel%"=="0" (',
|
|
215
|
-
' echo [Upgrade] npm install failed with exit code %errorlevel% >> "%LOGFILE%"',
|
|
216
|
-
' goto
|
|
237
|
+
' echo [Upgrade] npm install failed with exit code %errorlevel% at %time% >> "%LOGFILE%"',
|
|
238
|
+
' goto PM2_RESTART',
|
|
217
239
|
')',
|
|
218
|
-
'echo [Upgrade]
|
|
240
|
+
'echo [Upgrade] npm install succeeded at %time% >> "%LOGFILE%"',
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
// PM2 re-registration after successful upgrade
|
|
244
|
+
batLines.push(
|
|
219
245
|
'',
|
|
220
|
-
':
|
|
246
|
+
':PM2_RESTART',
|
|
247
|
+
);
|
|
248
|
+
if (isPm2) {
|
|
249
|
+
batLines.push(
|
|
250
|
+
'echo [Upgrade] Re-registering agent via PM2... >> "%LOGFILE%"',
|
|
251
|
+
`if exist "${ecoPath}" (`,
|
|
252
|
+
` call pm2 start "${ecoPath}" >> "%LOGFILE%" 2>&1`,
|
|
253
|
+
' call pm2 save >> "%LOGFILE%" 2>&1',
|
|
254
|
+
' echo [Upgrade] PM2 app re-registered at %time% >> "%LOGFILE%"',
|
|
255
|
+
') else (',
|
|
256
|
+
' echo [Upgrade] WARNING: ecosystem.config.cjs not found, PM2 not restarted >> "%LOGFILE%"',
|
|
257
|
+
')',
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
batLines.push(
|
|
262
|
+
'',
|
|
263
|
+
'echo [Upgrade] Finished at %time% >> "%LOGFILE%"',
|
|
264
|
+
':CLEANUP',
|
|
265
|
+
`del /F /Q "${vbsPath}" 2>NUL`,
|
|
221
266
|
`del /F /Q "${batPath}" 2>NUL`,
|
|
222
|
-
|
|
267
|
+
);
|
|
223
268
|
|
|
224
269
|
writeFileSync(batPath, batLines.join('\r\n'));
|
|
225
|
-
|
|
270
|
+
|
|
271
|
+
// Use VBScript wrapper to fully detach the bat process from the parent.
|
|
272
|
+
// WshShell.Run with 0 (hidden window) and False (don't wait) ensures the bat
|
|
273
|
+
// runs completely independently — survives parent exit, no console window flash.
|
|
274
|
+
const vbsLines = [
|
|
275
|
+
'Set WshShell = CreateObject("WScript.Shell")',
|
|
276
|
+
`WshShell.Run """${batPath}""", 0, False`,
|
|
277
|
+
];
|
|
278
|
+
writeFileSync(vbsPath, vbsLines.join('\r\n'));
|
|
279
|
+
|
|
280
|
+
spawn('wscript.exe', [vbsPath], {
|
|
226
281
|
detached: true,
|
|
227
282
|
stdio: 'ignore',
|
|
228
283
|
windowsHide: true,
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
console.log(`Upgrade script spawned
|
|
232
|
-
console.log(`The upgrade will proceed after
|
|
284
|
+
}).unref();
|
|
285
|
+
|
|
286
|
+
console.log(`Upgrade script spawned via VBScript wrapper.`);
|
|
287
|
+
console.log(`This process will exit now. The upgrade will proceed after exit.`);
|
|
233
288
|
console.log(`Check upgrade log: ${logPath}`);
|
|
234
289
|
process.exit(0);
|
|
235
290
|
}
|
package/connection/upgrade.js
CHANGED
|
@@ -116,6 +116,7 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
|
|
|
116
116
|
const logDir = join(configDir, 'logs');
|
|
117
117
|
mkdirSync(logDir, { recursive: true });
|
|
118
118
|
const batPath = join(configDir, 'upgrade.bat');
|
|
119
|
+
const vbsPath = join(configDir, 'upgrade.vbs');
|
|
119
120
|
const logPath = join(logDir, 'upgrade.log');
|
|
120
121
|
const isPm2 = !!process.env.pm_id;
|
|
121
122
|
const installDirWin = installDir.replace(/\//g, '\\');
|
|
@@ -145,18 +146,21 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
|
|
|
145
146
|
':: Change to temp dir to avoid EBUSY on cwd',
|
|
146
147
|
'cd /d "%TEMP%"',
|
|
147
148
|
'',
|
|
148
|
-
':: Redirect all output to log file',
|
|
149
149
|
'echo [Upgrade] Started at %date% %time% > "%LOGFILE%"',
|
|
150
|
+
`echo [Upgrade] Version: ${ctx.agentVersion} -> ${latestVersion} >> "%LOGFILE%"`,
|
|
151
|
+
`echo [Upgrade] PM2 managed: ${isPm2 ? 'yes (deleted pre-exit)' : 'no'} >> "%LOGFILE%"`,
|
|
152
|
+
`echo [Upgrade] Install dir: ${installDirWin} >> "%LOGFILE%"`,
|
|
150
153
|
];
|
|
151
154
|
|
|
152
155
|
// Wait for old process to exit (PM2 already deleted before exit, so no auto-restart race)
|
|
153
156
|
batLines.push(
|
|
157
|
+
'echo [Upgrade] Waiting for PID %PID% to exit... >> "%LOGFILE%"',
|
|
154
158
|
':WAIT_LOOP',
|
|
155
159
|
'tasklist /FI "PID eq %PID%" /NH 2>NUL | findstr /C:"%PID%" >NUL',
|
|
156
160
|
'if errorlevel 1 goto PID_EXITED',
|
|
157
161
|
'set /A COUNT+=1',
|
|
158
162
|
'if %COUNT% GEQ %MAX_WAIT% (',
|
|
159
|
-
' echo [Upgrade] Timeout waiting for PID %PID% to exit after %MAX_WAIT%
|
|
163
|
+
' echo [Upgrade] Timeout waiting for PID %PID% to exit after %MAX_WAIT%s >> "%LOGFILE%"',
|
|
160
164
|
' goto PID_EXITED',
|
|
161
165
|
')',
|
|
162
166
|
'ping -n 3 127.0.0.1 >NUL',
|
|
@@ -165,21 +169,21 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
|
|
|
165
169
|
);
|
|
166
170
|
|
|
167
171
|
// No need to pm2 stop — PM2 app was already deleted before process exit.
|
|
168
|
-
// Wait
|
|
172
|
+
// Wait extra time for file locks to fully release.
|
|
169
173
|
batLines.push(
|
|
170
|
-
'echo [Upgrade] Process exited
|
|
171
|
-
'ping -n
|
|
174
|
+
'echo [Upgrade] Process exited at %time%, waiting for file locks... >> "%LOGFILE%"',
|
|
175
|
+
'ping -n 5 127.0.0.1 >NUL',
|
|
172
176
|
);
|
|
173
177
|
|
|
174
178
|
// Use Node.js worker for file-level upgrade (avoids EBUSY on directory rename)
|
|
175
179
|
batLines.push(
|
|
176
|
-
'echo [Upgrade] Running upgrade worker
|
|
180
|
+
'echo [Upgrade] Running upgrade worker at %time%... >> "%LOGFILE%"',
|
|
177
181
|
'node "%WORKER%" "%PKG%" "%PKG_DIR%" "%LOGFILE%"',
|
|
178
182
|
'if not "%errorlevel%"=="0" (',
|
|
179
|
-
' echo [Upgrade] Worker failed with exit code %errorlevel% >> "%LOGFILE%"',
|
|
183
|
+
' echo [Upgrade] Worker failed with exit code %errorlevel% at %time% >> "%LOGFILE%"',
|
|
180
184
|
' goto CLEANUP',
|
|
181
185
|
')',
|
|
182
|
-
'echo [Upgrade] Worker completed successfully >> "%LOGFILE%"',
|
|
186
|
+
'echo [Upgrade] Worker completed successfully at %time% >> "%LOGFILE%"',
|
|
183
187
|
);
|
|
184
188
|
|
|
185
189
|
batLines.push(':CLEANUP');
|
|
@@ -187,26 +191,44 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
|
|
|
187
191
|
if (isPm2) {
|
|
188
192
|
// Re-register and start via ecosystem config (PM2 app was deleted pre-exit)
|
|
189
193
|
batLines.push(
|
|
190
|
-
'echo [Upgrade] Re-registering agent via
|
|
191
|
-
`
|
|
192
|
-
|
|
194
|
+
'echo [Upgrade] Re-registering agent via PM2... >> "%LOGFILE%"',
|
|
195
|
+
`if exist "${ecoPath}" (`,
|
|
196
|
+
` call pm2 start "${ecoPath}" >> "%LOGFILE%" 2>&1`,
|
|
197
|
+
' call pm2 save >> "%LOGFILE%" 2>&1',
|
|
198
|
+
' echo [Upgrade] PM2 app re-registered at %time% >> "%LOGFILE%"',
|
|
199
|
+
') else (',
|
|
200
|
+
' echo [Upgrade] WARNING: ecosystem.config.cjs not found, PM2 not restarted >> "%LOGFILE%"',
|
|
201
|
+
')',
|
|
193
202
|
);
|
|
194
203
|
}
|
|
195
204
|
|
|
196
|
-
// Clean up worker and bat script
|
|
205
|
+
// Clean up worker, vbs launcher, and bat script
|
|
197
206
|
batLines.push(
|
|
207
|
+
'',
|
|
208
|
+
'echo [Upgrade] Finished at %time% >> "%LOGFILE%"',
|
|
198
209
|
`del /F /Q "${workerDst}" 2>NUL`,
|
|
210
|
+
`del /F /Q "${vbsPath}" 2>NUL`,
|
|
199
211
|
`del /F /Q "${batPath}"`,
|
|
200
212
|
);
|
|
201
213
|
|
|
202
214
|
writeFileSync(batPath, batLines.join('\r\n'));
|
|
203
|
-
|
|
215
|
+
|
|
216
|
+
// Use VBScript wrapper to fully detach the bat process from the parent.
|
|
217
|
+
// WshShell.Run with 0 (hidden window) and False (don't wait) ensures the bat
|
|
218
|
+
// runs completely independently — survives parent exit, no console window flash.
|
|
219
|
+
const vbsLines = [
|
|
220
|
+
'Set WshShell = CreateObject("WScript.Shell")',
|
|
221
|
+
`WshShell.Run """${batPath}""", 0, False`,
|
|
222
|
+
];
|
|
223
|
+
writeFileSync(vbsPath, vbsLines.join('\r\n'));
|
|
224
|
+
|
|
225
|
+
spawn('wscript.exe', [vbsPath], {
|
|
204
226
|
detached: true,
|
|
205
227
|
stdio: 'ignore',
|
|
206
228
|
windowsHide: true,
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
console.log(`[Agent] Spawned upgrade
|
|
229
|
+
}).unref();
|
|
230
|
+
|
|
231
|
+
console.log(`[Agent] Spawned upgrade via VBScript (PID wait for ${pid}, pm2=${isPm2}, dir=${installDir}): ${batPath}`);
|
|
210
232
|
sendToServer({ type: 'upgrade_agent_ack', success: true, version: latestVersion, pendingRestart: true });
|
|
211
233
|
}
|
|
212
234
|
|