Keep the textarea width independent from the prompt controls so wrapping matches the visible layout. Split secondary controls from the primary stop/send rail to preserve the original action column width and add a matching divider.
# Git Changes PR Review Context
Fixes: #310
## Purpose of this document
This document is intended to give a PR reviewer or gatekeeper enough
neutral context to review the Git Changes feature series accurately.
## BEFORE/AFTER SNAPSHOT:
<img width="835" height="1163" alt="image"
src="https://github.com/user-attachments/assets/463d6f8c-1a6b-4cf0-8ab8-44a92c534ca5"
/>
It distinguishes:
1. the intended scope of the work
2. implementation choices that were deliberate
3. behaviors that were explicitly tested and accepted during development
4. remaining follow-up areas that were not part of the required intent
It should not be treated as a request to approve the PR automatically.
It exists to reduce false-positive review findings caused by missing
context.
---
## High-level scope
The work in this series refactors and extends the existing `Git Changes`
tab in the right panel.
The intended feature scope includes:
1. grouped staged / unstaged change presentation
2. correct section-aware diff loading
3. per-file stage / unstage controls
4. commit message compose box and commit action for staged changes
5. prompt-context insertion from the Git diff viewer
6. auto-refresh behavior that reduces dependence on the manual refresh
button
This work is intentionally implemented inside the existing Git Changes
vertical slice rather than as a new SCM subsystem.
---
## Files and areas intentionally changed
### Server / API surface
The following server areas were intentionally extended:
1. `packages/server/src/api-types.ts`
2. `packages/server/src/events/bus.ts`
3. `packages/server/src/server/http-server.ts`
4. `packages/server/src/server/routes/workspaces.ts`
5. `packages/server/src/workspaces/git-status.ts`
6. `packages/server/src/workspaces/git-mutations.ts`
7. `packages/server/src/workspaces/worktree-directory.ts`
8. `packages/server/src/workspaces/instance-events.ts`
### UI surface
The following UI areas were intentionally extended:
1. `packages/ui/src/components/file-viewer/monaco-diff-viewer.tsx`
2. `packages/ui/src/components/instance/instance-shell2.tsx`
3.
`packages/ui/src/components/instance/shell/right-panel/RightPanel.tsx`
4.
`packages/ui/src/components/instance/shell/right-panel/git-changes-model.ts`
5.
`packages/ui/src/components/instance/shell/right-panel/tabs/GitChangesTab.tsx`
6. `packages/ui/src/components/instance/shell/right-panel/types.ts`
7. `packages/ui/src/components/instance/shell/storage.ts`
8. `packages/ui/src/components/prompt-input.tsx`
9. `packages/ui/src/components/prompt-input/types.ts`
10. `packages/ui/src/components/session/session-view.tsx`
11. `packages/ui/src/lib/api-client.ts`
12. `packages/ui/src/lib/i18n/messages/*/instance.ts`
13. `packages/ui/src/styles/panels/right-panel.css`
---
## Intentional product and architecture decisions
The following outcomes were deliberate and should not be flagged as
issues merely because they exist.
### Git status / diff architecture
1. The UI does not rely only on the proxied OpenCode `file.status()`
payload.
2. CodeNomad adds server-backed worktree Git status and diff endpoints
to expose staged / unstaged semantics correctly.
3. Server-backed worktree mutation endpoints were added for:
- stage
- unstage
- commit
4. The existing event bus / SSE channel is reused for Git invalidation,
instead of adding a bespoke invalidation route.
### Git Changes UI structure
1. The file list is grouped into:
- `Staged Changes`
- `Changes`
2. Both sections are collapsible.
3. Section open state is persisted.
4. The same file may appear in both sections when Git state genuinely
requires that.
5. Rows are filename-first, with parent path as secondary text.
6. Rows are intentionally compact compared to the original flat list.
### Diff behavior
1. Diff loading is section-aware.
2. Deleted files are supported in grouped mode.
3. Binary files are treated as non-line-oriented in the diff viewer.
4. Binary diffs suppress line-based prompt-context affordances.
### Stage / unstage / commit workflow
1. Stage and unstage are per-file row actions.
2. Bulk stage-all / unstage-all was intentionally not added.
3. The commit compose box is intentionally rendered inside the `Staged
Changes` section.
4. The commit button is intentionally overlaid inside the commit input
area.
5. The current commit compose flow is minimal by design:
- no push
- no amend flow
- no branch management
### Prompt-context insertion
1. Prompt insertion is intentionally an HTML comment marker, not a full
diff payload.
2. The expected inserted form is:
`<!-- Git change context: <path> lines X-Y -->`
3. The trigger UI is intentionally a seam/gutter action in the Monaco
diff viewer, not a toolbar button.
### Row action reveal behavior
1. Stage / unstage row actions are intentionally hover-revealed on
hover-capable layouts.
2. The row action reveal intentionally uses:
- delayed hide
- slight stats fade/shift
- compact idle width
3. On non-hover layouts, the action remains visible for reliability.
### Auto-refresh behavior
The accepted refresh model is intentionally hybrid:
1. refresh on Git Changes tab activation
2. 20-second polling only while the Git Changes tab is active
3. immediate invalidation from completed raw tool events for:
- `write`
- `edit`
- `apply_patch`
This hybrid model is intentional. Polling remains as a fallback even
after tool-event invalidation.
---
## Behaviors explicitly tested during development
The following behaviors were explicitly exercised during development and
used to guide fixes.
### Grouped staged / unstaged behavior
1. files appear in the correct staged / unstaged sections
2. section collapse / expand works
3. collapse state persists
4. line counts are section-specific
### Diff behavior
1. staged diff loads differently from unstaged diff
2. deleted-file handling was verified and corrected
3. binary-file rendering was corrected to avoid line-oriented behavior
4. untracked binary files no longer report fake text line counts
### Mutation behavior
1. per-file stage works from `Changes`
2. per-file unstage works from `Staged Changes`
3. stage / unstage selection remapping was exercised and corrected
4. unborn-repo unstage behavior was explicitly hardened
### Prompt-context behavior
1. selected line / range insertion was tested
2. button placement in the Monaco seam/gutter was iterated and verified
### Auto-refresh behavior
1. tab-activation refresh was tested
2. 20-second active-tab polling was tested
3. raw completed tool invalidation was tested in the running UI for:
- `write`
- `edit`
- `apply_patch`
4. stale async overwrite and stale selection restoration bugs were found
and fixed through review/testing
---
## Review findings that were investigated and are no longer intended
blocker topics
The following areas were previously raised by strict reviews and then
either fixed or determined to be acceptable within scope.
### Fixed in the current series
1. duplicate stage / unstage firing
2. stale diff response overwriting newer selection
3. passive refresh restoring a stale selection
4. instance-wide invalidation overreach
5. selected diff staying stale after tool invalidation
6. worktree-switch status races
7. unhandled rejection risk from async invalidation publication
8. queued invalidation intent being lost during in-flight refresh
9. `git-diff` path traversal / absolute path boundary issue
### Investigated and considered non-blocking within current intent
1. split add/delete presentation for tracked rename behavior
- this was compared against VS Code behavior during manual testing
- no stage/unstage corruption was observed in the tested flow
- this is currently treated as a representation tradeoff, not a proven
blocker
---
## Remaining non-blocker follow-up areas
The following are still reasonable follow-up topics, but they were not
part of the required blocker-fix scope.
1. normalize directory-to-worktree matching more aggressively on Windows
so tool invalidation works more reliably from nested directories or
path-format variations
2. improve keyboard discoverability of hover-revealed stage / unstage
actions
3. reserve textarea space for the overlaid commit button if the overlay
tradeoff is reconsidered
4. reduce size/complexity in:
- `RightPanel.tsx`
- `right-panel.css`
5. tighten raw SSE tool-event parsing into a more explicit helper if
that event bridge grows further
These follow-ups should not be interpreted as evidence that the core
implementation is incomplete unless a reviewer finds a new concrete
failure.
---
## Suggested review focus
If a gatekeeper or reviewer is evaluating this PR, the most useful focus
areas are:
1. whether staged / unstaged behavior is correct for normal Git
workflows
2. whether the new server worktree Git endpoints remain narrowly scoped
3. whether auto-refresh remains bounded to the active Git Changes
context
4. whether the explicit fixes for stale async behavior and invalidation
races are sufficient
5. whether any unintentional server boundary broadening or state
corruption remains
Less useful review topics, unless tied to a concrete failure, are:
1. preference disagreements with accepted prompt insertion format
2. preference disagreements with the overlaid commit button placement
3. preference disagreements with keeping polling fallback alongside tool
invalidation
4. objections to server-backed Git endpoints purely because they add
surface area
---
## Summary
This series intentionally evolves the existing Git Changes tab into a
more complete source-control workflow for:
1. grouped staged / unstaged inspection
2. section-aware diffs
3. per-file staging and unstaging
4. commit composition for staged changes
5. prompt-context insertion from Git diffs
6. bounded auto-refresh for both passive viewing and agent-driven file
mutations
The intended review standard is to find concrete correctness, layering,
or maintenance problems that remain after this series — not to re-argue
the already accepted product choices listed above.
---------
Co-authored-by: Shantur Rathore <i@shantur.com>
## Summary
- preserve the current prompt text when dismissing the `@` mention/file
picker with `Esc`
- let `Enter` fall back to normal prompt submission when the mention
picker is open but there is no selectable result
## Verification
- source inspection of the prompt input and picker flow
- local `npm run typecheck --workspace @codenomad/ui` is blocked in this
environment because workspace dependencies are not installed
--
Yours,
[CodeNomadBot](https://github.com/NeuralNomadsAI/CodeNomad)
Co-authored-by: Shantur Rathore <i@shantur.com>
## Summary
- add server-backed speech capabilities and transcription endpoints plus
UI settings for speech configuration
- add push-to-talk prompt voice input with microphone controls,
transcription insertion, and browser capability gating
- keep prompt controls aligned by restoring right-side nav placement and
moving the mic beside the expand control
## Summary
- split the right panel, picker, and tool call secondary viewers into
smaller deferred chunks
- release hidden right-panel file buffers and stop tracking static
tool-call scrollers when they are not needed
- keep this branch focused on the remaining secondary viewer chunking
work now that the Monaco-specific chunking moved into PR 215
## Testing
- npm run build --workspace @codenomad/ui
## What and why
CodeNomad had no RTL (right-to-left) support, so users writing in Hebrew
or Arabic would see their messages displayed left-to-right — misaligned
text, broken reading flow, wrong punctuation placement.
This PR adds automatic direction detection to all elements that display
user or model text. The browser detects direction from the first strong
character in each text block: Hebrew/Arabic → RTL, Latin/code → LTR. No
configuration needed — it just works per message, per paragraph.
## Technical notes
The natural fix is `dir="auto"` on the containing elements. However,
Chromium does not propagate direction detection from a parent `<div>`
into its `<p>` children — so Hebrew inside `<p>` rendered via
`innerHTML` (as markdown is) was still detected as LTR. The fix is to
apply `unicode-bidi: plaintext` via CSS directly on the block-level
elements (`p`, `li`, headings, etc.), which has the same auto-detection
semantics but applies per element.
## Summary
- Add `dir="auto"` to all elements containing user-generated or
model-generated text (message content, prompt input, session names, tool
outputs) so the browser auto-detects text direction
- Add `unicode-bidi: plaintext` via CSS to markdown block elements (`p`,
`li`, headings, `blockquote`, `td`/`th`) to fix per-paragraph RTL
detection in Chromium (where `dir="auto"` on a parent div does not
recurse into block children)
- Convert physical CSS properties to logical equivalents in
`markdown.css`: `border-left` → `border-inline-start`, `padding-left` →
`padding-inline-start`, `text-align: left` → `text-align: start`,
`margin-left` → `margin-inline-start`
## Affected components
- `markdown.tsx` — main markdown renderer
- `message-part.tsx` — text part wrapper and plain-text fallback
- `message-item.tsx` — message body and error blocks
- `prompt-input.tsx` — user input textarea
- `session-list.tsx` — session titles in sidebar
- `session-rename-dialog.tsx` — session rename input
- `instance-welcome-view.tsx` — Resume Session dialog
- `tool-call/markdown-render.tsx` — tool output markdown fallback
- `tool-call/ansi-render.tsx` — ANSI output
- `tool-call/diagnostics-section.tsx` — diagnostic messages
## Test plan
- [ ] Send a Hebrew-only message → text right-aligned
- [ ] Send a mixed Hebrew + English message → correct per-paragraph
direction
- [ ] Message containing a code block → code stays LTR
- [ ] Type Hebrew in the prompt textarea → input flows right-to-left
- [ ] Hebrew session name in sidebar → right-aligned
- [ ] Hebrew session name in Resume Session dialog → right-aligned
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## What
Fix slash command execution so `[pasted #N]` placeholders are resolved
before calling `session.command`, matching normal prompt send behavior.
## Why
When pasting long text into a slash command (e.g. `/some-command [pasted
#1]`), the UI previously bypassed `resolvePastedPlaceholders(...)` for
known slash commands and sent the literal placeholder text as command
arguments.
## Changes
- Resolve pasted placeholders (and other prompt placeholders handled by
`resolvePastedPlaceholders`) in slash-command arguments before
`executeCustomCommand(...)`.
- Remove *consumed* pasted-text attachments (those referenced by
placeholders in the slash-command args) so they don’t linger for the
next prompt.
Fixes#234.
## Notes
- I attempted `npm run typecheck --workspace @codenomad/ui` locally but
the workspace dependencies aren’t installed in this bot environment, so
it fails with missing-module errors. CI should validate with a full
install.
--
Yours,
[CodeNomadBot](https://github.com/NeuralNomadsAI/CodeNomad)
Co-authored-by: Shantur Rathore <i@shantur.com>
Stop resetting history navigation on input so editing recalled entries doesn't wipe the bottom draft. Allow ArrowDown navigation while in history and persist the session draft only for fresh prompts.
Extract prompt draft/history, attachments, picker, and keydown logic into co-located hooks. Introduce PromptInputApi for quote/expand/setText and migrate SessionView off DOM poking; remove legacy registerQuoteHandler.
Converts hardcoded UI copy to i18n keys across the app, adds global translation for non-component modules, and splits the English catalog into feature modules with duplicate-key detection.
- Remove isMobileWidth signal and updateMobileWidth resize listener
- Use same placeholder text for all devices/platforms
- "Type your message, @file, @agent, or paste images and text..."
Simplifies implementation per dev feedback - one approach for all
- Remove 3-state logic (normal/50%/80%) - now only normal/expanded
- Remove double-click detection and tooltips for simplicity
- Remove platform-specific behavior (same UX for Electron and web)
- Optimize button layout: reduce from 36px to 28px to fit 3 buttons
- Position expand button above history buttons in vertical stack
- Keep 15-line expanded height (360px, capped to available space)
Per upstream dev feedback to keep it simple with one approach
- Add platform detection (Electron vs Web) for expand behavior
- Electron: 3-state (normal → 50% → 80%) with double-click
- Web/Mobile: 2-state (normal → expanded) with instant single tap
- Implement fixed 15-line height for web/mobile (360px, capped)
- Add orientation-aware height calculation (landscape vs portrait)
- Remove tooltip on web/mobile, keep for Electron desktop
- Add responsive placeholder text to prevent overlap on mobile
- Desktop: "Type your message, @file, @agent, or paste images and text..."
- Mobile (≤640px): "Type message, @file, @agent..."
- Delete dev-docs/expand-chat-input.md per upstream feedback
Addresses PR feedback to simplify from 3-state to 2-state for web/mobile
while maintaining rich desktop experience in Electron app.
- Add expand button with Maximize2/Minimize2 icons
- Implement 3-state height management (normal/50%/80%)
- Smart double-click detection with 300ms delay
- Height calculation based on session-view - 200px message space
- Custom CSS tooltip with dark gradient background and backdrop blur
- Send button anchored at bottom via margin-top: auto
- Smooth CSS transitions throughout
- Double-click at 80% now reduces to 50% (not normal)
- Removed all debug console.log statements