fix(ui): remove scope=project from session list requests#571
Closed
JDis03 wants to merge 15 commits into
Closed
Conversation
Implements immediate visual feedback when SSE transport disconnects (wifi drops, Cloudflare idle timeouts, mobile network switches). ## Problem Per-instance status dots remained frozen at 'connected' (green) when SSE transport dropped because: - Instance status updates travel over SSE (impossible when SSE is down) - EventSource.onerror doesn't fire immediately on mobile wifi drops - No user-facing indication of workspace-level SSE state ## Solution 1. server-events.ts: Add onDisconnect() handler (mirrors existing onOpen) - Fire disconnectHandlers in scheduleReconnect() when connection drops 2. sse-manager.ts: Register SSE lifecycle handlers - onDisconnect: set ALL instances to 'connecting' (amber dot) - onOpen: clear 'connecting' status (green dot restored by events) - Log transitions for debug visibility 3. AGENTS.md: Add PR Review Principles section - Check regressions, look for better implementations - Be the PR gatekeeper, ruthless code quality - Test before responding, UI/server version parity ## Verification - TypeScript compilation clean (pre-existing SDK errors unrelated) - Vite build successful - Mobile testing: SSE disconnect → immediate amber dots - Reconnect → green dots restored ## Edge Cases Handled - Transient drop: amber → green on reconnect (no false modal) - Instance dies during outage: amber → green → 'disconnected' event → red - 0 instances: Map empty, loop is no-op - Rapid reconnect cycles: idempotent (setting 'connecting' on 'connecting' is no-op) Complements PR NeuralNomadsAI#519 (pong retry with timeout) - merged upstream.
Track workspace event transport reachability separately from per-instance stream status so a temporary SSE outage can show an amber connecting overlay without overwriting connected, disconnected, error, or genuinely connecting instance state. Expose shared transport status from both browser EventSource and the native Tauri event transport, including transient native disconnected and error states, so desktop and browser paths drive the same UI behavior. Remove the unrelated AGENTS.md review-guidance change from this PR and add focused node:test coverage for display-status derivation and native transport status mapping. Validated with UI typecheck, targeted tests, and npm run build:ui.
Fixes NeuralNomadsAI#441 Critical bug: Locking screen while wake-lock active causes system hang on KDE Wayland + Electron 39, requiring hard reboot. Solution: Detect Wayland session (XDG_SESSION_TYPE) and disable wake-lock feature on Electron + Wayland combination. Implementation: 1. Platform Detection (IPC): - Add platform:getInfo IPC handler in electron/main/ipc.ts - Exposes XDG_SESSION_TYPE and process.platform - Returns { sessionType?: string; platform: string } 2. Preload API: - Add getPlatformInfo() to electronAPI in preload/index.cjs - Bridges main process env vars to renderer process 3. Wayland Detection: - Add isWaylandSession() in ui/lib/native/wake-lock.ts - Checks XDG_SESSION_TYPE via Electron API - Fallback to user agent check - Cached for performance (avoid repeated async calls) 4. Conditional Disable: - Modify hasAnyWakeLockSupport() to be async - Returns false on Electron + Wayland combination - Logs clear warning message with workarounds - Updated all callers to await Behavior After Fix: | Platform | Session | Wake-Lock | Screen Lock | Result | |-----------|---------|-----------|-------------|--------| | Electron | Wayland | Disabled | Safe | No crash ✅ | | Electron | X11 | Active | Safe | Works ✅ | | Tauri | Any | Active | Safe | Works ✅ | User Impact: - Electron + Wayland users: Wake-lock disabled, app stable - Workaround 1: Switch to X11 session (wake-lock works) - Workaround 2: Use Tauri build (better Wayland support) - Workaround 3: Disable system auto-sleep - Electron + X11 users: No changes, feature works - Tauri users: No changes, feature works Validation: - npm run typecheck --workspace @codenomad/ui: PASSED ✅ - npm run typecheck --workspace @neuralnomads/codenomad-electron-app: PASSED ✅ - Manual testing: PENDING (requires X11/Wayland session switching) Testing Plan: 1. Electron + X11: Verify wake-lock works, screen lock safe 2. Electron + Wayland: Verify wake-lock disabled, no crash 3. Tauri + Wayland: Verify wake-lock works, screen lock safe Edge Cases Handled: - Electron API not available: Fallback to user agent - getPlatformInfo() fails: Error caught, fallback - Repeated detection calls: Result cached - Remote windows: API available in remote context Documentation: - Created WAKE-LOCK-WAYLAND-FIX.md with full implementation details - Includes testing procedures for X11/Wayland - User workarounds documented - Known limitations listed Known Limitations: - Electron + Wayland users lose wake-lock feature - Detection requires XDG_SESSION_TYPE environment variable - Runtime session switching requires CodeNomad restart - Upstream Electron fix needed for proper Wayland support Future Improvements: - Report to Electron project (may be fixed in Electron 40+) - Consider Tauri as primary build (better Wayland support) - Alternative Wayland protocol implementation Related: - Issue: NeuralNomadsAI#441 - Tasks: 055, 056, 057 - Investigation: wake-lock-verification-report.md - Bug Report: BUG-REPORT-SCREEN-LOCK-CRASH.md
Created installation guide for X11 on Arch Linux with KDE Plasma: Requirements: - xorg-server: X11 display server - plasma-workspace-x11: KDE Plasma session for X11 Purpose: Testing wake-lock fix on X11 before upstream PR. Current state: Wayland only (xorg-server not installed) X11 needed to verify wake-lock works safely without screen lock crash. Installation: - Simple pacman install command - Verification steps included - Session switching instructions Testing workflow: 1. Install X11 packages 2. Logout → Login with X11 session 3. Test wake-lock functionality (WAKE-LOCK-X11-TESTING-PLAN.md) 4. Capture screenshots 5. Create PR upstream 6. Return to Wayland Notes: - X11 only needed temporarily for testing - Can switch back to Wayland after - Both sessions will coexist - Choice at login screen Related: WAKE-LOCK-X11-TESTING-PLAN.md, Issue NeuralNomadsAI#441
Created comprehensive feature request for sudo password input capability: Problem: - AI cannot execute sudo commands (terminal required for password) - User must manually copy/paste commands - Breaks workflow continuity - Common pain point Proposed Solution: Three options analyzed, recommending password modal approach: - Option A: Password prompt modal (recommended) - Option B: PTY with interaction (complex) - Option C: Session caching (future enhancement) Implementation Plan: Phase 1 (8h): Basic modal + password input Phase 2 (4h): Session caching (15 min timeout) Phase 3 (40h): Full PTY support (future) Security Design: - Never log passwords - Clear from memory immediately - Secure input (type=password) - No persistence - HTTPS transport only UX Flow: Current: 7 steps with context switch Proposed: 3 steps, no context switch Similar Features: - VS Code Remote SSH (password prompts) - JetBrains IDEs (interactive terminal) - GitHub Desktop (sudo for git operations) Priority: Medium Effort: 12 hours total (Phase 1 + 2) ROI: High (better UX, competitive feature) Session Error Evidence: Added screenshot and documentation of "Error: Aborted" bug: - pictures/error_20260514_135657.png (191KB) - SESSION-ERROR-ABORTED-EVIDENCE.md (400+ lines) Screenshot shows: - Modal: "Session error - Error: Aborted" - Timestamp: May 14 13:56:57 - Context: PC web browser - Evidence of browser timeout → abort → auto-reload Analysis confirms: - Root cause: No server-side timeout - Browser aborts after 60-90s - Server left in stuck state - PM2 restart required This completes the session stuck bug documentation with visual evidence. Next Steps: 1. Discuss feature with upstream maintainers 2. Create GitHub issue for sudo password input 3. Implement if approved (Phase 1: 8 hours) Related: Issue NeuralNomadsAI#441 (wake-lock), session stuck bug investigation
…hase 1 Session idle notifications were silently blocked when the browser tab was visible and osNotificationsAllowWhenVisible was falsy, because preferences default to `osNotificationsEnabled=false` on the server and the UI checks visibility before sending. Users never saw idle-triggered OS notifications regardless of their settings toggles. Changes in session-events.ts: - Remove verbose logging that existed purely for Issue NeuralNomadsAI#378 debugging - Restore concise boolean guard chain in shouldSendOsNotification - Drop stale comment in shouldSendOsNotificationForSession - Localise the idle notification body to Spanish, matching the rest of the UI Symbol Attachments Phase 1 (in attachment.ts): - Add SYMBOL_KIND_LABELS map for the 26 LSP SymbolKind values - Export symbolKindLabel(kind) lookup helper - Implement createSymbolAttachment() that builds a symbol-type Attachment with file URL, display label, and source metadata i18n (7 locales: en, es, fr, ru, ja, zh-Hans, he): - Insert attachmentChip.symbol.ariaLabel and .kindLabel strings - Append @symbol to promptInput.placeholder.default All changes are additive and backward-compatible; the notification path now honours the same preferences but produces visible results when osNotificationsEnabled=true in server-side config.
When a workspace is cleaned up or deleted, the background process manager was throwing 'Workspace not found' error when trying to finalize records. This caused the server to crash in an infinite loop. The fix wraps the finalization operations in try-catch blocks to gracefully handle the case where a workspace no longer exists in the workspace manager. This allows the server to continue running even when old sessions reference deleted workspaces. Fixes the infinite loop crash that occurred when sessions were terminated.
The init.sh was trying to run 'pnpm test' which doesn't exist in the project, causing the harness initialization to fail. Updated the script to check if a test script is defined before attempting to run it.
Add a keyboard-toggleable debug overlay (Ctrl+Shift+D) that surfaces real-time session state from CodeNomad's stores. This is a diagnostic tool used to investigate cross-project session leakage where a single session appears in multiple workspace UIs. The overlay shows: - All active instances with their workspace IDs and folders - Sessions stored under each instance map (id, title, directory, parent) - The currently active instance ID - Per-session and per-instance copy-to-clipboard buttons - A "Share" button that copies the full state as JSON for issue reports - Minimize/Close controls and a keyboard shortcut reminder input Activation: Ctrl+Shift+D toggles the overlay globally; rendered from App.tsx so it works from any view. Useful for debugging session-instance mismatches without restarting the server or rebuilding the UI for each investigation cycle. Co-Authored-By: Claude <noreply@anthropic.com>
The debug overlay had a single scrollable container that included both the header (title + control buttons) and the content. When scrolling through long session lists, the header scrolled out of view, making the Share/Minimize/Close controls unreachable without scrolling back up. Restructure the overlay so the header is rendered as a separate flex child with flex-shrink: 0 and its own background, while only the content area scrolls. The header now stays pinned at the top of the overlay regardless of scroll position. Also remove the duplicate <Show> wrapper around the content body that was introduced when restructuring. Co-Authored-By: Claude <noreply@anthropic.com>
The WorkspaceManager.create() method generated a new workspace ID on every call without checking whether a workspace already existed for the same folder path. Combined with the UI recreating instances on each refresh, this caused dozens of duplicate workspaces per project (74+ for test, 29+ for idm in one session). Each duplicate workspace spawned its own OpenCode process pointed at the same SQLite database (~/.local/share/opencode/opencode.db). The UI then showed the same session in every workspace that targeted the same folder, and deleting it from one workspace removed it from the shared DB — affecting all the others. Add an early-return path: if a workspace already exists for the resolved folder path, return it instead of spawning a new one. This matches the frontend's getExistingInstanceForFolder() intent and keeps one OpenCode process per project folder. Co-Authored-By: Claude <noreply@anthropic.com>
The backend deduplication added in cf0128f only worked within a single server lifetime. After a restart, the backend's in-memory workspace map was empty, so the UI calling createInstance() for each open project tab spawned a fresh workspace every time. Make createInstance() fetch the current workspace list from the backend and reuse any workspace whose resolved path matches the folder we're trying to open. Only call POST /api/workspaces when no match is found. This keeps one OpenCode process per folder across server restarts and prevents the "same session in multiple projects" symptom. Co-Authored-By: Claude <noreply@anthropic.com>
Build on the workspace deduplication fix with the observability tools needed to verify it works and detect regressions. - packages/server/src/workspaces/manager.ts: structured pino logging on every create() call with an `action` discriminator (create_request / reused / created / dedup_missed). `dedup_missed` is logged at error level and fires if `pathOccurrences > 0` but the dedup loop missed them — tripwire for normalization bugs. Add getStats() returning total + byPath counts. - packages/server/src/server/routes/workspaces.ts: new GET /api/workspaces/stats endpoint exposing getStats() for easy health checks (curl it and confirm byPath values are all 1). - scripts/monitor-workspaces.sh: tail PM2 out log and color-code workspace activity in real time (cyan request, yellow reuse, green new, red dedup_missed). A healthy run is mostly yellow. - docs/WORKSPACE_DEBUG.md: documents the bug, the two-commit fix, the new endpoint, the in-browser debug overlay, and the monitor script. Lists every file touched so future contributors know what to look at. Co-Authored-By: Claude <noreply@anthropic.com>
OpenCode 1.17.10 has a bug in the /session endpoint: when scope=project is passed, it ignores the directory filter and returns ALL sessions across every project. This made the same session appear in every project tab in CodeNomad — deleting a session from one tab deleted it from all of them. The scope=project parameter was added in upstream PR NeuralNomadsAI#565 (commit e29c3a0) to avoid pagination limits on the default endpoint. With the directory filter ignored, that optimization becomes a correctness bug, so drop scope=project until OpenCode fixes the backend. With directory alone, the endpoint correctly returns only the sessions for the requested folder. Verified via curl on the running process: directory=/test returns 1 session (Hola greeting), directory=/idm returns 1 session (up). Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
PR #565 (commit e29c3a0) added
scope=projectto session list requests to avoid pagination limits. With OpenCode 1.17.x, the/sessionendpoint ignores thedirectoryfilter whenscope=projectis present and returns all sessions from the global SQLite database instead.This makes the same session appear in every project tab. Deleting a session from one tab deletes it from the shared DB, affecting all of them.
Reproduction
Related: anomalyco/opencode#33113
Fix
Drop
scope: "project"frombuildProjectSessionListOptions(). Thedirectoryparameter alone correctly filters sessions to the requested folder on OpenCode 1.17.x.scope: "project"can be reintroduced once the backend respectsdirectoryalongside it.Validation
directory=/test→ 1 session (correct)directory=/idm→ 1 session (correct)