



















@@ -2471,6 +2471,78 @@ describe("update-cli", () => {
24712471expect(requiredServiceStopCallOrder).toBeLessThan(requiredNpmInstallCallOrder);
24722472});
247324732474+it("keeps managed service stop output off stdout during json package updates", async () => {
2475+const tempDir = await createTrackedTempDir("openclaw-update-json-stop-service-");
2476+const nodeModules = path.join(tempDir, "node_modules");
2477+const pkgRoot = path.join(nodeModules, "openclaw");
2478+const entryPath = path.join(pkgRoot, "dist", "index.js");
2479+const stdoutWrite = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
2480+mockPackageInstallStatus(pkgRoot);
2481+await fs.mkdir(path.dirname(entryPath), { recursive: true });
2482+await fs.writeFile(
2483+path.join(pkgRoot, "package.json"),
2484+JSON.stringify({ name: "openclaw", version: "2026.4.21" }),
2485+"utf-8",
2486+);
2487+await fs.writeFile(entryPath, "export {};\n", "utf-8");
2488+await writePackageDistInventory(pkgRoot);
2489+serviceReadCommand.mockResolvedValue({
2490+programArguments: ["openclaw", "gateway", "run"],
2491+environment: {
2492+OPENCLAW_SERVICE_MARKER: "openclaw",
2493+OPENCLAW_SERVICE_KIND: "gateway",
2494+},
2495+});
2496+serviceLoaded.mockResolvedValue(true);
2497+serviceReadRuntime.mockResolvedValue({
2498+status: "running",
2499+pid: 4242,
2500+state: "running",
2501+});
2502+serviceStop.mockImplementationOnce(async (params: { stdout?: NodeJS.WritableStream }) => {
2503+params.stdout?.write("Stopped systemd service: openclaw-gateway.service\n");
2504+});
2505+pathExists.mockImplementation(async (candidate: string) => {
2506+try {
2507+await fs.access(candidate);
2508+return true;
2509+} catch {
2510+return false;
2511+}
2512+});
2513+vi.mocked(runCommandWithTimeout).mockImplementation(async (argv) => {
2514+if (Array.isArray(argv) && argv[0] === "npm" && argv[1] === "root" && argv[2] === "-g") {
2515+return {
2516+stdout: `${nodeModules}\n`,
2517+stderr: "",
2518+code: 0,
2519+signal: null,
2520+killed: false,
2521+termination: "exit",
2522+};
2523+}
2524+return {
2525+stdout: "",
2526+stderr: "",
2527+code: 0,
2528+signal: null,
2529+killed: false,
2530+termination: "exit",
2531+};
2532+});
2533+2534+let writes = "";
2535+try {
2536+await updateCommand({ yes: true, json: true });
2537+writes = stdoutWrite.mock.calls.map((call) => String(call[0])).join("\n");
2538+} finally {
2539+stdoutWrite.mockRestore();
2540+}
2541+2542+expect(writes).not.toContain("Stopped systemd service");
2543+expect(serviceStop).toHaveBeenCalled();
2544+});
2545+24742546it("disarms legacy launchd updater jobs before stopping the gateway", async () => {
24752547const tempDir = await createTrackedTempDir("openclaw-update-launchd-loop-");
24762548const nodeModules = path.join(tempDir, "node_modules");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。