Skip to content

(MOT-4407) feat(console): open coder file rows in the shell explorer first - #792

Closed
rohitg00 wants to merge 2 commits into
mainfrom
feat/console-open-in-shell
Closed

rohitg00 wants to merge 2 commits into
mainfrom
feat/console-open-in-shell

Conversation

@rohitg00

Copy link
Copy Markdown
Contributor

The open-in menu on coder file-change chat rows now leads with the console's own surface: open in shell sits first, external editors (cursor / vs code / zed) and copy path keep their places below.

Refs MOT-4407.

How it opens

"open in shell" navigates to #/ext/shell/open/<encoded-abs-path>[:line]. The shell explorer page consumes the segment (companion change in #791): it strips the request from the URL, opens the file pinned when it lives under the browsed root, and re-roots the explorer to the file's own folder when it doesn't.

No presence probe needed: the shell worker serves both the coder::* functions that produce these rows and the #/ext/shell page — when the menu is visible, the route resolves.

Verification

  • tsc clean, biome clean, coder component tests green (122), full suite: 1076 tests pass; the 8 collection-failing files (@pierre/diffs reading navigator.userAgent at import under the node test env) fail identically on clean main — pre-existing, untouched by this change.
  • vite build clean.

The open-in menu on coder file-change rows leads with the console's own surface: 'open in shell' navigates to #/ext/shell/open/<encoded-path>[:line], which the shell explorer page consumes (re-rooting to the file's folder when it lives outside the browsed one). The shell worker serves both the coder::* functions that produce these rows and that page, so the route always resolves when the menu is visible. External editors and copy path keep their places below. Refs MOT-4407.
@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview Aug 13, 2026 12:35pm
workers-tech-spec Ready Ready Preview Aug 13, 2026 12:35pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 59 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

@rohitg00 rohitg00 changed the title feat(console): open coder file rows in the shell explorer first (MOT-4407) feat(console): open coder file rows in the shell explorer first Aug 13, 2026
rohitg00 added a commit that referenced this pull request Aug 13, 2026
The explorer handles #/ext/shell/open/<encoded-abs>[:line] — the chat's open-in menu (console #792) navigates here. The request is captured and stripped from the URL immediately, then applied once the root has resolved: the file opens pinned when it lives under the browsed root, and the explorer re-roots to the file's own folder when it doesn't (the effect refires on the new root and opens it there). Refs MOT-4407.
@rohitg00
rohitg00 marked this pull request as ready for review August 13, 2026 12:26
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@rohitg00, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a14d8f78-8f6f-49b6-8f2d-8c66746ad67e

📥 Commits

Reviewing files that changed from the base of the PR and between 31ac7d7 and acc5eb1.

