Repository navigation
refactor: gateway supervisor + disk logging + quit cleanup (PR-1 of v1.3.39) - #10
Conversation
Background: users in the Kakao group reported that the gateway keeps shutting down — particularly after sending a Telegram command — and EasyClaw silently leaves them with an unresponsive bot. Phase 1 (PR-1) lays the safety core without changing any user-visible behavior. Auto-restart, diagnostic UI, and the 3-state tray come in a follow-up PR (PR-2). What this changes: - New gateway-supervisor.ts owns the Gateway lifecycle through an EventEmitter-based singleton with platform adapters for macOS launchd and Windows WSL. Internal status machine: idle → starting → running → stopped/failed. Emits 'died' / 'started' / 'failed' / 'log' / 'status-changed'. - New gateway-probes.ts replaces the brittle "wsl.exe child .killed" check with a real liveness probe: macOS uses launchctl print + lsof on port 18789, WSL runs ss / lsof / /proc/net/tcp inside the distro. Works around lsof being missing in some Ubuntu images. - New gateway-log-rotator.ts persists daemon stdout/stderr to userData/logs/gateway-YYYY-MM-DD.log with 7-day retention and a 50 MB total cap so we always have the last crash output on disk. - gateway.ts is now a thin wrapper delegating to the supervisor — existing IPC / tray / index call sites keep their imports. - onboarder.ts patches the launchd plist to add StandardOutPath / StandardErrorPath and exposes a one-shot migrateGatewayPlist() helper that upgrades existing installs on first boot. Also exports wslKillOpenclaw() so the supervisor can reuse the same kill logic. - index.ts before-quit now stops the supervisor and flushes the log before exiting (with a 3 s cap and re-entry guard) so a force quit no longer leaves the WSL daemon orphaned. Verification: npm run typecheck and npm run lint both pass clean for the modified files. End-to-end QA scenarios are scheduled for the PR-2 release.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a8b64aadb4
ℹ️ 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".
| while (Date.now() < deadline) { | ||
| if (!(await supervisor.isAlive())) return | ||
| await new Promise((r) => setTimeout(r, 500)) | ||
| } | ||
| if (platform() !== 'win32') { | ||
| await forceKillGateway() | ||
| await new Promise((r) => setTimeout(r, 1000)) | ||
| } | ||
| } |
There was a problem hiding this comment.
Restore force-stop behavior after waitUntilStopped timeout
waitUntilStopped now exits silently once the deadline passes, even if supervisor.isAlive() is still true. Callers like backup restore depend on this helper to guarantee the gateway is down before modifying on-disk state; returning while the daemon is still running can leave concurrent writes during restore and produce inconsistent or failed imports. This refactor removed the previous hard-stop fallback without adding an equivalent safeguard.
Useful? React with 👍 / 👎.
| `(ss -ltn 2>/dev/null | awk '$4 ~ /:${port}$/ {print "OK"; exit 0}')`, | ||
| `(lsof -i :${port} -t 2>/dev/null | head -n1 | grep -q . && echo OK)`, | ||
| `(awk '$2 ~ /:${hex}$/ {print "OK"; exit}' /proc/net/tcp /proc/net/tcp6 2>/dev/null)` |
There was a problem hiding this comment.
Make WSL probe fallback chain execute on ss failure
The first branch of WSL_PROBE_SCRIPT is a pipeline (ss ... | awk ...) inside an || chain, but without pipefail the pipeline status comes from awk, which is 0 even when ss is missing or returns no match. That means the later lsof and /proc/net/tcp checks are skipped, so environments where ss is unavailable will incorrectly report the gateway as not alive despite the service running.
Useful? React with 👍 / 👎.
…(v1.3.39) PR-2 of two for the v1.3.39 stability release. Builds on the supervisor core from PR-1 (#10) and adds the user-visible behavior: gateway crashes now self-heal, the tray surfaces what's happening, and a single "Copy Diagnostic Info" button gives non-developer users a way to share the actual crash output in the Kakao group chat. What this changes: - Auto-restart with exponential backoff (0/2/5/15/60 s) and a 5-per-hour hard cap. Manual user actions clear the cap so users can recover from the gave_up state. Restart attempts are persisted to gateway-restart-history.json so the cap survives app restarts. - New diagnostic-collector aggregates Electron / OS / Node info, the last 200 stderr lines, recent stdout, restart history, port ownership, plus per-platform extras (launchctl print on macOS, wsl --version + ss output inside the distro on Windows). All output is PII-masked: Telegram bot tokens, sk-* / AIza* / sk-ant-* API keys are redacted before leaving the diagnostic surface. - New diagnostic:collect / diagnostic:copy IPC + electronAPI.diagnostic bridge. - Tray gains a 3-state label (running / restarting / failed), a "Copy Diagnostic Info" menu item, and notifications for died / gave_up events (5 min throttle, except gave_up which always fires). - DoneStep shows a yellow "Gateway 자동 재시작 중" banner during restart, and a red "Gateway 재시작 실패" banner with a copy button when the cap is hit. The DiagnosticModal opens automatically on gave_up and lets the user retry, copy to clipboard, or jump to the Kakao open chat. - ipc-handlers now drives the supervisor from onboard:run and config:switch-provider so the gateway is alive when DoneStep mounts (no more 30 s polling fallback) and switchProvider boots the daemon exactly once instead of twice. - i18n keys for ko/en/ja/zh. - Bump version to 1.3.39 + QA checklist (docs/QA-1.3.39.md). Verification: npm run typecheck and npm run lint both clean (only the pre-existing LobsterLogo prettier warning remains, untouched).
* feat: auto-restart + diagnostic copy + 3-state tray + boot order fix (v1.3.39) PR-2 of two for the v1.3.39 stability release. Builds on the supervisor core from PR-1 (#10) and adds the user-visible behavior: gateway crashes now self-heal, the tray surfaces what's happening, and a single "Copy Diagnostic Info" button gives non-developer users a way to share the actual crash output in the Kakao group chat. What this changes: - Auto-restart with exponential backoff (0/2/5/15/60 s) and a 5-per-hour hard cap. Manual user actions clear the cap so users can recover from the gave_up state. Restart attempts are persisted to gateway-restart-history.json so the cap survives app restarts. - New diagnostic-collector aggregates Electron / OS / Node info, the last 200 stderr lines, recent stdout, restart history, port ownership, plus per-platform extras (launchctl print on macOS, wsl --version + ss output inside the distro on Windows). All output is PII-masked: Telegram bot tokens, sk-* / AIza* / sk-ant-* API keys are redacted before leaving the diagnostic surface. - New diagnostic:collect / diagnostic:copy IPC + electronAPI.diagnostic bridge. - Tray gains a 3-state label (running / restarting / failed), a "Copy Diagnostic Info" menu item, and notifications for died / gave_up events (5 min throttle, except gave_up which always fires). - DoneStep shows a yellow "Gateway 자동 재시작 중" banner during restart, and a red "Gateway 재시작 실패" banner with a copy button when the cap is hit. The DiagnosticModal opens automatically on gave_up and lets the user retry, copy to clipboard, or jump to the Kakao open chat. - ipc-handlers now drives the supervisor from onboard:run and config:switch-provider so the gateway is alive when DoneStep mounts (no more 30 s polling fallback) and switchProvider boots the daemon exactly once instead of twice. - i18n keys for ko/en/ja/zh. - Bump version to 1.3.39 + QA checklist (docs/QA-1.3.39.md). Verification: npm run typecheck and npm run lint both clean (only the pre-existing LobsterLogo prettier warning remains, untouched). * chore: revert manual version bump — release.mjs handles it scripts/release.mjs runs npm version patch on its own. Pre-bumping in the PR would push the next release to 1.3.40 instead of 1.3.39. * docs: replace fake-but-matching bot token in QA checklist with placeholder shape GitGuardian flagged the literal string in S7 because it matched the Telegram bot token regex. Switch to placeholder syntax that conveys the same instruction without tripping secret scanners.
Summary
PR-1 of two for the v1.3.39 stability release addressing the bug
multiple users reported in the Kakao group chat: the gateway keeps
shutting down (often right after a Telegram command), and EasyClaw
silently leaves them with an unresponsive bot.
This PR is the safety core — it restructures gateway lifecycle
internals without changing user-visible behavior. Auto-restart, the
3-state tray, and the diagnostic copy modal land in PR-2.
gateway-supervisor.tsowns lifecyclevia an
EventEmittersingleton with macOS-launchd and WSL adapters.Existing IPC / tray / index call sites keep working through a thin
gateway.tswrapper.gateway-probes.tsreplaces the brittlewsl.exe child .killedcheck (which kept saying "running" while theWSL-internal openclaw was already dead). macOS uses
launchctl printlsof :18789; WSL runsss → lsof → /proc/net/tcpinside the distro.gateway-log-rotator.tswrites daemonstdout/stderr to
userData/logs/gateway-YYYY-MM-DD.logwith 7-dayretention + 50 MB cap. Combined with the new
StandardOutPath/StandardErrorPathlaunchd plist patch, future PR-2 diagnostics willalways have the last crash output on disk.
before-quitnow stops the supervisor + flushes thelog before exit with a 3 s cap, fixing orphaned WSL daemons that caused
port-already-in-use on next launch.
migrateGatewayPlist()runs once at startup soexisting v1.3.38 users upgrade to capturing daemon stdout/stderr without
needing to re-onboard.
Test plan
npm run typecheck— passes (node + web)npm run lint— no new warnings (1 pre-existing prettier warning inLobsterLogo.tsxunchanged)pkill -9 -f openclaw-gateway. Tray should flip to "stopped" within~10s. Manual restart via tray menu should bring it back.
and verify
~/Library/LaunchAgents/ai.openclaw.gateway.plistcontains
StandardOutPathafter first run, and thatuserData/logs/launchd-gateway.{out,err}.logstart populating.wsl -d Ubuntu -u root -- pkill -9 -f openclaw. Tray should flipto "stopped" (this is the regression case — previously the tray
stayed at "running" because
wsl.exe's.killedflag was false).wsl --list --runningdoes not show openclaw on Windows, andpgrep -f openclaw-gatewayreturns nothing on macOS.PR-2 (auto-restart, 3-state tray, diagnostic modal, switchProvider boot
order fix) follows immediately.