
















@@ -69,36 +69,44 @@ exit 0
6969}
70707171function expectWindowsRestartWaitOrdering(content: string, port = 18789) {
72-const endCommand = 'schtasks /End /TN "';
73-const pollAttemptsInit = "set /a attempts=0";
74-const pollLabel = ":wait_for_port_release";
75-const pollAttemptIncrement = "set /a attempts+=1";
76-const pollNetstatCheck = `netstat -ano | findstr /R /C:":${port} .*LISTENING" >nul`;
77-const forceKillLabel = ":force_kill_listener";
78-const forceKillCommand = "taskkill /F /PID %%P >>";
79-const portReleasedLabel = ":port_released";
80-const runCommand = 'schtasks /Run /TN "';
81-const endIndex = content.indexOf(endCommand);
82-const attemptsInitIndex = content.indexOf(pollAttemptsInit, endIndex);
83-const pollLabelIndex = content.indexOf(pollLabel, attemptsInitIndex);
84-const pollAttemptIncrementIndex = content.indexOf(pollAttemptIncrement, pollLabelIndex);
85-const pollNetstatCheckIndex = content.indexOf(pollNetstatCheck, pollAttemptIncrementIndex);
86-const forceKillLabelIndex = content.indexOf(forceKillLabel, pollNetstatCheckIndex);
87-const forceKillCommandIndex = content.indexOf(forceKillCommand, forceKillLabelIndex);
88-const portReleasedLabelIndex = content.indexOf(portReleasedLabel, forceKillCommandIndex);
89-const runIndex = content.indexOf(runCommand, portReleasedLabelIndex);
90-91-expect(endIndex).toBeGreaterThanOrEqual(0);
92-expect(attemptsInitIndex).toBeGreaterThan(endIndex);
93-expect(pollLabelIndex).toBeGreaterThan(attemptsInitIndex);
94-expect(pollAttemptIncrementIndex).toBeGreaterThan(pollLabelIndex);
95-expect(pollNetstatCheckIndex).toBeGreaterThan(pollAttemptIncrementIndex);
96-expect(forceKillLabelIndex).toBeGreaterThan(pollNetstatCheckIndex);
97-expect(forceKillCommandIndex).toBeGreaterThan(forceKillLabelIndex);
98-expect(portReleasedLabelIndex).toBeGreaterThan(forceKillCommandIndex);
99-expect(runIndex).toBeGreaterThan(portReleasedLabelIndex);
72+const stateCheck = "$taskState = Get-OpenClawScheduledTaskState -TaskName $taskName";
73+const runningGuard = 'if ($taskState -eq "Running")';
74+const endCommand =
75+'Invoke-OpenClawSchtasksWithTimeout -Arguments @("/End", "/TN", $taskName) -TimeoutSeconds 10';
76+const skipEndLog = "openclaw restart skipped schtasks end";
77+const pollLoop = "for ($attempt = 1; $attempt -le 10; $attempt++)";
78+const pollCall = `Get-OpenClawListenerPids -Port $port`;
79+const forceKillBranch = "if ($attempt -eq 10)";
80+const forceKillCommand = "Stop-Process -Id $listenerPid -Force";
81+const runCommand =
82+'Invoke-OpenClawSchtasksWithTimeout -Arguments @("/Run", "/TN", $taskName) -TimeoutSeconds 30';
83+const portAssignment = `$port = ${port}`;
84+const stateCheckIndex = content.indexOf(stateCheck);
85+const runningGuardIndex = content.indexOf(runningGuard, stateCheckIndex);
86+const endIndex = content.indexOf(endCommand, runningGuardIndex);
87+const skipEndLogIndex = content.indexOf(skipEndLog, endIndex);
88+const portAssignmentIndex = content.indexOf(portAssignment);
89+const pollLoopIndex = content.indexOf(pollLoop, skipEndLogIndex);
90+const pollCallIndex = content.indexOf(pollCall, pollLoopIndex);
91+const forceKillBranchIndex = content.indexOf(forceKillBranch, pollCallIndex);
92+const forceKillCommandIndex = content.indexOf(forceKillCommand, forceKillBranchIndex);
93+const runIndex = content.indexOf(runCommand, forceKillCommandIndex);
94+95+expect(stateCheckIndex).toBeGreaterThanOrEqual(0);
96+expect(runningGuardIndex).toBeGreaterThan(stateCheckIndex);
97+expect(endIndex).toBeGreaterThan(runningGuardIndex);
98+expect(skipEndLogIndex).toBeGreaterThan(endIndex);
99+expect(portAssignmentIndex).toBeGreaterThanOrEqual(0);
100+expect(pollLoopIndex).toBeGreaterThan(skipEndLogIndex);
101+expect(pollCallIndex).toBeGreaterThan(pollLoopIndex);
102+expect(forceKillBranchIndex).toBeGreaterThan(pollCallIndex);
103+expect(forceKillCommandIndex).toBeGreaterThan(forceKillBranchIndex);
104+expect(runIndex).toBeGreaterThan(forceKillCommandIndex);
100105101106expect(content).not.toContain("timeout /t 3 /nobreak >nul");
107+expect(content).not.toContain("findstr");
108+expect(content).not.toContain("netstat -ano |");
109+expect(content).not.toContain("schtasks /End /TN");
102110}
103111104112beforeEach(() => {
@@ -296,21 +304,25 @@ exit 0
296304await cleanupScript(scriptPath);
297305});
298306299-it("creates a schtasks restart script on Windows", async () => {
307+it("creates a guarded schtasks restart script on Windows", async () => {
300308Object.defineProperty(process, "platform", { value: "win32" });
301309302310const { scriptPath, content } = await prepareAndReadScript({
303311OPENCLAW_PROFILE: "default",
304312});
305-expect(scriptPath.endsWith(".bat")).toBe(true);
313+expect(scriptPath.endsWith(".cmd")).toBe(true);
306314expect(content).toContain("@echo off");
315+expect(content).toContain("powershell -NoProfile -ExecutionPolicy Bypass -Command");
316+expect(content).not.toContain("-File");
317+expect(content).toContain('$ErrorActionPreference = "Continue"');
307318expect(content).toContain("gateway-restart.log");
308-expect(content).toContain("openclaw restart attempt source=update target=OpenClaw Gateway");
309-expect(content).toContain('schtasks /End /TN "OpenClaw Gateway"');
310-expect(content).toContain('schtasks /Run /TN "OpenClaw Gateway" >>');
319+expect(content).toContain("$taskName = 'OpenClaw Gateway'");
320+expect(content).toContain("function Invoke-OpenClawSchtasksWithTimeout");
321+expect(content).toContain("function Get-OpenClawScheduledTaskState");
322+expect(content).toContain("Get-ScheduledTask -TaskName $TaskName");
323+expect(content).toContain("openclaw restart skipped schtasks end");
311324expectWindowsRestartWaitOrdering(content);
312-// Batch self-cleanup
313-expect(content).toContain('del "%~f0"');
325+expect(content).toContain('del "%~f0" >nul 2>&1');
314326await cleanupScript(scriptPath);
315327});
316328@@ -321,8 +333,11 @@ exit 0
321333OPENCLAW_PROFILE: "default",
322334OPENCLAW_WINDOWS_TASK_NAME: "OpenClaw Gateway (custom)",
323335});
324-expect(content).toContain('schtasks /End /TN "OpenClaw Gateway (custom)"');
325-expect(content).toContain('schtasks /Run /TN "OpenClaw Gateway (custom)"');
336+expect(content).toContain("$taskName = 'OpenClaw Gateway (custom)'");
337+expect(content).toContain("Get-OpenClawScheduledTaskState -TaskName $taskName");
338+expect(content).toContain(
339+'Invoke-OpenClawSchtasksWithTimeout -Arguments @("/End", "/TN", $taskName) -TimeoutSeconds 10',
340+);
326341expectWindowsRestartWaitOrdering(content);
327342await cleanupScript(scriptPath);
328343});
@@ -337,10 +352,10 @@ exit 0
337352},
338353customPort,
339354);
340-expect(content).toContain(`netstat -ano | findstr /R /C:":${customPort} .*LISTENING" >nul`);
341-expect(content).toContain(
342- `for /f "tokens=5" %%P in ('netstat -ano ^| findstr /R /C:":${customPort} .*LISTENING"') do (`,
343-);
355+expect(content).toContain(`$port = ${customPort}`);
356+expect(content).toContain("Get-NetTCPConnection -LocalPort $Port -State Listen");
357+expect(content).toContain("& netstat.exe -ano -p tcp");
358+expect(content).not.toContain("findstr");
344359expectWindowsRestartWaitOrdering(content, customPort);
345360await cleanupScript(scriptPath);
346361});
@@ -371,7 +386,7 @@ exit 0
371386const { scriptPath, content } = await prepareAndReadScript({
372387OPENCLAW_PROFILE: "production",
373388});
374-expect(content).toContain('schtasks /End /TN "OpenClaw Gateway (production)"');
389+expect(content).toContain("$taskName = 'OpenClaw Gateway (production)'");
375390expectWindowsRestartWaitOrdering(content);
376391await cleanupScript(scriptPath);
377392});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。