- Track messageInfoVersion in cache signature to rebuild when tokens arrive via SSE
- Read tokens from step-finish part directly (embedded in SSE events)
- Simplify available tokens to show full context window when no explicit input limit
Session diffs now use a compact patch field instead of storing full
before/after content. Added parsePatchToBeforeAfter utility to extract
before/after from unified diff format, and updated MonacoDiffViewer to
accept patch prop as alternative to before/after strings.
Send synthetic session notifications when background processes finish, fail, stop, or terminate so the originating agent can react without polling. Hide synthetic text-only prompts from the UI stream so operational notifications stay out of the visible transcript.
## 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
- Wraps store-proxied array iteration in `untrack()` in two
`createEffect` blocks and one `createMemo` in `message-section.tsx` to
prevent SolidJS from creating O(n) per-element reactive subscriptions on
every run
- Replaces `ids.includes()` with `Set.has()` for O(1) cleanup lookups in
the part-count tracking effect
## Problem
Two `createEffect` blocks in `message-section.tsx` iterate the
`messageIds()` store proxy array inside a tracked reactive context. This
causes SolidJS to create **O(n) per-element subscriptions** on every
run. When any element changes, all n subscriptions fire, re-running the
entire effect — resulting in **O(n²) total work**.
Additionally, the cleanup loop in the part-count tracking effect uses
`ids.includes(trackedId)` which is O(n) per tracked ID, compounding to
O(n²).
For long-running sessions with large message history (e.g. 7569
messages), this caused **~4.8 seconds of input latency** when sending a
new prompt.
## Fix
1. **Timeline sync effect (~line 738):** Wrap entire body in
`untrack()`, replace `ids.slice()` with `[...ids]` to snapshot without
proxy tracking
2. **Part-count tracking effect (~line 891):** Wrap iteration in
`untrack()`, replace `ids.includes()` with `new Set(ids).has()` for O(1)
lookups
3. **`lastAssistantIndex` memo:** Read message records via `untrack()`
to avoid O(n) subscriptions on part-level updates
## Result
On a 7569-message session: prompt input latency reduced from **~4.8s to
~42ms** (114x improvement).
## Summary
- add SideCar support across the server and UI, including proxied tabs,
picker/settings flows, and websocket-aware proxying
- unify top-level tab handling so workspace instances and SideCars share
the same tab model and navigation flows
- limit SideCars to port-based services only, removing server-managed
process control from the final API and UI
---------
Co-authored-by: Shantur <shantur@Mac.home>
Co-authored-by: Shantur <shantur@Shanturs-MacBook-Pro-M5.local>
# PR Title
Implement shared compact split and unified tool-call diff layout
---
Fixes#268
# PR Description
## Summary
This PR makes tool-call diffs more compact in both `Unified` and `Split`
views by reducing wasted horizontal space in line-number gutters and
content indentation.
## What changed
- introduced a shared compact-diff framework for tool-call diffs
- kept mobile-specific policy limited to:
- forcing unified mode below the breakpoint
- enabling wrap only in mobile unified mode
- added mode-specific compact applicators in the diff viewer:
- unified applicator
- split applicator
- reduced gutter width waste by measuring rendered line-number text and
tightening column width around it
- removed unnecessary right-side content padding
- aligned `+` / `-` markers closer to the left edge across both views
- simplified cleanup after gatekeeper review by removing extra plumbing
and residue
## Screenshots
### Before
<img width="581" height="341" alt="image"
src="https://github.com/user-attachments/assets/ec47b256-749a-4afc-8879-aaf33f0b46b6"
/>
### After
<img width="470" height="586" alt="image"
src="https://github.com/user-attachments/assets/7258a5a2-47c4-408d-84bc-1b497761c7ad"
/>
## Architectural approach
This change intentionally uses:
- shared policy in
`packages/ui/src/components/tool-call/diff-render.tsx`
- shared helper/measurement logic in
`packages/ui/src/components/diff-viewer.tsx`
- mode-specific applicators where unified and split DOM differ
- CSS for shared visual spacing and alignment cleanup
The goal was to keep the implementation architecturally clean and avoid
building separate duplicated compact-diff features for:
- mobile vs desktop
- unified vs split
Instead, the feature shares one compact-diff concept and only diverges
where the upstream diff DOM requires separate handling.
## Files changed
- `packages/ui/src/components/tool-call/diff-render.tsx`
- `packages/ui/src/components/diff-viewer.tsx`
- `packages/ui/src/styles/messaging/tool-call.css`
- `packages/ui/src/types/message.ts`
## Validation
Manual validation was performed in the running UI.
Verified manually:
- compact unified gutters on mobile
- compact unified gutters on desktop
- compact split gutters on desktop
- tighter operator alignment in both modes
Also verified:
- `npm run typecheck` passes
## Notes
- This PR is intended to address the compact diff layout problem
described in the related issue.
- Diff-specific CSS still lives in `tool-call.css`; future extraction
into a smaller dedicated stylesheet is possible but not required for
this change.
---------
Co-authored-by: Shantur Rathore <i@shantur.com>
Closes#261
## Summary
- improve startup remote URL selection when the server binds to
`0.0.0.0`
- print additional reachable remote URLs instead of advertising only the
first external address
- add targeted tests for address ordering and advertisability behavior
## Problem
When CodeNomad was started with `--host 0.0.0.0`, the CLI chose the
first external IPv4 address it discovered and displayed only that one as
the remote URL.
On Windows machines with WSL, Hyper-V, Docker, or other virtual
adapters, that often surfaced a virtual `172.x.x.x` address even though
a more useful LAN address such as `192.168.x.x` was also reachable and
usable from other devices.
That made remote access look broken or confusing even though the server
itself was accessible.
## What changed
- reuse the resolved network-address list for both:
- primary remote URL selection
- startup logging of additional reachable URLs
- choose the primary remote URL from the **advertisable** external
addresses instead of any external address
- print `Other Accessible URLs` when multiple useful remote URLs are
available
- avoid hard-coding a preference like `192.168 > 10 > 172`
- suppress link-local `169.254.*` addresses from user-facing advertised
URLs
- add tests covering:
- stable ordering across RFC1918 address ranges
- link-local addresses being non-advertisable
- link-local-first discovery not stealing the primary LAN URL
## Why this approach
This keeps address derivation in the network-address resolver layer and
limits `index.ts` to startup wiring and presentation.
It also fixes the misleading terminal output without redesigning binding
behavior, TLS behavior, or the server API contract.
## Validation
- `npm run typecheck --workspace @neuralnomads/codenomad`
- `npx tsx --test
'.\\src\\server\\__tests__\\network-addresses.test.ts'`
## Notes
- this change is intentionally focused on selection and presentation of
reachable addresses
- it does not attempt a broader virtual-adapter classification policy
beyond suppressing clearly low-value link-local addresses in user-facing
output
---------
Co-authored-by: Shantur Rathore <i@shantur.com>
Preserve retry metadata from session.status events so the session list and header can show a live retry countdown with context. Notify users when a session enters retry and reuse the existing error styling so retrying feels actionable without losing the current badge layout.
Only cache markdown HTML after Shiki has the required fence languages loaded so virtualized assistant messages can re-render with syntax highlighting when remounted.
## Summary
- add a per-session Yolo mode toggle for permission prompts and persist
its state
- move the control into the Status tab with clearer copy, an info
tooltip, and a visible header badge when it is enabled
- auto-accept queued permissions for any yolo-enabled session in the
instance, not only the currently focused session
## Why
- keeps this risky mode explicit and easy to audit from the session
status area
- matches the expected multi-session desktop behavior when several
sessions stay active in parallel
## Testing
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui
Closes#18
Let users refresh a session transcript from the sidebar without reopening it. Reuse the existing forced message loading path so the reload behavior stays aligned with normal session hydration.
## Summary
- escape raw HTML when rendering user message markdown so prompt input
is shown as text instead of injected HTML
- keep assistant and tool markdown behavior unchanged by scoping the
escape behavior to user messages
- update markdown cache keys so escaped and non-escaped render output do
not collide
## Verification
- `npm run typecheck --workspace @codenomad/ui` *(fails in this
workspace because frontend dependencies are not installed)*
- `npm run build --workspace @codenomad/ui` *(fails in this workspace
because `vite` is not installed)*
--
Yours,
[CodeNomadBot](https://github.com/NeuralNomadsAI/CodeNomad)
Co-authored-by: Shantur <shantur@Mac.home>
## Summary
- Adds file writing capability to Monaco editor in the file viewer
- Implements writeFile API on the server for workspace files
- Integrates save functionality into the file viewer UI with proper
state management
## Bug Fixes (Review Feedback)
- Fixed failed save discarding edits when switching files - now checks
save result and only proceeds if successful
- Fixed refresh overwriting dirty editor state - now prompts for
confirmation before discarding edits
- Fixed save button unable to save empty files - changed check from `if
(content)` to `if (content !== undefined && content !== null)`
- Added agent edit conflict detection - when agent edits file while user
has unsaved changes, shows conflict dialog with Overwrite/Cancel options
- Fixed dialog appearing behind unpinned sidebar - increased alert
dialog z-index to z-100
## Related Issues
- Closes#251
---------
Co-authored-by: Jess Chadwick <jchadwick@gmail.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
# feat(i18n): Hebrew locale + full RTL support
## Summary
This PR adds full Hebrew (he) locale support to the UI, including a
complete translation of all user-facing strings and comprehensive RTL
layout support across all components.
## What was done
### Hebrew translation
- Full translation of all i18n message files for the `he` locale (17
translation files)
- Registered the language in the i18n system and the language picker
### RTL support
- Automatic direction detection (`dir="rtl"`) when Hebrew is selected
- Replaced physical CSS properties (`left`/`right`) with logical
equivalents (`inline-start`/`inline-end`) across the project
- Fixed resize direction, file path alignment, and textarea padding
- Fixed navigation button positioning in textarea for RTL
- Fixed scrollbar direction in RTL
- Fixed code block direction and selector alignment
- Fixed Monaco editor direction in the file viewer
- Auto-detect text direction in reasoning block (`dir="auto"` +
`unicode-bidi: plaintext`)
### Adapted components
- `session-layout` — sidebar and resize handle
- `prompt-input` — text direction and buttons
- `message-base` — message blocks and reasoning
- `message-timeline` — timeline bar
- `right-panel` — right side panel
- `tool-call` — tool call display
- `settings-screen` — settings page
- `selector` — selection component
- `instance-shell` — main shell
## New files
```
packages/ui/src/lib/i18n/messages/he/
advancedSettings.ts
app.ts
commands.ts
dialogs.ts
filesystem.ts
folderSelection.ts
index.ts
instance.ts
loadingScreen.ts
logs.ts
markdown.ts
messaging.ts
remoteAccess.ts
session.ts
settings.ts
time.ts
toolCall.ts
```
## Suggested testing
- Switch language to Hebrew and verify all strings are translated
- Verify RTL layout is correct across all screens (session, settings,
file viewer)
- Verify that English text inside a reasoning block is displayed LTR
- Switch back to English and verify everything returns to LTR
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Shantur Rathore <i@shantur.com>
## Summary
- defer locale and overlay loading work away from the first critical
render path
- seed locale state from the bootstrap preload so the first render can
use the preloaded language immediately
- keep bootstrap cache and locale fallback behavior consistent on
subsequent launches
## Testing
- npm run build --workspace @codenomad/ui
## 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>
## Summary
- lazy-load the markdown and diff render paths so they stop inflating
initial UI startup work
- move shared text rendering helpers out of the markdown path and keep
diff rendering on the deferred path
- defer the Monaco secondary viewers so the markdown and diff path no
longer keeps that work in the main bundle
## Follow-ups
- related fork follow-up: Pagecran/CodeNomad#1
- that follow-up is now independent on dev and only keeps the remaining
right panel, picker, and tool-call secondary chunking work
## Testing
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui
## 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>