git:20260716.e9dedf8 to git:20260722.5fdcc9f
1 added, 1 removed. Audit A to A.
# DOX — packages/client/src/components/editor-pane
Files in this directory. One row per source file.
| File | Purpose |
|------|---------|
| `BinaryWarn.tsx` | Binary-file tab. Shows a "binary file" notice (path only). No content fetched. Native-editor buttons / `fetchEditors` removed. See change: add-internal-monaco-editor-pane, remove-external-editor-integration. |
| `ChangesRailSection.tsx` | Collapsible Changes section atop the editor-pane project-tree rail. Lists changed files (per-file `+adds −dels`); opens per-file diff as a `diff:` viewer tab. Reads shared `SessionDiffContext`. See change: add-change-summary-table. Threads `diff.data.otherChanges` into `DiffFileTree`; renders when either `files` or `otherChanges` non-empty. See change: detect-tool-created-files. |
| `ChangedOnDiskBanner.tsx` | Per-tab changed-on-disk banner. Refresh re-fetches; Dismiss keeps stale view. No auto-reload. See change: split-editor-workspace. |
| `ChangesRailSection.tsx` | Slim summary bar atop the rail: `Changes (N) · +X −Y`, `summed` badge (non-git), `this session only` toggle. Props `{sessionOnly, onSessionOnlyChange}` (rail-local, owned by `EditorPane`, D3 — not context; lifting breaks `FileDiffView` takeover). No per-file list / `DiffFileTree`. Reads `SessionDiffContext`; null when no `files`+`otherChanges`. See change: add-change-summary-table, detect-tool-created-files, collapse-diff-file-tree. |
| `DiffViewer.tsx` | `diff` viewer tab. Strips `diff:` prefix from virtual path, reads file `gitDiff` from `SessionDiffContext`, delegates render to `DiffPanel`. See change: add-change-summary-table. |
| `EditorFileTree.tsx` | Lazy file-tree rail rooted at session cwd. Expands one level per click. Lists `{name,isDir}` from single `GET /api/file/tree` (hidden included) — replaces the `/api/file`+`/api/browse` merge that mislabelled `.git`/`.pi` as files (#1). File rows show per-kind icon via `fileIcon()`. Clicking file calls `onOpenFile(rel, viewer)` via shared `fileKind`. `treeOpenRoots` persisted. Each row (file+dir) gains hover-revealed `RowCopyAffordance` copy glyph → anchored popup: Copy full path (`absOf`), relative (`rel`), file name (basename); guarded `navigator.clipboard?.writeText`, ✓ ~1.5s, flips above near rail bottom (`data-file-rail`); dismiss on outside-click/rail-scroll/Escape (Escape refocuses glyph); glyph `stopPropagation` — no open/toggle. Consumes `useOptionalSessionDiff()` (`buildDiffIndex`): changed `FileRow` shows per-kind icon + status `●`/`+` (`statusIndicator`; edit/tool/mixed→●), `CountBadges`, hover `diff` chip (`onOpenDiff`→`diff:` tab), >1-event `✏️/📝` expander; changed-descendant dirs show `folder-dot` (path-prefix, no fetch); NO auto-expand. `OtherChangesGroup` (muted, `<button>` rows) renders `otherChanges` at rail bottom unless `sessionOnly`. Null diff → plain tree. See change: add-internal-monaco-editor-pane, improve-content-editor, copy-file-path, collapse-diff-file-tree. |
| `EditorPane.tsx` | Editor pane shell. Composes `EditorTabs` + collapsible `EditorFileTree` + active viewer (`viewerRegistry`) + keep-alive `TerminalPaneLayer` (mounted in the body region beside the file viewer). Header adds `+ Terminal` (`data-testid=new-terminal-launch`)→`terminal.createTerminal()`; closing a `term:` tab routes to `terminal.closeTerminalTab` (kills PTY, D4); passes `terminalTitle` resolver to `EditorTabs`. See change: terminals-in-tabbed-panes. Replaces ChatView in content area, mirrors FileDiffView. Read-only v1. Header: back, tree-toggle, refresh. Footer: viewer kind, language, path. State via `useEditorPaneState(sessionId)`. See change: add-internal-monaco-editor-pane. Now controlled by `SplitWorkspaceContext`. Adds inner rail divider, search panel, changed-on-disk banner, unsplit button, Cmd-P/Cmd-Shift-F. See change: split-editor-workspace. Rail is a vertical stack: `ChangesRailSection` above the project tree. See change: add-change-summary-table. Rail toggle now a labelled "Files" control (aria-pressed, `data-testid=tree-toggle`), visibility persisted via `useTreeVisible(sessionId)` (#6). Header `mdiWeb` launcher (`data-testid=live-preview-launch`) opens a `live-server` tab. See change: improve-content-editor. |
| `EditorSearchPanel.tsx` | Dual-mode search. Filenames=bridge walk, Contents=`GET /api/grep`. Regexp toggle, min-3-char + debounce, keyboard nav ↑↓/↵/Esc. Injected search fns. See change: split-editor-workspace. |
| `EditorTabs.tsx` | Horizontal tab strip. Click activate, `×`/middle-click/Ctrl+Cmd-W close, drag reorder. Per-kind icon via `fileIcon()` + label = basename, tooltip = rel path. Tags `diff` tab kind. `terminal` tabs (`term:<id>`) render a console icon + `terminalTitle(id)` label (shell/title) via optional `terminalTitle` prop. See change: add-internal-monaco-editor-pane. See change: improve-content-editor. See change: add-change-summary-table. See change: terminals-in-tabbed-panes. |
| `MarkdownEditor.tsx` | Controlled editable Monaco buffer. Props `{value,onChange,readOnly}`. language=markdown, wordWrap on, minimap off. Lazy-mounts behind Suspense in InstructionsPage. Theme via shared `useThemeContext()` (recolors live on theme switch). See change: directory-settings-page-and-scoped-md-editing. See change: improve-content-editor. |
| `LiveServerViewer.tsx` | Live-server-preview tab (viewer kind `live-server`). Allowlist picker (`GET /api/live-server/list`) + confirmed URL entry → `startLiveServer` (client+server loopback SSRF check) → iframe proxied `/live/<id>/` on MAIN origin with `sandbox="allow-scripts allow-forms allow-popups"` (NO `allow-same-origin` — opaque origin D7). Remote hosts refused. Preset `ViewerProps.path` of form `live:<loopback-url>` auto-launches on mount (skips picker) and preserves the URL's `pathname+search` into the iframe `src` (deep link); `live:preview`/empty → picker. See change: improve-content-editor; open-loopback-links-in-split-viewer. |
| `MermaidViewer.tsx` | Mermaid tab. Fetches `.mmd`/`.mermaid` source via `/api/file/raw`, renders through shared `MermaidBlock` (theme-aware, zoom/pan). Loading/error states. See change: improve-content-editor. |
- | `MarkdownViewer.tsx` | Markdown tab, Preview (default) / Edit. Fetches content+mtime via `/api/file`. Preview→`MarkdownContent` (frontmatter=properties, `pi-asset:` via `SessionAssetsContext`). Edit (gated on `fileKind.editable` `.md`/`.mdx`)→controlled `MarkdownEditor`; Save→`POST /api/file/write` w/ loaded mtime, 200 clears dirty, 409→`ChangedOnDiskBanner`. See change: add-internal-monaco-editor-pane. See change: improve-content-editor. |
+ | `MarkdownViewer.tsx` | Markdown tab, Preview (default) / Edit. Fetches content+mtime via `/api/file`. Preview→`MarkdownContent` (frontmatter=properties, `pi-asset:` via `SessionAssetsContext`). Preview passes `imageBase={{cwd, dir: absOf(cwd, dirname(path))}}` so local images resolve. Edit (gated on `fileKind.editable` `.md`/`.mdx`)→controlled `MarkdownEditor`; Save→`POST /api/file/write` w/ loaded mtime, 200 clears dirty, 409→`ChangedOnDiskBanner`. See change: add-internal-monaco-editor-pane. See change: improve-content-editor. See change: fix-markdown-preview-relative-images. |
| `monaco-setup.ts` | Shared Monaco bootstrap. Worker `?worker` imports + MonacoEnvironment + loader.config. Side-effect import by MonacoBuffer + MarkdownEditor. See change: directory-settings-page-and-scoped-md-editing. |
| `MonacoBuffer.tsx` | Heavy lazy Monaco chunk. Imports `monaco-editor` + `@monaco-editor/react`. Bundles editor/json/css/html workers via `?worker`; ts.worker omitted (read-only, no LSP); ts/js diagnostics disabled. Read-only. Theme via `buildMonacoTheme`, recolors on theme/mode change. Fetches content via `/api/file`. Scrolls to line. Theme via shared `useThemeContext()` (recolors live on theme switch). See change: add-internal-monaco-editor-pane. Worker bootstrap moved to monaco-setup.ts. See change: directory-settings-page-and-scoped-md-editing. See change: improve-content-editor. |
| `TerminalPaneLayer.tsx` | Keep-alive terminal layer. Mounts one `TerminalView` per open `term:<id>` tab, visibility toggled by the active tab — switching to a file tab and back does NOT tear down + reconnect the xterm WS (single-mount-per-id contract, avoids fix-terminal-half-height-dual-mount). Fills the file-viewer body region; hidden when a file tab active. Reads `paneState`+`terminal` from `useSplitWorkspace`. Exports `TerminalPaneLayer`. See change: terminals-in-tabbed-panes. |
| `types.ts` | `ViewerProps` contract `{ cwd, path, kind, mimeType, size, line? }`. Shared by all viewers. See change: add-internal-monaco-editor-pane. |
| `viewer-registry.tsx` | `viewerRegistry` maps `ViewerKind`→component. monaco=`React.lazy(MonacoBuffer)` boundary. Rich kinds delegate to shared `preview/*` (thin `ViewerProps`→`{target}` adapters): pdf→`PdfPreview` (pdfjs, replaces broken `<object>`), html→`HtmlPreview` (sandboxed, no scripts), video→`VideoPreview`, image→`ImagePreview` variant=full (pan/zoom), audio→`AudioPreview`, mermaid→`MermaidViewer`, live-server→`LiveServerViewer`. markdown/binary-warn eager. `line` reaches Monaco only. Registers `diff`→`DiffViewer`. `terminal`→no-op placeholder (real xterm mount is the keep-alive `TerminalPaneLayer`, single mount per id). See change: add-internal-monaco-editor-pane. See change: improve-content-editor. See change: add-change-summary-table. See change: terminals-in-tabbed-panes. |