5.5 KiB
5.5 KiB
Failed Automation Rerun Action
Problem
- Failed Orca automation run details show only the disabled/open-target action when no workspace launched, so a user who sees a
dispatch_failederror has no local recovery action in the failed-run view:src/renderer/src/components/automations/AutomationsPage.tsx:1858. - The reusable detail header already accepts actions, but the run detail action set is limited to
getAutomationRunViewState/openRunWorkspace:src/renderer/src/components/automations/AutomationRunPageFrame.tsx:9,src/renderer/src/components/automations/automation-run-view-state.ts:13. - Manual rerun behavior already exists as
runNow, which creates a fresh manual run for the automation; the renderer wrapper currently refreshes the page after calling it:src/renderer/src/components/automations/AutomationsPage.tsx:1033,src/main/automations/service.ts:66.
Goal
Add an easy rerun button to Orca automation run detail pages for failed launch/recovery statuses. The button creates a fresh manual run for the same automation through the existing runNow path.
Non-goals
- Do not mutate or replay the failed run record.
- Do not add backend APIs or provider-specific rerun behavior.
- Do not add rerun support for external Hermes/OpenClaw run details in this change.
- Do not bypass existing SSH availability, worktree creation, or dispatch failure handling.
Design
- Add a small pure predicate near the run view state code, for example
canRerunAutomationRun({ automation, run }).- Return
trueonly when an Orca automation still exists,run.automationId === automation.id, and the run status is one ofdispatch_failed,skipped_unavailable, orskipped_needs_interactive_auth. - Do not show rerun for
pending,dispatching,dispatched,completed, orskipped_missed.skipped_missedis scheduler catch-up history, not a launch failure the detail page should recover.
- Return
- In
AutomationsPage, render aRerunaction inAutomationRunPageFrame.actionswhen that predicate is true forselectedandselectedAutomationRunPage. - The action calls
window.api.automations.runNow({ id: selected.id })through a small handler, thenrefresh(), then shows the existing queued toast. Wrap the call intry/catch/finally: if the automation was deleted or the IPC rejects, toast the error and refresh so the stale run detail can disappear. - Preserve dispatch behavior by reusing
runNow; do not duplicate local/SSH dispatch logic in the renderer.runNowcreates a new manual run andAutomationService.requestDispatchsends the existingautomations:dispatchRequestedpayload to the renderer, whereuseAutomationDispatchEventshandles SSH reconnect, interactive-auth skips, worktree creation/reuse, and terminal launch. - Add a local in-flight state keyed by the failed run id. Disable only that rerun button while pending so repeated clicks in one window cannot queue duplicates before the first request settles.
- Keep the existing
View run/Open workspaceaction beside the new rerun action. Do not gate rerun onselectedAutomationRunPageViewState.canOpen; failed runs with no launch should still show the disabled view action plus enabled rerun. - Use existing shadcn
Button, lucide icon sizing, and styleguide tokens. The button should be compact (size="sm"), outline-level emphasis, and fit the existing header action row. - Add focused tests for the pure predicate in
automation-run-view-state.test.ts. Avoid component-level tests unless a harness already exists locally.
Edge cases
- Failed run has no workspace because base ref refresh, SSH connection, missing project/workspace, or renderer availability failed: rerun remains available and lets the existing dispatch path try again.
- Failed run has a workspace but terminal is closed: rerun stays available, and open workspace behavior remains unchanged.
- Automation was deleted while the request is in flight or by another window:
runNowcan throwAutomation not found.; catch it, clear pending state, and refresh. - Selection changed while the request is in flight: capture
automation.idandrun.idbefore awaiting, clear that run id infinally, and avoid reading mutableselectedafter the await. - SSH automation cannot reconnect or needs credentials: rerun still goes through
runNow; existing dispatch code recordsskipped_unavailableorskipped_needs_interactive_authas a new run. - The user clicks rerun repeatedly in the same window: disable the rerun button while the request is pending.
- The user clicks rerun in two windows: the renderer guard will not prevent duplicate manual runs across windows. Do not claim backend idempotency unless a service-level dedupe key is added.
- Refresh after rerun may leave the failed run detail selected because
selectedAutomationRunPageIdstill points at the old run. That is acceptable for this change, but the run list count and rows must refresh so the new manual run is visible after navigating back. runNowitself does not broadcastorca:automations-changed; the initiating page must callrefresh()after the IPC resolves. Other windows update only when dispatch result handling fires the existing event or when focus/visibility refresh runs.
Rollout
- Add a small predicate/helper for rerun action visibility and unit tests if it can live near automation run view state without mixing responsibilities.
- Add rerun pending state, error handling, and handler in
AutomationsPage. - Render the new action in the selected Orca run detail header.
- Run focused tests, then
pnpm typecheckandpnpm lint.