Skip to content

feat: auto-restart + diagnostic + UX 3-state (PR-2 of v1.3.39) - #11

Merged
needsbuilder merged 3 commits into
mainfrom
feat/gateway-diagnostic
Apr 28, 2026
Merged

needsbuilder merged 3 commits into
mainfrom
feat/gateway-diagnostic

Conversation

@needsbuilder

Copy link
Copy Markdown
Owner

Summary

PR-2 of two for v1.3.39, building on #10. Where PR-1 stayed
behind the curtain (lifecycle, logging, plist migration), this PR is
what users actually see when the gateway dies.

  • Auto-restart with backoff — supervisor reacts to its own `'died'` event with delays `0 / 2 / 5 / 15 / 60 s`, capped at 5 attempts in any 1-hour window. The cap survives app restarts via `gateway-restart-history.json`. Manual actions clear the cap so users can recover from `gave_up`.
  • Diagnostic collector + copy button — one click in DoneStep or the tray gathers the last 200 stderr lines, recent stdout, restart history, port owner, OS / Node / Electron info, and platform-specific bits (`launchctl print` on macOS, `wsl --version` + ss output inside the distro on Windows). All Telegram bot tokens, `sk-…`, `sk-ant-…`, and `AIza…` strings are masked before leaving the collector. Plan said clipboard + Kakao open chat is the right channel here — no auto-upload, no bot tokens to embed.
  • 3-state tray — label flips to "Gateway 재시작 중..." or "Gateway 실패 (재시작 한도 초과)" when appropriate, with throttled notifications (`died` capped at 5 min, `gave_up` always fires and surfaces the main window).
  • DoneStep failure modal — auto-opens on `gave_up` with the diagnostic text, copy / Kakao / retry buttons.
  • Boot-order race fix — `onboard:run` and `config:switch-provider` now await `supervisor.start()` so DoneStep mounts with an alive gateway and `switchProvider` boots the daemon exactly once instead of twice.
  • i18n for ko / en / ja / zh.
  • Version bump `1.3.38 → 1.3.39` + `docs/QA-1.3.39.md` checklist.

Base branch: `feat/gateway-supervisor` (PR #10). Merge order: PR-1 first, then this.

Test plan

See `docs/QA-1.3.39.md` for the full 7-scenario manual checklist (force-kill, crash loop, post-onboard alive, single boot on switchProvider, quit cleanup, log rotation, PII masking).

  • `npm run typecheck` — clean
  • `npm run lint` — 0 errors, only the unchanged LobsterLogo prettier warning
  • macOS smoke: `pkill -9 -f openclaw-gateway` 5× → tray flips to "failed", DiagnosticModal opens, "Copy" puts a complete masked report on the clipboard
  • Windows WSL: `wsl -d Ubuntu -u root -- pkill -9 -f openclaw` → auto-restart fires within ~5 s
  • Plug a fake `bot1234567890:AAFAKE…` token into stderr → masked as `MASKED` in diagnostic output

@vercel

vercel Bot commented Apr 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
easyclaw Ready Ready Preview, Comment Apr 28, 2026 2:48am

Request Review

@gitguardian

gitguardian Bot commented Apr 27, 2026 •

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
32160370 Triggered Telegram Bot Token 7877998 docs/QA-1.3.39.md View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4915a12f2c

ℹ️ 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".

Comment on lines +207 to +208
const attempts = countAutoInLastHour()
if (attempts >= MAX_AUTO_RESTARTS_PER_HOUR) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reset auto-restart window on manual recovery

scheduleAutoRestart() always gates retries by countAutoInLastHour(), so after 5 auto attempts the next crash will immediately emit gave_up again even if the user clicked Retry/manual start. Because manual start only clears gaveUp and pending timers (not persisted auto-attempt history), recovery stays blocked for up to an hour, which breaks the intended “manual action clears the cap” behavior.

Useful? React with 👍 / 👎.


const PII_PATTERNS: Array<[RegExp, string]> = [
// Telegram bot tokens: bot1234567890:AAH...
[/(bot\d+:)[A-Za-z0-9_-]{30,}/g, '$1****MASKED****'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Mask plain Telegram bot tokens in diagnostics

The Telegram masking regex only matches tokens prefixed with bot (e.g. bot123:...), but real bot secrets are commonly logged as raw <digits>:<secret> (for example in env dumps). In that case the diagnostic copy path will include the unredacted token, creating a sensitive-secret leak when users paste reports externally.

Useful? React with 👍 / 👎.

useEffect(() => {
const unsub = window.electronAPI.gateway.onStatusChanged((s) => {
const unsub = window.electronAPI.gateway.onStatusChanged(({ status: s }) => {
setStatus(s === 'running' ? 'running' : 'stopped')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep startup status when handling supervisor updates

The status handler collapses every non-running supervisor state to stopped, so when the supervisor emits starting or restarting the UI flips to stopped and re-enables stopped-state actions while boot is still in progress. This regresses the new 3-state UX by showing an incorrect state during startup/restart windows.

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).
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.
…older 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.
@needsbuilder
needsbuilder force-pushed the feat/gateway-diagnostic branch from db52b9e to 53e3bcb Compare April 28, 2026 02:47
@needsbuilder
needsbuilder merged commit a7c7733 into main Apr 28, 2026
2 of 3 checks passed
@needsbuilder
needsbuilder deleted the feat/gateway-diagnostic branch April 28, 2026 03:01

This branch was successfully deployed

1 active deployment
Preview — 53e3bcba Deployed Apr 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant