dor ensure: add --restart to interrupt and re-run a matching surface#158
Merged
Conversation
`dor ensure --restart -- <command>` now restarts a surface that is already running the command instead of no-opping. The host interrupts the live command (Ctrl+C), waits for the shell to return to its prompt, types the command again, and waits for it to go live — driving the PTY directly so it works for minimized doors too. The CLI blocks until the restart completes (with a bumped 60s request timeout for that one command). With no matching surface, --restart behaves like a plain ensure and creates one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
aee4ac0
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://4fb8baf5.mouseterm.pages.dev |
| Branch Preview URL: | https://ensure-fixup.mouseterm.pages.dev |
dormouse-bot
approved these changes
Jun 19, 2026
Spawn a real interactive shell for `dor split/ensure -- <command>` and type the command into it once it reaches a prompt, rather than launching `shell -c command`. A `-c` invocation has no prompt behind it, so `dor ensure --restart`'s Ctrl+C would take the shell down with the command instead of returning to a re-runnable prompt. typeCommandWhenPromptReady waits for the seeded currentCommand to clear (the first-prompt signal) before writing the keystrokes, falling back to a best-effort send on timeout. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`dor ensure -- <command>` types the command into a real interactive shell rather than running `shell -c command`. That injection bypasses the keystroke heuristic, so only a shell whose integration emits OSC 633 boundaries ever reports the command back. Without it the surface can never be matched, so each ensure silently spawns a duplicate (and --restart can never reuse it). When ensure creates a surface, the host now waits for the new shell to report OSC 633 and, if it never does, returns a `warning` the CLI prints to stderr (stdout stays clean). Matched/existing surfaces still respond instantly; only a non-integration shell waits out the detection window, so the plain-ensure client timeout is raised to outlast it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cwd, casing)
On Windows + Git Bash the shell integration reports a pane's cwd as a POSIX path
(`/c/Users/...`) while the rest of the system speaks native Windows
(`C:\Users\...`). Three symptoms, all from that one dialect split, all verified
by measurement:
1. `dor ensure -- cmd` twice spawned two surfaces: surfaceRunsCommand compared
the bash POSIX cwd against the CLI's Windows cwd by exact string and never
matched. Canonicalize both sides (MSYS `/c/`->`C:\`, slashes, drive case)
before the compare. Anchored so genuine POSIX paths stay untouched off-Windows.
2. The `dor` CLI mangled a pure-POSIX `$PWD`: `path.resolve('/c/Users/x')` on
win32 yields `C:\c\Users\x`. Fold the MSYS drive form to a native drive before
resolving.
3. The pty spawn passed the cwd through verbatim: a POSIX `/c/...` failed the
directory check and silently fell back to the home dir, and a lowercase drive
(e.g. VS Code's workspaceFolder.fsPath) propagated into process.cwd() of the
shell and everything launched in it. Measured: the spawn cwd's drive-letter
case is preserved verbatim into a child's process.cwd(), so this is what
fragments Claude Code's per-directory state (`c--` vs `C--`). Canonicalize the
spawn cwd to one Windows form in the shared resolveSpawnConfig (covers both the
Tauri sidecar and the VS Code host via lib/pty-core.cjs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`dor ensure` needs OSC 633 shell integration to track a command. cmd.exe has none, and the old behavior was a slow, confusing half-failure: the webview blocked 15s waiting for OSC while the sidecar control server timed out at 10s (printing "timed out waiting for surface.ensure"), and the command got typed into the new split anyway on a separate best-effort timer. --restart additionally fired Ctrl+C into cmd.exe, leaving a stuck "Terminate batch job (Y/N)?". Now: - cmd.exe (explicitly configured) errors instantly with a clear message and no split: "dor ensure requires OSC 633 shell integration, which cmd.exe does not provide. Run it from a shell with Dormouse integration, such as Git Bash or PowerShell." - Any other shell that lacks integration: create the split, wait up to 8s for OSC 633, then kill the throwaway split and return the same error. - The command is only typed once OSC 633 is confirmed (requireIntegration gate in typeCommandWhenPromptReady); it is dropped, never best-effort typed, when integration is absent, so nothing half-runs. dor split keeps its best-effort typing into any shell. - restartSurfaceInPlace guards on isPaneOscDriven so Ctrl+C never reaches a non-integration shell. - The sidecar control-server timeout (10s) was preempting the CLI's 20s/60s budgets and is raised to 65s so the CLI deadline always governs. - The earlier soft stderr "warning" plumbing is removed in favor of the hard error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`code --install-extension` installs by renaming the extension folder; on Windows a running VS Code keeps the old Dormouse extension's node-pty native modules loaded and locks that folder, so the rename fails with a cryptic EPERM retry stack. Capture the install output and, on that lock signature, print a plain "quit all VS Code windows and re-run" banner and leave the built .vsix in place for a retry. Other failures still surface non-zero. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dormouse-bot
approved these changes
Jun 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
--restartflag todor ensure. When a surface is already running the target command,--restartinterrupts it (Ctrl+C), waits for the shell to return to its prompt, re-runs the command in place, and blocks until it's live again. If no surface matches, it behaves like a plainensureand creates one.--restartdrives the live PTY directly, so it works for minimized doors too (their PTY keeps running). A restarted surface keeps its minimized/visible state.currentCommandclears on prompt, then reports the command live again) rather than guessing at timings.restartedstatus surfaces in text and JSON output, with help text and snapshots updated.Test plan
dor/test/cli-output.test.mjscovers--restartplumbing (sendsrestart: true, rendersrestarted surface:3).tsc --noEmitpasses inlib.🤖 Generated with Claude Code