feat(up): reopen dev container in recovery mode on build failure - #785
Conversation
When a dev container build fails, allow launching a stripped-down recovery container (features and lifecycle commands disabled; a failed Dockerfile swapped for a known-good base image) so the workspace stays reachable and the user can repair devcontainer.json and rebuild. - CLI: add `--recovery` to `up`; classify recoverable build failures with a structured code (exit 79) and label recovery containers `sh.devsy.recovery`. - Recovery is declined for compose configs and skips a failing initializeCommand. - Persist/expose recovery state via the up result and `workspace status --recovery` so the desktop can reconcile it (in-app and external rebuilds). - Desktop: build-failure banner (Reopen in Recovery / Retry / Show Log), recovery-mode indicator, and an on-build-failure preference.
✅ Deploy Preview for devsydev canceled.
|
|
Warning Review limit reached
Next review available in: 8 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis change adds recoverable devcontainer build failures with a recovery-container retry path. CLI and IPC layers forward recovery options and metadata, while the desktop adds build-failure preferences, persisted recovery state, recovery actions, and status indicators. ChangesRecovery error and execution path
Desktop recovery workflow
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Desktop
participant CLI
participant Devcontainer
participant RecoveryContainer
Desktop->>CLI: workspace up
CLI->>Devcontainer: build configured container
Devcontainer-->>CLI: recoverable build failure
CLI-->>Desktop: structured error and recovery metadata
Desktop->>CLI: workspace up --recovery
CLI->>RecoveryContainer: build stripped recovery configuration
RecoveryContainer-->>Desktop: recovery success envelope
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Deploy Preview for images-devsy-sh canceled.
|
# Conflicts: # desktop/src/renderer/src/lib/components/workspace/WorkspaceWizard.svelte
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
desktop/src/main/ipc.ts (1)
866-902: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
workspace_rebuild/workspace_resetnever forwardcliError, silently breaking recovery detection for those ops.
WorkspaceDetailPage.svelte'sBUILD_OPSset includes"Rebuild"and"Reset"and callsisRecoverableBuildFailure(progress.cliError)for every op in that set. But these two handlers'runStreamingexit callbacks are still(code) => { void sink.done(formatLogLine(...)) }— unlike the fixedworkspace_upcallback (lines 765-774), they never passcliErrorthrough tosink.done. As a result,progress.cliErrorwill always beundefinedfor Rebuild/Reset failures, so the recovery banner/auto-recovery flow can never trigger for those two operations, even though the desktop UI is built to support it.🔧 Apply the same fix used for workspace_up
cli.runStreaming( cliArgs, (line) => { if (!sink.line(formatLogLine(line))) return logStore.onDrain(logPath) }, - (code) => { - void sink.done( - formatLogLine(`Exit code: ${code}`, code === 0 ? "INFO" : "ERROR"), - ) - }, + (code, cliError) => { + void sink.done( + formatLogLine(`Exit code: ${code}`, code === 0 ? "INFO" : "ERROR"), + code === 0 ? undefined : { level: "error", cliError }, + ) + }, args.workspaceId, )Apply to both the
workspace_rebuildandworkspace_resethandlers.Also applies to: 904-940
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@desktop/src/main/ipc.ts` around lines 866 - 902, Update the exit callbacks in both the workspace_rebuild and workspace_reset IPC handlers to receive the runStreaming cliError argument and forward it to sink.done, matching the existing workspace_up behavior. Preserve the current exit-code log formatting while ensuring failed operations populate progress.cliError for recovery detection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@desktop/src/main/ipc.ts`:
- Around line 866-902: Update the exit callbacks in both the workspace_rebuild
and workspace_reset IPC handlers to receive the runStreaming cliError argument
and forward it to sink.done, matching the existing workspace_up behavior.
Preserve the current exit-code log formatting while ensuring failed operations
populate progress.cliError for recovery detection.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 2e3123b4-4b2a-445e-9503-c88b5a0bc7d3
📒 Files selected for processing (33)
cmd/internal/agentworkspace/up.gocmd/root.gocmd/workspace/status.gocmd/workspace/up/up.gocmd/workspace/up/up_flags.godesktop/src/main/ipc.tsdesktop/src/renderer/src/lib/components/workspace/WorkspaceCard.sveltedesktop/src/renderer/src/lib/components/workspace/WorkspaceWizard.sveltedesktop/src/renderer/src/lib/ipc/commands.test.tsdesktop/src/renderer/src/lib/ipc/commands.tsdesktop/src/renderer/src/lib/stores/settings.test.tsdesktop/src/renderer/src/lib/stores/settings.tsdesktop/src/renderer/src/lib/utils/log-parser.test.tsdesktop/src/renderer/src/lib/utils/log-parser.tsdesktop/src/renderer/src/pages/SettingsPage.sveltedesktop/src/renderer/src/pages/WorkspaceDetailPage.sveltee2e/tests/up/handles_errors.goe2e/tests/up/testdata/docker-recovery/.devcontainer.jsone2e/tests/up/testdata/docker-recovery/Dockerfilepkg/client/client.gopkg/clierr/errors.gopkg/clierr/errors_test.gopkg/config/labels.gopkg/devcontainer/config/envelope.gopkg/devcontainer/config/envelope_test.gopkg/devcontainer/config/result.gopkg/devcontainer/config/result_test.gopkg/devcontainer/run.gopkg/devcontainer/single.gopkg/devcontainer/single_test.gopkg/exitcode/codes.gopkg/flags/names/names.gopkg/provider/workspace.go
Summary
Adds a "Reopen in Recovery Container" capability so a failed dev container build no longer leaves users locked out of their workspace.
CLI
up --recoveryflag: on a build failure, rebuilds a stripped-down container — features and lifecycle hooks removed. A plain image is reused as-is; a failing Dockerfile is swapped for the generic base image (language.None). Compose configs are unsupported and decline cleanly with a warning.BUILD_FAILED_RECOVERABLEerror and exit with code79(just past sysexitsEX__MAX).sh.devsy.recovery=true; the label is read back on container reuse so recovery state survives restarts.workspace status --recoverysurfaces the running container's recovery state (opt-in, so the frequent status poll pays no extra I/O).Desktop
inRecoveryis set from the authoritative up result and reconciled against the live container on mount (covers rebuilds done outside the app).On build failurepreference (prompt / auto-recovery / do nothing).Tests
%wwrapping, envelope/result round-trips.up-handle-errors): failing build exits79,--recoverysucceeds, container reachable over SSH.Live Docker execution of the recovery path is verified via the e2e harness (
task cli:test:e2e:focus -- up-handle-errors).Summary by CodeRabbit
New Features
--recoveryoptions for workspace start and status commands.Bug Fixes