imcodes 2026.4.1399-dev.1384 → 2026.4.1407-dev.1392
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/src/util/windows-daemon.d.ts +15 -0
- package/dist/src/util/windows-daemon.d.ts.map +1 -1
- package/dist/src/util/windows-daemon.js +89 -3
- package/dist/src/util/windows-daemon.js.map +1 -1
- package/dist/src/util/windows-launch-artifacts.d.ts +33 -5
- package/dist/src/util/windows-launch-artifacts.d.ts.map +1 -1
- package/dist/src/util/windows-launch-artifacts.js +104 -21
- package/dist/src/util/windows-launch-artifacts.js.map +1 -1
- package/dist/src/util/windows-upgrade-script.d.ts.map +1 -1
- package/dist/src/util/windows-upgrade-script.js +44 -12
- package/dist/src/util/windows-upgrade-script.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/** Tree-kill every cmd.exe process whose command line references
|
|
2
|
+
* daemon-watchdog. Works on any Windows locale and any Windows version
|
|
3
|
+
* (Windows 10/11, Server 2016/2019/2022/2025) — newer Windows Server
|
|
4
|
+
* images have deprecated `wmic`, so we use PowerShell's CIM cmdlets.
|
|
5
|
+
*
|
|
6
|
+
* Why this exists:
|
|
7
|
+
* - Old daemon installs (pre-fix) wrote watchdog.cmd with a UTF-8 BOM.
|
|
8
|
+
* - cmd.exe parses [BOM]@echo as the unknown command "[BOM]@echo" and
|
|
9
|
+
* crash-loops forever printing the same error.
|
|
10
|
+
* - Restart/upgrade must KILL these zombies before laying down new
|
|
11
|
+
* files; otherwise the old watchdog re-spawns on the next loop tick
|
|
12
|
+
* and overwrites the daemon PID with a stale one.
|
|
13
|
+
*
|
|
14
|
+
* This function is best-effort: it logs nothing and swallows all errors. */
|
|
15
|
+
export declare function killAllStaleWatchdogs(): void;
|
|
1
16
|
/** Restart the Windows daemon by killing the entire watchdog tree and
|
|
2
17
|
* spawning a fresh hidden watchdog.
|
|
3
18
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows-daemon.d.ts","sourceRoot":"","sources":["../../../src/util/windows-daemon.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"windows-daemon.d.ts","sourceRoot":"","sources":["../../../src/util/windows-daemon.ts"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;;6EAa6E;AAC7E,wBAAgB,qBAAqB,IAAI,IAAI,CAM5C;AA8FD;;;;;;;;;;;oCAWoC;AACpC,wBAAgB,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAqCjE"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execSync, spawn } from 'node:child_process';
|
|
2
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { resolve } from 'node:path';
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { homedir, tmpdir } from 'node:os';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
5
|
const WINDOWS_DAEMON_TASK = 'imcodes-daemon';
|
|
6
6
|
function readDaemonPid(currentPid) {
|
|
7
7
|
const pidFile = resolve(homedir(), '.imcodes', 'daemon.pid');
|
|
@@ -27,6 +27,86 @@ function isPidAlive(pid) {
|
|
|
27
27
|
function sleepMs(ms) {
|
|
28
28
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
29
29
|
}
|
|
30
|
+
/** Tree-kill every cmd.exe process whose command line references
|
|
31
|
+
* daemon-watchdog. Works on any Windows locale and any Windows version
|
|
32
|
+
* (Windows 10/11, Server 2016/2019/2022/2025) — newer Windows Server
|
|
33
|
+
* images have deprecated `wmic`, so we use PowerShell's CIM cmdlets.
|
|
34
|
+
*
|
|
35
|
+
* Why this exists:
|
|
36
|
+
* - Old daemon installs (pre-fix) wrote watchdog.cmd with a UTF-8 BOM.
|
|
37
|
+
* - cmd.exe parses [BOM]@echo as the unknown command "[BOM]@echo" and
|
|
38
|
+
* crash-loops forever printing the same error.
|
|
39
|
+
* - Restart/upgrade must KILL these zombies before laying down new
|
|
40
|
+
* files; otherwise the old watchdog re-spawns on the next loop tick
|
|
41
|
+
* and overwrites the daemon PID with a stale one.
|
|
42
|
+
*
|
|
43
|
+
* This function is best-effort: it logs nothing and swallows all errors. */
|
|
44
|
+
export function killAllStaleWatchdogs() {
|
|
45
|
+
if (process.platform !== 'win32')
|
|
46
|
+
return;
|
|
47
|
+
const pids = findStaleWatchdogPids();
|
|
48
|
+
for (const pid of pids) {
|
|
49
|
+
try {
|
|
50
|
+
execSync(`taskkill /f /t /pid ${pid}`, { stdio: 'ignore' });
|
|
51
|
+
}
|
|
52
|
+
catch { /* already dead */ }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Enumerate cmd.exe processes whose command line references daemon-watchdog.
|
|
56
|
+
* Tries PowerShell via a temp .ps1 file (works on every Windows since 7),
|
|
57
|
+
* then falls back to wmic for legacy Windows where PowerShell is missing.
|
|
58
|
+
*
|
|
59
|
+
* CRITICAL: PowerShell command must be in a .ps1 FILE, not passed via
|
|
60
|
+
* `-Command "..."`. When the script contains nested double quotes
|
|
61
|
+
* (e.g. inside a Filter clause), cmd.exe→powershell command-line parsing
|
|
62
|
+
* closes the outer quote prematurely and the script becomes truncated.
|
|
63
|
+
* This was the root cause of the CI failure. */
|
|
64
|
+
function findStaleWatchdogPids() {
|
|
65
|
+
const pids = new Set();
|
|
66
|
+
// ── PowerShell path (works on every Windows since 7) ────────────────────
|
|
67
|
+
let scriptDir = null;
|
|
68
|
+
try {
|
|
69
|
+
scriptDir = mkdtempSync(join(tmpdir(), 'imcodes-watchdog-query-'));
|
|
70
|
+
const scriptPath = join(scriptDir, 'find-stale.ps1');
|
|
71
|
+
// Use single quotes around 'cmd.exe' inside the filter to avoid escaping
|
|
72
|
+
// headaches. Format-Wide -Property ProcessId so each PID is on its own
|
|
73
|
+
// line for easy parsing.
|
|
74
|
+
writeFileSync(scriptPath, "Get-CimInstance Win32_Process -Filter \"Name='cmd.exe'\" | " +
|
|
75
|
+
"Where-Object { $_.CommandLine -like '*daemon-watchdog*' } | " +
|
|
76
|
+
"ForEach-Object { $_.ProcessId }\r\n");
|
|
77
|
+
const out = execSync(`powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "${scriptPath}"`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true });
|
|
78
|
+
for (const line of out.split(/\r?\n/)) {
|
|
79
|
+
const pid = parseInt(line.trim(), 10);
|
|
80
|
+
if (Number.isFinite(pid) && pid > 0)
|
|
81
|
+
pids.add(pid);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch { /* fall through to wmic */ }
|
|
85
|
+
finally {
|
|
86
|
+
if (scriptDir) {
|
|
87
|
+
try {
|
|
88
|
+
rmSync(scriptDir, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
catch { /* ignore */ }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (pids.size > 0)
|
|
94
|
+
return [...pids];
|
|
95
|
+
// ── Legacy wmic path ────────────────────────────────────────────────────
|
|
96
|
+
try {
|
|
97
|
+
const out = execSync('wmic process where "Name=\'cmd.exe\' and CommandLine like \'%daemon-watchdog%\'" get ProcessId /format:list', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true });
|
|
98
|
+
for (const line of out.split(/\r?\n/)) {
|
|
99
|
+
const m = line.match(/^ProcessId=(\d+)/);
|
|
100
|
+
if (m) {
|
|
101
|
+
const pid = parseInt(m[1], 10);
|
|
102
|
+
if (Number.isFinite(pid) && pid > 0)
|
|
103
|
+
pids.add(pid);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch { /* both methods failed */ }
|
|
108
|
+
return [...pids];
|
|
109
|
+
}
|
|
30
110
|
// ── Launcher methods (all hidden — no visible windows) ──────────────────────
|
|
31
111
|
function tryStartVbsLauncher() {
|
|
32
112
|
const vbs = resolve(homedir(), '.imcodes', 'daemon-launcher.vbs');
|
|
@@ -74,6 +154,12 @@ export function restartWindowsDaemon(currentPid) {
|
|
|
74
154
|
}
|
|
75
155
|
catch { /* not running */ }
|
|
76
156
|
}
|
|
157
|
+
// CRITICAL: also tree-kill any stale daemon-watchdog cmd.exe processes by
|
|
158
|
+
// command-line pattern. This handles the upgrade-from-bad-watchdog case
|
|
159
|
+
// where an OLD watchdog with a UTF-8 BOM is in a crash-loop printing
|
|
160
|
+
// "is not a recognized command" forever. Without this kill, the new
|
|
161
|
+
// watchdog we spawn below will race with the old one.
|
|
162
|
+
killAllStaleWatchdogs();
|
|
77
163
|
// If no watchdog is running (e.g. first start after bind), launch one.
|
|
78
164
|
// Priority: VBS (always hidden) > scheduled task > startup shortcut.
|
|
79
165
|
// If a watchdog IS already running, it will restart the daemon on its own —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows-daemon.js","sourceRoot":"","sources":["../../../src/util/windows-daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"windows-daemon.js","sourceRoot":"","sources":["../../../src/util/windows-daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,11 +11,28 @@ export interface LaunchPaths {
|
|
|
11
11
|
/** Resolve all paths needed for the Windows daemon launch chain. */
|
|
12
12
|
export declare function resolveLaunchPaths(): LaunchPaths;
|
|
13
13
|
/** Write the daemon-watchdog.cmd that loops and restarts the daemon.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
*
|
|
15
|
+
* IMPORTANT: this file is parsed by cmd.exe. Two non-obvious rules:
|
|
16
|
+
*
|
|
17
|
+
* 1. cmd.exe does NOT understand a UTF-8 BOM at the start of a .cmd file.
|
|
18
|
+
* The BOM bytes (EF BB BF) are treated as part of the first command,
|
|
19
|
+
* so `[BOM]@echo off` becomes the unknown command "[BOM]@echo".
|
|
20
|
+
* => never write a BOM here.
|
|
21
|
+
*
|
|
22
|
+
* 2. To support non-ASCII paths (e.g. usernames with Chinese characters)
|
|
23
|
+
* we never hard-code absolute paths. Instead we use environment-variable
|
|
24
|
+
* expansion (%USERPROFILE%, %APPDATA%) which cmd.exe resolves at runtime
|
|
25
|
+
* using the OS's native wide-character API — no encoding round-trip.
|
|
26
|
+
*
|
|
27
|
+
* 3. Uses the npm global shim (`imcodes.cmd`) by default so the watchdog
|
|
28
|
+
* always launches whatever version is currently installed, even after
|
|
29
|
+
* npm upgrades. Falls back to direct node+script for dev installs
|
|
30
|
+
* where the shim isn't on %APPDATA%\npm. */
|
|
17
31
|
export declare function writeWatchdogCmd(paths: LaunchPaths): Promise<void>;
|
|
18
|
-
/**
|
|
32
|
+
/** @deprecated cmd.exe does not understand UTF-8 BOMs in batch files; the BOM
|
|
33
|
+
* bytes break the very first command of the script. Kept here only so
|
|
34
|
+
* upgrade scripts that already imported it continue to compile — they should
|
|
35
|
+
* switch to plain `writeFile(..., 'utf8')` instead. */
|
|
19
36
|
export declare function encodeCmdAsUtf8Bom(content: string): Buffer;
|
|
20
37
|
/** Write the daemon-launcher.vbs that starts the watchdog CMD hidden.
|
|
21
38
|
*
|
|
@@ -36,6 +53,17 @@ export declare function encodeVbsAsUtf16(content: string): Buffer;
|
|
|
36
53
|
export declare function updateSchtasks(paths: LaunchPaths): boolean;
|
|
37
54
|
/** Truncate the watchdog log if it exceeds 1 MB. */
|
|
38
55
|
export declare function rotateWatchdogLog(paths: LaunchPaths): Promise<void>;
|
|
39
|
-
/** Regenerate all Windows daemon launch artifacts with current paths.
|
|
56
|
+
/** Regenerate all Windows daemon launch artifacts with current paths.
|
|
57
|
+
*
|
|
58
|
+
* Tree-kills any existing daemon-watchdog cmd.exe processes BEFORE writing
|
|
59
|
+
* the new files. This is critical when the user is recovering from a
|
|
60
|
+
* crash-loop caused by an OLD watchdog file with a UTF-8 BOM (cmd.exe
|
|
61
|
+
* parses [BOM]@echo as the unknown command "[BOM]@echo" forever).
|
|
62
|
+
* Without the kill, the old watchdog still has the bad file mapped and
|
|
63
|
+
* will overwrite our PID file with stale data.
|
|
64
|
+
*
|
|
65
|
+
* Process matching is by command-line pattern via wmic, which is
|
|
66
|
+
* language-independent — works on en-US, zh-CN, ja-JP and any other Windows
|
|
67
|
+
* locale. */
|
|
40
68
|
export declare function regenerateAllArtifacts(): Promise<void>;
|
|
41
69
|
//# sourceMappingURL=windows-launch-artifacts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows-launch-artifacts.d.ts","sourceRoot":"","sources":["../../../src/util/windows-launch-artifacts.ts"],"names":[],"mappings":"AAYA;8EAC8E;AAC9E,eAAO,MAAM,iBAAiB,QAA8C,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,IAAI,WAAW,CAShD;AAED
|
|
1
|
+
{"version":3,"file":"windows-launch-artifacts.d.ts","sourceRoot":"","sources":["../../../src/util/windows-launch-artifacts.ts"],"names":[],"mappings":"AAYA;8EAC8E;AAC9E,eAAO,MAAM,iBAAiB,QAA8C,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,IAAI,WAAW,CAShD;AAED;;;;;;;;;;;;;;;;;gDAiBgD;AAChD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCxE;AAED;;;wDAGwD;AACxD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;;;;4EAS4E;AAC5E,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAIxE;AAED;4DAC4D;AAC5D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;+CAC+C;AAC/C,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAW1D;AAED,oDAAoD;AACpD,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CASzE;AAED;;;;;;;;;;;cAWc;AACd,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAO5D"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { writeFile, mkdir, stat, truncate } from 'fs/promises';
|
|
2
|
-
import { existsSync } from 'fs';
|
|
2
|
+
import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'fs';
|
|
3
3
|
import { execSync } from 'child_process';
|
|
4
4
|
import { join, dirname } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
-
import { homedir } from 'os';
|
|
6
|
+
import { homedir, tmpdir } from 'os';
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = dirname(__filename);
|
|
9
9
|
const TASK_NAME = 'imcodes-daemon';
|
|
@@ -22,41 +22,62 @@ export function resolveLaunchPaths() {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
/** Write the daemon-watchdog.cmd that loops and restarts the daemon.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
*
|
|
26
|
+
* IMPORTANT: this file is parsed by cmd.exe. Two non-obvious rules:
|
|
27
|
+
*
|
|
28
|
+
* 1. cmd.exe does NOT understand a UTF-8 BOM at the start of a .cmd file.
|
|
29
|
+
* The BOM bytes (EF BB BF) are treated as part of the first command,
|
|
30
|
+
* so `[BOM]@echo off` becomes the unknown command "[BOM]@echo".
|
|
31
|
+
* => never write a BOM here.
|
|
32
|
+
*
|
|
33
|
+
* 2. To support non-ASCII paths (e.g. usernames with Chinese characters)
|
|
34
|
+
* we never hard-code absolute paths. Instead we use environment-variable
|
|
35
|
+
* expansion (%USERPROFILE%, %APPDATA%) which cmd.exe resolves at runtime
|
|
36
|
+
* using the OS's native wide-character API — no encoding round-trip.
|
|
37
|
+
*
|
|
38
|
+
* 3. Uses the npm global shim (`imcodes.cmd`) by default so the watchdog
|
|
39
|
+
* always launches whatever version is currently installed, even after
|
|
40
|
+
* npm upgrades. Falls back to direct node+script for dev installs
|
|
41
|
+
* where the shim isn't on %APPDATA%\npm. */
|
|
28
42
|
export async function writeWatchdogCmd(paths) {
|
|
29
43
|
await mkdir(dirname(paths.watchdogPath), { recursive: true });
|
|
30
|
-
//
|
|
44
|
+
// Detect whether the npm global shim exists. When yes, the watchdog can
|
|
45
|
+
// use the parameter-free env-var path; when no (e.g. tests, dev installs)
|
|
46
|
+
// we fall back to a direct node+script invocation with absolute paths.
|
|
31
47
|
const npmGlobalBin = dirname(paths.imcodesScript).replace(/[/\\]node_modules[/\\]imcodes[/\\]dist[/\\]src$/i, '');
|
|
32
48
|
const shimPath = join(npmGlobalBin, 'imcodes.cmd');
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
49
|
+
const useShim = existsSync(shimPath);
|
|
50
|
+
// Build the launch line. Either form gets prefixed with `call ` so cmd.exe
|
|
51
|
+
// returns to the loop after the daemon exits (without `call`, control would
|
|
52
|
+
// hand off to the .cmd shim and never come back).
|
|
53
|
+
const launchCmd = useShim
|
|
54
|
+
? `call "%APPDATA%\\npm\\imcodes.cmd" start --foreground`
|
|
55
|
+
: `call "${paths.nodeExe}" "${paths.imcodesScript}" start --foreground`;
|
|
38
56
|
const watchdog = [
|
|
39
57
|
'@echo off',
|
|
40
58
|
'chcp 65001 >nul 2>&1',
|
|
41
59
|
':loop',
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
'if exist "%USERPROFILE%\\.imcodes\\upgrade.lock" (',
|
|
61
|
+
' echo Upgrade in progress, waiting... >> "%USERPROFILE%\\.imcodes\\watchdog.log"',
|
|
44
62
|
' timeout /t 5 /nobreak >nul',
|
|
45
63
|
' goto loop',
|
|
46
64
|
')',
|
|
47
|
-
`${launchCmd} >> "
|
|
65
|
+
`${launchCmd} >> "%USERPROFILE%\\.imcodes\\watchdog.log" 2>&1`,
|
|
48
66
|
'timeout /t 5 /nobreak >nul',
|
|
49
67
|
'goto loop',
|
|
50
68
|
'',
|
|
51
69
|
].join('\r\n');
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
await writeFile(paths.watchdogPath,
|
|
70
|
+
// CRITICAL: write as plain UTF-8 with NO BOM. cmd.exe does not understand
|
|
71
|
+
// BOMs in batch files — the BOM bytes get prepended to the first command
|
|
72
|
+
// and cmd reports "[BOM]@echo is not a recognized command".
|
|
73
|
+
await writeFile(paths.watchdogPath, watchdog, 'utf8');
|
|
56
74
|
}
|
|
57
|
-
/**
|
|
75
|
+
/** @deprecated cmd.exe does not understand UTF-8 BOMs in batch files; the BOM
|
|
76
|
+
* bytes break the very first command of the script. Kept here only so
|
|
77
|
+
* upgrade scripts that already imported it continue to compile — they should
|
|
78
|
+
* switch to plain `writeFile(..., 'utf8')` instead. */
|
|
58
79
|
export function encodeCmdAsUtf8Bom(content) {
|
|
59
|
-
return Buffer.
|
|
80
|
+
return Buffer.from(content, 'utf8');
|
|
60
81
|
}
|
|
61
82
|
/** Write the daemon-launcher.vbs that starts the watchdog CMD hidden.
|
|
62
83
|
*
|
|
@@ -105,12 +126,74 @@ export async function rotateWatchdogLog(paths) {
|
|
|
105
126
|
// Log file doesn't exist yet — nothing to rotate.
|
|
106
127
|
}
|
|
107
128
|
}
|
|
108
|
-
/** Regenerate all Windows daemon launch artifacts with current paths.
|
|
129
|
+
/** Regenerate all Windows daemon launch artifacts with current paths.
|
|
130
|
+
*
|
|
131
|
+
* Tree-kills any existing daemon-watchdog cmd.exe processes BEFORE writing
|
|
132
|
+
* the new files. This is critical when the user is recovering from a
|
|
133
|
+
* crash-loop caused by an OLD watchdog file with a UTF-8 BOM (cmd.exe
|
|
134
|
+
* parses [BOM]@echo as the unknown command "[BOM]@echo" forever).
|
|
135
|
+
* Without the kill, the old watchdog still has the bad file mapped and
|
|
136
|
+
* will overwrite our PID file with stale data.
|
|
137
|
+
*
|
|
138
|
+
* Process matching is by command-line pattern via wmic, which is
|
|
139
|
+
* language-independent — works on en-US, zh-CN, ja-JP and any other Windows
|
|
140
|
+
* locale. */
|
|
109
141
|
export async function regenerateAllArtifacts() {
|
|
142
|
+
killAllStaleWatchdogsBeforeRegen();
|
|
110
143
|
const paths = resolveLaunchPaths();
|
|
111
144
|
await writeWatchdogCmd(paths);
|
|
112
145
|
await writeVbsLauncher(paths);
|
|
113
146
|
updateSchtasks(paths);
|
|
114
147
|
await rotateWatchdogLog(paths);
|
|
115
148
|
}
|
|
149
|
+
function killAllStaleWatchdogsBeforeRegen() {
|
|
150
|
+
if (process.platform !== 'win32')
|
|
151
|
+
return;
|
|
152
|
+
// PowerShell first (works on every Windows including ones where wmic is gone)
|
|
153
|
+
// CRITICAL: use a temp .ps1 file, NOT `-Command "..."` — nested double
|
|
154
|
+
// quotes inside the script body get truncated by cmd.exe→powershell
|
|
155
|
+
// command-line parsing. See windows-daemon.ts findStaleWatchdogPids.
|
|
156
|
+
let pids = [];
|
|
157
|
+
let scriptDir = null;
|
|
158
|
+
try {
|
|
159
|
+
scriptDir = mkdtempSync(join(tmpdir(), 'imcodes-watchdog-regen-'));
|
|
160
|
+
const scriptPath = join(scriptDir, 'find-stale.ps1');
|
|
161
|
+
writeFileSync(scriptPath, "Get-CimInstance Win32_Process -Filter \"Name='cmd.exe'\" | " +
|
|
162
|
+
"Where-Object { $_.CommandLine -like '*daemon-watchdog*' } | " +
|
|
163
|
+
"ForEach-Object { $_.ProcessId }\r\n");
|
|
164
|
+
const out = execSync(`powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "${scriptPath}"`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true });
|
|
165
|
+
for (const line of out.split(/\r?\n/)) {
|
|
166
|
+
const pid = parseInt(line.trim(), 10);
|
|
167
|
+
if (Number.isFinite(pid) && pid > 0)
|
|
168
|
+
pids.push(pid);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch { /* fall through */ }
|
|
172
|
+
finally {
|
|
173
|
+
if (scriptDir) {
|
|
174
|
+
try {
|
|
175
|
+
rmSync(scriptDir, { recursive: true, force: true });
|
|
176
|
+
}
|
|
177
|
+
catch { /* ignore */ }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (pids.length === 0) {
|
|
181
|
+
try {
|
|
182
|
+
const out = execSync('wmic process where "Name=\'cmd.exe\' and CommandLine like \'%daemon-watchdog%\'" get ProcessId /format:list', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true });
|
|
183
|
+
pids = out
|
|
184
|
+
.split(/\r?\n/)
|
|
185
|
+
.map((line) => line.match(/^ProcessId=(\d+)/))
|
|
186
|
+
.filter((m) => m !== null)
|
|
187
|
+
.map((m) => parseInt(m[1], 10))
|
|
188
|
+
.filter((pid) => Number.isFinite(pid) && pid > 0);
|
|
189
|
+
}
|
|
190
|
+
catch { /* both methods failed */ }
|
|
191
|
+
}
|
|
192
|
+
for (const pid of pids) {
|
|
193
|
+
try {
|
|
194
|
+
execSync(`taskkill /f /t /pid ${pid}`, { stdio: 'ignore' });
|
|
195
|
+
}
|
|
196
|
+
catch { /* already dead */ }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
116
199
|
//# sourceMappingURL=windows-launch-artifacts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows-launch-artifacts.js","sourceRoot":"","sources":["../../../src/util/windows-launch-artifacts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"windows-launch-artifacts.js","sourceRoot":"","sources":["../../../src/util/windows-launch-artifacts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows-upgrade-script.d.ts","sourceRoot":"","sources":["../../../src/util/windows-upgrade-script.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CASnE;AAED;8DAC8D;AAC9D,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;8DAG8D;AAC9D,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,yBAAyB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"windows-upgrade-script.d.ts","sourceRoot":"","sources":["../../../src/util/windows-upgrade-script.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CASnE;AAED;8DAC8D;AAC9D,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;8DAG8D;AAC9D,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,yBAAyB,GAAG,MAAM,CAmKjF"}
|
|
@@ -42,23 +42,55 @@ echo upgrade > "%UPGRADE_LOCK%"\r
|
|
|
42
42
|
echo Upgrade lock created >> "%LOG_FILE%"\r
|
|
43
43
|
\r
|
|
44
44
|
rem ── Kill daemon + old watchdog so npm can overwrite files cleanly ─────\r
|
|
45
|
-
rem
|
|
46
|
-
rem
|
|
47
|
-
rem
|
|
45
|
+
rem Three failure modes we must handle:\r
|
|
46
|
+
rem 1. Healthy daemon — kill PIDFILE and parent watchdog tree\r
|
|
47
|
+
rem 2. Daemon crashed but watchdog still spamming an error in a tight\r
|
|
48
|
+
rem loop because the OLD watchdog.cmd had a UTF-8 BOM and/or no\r
|
|
49
|
+
rem 'call' prefix (cmd.exe quoted-command parse rule). In this case\r
|
|
50
|
+
rem there is NO daemon.pid but the watchdog cmd.exe processes are\r
|
|
51
|
+
rem still running. We must find them by command-line pattern.\r
|
|
52
|
+
rem 3. Multiple watchdog instances (race after past upgrades)\r
|
|
53
|
+
rem Tree-kill EVERY cmd.exe whose command line references daemon-watchdog.\r
|
|
54
|
+
rem This catches both the healthy case and the crash-loop case.\r
|
|
55
|
+
echo Killing all daemon-watchdog cmd.exe processes... >> "%LOG_FILE%"\r
|
|
56
|
+
rem Try PowerShell first (works on Windows 11 / Server 2025 where wmic is\r
|
|
57
|
+
rem deprecated/removed), fall back to wmic for legacy Windows installs.\r
|
|
58
|
+
rem CRITICAL: write the PowerShell script to a .ps1 file rather than passing\r
|
|
59
|
+
rem it via -Command "..." — nested double quotes inside a -Command argument\r
|
|
60
|
+
rem get truncated by cmd.exe→powershell command-line parsing.\r
|
|
61
|
+
set "PS_SCRIPT=%SCRIPT_DIR%\\find-stale-watchdog.ps1"\r
|
|
62
|
+
> "%PS_SCRIPT%" echo Get-CimInstance Win32_Process -Filter "Name='cmd.exe'" ^| Where-Object { $_.CommandLine -like '*daemon-watchdog*' } ^| ForEach-Object { $_.ProcessId }\r
|
|
63
|
+
for /f "usebackq delims=" %%w in (\`powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%PS_SCRIPT%" 2^>nul\`) do (\r
|
|
64
|
+
set "STALE_WD=%%w"\r
|
|
65
|
+
set "STALE_WD=!STALE_WD: =!"\r
|
|
66
|
+
if defined STALE_WD if not "!STALE_WD!"=="" (\r
|
|
67
|
+
echo tree-killing watchdog PID !STALE_WD! ^(via powershell^) >> "%LOG_FILE%"\r
|
|
68
|
+
taskkill /f /t /pid !STALE_WD! >nul 2>&1\r
|
|
69
|
+
)\r
|
|
70
|
+
)\r
|
|
71
|
+
rem Fallback for systems where powershell returns nothing (or is unavailable).\r
|
|
72
|
+
for /f "tokens=2 delims==" %%w in ('wmic process where "Name='cmd.exe' and CommandLine like '%%daemon-watchdog%%'" get ProcessId /format:list 2^>nul ^| find "="') do (\r
|
|
73
|
+
set "STALE_WD=%%w"\r
|
|
74
|
+
set "STALE_WD=!STALE_WD: =!"\r
|
|
75
|
+
if defined STALE_WD if not "!STALE_WD!"=="" (\r
|
|
76
|
+
echo tree-killing watchdog PID !STALE_WD! ^(via wmic^) >> "%LOG_FILE%"\r
|
|
77
|
+
taskkill /f /t /pid !STALE_WD! >nul 2>&1\r
|
|
78
|
+
)\r
|
|
79
|
+
)\r
|
|
80
|
+
rem Also kill the daemon directly if PIDFILE has a fresh value.\r
|
|
48
81
|
set "PIDFILE=%USERPROFILE%\\.imcodes\\daemon.pid"\r
|
|
49
82
|
if exist "%PIDFILE%" (\r
|
|
50
83
|
set /p OLD_PID=<"%PIDFILE%"\r
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
set "WD_PID=%%a"\r
|
|
55
|
-
)\r
|
|
56
|
-
if defined WD_PID (\r
|
|
57
|
-
taskkill /f /t /pid !WD_PID! >nul 2>&1\r
|
|
84
|
+
if defined OLD_PID if not "!OLD_PID!"=="" (\r
|
|
85
|
+
echo Stopping daemon PID !OLD_PID!... >> "%LOG_FILE%"\r
|
|
86
|
+
taskkill /f /pid !OLD_PID! >nul 2>&1\r
|
|
58
87
|
)\r
|
|
59
|
-
taskkill /f /pid !OLD_PID! >nul 2>&1\r
|
|
60
|
-
timeout /t 2 /nobreak >nul\r
|
|
61
88
|
)\r
|
|
89
|
+
rem Belt-and-suspenders: if the watchdog file itself has a BOM (the bug we\r
|
|
90
|
+
rem just fixed), the new repair-watchdog step below will overwrite it with\r
|
|
91
|
+
rem clean bytes. Until then, prevent the freshly-killed watchdog from being\r
|
|
92
|
+
rem respawned by anyone (e.g. a scheduled task) by leaving the lock in place.\r
|
|
93
|
+
timeout /t 2 /nobreak >nul\r
|
|
62
94
|
\r
|
|
63
95
|
if defined NODE_OPTIONS (\r
|
|
64
96
|
set "NODE_OPTIONS=%NODE_OPTIONS% --max-old-space-size=16384"\r
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"windows-upgrade-script.js","sourceRoot":"","sources":["../../../src/util/windows-upgrade-script.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,yBAAyB,CAAC,SAAiB;IACzD,KAAK,SAAS,CAAC;IACf,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED;8DAC8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,OAAO,2FAA2F,WAAW,mBAAmB,CAAC;AACnI,CAAC;AAED;;;8DAG8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,OAAO,2FAA2F,SAAS,mBAAmB,CAAC;AACjI,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAgC;IACvE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IACxG,KAAK,OAAO,CAAC;IACb,KAAK,cAAc,CAAC;IACpB,KAAK,eAAe,CAAC;IACrB,KAAK,eAAe,CAAC;IACrB,OAAO
|
|
1
|
+
{"version":3,"file":"windows-upgrade-script.js","sourceRoot":"","sources":["../../../src/util/windows-upgrade-script.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,yBAAyB,CAAC,SAAiB;IACzD,KAAK,SAAS,CAAC;IACf,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED;8DAC8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,OAAO,2FAA2F,WAAW,mBAAmB,CAAC;AACnI,CAAC;AAED;;;8DAG8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,OAAO,2FAA2F,SAAS,mBAAmB,CAAC;AACjI,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAgC;IACvE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IACxG,KAAK,OAAO,CAAC;IACb,KAAK,cAAc,CAAC;IACpB,KAAK,eAAe,CAAC;IACrB,KAAK,eAAe,CAAC;IACrB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAyES,OAAO;QACjB,MAAM,gBAAgB,OAAO;;;;;;;;;;;4CAWO,MAAM;;;;;;;;;;;;;;;;;;;;;;sEAsBoB,SAAS;UACrE,SAAS,6CAA6C,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDxE,CAAC;AACF,CAAC"}
|
package/package.json
CHANGED