Commit graph

703 commits

Author SHA1 Message Date
Shantur Rathore
86ac87a314 fix(ui): clarify optimistic instance close
Keep the tab-close fix optimistic by removing the instance from local state immediately, but make the backend workspace deletion explicitly fire-and-forget instead of exposing a misleading async stop contract.

Remove stale awaits from call sites so callers no longer imply that stopInstance waits for backend teardown. If backend deletion fails after the tab is closed, surface the failure through the existing localized toast notification system while still logging the underlying error.

Validation: npm run typecheck --workspace @codenomad/ui; npm run build --workspace @codenomad/ui; git diff --check.
2026-06-15 09:36:42 +01:00
Aayurt Shrestha
bbfc2ace22
Merge branch 'NeuralNomadsAI:dev' into bugfix/tabCloseBug 2026-06-13 23:09:53 +05:45
aayurt
8cf6b03761 fix(instances): streamline instance stopping process and error handling 2026-06-13 23:09:09 +05:45
Dark
14dfd3e371
fix(ui): throttle SSE part deltas and prevent stale delta text duplication (#536)
## Problem

Streaming responses send many `message.part.delta` events per second.
Each event triggers a Solid store mutation + re-render, causing:

1. **Mobile freezes** — KaTeX/highlight.js re-renders on every delta
block the main thread
2. **Text duplication** — When `message.part.updated` replaces a part
with the server's complete state, previously enqueued deltas would flush
AFTER the replacement, concatenating stale text onto the fresh part

## Solution

### 1. Delta throttling (50ms buffer)
Accumulate deltas in a buffer and flush every 50ms instead of updating
on every event. This batches Solid mutations and cuts main-thread
blocking during streaming.

### 2. Stale delta cleanup
When a full `message.part.updated` arrives, clear any pending deltas for
that part before applying the update. The update already contains the
complete server state, so accumulated deltas are stale.

## Changes

- `packages/ui/src/stores/session-events.ts`: Added `enqueueDelta`,
`flushDeltas`, `clearPendingDeltasForPart`; updated
`handleMessagePartDelta` and `handleMessageUpdate`

## Verification

- Build passes: `npm run build:ui`
- Tested on mobile — eliminates visible freezes during long streaming
responses
- No duplicate text observed at end of assistant messages after part
updates

---------
2026-06-13 16:42:17 +02:00
Shantur Rathore
4a1d53bf2d Increment to v0.17.1 2026-06-08 21:10:57 +01:00
Shantur Rathore
1ff682e43a
fix(ui): simplify permission denial feedback (#535)
## Summary
- make permission Deny submit immediately while preserving optional
feedback
- replace the gated deny-confirmation UI with a compact one-line
feedback field
- remove visible feedback label/hint text and update placeholders across
all locales

## Validation
- npm run typecheck --workspace @codenomad/ui

## Notes
- Left unrelated untracked .opencode/package-lock.json out of the
commit.
2026-06-08 21:07:56 +01:00
Pascal André
d29dbf75cf
perf(tauri): Rust-native desktop event transport (#242)
## Summary

- switch the Tauri desktop runtime from the browser `EventSource` path
to a native Rust desktop event transport while leaving browser and
Electron unchanged
- restore SSE heartbeat parity by parsing named `event:` frames and
replying to `codenomad.client.ping` with an authenticated
`/api/client-connections/pong`
- add a Tauri-only settings toggle that lets the current device fall
back to the browser `EventSource` transport without leaking that choice
through shared config
- remove the temporary benchmark harness from the shipped code now that
the transport behavior has been validated

## Benchmark

The temporary in-app benchmark harness used during validation has been
removed from the final code, but the measured results are retained here
for review context.

Real Tauri/WebView2 benchmark on Windows using the dedicated session:
- workspace: `D:\CodeNomad`
- session: `ses_21feb15b3ffeLz3uRModK4KKnG`

Short command:
- `node -e "for (let i = 1; i <= 400; i += 1) console.log('line ' + i)"`

Results:
- browser `EventSource` forced in Tauri:
  - timed out after `131479.7ms`
  - `sawWorking=false`
  - `reachedIdle=false`
  - `batchesReceived=84`
  - `eventsReceived=84`
  - `maxBatchSize=1`
- Rust-native transport:
  - completed in `1437.4ms`
  - `sawWorking=true`
  - `reachedIdle=true`
  - `batchesReceived=4`
  - `eventsReceived=45`
  - `maxBatchSize=27`

Long heartbeat / stale-timeout validation:
- command: `powershell -NoProfile -Command Start-Sleep -Seconds 70`
- Rust-native transport:
  - completed in `71689.5ms`
  - `sawWorking=true`
  - `reachedIdle=true`
  - `batchesReceived=13`
  - `eventsReceived=72`
  - `maxBatchSize=25`

Confirmed separately afterward: the native transport also behaves better
on Linux.

## Validation

- `cargo test named_ping_event_is_routed_to_ping_channel`
- `cargo test session_cookie_is_attached_to_requests`
- `cargo test --no-run`
- `npx tsc --noEmit --pretty -p packages/ui/tsconfig.json`
- `npx tsc --noEmit --pretty -p packages/server/tsconfig.json`
- manual Tauri/WebView2 benchmark on Windows
- manual confirmation on Linux after the benchmark phase

## Notes

- this remains a Tauri-only transport; browser and Electron stay on the
browser `EventSource` path
- the Tauri fallback toggle is now genuinely device-local and restarts
the local event stream immediately when changed
- the long run validates heartbeat / stale-timeout robustness, not
headline perf
2026-06-08 18:20:00 +01:00
Shantur Rathore
b2f3e14ad1
fix(ui): remove session diff right drawer flow (#532)
## Summary
- remove the obsolete session.diff fetch/store/SSE pipeline from
packages/ui
- delete the right drawer Session Changes tab and Status accordion
section
- map stored removed "changes" tab values to Git Changes and remove
unused i18n keys

## Validation
- npm run typecheck --workspace @codenomad/ui
- git diff --check
2026-06-08 17:26:33 +01:00
Dark
ce77488d2f
fix(ui): add retry logic to SSE pong to improve connection resilience (#519)
## Problem

When the client receives a ping from the server, it responds with a pong
via HTTP POST. On unstable networks (mobile, WiFi with poor signal,
network switches), this POST can fail in multiple ways:

- **Hung requests**: `fetch()` never rejects, blocking retries
indefinitely
- **Network disconnection**: `Failed to fetch`
- **Brief disconnections**: transient network errors

Previously, a single missed pong would cause the server to close the SSE
connection after 45s, leaving message responses stuck in queue until the
next message triggered a reconnection.

## Solution

Three improvements to make the pong POST resilient:

### 1. Request timeout (10s)
Each pong POST is now bounded with a 10s `AbortSignal` timeout. Hung
requests fail fast instead of blocking indefinitely, allowing retries to
start before the server's stale connection sweep.

### 2. Selective retry with `isRetryableError()`
Only retries transient failures where recovery is possible:
- `AbortError` / `TimeoutError` (hung or timed-out requests)
- `Failed to fetch` (network disconnected)
- `NetworkError` (browser network errors)

Non-retryable errors like `404 Client connection not found` (permanently
closed connection) fail immediately instead of wasting retry attempts.

### 3. Exponential backoff (3 attempts, 100ms → 2000ms)
Handles burst failures gracefully without hammering the server.

## Changes

- **`packages/ui/src/lib/retry-utils.ts`** (new): Reusable retry utility
with `timeoutMs` and `shouldRetry` predicate support
- **`packages/ui/src/lib/server-events.ts`**: Updated pong handler to
use bounded timeout + selective retry

## Verification

- Build passes: `npm run build:ui` 
- Manually verified in production logs: retries now visible as `Pong
failed after retries` instead of single immediate failure
- SSE monitor log at `~/.codenomad/logs/sse-monitor.log` shows `PONG_OK`
/ `PONG_FAIL` / `STALE` events for ongoing monitoring
2026-06-08 17:20:10 +01:00
Shantur Rathore
ff10c1f395
fix(ui): stop message load retry loop (#529)
## Summary
- store per-session message load failures so automatic session effects
stop retrying after server errors
- show the server-provided error in the message stream with a reload
action that forces a fresh request
- add localized labels for the load-error title and reload button

## Validation
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui
2026-06-07 22:23:00 +01:00
Pascal André
8bcf365fc3
fix(ui): scope primary agent selector to selectable agents (#528)
## Summary

- rescope the UI portion of #385 to the remaining main-session selector
issue from #384
- keep main-session primary selectors limited to selectable primary
agents
- preserve child/subagent behavior by keeping the current hidden agent
available for steering
- add focused tests for selector eligibility behavior

This intentionally excludes the OMO/config-directory merge and plugin
retry scope from #385, since that part was determined to belong outside
CodeNomad. Credit to @jollyxenon for the original #385 investigation and
UI direction.

## Validation

- ode --test packages/ui/src/types/session.test.ts 
- pm run typecheck --workspace @codenomad/ui ⚠️ fails on existing
SDK/type drift outside this diff

Fixes #384
Based on #385
2026-06-07 17:19:21 +01:00
Pascal André
df7c507aa9
feat(ui): collapse pasted text in chat history (#407)
## Summary
- Collapse intact placeholder-backed long pasted text blocks by default
in user message history for readability.
- Keep pasted content fully visible to the model; this is a display-only
history treatment.
- Persist pasted-text collapse metadata across optimistic message
replacement and app reloads.
- Fall back to normal plain-text history rendering when the
placeholder-backed pasted structure has been edited or is no longer
intact before send.

Fixes #266

## Behavior
When a user submits a prompt containing an intact long pasted block from
the existing pasted-text placeholder flow, the full pasted text is still
sent to the model unchanged, but the chat history renders that pasted
section as a collapsed expandable block.

This applies to the existing placeholder-backed long-paste flow only. If
the pasted placeholder structure is broken before submission, the
message renders in history as normal plain text with no collapse
metadata.

## Verification
- `npx tsx --test
"packages/ui/src/components/prompt-input/submitPrompt.test.ts"
"packages/ui/src/lib/prompt-display-metadata.test.ts"
"packages/ui/src/stores/message-prompt-display.test.ts"`
- `npm run typecheck --workspace @codenomad/ui`
- `npm run build --workspace @codenomad/ui`
- `npm run build --workspace @codenomad/tauri-app`

## Local desktop verification
- Built executable:
`packages/tauri-app/target/release/codenomad-tauri.exe`
- Built installer:
`packages/tauri-app/target/release/bundle/nsis/CodeNomad_0.15.0_x64-setup.exe`
- Launched the built Tauri executable locally and confirmed startup
succeeded.

<img width="487" height="129" alt="image"
src="https://github.com/user-attachments/assets/6c3d670c-b049-4fa7-bc8b-c69d0fb3ca25"
/>
2026-06-07 17:17:27 +01:00
Pascal André
97dcc0a692
feat(ui): show the session title in the header bar (#340)
Fixes #299

## Summary
- show the active session title in the instance header, just after the
menu switch.
- keep the title visible whenever the left session drawer is not pinned,
using a quiet two-line header treatment without active-item
highlighting.
- when the unpinned drawer is open as a floating overlay, keep the title
in the same left header slot so the drawer covers it instead of pushing
toolbar controls around.
- disable the feature in mobile view

## Validation
- `git diff --check`
- `npm run typecheck --workspace @codenomad/ui`
- `npm run build --workspace @codenomad/ui`
- visually validated in the rebuilt desktop app raw executable
2026-06-07 12:02:06 +01:00
Shantur Rathore
4ae7baa8b4
Support OpenCode SDK 1.16 runtime APIs (#526)
## Summary
- upgrade the UI OpenCode SDK usage for the 1.16 v2 session
list/response shapes
- migrate session list/search handling to v2 while preserving
unsupported legacy session actions
- support mixed legacy/v2 permission and question queues, events,
hydration, and reply routing during the 1.16 transition

## Validation
- npm run typecheck --workspace packages/ui
- npx tsx --test "packages/ui/src/types/permission.test.ts"
"packages/ui/src/stores/message-v2/instance-store.test.ts"
2026-06-07 11:59:56 +01:00
Pascal André
006b4f790e
feat(ui): add message timing metrics (#357)
Fixes #297

## Summary
- show total assistant response duration next to the existing message
timestamp using only explicit OpenCode message timing
- show reasoning duration on reasoning cards only when OpenCode provides
explicit part timing

## Why
This revision keeps the UI scoped to explicit server-side timing data
that OpenCode already provides, which matches the maintainer feedback on
this PR.

## Validation
- node --experimental-strip-types --test
"packages/ui/src/lib/message-timing.test.ts"
- npm run build --workspace @codenomad/ui
2026-06-06 22:51:27 +02:00
Pascal André
e30c73716a
fix(ui): stabilize virtual follow autoscroll (#406)
## Summary
- Stabilize virtualized message autoscroll by keeping DOM/Virtua
orchestration in `VirtualFollowList` and moving pure follow/hold
behavior into a colocated tested module.
- Restore per-session scroll positions using Virtua metrics and anchor
snapshots while preventing hidden/inactive panes from overwriting good
snapshots.
- Gate streaming magnetization on active streaming, hold state, and the
bottom-of-viewport item so long assistant replies can still rejoin near
their tail without using stale top-of-viewport position.

## Supersedes / fixes
- supersedes #375.
- supersedes #356.
- fixes #305.

## Validation
- `node --test
packages/ui/src/components/virtual-follow-behavior.test.ts`
- `npm run typecheck --workspace @codenomad/ui`
- `npm run build --workspace @codenomad/tauri-app`
- Many manual release executable testing.
2026-06-06 20:13:23 +01:00
Aayurt Shrestha
29f9d2552f
Add German and Nepali Localizations (#523)
Added comprehensive German (de) and Nepali (ne) translations to the
CodeNomad UI.

Key Changes:

New Localization Files: Created 17 new message part files for each
locale in packages/ui/src/lib/i18n/messages/de/ and
packages/ui/src/lib/i18n/messages/ne/. These cover all application
areas, including settings, commands, session management, and the loading
screen.
I18n Registration: Updated the core i18n configuration to include the
new locales, enabling dynamic loading of the translation bundles.
UI Integration: Added "Deutsch" and "नेपाली" to the language selection
picker on the home screen, allowing users to switch to these languages.
Translation Quality: Provided high-quality translations that maintain
the humorous and technical tone of the original English strings. The
Nepali version uses the Devanagari script and includes technical terms
in parentheses where helpful for clarity.
Verification:

Verified that the UI build process completes successfully with the new
files.
Confirmed that all translation keys from the English source are
accounted for in both new languages.
Conducted a code review to ensure compliance with project i18n patterns.

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-06-05 09:40:22 +01:00
Shantur Rathore
55760f7b1a Bump version to 0.17.0 2026-06-04 21:05:56 +01:00
Shantur Rathore
994157f577
feat(ui): support custom workspace names (#522)
## Summary
- Adds editable workspace display names for recent folders.
- Shows the saved workspace name in the recent folder list and instance
tab, including the launching workspace state.
- Preserves workspace names when recent folders are relaunched and keeps
basename fallback for unnamed folders.

Fixes #510

## Validation
- npm run typecheck --workspace @codenomad/ui
- npm run typecheck --workspace @neuralnomads/codenomad
2026-06-04 12:41:05 +01:00
Shantur Rathore
9d4c304773
fix(worktrees): route OpenCode calls through workspaces (#521)
## Summary

This fixes #518 by moving CodeNomad worktree execution from
directory-header routing to OpenCode experimental workspace routing.

OpenCode changed existing-session routing so session routes can prefer
the session's stored directory over `x-opencode-directory`. That made
the old CodeNomad worktree proxy model unreliable for sessions that
should execute in a worktree. This PR switches CodeNomad to resolve an
OpenCode workspace ID for each CodeNomad worktree and pass that
workspace ID on worktree-scoped OpenCode calls.

## What changed

- Start OpenCode with `OPENCODE_EXPERIMENTAL_WORKSPACES=true`.
- Change the OpenCode server base URL from
`/workspaces/:id/worktrees/root/instance` to `/workspaces/:id/instance`.
- Add a root OpenCode client helper in
`packages/ui/src/stores/opencode-client.ts`.
- Add OpenCode workspace sync/cache helpers in
`packages/ui/src/stores/opencode-workspaces.ts`.
- Sync OpenCode workspaces after CodeNomad worktree hydration and after
worktree create/delete flows.
- Map CodeNomad worktree slugs/directories to OpenCode `workspace.id`
values discovered by `experimental.workspace.syncList` and
`experimental.workspace.list`.
- Replace all OpenCode worktree clients with the root client plus
explicit `workspace` payloads where the active session/worktree requires
it.
- Route session, permission/question, file browser reads, SDK git
status, and prompt/action calls through root OpenCode client + workspace
ID.
- Keep CodeNomad local git worktree server APIs intact; those still need
filesystem directories for local git operations.

## Review fix

- Fixed right-panel file saves so they no longer write to the root
workspace after reading from a selected worktree.
- The existing CodeNomad file-content API now accepts an optional
`worktree` query parameter.
- Right-panel saves pass `worktreeSlugForViewer()`, and the server
resolves that slug to the same worktree directory used by local git
worktree APIs before writing.
- Root saves continue to use the original root workspace path.

## Removed old routing

- Removed `/workspaces/:id/worktrees/:slug/instance` OpenCode proxy
routes.
- Removed directory override proxy support using `/__dir/<encoded>`.
- Removed proxy injection of `x-opencode-directory`.
- Removed the remaining background-process completion prompt
`x-opencode-directory` header.
- Removed `getOrCreateWorktreeClient`,
`getOrCreateWorktreeClientWithDirectoryOverride`, and worktree proxy
path helpers from the UI worktree store.
- Simplified `sdkManager.createClient` because clients are no longer
keyed by worktree slug.

## Why this fixes #518

Worktree sessions can now stay visible under the root project session
listing while worktree execution is selected through OpenCode's
workspace routing model. CodeNomad no longer depends on
`x-opencode-directory` to override existing session directories, so
sessions should not disappear from the root-directory list or execute in
the wrong directory because of stale session directory fallback
behavior.

Fixes #518

## Validation

- `npm run typecheck --workspace @codenomad/ui`
- `npm run typecheck --workspace @neuralnomads/codenomad`
- `git diff --check`

## Notes

Some touched files are already oversized and were not refactored as part
of this migration: `packages/server/src/server/http-server.ts`,
`packages/ui/src/stores/instances.ts`,
`packages/ui/src/stores/session-api.ts`,
`packages/ui/src/stores/session-state.ts`,
`packages/ui/src/components/instance/shell/right-panel/RightPanel.tsx`,
`packages/ui/src/stores/session-events.ts`, and
`packages/server/src/background-processes/manager.ts`.
2026-06-04 11:25:09 +01:00
VooDisss
b3594d29e5
feat(sessions): progressive loading, server-side search, and workspace scoping (#511)
# Session Pagination & Search Enhancement

## Changes

### Progressive Session Loading
- `fetchSessions()` now accepts `{ limit, search }` options
- Added pagination state: `sessionFetchLimit`, `sessionHasMore`
(50-session pages)
- Scroll-to-bottom sentinel triggers `loadMoreSessions()` via
IntersectionObserver
- Hydration loads initial 50 sessions; subsequent scrolls fetch 100,
150, etc.

### Server-Side Search
- Added `searchSessions()` using `session.list({ search, limit: 50,
directory })`
- Merges results into store (preserves active session, no replacement)
- Added `"sessionList.loading.more"` i18n key (7 locales)

### Hybrid Search Performance
- Client-side filtering runs first — instant results for loaded sessions
- Server search only fires when no client matches exist
- Debounce reduced from 300ms → 150ms for server fallback

### Workspace Scoping
- All `session.list()` calls pass `directory: instance.folder`
- Prevents cross-workspace session pollution

## Files
- `packages/ui/src/stores/session-state.ts`
- `packages/ui/src/stores/session-api.ts`
- `packages/ui/src/stores/instances.ts`
- `packages/ui/src/stores/sessions.ts`
- `packages/ui/src/components/session-list.tsx`
- `packages/ui/src/lib/i18n/messages/*/session.ts`

---------

Co-authored-by: Shantur Rathore <i@shantur.com>
2026-06-02 10:32:34 +01:00
Shantur Rathore
873235ee1e
Migrate worktree mappings to session metadata (#514)
## Summary
- Upgrade `@opencode-ai/sdk` to `1.15.13` and adapt UI types for the
current session/diff API surface.
- Add a session metadata store helper that safely updates OpenCode
session metadata via read-merge-full-replace while preserving
non-CodeNomad metadata.
- Migrate CodeNomad worktree assignments from
`.codenomad/worktreeMap.json` into `metadata.codenomad.worktreeSlug`,
with legacy fallback, stale-entry pruning, and server-side deletion of
the legacy map once empty.
- Add `.codenomad/background_processes/` to CodeNomad-managed
`.git/info/exclude` entries.

## Details
- New sessions and worktree reassignment now persist explicit session
worktree assignments in OpenCode session metadata under:
  `metadata.codenomad.worktreeSlug`
- Worktree resolution now prefers session metadata, then falls back to
legacy `parentSessionWorktreeSlug`, then `root`.
- Legacy migration runs after session/map loading; after the full
session list is known, missing legacy session IDs are treated as stale
and pruned.
- The UI no longer uses `defaultWorktreeSlug`; the fallback is `root`.
- `writeWorktreeMap` deletes `.codenomad/worktreeMap.json` server-side
when no legacy parent-session mappings remain.

## Validation
- `npm run typecheck --workspace @codenomad/ui`
- `npm run typecheck --workspace @neuralnomads/codenomad`
2026-06-01 10:16:17 +01:00
bluelovers
7812a0950f
feat(ui): Toast Notification History & Server Logs Enhancements (#278)
# PR: Enhance UI with Toast Notification History & Server Logs
Improvements

## 中文摘要 (Chinese Summary)

### 功能概述
本 PR 包含兩個 UI 增強功能:**通知歷史面板** 和 **伺服器日誌改進**。

### 功能一:通知歷史面板 (Toast Notification History)
- 新增 `ToastHistoryPanel` 組件,顯示所有 Toast 通知的歷史記錄
- 支援按類型(info/success/warning/error)篩選
- 支援時間分組(今日/昨日/更早)
- 支援清除全部、標記已讀、刪除單項
- 最多保留 50 筆歷史記錄

### 功能二:伺服器日誌改進 (Server Logs Enhancements)
- 新增清除日誌按鈕(垃圾桶圖標)
- 新增返回對話按鈕(箭頭圖標,位於日誌工具列)
- 新增浮動向上/向下滾動按鈕(圓形小球,與對話介面一致)
- 滾動按鈕根據位置自動顯示/隱藏
- 滾動按鈕狀態會隨日誌變化自動同步

---

## English Summary

### Overview
This PR introduces two UI enhancements: **Toast Notification History
Panel** and **Server Logs Improvements**.

### Feature 1: Toast Notification History Panel
- New `ToastHistoryPanel` component displays all toast notification
history
- Filter by variant type (info/success/warning/error)
- Time grouping (Today/Yesterday/Earlier)
- Clear all, mark as read, delete individual items
- Maximum 50 history records retained

### Feature 2: Server Logs Enhancements
- Clear logs button with Trash2 icon
- Back to conversation button with ArrowLeft icon (in logs toolbar)
- Floating scroll-to-top/scroll-to-bottom buttons (circular, consistent
with message section)
- Auto show/hide based on scroll position
- Scroll button state syncs automatically with log changes

---------

Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-31 14:57:39 +02:00
bluelovers
7f431aba8b
fix(ui): hide environment variable values and mask inputs as password (#284)
## Summary

- Display only environment variable names in instance info panel (hide
values)
- Display only environment variable names in logs view (hide values)
- Change environment variable value inputs to password type in settings
editor

## Motivation

Environment variable values (which may contain sensitive data like API
keys, tokens, or secrets) were displayed in plain text across multiple
UI surfaces. This change:

1. **Reduces visual exposure** — instance info and logs view now show
only variable names
2. **Masks input fields** — the settings editor uses `type="password"`
for value inputs, preventing shoulder-surfing and accidental exposure in
screenshots or screen recordings

---------

Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-27 16:24:13 +02:00
MusiCode1
01d9e46b3d
Update Hebrew translation coverage (#388)
## Summary
- Add missing Hebrew translation keys for Speech navigation and deleted
git changes.
- Fix Hebrew placeholder coverage for singular count strings and
apply-patch file counts.
- Polish stale Hebrew wording in notifications and tool call labels.

## Verification
- Hebrew catalog parity check: `en=1027 he=1027 missing=0 extra=0
placeholderMismatch=0`
- `git diff --check -- packages/ui/src/lib/i18n/messages/he`
- `npm run typecheck --workspace @codenomad/ui` fails on existing
unrelated issues: missing `virtua/solid`, missing
`@tauri-apps/plugin-dialog`, and implicit `any` parameters in
`virtual-follow-list.tsx`.

Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-25 23:27:10 +02:00
Claas Pancratius
8c0afa6f3a
Share YOLO mode across session families (#497)
## Summary
- make YOLO/permission auto-accept resolve by session family root so
master and subagent sessions share the same state
- keep fork/revert sessions as their own family root
- keep existing local YOLO persistence behavior; no server-backed
persistence, migration, global setting, or confirmation dialog
- re-drain queued child permissions when session metadata arrives so
permissions that arrived before parent metadata can be auto-accepted

Solves #495

## Validation
- npm run typecheck --workspace @codenomad/ui
- npx tsx --test packages/ui/src/stores/permission-auto-accept.test.ts
- git diff --check

## Build Artifact
- Not generated in this update

---------

Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-25 22:41:34 +02:00
Claas Pancratius
d639b8387a
Add reject feedback to permission UI (#499)
## Summary
- Adds a two-step deny flow for permission requests so users can provide
optional feedback.
- Passes reject feedback through `sendPermissionResponse` to
`client.permission.reply` as `message`.
- Hardens the flow by ignoring permission shortcuts while text inputs
are focused and capping feedback length.

## Validation
- `npm run typecheck --workspace @codenomad/ui`
- `npm run build:ui`
- `npm run build:linux --workspace @neuralnomads/codenomad-electron-app`

## Showcase
<img width="1709" height="1118" alt="image"
src="https://github.com/user-attachments/assets/9f516100-7c3f-4c08-95b2-236b5168394e"
/>

Related to #496

---------

Co-authored-by: Shantur Rathore <i@shantur.com>
Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-25 21:32:49 +02:00
Pascal André
d45a4b6371
fix(ui): support tuple plugin metadata (#501)
## Summary
- this fixes a bug where no plugin are displayed in the UI 
- normalize OpenCode plugin metadata through a dedicated helper instead
of assuming every entry is a string
- support tuple-form plugin entries by displaying the tuple specifier
and preserving existing file:// normalization
- add focused regression coverage for string, tuple, and invalid plugin
entry shapes

## Validation
- npm run typecheck --workspace @codenomad/ui
- node --test packages/ui/src/lib/hooks/use-instance-metadata.test.ts
- npm run build --workspace @codenomad/ui
2026-05-23 22:40:23 +02:00
Claas Pancratius
a9c9b427c5
fix(ui): render markdown horizontal rules (#498)
## Summary
- render Markdown horizontal rules instead of hiding them in message
content
- keep the existing Markdown parser behavior and style the generated hr
with the shared border token

Solves #491

## Validation
- npm run typecheck --workspace @codenomad/ui
- npm run build:linux --workspace @neuralnomads/codenomad-electron-app

## Test release artifact
Built locally for Linux; artifacts are ignored and not included in this
PR:
- packages/electron-app/release/CodeNomad-Electron-linux-x64-0.16.0.zip
-
packages/electron-app/release/CodeNomad-Electron-linux-x86_64-0.16.0.AppImage

Co-authored-by: Shantur Rathore <i@shantur.com>
Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-23 22:38:52 +02:00
Shantur Rathore
cabe89476f fix(ui): constrain mobile folder home layout
Reserve space for the absolute homepage controls on narrow screens so the language selector no longer overlaps the CodeNomad logo.

Apply the existing actions-column height constraint to the recent folder panel across viewport sizes so mobile lists scroll instead of expanding beyond the browse/actions section.

Validated with npm run typecheck --workspace @codenomad/ui.
2026-05-17 20:24:38 +01:00
Shantur Rathore
ee069bf4db
Add global config file editor (#477)
## Summary
- Add an allowlisted server API for editing global config files,
starting with OpenCode global config.
- Add a Config Files settings section using the existing Monaco editor
with save, reload, dirty-state handling, and responsive layout.
- Improve compact settings navigation with a full-width section
selector, settings icon, and close action in the compact toolbar.

## Validation
- npm run typecheck in packages/server
- npm run typecheck in packages/ui
- npm run build in packages/ui

## Notes
- Existing Vite warnings about virtua JSX import source and large chunks
remain unrelated.
2026-05-17 19:44:46 +01:00
Shantur Rathore
4ddd25602e
feat(ui): add instance-scoped provider manager from model selector (#476)
## Summary
- move provider authentication management out of global settings and
into the model selector so it always runs against a live OpenCode
instance
- add an instance-scoped provider manager modal with API-key and OAuth
flows, cancellable OAuth waiting, and provider discovery/configuration
details
- handle configured provider sources differently so config- and
env-backed providers are explained in the UI while auth-backed providers
can be disconnected safely

## Validation
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui
2026-05-17 18:18:41 +01:00
Omer Cohen
681755888f
fix(mobile): tappable instance/project tab bar while session drawer is open (#459)
## Summary

Fixes a mobile UX bug where, with the session list (left drawer) open on
phone layout, the still-visible instance/project tab bar at the top was
non-interactive. Tapping a tab did nothing — users had to close the
drawer first and then switch projects/instances.

After this change, tapping a tab in that bar switches the
instance/project **and** the drawer auto-closes in a single gesture,
matching user expectation.

## Root cause

On phone (`max-width: 767px`), `InstanceShell` renders the left session
sidebar via MUI's `Drawer variant="temporary"`. The drawer paper is
offset down to `floatingTopPx()` so the instance tab bar remains
visually visible above it. However, MUI's `Modal` Backdrop is `position:
fixed; inset: 0` and covers the entire viewport — including the area
over the tab bar. The backdrop is styled `backgroundColor: transparent`
(so it's invisible) but it still captures pointer events at `z-index:
60`. Taps over the tab bar hit the transparent backdrop → MUI calls
`onClose` (closing the drawer) but the tab's click handler never fires.

## Implementation

1. **`packages/ui/src/components/instance/instance-shell2.tsx`** —
Constrain the MUI Drawer Backdrop via `sx` overrides on both the left
(session list) and right drawers so the backdrop is bound to the drawer
paper's vertical range (`top: floatingTopPx(); height:
floatingHeight();`) instead of fullscreen. Taps over the tab bar now
reach the tab buttons.

2. **`packages/ui/src/styles/panels/tabs.css`** — Lift
`.tab-bar-instance` to `position: relative; z-index: 70` so it stacks
deterministically above the drawer (z-index 60) across browsers as
defense-in-depth.

3. **`packages/ui/src/components/instance/shell/useDrawerChrome.ts` +
`instance-shell2.tsx`** — Expose `closeFloatingDrawersIfAny` from
`useDrawerChrome` and call it from an `InstanceShell` effect that fires
when `props.isActiveInstance` flips `true → false`. This closes any open
floating drawer on the instance the user just switched away from, so its
previously-open state doesn't bleed back when the user returns to that
tab later.

Tablet (>=768px) and desktop (>=1280px) layouts use pinned drawers (no
temporary modal), so the backdrop constraint and z-index lift are inert
there. The fix applies symmetrically to the right drawer on phone.

## Verification

- `tsc --noEmit` clean.
- `vite build` clean.
- Manual mobile-emulation checklist in the task file
(`tasks/done/058-mobile-session-list-blocks-tab-switch.md`) and SUMMARY
in `evidences/058-mobile-session-list-blocks-tab-switch/`.

## Reviewer manual check (phone viewport <=767px)

- Open session list drawer. Tap a different instance tab → it activates
AND drawer closes.
- Tap "+" while drawer open → folder picker opens, drawer closes.
- Tap Settings / Notifications / Remote while drawer open → action
fires, drawer closes.
- Same checks against the right drawer.
- Tap area below tab bar but outside drawer paper → drawer still closes
(existing backdrop dismissal preserved).
- Resize to tablet and desktop widths → pinned drawers unaffected.
- No visual regression in light or dark theme.

---------

Co-authored-by: Ubuntu <omer@Omer.dn3uxh3znnmu5eefnjnut0i1af.tlvx.internal.cloudapp.net>
Co-authored-by: Shantur Rathore <i@shantur.com>
2026-05-16 16:07:46 +01:00
Shantur Rathore
311b60bfb6
fix(ui): prevent accidental prompt clear from tab focus (#461)
## Summary
- Fixes #460 by changing the prompt control DOM order so tabbing from
the textarea reaches expand before clear.
- Clears prompt text through the textarea native delete path so
Cmd/Ctrl+Z can restore cleared text where the browser supports native
undo.
- Keeps the existing app-state fallback for environments where native
editing commands are unavailable or throw.

## Validation
- npm run typecheck --workspace @codenomad/ui
- Reviewed fallback behavior: `document.execCommand` is checked for
callability and wrapped in `try/catch`, so unavailable native editing
commands still fall back to app-state clearing.

## Manual QA Notes
- In a supported desktop/browser host: type text, click clear, then
press Cmd/Ctrl+Z and confirm text restores.
- Type text, press Tab and confirm focus moves to expand before clear;
pressing Tab again reaches clear.
2026-05-16 14:46:43 +01:00
Pascal André
283d3d79dd
fix(ui): allow status panel sections to collapse (#458)
## Summary
- Stop the right panel from immediately re-opening collapsed Status
sections.
- Keep the existing default expanded sections, including session
changes.

## Why
Users could click Status sub-panels to collapse them, but the UI
immediately expanded them again, making the accordion controls feel
broken.

## Validation
- npm run typecheck --workspace @codenomad/ui
- git diff --check
- npm run build --workspace @codenomad/ui
2026-05-16 13:59:35 +01:00
Shantur Rathore
f019fcc2b7
fix(ui): keep home actions visible on short viewports (#452)
## Summary
- Make the folder selection home screen scroll vertically when short
viewports cannot fit the primary action column.
- Cap the recent folders/server list to the measured action column
height on desktop so it scrolls internally instead of stretching the
layout.
- Use a focused home layout stylesheet with equal-width desktop columns.

## Validation
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui

## Notes
- Build still emits existing warnings about virtua JSX import source and
large chunks; unrelated to this change.
2026-05-15 16:17:32 +01:00
Yao Jianxuan
9a6450c03a
feat(ui): add resizable session composer (#439)
## Summary
- add a top-edge resize handle so the session composer can be freely
stretched upward while keeping the bottom edge anchored
- switch the expand/shrink control to track the actual composer height,
clamp expansion to the session toolbar boundary, and reset the composer
back to its default height after each send
- preserve the right-side three-column control layout in narrow and
windowed panes so the five utility controls stay outside the input, the
stop button rises with the composer, and the send button remains
bottom-pinned

## Testing
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui

## Notes
- the build still reports the existing `virtua` JSX warning from
`../../node_modules/virtua/lib/solid/index.jsx`; this PR does not
introduce that warning
- local unstaged changes in `.opencode/package-lock.json`, `.sisyphus/`,
and Electron dev-port files were intentionally excluded from this PR
because they are unrelated to the composer height feature

---------

Co-authored-by: Shantur Rathore <i@shantur.com>
2026-05-15 14:46:46 +01:00
Claas Pancratius
1295cfabca
feat(settings): add Info section with version, runtime, and diagnostics (#413)
## Summary

Adds a new **Info** section to the Settings screen, giving users quick
visibility into their CodeNomad version, runtime environment, and a way
to collect diagnostic data for bug reports.

Closes #412

## Changes

- **New component:** `info-settings-section.tsx` — renders three cards:
- **About** — Server/UI version, runtime type (electron/tauri/web),
platform, OS with CPU architecture detection, server URL, workspace root
- **Updates** — Placeholder "Check for updates" button, ready to wire
into the existing dev release monitor (`serverMeta.update`)
- **Diagnostics** — Log scope dropdown (Summary only / Summary +
workspace logs), Copy to clipboard, Download .txt — generates a
structured diagnostic report

- **New styles:** `settings-info.css` — info row layout, select row,
toast feedback, update note

- **Wiring:** Added `"info"` to `SettingsSectionId` union, registered
nav item and routing case in `settings-screen.tsx`, imported CSS in
`controls.css`

- **i18n:** 20 new keys added to all 7 locales (English canonical,
others fall back via existing fallback chain)

## Design decisions

- No server changes needed — version/runtime info comes from existing
`GET /api/meta` endpoint and client-side `navigator` detection
- No sensitive data (API keys, env values) included in diagnostic
reports
- CPU architecture extracted from `navigator.userAgent` for
Linux/Windows/macOS
- Log scope dropdown uses existing Kobalte Select pattern for
consistency

## Verification

- `tsc --noEmit` passes (0 errors)
- `vite build` bundles successfully
- Tauri Rust backend compiles and starts correctly

---

> **Note:** The majority of this implementation was produced through
CodeNomad using DeepSeek v4 Pro and has undergone manual review before
submission. All design, architecture, and code quality decisions were
evaluated by a human reviewer.

---------

Co-authored-by: Shantur Rathore <i@shantur.com>
2026-05-15 14:09:03 +01:00
Shantur Rathore
1dbb4a91e1
fix(ui): support draft prompt command sessions (#446)
## Summary
- Show attachments added to the no-session draft prompt before a session
exists.
- Create and activate a real session before first-prompt slash commands
or shell commands execute.
- Keep existing session command behavior unchanged by adding an optional
PromptInput command handler.

## Validation
- npm run typecheck --workspace @codenomad/ui
2026-05-14 19:33:25 +01:00
Shantur Rathore
d3950df816 Merge branch 'dev' of github.com:NeuralNomadsAI/CodeNomad into dev 2026-05-14 10:49:31 +01:00
Shantur Rathore
779202d9d7 Increment version to 0.16.0 2026-05-14 10:40:21 +01:00
Shantur Rathore
5570929fe5
Improve messages layouts on narrow screens (#438)
## Summary
- Tighten thinking block action spacing so it matches adjacent action
groups.
- Collapse secondary message, thinking, and tool-call actions into a
Kobalte overflow menu only at the session-center narrow width stop.
- Keep single-action cases inline, preserve primary/status controls,
mirror delete hover overlays from menu items, and square the overflow
menu styling.

## Validation
- npm run typecheck --workspace @codenomad/ui
2026-05-12 20:00:59 +01:00
Shantur Rathore
533ccacd69 fix(ui): base timeline width on center pane
Move the compact timeline width rule from viewport media queries to the session-center narrow width step. This keeps the timeline compact when the chat pane is narrow due to side panels, even on wide desktop viewports.

Validation: npm run typecheck --workspace @codenomad/ui
2026-05-12 13:14:50 +01:00
Shantur Rathore
d9af413932
Improve prompt layout for narrow session panes (#437)
## Summary
- Add measured `narrow` / `medium` / `wide` width steps to the session
center column so chat UI can respond to pane width rather than viewport
width.
- Rework prompt composer controls: clear/expand move into the text
field, narrow panes place auxiliary controls below the textarea, and
stop/send align bottom-right.
- Reduce branded empty-state logo/title size in narrow session panes and
remove the prompt `@ files/agents` overlay hint.

## Validation
- `npm run typecheck --workspace @codenomad/ui`
2026-05-12 11:58:31 +01:00
Shantur Rathore
ca076f4fe0 fix(ui): remove active project return action
Remove the prominent Return to Active Project button from the folder selection actions area so the home screen no longer shows a redundant project-return call to action.

Drop the active project label plumbing and localized return subtitle strings because the overlay still has the existing close affordance for dismissing the home screen.

Validation: attempted pnpm --filter @codenomad/ui typecheck, but tsc was not available in the current environment.
2026-05-12 10:07:51 +01:00
Shantur Rathore
9165299027
Refactor workspace startup and empty session states (#434)
## Summary
- Replace the old instance welcome screen with a focused workspace
launching state.
- Move no-session empty content into `MessageSection` as a variant of
the existing empty message-list view.
- Keep the normal bottom prompt available before a session exists and
create the first session from that prompt using draft agent/model
selections.

## Validation
- `npm run typecheck --workspace @codenomad/ui`

## Notes
- Existing local changes in `packages/opencode-config/package.json` and
`packages/opencode-config/package-lock.json` were left uncommitted and
are not part of this PR.
2026-05-11 18:16:31 +01:00
Shantur Rathore
8e6780c198
fix(ui): align prompt attachment picker with drop behavior (#432)
## Summary
- Reuses the directory browser for web file attachment selection and
removes the separate filesystem browser dialog.
- Reads web-selected files through the filesystem browser API so
selection respects unrestricted and configured workspace roots.
- Keeps Electron/Tauri picker selection on the FileList ingestion path
so picked files behave like dropped files with byte-backed attachments.

## Validation
- npm run typecheck --workspace @codenomad/ui
- npm run typecheck --workspace @neuralnomads/codenomad
- npm run typecheck --workspace @neuralnomads/codenomad-electron-app
- cargo check
- git diff --check

## Notes
- Follow-up to #417; this branch currently includes the commits from
that PR plus the attachment picker parity fix.

---------

Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-11 10:55:06 +01:00
Shantur Rathore
efe3f5055f
Add session web preview mode (#430)
## Summary
- Add ephemeral per-session web preview mode for opening arbitrary
HTTP(S) URLs inside the session workspace without persisting preview
state across reloads.
- Reuse the SideCar iframe shell by extracting a shared BrowserFrame
with navigation, refresh, path entry, viewport presets, and no-injection
element comment targeting.
- Add authenticated preview proxy routes for HTTP and WebSocket traffic,
sharing lower-level proxy forwarding with SideCars to avoid duplicating
proxy code.
- Localize all new preview and viewport strings across English, Spanish,
French, Hebrew, Japanese, Russian, and Simplified Chinese.

## User-facing behavior
- Users can open a web preview from the session toolbar and toggle back
and forth between chat and preview mode.
- Preview mode replaces only the message stream/timeline area; the
prompt input and attachments stay available below the preview.
- Comment mode lets users select elements in the same-origin proxied
iframe and append structured page/element references to the prompt
draft.
- The generated prompt quotes the page/element reference while leaving
the user's actual comment as normal prompt text.
- Viewport selection supports responsive, desktop, tablet
portrait/landscape, and mobile portrait/landscape canvases, with fixed
sizes isolated inside the iframe scroll container.

## Implementation notes
- Preview sessions are in-memory and keyed by short-lived tokens exposed
through `/previews/:token`.
- Preview proxy responses strip frame-blocking headers and rewrite
same-origin redirect locations back under the preview route.
- SideCarView now composes the shared BrowserFrame, preserving existing
SideCar behavior while gaining shared viewport controls.
- Parent-side iframe DOM access powers hover highlighting and element
metadata extraction, avoiding HTML/script injection for the first
implementation.

## Validation
- `npm run typecheck --workspace @codenomad/ui`
- `npm run typecheck --workspace @neuralnomads/codenomad`

## Notes
- Existing unrelated local changes to `package.json` and
`package-lock.json` were intentionally left out of this PR.
- The initial proxy does not yet rewrite all HTML/CSS asset references;
pages with root-relative assets may need follow-up URL rewriting.
2026-05-10 21:46:10 +01:00
Pascal André
a3231c3da5
fix(ui): return to active projects from home (#411)
## Summary
- Return to an existing open project when users choose that from the
already-open folder dialog.
- When users click a recent folder that is already open, ask whether to
switch to the open project or intentionally open another instance.
- Surface a prominent Return to Active Project action so leaving the
home screen no longer depends on the subtle top-right close affordance.
- Keep multi-instance workflows available without requiring users to
remember a separate row-level button.

Fixes #281

## Why
Users can accidentally open the same workspace several times from the
add-project screen. The app now detects that ambiguity when the
already-open folder is clicked and asks what should happen, instead of
making the user remember a special alternate button ahead of time.

The dialog keeps the copy short: the title states that the project is
already open, and the buttons carry the actual choices.

## Verification
- `git diff --check`
- `npm run typecheck --workspace @codenomad/ui`
- `npm run build --workspace @codenomad/ui`
- `npm run build:tauri`
2026-05-10 18:36:49 +01:00
Pascal André
562c6325c7
fix(ui): follow up idle badge behavior (#423)
## Summary
- Follow-up to #395 after the idle badge persistence behavior regressed
around `keepUnseenSubagentIdleStatus`.
- Restores `keepUnseenSubagentIdleStatus` handling across session,
active-session, and instance-tab badge helpers.
- Starts a 5s fade when a viewed idle session/thread is seen, then
clears each exact idle transition after the animation even if focus
moves away.
- Keeps unseen subagent idle badges visible when the preference is
enabled, and keeps aggregate instance badges solid when any other
visible idle contributor is still unseen.

## Validation
- `git diff --check`
- `npm run typecheck --workspace @codenomad/ui`
- `npm run build --workspace @codenomad/ui`
- Gatekeeper re-review: no blocking findings remain for the prior
preference/race findings.

## Notes
- `node --test packages/ui/src/stores/session-status.test.ts` was
attempted, but the repo's extensionless TypeScript imports are not
directly resolvable by Node's test runner.
2026-05-10 18:27:05 +01:00