📒 Files selected for processing (1)
  • console/web/src/components/chat/coder/OpenInEditorButton.tsx

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The menu leads with open-in-shell and ends with copy path — 'open in editor' undersold it; the trigger now reads 'open file'.
@rohitg00 rohitg00 closed this Aug 13, 2026
rohitg00 added a commit that referenced this pull request Aug 13, 2026
…native diff surface (#791)

* feat(shell): stream workspace changes into the explorer

The explorer page subscribes to the editor worker's editor::changed push channel (it observes every filesystem-touching harness call through the post-trigger hook): agent writes refresh the tree and git views live, and the active file reloads in place when the agent wrote it, with a dirty buffer always keeping the user's edits. Events coalesce in a short window; the page degrades to load-once behavior when the editor worker is absent. Refs MOT-4407.

* feat(shell): system-level workspace watch behind shell::changed

Reworked per review direction: instead of observing harness calls, the worker owns a real OS directory watch (FSEvents/inotify via notify). A surface binds the shell::changed trigger type with config: { path } and the worker starts one recursive watcher per binding, coalesces the raw event storm per path, filters .git internals, and fans out {path, kind, root} — so agent calls, shell::exec side effects, and edits made entirely outside the engine all stream. No harness coupling, no other-worker dependency. The explorer binds its browsed root per tab (re-binding on root change), refreshes tree and git live, reloads a clean active buffer when its file changes on disk, and follows the last visible write into a preview tab, with hidden and system paths never stealing focus. Refs MOT-4407.

* feat(shell): live follow opens as a diff, deep noise filter

The live follow now shows the change the way the editor feed did — through the console's shared FileDiff renderer: git baseline when the root is a repo, empty baseline for created files, and the last content this page saw for modified files outside a repo (DiffPane grows an optional baseline override). The file still opens as the preview tab underneath, and an open diff tracks further writes to its file live. The follow filter also got depth-aware: noise directories (target, node_modules, dist, build, Library, ...) are rejected at any path depth, not just the first segment, and build-artifact extensions (.o, .rlib, .lock, .log, ...) never steal the view — a cargo build under a nested worktree was follow-opening object files. Refs MOT-4407.

* fix(shell): created files reach the live diff as creations

macOS reports a create and the write that fills it as separate events; latest-kind-wins coalescing collapsed that to modified, so a brand-new file outside a repo arrived with no baseline and the live view fell back to dumping raw content instead of the all-added diff. Kinds now merge toward the visible outcome within a window (create+modify stays created, deletion supersedes, create-after-delete is a creation), and the page keeps its own guard: a followed file absent from the previous tree render is treated as created even when the OS kind says otherwise. Refs MOT-4407.

* fix(shell): temp artifacts never steal the live follow

Session scratch files (.output, .tmp, .swp, .part, .pid, .sock) join the follow exclusion list — watching a shared directory like /private/tmp streams every process's temp churn, and those writes belong in the tree refresh, not the preview. Refs MOT-4407.

* docs(shell): document the shell::changed trigger type

README gains a Live change feed section — binding config, payload vocabulary, coalescing semantics, and what the explorer page does with the events — and the agent skill documents the trigger type alongside the function surfaces. Refs MOT-4407.

* feat(shell): review feed, lazy deep folders, nested-repo diffs, noise-free watch

Four explorer gaps from live use on a home-sized root. The watcher no longer reports reads or bare metadata touches as modifications (notify Access and Modify::Metadata events are dropped at the fold) — a cat or chmod is not a workspace change, and content writes carry their own Data events. A new changes side tab keeps the last 200 visible events (kind glyph, tail-ellipsized path, age) so a fast burst stays reviewable after the auto-follow has moved on; clicking a row reopens that file's diff. Folders the budgeted tree snapshot never reached now fetch their listing on expand and splice it into the rendered tree, with fetched-and-empty markers preventing refetch loops and live changes under a fetched subtree dropping it for refresh. And diffs now find a file's OWN repository when the browsed root sits above it — git -C from the file's directory auto-discovers upward — so a worktree under the home directory shows real baselines instead of 'not a git repository'; the git tab message explains its root scope. Refs MOT-4407.

* feat(shell): line-count chips and totals in the changes feed

Each feed row now carries the +N/−M of its change and the header sums the session — git diff HEAD --numstat probed from the file's own directory (nested repos included), untracked files counted whole, non-repo files measured against the page's last-seen content with a prefix/suffix line delta (chip-grade arithmetic, exact for contiguous edits). Stats fill in asynchronously and are bounded per burst; a row without a chip still opens its diff. Refs MOT-4407.

* feat(shell): burst-grouped changes feed

The feed now keeps each coalesced burst as one group with its own file count, +N/−M totals, and age — an agent turn that edits four files reads as one reviewable unit, and the same file edited across bursts keeps its history instead of collapsing to a single row. Oldest groups fall off whole past 300 rows. Refs MOT-4407.

* feat(shell): own diff renderer with folds, syntax color, and dir-aware events

The diff pane is now shell's own renderer instead of the console's shared component: a Myers line diff with unmodified context folded behind expandable 'N unmodified lines' rows, dual line-number gutters, lightweight per-line syntax coloring (strings, comments, numbers, keywords per family), intraline change emphasis on replaced line pairs, and +N/−M totals in the header. shell::changed events gain a dir flag — a burst's last event was sometimes the directory creation itself, and following it into coder::read-file returned C210 raw into the pane; directories now refresh the tree but never open, and never enter the feed. The page also stops chasing its own tail: config/shell-ui.yaml (its persisted UI state) is excluded from follow — every tab change writes it, so the live view kept replacing real diffs with a -0 +0 of its own state file. splitLines treats a trailing newline as a terminator, matching git's line counts. Verified live headless: created files render all-added with syntax color and counts, the active buffer follows disk writes, and the state-file loop is gone. Refs MOT-4407.

* fix(shell): own atomic-write temps never stream

coder::update-file and the fs backend write through sibling temp files (.coder-tmp-, .iii-tmp-, .tmp.<uuid>) that exist for a moment between write and rename — the watcher reported them, the live view followed one, and the read raced the rename into a raw C211 in the pane. They're this worker's own write machinery, not workspace changes, and the rename lands as an event on the real path regardless; the fold now drops them (suffix-shape matched, so a user's notes.tmp.md still streams). The diff pane also says 'file no longer exists on disk' instead of echoing a raw handler error when a followed file vanishes between event and read. Verified against the live coder::create-file path: only the final file delivers. Refs MOT-4407.

* feat(shell): diff pane matches the reference rendering

Studied the reference TUI's diff renderer source directly and ported its remaining decisions: one gutter (the new line number for additions and context, the old one for deletions — the sign column disambiguates), a verb-led header (Edited path (+A −R)), deleted-side syntax dimmed under its tint, and a row-count guard that drops per-line tokenizing on huge diffs so the pane stays instant. Verified live headless against a nested repo under a non-repo browsed root: folds above and below the hunk, intraline emphasis on the changed span, syntax coloring both sides. Refs MOT-4407.

* feat(shell): consume the open-in-shell deep link

The explorer handles #/ext/shell/open/<encoded-abs>[:line] — the chat's open-in menu (console #792) navigates here. The request is captured and stripped from the URL immediately, then applied once the root has resolved: the file opens pinned when it lives under the browsed root, and the explorer re-roots to the file's own folder when it doesn't (the effect refires on the new root and opens it there). Refs MOT-4407.

* fix(shell): jailed watch paths, unstallable fan-out, bounded diffs

Addresses the review findings. The watch path now goes through the coder surface's PathResolver (jail containment, operator denylist, canonicalization, hot-reload aware) — watching a tree is a read of every filename under it, so a path you can't read is a path you can't watch; README documents the policy and a test pins the jail. Deliveries ride their own tasks so one hung send can't stop the pump from draining the channel and silently dropping events. The Myers backtrack gets an edit-distance budget (memory is O(D*(N+M)) from the per-step frontier snapshots) with the coarse-replace fallback, plus a regression test. Also: poisoned-mutex recovery instead of silently skipping registration bookkeeping, literal git pathspecs for filenames containing glob metacharacters, a guarded decodeURIComponent in the deep-link capture, the feed surviving a hidden-filter toggle (root changes still clear it), inaccessible lazy folders recorded as fetched-and-empty instead of refetching every burst, malformed events without a root dropped at the guard, image previews no longer overwritten by text reloads, pointer-cancel handling on the sidebar resize handle, a preview-sized ceiling on the base64 image read, and bidi-safe tail ellipsis on feed paths. Refs MOT-4407.

* (MOT-4407) feat(shell): polish live explorer review UI

* (MOT-4407) feat(shell): add Codex-style workspace review

* (MOT-4407) feat(shell): edit worktree diffs safely

* (MOT-4407) docs(shell): add post-merge live review screenshot

* (MOT-4407) fix(shell): keep explorer synced to chat root

* (MOT-4407) fix(shell): retain exact working directory roots

* (MOT-4407) fix(shell): avoid replaying collapse all
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