fix(gateway): persist macOS stop disable after bootout#79235
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b4c239c461
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (params.stopWhenNotLoaded) { | ||
| try { | ||
| await params.service.stop({ env: process.env, stdout, disable: params.opts?.disable }); | ||
| } catch (err) { |
There was a problem hiding this comment.
Preserve unmanaged stop fallback for macOS
--disable
When openclaw gateway stop --disable runs on macOS and launchd reports the service as not loaded, this new branch calls service.stop(...) and returns stopped without invoking the existing onNotLoaded unmanaged-process path. In that scenario, a gateway started outside launchd (but still listening on the port) is left running even though the CLI reports success, because only the launchd disable/stop commands are attempted. This regresses stop semantics specifically for not-loaded + unmanaged runtime cases.
Useful? React with 👍 / 👎.
Summary
--disabletailopenclaw gateway stop --disablethrough the managed LaunchAgent stop path even when a previousbootoutmakes launchd report the service as not loadedBug / Behavior
#78412 changes the default macOS stop path from
launchctl disabletolaunchctl bootout, preserving KeepAlive recovery unless the operator explicitly requests--disable. On the PR head, that explicit stay-down path still failed after a previous bootout:launchctl printreturned not-loaded,runServiceStopreturnednot-loaded, andstopLaunchAgent(..., disable: true)never ran, leavinglaunchctl print-disabled gui/501as"ai.openclaw.gateway" => enabled.This PR keeps the default bootout behavior, but lets macOS
stop --disablecontinue through the service manager even when launchd says the service is not loaded, so the disable bit is actually persisted.Fixes #77934.
Fixes #77428.
Replaces #78412.
Real behavior proof
openclaw gateway stop --disablemust persist the LaunchAgent disable bit even after a prior default stop usedlaunchctl bootoutand left the service not loaded.Darwin 25.3.0, uid501, isolatedOPENCLAW_STATE_DIR=$HOME/.openclaw-78412-proofandOPENCLAW_CONFIG_PATH=$HOME/.openclaw-78412-proof/openclaw.json.openclaw gateway install --force --token proof-token --port 18789 --json, thenopenclaw gateway stop --json, thenopenclaw gateway stop --disable --json, then inspectedlaunchctl print-disabled gui/501andlaunchctl print gui/501/ai.openclaw.gateway.bootoutpath still leaves KeepAlive recovery enabled, while the explicit--disablepath now persists"ai.openclaw.gateway" => disabledafter the service is already not loaded.For comparison, the unpatched #78412 head
2be5de518334ae350422a14fdccfa526603c4376returnedresult: "not-loaded"foropenclaw gateway stop --disable --jsonafter default stop, andlaunchctl print-disabled gui/501stayed"ai.openclaw.gateway" => enabled.Verification
pnpm installpnpm test src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/lifecycle.test.ts src/daemon/launchd.test.tspnpm exec oxfmt --check --threads=1 CHANGELOG.md src/cli/daemon-cli/lifecycle-core.ts src/cli/daemon-cli/lifecycle.ts src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/lifecycle.test.ts docs/cli/gateway.md docs/gateway/index.md src/daemon/launchd.ts src/daemon/launchd.test.ts src/cli/daemon-cli/register-service-commands.ts src/cli/daemon-cli/types.ts src/daemon/service-types.tsgit diff --check origin/main...HEADpnpm build