Skip to content

feat: add rescue lifecycle and primary recovery in Doctor#15

Merged
Keith-CY merged 12 commits intolay2dev:mainfrom
Keith-CY:codex/rescue-bot-doctor-entry
Feb 25, 2026
Merged

feat: add rescue lifecycle and primary recovery in Doctor#15
Keith-CY merged 12 commits intolay2dev:mainfrom
Keith-CY:codex/rescue-bot-doctor-entry

Conversation

@Keith-CY
Copy link
Copy Markdown
Collaborator

@Keith-CY Keith-CY commented Feb 25, 2026

Summary

  • add full Rescue Bot lifecycle management in Tauri (local + SSH): set | activate | status | deactivate | unset
  • make rescue operations more robust and idempotent:
    • activation restart-timeout fallback (restart -> stop/start)
    • cleanup no-op tolerance for deactivate/unset (already stopped/uninstalled/unset)
  • add Rescue-driven primary health flow:
    • diagnosis result with checks/issues panel
    • safe auto-repair pipeline with re-check
  • remove manual dependency for primary doctor JSON mode:
    • auto fallback from openclaw --profile <profile> doctor --json to openclaw --profile <profile> doctor when --json is unsupported
  • improve Doctor UI interactions:
    • status-first Rescue card with Activate, Deactivate, Unset
    • quick-fix actions directly on failed checks and auto-fixable issue items
    • clearer localized messages (EN/ZH)

Test Plan

  • cargo check --quiet (in src-tauri/)
  • bun run tsc --noEmit
  • cargo test rescue_bot_tests --quiet blocked in this environment by DNS resolution to static.crates.io

Notes

  • Doctor remains the primary entrypoint for Rescue lifecycle operations.
  • Auto-repair still only applies to explicitly mapped safe primary issues.

@Keith-CY Keith-CY changed the title feat: add rescue bot activation from Doctor feat: add rescue lifecycle and primary recovery in Doctor Feb 25, 2026
@Keith-CY Keith-CY force-pushed the codex/rescue-bot-doctor-entry branch from eaf255a to d6703a9 Compare February 25, 2026 06:07
@Keith-CY Keith-CY marked this pull request as ready for review February 25, 2026 06:10
Copy link
Copy Markdown
Collaborator

@dev01lay2 dev01lay2 left a comment

Choose a reason for hiding this comment

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

Review Summary

Solid feature addition — Rescue Bot lifecycle + primary recovery diagnostics are well-structured. The local/remote symmetry is clean. A few things to address:

Issues

1. run_openclaw_dynamic duplicates OpenclawCommandOutput fields unnecessarily
commands.rsrun_openclaw_dynamic takes the output from run_openclaw (which already returns OpenclawCommandOutput) and reconstructs it field-by-field. If the types match, just return it directly.

2. json.syntax fix is a no-op pretending to be a fix
build_primary_issue_fix_command maps json.syntax to the same command as field.agents (set agents.defaults.model). The original remote_fix_issues just marks it applied without doing anything meaningful either. If the intent is "normalize the config by rewriting it," consider a dedicated config normalize command or at least add a comment explaining why this works.

3. collect_model_summary moved but unchanged — noisy diff
The function and several hundred lines of helpers (RescueBotAction, utility fns) were inserted in the middle of existing code, causing a large delete+reinsert of fix_issues / collect_model_summary. The actual logic is unchanged — consider reordering to minimize churn (new code at end of file, before tests).

4. Missing use_effect cleanup / abort for async operations in Doctor.tsx
refreshRescueStatus fires on mount via useEffect but has no abort/cleanup. If the component unmounts mid-flight (instance switch), the setState calls will fire on an unmounted component. Consider an abort flag or AbortController.

5. State explosion in Doctor.tsx
15+ individual useState hooks for rescue/primary state. Consider grouping into a reducer or at least an object state to make resets cleaner and reduce the reset list in the instance-change effect.

Minor / Nits

  • let _ = new_text; in remote_fix_issues is dead code (was there before, but worth cleaning up since you're touching the file)
  • rescue_port in RescuePrimaryDiagnosisResult is Option<u16> on Rust side but rescuePort?: number in TS — fine, but document the mapping for optional fields vs undefined
  • Test test_suggest_rescue_port_prefers_large_gap only tests one case — consider edge cases (port near u16::MAX, port 0)
  • cargo test rescue_bot_tests blocked by DNS — noted in PR description, but ensure CI has the fix before merge

.and_then(Value::as_str)
.or_else(|| obj.get("fix_hint").and_then(Value::as_str))
.map(str::to_string);
items.push(RescuePrimaryIssue {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

run_openclaw_dynamic reconstructs OpenclawCommandOutput field-by-field from the return of run_openclaw, which already returns the same struct. If the types truly match, just return it directly instead of destructuring and rebuilding.

if !output.stdout.trim().is_empty() {
return trim_for_detail(&output.stdout);
}
"no output".into()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This maps json.syntax to the exact same command as field.agents (config set agents.defaults.model). If the intent is "rewrite the config file to normalize JSON syntax," that's a side-effect of config set — worth a comment explaining why, otherwise it looks like a copy-paste error.

Copy link
Copy Markdown

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

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: d6703a9173

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

@Keith-CY
Copy link
Copy Markdown
Collaborator Author

Addressed review feedback in commits 3299c53 and d06370a:

  1. run_openclaw_dynamic now uses a From<CliOutput> conversion + direct map(Into::into) (no field-by-field rebuild).
  2. Added explicit rationale for json.syntax normalization path and removed copy-paste shape via a shared command builder.
  3. Refactored Doctor rescue/primary state into grouped object states (RescueUiState + PrimaryRecoveryState) so reset is single-call per group.
  4. Added cancellation guard in the rescue status effect to prevent stale async state updates on instance switch.
  5. Allowed Rescue re-activation after deactivation (removed configured==true early-return/disable guard).
  6. Also removed dead code in remote_fix_issues (let _ = new_text).

Validation re-run:

  • cargo check --quiet
  • bun run tsc --noEmit

Copy link
Copy Markdown
Collaborator

@dev01lay2 dev01lay2 left a comment

Choose a reason for hiding this comment

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

All review feedback addressed:

  • run_openclaw_dynamic now uses From trait (.map(Into::into))
  • json.syntax fix has explanatory comment about canonical rewrite
  • ✅ Dead let _ = new_text removed from remote_fix_issues
  • ✅ State grouped into RescueUiState + PrimaryRecoveryState with updateRescueState/updatePrimaryState helpers
  • useEffect cleanup with cancelled flag for refreshRescueStatus
  • ✅ Bonus: removed rescueConfigured === true guard on Activate button (allows reactivation after deactivation)

LGTM 🚀

Copy link
Copy Markdown

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

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: d06370a40a

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

@Keith-CY Keith-CY merged commit ac927fd into lay2dev:main Feb 25, 2026
Copy link
Copy Markdown

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

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: bece945f7d

ℹ️ 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 +3468 to +3472
if ch == closer {
depth += 1;
} else if ch == opener {
depth -= 1;
if depth == 0 {
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 Handle braces in JSON strings when slicing trailing payload

The backward depth scan treats every }/{ byte as structural, so outputs like "[warn] ...\n{\"message\":\"expected } at ...\",...}" never reach depth 0 and extract_json_from_output returns None even though valid JSON is present. This is a regression from the previous find('{') behavior and causes parse_json_loose callers (including rescue diagnosis/status parsing) to silently drop valid reports whenever a JSON string contains brace characters after prefixed log lines.

Useful? React with 👍 / 👎.

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.

2 participants